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