]> git.proxmox.com Git - mirror_qemu.git/commitdiff
scsi: move handling of REPORT LUNS and invalid LUNs to common code
authorPaolo Bonzini <pbonzini@redhat.com>
Wed, 3 Aug 2011 08:49:14 +0000 (10:49 +0200)
committerAnthony Liguori <aliguori@us.ibm.com>
Fri, 12 Aug 2011 13:30:20 +0000 (08:30 -0500)
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
hw/scsi-bus.c
hw/scsi-defs.h
hw/scsi-disk.c
hw/scsi-generic.c

index c7e7b08fd56654a0f723eb58ecf8569f8e24bbb9..8b229af989a2fbe23d8278867d87057b569aa4b9 100644 (file)
@@ -149,6 +149,172 @@ struct SCSIReqOps reqops_invalid_opcode = {
     .send_command = scsi_invalid_command
 };
 
+/* SCSIReqOps implementation for REPORT LUNS and for commands sent to
+   an invalid LUN.  */
+
+typedef struct SCSITargetReq SCSITargetReq;
+
+struct SCSITargetReq {
+    SCSIRequest req;
+    int len;
+    uint8_t buf[64];
+};
+
+static void store_lun(uint8_t *outbuf, int lun)
+{
+    if (lun < 256) {
+        outbuf[1] = lun;
+        return;
+    }
+    outbuf[1] = (lun & 255);
+    outbuf[0] = (lun >> 8) | 0x40;
+}
+
+static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
+{
+    int len;
+    if (r->req.cmd.xfer < 16) {
+        return false;
+    }
+    if (r->req.cmd.buf[2] > 2) {
+        return false;
+    }
+    len = MIN(sizeof r->buf, r->req.cmd.xfer);
+    memset(r->buf, 0, len);
+    if (r->req.dev->lun != 0) {
+        r->buf[3] = 16;
+        r->len = 24;
+        store_lun(&r->buf[16], r->req.dev->lun);
+    } else {
+        r->buf[3] = 8;
+        r->len = 16;
+    }
+    return true;
+}
+
+static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
+{
+    assert(r->req.dev->lun != r->req.lun);
+    if (r->req.cmd.buf[1] & 0x2) {
+        /* Command support data - optional, not implemented */
+        return false;
+    }
+
+    if (r->req.cmd.buf[1] & 0x1) {
+        /* Vital product data */
+        uint8_t page_code = r->req.cmd.buf[2];
+        if (r->req.cmd.xfer < 4) {
+            return false;
+        }
+
+        r->buf[r->len++] = page_code ; /* this page */
+        r->buf[r->len++] = 0x00;
+
+        switch (page_code) {
+        case 0x00: /* Supported page codes, mandatory */
+        {
+            int pages;
+            pages = r->len++;
+            r->buf[r->len++] = 0x00; /* list of supported pages (this page) */
+            r->buf[pages] = r->len - pages - 1; /* number of pages */
+            break;
+        }
+        default:
+            return false;
+        }
+        /* done with EVPD */
+        assert(r->len < sizeof(r->buf));
+        r->len = MIN(r->req.cmd.xfer, r->len);
+        return true;
+    }
+
+    /* Standard INQUIRY data */
+    if (r->req.cmd.buf[2] != 0) {
+        return false;
+    }
+
+    /* PAGE CODE == 0 */
+    if (r->req.cmd.xfer < 5) {
+        return -1;
+    }
+
+    r->len = MIN(r->req.cmd.xfer, 36);
+    memset(r->buf, 0, r->len);
+    if (r->req.lun != 0) {
+        r->buf[0] = TYPE_NO_LUN;
+    } else {
+        r->buf[0] = TYPE_NOT_PRESENT | TYPE_INACTIVE;
+        r->buf[2] = 5; /* Version */
+        r->buf[3] = 2 | 0x10; /* HiSup, response data format */
+        r->buf[4] = r->len - 5; /* Additional Length = (Len - 1) - 4 */
+        r->buf[7] = 0x10 | (r->req.bus->tcq ? 0x02 : 0); /* Sync, TCQ.  */
+        memcpy(&r->buf[8], "QEMU    ", 8);
+        memcpy(&r->buf[16], "QEMU TARGET     ", 16);
+        strncpy((char *) &r->buf[32], QEMU_VERSION, 4);
+    }
+    return true;
+}
+
+static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
+{
+    SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
+
+    switch (buf[0]) {
+    case REPORT_LUNS:
+        if (!scsi_target_emulate_report_luns(r)) {
+            goto illegal_request;
+        }
+        break;
+    case INQUIRY:
+        if (!scsi_target_emulate_inquiry(r)) {
+            goto illegal_request;
+        }
+        break;
+    default:
+        scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED));
+        scsi_req_complete(req, CHECK_CONDITION);
+        return 0;
+    illegal_request:
+        scsi_req_build_sense(req, SENSE_CODE(INVALID_FIELD));
+        scsi_req_complete(req, CHECK_CONDITION);
+        return 0;
+    }
+
+    if (!r->len) {
+        scsi_req_complete(req, GOOD);
+    }
+    return r->len;
+}
+
+static void scsi_target_read_data(SCSIRequest *req)
+{
+    SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
+    uint32_t n;
+
+    n = r->len;
+    if (n > 0) {
+        r->len = 0;
+        scsi_req_data(&r->req, n);
+    } else {
+        scsi_req_complete(&r->req, GOOD);
+    }
+}
+
+static uint8_t *scsi_target_get_buf(SCSIRequest *req)
+{
+    SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
+
+    return r->buf;
+}
+
+struct SCSIReqOps reqops_target_command = {
+    .size         = sizeof(SCSITargetReq),
+    .send_command = scsi_target_send_command,
+    .read_data    = scsi_target_read_data,
+    .get_buf      = scsi_target_get_buf,
+};
+
+
 SCSIRequest *scsi_req_alloc(SCSIReqOps *reqops, SCSIDevice *d, uint32_t tag,
                             uint32_t lun, void *hba_private)
 {
@@ -184,7 +350,14 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
             trace_scsi_req_parsed_lba(d->id, lun, tag, buf[0],
                                       cmd.lba);
         }
