[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 2/3] SG support (Asynchronous Read/Write)
From: |
Laurent Vivier |
Subject: |
[Qemu-devel] [PATCH 2/3] SG support (Asynchronous Read/Write) |
Date: |
Wed, 28 Nov 2007 14:23:40 +0100 |
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 */