PCI_ER="^[0-9a-fA-F]{4}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}\.[0-9a-fA-F]{1}" # Get values in synoinfo.conf K=V file # 1 - key function _get_conf_kv() { grep "${1}=" /etc/synoinfo.conf | sed "s|^${1}=\"\(.*\)\"$|\1|g" } # Replace/add values in synoinfo.conf K=V file # Args: $1 rd|hd, $2 key, $3 val function _set_conf_kv() { local ROOT local FILE [ "$1" = "rd" ] && ROOT="" || ROOT="/tmpRoot" for SD in etc etc.defaults; do FILE="${ROOT}/${SD}/synoinfo.conf" # Replace if grep -q "^$2=" ${FILE}; then sed -i ${FILE} -e "s\"^$2=.*\"$2=\\\"$3\\\"\"" else # Add if doesn't exist echo "$2=\"$3\"" >>${FILE} fi done } # Check if the user has customized the key # Args: $1 rd|hd, $2 key function _check_post_k() { local ROOT [ "$1" = "rd" ] && ROOT="" || ROOT="/tmpRoot" if grep -q -r "^_set_conf_kv.*${2}.*" "${ROOT}/sbin/init.post"; then return 0 # true else return 1 # false fi } # Check if the raid has been completed currently function _check_rootraidstatus() { if [ "$(_get_conf_kv supportraid)" != "yes" ]; then return 0 fi State=$(cat /sys/block/md0/md/array_state) 2>/dev/null if [ $? != 0 ]; then return 1 fi case ${State} in "clear" | "inactive" | "suspended " | "readonly" | "read-auto") return 1 ;; esac return 0 } # Calculate # 0 bits function getNum0Bits() { local VALUE=$1 local NUM=0 while [ $((${VALUE} % 2)) -eq 0 -a ${VALUE} -ne 0 ]; do NUM=$((${NUM} + 1)) VALUE=$((${VALUE} / 2)) done echo ${NUM} } # USB ports function getUsbPorts() { for I in $(ls -d /sys/bus/usb/devices/usb*); do # ROOT DCLASS=$(cat ${I}/bDeviceClass) [ "${DCLASS}" != "09" ] && continue SPEED=$(cat ${I}/speed) [ ${SPEED} -lt 480 ] && continue RBUS=$(cat ${I}/busnum) RCHILDS=$(cat ${I}/maxchild) HAVE_CHILD=0 for C in $(seq 1 ${RCHILDS}); do SUB="${RBUS}-${C}" if [ -d "${I}/${SUB}" ]; then DCLASS=$(cat ${I}/${SUB}/bDeviceClass) [ "${DCLASS}" != "09" ] && continue SPEED=$(cat ${I}/${SUB}/speed) [ ${SPEED} -lt 480 ] && continue CHILDS=$(cat ${I}/${SUB}/maxchild) HAVE_CHILD=1 for N in $(seq 1 ${CHILDS}); do echo -n "${RBUS}-${C}.${N} " done fi done if [ ${HAVE_CHILD} -eq 0 ]; then for N in $(seq 1 ${RCHILDS}); do echo -n "${RBUS}-${N} " done fi done echo } # SATA ports # 1 - is DT model function getSataPorts() { local SATA_PORTS=$(ls /sys/class/ata_port | wc -w) local OUTPUT="" for I in $(seq 1 ${SATA_PORTS}); do DUMMY=$((1 - $(cat /sys/class/ata_port/ata${I}/device/host*/scsi_host/host*/syno_port_thaw))) # Is DT if [ "${1}" = "true" ]; then [ ${DUMMY} -eq 1 ] && continue PORTNO=$(cat /sys/class/ata_port/ata${I}/port_no) _PATH=$(readlink /sys/class/ata_port/ata${I} | sed 's|^.*\(pci.*\)|\1|' | cut -d'/' -f2-) DSMPATH="" while true; do FIRST=$(echo "${_PATH}" | cut -d'/' -f1) echo "${FIRST}" | grep -qE "${PCI_ER}" || break [ -z "${DSMPATH}" ] && DSMPATH="$(echo "${FIRST}" | cut -d':' -f2-)" || DSMPATH="${DSMPATH},$(echo "${FIRST}" | cut -d':' -f3)" _PATH=$(echo ${_PATH} | cut -d'/' -f2-) done echo -n "${DSMPATH}:${PORTNO} " else if [ ${DUMMY} -eq 1 ]; then OUTPUT="0${OUTPUT}" else OUTPUT="1${OUTPUT}" fi fi done echo "${OUTPUT}" } # NVME ports # 1 - is DT model function nvmePorts() { local NVME_PORTS=$(ls /sys/class/nvme | wc -w) for I in $(seq 0 $((${NVME_PORTS} - 1))); do _PATH=$(readlink /sys/class/nvme/nvme${I} | sed 's|^.*\(pci.*\)|\1|' | cut -d'/' -f2-) if [ "${1}" = "true" ]; then # Device-tree: assemble complete path in DSM format DSMPATH="" while true; do FIRST=$(echo "${_PATH}" | cut -d'/' -f1) echo "${FIRST}" | grep -qE "${PCI_ER}" || break [ -z "${DSMPATH}" ] && DSMPATH="$(echo "${FIRST}" | cut -d':' -f2-)" || DSMPATH="${DSMPATH},$(echo "${FIRST}" | cut -d':' -f3)" _PATH=$(echo ${_PATH} | cut -d'/' -f2-) done else # Non-dt: just get PCI ID DSMPATH=$(echo "${_PATH}" | cut -d'/' -f1) fi echo -n "${DSMPATH} " done echo } # function dtModel() { DEST="/exts/model.dts" if [ ! -f "${DEST}" ]; then # Users can put their own dts. echo "/dts-v1/;" >${DEST} echo "/ {" >>${DEST} echo " compatible = \"Synology\";" >>${DEST} echo " model = \"${1}\";" >>${DEST} echo " version = <0x01>;" >>${DEST} # SATA ports I=1 while true; do [ ! -d /sys/block/sata${I} ] && break PCIEPATH=$(grep 'pciepath' /sys/block/sata${I}/device/syno_block_info | cut -d'=' -f2) ATAPORT=$(grep 'ata_port_no' /sys/block/sata${I}/device/syno_block_info | cut -d'=' -f2) echo " internal_slot@${I} {" >>${DEST} echo " protocol_type = \"sata\";" >>${DEST} echo " ahci {" >>${DEST} echo " pcie_root = \"${PCIEPATH}\";" >>${DEST} echo " ata_port = <0x$(printf '%02X' ${ATAPORT})>;" >>${DEST} echo " };" >>${DEST} echo " };" >>${DEST} I=$((${I} + 1)) done NUMPORTS=$((${I} - 1)) if [ $NUMPORTS -eq 1 ]; then # fix isSingleBay issue: # if maxdisks is 1, there is no create button in the storage panel NUMPORTS=2 fi _set_conf_kv rd "maxdisks" "${NUMPORTS}" echo "maxdisks=${NUMPORTS}" # NVME ports COUNT=1 for P in $(nvmePorts true); do echo " nvme_slot@${COUNT} {" >>${DEST} echo " pcie_root = \"${P}\";" >>${DEST} echo " port_type = \"ssdcache\";" >>${DEST} echo " };" >>${DEST} COUNT=$((${COUNT} + 1)) done # USB ports COUNT=1 for I in $(getUsbPorts); do echo " usb_slot@${COUNT} {" >>${DEST} echo " usb2 {" >>${DEST} echo " usb_port =\"${I}\";" >>${DEST} echo " };" >>${DEST} echo " usb3 {" >>${DEST} echo " usb_port =\"${I}\";" >>${DEST} echo " };" >>${DEST} echo " };" >>${DEST} COUNT=$((${COUNT} + 1)) done echo "};" >>${DEST} fi dtc -I dts -O dtb ${DEST} >/etc/model.dtb cp -fv /etc/model.dtb /run/model.dtb /usr/syno/bin/syno_slot_mapping } # function nondtModel() { local SATA_PORTS=0 local SAS_PORTS=0 local NUMPORTS=0 local ESATAPORTCFG=$(($(_get_conf_kv esataportcfg))) local INTPORTCFG local USBPORTCFG=$(($(_get_conf_kv usbportcfg))) local COUNT=1 if _check_post_k "rd" "maxdisks"; then NUMPORTS=$(($(_get_conf_kv maxdisks))) echo "get maxdisks=${NUMPORTS}" else # sysfs is populated here SATA_PORTS=$(ls /sys/class/ata_port | wc -w) [ -d '/sys/class/sas_phy' ] && SAS_PORTS=$(ls /sys/class/sas_phy | wc -w) [ -d '/sys/class/scsi_disk' ] && SCSI_PORTS=$(ls /sys/class/scsi_disk | wc -w) NUMPORTS=$((${SATA_PORTS} + ${SAS_PORTS} + ${SCSI_PORTS})) # Raidtool will read maxdisks, but when maxdisks is greater than 27, formatting error will occur 8%. if ! _check_rootraidstatus && [ ${NUMPORTS} -gt 26 ]; then _set_conf_kv rd "maxdisks" "26" echo "set maxdisks=26" else _set_conf_kv rd "maxdisks" "${NUMPORTS}" echo "set maxdisks=${NUMPORTS}" fi fi if ! _check_post_k "rd" "internalportcfg"; then INTPORTCFG="0x$(printf "%x" $((2 ** ${NUMPORTS} - 1 - ${ESATAPORTCFG})))" _set_conf_kv rd "internalportcfg" "${INTPORTCFG}" echo "set internalportcfg=${INTPORTCFG}" echo "get esataportcfg=${ESATAPORTCFG}" fi if ! _check_post_k "rd" "internalportcfg"; then # USB ports static, always 4 ports USBPORT_IDX=$(getNum0Bits ${USBPORTCFG}) [ ${USBPORT_IDX} -lt ${NUMPORTS} ] && USBPORT_IDX=${NUMPORTS} USBPORTCFG="0x$(printf '%x' $((15 * 2 ** ${USBPORT_IDX})))" _set_conf_kv rd "usbportcfg" "${USBPORTCFG}" echo "set usbportcfg=${USBPORTCFG}" fi # NVME rm -f /etc/extensionPorts echo "[pci]" >/etc/extensionPorts chmod 755 /etc/extensionPorts for P in $(nvmePorts false); do echo "pci${COUNT}=\"${P}\"" >>/etc/extensionPorts COUNT=$((${COUNT} + 1)) done # log echo "maxdisks=${NUMPORTS}" echo "internalportcfg=${INTPORTCFG}" echo "esataportcfg=${ESATAPORTCFG}" echo "usbportcfg=${USBPORTCFG}" } if [ $(mount | grep tmpRoot | wc -l) -gt 0 ]; then HASBOOTED="yes" echo "System passed junior" else echo "System is booting" HASBOOTED="no" fi [ -f /etc/model.dtb ] || [ -f /etc.defaults/model.dtb ] && ISDTMODEL="true" # if [ "$HASBOOTED" = "no" ]; then cp -vf dtc /usr/sbin/ cp -vf readlink /usr/sbin/ cp -vf sed /usr/sbin/sed chmod 755 /usr/sbin/dtc /usr/sbin/readlink /usr/sbin/sed echo "Adjust disks related configs automatically - patches" [ "$ISDTMODEL" = "true" ] && dtModel ${3} || nondtModel elif [ "$HASBOOTED" = "yes" ]; then cp -vf dtc /tmpRoot/usr/sbin/ cp -vf readlink /tmpRoot/usr/sbin/ cp -vf sed /tmpRoot/usr/sbin/sed chmod 755 /tmpRoot/usr/sbin/dtc /tmpRoot/usr/sbin/readlink /tmpRoot/usr/sbin/sed echo "Adjust disks related configs automatically - late" if [ "$ISDTMODEL" = "true" ]; then echo "Copying /etc.defaults/model.dtb" # copy file cp -vf /etc/model.dtb /tmpRoot/etc/model.dtb cp -vf /etc/model.dtb /tmpRoot/etc.defaults/model.dtb else echo "Adjust maxdisks and internalportcfg automatically" # sysfs is unpopulated here, get the values from junior synoinfo.conf NUMPORTS=$(_get_conf_kv maxdisks) INTPORTCFG=$(_get_conf_kv internalportcfg) USBPORTCFG=$(_get_conf_kv usbportcfg) [ ${NUMPORTS} -gt 16 ] && _set_conf_kv hd "maxdisks" "${NUMPORTS}" || _set_conf_kv hd "maxdisks" "${NUMPORTS}" _set_conf_kv hd "internalportcfg" "${INTPORTCFG}" _set_conf_kv hd "usbportcfg" "${USBPORTCFG}" # log echo "maxdisks=${NUMPORTS}" echo "internalportcfg=${INTPORTCFG}" echo "usbportcfg=${USBPORTCFG}" cp -vf /etc/extensionPorts /tmpRoot/etc/extensionPorts cp -vf /etc/extensionPorts /tmpRoot/etc.defaults/extensionPorts fi fi