From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:41554) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RwzQx-0003kg-2C for qemu-devel@nongnu.org; Mon, 13 Feb 2012 12:11:27 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RwzQq-0005HT-3I for qemu-devel@nongnu.org; Mon, 13 Feb 2012 12:11:22 -0500 Received: from mail-pz0-f45.google.com ([209.85.210.45]:45129) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RwzQp-00055Q-T7 for qemu-devel@nongnu.org; Mon, 13 Feb 2012 12:11:16 -0500 Received: by mail-pz0-f45.google.com with SMTP id p14so5365383dad.4 for ; Mon, 13 Feb 2012 09:11:15 -0800 (PST) Sender: Paolo Bonzini From: Paolo Bonzini Date: Mon, 13 Feb 2012 18:10:19 +0100 Message-Id: <1329153022-31159-13-git-send-email-pbonzini@redhat.com> In-Reply-To: <1329153022-31159-1-git-send-email-pbonzini@redhat.com> References: <1329153022-31159-1-git-send-email-pbonzini@redhat.com> Subject: [Qemu-devel] [PATCH v3 12/15] virtio-scsi: Add basic request processing infrastructure List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: kwolf@redhat.com, stefanha@gmail.com, christian.hoff@de.ibm.com, Stefan Hajnoczi , kvm@vger.kernel.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 7ebfba7..b34c14f 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, -- 1.7.7.6