diff options
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/40-usb-blacklist.rules | 14 | ||||
-rw-r--r-- | scripts/54-before-scsi-sg3_id.rules | 55 | ||||
-rw-r--r-- | scripts/55-scsi-sg3_id.rules | 109 | ||||
-rw-r--r-- | scripts/58-scsi-sg3_symlink.rules | 38 | ||||
-rw-r--r-- | scripts/59-fc-wwpn-id.rules | 17 | ||||
-rw-r--r-- | scripts/59-scsi-cciss_id.rules | 18 | ||||
-rw-r--r-- | scripts/Makefile.am | 3 | ||||
-rw-r--r-- | scripts/Makefile.in | 518 | ||||
-rw-r--r-- | scripts/README | 55 | ||||
-rwxr-xr-x | scripts/cciss_id | 66 | ||||
-rw-r--r-- | scripts/fc_wwpn_id | 51 | ||||
-rw-r--r-- | scripts/lunmask.service | 11 | ||||
-rwxr-xr-x | scripts/rescan-scsi-bus.sh | 1436 | ||||
-rwxr-xr-x | scripts/scsi-enable-target-scan.sh | 15 | ||||
-rwxr-xr-x | scripts/scsi_logging_level | 268 | ||||
-rwxr-xr-x | scripts/scsi_mandat | 133 | ||||
-rwxr-xr-x | scripts/scsi_readcap | 57 | ||||
-rwxr-xr-x | scripts/scsi_ready | 56 | ||||
-rwxr-xr-x | scripts/scsi_satl | 134 | ||||
-rwxr-xr-x | scripts/scsi_start | 55 | ||||
-rwxr-xr-x | scripts/scsi_stop | 58 | ||||
-rwxr-xr-x | scripts/scsi_temperature | 46 |
22 files changed, 3213 insertions, 0 deletions
diff --git a/scripts/40-usb-blacklist.rules b/scripts/40-usb-blacklist.rules new file mode 100644 index 00000000..66313880 --- /dev/null +++ b/scripts/40-usb-blacklist.rules @@ -0,0 +1,14 @@ +# +# Blacklist specific USB devices +# +# don't inquire sn and di on broken devices (https://bugzilla.suse.com/show_bug.cgi?id=840054) + +ACTION!="add|change", GOTO="usb_blacklist_end" +KERNEL!="sd*[!0-9]|sr*", GOTO="usb_blacklist_end" + +# unknown device +ATTRS{idVendor}=="0aec", ATTRS{idProduct}=="3260", ENV{ID_SCSI_INQUIRY}="1" +# Sony/JMicron port replicator +ATTRS{idVendor}=="054c", ATTRS{idProduct}=="06a0", ENV{ID_SCSI_INQUIRY}="1" + +LABEL="usb_blacklist_end" diff --git a/scripts/54-before-scsi-sg3_id.rules b/scripts/54-before-scsi-sg3_id.rules new file mode 100644 index 00000000..bb36650a --- /dev/null +++ b/scripts/54-before-scsi-sg3_id.rules @@ -0,0 +1,55 @@ +# do not edit this file, it will be overwritten on update + +# persistent storage links: /dev/disk/{by-id,by-path} +# scheme based on "Linux persistent device names", 2004, Hannes Reinecke <hare@suse.de> + +# This file contains rules for setting udev environment variables based on +# hardware properties (serial numbers etc), which can be obtained without +# actually reading from the device. +# +# Hopefully this will be integrated into systemd/udev soon (as 54-storage-hardware.rules). +# Until then, we ship it here in sg3-utils. +# It's important that rules dealing with low-level hardware attributes run +# before the generic SCSI rules in 55-scsi-sg3_utils.rules. + +ACTION=="remove", GOTO="storage_hardware_end" +SUBSYSTEM!="block", GOTO="block_storage_end" +KERNEL!="sd*|sr*|cciss*", GOTO="block_storage_end" + +# ignore partitions that span the entire disk +TEST=="whole_disk", GOTO="block_storage_end" + +# for partitions import parent information +ENV{DEVTYPE}=="partition", ENV{ID_SERIAL}!="?*", IMPORT{parent}="ID_*" + +# ATA +KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", IMPORT{program}="ata_id --export $devnode" + +# ATAPI devices (SPC-3 or later) +KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="scsi", ATTRS{type}=="5", ATTRS{scsi_level}=="[6-9]*", IMPORT{program}="ata_id --export $devnode" + +# Run ata_id on non-removable USB Mass Storage (SATA/PATA disks in enclosures) +KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", ATTR{removable}=="0", SUBSYSTEMS=="usb", IMPORT{program}="ata_id --export $devnode" + +# Fall back usb_id for USB devices +KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id" + +# FireWire +ENV{ID_IEEE1394}!="?*", KERNEL=="sd*|sr*", ATTRS{ieee1394_id}=="?*", ENV{ID_IEEE1394}="$attr{ieee1394_id}" + +# by-path +ENV{ID_PATH}!="?*", ENV{DEVTYPE}=="disk", DEVPATH!="*/virtual/*", IMPORT{builtin}="path_id" + +LABEL="block_storage_end" + +# SCSI tape devices +SUBSYSTEM!="scsi_tape", GOTO="storage_hardware_end" +KERNEL!="st*[0-9]|nst*[0-9]", GOTO="storage_hardware_end" + +ENV{ID_SERIAL}!="?*", ATTRS{ieee1394_id}=="?*", ENV{ID_SERIAL}="$attr{ieee1394_id}", ENV{ID_BUS}="ieee1394" +ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="usb", ATTRS{serial}=="?*", IMPORT{builtin}="usb_id" + +# by-path +ENV{ID_PATH}!="?*", IMPORT{builtin}="path_id" + +LABEL="storage_hardware_end" diff --git a/scripts/55-scsi-sg3_id.rules b/scripts/55-scsi-sg3_id.rules new file mode 100644 index 00000000..453210bd --- /dev/null +++ b/scripts/55-scsi-sg3_id.rules @@ -0,0 +1,109 @@ +# SCSI-ID mappings for sg3_utils + +ACTION=="remove", GOTO="sg3_utils_id_end" + +SUBSYSTEM=="block", GOTO="block_dev" + +# SCSI devices other than "block" +# This code used to live in 60-persistent-storage-tape.rules. + +# type 8 devices are "Medium Changers" +SUBSYSTEM=="scsi_generic", KERNEL=="sg*[0-9]", ATTRS{type}=="8", \ + GOTO="scsi_inquiry" +SUBSYSTEM=="scsi_changer", KERNEL=="sch*[0-9]", ATTRS{type}=="8", \ + ENV{.INQUIRY_DEV}="$root/bsg/$id", GOTO="scsi_inquiry" + +# tapes need to be accessed through their bsg device +KERNEL=="st*[0-9]|nst*[0-9]", SUBSYSTEMS=="scsi", KERNELS=="[0-9]*:*[0-9]", \ + ENV{.INQUIRY_DEV}="$root/bsg/$id", GOTO="scsi_inquiry" + +GOTO="sg3_utils_id_end" + +LABEL="block_dev" + +# Import values for partitions +ENV{DEVTYPE}=="partition", IMPORT{parent}="ID_SCSI", IMPORT{parent}="SCSI_*" +ENV{DEVTYPE}=="partition", ENV{ID_SCSI}=="1", GOTO="compat" + +# Handle non-SCSI devices that implement SCSI inquiry +KERNEL=="cciss*", ENV{DEVTYPE}=="disk", GOTO="sg_inquiry" + +# Ignore everything else except sd/sr +KERNEL!="sd*[!0-9]|sr*", GOTO="sg3_utils_id_end" + +# SCSI INQUIRY values +# If the 'inquiry' sysfs attribute is present the kernel will already +# have scanned for VPD pages, so if the vpd page attribute is not +# present it is not supported (or deemed unsafe to access). +# Hence we can skip the call to sg_inq and avoid I/O altogether. +# Set 'ID_SCSI_INQUIRY=0' in an earlier udev rule if the kernel +# fails to scan VPD pages correctly; the rules will then fall +# back to calling sg_vpd directly. +LABEL="scsi_inquiry" +ENV{ID_SCSI_INQUIRY}=="0", GOTO="sg_inquiry" + +# "inquiry" is an attribute of the scsi_device in sysfs, +# we obtain it by using $id after an ATTRS match. +SUBSYSTEMS=="scsi", ATTRS{inquiry}=="*", KERNELS=="[0-9]*:*[0-9]", \ + ENV{.SYSFS_PATH}="$sys/class/scsi_device/$id/device" +ENV{.SYSFS_PATH}=="", GOTO="sg_inquiry" + +IMPORT{program}="/usr/bin/sg_inq --export --inhex=$env{.SYSFS_PATH}/inquiry --raw", \ + ENV{ID_SCSI}="1", ENV{ID_SCSI_INQUIRY}="1" +# If inquiry sysfs attribute reading it failed, fallback to sg +ENV{ID_SCSI}!="1", GOTO="sg_inquiry" +# Read VPD pages 80 (sn) and 83 (di) +IMPORT{program}="/usr/bin/sg_inq --export --inhex=$env{.SYSFS_PATH}/vpd_pg80 --raw" +IMPORT{program}="/usr/bin/sg_inq --export --inhex=$env{.SYSFS_PATH}/vpd_pg83 --raw" +GOTO="compat" + +LABEL="sg_inquiry" +# Handle devices that have no inquiry attributes in sysfs +ENV{.INQUIRY_DEV}=="", ENV{.INQUIRY_DEV}="$tempnode" + +IMPORT{program}="/usr/bin/sg_inq --export $env{.INQUIRY_DEV}", ENV{ID_SCSI}="1" +# Give up if this fails, too +ENV{ID_SCSI}!="1", GOTO="sg3_utils_id_end" +IMPORT{program}="/usr/bin/sg_inq --export --page=sn $env{.INQUIRY_DEV}" +IMPORT{program}="/usr/bin/sg_inq --export --page=di $env{.INQUIRY_DEV}" + +LABEL="compat" + +# scsi_id compat mappings +ENV{ID_VENDOR}!="?*", ENV{SCSI_VENDOR}=="?*", ENV{ID_VENDOR}="$env{SCSI_VENDOR}" +ENV{ID_VENDOR_ENC}!="?*", ENV{SCSI_VENDOR_ENC}=="?*", ENV{ID_VENDOR_ENC}="$env{SCSI_VENDOR_ENC}" +ENV{ID_MODEL}!="?*", ENV{SCSI_MODEL}=="?*", ENV{ID_MODEL}="$env{SCSI_MODEL}" +ENV{ID_MODEL_ENC}!="?*", ENV{SCSI_MODEL_ENC}=="?*", ENV{ID_MODEL_ENC}="$env{SCSI_MODEL_ENC}" +ENV{ID_REVISION}!="?*", ENV{SCSI_REVISION}=="?*", ENV{ID_REVISION}="$env{SCSI_REVISION}" +ENV{ID_TYPE}!="?*", ENV{SCSI_TYPE}=="?*", ENV{ID_TYPE}="$env{SCSI_TYPE}" +ENV{ID_TARGET_PORT}!="?*", ENV{SCSI_IDENT_PORT_TARGET_PORT_GROUP}=="?*", \ + PROGRAM="/bin/sh -c 'echo $env{SCSI_IDENT_PORT_TARGET_PORT_GROUP} | /bin/sed s/^0x//'", \ + ENV{ID_TARGET_PORT}="$result" + +# ID_WWN compat mapping +ENV{SCSI_IDENT_LUN_NAA_REGEXT}=="?*", ENV{ID_WWN_WITH_EXTENSION}!="?*", ENV{ID_WWN_WITH_EXTENSION}="0x$env{SCSI_IDENT_LUN_NAA_REGEXT}" +ENV{SCSI_IDENT_LUN_NAA_REG}=="?*", ENV{ID_WWN_WITH_EXTENSION}!="?*", ENV{ID_WWN_WITH_EXTENSION}="0x$env{SCSI_IDENT_LUN_NAA_REG}" +ENV{SCSI_IDENT_LUN_NAA_EXT}=="?*", ENV{ID_WWN_WITH_EXTENSION}!="?*", ENV{ID_WWN_WITH_EXTENSION}="0x$env{SCSI_IDENT_LUN_NAA_EXT}" +ENV{SCSI_IDENT_LUN_NAA_LOCAL}=="?*", ENV{ID_WWN_WITH_EXTENSION}!="?*", ENV{ID_WWN_WITH_EXTENSION}="0x$env{SCSI_IDENT_LUN_NAA_LOCAL}" +# ID_WWN has max 16 characters +ENV{ID_WWN_WITH_EXTENSION}=="?*", ENV{ID_WWN}!="?*", \ + PROGRAM="/bin/sh -c 'echo $env{ID_WWN_WITH_EXTENSION} | /bin/sed s/^\\\(0x.\\\{1,16\\\}\\\).*/\\1/'", \ + ENV{ID_WWN}="$result" + +# ata_id compatibility +ENV{ID_SERIAL}!="?*", ENV{SCSI_IDENT_LUN_ATA}=="?*", ENV{ID_BUS}="ata", ENV{ID_ATA}="1", ENV{ID_SERIAL}="$env{SCSI_IDENT_LUN_ATA}" +ENV{ID_SERIAL_SHORT}!="?*", ENV{SCSI_VENDOR}=="ATA", ENV{SCSI_IDENT_LUN_VENDOR}=="?*", ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_VENDOR}" +# Compat ID_SERIAL setting +ENV{ID_SERIAL}!="?*", ENV{SCSI_IDENT_LUN_NAA_REGEXT}=="?*", ENV{ID_BUS}="scsi", ENV{ID_SERIAL}="3$env{SCSI_IDENT_LUN_NAA_REGEXT}", ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_NAA_REGEXT}" +ENV{ID_SERIAL}!="?*", ENV{SCSI_IDENT_LUN_NAA_REG}=="?*", ENV{ID_BUS}="scsi", ENV{ID_SERIAL}="3$env{SCSI_IDENT_LUN_NAA_REG}", ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_NAA_REG}" +ENV{ID_SERIAL}!="?*", ENV{SCSI_IDENT_LUN_NAA_EXT}=="?*", ENV{ID_BUS}="scsi", ENV{ID_SERIAL}="3$env{SCSI_IDENT_LUN_NAA_EXT}", ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_NAA_EXT}" +ENV{ID_SERIAL}!="?*", ENV{SCSI_IDENT_LUN_EUI64}=="?*", ENV{ID_BUS}="scsi", ENV{ID_SERIAL}="2$env{SCSI_IDENT_LUN_EUI64}", ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_EUI64}" +ENV{ID_SERIAL}!="?*", ENV{SCSI_IDENT_LUN_NAME}=="?*", ENV{ID_BUS}="scsi", ENV{ID_SERIAL}="8$env{SCSI_IDENT_LUN_NAME}", ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_NAME}" +ENV{ID_SERIAL}!="?*", ENV{SCSI_IDENT_LUN_T10}=="?*", ENV{ID_BUS}="scsi", ENV{ID_SERIAL}="1$env{SCSI_IDENT_LUN_T10}", ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_T10}" +ENV{ID_SERIAL}!="?*", ENV{SCSI_IDENT_LUN_NAA_LOCAL}=="?*", ENV{ID_BUS}="scsi", ENV{ID_SERIAL}="3$env{SCSI_IDENT_LUN_NAA_LOCAL}", ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_NAA_LOCAL}" +ENV{ID_SERIAL}!="?*", ENV{SCSI_IDENT_LUN_VENDOR}=="?*", ENV{ID_BUS}="scsi", ENV{ID_SERIAL}="0$env{SCSI_VENDOR}_$env{SCSI_MODEL}_$env{SCSI_IDENT_LUN_VENDOR}", ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_VENDOR}" +ENV{ID_SERIAL}!="?*", ENV{SCSI_IDENT_SERIAL}=="?*", ENV{ID_BUS}="scsi", ENV{ID_SERIAL}="S$env{SCSI_VENDOR}_$env{SCSI_MODEL}_$env{SCSI_IDENT_SERIAL}", ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_SERIAL}" + +# Compat ID_SCSI_SERIAL setting +ENV{ID_SCSI_SERIAL}!="?*", ENV{SCSI_IDENT_SERIAL}=="?*", ENV{ID_SCSI_SERIAL}="$env{SCSI_IDENT_SERIAL}" +LABEL="sg3_utils_id_end" diff --git a/scripts/58-scsi-sg3_symlink.rules b/scripts/58-scsi-sg3_symlink.rules new file mode 100644 index 00000000..fe6b0000 --- /dev/null +++ b/scripts/58-scsi-sg3_symlink.rules @@ -0,0 +1,38 @@ +# SCSI-ID symlinks for sg3_utils + +ACTION=="remove", GOTO="sg3_utils_symlink_end" + +SUBSYSTEM!="block", GOTO="sg3_utils_symlink_end" +ENV{UDEV_DISABLE_PERSISTENT_STORAGE_RULES_FLAG}=="1", GOTO="sg3_utils_symlink_end" + +# Select which identifier to use per default +# 0: vpd page 0x80 identifier +ENV{SCSI_IDENT_SERIAL}=="?*", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-id/scsi-S$env{SCSI_VENDOR}_$env{SCSI_MODEL}_$env{SCSI_IDENT_SERIAL}" +ENV{SCSI_IDENT_SERIAL}=="?*", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-id/scsi-S$env{SCSI_VENDOR}_$env{SCSI_MODEL}_$env{SCSI_IDENT_SERIAL}-part%n" +# NAA identifier (prefix 3) +# 1: IEEE Registered Extended first +ENV{SCSI_IDENT_LUN_NAA_REGEXT}=="?*", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-id/scsi-3$env{SCSI_IDENT_LUN_NAA_REGEXT}" +ENV{SCSI_IDENT_LUN_NAA_REGEXT}=="?*", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-id/scsi-3$env{SCSI_IDENT_LUN_NAA_REGEXT}-part%n" +# 2: IEEE Registered +ENV{SCSI_IDENT_LUN_NAA_REG}=="?*", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-id/scsi-3$env{SCSI_IDENT_LUN_NAA_REG}" +ENV{SCSI_IDENT_LUN_NAA_REG}=="?*", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-id/scsi-3$env{SCSI_IDENT_LUN_NAA_REG}-part%n" +# 3: IEEE Extended +ENV{SCSI_IDENT_LUN_NAA_EXT}=="?*", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-id/scsi-3$env{SCSI_IDENT_LUN_NAA_EXT}" +ENV{SCSI_IDENT_LUN_NAA_EXT}=="?*", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-id/scsi-3$env{SCSI_IDENT_LUN_NAA_EXT}-part%n" +# 4: EUI-64 identifier (prefix 2) +ENV{SCSI_IDENT_LUN_EUI64}=="?*", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-id/scsi-2$env{SCSI_IDENT_LUN_EUI64}" +ENV{SCSI_IDENT_LUN_EUI64}=="?*", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-id/scsi-2$env{SCSI_IDENT_LUN_EUI64}-part%n" +# 5: SCSI name identifier (prefix 8) +ENV{SCSI_IDENT_LUN_NAME}=="?*", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-id/scsi-8$env{SCSI_IDENT_LUN_NAME}" +ENV{SCSI_IDENT_LUN_NAME}=="?*", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-id/scsi-8$env{SCSI_IDENT_LUN_NAME}-part%n" +# 6: T10 Vendor identifier (prefix 1) +ENV{SCSI_IDENT_LUN_T10}=="?*", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-id/scsi-1$env{SCSI_IDENT_LUN_T10}" +ENV{SCSI_IDENT_LUN_T10}=="?*", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-id/scsi-1$env{SCSI_IDENT_LUN_T10}-part%n" +# 7: IEEE Locally assigned +ENV{SCSI_IDENT_LUN_NAA_LOCAL}=="?*", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-id/scsi-3$env{SCSI_IDENT_LUN_NAA_LOCAL}" +ENV{SCSI_IDENT_LUN_NAA_LOCAL}=="?*", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-id/scsi-3$env{SCSI_IDENT_LUN_NAA_LOCAL}-part%n" +# 8: Vendor-specific identifier (prefix 0) +ENV{SCSI_IDENT_LUN_VENDOR}=="?*", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-id/scsi-0$env{SCSI_VENDOR}_$env{SCSI_MODEL}_$env{SCSI_IDENT_LUN_VENDOR}" +ENV{SCSI_IDENT_LUN_VENDOR}=="?*", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-id/scsi-0$env{SCSI_VENDOR}_$env{SCSI_MODEL}_$env{SCSI_IDENT_LUN_VENDOR}-part%n" + +LABEL="sg3_utils_symlink_end" diff --git a/scripts/59-fc-wwpn-id.rules b/scripts/59-fc-wwpn-id.rules new file mode 100644 index 00000000..5ad0a5c8 --- /dev/null +++ b/scripts/59-fc-wwpn-id.rules @@ -0,0 +1,17 @@ +# +# FC WWPN-based by-path links +# + +ACTION!="add|change", GOTO="fc_wwpn_end" +KERNEL!="sd*", GOTO="fc_wwpn_end" + +ENV{DEVTYPE}=="disk", IMPORT{program}="fc_wwpn_id %p" +ENV{DEVTYPE}=="partition", IMPORT{parent}="FC_*" +ENV{FC_TARGET_WWPN}!="?*", GOTO="fc_wwpn_end" +ENV{FC_INITIATOR_WWPN}!="?*", GOTO="fc_wwpn_end" +ENV{FC_TARGET_LUN}!="?*", GOTO="fc_wwpn_end" + +ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-path/fc-$env{FC_INITIATOR_WWPN}-$env{FC_TARGET_WWPN}-lun-$env{FC_TARGET_LUN}" +ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-path/fc-$env{FC_INITIATOR_WWPN}-$env{FC_TARGET_WWPN}-lun-$env{FC_TARGET_LUN}-part%n" + +LABEL="fc_wwpn_end" diff --git a/scripts/59-scsi-cciss_id.rules b/scripts/59-scsi-cciss_id.rules new file mode 100644 index 00000000..4eb4561e --- /dev/null +++ b/scripts/59-scsi-cciss_id.rules @@ -0,0 +1,18 @@ +# cciss compat rules + +ACTION!="add|change", GOTO="cciss_compat_end" +KERNEL!="sd*", GOTO="cciss_compat_end" +ENV{ID_VENDOR}!="HP", ENV{ID_VENDOR}!="COMPAQ", GOTO="cciss_compat_end" +ENV{ID_MODEL}!="LOGICAL_VOLUME", GOTO="cciss_compat_end" + +ENV{DEVTYPE}=="disk", DRIVERS=="hpsa", IMPORT{program}="cciss_id %p" +ENV{DEVTYPE}=="partition", IMPORT{parent}="ID_*" +ENV{ID_CCISS}!="?*", GOTO="cciss_compat_end" + +ENV{DEVTYPE}=="disk", SYMLINK+="cciss/$env{ID_CCISS}" +ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/cciss-$env{ID_SERIAL}" + +ENV{DEVTYPE}=="partition", SYMLINK+="cciss/$env{ID_CCISS}p%n" +ENV{DEVTYPE}=="partition", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/cciss-$env{ID_SERIAL}-part%n" + +LABEL="cciss_compat_end" diff --git a/scripts/Makefile.am b/scripts/Makefile.am new file mode 100644 index 00000000..01d44362 --- /dev/null +++ b/scripts/Makefile.am @@ -0,0 +1,3 @@ +dist_bin_SCRIPTS = scsi_logging_level scsi_mandat scsi_readcap scsi_ready \ + scsi_satl scsi_start scsi_stop scsi_temperature \ + rescan-scsi-bus.sh diff --git a/scripts/Makefile.in b/scripts/Makefile.in new file mode 100644 index 00000000..21673ab2 --- /dev/null +++ b/scripts/Makefile.in @@ -0,0 +1,518 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = scripts +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(dist_bin_SCRIPTS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(bindir)" +SCRIPTS = $(dist_bin_SCRIPTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in README +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GETOPT_O_FILES = @GETOPT_O_FILES@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTHREAD_LIB = @PTHREAD_LIB@ +RANLIB = @RANLIB@ +RT_LIB = @RT_LIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +os_cflags = @os_cflags@ +os_libs = @os_libs@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +dist_bin_SCRIPTS = scsi_logging_level scsi_mandat scsi_readcap scsi_ready \ + scsi_satl scsi_start scsi_stop scsi_temperature \ + rescan-scsi-bus.sh + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign scripts/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign scripts/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-dist_binSCRIPTS: $(dist_bin_SCRIPTS) + @$(NORMAL_INSTALL) + @list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n' \ + -e 'h;s|.*|.|' \ + -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) { files[d] = files[d] " " $$1; \ + if (++n[d] == $(am__install_max)) { \ + print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ + else { print "f", d "/" $$4, $$1 } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-dist_binSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 's,.*/,,;$(transform)'`; \ + dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir) + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(SCRIPTS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-dist_binSCRIPTS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_binSCRIPTS + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am \ + install-dist_binSCRIPTS install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ + uninstall-am uninstall-dist_binSCRIPTS + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/scripts/README b/scripts/README new file mode 100644 index 00000000..72cbdcf5 --- /dev/null +++ b/scripts/README @@ -0,0 +1,55 @@ + README for sg3_utils/scripts + ============================ +Introduction +============ +This directory contains bash shell scripts. Most of them call one or +more utilities from the sg3_utils package. They assume the sg3_utils +package utilities are on the PATH of the user. + +rescan-scsi-bus.sh is written by Kurt Garloff (formerly from Suse Labs) +with patches from Hannes Reinecke (Suse) and Redhat. + +scsi_logging_level is written by Andreas Herrmann <aherrman at de dot ibm +dot com>. It sets the logging level of the SCSI subsystem in the Linux +2.6 series kernels. See that file for more information. + +The other scripts are written by the author. Some do testing while others +do bulk tasks (e.g. stopping multiple disks). + +Details +======= +Each script supplies more information, typically by supplying a '-h' +or '--help' option. The script source often contains explanatory +information. Following is a usage summary with a one line description: + rescan-scsi-bus.sh [OPTIONS] + - see the output of 'rescan-scsi-bus.sh --help' + scsi_logging_level [OPTIONS] + - set Linux SCSI subsystem logging level + scsi_mandat [-h] [-L] [-q] <device> + - check for mandatory SCSI command support + scsi_readcap [-b] [-h] [-v] <device>+ + - fetch capacity/size information for each <device> + scsi_ready [-h] [-v] <device>+ + - check the media ready status on each <device> + scsi_satl [-h] [-L] [-q] [-v] <device> + - check <device> for SCSI to ATA Translation Layer (SATL) + scsi_start [-h] [-v] [-w] <device>+ + - start media (i.e. spin up) in each <device> + scsi_stop [-h] [-v] [-w] <device>+ + - stop media (i.e. spin down) in each <device> + scsi_temperature [-h] [-v] <device>+ + - check temperature in each <device> + +These scripts assume that the main sg3_utils utilities are installed +and are on the user's PATH. + +This directory, prior to sg3_utils-1.28, contained the sas_disk_blink +script. Since it depends on the sdparm utility it has been moved to +the sdparm package in its scripts directory. + +59-scsi-sg3_utils.rules is a Linux specific file for udev. These rules use +'sg_inq --export' to help udev create identifying device nodes, for example +/dev/disk/by-id/wwn-0x5001501234567890-part1. + +Douglas Gilbert +4th October 2021 diff --git a/scripts/cciss_id b/scripts/cciss_id new file mode 100755 index 00000000..8ac11d5f --- /dev/null +++ b/scripts/cciss_id @@ -0,0 +1,66 @@ +#!/bin/bash +# +# cciss_id +# +# Generates device node names according to the cciss naming rules +# +# Copyright (C) 2011 SUSE Linux Products GmbH +# Author: +# Hannes Reinecke <hare@suse.de> +# +# +# 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 version 2 of the License. +# +# This script generates a device node name which is compatible +# with the 'cciss' device naming rules. +# It is intended to provide backward-compatible names for the +# 'hpsa' driver. +# + +cciss_enumerate() +{ + local last_pci_dev=${1##0000:} + local cur_pci_dev + local cciss_num=0 + + for cur_pci_dev in $(lspci -n | tac | sed -n 's/\(..:..\..\) .* 103c:\(3220\|3230\|3238\|323a\|323b\) .*/\1/p') ; do + if [ "$cur_pci_dev" == "$last_pci_dev" ] ; then + echo "$cciss_num" + return; + fi + cciss_num=$(($cciss_num + 1)) + done + echo "$cciss_num" +} + +hpsa_lun_offset() +{ + local scsi_host=$1 + + scsi_id=$(lsscsi 2>/dev/null | sed -n "s/.\(${scsi_host}:[0-9]*:[0-9]*:[0-9]*\)..*disk .*/\1/p" | head -1) + echo ${scsi_id##*:} +} + +DEVPATH=$1 +SCSIPATH=$(cd -P /sys$DEVPATH/device; echo $PWD) +SCSIID=${SCSIPATH##*/} +HOSTID=${SCSIID%%:*} +LUNID=${SCSIID##*:} +PCIPATH=${SCSIPATH%%/host*} +PCIDEV=${PCIPATH##*/} +HOSTPATH=${PCIPATH}/host${HOSTID}/scsi_host/host${HOSTID} +read controller 2>/dev/null <${HOSTPATH}/ctlr_num || controller=$(cciss_enumerate $PCIDEV) + +# hpsa lies about the LUN ... +disk_offset=$(hpsa_lun_offset $HOSTID) +if [ "$disk_offset" ] ; then + disk=$(( $LUNID - $disk_offset )) +else + disk=$LUNID +fi + +if [ "$controller" ] && [ "$disk" ] ; then + echo "ID_CCISS=c${controller}d${disk}" +fi diff --git a/scripts/fc_wwpn_id b/scripts/fc_wwpn_id new file mode 100644 index 00000000..17c74fe8 --- /dev/null +++ b/scripts/fc_wwpn_id @@ -0,0 +1,51 @@ +#!/bin/bash +# +# fc_wwpn_id +# +# Generates device node names links based on FC WWPN +# Copyright (c) 2016-2021 Hannes Reinecke, SUSE Linux GmbH +# +# 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 version 2 of the License. +# + +DEVPATH=$1 +SCSIPATH=$(cd -P "/sys$DEVPATH/device" || exit; echo "$PWD") + +d=$SCSIPATH +[ -d "$d/scsi_disk" ] || exit 0 +target_lun=${d##*:} + +while [ -n "$d" ] ; do + d=${d%/*} + e=${d##*/} + case "$e" in + rport*) + rport=$e + rport_dir="/sys/class/fc_remote_ports/$rport" + if [ -d "$rport_dir" ] ; then + rport_wwpn=$(cat "$rport_dir/port_name") + fi + ;; + host*) + host=$e + host_dir="/sys/class/fc_host/$host" + if [ -d "$host_dir" ] ; then + host_wwpn=$(cat "$host_dir/port_name") + break; + fi + esac +done + +if [ -n "$rport_wwpn" ] || [ -n "$host_wwpn" ] ; then + echo "FC_TARGET_LUN=$target_lun" +fi + +if [ -n "$rport_wwpn" ] ; then + echo "FC_TARGET_WWPN=$rport_wwpn" +fi + +if [ -n "$host_wwpn" ] ; then + echo "FC_INITIATOR_WWPN=$host_wwpn" +fi diff --git a/scripts/lunmask.service b/scripts/lunmask.service new file mode 100644 index 00000000..03fdd96a --- /dev/null +++ b/scripts/lunmask.service @@ -0,0 +1,11 @@ +[Unit] +Description=Disable LUN masking and scan SCSI Hosts +After=systemd-udev-trigger.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/lib/systemd/scripts/scsi-enable-target-scan.sh + +[Install] +WantedBy=multi-user.target diff --git a/scripts/rescan-scsi-bus.sh b/scripts/rescan-scsi-bus.sh new file mode 100755 index 00000000..1ebc0e91 --- /dev/null +++ b/scripts/rescan-scsi-bus.sh @@ -0,0 +1,1436 @@ +#!/bin/bash +# Script to rescan SCSI bus, using the scsi add-single-device mechanism. +# (c) 1998--2010 Kurt Garloff <kurt@garloff.de>, GNU GPL v2 or v3 +# (c) 2006--2022 Hannes Reinecke, GNU GPL v2 or later +# $Id: rescan-scsi-bus.sh,v 1.57 2012/03/31 14:08:48 garloff Exp $ + +VERSION="20220930" +SCAN_WILD_CARD=4294967295 + +TMPLUNINFOFILE="/tmp/rescan-scsi-mpath-info.txt" + +setcolor () +{ + red="\e[0;31m" + green="\e[0;32m" + yellow="\e[0;33m" + bold="\e[0;1m" + norm="\e[0;0m" +} + +unsetcolor () +{ + red=""; green="" + yellow=""; norm="" +} + +echo_debug() +{ + if [ "$debug" -eq 1 ] ; then + echo "$1" + fi +} + +# Output some text and return cursor to previous position +# (only works for simple strings) +# Stores length of string in LN and returns it +print_and_scroll_back () +{ + STRG="$1" + LN=${#STRG} + BK="" + declare -i cntr=0 + while [ $cntr -lt "$LN" ] ; do BK="$BK\e[D"; let cntr+=1; done + echo -en "$STRG$BK" + return "$LN" +} + +# Overwrite a text of length $LN with whitespace +white_out () +{ + BK=""; WH="" + declare -i cntr=0 + while [ $cntr -lt "$LN" ] ; do BK="$BK\e[D"; WH="$WH "; let cntr+=1; done + echo -en "$WH$BK" +} + +# Return hosts. sysfs must be mounted +findhosts_26 () +{ + hosts= + for hostdir in /sys/class/scsi_host/host* ; do + [ -e "$hostdir" ] || continue + hostno=${hostdir#/sys/class/scsi_host/host} + if [ -f "$hostdir/isp_name" ] ; then + hostname="qla2xxx" + elif [ -f "$hostdir/lpfc_drvr_version" ] ; then + hostname="lpfc" + else + hostname=$(cat "$hostdir/proc_name") + fi + hosts="$hosts $hostno" + echo_debug "Host adapter $hostno ($hostname) found." + done + if [ -z "$hosts" ] ; then + echo "No SCSI host adapters found in sysfs" + exit 1; + fi + # ensure numeric ordering. No quotes arount $hosts to skip leading space. + hosts=$(echo $hosts | tr ' ' '\n' | sort -n) +} + +# Return hosts. /proc/scsi/HOSTADAPTER/? must exist +findhosts () +{ + hosts= + for driverdir in /proc/scsi/*; do + driver=${driverdir#/proc/scsi/} + if [ "$driver" = scsi ] || [ "$driver" = sg ] || [ "$driver" = dummy ] || [ "$driver" = device_info ] ; then continue; fi + for hostdir in $driverdir/*; do + name=${hostdir#/proc/scsi/*/} + if [ "$name" = add_map ] || [ "$name" = map ] || [ "$name" = mod_parm ] ; then continue; fi + num=$name + driverinfo=$driver + if [ -r "$hostdir/status" ] ; then + 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." + done + done +} + +printtype () +{ + local type=$1 + + case "$type" in + 0) echo "Direct-Access" ;; + 1) echo "Sequential-Access" ;; + 2) echo "Printer" ;; + 3) echo "Processor" ;; + 4) echo "WORM" ;; + 5) echo "CD-ROM" ;; + 6) echo "Scanner" ;; + 7) echo "Optical-Device" ;; + 8) echo "Medium-Changer" ;; + 9) echo "Communications" ;; + 10) echo "Unknown" ;; + 11) echo "Unknown" ;; + 12) echo "RAID" ;; + 13) echo "Enclosure" ;; + 14) echo "Direct-Access-RBC" ;; + *) echo "Unknown" ;; + esac +} + +print02i() +{ + if [ "$1" = "*" ] ; then + echo "00" + else + printf "%02i" "$1" + fi +} + +# Get /proc/scsi/scsi info for device $host:$channel:$id:$lun +# Optional parameter: Number of lines after first (default = 2), +# result in SCSISTR, return code 1 means empty. +procscsiscsi () +{ + if [ -z "$1" ] ; then + LN=2 + else + LN=$1 + fi + CHANNEL=$(print02i "$channel") + ID=$(print02i "$id") + LUN=$(print02i "$lun") + if [ -d /sys/class/scsi_device ]; then + SCSIPATH="/sys/class/scsi_device/${host}:${channel}:${id}:${lun}" + 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 +$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 +$SCSITMP" + fi + else + return 1 + fi + else + grepstr="scsi$host Channel: $CHANNEL Id: $ID Lun: $LUN" + SCSISTR=$(grep -A "$LN" -e "$grepstr" /proc/scsi/scsi) + fi + if [ -z "$SCSISTR" ] ; then + return 1 + else + return 0 + fi +} + +# Find sg device with 2.6 sysfs support +sgdevice26 () +{ + local gendev + + # if the scsi device has not been added, then there would not + # a related sgdev. So it's pointless to scan all sgs to find + # a related sg. + scsidev=/sys/class/scsi_device/${host}:${channel}:${id}:${lun} + if [ ! -e "$scsidev" ]; then + SGDEV="" + return + fi + + gendev=/sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/generic + if [ -e "$gendev" ] ; then + SGDEV=$(basename "$(readlink "$gendev")") + return + fi + SGDEV="" +} + +# Find sg device with 2.4 report-devs extensions +sgdevice24 () +{ + if procscsiscsi 3; then + SGDEV=$(echo "$SCSISTR" | grep 'Attached drivers:' | sed 's/^ *Attached drivers: \(sg[0-9]*\).*/\1/') + fi +} + +# Find sg device that belongs to SCSI device $host $channel $id $lun +# and return in SGDEV +sgdevice () +{ + SGDEV= + if [ -d /sys/class/scsi_device ] ; then + sgdevice26 + else + DRV=$(grep 'Attached drivers:' /proc/scsi/scsi 2>/dev/null) + repdevstat=$((1-$?)) + if [ $repdevstat = 0 ]; then + echo "scsi report-devs 1" >/proc/scsi/scsi + DRV=$(grep 'Attached drivers:' /proc/scsi/scsi 2>/dev/null) + [ $? -eq 1 ] && return + fi + if ! echo "$DRV" | grep -q 'drivers: sg'; then + modprobe sg + fi + sgdevice24 + if [ $repdevstat = 0 ]; then + echo "scsi report-devs 0" >/proc/scsi/scsi + fi + fi +} + +# Whether or not the RMB (removable) bit has been set in the INQUIRY response. +# Uses ${host}, ${channel}, ${id} and ${lun}. Assumes that sg_device() has +# already been called. How to test this function: copy/paste this function +# in a shell and run +# (cd /sys/class/scsi_device && for d in *; do set ${d//:/ }; echo -n "$d $(</sys/class/scsi_device/${d}/device/block/*/removable) <> "; SGDEV=bsg/$d host=$1 channel=$2 id=$3 lun=$4 is_removable; done) +is_removable () +{ + local b p + + p=/sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/inquiry + # Extract the second byte of the INQUIRY response and check bit 7 (mask 0x80). + b=$(hexdump -n1 -e '/1 "%02X"' "$p" 2>/dev/null) + if [ -n "$b" ]; then + echo $(((0x$b & 0x80) != 0)) + else + sg_inq /dev/$SGDEV 2>/dev/null | sed -n 's/^.*RMB=\([0-9]*\).*$/\1/p' + fi +} + +# Test if SCSI device is still responding to commands +# Return values: +# 0 device is present +# 1 device has changed +# 2 device has been removed +testonline () +{ + local ctr RC RMB + + : testonline + ctr=0 + RC=0 + # Set default values + IPTYPE=31 + IPQUAL=3 + [ ! -x /usr/bin/sg_turs ] && return 0 + sgdevice + [ -z "$SGDEV" ] && return 0 + sg_turs /dev/$SGDEV >/dev/null 2>&1 + RC=$? + + # Handle in progress of becoming ready and unit attention + while [ $RC = 2 -o $RC = 6 ] && [ $ctr -lt $timeout ] ; do + if [ $RC = 2 ] && [ "$RMB" != "1" ] && sg_inq /dev/$SGDEV | grep -q -i "PQual=0" ; then + echo -n "." + let LN+=1 + sleep 1 + else + sleep 0.02 + fi + let ctr+=1 + sg_turs /dev/$SGDEV >/dev/null 2>&1 + RC=$? + # Check for removable device; TEST UNIT READY obviously will + # fail for a removable device with no medium + RMB=$(is_removable) + print_and_scroll_back "$host:$channel:$id:$lun $SGDEV ($RMB) " + [ $RC = 2 ] && [ "$RMB" = "1" ] && break + done + if [ $ctr != 0 ] ; then + white_out + fi + # echo -e "\e[A\e[A\e[A${yellow}Test existence of $SGDEV = $RC ${norm} \n\n\n" + [ $RC = 1 ] && return $RC + # Reset RC (might be !=0 for passive paths) + RC=0 + # OK, device online, compare INQUIRY string + INQ=$(sg_inq "$sg_len_arg" /dev/$SGDEV 2>/dev/null) + if [ -z "$INQ" ] ; then + echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV changed: ${bold}INQUIRY failed${norm} \n\n\n" + return 2 + fi + IVEND=$(echo "$INQ" | grep 'Vendor identification:' | sed 's/^[^:]*: \(.*\)$/\1/') + IPROD=$(echo "$INQ" | grep 'Product identification:' | sed 's/^[^:]*: \(.*\)$/\1/') + IPREV=$(echo "$INQ" | grep 'Product revision level:' | sed 's/^[^:]*: \(.*\)$/\1/') + STR=$(printf " Vendor: %-08s Model: %-16s Rev: %-4s" "$IVEND" "$IPROD" "$IPREV") + IPTYPE=$(echo "$INQ" | sed -n 's/.* Device_type=\([0-9]*\) .*/\1/p') + if [ -z "$IPTYPE" ]; then + IPTYPE=$(echo "$INQ" | sed -n 's/.* PDT=\([0-9]*\) .*/\1/p') + fi + IPQUAL=$(echo "$INQ" | sed -n 's/ *PQual=\([0-9]*\) Device.*/\1/p') + if [ -z "$IPQUAL" ] ; then + IPQUAL=$(echo "$INQ" | sed -n 's/ *PQual=\([0-9]*\) PDT.*/\1/p') + fi + if [ "$IPQUAL" != 0 ] ; then + [ -z "$IPQUAL" ] && IPQUAL=3 + [ -z "$IPTYPE" ] && IPTYPE=31 + echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV changed: ${bold}LU not available (PQual $IPQUAL)${norm} \n\n\n" + return 2 + fi + + TYPE=$(printtype $IPTYPE) + if ! procscsiscsi ; then + echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV removed. ${norm}\n\n\n" + return 2 + fi + TMPSTR=$(echo "$SCSISTR" | grep 'Vendor:') + if [ "$ignore_rev" -eq 0 ] ; then + if [ "$TMPSTR" != "$STR" ]; then + 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 + else + # Ignore disk revision change + local old_str_no_rev= + local new_str_no_rev= + + old_str_no_rev=${TMPSTR%Rev:*} + new_str_no_rev=${STR%Rev:*} + if [ "$old_str_no_rev" != "$new_str_no_rev" ]; then + 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 + fi + 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 + fi + return $RC +} + +# Test if SCSI device $host $channel $id $lun exists +# Outputs description from /proc/scsi/scsi (unless arg passed) +# Returns SCSISTR (empty if no dev) +testexist () +{ + : testexist + SCSISTR= + if procscsiscsi && [ -z "$1" ] ; then + echo "$SCSISTR" | head -n1 + echo "$SCSISTR" | tail -n2 | pr -o4 -l1 + fi +} + +# Returns the list of existing channels per host +chanlist () +{ + local hcil + local cil + local chan + local tmpchan + + for dev in /sys/class/scsi_device/${host}:* ; do + [ -d "$dev" ] || continue; + hcil=${dev##*/} + cil=${hcil#*:} + chan=${cil%%:*} + for tmpchan in $channelsearch ; do + if [ "$chan" -eq "$tmpchan" ] ; then + chan= + fi + done + if [ -n "$chan" ] ; then + channelsearch="$channelsearch $chan" + fi + done + if [ -z "$channelsearch" ] ; then + channelsearch="0" + fi +} + +# Returns the list of existing targets per host +idlist () +{ + local tmpid + local newid + local oldid + + oldlist=$(find /sys/class/scsi_device -name "${host}:${channel}:*" -printf "%f\n") + # Rescan LUN 0 to check if we found new targets + echo "${channel} - -" > "/sys/class/scsi_host/host${host}/scan" + newlist=$(find /sys/class/scsi_device -name "${host}:${channel}:*" -printf "%f\n") + for newid in $newlist ; do + oldid=$newid + for tmpid in $oldlist ; do + if [ "$newid" = "$tmpid" ] ; then + oldid= + break + fi + done + if [ -n "$oldid" ] ; then + if [ -d /sys/class/scsi_device/$oldid ] ; then + hcil=${oldid} + printf "\r${green}NEW: %s ${norm}" + testexist + if [ "$SCSISTR" ] ; then + incrfound "$hcil" + fi + fi + fi + done + idsearch=$(find /sys/bus/scsi/devices -name "target${host}:${channel}:*" -printf "%f\n" | cut -f 3 -d :) +} + +# Returns the list of existing LUNs from device $host $channel $id $lun +# and returns list to stdout +getluns() +{ + sgdevice + [ -z "$SGDEV" ] && return 1 + if [ ! -x /usr/bin/sg_luns ] ; then + echo 0 + return 1 + fi + LLUN=$(sg_luns /dev/$SGDEV 2>/dev/null | sed -n 's/ \(.*\)/\1/p') + # Added -z $LLUN condition because $? gets the RC from sed, not sg_luns + if [ $? -ne 0 ] || [ -z "$LLUN" ] ; then + echo 0 + return 1 + fi + for lun in $LLUN ; do + # Swap LUN number + l0=0x$lun + l1=$(( (l0 >> 48) & 0xffff )) + l2=$(( (l0 >> 32) & 0xffff )) + l3=$(( (l0 >> 16) & 0xffff )) + l4=$(( l0 & 0xffff )) + l0=$(( ( ( (l4 * 0xffff) + l3 ) * 0xffff + l2 ) * 0xffff + l1 )) + printf "%u\n" $l0 + done + return 0 +} + +# Wait for udev to settle (create device nodes etc.) +udevadm_settle() +{ + local tmo=60 + if [ -x /sbin/udevadm ] ; then + print_and_scroll_back " Calling udevadm settle (can take a while) " + # 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 [ -x /sbin/udevsettle ] ; then + print_and_scroll_back " Calling udevsettle (can take a while) " + /sbin/udevsettle + white_out + else + sleep 0.02 + fi +} + +# Perform scan on a single lun $host $channel $id $lun +dolunscan() +{ + local remappedlun0= + local devpath + SCSISTR= + devnr="$host $channel $id $lun" + echo -e " Scanning for device $devnr ... " + printf "${yellow}OLD: %s ${norm}" + testexist + # Device exists: Test whether it's still online + # (testonline returns 2 if it's gone and 1 if it has changed) + devpath="/sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device" + if [ "$SCSISTR" ] ; then + testonline + RC=$? + # Well known lun transition case. Only for Direct-Access devs (type 0) + # If block directory exists && and PQUAL != 0, we unmapped lun0 and just have a well-known lun + # If block directory doesn't exist && PQUAL == 0, we mapped a real lun0 + if [ "$lun" -eq 0 ] && [ $IPTYPE -eq 0 ] ; then + if [ $RC = 2 ] ; then + if [ -e "$devpath" ] ; then + if [ -d "$devpath/block" ] ; then + remappedlun0=2 # Transition from real lun 0 to well-known + else + RC=0 # Set this so the system leaves the existing well known lun alone. This is a lun 0 with no block directory + fi + fi + elif [ $RC = 0 ] && [ $IPTYPE -eq 0 ] ; then + if [ -e "$devpath" ] ; then + if [ ! -d "$devpath/block" ] ; then + remappedlun0=1 # Transition from well-known to real lun 0 + fi + fi + fi + fi + fi + + # Special case: lun 0 just got added (for reportlunscan), + # so make sure we correctly treat it as new + if [ "$lun" = "0" ] && [ "$1" = "1" ] && [ -z "$remappedlun0" ] ; then + SCSISTR="" + printf "\r\e[A\e[A\e[A" + fi + + : f "$remove" s $SCSISTR + if [ "$remove" ] && [ "$SCSISTR" -o "$remappedlun0" = "1" ] ; then + if [ $RC != 0 ] || [ ! -z "$forceremove" ] || [ -n "$remappedlun0" ] ; then + if [ "$remappedlun0" != "1" ] ; then + echo -en "\r\e[A\e[A\e[A${red}REM: " + echo "$SCSISTR" | head -n1 + echo -e "${norm}\e[B\e[B" + fi + if [ -e "$devpath" ] ; then + # have to preemptively do this so we can figure out the mpath device + # Don't do this if we're deleting a well known lun to replace it + if [ "$remappedlun0" != "1" ] ; then + incrrmvd "$host:$channel:$id:$lun" + fi + echo 1 > "$devpath/delete" + sleep 0.02 + else + echo "scsi remove-single-device $devnr" > /proc/scsi/scsi + if [ $RC -eq 1 ] || [ "$lun" -eq 0 ] ; then + # Try readding, should fail if device is gone + echo "scsi add-single-device $devnr" > /proc/scsi/scsi + fi + fi + fi + if [ $RC = 0 ] || [ "$forcerescan" ] ; then + if [ -e "$devpath" ] ; then + echo 1 > "$devpath/rescan" + fi + fi + printf "\r\e[A\e[A\e[A${yellow}OLD: %s ${norm}" + testexist + if [ -z "$SCSISTR" ] && [ $RC != 1 ] && [ "$remappedlun0" != "1" ] ; then + printf "\r${red}DEL: %s\r\n\n ${norm}" + # In the event we're replacing with a well known node, we need to let it continue, to create the replacement node + [ "$remappedlun0" != "2" ] && return 2 + fi + fi + if [ -z "$SCSISTR" ] || [ -n "$remappedlun0" ] ; then + if [ "$remappedlun0" != "2" ] ; then + # Device does not exist, try to add + printf "\r${green}NEW: %s ${norm}" + fi + if [ -e "/sys/class/scsi_host/host${host}/scan" ] ; then + echo "$channel $id $lun" > "/sys/class/scsi_host/host${host}/scan" 2> /dev/null + else + echo "scsi add-single-device $devnr" > /proc/scsi/scsi + fi + testexist + if [ -z "$SCSISTR" ] ; then + # Device not present + printf "\r\e[A"; + # Optimization: if lun==0, stop here (only if in non-remove mode) + if [ "$lun" = 0 ] && [ -z "$remove" ] && [ "$optscan" = 1 ] ; then + return 1; + fi + else + if [ "$remappedlun0" != "2" ] ; then + incrfound "$host:$channel:$id:$lun" + fi + fi + fi + return 0; +} + +# Perform report lun scan on $host $channel $id using REPORT_LUNS +doreportlun() +{ + lun=0 + SCSISTR= + devnr="$host $channel $id $lun" + echo -en " Scanning for device $devnr ...\r" + lun0added= + #printf "${yellow}OLD: %s ${norm}" + # Phase one: If LUN0 does not exist, try to add + testexist -q + if [ -z "$SCSISTR" ] ; then + # Device does not exist, try to add + #printf "\r${green}NEW: %s ${norm}" + if [ -e "/sys/class/scsi_host/host${host}/scan" ] ; then + echo "$channel $id $lun" > "/sys/class/scsi_host/host${host}/scan" 2> /dev/null + udevadm_settle + else + echo "scsi add-single-device $devnr" > /proc/scsi/scsi + fi + testexist -q + if [ -n "$SCSISTR" ] ; then + lun0added=1 + #testonline + else + # Device not present + # return + # Find alternative LUN to send getluns to + for dev in /sys/class/scsi_device/${host}:${channel}:${id}:*; do + [ -d "$dev" ] || continue + lun=${dev##*:} + break + done + fi + fi + targetluns=$(getluns) + REPLUNSTAT=$? + lunremove= + #echo "getluns reports " $targetluns + olddev=$(find /sys/class/scsi_device/ -name "$host:$channel:$id:*" 2>/dev/null | sort -t: -k4 -n) + oldtargets="$targetluns" + # OK -- if we don't have a LUN to send a REPORT_LUNS to, we could + # fall back to wildcard scanning. Same thing if the device does not + # support REPORT_LUNS + # TODO: We might be better off to ALWAYS use wildcard scanning if + # it works + if [ "$REPLUNSTAT" = "1" ] ; then + if [ -e "/sys/class/scsi_host/host${host}/scan" ] ; then + echo "$channel $id -" > "/sys/class/scsi_host/host${host}/scan" 2> /dev/null + udevadm_settle + else + echo "scsi add-single-device $host $channel $id $SCAN_WILD_CARD" > /proc/scsi/scsi + fi + targetluns=$(find /sys/class/scsi_device/ -name "$host:$channel:$id:*" -printf "%f\n" | cut -d : -f 4) + let found+=$(echo "$targetluns" | wc -l) + let found-=$(echo "$olddev" | wc -l) + fi + [ -z "$targetluns" ] && targetluns="$oldtargets" + # Check existing luns + for dev in $olddev; do + [ -d "$dev" ] || continue + lun=${dev##*:} + newsearch= + inlist= + # OK, is existing $lun (still) in reported list + for tmplun in $targetluns; do + if [ "$tmplun" = "$lun" ] ; then + inlist=1 + dolunscan $lun0added + [ $? -eq 1 ] && break + else + newsearch="$newsearch $tmplun" + fi + done + # OK, we have now done a lunscan on $lun and + # $newsearch is the old $targetluns without $lun + if [ -z "$inlist" ]; then + # Stale lun + lunremove="$lunremove $lun" + fi + # $lun removed from $lunsearch + targetluns=${newsearch# } + done + # Add new ones and check stale ones + for lun in $targetluns $lunremove; do + dolunscan $lun0added + [ $? -eq 1 ] && break + done +} + +# Perform search (scan $host) +dosearch () +{ + if [ -z "$channelsearch" ] ; then + chanlist + fi + for channel in $channelsearch; do + if [ -z "$idsearch" ] ; then + if [ -z "$lunsearch" ] ; then + idlist + else + idsearch=$(find /sys/bus/scsi/devices -name "target${host}:${channel}:*" -printf "%f\n" | cut -f 3 -d :) + fi + fi + for id in $idsearch; do + if [ -z "$lunsearch" ] ; then + doreportlun + else + for lun in $lunsearch; do + dolunscan + [ $? -eq 1 ] && break + done + fi + done + done +} + +expandlist () +{ + list=$1 + result="" + first=${list%%,*} + rest=${list#*,} + while [ ! -z "$first" ] ; do + beg=${first%%-*}; + if [ "$beg" = "$first" ] ; then + result="$result $beg"; + else + end=${first#*-} + result="$result $(seq -s ' ' $beg $end)" + fi + [ "$rest" = "$first" ] && rest="" + first=${rest%%,*} + rest=${rest#*,} + done + echo "$result" +} + +searchexisting() +{ + local tmpch; + local tmpid + local match=0 + local targets= + + targets=$(find /sys/bus/scsi/devices -name "target${host}:*" -printf "%f\n" | cut -d : -f 2-3) + # Nothing came back on this host, so we should skip it + [ -z "$targets" ] && return + + local target=; + for target in $targets ; do + channel=${target%:*} + id=${target#*:} + if [ -n "$channelsearch" ] ; then + for tmpch in $channelsearch ; do + [ $tmpch -eq "$channel" ] && match=1 + done + else + match=1 + fi + + [ $match -eq 0 ] && continue + match=0 + + if [ "$filter_ids" -eq 1 ] ; then + for tmpid in $idsearch ; do + if [ "$tmpid" = "$id" ] ; then + match=1 + fi + done + else + match=1 + fi + + [ $match -eq 0 ] && continue + + if [ -z "$lunsearch" ] ; then + doreportlun + else + for lun in $lunsearch ; do + dolunscan + [ $? -eq 1 ] && break + done + fi + done +} + +getallmultipathinfo() +{ + local mp= + local uuid= + local dmtmp= + local maj_min= + local tmpfile= + + truncate -s 0 $TMPLUNINFOFILE + for mp in $($DMSETUP ls --target=multipath | cut -f 1) ; do + [ "$mp" = "No" ] && break; + maj_min=$($DMSETUP status "$mp" | cut -d " " -f14) + if [ ! -L /dev/mapper/${mp} ]; then + echo "softlink /dev/mapper/${mp} not available." + continue + fi + local ret=$(readlink /dev/mapper/$mp 2>/dev/null) + if [[ $? -ne 0 || -z "$ret" ]]; then + echo "readlink /dev/mapper/$mp failed. check multipath status." + continue + fi + dmtmp=$(basename $ret) + uuid=$(cut -f2 -d- "/sys/block/$dmtmp/dm/uuid") + echo "$mp $maj_min $dmtmp $uuid" >> $TMPLUNINFOFILE + done +} + +# Go through all of the existing devices and figure out any that have been remapped +findremapped() +{ + local hctl=; + local devs= + local sddev= + local id_serial= + local id_serial_old= + local remapped= + mpaths="" + local tmpfile= + + tmpfile=$(mktemp /tmp/rescan-scsi-bus.XXXXXXXX 2> /dev/null) + 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 + devs=$(ls /sys/class/scsi_device/) + for hctl in $devs ; do + if [ -d "/sys/class/scsi_device/$hctl/device/block" ] ; then + 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 + fi + done + + # Trigger udev to update the info + echo -n "Triggering udev to update device information... " + /sbin/udevadm trigger + udevadm_settle 2>&1 /dev/null + echo "Done" + + getallmultipathinfo + + # See what changed and reload the respective multipath device if applicable + while read -r 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 + 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 + 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: %s ${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 -f $tmpfile + + if [ -n "$mp_enable" ] && [ -n "$mpaths" ] ; then + echo "Updating multipath device mappings" + flushmpaths + $MULTIPATH | grep "create:" 2> /dev/null + fi +} + +incrfound() +{ + local hctl="$1" + if [ -n "$hctl" ] ; then + let found+=1 + FOUNDDEVS="$FOUNDDEVS\t[$hctl]\n" + else + return + fi +} + +incrchgd() +{ + local hctl="$1" + if [ -n "$hctl" ] ; then + if ! echo "$CHGDEVS" | grep -q "\[$hctl\]"; then + let updated+=1 + CHGDEVS="$CHGDEVS\t[$hctl]\n" + fi + else + return + fi + + if [ -n "$mp_enable" ] ; then + local sdev + + sdev=$(findsddev "$hctl") + if [ -n "$sdev" ] ; then + findmultipath "$sdev" + fi + fi +} + +incrrmvd() +{ + local hctl="$1" + if [ -n "$hctl" ] ; then + let rmvd+=1; + RMVDDEVS="$RMVDDEVS\t[$hctl]\n" + else + return + fi + + if [ -n "$mp_enable" ] ; then + local sdev + + sdev=$(findsddev "$hctl") + if [ -n "$sdev" ] ; then + findmultipath "$sdev" + fi + fi +} + +findsddev() +{ + local hctl="$1" + local sddev= + local blkpath + + blkpath="/sys/class/scsi_device/$hctl/device/block" + if [ -e "$blkpath" ] ; then + sddev=$(ls "$blkpath") + echo "$sddev" + fi +} + +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 found_dup=0 + local maj_min= + + # Need a sdev, and executable multipath and dmsetup command here + if [ -z "$dev" ] || [ ! -x "$DMSETUP" ] || [ ! -x "$MULTIPATH" ] ; then + return 1 + fi + + maj_min=$(cat "/sys/block/$dev/dev") + mp=$(cat $TMPLUNINFOFILE | grep -w "$maj_min" | cut -d " " -f1) + if [ -n "$mp" ]; then + if [ -n "$find_mismatch" ] ; then + uuid=$(cat $TMPLUNINFOFILE | grep -w "$maj_min" | cut -d " " -f4) + if [ "$find_mismatch" != "$uuid" ] ; then + addmpathtolist "$mp" + found_dup=1 + fi + else + # Normal mode: Find the first multipath with the sdev + # and add it to the list + addmpathtolist "$mp" + return + fi + fi + + # 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 + 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 > /dev/null 2>&1 + return + fi + + # Reload the multipath devices + for mpath in $mpaths ; do + echo -n "Reloading multipath device $mpath... " + if $MULTIPATH -r "$mpath" > /dev/null 2>&1 ; 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 + local remove="" + local i + local flush_retries=5 + + if [ -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 + remove="$remove $mpath" + fi + done + else + remove="$mpaths" + 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 + if $MULTIPATH -f "$mpath" > /dev/null 2>&1 ; then + echo "Done ($i retries)" + break + elif [ $i -eq $flush_retries ] ; then + echo "Fail" + fi + sleep 0.02 + let i=$i+1 + done + done +} + + +# Find resized luns +findresized() +{ + local devs= + local size= + local new_size= + local sysfs_path= + local sddev= + local i= + local m= + local mpathsize= + declare -a mpathsizes + + if [ -z "$lunsearch" ] ; then + devs=$(ls /sys/class/scsi_device/) + else + for lun in $lunsearch ; do + devs="$devs $(cd /sys/class/scsi_device/ && ls -d *:${lun})" + done + fi + + 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") + + if [ "$size" != "$new_size" ] && [ "$size" != "0" ] && [ "$new_size" != "0" ] ; then + printf "${yellow}RESIZED: %s ${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 + fi + done + + if [ -n "$mp_enable" ] && [ -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 + 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 +} + +FOUNDDEVS="" +CHGDEVS="" +RMVDDEVS="" + +# main +if [ "@$1" = @--help ] || [ "@$1" = @-h ] || [ "@$1" = "@-?" ] ; then + echo "Usage: rescan-scsi-bus.sh [options] [host [host ...]]" + echo "Options:" + echo " -a scan all targets, not just currently existing [default: disabled]" + echo " -c enables scanning of channels 0 1 [default: 0 / all detected ones]" + echo " -d enable debug [default: 0]" + echo " -f flush failed multipath devices [default: disabled]" + echo " -h help: print this usage message then exit" + echo " -i issue a FibreChannel LIP reset [default: disabled]" + 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 " -t SECS timeout for testing if device is online. Test is skipped if 0 [default: 30]" + echo " -u look for existing disks that have been remapped" + echo " -V print version date then exit" + echo " -w scan for target device IDs 0--15 [default: 0--7]" + echo "--alltargets: same as -a" + echo "--attachpq3: Tell kernel to attach sg to LUN 0 that reports PQ=3" + echo "--channels=LIST: Scan only channel(s) in LIST" + echo "--color: use coloured prefixes OLD/NEW/DEL" + echo "--flush: same as -f" + echo "--forceremove: Remove stale devices (DANGEROUS)" + echo "--forcerescan: Remove and readd existing devices (DANGEROUS)" + echo "--help: print this usage message then exit" + echo "--hosts=LIST: Scan only host(s) in LIST" + echo "--ids=LIST: Scan only target ID(s) in LIST" + echo "--ignore-rev: Ignore the revision change" + echo "--issue-lip: same as -i" + 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 "--no-lip-scan: don't scan FC Host with issue-lip" + echo "--nooptscan: don't stop looking for LUNs if 0 is not found" + echo "--remove: same as -r" + echo "--reportlun2: Tell kernel to try REPORT_LUN even on SCSI2 devices" + echo "--resize: same as -s" + echo "--sparselun: Tell kernel to support sparse LUN numbering" + echo "--sync/nosync: Issue a sync / no sync [default: sync if remove]" + echo "--timeout=SECS: same as -t" + echo "--update: same as -u" + echo "--version: same as -V" + echo "--wide: same as -w" + echo "" + echo "Host numbers may thus be specified either directly on cmd line (deprecated)" + echo "or with the --hosts=LIST parameter (recommended)." + echo "LIST: A[-B][,C[-D]]... is a comma separated list of single values and ranges" + echo "(No spaces allowed.)" + exit 0 +fi + +if [ "@$1" = @--version ] || [ "@$1" = @-V ] ; then + echo ${VERSION} + exit 0 +fi + +if [ ! -d /sys/class/scsi_host/ ] && [ ! -d /proc/scsi/ ] ; then + echo "Error: SCSI subsystem not active" + exit 1 +fi + +# Make sure sg is there +modprobe sg >/dev/null 2>&1 + +if [ -x /usr/bin/sg_inq ] ; then + sg_version=$(sg_inq -V 2>&1 | cut -d " " -f 3) + if [ -n "$sg_version" ] ; then + sg_ver_maj=${sg_version:0:1} + sg_version=${sg_version##?.} + let sg_version+=$((100 * sg_ver_maj)) + fi + sg_version=${sg_version##0.} + #echo "\"$sg_version\"" + if [ -z "$sg_version" ] || [ "$sg_version" -lt 70 ] ; then + sg_len_arg="-36" + else + sg_len_arg="--len=36" + fi +else + echo "WARN: /usr/bin/sg_inq not present -- please install sg3_utils" + echo " or rescan-scsi-bus.sh might not fully work." +fi + +# defaults +unsetcolor +debug=0 +lunsearch= +opt_idsearch=$(seq -s ' ' 0 7) +filter_ids=0 +opt_channelsearch= +remove= +updated=0 +update=0 +resize=0 +forceremove= +optscan=1 +sync=1 +existing_targets=1 +mp_enable= +lipreset=-1 +timeout=30 +declare -i scan_flags=0 +ignore_rev=0 +no_lip_scan=0 + +# Scan options +opt="$1" +while [ ! -z "$opt" ] && [ -z "${opt##-*}" ] ; do + opt=${opt#-} + case "$opt" in + a) existing_targets=;; #Scan ALL targets when specified + c) opt_channelsearch="0 1" ;; + d) debug=1 ;; + f) flush=1 ;; + i) lipreset=0 ;; + I) shift; lipreset=$1 ;; + l) lunsearch=$(seq -s ' ' 0 7) ;; + L) lunsearch=$(seq -s ' ' 0 "$2"); shift ;; + m) mp_enable=1 ;; + r) remove=1 ;; + s) resize=1; mp_enable=1 ;; + t) timeout=$2; shift ;; + u) update=1 ;; + w) opt_idsearch=$(seq -s ' ' 0 15) ;; + -alltargets) existing_targets=;; + -attachpq3) scan_flags=$((scan_flags|0x1000000)) ;; + -channels=*) arg=${opt#-channels=};opt_channelsearch=$(expandlist "$arg") ;; + -color) setcolor ;; + -flush) flush=1 ;; + -forceremove) remove=1; forceremove=1 ;; + -forcerescan) remove=1; forcerescan=1 ;; + -hosts=*) arg=${opt#-hosts=}; hosts=$(expandlist "$arg") ;; + -ids=*) arg=${opt#-ids=}; opt_idsearch=$(expandlist "$arg") ; filter_ids=1;; + -ignore-rev) ignore_rev=1;; + -issue-lip) lipreset=0 ;; + -issue-lip-wait=*) lipreset=${opt#-issue-lip-wait=};; + -largelun) scan_flags=$((scan_flags|0x200)) ;; + -luns=*) arg=${opt#-luns=}; lunsearch=$(expandlist "$arg") ;; + -multipath) mp_enable=1 ;; + -no-lip-scan) no_lip_scan=1 ;; + -nooptscan) optscan=0 ;; + -nosync) sync=0 ;; + -remove) remove=1 ;; + -reportlun2) scan_flags=$((scan_flags|0x20000)) ;; + -resize) resize=1;; + -timeout=*) timeout=${opt#-timeout=};; + -sparselun) scan_flags=$((scan_flags|0x40)) ;; + -sync) sync=2 ;; + -update) update=1;; + -wide) opt_idsearch=$(seq -s ' ' 0 15) ;; + *) echo "Unknown option -$opt !" ;; + esac + shift + opt="$1" +done + +if [ -z "$hosts" ] ; then + if [ -d /sys/class/scsi_host ] ; then + findhosts_26 + else + findhosts + fi +fi + +if [ -d /sys/class/scsi_host ] && [ ! -w /sys/class/scsi_host ]; then + echo "You need to run scsi-rescan-bus.sh as root" + exit 2 +fi +[ "$sync" = 1 ] && [ "$remove" = 1 ] && sync=2 +if [ "$sync" = 2 ] ; then + echo "Syncing file systems" + sync +fi +if [ -w /sys/module/scsi_mod/parameters/default_dev_flags ] && [ $scan_flags != 0 ] ; then + OLD_SCANFLAGS=$(cat /sys/module/scsi_mod/parameters/default_dev_flags) + NEW_SCANFLAGS=$((OLD_SCANFLAGS|scan_flags)) + if [ "$OLD_SCANFLAGS" != "$NEW_SCANFLAGS" ] ; then + echo -n "Temporarily setting kernel scanning flags from " + printf "0x%08x to 0x%08x\n" "$OLD_SCANFLAGS" "$NEW_SCANFLAGS" + echo $NEW_SCANFLAGS > /sys/module/scsi_mod/parameters/default_dev_flags + else + unset OLD_SCANFLAGS + fi +fi +DMSETUP=$(which dmsetup) +[ -z "$DMSETUP" ] && flush= && mp_enable= +MULTIPATH=$(which multipath) +[ -z "$MULTIPATH" ] && flush= && mp_enable= + +echo -n "Scanning SCSI subsystem for new devices" +[ -z "$flush" ] || echo -n ", flush failed multipath devices," +[ -z "$remove" ] || echo -n " and remove devices that have disappeared" +echo +declare -i found=0 +declare -i updated=0 +declare -i rmvd=0 + +if [ -n "$flush" ] ; then + if [ -x "$MULTIPATH" ] ; then + flushmpaths 1 + fi +fi + +# Update existing mappings +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" + findresized +# Normal rescan mode +else + for host in $hosts; do + echo -n "Scanning host $host " + if [ $no_lip_scan -eq 0 ] && [ -e "/sys/class/fc_host/host$host" ] ; then + # It's pointless to do a target scan on FC + issue_lip=/sys/class/fc_host/host$host/issue_lip + if [ -e "$issue_lip" ] && [ "$lipreset" -ge 0 ] ; then + echo 1 > "$issue_lip" 2> /dev/null; + udevadm_settle + [ "$lipreset" -gt 0 ] && sleep "$lipreset" + fi + channelsearch= + idsearch= + else + channelsearch=$opt_channelsearch + idsearch=$opt_idsearch + fi + [ -n "$channelsearch" ] && echo -n "channels $channelsearch " + echo -n "for " + if [ -n "$idsearch" ] ; then + echo -n " SCSI target IDs $idsearch" + else + echo -n " all SCSI target IDs" + fi + if [ -n "$lunsearch" ] ; then + echo ", LUNs $lunsearch" + else + echo ", all LUNs" + fi + + if [ -n "$existing_targets" ] ; then + searchexisting + else + dosearch + fi + done + if [ -n "$OLD_SCANFLAGS" ] ; then + echo "$OLD_SCANFLAGS" > /sys/module/scsi_mod/parameters/default_dev_flags + fi +fi + +let rmvd_found=$rmvd+$found +if [ -n "$mp_enable" ] && [ $rmvd_found -gt 0 ] ; then + echo "Attempting to update multipath devices..." + if [ $rmvd -gt 0 ] ; then + udevadm_settle + echo "Removing multipath mappings for removed devices if all paths are now failed... " + flushmpaths 1 + fi + if [ $found -gt 0 ] ; then + /sbin/udevadm trigger --sysname-match=sd* + udevadm_settle + if [ -x "$MULTIPATH" ] ; then + echo "Trying to discover new multipath mappings for newly discovered devices... " + $MULTIPATH | grep "create:" 2> /dev/null + fi + fi +fi + +echo "$found new or changed device(s) found. " +if [ ! -z "$FOUNDDEVS" ] ; then + echo -e "$FOUNDDEVS" +fi +echo "$updated remapped or resized device(s) found." +if [ ! -z "$CHGDEVS" ] ; then + echo -e "$CHGDEVS" +fi +echo "$rmvd device(s) removed. " +if [ ! -z "$RMVDDEVS" ] ; then + echo -e "$RMVDDEVS" +fi + +# Local Variables: +# sh-basic-offset: 2 +# End: + diff --git a/scripts/scsi-enable-target-scan.sh b/scripts/scsi-enable-target-scan.sh new file mode 100755 index 00000000..63bb9afb --- /dev/null +++ b/scripts/scsi-enable-target-scan.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh + +MODPARM=/sys/module/scsi_mod/parameters +if [ -w "$MODPARM/scan" ] ; then + scan_type=$(cat $MODPARM/scan) + if [ "$scan_type" = "manual" ] ; then + echo sync > $MODPARM/scan + + for shost in /sys/class/scsi_host/host* ; do + echo '- - -' > ${shost}/scan + done + fi +fi diff --git a/scripts/scsi_logging_level b/scripts/scsi_logging_level new file mode 100755 index 00000000..2fba2b7f --- /dev/null +++ b/scripts/scsi_logging_level @@ -0,0 +1,268 @@ +#! /bin/bash +############################################################################### +# Conveniently create and set scsi logging level, show SCSI_LOG fields in human +# readable form. +# +# (C) Copyright IBM Corp. 2006 +# +# Modified by D. Gilbert to replace the use of sysctl [20080218] +# Lat change: D. Gilbert 20150219 +############################################################################### + + +REVISION="1.0" +SCRIPTNAME="scsi_logging_level" + +declare -i LOG_ERROR=0 +declare -i LOG_TIMEOUT=0 +declare -i LOG_SCAN=0 +declare -i LOG_MLQUEUE=0 +declare -i LOG_MLCOMPLETE=0 +declare -i LOG_LLQUEUE=0 +declare -i LOG_LLCOMPLETE=0 +declare -i LOG_HLQUEUE=0 +declare -i LOG_HLCOMPLETE=0 +declare -i LOG_IOCTL=0 + +declare -i LEVEL=0 + +SET=0 +GET=0 +CREATE=0 + +OPTS=$(getopt -o hvcgsa:E:T:S:I:M:L:H: --long \ +help,version,create,get,set,all:,error:,timeout:,scan:,ioctl:,\ +midlevel:,mlqueue:,mlcomplete:,lowlevel:,llqueue:,llcomplete:,\ +highlevel:,hlqueue:,hlcomplete: -n \'$SCRIPTNAME\' -- "$@") +eval set -- "$OPTS" + +# print version info +printversion() +{ + cat <<EOF +%S390_TOOLS_VERSION% ($SCRIPTNAME $REVISION) +(C) Copyright IBM Corp. 2006 +EOF +} + +# print usage and help +printhelp() +{ + cat <<EOF +Usage: $SCRIPTNAME [OPTIONS] + +Create, get or set scsi logging level. + +Options: + + -h, --help print this help + -v, --version print version information + -s, --set create and set logging level as specified on + command line + -g, --get get current logging level and display it + -c, --create create logging level as specified on command line + -a, --all specify value for all SCSI_LOG fields + -E, --error specify SCSI_LOG_ERROR + -T, --timeout specify SCSI_LOG_TIMEOUT + -S, --scan specify SCSI_LOG_SCAN + -M, --midlevel specify SCSI_LOG_MLQUEUE and SCSI_LOG_MLCOMPLETE + --mlqueue specify SCSI_LOG_MLQUEUE + --mlcomplete specify SCSI_LOG_MLCOMPLETE + -L, --lowlevel specify SCSI_LOG_LLQUEUE and SCSI_LOG_LLCOMPLETE + --llqueue specify SCSI_LOG_LLQUEUE + --llcomplete specify SCSI_LOG_LLCOMPLETE + -H, --highlevel specify SCSI_LOG_HLQUEUE and SCSI_LOG_HLCOMPLETE + --hlqueue specify SCSI_LOG_HLQUEUE + --hlcomplete specify SCSI_LOG_HLCOMPLETE + -I, --ioctl specify SCSI_LOG_IOCTL + +Exactly one of the options "-c", "-g" and "-s" has to be specified. +Valid values for SCSI_LOG fields are integers from 0 to 7. + +Note: Several SCSI_LOG fields can be specified using several options. +When multiple options specify same SCSI_LOG field the most specific +option has precedence. + +Example: "scsi_logging_level --hlqueue 3 --highlevel 2 --all 1 -s" sets +SCSI_LOG_HLQUEUE=3, SCSI_LOG_HLCOMPLETE=2 and assigns all other SCSI_LOG +fields the value 1. +EOF +} + +check_level() +{ + num=$(($1)) + if [ $num != "$1" ] ; then + invalid_cmdline "log level '$1' not a number" + elif [ $num -lt 0 ] || [ $num -gt 7 ] ; then + invalid_cmdline "log level '$1' out of range, expect '0' to '7'" + fi +} + +# check cmd line arguments +check_cmdline() +{ + while true ; do + case "$1" in + -a|--all) _ALL="$2"; check_level "$2" + shift 2;; + -c|--create) CREATE=1; + shift 1;; + -g|--get) GET=1 + shift 1;; + -h|--help) printhelp + exit 0;; + -s|--set) SET=1 + shift 1;; + -v|--version) printversion + exit 0;; + -E|--error) _ERROR="$2"; check_level "$2" + shift 2;; + -T|--timeout) _TIMEOUT="$2"; check_level "$2" + shift 2;; + -S|--scan) _SCAN="$2"; check_level "$2" + shift 2;; + -M|--midlevel) _ML="$2"; check_level "$2" + shift 2;; + --mlqueue) _MLQUEUE="$2"; check_level "$2" + shift 2;; + --mlcomplete) _MLCOMPLETE="$2"; check_level "$2" + shift 2;; + -L|--lowlevel) _LL="$2"; check_level "$2" + shift 2;; + --llqueue) _LLQUEUE="$2"; check_level "$2" + shift 2;; + --llcomplete) _LLCOMPLETE="$2"; check_level "$2" + shift 2;; + -H|--highlevel) _HL="$2"; check_level "$2" + shift 2;; + --hlqueue) _HLQUEUE="$2"; check_level "$2" + shift 2;; + --hlcomplete) _HLCOMPLETE="$2"; check_level "$2" + shift 2;; + -I|--ioctl) _IOCTL="$2"; check_level "$2" + shift 2;; + --) shift; break;; + *) echo "Internal error!" ; exit 1;; + esac + done + + if [ -n "$*" ] + then + invalid_cmdline invalid parameter "$@" + fi + + if [ $GET = "1" -a $SET = "1" ] + then + invalid_cmdline options \'-c\', \'-g\' and \'-s\' are mutual exclusive + elif [ $GET = "1" -a $CREATE = "1" ] + then + invalid_cmdline options \'-c\', \'-g\' and \'-s\' are mutual exclusive + elif [ $SET = "1" -a $CREATE = "1" ] + then + invalid_cmdline options \'-c\', \'-g\' and \'-s\' are mutual exclusive + fi + + LOG_ERROR=${_ERROR:-${_ALL:-0}} + LOG_TIMEOUT=${_TIMEOUT:-${_ALL:-0}} + LOG_SCAN=${_SCAN:-${_ALL:-0}} + LOG_MLQUEUE=${_MLQUEUE:-${_ML:-${_ALL:-0}}} + LOG_MLCOMPLETE=${_MLCOMPLETE:-${_ML:-${_ALL:-0}}} + LOG_LLQUEUE=${_LLQUEUE:-${_LL:-${_ALL:-0}}} + LOG_LLCOMPLETE=${_LLCOMPLETE:-${_LL:-${_ALL:-0}}} + LOG_HLQUEUE=${_HLQUEUE:-${_HL:-${_ALL:-0}}} + LOG_HLCOMPLETE=${_HLCOMPLETE:-${_HL:-${_ALL:-0}}} + LOG_IOCTL=${_IOCTL:-${_ALL:-0}} +} + +invalid_cmdline() +{ + echo "$SCRIPTNAME: $*" + echo "$SCRIPTNAME: Try '$SCRIPTNAME --help' for more information." + exit 1 +} + +get_logging_level() +{ + echo "Current scsi logging level:" +# LEVEL=$(sysctl -n dev.scsi.logging_level) + LEVEL=$(cat /proc/sys/dev/scsi/logging_level) + if [ $? != 0 ] + then + echo "$SCRIPTNAME: could not read scsi logging level" \ + "(kernel probably without SCSI_LOGGING support)" + exit 1 + fi +} + +show_logging_level() +{ + echo "/proc/sys/dev/scsi/logging_level = $LEVEL" + + LOG_ERROR=$((LEVEL & 7)); LEVEL=$((LEVEL>>3)) + LOG_TIMEOUT=$((LEVEL & 7)); LEVEL=$((LEVEL>>3)) + LOG_SCAN=$((LEVEL & 7)); LEVEL=$((LEVEL>>3)) + LOG_MLQUEUE=$((LEVEL & 7)); LEVEL=$((LEVEL>>3)) + LOG_MLCOMPLETE=$((LEVEL & 7)); LEVEL=$((LEVEL>>3)) + LOG_LLQUEUE=$((LEVEL & 7)); LEVEL=$((LEVEL>>3)) + LOG_LLCOMPLETE=$((LEVEL & 7)); LEVEL=$((LEVEL>>3)) + LOG_HLQUEUE=$((LEVEL & 7)); LEVEL=$((LEVEL>>3)); + LOG_HLCOMPLETE=$((LEVEL & 7)); LEVEL=$((LEVEL>>3)); + LOG_IOCTL=$((LEVEL & 7)) + + echo "SCSI_LOG_ERROR=$LOG_ERROR" + echo "SCSI_LOG_TIMEOUT=$LOG_TIMEOUT" + echo "SCSI_LOG_SCAN=$LOG_SCAN" + echo "SCSI_LOG_MLQUEUE=$LOG_MLQUEUE" + echo "SCSI_LOG_MLCOMPLETE=$LOG_MLCOMPLETE" + echo "SCSI_LOG_LLQUEUE=$LOG_LLQUEUE" + echo "SCSI_LOG_LLCOMPLETE=$LOG_LLCOMPLETE" + echo "SCSI_LOG_HLQUEUE=$LOG_HLQUEUE" + echo "SCSI_LOG_HLCOMPLETE=$LOG_HLCOMPLETE" + echo "SCSI_LOG_IOCTL=$LOG_IOCTL" +} + +set_logging_level() +{ + echo "New scsi logging level:" +# sysctl -q -w dev.scsi.logging_level=$LEVEL + echo $LEVEL > /proc/sys/dev/scsi/logging_level + if [ $? != 0 ] + then + echo "$SCRIPTNAME: could not write scsi logging level $LEVEL" + echo " kernel does not have SCSI_LOGGING support or needs superuser" + exit 1 + fi +} +create_logging_level() +{ + LEVEL=$((LOG_IOCTL & 7)); LEVEL=$((LEVEL<<3)) + LEVEL=$((LEVEL|(LOG_HLCOMPLETE & 7))); LEVEL=$((LEVEL<<3)) + LEVEL=$((LEVEL|(LOG_HLQUEUE & 7))); LEVEL=$((LEVEL<<3)) + LEVEL=$((LEVEL|(LOG_LLCOMPLETE & 7))); LEVEL=$((LEVEL<<3)) + LEVEL=$((LEVEL|(LOG_LLQUEUE & 7))); LEVEL=$((LEVEL<<3)) + LEVEL=$((LEVEL|(LOG_MLCOMPLETE & 7))); LEVEL=$((LEVEL<<3)) + LEVEL=$((LEVEL|(LOG_MLQUEUE & 7))); LEVEL=$((LEVEL<<3)) + LEVEL=$((LEVEL|(LOG_SCAN & 7))); LEVEL=$((LEVEL<<3)) + LEVEL=$((LEVEL|(LOG_TIMEOUT & 7))); LEVEL=$((LEVEL<<3)) + LEVEL=$((LEVEL|(LOG_ERROR & 7))) +} + +check_cmdline "$@" + +if [ $SET = "1" ] +then + create_logging_level + set_logging_level + show_logging_level +elif [ $GET = "1" ] +then + get_logging_level + show_logging_level +elif [ $CREATE = "1" ] +then + create_logging_level + show_logging_level +else + invalid_cmdline missing option \'-g\', \'-s\' or \'-c\' +fi diff --git a/scripts/scsi_mandat b/scripts/scsi_mandat new file mode 100755 index 00000000..1f72b406 --- /dev/null +++ b/scripts/scsi_mandat @@ -0,0 +1,133 @@ +#!/bin/bash +# scsi_mandat +# +# Script to test compliance with SCSI mandatory commands. +# The vintage is SPC-3 and SPC-4 (see www.t10.org). +# +# Coverage: +# Command Standard/Draft (is mandatory in) +# ------------------------------------------------------- +# INQUIRY (standard) SCSI-2, SPC, SPC-2, SPC-3, SPC-4 +# INQUIRY (VPD pages 0, 0x83) SPC-2, SPC-3, SPC-4 +# REPORT LUNS SPC-3, SPC-4 +# TEST UNIT READY SCSI-2, SPC, SPC-2, SPC-3, SPC-4 +# REQUEST SENSE SCSI-2, SBC, SBC-2,3, MMC-4,5, SSC-2,3 +# SEND DIAGNOSTIC SBC, SBC-2,3, SSC-2,3 +# +# This script uses utilities frim sg3_utils package (version +# 1.21 or later) +# +# Douglas Gilbert 20131016 + + +log=0 +quiet=0 +verbose="" + +file_err=0 +inv_opcode=0 +illeg_req=0 +not_ready=0 +medium=0 +other_err=0 +recovered=0 +sanity=0 +syntax=0 +timeout=0 +unit_attention=0 +aborted_command=0 + +## total_err=0 + +usage() +{ + echo "Usage: scsi_mandat [-h] [-L] [-q] [-v] <device>" + echo " where: -h, --help print usage message" + echo " -L, --log append stderr to 'scsi_mandat.err'" + echo " -q, --quiet suppress some output" + echo " -v, --verbose increase verbosity of output" + echo "" + echo "Check <device> for mandatory SCSI command support" +} + + +opt="$1" +while test ! -z "$opt" -a -z "${opt##-*}"; do + opt=${opt#-} + case "$opt" in + h|-help) usage ; exit 0 ;; + L|-log) let log=$log+1 ;; + q|-quiet) let quiet=$quiet+1 ;; + v|-verbose) verbose="-v" ;; + vv) verbose="-vv" ;; + vvv) verbose="-vvv" ;; + *) echo "Unknown option: -$opt " ; exit 1 ;; + esac + shift + opt="$1" +done + +if [ $# -lt 1 ] + then + usage + exit 1 +fi + +for command in "sg_inq" "sg_luns" "sg_turs" "sg_requests" "sg_vpd" \ + "sg_vpd -i" "sg_senddiag -t" +do + if [ $quiet -eq 0 ] + then echo "$command" $verbose "$1" + fi + + if [ $verbose ] + then + if [ $log -eq 0 ] + then + $command $verbose "$1" + else + $command $verbose "$1" >> scsi_mandat.err 2>> scsi_mandat.err + fi + else + if [ $log -eq 0 ] + then + $command "$1" > /dev/null 2>> /dev/null + else + $command "$1" > /dev/null 2>> scsi_mandat.err + fi + fi + res=$? + case "$res" in + 0) ;; + 1) echo " syntax error" ; let syntax=$syntax+1 ;; + 2) echo " not ready" ; let not_ready=$not_ready+1 ;; + 3) echo " medium error" ; let medium=$medium+1 ;; + 5) echo " illegal request, general" ; let illeg_req=$illeg_req+1 ;; + 6) echo " unit attention" ; let unit_attention=$unit_attention+1 ;; + 9) echo " illegal request, invalid opcode" ; let inv_opcode=$inv_opcode+1 ;; + 11) echo " aborted command" ; let aborted_command=$aborted_command+1 ;; + 15) echo " file error with $1 " ; let file_err=$file_err+1 ;; + 20) echo " no sense" ; let other_err=$other_err+1 ;; + 21) echo " recovered error" ; let recovered=$recovered+1 ;; + 33) echo " timeout" ; let timeout=$timeout+1 ;; + 97) echo " response fails sanity" ; let sanity=$sanity+1 ;; + 98) echo " other SCSI error" ; let other_err=$other_err+1 ;; + 99) echo " other error" ; let other_err=$other_err+1 ;; + *) echo " unknown exit status for sg_inq: $res" ; let other_err=$other_err+1 ;; + esac +done + +echo "" +let total_bad_err=$file_err+$inv_opcode+$illeg_req+$medium+$aborted_command +let total_bad_err+=$other_err+$recovered+$sanity+$syntax+$timeout + +let total_allow_err=$not_ready+$unit_attention + + echo "total number of bad errors: $total_bad_err " + +if [ $total_allow_err -gt 0 ] + then + echo "total number of allowable errors: $total_allow_err " +fi + +exit $total_bad_err diff --git a/scripts/scsi_readcap b/scripts/scsi_readcap new file mode 100755 index 00000000..8f308f4f --- /dev/null +++ b/scripts/scsi_readcap @@ -0,0 +1,57 @@ +#!/bin/bash + +################################################################### +# +# Fetch READ CAPACITY information for the given SCSI device(s). +# +# This script assumes the sg3_utils package is installed. +# +################################################################## + +verbose="" +brief="" +long_opt="" + +usage() +{ + echo "Usage: scsi_readcap [-b] [-h] [-l] [-v] <device>+" + echo " where:" + echo " -b, --brief output brief capacity data" + echo " -h, --help print usage message" + echo " -l, --long send longer SCSI READ CAPACITY (16) cdb" + echo " -v, --verbose more verbose output" + echo "" + echo "Use SCSI READ CAPACITY command to fetch the size of each <device>" +} + +opt="$1" +while test ! -z "$opt" -a -z "${opt##-*}"; do + opt=${opt#-} + case "$opt" in + b|-brief) brief="-b" ;; + h|-help) usage ; exit 0 ;; + l|-long) long_opt="--16" ;; + v|-verbose) verbose="-v" ;; + vv) verbose="-vv" ;; + vvv) verbose="-vvv" ;; + *) echo "Unknown option: -$opt " ; exit 1 ;; + esac + shift + opt="$1" +done + +if [ $# -lt 1 ] + then + usage + exit 1 +fi + +for i +do + if [ $brief ] ; then + sg_readcap $brief $long_opt $verbose $i 2> /dev/null + else + echo "sg_readcap $brief $long_opt $verbose $i" + sg_readcap $brief $long_opt $verbose $i + fi +done diff --git a/scripts/scsi_ready b/scripts/scsi_ready new file mode 100755 index 00000000..724c2c63 --- /dev/null +++ b/scripts/scsi_ready @@ -0,0 +1,56 @@ +#!/bin/bash + +################################################ +# +# Send a TEST UNIT READY SCSI command to each given device. +# +# This script assumes the sg3_utils package is installed and uses +# the sg_turs utility.. +# +############################################### + +verbose="" +brief="" + +usage() +{ + echo "Usage: scsi_ready [-b] [-h] [-v] <device>+" + echo " where:" + echo " -b, --brief print 'ready' or 'device not ready' only" + echo " -h, --help print usage message" + echo " -v, --verbose more verbose output" + echo "" + echo "Send SCSI TEST UNIT READY to each <device>" +} + +opt="$1" +while test ! -z "$opt" -a -z "${opt##-*}"; do + opt=${opt#-} + case "$opt" in + b|-brief) brief="1" ;; + h|-help) usage ; exit 0 ;; + v|-verbose) verbose="-v" ;; + vv) verbose="-vv" ;; + vvv) verbose="-vvv" ;; + *) echo "Unknown option: -$opt " ; exit 1 ;; + esac + shift + opt="$1" +done + +if [ $# -lt 1 ] + then + usage + exit 1 +fi + +for i +do + if [ ! $brief ] ; then + echo "sg_turs $verbose $i" + fi + echo -n " " + if sg_turs $verbose $i ; then + echo "ready" + fi +done diff --git a/scripts/scsi_satl b/scripts/scsi_satl new file mode 100755 index 00000000..08042ae3 --- /dev/null +++ b/scripts/scsi_satl @@ -0,0 +1,134 @@ +#!/bin/bash +# scsi_satl +# +# Script to test compliance of SCSI commands on a SCSI to ATA +# Translation (SAT) Layer (SATL). This script was compiled using +# sat-r09.pdf found at www.t10.org . +# The scripts still seems to be valid for sat2r09.pdf . +# The vintage is SPC-3 and SPC-4 (see www.t10.org). +# +# Coverage: +# Command SATL notes +# ------------------------------------------------------- +# INQUIRY (standard) +# INQUIRY (VPD: 0) +# INQUIRY (VPD: 0x83) Device identification VPD page +# INQUIRY (VPD: 0x89) ATA Information VPD page +# REPORT LUNS SPC-3, SPC-4 (hardly mentioned in sat-r08c) +# TEST UNIT READY +# REQUEST SENSE +# SEND DIAGNOSTIC default self test +# MODE SENSE(10) draft unclear which mode pages, so ask for all +# ATA PASS THROUGH(16) send IDENTIFY DEVICE command. Assume non-packet +# device, if packet device add "-p" option +# +# This script uses utilities from sg3_utils package (version +# 1.22 or later) +# +# Douglas Gilbert 20090930 + + +log=0 +quiet=0 +verbose="" + +file_err=0 +inv_opcode=0 +illeg_req=0 +not_ready=0 +medium=0 +other_err=0 +recovered=0 +sanity=0 +syntax=0 +timeout=0 +unit_attention=0 +aborted_command=0 + +## total_err=0 + +usage() +{ + echo "Usage: scsi_satl [-h] [-L] [-q] [-v] <device>" + echo " where: -h, --help print usage message" + echo " -L, --log append stderr to 'scsi_satl.err'" + echo " -q, --quiet suppress some output" + echo " -v, --verbose more verbose output" + echo "" + echo "Check <device> for SCSI to ATA Translation Layer (SATL) support" +} + +opt="$1" +while test ! -z "$opt" -a -z "${opt##-*}"; do + opt=${opt#-} + case "$opt" in + h|-help) usage ; exit 1 ;; + L|-log) let log=$log+1 ;; + q|-quiet) let quiet=$quiet+1 ;; + v|-verbose) verbose="-v" ;; + *) echo "Unknown option: -$opt " ; exit 1 ;; + esac + shift + opt="$1" +done + +if [ $# -lt 1 ] + then + usage + exit 1 +fi + +for command in "sg_inq" "sg_vpd" "sg_vpd -p di" "sg_vpd -p ai" "sg_luns" \ + "sg_turs" "sg_requests -s" "sg_senddiag -t" "sg_modes -a" \ + "sg_sat_identify" +do + if [ $quiet -eq 0 ] + then echo "$command" "$1" + fi + + if [ $log -eq 0 ] + then + if [ $verbose ] + then + $command $verbose "$1" > /dev/null + else + $command "$1" > /dev/null 2>> /dev/null + fi + else + $command $verbose "$1" > /dev/null 2>> scsi_satl.err + fi + res=$? + case "$res" in + 0) ;; + 1) echo " syntax error" ; let syntax=$syntax+1 ;; + 2) echo " not ready" ; let not_ready=$not_ready+1 ;; + 3) echo " medium error" ; let medium=$medium+1 ;; + 5) echo " illegal request, general" ; let illeg_req=$illeg_req+1 ;; + 6) echo " unit attention" ; let unit_attention=$unit_attention+1 ;; + 9) echo " illegal request, invalid opcode" ; let inv_opcode=$inv_opcode+1 ;; + 11) echo " aborted command" ; let aborted_command=$aborted_command+1 ;; + 15) echo " file error with $1 " ; let file_err=$file_err+1 ;; + 20) echo " no sense" ; let other_err=$other_err+1 ;; + 21) echo " recovered error" ; let recovered=$recovered+1 ;; + 33) echo " timeout" ; let timeout=$timeout+1 ;; + 97) echo " response fails sanity" ; let sanity=$sanity+1 ;; + 98) echo " other SCSI error" ; let other_err=$other_err+1 ;; + 99) echo " other error" ; let other_err=$other_err+1 ;; + *) echo " unknown exit status for sg_inq: $res" ; let other_err=$other_err+1 ;; + esac +done + +echo "" +let total_bad_err=$file_err+$inv_opcode+$illeg_req+$medium+$aborted_command +let total_bad_err+=$other_err+$recovered+$sanity+$syntax+$timeout + +let total_allow_err=$not_ready+$unit_attention + + echo "total number of bad errors: $total_bad_err " + +if [ $total_allow_err -gt 0 ] + then + echo "total number of allowable errors: $total_allow_err " +fi + +exit $total_bad_err diff --git a/scripts/scsi_start b/scripts/scsi_start new file mode 100755 index 00000000..aec7ab97 --- /dev/null +++ b/scripts/scsi_start @@ -0,0 +1,55 @@ +#!/bin/bash + +################################################ +# +# Spin up the given SCSI disk(s). +# +# SCSI disks (or disks that understand SCSI commands) +# are assumed. By default, the immediate bit is set so the +# command should return immediately. The disk however will +# take 10 seconds or more to spin up. The '-w' option +# causes each start to wait until the disk reports that it +# has started. +# +# This script assumes the sg3_utils package is installed. +# +############################################### + +verbose="" +immediate="-i" + +usage() +{ + echo "Usage: scsi_start [-h] [-v] [-w] <device>+" + echo " where:" + echo " -h, --help print usage message" + echo " -v, --verbose more verbose output" + echo " -w, --wait wait for each start to complete" + echo "" + echo "Send SCSI START STOP UNIT command to start each <device>" +} + +opt="$1" +while test ! -z "$opt" -a -z "${opt##-*}"; do + opt=${opt#-} + case "$opt" in + h|-help) usage ; exit 0 ;; + v|-verbose) verbose="-v" ;; + w|-wait) immediate="" ;; + *) echo "Unknown option: -$opt " ; exit 1 ;; + esac + shift + opt="$1" +done + +if [ $# -lt 1 ] + then + usage + exit 1 +fi + +for i +do + echo "sg_start $immediate 1 $verbose $i" + sg_start $immediate 1 $verbose $i +done diff --git a/scripts/scsi_stop b/scripts/scsi_stop new file mode 100755 index 00000000..76807234 --- /dev/null +++ b/scripts/scsi_stop @@ -0,0 +1,58 @@ +#!/bin/bash + +################################################ +# +# Spin down the given SCS disk(s). +# +# SCSI disks (or disks that understand SCSI commands) +# are assumed. By default, the immediate bit is set so the +# command should return immediately. The disk however will +# take 10 seconds or more to spin down. The '-w' option +# causes each stop to wait until the disk reports that it +# has stopped. +# +# This script assumes the sg3_utils package is installed. +# +############################################### + +verbose="" +immediate="-i" + +usage() +{ + echo "Usage: scsi_stop [-h] [-v] [-w] <device>+" + echo " where:" + echo " -h, --help print usage message" + echo " -v, --verbose more verbose output" + echo " -w, --wait wait for each stop to complete" + echo "" + echo "Send SCSI START STOP UNIT command to stop each <device>" +} + +opt="$1" +while test ! -z "$opt" -a -z "${opt##-*}"; do + opt=${opt#-} + case "$opt" in + h|-help) usage ; exit 0 ;; + v|-verbose) verbose="-v" ;; + w|-wait) immediate="" ;; + *) echo "Unknown option: -$opt " ; exit 1 ;; + esac + shift + opt="$1" +done + +if [ $# -lt 1 ] + then + usage + exit 1 +fi + +for i +do +# Use '-r' (read-only) otherwise using a block device node +# (e.g. 'sg_start 0 /dev/sdb') can result in a change of state +# event causing the disk to spin up again immediately. + echo "sg_start -r $immediate 0 $verbose $i" + sg_start -r $immediate 0 $verbose $i +done diff --git a/scripts/scsi_temperature b/scripts/scsi_temperature new file mode 100755 index 00000000..f7d041cd --- /dev/null +++ b/scripts/scsi_temperature @@ -0,0 +1,46 @@ +#!/bin/bash + +################################################################### +# +# Check the temperature of the given SCSI device(s). +# +# This script assumes the sg3_utils package is installed. +# +################################################################## + +verbose="" + +usage() +{ + echo "Usage: scsi_temperature [-h] [-v] <device>+" + echo " where:" + echo " -h, --help print usage message" + echo " -v, --verbose more verbose output" + echo "" + echo "Use SCSI LOG SENSE command to fetch temperature of each <device>" +} + +opt="$1" +while test ! -z "$opt" -a -z "${opt##-*}"; do + opt=${opt#-} + case "$opt" in + h|-help) usage ; exit 0 ;; + v|-verbose) verbose="-v" ;; + vv) verbose="-vv" ;; + *) echo "Unknown option: -$opt " ; exit 1 ;; + esac + shift + opt="$1" +done + +if [ $# -lt 1 ] + then + usage + exit 1 +fi + +for i +do + echo "sg_logs -t $verbose $i" + sg_logs -t $verbose $i +done |