Blame SOURCES/seabios-blockcmd-generic-SCSI-luns-enumeration.patch

3abf7a
From 456d0bab4f280e3fe4b8041a89385547b02454e0 Mon Sep 17 00:00:00 2001
3abf7a
From: Paolo Bonzini <pbonzini@redhat.com>
3abf7a
Date: Tue, 9 May 2017 11:24:35 +0200
3abf7a
Subject: [PATCH 2/4] blockcmd: generic SCSI luns enumeration
3abf7a
3abf7a
RH-Author: Paolo Bonzini <pbonzini@redhat.com>
3abf7a
Message-id: <20170509112437.30666-3-pbonzini@redhat.com>
3abf7a
Patchwork-id: 75051
3abf7a
O-Subject: [RHEL7.4 seabios PATCH 2/4] blockcmd: generic SCSI luns enumeration
3abf7a
Bugzilla: 1020622
3abf7a
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
3abf7a
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
3abf7a
RH-Acked-by: Fam Zheng <famz@redhat.com>
3abf7a
3abf7a
From: Roman Kagan <rkagan@virtuozzo.com>
3abf7a
3abf7a
Add two generic functions to discover active LUNs on a SCSI target.
3abf7a
3abf7a
The functions take a temporary drive descriptor on the target, and a
3abf7a
callback to create a new drive descriptor with a new LUN using the
3abf7a
temporary one as a template.
3abf7a
3abf7a
One of the functions performs REPORT LUNS on the temporary drive to
3abf7a
obtain the list of candidate luns; the other sequentially iterates the
3abf7a
lun numbers up to the given maximum, and is meant as a fallback.  Both
3abf7a
functions return the number of successfully created drive descriptors,
3abf7a
or a negative number if an error occured.
3abf7a
3abf7a
This will allow to lift the limitation of most of the SCSI drivers that
3abf7a
support booting off the LUN #0 only.
3abf7a
3abf7a
Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
3abf7a
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
3abf7a
(cherry picked from commit 750188dfb35f61f1533f1138d6972b19f36f1a2c)
3abf7a
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
3abf7a
---
3abf7a
 src/hw/blockcmd.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
3abf7a
 src/hw/blockcmd.h |  4 +++
3abf7a
 2 files changed, 98 insertions(+)
3abf7a
3abf7a
diff --git a/src/hw/blockcmd.c b/src/hw/blockcmd.c
3abf7a
index 5ad128e..324188d 100644
3abf7a
--- a/src/hw/blockcmd.c
3abf7a
+++ b/src/hw/blockcmd.c
3abf7a
@@ -13,6 +13,7 @@
3abf7a
 #include "std/disk.h" // DISK_RET_EPARAM
3abf7a
 #include "string.h" // memset
3abf7a
 #include "util.h" // timer_calc
3abf7a
+#include "malloc.h"
3abf7a
 
3abf7a
 
