|
|
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 |
|