diff options
Diffstat (limited to 'meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh')
-rw-r--r-- | meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh | 116 |
1 files changed, 107 insertions, 9 deletions
diff --git a/meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh b/meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh index 335e0b21c..d02eeab47 100644 --- a/meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh +++ b/meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh @@ -23,6 +23,20 @@ IPMI_FRU_COMMON_HEADER_MULTI_RECORD_OFFSET_IDX=5 IPMI_FRU_AREA_HEADER_SIZE_IDX=1 IPMI_FRU_CHECKSUM_IDX=-1 +offset_1bw() { + local addr="$1" + local off="$2" + local extra="${3-0}" + echo w$((1+extra))@$addr $(( off & 0xff )) +} + +offset_2bw() { + local addr="$1" + local off="$2" + local extra="${3-0}" + echo w$((2+extra))@$addr $(( (off >> 8) & 0xff )) $(( off & 0xff )) +} + of_name_to_eeproms() { local names if ! names="$(grep -xl "$1" /sys/bus/i2c/devices/*/of_node/name)"; then @@ -42,6 +56,78 @@ of_name_to_eeprom() { echo "$eeproms" } +# Each element is a `filename` +declare -A IPMI_FRU_EEPROM_FILE=() +# Each element is a `bus` + `addr` + `offset_bytes_func` +declare -A IPMI_FRU_EEPROM_BUSADDR=() + +ipmi_fru_device_alloc() { + local fdn="$1" + local idx="$2" + + local json + json="$(busctl -j call xyz.openbmc_project.FruDevice \ + /xyz/openbmc_project/FruDevice/"$fdn" org.freedesktop.DBus.Properties \ + GetAll s xyz.openbmc_project.FruDevice)" || return 80 + + local jqq='.data[0] | (.BUS.data | tostring) + " " + (.ADDRESS.data | tostring)' + local busaddr + busaddr=($(echo "$json" | jq -r "$jqq")) || return + + # FRU 0 is hardcoded and FruDevice does not report the correct bus for it + # Hardcode a workaround for this specifically known bus + if (( busaddr[0] == 0 && busaddr[1] == 0 )); then + IPMI_FRU_EEPROM_FILE["$idx"]=/etc/fru/baseboard.fru.bin + else + local offset_bw=offset_2bw + local rsp + rsp=$(i2ctransfer -f -y ${busaddr[0]} $(offset_1bw ${busaddr[1]} 0) r1) || return + # FRUs never start with 0xff bytes, so we can figure out addressing mode + if (( rsp != 0xff )); then + offset_bw=offset_1bw + fi + IPMI_FRU_EEPROM_BUSADDR["$idx"]="${busaddr[*]} $offset_bw" + fi +} + +ipmi_fru_alloc() { + local name="$1" + local -n ret="$2" + + # Pick the first free index to return as the allocated entry + for (( ret = 0; ret < "${#IPMI_FRU_EEPROM_FILE[@]}"; ++ret )); do + [ -n "${IPMI_FRU_EEPROM_FILE[@]+1}" ] || \ + [ -n "${IPMI_FRU_EEPROM_BUSADDR[@]+1}" ]|| break + done + + if [[ "$name" =~ ^of-name:(.*)$ || "$name" =~ ^([^:]*)$ ]]; then + local ofn="${BASH_REMATCH[1]}" + local file + file="$(of_name_to_eeprom "$ofn")" || return + IPMI_FRU_EEPROM_FILE["$ret"]="$file" + elif [[ "$name" =~ ^frudev-name:(.*)$ ]]; then + local fdn="${BASH_REMATCH[1]}" + local start=$SECONDS + local file + while (( SECONDS - start < 60 )); do + local rc=0 + ipmi_fru_device_alloc "$fdn" "$ret" || rc=$? + (( rc == 0 )) && break + # Immediately return any errors, 80 is special to signify retry + (( rc != 80 )) && return $rc + sleep 1 + done + else + echo "Invalid IPMI FRU eeprom specification: $name" >&2 + return 1 + fi +} + +ipmi_fru_free() { + unset 'IPMI_FRU_EEPROM_FILE[$1]' + unset 'IPMI_FRU_EEPROM_BUSADDR[$1]' +} + checksum() { local -n checksum_arr="$1" local checksum=0 @@ -61,24 +147,36 @@ fix_checksum() { } read_bytes() { - local file="$1" + local busaddr=(${IPMI_FRU_EEPROM_BUSADDR["$1"]-}) + local file="${IPMI_FRU_EEPROM_FILE["$1"]-$1}" local offset="$2" local size="$3" - echo "Reading $file at $offset for $size" >&2 - dd if="$file" bs=1 count="$size" skip="$offset" 2>/dev/null | \ - hexdump -v -e '1/1 "%d "' + if (( "${#busaddr[@]}" > 0)); then + echo "Reading ${busaddr[*]} at $offset for $size" >&2 + i2ctransfer -f -y ${busaddr[0]} $(${busaddr[2]} ${busaddr[1]} $offset) r$size + else + echo "Reading $file at $offset for $size" >&2 + dd if="$file" bs=1 count="$size" skip="$offset" 2>/dev/null | \ + hexdump -v -e '1/1 "%d "' + fi } write_bytes() { - local file="$1" + local busaddr=(${IPMI_FRU_EEPROM_BUSADDR["$1"]-}) + local file="${IPMI_FRU_EEPROM_FILE["$1"]-$1}" local offset="$2" local -n bytes_arr="$3" - local hexstr - hexstr="$(printf '\\x%x' "${bytes_arr[@]}")" || return - echo "Writing $file at $offset for ${#bytes_arr[@]}" >&2 - printf "$hexstr" | dd of="$file" bs=1 seek=$offset 2>/dev/null + if (( "${#busaddr[@]}" > 0)); then + echo "Writing ${busaddr[*]} at $offset for ${#bytes_arr[@]}" >&2 + i2ctransfer -f -y ${busaddr[0]} $(${busaddr[2]} ${busaddr[1]} $offset ${#bytes_arr[@]}) ${bytes_arr[@]} + else + local hexstr + hexstr="$(printf '\\x%x' "${bytes_arr[@]}")" || return + echo "Writing $file at $offset for ${#bytes_arr[@]}" >&2 + printf "$hexstr" | dd of="$file" bs=1 seek=$offset 2>/dev/null + fi } read_header() { |