diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2015-04-01 21:45:22 +0000 |
---|---|---|
committer | Douglas Gilbert <dgilbert@interlog.com> | 2015-04-01 21:45:22 +0000 |
commit | baa91c3f8356cf0b5ff94a778070c3c6714ac5f9 (patch) | |
tree | 826c695e97adaba3d4cd421a4fb115014f516b87 | |
parent | e65afc2448aee567499271a1a0c904be67f797d4 (diff) | |
download | sg3_utils-baa91c3f8356cf0b5ff94a778070c3c6714ac5f9.tar.gz |
rescan-scsi-bus.sh+sg_rdac+sg_inq+sg_vpd: updates from Sean Stewart, NetApp
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@640 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | doc/sg_rdac.8 | 11 | ||||
-rwxr-xr-x | scripts/rescan-scsi-bus.sh | 250 | ||||
-rw-r--r-- | src/sg_inq.c | 165 | ||||
-rw-r--r-- | src/sg_rdac.c | 222 | ||||
-rw-r--r-- | src/sg_vpd_vendor.c | 241 |
6 files changed, 702 insertions, 194 deletions
@@ -2,7 +2,7 @@ Each utility has its own version number, date of last change and some description at the top of its ".c" file. All utilities in the main directory have their own "man" pages. There is also a sg3_utils man page. -Changelog for sg3_utils-1.41 [20150311] [svn: r639] +Changelog for sg3_utils-1.41 [20150401] [svn: r640] - sg_zone: new utility for open, close and finish zone commands introduced in zbc-r02 - sg_rep_zones and sg_reset_wp: change opcodes as @@ -17,6 +17,7 @@ Changelog for sg3_utils-1.41 [20150311] [svn: r639] - sg_inq+sg_vpd: fix SCSI name string decoding in device identification VPD page (0x83) - increase sanity on Unit Serial number VPD page + - improve rdac vpd page reporting (vendor) - sg_inq: improve NAA handling in dev_id VPD page - update version descriptor list to 20141221 - sg_vpd: add atomic boundary values (sbc4r04) @@ -31,8 +32,12 @@ Changelog for sg3_utils-1.41 [20150311] [svn: r639] multiple trailing NULLs - rescan-scsi-bus.sh: add --issue-lip-wait option and improve error handling + - improve dm-multipath handling - sg_modes: make '-HHH' output suitable as input to 'sdparm --inhex=' + - sg_rdac: add '-6' option for mode sense/select(6) + - add support for reporting more SCSI transports + and accessing rdac extended mode page 2c - sg_write_same: cleanup, mainly man page - scsi_logging_level: replace use of tr command - examples/sg_tst_async: cleanup diff --git a/doc/sg_rdac.8 b/doc/sg_rdac.8 index 8e3d27aa..fed5e90f 100644 --- a/doc/sg_rdac.8 +++ b/doc/sg_rdac.8 @@ -1,9 +1,9 @@ -.TH SG_RDAC "8" "November 2012" "sg3_utils\-1.35" SG3_UTILS +.TH SG_RDAC "8" "April 2015" "sg3_utils\-1.41" SG3_UTILS .SH NAME sg_rdac \- display or modify SCSI RDAC Redundant Controller mode page .SH SYNOPSIS .B sg_rdac -[\fI\-a\fR] [\fI\-f=LUN\fR] [\fI\-v\fR] [\fI\-V\fR] \fIDEVICE\fR +[\fI\-6\fR] [\fI\-a\fR] [\fI\-f=LUN\fR] [\fI\-v\fR] [\fI\-V\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP @@ -13,6 +13,11 @@ allows to transfer the ownership of individual drives to the controller the command was received on. .SH OPTIONS .TP +\fB\-6\fR +Use the 6 byte cdb variants of the SCSI MODE SENSE and MODE SELECT commands. +The default action (in the absence of this option) is to use the 10 byte +cdb variants. +.TP \fB\-a\fR Transfer all (visible) devices .TP @@ -33,7 +38,7 @@ Written by Hannes Reinecke <hare at suse dot com>, based on sg_emc_trespass. .SH "REPORTING BUGS" Report bugs to <dgilbert at interlog dot com>. .SH COPYRIGHT -Copyright \(co 2006\-2012 Hannes Reinecke, Douglas Gilbert. +Copyright \(co 2006\-2015 Hannes Reinecke, Douglas Gilbert. .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff --git a/scripts/rescan-scsi-bus.sh b/scripts/rescan-scsi-bus.sh index 51fdfd99..96c06890 100755 --- a/scripts/rescan-scsi-bus.sh +++ b/scripts/rescan-scsi-bus.sh @@ -91,8 +91,8 @@ findhosts () num=$name driverinfo=$driver if test -r $hostdir/status; then - num=$(printf '%d\n' `sed -n 's/SCSI host number://p' $hostdir/status`) - driverinfo="$driver:$name" + num=$(printf '%d\n' `sed -n 's/SCSI host number://p' $hostdir/status`) + driverinfo="$driver:$name" fi hosts="$hosts $num" echo "Host adapter $num ($driverinfo) found." @@ -147,19 +147,19 @@ procscsiscsi () if [ -d "$SCSIPATH" ] ; then SCSISTR="Host: scsi${host} Channel: $CHANNEL Id: $ID Lun: $LUN" if [ "$LN" -gt 0 ] ; then - IVEND=$(cat ${SCSIPATH}/device/vendor) - IPROD=$(cat ${SCSIPATH}/device/model) - IPREV=$(cat ${SCSIPATH}/device/rev) - SCSIDEV=$(printf ' Vendor: %-08s Model: %-16s Rev: %-4s' "$IVEND" "$IPROD" "$IPREV") - SCSISTR="$SCSISTR + IVEND=$(cat ${SCSIPATH}/device/vendor) + IPROD=$(cat ${SCSIPATH}/device/model) + IPREV=$(cat ${SCSIPATH}/device/rev) + SCSIDEV=$(printf ' Vendor: %-08s Model: %-16s Rev: %-4s' "$IVEND" "$IPROD" "$IPREV") + SCSISTR="$SCSISTR $SCSIDEV" fi if [ "$LN" -gt 1 ] ; then - ILVL=$(cat ${SCSIPATH}/device/scsi_level) - type=$(cat ${SCSIPATH}/device/type) - ITYPE=$(printtype $type) - SCSITMP=$(printf ' Type: %-17s ANSI SCSI revision: %02d' "$ITYPE" "$((ILVL - 1))") - SCSISTR="$SCSISTR + ILVL=$(cat ${SCSIPATH}/device/scsi_level) + type=$(cat ${SCSIPATH}/device/type) + ITYPE=$(printtype $type) + SCSITMP=$(printf ' Type: %-17s ANSI SCSI revision: %02d' "$ITYPE" "$((ILVL - 1))") + SCSISTR="$SCSISTR $SCSITMP" fi else @@ -175,14 +175,14 @@ $SCSITMP" # Find sg device with 2.6 sysfs support sgdevice26 () { - if test -e /sys/class/scsi_device/$host\:$channel\:$id\:$lun/device/generic; then + if test -e /sys/class/scsi_device/$host\:$channel\:$id\:$lun/device/generic; then SGDEV=`readlink /sys/class/scsi_device/$host\:$channel\:$id\:$lun/device/generic` SGDEV=`basename $SGDEV` else for SGDEV in /sys/class/scsi_generic/sg*; do DEV=`readlink $SGDEV/device` if test "${DEV##*/}" = "$host:$channel:$id:$lun"; then - SGDEV=`basename $SGDEV`; return + SGDEV=`basename $SGDEV`; return fi done SGDEV="" @@ -286,7 +286,7 @@ testonline () echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV changed: ${bold}\nfrom:${SCSISTR#* } \nto: $STR ${norm} \n\n\n" return 1 fi - TMPSTR=`echo "$SCSISTR" | sed -n 's/.*Type: *\(.*\) *ANSI.*/\1/p'` + TMPSTR=`echo "$SCSISTR" | sed -n 's/.*Type: *\(.*\) *ANSI.*/\1/p' | sed 's/ *$//g'` if [ "$TMPSTR" != "$TYPE" ] ; then echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV changed: ${bold}\nfrom:${TMPSTR} \nto: $TYPE ${norm} \n\n\n" return 1 @@ -322,7 +322,7 @@ chanlist () chan=${cil%%:*} for tmpchan in $channelsearch ; do if test "$chan" -eq $tmpchan ; then - chan= + chan= fi done if test -n "$chan" ; then @@ -348,8 +348,8 @@ idlist () newid=$id for tmpid in $idsearch ; do if test $id -eq $tmpid ; then - newid= - break + newid= + break fi done if test -n "$newid" ; then @@ -394,9 +394,17 @@ getluns() # Wait for udev to settle (create device nodes etc.) udevadm_settle() { + local tmo=60 if test -x /sbin/udevadm; then print_and_scroll_back " Calling udevadm settle (can take a while) " - /sbin/udevadm settle + # Loop for up to 60 seconds if sd devices still are settling.. + # This allows us to continue if udev events are stuck on multipaths in recovery mode + while [ $tmo -gt 0 ] ; do + if ! /sbin/udevadm settle --timeout=1 | egrep -q sd[a-z]+ ; then + break; + fi + let tmo=$tmo-1 + done white_out elif test -x /sbin/udevsettle; then print_and_scroll_back " Calling udevsettle (can take a while) " @@ -465,13 +473,13 @@ dolunscan() incrrmvd "$host:$channel:$id:$lun" fi echo 1 > /sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/delete - usleep 20000 + usleep 20000 else echo "scsi remove-single-device $devnr" > /proc/scsi/scsi - if test $RC -eq 1 -o $lun -eq 0 ; then + if test $RC -eq 1 -o $lun -eq 0 ; then # Try readding, should fail if device is gone echo "scsi add-single-device $devnr" > /proc/scsi/scsi - fi + fi fi fi if test $RC = 0 -o "$forcerescan" ; then @@ -543,7 +551,7 @@ doreportlun() # Find alternative LUN to send getluns to for dev in /sys/class/scsi_device/${host}:${channel}:${id}:*; do [ -d "$dev" ] || continue - lun=${dev##*:} + lun=${dev##*:} break done fi @@ -581,10 +589,10 @@ doreportlun() # OK, is existing $lun (still) in reported list for tmplun in $targetluns; do if test $tmplun -eq $lun ; then - inlist=1 - dolunscan $lun0added + inlist=1 + dolunscan $lun0added else - newsearch="$newsearch $tmplun" + newsearch="$newsearch $tmplun" fi done # OK, we have now done a lunscan on $lun and @@ -614,9 +622,9 @@ dosearch () fi for id in $idsearch; do if test -z "$lunsearch" ; then - doreportlun + doreportlun else - for lun in $lunsearch; do + for lun in $lunsearch; do dolunscan done fi @@ -661,12 +669,12 @@ searchexisting() id=`echo $target | cut -d":" -f 3` if [ -n "$channelsearch" ] ; then for tmpch in $channelsearch ; do - test $tmpch -eq $channel && match=1 + test $tmpch -eq $channel && match=1 done else match=1 fi - + test $match -eq 0 && continue match=0 @@ -692,6 +700,8 @@ findremapped() local id_serial= local id_serial_old= local sysfs_devpath= + local mpath_uuid= + local remapped= mpaths="" local tmpfile="/tmp/rescan-scsi-bus-`date +s`" @@ -700,7 +710,7 @@ findremapped() # Get all of the ID_SERIAL attributes, after finding their sd node for hctl in $devs ; do if [ -d /sys/class/scsi_device/$hctl/device/block ] ; then - sddev=`ls /sys/class/scsi_device/$hctl/device/block` + sddev=`ls /sys/class/scsi_device/$hctl/device/block` id_serial_old=`udevadm info -q all -n $sddev | grep "ID_SERIAL=" | cut -d"=" -f2` [ -z "$id_serial_old" ] && id_serial_old="none" echo "$hctl $sddev $id_serial_old" >> $tmpfile @@ -710,33 +720,46 @@ findremapped() # Trigger udev to update the info echo -n "Triggering udev to update device information... " /sbin/udevadm trigger - udevadm_settle 2&>1 /dev/null + udevadm_settle 2>&1 /dev/null echo "Done" # See what changed and reload the respective multipath device if applicable while read hctl sddev id_serial_old ; do + remapped=0 id_serial=`udevadm info -q all -n $sddev | grep "ID_SERIAL=" | cut -d"=" -f2` [ -z "$id_serial" ] && id_serial="none" if [ "$id_serial_old" != "$id_serial" ] ; then - if [ "$id_serial" = "1" ] ; then - continue # the lun was unmapped and is getting the blank scsi id (1) + remapped=1 + fi + # If udev events updated the disks already, but the multipath device isn't update + # check for old devices to make sure we found remapped luns + if [ -n "$mp_enable" ] && [ $remapped -eq 0 ]; then + findmultipath $sddev $id_serial + if [ $? -eq 1 ] ; then + remapped=1 fi - printf "${yellow}REMAPPED: $norm" - host=`echo $hctl | cut -d":" -f1` - channel=`echo $hctl | cut -d":" -f2` - id=`echo $hctl | cut -d":" -f3` - lun=`echo $hctl | cut -d":" -f4` - procscsiscsi - echo "$SCSISTR" - incrchgd "$hctl" fi + + # if uuid is 1, it's unmapped, so we don't want to treat it as a remap + # if remapped flag is 0, just skip the rest of the logic + if [ "$id_serial" = "1" ] || [ $remapped -eq 0 ] ; then + continue + fi + printf "${yellow}REMAPPED: $norm" + host=`echo $hctl | cut -d":" -f1` + channel=`echo $hctl | cut -d":" -f2` + id=`echo $hctl | cut -d":" -f3` + lun=`echo $hctl | cut -d":" -f4` + procscsiscsi + echo "$SCSISTR" + incrchgd "$hctl" done < $tmpfile - rm $tmpfile 2&>1 /dev/null + rm $tmpfile 2>&1 /dev/null if test -n "$mp_enable" -a -n "$mpaths" ; then echo "Updating multipath device mappings" flushmpaths - $MULTIPATH | grep "create:" 2> /dev/null #2&>1 /dev/null + $MULTIPATH | grep "create:" 2> /dev/null fi } @@ -755,8 +778,10 @@ incrchgd() { local hctl="$1" if test -n "$hctl" ; then - let updated+=1 - CHGDEVS="$CHGDEVS\t[$hctl]\n" + if ! echo $CHGDEVS | grep -q "\[$hctl\]"; then + let updated+=1 + CHGDEVS="$CHGDEVS\t[$hctl]\n" + fi else return fi @@ -802,30 +827,61 @@ findsddev() return 0 } +addmpathtolist() +{ + local mp="$1" + local mp2= + + for mp2 in $mpaths ; do + # The multipath device is already in the list + if [ "$mp2" = "$mp" ] ; then + return + fi + done + mpaths="$mpaths $mp" +} + findmultipath() { local dev="$1" + local find_mismatch="$2" local mp= local mp2= + local found_dup=0 # Need a sdev, and executable multipath and dmsetup command here - if [ -z "$dev" ] || [ ! -x $DMSETUP ] ; then + if [ -z "$dev" ] || [ ! -x $DMSETUP ] || [ ! -x $MULTIPATH ] ; then return 1 fi local maj_min=`cat /sys/block/$dev/dev` for mp in $($DMSETUP ls --target=multipath | cut -f 1) ; do if $($DMSETUP status $mp | grep -q " $maj_min ") ; then - for mp2 in $mpaths ; do - # mp device is already there, return - if [ "$mp2" = "$mp" ] ; then - return + # With two arguments, look up current uuid from sysfs + # if it doesn't match what was passed, this multipath + # device is not updated, so this is a remapped LUN + if [ -n "$find_mismatch" ] ; then + mp2=`$MULTIPATH -l $mp | egrep -o dm-[0-9]+` + mp2=`cat /sys/block/$mp2/dm/uuid | cut -f2 -d-` + if [ "$find_mismatch" != "$mp2" ] ; then + addmpathtolist $mp + found_dup=1 fi - done - mpaths="$mpaths $mp" + continue + fi + # Normal mode: Find the first multipath with the sdev + # and add it to the list + addmpathtolist $mp return fi done + + # Return 1 to signal that a duplicate was found to the calling function + if [ $found_dup -eq 1 ] ; then + return 1 + else + return 0 + fi } reloadmpaths() @@ -836,51 +892,58 @@ reloadmpaths() return fi + # Pass 1 as the argument to reload all mpaths if [ "$1" = "1" ] ; then echo "Reloading all multipath devices" - $MULTIPATH -r 2&>1 /dev/null + $MULTIPATH -r > /dev/null 2>&1 return fi # Reload the multipath devices for mpath in $mpaths ; do - echo "Reloading multipath device $mpath" - $MULTIPATH -r $mpath 2&>1 /dev/null + echo -n "Reloading multipath device $mpath... " + $MULTIPATH -r $mpath > /dev/null 2>&1 + if test "$?" = "0" ; then + echo "Done" + else + echo "Fail" + fi done } flushmpaths() { local mpath - # Mode: flush only failed + local remove="" + local i + local flush_retries=5 + if test -n "$1" ; then for mpath in $($DMSETUP ls --target=multipath | cut -f 1) ; do num=$($DMSETUP status $mpath | awk 'BEGIN{RS=" ";active=0}/[0-9]+:[0-9]+/{dev=1}/A/{if (dev == 1) active++; dev=0} END{ print active }') if [ $num -eq 0 ] ; then - echo -n "Flushing multipath device $mpath... " - $DMSETUP message $mpath 0 fail_if_no_path 2&>1 /dev/null - $MULTIPATH -f $mpath 2&>1 /dev/null - $DMSETUP status $mpath 2&>1 /dev/null - if test "$?" = "1" ; then - echo "Done" - else - echo "Fail" - fi + remove="$remove $mpath" fi done - return + else + remove="$mpaths" fi - # Flush all the devs specified in $mpaths - for mpath in $mpaths ; do - echo -n "Flushing multipath device $mpath... " - $DMSETUP message $mpath 0 fail_if_no_path 2&>1 /dev/null - $MULTIPATH -f $mpath 2&>1 /dev/null - $DMSETUP status $mpath 2&>1 /dev/null - if test "$?" = "1" ; then - echo "Done" - else - echo "Fail" - fi + + for mpath in $remove ; do + i=0 + echo -n "Flushing multipath device $mpath... " + while [ $i -lt $flush_retries ] ; do + $DMSETUP message $mpath 0 fail_if_no_path > /dev/null 2>&1 + $MULTIPATH -f $mpath > /dev/null 2>&1 + if test "$?" = "0" ; then + echo "Done ($i retries)" + break + elif test $i -eq $flush_retries ; then + echo "Fail" + fi + usleep 20000 + let i=$i+1 + done done } @@ -893,16 +956,20 @@ findresized() local new_size= local sysfs_path= local sddev= + local i= + local m= + local mpathsize= + declare -a mpathsizes for hctl in $devs ; do sysfs_path="/sys/class/scsi_device/$hctl/device" if [ -d "$sysfs_path/block" ] ; then sddev=`ls $sysfs_path/block` size=`cat $sysfs_path/block/$sddev/size` - + echo 1 > $sysfs_path/rescan - new_size=`cat $sysfs_path/block/$sddev/size` - + new_size=`cat $sysfs_path/block/$sddev/size` + if [ "$size" != "$new_size" ] && [ "$size" != "0" ] && [ "$new_size" != "0" ] ; then printf "${yellow}RESIZED: $norm" host=`echo $hctl | cut -d":" -f1` @@ -918,7 +985,18 @@ findresized() done if test -n "$mp_enable" -a -n "$mpaths" ; then + i=0 + for m in $mpaths ; do + mpathsizes[$i]="`$MULTIPATH -l $m | egrep -o [0-9]+.[0-9]+[KMGT]`" + let i=$i+1 + done reloadmpaths + i=0 + for m in $mpaths ; do + mpathsize="`$MULTIPATH -l $m | egrep -o [0-9\.]+[KMGT]`" + echo "$m ${mpathsizes[$i]} => $mpathsize" + let i=$i+1 + done fi } @@ -976,7 +1054,7 @@ fi if test ! -d /sys/class/scsi_host/ -a ! -d /proc/scsi/; then echo "Error: SCSI subsystem not active" exit 1 -fi +fi # Make sure sg is there modprobe sg >/dev/null 2>&1 @@ -1114,6 +1192,9 @@ fi if [ $update -eq 1 ] ; then echo "Searching for remapped LUNs" findremapped + # If you've changed the mapping, there's a chance it's a different size + mpaths="" + findresized # Search for resized LUNs elif [ $resize -eq 1 ] ; then echo "Searching for resized LUNs" @@ -1164,13 +1245,12 @@ let rmvd_found=$rmvd+$found if test -n "$mp_enable" -a $rmvd_found -gt 0 ; then echo "Attempting to update multipath devices..." if test $rmvd -gt 0 ; then - /sbin/udevadm trigger udevadm_settle echo "Removing multipath mappings for removed devices if all paths are now failed... " flushmpaths 1 fi if test $found -gt 0 ; then - /sbin/udevadm trigger + /sbin/udevadm trigger --sysname-match=sd* udevadm_settle echo "Trying to discover new multipath mappings for newly discovered devices... " $MULTIPATH | grep "create:" 2> /dev/null @@ -1181,7 +1261,7 @@ echo "$found new or changed device(s) found. " if test ! -z "$FOUNDDEVS" ; then printf "$FOUNDDEVS" fi -echo "$updated remapped or resized device(s) found. " +echo "$updated remapped or resized device(s) found." if test ! -z "$CHGDEVS" ; then printf "$CHGDEVS" fi diff --git a/src/sg_inq.c b/src/sg_inq.c index 5c050b1e..16d1b4c6 100644 --- a/src/sg_inq.c +++ b/src/sg_inq.c @@ -2661,8 +2661,8 @@ decode_rdac_vpd_c2(unsigned char * buff, int len, int do_hex) "not possible.\n" , buff[4], buff[5], buff[6], buff[7]); return; } - printf(" Software Version: %d.%d.%d\n", buff[8], buff[9], buff[10]); - printf(" Software Date: %02x/%02x/%02x\n", buff[11], buff[12], buff[13]); + printf(" Software Version: %02x.%02x.%02x\n", buff[8], buff[9], buff[10]); + printf(" Software Date: %02d/%02d/%02d\n", buff[11], buff[12], buff[13]); printf(" Features:"); if (buff[14] & 0x01) printf(" Dual Active,"); @@ -2671,15 +2671,77 @@ decode_rdac_vpd_c2(unsigned char * buff, int len, int do_hex) if (buff[14] & 0x04) printf(" Multiple Sub-enclosures,"); if (buff[14] & 0x08) - printf(" DCE/DRM,"); + printf(" DCE/DRM/DSS/DVE,"); if (buff[14] & 0x10) - printf(" AVT,"); + printf(" Asymmetric Logical Unit Access,"); printf("\n"); printf(" Max. #of LUNS: %d\n", buff[15]); return; } static void +decode_rdac_vpd_c9_rtpg_data(unsigned char aas, unsigned char vendor) +{ + printf(" Asymmetric Access State:"); + switch(aas & 0x0F) { + case 0x0: + printf(" Active/Optimized"); + break; + case 0x1: + printf(" Active/Non-Optimized"); + break; + case 0x2: + printf(" Standby"); + break; + case 0x3: + printf(" Unavailable"); + break; + case 0xE: + printf(" Offline"); + break; + case 0xF: + printf(" Transitioning"); + break; + default: + printf(" (unknown)"); + break; + } + printf("\n"); + + printf(" Vendor Specific Field:"); + switch(vendor) { + case 0x01: + printf(" Operating normally"); + break; + case 0x02: + printf(" Non-responsive to queries"); + break; + case 0x03: + printf(" Controller being held in reset"); + break; + case 0x04: + printf(" Performing controller firmware download (1st controller)"); + break; + case 0x05: + printf(" Performing controller firmware download (2nd controller)"); + break; + case 0x06: + printf(" Quiesced as a result of an administrative request"); + break; + case 0x07: + printf(" Service mode as a result of an administrative request"); + break; + case 0xFF: + printf(" Details are not available"); + break; + default: + printf(" (unknown)"); + break; + } + printf("\n"); +} + +static void decode_rdac_vpd_c9(unsigned char * buff, int len, int do_hex) { if (len < 3) { @@ -2698,14 +2760,18 @@ decode_rdac_vpd_c9(unsigned char * buff, int len, int do_hex) if (buff[7] != '1') { pr2serr("Invalid page version '%c' (should be 1)\n", buff[7]); } - printf(" AVT:"); - if (buff[8] & 0x80) { - printf(" Enabled"); - if (buff[8] & 0x40) - printf(" (Allow reads on sector 0)"); - printf("\n"); + if ( (buff[8] & 0xE0) == 0xE0 ) { + printf(" IOShipping (ALUA): Enabled\n"); } else { - printf(" Disabled\n"); + printf(" AVT:"); + if (buff[8] & 0x80) { + printf(" Enabled"); + if (buff[8] & 0x40) + printf(" (Allow reads on sector 0)"); + printf("\n"); + } else { + printf(" Disabled\n"); + } } printf(" Volume Access via: "); if (buff[8] & 0x01) @@ -2713,17 +2779,72 @@ decode_rdac_vpd_c9(unsigned char * buff, int len, int do_hex) else printf("alternate controller\n"); - printf(" Path priority: %d ", buff[9] & 0xf); - switch(buff[9] & 0xf) { - case 0x1: - printf("(preferred path)\n"); - break; - case 0x2: - printf("(secondary path)\n"); - break; - default: - printf("(unknown)\n"); - break; + if (buff[8] & 0x08) { + printf(" Path priority: %d ", buff[15] & 0xf); + switch(buff[15] & 0xf) { + case 0x1: + printf("(preferred path)\n"); + break; + case 0x2: + printf("(secondary path)\n"); + break; + default: + printf("(unknown)\n"); + break; + } + + printf(" Preferred Path Auto Changeable:"); + switch(buff[14] & 0x3C) { + case 0x14: + printf(" No (User Disabled and Host Type Restricted)\n"); + break; + case 0x18: + printf(" No (User Disabled)\n"); + break; + case 0x24: + printf(" No (Host Type Restricted)\n"); + break; + case 0x28: + printf(" Yes\n"); + break; + default: + printf(" (Unknown)\n"); + break; + } + + printf(" Implicit Failback:"); + switch(buff[14] & 0x03) { + case 0x1: + printf(" Disabled\n"); + break; + case 0x2: + printf(" Enabled\n"); + break; + default: + printf(" (Unknown)\n"); + break; + } + } else { + printf(" Path priority: %d ", buff[9] & 0xf); + switch(buff[9] & 0xf) { + case 0x1: + printf("(preferred path)\n"); + break; + case 0x2: + printf("(secondary path)\n"); + break; + default: + printf("(unknown)\n"); + break; + } + } + + if (buff[8] & 0x80) { + printf(" Target Port Group Data (This controller):\n"); + decode_rdac_vpd_c9_rtpg_data(buff[10], buff[11]); + + printf(" Target Port Group Data (Alternate controller):\n"); + decode_rdac_vpd_c9_rtpg_data(buff[12], buff[13]); } return; diff --git a/src/sg_rdac.c b/src/sg_rdac.c index c1470438..6488e982 100644 --- a/src/sg_rdac.c +++ b/src/sg_rdac.c @@ -3,7 +3,7 @@ * * Retrieve / set RDAC options. * - * Copyright (C) 2006-2007 Hannes Reinecke <hare@suse.de> + * Copyright (C) 2006-2015 Hannes Reinecke <hare@suse.de> * * Based on sg_modes.c and sg_emc_trespass.c; credits from there apply. * @@ -25,15 +25,23 @@ #include "sg_cmds_basic.h" -static const char * version_str = "1.06 20130507"; +static const char * version_str = "1.07 20150401"; unsigned char mode6_hdr[] = { - 75, /* Length */ + 0x75, /* Length */ 0, /* medium */ 0, /* params */ 8, /* Block descriptor length */ }; +unsigned char mode10_hdr[] = { + 0x01, 0x18, /* Length */ + 0, /* medium */ + 0, /* params */ + 0, 0, /* reserved */ + 0, 0, /* block descriptor length */ +}; + unsigned char block_descriptor[] = { 0, /* Density code */ 0, 0, 0, /* Number of blocks */ @@ -41,22 +49,35 @@ unsigned char block_descriptor[] = { 0, 0x02, 0, /* 512 byte blocks */ }; -struct rdac_legacy_page { - unsigned char page_code; - unsigned char page_length; - char current_serial[16]; - char alternate_serial[16]; +struct rdac_page_common { + unsigned char current_serial[16]; + unsigned char alternate_serial[16]; unsigned char current_mode_msb; unsigned char current_mode_lsb; unsigned char alternate_mode_msb; unsigned char alternate_mode_lsb; unsigned char quiescence; unsigned char options; +}; + +struct rdac_legacy_page { + unsigned char page_code; + unsigned char page_length; + struct rdac_page_common attr; unsigned char lun_table[32]; unsigned char lun_table_exp[32]; unsigned short reserved; }; +struct rdac_expanded_page { + unsigned char page_code; + unsigned char subpage_code; + unsigned char page_length[2]; + struct rdac_page_common attr; + unsigned char lun_table[256]; + unsigned char reserved[2]; +}; + static int do_verbose = 0; static void dump_mode_page( unsigned char *page, int len ) @@ -83,31 +104,53 @@ static void dump_mode_page( unsigned char *page, int len ) #define RDAC_CONTROLLER_PAGE_LEN 0x68 #define LEGACY_PAGE 0x00 #define EXPANDED_LUN_SPACE_PAGE 0x01 +#define EXPANDED_LUN_SPACE_PAGE_LEN 0x128 #define RDAC_FAIL_ALL_PATHS 0x1 #define RDAC_FAIL_SELECTED_PATHS 0x2 #define RDAC_FORCE_QUIESCENCE 0x2 #define RDAC_QUIESCENCE_TIME 10 -static int fail_all_paths(int fd) +static int fail_all_paths(int fd, int use_6_byte) { - unsigned char fail_paths_pg[118]; + unsigned char fail_paths_pg[308]; struct rdac_legacy_page *rdac_page; + struct rdac_expanded_page *rdac_page_exp; + struct rdac_page_common *rdac_common = NULL; + int res; char b[80]; - memset(fail_paths_pg, 0, 118); - memcpy(fail_paths_pg, mode6_hdr, 4); - memcpy(fail_paths_pg + 4, block_descriptor, 8); - rdac_page = (struct rdac_legacy_page *)(fail_paths_pg + 4 + 8); - rdac_page->page_code = RDAC_CONTROLLER_PAGE | 0x40; - rdac_page->page_length = RDAC_CONTROLLER_PAGE_LEN; - rdac_page->quiescence = RDAC_QUIESCENCE_TIME; - rdac_page->options = RDAC_FORCE_QUIESCENCE; - rdac_page->current_mode_lsb = RDAC_FAIL_ALL_PATHS; + memset(fail_paths_pg, 0, 308); + if (use_6_byte) { + memcpy(fail_paths_pg, mode6_hdr, 4); + memcpy(fail_paths_pg + 4, block_descriptor, 8); + rdac_page = (struct rdac_legacy_page *)(fail_paths_pg + 4 + 8); + rdac_page->page_code = RDAC_CONTROLLER_PAGE; + rdac_page->page_length = RDAC_CONTROLLER_PAGE_LEN; + rdac_common = &rdac_page->attr; + } else { + memcpy(fail_paths_pg, mode10_hdr, 8); + rdac_page_exp = (struct rdac_expanded_page *)(fail_paths_pg + 8); + rdac_page_exp->page_code = RDAC_CONTROLLER_PAGE | 0x40; + rdac_page_exp->subpage_code = 0x1; + rdac_page_exp->page_length[0] = EXPANDED_LUN_SPACE_PAGE_LEN >> 8; + rdac_page_exp->page_length[1] = EXPANDED_LUN_SPACE_PAGE_LEN & 0xFF; + rdac_common = &rdac_page_exp->attr; + } + + rdac_common->current_mode_lsb = RDAC_FAIL_ALL_PATHS; + rdac_common->quiescence = RDAC_QUIESCENCE_TIME; + rdac_common->options = RDAC_FORCE_QUIESCENCE; - res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */, - fail_paths_pg, 118, - 1, (do_verbose ? 2 : 0)); + if (use_6_byte) { + res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */, + fail_paths_pg, 118, + 1, (do_verbose ? 2 : 0)); + } else { + res = sg_ll_mode_select10(fd, 1 /* pf */, 0 /* sp */, + fail_paths_pg, 308, + 1, (do_verbose ? 2: 0)); + } switch (res) { case 0: @@ -123,28 +166,55 @@ static int fail_all_paths(int fd) return res; } -static int fail_this_path(int fd, int lun) +static int fail_this_path(int fd, int lun, int use_6_byte) { - unsigned char fail_paths_pg[118]; + unsigned char fail_paths_pg[308]; struct rdac_legacy_page *rdac_page; + struct rdac_expanded_page *rdac_page_exp; + struct rdac_page_common *rdac_common = NULL; int res; char b[80]; - memset(fail_paths_pg, 0, 118); - memcpy(fail_paths_pg, mode6_hdr, 4); - memcpy(fail_paths_pg + 4, block_descriptor, 8); - rdac_page = (struct rdac_legacy_page *)(fail_paths_pg + 4 + 8); - rdac_page->page_code = RDAC_CONTROLLER_PAGE | 0x40; - rdac_page->page_length = RDAC_CONTROLLER_PAGE_LEN; - rdac_page->current_mode_lsb = RDAC_FAIL_SELECTED_PATHS; - rdac_page->quiescence = RDAC_QUIESCENCE_TIME; - rdac_page->options = RDAC_FORCE_QUIESCENCE; - memset(rdac_page->lun_table, 0x0, 32); - rdac_page->lun_table[lun] = 0x81; - - res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */, - fail_paths_pg, 118, - 1, (do_verbose ? 2 : 0)); + if (use_6_byte && lun > 32) { + fprintf(stderr, "must use 10 byte cdb to fail luns over 32\n"); + return -1; + } + + memset(fail_paths_pg, 0, 308); + if (use_6_byte) { + memcpy(fail_paths_pg, mode6_hdr, 4); + memcpy(fail_paths_pg + 4, block_descriptor, 8); + rdac_page = (struct rdac_legacy_page *)(fail_paths_pg + 4 + 8); + rdac_page->page_code = RDAC_CONTROLLER_PAGE; + rdac_page->page_length = RDAC_CONTROLLER_PAGE_LEN; + rdac_common = &rdac_page->attr; + memset(rdac_page->lun_table, 0x0, 32); + rdac_page->lun_table[lun] = 0x81; + } else { + memcpy(fail_paths_pg, mode10_hdr, 8); + rdac_page_exp = (struct rdac_expanded_page *)(fail_paths_pg + 8); + rdac_page_exp->page_code = RDAC_CONTROLLER_PAGE | 0x40; + rdac_page_exp->subpage_code = 0x1; + rdac_page_exp->page_length[0] = EXPANDED_LUN_SPACE_PAGE_LEN >> 8; + rdac_page_exp->page_length[1] = EXPANDED_LUN_SPACE_PAGE_LEN & 0xFF; + rdac_common = &rdac_page_exp->attr; + memset(rdac_page_exp->lun_table, 0x0, 256); + rdac_page_exp->lun_table[lun] = 0x81; + } + + rdac_common->current_mode_lsb = RDAC_FAIL_SELECTED_PATHS; + rdac_common->quiescence = RDAC_QUIESCENCE_TIME; + rdac_common->options = RDAC_FORCE_QUIESCENCE; + + if (use_6_byte) { + res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */, + fail_paths_pg, 118, + 1, (do_verbose ? 2 : 0)); + } else { + res = sg_ll_mode_select10(fd, 1 /* pf */, 0 /* sp */, + fail_paths_pg, 308, + 1, (do_verbose ? 2: 0)); + } switch (res) { case 0: @@ -161,16 +231,29 @@ static int fail_this_path(int fd, int lun) return res; } -static void print_rdac_mode( unsigned char *ptr ) +static void print_rdac_mode( unsigned char *ptr, int subpg) { - struct rdac_legacy_page *rdac_ptr; - int i, k, bd_len; - - bd_len = ptr[3]; - - rdac_ptr = (struct rdac_legacy_page *)(ptr + 4 + bd_len); + struct rdac_legacy_page *legacy; + struct rdac_expanded_page *expanded; + struct rdac_page_common *rdac_ptr = NULL; + unsigned char * lun_table = NULL; + int i, k, bd_len, lun_table_len; + + if (subpg == 1) { + bd_len = ptr[7]; + expanded = (struct rdac_expanded_page *)(ptr + 8 + bd_len); + rdac_ptr = &expanded->attr; + lun_table = expanded->lun_table; + lun_table_len = 256; + } else { + bd_len = ptr[3]; + legacy = (struct rdac_legacy_page *)(ptr + 4 + bd_len); + rdac_ptr = &legacy->attr; + lun_table = legacy->lun_table; + lun_table_len = 32; + } - printf("RDAC Legacy page\n"); + printf("RDAC %s page\n", (subpg == 1) ? "Expanded" : "Legacy"); printf(" Controller serial: %s\n", rdac_ptr->current_serial); printf(" Alternate controller serial: %s\n", @@ -211,9 +294,6 @@ static void print_rdac_mode( unsigned char *ptr ) case 0x01: printf("alternate controller present; "); break; - case 0x02: - printf("active/active mode; "); - break; default: printf("(Unknown status 0x%x); ", rdac_ptr->alternate_mode_msb); @@ -229,7 +309,10 @@ static void print_rdac_mode( unsigned char *ptr ) case 0x2: printf("Dual active mode\n"); break; - case 0x04: + case 0x3: + printf("Not present\n"); + break; + case 0x4: printf("held in reset\n"); break; default: @@ -238,11 +321,14 @@ static void print_rdac_mode( unsigned char *ptr ) } printf(" Quiescence timeout: %d\n", rdac_ptr->quiescence); printf(" RDAC option 0x%x\n", rdac_ptr->options); - printf (" LUN Table:\n"); - for (k = 0; k < 32; k += 8) { - printf(" %x:",k / 8); - for (i = 0; i < 8; i++) { - switch (rdac_ptr->lun_table[k + i]) { + printf(" ALUA: %s\n", (rdac_ptr->options & 0x4 ? "Enabled" : "Disabled" )); + printf(" Force Quiescence: %s\n", (rdac_ptr->options & 0x2 ? "Enabled" : "Disabled" )); + printf (" LUN Table: (p = preferred, a = alternate, u = utm lun)\n"); + printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"); + for (k = 0; k < lun_table_len; k += 16) { + printf(" 0x%x:",k / 16); + for (i = 0; i < 16; i++) { + switch (lun_table[k + i]) { case 0x0: printf(" x"); break; @@ -259,6 +345,9 @@ static void print_rdac_mode( unsigned char *ptr ) printf(" ?"); break; } + if (i == 7) { + printf(" "); + } } printf("\n"); } @@ -266,8 +355,9 @@ static void print_rdac_mode( unsigned char *ptr ) static void usage() { - printf("Usage: sg_rdac [-a] [-f=LUN] [-v] [-V] DEVICE\n" + printf("Usage: sg_rdac [-6] [-a] [-f=LUN] [-v] [-V] DEVICE\n" " where:\n" + " -6 use 6 byte cdbs for mode sense/select\n" " -a transfer all devices to the controller\n" " serving DEVICE.\n" " -f=LUN transfer the device at LUN to the\n" @@ -288,6 +378,7 @@ int main(int argc, char * argv[]) int fail_all = 0; int fail_path = 0; int ret = 0; + int use_6_byte = 0; if (argc < 2) { usage (); @@ -305,6 +396,9 @@ int main(int argc, char * argv[]) else if (!strcmp(*argptr, "-a")) { ++fail_all; } + else if (!strcmp(*argptr, "-6")) { + use_6_byte = 1; + } else if (!strcmp(*argptr, "-V")) { fprintf(stderr, "sg_rdac version: %s\n", version_str); return 0; @@ -336,18 +430,24 @@ int main(int argc, char * argv[]) } if (fail_all) { - res = fail_all_paths(fd); + res = fail_all_paths(fd, use_6_byte); } else if (fail_path) { - res = fail_this_path(fd, lun); + res = fail_this_path(fd, lun, use_6_byte); } else { - res = sg_ll_mode_sense6(fd, /*DBD*/ 0, /* page control */0, + if (use_6_byte) { + res = sg_ll_mode_sense6(fd, /*DBD*/ 0, /* page control */0, 0x2c, 0, rsp_buff, 252, 1, do_verbose); + } else { + res = sg_ll_mode_sense10(fd, /*llbaa*/ 0, /*DBD*/ 0, /* page control */0, + 0x2c, 0x1, rsp_buff, 308, + 1, do_verbose); + } if (!res) { if (do_verbose) dump_mode_page(rsp_buff, rsp_buff[0]); - print_rdac_mode(rsp_buff); + print_rdac_mode(rsp_buff, !use_6_byte); } else { if (SG_LIB_CAT_INVALID_OP == res) fprintf(stderr, ">>>>>> try again without " diff --git a/src/sg_vpd_vendor.c b/src/sg_vpd_vendor.c index c0344d56..8f127c23 100644 --- a/src/sg_vpd_vendor.c +++ b/src/sg_vpd_vendor.c @@ -136,7 +136,7 @@ static struct svpd_vp_name_t vp_arr[] = { {VPD_VP_HP3PAR, "hp3par", "3PAR array (HP was Left Hand)"}, {VPD_VP_LTO5, "lto5", "LTO-5 tape/systems (IBM)"}, {VPD_VP_LTO6, "lto6", "LTO-6 tape/systems (IBM)"}, - {VPD_VP_RDAC, "rdac", "RDAC array (EMC Clariion)"}, + {VPD_VP_RDAC, "rdac", "RDAC array (NetApp E-Series)"}, {VPD_VP_SEAGATE, "sea", "Seagate disk"}, {0, NULL, NULL}, }; @@ -157,19 +157,19 @@ static struct svpd_values_name_t vendor_vpd_pg[] = { "configuration data (LTO-5)"}, {VPD_V_EDID_RDAC, VPD_VP_RDAC, 0, "edid", "Extended device " "identification (RDAC)"}, - {VPD_V_FEAT_RDAC, VPD_VP_RDAC, 0, "feat", "Feature Parameters (RDAC)"}, + {VPD_V_FEAT_RDAC, VPD_VP_RDAC, 0, "prm4", "Feature Parameters (RDAC)"}, {VPD_V_FIRM_SEA, VPD_VP_SEAGATE, 0, "firm", "Firmware numbers " "(Seagate)"}, {VPD_V_FVER_LTO6, VPD_VP_LTO6, 0, "frl" , "Firmware revision level " "(LTO-6)"}, - {VPD_V_FVER_RDAC, VPD_VP_RDAC, 0, "fver", "Firmware version (RDAC)"}, + {VPD_V_FVER_RDAC, VPD_VP_RDAC, 0, "fwr4", "Firmware version (RDAC)"}, {VPD_V_HEAD_LTO6, VPD_VP_LTO6, 1, "head", "Head Assy revision level " "(LTO-6)"}, {VPD_V_HP3PAR, VPD_VP_HP3PAR, 0, "hp3par", "Volume information " "(HP/3PAR)"}, {VPD_V_HVER_LTO6, VPD_VP_LTO6, 1, "hrl", "Hardware revision level " "(LTO-6)"}, - {VPD_V_HVER_RDAC, VPD_VP_RDAC, 0, "hver", "Hardware version (RDAC)"}, + {VPD_V_HVER_RDAC, VPD_VP_RDAC, 0, "hwr4", "Hardware version (RDAC)"}, {VPD_V_JUMP_SEA, VPD_VP_SEAGATE, 0, "jump", "Jump setting (Seagate)"}, {VPD_V_MECH_LTO6, VPD_VP_LTO6, 1, "mech", "Mechanism revision level " "(LTO-6)"}, @@ -180,10 +180,10 @@ static struct svpd_values_name_t vendor_vpd_pg[] = { "identifier (RDAC)"}, {VPD_V_SAID_RDAC, VPD_VP_RDAC, 0, "said", "Storage array world wide " "name (RDAC)"}, - {VPD_V_SUBS_RDAC, VPD_VP_RDAC, 0, "sub", "Subsystem identifier (RDAC)"}, - {VPD_V_SVER_RDAC, VPD_VP_RDAC, 0, "sver", "Software version (RDAC)"}, + {VPD_V_SUBS_RDAC, VPD_VP_RDAC, 0, "subs", "Subsystem identifier (RDAC)"}, + {VPD_V_SVER_RDAC, VPD_VP_RDAC, 0, "swr4", "Software version (RDAC)"}, {VPD_V_UPR_EMC, VPD_VP_EMC, 0, "upr", "Unit path report (EMC)"}, - {VPD_V_VAC_RDAC, VPD_VP_RDAC, 0, "vac", "Volume access control (RDAC)"}, + {VPD_V_VAC_RDAC, VPD_VP_RDAC, 0, "vac1", "Volume access control (RDAC)"}, {0, 0, 0, NULL, NULL}, }; @@ -666,7 +666,7 @@ decode_rdac_vpd_c0(unsigned char * buff, int len) memcpy(name, buff + 152, 2); printf(" Board Revision: %s\n", name); memset(name, 0, 65); - memcpy(name, buff + 154, 2); + memcpy(name, buff + 154, 4); printf(" Board Identifier: %s\n", name); return; @@ -687,7 +687,7 @@ decode_rdac_vpd_c1(unsigned char * buff, int len) buff[4], buff[5], buff[6], buff[7]); return; } - printf(" Firmware Version: %x.%x.%x\n", buff[8], buff[9], buff[10]); + printf(" Firmware Version: %02x.%02x.%02x\n", buff[8], buff[9], buff[10]); printf(" Firmware Date: %02d/%02d/%02d\n", buff[11], buff[12], buff[13]); num_part = (len - 12) / 16; @@ -729,7 +729,7 @@ decode_rdac_vpd_c2(unsigned char * buff, int len) buff[4], buff[5], buff[6], buff[7]); return; } - printf(" Software Version: %x.%x.%x\n", buff[8], buff[9], buff[10]); + printf(" Software Version: %02x.%02x.%02x\n", buff[8], buff[9], buff[10]); printf(" Software Date: %02d/%02d/%02d\n", buff[11], buff[12], buff[13]); printf(" Features:"); if (buff[14] & 0x01) @@ -739,9 +739,9 @@ decode_rdac_vpd_c2(unsigned char * buff, int len) if (buff[14] & 0x04) printf(" Multiple Sub-enclosures,"); if (buff[14] & 0x08) - printf(" DCE/DRM,"); + printf(" DCE/DRM/DSS/DVE,"); if (buff[14] & 0x10) - printf(" AVT,"); + printf(" Asymmetric Logical Unit Access,"); printf("\n"); printf(" Max. #of LUNS: %d\n", buff[15]); @@ -786,6 +786,7 @@ decode_rdac_vpd_c3(unsigned char * buff, int len) printf(" UTM: %s\n", buff[11] & 0x80?"enabled":"disabled"); if ((buff[11] & 0x80)) printf(" UTM LUN: %02x\n", buff[11] & 0x7f); + printf(" Persistent Reservations Bus Reset Support: %s\n", buff[12] & 0x01?"enabled":"disabled"); return; } @@ -826,6 +827,32 @@ decode_rdac_vpd_c4(unsigned char * buff, int len) printf(" (Board ID 2880)\n"); else if (!strcmp(subsystem_rev, "14.0")) printf(" (Board ID 2822)\n"); + else if (!strcmp(subsystem_rev, "15.0")) + printf(" (Board ID 6091)\n"); + else if (!strcmp(subsystem_rev, "16.0")) + printf(" (Board ID 3992)\n"); + else if (!strcmp(subsystem_rev, "16.1")) + printf(" (Board ID 3991)\n"); + else if (!strcmp(subsystem_rev, "17.0")) + printf(" (Board ID 1331)\n"); + else if (!strcmp(subsystem_rev, "17.1")) + printf(" (Board ID 1332)\n"); + else if (!strcmp(subsystem_rev, "17.3")) + printf(" (Board ID 1532)\n"); + else if (!strcmp(subsystem_rev, "17.4")) + printf(" (Board ID 1932)\n"); + else if (!strcmp(subsystem_rev, "42.0")) + printf(" (Board ID 26x0)\n"); + else if (!strcmp(subsystem_rev, "43.0")) + printf(" (Board ID 498x)\n"); + else if (!strcmp(subsystem_rev, "44.0")) + printf(" (Board ID 548x)\n"); + else if (!strcmp(subsystem_rev, "45.0")) + printf(" (Board ID 5501)\n"); + else if (!strcmp(subsystem_rev, "46.0")) + printf(" (Board ID 2701)\n"); + else if (!strcmp(subsystem_rev, "47.0")) + printf(" (Board ID 5601)\n"); else printf(" (Board ID unknown)\n"); @@ -835,6 +862,16 @@ decode_rdac_vpd_c4(unsigned char * buff, int len) } static void +convert_binary_to_ascii(unsigned char * src, unsigned char * dst, int len) +{ + int i; + + for (i = 0; i < len; i++) { + sprintf((char *)(dst+2*i), "%02x", *(src+i)); + } +} + +static void decode_rdac_vpd_c8(unsigned char * buff, int len) { int i; @@ -846,6 +883,8 @@ decode_rdac_vpd_c8(unsigned char * buff, int len) int label_len; char uuid[33]; int uuid_len; + unsigned char port_id[128]; + int n; if (len < 0xab) { pr2serr("Extended Device Identification VPD page length too " @@ -902,10 +941,110 @@ decode_rdac_vpd_c8(unsigned char * buff, int len) printf(" Logical Unit Number: %s\n", uuid); + /* Initiator transport ID */ + if ( buff[10] & 0x01 ) { + memset(port_id, 0, 128); + printf(" Transport Protocol: "); + switch (buff[175] & 0x0F) { + case TPROTO_FCP: /* FC */ + printf("FC\n"); + convert_binary_to_ascii(&buff[183], port_id, 8); + n = 199; + break; + case TPROTO_SRP: /* SRP */ + printf("SRP\n"); + convert_binary_to_ascii(&buff[183], port_id, 8); + n = 199; + break; + case TPROTO_ISCSI: /* iSCSI */ + printf("iSCSI\n"); + n = (buff[177] << 8) + buff[178]; + memcpy(port_id, &buff[179], n); + n = 179 + n; + break; + case TPROTO_SAS: /* SAS */ + printf("SAS\n"); + convert_binary_to_ascii(&buff[179], port_id, 8); + n = 199; + break; + default: + return; /* Can't continue decoding, so return */ + } + + printf(" Initiator Port Identifier: %s\n", port_id); + if ( buff[10] & 0x02 ) { + memset(port_id, 0, 128); + memcpy(port_id, &buff[n], 8); + printf(" Supplemental Vendor ID: %s\n", port_id); + } + } + return; } static void +decode_rdac_vpd_c9_rtpg_data(unsigned char aas, unsigned char vendor) +{ + printf(" Asymmetric Access State:"); + switch(aas & 0x0F) { + case 0x0: + printf(" Active/Optimized"); + break; + case 0x1: + printf(" Active/Non-Optimized"); + break; + case 0x2: + printf(" Standby"); + break; + case 0x3: + printf(" Unavailable"); + break; + case 0xE: + printf(" Offline"); + break; + case 0xF: + printf(" Transitioning"); + break; + default: + printf(" (unknown)"); + break; + } + printf("\n"); + + printf(" Vendor Specific Field:"); + switch(vendor) { + case 0x01: + printf(" Operating normally"); + break; + case 0x02: + printf(" Non-responsive to queries"); + break; + case 0x03: + printf(" Controller being held in reset"); + break; + case 0x04: + printf(" Performing controller firmware download (1st controller)"); + break; + case 0x05: + printf(" Performing controller firmware download (2nd controller)"); + break; + case 0x06: + printf(" Quiesced as a result of an administrative request"); + break; + case 0x07: + printf(" Service mode as a result of an administrative request"); + break; + case 0xFF: + printf(" Details are not available"); + break; + default: + printf(" (unknown)"); + break; + } + printf("\n"); +} + +static void decode_rdac_vpd_c9(unsigned char * buff, int len) { if (len < 3) { @@ -920,14 +1059,18 @@ decode_rdac_vpd_c9(unsigned char * buff, int len) if (buff[7] != '1') { pr2serr("Invalid page version '%c' (should be 1)\n", buff[7]); } - printf(" AVT:"); - if (buff[8] & 0x80) { - printf(" Enabled"); - if (buff[8] & 0x40) - printf(" (Allow reads on sector 0)"); - printf("\n"); + if ( (buff[8] & 0xE0) == 0xE0 ) { + printf(" IOShipping (ALUA): Enabled\n"); } else { - printf(" Disabled\n"); + printf(" AVT:"); + if (buff[8] & 0x80) { + printf(" Enabled"); + if (buff[8] & 0x40) + printf(" (Allow reads on sector 0)"); + printf("\n"); + } else { + printf(" Disabled\n"); + } } printf(" Volume Access via: "); if (buff[8] & 0x01) @@ -935,8 +1078,9 @@ decode_rdac_vpd_c9(unsigned char * buff, int len) else printf("alternate controller\n"); - printf(" Path priority: %d ", buff[9] & 0xf); - switch(buff[9] & 0xf) { + if (buff[8] & 0x08) { + printf(" Path priority: %d ", buff[15] & 0xf); + switch(buff[15] & 0xf) { case 0x1: printf("(preferred path)\n"); break; @@ -946,9 +1090,62 @@ decode_rdac_vpd_c9(unsigned char * buff, int len) default: printf("(unknown)\n"); break; + } + + printf(" Preferred Path Auto Changeable:"); + switch(buff[14] & 0x3C) { + case 0x14: + printf(" No (User Disabled and Host Type Restricted)\n"); + break; + case 0x18: + printf(" No (User Disabled)\n"); + break; + case 0x24: + printf(" No (Host Type Restricted)\n"); + break; + case 0x28: + printf(" Yes\n"); + break; + default: + printf(" (Unknown)\n"); + break; + } + + printf(" Implicit Failback:"); + switch(buff[14] & 0x03) { + case 0x1: + printf(" Disabled\n"); + break; + case 0x2: + printf(" Enabled\n"); + break; + default: + printf(" (Unknown)\n"); + break; + } + } else { + printf(" Path priority: %d ", buff[9] & 0xf); + switch(buff[9] & 0xf) { + case 0x1: + printf("(preferred path)\n"); + break; + case 0x2: + printf("(secondary path)\n"); + break; + default: + printf("(unknown)\n"); + break; + } } - return; + + if (buff[8] & 0x80) { + printf(" Target Port Group Data (This controller):\n"); + decode_rdac_vpd_c9_rtpg_data(buff[10], buff[11]); + + printf(" Target Port Group Data (Alternate controller):\n"); + decode_rdac_vpd_c9_rtpg_data(buff[12], buff[13]); + } } static void |