From patchwork Wed Feb 22 14:33:50 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 142475 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 3ED95B6FA8 for ; Thu, 23 Feb 2012 01:56:53 +1100 (EST) Received: from localhost ([::1]:44416 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S0DHm-0004U0-N8 for incoming@patchwork.ozlabs.org; Wed, 22 Feb 2012 09:35:14 -0500 Received: from eggs.gnu.org ([140.186.70.92]:37717) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S0DHG-0003fP-Rc for qemu-devel@nongnu.org; Wed, 22 Feb 2012 09:34:48 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1S0DHF-0002T3-1Q for qemu-devel@nongnu.org; Wed, 22 Feb 2012 09:34:42 -0500 Received: from mail-pz0-f45.google.com ([209.85.210.45]:44009) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S0DHE-0002Mp-Qs for qemu-devel@nongnu.org; Wed, 22 Feb 2012 09:34:40 -0500 Received: by mail-pz0-f45.google.com with SMTP id p14so104760dad.4 for ; Wed, 22 Feb 2012 06:34:40 -0800 (PST) Received-SPF: pass (google.com: domain of paolo.bonzini@gmail.com designates 10.68.226.170 as permitted sender) client-ip=10.68.226.170; Authentication-Results: mr.google.com; spf=pass (google.com: domain of paolo.bonzini@gmail.com designates 10.68.226.170 as permitted sender) smtp.mail=paolo.bonzini@gmail.com; dkim=pass header.i=paolo.bonzini@gmail.com Received: from mr.google.com ([10.68.226.170]) by 10.68.226.170 with SMTP id rt10mr2018139pbc.127.1329921280449 (num_hops = 1); Wed, 22 Feb 2012 06:34:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=sender:from:to:subject:date:message-id:x-mailer:in-reply-to :references; bh=IIUmDGUMeJLiyysmvacN7Dpp1CSkfkuccEjpg0qPzBw=; b=gII3Y34qyCtPE8Et3K8WMwniCL90+z78l1CEaIfsRMEsSK8CUmcQonQk0eQCw5l15q f1x5nKL4KlDiYGsdgx5Y5LsE5O98GzyO4fxG27Tu1QrtalNTJw2+kWwrEWTZWNBREUkd zPTZlhRWT+lYnK1yzG0G2am0vzNAvKlDKDIBg= Received: by 10.68.226.170 with SMTP id rt10mr1725406pbc.127.1329921280407; Wed, 22 Feb 2012 06:34:40 -0800 (PST) Received: from yakj.usersys.redhat.com (93-34-182-16.ip50.fastwebnet.it. [93.34.182.16]) by mx.google.com with ESMTPS id q1sm19120759pbv.49.2012.02.22.06.34.37 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 22 Feb 2012 06:34:39 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Wed, 22 Feb 2012 15:33:50 +0100 Message-Id: <1329921236-23461-13-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.7.7.6 In-Reply-To: <1329921236-23461-1-git-send-email-pbonzini@redhat.com> References: <1329921236-23461-1-git-send-email-pbonzini@redhat.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.85.210.45 Subject: [Qemu-devel] [PATCH v4 12/18] virtio-scsi: Add basic request processing infrastructure 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 From: Stefan Hajnoczi Signed-off-by: Stefan Hajnoczi Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini --- hw/virtio-scsi.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 140 insertions(+), 2 deletions(-) diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c index a297fed..a9f883c 100644 --- a/hw/virtio-scsi.c +++ b/hw/virtio-scsi.c @@ -135,14 +135,152 @@ typedef struct { uint32_t cdb_size; } VirtIOSCSI; +typedef struct VirtIOSCSIReq { + VirtIOSCSI *dev; + VirtQueue *vq; + VirtQueueElement elem; + QEMUSGList qsgl; + SCSIRequest *sreq; + union { + char *buf; + VirtIOSCSICmdReq *cmd; + VirtIOSCSICtrlTMFReq *tmf; + VirtIOSCSICtrlANReq *an; + } req; + union { + char *buf; + VirtIOSCSICmdResp *cmd; + VirtIOSCSICtrlTMFResp *tmf; + VirtIOSCSICtrlANResp *an; + VirtIOSCSIEvent *event; + } resp; +} VirtIOSCSIReq; + +static void virtio_scsi_complete_req(VirtIOSCSIReq *req) +{ + VirtIOSCSI *s = req->dev; + VirtQueue *vq = req->vq; + virtqueue_push(vq, &req->elem, req->qsgl.size + req->elem.in_sg[0].iov_len); + qemu_sglist_destroy(&req->qsgl); + if (req->sreq) { + req->sreq->hba_private = NULL; + scsi_req_unref(req->sreq); + } + g_free(req); + virtio_notify(&s->vdev, vq); +} + +static void virtio_scsi_bad_req(void) +{ + error_report("wrong size for virtio-scsi headers"); + exit(1); +} + +static void qemu_sgl_init_external(QEMUSGList *qsgl, struct iovec *sg, + target_phys_addr_t *addr, int num) +{ + memset(qsgl, 0, sizeof(*qsgl)); + while (num--) { + qemu_sglist_add(qsgl, *(addr++), (sg++)->iov_len); + } +} + +static void virtio_scsi_parse_req(VirtIOSCSI *s, VirtQueue *vq, + VirtIOSCSIReq *req) +{ + assert(req->elem.out_num && req->elem.in_num); + req->vq = vq; + req->dev = s; + req->sreq = NULL; + req->req.buf = req->elem.out_sg[0].iov_base; + req->resp.buf = req->elem.in_sg[0].iov_base; + + if (req->elem.out_num > 1) { + qemu_sgl_init_external(&req->qsgl, &req->elem.out_sg[1], + &req->elem.out_addr[1], + req->elem.out_num - 1); + } else { + qemu_sgl_init_external(&req->qsgl, &req->elem.in_sg[1], + &req->elem.in_addr[1], + req->elem.in_num - 1); + } +} + +static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq) +{ + VirtIOSCSIReq *req; + req = g_malloc(sizeof(*req)); + if (!virtqueue_pop(vq, &req->elem)) { + g_free(req); + return NULL; + } + + virtio_scsi_parse_req(s, vq, req); + return req; +} + +static void virtio_scsi_fail_ctrl_req(VirtIOSCSIReq *req) +{ + if (req->req.tmf->type == VIRTIO_SCSI_T_TMF) { + req->resp.tmf->response = VIRTIO_SCSI_S_FAILURE; + } else { + req->resp.an->response = VIRTIO_SCSI_S_FAILURE; + } + + virtio_scsi_complete_req(req); +} + static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) { - /* TODO */ + VirtIOSCSI *s = (VirtIOSCSI *)vdev; + VirtIOSCSIReq *req; + + while ((req = virtio_scsi_pop_req(s, vq))) { + virtio_scsi_fail_ctrl_req(req); + } +} + +static void virtio_scsi_fail_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req) +{ + req->resp.cmd->response = VIRTIO_SCSI_S_FAILURE; + virtio_scsi_complete_req(req); } static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) { - /* TODO */ + VirtIOSCSI *s = (VirtIOSCSI *)vdev; + VirtIOSCSIReq *req; + + while ((req = virtio_scsi_pop_req(s, vq))) { + int out_size, in_size; + if (req->elem.out_num < 1 || req->elem.in_num < 1) { + virtio_scsi_bad_req(); + } + + out_size = req->elem.out_sg[0].iov_len; + in_size = req->elem.in_sg[0].iov_len; + if (out_size < sizeof(VirtIOSCSICmdReq) + s->cdb_size || + in_size < sizeof(VirtIOSCSICmdResp) + s->sense_size) { + virtio_scsi_bad_req(); + } + + if (req->elem.out_num > 1 && req->elem.in_num > 1) { + virtio_scsi_fail_cmd_req(s, req); + continue; + } + + req->resp.cmd->resid = 0; + req->resp.cmd->status_qualifier = 0; + req->resp.cmd->status = CHECK_CONDITION; + req->resp.cmd->sense_len = 4; + req->resp.cmd->sense[0] = 0xf0; /* Fixed format current sense */ + req->resp.cmd->sense[1] = ILLEGAL_REQUEST; + req->resp.cmd->sense[2] = 0x20; + req->resp.cmd->sense[3] = 0x00; + req->resp.cmd->response = VIRTIO_SCSI_S_OK; + + virtio_scsi_complete_req(req); + } } static void virtio_scsi_get_config(VirtIODevice *vdev,