From 43bdd93a1f8baaf25eed4824d78896d35a930ae4 Mon Sep 17 00:00:00 2001
From: Hannes Reinecke <hare@suse.de>
Date: Thu, 5 Dec 2013 10:37:12 +0100
Subject: [PATCH 2/2] Update to 0.25

Signed-off-by: Hannes Reinecke <hare@suse.de>

diff --git a/lsscsi.8 b/lsscsi.8
index 324066a..7a03a54 100644
--- a/lsscsi.8
+++ b/lsscsi.8
@@ -1,12 +1,13 @@
-.TH lsscsi "8" "November 2009" "lsscsi\-0.23" LSSCSI
+.TH lsscsi "8" "March 2011" "lsscsi\-0.23" LSSCSI
 .SH NAME
 lsscsi \- list SCSI devices (or hosts) and their attributes
 .SH SYNOPSIS
 .B lsscsi
 [\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\-\-protection\fR] [\fI\-\-sysfsroot=PATH\fR] [\fI\-\-transport\fR]
-[\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fIH:C:T:L\fR]
+[\fI\-\-protection\fR] [\fI\-\-protmode\fR] [\fI\-\-size\fR]
+[\fI\-\-sysfsroot=PATH\fR] [\fI\-\-transport\fR] [\fI\-\-verbose\fR]
+[\fI\-\-version\fR] [\fIH:C:T:L\fR]
 .SH DESCRIPTION
 .\" Add any additional description here
 .PP
@@ -76,7 +77,13 @@ outputs SCSI device (host) attributes one per line; preceded by
 two spaces; in the form "<attribute_name>=<value>".
 .TP
 \fB\-p\fR, \fB\-\-protection\fR
-Output additional data integrity (protection) information.
+Output target (DIF) and initiator (DIX) protection types.
+.TP
+\fB\-P\fR, \fB\-\-protmode\fR
+Output effective protection information mode for each disk device.
+.TP
+\fB\-s\fR, \fB\-\-size\fR
+Print disk capacity in human readable form.
 .TP
 \fB\-t\fR, \fB\-\-transport\fR
 Output transport information. This will be a target related information or,
@@ -200,7 +207,7 @@ Written by Doug Gilbert
 .SH "REPORTING BUGS"
 Report bugs to <dgilbert at interlog dot com>.
 .SH COPYRIGHT
