From patchwork Thu Nov 26 14:34:04 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gerd Hoffmann X-Patchwork-Id: 39544 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 572861007E8 for ; Fri, 27 Nov 2009 02:48:17 +1100 (EST) Received: from localhost ([127.0.0.1]:36009 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NDgZq-0003PR-18 for incoming@patchwork.ozlabs.org; Thu, 26 Nov 2009 10:48:14 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NDfRB-00074Z-Mq for qemu-devel@nongnu.org; Thu, 26 Nov 2009 09:35:16 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1NDfR4-0006uH-HM for qemu-devel@nongnu.org; Thu, 26 Nov 2009 09:35:10 -0500 Received: from [199.232.76.173] (port=56178 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NDfR3-0006tJ-7s for qemu-devel@nongnu.org; Thu, 26 Nov 2009 09:35:05 -0500 Received: from mx1.redhat.com ([209.132.183.28]:63211) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1NDfR2-0000JA-LB for qemu-devel@nongnu.org; Thu, 26 Nov 2009 09:35:05 -0500 Received: from int-mx03.intmail.prod.int.phx2.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.16]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id nAQEZ31L026258 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 26 Nov 2009 09:35:03 -0500 Received: from zweiblum.home.kraxel.org (vpn2-8-164.ams2.redhat.com [10.36.8.164]) by int-mx03.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id nAQEYp4P028190; Thu, 26 Nov 2009 09:34:55 -0500 Received: by zweiblum.home.kraxel.org (Postfix, from userid 500) id 4EAC570115; Thu, 26 Nov 2009 15:34:18 +0100 (CET) From: Gerd Hoffmann To: qemu-devel@nongnu.org Date: Thu, 26 Nov 2009 15:34:04 +0100 Message-Id: <1259246056-5389-19-git-send-email-kraxel@redhat.com> In-Reply-To: <1259246056-5389-1-git-send-email-kraxel@redhat.com> References: <1259246056-5389-1-git-send-email-kraxel@redhat.com> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.16 X-detected-operating-system: by monty-python.gnu.org: Genre and OS details not recognized. Cc: Gerd Hoffmann Subject: [Qemu-devel] [PATCH 18/30] scsi-disk: restruct emulation: INQUIRY 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 Move INQUIRY emulation from scsi_send_command() to scsi_disk_emulate_command(). Also split the longish INQUITY emulation code into the new scsi_disk_emulate_inquiry() function. Serial number handling is slightly changed, we don't copy it any more but look it up directly in DriveInfo which we have at hand anyway. Signed-off-by: Gerd Hoffmann --- hw/scsi-disk.c | 305 ++++++++++++++++++++++++++------------------------------ 1 files changed, 143 insertions(+), 162 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 7597b52..f94d513 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -58,7 +58,6 @@ struct SCSIDiskState This is the number of 512 byte blocks in a single scsi sector. */ int cluster_size; uint64_t max_lba; - char drive_serial_str[21]; QEMUBH *bh; }; @@ -306,6 +305,141 @@ static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag) return (uint8_t *)r->iov.iov_base; } +static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) +{ + BlockDriverState *bdrv = req->dev->dinfo->bdrv; + int buflen = 0; + + if (req->cmd.buf[1] & 0x2) { + /* Command support data - optional, not implemented */ + BADF("optional INQUIRY command support request not implemented\n"); + return -1; + } + + if (req->cmd.buf[1] & 0x1) { + /* Vital product data */ + uint8_t page_code = req->cmd.buf[2]; + if (req->cmd.xfer < 4) { + BADF("Error: Inquiry (EVPD[%02X]) buffer size %zd is " + "less than 4\n", page_code, req->cmd.xfer); + return -1; + } + + if (bdrv_get_type_hint(bdrv) == BDRV_TYPE_CDROM) { + outbuf[buflen++] = 5; + } else { + outbuf[buflen++] = 0; + } + outbuf[buflen++] = page_code ; // this page + outbuf[buflen++] = 0x00; + + switch (page_code) { + case 0x00: /* Supported page codes, mandatory */ + DPRINTF("Inquiry EVPD[Supported pages] " + "buffer size %zd\n", req->cmd.xfer); + outbuf[buflen++] = 3; // number of pages + outbuf[buflen++] = 0x00; // list of supported pages (this page) + outbuf[buflen++] = 0x80; // unit serial number + outbuf[buflen++] = 0x83; // device identification + break; + + case 0x80: /* Device serial number, optional */ + { + const char *serial = req->dev->dinfo->serial ?: "0"; + int l = strlen(serial); + + if (l > req->cmd.xfer) + l = req->cmd.xfer; + if (l > 20) + l = 20; + + DPRINTF("Inquiry EVPD[Serial number] " + "buffer size %zd\n", req->cmd.xfer); + outbuf[buflen++] = l; + memcpy(outbuf+buflen, serial, l); + buflen += l; + break; + } + + case 0x83: /* Device identification page, mandatory */ + { + int max_len = 255 - 8; + int id_len = strlen(bdrv_get_device_name(bdrv)); + + if (id_len > max_len) + id_len = max_len; + DPRINTF("Inquiry EVPD[Device identification] " + "buffer size %zd\n", req->cmd.xfer); + + outbuf[buflen++] = 3 + id_len; + outbuf[buflen++] = 0x2; // ASCII + outbuf[buflen++] = 0; // not officially assigned + outbuf[buflen++] = 0; // reserved + outbuf[buflen++] = id_len; // length of data following + + memcpy(outbuf+buflen, bdrv_get_device_name(bdrv), id_len); + buflen += id_len; + break; + } + default: + BADF("Error: unsupported Inquiry (EVPD[%02X]) " + "buffer size %zd\n", page_code, req->cmd.xfer); + return -1; + } + /* done with EVPD */ + return buflen; + } + + /* Standard INQUIRY data */ + if (req->cmd.buf[2] != 0) { + BADF("Error: Inquiry (STANDARD) page or code " + "is non-zero [%02X]\n", req->cmd.buf[2]); + return -1; + } + + /* PAGE CODE == 0 */ + if (req->cmd.xfer < 5) { + BADF("Error: Inquiry (STANDARD) buffer size %zd " + "is less than 5\n", req->cmd.xfer); + return -1; + } + + if (req->cmd.xfer < 36) { + BADF("Error: Inquiry (STANDARD) buffer size %zd " + "is less than 36 (TODO: only 5 required)\n", req->cmd.xfer); + } + + buflen = req->cmd.xfer; + if (buflen > SCSI_MAX_INQUIRY_LEN) + buflen = SCSI_MAX_INQUIRY_LEN; + + memset(outbuf, 0, buflen); + + if (req->lun || req->cmd.buf[1] >> 5) { + outbuf[0] = 0x7f; /* LUN not supported */ + return buflen; + } + + if (bdrv_get_type_hint(bdrv) == BDRV_TYPE_CDROM) { + outbuf[0] = 5; + outbuf[1] = 0x80; + memcpy(&outbuf[16], "QEMU CD-ROM ", 16); + } else { + outbuf[0] = 0; + memcpy(&outbuf[16], "QEMU HARDDISK ", 16); + } + memcpy(&outbuf[8], "QEMU ", 8); + memcpy(&outbuf[32], QEMU_VERSION, 4); + /* Identify device as SCSI-3 rev 1. + Some later commands are also implemented. */ + outbuf[2] = 3; + outbuf[3] = 2; /* Format 2 */ + outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */ + /* Sync data transfer and TCQ. */ + outbuf[7] = 0x10 | (req->bus->tcq ? 0x02 : 0); + return buflen; +} + static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) { BlockDriverState *bdrv = req->dev->dinfo->bdrv; @@ -334,6 +468,11 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) outbuf[2] = req->dev->sense.key; scsi_dev_clear_sense(req->dev); break; + case INQUIRY: + buflen = scsi_disk_emulate_inquiry(req, outbuf); + if (buflen < 0) + goto illegal_request; + break; default: goto illegal_request; } @@ -438,170 +577,16 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, switch (command) { case TEST_UNIT_READY: case REQUEST_SENSE: + case INQUIRY: rc = scsi_disk_emulate_command(&r->req, outbuf); if (rc > 0) { r->iov.iov_len = rc; } else { scsi_req_complete(&r->req); scsi_remove_request(r); + return 0; } - return rc; - case INQUIRY: - DPRINTF("Inquiry (len %d)\n", len); - if (buf[1] & 0x2) { - /* Command support data - optional, not implemented */ - BADF("optional INQUIRY command support request not implemented\n"); - goto fail; - } - else if (buf[1] & 0x1) { - /* Vital product data */ - uint8_t page_code = buf[2]; - if (len < 4) { - BADF("Error: Inquiry (EVPD[%02X]) buffer size %d is " - "less than 4\n", page_code, len); - goto fail; - } - - switch (page_code) { - case 0x00: - { - /* Supported page codes, mandatory */ - DPRINTF("Inquiry EVPD[Supported pages] " - "buffer size %d\n", len); - - r->iov.iov_len = 0; - - if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM) { - outbuf[r->iov.iov_len++] = 5; - } else { - outbuf[r->iov.iov_len++] = 0; - } - - outbuf[r->iov.iov_len++] = 0x00; // this page - outbuf[r->iov.iov_len++] = 0x00; - outbuf[r->iov.iov_len++] = 3; // number of pages - outbuf[r->iov.iov_len++] = 0x00; // list of supported pages (this page) - outbuf[r->iov.iov_len++] = 0x80; // unit serial number - outbuf[r->iov.iov_len++] = 0x83; // device identification - } - break; - case 0x80: - { - int l; - - /* Device serial number, optional */ - if (len < 4) { - BADF("Error: EVPD[Serial number] Inquiry buffer " - "size %d too small, %d needed\n", len, 4); - goto fail; - } - - DPRINTF("Inquiry EVPD[Serial number] buffer size %d\n", len); - l = MIN(len, strlen(s->drive_serial_str)); - - r->iov.iov_len = 0; - - /* Supported page codes */ - if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM) { - outbuf[r->iov.iov_len++] = 5; - } else { - outbuf[r->iov.iov_len++] = 0; - } - - outbuf[r->iov.iov_len++] = 0x80; // this page - outbuf[r->iov.iov_len++] = 0x00; - outbuf[r->iov.iov_len++] = l; - memcpy(&outbuf[r->iov.iov_len], s->drive_serial_str, l); - r->iov.iov_len += l; - } - - break; - case 0x83: - { - /* Device identification page, mandatory */ - int max_len = 255 - 8; - int id_len = strlen(bdrv_get_device_name(s->qdev.dinfo->bdrv)); - if (id_len > max_len) - id_len = max_len; - - DPRINTF("Inquiry EVPD[Device identification] " - "buffer size %d\n", len); - r->iov.iov_len = 0; - if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM) { - outbuf[r->iov.iov_len++] = 5; - } else { - outbuf[r->iov.iov_len++] = 0; - } - - outbuf[r->iov.iov_len++] = 0x83; // this page - outbuf[r->iov.iov_len++] = 0x00; - outbuf[r->iov.iov_len++] = 3 + id_len; - - outbuf[r->iov.iov_len++] = 0x2; // ASCII - outbuf[r->iov.iov_len++] = 0; // not officially assigned - outbuf[r->iov.iov_len++] = 0; // reserved - outbuf[r->iov.iov_len++] = id_len; // length of data following - - memcpy(&outbuf[r->iov.iov_len], - bdrv_get_device_name(s->qdev.dinfo->bdrv), id_len); - r->iov.iov_len += id_len; - } - break; - default: - BADF("Error: unsupported Inquiry (EVPD[%02X]) " - "buffer size %d\n", page_code, len); - goto fail; - } - /* done with EVPD */ - break; - } - else { - /* Standard INQUIRY data */ - if (buf[2] != 0) { - BADF("Error: Inquiry (STANDARD) page or code " - "is non-zero [%02X]\n", buf[2]); - goto fail; - } - - /* PAGE CODE == 0 */ - if (len < 5) { - BADF("Error: Inquiry (STANDARD) buffer size %d " - "is less than 5\n", len); - goto fail; - } - - if (len < 36) { - BADF("Error: Inquiry (STANDARD) buffer size %d " - "is less than 36 (TODO: only 5 required)\n", len); - } - } - - if(len > SCSI_MAX_INQUIRY_LEN) - len = SCSI_MAX_INQUIRY_LEN; - - memset(outbuf, 0, len); - - if (lun || buf[1] >> 5) { - outbuf[0] = 0x7f; /* LUN not supported */ - } else if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM) { - outbuf[0] = 5; - outbuf[1] = 0x80; - memcpy(&outbuf[16], "QEMU CD-ROM ", 16); - } else { - outbuf[0] = 0; - memcpy(&outbuf[16], "QEMU HARDDISK ", 16); - } - memcpy(&outbuf[8], "QEMU ", 8); - memcpy(&outbuf[32], QEMU_VERSION, 4); - /* Identify device as SCSI-3 rev 1. - Some later commands are also implemented. */ - outbuf[2] = 3; - outbuf[3] = 2; /* Format 2 */ - outbuf[4] = len - 5; /* Additional Length = (Len - 1) - 4 */ - /* Sync data transfer and TCQ. */ - outbuf[7] = 0x10 | (r->req.bus->tcq ? 0x02 : 0); - r->iov.iov_len = len; - break; + break; case RESERVE: DPRINTF("Reserve(6)\n"); if (buf[1] & 1) @@ -983,10 +968,6 @@ static int scsi_disk_initfn(SCSIDevice *dev) if (nb_sectors) nb_sectors--; s->max_lba = nb_sectors; - strncpy(s->drive_serial_str, drive_get_serial(s->qdev.dinfo->bdrv), - sizeof(s->drive_serial_str)); - if (strlen(s->drive_serial_str) == 0) - pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), "0"); qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s); return 0; }