diff --git a/smartmontools/ChangeLog b/smartmontools/ChangeLog index f7b4dc37d8d57457857d7d3401797bbe23d94b17..975defb7d8997720bcf0227083c344b856cc8e8f 100644 --- a/smartmontools/ChangeLog +++ b/smartmontools/ChangeLog @@ -1,5 +1,14 @@ $Id$ +2022-05-27 Douglas Gilbert <dgilbert@interlog.com> + + [SCSI]: prepare for calling REPORT SUPPORTED OPERATION + CODES [RSOC] command (and several others that use an + additional "service action" code to identify them). For + SCSI devices >= SPC-4 plan to call the RSOC command and + cache its result. Use that cache to determine if + commands like GET PHYSICAL ELEMENT STATUS are supported. + 2022-05-26 Christian Franke <franke@computer.org> INSTALL: Update ./configure description and Windows info. diff --git a/smartmontools/os_freebsd.cpp b/smartmontools/os_freebsd.cpp index bc7ecf8a33295a974daa352bc397940d0fcaab43..5d0c8b68a7edf9d738530e6208580c90850203d2 100644 --- a/smartmontools/os_freebsd.cpp +++ b/smartmontools/os_freebsd.cpp @@ -889,7 +889,7 @@ bool freebsd_megaraid_device::scsi_pass_through(scsi_cmnd_io *iop) char buff[256]; const int sz = (int)sizeof(buff); - np = scsi_get_opcode_name(ucp[0]); + np = scsi_get_opcode_name(ucp[0], false, 0); j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>"); for (k = 0; k < (int)iop->cmnd_len; ++k) j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); @@ -1253,7 +1253,7 @@ bool freebsd_scsi_device::scsi_pass_through(scsi_cmnd_io * iop) const unsigned char * ucp = iop->cmnd; const char * np; - np = scsi_get_opcode_name(ucp[0]); + np = scsi_get_opcode_name(ucp[0], false, 0); pout(" [%s: ", np ? np : "<unknown opcode>"); for (k = 0; k < iop->cmnd_len; ++k) pout("%02x ", ucp[k]); diff --git a/smartmontools/os_linux.cpp b/smartmontools/os_linux.cpp index e8b9438cca35624cc5a545a7ca8a7afb04312fcc..b750521fb58fc012a7497d43fda29e8bb3e4650d 100644 --- a/smartmontools/os_linux.cpp +++ b/smartmontools/os_linux.cpp @@ -542,7 +542,7 @@ static int sg_io_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report, const int sz = (int)sizeof(buff); pout(">>>> do_scsi_cmnd_io: sg_io_ifc=%d\n", (int)sg_io_ifc); - np = scsi_get_opcode_name(ucp[0]); + np = scsi_get_opcode_name(ucp[0], false, 0); j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>"); for (k = 0; k < (int)iop->cmnd_len; ++k) j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); @@ -921,7 +921,7 @@ bool linux_aacraid_device::scsi_pass_through(scsi_cmnd_io *iop) char buff[256]; const int sz = (int)sizeof(buff); - np = scsi_get_opcode_name(ucp[0]); + np = scsi_get_opcode_name(ucp[0], false, 0); j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>"); for (k = 0; k < (int)iop->cmnd_len; ++k) j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); @@ -1226,7 +1226,7 @@ bool linux_megaraid_device::scsi_pass_through(scsi_cmnd_io *iop) char buff[256]; const int sz = (int)sizeof(buff); - np = scsi_get_opcode_name(ucp[0]); + np = scsi_get_opcode_name(ucp[0], false, 0); j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>"); for (k = 0; k < (int)iop->cmnd_len; ++k) j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); diff --git a/smartmontools/os_netbsd.cpp b/smartmontools/os_netbsd.cpp index abf2f3242a7eb1f4f8c6bb630d74e55ab6bdede5..66c3a4795bbeed8f7e6c475242af9571f7ff842f 100644 --- a/smartmontools/os_netbsd.cpp +++ b/smartmontools/os_netbsd.cpp @@ -357,7 +357,7 @@ bool netbsd_scsi_device::scsi_pass_through(scsi_cmnd_io * iop) const unsigned char * ucp = iop->cmnd; const char * np; - np = scsi_get_opcode_name(ucp[0]); + np = scsi_get_opcode_name(ucp[0], false, 0); pout(" [%s: ", np ? np : "<unknown opcode>"); for (k = 0; k < iop->cmnd_len; ++k) pout("%02x ", ucp[k]); diff --git a/smartmontools/os_openbsd.cpp b/smartmontools/os_openbsd.cpp index 25f66adc69dbb8c7aec6a3497f763dda4b5d5204..d2ffe9c33a4dfaa9edb8453a14b6cff2c053e510 100644 --- a/smartmontools/os_openbsd.cpp +++ b/smartmontools/os_openbsd.cpp @@ -244,7 +244,7 @@ bool openbsd_scsi_device::scsi_pass_through(scsi_cmnd_io * iop) const unsigned char * ucp = iop->cmnd; const char * np; - np = scsi_get_opcode_name(ucp[0]); + np = scsi_get_opcode_name(ucp[0], false, 0); pout(" [%s: ", np ? np : "<unknown opcode>"); for (k = 0; k < iop->cmnd_len; ++k) pout("%02x ", ucp[k]); diff --git a/smartmontools/os_solaris.cpp b/smartmontools/os_solaris.cpp index 8aaeda7f98d672e667a36f2dddbced82839cb604..00c9645575f51a28eb7a41d61597bd545ecc4079 100644 --- a/smartmontools/os_solaris.cpp +++ b/smartmontools/os_solaris.cpp @@ -240,7 +240,7 @@ int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report) const unsigned char * ucp = iop->cmnd; const char * np; - np = scsi_get_opcode_name(ucp[0]); + np = scsi_get_opcode_name(ucp[0], false, 0); pout(" [%s: ", np ? np : "<unknown opcode>"); for (k = 0; k < (int)iop->cmnd_len; ++k) pout("%02x ", ucp[k]); diff --git a/smartmontools/os_win32.cpp b/smartmontools/os_win32.cpp index 8506347c1459947eda3703459c691ea531e784b1..0af305b1cfe5ee7971942c0149ee9df87e2efd6e 100644 --- a/smartmontools/os_win32.cpp +++ b/smartmontools/os_win32.cpp @@ -2830,7 +2830,7 @@ bool win_scsi_device::scsi_pass_through(struct scsi_cmnd_io * iop) char buff[256]; const int sz = (int)sizeof(buff); - np = scsi_get_opcode_name(ucp[0]); + np = scsi_get_opcode_name(ucp[0], false, 0); j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>"); for (k = 0; k < (int)iop->cmnd_len; ++k) j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); @@ -2959,7 +2959,7 @@ static long scsi_pass_through_direct(HANDLE fd, UCHAR targetid, struct scsi_cmnd char buff[256]; const int sz = (int)sizeof(buff); - np = scsi_get_opcode_name(ucp[0]); + np = scsi_get_opcode_name(ucp[0], false, 0); j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>"); for (k = 0; k < (int)iop->cmnd_len; ++k) j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); @@ -3396,7 +3396,7 @@ bool win_aacraid_device::scsi_pass_through(struct scsi_cmnd_io *iop) const char * np; char buff[256]; const int sz = (int)sizeof(buff); - np = scsi_get_opcode_name(ucp[0]); + np = scsi_get_opcode_name(ucp[0], false, 0); j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>"); for (k = 0; k < (int)iop->cmnd_len; ++k) j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); diff --git a/smartmontools/scsicmds.cpp b/smartmontools/scsicmds.cpp index b90b913461a780c2598c9e4d39dd22b64197895c..c094a90aa2d865ae6b51131a357978b18fcae8fb 100644 --- a/smartmontools/scsicmds.cpp +++ b/smartmontools/scsicmds.cpp @@ -199,30 +199,38 @@ is_scsi_cdb(const uint8_t * cdbp, int clen) struct scsi_opcode_name { uint8_t opcode; + bool sa_valid; + uint16_t sa; const char * name; }; +/* Array assumed to be sorted by opcode then service action (sa) */ static struct scsi_opcode_name opcode_name_arr[] = { /* in ascending opcode order */ - {TEST_UNIT_READY, "test unit ready"}, /* 0x00 */ - {REQUEST_SENSE, "request sense"}, /* 0x03 */ - {INQUIRY, "inquiry"}, /* 0x12 */ - {MODE_SELECT, "mode select(6)"}, /* 0x15 */ - {MODE_SENSE, "mode sense(6)"}, /* 0x1a */ - {START_STOP_UNIT, "start stop unit"}, /* 0x1b */ - {RECEIVE_DIAGNOSTIC, "receive diagnostic"}, /* 0x1c */ - {SEND_DIAGNOSTIC, "send diagnostic"}, /* 0x1d */ - {READ_CAPACITY_10, "read capacity(10)"}, /* 0x25 */ - {READ_DEFECT_10, "read defect list(10)"}, /* 0x37 */ - {LOG_SELECT, "log select"}, /* 0x4c */ - {LOG_SENSE, "log sense"}, /* 0x4d */ - {MODE_SELECT_10, "mode select(10)"}, /* 0x55 */ - {MODE_SENSE_10, "mode sense(10)"}, /* 0x5a */ - {SAT_ATA_PASSTHROUGH_16, "ata pass-through(16)"}, /* 0x85 */ - {READ_CAPACITY_16, "read capacity(16)"}, /* 0x9e,0x10 */ - {REPORT_LUNS, "report luns"}, /* 0xa0 */ - {SAT_ATA_PASSTHROUGH_12, "ata pass-through(12)"}, /* 0xa1 */ - {READ_DEFECT_12, "read defect list(12)"}, /* 0xb7 */ + {TEST_UNIT_READY, false, 0, "test unit ready"}, /* 0x00 */ + {REQUEST_SENSE, false, 0, "request sense"}, /* 0x03 */ + {INQUIRY, false, 0, "inquiry"}, /* 0x12 */ + {MODE_SELECT_6, false, 0, "mode select(6)"}, /* 0x15 */ + {MODE_SENSE_6, false, 0, "mode sense(6)"}, /* 0x1a */ + {START_STOP_UNIT, false, 0, "start stop unit"}, /* 0x1b */ + {RECEIVE_DIAGNOSTIC, false, 0, "receive diagnostic"}, /* 0x1c */ + {SEND_DIAGNOSTIC, false, 0, "send diagnostic"}, /* 0x1d */ + {READ_CAPACITY_10, false, 0, "read capacity(10)"}, /* 0x25 */ + {READ_DEFECT_10, false, 0, "read defect list(10)"}, /* 0x37 */ + {LOG_SELECT, false, 0, "log select"}, /* 0x4c */ + {LOG_SENSE, false, 0, "log sense"}, /* 0x4d */ + {MODE_SELECT_10, false, 0, "mode select(10)"}, /* 0x55 */ + {MODE_SENSE_10, false, 0, "mode sense(10)"}, /* 0x5a */ + {SAT_ATA_PASSTHROUGH_16, false, 0, "ata pass-through(16)"}, /* 0x85 */ + {SERVICE_ACTION_IN_16, true, SAI_READ_CAPACITY_16, "read capacity(16)"}, + /* 0x9e,0x10 */ + {SERVICE_ACTION_IN_16, true, SAI_GET_PHY_ELEM_STATUS, + "get physical element status"}, /* 0x9e,0x17 */ + {REPORT_LUNS, false, 0, "report luns"}, /* 0xa0 */ + {SAT_ATA_PASSTHROUGH_12, false, 0, "ata pass-through(12)"}, /* 0xa1 */ + {MAINTENANCE_IN_12, true, MI_REP_SUP_OPCODES, + "report suported operation codes"}, /* 0xa3,0xc */ + {READ_DEFECT_12, false, 0, "read defect list(12)"}, /* 0xb7 */ }; static const char * vendor_specific = "<vendor specific>"; @@ -230,7 +238,7 @@ static const char * vendor_specific = "<vendor specific>"; /* Need to expand to take service action into account. For commands * of interest the service action is in the 2nd command byte */ const char * -scsi_get_opcode_name(uint8_t opcode) +scsi_get_opcode_name(uint8_t opcode, bool sa_valid, uint16_t sa) { static const int len = sizeof(opcode_name_arr) / sizeof(opcode_name_arr[0]); @@ -239,9 +247,16 @@ scsi_get_opcode_name(uint8_t opcode) return vendor_specific; for (int k = 0; k < len; ++k) { struct scsi_opcode_name * onp = &opcode_name_arr[k]; - if (opcode == onp->opcode) - return onp->name; - else if (opcode < onp->opcode) + + if (opcode == onp->opcode) { + if ((! sa_valid) && (! onp->sa_valid)) + return onp->name; + if (sa_valid && onp->sa_valid) { + if (sa == onp->sa) + return onp->name; + } + /* should see sa_valid and ! onp->sa_valid (or vice versa) */ + } else if (opcode < onp->opcode) return NULL; } return NULL; @@ -690,7 +705,7 @@ scsiModeSense(scsi_device * device, int pagenum, int subpagenum, int pc, io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = bufLen; io_hdr.dxferp = pBuf; - cdb[0] = MODE_SENSE; + cdb[0] = MODE_SENSE_6; cdb[2] = (pc << 6) | (pagenum & 0x3f); cdb[3] = subpagenum; cdb[4] = bufLen; @@ -743,7 +758,7 @@ scsiModeSelect(scsi_device * device, int sp, uint8_t *pBuf, int bufLen) io_hdr.dxfer_dir = DXFER_TO_DEVICE; io_hdr.dxfer_len = hdr_plus_1_pg; io_hdr.dxferp = pBuf; - cdb[0] = MODE_SELECT; + cdb[0] = MODE_SELECT_6; cdb[1] = 0x10 | (sp & 1); /* set PF (page format) bit always */ cdb[4] = hdr_plus_1_pg; /* make sure only one page sent */ io_hdr.cmnd = cdb; @@ -1294,7 +1309,7 @@ scsiReadCapacity16(scsi_device * device, uint8_t *pBuf, int bufLen) io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = bufLen; io_hdr.dxferp = pBuf; - cdb[0] = READ_CAPACITY_16; + cdb[0] = SERVICE_ACTION_IN_16; cdb[1] = SAI_READ_CAPACITY_16; sg_put_unaligned_be32(bufLen, cdb + 10); io_hdr.cmnd = cdb; diff --git a/smartmontools/scsicmds.h b/smartmontools/scsicmds.h index a0b73932fccecbb22163d3ef719fca2e9d9f88ae..bcb03087326f1d47d4b2276f2eeeecd52249d357 100644 --- a/smartmontools/scsicmds.h +++ b/smartmontools/scsicmds.h @@ -39,14 +39,14 @@ #ifndef LOG_SENSE #define LOG_SENSE 0x4d #endif -#ifndef MODE_SENSE -#define MODE_SENSE 0x1a +#ifndef MODE_SENSE_6 +#define MODE_SENSE_6 0x1a #endif #ifndef MODE_SENSE_10 #define MODE_SENSE_10 0x5a #endif -#ifndef MODE_SELECT -#define MODE_SELECT 0x15 +#ifndef MODE_SELECT_6 +#define MODE_SELECT_6 0x15 #endif #ifndef MODE_SELECT_10 #define MODE_SELECT_10 0x55 @@ -78,12 +78,21 @@ #ifndef READ_CAPACITY_10 #define READ_CAPACITY_10 0x25 #endif -#ifndef READ_CAPACITY_16 -#define READ_CAPACITY_16 0x9e +#ifndef SERVICE_ACTION_IN_16 +#define SERVICE_ACTION_IN_16 0x9e #endif -#ifndef SAI_READ_CAPACITY_16 /* service action for READ_CAPACITY_16 */ +#ifndef SAI_READ_CAPACITY_16 /* service action in for READ_CAPACITY_16 */ #define SAI_READ_CAPACITY_16 0x10 #endif +#ifndef SAI_GET_PHY_ELEM_STATUS /* Get physical element status */ +#define SAI_GET_PHY_ELEM_STATUS 0x17 +#endif +#ifndef MAINTENANCE_IN_12 +#define MAINTENANCE_IN_12 0xa3 +#endif +#ifndef MI_REP_SUP_OPCODES +#define MI_REP_SUP_OPCODES 0xc /* maintenance in (12) */ +#endif #ifndef SAT_ATA_PASSTHROUGH_12 #define SAT_ATA_PASSTHROUGH_12 0xa1 @@ -514,7 +523,7 @@ int scsiSmartSelfTestAbort(scsi_device * device); const char * scsiTapeAlertsTapeDevice(unsigned short code); const char * scsiTapeAlertsChangerDevice(unsigned short code); -const char * scsi_get_opcode_name(uint8_t opcode); +const char * scsi_get_opcode_name(uint8_t opcode, bool sa_valid, uint16_t sa); void scsi_format_id_string(char * out, const uint8_t * in, int n); void dStrHex(const uint8_t * up, int len, int no_ascii);