From df6814c987aaa36341f90af2e010156ccf6216d4 Mon Sep 17 00:00:00 2001
From: dpgilbert <dpgilbert@4ea69e1a-61f1-4043-bf83-b5c94c648137>
Date: Sun, 21 Jun 2009 02:39:32 +0000
Subject: [PATCH] add '-l sasphy' and '-l sasphy,reset' into smartctl

git-svn-id: https://smartmontools.svn.sourceforge.net/svnroot/smartmontools/trunk@2809 4ea69e1a-61f1-4043-bf83-b5c94c648137
---
 sm5/CHANGELOG     |   6 +-
 sm5/scsicmds.h    |   3 +-
 sm5/scsiprint.cpp | 336 +++++++++++++++++++++++++++++++++++++++++++++-
 sm5/scsiprint.h   |   7 +-
 sm5/smartctl.8.in |  10 +-
 sm5/smartctl.cpp  |  14 +-
 6 files changed, 364 insertions(+), 12 deletions(-)

diff --git a/sm5/CHANGELOG b/sm5/CHANGELOG
index a23ebd292..efc697dde 100644
--- a/sm5/CHANGELOG
+++ b/sm5/CHANGELOG
@@ -1,6 +1,6 @@
 CHANGELOG for smartmontools
 
-$Id: CHANGELOG,v 1.808 2009/06/20 19:51:42 chrfranke Exp $
+$Id: CHANGELOG,v 1.809 2009/06/21 02:39:32 dpgilbert Exp $
 
 The most recent version of this file is:
 http://smartmontools.cvs.sourceforge.net/smartmontools/sm5/CHANGELOG?view=markup
@@ -41,6 +41,10 @@ NOTES FOR FUTURE RELEASES: see TODO file.
 
 <DEVELOPERS: ADDITIONS TO THE CHANGE LOG GO JUST BELOW HERE, PLEASE>
 
+  [DG] SCSI (SAS): add '-l sasphy' and '-l sasphy,reset' into smartctl
+       to output SAS device phy information (from the Protocol specific
+       log page)
+
   [CF] autogen.sh: Remove 'CYGWIN=check_case:strict', this does no
        longer work on Cygwin 1.7.  Print warning if Automake version
        cannot handle case insensitive filesystems.
diff --git a/sm5/scsicmds.h b/sm5/scsicmds.h
index 521e6df37..76d347d05 100644
--- a/sm5/scsicmds.h
+++ b/sm5/scsicmds.h
@@ -32,7 +32,7 @@
 #ifndef SCSICMDS_H_
 #define SCSICMDS_H_
 
-#define SCSICMDS_H_CVSID "$Id: scsicmds.h,v 1.67 2008/07/25 21:16:00 chrfranke Exp $\n"
+#define SCSICMDS_H_CVSID "$Id: scsicmds.h,v 1.68 2009/06/21 02:39:32 dpgilbert Exp $\n"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -171,6 +171,7 @@ struct scsiNonMediumError {
 #define APPLICATION_CLIENT_LPAGE                0x0f
 #define SELFTEST_RESULTS_LPAGE                  0x10
 #define BACKGROUND_RESULTS_LPAGE                0x15   /* SBC-3 */
+#define PROTOCOL_SPECIFIC_LPAGE                 0x18
 #define IE_LPAGE                                0x2f
 
 /* Seagate vendor specific log pages. */
diff --git a/sm5/scsiprint.cpp b/sm5/scsiprint.cpp
index a1df47597..e37e84351 100644
--- a/sm5/scsiprint.cpp
+++ b/sm5/scsiprint.cpp
@@ -44,7 +44,7 @@
 
 #define GBUF_SIZE 65535
 
-const char* scsiprint_c_cvsid="$Id: scsiprint.cpp,v 1.127 2009/06/20 17:58:33 chrfranke Exp $"
+const char* scsiprint_c_cvsid="$Id: scsiprint.cpp,v 1.128 2009/06/21 02:39:32 dpgilbert Exp $"
 CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID SCSIPRINT_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID;
 
 // control block which points to external global control variables
@@ -52,7 +52,7 @@ extern smartmonctrl *con;
 
 UINT8 gBuf[GBUF_SIZE];
 #define LOG_RESP_LEN 252
