[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 08/15] scsi-disk: Allocate iovec dynamically
From: |
Hannes Reinecke |
Subject: |
[Qemu-devel] [PATCH 08/15] scsi-disk: Allocate iovec dynamically |
Date: |
Wed, 24 Nov 2010 12:16:03 +0100 |
Rather than have the iovec part of the structure with a fixed size
of '1' we should be allocating it dynamically. This will allow us
to pass in SGLs directly.
Signed-off-by: Hannes Reinecke <address@hidden>
---
hw/scsi-disk.c | 102 +++++++++++++++++++++++++++++++++-----------------------
1 files changed, 60 insertions(+), 42 deletions(-)
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index a71607e..deec825 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -37,6 +37,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); }
while (0)
#include "scsi-defs.h"
#include "sysemu.h"
#include "blockdev.h"
+#include "iov.h"
#define SCSI_DMA_BUF_SIZE 131072
#define SCSI_MAX_INQUIRY_LEN 256
@@ -56,7 +57,10 @@ typedef struct SCSIDiskReq {
/* Both sector and sector_count are in terms of qemu 512 byte blocks. */
uint64_t sector;
uint32_t sector_count;
- struct iovec iov;
+ uint8_t *iov_buf;
+ uint64_t iov_len;
+ struct iovec *iov;
+ int iov_num;
QEMUIOVector qiov;
uint32_t status;
} SCSIDiskReq;
@@ -86,13 +90,19 @@ static SCSIDiskReq *scsi_new_request(SCSIDiskState *s,
uint32_t tag,
req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun);
r = DO_UPCAST(SCSIDiskReq, req, req);
- r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE);
+ r->iov_buf = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE);
+ r->iov = qemu_mallocz(sizeof(struct iovec));
+ r->iov[0].iov_base = r->iov_buf;
+ r->iov_num = 1;
return r;
}
static void scsi_remove_request(SCSIDiskReq *r)
{
- qemu_vfree(r->iov.iov_base);
+ qemu_free(r->iov);
+ r->iov = NULL;
+ qemu_vfree(r->iov_buf);
+ r->iov_buf = NULL;
scsi_req_free(&r->req);
}
@@ -117,7 +127,7 @@ static void scsi_req_set_status(SCSIDiskReq *r, int status,
SCSISense sense)
/* Helper function for command completion. */
static void scsi_command_complete(SCSIDiskReq *r, int status, SCSISense sense)
{
- DPRINTF("Command complete tag=0x%x status=%d sense=%d/%d/%d\n",
+ DPRINTF("Command complete tag=0x%x status=%d sense=%02x/%02x/%02x\n",
r->req.tag, status, sense.key, sense.asc, sense.ascq);
scsi_req_set_status(r, status, sense);
scsi_req_complete(&r->req);
@@ -142,7 +152,7 @@ static void scsi_cancel_io(SCSIDevice *d, uint32_t tag)
static void scsi_read_complete(void * opaque, int ret)
{
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
- int n;
+ size_t iov_len = 0;
r->req.aiocb = NULL;
@@ -151,13 +161,11 @@ static void scsi_read_complete(void * opaque, int ret)
return;
}
}
+ iov_len = iov_size(r->iov, r->iov_num);
- DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->iov.iov_len);
+ DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, iov_len);
- n = r->iov.iov_len / 512;
- r->sector += n;
- r->sector_count -= n;
- r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag,
r->iov.iov_len);
+ r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, iov_len);
}
@@ -167,9 +175,10 @@ static void scsi_read_request(SCSIDiskReq *r)
uint32_t n;
if (r->sector_count == (uint32_t)-1) {
- DPRINTF("Read buf_len=%zd\n", r->iov.iov_len);
+ DPRINTF("Read buf_len=%zd\n", r->iov[0].iov_len);
r->sector_count = 0;
- r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag,
r->iov.iov_len);
+ r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag,
+ r->iov[0].iov_len);
return;
}
DPRINTF("Read sector_count=%d\n", r->sector_count);
@@ -179,15 +188,21 @@ static void scsi_read_request(SCSIDiskReq *r)
}
n = r->sector_count;
- if (n > SCSI_DMA_BUF_SIZE / 512)
- n = SCSI_DMA_BUF_SIZE / 512;
+ if (r->iov_buf) {
+ /* Reset iovec */
+ if (n > SCSI_DMA_BUF_SIZE / 512)
+ n = SCSI_DMA_BUF_SIZE / 512;
+ r->iov[0].iov_len = n * 512;
+ }
- r->iov.iov_len = n * 512;
- qemu_iovec_init_external(&r->qiov, &r->iov, 1);
+ qemu_iovec_init_external(&r->qiov, r->iov, r->iov_num);
r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n,
scsi_read_complete, r);
if (r->req.aiocb == NULL) {
scsi_read_complete(r, -EIO);
+ } else {
+ r->sector += n;
+ r->sector_count -= n;
}
}
@@ -264,17 +279,20 @@ static void scsi_write_complete(void * opaque, int ret)
}
}
- n = r->iov.iov_len / 512;
+ n = iov_size(r->iov, r->iov_num) / 512;
r->sector += n;
r->sector_count -= n;
if (r->sector_count == 0) {
scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
} else {
len = r->sector_count * 512;
- if (len > SCSI_DMA_BUF_SIZE) {
- len = SCSI_DMA_BUF_SIZE;
+ if (r->iov_buf) {
+ /* Reset iovec */
+ if (len > SCSI_DMA_BUF_SIZE) {
+ len = SCSI_DMA_BUF_SIZE;
+ }
+ r->iov[0].iov_len = len;
}
- r->iov.iov_len = len;
DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, len);
r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, len);
}
@@ -285,9 +303,9 @@ static void scsi_write_request(SCSIDiskReq *r)
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint32_t n;
- n = r->iov.iov_len / 512;
+ n = iov_size(r->iov, r->iov_num) / 512;
if (n) {
- qemu_iovec_init_external(&r->qiov, &r->iov, 1);
+ qemu_iovec_init_external(&r->qiov, r->iov, r->iov_num);
r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n,
scsi_write_complete, r);
if (r->req.aiocb == NULL) {
@@ -352,7 +370,7 @@ static void scsi_dma_restart_bh(void *opaque)
scsi_write_request(r);
break;
case SCSI_REQ_STATUS_RETRY_FLUSH:
- ret = scsi_disk_emulate_command(r, r->iov.iov_base);
+ ret = scsi_disk_emulate_command(r, r->iov[0].iov_base);
if (ret == 0) {
scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
}
@@ -385,7 +403,7 @@ static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
BADF("Bad buffer tag 0x%x\n", tag);
return NULL;
}
- return (uint8_t *)r->iov.iov_base;
+ return r->iov_buf;
}
static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
@@ -1001,12 +1019,10 @@ static int32_t scsi_send_command(SCSIDevice *d,
uint32_t tag,
uint8_t *buf, int lun)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
- uint32_t len;
+ ssize_t len = 0;
int is_write;
uint8_t command;
- uint8_t *outbuf;
SCSIDiskReq *r;
- int rc;
command = buf[0];
r = scsi_find_request(s, tag);
@@ -1017,7 +1033,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t
tag,
/* ??? Tags are not unique for different luns. We only implement a
single lun, so this should not matter. */
r = scsi_new_request(s, tag, lun);
- outbuf = (uint8_t *)r->iov.iov_base;
is_write = 0;
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
@@ -1065,23 +1080,25 @@ static int32_t scsi_send_command(SCSIDevice *d,
uint32_t tag,
case REPORT_LUNS:
case VERIFY:
case REZERO_UNIT:
- rc = scsi_disk_emulate_command(r, outbuf);
- if (rc < 0) {
+ len = scsi_disk_emulate_command(r, r->iov[0].iov_base);
+ if (len < 0) {
return 0;
}
- r->iov.iov_len = rc;
+ r->iov[0].iov_len = len;
break;
case READ_6:
case READ_10:
case READ_12:
case READ_16:
- len = r->req.cmd.xfer / d->blocksize;
- DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len);
- if (r->req.cmd.lba > s->max_lba)
+ r->sector_count = r->req.cmd.xfer / d->blocksize * s->cluster_size;
+ DPRINTF("Read (sector %" PRId64 ", blocks %d)\n", r->req.cmd.lba,
+ r->sector_count);
+ if (r->req.cmd.lba > s->max_lba) {
+ r->sector_count = 0;
goto illegal_lba;
+ }
r->sector = r->req.cmd.lba * s->cluster_size;
- r->sector_count = len * s->cluster_size;
break;
case WRITE_6:
case WRITE_10:
@@ -1090,14 +1107,15 @@ static int32_t scsi_send_command(SCSIDevice *d,
uint32_t tag,
case WRITE_VERIFY:
case WRITE_VERIFY_12:
case WRITE_VERIFY_16:
- len = r->req.cmd.xfer / d->blocksize;
- DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",
+ r->sector_count = r->req.cmd.xfer / d->blocksize * s->cluster_size;
+ DPRINTF("Write %s(sector %" PRId64 ", blocks %d)\n",
(command & 0xe) == 0xe ? "And Verify " : "",
- r->req.cmd.lba, len);
- if (r->req.cmd.lba > s->max_lba)
+ r->req.cmd.lba, r->sector_count);
+ if (r->req.cmd.lba > s->max_lba) {
+ r->sector_count = 0;
goto illegal_lba;
+ }
r->sector = r->req.cmd.lba * s->cluster_size;
- r->sector_count = len * s->cluster_size;
is_write = 1;
break;
case MODE_SELECT:
@@ -1135,10 +1153,10 @@ static int32_t scsi_send_command(SCSIDevice *d,
uint32_t tag,
scsi_command_complete(r, CHECK_CONDITION,
SENSE_CODE(LBA_OUT_OF_RANGE));
return 0;
}
- if (r->sector_count == 0 && r->iov.iov_len == 0) {
+ if (r->sector_count == 0 && len == 0) {
scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
}
- len = r->sector_count * 512 + r->iov.iov_len;
+ len += r->sector_count * 512;
if (is_write) {
return -len;
} else {
--
1.6.0.2
- [Qemu-devel] [PATCH 00/15] Megasas HBA emulation and SCSI update v.3, Hannes Reinecke, 2010/11/24
- [Qemu-devel] [PATCH 03/15] scsi: INQUIRY VPD fixes, Hannes Reinecke, 2010/11/24
- [Qemu-devel] [PATCH 07/15] lsi53c895a: Rename 'sense' to 'status', Hannes Reinecke, 2010/11/24
- [Qemu-devel] [PATCH 05/15] scsi-disk: Remove duplicate cdb parsing, Hannes Reinecke, 2010/11/24
- [Qemu-devel] [PATCH 02/15] scsi: Return SAM status codes, Hannes Reinecke, 2010/11/24
- [Qemu-devel] [PATCH 01/15] scsi: Increase the number of possible devices, Hannes Reinecke, 2010/11/24
- [Qemu-devel] [PATCH 08/15] scsi-disk: Allocate iovec dynamically,
Hannes Reinecke <=
- [Qemu-devel] [PATCH 12/15] scsi: Implement 'get_sense' callback, Hannes Reinecke, 2010/11/24
- [Qemu-devel] [PATCH 13/15] scsi: Implement alloc_req_iov callback, Hannes Reinecke, 2010/11/24
[Qemu-devel] [PATCH 04/15] scsi: Move sense handling into the driver, Hannes Reinecke, 2010/11/24
[Qemu-devel] [PATCH 15/15] Make SCSI HBA configurable, Hannes Reinecke, 2010/11/24
[Qemu-devel] [PATCH 10/15] scsi-disk: add data direction checking, Hannes Reinecke, 2010/11/24