From patchwork Tue Mar 13 14:26:44 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Henrique Barboza X-Patchwork-Id: 10279171 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 76984602BD for ; Tue, 13 Mar 2018 14:28:45 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 64F4A28FEB for ; Tue, 13 Mar 2018 14:28:45 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5988A28FFC; Tue, 13 Mar 2018 14:28:45 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id B077428FF1 for ; Tue, 13 Mar 2018 14:28:44 +0000 (UTC) Received: from localhost ([::1]:40215 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evkux-0000Yx-NY for patchwork-qemu-devel@patchwork.kernel.org; Tue, 13 Mar 2018 10:28:43 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54089) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evkuI-00008L-3A for qemu-devel@nongnu.org; Tue, 13 Mar 2018 10:28:07 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1evkuD-0006ea-4g for qemu-devel@nongnu.org; Tue, 13 Mar 2018 10:28:02 -0400 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:44666) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1evkuC-0006Lg-Ro for qemu-devel@nongnu.org; Tue, 13 Mar 2018 10:27:57 -0400 Received: from pps.filterd (m0098404.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w2DEQmBV105330 for ; Tue, 13 Mar 2018 10:27:01 -0400 Received: from e34.co.us.ibm.com (e34.co.us.ibm.com [32.97.110.152]) by mx0a-001b2d01.pphosted.com with ESMTP id 2gpgd283k7-1 (version=TLSv1.2 cipher=AES256-SHA256 bits=256 verify=NOT) for ; Tue, 13 Mar 2018 10:26:56 -0400 Received: from localhost by e34.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 13 Mar 2018 08:26:55 -0600 Received: from b03cxnp08025.gho.boulder.ibm.com (9.17.130.17) by e34.co.us.ibm.com (192.168.1.134) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Tue, 13 Mar 2018 08:26:51 -0600 Received: from b03ledav005.gho.boulder.ibm.com (b03ledav005.gho.boulder.ibm.com [9.17.130.236]) by b03cxnp08025.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id w2DEQlmP5112254; Tue, 13 Mar 2018 07:26:51 -0700 Received: from b03ledav005.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 2EE58BE039; Tue, 13 Mar 2018 08:26:51 -0600 (MDT) Received: from dhcp-9-18-235-55.br.ibm.com (unknown [9.18.235.55]) by b03ledav005.gho.boulder.ibm.com (Postfix) with ESMTP id 4F2D6BE042; Tue, 13 Mar 2018 08:26:50 -0600 (MDT) From: Daniel Henrique Barboza To: qemu-devel@nongnu.org Date: Tue, 13 Mar 2018 11:26:44 -0300 X-Mailer: git-send-email 2.14.3 X-TM-AS-GCONF: 00 x-cbid: 18031314-0016-0000-0000-0000086247F0 X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00008666; HX=3.00000241; KW=3.00000007; PH=3.00000004; SC=3.00000254; SDB=6.01002470; UDB=6.00510092; IPR=6.00781800; MB=3.00020007; MTD=3.00000008; XFM=3.00000015; UTC=2018-03-13 14:26:53 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 18031314-0017-0000-0000-00003DD2B0AB Message-Id: <20180313142644.16778-1-danielhb@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2018-03-13_07:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=5 phishscore=0 bulkscore=0 spamscore=0 clxscore=1011 lowpriorityscore=0 impostorscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1709140000 definitions=main-1803130171 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [generic] [fuzzy] X-Received-From: 148.163.156.1 Subject: [Qemu-devel] [PATCH 1/1] hw/scsi: support SCSI-2 passthrough without PI X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Daniel Henrique Barboza , pbonzini@redhat.com, famz@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP QEMU SCSI code makes assumptions about how the PROTECT and BYTCHK works in the protocol, denying support for PI (Protection Information) in case the guest OS requests it. However, in SCSI versions 2 and older, there is no PI concept in the protocol. This means that when dealing with such devices: - there is no PROTECT bit in byte 5 of the standard INQUIRY response. The whole byte is marked as "Reserved"; - there is no RDPROTECT in byte 2 of READ. We have 'Logical Unit Number' in this field instead; - there is no VRPROTECT in byte 2 of VERIFY. We have 'Logical Unit Number' in this field instead. This also means that the BYTCHK bit in this case is not related to PI. Since QEMU does not consider these changes, a SCSI passthrough using a SCSI-2 device will not work. It will mistake these fields with PI information and return Illegal Request SCSI SENSE thinking that the driver is asking for PI support. This patch fixes it by adding a new attribute called 'scsi_version' that is read from the standard INQUIRY response of passthrough devices. This allows for a version verification before applying conditions related to PI that doesn't apply for older versions. Reported-by: Dac Nguyen Signed-off-by: Daniel Henrique Barboza --- hw/scsi/scsi-disk.c | 13 ++++++++++--- hw/scsi/scsi-generic.c | 41 ++++++++++++++++++++++++++++++----------- include/hw/scsi/scsi.h | 1 + 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 49d2559d93..185c6153a8 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2176,7 +2176,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) case READ_12: case READ_16: DPRINTF("Read (sector %" PRId64 ", count %u)\n", r->req.cmd.lba, len); - if (r->req.cmd.buf[1] & 0xe0) { + if ((r->req.cmd.buf[1] & 0xe0) && (s->qdev.scsi_version > 2)) { goto illegal_request; } if (!check_lba_range(s, r->req.cmd.lba, len)) { @@ -2206,8 +2206,12 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) /* We get here only for BYTCHK == 0x01 and only for scsi-block. * As far as DMA is concerned, we can treat it the same as a write; * scsi_block_do_sgio will send VERIFY commands. + * + * For scsi versions 2 and older, the BYTCHK isn't related + * to VRPROTECT (in fact, there is no VRPROTECT). Skip + * this check in these versions. */ - if (r->req.cmd.buf[1] & 0xe0) { + if ((r->req.cmd.buf[1] & 0xe0) && (s->qdev.scsi_version > 2)) { goto illegal_request; } if (!check_lba_range(s, r->req.cmd.lba, len)) { @@ -2796,6 +2800,8 @@ static bool scsi_block_is_passthrough(SCSIDiskState *s, uint8_t *buf) static int32_t scsi_block_dma_command(SCSIRequest *req, uint8_t *buf) { SCSIBlockReq *r = (SCSIBlockReq *)req; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); + r->cmd = req->cmd.buf[0]; switch (r->cmd >> 5) { case 0: @@ -2821,7 +2827,7 @@ static int32_t scsi_block_dma_command(SCSIRequest *req, uint8_t *buf) abort(); } - if (r->cdb1 & 0xe0) { + if ((r->cdb1 & 0xe0) && (s->qdev.scsi_version > 2)) { /* Protection information is not supported. */ scsi_check_condition(&r->req, SENSE_CODE(INVALID_FIELD)); return 0; @@ -3007,6 +3013,7 @@ static Property scsi_block_properties[] = { DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.blk), DEFINE_PROP_BOOL("share-rw", SCSIDiskState, qdev.conf.share_rw, false), DEFINE_PROP_UINT16("rotation_rate", SCSIDiskState, rotation_rate, 0), + DEFINE_PROP_INT32("scsi-version", SCSIDevice, scsi_version, -1), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 7414fe2d67..80f9311b17 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -194,17 +194,35 @@ static void scsi_read_complete(void * opaque, int ret) r->buf[3] |= 0x80; } } - if (s->type == TYPE_DISK && - r->req.cmd.buf[0] == INQUIRY && - r->req.cmd.buf[2] == 0xb0) { - uint32_t max_transfer = - blk_get_max_transfer(s->conf.blk) / s->blocksize; - - assert(max_transfer); - stl_be_p(&r->buf[8], max_transfer); - /* Also take care of the opt xfer len. */ - stl_be_p(&r->buf[12], - MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12]))); + if (r->req.cmd.buf[0] == INQUIRY) { + /* + * EVPD set to zero returns the standard INQUIRY data. + * + * Check if scsi_version is unset (-1) to avoid re-defining it + * each time an INQUIRY with standard data is received. + * + * On SCSI-2 and older, first 3 bits of byte 2 is the + * ANSI-approved version, while on later versions the + * whole byte 2 contains the version. Check if we're dealing + * with a newer version and, in that case, assign the + * whole byte. + */ + if ((s->scsi_version == -1) && ((r->req.cmd.buf[1] & 0x01) == 0)) { + s->scsi_version = r->buf[2] & 0x07; + if (s->scsi_version > 2) { + s->scsi_version = r->buf[2]; + } + } + if (s->type == TYPE_DISK && r->req.cmd.buf[2] == 0xb0) { + uint32_t max_transfer = + blk_get_max_transfer(s->conf.blk) / s->blocksize; + + assert(max_transfer); + stl_be_p(&r->buf[8], max_transfer); + /* Also take care of the opt xfer len. */ + stl_be_p(&r->buf[12], + MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12]))); + } } scsi_req_data(&r->req, len); scsi_req_unref(&r->req); @@ -571,6 +589,7 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, static Property scsi_generic_properties[] = { DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.blk), DEFINE_PROP_BOOL("share-rw", SCSIDevice, conf.share_rw, false), + DEFINE_PROP_INT32("scsi-version", SCSIDevice, scsi_version, -1), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 7ecaddac9d..a698c7f60c 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -85,6 +85,7 @@ struct SCSIDevice uint64_t max_lba; uint64_t wwn; uint64_t port_wwn; + int scsi_version; }; extern const VMStateDescription vmstate_scsi_device;