From patchwork Mon Jun 6 16:27:00 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 99006 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id C992CB6F86 for ; Tue, 7 Jun 2011 05:15:57 +1000 (EST) Received: from localhost ([::1]:32946 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QTfHE-0005n0-MH for incoming@patchwork.ozlabs.org; Mon, 06 Jun 2011 15:15:53 -0400 Received: from eggs.gnu.org ([140.186.70.92]:43784) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QTceW-00046D-7A for qemu-devel@nongnu.org; Mon, 06 Jun 2011 12:27:45 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QTceQ-0003yg-1m for qemu-devel@nongnu.org; Mon, 06 Jun 2011 12:27:43 -0400 Received: from mail-px0-f174.google.com ([209.85.212.174]:57224) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QTceP-0003wK-Of for qemu-devel@nongnu.org; Mon, 06 Jun 2011 12:27:37 -0400 Received: by mail-px0-f174.google.com with SMTP id 15so964653pxi.33 for ; Mon, 06 Jun 2011 09:27:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:sender:from:to:subject:date:message-id:x-mailer :in-reply-to:references; bh=Ambcvlwhvy4/2AL2Eyfh0OGw6fQMmlrIAKGwzpbg6Hc=; b=qHS9YFPnEMA6EXAVclRLem6KdyPWxS4H2kiJpw1/bfLqDC05903dlVgcZ6bxotqFkc T+oNLJu3oYdzTzXXwePGr3wC1RAMY4rIII/6AfWA7nluTlIgWKIkZPysuhIPbWAw84mv 1AIAMP5ddJN9ZhbObF0oi3ni6yw0+wsn0Qxqk= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=sender:from:to:subject:date:message-id:x-mailer:in-reply-to :references; b=IBPBfZ9Icgv/H70yPoY8XmO9DAJdI5optQHObnrJsoFOD1g9dRyZm8yyKJ7gWwLV/q 2p/dcE38/j9g7WCO5OF7rSGH3eNGd8MBkHppSVyZpTHzObHcWDqxtl3gm0MANHkv9alR u6kVIuNMEuhN6swy9ituXbvsNhUbvOtDvJkLw= Received: by 10.68.39.72 with SMTP id n8mr2270235pbk.93.1307377657383; Mon, 06 Jun 2011 09:27:37 -0700 (PDT) Received: from localhost.localdomain (93-34-184-88.ip51.fastwebnet.it [93.34.184.88]) by mx.google.com with ESMTPS id y2sm3785829pbi.51.2011.06.06.09.27.35 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 06 Jun 2011 09:27:36 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Mon, 6 Jun 2011 18:27:00 +0200 Message-Id: <1307377620-7538-10-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.7.4.4 In-Reply-To: <1307377620-7538-1-git-send-email-pbonzini@redhat.com> References: <1307377620-7538-1-git-send-email-pbonzini@redhat.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 209.85.212.174 Subject: [Qemu-devel] [RFC PATCH 9/9] pvscsi: implement s/g operation without a bounce buffer X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This implements the new callbacks in the pvscsi device. Signed-off-by: Paolo Bonzini --- hw/vmw_pvscsi.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 114 insertions(+), 1 deletions(-) diff --git a/hw/vmw_pvscsi.c b/hw/vmw_pvscsi.c index 1cb6715..ac16e52 100644 --- a/hw/vmw_pvscsi.c +++ b/hw/vmw_pvscsi.c @@ -49,6 +49,7 @@ typedef struct { QEMUBH *complete_reqs_bh; int mmio_io_addr; + uint32_t use_iovec; /* zeroed on reset */ uint32_t cmd_latch; @@ -387,6 +388,112 @@ static bool pvscsi_check_addresses(PVSCSIRequest *p) } } +static bool pvscsi_iovec_add(PVSCSIRequest *p, target_phys_addr_t addr, + uint64_t len) +{ + while (len) { + target_phys_addr_t n = len; + uint8_t *buf = cpu_physical_memory_map_fast(addr, &n); + if (!buf) { + return false; + } + qemu_iovec_add(&p->sreq->qiov, buf, n); + addr += n; + len -= n; + } + return true; +} + +static bool pvscsi_get_sg_list_iovec(PVSCSIRequest *p, uint64_t len) +{ + int n; + PVSCSISGState sg = p->sg; + while (len) { + while (!sg.resid) { + pvscsi_get_next_sg_elem(&sg); + trace_pvscsi_sg_elem(p->req.context, sg.dataAddr, sg.resid); + } + assert(len > 0); + n = MIN((unsigned) len, sg.resid); + if (n) { + if (!pvscsi_iovec_add(p, sg.dataAddr, n)) { + return false; + } + } + + sg.dataAddr += n; + + len -= n; + sg.resid -= n; + } + return true; +} + +static void pvscsi_get_iovec(SCSIRequest *req, uint64_t len) +{ + PVSCSIState *s = DO_UPCAST(PVSCSIState, dev.qdev, req->bus->qbus.parent); + PVSCSIRequest *p = pvscsi_find_request(s, req); + bool ok; + + if (!s->use_iovec) { + return; + } + if (p->req.flags & PVSCSI_FLAG_CMD_WITH_SG_LIST) { + ok = pvscsi_get_sg_list_iovec(p, len); + } else { + ok = pvscsi_iovec_add(p, p->req.dataAddr, MIN(len, p->req.dataLen)); + } + if (!ok) { + qemu_iovec_reset(&p->sreq->qiov); + } +} + +/* Callback to indicate that the SCSI layer has completed a transfer. */ +static void pvscsi_unmap_iovec(SCSIRequest *req, uint64_t len) +{ + PVSCSIState *s = DO_UPCAST(PVSCSIState, dev.qdev, req->bus->qbus.parent); + PVSCSIRequest *p = pvscsi_find_request(s, req); + int to_host = (p->req.flags & PVSCSI_FLAG_CMD_DIR_TOHOST) != 0; + QEMUIOVector *qiov = &req->qiov; + int i; + + if (!p) { + fprintf(stderr, "PVSCSI: Can't find request for tag 0x%x\n", req->tag); + return; + } + + trace_pvscsi_transfer_data(p->req.context, len); + if (!len) { + /* Short transfer. */ + p->cmp.hostStatus = BTSTAT_DATARUN; + scsi_req_cancel(req); + return; + } + + for (i = 0; i < qiov->niov; i++) { + uint64_t n = req->qiov.iov[i].iov_len; + uint64_t access_len = MIN(len, n); + cpu_physical_memory_unmap(req->qiov.iov[i].iov_base, n, + to_host, access_len); + + if (p->req.flags & PVSCSI_FLAG_CMD_WITH_SG_LIST) { + while (!p->sg.resid) { + pvscsi_get_next_sg_elem(&p->sg); + } + assert(n <= p->sg.resid); + p->sg.dataAddr += n; + p->sg.resid -= n; + } + + assert(access_len <= p->resid); + p->cmp.dataLen += access_len; + p->resid -= access_len; + len -= access_len; + } + + scsi_req_continue(req); +} + /* Callback to indicate that the SCSI layer has completed a transfer. */ static void pvscsi_transfer_data(SCSIRequest *req, uint32_t len) { @@ -837,7 +944,9 @@ static int pvscsi_uninit(PCIDevice *d) static struct SCSIBusOps pvscsi_scsi_ops = { .transfer_data = pvscsi_transfer_data, .complete = pvscsi_command_complete, - .cancel = pvscsi_request_cancelled + .cancel = pvscsi_request_cancelled, + .get_iovec = pvscsi_get_iovec, + .unmap_iovec = pvscsi_unmap_iovec }; static int pvscsi_init(PCIDevice *dev) @@ -891,6 +1000,10 @@ static PCIDeviceInfo pvscsi_info = { .qdev.reset = pvscsi_reset, .init = pvscsi_init, .exit = pvscsi_uninit, + .qdev.props = (Property[]) { + DEFINE_PROP_BIT("sg", PVSCSIState, use_iovec, 0, true), + DEFINE_PROP_END_OF_LIST(), + }, }; static void vmw_pvscsi_register_devices(void)