qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 3/3] scsi-disk: Implement 'REPORT TARGET PORT GROUPS


From: Hannes Reinecke
Subject: [Qemu-devel] [PATCH 3/3] scsi-disk: Implement 'REPORT TARGET PORT GROUPS'
Date: Mon, 16 Nov 2015 15:36:58 +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 | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 156 insertions(+)

diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index fbd30f3..2ca2ef0 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -794,6 +794,10 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, 
uint8_t *outbuf)
         outbuf[4] = 36 - 5;
     }
 
+    /* Enable TGPS bit */
+    if (s->wwn)
+        outbuf[4] = 1;
+
     /* Sync data transfer and TCQ.  */
     outbuf[7] = 0x10 | (req->bus->info->tcq ? 0x02 : 0);
     return buflen;
@@ -1859,6 +1863,145 @@ static void scsi_disk_emulate_write_data(SCSIRequest 
*req)
     }
 }
 
+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);
+        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;
+                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 >> 16;
+            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 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;
+        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);
@@ -2054,6 +2197,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) {
-- 
1.8.4.5




reply via email to

[Prev in Thread] Current Thread [Next in Thread]