From patchwork Thu Nov 18 14:47:23 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hannes Reinecke X-Patchwork-Id: 72104 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 03E9EB71A7 for ; Fri, 19 Nov 2010 01:52:23 +1100 (EST) Received: from localhost ([127.0.0.1]:59466 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PJ5pB-0004IX-V0 for incoming@patchwork.ozlabs.org; Thu, 18 Nov 2010 09:50:58 -0500 Received: from [140.186.70.92] (port=35702 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PJ5jS-0001hb-JR for qemu-devel@nongnu.org; Thu, 18 Nov 2010 09:45:04 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PJ5jQ-0001hY-LH for qemu-devel@nongnu.org; Thu, 18 Nov 2010 09:45:02 -0500 Received: from cantor2.suse.de ([195.135.220.15]:47113 helo=mx2.suse.de) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PJ5jQ-0001hA-8g for qemu-devel@nongnu.org; Thu, 18 Nov 2010 09:45:00 -0500 Received: from relay1.suse.de (charybdis-ext.suse.de [195.135.221.2]) by mx2.suse.de (Postfix) with ESMTP id 8FA8A89783; Thu, 18 Nov 2010 15:44:59 +0100 (CET) Date: Thu, 18 Nov 2010 15:47:23 +0100 To: qemu-devel@nongnu.org User-Agent: Heirloom mailx 12.2 01/07/07 MIME-Version: 1.0 Message-Id: <20101118144723.61032F90AB@ochil.suse.de> From: hare@suse.de (Hannes Reinecke) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4-2.6 Cc: stefanha@gmail.com, nab@linux-iscsi.org, kraxel@redhat.com Subject: [Qemu-devel] [PATCH 09/16] scsi-disk: Allocate iovec dynamically X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- hw/scsi-disk.c | 112 +++++++++++++++++++++++++++++++++++--------------------- 1 files changed, 70 insertions(+), 42 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index a71607e..2d2e770 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -56,7 +56,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 +89,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_vfree(r->iov); + r->iov = NULL; + qemu_vfree(r->iov_buf); + r->iov_buf = NULL; scsi_req_free(&r->req); } @@ -114,10 +123,21 @@ static void scsi_req_set_status(SCSIDiskReq *r, int status, SCSISense sense) s->sense = sense; } +static size_t scsi_req_iov_len(SCSIDiskReq *r) +{ + size_t iov_len = 0; + int i; + + for (i = 0; i < r->iov_num; i++) + iov_len += r->iov[i].iov_len; + + return iov_len; +} + /* 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 +162,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 +171,11 @@ static void scsi_read_complete(void * opaque, int ret) return; } } + iov_len = scsi_req_iov_len(r); - 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 +185,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 +198,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 +289,20 @@ static void scsi_write_complete(void * opaque, int ret) } } - n = r->iov.iov_len / 512; + n = scsi_req_iov_len(r) / 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 +313,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 = scsi_req_iov_len(r) / 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 +380,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 +413,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 +1029,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 +1043,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 +1090,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 +1117,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 +1163,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 {