* [Qemu-devel] [PATCH 00/10] scsi: add specialized block device passthrough
@ 2011-10-12 14:24 Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 01/10] scsi-generic: drop SCSIGenericState Paolo Bonzini
` (9 more replies)
0 siblings, 10 replies; 11+ messages in thread
From: Paolo Bonzini @ 2011-10-12 14:24 UTC (permalink / raw)
To: qemu-devel
This series adds a new scsi-block device that is able to do SCSI
passthrough for block devices only, but at the same time does not suffer
the limitations of scsi-generic. In particular it does not need a
bounce buffer that is as big as the request, and will be able to support
s/g lists. This puts scsi-block and virtio-blk on feature parity.
To do this, scsi-generic is simplified to the point that its ReqOps can be
used by any SCSIDevice. Then, a new scsi-disk variant is introduced that
uses regular AIO read/writes whenever possible, and falls back to SG_IO
for other SCSI commands. Management can then choose between isolating
the guest from the specificities of the target device (scsi-hd/scsi-cd),
or making it aware of them (scsi-block).
In the future, both scsi-generic and scsi-block could be made to support
other types of passthrough, for example iSCSI passthrough.
Patches 1-4 are cleanups to scsi-generic, patches 5-6 are cleanups
to scsi-disk. Then comes the actual implementation of the feature.
Paolo Bonzini (10):
scsi-generic: drop SCSIGenericState
scsi-generic: remove scsi_req_fixup
scsi-generic: check ioctl statuses when SG_IO succeeds
scsi-generic: look at host status
scsi-disk: do not duplicate BlockDriverState member
scsi-disk: small clean up to INQUIRY
scsi: make reqops const
scsi: export scsi_generic_reqops
scsi: pass cdb to alloc_req
scsi-disk: add scsi-block for device passthrough
hw/scsi-bus.c | 12 ++--
hw/scsi-disk.c | 260 +++++++++++++++++++++++++++++++++++++---------------
hw/scsi-generic.c | 128 ++++++++++++---------------
hw/scsi.h | 12 ++-
4 files changed, 255 insertions(+), 157 deletions(-)
--
1.7.6
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 01/10] scsi-generic: drop SCSIGenericState
2011-10-12 14:24 [Qemu-devel] [PATCH 00/10] scsi: add specialized block device passthrough Paolo Bonzini
@ 2011-10-12 14:24 ` Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 02/10] scsi-generic: remove scsi_req_fixup Paolo Bonzini
` (8 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Paolo Bonzini @ 2011-10-12 14:24 UTC (permalink / raw)
To: qemu-devel
It is not needed, because s->bs is already stored in SCSIDevice, and
can be reached from the conf.bs member.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi-generic.c | 85 +++++++++++++++++++++++------------------------------
1 files changed, 37 insertions(+), 48 deletions(-)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 2696fa1..1e5c41b 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -46,8 +46,6 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
#define MAX_UINT ((unsigned int)-1)
#endif
-typedef struct SCSIGenericState SCSIGenericState;
-
typedef struct SCSIGenericReq {
SCSIRequest req;
uint8_t *buf;
@@ -56,12 +54,6 @@ typedef struct SCSIGenericReq {
sg_io_hdr_t io_header;
} SCSIGenericReq;
-struct SCSIGenericState
-{
- SCSIDevice qdev;
- BlockDriverState *bs;
-};
-
static void scsi_free_request(SCSIRequest *req)
{
SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
@@ -174,7 +166,7 @@ static void scsi_read_complete(void * opaque, int ret)
static void scsi_read_data(SCSIRequest *req)
{
SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
- SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
+ SCSIDevice *s = r->req.dev;
int ret;
DPRINTF("scsi_read_data 0x%x\n", req->tag);
@@ -183,7 +175,7 @@ static void scsi_read_data(SCSIRequest *req)
return;
}
- ret = execute_command(s->bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
+ ret = execute_command(s->conf.bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
if (ret < 0) {
scsi_command_complete(r, ret);
return;
@@ -193,7 +185,7 @@ static void scsi_read_data(SCSIRequest *req)
static void scsi_write_complete(void * opaque, int ret)
{
SCSIGenericReq *r = (SCSIGenericReq *)opaque;
- SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
+ SCSIDevice *s = r->req.dev;
DPRINTF("scsi_write_complete() ret = %d\n", ret);
r->req.aiocb = NULL;
@@ -204,9 +196,9 @@ static void scsi_write_complete(void * opaque, int ret)
}
if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
- s->qdev.type == TYPE_TAPE) {
- s->qdev.blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
- DPRINTF("block size %d\n", s->qdev.blocksize);
+ s->type == TYPE_TAPE) {
+ s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
+ DPRINTF("block size %d\n", s->blocksize);
}
scsi_command_complete(r, ret);
@@ -216,8 +208,8 @@ static void scsi_write_complete(void * opaque, int ret)
The transfer may complete asynchronously. */
static void scsi_write_data(SCSIRequest *req)
{
- SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+ SCSIDevice *s = r->req.dev;
int ret;
DPRINTF("scsi_write_data 0x%x\n", req->tag);
@@ -227,7 +219,7 @@ static void scsi_write_data(SCSIRequest *req)
return;
}
- ret = execute_command(s->bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
+ ret = execute_command(s->conf.bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
if (ret < 0) {
scsi_command_complete(r, ret);
}
@@ -261,8 +253,8 @@ static void scsi_req_fixup(SCSIRequest *req)
static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
{
- SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+ SCSIDevice *s = r->req.dev;
int ret;
scsi_req_fixup(&r->req);
@@ -285,7 +277,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
g_free(r->buf);
r->buflen = 0;
r->buf = NULL;
- ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete);
+ ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete);
if (ret < 0) {
scsi_command_complete(r, ret);
return 0;
@@ -372,77 +364,74 @@ static int get_stream_blocksize(BlockDriverState *bdrv)
static void scsi_generic_reset(DeviceState *dev)
{
- SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev.qdev, dev);
+ SCSIDevice *s = DO_UPCAST(SCSIDevice, qdev, dev);
- scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET));
+ scsi_device_purge_requests(s, SENSE_CODE(RESET));
}
-static void scsi_destroy(SCSIDevice *d)
+static void scsi_destroy(SCSIDevice *s)
{
- SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
-
- scsi_device_purge_requests(&s->qdev, SENSE_CODE(NO_SENSE));
- blockdev_mark_auto_del(s->qdev.conf.bs);
+ scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE));
+ blockdev_mark_auto_del(s->conf.bs);
}
-static int scsi_generic_initfn(SCSIDevice *dev)
+static int scsi_generic_initfn(SCSIDevice *s)
{
- SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, dev);
int sg_version;
struct sg_scsi_id scsiid;
- if (!s->qdev.conf.bs) {
+ if (!s->conf.bs) {
error_report("scsi-generic: drive property not set");
return -1;
}
- s->bs = s->qdev.conf.bs;
/* check we are really using a /dev/sg* file */
- if (!bdrv_is_sg(s->bs)) {
+ if (!bdrv_is_sg(s->conf.bs)) {
error_report("scsi-generic: not /dev/sg*");
return -1;
}
- if (bdrv_get_on_error(s->bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
+ if (bdrv_get_on_error(s->conf.bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
error_report("Device doesn't support drive option werror");
return -1;
}
- if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) {
+ if (bdrv_get_on_error(s->conf.bs, 1) != BLOCK_ERR_REPORT) {
error_report("Device doesn't support drive option rerror");
return -1;
}
/* check we are using a driver managing SG_IO (version 3 and after */
- if (bdrv_ioctl(s->bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
+ if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
sg_version < 30000) {
error_report("scsi-generic: scsi generic interface too old");
return -1;
}
/* get LUN of the /dev/sg? */
- if (bdrv_ioctl(s->bs, SG_GET_SCSI_ID, &scsiid)) {
+ if (bdrv_ioctl(s->conf.bs, SG_GET_SCSI_ID, &scsiid)) {
error_report("scsi-generic: SG_GET_SCSI_ID ioctl failed");
return -1;
}
/* define device state */
- s->qdev.type = scsiid.scsi_type;
- DPRINTF("device type %d\n", s->qdev.type);
- if (s->qdev.type == TYPE_TAPE) {
- s->qdev.blocksize = get_stream_blocksize(s->bs);
- if (s->qdev.blocksize == -1)
- s->qdev.blocksize = 0;
+ s->type = scsiid.scsi_type;
+ DPRINTF("device type %d\n", s->type);
+ if (s->type == TYPE_TAPE) {
+ s->blocksize = get_stream_blocksize(s->conf.bs);
+ if (s->blocksize == -1)
+ s->blocksize = 0;
} else {
- s->qdev.blocksize = get_blocksize(s->bs);
+ s->blocksize = get_blocksize(s->conf.bs);
/* removable media returns 0 if not present */
- if (s->qdev.blocksize <= 0) {
- if (s->qdev.type == TYPE_ROM || s->qdev.type == TYPE_WORM)
- s->qdev.blocksize = 2048;
+ if (s->blocksize <= 0) {
+ if (s->type == TYPE_ROM || s->type == TYPE_WORM)
+ s->blocksize = 2048;
else
- s->qdev.blocksize = 512;
+ s->blocksize = 512;
}
}
- DPRINTF("block size %d\n", s->qdev.blocksize);
+
+ DPRINTF("block size %d\n", s->blocksize);
return 0;
}
@@ -468,13 +457,13 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
static SCSIDeviceInfo scsi_generic_info = {
.qdev.name = "scsi-generic",
.qdev.desc = "pass through generic scsi device (/dev/sg*)",
- .qdev.size = sizeof(SCSIGenericState),
+ .qdev.size = sizeof(SCSIDevice),
.qdev.reset = scsi_generic_reset,
.init = scsi_generic_initfn,
.destroy = scsi_destroy,
.alloc_req = scsi_new_request,
.qdev.props = (Property[]) {
- DEFINE_BLOCK_PROPERTIES(SCSIGenericState, qdev.conf),
+ DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
DEFINE_PROP_END_OF_LIST(),
},
};
--
1.7.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 02/10] scsi-generic: remove scsi_req_fixup
2011-10-12 14:24 [Qemu-devel] [PATCH 00/10] scsi: add specialized block device passthrough Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 01/10] scsi-generic: drop SCSIGenericState Paolo Bonzini
@ 2011-10-12 14:24 ` Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 03/10] scsi-generic: check ioctl statuses when SG_IO succeeds Paolo Bonzini
` (7 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Paolo Bonzini @ 2011-10-12 14:24 UTC (permalink / raw)
To: qemu-devel
This is not needed anymore, since asynchronous ioctls were introduced
by commit 221f715 (new scsi-generic abstraction, use SG_IO, 2009-03-28).
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi-generic.c | 15 ---------------
1 files changed, 0 insertions(+), 15 deletions(-)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 1e5c41b..5130e9a 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -233,19 +233,6 @@ static uint8_t *scsi_get_buf(SCSIRequest *req)
return r->buf;
}
-static void scsi_req_fixup(SCSIRequest *req)
-{
- switch(req->cmd.buf[0]) {
- case REWIND:
- case START_STOP:
- if (req->dev->type == TYPE_TAPE) {
- /* force IMMED, otherwise qemu waits end of command */
- req->cmd.buf[1] = 0x01;
- }
- break;
- }
-}
-
/* Execute a scsi command. Returns the length of the data expected by the
command. This will be Positive for data transfers from the device
(eg. disk reads), negative for transfers to the device (eg. disk writes),
@@ -257,8 +244,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
SCSIDevice *s = r->req.dev;
int ret;
- scsi_req_fixup(&r->req);
-
DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
r->req.cmd.xfer, cmd[0]);
--
1.7.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 03/10] scsi-generic: check ioctl statuses when SG_IO succeeds
2011-10-12 14:24 [Qemu-devel] [PATCH 00/10] scsi: add specialized block device passthrough Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 01/10] scsi-generic: drop SCSIGenericState Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 02/10] scsi-generic: remove scsi_req_fixup Paolo Bonzini
@ 2011-10-12 14:24 ` Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 04/10] scsi-generic: look at host status Paolo Bonzini
` (6 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Paolo Bonzini @ 2011-10-12 14:24 UTC (permalink / raw)
To: qemu-devel
A succeeding ioctl does not imply that the SCSI command succeeded.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi-generic.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 5130e9a..04549aa 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -311,7 +311,7 @@ static int get_blocksize(BlockDriverState *bdrv)
io_header.timeout = 6000; /* XXX */
ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
- if (ret < 0)
+ if (ret < 0 || io_header.driver_status || io_header.host_status)
return -1;
return ldl_be_p(&buf[4]);
@@ -341,7 +341,7 @@ static int get_stream_blocksize(BlockDriverState *bdrv)
io_header.timeout = 6000; /* XXX */
ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
- if (ret < 0)
+ if (ret < 0 || io_header.driver_status || io_header.host_status)
return -1;
return ldl_be_p(&buf[0]) & 0xffffff;
--
1.7.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 04/10] scsi-generic: look at host status
2011-10-12 14:24 [Qemu-devel] [PATCH 00/10] scsi: add specialized block device passthrough Paolo Bonzini
` (2 preceding siblings ...)
2011-10-12 14:24 ` [Qemu-devel] [PATCH 03/10] scsi-generic: check ioctl statuses when SG_IO succeeds Paolo Bonzini
@ 2011-10-12 14:24 ` Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 05/10] scsi-disk: do not duplicate BlockDriverState member Paolo Bonzini
` (5 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Paolo Bonzini @ 2011-10-12 14:24 UTC (permalink / raw)
To: qemu-devel
Pass down the host status so that failing transport can be detected
by the guest. Similar treatment of host status could be done in
virtio-blk, too.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi-generic.c | 20 ++++++++++++++++----
1 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 04549aa..7b291ec 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -39,8 +39,13 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
#define SCSI_SENSE_BUF_SIZE 96
-#define SG_ERR_DRIVER_TIMEOUT 0x06
-#define SG_ERR_DRIVER_SENSE 0x08
+#define SG_ERR_DRIVER_TIMEOUT 0x06
+#define SG_ERR_DRIVER_SENSE 0x08
+
+#define SG_ERR_DID_OK 0x00
+#define SG_ERR_DID_NO_CONNECT 0x01
+#define SG_ERR_DID_BUS_BUSY 0x02
+#define SG_ERR_DID_TIME_OUT 0x03
#ifndef MAX_UINT
#define MAX_UINT ((unsigned int)-1)
@@ -68,8 +73,9 @@ static void scsi_command_complete(void *opaque, int ret)
SCSIGenericReq *r = (SCSIGenericReq *)opaque;
r->req.aiocb = NULL;
- if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE)
+ if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
r->req.sense_len = r->io_header.sb_len_wr;
+ }
if (ret != 0) {
switch (ret) {
@@ -86,9 +92,15 @@ static void scsi_command_complete(void *opaque, int ret)
break;
}
} else {
- if (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT) {
+ if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT ||
+ r->io_header.host_status == SG_ERR_DID_BUS_BUSY ||
+ r->io_header.host_status == SG_ERR_DID_TIME_OUT ||
+ (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) {
status = BUSY;
BADF("Driver Timeout\n");
+ } else if (r->io_header.host_status) {
+ status = CHECK_CONDITION;
+ scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
} else if (r->io_header.status) {
status = r->io_header.status;
} else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
--
1.7.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 05/10] scsi-disk: do not duplicate BlockDriverState member
2011-10-12 14:24 [Qemu-devel] [PATCH 00/10] scsi: add specialized block device passthrough Paolo Bonzini
` (3 preceding siblings ...)
2011-10-12 14:24 ` [Qemu-devel] [PATCH 04/10] scsi-generic: look at host status Paolo Bonzini
@ 2011-10-12 14:24 ` Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 06/10] scsi-disk: small clean up to INQUIRY Paolo Bonzini
` (4 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Paolo Bonzini @ 2011-10-12 14:24 UTC (permalink / raw)
To: qemu-devel
Same as for scsi-generic, avoid duplication even if it causes longer
lines.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi-disk.c | 94 +++++++++++++++++++++++++++----------------------------
1 files changed, 46 insertions(+), 48 deletions(-)
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 860a3bf..5e3ef51 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -65,7 +65,6 @@ typedef struct SCSIDiskReq {
struct SCSIDiskState
{
SCSIDevice qdev;
- BlockDriverState *bs;
/* The qemu block layer uses a fixed 512 byte sector size.
This is the number of 512 byte blocks in a single scsi sector. */
int cluster_size;
@@ -119,7 +118,7 @@ static uint32_t scsi_init_iovec(SCSIDiskReq *r)
if (!r->iov.iov_base) {
r->buflen = SCSI_DMA_BUF_SIZE;
- r->iov.iov_base = qemu_blockalign(s->bs, r->buflen);
+ r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen);
}
r->iov.iov_len = MIN(r->sector_count * 512, r->buflen);
qemu_iovec_init_external(&r->qiov, &r->iov, 1);
@@ -134,7 +133,7 @@ static void scsi_read_complete(void * opaque, int ret)
if (r->req.aiocb != NULL) {
r->req.aiocb = NULL;
- bdrv_acct_done(s->bs, &r->acct);
+ bdrv_acct_done(s->qdev.conf.bs, &r->acct);
}
if (ret) {
@@ -160,7 +159,7 @@ static void scsi_flush_complete(void * opaque, int ret)
if (r->req.aiocb != NULL) {
r->req.aiocb = NULL;
- bdrv_acct_done(s->bs, &r->acct);
+ bdrv_acct_done(s->qdev.conf.bs, &r->acct);
}
if (ret < 0) {
@@ -210,8 +209,8 @@ static void scsi_read_data(SCSIRequest *req)
/* Save a ref for scsi_read_complete, in case r is canceled. */
scsi_req_ref(&r->req);
n = scsi_init_iovec(r);
- bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
- r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n,
+ bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
+ r->req.aiocb = bdrv_aio_readv(s->qdev.conf.bs, r->sector, &r->qiov, n,
scsi_read_complete, r);
if (r->req.aiocb == NULL) {
scsi_read_complete(r, -EIO);
@@ -222,10 +221,10 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
{
int is_read = (type == SCSI_REQ_STATUS_RETRY_READ);
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- BlockErrorAction action = bdrv_get_on_error(s->bs, is_read);
+ BlockErrorAction action = bdrv_get_on_error(s->qdev.conf.bs, is_read);
if (action == BLOCK_ERR_IGNORE) {
- bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, is_read);
+ bdrv_mon_event(s->qdev.conf.bs, BDRV_ACTION_IGNORE, is_read);
return 0;
}
@@ -235,9 +234,9 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
type &= SCSI_REQ_STATUS_RETRY_TYPE_MASK;
r->status |= SCSI_REQ_STATUS_RETRY | type;
- bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
+ bdrv_mon_event(s->qdev.conf.bs, BDRV_ACTION_STOP, is_read);
vm_stop(RUN_STATE_IO_ERROR);
- bdrv_iostatus_set_err(s->bs, error);
+ bdrv_iostatus_set_err(s->qdev.conf.bs, error);
return 1;
} else {
switch (error) {
@@ -254,7 +253,7 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
scsi_check_condition(r, SENSE_CODE(IO_ERROR));
break;
}
- bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read);
+ bdrv_mon_event(s->qdev.conf.bs, BDRV_ACTION_REPORT, is_read);
return 0;
}
}
@@ -267,7 +266,7 @@ static void scsi_write_complete(void * opaque, int ret)
if (r->req.aiocb != NULL) {
r->req.aiocb = NULL;
- bdrv_acct_done(s->bs, &r->acct);
+ bdrv_acct_done(s->qdev.conf.bs, &r->acct);
}
if (ret) {
@@ -311,8 +310,8 @@ static void scsi_write_data(SCSIRequest *req)
if (s->tray_open) {
scsi_write_complete(r, -ENOMEDIUM);
}
- bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE);
- r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n,
+ bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE);
+ r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, r->sector, &r->qiov, n,
scsi_write_complete, r);
if (r->req.aiocb == NULL) {
scsi_write_complete(r, -ENOMEM);
@@ -450,7 +449,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
case 0x83: /* Device identification page, mandatory */
{
int max_len = 255 - 8;
- int id_len = strlen(bdrv_get_device_name(s->bs));
+ int id_len = strlen(bdrv_get_device_name(s->qdev.conf.bs));
if (id_len > max_len)
id_len = max_len;
@@ -463,7 +462,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
outbuf[buflen++] = 0; // reserved
outbuf[buflen++] = id_len; // length of data following
- memcpy(outbuf+buflen, bdrv_get_device_name(s->bs), id_len);
+ memcpy(outbuf+buflen, bdrv_get_device_name(s->qdev.conf.bs), id_len);
buflen += id_len;
break;
}
@@ -580,10 +579,10 @@ static inline bool media_is_dvd(SCSIDiskState *s)
if (s->qdev.type != TYPE_ROM) {
return false;
}
- if (!bdrv_is_inserted(s->bs)) {
+ if (!bdrv_is_inserted(s->qdev.conf.bs)) {
return false;
}
- bdrv_get_geometry(s->bs, &nb_sectors);
+ bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
return nb_sectors > CD_MAX_SECTORS;
}
@@ -593,10 +592,10 @@ static inline bool media_is_cd(SCSIDiskState *s)
if (s->qdev.type != TYPE_ROM) {
return false;
}
- if (!bdrv_is_inserted(s->bs)) {
+ if (!bdrv_is_inserted(s->qdev.conf.bs)) {
return false;
}
- bdrv_get_geometry(s->bs, &nb_sectors);
+ bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
return nb_sectors <= CD_MAX_SECTORS;
}
@@ -615,10 +614,10 @@ static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r,
uint8_t format = r->req.cmd.buf[7];
int size = -1;
- if (s->qdev.type != TYPE_ROM || !bdrv_is_inserted(s->bs)) {
+ if (s->qdev.type != TYPE_ROM || !bdrv_is_inserted(s->qdev.conf.bs)) {
return -1;
}
- if (s->tray_open || !bdrv_is_inserted(s->bs)) {
+ if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
return -1;
}
@@ -645,7 +644,7 @@ static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r,
uint64_t nb_sectors;
if (layer != 0)
goto fail;
- bdrv_get_geometry(s->bs, &nb_sectors);
+ bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
outbuf[4] = 1; /* DVD-ROM, part version 1 */
outbuf[5] = 0xf; /* 120mm disc, minimum rate unspecified */
@@ -700,7 +699,7 @@ static int scsi_event_status_media(SCSIDiskState *s, uint8_t *outbuf)
media_status = 0;
if (s->tray_open) {
media_status = MS_TRAY_OPEN;
- } else if (bdrv_is_inserted(s->bs)) {
+ } else if (bdrv_is_inserted(s->qdev.conf.bs)) {
media_status = MS_MEDIA_PRESENT;
}
@@ -803,7 +802,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
[MODE_PAGE_CAPABILITIES] = (1 << TYPE_ROM),
};
- BlockDriverState *bdrv = s->bs;
+ BlockDriverState *bdrv = s->qdev.conf.bs;
int cylinders, heads, secs;
uint8_t *p = *p_outbuf;
@@ -895,7 +894,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
if (page_control == 1) { /* Changeable Values */
break;
}
- if (bdrv_enable_write_cache(s->bs)) {
+ if (bdrv_enable_write_cache(s->qdev.conf.bs)) {
p[2] = 4; /* WCE */
}
break;
@@ -967,7 +966,7 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
memset(outbuf, 0, r->req.cmd.xfer);
p = outbuf;
- if (bdrv_is_read_only(s->bs)) {
+ if (bdrv_is_read_only(s->qdev.conf.bs)) {
dev_specific_param = 0x80; /* Readonly. */
} else {
dev_specific_param = 0x00;
@@ -985,7 +984,7 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
p += 8;
}
- bdrv_get_geometry(s->bs, &nb_sectors);
+ bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
if (!dbd && nb_sectors) {
if (r->req.cmd.buf[0] == MODE_SENSE) {
outbuf[3] = 8; /* Block descriptor length */
@@ -1049,7 +1048,7 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
msf = req->cmd.buf[1] & 2;
format = req->cmd.buf[2] & 0xf;
start_track = req->cmd.buf[6];
- bdrv_get_geometry(s->bs, &nb_sectors);
+ bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
nb_sectors /= s->cluster_size;
switch (format) {
@@ -1085,12 +1084,12 @@ static int scsi_disk_emulate_start_stop(SCSIDiskReq *r)
if (s->qdev.type == TYPE_ROM && loej) {
if (!start && !s->tray_open && s->tray_locked) {
scsi_check_condition(r,
- bdrv_is_inserted(s->bs)
+ bdrv_is_inserted(s->qdev.conf.bs)
? SENSE_CODE(ILLEGAL_REQ_REMOVAL_PREVENTED)
: SENSE_CODE(NOT_READY_REMOVAL_PREVENTED));
return -1;
}
- bdrv_eject(s->bs, !start);
+ bdrv_eject(s->qdev.conf.bs, !start);
s->tray_open = !start;
}
return 0;
@@ -1117,13 +1116,13 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
goto illegal_request;
}
r->buflen = MAX(4096, req->cmd.xfer);
- r->iov.iov_base = qemu_blockalign(s->bs, r->buflen);
+ r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen);
}
outbuf = r->iov.iov_base;
switch (req->cmd.buf[0]) {
case TEST_UNIT_READY:
- if (s->tray_open || !bdrv_is_inserted(s->bs))
+ if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs))
goto not_ready;
break;
case INQUIRY:
@@ -1165,12 +1164,12 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
break;
case ALLOW_MEDIUM_REMOVAL:
s->tray_locked = req->cmd.buf[4] & 1;
- bdrv_lock_medium(s->bs, req->cmd.buf[4] & 1);
+ bdrv_lock_medium(s->qdev.conf.bs, req->cmd.buf[4] & 1);
break;
case READ_CAPACITY_10:
/* The normal LEN field for this command is zero. */
memset(outbuf, 0, 8);
- bdrv_get_geometry(s->bs, &nb_sectors);
+ bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
if (!nb_sectors) {
goto not_ready;
}
@@ -1220,7 +1219,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
if ((req->cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
DPRINTF("SAI READ CAPACITY(16)\n");
memset(outbuf, 0, req->cmd.xfer);
- bdrv_get_geometry(s->bs, &nb_sectors);
+ bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
if (!nb_sectors) {
goto not_ready;
}
@@ -1267,7 +1266,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
return buflen;
not_ready:
- if (s->tray_open || !bdrv_is_inserted(s->bs)) {
+ if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
} else {
scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
@@ -1336,8 +1335,8 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
case SYNCHRONIZE_CACHE:
/* Save a ref for scsi_flush_complete, in case r is canceled. */
scsi_req_ref(&r->req);
- bdrv_acct_start(s->bs, &r->acct, 0, BDRV_ACCT_FLUSH);
- r->req.aiocb = bdrv_aio_flush(s->bs, scsi_flush_complete, r);
+ bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
+ r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_flush_complete, r);
if (r->req.aiocb == NULL) {
scsi_flush_complete(r, -EIO);
}
@@ -1410,7 +1409,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
goto fail;
}
- rc = bdrv_discard(s->bs, r->req.cmd.lba * s->cluster_size,
+ rc = bdrv_discard(s->qdev.conf.bs, r->req.cmd.lba * s->cluster_size,
len * s->cluster_size);
if (rc < 0) {
/* XXX: better error code ?*/
@@ -1451,7 +1450,7 @@ static void scsi_disk_reset(DeviceState *dev)
scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET));
- bdrv_get_geometry(s->bs, &nb_sectors);
+ bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
nb_sectors /= s->cluster_size;
if (nb_sectors) {
nb_sectors--;
@@ -1521,16 +1520,15 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
error_report("scsi-disk: drive property not set");
return -1;
}
- s->bs = s->qdev.conf.bs;
- if (scsi_type == TYPE_DISK && !bdrv_is_inserted(s->bs)) {
+ if (scsi_type == TYPE_DISK && !bdrv_is_inserted(s->qdev.conf.bs)) {
error_report("Device needs media, but drive is empty");
return -1;
}
if (!s->serial) {
/* try to fall back to value set with legacy -drive serial=... */
- dinfo = drive_get_by_blockdev(s->bs);
+ dinfo = drive_get_by_blockdev(s->qdev.conf.bs);
if (*dinfo->serial) {
s->serial = g_strdup(dinfo->serial);
}
@@ -1540,13 +1538,13 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
s->version = g_strdup(QEMU_VERSION);
}
- if (bdrv_is_sg(s->bs)) {
+ if (bdrv_is_sg(s->qdev.conf.bs)) {
error_report("scsi-disk: unwanted /dev/sg*");
return -1;
}
if (scsi_type == TYPE_ROM) {
- bdrv_set_dev_ops(s->bs, &scsi_cd_block_ops, s);
+ bdrv_set_dev_ops(s->qdev.conf.bs, &scsi_cd_block_ops, s);
s->qdev.blocksize = 2048;
} else if (scsi_type == TYPE_DISK) {
s->qdev.blocksize = s->qdev.conf.logical_block_size;
@@ -1555,11 +1553,11 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
return -1;
}
s->cluster_size = s->qdev.blocksize / 512;
- bdrv_set_buffer_alignment(s->bs, s->qdev.blocksize);
+ bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize);
s->qdev.type = scsi_type;
qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
- bdrv_iostatus_enable(s->bs);
+ bdrv_iostatus_enable(s->qdev.conf.bs);
add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
return 0;
}
--
1.7.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 06/10] scsi-disk: small clean up to INQUIRY
2011-10-12 14:24 [Qemu-devel] [PATCH 00/10] scsi: add specialized block device passthrough Paolo Bonzini
` (4 preceding siblings ...)
2011-10-12 14:24 ` [Qemu-devel] [PATCH 05/10] scsi-disk: do not duplicate BlockDriverState member Paolo Bonzini
@ 2011-10-12 14:24 ` Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 07/10] scsi: make reqops const Paolo Bonzini
` (3 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Paolo Bonzini @ 2011-10-12 14:24 UTC (permalink / raw)
To: qemu-devel
Set s->removable, s->qdev.blocksize and s->qdev.type in the callers
of scsi_initfn.
With this in place, s->qdev.type is allowed, and we can just reuse it
as the first byte in VPD data (just like we do in standard INQUIRY data).
Also set s->removable is set consistently and we can use it.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi-disk.c | 46 +++++++++++++++++++++-------------------------
1 files changed, 21 insertions(+), 25 deletions(-)
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 5e3ef51..a4daa29 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -397,11 +397,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
return -1;
}
- if (s->qdev.type == TYPE_ROM) {
- outbuf[buflen++] = 5;
- } else {
- outbuf[buflen++] = 0;
- }
+ outbuf[buflen++] = s->qdev.type & 0x1f;
outbuf[buflen++] = page_code ; // this page
outbuf[buflen++] = 0x00;
@@ -541,11 +537,10 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
memset(outbuf, 0, buflen);
outbuf[0] = s->qdev.type & 0x1f;
+ outbuf[1] = s->removable ? 0x80 : 0;
if (s->qdev.type == TYPE_ROM) {
- outbuf[1] = 0x80;
memcpy(&outbuf[16], "QEMU CD-ROM ", 16);
} else {
- outbuf[1] = s->removable ? 0x80 : 0;
memcpy(&outbuf[16], "QEMU HARDDISK ", 16);
}
memcpy(&outbuf[8], "QEMU ", 8);
@@ -1511,7 +1506,7 @@ static void scsi_disk_unit_attention_reported(SCSIDevice *dev)
}
}
-static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
+static int scsi_initfn(SCSIDevice *dev)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
DriveInfo *dinfo;
@@ -1521,7 +1516,7 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
return -1;
}
- if (scsi_type == TYPE_DISK && !bdrv_is_inserted(s->qdev.conf.bs)) {
+ if (!s->removable && !bdrv_is_inserted(s->qdev.conf.bs)) {
error_report("Device needs media, but drive is empty");
return -1;
}
@@ -1543,19 +1538,12 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
return -1;
}
- if (scsi_type == TYPE_ROM) {
+ if (s->removable) {
bdrv_set_dev_ops(s->qdev.conf.bs, &scsi_cd_block_ops, s);
- s->qdev.blocksize = 2048;
- } else if (scsi_type == TYPE_DISK) {
- s->qdev.blocksize = s->qdev.conf.logical_block_size;
- } else {
- error_report("scsi-disk: Unhandled SCSI type %02x", scsi_type);
- return -1;
}
s->cluster_size = s->qdev.blocksize / 512;
bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize);
- s->qdev.type = scsi_type;
qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
bdrv_iostatus_enable(s->qdev.conf.bs);
add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
@@ -1564,27 +1552,35 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
static int scsi_hd_initfn(SCSIDevice *dev)
{
- return scsi_initfn(dev, TYPE_DISK);
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+ s->qdev.blocksize = s->qdev.conf.logical_block_size;
+ s->qdev.type = TYPE_DISK;
+ return scsi_initfn(&s->qdev);
}
static int scsi_cd_initfn(SCSIDevice *dev)
{
- return scsi_initfn(dev, TYPE_ROM);
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+ s->qdev.blocksize = 2048;
+ s->qdev.type = TYPE_ROM;
+ s->removable = true;
+ return scsi_initfn(&s->qdev);
}
static int scsi_disk_initfn(SCSIDevice *dev)
{
DriveInfo *dinfo;
- uint8_t scsi_type;
if (!dev->conf.bs) {
- scsi_type = TYPE_DISK; /* will die in scsi_initfn() */
- } else {
- dinfo = drive_get_by_blockdev(dev->conf.bs);
- scsi_type = dinfo->media_cd ? TYPE_ROM : TYPE_DISK;
+ return scsi_initfn(dev); /* ... and die there */
}
- return scsi_initfn(dev, scsi_type);
+ dinfo = drive_get_by_blockdev(dev->conf.bs);
+ if (dinfo->media_cd) {
+ return scsi_cd_initfn(dev);
+ } else {
+ return scsi_hd_initfn(dev);
+ }
}
static SCSIReqOps scsi_disk_reqops = {
--
1.7.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 07/10] scsi: make reqops const
2011-10-12 14:24 [Qemu-devel] [PATCH 00/10] scsi: add specialized block device passthrough Paolo Bonzini
` (5 preceding siblings ...)
2011-10-12 14:24 ` [Qemu-devel] [PATCH 06/10] scsi-disk: small clean up to INQUIRY Paolo Bonzini
@ 2011-10-12 14:24 ` Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 08/10] scsi: export scsi_generic_reqops Paolo Bonzini
` (2 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Paolo Bonzini @ 2011-10-12 14:24 UTC (permalink / raw)
To: qemu-devel
Also delete a stale occurrence of SCSIReqOps inside SCSIDeviceInfo.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi-bus.c | 10 +++++-----
hw/scsi-disk.c | 2 +-
hw/scsi-generic.c | 2 +-
hw/scsi.h | 7 +++----
4 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index bdd6e94..252e903 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -160,7 +160,7 @@ static int32_t scsi_invalid_command(SCSIRequest *req, uint8_t *buf)
return 0;
}
-struct SCSIReqOps reqops_invalid_opcode = {
+const struct SCSIReqOps reqops_invalid_opcode = {
.size = sizeof(SCSIRequest),
.send_command = scsi_invalid_command
};
@@ -178,7 +178,7 @@ static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf)
return 0;
}
-struct SCSIReqOps reqops_unit_attention = {
+const struct SCSIReqOps reqops_unit_attention = {
.size = sizeof(SCSIRequest),
.send_command = scsi_unit_attention
};
@@ -386,7 +386,7 @@ static uint8_t *scsi_target_get_buf(SCSIRequest *req)
return r->buf;
}
-struct SCSIReqOps reqops_target_command = {
+const struct SCSIReqOps reqops_target_command = {
.size = sizeof(SCSITargetReq),
.send_command = scsi_target_send_command,
.read_data = scsi_target_read_data,
@@ -394,8 +394,8 @@ struct SCSIReqOps reqops_target_command = {
};
-SCSIRequest *scsi_req_alloc(SCSIReqOps *reqops, SCSIDevice *d, uint32_t tag,
- uint32_t lun, void *hba_private)
+SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
+ uint32_t tag, uint32_t lun, void *hba_private)
{
SCSIRequest *req;
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index a4daa29..6c1d5a2 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1583,7 +1583,7 @@ static int scsi_disk_initfn(SCSIDevice *dev)
}
}
-static SCSIReqOps scsi_disk_reqops = {
+static const SCSIReqOps scsi_disk_reqops = {
.size = sizeof(SCSIDiskReq),
.free_req = scsi_free_request,
.send_command = scsi_send_command,
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 7b291ec..9c9f64a 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -432,7 +432,7 @@ static int scsi_generic_initfn(SCSIDevice *s)
return 0;
}
-static SCSIReqOps scsi_generic_req_ops = {
+static const SCSIReqOps scsi_generic_req_ops = {
.size = sizeof(SCSIGenericReq),
.free_req = scsi_free_request,
.send_command = scsi_send_command,
diff --git a/hw/scsi.h b/hw/scsi.h
index c8649cf..832682e 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -41,7 +41,7 @@ struct SCSICommand {
struct SCSIRequest {
SCSIBus *bus;
SCSIDevice *dev;
- SCSIReqOps *ops;
+ const SCSIReqOps *ops;
uint32_t refcount;
uint32_t tag;
uint32_t lun;
@@ -95,7 +95,6 @@ struct SCSIDeviceInfo {
SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
void *hba_private);
void (*unit_attention_reported)(SCSIDevice *s);
- SCSIReqOps reqops;
};
struct SCSIBusInfo {
@@ -175,8 +174,8 @@ extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
int scsi_sense_valid(SCSISense sense);
-SCSIRequest *scsi_req_alloc(SCSIReqOps *reqops, SCSIDevice *d, uint32_t tag,
- uint32_t lun, void *hba_private);
+SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
+ uint32_t tag, uint32_t lun, void *hba_private);
SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
uint8_t *buf, void *hba_private);
int32_t scsi_req_enqueue(SCSIRequest *req);
--
1.7.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 08/10] scsi: export scsi_generic_reqops
2011-10-12 14:24 [Qemu-devel] [PATCH 00/10] scsi: add specialized block device passthrough Paolo Bonzini
` (6 preceding siblings ...)
2011-10-12 14:24 ` [Qemu-devel] [PATCH 07/10] scsi: make reqops const Paolo Bonzini
@ 2011-10-12 14:24 ` Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 09/10] scsi: pass cdb to alloc_req Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 10/10] scsi-disk: add scsi-block for device passthrough Paolo Bonzini
9 siblings, 0 replies; 11+ messages in thread
From: Paolo Bonzini @ 2011-10-12 14:24 UTC (permalink / raw)
To: qemu-devel
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi-generic.c | 2 +-
hw/scsi.h | 3 +++
2 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 9c9f64a..eb066ba 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -432,7 +432,7 @@ static int scsi_generic_initfn(SCSIDevice *s)
return 0;
}
-static const SCSIReqOps scsi_generic_req_ops = {
+const SCSIReqOps scsi_generic_req_ops = {
.size = sizeof(SCSIGenericReq),
.free_req = scsi_free_request,
.send_command = scsi_send_command,
diff --git a/hw/scsi.h b/hw/scsi.h
index 832682e..c2eeee3 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -196,4 +196,7 @@ void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun);
+/* scsi-generic.c. */
+extern const SCSIReqOps scsi_generic_req_ops;
+
#endif
--
1.7.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 09/10] scsi: pass cdb to alloc_req
2011-10-12 14:24 [Qemu-devel] [PATCH 00/10] scsi: add specialized block device passthrough Paolo Bonzini
` (7 preceding siblings ...)
2011-10-12 14:24 ` [Qemu-devel] [PATCH 08/10] scsi: export scsi_generic_reqops Paolo Bonzini
@ 2011-10-12 14:24 ` Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 10/10] scsi-disk: add scsi-block for device passthrough Paolo Bonzini
9 siblings, 0 replies; 11+ messages in thread
From: Paolo Bonzini @ 2011-10-12 14:24 UTC (permalink / raw)
To: qemu-devel
This will let scsi-block choose between passthrough and emulation.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi-bus.c | 2 +-
hw/scsi-disk.c | 4 ++--
hw/scsi-generic.c | 2 +-
hw/scsi.h | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 252e903..72c0dd2 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -451,7 +451,7 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
req = scsi_req_alloc(&reqops_target_command, d, tag, lun,
hba_private);
} else {
- req = d->info->alloc_req(d, tag, lun, hba_private);
+ req = d->info->alloc_req(d, tag, lun, buf, hba_private);
}
}
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 6c1d5a2..835cc7f 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1593,8 +1593,8 @@ static const SCSIReqOps scsi_disk_reqops = {
.get_buf = scsi_get_buf,
};
-static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag,
- uint32_t lun, void *hba_private)
+static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
+ uint8_t *buf, void *hba_private)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
SCSIRequest *req;
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index eb066ba..9091e13 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -443,7 +443,7 @@ const SCSIReqOps scsi_generic_req_ops = {
};
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
- void *hba_private)
+ uint8_t *buf, void *hba_private)
{
SCSIRequest *req;
diff --git a/hw/scsi.h b/hw/scsi.h
index c2eeee3..aa816e6 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -93,7 +93,7 @@ struct SCSIDeviceInfo {
scsi_qdev_initfn init;
void (*destroy)(SCSIDevice *s);
SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
- void *hba_private);
+ uint8_t *buf, void *hba_private);
void (*unit_attention_reported)(SCSIDevice *s);
};
--
1.7.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 10/10] scsi-disk: add scsi-block for device passthrough
2011-10-12 14:24 [Qemu-devel] [PATCH 00/10] scsi: add specialized block device passthrough Paolo Bonzini
` (8 preceding siblings ...)
2011-10-12 14:24 ` [Qemu-devel] [PATCH 09/10] scsi: pass cdb to alloc_req Paolo Bonzini
@ 2011-10-12 14:24 ` Paolo Bonzini
9 siblings, 0 replies; 11+ messages in thread
From: Paolo Bonzini @ 2011-10-12 14:24 UTC (permalink / raw)
To: qemu-devel
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi-disk.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 116 insertions(+), 0 deletions(-)
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 835cc7f..c97ef52 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -39,6 +39,10 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
#include "blockdev.h"
#include "block_int.h"
+#ifdef __linux
+#include <scsi/sg.h>
+#endif
+
#define SCSI_DMA_BUF_SIZE 131072
#define SCSI_MAX_INQUIRY_LEN 256
@@ -1603,6 +1607,103 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
return req;
}
+#ifdef __linux__
+static int get_device_type(SCSIDiskState *s)
+{
+ BlockDriverState *bdrv = s->qdev.conf.bs;
+ uint8_t cmd[16];
+ uint8_t buf[36];
+ uint8_t sensebuf[8];
+ sg_io_hdr_t io_header;
+ int ret;
+
+ memset(cmd, 0, sizeof(cmd));
+ memset(buf, 0, sizeof(buf));
+ cmd[0] = INQUIRY;
+ cmd[4] = sizeof(buf);
+
+ memset(&io_header, 0, sizeof(io_header));
+ io_header.interface_id = 'S';
+ io_header.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_header.dxfer_len = sizeof(buf);
+ io_header.dxferp = buf;
+ io_header.cmdp = cmd;
+ io_header.cmd_len = sizeof(cmd);
+ io_header.mx_sb_len = sizeof(sensebuf);
+ io_header.sbp = sensebuf;
+ io_header.timeout = 6000; /* XXX */
+
+ ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
+ if (ret < 0 || io_header.driver_status || io_header.host_status) {
+ return -1;
+ }
+ s->qdev.blocksize = s->qdev.conf.logical_block_size;
+ s->qdev.type = buf[0];
+ s->removable = (buf[1] & 0x80) != 0;
+ return 0;
+}
+
+static int scsi_block_initfn(SCSIDevice *dev)
+{
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+ int sg_version;
+ int rc;
+
+ if (!s->qdev.conf.bs) {
+ error_report("scsi-block: drive property not set");
+ return -1;
+ }
+
+ /* check we are using a driver managing SG_IO (version 3 and after) */
+ if (bdrv_ioctl(s->qdev.conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
+ sg_version < 30000) {
+ error_report("scsi-block: scsi generic interface too old");
+ return -1;
+ }
+
+ /* get device type from INQUIRY data */
+ rc = get_device_type(s);
+ if (rc < 0) {
+ error_report("scsi-block: INQUIRY failed");
+ return -1;
+ }
+
+ return scsi_initfn(&s->qdev);
+}
+
+static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
+ uint32_t lun, uint8_t *buf,
+ void *hba_private)
+{
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
+
+ switch (buf[0]) {
+ case SERVICE_ACTION_IN_16:
+ if ((buf[1] & 31) != SAI_READ_CAPACITY_16) {
+ break;
+ }
+
+ case READ_6:
+ case READ_10:
+ case READ_12:
+ case READ_16:
+ case READ_CAPACITY_10:
+ case WRITE_6:
+ case WRITE_10:
+ case WRITE_12:
+ case WRITE_16:
+ case WRITE_VERIFY_10:
+ case WRITE_VERIFY_12:
+ case WRITE_VERIFY_16:
+ return scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun,
+ hba_private);
+ }
+
+ return scsi_req_alloc(&scsi_generic_req_ops, &s->qdev, tag, lun,
+ hba_private);
+}
+#endif
+
#define DEFINE_SCSI_DISK_PROPERTIES() \
DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf), \
DEFINE_PROP_STRING("ver", SCSIDiskState, version), \
@@ -1638,6 +1739,21 @@ static SCSIDeviceInfo scsi_disk_info[] = {
DEFINE_SCSI_DISK_PROPERTIES(),
DEFINE_PROP_END_OF_LIST(),
},
+#ifdef __linux__
+ },{
+ .qdev.name = "scsi-block",
+ .qdev.fw_name = "disk",
+ .qdev.desc = "SCSI block device passthrough",
+ .qdev.size = sizeof(SCSIDiskState),
+ .qdev.reset = scsi_disk_reset,
+ .init = scsi_block_initfn,
+ .destroy = scsi_destroy,
+ .alloc_req = scsi_block_new_request,
+ .qdev.props = (Property[]) {
+ DEFINE_SCSI_DISK_PROPERTIES(),
+ DEFINE_PROP_END_OF_LIST(),
+ },
+#endif
},{
.qdev.name = "scsi-disk", /* legacy -device scsi-disk */
.qdev.fw_name = "disk",
--
1.7.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
end of thread, other threads:[~2011-10-12 14:24 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-10-12 14:24 [Qemu-devel] [PATCH 00/10] scsi: add specialized block device passthrough Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 01/10] scsi-generic: drop SCSIGenericState Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 02/10] scsi-generic: remove scsi_req_fixup Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 03/10] scsi-generic: check ioctl statuses when SG_IO succeeds Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 04/10] scsi-generic: look at host status Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 05/10] scsi-disk: do not duplicate BlockDriverState member Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 06/10] scsi-disk: small clean up to INQUIRY Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 07/10] scsi: make reqops const Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 08/10] scsi: export scsi_generic_reqops Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 09/10] scsi: pass cdb to alloc_req Paolo Bonzini
2011-10-12 14:24 ` [Qemu-devel] [PATCH 10/10] scsi-disk: add scsi-block for device passthrough Paolo Bonzini
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).