From patchwork Mon Apr 4 05:06:06 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shaun Tancheff X-Patchwork-Id: 8737341 Return-Path: X-Original-To: patchwork-linux-scsi@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 62563C0554 for ; Mon, 4 Apr 2016 05:06:46 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 2EA76201FA for ; Mon, 4 Apr 2016 05:06:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id E3EF0201F2 for ; Mon, 4 Apr 2016 05:06:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751660AbcDDFGl (ORCPT ); Mon, 4 Apr 2016 01:06:41 -0400 Received: from mail-pa0-f65.google.com ([209.85.220.65]:33812 "EHLO mail-pa0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751476AbcDDFGj (ORCPT ); Mon, 4 Apr 2016 01:06:39 -0400 Received: by mail-pa0-f65.google.com with SMTP id hb4so3816665pac.1; Sun, 03 Apr 2016 22:06:38 -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=9Pgy0WKUPHmnu2e9ed0iKYY78diWwkF4wr47f+hkCEE=; b=zKXRb4be/D537ZgLaOYyyb9jnhnsnUoup5uTiu3npwxZmWr3pGyU5himcIDlSDlf7i 6sv6mg2h4zOUpLaH7PL6pdh1k1aH8RQS8SYoIGT8Yq1AVHLi1PQyD5ZW5xl1ro/hfdHQ voKHDf0GAz7A+JUWgjKdeptpJzeVA+L5OCD9zxid+nDJJ2ASwBlabFbqOWQNeAsCRCac 5TsVxKWcafTL4VpixoT4hk3M7FG10JgO30ZSbYm6GI2wh4rd5ug0/DAwrolgy+CwJsn/ MQ43couswxCC5/TmX/964MyiLK/9dbOypBMSJulbIctKaeVDBwhxmeW9t7BC7aIMjDFx WfhQ== 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=9Pgy0WKUPHmnu2e9ed0iKYY78diWwkF4wr47f+hkCEE=; b=hdpMOERhzqwiFUr5rng41xX+K9LO9J3gcoBNK9OSLonVsMJUt8PHHHbDvthHmC8BcI Gpt3bkQNYAKdbvV51Uk9yicZ1b9061VEwZVz3ebDWszcW6RD3UiP7E9Tc/cMz5UZQBHO HzZJvgTGv4pgNT7ICvz4yQBf0LtHn33+Ae0G0ivyIaS4PrY0ZHEFZ2sy980TirSuR0o/ YBpSku/cnZTyPkL2EIlCtsZB9QBAzHEU3R18kp4yaDShRfcP33UzAlZSxS0wdHCtHmJJ O6R7KJ0PaYpuRbHsCUUTjGs1eScowsSIlThXRI61AZpYp/vgsxLsrsd7temrqu54zhAU T/1A== X-Gm-Message-State: AD7BkJKJzKzmLabBerGn+Xk0lhRMnvpby9qrGc/JsXNGtq7Vj/JSdUzseS6VixC+axvAKg== X-Received: by 10.66.160.231 with SMTP id xn7mr50890352pab.134.1459746398084; Sun, 03 Apr 2016 22:06:38 -0700 (PDT) Received: from localhost.localdomain ([103.47.135.1]) by smtp.gmail.com with ESMTPSA id k65sm35804188pfb.30.2016.04.03.22.06.35 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 03 Apr 2016 22:06:37 -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 02/12] ata-scsi: Translate ReportZones result to big endian Date: Mon, 4 Apr 2016 12:06:06 +0700 Message-Id: <1459746376-27983-3-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 Translate T13 (little endian) output to match T10 (big endian). In the common case SATA drives connected via AHCI controllers libata translates commands from T10 to T13. On reply the converse should also be performed. If the originating command was translate from T10 to T13 the result should be translated from T13 to T10 format. Add this T13->T10 translation on the result from Report Zones. Code originially from: Hannes Reinecke with minor changes. http://kernel.opensuse.org/cgit/kernel-source/commit/?id=6e219225108bf49c59aa69d14f3cbc74708777ae Signed-off-by: Shaun Tancheff --- drivers/ata/libata-eh.c | 2 + drivers/ata/libata-scsi.c | 229 +++++++++++++++++++++++++++--------------- include/trace/events/libata.h | 2 + 3 files changed, 154 insertions(+), 79 deletions(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 961acc7..c217471 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2398,6 +2398,8 @@ const char *ata_get_cmd_descript(u8 command) { ATA_CMD_CFA_WRITE_MULT_NE, "CFA WRITE MULTIPLE WITHOUT ERASE" }, { ATA_CMD_REQ_SENSE_DATA, "REQUEST SENSE DATA EXT" }, { ATA_CMD_SANITIZE_DEVICE, "SANITIZE DEVICE" }, + { ATA_CMD_ZONE_MAN_IN, "ZAC MANAGEMENT IN" }, + { ATA_CMD_ZONE_MAN_OUT, "ZAC MANAGEMENT OUT" }, { ATA_CMD_READ_LONG, "READ LONG (with retries)" }, { ATA_CMD_READ_LONG_ONCE, "READ LONG (without retries)" }, { ATA_CMD_WRITE_LONG, "WRITE LONG (with retries)" }, diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index a7c5ec8..ea454c4 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1518,85 +1518,6 @@ static unsigned int ata_scsi_zone_command_xlat(struct ata_queued_cmd *qc) } /** - * 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 * @@ -1950,6 +1871,156 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) ata_qc_done(qc); } +/* + * ata_scsi_report_zones_complete + * + * Convert T-13 little-endian field representation into + * T-10 big-endian field representation. + */ +static void ata_scsi_report_zones_complete(struct ata_queued_cmd *qc) +{ + struct scsi_cmnd *scmd = qc->scsicmd; + struct sg_mapping_iter miter; + unsigned long flags; + unsigned int bytes = 0; + + sg_miter_start(&miter, scsi_sglist(scmd), scsi_sg_count(scmd), + SG_MITER_TO_SG | SG_MITER_ATOMIC); + + local_irq_save(flags); + while (sg_miter_next(&miter)) { + unsigned int offset = 0; + + if (bytes == 0) { + char *hdr; + u32 list_length; + u64 max_lba, opt_lba; + u16 same; + + /* Swizzle header */ + hdr = miter.addr; + list_length = get_unaligned_le32(&hdr[0]); + same = get_unaligned_le16(&hdr[4]); + max_lba = get_unaligned_le64(&hdr[8]); + opt_lba = get_unaligned_le64(&hdr[16]); + put_unaligned_be32(list_length, &hdr[0]); + hdr[4] = same & 0xf; + put_unaligned_be64(max_lba, &hdr[8]); + put_unaligned_be64(opt_lba, &hdr[16]); + offset += 64; + bytes += 64; + } + while (offset < miter.length) { + char *rec; + u16 option; + u8 cond, type, reset; + u64 size, start, wp, checkpoint; + + /* Swizzle zone descriptor */ + rec = miter.addr + offset; + option = get_unaligned_le16(&rec[0]); + cond = (option >> 4) & 0xf; + type = (option >> 8) & 0xf; + reset = (option & 1); + size = get_unaligned_le64(&rec[8]); + start = get_unaligned_le64(&rec[16]); + wp = get_unaligned_le64(&rec[24]); + checkpoint = get_unaligned_le64(&rec[32]); + put_unaligned_be64(size, &rec[8]); + put_unaligned_be64(start, &rec[16]); + put_unaligned_be64(wp, &rec[24]); + put_unaligned_be64(checkpoint, &rec[32]); + WARN_ON(offset + 64 > miter.length); + offset += 64; + bytes += 64; + } + } + sg_miter_stop(&miter); + local_irq_restore(flags); + + ata_scsi_qc_complete(qc); +} + +/** + * 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); + + qc->complete_fn = ata_scsi_report_zones_complete; + + 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_translate - Translate then issue SCSI command to ATA device * @dev: ATA device to which the command is addressed diff --git a/include/trace/events/libata.h b/include/trace/events/libata.h index 8b0fbd9..157ca7b 100644 --- a/include/trace/events/libata.h +++ b/include/trace/events/libata.h @@ -97,6 +97,8 @@ ata_opcode_name(ATA_CMD_CFA_WRITE_MULT_NE), \ ata_opcode_name(ATA_CMD_REQ_SENSE_DATA), \ ata_opcode_name(ATA_CMD_SANITIZE_DEVICE), \ + ata_opcode_name(ATA_CMD_ZONE_MAN_IN), \ + ata_opcode_name(ATA_CMD_ZONE_MAN_OUT), \ ata_opcode_name(ATA_CMD_RESTORE), \ ata_opcode_name(ATA_CMD_READ_LONG), \ ata_opcode_name(ATA_CMD_READ_LONG_ONCE), \