qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH] scsi-bus: fix to allow some special SCSI commands


From: TAMUKI Shoichi
Subject: [Qemu-devel] [PATCH] scsi-bus: fix to allow some special SCSI commands
Date: Fri, 11 Jul 2014 17:53:31 +0900

Currently, some special SCSI commands sent from the initiator in a
guest do not reach the target device.  To avoid this, extended (0x7e,)
variable length (0x7f,) and vendor specific (0xc0..0xff) opcodes are
now treated as valid CDBs.

Originally, the most significant 3 bits of a SCSI opcode specified the
length of the CDB.  However, when variable-length CDBs were created,
this correspondence was changed, and the entire opcode must be
examined to determine the CDB length.  The CDBs with the opcodes above
are done that way for now.

Signed-off-by: TAMUKI Shoichi <address@hidden>
---
 hw/scsi/scsi-bus.c              | 21 ++++++++++++++++++---
 hw/scsi/virtio-scsi.c           | 25 -------------------------
 include/hw/virtio/virtio-scsi.h | 25 +++++++++++++++++++++++++
 3 files changed, 43 insertions(+), 28 deletions(-)

diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index ea1ac09..c631ebd 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -6,10 +6,12 @@
 #include "sysemu/blockdev.h"
 #include "trace.h"
 #include "sysemu/dma.h"
+#include "hw/virtio/virtio-scsi.h"
 
 static char *scsibus_get_dev_path(DeviceState *dev);
 static char *scsibus_get_fw_dev_path(DeviceState *dev);
-static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf);
+static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf,
+        uint32_t len);
 static void scsi_req_dequeue(SCSIRequest *req);
 static uint8_t *scsi_target_alloc_buf(SCSIRequest *req, size_t len);
 static void scsi_target_free_buf(SCSIRequest *req);
@@ -563,7 +565,8 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, 
uint32_t lun,
     SCSIRequest *req;
     SCSICommand cmd;
 
-    if (scsi_req_parse(&cmd, d, buf) != 0) {
+    if (scsi_req_parse(&cmd, d, buf,
+            ((VirtIOSCSIReq *) hba_private)->dev->parent_obj.cdb_size) != 0) {
         trace_scsi_req_parse_bad(d->id, lun, tag, buf[0]);
         req = scsi_req_alloc(&reqops_invalid_opcode, d, tag, lun, hba_private);
     } else {
@@ -1181,7 +1184,8 @@ static uint64_t scsi_cmd_lba(SCSICommand *cmd)
     return lba;
 }
 
-static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
+static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf,
+        uint32_t len)
 {
     int rc;
 
@@ -1193,12 +1197,23 @@ static int scsi_req_parse(SCSICommand *cmd, SCSIDevice 
*dev, uint8_t *buf)
     case 2:
         cmd->len = 10;
         break;
+    case 3:
+        if (buf[0] == 0x7e || (buf[0] == 0x7f && len >= 16)) {
+            cmd->len = len;
+        } else {
+            return -1;
+        }
+        break;
     case 4:
         cmd->len = 16;
         break;
     case 5:
         cmd->len = 12;
         break;
+    case 6:
+    case 7:
+        cmd->len = len;
+        break;
     default:
         return -1;
     }
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 0eb069a..c5710aa 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -21,31 +21,6 @@
 #include <hw/virtio/virtio-bus.h>
 #include "hw/virtio/virtio-access.h"
 
-typedef struct VirtIOSCSIReq {
-    VirtIOSCSI *dev;
-    VirtQueue *vq;
-    VirtQueueElement elem;
-    QEMUSGList qsgl;
-    SCSIRequest *sreq;
-    size_t resp_size;
-    enum SCSIXferMode mode;
-    QEMUIOVector resp_iov;
-    union {
-        VirtIOSCSICmdResp     cmd;
-        VirtIOSCSICtrlTMFResp tmf;
-        VirtIOSCSICtrlANResp  an;
-        VirtIOSCSIEvent       event;
-    } resp;
-    union {
-        struct {
-            VirtIOSCSICmdReq  cmd;
-            uint8_t           cdb[];
-        } QEMU_PACKED;
-        VirtIOSCSICtrlTMFReq  tmf;
-        VirtIOSCSICtrlANReq   an;
-    } req;
-} VirtIOSCSIReq;
-
 QEMU_BUILD_BUG_ON(offsetof(VirtIOSCSIReq, req.cdb) !=
                   offsetof(VirtIOSCSIReq, req.cmd) + sizeof(VirtIOSCSICmdReq));
 
diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h
index 0419ee4..fae3f81 100644
--- a/include/hw/virtio/virtio-scsi.h
+++ b/include/hw/virtio/virtio-scsi.h
@@ -172,6 +172,31 @@ typedef struct {
     bool events_dropped;
 } VirtIOSCSI;
 
+typedef struct VirtIOSCSIReq {
+    VirtIOSCSI *dev;
+    VirtQueue *vq;
+    VirtQueueElement elem;
+    QEMUSGList qsgl;
+    SCSIRequest *sreq;
+    size_t resp_size;
+    enum SCSIXferMode mode;
+    QEMUIOVector resp_iov;
+    union {
+        VirtIOSCSICmdResp     cmd;
+        VirtIOSCSICtrlTMFResp tmf;
+        VirtIOSCSICtrlANResp  an;
+        VirtIOSCSIEvent       event;
+    } resp;
+    union {
+        struct {
+            VirtIOSCSICmdReq  cmd;
+            uint8_t           cdb[];
+        } QEMU_PACKED;
+        VirtIOSCSICtrlTMFReq  tmf;
+        VirtIOSCSICtrlANReq   an;
+    } req;
+} VirtIOSCSIReq;
+
 #define DEFINE_VIRTIO_SCSI_PROPERTIES(_state, _conf_field)                     
\
     DEFINE_PROP_UINT32("num_queues", _state, _conf_field.num_queues, 1),       
\
     DEFINE_PROP_UINT32("max_sectors", _state, _conf_field.max_sectors, 
0xFFFF),\
-- 
1.9.0



reply via email to

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