3abf7a
 /****************************************************************
3abf7a
@@ -181,6 +182,99 @@ scsi_is_ready(struct disk_op_s *op)
3abf7a
     return 0;
3abf7a
 }
3abf7a
 
3abf7a
+#define CDB_CMD_REPORT_LUNS  0xA0
3abf7a
+
3abf7a
+struct cdb_report_luns {
3abf7a
+    u8 command;
3abf7a
+    u8 reserved_01[5];
3abf7a
+    u32 length;
3abf7a
+    u8 pad[6];
3abf7a
+} PACKED;
3abf7a
+
3abf7a
+struct scsi_lun {
3abf7a
+    u16 lun[4];
3abf7a
+};
3abf7a
+
3abf7a
+struct cdbres_report_luns {
3abf7a
+    u32 length;
3abf7a
+    u32 reserved;
3abf7a
+    struct scsi_lun luns[];
3abf7a
+};
3abf7a
+
3abf7a
+static u64 scsilun2u64(struct scsi_lun *scsi_lun)
3abf7a
+{
3abf7a
+    int i;
3abf7a
+    u64 ret = 0;
3abf7a
+    for (i = 0; i < ARRAY_SIZE(scsi_lun->lun); i++)
3abf7a
+        ret |= be16_to_cpu(scsi_lun->lun[i]) << (16 * i);
3abf7a
+    return ret;
3abf7a
+}
3abf7a
+
3abf7a
+// Issue REPORT LUNS on a temporary drive and iterate reported luns calling
3abf7a
+// @add_lun for each
3abf7a
+int scsi_rep_luns_scan(struct drive_s *tmp_drive, scsi_add_lun add_lun)
3abf7a
+{
3abf7a
+    int ret = -1;
3abf7a
+    u32 maxluns = 511;
3abf7a
+    u32 nluns, i;
3abf7a
+    struct cdb_report_luns cdb = {
3abf7a
+        .command = CDB_CMD_REPORT_LUNS,
3abf7a
+    };
3abf7a
+    struct disk_op_s op = {
3abf7a
+        .drive_gf = tmp_drive,
3abf7a
+        .command = CMD_SCSI,
3abf7a
+        .count = 1,
3abf7a
+        .cdbcmd = &cdb,
3abf7a
+    };
3abf7a
+    struct cdbres_report_luns *resp;
3abf7a
+
3abf7a
+    ASSERT32FLAT();
3abf7a
+
3abf7a
+    while (1) {
3abf7a
+        op.blocksize = sizeof(struct cdbres_report_luns) +
3abf7a
+            maxluns * sizeof(struct scsi_lun);
3abf7a
+        op.buf_fl = malloc_tmp(op.blocksize);
3abf7a
+        if (!op.buf_fl) {
3abf7a
+            warn_noalloc();
3abf7a
+            return -1;
3abf7a
+        }
3abf7a
+
3abf7a
+        cdb.length = cpu_to_be32(op.blocksize);
3abf7a
+        if (process_op(&op) != DISK_RET_SUCCESS)
3abf7a
+            goto out;
3abf7a
+
3abf7a
+        resp = op.buf_fl;
3abf7a
+        nluns = be32_to_cpu(resp->length) / sizeof(struct scsi_lun);
3abf7a
+        if (nluns <= maxluns)
3abf7a
+            break;
3abf7a
+
3abf7a
+        free(op.buf_fl);
3abf7a
+        maxluns = nluns;
3abf7a
+    }
3abf7a
+
3abf7a
+    for (i = 0, ret = 0; i < nluns; i++) {
3abf7a
+        u64 lun = scsilun2u64(&resp->luns[i]);
3abf7a
+        if (lun >> 32)
3abf7a
+            continue;
3abf7a
+        ret += !add_lun((u32)lun, tmp_drive);
3abf7a
+    }
3abf7a
+out:
3abf7a
+    free(op.buf_fl);
3abf7a
+    return ret;
3abf7a
+}
3abf7a
+
3abf7a
+// Iterate LUNs on the target and call @add_lun for each
3abf7a
+int scsi_sequential_scan(struct drive_s *tmp_drive, u32 maxluns,
3abf7a
+                         scsi_add_lun add_lun)
3abf7a
+{
3abf7a
+    int ret;
3abf7a
+    u32 lun;
3abf7a
+
3abf7a
+    for (lun = 0, ret = 0; lun < maxluns; lun++)
3abf7a
+        ret += !add_lun(lun, tmp_drive);
3abf7a
+    return ret;
3abf7a
+}
3abf7a
+
3abf7a
 // Validate drive, find block size / sector count, and register drive.
3abf7a
 int
3abf7a
 scsi_drive_setup(struct drive_s *drive, const char *s, int prio)
3abf7a
diff --git a/src/hw/blockcmd.h b/src/hw/blockcmd.h
3abf7a
index b543f85..f18543e 100644
3abf7a
--- a/src/hw/blockcmd.h
3abf7a
+++ b/src/hw/blockcmd.h
3abf7a
@@ -106,5 +106,9 @@ int scsi_is_read(struct disk_op_s *op);
3abf7a
 int scsi_is_ready(struct disk_op_s *op);
3abf7a
 struct drive_s;
3abf7a
 int scsi_drive_setup(struct drive_s *drive, const char *s, int prio);
3abf7a
+typedef int (*scsi_add_lun)(u32 lun, struct drive_s *tmpl_drv);
3abf7a
+int scsi_rep_luns_scan(struct drive_s *tmp_drive, scsi_add_lun add_lun);
3abf7a
+int scsi_sequential_scan(struct drive_s *tmp_drive, u32 maxluns,
3abf7a
+                         scsi_add_lun add_lun);
3abf7a
 
3abf7a
 #endif // blockcmd.h
3abf7a
-- 
3abf7a
1.8.3.1
3abf7a