diff --git a/smartmontools/ChangeLog b/smartmontools/ChangeLog index e8543ec5a0d462f4304818b670d1ee6021f018a9..08893ef75132f0a993774054b9c24907aa35ef72 100644 --- a/smartmontools/ChangeLog +++ b/smartmontools/ChangeLog @@ -1,5 +1,12 @@ $Id$ +2022-02-20 Douglas Gilbert <dgilbert@interlog.com> + + smartctl.cpp, scsiprint.cpp: implement the change to + TapeAlert handling documented in the previous commit. + Add --log=tapealert option to explicitly fetch the + Tape Alert log page. Tweak some tape-specific formatting. + 2022-02-19 Douglas Gilbert <dgilbert@interlog.com> smartctl.8.in: proposed change to TapeAlert handling. No code diff --git a/smartmontools/scsiprint.cpp b/smartmontools/scsiprint.cpp index 6a2a1daceacfccb0eb4384e3de1b615fc4384c8b..6b716ef99a8b2a38f2aeec715a08c556937b7a08 100644 --- a/smartmontools/scsiprint.cpp +++ b/smartmontools/scsiprint.cpp @@ -391,7 +391,8 @@ scsiGetSmartData(scsi_device * device, bool attribs) static const char * const severities = "CWI"; static int -scsiGetTapeAlertsData(scsi_device * device, int peripheral_type) +scsiPrintActiveTapeAlerts(scsi_device * device, int peripheral_type, + bool from_health) { unsigned short pagelength; unsigned short parametercode; @@ -399,6 +400,8 @@ scsiGetTapeAlertsData(scsi_device * device, int peripheral_type) const char *s; const char *ts; int failures = 0; + const char * pad = from_health ? "" : " "; + static const char * const tapealert_s = "scsi_tapealert"; print_on(); if ((err = scsiLogSense(device, TAPE_ALERTS_LPAGE, 0, gBuf, @@ -408,13 +411,13 @@ scsiGetTapeAlertsData(scsi_device * device, int peripheral_type) return -1; } if (gBuf[0] != 0x2e) { - pout("TapeAlerts %s Failed\n", logSenStr); + pout("%sTapeAlerts %s Failed\n", pad, logSenStr); print_off(); return -1; } pagelength = sg_get_unaligned_be16(gBuf + 2); - json::ref jref = jglb["scsi_tapealert"]["status"]; + json::ref jref = jglb[tapealert_s]["status"]; for (s=severities, k = 0, j = 0; *s; s++, ++k) { for (i = 4, m = 0; i < pagelength; i += 5, ++k, ++m) { parametercode = sg_get_unaligned_be16(gBuf + i); @@ -425,9 +428,9 @@ scsiGetTapeAlertsData(scsi_device * device, int peripheral_type) scsiTapeAlertsTapeDevice(parametercode); if (*ts == *s) { if (!failures) - pout("TapeAlert Errors (C=Critical, W=Warning, " - "I=Informational):\n"); - jout("[0x%02x] %s\n", parametercode, ts); + jout("%sTapeAlert Errors (C=Critical, W=Warning, " + "I=Informational):\n", pad); + jout("%s[0x%02x] %s\n", pad, parametercode, ts); jref[j]["descriptor_idx"] = m + 1; jref[j]["parameter_code"] = parametercode; jref[j]["string"] = ts; @@ -440,8 +443,8 @@ scsiGetTapeAlertsData(scsi_device * device, int peripheral_type) print_off(); if (! failures) { - jout("TapeAlert: OK\n"); - jglb["scsi_tapealert"]["status"] = "Good"; + jout("%sTapeAlert: OK\n", pad); + jglb[tapealert_s]["status"] = "Good"; } return failures; @@ -2353,7 +2356,7 @@ show_protocol_specific_port_page(unsigned char * resp, int len) if (SCSI_TPROTO_SAS != (0xf & ucp[4])) return 0; /* only decode SAS log page */ if (0 == k) - jout("Protocol Specific port log page for SAS SSP\n"); + jout("\nProtocol Specific port log page for SAS SSP\n"); show_sas_port_param(j, ucp, param_len); k += param_len; ucp += param_len; @@ -3122,7 +3125,7 @@ scsiPrintEnviroReporting(scsi_device * device) int scsiPrintMain(scsi_device * device, const scsi_print_options & options) { - int checkedSupportedLogPages = 0; + bool checkedSupportedLogPages = false; uint8_t peripheral_type = 0; int returnval = 0; int res, durationSec; @@ -3322,15 +3325,17 @@ scsiPrintMain(scsi_device * device, const scsi_print_options & options) if (options.smart_check_status) { scsiGetSupportedLogPages(device); - checkedSupportedLogPages = 1; + checkedSupportedLogPages = true; if (is_tape) { if (gTapeAlertsLPage) { if (options.drive_info) { jout("TapeAlert Supported\n"); jglb["tapealert"]["supported"] = true; } - if (-1 == scsiGetTapeAlertsData(device, peripheral_type)) - failuretest(OPTIONAL_CMD, returnval |= FAILSMART); + if (options.health_opt_count > 1) { + if (-1 == scsiPrintActiveTapeAlerts(device, peripheral_type, true)) + failuretest(OPTIONAL_CMD, returnval |= FAILSMART); + } } else { jout("TapeAlert Not Supported\n"); jglb["tapealert"]["supported"] = false; @@ -3348,8 +3353,10 @@ scsiPrintMain(scsi_device * device, const scsi_print_options & options) } if (is_disk && options.smart_ss_media_log) { - if (! checkedSupportedLogPages) + if (! checkedSupportedLogPages) { scsiGetSupportedLogPages(device); + checkedSupportedLogPages = true; + } res = 0; if (gSSMediaLPage) res = scsiPrintSSMedia(device); @@ -3362,8 +3369,10 @@ scsiPrintMain(scsi_device * device, const scsi_print_options & options) any_output = true; } if (options.smart_vendor_attrib) { - if (! checkedSupportedLogPages) + if (! checkedSupportedLogPages) { scsiGetSupportedLogPages(device); + checkedSupportedLogPages = true; + } if (gEnviroReportingLPage && options.smart_env_rep) scsiPrintEnviroReporting(device); else if (gTempLPage) @@ -3387,8 +3396,10 @@ scsiPrintMain(scsi_device * device, const scsi_print_options & options) any_output = true; } if (options.smart_error_log) { - if (! checkedSupportedLogPages) + if (! checkedSupportedLogPages) { scsiGetSupportedLogPages(device); + checkedSupportedLogPages = true; + } scsiPrintErrorCounterLog(device); if (gPendDefectsLPage) scsiPrintPendingDefectsLPage(device); @@ -3398,8 +3409,10 @@ scsiPrintMain(scsi_device * device, const scsi_print_options & options) any_output = true; } if (options.smart_selftest_log) { - if (! checkedSupportedLogPages) + if (! checkedSupportedLogPages) { scsiGetSupportedLogPages(device); + checkedSupportedLogPages = true; + } res = 0; if (gSelfTestLPage) res = scsiPrintSelfTest(device); @@ -3412,8 +3425,10 @@ scsiPrintMain(scsi_device * device, const scsi_print_options & options) any_output = true; } if (options.smart_background_log && is_disk) { - if (! checkedSupportedLogPages) + if (! checkedSupportedLogPages) { scsiGetSupportedLogPages(device); + checkedSupportedLogPages = true; + } res = 0; if (gBackgroundResultsLPage) res = scsiPrintBackgroundResults(device, false); @@ -3426,8 +3441,10 @@ scsiPrintMain(scsi_device * device, const scsi_print_options & options) any_output = true; } if (options.smart_background_log && is_zbc) { - if (! checkedSupportedLogPages) + if (! checkedSupportedLogPages) { scsiGetSupportedLogPages(device); + checkedSupportedLogPages = true; + } res = 0; if (gZBDeviceStatsLPage) res = scsiPrintZBDeviceStats(device); @@ -3441,21 +3458,44 @@ scsiPrintMain(scsi_device * device, const scsi_print_options & options) any_output = true; } - if (options.tape_device_stats && is_tape) { - if (! checkedSupportedLogPages) - scsiGetSupportedLogPages(device); - res = 0; - if (gTapeDeviceStatsLPage) - res = scsiPrintTapeDeviceStats(device); - else { - pout("Device does not support (tape) device characteristics " - "(SSC) logging\n"); - failuretest(OPTIONAL_CMD, returnval|=FAILSMART); + if (is_tape) { + if (options.tape_device_stats) { + if (! checkedSupportedLogPages) { + scsiGetSupportedLogPages(device); + checkedSupportedLogPages = true; + } + res = 0; + if (gTapeDeviceStatsLPage) { + jout("\nDevice Statistics (SSC, tape) log page:\n"); + res = scsiPrintTapeDeviceStats(device); + } else { + pout("Device does not support (tape) device characteristics " + "(SSC) logging\n"); + failuretest(OPTIONAL_CMD, returnval|=FAILSMART); + } + if (0 != res) + failuretest(OPTIONAL_CMD, returnval|=res); + any_output = true; + } + if (options.tape_alert) { + if (! checkedSupportedLogPages) { + scsiGetSupportedLogPages(device); + // checkedSupportedLogPages = true; // not needed when last + } + res = 0; + if (gTapeAlertsLPage) { + jout("\nTape Alert log page:\n"); + res = scsiPrintActiveTapeAlerts(device, peripheral_type, false); + } else { + pout("Device does not support TapeAlert logging\n"); + failuretest(OPTIONAL_CMD, returnval|=FAILSMART); + } + if (res < 0) + failuretest(OPTIONAL_CMD, returnval|=res); + if ((scsi_debugmode > 0) && (res == 0)) + pout("TapeAlerts only printed if active, so none printed is good\n"); + any_output = true; } - if (0 != res) - failuretest(OPTIONAL_CMD, returnval|=res); - any_output = true; - } if (options.smart_default_selftest) { if (scsiSmartDefaultSelfTest(device)) diff --git a/smartmontools/scsiprint.h b/smartmontools/scsiprint.h index 5449257dc4221c85b2002b3a9891bd2ce1db970f..3a06c836b4ffaa24e6ee64e8a8d275dec54e3fb1 100644 --- a/smartmontools/scsiprint.h +++ b/smartmontools/scsiprint.h @@ -43,6 +43,7 @@ struct scsi_print_options bool sasphy = false, sasphy_reset = false; bool tape_device_stats = false; + bool tape_alert = false; bool get_wce = false, get_rcd = false; short int set_wce = 0, set_rcd = 0; // disable(-1), enable(1) cache @@ -53,6 +54,8 @@ struct scsi_print_options int set_standby = 0; // set(1..255->0..254) standby timer bool set_standby_now = false; // set drive to standby bool set_active = false; // set drive to active + + int health_opt_count = 0; // TapeAlert log page only read if this value > 1 }; int scsiPrintMain(scsi_device * device, const scsi_print_options & options); diff --git a/smartmontools/smartctl.8.in b/smartmontools/smartctl.8.in index 1de878877148c86f2a5d12051a1e4d561a0939bd..741d1986a1db6024f3dc68d58741f0f60a784833 100644 --- a/smartmontools/smartctl.8.in +++ b/smartmontools/smartctl.8.in @@ -1567,6 +1567,11 @@ drives. Protocol Specific log page (log page 0x18). If \*(Aq\-l sasphy,reset\*(Aq is specified, all counters are reset after reading the values. .Sp +.I tapealert +\- [SCSI tape drives and changers] prints values and descriptions of +the (SSC) Tape Alert log page. See \fBTAPE DRIVES\fP below for issue +associated with printing this log page. +.Sp .I tapedevstat \- [SCSI tape drives and changers] prints values and descriptions of the (SSC) Device Statistics log page. @@ -2291,7 +2296,9 @@ standards can be found at <\fBhttps://www.t10.org/\fP> . Many SMART related features of SCSI disks are shared by SCSI tape drives. One important tape\-specific log page is called "TapeAlert" which is used to report abnormal conditions. Unlike most other log pages the TapeAlert -log page clears pending alerts after that page is fetched (i.e. read from +log page +.B clears +pending alerts after that page is fetched (i.e. read from the tape drive). To be more precise, the TapeAlert log page is cleared for the I_T nexus (initiator-target pair) that sent the (SCSI LOG SENSE) command; so another initiator (e.g. a HBA on another machine) will still diff --git a/smartmontools/smartctl.cpp b/smartmontools/smartctl.cpp index 2f7cbe5ccc2508549dcc1804df328b76feb2d4d0..1021e7a109bad2e40b9c95b76f382392ee8a37ba 100644 --- a/smartmontools/smartctl.cpp +++ b/smartmontools/smartctl.cpp @@ -493,6 +493,7 @@ static int parse_options(int argc, char** argv, const char * & type, case 'H': ataopts.smart_check_status = scsiopts.smart_check_status = nvmeopts.smart_check_status = true; scsiopts.smart_ss_media_log = true; + ++scsiopts.health_opt_count; break; case 'F': if (!strcmp(optarg, "swapid")) @@ -550,6 +551,8 @@ static int parse_options(int argc, char** argv, const char * & type, ataopts.sct_temp_sts = true; } else if (!strcmp(optarg,"scttemphist")) { ataopts.sct_temp_hist = true; + } else if (!strcmp(optarg,"tapealert")) { + scsiopts.tape_alert = true; } else if (!strcmp(optarg,"tapedevstat")) { scsiopts.tape_device_stats = true;