Add callback to create a request with a predefined iovec. This is required for drivers which can use the iovec of a command directly.
Signed-off-by: Hannes Reinecke <h...@suse.de> --- hw/scsi-disk.c | 25 +++++++++++++++++++++---- hw/scsi-generic.c | 44 +++++++++++++++++++++++++++++++++----------- hw/scsi.h | 2 ++ 3 files changed, 56 insertions(+), 15 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 68b8667..67f93a5 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -96,14 +96,30 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, return req; } +static SCSIRequest *scsi_new_request_iovec(SCSIDevice *d, uint32_t tag, + uint32_t lun, struct iovec *iov, int iov_num) +{ + SCSIRequest *req; + SCSIDiskReq *r; + + req = scsi_req_alloc(sizeof(SCSIDiskReq), d, tag, lun); + r = DO_UPCAST(SCSIDiskReq, req, req); + r->iov = iov; + r->iov_num = iov_num; + r->iov_buf = NULL; + return req; +} + static void scsi_remove_request(SCSIRequest *req) { SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); - qemu_free(r->iov); - r->iov = NULL; - qemu_vfree(r->iov_buf); - r->iov_buf = NULL; + if (r->iov_buf) { + qemu_free(r->iov); + r->iov = NULL; + qemu_vfree(r->iov_buf); + r->iov_buf = NULL; + } scsi_req_free(&r->req); } @@ -1220,6 +1236,7 @@ static SCSIDeviceInfo scsi_disk_info = { .init = scsi_disk_initfn, .destroy = scsi_destroy, .alloc_req = scsi_new_request, + .alloc_req_iov = scsi_new_request_iovec, .free_req = scsi_remove_request, .send_command = scsi_send_command, .read_data = scsi_read_data, diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 949b4cc..8c99e9e 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -108,6 +108,25 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun) return req; } +static SCSIRequest *scsi_new_request_iovec(SCSIDevice *d, uint32_t tag, + uint32_t lun, struct iovec *iov, int iov_num) +{ + SCSIRequest *req; + SCSIGenericReq *r; + int i; + + req = scsi_req_alloc(sizeof(SCSIGenericReq), d, tag, lun); + r = DO_UPCAST(SCSIGenericReq, req, req); + r->io_header.dxferp = iov; + r->io_header.iovec_count = iov_num; + r->io_header.dxfer_len = 0; + for (i = 0; i < iov_num; i++) + r->io_header.dxfer_len += iov[i].iov_len; + r->buf = NULL; + r->buflen = 0; + return req; +} + static void scsi_remove_request(SCSIRequest *req) { SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); @@ -180,8 +199,10 @@ static int execute_command(BlockDriverState *bdrv, r->io_header.interface_id = 'S'; r->io_header.dxfer_direction = direction; - r->io_header.dxferp = r->buf; - r->io_header.dxfer_len = r->buflen; + if (r->buf) { + r->io_header.dxferp = r->buf; + r->io_header.dxfer_len = r->buflen; + } r->io_header.cmdp = r->req.cmd.buf; r->io_header.cmd_len = r->req.cmd.len; r->io_header.mx_sb_len = sizeof(s->sensebuf); @@ -287,7 +308,7 @@ static int scsi_write_data(SCSIRequest *req) DPRINTF("scsi_write_data 0x%x\n", req->tag); - if (r->len == 0) { + if (r->len == 0 && r->io_header.dxfer_len == 0) { r->len = r->buflen; r->req.bus->complete(&r->req, SCSI_REASON_DATA, r->len); return 0; @@ -369,8 +390,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd) #endif if (r->req.cmd.xfer == 0) { - if (r->buf != NULL) - qemu_free(r->buf); + qemu_free(r->buf); r->buflen = 0; r->buf = NULL; ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete); @@ -381,14 +401,15 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd) return 0; } - if (r->buflen != r->req.cmd.xfer) { - if (r->buf != NULL) + if (!r->io_header.iovec_count) { + if (r->buflen != r->req.cmd.xfer) { qemu_free(r->buf); - r->buf = qemu_malloc(r->req.cmd.xfer); - r->buflen = r->req.cmd.xfer; - } + r->buf = qemu_malloc(r->req.cmd.xfer); + r->buflen = r->req.cmd.xfer; + } - memset(r->buf, 0, r->buflen); + memset(r->buf, 0, r->buflen); + } r->len = r->req.cmd.xfer; if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { r->len = 0; @@ -561,6 +582,7 @@ static SCSIDeviceInfo scsi_generic_info = { .init = scsi_generic_initfn, .destroy = scsi_destroy, .alloc_req = scsi_new_request, + .alloc_req_iov = scsi_new_request_iovec, .free_req = scsi_remove_request, .send_command = scsi_send_command, .read_data = scsi_read_data, diff --git a/hw/scsi.h b/hw/scsi.h index cc96f85..063154d 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -72,6 +72,8 @@ struct SCSIDeviceInfo { scsi_qdev_initfn init; void (*destroy)(SCSIDevice *s); SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun); + SCSIRequest *(*alloc_req_iov)(SCSIDevice *s, uint32_t tag, uint32_t lun, + struct iovec *iov, int iov_num); void (*free_req)(SCSIRequest *req); int32_t (*send_command)(SCSIRequest *req, uint8_t *buf); void (*read_data)(SCSIRequest *req); -- 1.6.0.2