[SeaBIOS] [PATCH 2/2] virtio-scsi: speed up SCSI bus scan

Paolo Bonzini pbonzini at redhat.com
Mon Jun 19 18:21:10 CEST 2017


The introduction of REPORT LUNS caused virtio-scsi to send two SCSI
commands (INQUIRY and REPORT LUNS) to each target rather than just
one.

However, INQUIRY will only fail if _no_ LUN is present on that target.
If all devices have LUN>0 is present, INQUIRY will report a dummy
device.  Therefore, the LUN0 scan can be used to prepare a compact
bitmap of targets that we have to scan, and omit sending REPORT LUNS to
the others.

Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
---
 src/hw/blockcmd.c    |  2 ++
 src/hw/virtio-scsi.c | 45 +++++++++++++++++++++++++++++++++++----------
 2 files changed, 37 insertions(+), 10 deletions(-)

diff --git a/src/hw/blockcmd.c b/src/hw/blockcmd.c
index af9cd4d..32d8d68 100644
--- a/src/hw/blockcmd.c
+++ b/src/hw/blockcmd.c
@@ -276,6 +276,8 @@ int scsi_sequential_scan(struct drive_s *tmp_drive, u32 maxluns,
 }
 
 // Validate drive, find block size / sector count, and register drive.
+// Return positive value if disk error, 0 if success, negative if
+// not a disk or the disk parameters are invalid.
 int
 scsi_drive_setup(struct drive_s *drive, const char *s, int prio)
 {
diff --git a/src/hw/virtio-scsi.c b/src/hw/virtio-scsi.c
index 3e8f13e..ad09701 100644
--- a/src/hw/virtio-scsi.c
+++ b/src/hw/virtio-scsi.c
@@ -130,22 +130,40 @@ virtio_scsi_add_lun(u32 lun, struct drive_s *tmpl_drv)
 
 fail:
     free(vlun);
-    return -1;
+    return ret;
 }
 
 static int
 virtio_scsi_scan_target(struct pci_device *pci, struct vp_device *vp,
-                        struct vring_virtqueue *vq, u16 target, u8 report_luns)
+                        struct vring_virtqueue *vq, u16 target, u32 *targets,
+                        u8 report_luns)
 {
 
     struct virtio_lun_s vlun0;
 
     virtio_scsi_init_lun(&vlun0, pci, vp, vq, target, 0);
-    if (!report_luns)
-        return !virtio_scsi_add_lun(0, &vlun0.drive);
-
-    int ret = scsi_rep_luns_scan(&vlun0.drive, virtio_scsi_add_lun);
-    return ret < 0 ? 0 : ret;
+    dprintf(3, "scanning target %d, pass %d\n", target, report_luns);
+    if (!report_luns) {
+        int ret = virtio_scsi_add_lun(0, &vlun0.drive);
+        if (ret > 0) {
+           /* Target error */
+           return 0;
+        }
+        /* Found a SCSI device (maybe not a disk if ret < 0).  Search higher
+         * LUNs in the second pass.
+         */
+        dprintf(1, "will scan target %d\n", target);
+        targets[target >> 5] |= 1 << (target & 31);
+        return !ret;
+    } else {
+        int ret = 0;
+        if (targets[target >> 5] & (1 << (target & 31))) {
+            ret = scsi_rep_luns_scan(&vlun0.drive, virtio_scsi_add_lun);
+            if (ret < 0)
+               ret = 0;
+        }
+        return ret;
+    }
 }
 
 static void
@@ -188,11 +206,18 @@ init_virtio_scsi(void *data)
     vp_set_status(vp, status);
 
     int tot = 0;
+    u32 targets[256 / 32];
     int i;
+    memset(targets, 0, sizeof(targets));
     for (i = 0; i < 256; i++)
-        tot += virtio_scsi_scan_target(pci, vp, vq, i, 0);
-    for (i = 0; i < 256; i++)
-        tot += virtio_scsi_scan_target(pci, vp, vq, i, 1);
+        tot += virtio_scsi_scan_target(pci, vp, vq, i, targets, 0);
+    for (i = 0; i < 256; i++) {
+        if (!targets[i >> 5]) {
+            i |= 31;
+            continue;
+        }
+        tot += virtio_scsi_scan_target(pci, vp, vq, i, targets, 1);
+    }
 
     if (!tot)
         goto fail;
-- 
2.13.0




More information about the SeaBIOS mailing list