Search
j0ke.net Open Build Service
>
Projects
>
GFS
>
scsi
> lsscsi-transport-update
Sign Up
|
Log In
Username
Password
Cancel
Overview
Repositories
Revisions
Requests
Users
Advanced
Attributes
Meta
File lsscsi-transport-update of Package scsi
diff -pur lsscsi-0.17/CREDITS lsscsi-0.19/CREDITS --- lsscsi-0.17/CREDITS 2005-07-19 03:14:32.000000000 +0200 +++ lsscsi-0.19/CREDITS 2007-01-07 19:57:18.000000000 +0100 @@ -1,11 +1,26 @@ The author of lsscsi would like to thank the following people who have made contributions: +FUJITA Tomonori <fujita dot tomonori at lab dot ntt dot co dot jp> + iSCSI transport help [20070107] + +James Smart <James dot Smart at Emulex dot Com> + transport help, especially for FC [20061128] + +Luben Tuikov <ltuikov at yahoo dot com> + transport help [20061127] + +Mike Christie <michaelc at cs dot wisc dot edu> + iSCSI transport help [20070104] + Nate Dailey <Nate dot Dailey at stratus dot com> -Code to get actual /dev device name rather than produce synthetic -device name based on major and minor number. '--kname' option -shows "synthetic" device name; /dev device name is now the -default. [20050620] + Code to get actual /dev device name rather than produce synthetic + device name based on major and minor number. '--kname' option + shows "synthetic" device name; /dev device name is now the + default. [20050620] + +Stefan Richter <stefanr at s5r6 dot in-berlin dot de> + transport help with ieee1394 [20061231] Doug Gilbert -22nd June 2005 +7th January 2007 diff -pur lsscsi-0.17/doc/lsscsi.html lsscsi-0.19/doc/lsscsi.html --- lsscsi-0.17/doc/lsscsi.html 2005-12-30 07:22:13.000000000 +0100 +++ lsscsi-0.19/doc/lsscsi.html 2007-01-25 21:23:35.000000000 +0100 @@ -4,15 +4,39 @@ <title>lsscsi utility for Linux</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> - <meta name="keywords" content="Linux, SCSI, device scan, sysfs"> + <meta name="keywords" + content="lsscsi, linux, SCSI, device scan, sysfs"> <meta name="GENERATOR" content="Mozilla/4.79 [en] (X11; U; Linux 2.5.31 i686) [Netscape]"> </head> <body background="paper.jpg"> <center> -<h1>lsscsi</h1> +<h1><a class="mozTocH1" name="mozTocId944699"></a>lsscsi</h1> </center> -<h2> <b>Introduction</b></h2> +<ol id="mozToc"> +<!--mozToc h1 1 h2 2 h3 3 h4 4 h5 5 h6 6--> + <li><a href="#mozTocId944699">lsscsi</a> + <ol> + <li><a href="#mozTocId557900">Introduction</a></li> + <li><a href="#mozTocId305911"> Overview</a></li> + <li><a href="#mozTocId473619">Command line interface</a></li> + <li><a href="#mozTocId782775">Transports</a> + <ol> + <li><a href="#mozTocId339163">FC</a></li> + <li><a href="#mozTocId419863">1394</a></li> + <li><a href="#mozTocId194875">iSCSI</a></li> + <li><a href="#mozTocId798449">SPI</a></li> + <li><a href="#mozTocId80471">SAS</a></li> + </ol> + </li> + <li><a href="#mozTocId908089">lsscsi version 0.15 +to 0.19 notes</a></li> + <li><a href="#mozTocId856130"> Download and Build +information</a></li> + </ol> + </li> +</ol> +<h2><a class="mozTocH2" name="mozTocId557900"></a><b>Introduction</b></h2> In the 2.6 linux kernel series a new pseudo file system call <b>sysfs</b> reflects the way that various devices and their drivers are configured in the system. Sysfs support has been added to the SCSI subsystem (as @@ -20,7 +44,7 @@ well as most other driver subsystems) so information can be deduced by scanning the sysfs tree. The <b>lsscsi</b> command scans the sysfs tree and outputs information about SCSI devices (or SCSI hosts) that are attached. -<h2> Details</h2> +<h2><a class="mozTocH2" name="mozTocId305911"></a> Overview</h2> The <span style="font-weight: bold;">lsscsi</span> command accesses the sysfs file system (usually mounted under <span style="font-family: monospace;">/sys</span> ) to obtain information @@ -51,7 +75,7 @@ CD5233E &nb Linux scsi_debug 0004 /dev/sdb</tt><br> <br> -The first entry on each line is the scsi_host,channel,target_id,lun +The first entry on each line is the scsi_host,channel,target_number,lun tuple. It is placed in brackets and each element is colon separated. When there are multiple SCSI devices their entries are sorted in ascending tuple order. @@ -68,6 +92,11 @@ note that the tape medium exchanger does not have a primary device name and thus can only be accessed via its corresponding scsi generic (sg) device name.<br> <br> +The target_number (the third element of the tuple) is the target +identifier for the SCSI Parallel Interface (SPI). For all other +transports the target_number is simply a kernel generated enumeration +(as is the scsi_host value).<br> +<br> Here is a "long" variant of this command:<br> $ lscssi -l<br> <tt>[0:0:1:0] disk FUJITSU @@ -165,11 +194,595 @@ sg_tablesize=255 unchecked_isa_dma <span style="font-family: monospace;"> device dir: /sys/devices/platform/host1</span><br> <br> -See "man lsscsi" for more information. The command also contains +For transport information see the section of that name below. Online +there is a "man" page (invoked by 'man lsscsi') which contains +information specific to the version of lsscsi installed on a machine. +The command also contains usage information that can be output by using "lsscsi -h" or "lsscsi --help".<br> +<h2><a class="mozTocH2" name="mozTocId473619"></a>Command line interface</h2> +The lsscsi command has this command line interface:<br> + <span style="font-family: monospace;">lsscsi [options] [filter]</span><br> +The command line options are shown in table 1.<br> +<br> +The filter argument is designed to select a subset of available devices +(or hosts when the '--hosts' option is given [added version in 0.19]). +The filter can comprise of up to four numbers, separated by ":" or +spaces; alternatively it can be of the form "host<n>" where +<n> is a host number. The four numbers represent host number, +channel (or bus) number, target number and logical unit number (i.e. +lun) respectively. The "-" symbol is used to represent a wildcard. For +device listings, no filter argument is equivalent to "-:-:-:-". Numbers +missing from the filter are treated as wildcards: hence "5:0:1" and +"5:0:1:-" are the same.<br> +<br> +<table style="width: 100%; text-align: left;" border="1" cellpadding="2" + cellspacing="2"> + <caption><span style="font-weight: bold;">Table 1. lsscsi command +line options</span><br> + </caption> <tbody> + <tr> + <td style="vertical-align: top;"><span style="font-weight: bold;">long +option format</span><br> + </td> + <td style="vertical-align: top;"><span style="font-weight: bold;">short +option format</span><br> + </td> + <td style="vertical-align: top;"><span style="font-weight: bold;">version</span><br> + <span style="font-weight: bold;">added</span><br> + </td> + <td style="vertical-align: top;"><span style="font-weight: bold;">description</span><br> + </td> + </tr> + <tr> + <td style="vertical-align: top;">--classic<br> + </td> + <td style="vertical-align: top;">-c<br> + </td> + <td style="vertical-align: top;"><br> + </td> + <td style="vertical-align: top;">generate output similar to 'cat +/proc/scsi/scsi'<br> + </td> + </tr> + <tr> + <td style="vertical-align: top;">--device<br> + </td> + <td style="vertical-align: top;">-d<br> + </td> + <td style="vertical-align: top;"><br> + </td> + <td style="vertical-align: top;">show device node's major and +minor numbers<br> + </td> + </tr> + <tr> + <td style="vertical-align: top;">--generic<br> + </td> + <td style="vertical-align: top;">-g<br> + </td> + <td style="vertical-align: top;"><br> + </td> + <td style="vertical-align: top;">show scsi generic device node +name<br> + </td> + </tr> + <tr> + <td style="vertical-align: top;">--help<br> + </td> + <td style="vertical-align: top;">-h<br> + </td> + <td style="vertical-align: top;"><br> + </td> + <td style="vertical-align: top;">print usage message then exit<br> + </td> + </tr> + <tr> + <td style="vertical-align: top;">--hosts<br> + </td> + <td style="vertical-align: top;">-H<br> + </td> + <td style="vertical-align: top;"><br> + </td> + <td style="vertical-align: top;">rather than list SCSI devices +(logical units), list SCSI hosts instead<br> + </td> + </tr> + <tr> + <td style="vertical-align: top;">--kname<br> + </td> + <td style="vertical-align: top;">-k<br> + </td> + <td style="vertical-align: top;">0.15<br> + </td> + <td style="vertical-align: top;">show kernel name (as found in +sysfs) instead of device node name (as found in the /dev directory)<br> + </td> + </tr> + <tr> + <td style="vertical-align: top;">--list<br> + </td> + <td style="vertical-align: top;">-L<br> + </td> + <td style="vertical-align: top;">0.19<br> + </td> + <td style="vertical-align: top;">show +<attribute>=<value> pairs, one per line, indented by two +or more spaces<br> + </td> + </tr> + <tr> + <td style="vertical-align: top;">--long<br> + </td> + <td style="vertical-align: top;">-l<br> + </td> + <td style="vertical-align: top;"><br> + </td> + <td style="vertical-align: top;">show +<attribute>=<value> pairs, several to a line. can be used +multiple times for more output and different format.<br> + </td> + </tr> + <tr> + <td style="vertical-align: top;">--transport<br> + </td> + <td style="vertical-align: top;">-t<br> + </td> + <td style="vertical-align: top;">0.19<br> + </td> + <td style="vertical-align: top;">show transport information. If +'--hosts' not given then this will be for targets. If '--hosts' is +given then this will be for initiators (i.e. hosts). More information +shown when used with '--list'.<br> + </td> + </tr> + <tr> + <td style="vertical-align: top;">--verbose<br> + </td> + <td style="vertical-align: top;">-v<br> + </td> + <td style="vertical-align: top;"><br> + </td> + <td style="vertical-align: top;">increase verbosity of output. +May be used multiple times to further increase verbosity.<br> + </td> + </tr> + <tr> + <td style="vertical-align: top;">--version<br> + </td> + <td style="vertical-align: top;">-V<br> + </td> + <td style="vertical-align: top;"><br> + </td> + <td style="vertical-align: top;">print out the version and the +date of last code change then exits<br> + </td> + </tr> + </tbody> +</table> +<br> +The <span style="font-weight: bold;">lsscsi</span> man page and +the usage message in the executable also show the command line syntax.<br> +<h2><a class="mozTocH2" name="mozTocId782775"></a>Transports</h2> +When the '--transport' (or '-t') option is given <span + style="font-weight: bold;">lsscsi</span> attempts to determine the +transport being used and outputs information specific to that +transport. In the case of modern transports that may include a world +wide unique name or identifier. The transports for which extra +information is provided are:<br> +<ul> + <li>Fibre channel (FC): substantial amount both for target and host<br> + </li> + <li>IEEE 1394 (SBP): target and host<br> + </li> + <li>iSCSI: target only<br> + </li> + <li>SCSI Parallel Interface (SPI): trivial<br> + </li> + <li>Serial Attached SCSI (SAS): substantial amount for both target +and host<br> + </li> +</ul> +Even though <span style="font-weight: bold;">lsscsi</span>, in the +absence of the '--hosts' option, shows logical unit information, once +the '--transport' option is specified the output relates to the <span + style="text-decoration: underline;">target</span> which contains the +logical unit. This occurs since the computer (and thus sysfs) see a +"transport" (or interconnect) whose near end is a host (i.e. a SCSI +initiator) and whose far end is a <span + style="text-decoration: underline;">target</span>. A target may +contain one or more logical units (and in special cases a target may +contain no logical units). SCSI initiators and targets can also have +one or more ports. Linux tends to show each port of a target (that +contains one logical unit) as two devices; to be more precise, linux +shows a different device for each distinct path to a logical unit.<br> +<br> +When the '--transport' option is given the SCSI INQUIRY strings +(vendor, product and revison) usually output by <span + style="font-weight: bold;">lsscsi</span> are replaced by a target name +or identifier. Annex A in the <a + href="http://www.t10.org/ftp/t10/drafts/sam4/sam4r08.pdf">SAM-4</a> +document has been used as a guide for the appropriate initiator (i.e. +host) and target names and identifiers to display.<br> +<h3><a class="mozTocH3" name="mozTocId339163"></a>FC</h3> +For FC devices (logical units), the '--transport' option will show the +port name and the port identifier instead of the SCSI INQUIRY +"strings". For example:<br> +<span style="font-family: monospace;">$ lsscsi -g</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[3:0:0:0] +enclosu HP +A6255A +HP04 - /dev/sg3</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[3:0:1:0] +disk HP 36.4G +ST336753FC HP00 +/dev/sdd /dev/sg4</span><br style="font-family: monospace;"> +<span style="font-family: monospace;">[3:0:2:0] +disk HP 36.4G +ST336753FC HP00 +/dev/sde /dev/sg5</span><br style="font-family: monospace;"> +<br style="font-family: monospace;"> +<span style="font-family: monospace;">$ lsscsi -g --transport</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[3:0:0:0] +enclosu fc:0x50060b00002e48a3,0x0b109b +- /dev/sg3</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[3:0:1:0] +disk fc:0x21000004cf97de68,0x0b109f +/dev/sdd /dev/sg4</span><br style="font-family: monospace;"> +<span style="font-family: monospace;">[3:0:2:0] +disk fc:0x21000004cf97e385,0x0b10a3 +/dev/sde /dev/sg5</span><br> +<br> +Notice that the port name for the enclosure is naa-5 while the port +names for the disks are naa-2. Since SAS also uses naa-5 the leading +"fc:" indicates that the transport has been identified as FC. When +'--list' is added, more transport information is provided in +"name=value" pairs, indented by two or more spaces. The output is +restricted to one disk by added the 3:0:2:0 filter:<br> +<span style="font-family: monospace;">$ lsscsi -t --list [3:0:2:0]</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[3:0:2:0] +disk fc:0x21000004cf97e385,0x0b10a3 +/dev/sde</span><br style="font-family: monospace;"> +<span style="font-family: monospace;"> transport=fc</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> +node_name=0x20000004cf97e385</span><br style="font-family: monospace;"> +<span style="font-family: monospace;"> +port_name=0x21000004cf97e385</span><br style="font-family: monospace;"> +<span style="font-family: monospace;"> port_id=0x0b10a3</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> port_state=Online</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> roles=FCP Target</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> scsi_target_id=2</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> supported_classes=Class 3</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> dev_loss_tmo=35</span><br> +<br> +When the '--hosts' option is used with '--transport' then transport +information for the initiator (port) is output:<br> +<span style="font-family: monospace;">$ lsscsi --hosts --transport 3</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[3] +qla2xxx +fc:0x50060b00741cc28e,0x0b1900</span><br> +<br> +This shows for host 3 the driver is called qla2xxx, the transport is +FC, the initiator's port name is in naa-5 format with the final (hex) +number being the initiator's port identifier. Adding '--list' will +again add "name=value" pairs:<br> +<span style="font-family: monospace;">$ lsscsi -H -t --list 3</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[3] +qla2xxx +fc:0x50060b00741cc28e,0x0b1900</span><br style="font-family: monospace;"> +<span style="font-family: monospace;"> transport=fc</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> +node_name=0x50060b00741cc28f</span><br style="font-family: monospace;"> +<span style="font-family: monospace;"> +port_name=0x50060b00741cc28e</span><br style="font-family: monospace;"> +<span style="font-family: monospace;"> port_id=0x0b1900</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> port_type=NPort (fabric +via point-to-point)</span><br style="font-family: monospace;"> +<span style="font-family: monospace;"> speed=2 Gbit</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> supported_classes=Class 3</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> tgtid_bind_type=wwpn +(World Wide Port Name)</span><br> +<br> + The "name=value" pairs are fetched from a sysfs directory (apart +from "transport=fc") so the meaning should be what is defined by the +transport. Too see which directory (or directories) provide this +information add '-vvv'.<br> +<h3><a class="mozTocH3" name="mozTocId419863"></a>1394</h3> +There are two versions of the SBP SCSI standard known as SBP-2 and +SBP-3 for conveying +SCSI command sets over a IEEE 1394 transport. The SCSI commands sets +are typically for accessing storage devices. Hence the acronym "SBP" +is often associated with the IEEE 1394 transport in the storage context.<br> +<br> +SBP defines world wide unique names for a target and initiator (host) +using EUI-64 format. These names are what the lsscsi command fetches +when the '-t' option is given:<br> +<span style="font-family: monospace;">$ lsscsi</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[6:0:1:0] sim +dsk QUANTUM FIREBALL +SE3.2A /dev/sdk</span><br + style="font-family: monospace;"> +<br style="font-family: monospace;"> +<span style="font-family: monospace;">$ lsscsi -t</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[6:0:1:0] sim +dsk sbp:00043b000000071d:1:0 +/dev/sdk</span><br style="font-family: monospace;"> +<br style="font-family: monospace;"> +<span style="font-family: monospace;">$ lsscsi -t -L</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[6:0:1:0] sim +dsk sbp:00043b000000071d:1:0 +/dev/sdk</span><br style="font-family: monospace;"> +<span style="font-family: monospace;"> transport=sbp</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> +ieee1394_id=00043b000000071d:1:0</span><br + style="font-family: monospace;"> +<br style="font-family: monospace;"> +<span style="font-family: monospace;">$ lsscsi -t -H</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[6] +sbp2 +sbp:005042b500004a48</span><br style="font-family: monospace;"> +<br style="font-family: monospace;"> +<span style="font-family: monospace;">$ lsscsi -t -H -L</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[6] +sbp2 +sbp:005042b500004a48</span><br style="font-family: monospace;"> +<span style="font-family: monospace;"> transport=sbp</span><br> +<br> +The SBP standard requires that disks (typically ATA disks in an +external enclosure) use the SCSI peripheral device type: "simplified +direct access device". The is abbreviated by the lsscsi command to "sim +dsk".<br> +<h3><a class="mozTocH3" name="mozTocId194875"></a>iSCSI</h3> +The <span style="font-weight: bold;">lsscsi</span> command won't show +anything iSCSI related on a machine with a iSCSI target running (either +as a kernel driver or as a user space daemon). The following output is +from a machine running a iSCSI initiator with a session established:<br> +<span style="font-family: monospace;">$ lsscsi</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[2:0:0:0] +disk IET +VIRTUAL-DISK 0 /dev/sda</span><br + style="font-family: monospace;"> +<br style="font-family: monospace;"> +<span style="font-family: monospace;">$ lsscsi -t</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[2:0:0:0] +disk iqn.2001-04.com.example:sda.sdb.sdc,t,0x1 +/dev/sda</span><br style="font-family: monospace;"> +<br style="font-family: monospace;"> +<span style="font-family: monospace;">$ lsscsi -t -L</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[2:0:0:0] +disk iqn.2001-04.com.example:sda.sdb.sdc,t,0x1 +/dev/sda</span><br style="font-family: monospace;"> +<span style="font-family: monospace;"> transport=iSCSI</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> +targetname=iqn.2001-04.com.example:sda.sdb.sdc</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> tpgt=1</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> data_pdu_in_order=1</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> data_seq_in_order=1</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> erl=0</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> first_burst_len=65536</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> initial_r2t=1</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> max_burst_len=262144</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> max_outstanding_r2t=1</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> recovery_tmo=120</span><br + style="font-family: monospace;"> +<br style="font-family: monospace;"> +<span style="font-family: monospace;">$ lsscsi -t -H</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[2] +iscsi_tcp iscsi:</span><br + style="font-family: monospace;"> +<br style="font-family: monospace;"> +<span style="font-family: monospace;">$ lsscsi -t -H -L</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[2] +iscsi_tcp iscsi:</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> transport=iSCSI</span><br> <br> -<h2>lsscsi version 0.15 and 0.16 notes</h2> +As can be seen, there is no useful host information (e.g. the iSCSI +initiator name) when the '-H' option (or the '--hosts' option) is +given. The information given for the target is session related. An +iSCSI session is made up of 1 or more connections which have available +information in sysfs but the <span style="font-weight: bold;">lsscsi</span> +command doesn't output them currently.<br> +<h3><a class="mozTocH3" name="mozTocId80471"></a>SAS</h3> +For SAS devices (logical units), the '--transport' option will show the +target's SAS address instead of the SCSI INQUIRY +"strings". For example:<br> +<span style="font-family: monospace;">$ lsscsi -t</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[4:0:3:0] +disk +sas:0x5000d50001b02139 +/dev/sdd</span><br style="font-family: monospace;"> +<span style="font-family: monospace;">[4:0:4:0] +disk +sas:0x5000d500005208ed +/dev/sde</span><br style="font-family: monospace;"> +<span style="font-family: monospace;">[5:0:0:0] +disk +sas:5000d50001b02139 +/dev/sdf</span><br style="font-family: monospace;"> +<span style="font-family: monospace;">[5:0:1:0] +disk +sas:5000d500005208ed +/dev/sdg</span><br> +<br> +The SAS address is prefixed by "sas:" to identify the transport. The +are currently two different representations and lsscsi prints out +whatever is in the relevant sysfs attribute. When a '--list' (or '-L) +option is added more information is output:<br> +<span style="font-family: monospace;">$ lsscsi -t -L [4:0:4:0]</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[4:0:4:0] +disk +sas:0x5000d500005208ed +/dev/sde</span><br style="font-family: monospace;"> +<span style="font-family: monospace;"> transport=sas</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> +initiator_port_protocols=none</span><br style="font-family: monospace;"> +<span style="font-family: monospace;"> +initiator_response_timeout=10000</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> I_T_nexus_loss_timeout=1744</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> phy_identifier=11</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> ready_led_meaning=1</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> +sas_address=0x5000d500005208ed</span><br style="font-family: monospace;"> +<span style="font-family: monospace;"> target_port_protocols=ssp<br> +<br> +# lsscsi -t -L [5:0:1:0]<br> +[5:0:1:0] disk +sas:5000d500005208ed +/dev/sdg<br> + transport=sas<br> + sub_transport=sas_class<br> + device_name=0000000000000000<br> + dev_type=end device<br> + iproto=<br> + iresp_timeout=0x2710<br> + itnl_timeout=0x07d0<br> + linkrate=3,0 Gbps<br> + max_linkrate=3,0 Gbps<br> + max_pathways=1<br> + min_linkrate=3,0 Gbps<br> + pathways=1<br> + ready_led_meaning=1<br> + rl_wlun=0<br> + sas_addr=5000d500005208ed<br> + tproto=SSP<br> + transport_layer_retries=0<br> +<br> +</span>Both 4:0:4:0 and 5:0:1:0 are the same logical unit accessed via +the same target port but from different hosts. The two drivers (one for +each host) choose to represent the same (target port) information in +different ways.<br> +<br> +When the '--hosts' option is added, then the SAS address of the +initiator is output. In the case of SAS a Linux host corresponds to a +initiator device (not one of its ports):<br> +<span style="font-family: monospace;">$ ./lsscsi -t -H</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[0] sata_nv</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[1] sata_nv</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[2] sata_nv</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[3] sata_nv</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[4] +mptsas sas:0x500605b000f6f260</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[5] +aic94xx sas:50000d100f2dc000</span><br> +<br> +Adding a '--list' option will print multiple 'name=value' pair lines, +each indented with two or more spaces.<br> +<br> +<h3><a class="mozTocH3" name="mozTocId798449"></a>SPI</h3> +The SCSI parallel interface (SPI) can be detected (as indicated by the +"spi:" prefix) but sysfs provides no world wide unique names (there may +be some in the device identification VPD page). The only thing that is +available in sysfs is the target identifier which is usually a number +between 0 and 15 inclusive. The initiator (host) identifier is not +provided by by convention it is usually 7. Following are some examples +of target and host transport information for SPI:<br> +<span style="font-family: monospace;">$ lsscsi [0:0:1:0]</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[0:0:1:0] +disk HP 36.4G +ST336753LC HPC7 /dev/sdb</span><br + style="font-family: monospace;"> +<br style="font-family: monospace;"> +<span style="font-family: monospace;">$ lsscsi -t [0:0:1:0]</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[0:0:1:0] +disk +spi:1 +/dev/sdb</span><br style="font-family: monospace;"> +<br style="font-family: monospace;"> +<span style="font-family: monospace;">$ lsscsi -t -L [0:0:1:0]</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[0:0:1:0] +disk +spi:1 +/dev/sdb</span><br style="font-family: monospace;"> +<span style="font-family: monospace;"> transport=spi</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> target_id=1</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> dt=1</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> max_offset=127</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> max_width=1</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> min_period=6.25</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> offset=63</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> period=6.25</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> width=1</span><br + style="font-family: monospace;"> +<br style="font-family: monospace;"> +<span style="font-family: monospace;">$ lsscsi -t -H [0:0:1:0]</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[0] +mptspi spi:</span><br + style="font-family: monospace;"> +<br style="font-family: monospace;"> +<span style="font-family: monospace;">$ lsscsi -t -H -L [0:0:1:0]</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;">[0] +mptspi spi:</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> transport=spi</span><br + style="font-family: monospace;"> +<span style="font-family: monospace;"> signalling=unknown</span><br> +<h2><a class="mozTocH2" name="mozTocId908089"></a>lsscsi version 0.15 +to 0.19 notes</h2> These versions attempt to find the device name used in the <span style="font-family: monospace;">/dev</span> directory rather than the kernel generated name. The kernel generated @@ -208,11 +821,12 @@ select+sort facility).<br> Extra SCSI device and host attributes (as found in lk 2.6.12) can be seen by using the '--long' option twice (or more conveniently using '-ll'). Attributes are listed as "<name>=<value>" pairs, -one per line (indented two spaces) when the '-lll' option is given.<br> +one per line (indented two spaces) when the '--list' option is given.<br> <br> <p> </p> <p> </p> -<h2> Download and Build information</h2> +<h2><a class="mozTocH2" name="mozTocId856130"></a> Download and Build +information</h2> <p> </p> <p>Here is a table of the versions of lsscsi available for the lk 2.6 series. <br> @@ -222,9 +836,9 @@ series. <br> <tr> <td valign="top"><b>tarball</b><br> </td> - <td valign="top"><b>binary rpm</b><br> + <td valign="top"><b>binary rpm **+ deb</b><br> </td> - <td valign="top"><b>source rpm</b><br> + <td valign="top"><b>source rpm **</b><br> </td> <td valign="top"><b>notes</b><br> </td> @@ -288,22 +902,49 @@ arguments and /dev scanning. Does not us <td style="vertical-align: top;">lk 2.6.14, fixes for osst and ch devices, debian build. Does not use libsysfs. </td> </tr> + <tr> + <td style="vertical-align: top;"><a href="lsscsi-0.17.tgz">lsscsi-0.17.tgz</a></td> + <td style="vertical-align: top;"><a href="lsscsi-0.17-1.i386.rpm">lsscsi-0.17-1.i386.rpm</a></td> + <td style="vertical-align: top;"><a href="lsscsi-0.17-1.src.rpm">lsscsi-0.17-1.src.rpm</a></td> + <td style="vertical-align: top;">lk 2.6.16, kernel (sysfs) change +that first appeared in lk 2.6.16-rc1 requires this version to see block +devices<br> + </td> + </tr> + <tr> + <td style="vertical-align: top;"><a href="lsscsi-0.18.tgz">lsscsi-0.18.tgz</a></td> + <td style="vertical-align: top;"><a href="lsscsi-0.18-1.i386.rpm">lsscsi-0.18-1.i386.rpm</a> + </td> + <td style="vertical-align: top;"><a href="lsscsi-0.18-1.src.rpm">lsscsi-0.18-1.src.rpm</a> + </td> + <td style="vertical-align: top;"><span style="font-weight: bold;"></span>allow +for "generic" and "tape" symlinks to be dropped in sysfs.<br> + </td> + </tr> + <tr> + <td style="vertical-align: top;"><a href="lsscsi-0.19.tgz">lsscsi-0.19.tgz</a></td> + <td style="vertical-align: top;"><a href="lsscsi-0.19-1.i386.rpm">lsscsi-0.19-1.i386.rpm</a><br> + <a href="lsscsi_0.19-0.1_i386.deb">lsscsi_0.19-0.1_i386.deb</a><br> + </td> + <td style="vertical-align: top;"><a href="lsscsi-0.19-1.src.rpm">lsscsi-0.19-1.src.rpm</a> + </td> + <td style="vertical-align: top;">add transport information, +'--list' option, fixes for lk 2.6.20<br> + </td> + </tr> </tbody> </table> -<p><br> +<p>Here is the most recent <a href="lsscsi.ChangeLog">ChangeLog</a> .<br> </p> -<h2>Related utilities -</h2> -<p>In lk 2.6 various sysfs utilities are (becoming) available. See the <a - href="http://linux-diag.sourceforge.net/Sysfsutils.html">sysfsutils</a> -package for the <span style="font-weight: bold;"></span><span - style="font-weight: bold;">systool</span> utility that is more -generic than <span style="font-weight: bold;">lsscsi</span>.<br> -<br> +<p>** Some browsers (e.g. firefox) may interpret a file with an +extension +of "rpm" as an audio file. In which case press the right button over +the link and select "Save link as ..." to download the file. </p> <p> </p> -<p>Doug Gilbert (dgilbert@interlog.com) <br> -Last updated: 30th December 2005<br> - </p> +<div style="text-align: center;">Doug Gilbert (dgilbert@interlog.com) <br> +Last updated: 25th January 2007<br> +</div> +<p> </p> </body> </html> diff -pur lsscsi-0.17/lsscsi.8 lsscsi-0.19/lsscsi.8 --- lsscsi-0.17/lsscsi.8 2005-12-30 14:28:02.000000000 +0100 +++ lsscsi-0.19/lsscsi.8 2007-01-25 21:03:54.000000000 +0100 @@ -1,100 +1,179 @@ -.TH lsscsi "8" "December 2005" "lsscsi-0.16" LSSCSI +.TH lsscsi "8" "January 2007" "lsscsi\-0.19" LSSCSI .SH NAME lsscsi \- list SCSI devices (or hosts) and their attributes .SH SYNOPSIS .B lsscsi -[\fI--classic|-c\fR] [\fI--device|-d\fR] [\fI--generic|-g\fR] -[\fI--help|-h\fR] [\fI--hosts|-H\fR] [\fI--kname|-k\fR] [\fI--long|-l\fR] -[\fI--verbose\fR] [\fI--version\fR] [\fI<h:c:t:l>\fR] +[\fI\-\-classic\fR] [\fI\-\-device\fR] [\fI\-\-generic\fR] [\fI\-\-help\fR] +[\fI\-\-hosts\fR] [\fI\-\-kname\fR] [\fI\-\-list\fR] [\fI\-\-long\fR] +[\fI\-\-transport\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] +[\fIH:C:T:L\fR] .SH DESCRIPTION .\" Add any additional description here .PP -Uses information in sysfs (linux kernels 2.6.0 and later) to list -scsi devices (or hosts) currently attached to the system. Options can -be used to control the amount and form of information provided for -each device. -.PP -If a <h:c:t:l> argument is given then it acts as a filter and only -devices that match it are listed. The colons don't have to be -present, and '-', '*', '?' or missing arguments at the end are -wildcards. '-' needs to stand alone or else it is taken as the -beginning of an option (e.g. '-:-:-:-' is illegal). '*' needs -to be escaped from the shell. A leading '[' and trailing ']' -are permitted (e.g. '[1:0:0]' matches all luns on 1:0:0). +Uses information in sysfs (linux kernel series 2.6 and later) to list scsi +devices (or hosts) currently attached to the system. Options can be used to +control the amount and form of information provided for each device. +.PP +If a \fIH:C:T:L\fR argument is given then it acts as a filter and only +devices that match it are listed. The colons don't have to be present, +and '\-', '*', '?' or missing arguments at the end are interpreted as +wildcards. '\-' needs to stand alone or else it is taken as the beginning of +an option (e.g. '\-:\-:\-:\-' is illegal). '*' needs to be escaped from the +shell. A leading '[' and trailing ']' are permitted (e.g. '[1:0:0]' +matches all luns on 1:0:0). May also be used to filter \fI\-\-hosts\fR +in which case only the \fIH\fR is active and may be either a number +or in the form "host<n>" where <n> is a host number. .PP By default in this utility device node names (e.g. "/dev/sda" -or "/dev/root_disk") are obtained by noting the major and minor -numbers for the listed device obtained from sysfs (e.g. the -contents of /sys/block/sda/dev) and then looking for a match -in the "/dev" directory. This "match by major and minor" will allow -devices that have been given a different name by udev (for example) -to be correctly reported by this utility. +or "/dev/root_disk") are obtained by noting the major and minor numbers for +the listed device obtained from sysfs (e.g. the contents +of "/sys/block/sda/dev") and then looking for a match in the "/dev" +directory. This "match by major and minor" will allow devices that have been +given a different name by udev (for example) to be correctly reported by +this utility. .PP In some situations it may be useful to see the device node name that -linux would produce by default, so the '--kname' option is provided. -An example of where this may be useful is kernel error logs which -tend to report disk error messages using the disk's default kernel -name. +linux would produce by default, so the \fI\-\-kname\fR option is provided. +An example of where this may be useful is kernel error logs which tend to +report disk error messages using the disk's default kernel name. +.PP +Information about this utility including examples can also be found at: +http://www.torque.net/scsi/lsscsi.html . +.SH OPTIONS .TP ---classic | -c +\fB\-c\fR, \fB\-\-classic\fR The output is similar to that obtained from 'cat /proc/scsi/scsi' .TP ---device | -d -After outputting the (probable) scsi device name the the device node +\fB\-d\fR, \fB\-\-device\fR +After outputting the (probable) scsi device name the device node major and minor numbers are shown in brackets (e.g. "/dev/sda[8:0]"). .TP ---generic | -g +\fB\-g\fR, \fB\-\-generic\fR Output the scsi generic device file name. Note that if the sg driver -is a module it needs to be loaded otherwise '-' will appear +is a module it may need to be loaded otherwise '\-' may appear. .TP ---help | -h -Output the usage message and exit +\fB\-h\fR, \fB\-\-help\fR +Output the usage message and exit. .TP ---hosts | -H +\fB\-H\fR, \fB\-\-hosts\fR List the SCSI hosts currently attached to the system. If this option is -not given then SCSI devices are listed +not given then SCSI devices are listed. .TP ---kname | -k +\fB\-k\fR, \fB\-\-kname\fR Use linux default algorithm for naming devices (e.g. block major 8, minor 0 is "/dev/sda") rather than the "match by major and minor" in the "/dev" directory as discussed above. .TP ---long | -l +\fB\-L\fR, \fB\-\-list\fR +Output additional information in <attribute_name>=<value> pairs, one pair +per line preceded by two spaces. This option has the same effect as '\-lll' +.TP +\fB\-l\fR, \fB\-\-long\fR Output additional information for each SCSI device (host). Can be -used multiple times for more output in which case the shorter -form is more convenient (e.g. '-lll'). When used three times (i.e. '-lll') +used multiple times for more output in which case the shorter option +form is more convenient (e.g. '\-lll'). When used three times (i.e. '\-lll') outputs SCSI device (host) attributes one per line; preceded by two spaces; in the form "<attribute_name>=<value>". .TP ---verbose | -v -outputs directory names where information is found. Use twice for +\fB\-t\fR, \fB\-\-transport\fR +Output transport information. This will be a target related information or, +if \fI\-\-hosts\fR is given, initiator related information. When used without +\fI\-\-list\fR, a name or identifier (or both) are output on a single line, +usually prefixed by the type of transport. For devices this information +replaces the normal vendor, product and revision strings. When the +\fI\-\-list\fR option is also given then additionally multiple lines +of attribute_name=value pairs are ouput, each indented by two spaces. See +the section on transports below. +.TP +\fB\-v\fR, \fB\-\-verbose\fR +outputs directory names where information is found. Use multiple times for more output. .TP ---version | -V -outputs version number information and exits -.PP -Information for this command is derived from the the sysfs file system +\fB\-V\fR, \fB\-\-version\fR +outputs version information then exits. +.SH NOTES +Information for this command is derived from the sysfs file system whose mount point is found by examining the contents of /proc/mounts . SCSI (pseudo) devices that have been detected by the SCSI mid level will be listed even if the required upper level drivers (i.e. sd, sr, st, osst or ch) have not been loaded. If the appropriate upper level driver has not been loaded then the device file name will appear -as '-' rather than something like '/dev/st0'. Note that some +as '\-' rather than something like '/dev/st0'. Note that some devices (e.g. scanners and medium changers) do not have a primary upper level driver and can only be accessed via a scsi generic (sg) device name. +.SH TRANSPORTS +This utility lists SCSI devices which are known as logical units (lu) in +the SCSI Architecture Model (ref: SAM\-4 at http://www.t10.org) or hosts +when the \fI\-\-hosts\fR option is given. A host is called an initiator in +SAM\-4. A SCSI command travels out via an initiator, across some transport +to a target and then onwards to a logical unit. A target device may contain +several logical units. A target device has one or more ports that can be +viewed as transport end points. Each FC and SAS disk is a single target +that has two ports and contains one logical unit. If both target ports +on a FC or SAS disk are connected and visible to a machine, then lsscsi +will show two entries. Initiators (i.e. hosts) also have one or more ports +and some HBAs in Linux have a host entry per initiator port while others +have a host entry per initiator device. +.PP +When the \fI\-\-transport\fR option is given for devices (i.e. +\fI\-\-hosts\fR not given) then most of the information produced by lsscsi +is associated with the target, or more precisely: the target port, through +which SCSI commands pass that access a logical unit. +.PP +Typically this utility provides one line of output per "device" or host. +Significantly more information can be obtained by adding the \fI\-\-list\fR +option. When used together with the \fI\-\-transport\fR option, after +the summary line, multiple lines of transport specific information in the +form "<attribute_name>=<value>" are output, each indented by two spaces. +Using a filter argument will reduce the volume of output if a lot of +devices or hosts are present. +.PP +The transports that are currently recognized are: IEEE 1394, FC, iSCSI, SAS +and SPI. +.PP +For IEEE 1394 (a.k.a. Firewire and "SBP" when storage is involved), the +EUI-64 based target port name is output when \fI\-\-transport\fR is given, +in the absence of the \fI\-\-hosts\fR option. When the \fI\-\-hosts\fR +option is given then the EUI-64 initiator port name is output. Output on +the summary line specific to the IEEE 1394 transport is prefixed by "sbp:". +.PP +For Fibre Channel (FC) the port name and port identifier are output +when \fI\-\-transport\fR is given. In the absence of the \fI\-\-hosts\fR +option these ids will be for the target port associated with the +device (logical unit) being listed. When the \fI\-\-hosts\fR option is +given then the ids are for the initiator port used by the host. Output +on the summary line specific to the FC transport is prefixed by "fc:". +.PP +For iSCSI the target port name is output when \fI\-\-transport\fR is given, +in the absence of the \fI\-\-hosts\fR option. This is made up of the +iSCSI name and the target portal group tag. Since the iSCSI name starts +with "iqn" no further prefix is used. When the \fI\-\-hosts\fR option +is given then only "iscsi:" is output on the summary line. +.PP +For Serial Attached SCSI the SAS address of the target port (or initiator +port if \fI\-\-hosts\fR option is also given) is output. This will be a naa\-5 +address. For SAS HBAs and SAS targets (such as SAS disks and tape drives) +the SAS address will be world wide unique. For SATA disks attached to a +SAS expander, the expander provides the SAS address by adding a non zero +value to its (i.e. the expander's) SAS address (e.g. expander_sas_address + +phy_id + 1). SATA disks directly attached to SAS HBAs seem to have an +indeterminate SAS address. Output on the summary line specific to the SAS +transport is prefixed by "sas:". +.PP +For the SCSI Parallel Interface (SPI) the target port identifier (usually +a number between 0 and 15 inclusive) is output when \fI\-\-transport\fR is +given, in the absence of the \fI\-\-hosts\fR option. When the \fI\-\-hosts\fR +option is given then only "spi:" is output on the summary line. .SH AUTHOR Written by Doug Gilbert .SH "REPORTING BUGS" Report bugs to <dgilbert at interlog dot com>. .SH COPYRIGHT -Copyright \(co 2003-2005 Douglas Gilbert +Copyright \(co 2003\-2007 Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B lspci .B lsusb -and -.B systool -The latter utility can be found in the sysfsutils package. diff -pur lsscsi-0.17/lsscsi.c lsscsi-0.19/lsscsi.c --- lsscsi-0.17/lsscsi.c 2006-02-06 08:03:24.000000000 +0100 +++ lsscsi-0.19/lsscsi.c 2007-01-25 19:53:45.000000000 +0100 @@ -1,7 +1,7 @@ /* This is a utility program for listing SCSI devices and hosts (HBAs) * in the Linux operating system. It is applicable to kernel versions * 2.6.1 and greater. - * Copyright (C) 2003-2005 D. Gilbert + * Copyright (C) 2003-2007 D. Gilbert * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) @@ -9,7 +9,9 @@ */ #define _XOPEN_SOURCE 500 +#ifndef _GNU_SOURCE #define _GNU_SOURCE +#endif #include <stdio.h> #include <stdlib.h> @@ -24,16 +26,42 @@ #include <linux/major.h> #include <time.h> +static const char * version_str = "0.19 2007/01/25"; + #define NAME_LEN_MAX 260 +#define FT_OTHER 0 +#define FT_BLOCK 1 +#define FT_CHAR 2 + +#define TRANSPORT_UNKNOWN 0 +#define TRANSPORT_SPI 1 +#define TRANSPORT_FC 2 +#define TRANSPORT_SAS 3 +#define TRANSPORT_SAS_CLASS 4 +#define TRANSPORT_ISCSI 5 +#define TRANSPORT_SBP 6 + +static int transport_id = TRANSPORT_UNKNOWN; + -static const char * version_str = "0.17 2006/2/6"; static char sysfsroot[NAME_LEN_MAX]; static const char * sysfs_name = "sysfs"; static const char * sysfs_test_dir = "/sys/class"; static const char * sysfs_test_top = "/sys"; static const char * proc_mounts = "/proc/mounts"; -static const char * scsi_devs = "/bus/scsi/devices"; -static const char * scsi_hosts = "/class/scsi_host"; +static const char * bus_scsi_devs = "/bus/scsi/devices"; +static const char * class_scsi_dev = "/class/scsi_device/"; +static const char * scsi_host = "/class/scsi_host"; +static const char * spi_host = "/class/spi_host/"; +static const char * spi_transport = "/class/spi_transport/"; +static const char * sas_host = "/class/sas_host/"; +static const char * sas_phy = "/class/sas_phy/"; +static const char * sas_device = "/class/sas_device/"; +static const char * sas_end_device = "/class/sas_end_device/"; +static const char * fc_host = "/class/fc_host/"; +static const char * fc_transport = "/class/fc_transport/"; +static const char * iscsi_host = "/class/iscsi_host/"; +static const char * iscsi_session = "/class/iscsi_session/"; static const char * dev_dir = "/dev"; @@ -53,6 +81,7 @@ struct lsscsi_opt_coll { int generic; int dev_maj_min; /* --device */ int kname; + int transport; int verbose; }; @@ -104,9 +133,10 @@ static struct option long_options[] = { {"hosts", 0, 0, 'H'}, {"kname", 0, 0, 'k'}, {"long", 0, 0, 'l'}, + {"list", 0, 0, 'L'}, /* {"name", 0, 0, 'n'}, */ /* {"sysfsroot", 1, 0, 'y'}, */ -/* {"transport", 0, 0, 't'}, */ + {"transport", 0, 0, 't'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0} @@ -130,6 +160,23 @@ struct dev_node_list { }; static struct dev_node_list* dev_node_listhead = NULL; +struct sg_item_t { + char name[NAME_LEN_MAX]; + int ft; +}; + +static struct sg_item_t non_sg; +static struct sg_item_t aa_sg; + +static char sas_low_phy[NAME_LEN_MAX]; +static char sas_hold_end_device[NAME_LEN_MAX]; + +static const char * iscsi_dir_name; +static const struct addr_hctl * iscsi_target_hct; +static int iscsi_tsession_num; + + + static int cmp_hctl(const struct addr_hctl * le, const struct addr_hctl * ri) { if (le->h == ri->h) { @@ -159,26 +206,211 @@ static void usage() { fprintf(stderr, "Usage: lsscsi [--classic] [--device] [--generic]" " [--help] [--hosts]\n" - "\t\t[--kname] [--long] [--verbose]" - " [--version]\n" - "\t\t[<h:c:t:l>]\n"); - fprintf(stderr, "\t--classic|-c alternate output similar " + "\t\t[--kname] [--list] [--long] [--transport] " + "[--verbose]\n" + "\t\t[--version] [<h:c:t:l>]\n"); + fprintf(stderr, " where:\n"); + fprintf(stderr, " --classic|-c alternate output similar " "to 'cat /proc/scsi/scsi'\n"); - fprintf(stderr, "\t--device|-d show device node's major + minor" - " numbers\n"); - fprintf(stderr, "\t--generic|-g show scsi generic device name\n"); - fprintf(stderr, "\t--help|-h this usage information\n"); - fprintf(stderr, "\t--hosts|-H lists scsi hosts rather than scsi " - "devices\n"); - fprintf(stderr, "\t--kname|-k show kernel name instead of device" - " node name\n"); - fprintf(stderr, "\t--long|-l additional information output\n"); -/* fprintf(stderr, "\t--transport|-t output transport information\n"); */ - fprintf(stderr, "\t--verbose|-v output path names where data " + fprintf(stderr, " --device|-d show device node's major + " + "minor numbers\n"); + fprintf(stderr, " --generic|-g show scsi generic device " + "name\n"); + fprintf(stderr, " --help|-h this usage information\n"); + fprintf(stderr, " --hosts|-H lists scsi hosts rather than " + "scsi devices\n"); + fprintf(stderr, " --kname|-k show kernel name instead of " + "device node name\n"); + fprintf(stderr, " --list|-L additional information " + "output one\n"); + fprintf(stderr, " attribute=value per line\n"); + fprintf(stderr, " --long|-l additional information " + "output\n"); + fprintf(stderr, " --transport|-t transport information for " + "target or, if '--hosts'\n" + " given, for initiator\n"); + fprintf(stderr, " --verbose|-v output path names where data " "is found\n"); - fprintf(stderr, "\t--version|-V output version string and exit\n"); - fprintf(stderr, "\t<h:c:t:l> filter output list (def: " - "'- - - -' (all))\n"); + fprintf(stderr, " --version|-V output version string and " + "exit\n"); + fprintf(stderr, " <h:c:t:l> filter output list (def: " + "'- - - -' (all))\n\n"); + fprintf(stderr, "List SCSI devices or hosts\n"); +} + +static int non_sg_scandir_select(const struct dirent * s) +{ + int len; + + if (FT_OTHER != non_sg.ft) + return 0; + if (DT_LNK != s->d_type) + return 0; + if (0 == strncmp("scsi_changer", s->d_name, 12)) { + strncpy(non_sg.name, s->d_name, NAME_LEN_MAX); + non_sg.ft = FT_CHAR; + return 1; + } else if (0 == strncmp("block", s->d_name, 5)) { + strncpy(non_sg.name, s->d_name, NAME_LEN_MAX); + non_sg.ft = FT_BLOCK; + return 1; + } else if (0 == strcmp("tape", s->d_name)) { + strcpy(non_sg.name, s->d_name); + non_sg.ft = FT_CHAR; + return 1; + } else if (0 == strncmp("scsi_tape:st", s->d_name, 12)) { + len = strlen(s->d_name); + if (isdigit(s->d_name[len - 1])) { + /* want 'st<num>' symlink only */ + strcpy(non_sg.name, s->d_name); + non_sg.ft = FT_CHAR; + return 1; + } else + return 0; + } else if (0 == strncmp("onstream_tape:os", s->d_name, 16)) { + strcpy(non_sg.name, s->d_name); + non_sg.ft = FT_CHAR; + return 1; + } else + return 0; +} + +static int non_sg_scan(const char * dir_name, + const struct lsscsi_opt_coll * opts) +{ + char name[NAME_LEN_MAX]; + struct dirent ** namelist; + int num, k; + + non_sg.ft = FT_OTHER; + num = scandir(dir_name, &namelist, non_sg_scandir_select, NULL); + if (num < 0) { + if (opts->verbose > 0) { + snprintf(name, NAME_LEN_MAX, "scandir: %s", dir_name); + perror(name); + } + return -1; + } + for (k = 0; k < num; ++k) + free(namelist[k]); + free(namelist); + return num; +} + + +static int sg_scandir_select(const struct dirent * s) +{ + if (FT_OTHER != aa_sg.ft) + return 0; + if (DT_LNK != s->d_type) + return 0; + if (0 == strncmp("scsi_generic", s->d_name, 12)) { + strncpy(aa_sg.name, s->d_name, NAME_LEN_MAX); + aa_sg.ft = FT_CHAR; + return 1; + } else + return 0; +} + +static int sg_scan(const char * dir_name) +{ + struct dirent ** namelist; + int num, k; + + aa_sg.ft = FT_OTHER; + num = scandir(dir_name, &namelist, sg_scandir_select, NULL); + if (num < 0) + return -1; + for (k = 0; k < num; ++k) + free(namelist[k]); + free(namelist); + return num; +} + + +static int sas_low_phy_scandir_select(const struct dirent * s) +{ + char * cp; + int n, m; + + if ((DT_LNK != s->d_type) && (DT_DIR != s->d_type)) + return 0; + if (0 == strncmp("phy", s->d_name, 3)) { + if (0 == strlen(sas_low_phy)) + strncpy(sas_low_phy, s->d_name, NAME_LEN_MAX); + else { + cp = strrchr(s->d_name, ':'); + if (NULL == cp) + return 0; + n = atoi(cp + 1); + cp = strrchr(sas_low_phy, ':'); + if (NULL == cp) + return 0; + m = atoi(cp + 1); + if (n < m) + strncpy(sas_low_phy, s->d_name, + NAME_LEN_MAX); + } + return 1; + } else + return 0; +} + +static int sas_low_phy_scan(const char * dir_name) +{ + struct dirent ** namelist; + int num, k; + + memset(sas_low_phy, 0, sizeof(sas_low_phy)); + num = scandir(dir_name, &namelist, sas_low_phy_scandir_select, NULL); + if (num < 0) + return -1; + for (k = 0; k < num; ++k) + free(namelist[k]); + free(namelist); + return num; +} + + +static int iscsi_target_scandir_select(const struct dirent * s) +{ + char buff[NAME_LEN_MAX]; + int off; + struct stat a_stat; + + if ((DT_LNK != s->d_type) && (DT_DIR != s->d_type)) + return 0; + if (0 == strncmp("session", s->d_name, 7)) { + iscsi_tsession_num = atoi(s->d_name + 7); + strcpy(buff, iscsi_dir_name); + off = strlen(buff); + snprintf(buff + off, sizeof(buff) - off, + "/%s/target%d:%d:%d", s->d_name, iscsi_target_hct->h, + iscsi_target_hct->c, iscsi_target_hct->t); + if ((stat(buff, &a_stat) >= 0) && S_ISDIR(a_stat.st_mode)) + return 1; + else + return 0; + } else + return 0; +} + +static int iscsi_target_scan(const char * dir_name, + const struct addr_hctl * hctl) +{ + struct dirent ** namelist; + int num, k; + + iscsi_dir_name = dir_name; + iscsi_target_hct = hctl; + iscsi_tsession_num = -1; + num = scandir(dir_name, &namelist, iscsi_target_scandir_select, NULL); + if (num < 0) + return -1; + for (k = 0; k < num; ++k) + free(namelist[k]); + free(namelist); + return num; } @@ -243,6 +475,37 @@ static int if_directory_chdir(const char return 0; } +/* Return 1 if directory, else 0 */ +static int if_directory_ch2generic(const char * dir_name) +{ + char buff[NAME_LEN_MAX]; + struct stat a_stat; + const char * old_name = "generic"; + + strcpy(buff, dir_name); + strcat(buff, "/"); + strcat(buff, old_name); + if ((stat(buff, &a_stat) >= 0) && S_ISDIR(a_stat.st_mode)) { + if (chdir(buff) < 0) + return 0; + return 1; + } + /* No "generic", so now look for "scsi_generic:sg<n>" */ + if (1 != sg_scan(dir_name)) + return 0; + strcpy(buff, dir_name); + strcat(buff, "/"); + strcat(buff, aa_sg.name); + if (stat(buff, &a_stat) < 0) + return 0; + if (S_ISDIR(a_stat.st_mode)) { + if (chdir(buff) < 0) + return 0; + return 1; + } + return 0; +} + /* Return 1 if found, else 0 if problems */ static int get_value(const char * dir_name, const char * base_name, char * value, int max_value_len) @@ -258,8 +521,10 @@ static int get_value(const char * dir_na return 0; } if (NULL == fgets(value, max_value_len, f)) { + /* assume empty */ + value[0] = '\0'; fclose(f); - return 0; + return 1; } len = strlen(value); if ((len > 0) && (value[len - 1] == '\n')) @@ -438,11 +703,637 @@ static int parse_colon_list(const char * return 1; } -static void longer_entry(const char * path_name, - const struct lsscsi_opt_coll * opts) +/* Fetch initiator (port) wwn(s) or identifier if available. Return 1 if + successful, 0 otherwise */ +static int transport_init(const char * devname, + /* const struct lsscsi_opt_coll * opts, */ + int b_len, char * b) +{ + char buff[NAME_LEN_MAX]; + int off; + struct stat a_stat; + + /* SPI host */ + strcpy(buff, sysfsroot); + strcat(buff, spi_host); + strcat(buff, devname); + if ((stat(buff, &a_stat) >= 0) && S_ISDIR(a_stat.st_mode)) { + transport_id = TRANSPORT_SPI; + snprintf(b, b_len, "spi:"); + return 1; + } + + /* FC host */ + strcpy(buff, sysfsroot); + strcat(buff, fc_host); + strcat(buff, devname); + if ((stat(buff, &a_stat) >= 0) && S_ISDIR(a_stat.st_mode)) { + transport_id = TRANSPORT_FC; + snprintf(b, b_len, "fc:"); + off = strlen(b); + if (get_value(buff, "port_name", b + off, b_len - off)) { + strcat(b, ","); + off = strlen(b); + } else + return 0; + if (get_value(buff, "port_id", b + off, b_len - off)) + return 1; + else + return 0; + } + + /* SAS host */ + /* SAS transport layer representation */ + strcpy(buff, sysfsroot); + strcat(buff, sas_host); + strcat(buff, devname); + if ((stat(buff, &a_stat) >= 0) && S_ISDIR(a_stat.st_mode)) { + transport_id = TRANSPORT_SAS; + strcat(buff, "/device"); + if (sas_low_phy_scan(buff) < 1) + return 0; + strcpy(buff, sysfsroot); + strcat(buff, sas_phy); + strcat(buff, sas_low_phy); + snprintf(b, b_len, "sas:"); + off = strlen(b); + if (get_value(buff, "sas_address", b + off, b_len - off)) + return 1; + else + fprintf(stderr, "_init: no sas_address, wd=%s\n", + buff); + } + + /* SAS class representation */ + strcpy(buff, sysfsroot); + strcat(buff, scsi_host); + strcat(buff, "/"); + strcat(buff, devname); + strcat(buff, "/device/sas/ha"); + if ((stat(buff, &a_stat) >= 0) && S_ISDIR(a_stat.st_mode)) { + transport_id = TRANSPORT_SAS_CLASS; + snprintf(b, b_len, "sas:"); + off = strlen(b); + if (get_value(buff, "device_name", b + off, b_len - off)) + return 1; + else + fprintf(stderr, "_init: no device_name, wd=%s\n", + buff); + } + + /* SBP (FireWire) host */ + do { + char *t, buff2[NAME_LEN_MAX]; + + /* resolve SCSI host device */ + strcpy(buff, sysfsroot); + strcat(buff, scsi_host); + strcat(buff, "/"); + strcat(buff, devname); + strcat(buff, "/device"); + if (readlink(buff, buff2, sizeof(buff2)) <= 0) + break; + + /* check if the SCSI host has a FireWire host as ancestor */ + if (!(t = strstr(buff2, "/fw-host"))) + break; + transport_id = TRANSPORT_SBP; + + /* terminate buff2 after FireWire host */ + if (!(t = strchr(t+1, '/'))) + break; + *t = 0; + + /* resolve FireWire host device */ + buff[strlen(buff) - strlen("device")] = 0; + if (strlen(buff) + strlen(buff2) + strlen("host_id/guid") + 2 + > NAME_LEN_MAX) + break; + strcat(buff, buff2); + + /* read the FireWire host's EUI-64 */ + if (!get_value(buff, "host_id/guid", buff2, sizeof(buff)) || + strlen(buff2) != 18) + break; + snprintf(b, b_len, "sbp:%s", buff2 + 2); + return 1; + } while (0); + + /* iSCSI host */ + strcpy(buff, sysfsroot); + strcat(buff, iscsi_host); + strcat(buff, devname); + if ((stat(buff, &a_stat) >= 0) && S_ISDIR(a_stat.st_mode)) { + transport_id = TRANSPORT_ISCSI; + snprintf(b, b_len, "iscsi:"); +// >>> Can anything useful be placed after "iscsi:" in single line +// host output? +// Hmmm, probably would like SAM-4 ",i,0x" notation here. + return 1; + } + return 0; +} + +static void transport_init_longer(const char * path_name, + const struct lsscsi_opt_coll * opts) +{ + char buff[NAME_LEN_MAX]; + char wd[NAME_LEN_MAX]; + char value[NAME_LEN_MAX]; + char * cp; + + strcpy(buff, path_name); + strcpy(wd, path_name); + cp = basename(wd); + switch (transport_id) { + case TRANSPORT_SPI: + printf(" transport=spi\n"); + strcpy(buff, sysfsroot); + strcat(buff, spi_host); + strcat(buff, cp); + if (get_value(buff, "signalling", value, NAME_LEN_MAX)) + printf(" signalling=%s\n", value); + break; + case TRANSPORT_FC: + printf(" transport=fc\n"); + strcat(buff, "/device/fc_host:"); + strcat(buff, cp); + if (get_value(buff, "node_name", value, NAME_LEN_MAX)) + printf(" node_name=%s\n", value); + if (get_value(buff, "port_name", value, NAME_LEN_MAX)) + printf(" port_name=%s\n", value); + if (get_value(buff, "port_id", value, NAME_LEN_MAX)) + printf(" port_id=%s\n", value); + if (get_value(buff, "port_type", value, NAME_LEN_MAX)) + printf(" port_type=%s\n", value); + if (get_value(buff, "speed", value, NAME_LEN_MAX)) + printf(" speed=%s\n", value); + if (get_value(buff, "supported_classes", value, NAME_LEN_MAX)) + printf(" supported_classes=%s\n", value); + if (get_value(buff, "tgtid_bind_type", value, NAME_LEN_MAX)) + printf(" tgtid_bind_type=%s\n", value); + if (opts->verbose > 2) + printf("fetched from directory: %s\n", buff); + break; + case TRANSPORT_SAS: + printf(" transport=sas\n"); + strcat(buff, "/device"); + if (sas_low_phy_scan(buff) < 1) + return; + strcpy(buff, sysfsroot); + strcat(buff, sas_phy); + strcat(buff, sas_low_phy); + if (get_value(buff, "device_type", value, NAME_LEN_MAX)) + printf(" device_type=%s\n", value); + if (get_value(buff, "initiator_port_protocols", value, + NAME_LEN_MAX)) + printf(" initiator_port_protocols=%s\n", value); + if (get_value(buff, "invalid_dword_count", value, + NAME_LEN_MAX)) + printf(" invalid_dword_count=%s\n", value); + if (get_value(buff, "loss_of_dword_sync_count", value, + NAME_LEN_MAX)) + printf(" loss_of_dword_sync_count=%s\n", value); + if (get_value(buff, "maximum_linkrate", value, NAME_LEN_MAX)) + printf(" maximum_linkrate=%s\n", value); + if (get_value(buff, "maximum_linkrate_hw", value, + NAME_LEN_MAX)) + printf(" maximum_linkrate_hw=%s\n", value); + if (get_value(buff, "minimum_linkrate", value, NAME_LEN_MAX)) + printf(" minimum_linkrate=%s\n", value); + if (get_value(buff, "minimum_linkrate_hw", value, + NAME_LEN_MAX)) + printf(" minimum_linkrate_hw=%s\n", value); + if (get_value(buff, "negotiated_linkrate", value, + NAME_LEN_MAX)) + printf(" negotiated_linkrate=%s\n", value); + if (get_value(buff, "phy_identifier", value, NAME_LEN_MAX)) + printf(" phy_identifier=%s\n", value); + if (get_value(buff, "phy_reset_problem_count", value, + NAME_LEN_MAX)) + printf(" phy_reset_problem_count=%s\n", value); + if (get_value(buff, "running_disparity_error_count", value, + NAME_LEN_MAX)) + printf(" running_disparity_error_count=%s\n", value); + if (get_value(buff, "sas_address", value, NAME_LEN_MAX)) + printf(" sas_address=%s\n", value); + if (get_value(buff, "target_port_protocols", value, + NAME_LEN_MAX)) + printf(" target_port_protocols=%s\n", value); + if (opts->verbose > 2) + printf("fetched from directory: %s\n", buff); + break; + case TRANSPORT_SAS_CLASS: + printf(" transport=sas\n"); + printf(" sub_transport=sas_class\n"); + strcat(buff, "/device/sas/ha"); + if (get_value(buff, "device_name", value, NAME_LEN_MAX)) + printf(" device_name=%s\n", value); + if (get_value(buff, "ha_name", value, NAME_LEN_MAX)) + printf(" ha_name=%s\n", value); + if (get_value(buff, "version_descriptor", value, NAME_LEN_MAX)) + printf(" version_descriptor=%s\n", value); + printf(" phy0:\n"); + strcat(buff, "/phys/0"); + if (get_value(buff, "class", value, NAME_LEN_MAX)) + printf(" class=%s\n", value); + if (get_value(buff, "enabled", value, NAME_LEN_MAX)) + printf(" enabled=%s\n", value); + if (get_value(buff, "id", value, NAME_LEN_MAX)) + printf(" id=%s\n", value); + if (get_value(buff, "iproto", value, NAME_LEN_MAX)) + printf(" iproto=%s\n", value); + if (get_value(buff, "linkrate", value, NAME_LEN_MAX)) + printf(" linkrate=%s\n", value); + if (get_value(buff, "oob_mode", value, NAME_LEN_MAX)) + printf(" oob_mode=%s\n", value); + if (get_value(buff, "role", value, NAME_LEN_MAX)) + printf(" role=%s\n", value); + if (get_value(buff, "sas_addr", value, NAME_LEN_MAX)) + printf(" sas_addr=%s\n", value); + if (get_value(buff, "tproto", value, NAME_LEN_MAX)) + printf(" tproto=%s\n", value); + if (get_value(buff, "type", value, NAME_LEN_MAX)) + printf(" type=%s\n", value); + if (opts->verbose > 2) + printf("fetched from directory: %s\n", buff); + break; + case TRANSPORT_ISCSI: + printf(" transport=iSCSI\n"); +// >>> This is the multi-line host output for iSCSI. Anymore to +// add here? [From /sys/class/scsi_host/hostN/device/iscsi_host:hostN directory] + break; + case TRANSPORT_SBP: + printf(" transport=sbp\n"); + break; + default: + if (opts->verbose > 1) + fprintf(stderr, "No transport information\n"); + break; + } +} + +/* Fetch target port wwn(s) or identifier if available. Return 1 if + successful, 0 otherwise */ +static int transport_tport(const char * devname, + /* const struct lsscsi_opt_coll * opts, */ + int b_len, char * b) +{ + char buff[NAME_LEN_MAX]; + char wd[NAME_LEN_MAX]; + char nm[NAME_LEN_MAX]; + char tpgt[NAME_LEN_MAX]; + char * cp; + struct addr_hctl hctl; + int len, off, n; + struct stat a_stat; + + if (! parse_colon_list(devname, &hctl)) + return 0; + /* SAS host? */ + strcpy(buff, sysfsroot); + strcat(buff, sas_host); + len = strlen(buff); + snprintf(buff + len, NAME_LEN_MAX - len, "host%d", hctl.h); + if ((stat(buff, &a_stat) >= 0) && S_ISDIR(a_stat.st_mode)) { + /* SAS transport layer representation */ + transport_id = TRANSPORT_SAS; + strcpy(buff, sysfsroot); + strcat(buff, class_scsi_dev); + strcat(buff, devname); + if (if_directory_chdir(buff, "device")) { + if (NULL == getcwd(wd, NAME_LEN_MAX)) + return 0; + cp = strrchr(wd, '/'); + if (NULL == cp) + return 0; + *cp = '\0'; + cp = strrchr(wd, '/'); + if (NULL == cp) + return 0; + *cp = '\0'; + cp = basename(wd); + strcpy(sas_hold_end_device, cp); + strcpy(buff, sysfsroot); + strcat(buff, sas_device); + strcat(buff, cp); + snprintf(b, b_len, "sas:"); + off = strlen(b); + if (get_value(buff, "sas_address", b + off, + b_len - off)) + return 1; + else + fprintf(stderr, "_tport: no " + "sas_address, wd=%s\n", buff); + } else + fprintf(stderr, "_tport: down FAILED: %s\n", buff); + return 0; + } + /* SPI host? */ + strcpy(buff, sysfsroot); + strcat(buff, spi_host); + len = strlen(buff); + snprintf(buff + len, NAME_LEN_MAX - len, "host%d", hctl.h); + if ((stat(buff, &a_stat) >= 0) && S_ISDIR(a_stat.st_mode)) { + transport_id = TRANSPORT_SPI; + snprintf(b, b_len, "spi:%d", hctl.t); + return 1; + } + /* FC host? */ + strcpy(buff, sysfsroot); + strcat(buff, fc_host); + len = strlen(buff); + snprintf(buff + len, NAME_LEN_MAX - len, "host%d", hctl.h); + if ((stat(buff, &a_stat) >= 0) && S_ISDIR(a_stat.st_mode)) { + transport_id = TRANSPORT_FC; + strcpy(buff, sysfsroot); + strcat(buff, fc_transport); + len = strlen(buff); + snprintf(buff + len, NAME_LEN_MAX - len, "target%d:%d:%d", + hctl.h, hctl.c, hctl.t); + snprintf(b, b_len, "fc:"); + off = strlen(b); + if (get_value(buff, "port_name", b + off, b_len - off)) { + strcat(b, ","); + off = strlen(b); + } else + return 0; + if (get_value(buff, "port_id", b + off, b_len - off)) + return 1; + else + return 0; + } + /* SAS class representation or SBP? */ + strcpy(buff, sysfsroot); + strcat(buff, bus_scsi_devs); + strcat(buff, "/"); + strcat(buff, devname); + if (if_directory_chdir(buff, "sas_device")) { + transport_id = TRANSPORT_SAS_CLASS; + snprintf(b, b_len, "sas:"); + off = strlen(b); + if (get_value(".", "sas_addr", b + off, b_len - off)) + return 1; + else + fprintf(stderr, "_tport: no sas_addr, " + "wd=%s\n", buff); + } else if (get_value(buff, "ieee1394_id", wd, sizeof(wd))) { + /* IEEE1394 SBP device */ + transport_id = TRANSPORT_SBP; + snprintf(b, b_len, "sbp:%s", wd); + return 1; + } + /* iSCSI device? */ + strcpy(buff, sysfsroot); + strcat(buff, iscsi_host); + off = strlen(buff); + snprintf(buff + off, sizeof(buff) - off, "host%d/device", hctl.h); + if ((stat(buff, &a_stat) >= 0) && S_ISDIR(a_stat.st_mode)) { + if (1 != iscsi_target_scan(buff, &hctl)) + return 0; + transport_id = TRANSPORT_ISCSI; + strcpy(buff, sysfsroot); + strcat(buff, iscsi_session); + off = strlen(buff); + snprintf(buff + off, sizeof(buff) - off, "session%d", + iscsi_tsession_num); + if (! get_value(buff, "targetname", nm, sizeof(nm))) + return 0; + if (! get_value(buff, "tpgt", tpgt, sizeof(tpgt))) + return 0; + n = atoi(tpgt); + // output target port name as per sam4r08, annex A, table A.3 + snprintf(b, b_len, "%s,t,0x%x", nm, n); +// >>> That reference says maximum length of targetname is 223 bytes +// (UTF-8) excluding trailing null. + return 1; + } + return 0; +} + +static void transport_tport_longer(const char * devname, + const struct lsscsi_opt_coll * opts) { + char path_name[NAME_LEN_MAX]; + char buff[NAME_LEN_MAX]; + char b2[NAME_LEN_MAX]; + char wd[NAME_LEN_MAX]; char value[NAME_LEN_MAX]; + struct addr_hctl hctl; + int len, off; + char * cp; + +#if 0 + strcpy(buff, path_name); + len = strlen(buff); + snprintf(buff + len, NAME_LEN_MAX - len, "/scsi_device:%s", devname); + if (! if_directory_chdir(buff, "device")) + return; + if (NULL == getcwd(wd, NAME_LEN_MAX)) + return; +#else + strcpy(path_name, sysfsroot); + strcat(path_name, class_scsi_dev); + strcat(path_name, devname); + strcat(buff, path_name); +#endif + switch (transport_id) { + case TRANSPORT_SPI: + printf(" transport=spi\n"); + if (! parse_colon_list(devname, &hctl)) + break; + strcpy(buff, sysfsroot); + strcat(buff, spi_transport); + len = strlen(buff); + snprintf(buff + len, NAME_LEN_MAX - len, "target%d:%d:%d", + hctl.h, hctl.c, hctl.t); + printf(" target_id=%d\n", hctl.t); + if (get_value(buff, "dt", value, NAME_LEN_MAX)) + printf(" dt=%s\n", value); + if (get_value(buff, "max_offset", value, NAME_LEN_MAX)) + printf(" max_offset=%s\n", value); + if (get_value(buff, "max_width", value, NAME_LEN_MAX)) + printf(" max_width=%s\n", value); + if (get_value(buff, "min_period", value, NAME_LEN_MAX)) + printf(" min_period=%s\n", value); + if (get_value(buff, "offset", value, NAME_LEN_MAX)) + printf(" offset=%s\n", value); + if (get_value(buff, "period", value, NAME_LEN_MAX)) + printf(" period=%s\n", value); + if (get_value(buff, "width", value, NAME_LEN_MAX)) + printf(" width=%s\n", value); + break; + case TRANSPORT_FC: + printf(" transport=fc\n"); + if (! if_directory_chdir(path_name, "device")) + return; + if (NULL == getcwd(wd, NAME_LEN_MAX)) + return; + cp = strrchr(wd, '/'); + if (NULL == cp) + return; + *cp = '\0'; + cp = strrchr(wd, '/'); + if (NULL == cp) + return; + *cp = '\0'; + cp = basename(wd); + strcpy(buff, "fc_remote_ports:"); + strcat(buff, cp); + if (! if_directory_chdir(wd, buff)) + return; + if (NULL == getcwd(buff, NAME_LEN_MAX)) + return; + if (get_value(buff, "node_name", value, NAME_LEN_MAX)) + printf(" node_name=%s\n", value); + if (get_value(buff, "port_name", value, NAME_LEN_MAX)) + printf(" port_name=%s\n", value); + if (get_value(buff, "port_id", value, NAME_LEN_MAX)) + printf(" port_id=%s\n", value); + if (get_value(buff, "port_state", value, NAME_LEN_MAX)) + printf(" port_state=%s\n", value); + if (get_value(buff, "roles", value, NAME_LEN_MAX)) + printf(" roles=%s\n", value); + if (get_value(buff, "scsi_target_id", value, NAME_LEN_MAX)) + printf(" scsi_target_id=%s\n", value); + if (get_value(buff, "supported_classes", value, NAME_LEN_MAX)) + printf(" supported_classes=%s\n", value); + if (get_value(buff, "dev_loss_tmo", value, NAME_LEN_MAX)) + printf(" dev_loss_tmo=%s\n", value); + if (opts->verbose > 2) + printf("fetched from directory: %s\n", buff); + break; + case TRANSPORT_SAS: + printf(" transport=sas\n"); + strcpy(buff, sysfsroot); + strcat(buff, sas_device); + strcat(buff, sas_hold_end_device); + strcpy(b2, sysfsroot); + strcat(b2, sas_end_device); + strcat(b2, sas_hold_end_device); + if (get_value(buff, "initiator_port_protocols", value, + NAME_LEN_MAX)) + printf(" initiator_port_protocols=%s\n", value); + if (get_value(b2, "initiator_response_timeout", value, + NAME_LEN_MAX)) + printf(" initiator_response_timeout=%s\n", value); + if (get_value(b2, "I_T_nexus_loss_timeout", value, + NAME_LEN_MAX)) + printf(" I_T_nexus_loss_timeout=%s\n", value); + if (get_value(buff, "phy_identifier", value, NAME_LEN_MAX)) + printf(" phy_identifier=%s\n", value); + if (get_value(b2, "ready_led_meaning", value, NAME_LEN_MAX)) + printf(" ready_led_meaning=%s\n", value); + if (get_value(buff, "sas_address", value, NAME_LEN_MAX)) + printf(" sas_address=%s\n", value); + if (get_value(buff, "target_port_protocols", value, + NAME_LEN_MAX)) + printf(" target_port_protocols=%s\n", value); + if (opts->verbose > 2) { + printf("fetched from directory: %s\n", buff); + printf("fetched from directory: %s\n", b2); + } + break; + case TRANSPORT_SAS_CLASS: + printf(" transport=sas\n"); + printf(" sub_transport=sas_class\n"); + strcpy(buff, path_name); + strcat(buff, "/device/sas_device"); + if (get_value(buff, "device_name", value, NAME_LEN_MAX)) + printf(" device_name=%s\n", value); + if (get_value(buff, "dev_type", value, NAME_LEN_MAX)) + printf(" dev_type=%s\n", value); + if (get_value(buff, "iproto", value, NAME_LEN_MAX)) + printf(" iproto=%s\n", value); + if (get_value(buff, "iresp_timeout", value, NAME_LEN_MAX)) + printf(" iresp_timeout=%s\n", value); + if (get_value(buff, "itnl_timeout", value, NAME_LEN_MAX)) + printf(" itnl_timeout=%s\n", value); + if (get_value(buff, "linkrate", value, NAME_LEN_MAX)) + printf(" linkrate=%s\n", value); + if (get_value(buff, "max_linkrate", value, NAME_LEN_MAX)) + printf(" max_linkrate=%s\n", value); + if (get_value(buff, "max_pathways", value, NAME_LEN_MAX)) + printf(" max_pathways=%s\n", value); + if (get_value(buff, "min_linkrate", value, NAME_LEN_MAX)) + printf(" min_linkrate=%s\n", value); + if (get_value(buff, "pathways", value, NAME_LEN_MAX)) + printf(" pathways=%s\n", value); + if (get_value(buff, "ready_led_meaning", value, NAME_LEN_MAX)) + printf(" ready_led_meaning=%s\n", value); + if (get_value(buff, "rl_wlun", value, NAME_LEN_MAX)) + printf(" rl_wlun=%s\n", value); + if (get_value(buff, "sas_addr", value, NAME_LEN_MAX)) + printf(" sas_addr=%s\n", value); + if (get_value(buff, "tproto", value, NAME_LEN_MAX)) + printf(" tproto=%s\n", value); + if (get_value(buff, "transport_layer_retries", value, + NAME_LEN_MAX)) + printf(" transport_layer_retries=%s\n", value); + if (opts->verbose > 2) + printf("fetched from directory: %s\n", buff); + break; + case TRANSPORT_ISCSI: + printf(" transport=iSCSI\n"); + strcpy(buff, sysfsroot); + strcat(buff, iscsi_session); + off = strlen(buff); + snprintf(buff + off, sizeof(buff) - off, "session%d", + iscsi_tsession_num); + if (get_value(buff, "targetname", value, NAME_LEN_MAX)) + printf(" targetname=%s\n", value); + if (get_value(buff, "tpgt", value, NAME_LEN_MAX)) + printf(" tpgt=%s\n", value); + if (get_value(buff, "data_pdu_in_order", value, NAME_LEN_MAX)) + printf(" data_pdu_in_order=%s\n", value); + if (get_value(buff, "data_seq_in_order", value, NAME_LEN_MAX)) + printf(" data_seq_in_order=%s\n", value); + if (get_value(buff, "erl", value, NAME_LEN_MAX)) + printf(" erl=%s\n", value); + if (get_value(buff, "first_burst_len", value, NAME_LEN_MAX)) + printf(" first_burst_len=%s\n", value); + if (get_value(buff, "initial_r2t", value, NAME_LEN_MAX)) + printf(" initial_r2t=%s\n", value); + if (get_value(buff, "max_burst_len", value, NAME_LEN_MAX)) + printf(" max_burst_len=%s\n", value); + if (get_value(buff, "max_outstanding_r2t", value, NAME_LEN_MAX)) + printf(" max_outstanding_r2t=%s\n", value); + if (get_value(buff, "recovery_tmo", value, NAME_LEN_MAX)) + printf(" recovery_tmo=%s\n", value); +// >>> Would like to see what are readable attributes in this directory. +// Ignoring connections for the time being. Could add with an entry +// for connection=<n> with normal two space indent followed by attributes +// for that connection indented 4 spaces + if (opts->verbose > 2) + printf("fetched from directory: %s\n", buff); + break; + case TRANSPORT_SBP: + printf(" transport=sbp\n"); + if (! if_directory_chdir(path_name, "device")) + return; + if (NULL == getcwd(buff, NAME_LEN_MAX)) + return; + if (get_value(buff, "ieee1394_id", value, NAME_LEN_MAX)) + printf(" ieee1394_id=%s\n", value); + if (opts->verbose > 2) + printf("fetched from directory: %s\n", buff); + break; + default: + if (opts->verbose > 1) + fprintf(stderr, "No transport information\n"); + break; + } +} +static void longer_d_entry(const char * path_name, const char * devname, + const struct lsscsi_opt_coll * opts) +{ + char value[NAME_LEN_MAX]; + + if (opts->transport > 0) { + transport_tport_longer(devname, opts); + return; + } if (opts->long_opt >= 3) { if (get_value(path_name, "device_blocked", value, NAME_LEN_MAX)) @@ -602,7 +1493,7 @@ static void one_classic_sdev_entry(const printf("ANSI SCSI revision: %02x\n", (scsi_level - 1) ? scsi_level - 1 : 1); if (opts->generic) { - if (if_directory_chdir(buff, "generic")) { + if (if_directory_ch2generic(buff)) { char wd[NAME_LEN_MAX]; if (NULL == getcwd(wd, NAME_LEN_MAX)) @@ -623,70 +1514,11 @@ static void one_classic_sdev_entry(const printf("-\n"); } if (opts->long_opt > 0) - longer_entry(buff, opts); + longer_d_entry(buff, devname, opts); if (opts->verbose) printf(" dir: %s\n", buff); } -#define FT_OTHER 0 -#define FT_BLOCK 1 -#define FT_CHAR 2 - -struct non_sg_item { - char name[NAME_LEN_MAX]; - int ft; -}; - -static struct non_sg_item non_sg; - -static int non_sg_scandir_select(const struct dirent * s) -{ - if (FT_OTHER != non_sg.ft) - return 0; - if (DT_LNK != s->d_type) - return 0; - if (0 == strncmp("scsi_changer", s->d_name, 12)) { - strncpy(non_sg.name, s->d_name, NAME_LEN_MAX); - non_sg.ft = FT_CHAR; - return 1; - } else if (0 == strncmp("block", s->d_name, 5)) { - strncpy(non_sg.name, s->d_name, NAME_LEN_MAX); - non_sg.ft = FT_BLOCK; - return 1; - } else if (0 == strcmp("tape", s->d_name)) { - strcpy(non_sg.name, s->d_name); - non_sg.ft = FT_CHAR; - return 1; - } else if (0 == strncmp("onstream_tape:os", s->d_name, 16)) { - strcpy(non_sg.name, s->d_name); - non_sg.ft = FT_CHAR; - return 1; - } else - return 0; -} - -static int non_sg_scan(const char * dir_name, - const struct lsscsi_opt_coll * opts) -{ - char name[NAME_LEN_MAX]; - struct dirent ** namelist; - int num, k; - - non_sg.ft = FT_OTHER; - num = scandir(dir_name, &namelist, non_sg_scandir_select, NULL); - if (num < 0) { - if (opts->verbose > 0) { - snprintf(name, NAME_LEN_MAX, "scandir: %s", dir_name); - perror(name); - } - return -1; - } - for (k = 0; k < num; ++k) - free(namelist[k]); - free(namelist); - return num; -} - static void one_sdev_entry(const char * dir_name, const char * devname, const struct lsscsi_opt_coll * opts) { @@ -712,20 +1544,28 @@ static void one_sdev_entry(const char * } else printf("%s ", scsi_short_device_types[type]); - if (get_value(buff, "vendor", value, NAME_LEN_MAX)) - printf("%-8s ", value); - else - printf("vendor? "); - - if (get_value(buff, "model", value, NAME_LEN_MAX)) - printf("%-16s ", value); - else - printf("model? "); - - if (get_value(buff, "rev", value, NAME_LEN_MAX)) - printf("%-4s ", value); - else - printf("rev? "); + if (0 == opts->transport) { + if (get_value(buff, "vendor", value, NAME_LEN_MAX)) + printf("%-8s ", value); + else + printf("vendor? "); + + if (get_value(buff, "model", value, NAME_LEN_MAX)) + printf("%-16s ", value); + else + printf("model? "); + + if (get_value(buff, "rev", value, NAME_LEN_MAX)) + printf("%-4s ", value); + else + printf("rev? "); + } else { + if (transport_tport(devname, /* opts, */ + sizeof(value), value)) + printf("%-30s ", value); + else + printf(" "); + } if ((1 == non_sg_scan(buff, opts)) && (if_directory_chdir(buff, non_sg.name))) { @@ -756,7 +1596,7 @@ static void one_sdev_entry(const char * printf("- "); if (opts->generic) { - if (if_directory_chdir(buff, "generic")) { + if (if_directory_ch2generic(buff)) { char wd[NAME_LEN_MAX]; if (NULL == getcwd(wd, NAME_LEN_MAX)) @@ -785,7 +1625,7 @@ static void one_sdev_entry(const char * } printf("\n"); if (opts->long_opt > 0) - longer_entry(buff, opts); + longer_d_entry(buff, devname, opts); if (opts->verbose > 0) { printf(" dir: %s [", buff); if (if_directory_chdir(buff, "")) { @@ -859,7 +1699,7 @@ static void list_sdevices(const struct l int num, k; strcpy(buff, sysfsroot); - strcat(buff, scsi_devs); + strcat(buff, bus_scsi_devs); num = scandir(buff, &namelist, sdev_scandir_select, sdev_scandir_sort); @@ -878,79 +1718,132 @@ static void list_sdevices(const struct l for (k = 0; k < num; ++k) { strncpy(name, namelist[k]->d_name, NAME_LEN_MAX); + transport_id = TRANSPORT_UNKNOWN; one_sdev_entry(buff, name, opts); free(namelist[k]); } free(namelist); } -static void one_host_entry(const char * dir_name, const char * devname, +static void longer_h_entry(const char * path_name, const struct lsscsi_opt_coll * opts) { - char buff[NAME_LEN_MAX]; char value[NAME_LEN_MAX]; - unsigned int host_id; - if (opts->classic) { - // one_classic_host_entry(dir_name, devname, opts); - printf(" <'--classic' not supported for hosts>\n"); + if (opts->transport > 0) { + transport_init_longer(path_name, opts); return; } - if (1 == sscanf(devname, "host%u", &host_id)) - printf("[%u] ", host_id); - else - printf("[?] "); - strcpy(buff, dir_name); - strcat(buff, "/"); - strcat(buff, devname); - if (get_value(buff, "proc_name", value, NAME_LEN_MAX)) - printf(" %-12s\n", value); - else - printf(" proc_name=????\n"); - if (opts->long_opt >= 3) { - if (get_value(buff, "cmd_per_lun", value, NAME_LEN_MAX)) + if (get_value(path_name, "can_queue", value, NAME_LEN_MAX)) + printf(" can_queue=%s\n", value); + else if (opts->verbose) + printf(" can_queue=?\n"); + if (get_value(path_name, "cmd_per_lun", value, NAME_LEN_MAX)) printf(" cmd_per_lun=%s\n", value); else if (opts->verbose) printf(" cmd_per_lun=?\n"); - if (get_value(buff, "host_busy", value, NAME_LEN_MAX)) + if (get_value(path_name, "host_busy", value, NAME_LEN_MAX)) printf(" host_busy=%s\n", value); else if (opts->verbose) printf(" host_busy=?\n"); - if (get_value(buff, "sg_tablesize", value, NAME_LEN_MAX)) + if (get_value(path_name, "sg_tablesize", value, NAME_LEN_MAX)) printf(" sg_tablesize=%s\n", value); else if (opts->verbose) printf(" sg_tablesize=?\n"); - if (get_value(buff, "unchecked_isa_dma", value, NAME_LEN_MAX)) + if (get_value(path_name, "state", value, NAME_LEN_MAX)) + printf(" state=%s\n", value); + else if (opts->verbose) + printf(" state=?\n"); + if (get_value(path_name, "unchecked_isa_dma", value, + NAME_LEN_MAX)) printf(" unchecked_isa_dma=%s\n", value); else if (opts->verbose) printf(" unchecked_isa_dma=?\n"); - if (get_value(buff, "unique_id", value, NAME_LEN_MAX)) + if (get_value(path_name, "unique_id", value, NAME_LEN_MAX)) printf(" unique_id=%s\n", value); else if (opts->verbose) printf(" unique_id=?\n"); } else if (opts->long_opt > 0) { - if (get_value(buff, "cmd_per_lun", value, NAME_LEN_MAX)) + if (get_value(path_name, "cmd_per_lun", value, NAME_LEN_MAX)) printf(" cmd_per_lun=%-4s ", value); else printf(" cmd_per_lun=???? "); - if (get_value(buff, "host_busy", value, NAME_LEN_MAX)) + if (get_value(path_name, "host_busy", value, NAME_LEN_MAX)) printf("host_busy=%-4s ", value); else printf("host_busy=???? "); - if (get_value(buff, "sg_tablesize", value, NAME_LEN_MAX)) + if (get_value(path_name, "sg_tablesize", value, NAME_LEN_MAX)) printf("sg_tablesize=%-4s ", value); else printf("sg_tablesize=???? "); - if (get_value(buff, "unchecked_isa_dma", value, NAME_LEN_MAX)) + if (get_value(path_name, "unchecked_isa_dma", value, + NAME_LEN_MAX)) printf("unchecked_isa_dma=%-2s ", value); else printf("unchecked_isa_dma=?? "); printf("\n"); + if (2 == opts->long_opt) { + if (get_value(path_name, "can_queue", value, + NAME_LEN_MAX)) + printf(" can_queue=%-4s ", value); + if (get_value(path_name, "state", value, NAME_LEN_MAX)) + printf(" state=%-8s ", value); + if (get_value(path_name, "unique_id", value, + NAME_LEN_MAX)) + printf(" unique_id=%-2s ", value); + printf("\n"); + } + } +} + +static void one_host_entry(const char * dir_name, const char * devname, + const struct lsscsi_opt_coll * opts) +{ + char buff[NAME_LEN_MAX]; + char value[NAME_LEN_MAX]; + char * nullname = "<NULL>"; + unsigned int host_id; + + if (opts->classic) { + // one_classic_host_entry(dir_name, devname, opts); + printf(" <'--classic' not supported for hosts>\n"); + return; } + if (1 == sscanf(devname, "host%u", &host_id)) + printf("[%u] ", host_id); + else + printf("[?] "); + strcpy(buff, dir_name); + strcat(buff, "/"); + strcat(buff, devname); + if ((get_value(buff, "proc_name", value, NAME_LEN_MAX)) && + (strncmp(value, nullname, 6))) + printf(" %-12s ", value); + else if (if_directory_chdir(buff, "device/../driver")) { + char wd[NAME_LEN_MAX]; + + if (NULL == getcwd(wd, NAME_LEN_MAX)) + printf(" %-12s ", nullname); + else + printf(" %-12s ", basename(wd)); + + } else + printf(" proc_name=???? "); + if (opts->transport > 0) { + if (transport_init(devname, /* opts, */ sizeof(value), value)) + printf("%s\n", value); + else + printf("\n"); + } else + printf("\n"); + + if (opts->long_opt > 0) + longer_h_entry(buff, opts); + if (opts->verbose > 0) { printf(" dir: %s\n device dir: ", buff); if (if_directory_chdir(buff, "device")) { @@ -967,8 +1860,20 @@ static void one_host_entry(const char * static int host_scandir_select(const struct dirent * s) { - if (0 == strncmp("host", s->d_name, 4)) - return 1; + int h; + + if (0 == strncmp("host", s->d_name, 4)) { + if (filter_active) { + if (-1 == filter.h) + return 1; + else if ((1 == sscanf(s->d_name + 4, "%d", &h) && + (h == filter.h))) + return 1; + else + return 0; + } else + return 1; + } return 0; } @@ -997,7 +1902,7 @@ static void list_hosts(const struct lssc int num, k; strcpy(buff, sysfsroot); - strcat(buff, scsi_hosts); + strcat(buff, scsi_host); num = scandir(buff, &namelist, host_scandir_select, host_scandir_sort); @@ -1011,13 +1916,14 @@ static void list_hosts(const struct lssc for (k = 0; k < num; ++k) { strncpy(name, namelist[k]->d_name, NAME_LEN_MAX); + transport_id = TRANSPORT_UNKNOWN; one_host_entry(buff, name, opts); free(namelist[k]); } free(namelist); } - +/* Return 0 if able to decode, otheriwse 1 */ static int one_filter_arg(const char * arg, struct addr_hctl * filtp) { const char * cp; @@ -1067,6 +1973,7 @@ static int one_filter_arg(const char * a return 0; } +/* Return 0 if able to decode, otheriwse 1 */ static int decode_filter_arg(const char * a1p, const char * a2p, const char * a3p, const char * a4p, struct addr_hctl * filtp) @@ -1083,6 +1990,11 @@ static int decode_filter_arg(const char filtp->c = -1; filtp->t = -1; filtp->l = -1; + if ((0 == strncmp("host", a1p, 4)) && + (1 == sscanf(a1p, "host%d", &n)) && ( n >= 0)) { + filtp->h = n; + return 0; + } if ((NULL == a2p) || strchr(a1p, ':')) return one_filter_arg(a1p, filtp); else { @@ -1129,7 +2041,6 @@ int main(int argc, char **argv) int c; int do_sdevices = 1; int do_hosts = 0; - /* int do_transport = 0; */ struct lsscsi_opt_coll opts; sysfsroot[0] = '\0'; @@ -1138,38 +2049,39 @@ int main(int argc, char **argv) while (1) { int option_index = 0; - c = getopt_long(argc, argv, "cdghHklvV", long_options, + c = getopt_long(argc, argv, "cdghHklLtvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': - opts.classic = 1; + ++opts.classic; break; case 'd': - opts.dev_maj_min = 1; + ++opts.dev_maj_min; break; case 'g': - opts.generic = 1; + ++opts.generic; break; case 'h': usage(); return 0; case 'H': - do_hosts = 1; + ++do_hosts; break; case 'k': - opts.kname = 1; + ++opts.kname; break; case 'l': ++opts.long_opt; break; -#if 0 + case 'L': + opts.long_opt += 3; + break; case 't': - do_transport = 1; + ++opts.transport; break; -#endif case 'v': ++opts.verbose; break; @@ -1220,6 +2132,12 @@ int main(int argc, char **argv) (filter.t != -1) || (filter.l != -1)) filter_active = 1; } + if ((opts.transport > 0) && + ((1 == opts.long_opt) || (2 == opts.long_opt))) { + fprintf(stderr, "please '--list' (rather than '--long') " + "with --transport\n"); + return 1; + } if ('\0' == sysfsroot[0]) { if (! find_sysfsroot()) { fprintf(stderr, "Unable to locate sysfsroot. If " diff -pur lsscsi-0.17/Makefile.in lsscsi-0.19/Makefile.in --- lsscsi-0.17/Makefile.in 2006-02-06 07:52:29.000000000 +0100 +++ lsscsi-0.19/Makefile.in 2007-01-25 21:16:21.000000000 +0100 @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.9.5 from Makefile.am. +# Makefile.in generated by automake 1.9.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, @@ -14,8 +14,6 @@ @SET_MAKE@ -SOURCES = $(lsscsi_SOURCES) - srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@