-#define LOG_RESP_LONG_LEN 16384
+#define LOG_RESP_LONG_LEN ((62 * 256) + 252)
 #define LOG_RESP_TAPE_ALERT_LEN 0x144
 
 /* Log pages supported */
@@ -66,6 +66,7 @@ static int gVerifyECounterLPage = 0;
 static int gNonMediumELPage = 0;
 static int gLastNErrorLPage = 0;
 static int gBackgroundResultsLPage = 0;
+static int gProtocolSpecificLPage = 0;
 static int gTapeAlertsLPage = 0;
 static int gSeagateCacheLPage = 0;
 static int gSeagateFactoryLPage = 0;
@@ -125,6 +126,9 @@ static void scsiGetSupportedLogPages(scsi_device * device)
             case BACKGROUND_RESULTS_LPAGE:
                 gBackgroundResultsLPage = 1;
                 break;
+            case PROTOCOL_SPECIFIC_LPAGE:
+                gProtocolSpecificLPage = 1;
+                break;
             case TAPE_ALERTS_LPAGE:
                 gTapeAlertsLPage = 1;
                 break;
@@ -948,6 +952,330 @@ static int scsiPrintBackgroundResults(scsi_device * device)
     return retval;
 }
 
+
+static void show_sas_phy_event_info(int peis, unsigned int val,
+                                    unsigned thresh_val)
+{
+    unsigned int u;
+
+    switch (peis) {
+    case 0:
+        pout("     No event\n");
+        break;
+    case 0x1:
+        pout("     Invalid word count: %u\n", val);
+        break;
+    case 0x2:
+        pout("     Running disparity error count: %u\n", val);
+        break;
+    case 0x3:
+        pout("     Loss of dword synchronization count: %u\n", val);
+        break;
+    case 0x4:
+        pout("     Phy reset problem count: %u\n", val);
+        break;
+    case 0x5:
+        pout("     Elasticity buffer overflow count: %u\n", val);
+        break;
+    case 0x6:
+        pout("     Received ERROR  count: %u\n", val);
+        break;
+    case 0x20:
+        pout("     Received address frame error count: %u\n", val);
+        break;
+    case 0x21:
+        pout("     Transmitted abandon-class OPEN_REJECT count: %u\n", val);
+        break;
+    case 0x22:
+        pout("     Received abandon-class OPEN_REJECT count: %u\n", val);
+        break;
+    case 0x23:
+        pout("     Transmitted retry-class OPEN_REJECT count: %u\n", val);
+        break;
+    case 0x24:
+        pout("     Received retry-class OPEN_REJECT count: %u\n", val);
+        break;
+    case 0x25:
+        pout("     Received AIP (WATING ON PARTIAL) count: %u\n", val);
+        break;
+    case 0x26:
+        pout("     Received AIP (WAITING ON CONNECTION) count: %u\n", val);
+        break;
+    case 0x27:
+        pout("     Transmitted BREAK count: %u\n", val);
+        break;
+    case 0x28:
+        pout("     Received BREAK count: %u\n", val);
+        break;
+    case 0x29:
+        pout("     Break timeout count: %u\n", val);
+        break;
+    case 0x2a:
+        pout("     Connection count: %u\n", val);
+        break;
+    case 0x2b:
+        pout("     Peak transmitted pathway blocked count: %u\n",
+               val & 0xff);
+        pout("         Peak value detector threshold: %u\n",
+               thresh_val & 0xff);
+        break;
+    case 0x2c:
+        u = val & 0xffff;
+        if (u < 0x8000)
+            pout("     Peak transmitted arbitration wait time (us): "
+                   "%u\n", u);
+        else
+            pout("     Peak transmitted arbitration wait time (ms): "
+                   "%u\n", 33 + (u - 0x8000));
+        u = thresh_val & 0xffff;
+        if (u < 0x8000)
+            pout("         Peak value detector threshold (us): %u\n",
+                   u);
+        else
+            pout("         Peak value detector threshold (ms): %u\n",
+                   33 + (u - 0x8000));
+        break;
+    case 0x2d:
+        pout("     Peak arbitration time (us): %u\n", val);
+        pout("         Peak value detector threshold: %u\n", thresh_val);
+        break;
+    case 0x2e:
+        pout("     Peak connection time (us): %u\n", val);
+        pout("         Peak value detector threshold: %u\n", thresh_val);
+        break;
+    case 0x40:
+        pout("     Transmitted SSP frame count: %u\n", val);
+        break;
+    case 0x41:
+        pout("     Received SSP frame count: %u\n", val);
+        break;
+    case 0x42:
+        pout("     Transmitted SSP frame error count: %u\n", val);
+        break;
+    case 0x43:
+        pout("     Received SSP frame error count: %u\n", val);
+        break;
+    case 0x44:
+        pout("     Transmitted CREDIT_BLOCKED count: %u\n", val);
+        break;
+    case 0x45:
+        pout("     Received CREDIT_BLOCKED count: %u\n", val);
+        break;
+    case 0x50:
+        pout("     Transmitted SATA frame count: %u\n", val);
+        break;
+    case 0x51:
+        pout("     Received SATA frame count: %u\n", val);
+        break;
+    case 0x52:
+        pout("     SATA flow control buffer overflow count: %u\n", val);
+        break;
+    case 0x60:
+        pout("     Transmitted SMP frame count: %u\n", val);
+        break;
+    case 0x61:
+        pout("     Received SMP frame count: %u\n", val);
+        break;
+    case 0x63:
+        pout("     Received SMP frame error count: %u\n", val);
+        break;
+    default:
+        break;
+    }
+}
+
+static void show_sas_port_param(unsigned char * ucp, int param_len)
+{
+    int j, m, n, nphys, pcb, t, sz, spld_len;
+    unsigned char * vcp;
+    uint64_t ull;
+    unsigned int ui;
+    char s[64];
+
+    sz = sizeof(s);
+    pcb = ucp[2];
+    t = (ucp[0] << 8) | ucp[1];
+    pout("relative target port id = %d\n", t);
+    pout("  generation code = %d\n", ucp[6]);
+    nphys = ucp[7];
+    pout("  number of phys = %d\n", nphys);
+
+    for (j = 0, vcp = ucp + 8; j < (param_len - 8);
+         vcp += spld_len, j += spld_len) {
+        pout("  phy identifier = %d\n", vcp[1]);
+        spld_len = vcp[3];
+        if (spld_len < 44)
+            spld_len = 48;      /* in SAS-1 and SAS-1.1 vcp[3]==0 */
+        else
+            spld_len += 4;
+        t = ((0x70 & vcp[4]) >> 4);
+        switch (t) {
+        case 0: snprintf(s, sz, "no device attached"); break;
+        case 1: snprintf(s, sz, "end device"); break;
+        case 2: snprintf(s, sz, "expander device"); break;
+        case 3: snprintf(s, sz, "expander device (fanout)"); break;
+        default: snprintf(s, sz, "reserved [%d]", t); break;
+        }
+        pout("    attached device type: %s\n", s);
+        t = 0xf & vcp[4];
+        switch (t) {
+        case 0: snprintf(s, sz, "unknown"); break;
+        case 1: snprintf(s, sz, "power on"); break;
+        case 2: snprintf(s, sz, "hard reset"); break;
+        case 3: snprintf(s, sz, "SMP phy control function"); break;
+        case 4: snprintf(s, sz, "loss of dword synchronization"); break;
+        case 5: snprintf(s, sz, "mux mix up"); break;
+        case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA");
+            break;
+        case 7: snprintf(s, sz, "break timeout timer expired"); break;
+        case 8: snprintf(s, sz, "phy test function stopped"); break;
+        case 9: snprintf(s, sz, "expander device reduced functionality");
+             break;
+        default: snprintf(s, sz, "reserved [0x%x]", t); break;
+        }
+        pout("    attached reason: %s\n", s);
+        t = (vcp[5] & 0xf0) >> 4;
+        switch (t) {
+        case 0: snprintf(s, sz, "unknown"); break;
+        case 1: snprintf(s, sz, "power on"); break;
+        case 2: snprintf(s, sz, "hard reset"); break;
+        case 3: snprintf(s, sz, "SMP phy control function"); break;
+        case 4: snprintf(s, sz, "loss of dword synchronization"); break;
+        case 5: snprintf(s, sz, "mux mix up"); break;
+        case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA");
+            break;
+        case 7: snprintf(s, sz, "break timeout timer expired"); break;
+        case 8: snprintf(s, sz, "phy test function stopped"); break;
+        case 9: snprintf(s, sz, "expander device reduced functionality");
+             break;
+        default: snprintf(s, sz, "reserved [0x%x]", t); break;
+        }
+        pout("    reason: %s\n", s);
+        t = (0xf & vcp[5]);
+        switch (t) {
+        case 0: snprintf(s, sz, "phy enabled; unknown");
+                     break;
+        case 1: snprintf(s, sz, "phy disabled"); break;
+        case 2: snprintf(s, sz, "phy enabled; speed negotiation failed");
+                     break;
+        case 3: snprintf(s, sz, "phy enabled; SATA spinup hold state");
+                     break;
+        case 4: snprintf(s, sz, "phy enabled; port selector");
+                     break;
+        case 5: snprintf(s, sz, "phy enabled; reset in progress");
+                     break;
+        case 6: snprintf(s, sz, "phy enabled; unsupported phy attached");
+                     break;
+        case 8: snprintf(s, sz, "phy enabled; 1.5 Gbps"); break;
+        case 9: snprintf(s, sz, "phy enabled; 3 Gbps"); break;
+        case 0xa: snprintf(s, sz, "phy enabled; 6 Gbps"); break;
+        default: snprintf(s, sz, "reserved [%d]", t); break;
+        }
+        pout("    negotiated logical link rate: %s\n", s);
+        pout("    attached initiator port: ssp=%d stp=%d smp=%d\n",
+               !! (vcp[6] & 8), !! (vcp[6] & 4), !! (vcp[6] & 2));
+        pout("    attached target port: ssp=%d stp=%d smp=%d\n",
+               !! (vcp[7] & 8), !! (vcp[7] & 4), !! (vcp[7] & 2));
+        for (n = 0, ull = vcp[8]; n < 8; ++n) {
+            ull <<= 8; ull |= vcp[8 + n];
+        }
+        pout("    SAS address = 0x%" PRIx64 "\n", ull);
+        for (n = 0, ull = vcp[16]; n < 8; ++n) {
+            ull <<= 8; ull |= vcp[16 + n];
+        }
+        pout("    attached SAS address = 0x%" PRIx64 "\n", ull);
+        pout("    attached phy identifier = %d\n", vcp[24]);
+        ui = (vcp[32] << 24) | (vcp[33] << 16) | (vcp[34] << 8) | vcp[35];
+        pout("    Invalid DWORD count = %u\n", ui);
+        ui = (vcp[36] << 24) | (vcp[37] << 16) | (vcp[38] << 8) | vcp[39];
+        pout("    Running disparity error count = %u\n", ui);
+        ui = (vcp[40] << 24) | (vcp[41] << 16) | (vcp[42] << 8) | vcp[43];
+        pout("    Loss of DWORD synchronization = %u\n", ui);
+        ui = (vcp[44] << 24) | (vcp[45] << 16) | (vcp[46] << 8) | vcp[47];
+        pout("    Phy reset problem = %u\n", ui);
+        if (spld_len > 51) {
+            int num_ped, peis;
+            unsigned char * xcp;
+            unsigned int pvdt;
+
+            num_ped = vcp[51];
+            if (num_ped > 0)
+               pout("    Phy event descriptors:\n");
+            xcp = vcp + 52;
+            for (m = 0; m < (num_ped * 12); m += 12, xcp += 12) {
+                peis = xcp[3];
+                ui = (xcp[4] << 24) | (xcp[5] << 16) | (xcp[6] << 8) |
+                     xcp[7];
+                pvdt = (xcp[8] << 24) | (xcp[9] << 16) | (xcp[10] << 8) |
+                       xcp[11];
+                show_sas_phy_event_info(peis, ui, pvdt);
+            }
+        }
+    }
+}
+
+// Returns 1 if okay, 0 if non SAS descriptors
+static int show_protocol_specific_page(unsigned char * resp, int len)
+{
+    int k, num, param_len;
+    unsigned char * ucp;
+
+    num = len - 4;
+    for (k = 0, ucp = resp + 4; k < num; ) {
+        param_len = ucp[3] + 4;
+        if (6 != (0xf & ucp[4]))
+            return 0;   /* only decode SAS log page */
+        if (0 == k)
+            pout("Protocol Specific port log page for SAS SSP\n");
+        show_sas_port_param(ucp, param_len);
+        k += param_len;
+        ucp += param_len;
+    }
+    return 1;
+}
+
+
+// See Serial Attached SCSI (SAS-2) (e.g. revision 16) the Protocol Specific
+// log pageSerial Attached SCSI (SAS-2) (e.g. revision 16) the Protocol
+// Specific log page.
+// Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
+// 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
+// FAILSMART is returned.
+static int scsiPrintSasPhy(scsi_device * device, int reset)
+{
+    int num, err;
+
+    if (reset) {
+        PRINT_ON(con);
+        pout("sasphy_reset not supported yet (need LOG SELECT)\n");
+        PRINT_OFF(con);
+        return FAILSMART;
+    }
+    if ((err = scsiLogSense(device, PROTOCOL_SPECIFIC_LPAGE, 0, gBuf,
+                            LOG_RESP_LONG_LEN, 0))) {
+        PRINT_ON(con);
+        pout("scsiPrintSasPhy Failed [%s]\n", scsiErrString(err));
+        PRINT_OFF(con);
+        return FAILSMART;
+    }
+    if ((gBuf[0] & 0x3f) != PROTOCOL_SPECIFIC_LPAGE) {
+        PRINT_ON(con);
+        pout("Protocol specific Log Sense Failed, page mismatch\n");
+        PRINT_OFF(con);
+        return FAILSMART;
+    }
+    // compute page length
+    num = (gBuf[2] << 8) + gBuf[3];
+    if (1 != show_protocol_specific_page(gBuf, num + 4)) {
+        PRINT_ON(con);
+        pout("Only support protocol specific log page on SAS devices\n");
+        PRINT_OFF(con);
+        return FAILSMART;
+    }
+    return 0;
+}
+
+
 static const char * peripheral_dt_arr[] = {
         "disk",
         "tape",
@@ -1391,5 +1719,9 @@ int scsiPrintMain(scsi_device * device, const scsi_print_options & options)
             return returnval | FAILSMART;
         pout("Self Test returned without error\n");
     }           
