aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2015-04-01 21:45:22 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2015-04-01 21:45:22 +0000
commitbaa91c3f8356cf0b5ff94a778070c3c6714ac5f9 (patch)
tree826c695e97adaba3d4cd421a4fb115014f516b87
parente65afc2448aee567499271a1a0c904be67f797d4 (diff)
downloadsg3_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--ChangeLog7
-rw-r--r--doc/sg_rdac.811
-rwxr-xr-xscripts/rescan-scsi-bus.sh250
-rw-r--r--src/sg_inq.c165
-rw-r--r--src/sg_rdac.c222
-rw-r--r--src/sg_vpd_vendor.c241
6 files changed, 702 insertions, 194 deletions
diff --git a/ChangeLog b/ChangeLog
index 4cfc0d08..f05670fb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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