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 <h...@suse.de> --- 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