-Copyright \(co 2003\-2010 Douglas Gilbert
+Copyright \(co 2003\-2011 Douglas Gilbert
 .br
 This software is distributed under the GPL version 2. There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/lsscsi.c b/lsscsi.c
index 7b5dfea..7cb7ced 100644
--- a/lsscsi.c
+++ b/lsscsi.c
@@ -1,20 +1,21 @@
 /* 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-2009 D. Gilbert
+ *  Copyright (C) 2003-2011 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)
  *  any later version.
  */
 
-#define _XOPEN_SOURCE 500
+#define _XOPEN_SOURCE 600
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
 #endif
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdint.h>
 #include <string.h>
 #include <ctype.h>
 #include <unistd.h>
@@ -26,7 +27,7 @@
 #include <linux/major.h>
 #include <time.h>
 
-static const char * version_str = "0.23  2010/12/23 [svn: r83]";
+static const char * version_str = "0.23  2011/05/09 [svn: r92]";
 
 #define NAME_LEN_MAX 260
 #define FT_OTHER 0
@@ -55,10 +56,12 @@ 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_port = "/class/sas_port/";
 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 * fc_remote_ports = "/class/fc_remote_ports/";
 static const char * iscsi_host = "/class/iscsi_host/";
 static const char * iscsi_session = "/class/iscsi_session/";
 static const char * dev_dir = "/dev";
@@ -83,6 +86,8 @@ struct lsscsi_opt_coll {
         int transport;
         int verbose;
         int protection;         /* data integrity */
+        int protmode;           /* data integrity */
+        int size;
 };
 
 
@@ -125,6 +130,7 @@ static const char * scsi_short_device_types[] =
         "wlun   ", "no dev ",
 };
 
+/* '--name' ('-n') option removed in version 0.11 and can now be reused */
 static struct option long_options[] = {
         {"classic", 0, 0, 'c'},
         {"device", 0, 0, 'd'},
@@ -134,8 +140,9 @@ static struct option long_options[] = {
         {"kname", 0, 0, 'k'},
         {"long", 0, 0, 'l'},
         {"list", 0, 0, 'L'},
-/*      {"name", 0, 0, 'n'},    */
         {"protection", 0, 0, 'p'},
+        {"protmode", 0, 0, 'P'},
+        {"size", 0, 0, 's'},
         {"sysfsroot", 1, 0, 'y'},
         {"transport", 0, 0, 't'},
         {"verbose", 0, 0, 'v'},
@@ -144,6 +151,82 @@ static struct option long_options[] = {
 };
 
 
+static unsigned int
+do_div_rem(uint64_t * np, unsigned int base)
+{
+        unsigned int res;
+
+        res = *np % base;
+        *np /= base;
+        return res;
+}
+
+enum string_size_units {
+        STRING_UNITS_10,        /* use powers of 10^3 (standard SI) */
+        STRING_UNITS_2,         /* use binary powers of 2^10 */
+};
+
+/**
+ * string_get_size - get the size in the specified units
+ * @size:       The size to be converted
+ * @units:      units to use (powers of 1000 or 1024)
+ * @buf:        buffer to format to
+ * @len:        length of buffer
+ *
+ * This function returns a string formatted to 3 significant figures
+ * giving the size in the required units.  Returns 0 on success or
+ * error on failure.  @buf is always zero terminated.
+ *
+ */
+int string_get_size(uint64_t size, const enum string_size_units units,
+                    char *buf, int len)
+{
+        const char *units_10[] = { "B", "kB", "MB", "GB", "TB", "PB",
+                                   "EB", "ZB", "YB", NULL};
+        const char *units_2[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB",
+                                 "EiB", "ZiB", "YiB", NULL };
+        const char **units_str[] = {
+                [STRING_UNITS_10] =  units_10,
+                [STRING_UNITS_2] = units_2,
+        };
+        const unsigned int divisor[] = {
+                [STRING_UNITS_10] = 1000,
+                [STRING_UNITS_2] = 1024,
+        };
+        int i, j;
+        unsigned int res;
+        uint64_t sf_cap;
+        uint64_t remainder = 0;
+        char tmp[8];
+
+        tmp[0] = '\0';
+        i = 0;
+        if (size >= divisor[units]) {
+                while ((size >= divisor[units]) && units_str[units][i]) {
+                        remainder = do_div_rem(&size, divisor[units]);
+                        i++;
+                }
+
+                sf_cap = size;
+                for (j = 0; sf_cap*10 < 1000; j++)
+                        sf_cap *= 10;
+
+                if (j) {
+                        remainder *= 1000;
+                        do_div_rem(&remainder, divisor[units]);
+                        res = remainder;
+                        snprintf(tmp, sizeof(tmp), ".%03u", res);
+                        tmp[j+1] = '\0';
+                }
+        }
+
+        res = size;
+        snprintf(buf, len, "%u%s%s", res, tmp, units_str[units][i]);
+
+        return 0;
+}
+
+
 /* Device node list: contains the information needed to match a node with a
    sysfs class device. */
 #define DEV_NODE_LIST_ENTRIES 16
@@ -170,8 +253,7 @@ struct item_t {
 static struct item_t non_sg;
 static struct item_t aa_sg;
 static struct item_t aa_first;
-static struct item_t aa_sd;
-static struct item_t aa_block;
+static struct item_t enclosure_device;
 
 static char sas_low_phy[NAME_LEN_MAX];
 static char sas_hold_end_device[NAME_LEN_MAX];
@@ -183,8 +265,9 @@ static int iscsi_tsession_num;
 
 static const char * usage_message =
 "Usage: lsscsi   [--classic] [--device] [--generic] [--help] [--hosts]\n"
-            "\t\t[--kname] [--list] [--long] [--protection] [--sysfsroot=PATH]\n"
-            "\t\t[--transport] [--verbose] [--version] [<h:c:t:l>]\n"
+            "\t\t[--kname] [--list] [--long] [--protection] [--size]\n"
+            "\t\t[--sysfsroot=PATH] [--transport] [--verbose] [--version]\n"
+            "\t\t[<h:c:t:l>]\n"
 "  where:\n"
 "    --classic|-c      alternate output similar to 'cat /proc/scsi/scsi'\n"
 "    --device|-d       show device node's major + minor numbers\n"
@@ -195,7 +278,9 @@ static const char * usage_message =
 "    --list|-L         additional information output one\n"
 "                      attribute=value per line\n"
 "    --long|-l         additional information output\n"
-"    --protection|-p   show data integrity (protection) information\n"
+"    --protection|-p   show target and initiator protection information\n"
+"    --protmode|-P     show negotiated protection information mode\n"
+"    --size|-s         show disk size\n"
 "    --sysfsroot=PATH|-y PATH    set sysfs mount point to PATH (def: /sys)\n"
 "    --transport|-t    transport information for target or, if '--hosts'\n"
 "                      given, for initiator\n"
@@ -255,67 +340,133 @@ first_scandir_select(const struct dirent * s)
         return 1;
 }
 
+static int
+sub_scandir_select(const struct dirent * s)
+{
+        if (s->d_type == DT_LNK)
+                return 1;
+
+        if (s->d_type == DT_DIR && s->d_name[0] != '.')
+                return 1;
+
+        return 0;
+}
+
+static int
+sd_scandir_select(const struct dirent * s)
+{
+        if (s->d_type != DT_LNK && s->d_type != DT_DIR)
+                return 0;
+
+        if (s->d_name[0] == '.')
+                return 0;
+
+        if (strstr(s->d_name, "scsi_disk"))
+                return 1;
+
+        return 0;
+}
+
 /* Return 1 for directory entry that is link or directory (other than a
  * directory name starting with dot) that contains "block". Else return 0.
  */
 static int
 block_scandir_select(const struct dirent * s)
 {
-        if ((DT_LNK != s->d_type) &&
-            ((DT_DIR != s->d_type) || ('.' == s->d_name[0])))
+        if (s->d_type != DT_LNK && s->d_type != DT_DIR)
                 return 0;
-        if (strstr(s->d_name, "block")){
-                strncpy(aa_block.name, s->d_name, NAME_LEN_MAX);
-                aa_block.ft = FT_CHAR;  /* dummy */
-                aa_block.d_type =  s->d_type;
-        }
-        return 1;
+
+        if (s->d_name[0] == '.')
+                return 0;
+
+        if (strstr(s->d_name, "block"))
+                return 1;
+
+        return 0;
 }
 
-/* scan for scsi_disk directory in  /sys/bus/scsi/devices/<h:c:i:l> */
+typedef int (* dirent_select_fn) (const struct dirent *);
+
 static int
-block_scan(const char * dir_name, const struct lsscsi_opt_coll * opts)
+sub_scan(char * dir_name, const char * sub_str, dirent_select_fn fn)
 {
-        char name[NAME_LEN_MAX];
         struct dirent ** namelist;
-        int num, k;
+        int num, i;
 
-        num = scandir(dir_name, &namelist, block_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]);
+        num = scandir(dir_name, &namelist, fn, NULL);
+        if (num <= 0)
+                return 0;
+
+        strcat(dir_name, "/");
+        strcat(dir_name, namelist[0]->d_name);
+
+        for (i = 0; i < num; i++)
+                free(namelist[i]);
         free(namelist);
-        return num;
+
+        if (num && strstr(dir_name, sub_str) == 0) {
+
+                num = scandir(dir_name, &namelist, sub_scandir_select, NULL);
+
+                if (num <= 0)
+                        return 0;
+
+                strcat(dir_name, "/");
+                strcat(dir_name, namelist[0]->d_name);
+
+                for (i = 0; i < num; i++)
+                        free(namelist[i]);
+                free(namelist);
+        }
+
+        return 1;
 }
 
+/* Scan for block:sdN or block/sdN directory in
+ * /sys/bus/scsi/devices/h:c:i:l
+ */
 static int
-sd_scandir_select(const struct dirent * s)
+block_scan(char * dir_name)
+{
+        return sub_scan(dir_name, "block:", block_scandir_select);
+}
+
+/* Scan for scsi_disk:h:c:i:l or scsi_disk/h:c:i:l directory in
+ * /sys/bus/scsi/devices/h:c:i:l
+ */
+static int
+sd_scan(char * dir_name)
+{
+        return sub_scan(dir_name, "scsi_disk:", sd_scandir_select);
+}
+
+static int
+enclosure_device_scandir_select(const struct dirent * s)
 {
         if ((DT_LNK != s->d_type) &&
             ((DT_DIR != s->d_type) || ('.' == s->d_name[0])))
                 return 0;
-        if (strstr(s->d_name, "scsi_disk")){
-                strncpy(aa_sd.name, s->d_name, NAME_LEN_MAX);
-                aa_sd.ft = FT_CHAR;  /* dummy */
-                aa_sd.d_type =  s->d_type;
+        if (strstr(s->d_name, "enclosure_device")){
+                strncpy(enclosure_device.name, s->d_name, NAME_LEN_MAX);
+                enclosure_device.ft = FT_CHAR;  /* dummy */
+                enclosure_device.d_type =  s->d_type;
+                return 1;
         }
-        return 1;
+        return 0;
 }
 
+/* Return 1 for directory entry that is link or directory (other than a
+ * directory name starting with dot) that contains "enclosure_device".
+ * Else return 0.
+ */
 static int
-sd_scan(const char * dir_name, const struct lsscsi_opt_coll * opts)
+enclosure_device_scan(const char * dir_name, const struct lsscsi_opt_coll * opts)
 {
         char name[NAME_LEN_MAX];
         struct dirent ** namelist;
         int num, k;
 
-        num = scandir(dir_name, &namelist, sd_scandir_select, NULL);
+        num = scandir(dir_name, &namelist, enclosure_device_scandir_select, NULL);
         if (num < 0) {
                 if (opts->verbose > 0) {
                         snprintf(name, NAME_LEN_MAX, "scandir: %s", dir_name);
@@ -454,6 +605,33 @@ sg_scan(const char * dir_name)
 
 
 static int
+sas_port_scandir_select(const struct dirent * s)
+{
+        if ((DT_LNK != s->d_type) && (DT_DIR != s->d_type))
+                return 0;
+        if (0 == strncmp("port-", s->d_name, 5))
+                return 1;
+        return 0;
+}
+
+static int
+sas_port_scan(const char * dir_name, struct dirent ***port_list)
+{
+        struct dirent ** namelist;
+        int num;
+
+        namelist = NULL;
+        num = scandir(dir_name, &namelist, sas_port_scandir_select, NULL);
+        if (num < 0) {
+                *port_list = NULL;
+                return -1;
+        }
+        *port_list = namelist;
+        return num;
+}
+
+
+static int
 sas_low_phy_scandir_select(const struct dirent * s)
 {
         char * cp;
@@ -483,22 +661,25 @@ sas_low_phy_scandir_select(const struct dirent * s)
 }
 
 static int
-sas_low_phy_scan(const char * dir_name)
+sas_low_phy_scan(const char * dir_name, struct dirent ***phy_list)
 {
-        struct dirent ** namelist;
+        struct dirent ** namelist=NULL;
         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);
+        if (!phy_list) {
+                for (k=0; k<num; ++k)
+                        free(namelist[k]);
+                free(namelist);
+        }
+        else
+                *phy_list = namelist;
         return num;
 }
 
-
 static int
 iscsi_target_scandir_select(const struct dirent * s)
 {
@@ -843,6 +1024,27 @@ parse_colon_list(const char * colon_list, struct addr_hctl * outp)
         return 1;
 }
 
+/* Print enclosure device link from the rport- or end_device- */
+static void
+print_enclosure_device(const char *devname, const char *path,
+                        const struct lsscsi_opt_coll * opts)
+{
+        struct addr_hctl hctl;
+        char buff[NAME_LEN_MAX];
+        int len;
+
+        if (parse_colon_list(devname, &hctl)) {
+                strcpy(buff, path);
+                len = strlen(buff);
+                snprintf(buff + len, NAME_LEN_MAX - len, "/device/target%d:%d:%d/%d:%d:%d:%d",
+                         hctl.h, hctl.c, hctl.t,
+                         hctl.h, hctl.c, hctl.t, hctl.l);
+                if (enclosure_device_scan(buff, opts) > 0)
+                        printf("  %s\n",enclosure_device.name);
+        }
+}
+
+
 /* Check host associated with 'devname' for known transport types. If so set
    transport_id, place a string in 'b' and return 1. Otherwise return 0. */
 static int
@@ -892,7 +1094,7 @@ transport_init(const char * devname, /* const struct lsscsi_opt_coll * opts, */
         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)
+                if (sas_low_phy_scan(buff, NULL) < 1)
                         return 0;
                 strcpy(buff, sysfsroot);
                 strcat(buff, sas_phy);
@@ -1012,6 +1214,12 @@ transport_init_longer(const char * path_name,
         char wd[NAME_LEN_MAX];
         char value[NAME_LEN_MAX];
         char * cp;
+        struct stat a_stat;
+        struct dirent ** phylist;
+        struct dirent ** portlist;
+        int phynum;
+        int portnum;
+        int i, j;
 
         strcpy(buff, path_name);
         strcpy(wd, path_name);
@@ -1029,16 +1237,44 @@ transport_init_longer(const char * path_name,
                 printf("  transport=fc\n");
                 strcat(buff, "/device/fc_host/");
                 strcat(buff, cp);
+
+                if (stat(buff, &a_stat) < 0) {
+                        /* newer sysfs format: /sys/class/scsi_host/host6/device/fc_host/host6 */
+                        strcpy(buff, path_name);
+                        strcat(buff, "/device/fc_host/");
+                        strcat(buff, cp);
+                        if (stat(buff, &a_stat) < 0) {
+                                if (opts->verbose > 2)
+                                        printf("no fc_host directory\n");
+                                break;
+                        }
+                }
+                if (get_value(buff, "active_fc4s", value, NAME_LEN_MAX))
+                        printf("  active_fc4s=%s\n", value);
+                if (get_value(buff, "supported_fc4s", value, NAME_LEN_MAX))
+                        printf("  supported_fc4s=%s\n", value);
+                if (get_value(buff, "fabric_name", value, NAME_LEN_MAX))
+                        printf("  fabric_name=%s\n", value);
+                if (get_value(buff, "maxframe_size", value, NAME_LEN_MAX))
+                        printf("  maxframe_size=%s\n", value);
+                if (get_value(buff, "max_npiv_vports", value, NAME_LEN_MAX))
+                        printf("  max_npiv_vports=%s\n", value);
+                if (get_value(buff, "npiv_vports_inuse", value, NAME_LEN_MAX))
+                        printf("  npiv_vports_inuse=%s\n", value);
                 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, "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_speeds", value, NAME_LEN_MAX))
+                        printf("  supported_speeds=%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))
@@ -1049,50 +1285,111 @@ transport_init_longer(const char * path_name,
         case TRANSPORT_SAS:
                 printf("  transport=sas\n");
                 strcat(buff, "/device");
-                if (sas_low_phy_scan(buff) < 1)
+                if ((portnum=sas_port_scan(buff, &portlist)) < 1) {     /* no configured ports */
+                        printf("  no configured ports\n");
+                        if ((phynum=sas_low_phy_scan(buff, &phylist)) < 1) {    /* no phys */
+                                printf("  no configured phys\n");
+                                return;
+                        }
+                        for (i=0; i<phynum; i++) {
+                                /* emit something potentially useful */
+                                strcpy(buff, sysfsroot);
+                                strcat(buff, sas_phy);
+                                strcat(buff, phylist[i]->d_name);
+                                printf("  %s\n",phylist[i]->d_name);
+                                if (get_value(buff, "sas_address", value, NAME_LEN_MAX))
+                                        printf("    sas_address=%s\n", value);
+                                if (get_value(buff, "phy_identifier", value, NAME_LEN_MAX))
+                                        printf("    phy_identifier=%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, "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, "negotiated_linkrate", value,
+                                              NAME_LEN_MAX))
+                                        printf("    negotiated_linkrate=%s\n", value);
+                        }
                         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);
+                }
+                for (i=0; i<portnum; i++) {     /* for each host port */
+                        strcpy(buff, path_name);
+                        strcat(buff, "/device/");
+                        strcat(buff, portlist[i]->d_name);
+                        if ((phynum=sas_low_phy_scan(buff, &phylist)) < 1) {
+                                printf("  %s: phy list not available\n",portlist[i]->d_name);
+                                free(portlist[i]);
+                                continue;
+                        }
+
+                        strcpy(buff, sysfsroot);
+                        strcat(buff, sas_port);
+                        strcat(buff, portlist[i]->d_name);
+
+                        if (get_value(buff, "num_phys", value, NAME_LEN_MAX)) {
+                                printf("  %s: num_phys=%s,",portlist[i]->d_name, value);
+                                for (j=0; j<phynum; j++) {
+                                        printf(" %s",phylist[j]->d_name);
+                                        free(phylist[j]);
+                                }
+                                printf("\n");
+                                if (opts->verbose > 2)
+                                        printf("  fetched from directory: %s\n", buff);
+                                free(phylist);
+                        }
+                        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, "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, "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, "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);
+
+                        free(portlist[i]);
+
+                }
+                free(portlist);
+
                 break;
         case TRANSPORT_SAS_CLASS:
                 printf("  transport=sas\n");
@@ -1396,10 +1693,23 @@ transport_tport_longer(const char * devname,
                 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 (if_directory_chdir(wd, buff)) {
+                        if (NULL == getcwd(buff, NAME_LEN_MAX))
+                                return;
+                }
+                else {  /* newer transport */
+                        strcpy(buff, sysfsroot);        /* /sys */
+                        strcat(buff, fc_remote_ports);  /* /class/fc_remote_ports/ */
+                        strcat(buff, cp);               /* rport-x:y-z */
+                        strcat(buff, "/");              /* rport-x:y-z */
+                }
+                strcpy(b2, path_name);
+                strcat(b2, "/device/");
+                if (get_value(b2, "vendor", value, NAME_LEN_MAX))
+                        printf("  vendor=%s\n", value);
+                if (get_value(b2, "model", value, NAME_LEN_MAX))
+                        printf("  model=%s\n", value);
+                printf("  %s\n",cp);    /* rport */
                 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))
@@ -1410,23 +1720,43 @@ transport_tport_longer(const char * devname,
                         printf("  port_state=%s\n", value);
                 if (get_value(buff, "roles", value, NAME_LEN_MAX))
                         printf("  roles=%s\n", value);
+                print_enclosure_device(devname, b2, opts);
                 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, "fast_io_fail_tmo", value, NAME_LEN_MAX))
+                        printf("  fast_io_fail_tmo=%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);
+                if (opts->verbose > 2) {
+                        printf("  fetched from directory: %s\n", buff);
+                        printf("  fetched from directory: %s\n", b2);
+                }
                 break;
         case TRANSPORT_SAS:
                 printf("  transport=sas\n");
                 strcpy(buff, sysfsroot);
                 strcat(buff, sas_device);
                 strcat(buff, sas_hold_end_device);
+
+                strcpy(b2, path_name);
+                strcat(b2, "/device/");
+                if (get_value(b2, "vendor", value, NAME_LEN_MAX))
+                        printf("  vendor=%s\n", value);
+                if (get_value(b2, "model", value, NAME_LEN_MAX))
+                        printf("  model=%s\n", value);
+
                 strcpy(b2, sysfsroot);
                 strcat(b2, sas_end_device);
                 strcat(b2, sas_hold_end_device);
+                if (get_value(buff, "bay_identifier", value,
+                              NAME_LEN_MAX))
+                        printf("  bay_identifier=%s\n", value);
+                print_enclosure_device(devname, b2, opts);
+                if (get_value(buff, "enclosure_identifier", value,
+                              NAME_LEN_MAX))
+                        printf("  enclosure_identifier=%s\n", value);
                 if (get_value(buff, "initiator_port_protocols", value,
                               NAME_LEN_MAX))
                         printf("  initiator_port_protocols=%s\n", value);
@@ -1445,6 +1775,10 @@ transport_tport_longer(const char * devname,
                 if (get_value(buff, "target_port_protocols", value,
                               NAME_LEN_MAX))
                         printf("  target_port_protocols=%s\n", value);
+                if (get_value(b2, "tlr_enabled", value, NAME_LEN_MAX))
+                        printf("  tlr_enabled=%s\n", value);
+                if (get_value(b2, "tlr_supported", value, NAME_LEN_MAX))
+                        printf("  tlr_supported=%s\n", value);
                 if (opts->verbose > 2) {
                         printf("fetched from directory: %s\n", buff);
                         printf("fetched from directory: %s\n", b2);
@@ -1840,7 +2174,7 @@ one_sdev_entry(const char * dir_name, const char * devname,
                         }
                 }
         } else
-                printf("-       ");
+                printf("%-9s", "-");
 
         if (opts->generic) {
                 if (if_directory_ch2generic(buff)) {
@@ -1857,7 +2191,7 @@ one_sdev_entry(const char * dir_name, const char * devname,
                                 else if (!get_dev_node(wd, dev_node, CHR_DEV))
                                         snprintf(dev_node, NAME_MAX, "-");
 
-                                printf("  %s", dev_node);
+                                printf("  %-9s", dev_node);
                                 if (opts->dev_maj_min) {
                                         if (get_value(wd, "dev", value,
                                                       NAME_LEN_MAX))
@@ -1868,58 +2202,74 @@ one_sdev_entry(const char * dir_name, const char * devname,
                         }
                 }
                 else
-                        printf("  -");
+                        printf("  %-9s", "-");
         }
 
         if (opts->protection) {
-                int kernel_dif_support = 0;
-                if (sd_scan(buff,opts)) {
-                        if (if_directory_chdir(buff,aa_sd.name)) {
-                                char value[NAME_LEN_MAX];
-                                char sddir[NAME_LEN_MAX];
-                                strncpy(sddir,buff,NAME_LEN_MAX);
-                                strcat(sddir,"/");
-                                strcat(sddir,aa_sd.name);
-                                if (!get_value(sddir, "protection_type", value, 
-                                        NAME_LEN_MAX)) {
-                                        /* kernel < 2.6.27 */
-                                        if (opts->verbose)
-                                                printf(" No Data Integrity "
-                                                                "Support\n");
-                                } else {
-                                        kernel_dif_support = 1;
-                                        if (strncmp(value, "0", 1))
-                                                printf("  DIF/Type%1s ",value);
-                                        else
-                                                printf("  -         ");
-                                }
-                        } else {
-                                printf("  -         ");
-                        }
-                }
+                char sddir[NAME_LEN_MAX];
+                char blkdir[NAME_LEN_MAX];
 
-                if (kernel_dif_support && block_scan(buff,opts)) {
-                        if (if_directory_chdir(buff,aa_block.name)) {
-                                char value[NAME_LEN_MAX];
-                                char blkdir[NAME_LEN_MAX];
-                                strncpy(blkdir,buff,NAME_LEN_MAX);
-                                strcat(blkdir,"/");
-                                strcat(blkdir,aa_block.name);
-                                if (if_directory_chdir(blkdir,"integrity")) {
-                                        if (!get_value(".", "format", value, 
-                                                                NAME_LEN_MAX)) {
-                                                if (opts->verbose)
-                                                        printf(" No Data "
-                                                                "Integrity "
-                                                                "Support\n");
-                                        } else {
-                                                printf(" %-17s",value);
-                                        }
-                                } else {
-                                        printf(" %-17s","-   ");
-                                }
-                        }
-                }
+                strncpy(sddir,  buff, NAME_LEN_MAX);
+                strncpy(blkdir, buff, NAME_LEN_MAX);
+
+                if (sd_scan(sddir) &&
+                    if_directory_chdir(sddir, ".") &&
+                    get_value(".", "protection_type", value, NAME_LEN_MAX)) {
+
+                        if (!strncmp(value, "0", 1))
+                                printf("  %-9s", "-");
+                        else
+                                printf("  DIF/Type%1s", value);
+
+                } else
+                        printf("  %-9s", "-");
+
+                if (block_scan(blkdir) &&
+                    if_directory_chdir(blkdir, "integrity") &&
+                    get_value(".", "format", value, NAME_LEN_MAX))
+                        printf("  %-16s", value);
+                else
+                        printf("  %-16s", "-");
+        }
+
+        if (opts->protmode) {
+                char sddir[NAME_LEN_MAX];
+
+                strncpy(sddir, buff, NAME_LEN_MAX);
+
+                if (sd_scan(sddir) &&
+                    if_directory_chdir(sddir, ".") &&
+                    get_value(sddir, "protection_mode", value, NAME_LEN_MAX)) {
+
+                        if (!strcmp(value, "none"))
+                                printf("  %-4s", "-");
+                        else
+                                printf("  %-4s", value);
+                } else
+                        printf("  %-4s", "-");
+        }
+
+        if (opts->size) {
+                char blkdir[NAME_LEN_MAX];
+
+                strncpy(blkdir, buff, NAME_LEN_MAX);
+
+                value[0] = 0;
+                if (type == 0 &&
+                    block_scan(blkdir) &&
+                    if_directory_chdir(blkdir, ".") &&
+                    get_value(".", "size", value, NAME_LEN_MAX)) {
+                        uint64_t blocks = atoll(value);
+
+                        blocks <<= 9;
+                        if (blocks > 0 &&
+                            !string_get_size(blocks, STRING_UNITS_10, value,
+                                             NAME_LEN_MAX)) {
+                                printf("  %6s", value);
+                        } else
+                                printf("  %6s", "-");
+                } else
+                        printf("  %6s", "-");
         }
 
         printf("\n");
@@ -2373,7 +2723,7 @@ main(int argc, char **argv)
         while (1) {
                 int option_index = 0;
 
-                c = getopt_long(argc, argv, "cdghHklLptvVy:", long_options,
+                c = getopt_long(argc, argv, "cdghHklLpPstvVy:", long_options,
                                 &option_index);
                 if (c == -1)
                         break;
@@ -2406,6 +2756,12 @@ main(int argc, char **argv)
                 case 'p':
                         ++opts.protection;
                         break;
+                case 'P':
+                        ++opts.protmode;
+                        break;
+                case 's':
+                        ++opts.size;
+                        break;
                 case 't':
                         ++opts.transport;
                         break;

