*
* Copyright (C) 2002-11 Bruce Allen
* Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
- * Copyright (C) 2003-15 Douglas Gilbert <dgilbert@interlog.com>
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * (for example COPYING); if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * This code was originally developed as a Senior Thesis by Michael Cornwell
- * at the Concurrent Systems Laboratory (now part of the Storage Systems
- * Research Center), Jack Baskin School of Engineering, University of
- * California, Santa Cruz. http://ssrc.soe.ucsc.edu/
+ * Copyright (C) 2003-18 Douglas Gilbert <dgilbert@interlog.com>
*
+ * SPDX-License-Identifier: GPL-2.0-or-later
*/
+#include "config.h"
+#define __STDC_FORMAT_MACROS 1 // enable PRI* for C++
+
+#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
-#include "config.h"
-#include "int64.h"
#include "scsicmds.h"
#include "atacmds.h" // smart_command_set
#include "dev_interface.h"
#include "scsiprint.h"
#include "smartctl.h"
#include "utility.h"
+#include "sg_unaligned.h"
-#define GBUF_SIZE 65535
+#define GBUF_SIZE 65532
-const char * scsiprint_c_cvsid = "$Id: scsiprint.cpp 4415 2017-03-27 21:14:53Z chrfranke $"
+const char * scsiprint_c_cvsid = "$Id: scsiprint.cpp 4870 2018-12-27 17:07:44Z chrfranke $"
SCSIPRINT_H_CVSID;
-UINT8 gBuf[GBUF_SIZE];
+uint8_t gBuf[GBUF_SIZE];
#define LOG_RESP_LEN 252
#define LOG_RESP_LONG_LEN ((62 * 256) + 252)
#define LOG_RESP_TAPE_ALERT_LEN 0x144
/* Log pages supported */
-static int gSmartLPage = 0; /* Informational Exceptions log page */
-static int gTempLPage = 0;
-static int gSelfTestLPage = 0;
-static int gStartStopLPage = 0;
-static int gReadECounterLPage = 0;
-static int gWriteECounterLPage = 0;
-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 gSSMediaLPage = 0;
+static bool gSmartLPage = false; /* Informational Exceptions log page */
+static bool gTempLPage = false;
+static bool gSelfTestLPage = false;
+static bool gStartStopLPage = false;
+static bool gReadECounterLPage = false;
+static bool gWriteECounterLPage = false;
+static bool gVerifyECounterLPage = false;
+static bool gNonMediumELPage = false;
+static bool gLastNErrorEvLPage = false;
+static bool gBackgroundResultsLPage = false;
+static bool gProtocolSpecificLPage = false;
+static bool gTapeAlertsLPage = false;
+static bool gSSMediaLPage = false;
+static bool gFormatStatusLPage = false;
+static bool gEnviroReportingLPage = false;
+static bool gEnviroLimitsLPage = false;
+static bool gUtilizationLPage = false;
+static bool gPendDefectsLPage = false;
+static bool gBackgroundOpLPage = false;
+static bool gLPSMisalignLPage = false;
/* Vendor specific log pages */
-static int gSeagateCacheLPage = 0;
-static int gSeagateFactoryLPage = 0;
+static bool gSeagateCacheLPage = false;
+static bool gSeagateFactoryLPage = false;
/* Mode pages supported */
-static int gIecMPage = 1; /* N.B. assume it until we know otherwise */
+static bool gIecMPage = true; /* N.B. assume it until we know otherwise */
/* Remember last successful mode sense/select command */
static int modese_len = 0;
+/* Remember this value from the most recent INQUIRY */
+static int scsi_version;
+#define SCSI_VERSION_SPC_4 0x6
+#define SCSI_VERSION_SPC_5 0x7
+#define SCSI_VERSION_HIGHEST SCSI_VERSION_SPC_5
+
+/* T10 vendor identification. Should match entry in last Annex of SPC
+ * drafts and standards (e.g. SPC-4). */
+static char scsi_vendor[8+1];
+#define T10_VENDOR_SEAGATE "SEAGATE"
+#define T10_VENDOR_HITACHI_1 "HITACHI"
+#define T10_VENDOR_HITACHI_2 "HL-DT-ST"
+#define T10_VENDOR_HITACHI_3 "HGST"
+
+static const char * logSenStr = "Log Sense";
+static const char * logSenRspStr = "Log Sense response";
+
+
+static bool
+seagate_or_hitachi(void)
+{
+ return ((0 == memcmp(scsi_vendor, T10_VENDOR_SEAGATE,
+ strlen(T10_VENDOR_SEAGATE))) ||
+ (0 == memcmp(scsi_vendor, T10_VENDOR_HITACHI_1,
+ strlen(T10_VENDOR_HITACHI_1))) ||
+ (0 == memcmp(scsi_vendor, T10_VENDOR_HITACHI_2,
+ strlen(T10_VENDOR_HITACHI_2))) ||
+ (0 == memcmp(scsi_vendor, T10_VENDOR_HITACHI_3,
+ strlen(T10_VENDOR_HITACHI_3))));
+}
+
+static bool
+all_ffs(const uint8_t * bp, int b_len)
+{
+ if ((NULL == bp) || (b_len <= 0))
+ return false;
+ for (--b_len; b_len >= 0; --b_len) {
+ if (0xff != bp[b_len])
+ return false;
+ }
+ return true;
+}
static void
scsiGetSupportedLogPages(scsi_device * device)
{
- int i, err;
+ bool got_subpages = false;
+ int k, bump, err, payload_len, num_unreported, num_unreported_spg;
+ const uint8_t * up;
+ uint8_t sup_lpgs[LOG_RESP_LEN];
+ memset(gBuf, 0, LOG_RESP_LEN);
if ((err = scsiLogSense(device, SUPPORTED_LPAGES, 0, gBuf,
LOG_RESP_LEN, 0))) {
if (scsi_debugmode > 0)
- pout("Log Sense for supported pages failed [%s]\n",
+ pout("%s for supported pages failed [%s]\n", logSenStr,
scsiErrString(err));
/* try one more time with defined length, workaround for the bug #678
found with ST8000NM0075/E001 */
err = scsiLogSense(device, SUPPORTED_LPAGES, 0, gBuf,
LOG_RESP_LEN, 68); /* 64 max pages + 4b header */
if (scsi_debugmode > 0)
- pout("Log Sense for supported pages failed (second attempt) [%s]\n",
- scsiErrString(err));
+ pout("%s for supported pages failed (second attempt) [%s]\n",
+ logSenStr, scsiErrString(err));
if (err)
return;
+ memcpy(sup_lpgs, gBuf, LOG_RESP_LEN);
+ } else if ((scsi_version >= SCSI_VERSION_SPC_4) &&
+ (scsi_version <= SCSI_VERSION_HIGHEST)) {
+ /* unclear what code T10 will choose for SPC-6 */
+ memcpy(sup_lpgs, gBuf, LOG_RESP_LEN);
+ if ((err = scsiLogSense(device, SUPPORTED_LPAGES, SUPP_SPAGE_L_SPAGE,
+ gBuf, LOG_RESP_LONG_LEN,
+ -1 /* just single not double fetch */))) {
+ if (scsi_debugmode > 0)
+ pout("%s for supported pages and subpages failed [%s]\n",
+ logSenStr, scsiErrString(err));
+ } else {
+ if (0 == memcmp(gBuf, sup_lpgs, LOG_RESP_LEN)) {
+ if (scsi_debugmode > 0)
+ pout("%s: %s ignored subpage field, bad\n",
+ __func__, logSenRspStr);
+ } else if (! ((0x40 & gBuf[0]) &&
+ (SUPP_SPAGE_L_SPAGE == gBuf[1]))) {
+ if (scsi_debugmode > 0)
+ pout("%s supported subpages is bad SPF=%u SUBPG=%u\n",
+ logSenRspStr, !! (0x40 & gBuf[0]), gBuf[2]);
+ } else
+ got_subpages = true;
+ }
+ } else
+ memcpy(sup_lpgs, gBuf, LOG_RESP_LEN);
+
+ if (got_subpages) {
+ payload_len = sg_get_unaligned_be16(gBuf + 2);
+ bump = 2;
+ up = gBuf + LOGPAGEHDRSIZE;
+ } else {
+ payload_len = sup_lpgs[3];
+ bump = 1;
+ up = sup_lpgs + LOGPAGEHDRSIZE;
}
- for (i = 4; i < gBuf[3] + LOGPAGEHDRSIZE; i++) {
- switch (gBuf[i])
+ num_unreported_spg = 0;
+ for (num_unreported = 0, k = 0; k < payload_len; k += bump, up += bump) {
+ uint8_t pg_num = 0x3f & up[0];
+ uint8_t sub_pg_num = (0x40 & up[0]) ? up[1] : 0;
+
+ switch (pg_num)
{
+ case SUPPORTED_LPAGES:
+ if (! ((NO_SUBPAGE_L_SPAGE == sub_pg_num) ||
+ (SUPP_SPAGE_L_SPAGE == sub_pg_num))) {
+ if (scsi_debugmode > 1)
+ pout("%s: Strange Log page number: 0x0,0x%x\n",
+ __func__, sub_pg_num);
+ }
+ break;
case READ_ERROR_COUNTER_LPAGE:
- gReadECounterLPage = 1;
+ gReadECounterLPage = true;
break;
case WRITE_ERROR_COUNTER_LPAGE:
- gWriteECounterLPage = 1;
+ gWriteECounterLPage = true;
break;
case VERIFY_ERROR_COUNTER_LPAGE:
- gVerifyECounterLPage = 1;
+ gVerifyECounterLPage = true;
break;
- case LAST_N_ERROR_LPAGE:
- gLastNErrorLPage = 1;
+ case LAST_N_ERROR_EVENTS_LPAGE:
+ gLastNErrorEvLPage = true;
break;
case NON_MEDIUM_ERROR_LPAGE:
- gNonMediumELPage = 1;
+ gNonMediumELPage = true;
break;
case TEMPERATURE_LPAGE:
- gTempLPage = 1;
+ if (NO_SUBPAGE_L_SPAGE == sub_pg_num)
+ gTempLPage = true;
+ else if (ENVIRO_REP_L_SPAGE == sub_pg_num)
+ gEnviroReportingLPage = true;
+ else if (ENVIRO_LIMITS_L_SPAGE == sub_pg_num)
+ gEnviroLimitsLPage = true;
+ else {
+ ++num_unreported;
+ ++num_unreported_spg;
+ }
break;
case STARTSTOP_CYCLE_COUNTER_LPAGE:
- gStartStopLPage = 1;
+ if (NO_SUBPAGE_L_SPAGE == sub_pg_num)
+ gStartStopLPage = true;
+ else if (UTILIZATION_L_SPAGE == sub_pg_num)
+ gUtilizationLPage = true;
+ else {
+ ++num_unreported;
+ ++num_unreported_spg;
+ }
break;
case SELFTEST_RESULTS_LPAGE:
- gSelfTestLPage = 1;
+ gSelfTestLPage = true;
break;
case IE_LPAGE:
- gSmartLPage = 1;
+ gSmartLPage = true;
break;
case BACKGROUND_RESULTS_LPAGE:
- gBackgroundResultsLPage = 1;
+ if (NO_SUBPAGE_L_SPAGE == sub_pg_num)
+ gBackgroundResultsLPage = true;
+ else if (PEND_DEFECTS_L_SPAGE == sub_pg_num)
+ gPendDefectsLPage = true;
+ else if (BACKGROUND_OP_L_SPAGE == sub_pg_num)
+ gBackgroundOpLPage = true;
+ else if (LPS_MISALIGN_L_SPAGE == sub_pg_num)
+ gLPSMisalignLPage = true;
+ else {
+ ++num_unreported;
+ ++num_unreported_spg;
+ }
break;
case PROTOCOL_SPECIFIC_LPAGE:
- gProtocolSpecificLPage = 1;
+ gProtocolSpecificLPage = true;
break;
case TAPE_ALERTS_LPAGE:
- gTapeAlertsLPage = 1;
+ gTapeAlertsLPage = true;
break;
case SS_MEDIA_LPAGE:
- gSSMediaLPage = 1;
+ gSSMediaLPage = true;
+ break;
+ case FORMAT_STATUS_LPAGE:
+ gFormatStatusLPage = true;
break;
case SEAGATE_CACHE_LPAGE:
- gSeagateCacheLPage = 1;
+ if (failuretest_permissive) {
+ gSeagateCacheLPage = true;
+ break;
+ }
+ if (seagate_or_hitachi())
+ gSeagateCacheLPage = true;
break;
case SEAGATE_FACTORY_LPAGE:
- gSeagateFactoryLPage = 1;
+ if (failuretest_permissive) {
+ gSeagateFactoryLPage = true;
+ break;
+ }
+ if (seagate_or_hitachi())
+ gSeagateFactoryLPage = true;
break;
default:
+ if (pg_num < 0x30) { /* don't count VS pages */
+ ++num_unreported;
+ if (sub_pg_num > 0)
+ ++num_unreported_spg;
+ }
break;
}
}
+ if (scsi_debugmode > 1)
+ pout("%s: number of unreported (standard) log pages: %d (sub-pages: "
+ "%d)\n", __func__, num_unreported, num_unreported_spg);
}
/* Returns 0 if ok, -1 if can't check IE, -2 if can check and bad
static int
scsiGetSmartData(scsi_device * device, bool attribs)
{
- UINT8 asc;
- UINT8 ascq;
- UINT8 currenttemp = 255;
- UINT8 triptemp = 255;
+ uint8_t asc;
+ uint8_t ascq;
+ uint8_t currenttemp = 255;
+ uint8_t triptemp = 255;
const char * cp;
int err = 0;
print_on();
if (cp) {
err = -2;
print_on();
- pout("SMART Health Status: %s [asc=%x, ascq=%x]\n", cp, asc, ascq);
+ jout("SMART Health Status: %s [asc=%x, ascq=%x]\n", cp, asc, ascq);
print_off();
- } else if (gIecMPage)
- pout("SMART Health Status: OK\n");
+ jglb["smart_status"]["passed"] = false;
+ jglb["smart_status"]["scsi"]["asc"] = asc;
+ jglb["smart_status"]["scsi"]["ascq"] = ascq;
+ jglb["smart_status"]["scsi"]["ie_string"] = cp;
+ }
+ else if (gIecMPage) {
+ jout("SMART Health Status: OK\n");
+ jglb["smart_status"]["passed"] = true;
+ }
if (attribs && !gTempLPage) {
if (255 == currenttemp)
pout("Current Drive Temperature: <not available>\n");
- else
- pout("Current Drive Temperature: %d C\n", currenttemp);
+ else {
+ jout("Current Drive Temperature: %d C\n", currenttemp);
+ jglb["temperature"]["current"] = currenttemp;
+ }
if (255 == triptemp)
pout("Drive Trip Temperature: <not available>\n");
- else
- pout("Drive Trip Temperature: %d C\n", triptemp);
+ else {
+ jout("Drive Trip Temperature: %d C\n", triptemp);
+ jglb["temperature"]["drive_trip"] = triptemp;
+ }
}
pout("\n");
return err;
return -1;
}
if (gBuf[0] != 0x2e) {
- pout("TapeAlerts Log Sense Failed\n");
+ pout("TapeAlerts %s Failed\n", logSenStr);
print_off();
return -1;
}
- pagelength = (unsigned short) gBuf[2] << 8 | gBuf[3];
+ pagelength = sg_get_unaligned_be16(gBuf + 2);
for (s=severities; *s; s++) {
for (i = 4; i < pagelength; i += 5) {
- parametercode = (unsigned short) gBuf[i] << 8 | gBuf[i+1];
+ parametercode = sg_get_unaligned_be16(gBuf + i);
if (gBuf[i + 4]) {
ts = SCSI_PT_MEDIUM_CHANGER == peripheral_type ?
}
if ((gBuf[0] & 0x3f) != STARTSTOP_CYCLE_COUNTER_LPAGE) {
print_on();
- pout("StartStop Log Sense Failed, page mismatch\n");
+ pout("StartStop %s Failed, page mismatch\n", logSenStr);
print_off();
return;
}
- len = ((gBuf[2] << 8) | gBuf[3]);
+ len = sg_get_unaligned_be16(gBuf + 2);
ucp = gBuf + 4;
for (k = len; k > 0; k -= extra, ucp += extra) {
if (k < 3) {
print_on();
- pout("StartStop Log Sense Failed: short\n");
+ pout("StartStop %s: short\n", logSenRspStr);
print_off();
return;
}
extra = ucp[3] + 4;
- int pc = (ucp[0] << 8) + ucp[1];
- UINT32 u;
+ int pc = sg_get_unaligned_be16(ucp + 0);
+ uint32_t u = (extra > 7) ? sg_get_unaligned_be32(ucp + 4) : 0;
+ bool is_all_ffs = (extra > 7) ? all_ffs(ucp + 4, 4) : false;
switch (pc) {
case 1:
if (10 == extra)
/* ignore Accounting date */
break;
case 3:
- if (extra > 7) {
- u = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7];
- if (0xffffffff != u)
- pout("Specified cycle count over device lifetime: %u\n",
- u);
- }
+ if ((extra > 7) && (! is_all_ffs))
+ pout("Specified cycle count over device lifetime: %u\n", u);
break;
case 4:
- if (extra > 7) {
- u = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7];
- if (0xffffffff != u)
- pout("Accumulated start-stop cycles: %u\n", u);
- }
+ if ((extra > 7) && (! is_all_ffs))
+ pout("Accumulated start-stop cycles: %u\n", u);
break;
case 5:
- if (extra > 7) {
- u = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7];
- if (0xffffffff != u)
- pout("Specified load-unload count over device "
- "lifetime: %u\n", u);
- }
+ if ((extra > 7) && (! is_all_ffs))
+ pout("Specified load-unload count over device lifetime: "
+ "%u\n", u);
break;
case 6:
- if (extra > 7) {
- u = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7];
- if (0xffffffff != u)
- pout("Accumulated load-unload cycles: %u\n", u);
- }
+ if ((extra > 7) && (! is_all_ffs))
+ pout("Accumulated load-unload cycles: %u\n", u);
break;
default:
/* ignore */
}
}
}
+/* PENDING_DEFECTS_SUBPG [0x15,0x1] introduced: SBC-4 */
+static void
+scsiPrintPendingDefectsLPage(scsi_device * device)
+{
+ int num, pl, pc, err;
+ uint32_t count;
+ const uint8_t * bp;
+ static const char * pDefStr = "Pending Defects";
+ static const char * jname = "pending_defects";
+
+ if ((err = scsiLogSense(device, BACKGROUND_RESULTS_LPAGE,
+ PEND_DEFECTS_L_SPAGE, gBuf, LOG_RESP_LONG_LEN,
+ 0))) {
+ print_on();
+ pout("%s Failed [%s]\n", __func__, scsiErrString(err));
+ print_off();
+ return;
+ }
+ if (((gBuf[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE) &&
+ (gBuf[1] != PEND_DEFECTS_L_SPAGE)) {
+ print_on();
+ pout("%s %s, page mismatch\n", pDefStr, logSenRspStr);
+ print_off();
+ return;
+ }
+ num = sg_get_unaligned_be16(gBuf + 2);
+ if (num > LOG_RESP_LONG_LEN) {
+ print_on();
+ pout("%s %s too long\n", pDefStr, logSenRspStr);
+ print_off();
+ return;
+ }
+ bp = gBuf + 4;
+ while (num > 3) {
+ pc = sg_get_unaligned_be16(bp + 0);
+ pl = bp[3] + 4;
+ switch (pc) {
+ case 0x0:
+ printf(" Pending defect count:");
+ if ((pl < 8) || (num < 8)) {
+ print_on();
+ pout("%s truncated descriptor\n", pDefStr);
+ print_off();
+ return;
+ }
+ count = sg_get_unaligned_be32(bp + 4);
+ jglb[jname]["count"] = count;
+ if (0 == count)
+ jout("0 %s\n", pDefStr);
+ else if (1 == count)
+ jout("1 Pending Defect, LBA and accumulated_power_on_hours "
+ "follow\n");
+ else
+ jout("%u %s: index, LBA and accumulated_power_on_hours "
+ "follow\n", count, pDefStr);
+ break;
+ default:
+ if ((pl < 16) || (num < 16)) {
+ print_on();
+ pout("%s truncated descriptor\n", pDefStr);
+ print_off();
+ return;
+ }
+ jout(" %4d: 0x%-16" PRIx64 ", %5u\n", pc,
+ sg_get_unaligned_be64(bp + 8), sg_get_unaligned_be32(bp + 4));
+ jglb[jname][pc]["LBA"] = sg_get_unaligned_be64(bp + 8);
+ jglb[jname][pc]["accum_power_on_hours"] =
+ sg_get_unaligned_be32(bp + 4);
+ break;
+ }
+ num -= pl;
+ bp += pl;
+ }
+}
static void
scsiPrintGrownDefectListLen(scsi_device * device)
{
- int err, dl_format, got_rd12;
+ bool got_rd12;
+ int err, dl_format;
unsigned int dl_len, div;
+ static const char * hname = "Read defect list";
memset(gBuf, 0, 8);
if ((err = scsiReadDefect12(device, 0 /* req_plist */, 1 /* req_glist */,
4 /* format: bytes from index */,
0 /* addr desc index */, gBuf, 8))) {
if (2 == err) { /* command not supported */
- if ((err = scsiReadDefect10(device, 0 /* req_plist */, 1 /* req_glist */,
- 4 /* format: bytes from index */, gBuf, 4))) {
+ err = scsiReadDefect10(device, 0 /* req_plist */,
+ 1 /* req_glist */,
+ 4 /* format: bytes from index */, gBuf, 4);
+ if (err) {
if (scsi_debugmode > 0) {
print_on();
- pout("Read defect list (10) Failed: %s\n", scsiErrString(err));
+ pout("%s (10) Failed: %s\n", hname, scsiErrString(err));
print_off();
}
return;
else {
if (scsi_debugmode > 0) {
print_on();
- pout("Read defect list (12) Failed: %s\n", scsiErrString(err));
+ pout("%s (12) Failed: %s\n", hname, scsiErrString(err));
print_off();
}
return;
}
} else
- got_rd12 = 1;
+ got_rd12 = true;
if (got_rd12) {
- int generation = (gBuf[2] << 8) + gBuf[3];
+ int generation = sg_get_unaligned_be16(gBuf + 2);
if ((generation > 1) && (scsi_debugmode > 0)) {
print_on();
- pout("Read defect list (12): generation=%d\n", generation);
+ pout("%s (12): generation=%d\n", hname, generation);
print_off();
}
- dl_len = (gBuf[4] << 24) + (gBuf[5] << 16) + (gBuf[6] << 8) + gBuf[7];
- } else {
- dl_len = (gBuf[2] << 8) + gBuf[3];
- }
+ dl_len = sg_get_unaligned_be32(gBuf + 4);
+ } else
+ dl_len = sg_get_unaligned_be16(gBuf + 2);
if (0x8 != (gBuf[1] & 0x18)) {
print_on();
- pout("Read defect list: asked for grown list but didn't get it\n");
+ pout("%s: asked for grown list but didn't get it\n", hname);
print_off();
return;
}
print_off();
break;
}
- if (0 == dl_len)
- pout("Elements in grown defect list: 0\n\n");
+ if (0 == dl_len) {
+ jout("Elements in grown defect list: 0\n\n");
+ jglb["scsi_grown_defect_list"] = 0;
+ }
else {
if (0 == div)
pout("Grown defect list length=%u bytes [unknown "
"number of elements]\n\n", dl_len);
- else
- pout("Elements in grown defect list: %u\n\n", dl_len / div);
+ else {
+ jout("Elements in grown defect list: %u\n\n", dl_len / div);
+ jglb["scsi_grown_defect_list"] = dl_len;
+ }
}
}
int num, pl, pc, err, len;
unsigned char * ucp;
uint64_t ull;
+ static const char * seaCacStr = "Seagate Cache";
if ((err = scsiLogSense(device, SEAGATE_CACHE_LPAGE, 0, gBuf,
LOG_RESP_LEN, 0))) {
- print_on();
- pout("Seagate Cache Log Sense Failed: %s\n", scsiErrString(err));
- print_off();
+ if (scsi_debugmode > 0) {
+ print_on();
+ pout("%s %s Failed: %s\n", seaCacStr, logSenStr,
+ scsiErrString(err));
+ print_off();
+ }
return;
}
if ((gBuf[0] & 0x3f) != SEAGATE_CACHE_LPAGE) {
- print_on();
- pout("Seagate Cache Log Sense Failed, page mismatch\n");
- print_off();
+ if (scsi_debugmode > 0) {
+ print_on();
+ pout("%s %s, page mismatch\n", seaCacStr, logSenRspStr);
+ print_off();
+ }
return;
}
- len = ((gBuf[2] << 8) | gBuf[3]) + 4;
+ len = sg_get_unaligned_be16(gBuf + 2) + 4;
num = len - 4;
ucp = &gBuf[0] + 4;
while (num > 3) {
- pc = (ucp[0] << 8) | ucp[1];
+ pc = sg_get_unaligned_be16(ucp + 0);
pl = ucp[3] + 4;
switch (pc) {
case 0: case 1: case 2: case 3: case 4:
default:
if (scsi_debugmode > 0) {
print_on();
- pout("Vendor (Seagate) cache lpage has unexpected parameter"
- ", skip\n");
+ pout("Vendor (%s) lpage has unexpected parameter, skip\n",
+ seaCacStr);
print_off();
}
return;
num -= pl;
ucp += pl;
}
- pout("Vendor (Seagate) cache information\n");
+ pout("Vendor (%s) information\n", seaCacStr);
num = len - 4;
ucp = &gBuf[0] + 4;
while (num > 3) {
- pc = (ucp[0] << 8) | ucp[1];
+ pc = sg_get_unaligned_be16(ucp + 0);
pl = ucp[3] + 4;
switch (pc) {
case 0: pout(" Blocks sent to initiator"); break;
default: pout(" Unknown Seagate parameter code [0x%x]", pc); break;
}
int k = pl - 4;
+ const int sz_ull = (int)sizeof(ull);
unsigned char * xp = ucp + 4;
- if (k > (int)sizeof(ull)) {
- xp += (k - (int)sizeof(ull));
- k = (int)sizeof(ull);
- }
- ull = 0;
- for (int j = 0; j < k; ++j) {
- if (j > 0)
- ull <<= 8;
- ull |= xp[j];
+ if (k > sz_ull) {
+ xp += (k - sz_ull);
+ k = sz_ull;
}
+ ull = sg_get_unaligned_be(k, xp + 0);
pout(" = %" PRIu64 "\n", ull);
num -= pl;
ucp += pl;
if ((err = scsiLogSense(device, SEAGATE_FACTORY_LPAGE, 0, gBuf,
LOG_RESP_LEN, 0))) {
- print_on();
- pout("%s Failed [%s]\n", __func__, scsiErrString(err));
- print_off();
+ if (scsi_debugmode > 0) {
+ print_on();
+ pout("%s Failed [%s]\n", __func__, scsiErrString(err));
+ print_off();
+ }
return;
}
if ((gBuf[0] & 0x3f) != SEAGATE_FACTORY_LPAGE) {
- print_on();
- pout("Seagate/Hitachi Factory Log Sense Failed, page mismatch\n");
- print_off();
+ if (scsi_debugmode > 0) {
+ print_on();
+ pout("Seagate/Hitachi Factory %s, page mismatch\n", logSenRspStr);
+ print_off();
+ }
return;
}
- len = ((gBuf[2] << 8) | gBuf[3]) + 4;
+ len = sg_get_unaligned_be16(gBuf + 2) + 4;
num = len - 4;
ucp = &gBuf[0] + 4;
good = 0;
bad = 0;
while (num > 3) {
- pc = (ucp[0] << 8) | ucp[1];
+ pc = sg_get_unaligned_be16(ucp + 0);
pl = ucp[3] + 4;
switch (pc) {
case 0: case 8:
num = len - 4;
ucp = &gBuf[0] + 4;
while (num > 3) {
- pc = (ucp[0] << 8) | ucp[1];
+ pc = sg_get_unaligned_be16(ucp + 0);
pl = ucp[3] + 4;
good = 0;
switch (pc) {
xp += (k - (int)sizeof(ull));
k = (int)sizeof(ull);
}
- ull = 0;
- for (int j = 0; j < k; ++j) {
- if (j > 0)
- ull <<= 8;
- ull |= xp[j];
- }
- if (0 == pc)
+ ull = sg_get_unaligned_be(k, xp + 0);
+ if (0 == pc) {
pout(" = %.2f\n", ull / 60.0 );
+ jglb["power_on_time"]["hours"] = ull / 60;
+ jglb["power_on_time"]["minutes"] = ull % 60;
+ }
else
pout(" = %" PRIu64 "\n", ull);
}
"algorithm processed uncorrected\n");
pout(" fast | delayed rewrites corrected "
"invocations [10^9 bytes] errors\n");
+
+ json::ref jref = jglb["scsi_error_counter_log"];
for (int k = 0; k < 3; ++k) {
if (! found[k])
continue;
ecp = &errCounterArr[k];
- static const char * const pageNames[3] = {"read: ", "write: ", "verify: "};
- pout("%s%8" PRIu64 " %8" PRIu64 " %8" PRIu64 " %8" PRIu64 " %8" PRIu64,
- pageNames[k], ecp->counter[0], ecp->counter[1],
- ecp->counter[2], ecp->counter[3], ecp->counter[4]);
+ static const char * const pageNames[3] =
+ {"read: ", "write: ", "verify: "};
+ static const char * jpageNames[3] =
+ {"read", "write", "verify"};
+ jout("%s%8" PRIu64 " %8" PRIu64 " %8" PRIu64 " %8" PRIu64
+ " %8" PRIu64, pageNames[k], ecp->counter[0],
+ ecp->counter[1], ecp->counter[2], ecp->counter[3],
+ ecp->counter[4]);
double processed_gb = ecp->counter[5] / 1000000000.0;
- pout(" %12.3f %8" PRIu64 "\n", processed_gb, ecp->counter[6]);
+ jout(" %12.3f %8" PRIu64 "\n", processed_gb,
+ ecp->counter[6]);
+ // Error counter log info
+ jref[jpageNames[k]]["errors_corrected_by_eccfast"] = ecp->counter[0];
+ jref[jpageNames[k]]["errors_corrected_by_eccdelayed"] = ecp->counter[1];
+ jref[jpageNames[k]]["errors_corrected_by_rereads_rewrites"] = ecp->counter[2];
+ jref[jpageNames[k]]["total_errors_corrected"] = ecp->counter[3];
+ jref[jpageNames[k]]["correction_algorithm_invocations"] = ecp->counter[4];
+ jref[jpageNames[k]]["gigabytes_processed"] = strprintf("%.3f", processed_gb);
+ jref[jpageNames[k]]["total_uncorrected_errors"] = ecp->counter[6];
}
}
else
pout("Positioning error count [Hitachi]: %8" PRIu64 "\n",
nme.counterPE_H);
}
- if (gLastNErrorLPage && (0 == scsiLogSense(device,
- LAST_N_ERROR_LPAGE, 0, gBuf, LOG_RESP_LONG_LEN, 0))) {
- int num = (gBuf[2] << 8) + gBuf[3] + 4;
+ if (gLastNErrorEvLPage &&
+ (0 == scsiLogSense(device, LAST_N_ERROR_EVENTS_LPAGE, 0, gBuf,
+ LOG_RESP_LONG_LEN, 0))) {
+ int num = sg_get_unaligned_be16(gBuf + 2) + 4;
int truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
if (truncated)
num = LOG_RESP_LONG_LEN;
break;
}
pl = ucp[3] + 4;
- int pc = (ucp[0] << 8) + ucp[1];
+ int pc = sg_get_unaligned_be16(ucp + 0);
if (pl > 4) {
if ((ucp[2] & 0x1) && (ucp[2] & 0x2)) {
pout(" Error event %d:\n", pc);
pout(" [binary]:\n");
- dStrHex((const char *)ucp + 4, pl - 4, 1);
+ dStrHex((const uint8_t *)ucp + 4, pl - 4, 1);
} else if (ucp[2] & 0x1) {
pout(" Error event %d:\n", pc);
pout(" %.*s\n", pl - 4, (const char *)(ucp + 4));
if (scsi_debugmode > 0) {
pout(" Error event %d:\n", pc);
pout(" [data counter??]:\n");
- dStrHex((const char *)ucp + 4, pl - 4, 1);
+ dStrHex((const uint8_t *)ucp + 4, pl - 4, 1);
}
}
}
int num, k, err, durationSec;
int noheader = 1;
int retval = 0;
- UINT8 * ucp;
- uint64_t ull=0;
+ uint8_t * ucp;
+ uint64_t ull;
struct scsi_sense_disect sense_info;
+ static const char * hname = "Self-test";
// check if test is running
if (!scsiRequestSense(device, &sense_info) &&
(sense_info.asc == 0x04 && sense_info.ascq == 0x09 &&
sense_info.progress != -1)) {
- pout("Self-test execution status:\t\t%d%% of test remaining\n",
+ pout("%s execution status:\t\t%d%% of test remaining\n", hname,
100 - ((sense_info.progress * 100) / 65535));
}
}
if ((gBuf[0] & 0x3f) != SELFTEST_RESULTS_LPAGE) {
print_on();
- pout("Self-test Log Sense Failed, page mismatch\n");
+ pout("%s %s, page mismatch\n", hname, logSenRspStr);
print_off();
return FAILSMART;
}
// compute page length
- num = (gBuf[2] << 8) + gBuf[3];
+ num = sg_get_unaligned_be16(gBuf + 2);
// Log sense page length 0x190 bytes
if (num != 0x190) {
print_on();
- pout("Self-test Log Sense length is 0x%x not 0x190 bytes\n",num);
+ pout("%s %s length is 0x%x not 0x190 bytes\n", hname, logSenStr, num);
print_off();
return FAILSMART;
}
// loop through the twenty possible entries
for (k = 0, ucp = gBuf + 4; k < 20; ++k, ucp += 20 ) {
- int i;
-
// timestamp in power-on hours (or zero if test in progress)
- int n = (ucp[6] << 8) | ucp[7];
+ int n = sg_get_unaligned_be16(ucp + 6);
// The spec says "all 20 bytes will be zero if no test" but
// DG has found otherwise. So this is a heuristic.
// only print header if needed
if (noheader) {
- pout("SMART Self-test log\n");
+ pout("SMART %s log\n", hname);
pout("Num Test Status segment "
"LifeTime LBA_first_err [SK ASC ASQ]\n");
pout(" Description number "
}
// print parameter code (test number) & self-test code text
- pout("#%2d %s", (ucp[0] << 8) | ucp[1],
+ pout("#%2d %s", sg_get_unaligned_be16(ucp + 0),
self_test_code[(ucp[4] >> 5) & 0x7]);
// check the self-test result nibble, using the self-test results
pout(" %5d", n);
// construct 8-byte integer address of first failure
- for (i = 0; i < 8; i++) {
- ull <<= 8;
- ull |= ucp[i+8];
- }
+ ull = sg_get_unaligned_be64(ucp + 8);
+ bool is_all_ffs = all_ffs(ucp + 8, 8);
// print Address of First Failure, if sensible
- if ((~(uint64_t)0 != ull) && (res > 0) && (res < 0xf)) {
+ if ((! is_all_ffs) && (res > 0) && (res < 0xf)) {
char buff[32];
// was hex but change to decimal to conform with ATA
// if header never printed, then there was no output
if (noheader)
- pout("No self-tests have been logged\n");
+ pout("No %ss have been logged\n", hname);
else
if ((0 == scsiFetchExtendedSelfTestTime(device, &durationSec,
modese_len)) && (durationSec > 0)) {
- pout("\nLong (extended) Self Test duration: %d seconds "
- "[%.1f minutes]\n", durationSec, durationSec / 60.0);
+ pout("\nLong (extended) %s duration: %d seconds "
+ "[%.1f minutes]\n", hname, durationSec, durationSec / 60.0);
}
pout("\n");
return retval;
int noheader = 1;
int firstresult = 1;
int retval = 0;
- UINT8 * ucp;
+ uint8_t * ucp;
+ static const char * hname = "Background scan results";
if ((err = scsiLogSense(device, BACKGROUND_RESULTS_LPAGE, 0, gBuf,
LOG_RESP_LONG_LEN, 0))) {
}
if ((gBuf[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE) {
print_on();
- pout("Background scan results Log Sense Failed, page mismatch\n");
+ pout("%s %s, page mismatch\n", hname, logSenRspStr);
print_off();
return FAILSMART;
}
// compute page length
- num = (gBuf[2] << 8) + gBuf[3] + 4;
+ num = sg_get_unaligned_be16(gBuf + 2) + 4;
if (num < 20) {
print_on();
- pout("Background scan results Log Sense length is %d, no scan "
- "status\n", num);
+ pout("%s %s length is %d, no scan status\n", hname, logSenStr, num);
print_off();
return FAILSMART;
}
ucp = gBuf + 4;
num -= 4;
while (num > 3) {
- int pc = (ucp[0] << 8) | ucp[1];
+ int pc = sg_get_unaligned_be16(ucp + 0);
// pcb = ucp[2];
int pl = ucp[3] + 4;
switch (pc) {
case 0:
if (noheader) {
noheader = 0;
- pout("Background scan results log\n");
+ pout("%s log\n", hname);
}
pout(" Status: ");
if ((pl < 16) || (num < 16)) {
pout("%s\n", bms_status[j]);
else
pout("unknown [0x%x] background scan status value\n", j);
- j = (ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7];
+ j = sg_get_unaligned_be32(ucp + 4);
pout(" Accumulated power on time, hours:minutes %d:%02d "
"[%d minutes]\n", (j / 60), (j % 60), j);
+ jglb["power_on_time"]["hours"] = j / 60;
+ jglb["power_on_time"]["minutes"] = j % 60;
pout(" Number of background scans performed: %d, ",
- (ucp[10] << 8) + ucp[11]);
+ sg_get_unaligned_be16(ucp + 10));
pout("scan progress: %.2f%%\n",
- (double)((ucp[12] << 8) + ucp[13]) * 100.0 / 65536.0);
+ (double)sg_get_unaligned_be16(ucp + 12) * 100.0 / 65536.0);
pout(" Number of background medium scans performed: %d\n",
- (ucp[14] << 8) + ucp[15]);
+ sg_get_unaligned_be16(ucp + 14));
break;
default:
if (noheader) {
noheader = 0;
- pout("\nBackground scan results log\n");
+ pout("\n%s log\n", hname);
}
if (firstresult) {
firstresult = 0;
pout("parameter length >= 24 expected, got %d\n", pl);
break;
}
- j = (ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7];
+ j = sg_get_unaligned_be32(ucp + 4);
pout("%4d:%02d ", (j / 60), (j % 60));
for (m = 0; m < 8; ++m)
pout("%02x", ucp[16 + m]);
{
int num, err, truncated;
int retval = 0;
- UINT8 * ucp;
+ uint8_t * ucp;
+ static const char * hname = "Solid state media";
if ((err = scsiLogSense(device, SS_MEDIA_LPAGE, 0, gBuf,
LOG_RESP_LONG_LEN, 0))) {
}
if ((gBuf[0] & 0x3f) != SS_MEDIA_LPAGE) {
print_on();
- pout("Solid state media Log Sense Failed, page mismatch\n");
+ pout("%s %s, page mismatch\n", hname, logSenStr);
print_off();
return FAILSMART;
}
// compute page length
- num = (gBuf[2] << 8) + gBuf[3] + 4;
+ num = sg_get_unaligned_be16(gBuf + 2) + 4;
if (num < 12) {
print_on();
- pout("Solid state media Log Sense length is %d, too short\n", num);
+ pout("%s %s length is %d, too short\n", hname, logSenStr, num);
print_off();
return FAILSMART;
}
ucp = gBuf + 4;
num -= 4;
while (num > 3) {
- int pc = (ucp[0] << 8) | ucp[1];
+ int pc = sg_get_unaligned_be16(ucp + 0);
// pcb = ucp[2];
int pl = ucp[3] + 4;
switch (pc) {
case 1:
if (pl < 8) {
print_on();
- pout("SS Media Percentage used endurance indicator parameter "
- "too short (pl=%d)\n", pl);
+ pout("%s Percentage used endurance indicator parameter "
+ "too short (pl=%d)\n", hname, pl);
print_off();
return FAILSMART;
}
- pout("Percentage used endurance indicator: %d%%\n", ucp[7]);
+ jout("Percentage used endurance indicator: %d%%\n", ucp[7]);
+ jglb["scsi_percentage_used_endurance_indicator"] = ucp[7];
default: /* ignore other parameter codes */
break;
}
return retval;
}
+static int
+scsiPrintFormatStatus(scsi_device * device)
+{
+ bool is_count;
+ int k, num, err, truncated;
+ int retval = 0;
+ uint64_t ull;
+ uint8_t * ucp;
+ uint8_t * xp;
+ const char * jout_str;
+ const char * jglb_str;
+ static const char * hname = "Format Status";
+ static const char * jname = "format_status";
+
+ if ((err = scsiLogSense(device, FORMAT_STATUS_LPAGE, 0, gBuf,
+ LOG_RESP_LONG_LEN, 0))) {
+ print_on();
+ jout("%s: Failed [%s]\n", __func__, scsiErrString(err));
+ print_off();
+ return FAILSMART;
+ }
+ if ((gBuf[0] & 0x3f) != FORMAT_STATUS_LPAGE) {
+ print_on();
+ jout("%s %s, page mismatch\n", hname, logSenRspStr);
+ print_off();
+ return FAILSMART;
+ }
+ // compute page length
+ num = sg_get_unaligned_be16(gBuf + 2) + 4;
+ if (num < 12) {
+ print_on();
+ jout("%s %s length is %d, too short\n", hname, logSenStr, num);
+ print_off();
+ return FAILSMART;
+ }
+ truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
+ if (truncated)
+ num = LOG_RESP_LONG_LEN;
+ ucp = gBuf + 4;
+ num -= 4;
+ while (num > 3) {
+ int pc = sg_get_unaligned_be16(ucp + 0);
+ // pcb = ucp[2];
+ int pl = ucp[3] + 4;
+
+ is_count = true;
+ jout_str = "";
+ jglb_str = "x";
+ switch (pc) {
+ case 0:
+ if (scsi_debugmode > 1) {
+ if (pl < 5)
+ jout("Format data out: <empty>\n");
+ else {
+ if (all_ffs(ucp + 4, pl - 4))
+ jout("Format data out: <not available>\n");
+ else {
+ jout("Format data out:\n");
+ dStrHex((const uint8_t *)ucp + 4, pl - 4, 0);
+ }
+ }
+ }
+ is_count = false;
+ break;
+ case 1:
+ jout_str = "Grown defects during certification";
+ jglb_str = "grown_defects_during_cert";
+ break;
+ case 2:
+ jout_str = "Total blocks reassigned during format";
+ jglb_str = "blocks_reassigned_during_format";
+ break;
+ case 3:
+ jout_str = "Total new blocks reassigned";
+ jglb_str = "total_new_block_since_format";
+ break;
+ case 4:
+ jout_str = "Power on minutes since format";
+ jglb_str = "power_on_minutes_since_format";
+ break;
+ default:
+ if (scsi_debugmode > 3) {
+ pout(" Unknown Format parameter code = 0x%x\n", pc);
+ dStrHex((const uint8_t *)ucp, pl, 0);
+ }
+ is_count = false;
+ break;
+ }
+ if (is_count) {
+ k = pl - 4;
+ xp = ucp + 4;
+ if (all_ffs(xp, k)) {
+ pout("%s <not available>\n", jout_str);
+ } else {
+ if (k > (int)sizeof(ull)) {
+ xp += (k - sizeof(ull));
+ k = sizeof(ull);
+ }
+ ull = sg_get_unaligned_be(k, xp);
+ jout("%s = %" PRIu64 "\n", jout_str, ull);
+ jglb[jname][jglb_str] = ull;
+ }
+ } else
+ num -= pl;
+ ucp += pl;
+ }
+ return retval;
+
+}
+
static void
show_sas_phy_event_info(int peis, unsigned int val, unsigned thresh_val)
{
pout(" Received retry-class OPEN_REJECT count: %u\n", val);
break;
case 0x25:
- pout(" Received AIP (WATING ON PARTIAL) count: %u\n", val);
+ pout(" Received AIP (WAITING ON PARTIAL) count: %u\n", val);
break;
case 0x26:
pout(" Received AIP (WAITING ON CONNECTION) count: %u\n", val);
static void
show_sas_port_param(unsigned char * ucp, int param_len)
{
- int j, m, n, nphys, t, sz, spld_len;
+ int j, m, nphys, t, sz, spld_len;
unsigned char * vcp;
char s[64];
sz = sizeof(s);
// pcb = ucp[2];
- t = (ucp[0] << 8) | ucp[1];
+ t = sg_get_unaligned_be16(ucp + 0);
pout("relative target port id = %d\n", t);
pout(" generation code = %d\n", ucp[6]);
nphys = ucp[7];
pout(" attached target port: ssp=%d stp=%d smp=%d\n",
!! (vcp[7] & 8), !! (vcp[7] & 4), !! (vcp[7] & 2));
if (!dont_print_serial_number) {
- uint64_t ull;
- for (n = 0, ull = vcp[8]; n < 8; ++n) {
- ull <<= 8; ull |= vcp[8 + n];
- }
+ uint64_t ull = sg_get_unaligned_be64(vcp + 8);
+
pout(" SAS address = 0x%" PRIx64 "\n", ull);
- for (n = 0, ull = vcp[16]; n < 8; ++n) {
- ull <<= 8; ull |= vcp[16 + n];
- }
+ ull = sg_get_unaligned_be64(vcp + 16);
pout(" attached SAS address = 0x%" PRIx64 "\n", ull);
}
pout(" attached phy identifier = %d\n", vcp[24]);
- unsigned int ui;
- ui = (vcp[32] << 24) | (vcp[33] << 16) | (vcp[34] << 8) | vcp[35];
+ unsigned int ui = sg_get_unaligned_be32(vcp + 32);
+
pout(" Invalid DWORD count = %u\n", ui);
- ui = (vcp[36] << 24) | (vcp[37] << 16) | (vcp[38] << 8) | vcp[39];
+ ui = sg_get_unaligned_be32(vcp + 36);
pout(" Running disparity error count = %u\n", ui);
- ui = (vcp[40] << 24) | (vcp[41] << 16) | (vcp[42] << 8) | vcp[43];
+ ui = sg_get_unaligned_be32(vcp + 40);
pout(" Loss of DWORD synchronization = %u\n", ui);
- ui = (vcp[44] << 24) | (vcp[45] << 16) | (vcp[46] << 8) | vcp[47];
+ ui = sg_get_unaligned_be32(vcp + 44);
pout(" Phy reset problem = %u\n", ui);
if (spld_len > 51) {
int num_ped;
int peis;
unsigned int pvdt;
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];
+ ui = sg_get_unaligned_be32(xcp + 4);
+ pvdt = sg_get_unaligned_be32(xcp + 8);
show_sas_phy_event_info(peis, ui, pvdt);
}
}
num = len - 4;
for (k = 0, ucp = resp + 4; k < num; ) {
int param_len = ucp[3] + 4;
- if (6 != (0xf & ucp[4]))
+ if (SCSI_TPROTO_SAS != (0xf & ucp[4]))
return 0; /* only decode SAS log page */
if (0 == k)
pout("Protocol Specific port log page for SAS SSP\n");
scsiPrintSasPhy(scsi_device * device, int reset)
{
int num, err;
+ static const char * hname = "Protocol specific port";
if ((err = scsiLogSense(device, PROTOCOL_SPECIFIC_LPAGE, 0, gBuf,
LOG_RESP_LONG_LEN, 0))) {
print_on();
- pout("%s Log Sense Failed [%s]\n\n", __func__, scsiErrString(err));
+ pout("%s %s Failed [%s]\n\n", __func__, logSenStr,
+ scsiErrString(err));
print_off();
return FAILSMART;
}
if ((gBuf[0] & 0x3f) != PROTOCOL_SPECIFIC_LPAGE) {
print_on();
- pout("Protocol specific Log Sense Failed, page mismatch\n\n");
+ pout("%s %s, page mismatch\n\n", hname, logSenRspStr);
print_off();
return FAILSMART;
}
// compute page length
- num = (gBuf[2] << 8) + gBuf[3];
+ num = sg_get_unaligned_be16(gBuf + 2);
if (1 != show_protocol_specific_page(gBuf, num + 4)) {
print_on();
- pout("Only support protocol specific log page on SAS devices\n\n");
+ pout("Only support %s log page on SAS devices\n\n", hname);
print_off();
return FAILSMART;
}
"unknown or no device type",
};
+/* Symbolic indexes to this array SCSI_TPROTO_* in scscmds.h */
static const char * transport_proto_arr[] = {
"Fibre channel (FCP-2)",
"Parallel SCSI (SPI-4)",
"ATA (ACS-2)",
"UAS",
"SOP",
- "0xb",
+ "PCIe",
"0xc",
"0xd",
"0xe",
- "0xf"
+ "None given [0xf]"
};
/* Returns 0 on success, 1 on general error and 2 for early, clean exit */
static int
-scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool all)
+scsiGetDriveInfo(scsi_device * device, uint8_t * peripheral_type, bool all)
{
- char timedatetz[DATEANDEPOCHLEN];
struct scsi_iec_mode_page iec;
- int err, iec_err, len, req_len, avail_len, scsi_version;
+ int err, iec_err, len, req_len, avail_len;
bool is_tape = false;
int peri_dt = 0;
int transport = -1;
pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err));
pout("Retrying with a 64 byte Standard Inquiry\n");
print_off();
- /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */
+ /* Marvell controllers fail with 36 byte StdInquiry, but 64 is ok */
req_len = 64;
if ((err = scsiStdInquiry(device, gBuf, req_len))) {
print_on();
scsi_version = gBuf[2] & 0x7;
if (all && (0 != strncmp((char *)&gBuf[8], "ATA", 3))) {
- char vendor[8+1], product[16+1], revision[4+1];
- scsi_format_id_string(vendor, (const unsigned char *)&gBuf[8], 8);
- scsi_format_id_string(product, (const unsigned char *)&gBuf[16], 16);
- scsi_format_id_string(revision, (const unsigned char *)&gBuf[32], 4);
+ char product[16+1], revision[4+1];
+ scsi_format_id_string(scsi_vendor, &gBuf[8], 8);
+ scsi_format_id_string(product, &gBuf[16], 16);
+ scsi_format_id_string(revision, &gBuf[32], 4);
pout("=== START OF INFORMATION SECTION ===\n");
- pout("Vendor: %.8s\n", vendor);
- pout("Product: %.16s\n", product);
- if (gBuf[32] >= ' ')
- pout("Revision: %.4s\n", revision);
- if (scsi_version == 0x6)
- pout("Compliance: SPC-4\n");
- else if (scsi_version == 0x7)
- pout("Compliance: SPC-5\n");
+ jout("Vendor: %.8s\n", scsi_vendor);
+ jglb["vendor"] = scsi_vendor;
+ jout("Product: %.16s\n", product);
+ jglb["product"] = product;
+ jglb["model_name"] = strprintf("%s%s%s",
+ scsi_vendor, (*scsi_vendor && *product ? " " : ""), product);
+ if (gBuf[32] >= ' ') {
+ jout("Revision: %.4s\n", revision);
+ // jglb["firmware_version"] = revision;
+ jglb["revision"] = revision; /* could be a hardware rev */
+ }
+ if ((scsi_version > 0x3) && (scsi_version < 0x8)) {
+ char sv_arr[8];
+
+ snprintf(sv_arr, sizeof(sv_arr), "SPC-%d", scsi_version - 2);
+ jout("Compliance: %s\n", sv_arr);
+ jglb["scsi_version"] = sv_arr;
+ }
}
if (!*device->get_req_type()/*no type requested*/ &&
protect = gBuf[5] & 0x1; /* from and including SPC-3 */
if (! is_tape) { /* assume disk if not tape drive (or tape changer) */
- unsigned int lb_size = 0;
+ struct scsi_readcap_resp srr;
+ int lbpme = -1;
+ int lbprz = -1;
unsigned char lb_prov_resp[8];
- char lb_str[16];
- int lb_per_pb_exp = 0;
- uint64_t capacity = scsiGetSize(device, &lb_size, &lb_per_pb_exp);
+ uint64_t capacity = scsiGetSize(device, false /*avoid_rcap16 */,
+ &srr);
if (capacity) {
char cap_str[64], si_str[64];
format_with_thousands_sep(cap_str, sizeof(cap_str), capacity);
format_capacity(si_str, sizeof(si_str), capacity);
- pout("User Capacity: %s bytes [%s]\n", cap_str, si_str);
- snprintf(lb_str, sizeof(lb_str) - 1, "%u", lb_size);
- pout("Logical block size: %s bytes\n", lb_str);
- }
- int lbpme = -1;
- int lbprz = -1;
- if (protect || lb_per_pb_exp) {
- unsigned char rc16_12[20] = {0, };
-
- if (0 == scsiGetProtPBInfo(device, rc16_12)) {
- lb_per_pb_exp = rc16_12[1] & 0xf; /* just in case */
- if (lb_per_pb_exp > 0) {
- snprintf(lb_str, sizeof(lb_str) - 1, "%u",
- (lb_size * (1 << lb_per_pb_exp)));
- pout("Physical block size: %s bytes\n", lb_str);
- int n = ((rc16_12[2] & 0x3f) << 8) + rc16_12[3];
- if (n > 0) // not common so cut the clutter
- pout("Lowest aligned LBA: %d\n", n);
+ jout("User Capacity: %s bytes [%s]\n", cap_str, si_str);
+ if (srr.lb_size)
+ jglb["user_capacity"]["blocks"].set_unsafe_uint64(capacity /
+ srr.lb_size);
+ jglb["user_capacity"]["bytes"].set_unsafe_uint64(capacity);
+ jout("Logical block size: %u bytes\n", srr.lb_size);
+ jglb["logical_block_size"] = srr.lb_size;
+ if (protect || srr.lb_p_pb_exp) {
+ if (srr.lb_p_pb_exp > 0) {
+ unsigned pb_size = srr.lb_size * (1 << srr.lb_p_pb_exp);
+ jout("Physical block size: %u bytes\n", pb_size);
+ jglb["physical_block_size"] = pb_size;
+ if (srr.l_a_lba > 0) // not common so cut the clutter
+ pout("Lowest aligned LBA: %u\n", srr.l_a_lba);
}
- if (rc16_12[0] & 0x1) { /* PROT_EN set */
- int p_type = ((rc16_12[0] >> 1) & 0x7);
-
- switch (p_type) {
- case 0 :
+ if (srr.prot_type > 0) {
+ switch (srr.prot_type) {
+ case 1 :
pout("Formatted with type 1 protection\n");
break;
- case 1 :
+ case 2 :
pout("Formatted with type 2 protection\n");
break;
- case 2 :
+ case 3 :
pout("Formatted with type 3 protection\n");
break;
default:
pout("Formatted with unknown protection type [%d]\n",
- p_type);
+ srr.prot_type);
break;
}
- int p_i_exp = ((rc16_12[1] >> 4) & 0xf);
+ unsigned p_i_per_lb = (1 << srr.p_i_exp);
+ const unsigned pi_sz = 8; /* ref-tag(4 bytes),
+ app-tag(2), tag-mask(2) */
- if (p_i_exp > 0)
+ if (p_i_per_lb > 1)
pout("%d protection information intervals per "
- "logical block\n", (1 << p_i_exp));
+ "logical block\n", p_i_per_lb);
+ pout("%d bytes of protection information per logical "
+ "block\n", pi_sz * p_i_per_lb);
}
/* Pick up some LB provisioning info since its available */
- lbpme = !! (rc16_12[2] & 0x80);
- lbprz = !! (rc16_12[2] & 0x40);
+ lbpme = (int)srr.lbpme;
+ lbprz = (int)srr.lbprz;
}
}
/* Thin Provisioning VPD page renamed Logical Block Provisioning VPD
if (0 == rpm)
; // Not reported
else if (1 == rpm)
- pout("Rotation Rate: Solid State Device\n");
+ jout("Rotation Rate: Solid State Device\n");
else if ((rpm <= 0x400) || (0xffff == rpm))
; // Reserved
else
- pout("Rotation Rate: %d rpm\n", rpm);
+ jout("Rotation Rate: %d rpm\n", rpm);
+ jglb["rotation_rate"] = (rpm == 1 ? 0 : rpm);
}
if (form_factor > 0) {
const char * cp = NULL;
cp = "< 1.8";
break;
}
- if (cp)
- pout("Form Factor: %s inches\n", cp);
+ jglb["form_factor"]["scsi_value"] = form_factor;
+ if (cp) {
+ jout("Form Factor: %s inches\n", cp);
+ jglb["form_factor"]["name"] = strprintf("%s inches", cp);
+ }
}
if (haw_zbc > 0)
pout("Host aware zoned block capable\n");
gBuf[4 + len] = '\0';
scsi_format_id_string(serial, &gBuf[4], len);
- pout("Serial number: %s\n", serial);
+ jout("Serial number: %s\n", serial);
+ jglb["serial_number"] = serial;
} else if (scsi_debugmode > 0) {
print_on();
if (SIMPLE_ERR_BAD_RESP == err)
}
// print SCSI peripheral device type
+ jglb["device_type"]["scsi_value"] = peri_dt;
if (peri_dt < (int)(sizeof(peripheral_dt_arr) /
- sizeof(peripheral_dt_arr[0])))
- pout("Device type: %s\n", peripheral_dt_arr[peri_dt]);
+ sizeof(peripheral_dt_arr[0]))) {
+ jout("Device type: %s\n", peripheral_dt_arr[peri_dt]);
+ jglb["device_type"]["name"] = peripheral_dt_arr[peri_dt];
+ }
else
- pout("Device type: <%d>\n", peri_dt);
+ jout("Device type: <%d>\n", peri_dt);
// See if transport protocol is known
if (transport < 0)
pout("Transport protocol: %s\n", transport_proto_arr[transport]);
// print current time and date and timezone
- dateandtimezone(timedatetz);
- pout("Local Time is: %s\n", timedatetz);
+ time_t now = time(0);
+ char timedatetz[DATEANDEPOCHLEN]; dateandtimezoneepoch(timedatetz, now);
+ jout("Local Time is: %s\n", timedatetz);
+ jglb["local_time"]["time_t"] = now;
+ jglb["local_time"]["asctime"] = timedatetz;
- // See if unit accepts SCSI commmands from us
+ // See if unit accepts SCSI commands from us
if ((err = scsiTestUnitReady(device))) {
if (SIMPLE_ERR_NOT_READY == err) {
print_on();
if (iec_err) {
if (!is_tape) {
print_on();
- pout("SMART support is: Unavailable - device lacks SMART capability.\n");
+ pout("SMART support is: Unavailable - device lacks SMART "
+ "capability.\n");
if (scsi_debugmode > 0)
pout(" [%s]\n", scsiErrString(iec_err));
print_off();
static void
scsiPrintTemp(scsi_device * device)
{
- UINT8 temp = 255;
- UINT8 trip = 255;
+ uint8_t temp = 255;
+ uint8_t trip = 255;
if (scsiGetTemp(device, &temp, &trip))
return;
if (255 == temp)
pout("Current Drive Temperature: <not available>\n");
- else
- pout("Current Drive Temperature: %d C\n", temp);
+ else {
+ jout("Current Drive Temperature: %d C\n", temp);
+ jglb["temperature"]["current"] = temp;
+ }
if (255 == trip)
pout("Drive Trip Temperature: <not available>\n");
- else
- pout("Drive Trip Temperature: %d C\n", trip);
+ else {
+ jout("Drive Trip Temperature: %d C\n", trip);
+ jglb["temperature"]["drive_trip"] = trip;
+ }
pout("\n");
}
scsiPrintMain(scsi_device * device, const scsi_print_options & options)
{
int checkedSupportedLogPages = 0;
- UINT8 peripheral_type = 0;
+ uint8_t peripheral_type = 0;
int returnval = 0;
int res, durationSec;
struct scsi_sense_disect sense_info;
failuretest(MANDATORY_CMD, returnval |= FAILID);
any_output = true;
}
- is_disk = (SCSI_PT_DIRECT_ACCESS == peripheral_type);
+ is_disk = ((SCSI_PT_DIRECT_ACCESS == peripheral_type) ||
+ (SCSI_PT_HOST_MANAGED == peripheral_type));
is_tape = ((SCSI_PT_SEQUENTIAL_ACCESS == peripheral_type) ||
(SCSI_PT_MEDIUM_CHANGER == peripheral_type));
else
pout("TapeAlert Not Supported\n");
} else { /* disk, cd/dvd, enclosure, etc */
- if ((res = scsiGetSmartData(device, options.smart_vendor_attrib))) {
+ if ((res = scsiGetSmartData(device,
+ options.smart_vendor_attrib))) {
if (-2 == res)
returnval |= FAILSTATUS;
else
res = scsiPrintSSMedia(device);
if (0 != res)
failuretest(OPTIONAL_CMD, returnval|=res);
+ if (gFormatStatusLPage)
+ res = scsiPrintFormatStatus(device);
+ if (0 != res)
+ failuretest(OPTIONAL_CMD, returnval|=res);
any_output = true;
}
if (options.smart_vendor_attrib) {
if (! checkedSupportedLogPages)
scsiGetSupportedLogPages(device);
scsiPrintErrorCounterLog(device);
+ if (gPendDefectsLPage)
+ scsiPrintPendingDefectsLPage(device);
if (1 == scsiFetchControlGLTSD(device, modese_len, 1))
pout("\n[GLTSD (Global Logging Target Save Disable) set. "
"Enable Save with '-S on']\n");