From 712a6ebcfda07efd534b563b29d573ea77ab156e Mon Sep 17 00:00:00 2001
From: Johannes Thumshirn <jthumshirn@suse.de>
Date: Wed, 10 Feb 2016 12:03:06 +0100
Subject: [PATCH] Backport changes from upstream

scripts/rescan-scsi-bus.sh
- Changed whitespaces to be consistent at start of lines, and removed extra
  whitespaces at the end of lines
- Enhanced the udevadm_settle function, and changed calls to udevadm trigger
  to only use sd devices, to prevent it from hanging when a udev event is stuck
  on a dm-multipath device in recovery mode
- Enhanced findremapped and findmultipath to handle another case where udev
  might have already updated the scsi id, but multipath has not
- Added retries when flushing removed multipaths, as it can sometimes fail
  transiently
- Enhanced findresized to print the before and after sizes of multipath
  devices
- When passing the flag to find remapped LUNs, it will now also try to update
  the size

Include upstream changes into src/sg_inq.c
- Fixed display of software version and date, and added decoding of additional
  features for rdac page c2
- Updated decoding of rdac c9 page to be current

Include upstream changes into src/sg_inq.c
- Fixed display of software version and date, and added decoding of additional
  features for rdac page c2
- Updated decoding of rdac c9 page to be current

Include upstream changes into src/sg_rdac.c
- Added support for rdac extended page 2c and mode select(10) to all
  functionality
- Fixed mode select(6) logic, as there was an invalid parameter keeping it
  from working at all
- Updated feature decoding in print_rdac_mode to be current
- Added -6 flag to force to use 6 byte CDBs

Include upstream changes into src/sg_vpd_vendor.c
- vp_arr[] data structure had rdac incorrectly listed as an EMC array
- Updated rdac page names
- Fixed rdac page c0 decoding to get correct number of bytes for board
  identifier
- Same fixes and enhancements for decoding as in sg_inq.c for pages c2 and c9
- Updated rdac pages c3 and c4 decoding to decode additional information
- Updated rdac page c8 to decode initiator transport IDs for FC, SAS, iSCSI,
  and SRP

Signed-off-by: Johannes Thumshirn <jthumshirn@suse.de>
---
 scripts/rescan-scsi-bus.sh |  290 ++++++++++++++++++++++++++++++---------------
 src/sg_inq.c               |  208 ++++++++++++++++++++++++++------
 src/sg_rdac.c              |  241 +++++++++++++++++++++++++++----------
 src/sg_vpd_vendor.c        |  245 ++++++++++++++++++++++++++++++++++----
 4 files changed, 766 insertions(+), 218 deletions(-)

--- 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."
@@ -112,8 +112,8 @@ printtype ()
     4) echo "WORM" ;;
     5) echo "CD-ROM" ;;
     6) echo "Scanner" ;;
-    7) echo "Optical Device" ;;
-    8) echo "Medium Changer" ;;
+    7) echo "Optical-Device" ;;
+    8) echo "Medium-Changer" ;;
     9) echo "Communications" ;;
     10) echo "Unknown" ;;
     11) echo "Unknown" ;;
@@ -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=""
@@ -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
@@ -552,7 +560,7 @@ doreportlun()
   REPLUNSTAT=$?
   lunremove=
   #echo "getluns reports " $targetluns
-  olddev=`find /sys/class/scsi_device/ -name $host:$channel:$id:* 2>/dev/null`
+  olddev=`find /sys/class/scsi_device/ -name $host:$channel:$id:* 2>/dev/null | sort -t: -k4 -n`
   oldluns=`echo "$olddev" | awk -F'/' '{print $5}' | awk -F':' '{print $4}'`
   oldtargets="$targetluns"
   # OK -- if we don't have a LUN to send a REPORT_LUNS to, we could
