usb-msc: go through TEST UNIT READY for hard disks.
[seabios.git] / src / blockcmd.c
index f5e2ce3f70518ba85bd504e2bb23486bd9056fdd..e86fe29c86d7dd6fb071a62fa5ee6a2a78be2346 100644 (file)
@@ -31,6 +31,50 @@ cdb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
     }
 }
 
+int
+scsi_is_ready(struct disk_op_s *op)
+{
+    dprintf(6, "scsi_is_ready (drive=%p)\n", op->drive_g);
+
+    /* Retry TEST UNIT READY for 5 seconds unless MEDIUM NOT PRESENT is
+     * reported by the device.  If the device reports "IN PROGRESS",
+     * 30 seconds is added. */
+    int in_progress = 0;
+    u64 end = calc_future_tsc(5000);
+    for (;;) {
+        if (check_tsc(end)) {
+            dprintf(1, "test unit ready failed\n");
+            return -1;
+        }
+
+        int ret = cdb_test_unit_ready(op);
+        if (!ret)
+            // Success
+            break;
+
+        struct cdbres_request_sense sense;
+        ret = cdb_get_sense(op, &sense);
+        if (ret)
+            // Error - retry.
+            continue;
+
+        // Sense succeeded.
+        if (sense.asc == 0x3a) { /* MEDIUM NOT PRESENT */
+            dprintf(1, "Device reports MEDIUM NOT PRESENT\n");
+            return -1;
+        }
+
+        if (sense.asc == 0x04 && sense.ascq == 0x01 && !in_progress) {
+            /* IN PROGRESS OF BECOMING READY */
+            printf("Waiting for device to detect medium... ");
+            /* Allow 30 seconds more */
+            end = calc_future_tsc(30000);
+            in_progress = 1;
+        }
+    }
+    return 0;
+}
+
 int
 cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data)
 {