qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Hannes Reinecke <hare@suse.de>
To: Paolo Bonzini <pbonzini@redhat.com>
Cc: Johannes Thumshirn <jthumshirn@suse.com>,
	Stefan Hajnoczi <stefanha@gmail.com>,
	Hannes Reinecke <hare@suse.de>,
	qemu-devel@nongnu.org, Alexander Graf <agraf@suse.de>
Subject: [Qemu-devel] [PATCH 3/8] scsi-disk: Implement 'REPORT TARGET PORT GROUPS'
Date: Fri, 27 Nov 2015 15:59:01 +0100	[thread overview]
Message-ID: <1448636346-24641-4-git-send-email-hare@suse.de> (raw)
In-Reply-To: <1448636346-24641-1-git-send-email-hare@suse.de>

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 <hare@suse.de>
---
 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

  parent reply	other threads:[~2015-11-27 14:59 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-27 14:58 [Qemu-devel] [PATCH RFC 0/8] scsi-disk: Active/passive ALUA support Hannes Reinecke
2015-11-27 14:58 ` [Qemu-devel] [PATCH 1/8] scsi-disk: Add 'port_group' property Hannes Reinecke
2015-11-27 14:59 ` [Qemu-devel] [PATCH 2/8] scsi-disk: Add 'alua_state' property Hannes Reinecke
2015-11-27 14:59 ` Hannes Reinecke [this message]
2015-11-27 14:59 ` [Qemu-devel] [PATCH 4/8] scsi-disk: Implement 'SET TARGET PORT GROUPS' Hannes Reinecke
2015-11-27 14:59 ` [Qemu-devel] [PATCH 5/8] scsi-disk: implement ALUA policy Hannes Reinecke
2015-11-27 14:59 ` [Qemu-devel] [PATCH 6/8] scsi-disk: Allow READ CAPACITY in standby Hannes Reinecke
2015-11-27 14:59 ` [Qemu-devel] [PATCH 7/8] scsi-disk: Implement 'alua_preferred' option Hannes Reinecke
2015-11-27 14:59 ` [Qemu-devel] [PATCH 8/8] block: Implement 'block_disconnect' HMP command Hannes Reinecke
2015-11-27 18:00   ` Eric Blake
2015-12-10  8:26 ` [Qemu-devel] [PATCH RFC 0/8] scsi-disk: Active/passive ALUA support Stefan Hajnoczi
2015-12-10  9:13   ` Hannes Reinecke
2015-12-14  7:24     ` Stefan Hajnoczi
2015-12-14  7:35       ` Hannes Reinecke
2015-12-15  3:02         ` Stefan Hajnoczi
2015-12-15  6:49           ` Hannes Reinecke

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1448636346-24641-4-git-send-email-hare@suse.de \
    --to=hare@suse.de \
    --cc=agraf@suse.de \
    --cc=jthumshirn@suse.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).