From patchwork Mon Apr 4 05:06:05 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shaun Tancheff X-Patchwork-Id: 8737321 Return-Path: X-Original-To: patchwork-linux-scsi@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id C01929F38C for ; Mon, 4 Apr 2016 05:06:43 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id A3D07201EF for ; Mon, 4 Apr 2016 05:06:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 6CBAA201F2 for ; Mon, 4 Apr 2016 05:06:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751428AbcDDFGi (ORCPT ); Mon, 4 Apr 2016 01:06:38 -0400 Received: from mail-pa0-f66.google.com ([209.85.220.66]:36053 "EHLO mail-pa0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750753AbcDDFGg (ORCPT ); Mon, 4 Apr 2016 01:06:36 -0400 Received: by mail-pa0-f66.google.com with SMTP id 1so19001250pal.3; Sun, 03 Apr 2016 22:06:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=WOyw/PnosjZD+Qh4gUijg0BtAAwyfJyRMVchzMAr+N0=; b=JRVA/shgo238iBb82XxyEpOCvKkd2+OhEIYAl/JeR4T1AjnhVq+ukMGqn/ln7Hdsuf 0GIqs4yysY9gkByCFPFcN4dhRuxEyhfljUvnhkAdVau9b1Qh8EN1tgoU4qjq5TRTY0wa 65DvYGGD4Q/pVhFPATyS+di7sSyrkhs7+PpNhYwTTg/egI3Q/FhY35BCjlStHuSYvtjt zKdT3ea8Ji6hnIloDaga4+zL0VR3+GEws5ttRFuDRt1k47GdkrubImEiMdEEkyTLUBPd DFFKGVtClLmVNs1gByxUKzsz7ISlygkxWJmFv0iMj6RUniwGdaXzMUXn8zHSZIUpm0se QwEA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=WOyw/PnosjZD+Qh4gUijg0BtAAwyfJyRMVchzMAr+N0=; b=KEg861zUOlWN5eioEd+bf14BeAT8xk9+Zj+8ndNFldVNp8wQq/aDRb1SNB3k+sYiMT oT6w/41KHReKUFpkOIfyW+F2cQ0I0xAi1c6Dq/D2i6AfnsK94pTCFlaASjLVYlhO6v4s NwFWMpAP3RkPrUylAKWFo0MrvqrenCXN1ZNKQ+f6dwJmbFxz/lS6Ls2jnXExiChZ2oqd /Uwt3a48XxpxNmeqkH8CKwq7Hg8TcfCJ8QsQVEW7SRySevhywb8am/kyln29R4DcOKmA QaKJ02ABFdDXb3+vmluLckeXOMJ+4sSioUmY02bQ3YN4PEfxPhsQHRYLqHadSzgSK7Cl Rs5g== X-Gm-Message-State: AD7BkJINUnGBIaN2Hn4OvkekeGgjOypjHJbufv/PbU1zsezGY+mAkRVhSuJ+vpP2HG1KhQ== X-Received: by 10.67.2.41 with SMTP id bl9mr3217685pad.39.1459746395448; Sun, 03 Apr 2016 22:06:35 -0700 (PDT) Received: from localhost.localdomain ([103.47.135.1]) by smtp.gmail.com with ESMTPSA id k65sm35804188pfb.30.2016.04.03.22.06.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 03 Apr 2016 22:06:34 -0700 (PDT) From: Shaun Tancheff To: linux-ide@vger.kernel.org, dm-devel@redhat.com, linux-block@vger.kernel.org, linux-scsi@vger.kernel.org Cc: Jens Axboe , Shaun Tancheff , Shaun Tancheff Subject: [PATCH 01/12] Add ZBC <-> ZAC xlat support for report, open, close, reset, finish Date: Mon, 4 Apr 2016 12:06:05 +0700 Message-Id: <1459746376-27983-2-git-send-email-shaun@tancheff.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1459746376-27983-1-git-send-email-shaun@tancheff.com> References: <1459746376-27983-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-Spam-Status: No, score=-7.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Provide SCSI <-> ATA translation layer for ZBC commands: - Report Zones - Open, Close, Reset and Finish zones Signed-off-by: Shaun Tancheff --- drivers/ata/libata-scsi.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/ata.h | 18 +++++ include/scsi/scsi_proto.h | 14 ++++ 3 files changed, 199 insertions(+) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index e417e1a..a7c5ec8 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -65,6 +65,7 @@ static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); static struct ata_device *ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); +static void scsi_16_lba_len(const u8 *cdb, u64 *plba, u32 *plen); #define RW_RECOVERY_MPAGE 0x1 #define RW_RECOVERY_MPAGE_LEN 12 @@ -1442,6 +1443,160 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc) } /** + * ata_scsi_zone_command_xlat - Translate SCSI Reset Write Pointer command + * @qc: Storage for translated ATA taskfile + * + * Sets up an ATA taskfile to issue Reset Write Pointers Ext command. + * May need change when zac specs is available. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * Zero on success, non-zero on error. + */ +static unsigned int ata_scsi_zone_command_xlat(struct ata_queued_cmd *qc) +{ + struct scsi_cmnd *scmd = qc->scsicmd; + struct ata_taskfile *tf = &qc->tf; + const u8 *cdb = scmd->cmnd; + u8 sa; /* service action */ + u8 all_bit; + + if (scmd->cmd_len < 16) + goto invalid_fld; + + sa = cdb[1] & 0x1f; + + if (!(sa == ATA_SUBCMD_CLOSE_ZONES || + sa == ATA_SUBCMD_FINISH_ZONES || + sa == ATA_SUBCMD_OPEN_ZONES || + sa == ATA_SUBCMD_RESET_WP)) + goto invalid_fld; + + all_bit = cdb[14] & 0x01; + if (!all_bit) { + struct ata_device *dev = qc->dev; + u64 max_lba = dev->n_sectors; /* Maximal LBA supported */ + u64 slba; + u32 slen; + + scsi_16_lba_len(cdb, &slba, &slen); + if (slba > max_lba) { + ata_dev_err(dev, + "Zone start LBA %llu > %llu (Max LBA)\n", + slba, max_lba); + goto out_of_range; + } + + tf->hob_lbah = (slba >> 40) & 0xff; + tf->hob_lbam = (slba >> 32) & 0xff; + tf->hob_lbal = (slba >> 24) & 0xff; + tf->lbah = (slba >> 16) & 0xff; + tf->lbam = (slba >> 8) & 0xff; + tf->lbal = slba & 0xff; + } + + + tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48; + tf->protocol = ATA_PROT_NODATA; + + tf->command = ATA_CMD_ZONE_MAN_OUT; + tf->feature = sa; + tf->hob_feature = all_bit; + + return 0; + + invalid_fld: + ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + return 1; + out_of_range: + ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x21, 0x0); + /* LBA out of range */ + return 1; +} + +/** + * ata_scsi_report_zones_xlat - Translate SCSI Report Zones command + * @qc: Storage for translated ATA taskfile + * + * Sets up an ATA taskfile to issue Report Zones Ext command. + * May need change when zac specs is updated. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * Zero on success, non-zero on error. + */ +static unsigned int ata_scsi_report_zones_xlat(struct ata_queued_cmd *qc) +{ + struct ata_device *dev = qc->dev; + struct scsi_cmnd *scmd = qc->scsicmd; + struct ata_taskfile *tf = &qc->tf; + const u8 *cdb = scmd->cmnd; + u64 max_lba = dev->n_sectors; /* Maximal LBA supported */ + u64 slba; /* Start LBA in scsi command */ + u32 alloc_len; /* Alloc length (in bytes) */ + u8 reporting_option; + + if (scmd->cmd_len < 16) { + ata_dev_err(dev, "ZAC Error: Command length is less than 16\n"); + goto invalid_fld; + } + if (unlikely(!dev->dma_mode)) { + ata_dev_err(dev, "ZAC Error: No DMA mode is set\n"); + goto invalid_fld; + } + if (!scsi_sg_count(scmd)) { + ata_dev_err(dev, "ZAC Error: SCSI sg count is zero\n"); + goto invalid_fld; + } + scsi_16_lba_len(cdb, &slba, &alloc_len); + if (slba > max_lba) { + ata_dev_err(dev, "Zone start LBA %llu > %llu (Max LBA)\n", + slba, max_lba); + goto out_of_range; + } + + reporting_option = cdb[14] & 0x3f; + + tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR; + tf->protocol = ATA_PROT_DMA; + + tf->command = ATA_CMD_ZONE_MAN_IN; + + tf->hob_lbah = (slba >> 40) & 0xff; + tf->hob_lbam = (slba >> 32) & 0xff; + tf->hob_lbal = (slba >> 24) & 0xff; + tf->lbah = (slba >> 16) & 0xff; + tf->lbam = (slba >> 8) & 0xff; + tf->lbal = slba & 0xff; + + tf->feature = 0x00; + tf->hob_feature = reporting_option; + + alloc_len /= 512; /* bytes in scsi, blocks in ata */ + tf->nsect = alloc_len & 0xff; + tf->hob_nsect = alloc_len >> 8; + + ata_qc_set_pc_nbytes(qc); + + return 0; + + invalid_fld: + ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + return 1; + out_of_range: + ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x21, 0x0); + /* LBA out of range */ + return 1; +} + + +/** * scsi_6_lba_len - Get LBA and transfer length * @cdb: SCSI command to translate * @@ -2232,12 +2387,17 @@ static unsigned int ata_scsiop_inq_b1(struct ata_scsi_args *args, u8 *rbuf) { int form_factor = ata_id_form_factor(args->id); int media_rotation_rate = ata_id_rotation_rate(args->id); + bool zac_ha = ata_drive_zac_ha(args->id); rbuf[1] = 0xb1; rbuf[3] = 0x3c; rbuf[4] = media_rotation_rate >> 8; rbuf[5] = media_rotation_rate; rbuf[7] = form_factor; + if (zac_ha) { + rbuf[8] &= 0xcf; + rbuf[8] |= 0x10; /* SBC4: 0x01 for zoned host aware device */ + } return 0; } @@ -3421,6 +3581,13 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd) case START_STOP: return ata_scsi_start_stop_xlat; + + case ZBC_ACTION: + return ata_scsi_zone_command_xlat; + + case ZBC_REPORT_ZONES: + return ata_scsi_report_zones_xlat; + break; } return NULL; diff --git a/include/linux/ata.h b/include/linux/ata.h index c1a2f34..779b7f2 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -305,6 +305,17 @@ enum { /* marked obsolete in the ATA/ATAPI-7 spec */ ATA_CMD_RESTORE = 0x10, + /* ZAC commands */ + ATA_CMD_ZONE_MAN_OUT = 0x9F, + + ATA_SUBCMD_CLOSE_ZONES = 0x01, + ATA_SUBCMD_FINISH_ZONES = 0x02, + ATA_SUBCMD_OPEN_ZONES = 0x03, + ATA_SUBCMD_RESET_WP = 0x04, + + ATA_CMD_ZONE_MAN_IN = 0x4A, + ATA_SUBCMD_REP_ZONES = 0x00, + /* Subcmds for ATA_CMD_FPDMA_SEND */ ATA_SUBCMD_FPDMA_SEND_DSM = 0x00, ATA_SUBCMD_FPDMA_SEND_WR_LOG_DMA_EXT = 0x02, @@ -899,6 +910,13 @@ static inline bool ata_drive_40wire_relaxed(const u16 *dev_id) return true; } +static inline bool ata_drive_zac_ha(const u16 *dev_id) +{ + if ((dev_id[69] & 0x0003) == 0x0001) + return true; + return false; +} + static inline int atapi_cdb_len(const u16 *dev_id) { u16 tmp = dev_id[ATA_ID_CONFIG] & 0x3; diff --git a/include/scsi/scsi_proto.h b/include/scsi/scsi_proto.h index a9fbf1b..dd0e089 100644 --- a/include/scsi/scsi_proto.h +++ b/include/scsi/scsi_proto.h @@ -115,6 +115,10 @@ #define VERIFY_16 0x8f #define SYNCHRONIZE_CACHE_16 0x91 #define WRITE_SAME_16 0x93 +/* Op codes for Zoned Block Commands */ +#define ZBC_ACTION 0x94 +#define ZBC_REPORT_ZONES 0x95 + #define SERVICE_ACTION_BIDIRECTIONAL 0x9d #define SERVICE_ACTION_IN_16 0x9e #define SERVICE_ACTION_OUT_16 0x9f @@ -157,6 +161,16 @@ #define ATA_16 0x85 /* 16-byte pass-thru */ #define ATA_12 0xa1 /* 12-byte pass-thru */ +/* ZBC_ACTION: Values for T-10 ZBC sub action */ +#define ZBC_SA_ZONE_CLOSE 0x01 +#define ZBC_SA_ZONE_FINISH 0x02 +#define ZBC_SA_ZONE_OPEN 0x03 +#define ZBC_SA_RESET_WP 0x04 + +/* ZBC_REPORT_ZONES: Default report option. T-10 ZBC report zones */ +#define ZBC_REPORT_OPT 0x00 + + /* Vendor specific CDBs start here */ #define VENDOR_SPECIFIC_CDB 0xc0