@@ -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,15 +700,20 @@ 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`"
+  local tmpfile=$(mktemp /tmp/rescan-scsi-bus.XXXXXXXX 2> /dev/null)
 
-  test -f $tmpfile && rm $tmpfile
+  if [ -z "$tmpfile" ] ; then
+    tmpfile="/tmp/rescan-scsi-bus.$$"
+    rm -f $tmpfile
+  fi
 
   # 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 +723,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
-  [ -f $tmpfile ] && rm $tmpfile
+  rm -f $tmpfile
 
   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 +781,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,85 +830,136 @@ 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
+    [ "$mp" = "No" ] && break;
     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()
 {
   local mpath
-  if [ ! -x $MULTIPATH ] ; then
+  if [ ! -x "$MULTIPATH" ] ; then
     echo "no -x multipath"
     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
+}
+
+resizempaths()
+{
+  local mpath
+
+  for mpath in $mpaths ; do
+    echo -n "Resizing multipath map $mpath ..."
+    multipathd -k"resize map $mpath"
+    let updated+=1
   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
+      [ "$mpath" = "No" ] && break
       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 +972,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 +1001,18 @@ findresized()
   done
 
   if test -n "$mp_enable" -a -n "$mpaths" ; then
-    reloadmpaths
+    i=0
+    for m in $mpaths ; do
+      mpathsizes[$i]="`$MULTIPATH -l $m | egrep -o [0-9]+.[0-9]+[KMGT]`"
+      let i=$i+1
+    done
+    resizempaths
+    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
 }
 
@@ -939,6 +1033,7 @@ if test @$1 = @--help -o @$1 = @-h -o @$
     echo " -I SECS issue a FibreChannel LIP reset and wait for SECS seconds [default: disabled]"
     echo " -l      activates scanning for LUNs 0--7   [default: 0]"
     echo " -L NUM  activates scanning for LUNs 0--NUM [default: 0]"
+    echo " -m      update multipath devices           [default: disabled]"
     echo " -r      enables removing of devices        [default: disabled]"
     echo " -s      look for resized disks and reload associated multipath devices, if applicable"
     echo " -u      look for existing disks that have been remapped"
@@ -957,6 +1052,7 @@ if test @$1 = @--help -o @$1 = @-h -o @$
     echo "--issue-lip-wait=SECS:     same as -I"
     echo "--largelun:      Tell kernel to support LUNs > 7 even on SCSI2 devs"
     echo "--luns=LIST:     Scan only lun(s) in LIST"  
+    echo "--multipath:     same as -m"
     echo "--nooptscan:     don't stop looking for LUNs is 0 is not found"
     echo "--remove:        same as -r"
     echo "--reportlun2:    Tell kernel to try REPORT_LUN even on SCSI2 devices"
@@ -976,7 +1072,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
@@ -1033,7 +1129,7 @@ while test ! -z "$opt" -a -z "${opt##-*}
     w) opt_idsearch=`seq 0 15` ;;
     c) opt_channelsearch="0 1" ;;
     r) remove=1 ;;
-    s) resize=1 ;;
+    s) resize=1; mp_enable=1 ;;
     i) lipreset=0 ;;
     I) shift; lipreset=$opt ;;
     u) update=1 ;;
@@ -1105,7 +1201,7 @@ declare -i updated=0
 declare -i rmvd=0
 
 if [ -n "$flush" ] ; then
-  if [-x $MULTIPATH ] ; then
+  if [ -x "$MULTIPATH" ] ; then
     flushmpaths 1
   fi
 fi
@@ -1114,6 +1210,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,16 +1263,17 @@ 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
+    if [ -x "$MULTIPATH" ] ; then
+      echo "Trying to discover new multipath mappings for newly discovered devices... "
+      $MULTIPATH | grep "create:" 2> /dev/null
+    fi
   fi 
 fi
 
@@ -1181,7 +1281,7 @@ echo "$found new or changed device(s) fo
 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
--- a/src/sg_inq.c
+++ b/src/sg_inq.c
@@ -1,5 +1,5 @@
 /* A utility program originally written for the Linux OS SCSI subsystem.
-*  Copyright (C) 2000-2014 D. Gilbert
+*  Copyright (C) 2000-2015 D. Gilbert
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
@@ -41,7 +41,7 @@
 #include "sg_cmds_basic.h"
 #include "sg_pt.h"
 
-static const char * version_str = "1.43 20141107";    /* SPC-4 rev 37 */
+static const char * version_str = "1.51 20151201";    /* SPC-5 rev 06 */
 
 /* INQUIRY notes:
  * It is recommended that the initial allocation length given to a
@@ -2225,7 +2225,8 @@ decode_x_inq_vpd(unsigned char * buff, i
            "SIMPSUP=%d\n", !!(buff[5] & 0x20), !!(buff[5] & 0x10),
            !!(buff[5] & 0x8), !!(buff[5] & 0x4), !!(buff[5] & 0x2),
            !!(buff[5] & 0x1));
-    printf("  WU_SUP=%d CRD_SUP=%d NV_SUP=%d V_SUP=%d\n",
+    /* CRD_SUP made obsolete in spc5r04 */
+    printf("  WU_SUP=%d [CRD_SUP=%d] NV_SUP=%d V_SUP=%d\n",
            !!(buff[6] & 0x8), !!(buff[6] & 0x4), !!(buff[6] & 0x2),
            !!(buff[6] & 0x1));
     printf("  P_I_I_SUP=%d LUICLR=%d R_SUP=%d CBCS=%d\n",
@@ -2489,7 +2490,7 @@ decode_b1_vpd(unsigned char * buff, int
                 printf("reserved [%u]\n", u);
                 break;
             }
-            printf("  HAW_ZBC=%d\n", buff[8] & 0x10);       /* sbc4r01 */
+            printf("  ZONED=%d\n", (buff[8] >> 4) & 0x3);   /* sbc4r04 */
             printf("  FUAB=%d\n", buff[8] & 0x2);
             printf("  VBULS=%d\n", buff[8] & 0x1);
             break;
@@ -2681,8 +2682,8 @@ decode_rdac_vpd_c2(unsigned char * buff,
                 "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,");
@@ -2691,15 +2692,79 @@ decode_rdac_vpd_c2(unsigned char * buff,
     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) {
@@ -2718,14 +2783,18 @@ decode_rdac_vpd_c9(unsigned char * buff,
     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)
@@ -2733,17 +2802,72 @@ decode_rdac_vpd_c9(unsigned char * buff,
     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;
@@ -2860,9 +2984,11 @@ std_inq_response(const struct opts_t * o
                 xtra_buff[i] = ' ';
         if (op->do_export) {
             len = encode_whitespaces((unsigned char *)xtra_buff, 8);
-            printf("SCSI_VENDOR=%s\n", xtra_buff);
-            encode_string(xtra_buff, &rp[8], 8);
-            printf("SCSI_VENDOR_ENC=%s\n", xtra_buff);
+            if (len > 0) {
+                printf("SCSI_VENDOR=%s\n", xtra_buff);
+                encode_string(xtra_buff, &rp[8], 8);
+                printf("SCSI_VENDOR_ENC=%s\n", xtra_buff);
+            }
         } else
             printf(" Vendor identification: %s\n", xtra_buff);
         if (act_len <= 16) {
@@ -2873,9 +2999,11 @@ std_inq_response(const struct opts_t * o
             xtra_buff[16] = '\0';
             if (op->do_export) {
                 len = encode_whitespaces((unsigned char *)xtra_buff, 16);
-                printf("SCSI_MODEL=%s\n", xtra_buff);
-                encode_string(xtra_buff, &rp[16], 16);
-                printf("SCSI_MODEL_ENC=%s\n", xtra_buff);
+                if (len > 0) {
+                    printf("SCSI_MODEL=%s\n", xtra_buff);
+                    encode_string(xtra_buff, &rp[16], 16);
+                    printf("SCSI_MODEL_ENC=%s\n", xtra_buff);
+                }
             } else
                 printf(" Product identification: %s\n", xtra_buff);
         }
@@ -2887,7 +3015,8 @@ std_inq_response(const struct opts_t * o
             xtra_buff[4] = '\0';
             if (op->do_export) {
                 len = encode_whitespaces((unsigned char *)xtra_buff, 4);
-                printf("SCSI_REVISION=%s\n", xtra_buff);
+                if (len > 0)
+                    printf("SCSI_REVISION=%s\n", xtra_buff);
             } else
                 printf(" Product revision level: %s\n", xtra_buff);
         }
@@ -2897,7 +3026,8 @@ std_inq_response(const struct opts_t * o
                    20);
             if (op->do_export) {
                 len = encode_whitespaces((unsigned char *)xtra_buff, 20);
-                printf("VENDOR_SPECIFIC=%s\n", xtra_buff);
+                if (len > 0)
+                    printf("VENDOR_SPECIFIC=%s\n", xtra_buff);
             } else
                 printf(" Vendor specific: %s\n", xtra_buff);
         }
@@ -2911,7 +3041,8 @@ std_inq_response(const struct opts_t * o
             if (op->do_export) {
                 len = encode_whitespaces((unsigned char *)xtra_buff,
                                          act_len - 96);
-                printf("VENDOR_SPECIFIC=%s\n", xtra_buff);
+                if (len > 0)
+                    printf("VENDOR_SPECIFIC=%s\n", xtra_buff);
             } else
                 printf(" Vendor specific: %s\n", xtra_buff);
         }
@@ -2976,6 +3107,13 @@ vpd_fetch_page_from_dev(int sg_fd, unsig
         pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
                 "response\n");
         return SG_LIB_CAT_MALFORMED;
+    } else if ((0x80 == page) && (0x2 == rp[2]) && (0x2 == rp[3])) {
+        /* could be a Unit Serial number VPD page with a very long
+         * length of 4+514 bytes; more likely standard response for
+         * SCSI-2, RMB=1 and a response_data_format of 0x2. */
+        pr2serr("invalid Unit Serial Number VPD response; probably a "
+                "STANDARD INQUIRY response\n");
+        return SG_LIB_CAT_MALFORMED;
     }
     if (mxlen < 0)
         len = rp[3] + 4;
--- 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.09 20151207";
 
 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,62 @@ static void dump_mode_page( unsigned cha
 #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 inline void sg_put_unaligned_be16(uint16_t val, void *p)
+{
+	uint8_t *ptr = p;
+
+	*ptr++ = val >> 8;
+	*ptr++ = val;
+}
+
+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;
-
-        res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */,
-                                 fail_paths_pg, 118,
-                                 1, (do_verbose ? 2 : 0));
+        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;
+                sg_put_unaligned_be16(EXPANDED_LUN_SPACE_PAGE_LEN,
+                                      rdac_page_exp->page_length + 0);
+                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;
+
+        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 +175,56 @@ 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;
+                sg_put_unaligned_be16(EXPANDED_LUN_SPACE_PAGE_LEN,
+                                      rdac_page_exp->page_length + 0);
+                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 +241,29 @@ static int fail_this_path(int fd, int lu
         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 +304,6 @@ static void print_rdac_mode( unsigned ch
         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 +319,10 @@ static void print_rdac_mode( unsigned ch
         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 +331,16 @@ static void print_rdac_mode( unsigned ch
         }
         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 +357,9 @@ static void print_rdac_mode( unsigned ch
                                 printf(" ?");
                                 break;
                         }
+                        if (i == 7) {
+                                printf(" ");
+                        }
                 }
                 printf("\n");
         }
@@ -266,8 +367,9 @@ static void print_rdac_mode( unsigned ch
 
 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 +390,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 +408,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 +442,25 @@ 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,
-                                        0x2c, 0, rsp_buff, 252,
-                                        1, do_verbose);
+                if (use_6_byte)
+                        res = sg_ll_mode_sense6(fd, /* DBD */ 0, /* PC */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 "
--- a/src/sg_vpd_vendor.c
+++ b/src/sg_vpd_vendor.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2014 Douglas Gilbert.
+ * Copyright (c) 2006-2015 Douglas Gilbert.
  * All rights reserved.
  * Use of this source code is governed by a BSD-style
  * license that can be found in the BSD_LICENSE file.
@@ -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_
      "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_
      "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,
     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,
                 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,
                 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,
     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,7 +786,8 @@ decode_rdac_vpd_c3(unsigned char * buff,
     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,
         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,
 }
 
 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 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,
 
     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,
     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,54 @@ decode_rdac_vpd_c9(unsigned char * buff,
     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;
+        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;
@@ -946,9 +1135,17 @@ decode_rdac_vpd_c9(unsigned char * buff,
         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
