From patchwork Wed Aug 3 08:49:14 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 108072 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 536CBB71E3 for ; Wed, 3 Aug 2011 19:29:50 +1000 (EST) Received: from localhost ([::1]:54509 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QoX9u-00089i-Dk for incoming@patchwork.ozlabs.org; Wed, 03 Aug 2011 04:50:34 -0400 Received: from eggs.gnu.org ([140.186.70.92]:44673) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QoX90-0005tN-JU for qemu-devel@nongnu.org; Wed, 03 Aug 2011 04:49:39 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QoX8y-0003iq-Bb for qemu-devel@nongnu.org; Wed, 03 Aug 2011 04:49:38 -0400 Received: from mail-wy0-f173.google.com ([74.125.82.173]:44070) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QoX8x-0003gH-U3 for qemu-devel@nongnu.org; Wed, 03 Aug 2011 04:49:36 -0400 Received: by mail-wy0-f173.google.com with SMTP id 20so154406wye.4 for ; Wed, 03 Aug 2011 01:49:35 -0700 (PDT) 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=6IqBQSwOLSvCSzWm/c0UJ/lfDwtd1Sj4YbGBOlhDfEg=; b=sEQvu6ZbxfXYeT9+VXeWSonJkZYPn/YW2C2J+uT7nOcAq8R8EScD33+y8guQkMQ6Dx Pv/3JhhGYe3uEn5PmVMdvjmKoOJAE/RITv+RoFqY8EqxpE3FSaJtNZODNoaXDUInZf/Y ASZ1ps5uKhY5KNgy/0VPJTEoMbJNmqkidTz5k= Received: by 10.227.174.79 with SMTP id s15mr7968853wbz.68.1312361375504; Wed, 03 Aug 2011 01:49:35 -0700 (PDT) Received: from localhost.localdomain (93-34-199-31.ip51.fastwebnet.it [93.34.199.31]) by mx.google.com with ESMTPS id ff6sm485877wbb.66.2011.08.03.01.49.34 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 03 Aug 2011 01:49:35 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Wed, 3 Aug 2011 10:49:14 +0200 Message-Id: <1312361359-15445-12-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.7.6 In-Reply-To: <1312361359-15445-1-git-send-email-pbonzini@redhat.com> References: <1312361359-15445-1-git-send-email-pbonzini@redhat.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 74.125.82.173 Subject: [Qemu-devel] [PATCH 11/16] scsi: move handling of REPORT LUNS and invalid LUNs to common code 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 Signed-off-by: Paolo Bonzini --- hw/scsi-bus.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++- hw/scsi-defs.h | 3 + hw/scsi-disk.c | 21 ------ hw/scsi-generic.c | 7 -- 4 files changed, 177 insertions(+), 29 deletions(-) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 01dbe02..139f6a6 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -149,6 +149,172 @@ struct SCSIReqOps reqops_invalid_opcode = { .send_command = scsi_invalid_command }; +/* SCSIReqOps implementation for REPORT LUNS and for commands sent to + an invalid LUN. */ + +typedef struct SCSITargetReq SCSITargetReq; + +struct SCSITargetReq { + SCSIRequest req; + int len; + uint8_t buf[64]; +}; + +static void store_lun(uint8_t *outbuf, int lun) +{ + if (lun < 256) { + outbuf[1] = lun; + return; + } + outbuf[1] = (lun & 255); + outbuf[0] = (lun >> 8) | 0x40; +} + +static bool scsi_target_emulate_report_luns(SCSITargetReq *r) +{ + int len; + if (r->req.cmd.xfer < 16) { + return false; + } + if (r->req.cmd.buf[2] > 2) { + return false; + } + len = MIN(sizeof r->buf, r->req.cmd.xfer); + memset(r->buf, 0, len); + if (r->req.dev->lun != 0) { + r->buf[3] = 16; + r->len = 24; + store_lun(&r->buf[16], r->req.dev->lun); + } else { + r->buf[3] = 8; + r->len = 16; + } + return true; +} + +static bool scsi_target_emulate_inquiry(SCSITargetReq *r) +{ + assert(r->req.dev->lun != r->req.lun); + if (r->req.cmd.buf[1] & 0x2) { + /* Command support data - optional, not implemented */ + return false; + } + + if (r->req.cmd.buf[1] & 0x1) { + /* Vital product data */ + uint8_t page_code = r->req.cmd.buf[2]; + if (r->req.cmd.xfer < 4) { + return false; + } + + r->buf[r->len++] = page_code ; /* this page */ + r->buf[r->len++] = 0x00; + + switch (page_code) { + case 0x00: /* Supported page codes, mandatory */ + { + int pages; + pages = r->len++; + r->buf[r->len++] = 0x00; /* list of supported pages (this page) */ + r->buf[pages] = r->len - pages - 1; /* number of pages */ + break; + } + default: + return false; + } + /* done with EVPD */ + assert(r->len < sizeof(r->buf)); + r->len = MIN(r->req.cmd.xfer, r->len); + return true; + } + + /* Standard INQUIRY data */ + if (r->req.cmd.buf[2] != 0) { + return false; + } + + /* PAGE CODE == 0 */ + if (r->req.cmd.xfer < 5) { + return -1; + } + + r->len = MIN(r->req.cmd.xfer, 36); + memset(r->buf, 0, r->len); + if (r->req.lun != 0) { + r->buf[0] = TYPE_NO_LUN; + } else { + r->buf[0] = TYPE_NOT_PRESENT | TYPE_INACTIVE; + r->buf[2] = 5; /* Version */ + r->buf[3] = 2 | 0x10; /* HiSup, response data format */ + r->buf[4] = r->len - 5; /* Additional Length = (Len - 1) - 4 */ + r->buf[7] = 0x10 | (r->req.bus->tcq ? 0x02 : 0); /* Sync, TCQ. */ + memcpy(&r->buf[8], "QEMU ", 8); + memcpy(&r->buf[16], "QEMU TARGET ", 16); + strncpy((char *) &r->buf[32], QEMU_VERSION, 4); + } + return true; +} + +static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf) +{ + SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req); + + switch (buf[0]) { + case REPORT_LUNS: + if (!scsi_target_emulate_report_luns(r)) { + goto illegal_request; + } + break; + case INQUIRY: + if (!scsi_target_emulate_inquiry(r)) { + goto illegal_request; + } + break; + default: + scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED)); + scsi_req_complete(req, CHECK_CONDITION); + return 0; + illegal_request: + scsi_req_build_sense(req, SENSE_CODE(INVALID_FIELD)); + scsi_req_complete(req, CHECK_CONDITION); + return 0; + } + + if (!r->len) { + scsi_req_complete(req, GOOD); + } + return r->len; +} + +static void scsi_target_read_data(SCSIRequest *req) +{ + SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req); + uint32_t n; + + n = r->len; + if (n > 0) { + r->len = 0; + scsi_req_data(&r->req, n); + } else { + scsi_req_complete(&r->req, GOOD); + } +} + +static uint8_t *scsi_target_get_buf(SCSIRequest *req) +{ + SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req); + + return r->buf; +} + +struct SCSIReqOps reqops_target_command = { + .size = sizeof(SCSITargetReq), + .send_command = scsi_target_send_command, + .read_data = scsi_target_read_data, + .get_buf = scsi_target_get_buf, +}; + + SCSIRequest *scsi_req_alloc(SCSIReqOps *reqops, SCSIDevice *d, uint32_t tag, uint32_t lun, void *hba_private) { @@ -184,7 +350,14 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, trace_scsi_req_parsed_lba(d->id, lun, tag, buf[0], cmd.lba); } - req = d->info->alloc_req(d, tag, lun, hba_private); + + if ((lun != d->lun && buf[0] != REQUEST_SENSE) || + buf[0] == REPORT_LUNS) { + req = scsi_req_alloc(&reqops_target_command, d, tag, lun, + hba_private); + } else { + req = d->info->alloc_req(d, tag, lun, hba_private); + } } req->cmd = cmd; diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h index 413cce0..79ab9d5 100644 --- a/hw/scsi-defs.h +++ b/hw/scsi-defs.h @@ -162,5 +162,8 @@ * - treated as TYPE_DISK */ #define TYPE_MEDIUM_CHANGER 0x08 #define TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */ +#define TYPE_WLUN 0x1e /* Well known LUN */ +#define TYPE_NOT_PRESENT 0x1f +#define TYPE_INACTIVE 0x20 #define TYPE_NO_LUN 0x7f diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 64aa141..a5fdb05 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -485,11 +485,6 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) memset(outbuf, 0, buflen); - if (req->lun) { - outbuf[0] = 0x7f; /* LUN not supported */ - return buflen; - } - if (s->drive_kind == SCSI_CD) { outbuf[0] = 5; outbuf[1] = 0x80; @@ -922,13 +917,6 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf) } DPRINTF("Unsupported Service Action In\n"); goto illegal_request; - case REPORT_LUNS: - if (req->cmd.xfer < 16) - goto illegal_request; - memset(outbuf, 0, 16); - outbuf[3] = 8; - buflen = 16; - break; case VERIFY: break; case REZERO_UNIT: @@ -984,14 +972,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf) } #endif - if (req->lun) { - /* Only LUN 0 supported. */ - DPRINTF("Unimplemented LUN %d\n", req->lun); - if (command != REQUEST_SENSE && command != INQUIRY) { - scsi_check_condition(r, SENSE_CODE(LUN_NOT_SUPPORTED)); - return 0; - } - } switch (command) { case TEST_UNIT_READY: case REQUEST_SENSE: @@ -1009,7 +989,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf) case READ_TOC: case GET_CONFIGURATION: case SERVICE_ACTION_IN: - case REPORT_LUNS: case VERIFY: case REZERO_UNIT: rc = scsi_disk_emulate_command(r, outbuf); diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index e91c32e..5217aaf 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -287,13 +287,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd) SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); int ret; - if (cmd[0] != REQUEST_SENSE && req->lun != s->qdev.lun) { - DPRINTF("Unimplemented LUN %d\n", req->lun); - scsi_req_build_sense(&r->req, SENSE_CODE(LUN_NOT_SUPPORTED)); - scsi_req_complete(&r->req, CHECK_CONDITION); - return 0; - } - scsi_req_fixup(&r->req); DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,