+    if (options.sasphy) {
+        if (scsiPrintSasPhy(device, options.sasphy_reset))
+            return returnval | FAILSMART;
+    }           
     return returnval;
 }
diff --git a/sm5/scsiprint.h b/sm5/scsiprint.h
index 46a227568..dcc1d64ac 100644
--- a/sm5/scsiprint.h
+++ b/sm5/scsiprint.h
@@ -29,7 +29,7 @@
 #ifndef SCSI_PRINT_H_
 #define SCSI_PRINT_H_
 
-#define SCSIPRINT_H_CVSID "$Id: scsiprint.h,v 1.23 2009/06/20 17:58:33 chrfranke Exp $\n"
+#define SCSIPRINT_H_CVSID "$Id: scsiprint.h,v 1.24 2009/06/21 02:39:32 dpgilbert Exp $\n"
 
 // Options for scsiPrintMain
 // TODO: Move remaining options from con->* to here.
@@ -50,6 +50,8 @@ struct scsi_print_options
   bool smart_extend_selftest, smart_extend_cap_selftest;
   bool smart_selftest_abort;
 
+  bool sasphy, sasphy_reset;
+
   scsi_print_options()
     : drive_info(false),
       smart_check_status(false),
@@ -62,7 +64,8 @@ struct scsi_print_options
       smart_default_selftest(false),
       smart_short_selftest(false), smart_short_cap_selftest(false),
       smart_extend_selftest(false), smart_extend_cap_selftest(false),
