diff options
-rw-r--r-- | meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh | 72 |
1 files changed, 52 insertions, 20 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 940be7fb0..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,10 +56,14 @@ 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_to_file() { +ipmi_fru_device_alloc() { local fdn="$1" + local idx="$2" local json json="$(busctl -j call xyz.openbmc_project.FruDevice \ @@ -54,20 +72,21 @@ ipmi_fru_device_to_file() { local jqq='.data[0] | (.BUS.data | tostring) + " " + (.ADDRESS.data | tostring)' local busaddr - busaddr="$(echo "$json" | jq -r "$jqq")" || return + 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' ]; then - echo "/etc/fru/baseboard.fru.bin" + if (( busaddr[0] == 0 && busaddr[1] == 0 )); then + IPMI_FRU_EEPROM_FILE["$idx"]=/etc/fru/baseboard.fru.bin else - local dev="$(printf '%d-%04x' $busaddr)" - local efile="/sys/bus/i2c/devices/$dev/eeprom" - # The at24 eeprom driver is not guaranteed to be bound - if [ ! -e "$efile" ]; then - echo "$dev" >/sys/bus/i2c/drivers/at24/bind || return + 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 - echo "$efile" + IPMI_FRU_EEPROM_BUSADDR["$idx"]="${busaddr[*]} $offset_bw" fi } @@ -77,7 +96,8 @@ ipmi_fru_alloc() { # 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}" ] || break + [ -n "${IPMI_FRU_EEPROM_FILE[@]+1}" ] || \ + [ -n "${IPMI_FRU_EEPROM_BUSADDR[@]+1}" ]|| break done if [[ "$name" =~ ^of-name:(.*)$ || "$name" =~ ^([^:]*)$ ]]; then @@ -91,13 +111,12 @@ ipmi_fru_alloc() { local file while (( SECONDS - start < 60 )); do local rc=0 - file="$(ipmi_fru_device_to_file "$fdn")" || rc=$? + 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 - IPMI_FRU_EEPROM_FILE["$ret"]="$file" else echo "Invalid IPMI FRU eeprom specification: $name" >&2 return 1 @@ -106,6 +125,7 @@ ipmi_fru_alloc() { ipmi_fru_free() { unset 'IPMI_FRU_EEPROM_FILE[$1]' + unset 'IPMI_FRU_EEPROM_BUSADDR[$1]' } checksum() { @@ -127,24 +147,36 @@ fix_checksum() { } read_bytes() { + 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 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() { |