-        req = d->info->alloc_req(d, tag, lun, hba_private);
+
+        if ((lun != d->lun && buf[0] != REQUEST_SENSE) ||
+            buf[0] == REPORT_LUNS) {
+            req = scsi_req_alloc(&reqops_target_command, d, tag, lun,
+                                 hba_private);
+        } else {
+            req = d->info->alloc_req(d, tag, lun, hba_private);
+        }
     }
 
     req->cmd = cmd;
index 27010b74c072d2c2ff36fd6d6e6dd0baa36f6855..977c38b721e16327ae762a4d105a20fbbf4d3647 100644 (file)
 #define TYPE_ENCLOSURE      0x0d    /* Enclosure Services Device */
 #define TYPE_RBC            0x0e    /* Simplified Direct-Access Device */
 #define TYPE_OSD            0x11    /* Object-storage Device */
+#define TYPE_WLUN           0x1e    /* Well known LUN */
+#define TYPE_NOT_PRESENT    0x1f
+#define TYPE_INACTIVE       0x20
 #define TYPE_NO_LUN         0x7f
 
index 1abf90952b7aa08d032c6d0395b65decb95525ed..fe7368ba2c4240014d0425c29aeec6fd204c3baf 100644 (file)
@@ -482,11 +482,6 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
 
     memset(outbuf, 0, buflen);
 
-    if (req->lun) {
-        outbuf[0] = 0x7f;       /* LUN not supported */
-        return buflen;
-    }
-
     outbuf[0] = s->qdev.type & 0x1f;
     if (s->qdev.type == TYPE_ROM) {
         outbuf[1] = 0x80;
@@ -918,13 +913,6 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
         }
         DPRINTF("Unsupported Service Action In\n");
         goto illegal_request;
-    case REPORT_LUNS:
-        if (req->cmd.xfer < 16)
-            goto illegal_request;
-        memset(outbuf, 0, 16);
-        outbuf[3] = 8;
-        buflen = 16;
-        break;
     case VERIFY_10:
         break;
     default:
@@ -974,14 +962,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
     }
 #endif
 
-    if (req->lun) {
-        /* Only LUN 0 supported.  */
-        DPRINTF("Unimplemented LUN %d\n", req->lun);
-        if (command != REQUEST_SENSE && command != INQUIRY) {
-            scsi_check_condition(r, SENSE_CODE(LUN_NOT_SUPPORTED));
-            return 0;
-        }
-    }
     switch (command) {
     case TEST_UNIT_READY:
     case REQUEST_SENSE:
@@ -999,7 +979,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
     case READ_TOC:
     case GET_CONFIGURATION:
     case SERVICE_ACTION_IN:
-    case REPORT_LUNS:
     case VERIFY_10:
         rc = scsi_disk_emulate_command(r, outbuf);
         if (rc < 0) {
index 3b43f1c7e2b1a75d332cfc02b0c71b60b2d13d15..70265d06b9d9ccbbc3caecd04432fc4751ad9fc0 100644 (file)
@@ -287,13 +287,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
     SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
     int ret;
 
-    if (cmd[0] != REQUEST_SENSE && req->lun != s->qdev.lun) {
-        DPRINTF("Unimplemented LUN %d\n", req->lun);
-        scsi_req_build_sense(&r->req, SENSE_CODE(LUN_NOT_SUPPORTED));
-        scsi_req_complete(&r->req, CHECK_CONDITION);
-        return 0;
-    }
-
     scsi_req_fixup(&r->req);
 
     DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,