*
*/
+/** Maximum number of TEST UNIT READY retries */
+#define SCSI_READY_MAX_RETRIES 10
+
/* Error numbers generated by SCSI sense data */
#define EIO_NO_SENSE __einfo_error ( EINFO_EIO_NO_SENSE )
#define EINFO_EIO_NO_SENSE \
struct interface ready;
/** TEST UNIT READY process */
struct process process;
+ /** TEST UNIT READY retry count */
+ unsigned int retries;
/** List of commands */
struct list_head cmds;
static void scsidev_ready ( struct scsi_device *scsidev, int rc ) {
/* Shut down interface */
- intf_shutdown ( &scsidev->ready, rc );
+ intf_restart ( &scsidev->ready, rc );
- /* Close device on failure */
- if ( rc != 0 ) {
- DBGC ( scsidev, "SCSI %p not ready: %s\n",
- scsidev, strerror ( rc ) );
- scsidev_close ( scsidev, rc );
+ /* Mark device as ready, if applicable */
+ if ( rc == 0 ) {
+ DBGC ( scsidev, "SCSI %p unit is ready\n", scsidev );
+ scsidev->flags |= SCSIDEV_UNIT_READY;
+ xfer_window_changed ( &scsidev->block );
+ return;
+ }
+ DBGC ( scsidev, "SCSI %p not ready: %s\n", scsidev, strerror ( rc ) );
+
+ /* SCSI targets have an annoying habit of returning occasional
+ * pointless "error" messages such as "power-on occurred", so
+ * we have to be prepared to retry commands.
+ *
+ * For most commands, we rely on the caller (e.g. the generic
+ * SAN device layer) to retry commands as needed. However, a
+ * TEST UNIT READY failure is used as an indication that the
+ * whole SCSI device is unavailable and should be closed. We
+ * must therefore perform this retry loop within the SCSI
+ * layer.
+ */
+ if ( scsidev->retries++ < SCSI_READY_MAX_RETRIES ) {
+ DBGC ( scsidev, "SCSI %p retrying (retry %d)\n",
+ scsidev, scsidev->retries );
+ scsidev->flags &= ~SCSIDEV_UNIT_TESTED;
+ process_add ( &scsidev->process );
return;
}
- /* Mark device as ready */
- scsidev->flags |= SCSIDEV_UNIT_READY;
- xfer_window_changed ( &scsidev->block );
- DBGC ( scsidev, "SCSI %p unit is ready\n", scsidev );
+ /* Close device */
+ DBGC ( scsidev, "SCSI %p never became ready: %s\n",
+ scsidev, strerror ( rc ) );
+ scsidev_close ( scsidev, rc );
}
/** SCSI device TEST UNIT READY interface operations */