diff --git a/smartmontools/ChangeLog b/smartmontools/ChangeLog index 259b44e2e..1b378fbc9 100644 --- a/smartmontools/ChangeLog +++ b/smartmontools/ChangeLog @@ -1,5 +1,13 @@ $Id$ +2021-11-08 Yannick Hemery + + scsicmds.cpp: Retry on UNIT ATTENTION when fetching capacity (#1303). + + If a UNIT ATTENTION is raised when READ CAPACITY (16) is called, + smartctl might wrongly assume that the drive only supports READ + CAPACITY (10), and return an invalid drive size / block size as a result. + 2021-11-06 Christian Franke update-smart-drivedb.in: Add '-q' option to suppress info messages. diff --git a/smartmontools/scsicmds.cpp b/smartmontools/scsicmds.cpp index b5e801550..30d4af286 100644 --- a/smartmontools/scsicmds.cpp +++ b/smartmontools/scsicmds.cpp @@ -1198,6 +1198,29 @@ scsiReadDefect12(scsi_device * device, int req_plist, int req_glist, return scsiSimpleSenseFilter(&sinfo); } +/* Call scsi_pass_through, and retry only if a UNIT_ATTENTION is raised. + * As for scsi_pass_through, return false on error. */ +bool +scsi_pass_through_with_retry(scsi_device * device, scsi_cmnd_io * iop) +{ + scsi_sense_disect sinfo; + + if (!device->scsi_pass_through(iop)) + return false; + + scsi_do_sense_disect(iop, &sinfo); + + int err = scsiSimpleSenseFilter(&sinfo); + if (SIMPLE_ERR_TRY_AGAIN != err) + return true; + + if (scsi_debugmode > 0) + pout("%s failed with errno=%d [%s], retrying\n", + __func__, err, scsiErrString(err)); + + return device->scsi_pass_through(iop); +} + /* READ CAPACITY (10) command. Returns 0 if ok, 1 if NOT READY, 2 if * command not supported, 3 if field in command not supported or returns * negated errno. SBC-3 section 5.15 (rev 26) */ @@ -1225,7 +1248,7 @@ scsiReadCapacity10(scsi_device * device, unsigned int * last_lbap, io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; - if (!device->scsi_pass_through(&io_hdr)) + if (!scsi_pass_through_with_retry(device, &io_hdr)) return -device->get_errno(); scsi_do_sense_disect(&io_hdr, &sinfo); res = scsiSimpleSenseFilter(&sinfo); @@ -1263,7 +1286,7 @@ scsiReadCapacity16(scsi_device * device, uint8_t *pBuf, int bufLen) io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; - if (!device->scsi_pass_through(&io_hdr)) + if (!scsi_pass_through_with_retry(device, &io_hdr)) return -device->get_errno(); scsi_do_sense_disect(&io_hdr, &sinfo); return scsiSimpleSenseFilter(&sinfo); diff --git a/smartmontools/scsicmds.h b/smartmontools/scsicmds.h index c66c1966e..70ccaa738 100644 --- a/smartmontools/scsicmds.h +++ b/smartmontools/scsicmds.h @@ -440,6 +440,8 @@ int scsiSetPowerCondition(scsi_device * device, int power_cond, int scsiSendDiagnostic(scsi_device * device, int functioncode, uint8_t *pBuf, int bufLen); +bool scsi_pass_through_with_retry(scsi_device * device, scsi_cmnd_io * iop); + int scsiReadDefect10(scsi_device * device, int req_plist, int req_glist, int dl_format, uint8_t *pBuf, int bufLen);