From: Laurent Vivier <Laurent.Vivier@bull.net>
Cc: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH 2/3] SG support (Asynchronous Read/Write)
Date: Wed, 28 Nov 2007 14:23:40 +0100 [thread overview]
Message-ID: <11962562201796@bull.net> (raw)
In-Reply-To: <11962562172906@bull.net>
This patch modifies scsi_read_data() and scsi_write_data()
to use asynchronous I/O whith SCSI Generic.
block-raw.s has been modified to define the number of bytes to
transfer instead of the number of blocks: if nb_sectors is less than zero
the nb_sectors is a number of bytes.
---
block-raw.c | 5 +
hw/lsi53c895a.c | 2
hw/scsi-generic.c | 198 ++++++++++++++++++++++++++++++++++--------------------
3 files changed, 133 insertions(+), 72 deletions(-)
Index: qemu/block-raw.c
===================================================================
--- qemu.orig/block-raw.c 2007-11-28 13:12:02.000000000 +0100
+++ qemu/block-raw.c 2007-11-28 13:12:22.000000000 +0100
@@ -385,7 +385,10 @@ static RawAIOCB *raw_aio_setup(BlockDriv
acb->aiocb.aio_sigevent.sigev_signo = aio_sig_num;
acb->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
acb->aiocb.aio_buf = buf;
- acb->aiocb.aio_nbytes = nb_sectors * 512;
+ if (nb_sectors < 0)
+ acb->aiocb.aio_nbytes = -nb_sectors;
+ else
+ acb->aiocb.aio_nbytes = nb_sectors * 512;
acb->aiocb.aio_offset = sector_num * 512;
acb->next = first_aio;
first_aio = acb;
Index: qemu/hw/scsi-generic.c
===================================================================
--- qemu.orig/hw/scsi-generic.c 2007-11-28 13:12:12.000000000 +0100
+++ qemu/hw/scsi-generic.c 2007-11-28 13:13:13.000000000 +0100
@@ -53,6 +53,7 @@ do { fprintf(stderr, "scsi-generic: " fm
#define SG_ERR_DRIVER_SENSE 0x08
typedef struct SCSIRequest {
+ BlockDriverAIOCB *aiocb;
struct SCSIRequest *next;
SCSIDeviceState *dev;
uint32_t tag;
@@ -61,8 +62,8 @@ typedef struct SCSIRequest {
uint8_t *buf;
int buflen;
int len;
- int driver_status;
uint8_t sensebuf[SCSI_SENSE_BUF_SIZE];
+ sg_io_hdr_t io_header;
} SCSIRequest;
struct SCSIDeviceState
@@ -94,13 +95,16 @@ static SCSIRequest *scsi_new_request(SCS
r->tag = tag;
memset(r->cmd, 0, sizeof(r->cmd));
memset(r->sensebuf, 0, sizeof(r->sensebuf));
+ memset(&r->io_header, 0, sizeof(r->io_header));
r->cmdlen = 0;
r->len = 0;
+ r->aiocb = NULL;
/* link */
r->next = s->requests;
s->requests = r;
+ DPRINTF("scsi_new_request tag=0x%x\n", tag);
return r;
}
@@ -109,6 +113,7 @@ static void scsi_remove_request(SCSIRequ
SCSIRequest *last;
SCSIDeviceState *s = r->dev;
+ DPRINTF("scsi_remove_request tag=0x%x\n", r->tag);
if (s->requests == r) {
s->requests = r->next;
} else {
@@ -138,16 +143,24 @@ static SCSIRequest *scsi_find_request(SC
static int scsi_get_sense(SCSIRequest *r)
{
- if ((r->driver_status & SG_ERR_DRIVER_SENSE) == 0)
+ if ((r->io_header.driver_status & SG_ERR_DRIVER_SENSE) == 0)
return NO_SENSE;
return r->sensebuf[2] & 0x0f;
}
/* Helper function for command completion. */
-static void scsi_command_complete(SCSIRequest *r, int sense)
+static void scsi_command_complete(void *opaque, int ret)
{
+ SCSIRequest *r = (SCSIRequest *)opaque;
SCSIDeviceState *s = r->dev;
uint32_t tag;
+ int sense;
+
+ if (ret != 0)
+ sense = HARDWARE_ERROR;
+ else
+ sense = scsi_get_sense(r);
+
DPRINTF("Command complete 0x%p tag=0x%x sense=%d\n", r, r->tag, sense);
tag = r->tag;
scsi_remove_request(r);
@@ -163,46 +176,70 @@ static void scsi_cancel_io(SCSIDevice *d
DPRINTF("Cancel tag=0x%x\n", tag);
r = scsi_find_request(s, tag);
if (r) {
+ if (r->aiocb)
+ bdrv_aio_cancel(r->aiocb);
+ r->aiocb = NULL;
scsi_remove_request(r);
}
}
-static int execute_command(BlockDriverState *bdrv, uint8_t *cmdbuf, int cmdlen,
- uint8_t *outbuf, uint32_t outlen,
- uint8_t *sensebuf, int senselen,
- int direction, int *len)
-{
- sg_io_hdr_t io_header;
- int ret;
-
- memset(&io_header, 0, sizeof(io_header));
- io_header.interface_id = 'S';
- io_header.dxfer_direction = direction;
- io_header.dxfer_len = outlen;
- io_header.dxferp = outbuf;
- io_header.cmdp = cmdbuf;
- io_header.cmd_len = cmdlen;
- io_header.mx_sb_len = senselen;
- io_header.sbp = sensebuf;
- io_header.timeout = 6000; /* XXX */
+static int execute_command(BlockDriverState *bdrv,
+ SCSIRequest *r, int direction,
+ BlockDriverCompletionFunc *complete)
+{
+ r->io_header.interface_id = 'S';
+ r->io_header.dxfer_direction = direction;
+ r->io_header.dxfer_len = r->buflen;
+ r->io_header.dxferp = r->buf;
+ r->io_header.cmdp = r->cmd;
+ r->io_header.cmd_len = r->cmdlen;
+ r->io_header.mx_sb_len = sizeof(r->sensebuf);
+ r->io_header.sbp = r->sensebuf;
+ r->io_header.timeout = 6000; /* XXX */
- ret = bdrv_pwrite(bdrv, -1, &io_header, sizeof(io_header));
- if (ret == -1) {
+ if (bdrv_pwrite(bdrv, -1, &r->io_header, sizeof(r->io_header)) == -1) {
BADF("execute_command: write failed ! (%d)\n", errno);
return -1;
}
- while ((ret = bdrv_pread(bdrv, -1, &io_header, sizeof(io_header))) == -1 &&
- errno == EINTR);
+ if (complete == NULL) {
+ int ret;
+ r->aiocb = NULL;
+ while ((ret = bdrv_pread(bdrv, -1, &r->io_header,
+ sizeof(r->io_header))) == -1 &&
+ errno == EINTR);
+ if (ret == -1) {
+ BADF("execute_command: read failed !\n");
+ return -1;
+ }
+ return 0;
+ }
- if (ret == -1) {
+ r->aiocb = bdrv_aio_read(bdrv, 0, (uint8_t*)&r->io_header,
+ -(int64_t)sizeof(r->io_header), complete, r);
+ if (r->aiocb == NULL) {
BADF("execute_command: read failed !\n");
return -1;
}
- if (len != NULL)
- *len = io_header.dxfer_len - io_header.resid;
+ return 0;
+}
+
+static void scsi_read_complete(void * opaque, int ret)
+{
+ SCSIRequest *r = (SCSIRequest *)opaque;
+ SCSIDeviceState *s = r->dev;
+ int len;
- return io_header.driver_status;
+ if (ret) {
+ DPRINTF("IO error\n");
+ scsi_command_complete(r, ret);
+ return;
+ }
+ len = r->io_header.dxfer_len - r->io_header.resid;
+ DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, len);
+
+ r->len = -1;
+ s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len);
}
/* Read more data from scsi device into buffer. */
@@ -210,25 +247,40 @@ static void scsi_read_data(SCSIDevice *d
{
SCSIDeviceState *s = d->state;
SCSIRequest *r;
- int len;
+ int ret;
DPRINTF("scsi_read_data 0x%x\n", tag);
r = scsi_find_request(s, tag);
if (!r) {
BADF("Bad read tag 0x%x\n", tag);
/* ??? This is the wrong error. */
- scsi_command_complete(r, HARDWARE_ERROR);
+ scsi_command_complete(r, -EINVAL);
return;
}
if (r->len == -1) {
- scsi_command_complete(r, scsi_get_sense(r));
+ scsi_command_complete(r, 0);
return;
}
- len = r->len;
- r->len = -1;
- s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len);
+ ret = execute_command(s->bdrv, r, SG_DXFER_FROM_DEV, scsi_read_complete);
+ if (ret == -1) {
+ scsi_command_complete(r, -EINVAL);
+ return;
+ }
+}
+
+static void scsi_write_complete(void * opaque, int ret)
+{
+ SCSIRequest *r = (SCSIRequest *)opaque;
+
+ if (ret) {
+ DPRINTF("IO error\n");
+ scsi_command_complete(r, ret);
+ return;
+ }
+
+ scsi_command_complete(r, ret);
}
/* Write data to a scsi device. Returns nonzero on failure.
@@ -244,7 +296,7 @@ static int scsi_write_data(SCSIDevice *d
if (!r) {
BADF("Bad write tag 0x%x\n", tag);
/* ??? This is the wrong error. */
- scsi_command_complete(r, HARDWARE_ERROR);
+ scsi_command_complete(r, -EINVAL);
return 0;
}
@@ -254,15 +306,11 @@ static int scsi_write_data(SCSIDevice *d
return 0;
}
- ret = execute_command(s->bdrv, r->cmd, r->cmdlen, r->buf, r->len,
- r->sensebuf, sizeof(r->sensebuf),
- SG_DXFER_TO_DEV, NULL);
+ ret = execute_command(s->bdrv, r, SG_DXFER_TO_DEV, scsi_write_complete);
if (ret == -1) {
- scsi_command_complete(r, HARDWARE_ERROR);
+ scsi_command_complete(r, -EINVAL);
return 1;
}
- r->driver_status = ret;
- scsi_command_complete(r, scsi_get_sense(r));
return 0;
}
@@ -416,19 +464,12 @@ static int32_t scsi_send_command(SCSIDev
SCSIRequest *r;
int ret;
- r = scsi_find_request(s, tag);
- if (r) {
- BADF("Tag 0x%x already in use %p\n", tag, r);
- scsi_cancel_io(d, tag);
- }
- r = scsi_new_request(s, tag);
-
/* ??? Tags are not unique for different luns. We only implement a
single lun, so this should not matter. */
if (lun != s->lun || (cmd[1] >> 5) != s->lun) {
DPRINTF("Unimplemented LUN %d\n", lun ? lun : cmd[1] >> 5);
- scsi_command_complete(r, ILLEGAL_REQUEST);
+ s->completion(s->opaque, SCSI_REASON_DONE, tag, HARDWARE_ERROR);
return 0;
}
@@ -438,21 +479,28 @@ static int32_t scsi_send_command(SCSIDev
}
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x len %d\n", lun, tag,
- command, len);
+ cmd[0], len);
+
+ r = scsi_find_request(s, tag);
+ if (r) {
+ BADF("Tag 0x%x already in use %p\n", tag, r);
+ scsi_cancel_io(d, tag);
+ }
+ r = scsi_new_request(s, tag);
memcpy(r->cmd, cmd, cmdlen);
r->cmdlen = cmdlen;
if (len == 0) {
- ret = execute_command(s->bdrv, r->cmd, r->cmdlen, NULL, 0,
- r->sensebuf, sizeof(r->sensebuf),
- SG_DXFER_NONE, NULL);
+ if (r->buf != NULL)
+ free(r->buf);
+ r->buflen = 0;
+ r->buf = NULL;
+ ret = execute_command(s->bdrv, r, SG_DXFER_NONE, NULL);
if (ret == -1) {
- scsi_command_complete(r, HARDWARE_ERROR);
+ scsi_command_complete(r, -EINVAL);
return 0;
}
- r->driver_status = ret;
-
scsi_command_complete(r, scsi_get_sense(r));
return 0;
}
@@ -471,16 +519,6 @@ static int32_t scsi_send_command(SCSIDev
return -len;
}
- ret = execute_command(s->bdrv, r->cmd, r->cmdlen, r->buf, r->len,
- r->sensebuf, sizeof(r->sensebuf),
- SG_DXFER_FROM_DEV, &len);
- if (ret == -1) {
- scsi_command_complete(r, HARDWARE_ERROR);
- return 0;
- }
- r->len = len;
- r->driver_status = ret;
-
return len;
}
@@ -489,16 +527,34 @@ static int get_blocksize(BlockDriverStat
uint8_t cmd[10];
uint8_t buf[8];
uint8_t sensebuf[8];
+ sg_io_hdr_t io_header;
int ret;
memset(cmd, sizeof(cmd), 0);
memset(buf, sizeof(buf), 0);
cmd[0] = READ_CAPACITY;
- ret = execute_command(bdrv, cmd, sizeof(cmd), buf, sizeof(buf),
- sensebuf, sizeof(sensebuf),
- SG_DXFER_FROM_DEV, NULL);
- if (ret < 0)
+
+ 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_pwrite(bdrv, -1, &io_header, sizeof(io_header));
+ if (ret == -1)
+ return -1;
+
+ while ((ret = bdrv_pread(bdrv, -1, &io_header, sizeof(io_header))) == -1 &&
+ errno == EINTR);
+
+ if (ret == -1)
return -1;
+
return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
}
Index: qemu/hw/lsi53c895a.c
===================================================================
--- qemu.orig/hw/lsi53c895a.c 2007-11-28 13:12:02.000000000 +0100
+++ qemu/hw/lsi53c895a.c 2007-11-28 13:12:22.000000000 +0100
@@ -1225,6 +1225,8 @@ static uint8_t lsi_reg_readb(LSIState *s
return s->sdid;
case 0x07: /* GPREG0 */
return 0x7f;
+ case 0x08: /* Revision ID */
+ return 0x00;
case 0xa: /* SSID */
return s->ssid;
case 0xb: /* SBCL */
next prev parent reply other threads:[~2007-11-28 13:22 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-11-28 13:23 [Qemu-devel] [PATCH 0/3] Real SCSI device passthrough Laurent Vivier
2007-11-28 13:23 ` [Qemu-devel] [PATCH 1/3] SG support (Synchronous I/O) Laurent Vivier
2007-11-28 13:23 ` Laurent Vivier [this message]
2007-11-28 13:23 ` [Qemu-devel] [PATCH 3/3] SG support (Asynchronous Send Command) Laurent Vivier
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=11962562201796@bull.net \
--to=laurent.vivier@bull.net \
--cc=qemu-devel@nongnu.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.