-      smart_selftest_abort(false)
+      smart_selftest_abort(false),
+      sasphy(false), sasphy_reset(false)
     { }
 };
 
diff --git a/sm5/smartctl.8.in b/sm5/smartctl.8.in
index f2c50b786..acf99a603 100644
--- a/sm5/smartctl.8.in
+++ b/sm5/smartctl.8.in
@@ -1,7 +1,7 @@
 .ig
  Copyright (C) 2002-8 Bruce Allen <smartmontools-support@lists.sourceforge.net>
 
- $Id: smartctl.8.in,v 1.127 2009/06/13 17:04:19 chrfranke Exp $
+ $Id: smartctl.8.in,v 1.128 2009/06/21 02:39:32 dpgilbert Exp $
  
  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
@@ -955,6 +955,12 @@ and descriptions of the SATA Phy Event Counters (General Purpose Log
 address 0x11). If \'\-l sataphy,reset\' is specified, all counters
 are reset after reading the values.
 
+.I sasphy[,reset]
+\- [SAS (SCSI) only] [NEW EXPERIMENTAL SMARTCTL FEATURE] prints values
+and descriptions of the SAS (SSP) Protocol Specific log page (log page
+0x18). If \'\-l sasphy,reset\' is specified, all counters
+are reset after reading the values (not yet implemented).
+
 .I gplog,ADDR[,FIRST[\-LAST|+SIZE]]
 \- [ATA only] [NEW EXPERIMENTAL SMARTCTL FEATURE] prints a hex dump
 of any log accessible via General Purpose Logging (GPL) feature.
