From patchwork Mon Jun 6 15:39:31 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shaun Tancheff X-Patchwork-Id: 9158639 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 11E2B60572 for ; Mon, 6 Jun 2016 15:45:15 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 04508282EE for ; Mon, 6 Jun 2016 15:45:15 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id ED9972833A; Mon, 6 Jun 2016 15:45:14 +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 vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 414AE282EE for ; Mon, 6 Jun 2016 15:45:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752652AbcFFPpM (ORCPT ); Mon, 6 Jun 2016 11:45:12 -0400 Received: from smtp81.mediacombb.net ([68.66.77.81]:37284 "EHLO dsmdc-mail-smtp.mcomdc.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752020AbcFFPpI (ORCPT ); Mon, 6 Jun 2016 11:45:08 -0400 Received: from helios ([173.23.250.243]) by njtocomv02.mcomdc.com with bizsmtp id 3Tg01t00v5FqEsV01Tg1n3; Mon, 06 Jun 2016 11:40:01 -0400 X-Outbound-Route: TO X-Authenticated-Sender: shaun@helios.aeonazure.com X-Authority-Analysis: v=2.1 cv=LMPoQfm9 c=1 sm=1 tr=0 a=OCiMecrhrNRzvyrd/uXHhg==:117 a=OCiMecrhrNRzvyrd/uXHhg==:17 a=L9H7d07YOLsA:10 a=9cW_t1CCXrUA:10 a=s5jvgZ67dGcA:10 a=pD_ry4oyNxEA:10 a=3go8odswAAAA:8 a=bHhbspMKCPSioLZoWQIA:9 a=WCphLhRDQySbTNkkd-8K:22 X-Authenticated-Sender: shaun@helios.aeonazure.com Received: from shaun by helios with local (Exim 4.87) (envelope-from ) id 1b9wdE-00074w-Ld; Mon, 06 Jun 2016 10:40:00 -0500 From: Shaun Tancheff To: linux-ide@vger.kernel.org, linux-block@vger.kernel.org, linux-scsi@vger.kernel.org Cc: Shaun Tancheff , Shaun Tancheff Subject: [PATCH 4/4] Add ata pass-through path for ZAC commands. Date: Mon, 6 Jun 2016 10:39:31 -0500 Message-Id: <1465227572-27149-5-git-send-email-shaun@tancheff.com> X-Mailer: git-send-email 2.8.1 In-Reply-To: <1465227572-27149-1-git-send-email-shaun@tancheff.com> References: <1465227572-27149-1-git-send-email-shaun@tancheff.com> Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The current generation of HBA SAS adapters support connecting SATA drives and perform SCSI<->ATA translations in hardware. Unfortunately the ZBC commands are not being translate (yet). Currently users of SAS controllers can only send ZAC commands via ata pass-through. This method overloads the meaning of REQ_META to direct ZBC commands to construct ZAC equivalent ATA pass through commands. Note also that this approach expects the initiator to deal with the little endian result due to bypassing the normal translation layers. Signed-off-by: Shaun Tancheff --- block/ioctl.c | 29 ++++++++++++++++++++++ drivers/scsi/sd.c | 70 +++++++++++++++++++++++++++++++++++++++++------------ include/linux/ata.h | 15 ++++++++++++ 3 files changed, 99 insertions(+), 15 deletions(-) diff --git a/block/ioctl.c b/block/ioctl.c index 46a8553..03a5808 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -284,6 +284,35 @@ static int blk_zoned_action_ioctl(struct block_device *bdev, fmode_t mode, return -EFAULT; } + /* + * When the low bit is set force ATA passthrough try to work around + * older SAS HBA controllers that don't support ZBC to ZAC translation. + * + * When the low bit is clear follow the normal path but also correct + * for ~0ul LBA means 'for all lbas'. + * + * NB: We should do extra checking here to see if the user specified + * the entire block device as opposed to a partition of the + * device.... + */ + if (arg & 1) { + bi_rw |= REQ_META; + if (arg != ~0ul) + arg &= ~1ul; /* ~1 :: 0xFF...FE */ + } else { + if (arg == ~1ul) + arg = ~0ul; + } + + /* + * When acting on zones we explicitly disallow using a partition. + */ + if (bdev != bdev->bd_contains) { + pr_err("%s: All zone operations disallowed on this device\n", + __func__); + return -EFAULT; + } + switch (cmd) { case BLKOPENZONE: bi_rw |= REQ_OPEN_ZONE; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 372b5e2..177d5fb 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -1182,12 +1183,29 @@ static int sd_setup_zoned_cmnd(struct scsi_cmnd *cmd) cmd->cmd_len = 16; memset(cmd->cmnd, 0, cmd->cmd_len); - cmd->cmnd[0] = ZBC_IN; - cmd->cmnd[1] = ZI_REPORT_ZONES; - put_unaligned_be64(sector, &cmd->cmnd[2]); - put_unaligned_be32(nr_bytes, &cmd->cmnd[10]); - /* FUTURE ... when streamid is available */ - /* cmd->cmnd[14] = bio_get_streamid(bio); */ + if (rq->cmd_flags & REQ_META) { + cmd->cmnd[0] = ATA_16; + cmd->cmnd[1] = (0x6 << 1) | 1; + cmd->cmnd[2] = 0x0e; + /* FUTURE ... when streamid is available */ + /* cmd->cmnd[3] = bio_get_streamid(bio); */ + cmd->cmnd[4] = ATA_SUBCMD_ZAC_MGMT_IN_REPORT_ZONES; + cmd->cmnd[5] = ((nr_bytes / 512) >> 8) & 0xff; + cmd->cmnd[6] = (nr_bytes / 512) & 0xff; + + _lba_to_cmd_ata(&cmd->cmnd[7], sector); + + cmd->cmnd[13] = 1 << 6; + cmd->cmnd[14] = ATA_CMD_ZAC_MGMT_IN; + } else { + cmd->cmnd[0] = ZBC_IN; + cmd->cmnd[1] = ZI_REPORT_ZONES; + put_unaligned_be64(sector, &cmd->cmnd[2]); + put_unaligned_be32(nr_bytes, &cmd->cmnd[10]); + /* FUTURE ... when streamid is available */ + /* cmd->cmnd[14] = bio_get_streamid(bio); */ + } + cmd->sc_data_direction = DMA_FROM_DEVICE; cmd->sdb.length = nr_bytes; cmd->transfersize = sdp->sector_size; @@ -1208,14 +1226,29 @@ static int sd_setup_zoned_cmnd(struct scsi_cmnd *cmd) cmd->cmd_len = 16; memset(cmd->cmnd, 0, cmd->cmd_len); memset(&cmd->sdb, 0, sizeof(cmd->sdb)); - cmd->cmnd[0] = ZBC_OUT; - cmd->cmnd[1] = ZO_OPEN_ZONE; - if (rq->cmd_flags & REQ_CLOSE_ZONE) - cmd->cmnd[1] = ZO_CLOSE_ZONE; - if (rq->cmd_flags & REQ_RESET_ZONE) - cmd->cmnd[1] = ZO_RESET_WRITE_POINTER; - cmd->cmnd[14] = allbit; - put_unaligned_be64(sector, &cmd->cmnd[2]); + if (rq->cmd_flags & REQ_META) { + cmd->cmnd[0] = ATA_16; + cmd->cmnd[1] = (3 << 1) | 1; + cmd->cmnd[3] = allbit; + cmd->cmnd[4] = ATA_SUBCMD_ZAC_MGMT_OUT_RESET_WRITE_POINTER; + if (rq->cmd_flags & REQ_OPEN_ZONE) + cmd->cmnd[4] = ATA_SUBCMD_ZAC_MGMT_OUT_OPEN_ZONE; + if (rq->cmd_flags & REQ_CLOSE_ZONE) + cmd->cmnd[4] = ATA_SUBCMD_ZAC_MGMT_OUT_CLOSE_ZONE; + _lba_to_cmd_ata(&cmd->cmnd[7], sector); + cmd->cmnd[13] = 1 << 6; + cmd->cmnd[14] = ATA_CMD_ZAC_MGMT_OUT; + } else { + cmd->cmnd[0] = ZBC_OUT; + cmd->cmnd[1] = ZO_OPEN_ZONE; + if (rq->cmd_flags & REQ_CLOSE_ZONE) + cmd->cmnd[1] = ZO_CLOSE_ZONE; + if (rq->cmd_flags & REQ_RESET_ZONE) + cmd->cmnd[1] = ZO_RESET_WRITE_POINTER; + cmd->cmnd[14] = allbit; + put_unaligned_be64(sector, &cmd->cmnd[2]); + } + cmd->transfersize = 0; cmd->underflow = 0; cmd->allowed = SD_MAX_RETRIES; @@ -2806,7 +2839,7 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp) { unsigned char *buffer; u16 rot; - const int vpd_len = 64; + const int vpd_len = 512; buffer = kmalloc(vpd_len, GFP_KERNEL); @@ -2823,6 +2856,13 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp) } sdkp->zoned = (buffer[8] >> 4) & 3; + if (sdkp->zoned != 1) { + struct scsi_device *sdev = sdkp->device; + + /* buf size is 512, page is 60 + 512, we need page 206 */ + if (!scsi_get_vpd_page(sdev, 0x89, buffer, SD_BUF_SIZE)) + sdkp->zoned = ata_id_zoned_cap((u16 *)&buffer[60]); + } out: kfree(buffer); diff --git a/include/linux/ata.h b/include/linux/ata.h index 99346be..5cc1a85 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -1060,6 +1060,21 @@ static inline void ata_id_to_hd_driveid(u16 *id) #endif } +/** + * _lba_to_cmd_ata() - Copy lba48 to ATA command + * @cmd: ATA command as an array of bytes + * @_lba: lba48 in the low 48 bits + */ +static inline void _lba_to_cmd_ata(u8 *cmd, u64 _lba) +{ + cmd[1] = _lba & 0xff; + cmd[3] = (_lba >> 8) & 0xff; + cmd[5] = (_lba >> 16) & 0xff; + cmd[0] = (_lba >> 24) & 0xff; + cmd[2] = (_lba >> 32) & 0xff; + cmd[4] = (_lba >> 40) & 0xff; +} + /* * Write LBA Range Entries to the buffer that will cover the extent from * sector to sector + count. This is used for TRIM and for ADD LBA(S)