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 4/8] scsi-disk: Implement 'SET TARGET PORT GROUPS'
Date: Fri, 27 Nov 2015 15:59:02 +0100	[thread overview]
Message-ID: <1448636346-24641-5-git-send-email-hare@suse.de> (raw)
In-Reply-To: <1448636346-24641-1-git-send-email-hare@suse.de>

Implement 'SET TARGET PORT GROUPS' handling. The ports states are
switched as indicated in the command; no strategy is implemented.
This might cause issues with standard Linux behaviour, which will
only switch the passive path to 'active' and leave the former
active path alone.

Signed-off-by: Hannes Reinecke <hare@suse.de>
---
 hw/scsi/scsi-disk.c  | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/block/scsi.h |   5 +++
 2 files changed, 123 insertions(+)

diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 8dabed3..52c73be 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -1915,6 +1915,111 @@ static void qbus_enumerate_port_desc(PortDescEnumerate *pd, BusState *bus)
     }
 }
 
+typedef struct PortGroupSetEnumerate {
+    uint64_t wwn;
+    uint16_t port_group;
+    uint8_t alua_state;
+} PortGroupSetEnumerate;
+
+static void qbus_enumerate_set_port(PortGroupSetEnumerate *, BusState *);
+
+static void qdev_enumerate_set_port(PortGroupSetEnumerate *ps, 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 == ps->wwn &&
+            s->port_group == ps->port_group) {
+            printf("pg %x: switch ALUA state %x -> %x\n",
+                   s->port_group, (s->alua_state & 0x0f), ps->alua_state);
+            s->alua_state = (s->alua_state & 0xf0) | ps->alua_state;
+            scsi_device_set_ua(&s->qdev,
+                               SENSE_CODE(ASYMMETRIC_ACCESS_STATE_CHANGED));
+        }
+    }
+    QLIST_FOREACH(child, &dev->child_bus, sibling) {
+        qbus_enumerate_set_port(ps, child);
+    }
+}
+
+static void qbus_enumerate_set_port(PortGroupSetEnumerate *ps, BusState *bus)
+{
+    BusChild *kid;
+
+    QTAILQ_FOREACH(kid, &bus->children, sibling) {
+        DeviceState *dev = kid->child;
+        qdev_enumerate_set_port(ps, dev);
+    }
+}
+
+static void scsi_emulate_set_target_port_groups(SCSIDiskReq *r, uint8_t *inbuf)
+{
+    SCSIRequest *req = &r->req;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+    uint32_t buflen = scsi_data_cdb_xfer(r->req.cmd.buf);
+    uint8_t *p = inbuf;
+    PortGroupEnumerate pg;
+    PortGroupSetEnumerate ps;
+    int i, pg_found = 0;
+
+    if (!s->wwn) {
+        scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
+    }
+
+    pg.numgrp = 0;
+    pg.wwn = s->wwn;
+    qbus_enumerate_port_group(&pg, sysbus_get_default());
+
+    p = &inbuf[4];
+    /* Validate input before continuing */
+    while (p < inbuf + buflen) {
+        uint16_t port_group;
+        uint8_t alua_state;
+
+        port_group = ((uint16_t)p[2] << 8) + p[3];
+        alua_state = p[0] & 0x7;
+
+        for (i = 0; i < pg.numgrp; i++) {
+            if ((port_group == pg.grp[i]) &&
+                (alua_state == (pg.alua_state[i] & 0x0f))) {
+                printf("pg %x: port already in state %d\n",
+                       pg.grp[i], (pg.alua_state[i] & 0x0f));
+                pg_found++;
+            }
+        }
+        p += 4;
+    }
+    if (pg_found == pg.numgrp) {
+        printf("all ports in requested state\n");
+        scsi_req_complete(&r->req, GOOD);
+        return;
+    }
+
+    p = &inbuf[4];
+    while (p < inbuf + buflen) {
+        uint16_t port_group;
+        uint8_t alua_state;
+
+        port_group = ((uint16_t)p[2] << 8) + p[3];
+        alua_state = p[0] & 0x7;
+
+        if (port_group == s->port_group) {
+            printf("pg %x: explicit switch current ALUA state "
+                   "%x -> %x\n",
+                   port_group, (s->alua_state & 0x0f), alua_state);
+            s->alua_state = (s->alua_state & 0xf0) | alua_state;
+        } else {
+            ps.wwn = s->wwn;
+            ps.port_group = port_group;
+            ps.alua_state = alua_state;
+            qbus_enumerate_set_port(&ps, sysbus_get_default());
+        }
+        p += 4;
+    }
+    scsi_req_complete(&r->req, GOOD);
+}
+
 static void scsi_disk_emulate_write_data(SCSIRequest *req)
 {
     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
@@ -1951,6 +2056,16 @@ static void scsi_disk_emulate_write_data(SCSIRequest *req)
         scsi_disk_emulate_write_same(r, r->iov.iov_base);
         break;
 
+    case MAINTENANCE_OUT:
+        if ((req->cmd.buf[1] & 31) == MO_SET_TARGET_PORT_GROUPS) {
+            DPRINTF("MO SET TARGET PORT GROUPS\n");
+            scsi_emulate_set_target_port_groups(r, r->iov.iov_base);
+            break;
+        }
+        DPRINTF("Unsupported Maintenance Out\n");
+        scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
+        break;
+
     default:
         abort();
     }
@@ -2215,6 +2330,9 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
         DPRINTF("Unsupported Maintenance In\n");
         goto illegal_request;
         break;
+    case MAINTENANCE_OUT:
+        DPRINTF("Maintenance Out (len %lu)\n", (long)r->req.cmd.xfer);
+        break;
     case MECHANISM_STATUS:
         buflen = scsi_emulate_mechanism_status(s, outbuf);
         if (buflen < 0) {
diff --git a/include/block/scsi.h b/include/block/scsi.h
index a9d0f64..47a25b8 100644
--- a/include/block/scsi.h
+++ b/include/block/scsi.h
@@ -156,6 +156,11 @@ const char *scsi_command_name(uint8_t cmd);
 #define MI_REPORT_TARGET_PORT_GROUPS 0xa
 
 /*
+ * MAINTENANCE OUT subcodes
+ */
+#define MO_SET_TARGET_PORT_GROUPS 0xa
+
+/*
  * READ POSITION service action codes
  */
 #define SHORT_FORM_BLOCK_ID  0x00
-- 
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 ` [Qemu-devel] [PATCH 3/8] scsi-disk: Implement 'REPORT TARGET PORT GROUPS' Hannes Reinecke
2015-11-27 14:59 ` Hannes Reinecke [this message]
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-5-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).