@@ -1686,7 +1692,7 @@ these documents may be found in the References section of the
 
 .SH
 CVS ID OF THIS PAGE:
-$Id: smartctl.8.in,v 1.127 2009/06/13 17:04:19 chrfranke Exp $
+$Id: smartctl.8.in,v 1.128 2009/06/21 02:39:32 dpgilbert Exp $
 .\" Local Variables:	         
 .\" mode: nroff         
 .\" End:
diff --git a/sm5/smartctl.cpp b/sm5/smartctl.cpp
index f5300f99e..0d40dec20 100644
--- a/sm5/smartctl.cpp
+++ b/sm5/smartctl.cpp
@@ -63,7 +63,7 @@ extern const char *os_solaris_ata_s_cvsid;
 extern const char *cciss_c_cvsid;
 #endif
 extern const char *atacmdnames_c_cvsid, *atacmds_c_cvsid, *ataprint_c_cvsid, *knowndrives_c_cvsid, *os_XXXX_c_cvsid, *scsicmds_c_cvsid, *scsiprint_c_cvsid, *utility_c_cvsid;
-const char* smartctl_c_cvsid="$Id: smartctl.cpp,v 1.199 2009/06/20 19:11:04 chrfranke Exp $"
+const char* smartctl_c_cvsid="$Id: smartctl.cpp,v 1.200 2009/06/21 02:39:32 dpgilbert Exp $"
 ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID KNOWNDRIVES_H_CVSID SCSICMDS_H_CVSID SCSIPRINT_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID;
 
 // This is a block containing all the "control variables".  We declare
