[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 3/8] scsi-disk: Implement 'REPORT TARGET PORT GROUPS
From: |
Hannes Reinecke |
Subject: |
[Qemu-devel] [PATCH 3/8] scsi-disk: Implement 'REPORT TARGET PORT GROUPS' |
Date: |
Fri, 27 Nov 2015 15:59:01 +0100 |
Implement support for REPORT TARGET PORT GROUPS scsi command.
Note that target port groups are referenced per SCSI wwn ,
which might be connected to different hosts. So we need to
walk the entire qtree to find all eligible SCSI devices.
Signed-off-by: Hannes Reinecke <address@hidden>
---
hw/scsi/scsi-disk.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 158 insertions(+), 1 deletion(-)
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 583cacd..8dabed3 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -795,6 +795,11 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req,
uint8_t *outbuf)
outbuf[4] = 36 - 5;
}
+ /* Enable TGPS bit */
+ if (s->wwn) {
+ outbuf[5] = 0x10;
+ }
+
/* Sync data transfer and TCQ. */
outbuf[7] = 0x10 | (req->bus->info->tcq ? 0x02 : 0);
return buflen;
@@ -1819,6 +1824,97 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r,
uint8_t *inbuf)
scsi_write_same_complete, data);
}
+typedef struct PortGroupEnumerate {
+ int numgrp;
+ uint64_t wwn;
+ uint16_t grp[16];
+ uint8_t alua_state[16];
+ uint16_t alua_mask;
+} PortGroupEnumerate;
+
+static void qbus_enumerate_port_group(PortGroupEnumerate *, BusState *);
+
+static void qdev_enumerate_port_group(PortGroupEnumerate *pg, DeviceState *dev)
+{
+ BusState *child;
+
+ if (!strcmp(object_get_typename(OBJECT(dev->parent_bus)), TYPE_SCSI_BUS)) {
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev.qdev, dev);
+ DPRINTF("wwn 0x%" PRIx64 " pg %u state %x\n",
+ s->wwn, s->port_group, (s->alua_state & 0x0f));
+ if (s->wwn == pg->wwn) {
+ bool pg_found = false;
+ int i;
+
+ for (i = 0; i < pg->numgrp; i++) {
+ if (pg->grp[i] == s->port_group) {
+ pg_found = true;
+ break;
+ }
+ }
+ if (!pg_found) {
+ pg->grp[pg->numgrp] = s->port_group;
+ pg->alua_state[pg->numgrp] = s->alua_state;
+ pg->alua_mask |= 1 << (s->alua_state & 0x0f);
+ pg->numgrp++;
+ }
+ }
+ }
+ QLIST_FOREACH(child, &dev->child_bus, sibling) {
+ qbus_enumerate_port_group(pg, child);
+ }
+}
+
+static void qbus_enumerate_port_group(PortGroupEnumerate *pg, BusState *bus)
+{
+ BusChild *kid;
+
+ QTAILQ_FOREACH(kid, &bus->children, sibling) {
+ DeviceState *dev = kid->child;
+ qdev_enumerate_port_group(pg, dev);
+ }
+}
+
+typedef struct PortDescEnumerate {
+ int numdesc;
+ uint64_t wwn;
+ uint16_t port_group;
+ uint8_t *desc;
+} PortDescEnumerate;
+
+static void qbus_enumerate_port_desc(PortDescEnumerate *, BusState *);
+
+static void qdev_enumerate_port_desc(PortDescEnumerate *pd, DeviceState *dev)
+{
+ BusState *child;
+
+ if (!strcmp(object_get_typename(OBJECT(dev->parent_bus)), TYPE_SCSI_BUS)) {
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev.qdev, dev);
+ if (s->wwn == pd->wwn &&
+ s->port_group == pd->port_group) {
+ pd->desc[0] = 0;
+ pd->desc[1] = 0;
+ pd->desc[2] = (s->port_index >> 8) & 0xff;
+ pd->desc[3] = s->port_index & 0xff;
+ pd->desc += 4;
+ pd->numdesc++;
+ }
+ }
+ QLIST_FOREACH(child, &dev->child_bus, sibling) {
+ qbus_enumerate_port_desc(pd, child);
+ }
+}
+
+static void qbus_enumerate_port_desc(PortDescEnumerate *pd, BusState *bus)
+{
+ BusChild *kid;
+
+ QTAILQ_FOREACH(kid, &bus->children, sibling) {
+ DeviceState *dev = kid->child;
+ qdev_enumerate_port_desc(pd, dev);
+ }
+}
+
static void scsi_disk_emulate_write_data(SCSIRequest *req)
{
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
@@ -1860,6 +1956,54 @@ static void scsi_disk_emulate_write_data(SCSIRequest
*req)
}
}
+static int scsi_emulate_report_target_port_groups(SCSIDiskState *s, uint8_t
*inbuf)
+{
+ uint8_t *p = inbuf;
+ PortGroupEnumerate pg;
+ PortDescEnumerate pd;
+ int buflen = 0, i;
+
+ if (!s->wwn) {
+ return -1;
+ }
+
+ pg.numgrp = 0;
+ pg.wwn = s->wwn;
+
+ if (sysbus_get_default())
+ qbus_enumerate_port_group(&pg, sysbus_get_default());
+
+ if (pg.numgrp == 0) {
+ return -1;
+ }
+ DPRINTF("wwn 0x%" PRIx64 " %d port groups \n", s->wwn, pg.numgrp);
+ p = &inbuf[4];
+ for (i = 0; i < pg.numgrp; i++) {
+ pd.numdesc = 0;
+ pd.wwn = s->wwn;
+ pd.port_group = pg.grp[i];
+ pd.desc = &p[8];
+ buflen += 8;
+ qbus_enumerate_port_desc(&pd, sysbus_get_default());
+ DPRINTF("pg %x: %d port descriptors\n", pg.grp[i], pd.numdesc);
+ p[0] = pg.alua_state[i];
+ p[1] = pg.alua_mask;
+ p[2] = (pg.grp[i] >> 8) & 0xff;
+ p[3] = pg.grp[i] & 0xff;
+ p[7] = pd.numdesc;
+ p += 8 + pd.numdesc * 4;
+ buflen += pd.numdesc * 4;
+ }
+ if (buflen) {
+ inbuf[0] = (buflen >> 24) & 0xff;
+ inbuf[1] = (buflen >> 16) & 0xff;
+ inbuf[2] = (buflen >> 8) & 0xff;
+ inbuf[3] = buflen & 0xff;
+ }
+
+ return buflen + 4;
+}
+
static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
{
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
@@ -2058,6 +2202,19 @@ static int32_t scsi_disk_emulate_command(SCSIRequest
*req, uint8_t *buf)
goto illegal_request;
}
break;
+ case MAINTENANCE_IN:
+ if ((req->cmd.buf[1] & 31) == MI_REPORT_TARGET_PORT_GROUPS) {
+ DPRINTF("MI REPORT TARGET PORT GROUPS\n");
+ memset(outbuf, 0, req->cmd.xfer);
+ buflen = scsi_emulate_report_target_port_groups(s, outbuf);
+ if (buflen < 0) {
+ goto illegal_request;
+ }
+ break;
+ }
+ DPRINTF("Unsupported Maintenance In\n");
+ goto illegal_request;
+ break;
case MECHANISM_STATUS:
buflen = scsi_emulate_mechanism_status(s, outbuf);
if (buflen < 0) {
@@ -2918,7 +3075,7 @@ static void scsi_disk_set_alua_state(Object *obj, Visitor
*v, void *opaque,
goto out;
}
- s->alua_state = alua_state;
+ s->alua_state = (s->alua_state & 0xf0) | alua_state;
scsi_device_set_ua(&s->qdev, SENSE_CODE(ASYMMETRIC_ACCESS_STATE_CHANGED));
out:
--
1.8.4.5
- [Qemu-devel] [PATCH RFC 0/8] scsi-disk: Active/passive ALUA support, Hannes Reinecke, 2015/11/27
- [Qemu-devel] [PATCH 5/8] scsi-disk: implement ALUA policy, Hannes Reinecke, 2015/11/27
- [Qemu-devel] [PATCH 4/8] scsi-disk: Implement 'SET TARGET PORT GROUPS', Hannes Reinecke, 2015/11/27
- [Qemu-devel] [PATCH 8/8] block: Implement 'block_disconnect' HMP command, Hannes Reinecke, 2015/11/27
- [Qemu-devel] [PATCH 3/8] scsi-disk: Implement 'REPORT TARGET PORT GROUPS',
Hannes Reinecke <=
- [Qemu-devel] [PATCH 1/8] scsi-disk: Add 'port_group' property, Hannes Reinecke, 2015/11/27
- [Qemu-devel] [PATCH 6/8] scsi-disk: Allow READ CAPACITY in standby, Hannes Reinecke, 2015/11/27
- [Qemu-devel] [PATCH 7/8] scsi-disk: Implement 'alua_preferred' option, Hannes Reinecke, 2015/11/27
- [Qemu-devel] [PATCH 2/8] scsi-disk: Add 'alua_state' property, Hannes Reinecke, 2015/11/27