[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC PATCH 6/6] scsi: add walking of hierarchical LUNs
From: |
Paolo Bonzini |
Subject: |
[Qemu-devel] [RFC PATCH 6/6] scsi: add walking of hierarchical LUNs |
Date: |
Fri, 20 May 2011 17:03:37 +0200 |
Signed-off-by: Paolo Bonzini <address@hidden>
---
hw/scsi-bus.c | 79 +++++++++++++++++++++++++++++++++++++++++++-----------
hw/scsi.h | 9 +++++-
hw/spapr_vscsi.c | 6 +++-
3 files changed, 75 insertions(+), 19 deletions(-)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 4d46831..2037da3 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -811,33 +811,80 @@ retry:
abort();
}
-/* Extract bus and target from the given LUN and use it to identify a
- SCSIDevice from a SCSIBus. Right now, only 1 target per bus is
- supported. In the future a SCSIDevice could host its own SCSIBus,
- in an alternation of devices that select a bus (target ports) and
- devices that select a target (initiator ports). */
-SCSIDevice *scsi_decode_lun(SCSIBus *sbus, uint64_t sam_lun, int *lun)
+/* Reusable implementation of the decode_lun entry in SCSIBusOps. */
+SCSIDevice *scsi_decode_bus_from_lun(SCSIBus *sbus, uint64_t sam_lun,
+ uint64_t *next_lun)
{
- int bus, target, decoded_lun;
- uint64_t next_lun;
+ int bus, target;
+ uint64_t my_next_lun;
+ SCSIDevice *sdev;
- if (!scsi_decode_level(sam_lun, &bus, &target, &next_lun)) {
+ if (!scsi_decode_level(sam_lun, &bus, &target, &my_next_lun)) {
/* Unsupported LUN format. */
return NULL;
}
- if (bus >= sbus->ndev || (bus == 0 && target > 0)) {
+ if (bus >= sbus->ndev) {
/* Out of range. */
return NULL;
}
- if (target != 0) {
- /* Only one target for now. */
+
+ sdev = sbus->devs[bus];
+ if (!sdev) {
+ return NULL;
+ } else if (bus == 0 || !sdev->children) {
+ return target ? NULL : sdev;
+ } else {
+ /* Next we'll decode the target, so pass down the same LUN we got. */
+ return sdev->children->ops.decode_lun(sbus, sam_lun, next_lun);
+ }
+}
+
+SCSIDevice *scsi_decode_target_from_lun(SCSIBus *sbus, uint64_t sam_lun,
+ uint64_t *next_lun)
+{
+ int bus, target;
+ SCSIDevice *sdev;
+
+ if (!scsi_decode_level(sam_lun, &bus, &target, next_lun)) {
+ /* Unsupported LUN format. */
+ return NULL;
+ }
+ if (target >= sbus->ndev) {
+ /* Out of range. */
return NULL;
}
+ sdev = sbus->devs[target];
+ if (!sdev || !sdev->children || (*next_lun >> 56) == ADDR_WELL_KNOWN_LUN) {
+ return sdev;
+ } else {
+ return sdev->children->ops.decode_lun(sbus, *next_lun, next_lun);
+ }
+}
+
+/* Extract bus and target from the given LUN and use it to identify a
+ SCSIDevice from a SCSIBus. Right now, only 1 target per bus is
+ supported. In the future a SCSIDevice could host its own SCSIBus,
+ in an alternation of devices that select a bus (target ports) and
+ devices that select a target (initiator ports). */
+SCSIDevice *scsi_decode_lun(SCSIBus *sbus, uint64_t sam_lun,
+ uint8_t *cdb, int *lun)
+{
+ int decoded_lun;
+ uint64_t next_lun;
+ SCSIDevice *sdev;
+
+ sdev = sbus->ops.decode_lun(sbus, sam_lun, &next_lun);
+ if (!sdev) {
+ return NULL;
+ }
decoded_lun = scsi_get_lun(next_lun);
- if (decoded_lun != LUN_INVALID) {
- *lun = decoded_lun;
- return sbus->devs[bus];
+ if (decoded_lun == LUN_INVALID) {
+ return NULL;
+ }
+ if ((decoded_lun & ~LUN_WLUN_MASK) == LUN_WLUN_BASE) {
+ return sdev;
}
- return NULL;
+ *lun = decoded_lun;
+ return scsi_find_lun(sdev, decoded_lun, cdb);
}
diff --git a/hw/scsi.h b/hw/scsi.h
index 438dd89..c4cca0b 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -88,6 +88,8 @@ struct SCSIBusOps {
void (*transfer_data)(SCSIRequest *req, uint32_t arg);
void (*complete)(SCSIRequest *req, uint32_t arg);
void (*cancel)(SCSIRequest *req);
+ SCSIDevice *(*decode_lun)(SCSIBus *sbus, uint64_t sam_lun,
+ uint64_t *next_lun);
};
struct SCSIBus {
@@ -145,7 +147,12 @@ extern const struct SCSISense sense_code_LUN_FAILURE;
int scsi_build_sense(SCSISense sense, uint8_t *buf, int len, int fixed);
int scsi_sense_valid(SCSISense sense);
-SCSIDevice *scsi_decode_lun(SCSIBus *sbus, uint64_t sam_lun, int *lun);
+SCSIDevice *scsi_decode_lun(SCSIBus *sbus, uint64_t sam_lun, uint8_t *cdb,
+ int *lun);
+SCSIDevice *scsi_decode_bus_from_lun(SCSIBus *sbus, uint64_t sam_lun,
+ uint64_t *next_lun);
+SCSIDevice *scsi_decode_target_from_lun(SCSIBus *sbus, uint64_t sam_lun,
+ uint64_t *next_lun);
SCSIDevice *scsi_find_lun(SCSIDevice *sdev, int lun, uint8_t *cdb);
SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t
lun);
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index ee88ff6..d46ab30 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -640,7 +640,8 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
SCSIDevice *sdev;
int n, lun;
- sdev = scsi_decode_lun(&s->bus, be64_to_cpu(srp->cmd.lun), &lun);
+ sdev = scsi_decode_lun(&s->bus, be64_to_cpu(srp->cmd.lun),
+ srp->cmd.cdb, &lun);
if (!sdev) {
if (srp->cmd.cdb[0] == INQUIRY) {
vscsi_inquiry_no_target(s, req);
@@ -918,7 +919,8 @@ static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t
*crq_data)
static struct SCSIBusOps vscsi_scsi_ops = {
.transfer_data = vscsi_transfer_data,
.complete = vscsi_command_complete,
- .cancel = vscsi_request_cancelled
+ .cancel = vscsi_request_cancelled,
+ .decode_lun = scsi_decode_bus_from_lun
};
static int spapr_vscsi_init(VIOsPAPRDevice *dev)
--
1.7.4.4
- [Qemu-devel] [RFC PATCH 3/6] scsi-generic: allow customization of the lun, (continued)
[Qemu-devel] [RFC PATCH 1/6] scsi: ignore LUN field in the CDB, Paolo Bonzini, 2011/05/20
[Qemu-devel] [RFC PATCH 4/6] scsi-disk: allow customization of the lun, Paolo Bonzini, 2011/05/20
[Qemu-devel] [RFC PATCH 5/6] scsi: let a SCSIDevice have children devices, Paolo Bonzini, 2011/05/20
[Qemu-devel] [RFC PATCH 6/6] scsi: add walking of hierarchical LUNs,
Paolo Bonzini <=
Re: [Qemu-devel] [RFC PATCH 0/6] SCSI series part 2, rewrite LUN parsing, Christoph Hellwig, 2011/05/20