@@ -167,8 +167,9 @@ void Usage (void){
 "        Show device SMART vendor-specific Attributes and values\n\n"
 "  -l TYPE, --log=TYPE\n"
 "        Show device log. TYPE: error, selftest, selective, directory[,g|s],\n"
-"                               background, sataphy[,reset], scttemp[sts,hist]\n"
-"                               gplog,N[,RANGE], smartlog,N[,RANGE],\n"
+"                               background, sasphy[,reset], sataphy[,reset],\n"
+"                               scttemp[sts,hist],gplog,N[,RANGE],\n"
+"                               smartlog,N[,RANGE],\n"
 "                               xerror[,N], xselftest[,N]\n\n"
 "  -v N,OPTION , --vendorattribute=N,OPTION                            (ATA)\n"
 "        Set display OPTION for vendor Attribute N (see man page)\n\n"
@@ -224,7 +225,8 @@ static const char *getvalidarglist(char opt)
     return "on, off";
   case 'l':
     return "error, selftest, selective, directory[,g|s], background, scttemp[sts|hist], "
-           "sataphy[,reset], gplog,N[,RANGE], smartlog,N[,RANGE], xerror[,N], xselftest[,N]";
+           "sasphy[,reset], sataphy[,reset], gplog,N[,RANGE], smartlog,N[,RANGE], "
+	   "xerror[,N], xselftest[,N]";
   case 'P':
     return "use, ignore, show, showall";
   case 't':
@@ -464,6 +466,10 @@ const char * parse_options(int argc, char** argv,
         ataopts.smart_logdir = true; // SMART
       } else if (!strcmp(optarg,"directory,g")) {
         ataopts.gp_logdir = true; // GPL
+      } else if (!strcmp(optarg,"sasphy")) {
+        scsiopts.sasphy = true;
+      } else if (!strcmp(optarg,"sasphy,reset")) {
+        scsiopts.sasphy = scsiopts.sasphy_reset = true;
       } else if (!strcmp(optarg,"sataphy")) {
         ataopts.sataphy = true;
       } else if (!strcmp(optarg,"sataphy,reset")) {
-- 
GitLab