From patchwork Thu Dec 8 10:59:17 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 632160 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C49DDC63709 for ; Thu, 8 Dec 2022 11:03:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229735AbiLHLDT (ORCPT ); Thu, 8 Dec 2022 06:03:19 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35210 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229895AbiLHLBt (ORCPT ); Thu, 8 Dec 2022 06:01:49 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 62875F32; Thu, 8 Dec 2022 03:00:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497245; x=1702033245; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=eZzNmPx8xLJS/2iCoWEwaDCKY/FsQzz0UuowB8TiF74=; b=JKhRm+SXQqHlZNWwYzbr+pkWxh2asF6YtvDjEb1zRH6xNGx7bDomwVd0 URD9BmWN2GuxLQz5J2obvxR6N1wgUiGlyiDg/Pltzb4fDQUcMtwuO3+HG 9Pcw4Gs7/8F+XvTOMqGlgImkDYe0fZX5KhhMZ2hHjJcf+PDQUqXgGOM+G gLnj+Sa7/A0cf/tFRFK4YpDjTkN8lHtTFgWqtt0JLxTimhTSeLYZcZBbz W38vl6l/+ZDDUh1cGcSLGrNdMfHbQ7xHcl51UlEpUtieE8OmeHyvxQwww 5Gjq42N5ulQ2sG927lWdw7yRssgDjZxsJPfIhZ4d0Fl/f5jYGytGAJC7i Q==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333349" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:00:45 +0800 IronPort-SDR: qFwo6cZ6GJfMJ97dlHioH79ZwAJiIC/Nh7akgWWekHAuNIxxr6/X3jca8G2jr2YpX9NBI+aZ4b 375hcfHPTcoct1QiJULr0rThoAh4zqIkBk2Uc7NQ4/gtN1FltimlxtiMs1aibaaHzy0APQiOvv FTpum78j16D8AbbEBcQXJEUSNCwJ6Hlyz8CpI30VHlFJxoyhWDfnNOIS7wycTnyTke01nBaKUI ZegBQ/h+KGw7ZmuzomgV5ghkYhqnyuhBAcDk/oUtm6D+Hz+9Rfj16hmZuPWdGnqPbqKgRU0HZT j6c= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:13:30 -0800 IronPort-SDR: wtxiLUnrhNe1bjU6u31uZnMTChrS3DF2jbY1CDKrquhPyG9oT9jHE++Hj7OlqzdbqxyABipRH3 bF5e5L9mkVoUPN5VDqki7Px/+5fPqGLQSHKMtn3hMVc8/fdX8ZDHLGVwLa52MO+PvCla0xQRuL sFhI+8RzwY2E6dwB+oyo2Q4tqsWRX+EkhSn8kOxaRqrp5N9LX2lkDXMJAfp2Tvl8ZwCpllRLDt U34C0r6OkWRxWjq+zSYbMFQXA5UEponxyuWLQF4aB3oGgaXz6W7Jkes/ibdnw9Ktu7oeo10j8C HiM= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:00:43 -0800 From: Niklas Cassel To: Damien Le Moal , Mikael Pettersson , Brian King , "James E.J. Bottomley" , "Martin K. Petersen" Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Niklas Cassel , linux-ide@vger.kernel.org Subject: [PATCH 01/25] ata: scsi: rename flag ATA_QCFLAG_FAILED to ATA_QCFLAG_EH Date: Thu, 8 Dec 2022 11:59:17 +0100 Message-Id: <20221208105947.2399894-2-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org The name ATA_QCFLAG_FAILED is misleading since it does not mean that a QC was actually an error. It means that libata decided to schedule EH for the QC, so the QC is now owned by the libata error handler (EH). The normal execution path is responsible for not accessing a QC owned by EH. libata core enforces the rule by returning NULL from ata_qc_from_tag() for QCs owned by EH. It is quite easy to mistake that a QC marked with ATA_QCFLAG_FAILED was an error. However, a QC that was actually an error is instead indicated by having qc->err_mask set. E.g. when we have a NCQ error, we abort all QCs, which currently will mark all QCs as ATA_QCFLAG_FAILED. However, it will only be a single QC that is an error (i.e. has qc->err_mask set). Rename ATA_QCFLAG_FAILED to ATA_QCFLAG_EH to more clearly highlight that this flag simply means that a QC is now owned by EH. This new name will not mislead to think that the QC was an error (which is instead indicated by having qc->err_mask set). This also makes it more obvious that the EH code skips all QCs that do not have ATA_QCFLAG_EH set (rather than ATA_QCFLAG_FAILED), since the EH code should simply only care about QCs that are owned by EH itself. Signed-off-by: Niklas Cassel Reviewed-by: John Garry --- drivers/ata/acard-ahci.c | 2 +- drivers/ata/libahci.c | 4 ++-- drivers/ata/libata-core.c | 12 ++++++------ drivers/ata/libata-eh.c | 22 +++++++++++----------- drivers/ata/libata-sata.c | 4 ++-- drivers/ata/libata-sff.c | 4 ++-- drivers/ata/libata-trace.c | 2 +- drivers/ata/sata_fsl.c | 2 +- drivers/ata/sata_inic162x.c | 2 +- drivers/ata/sata_promise.c | 2 +- drivers/ata/sata_sil24.c | 2 +- drivers/ata/sata_sx4.c | 2 +- drivers/scsi/ipr.c | 4 ++-- drivers/scsi/libsas/sas_ata.c | 8 ++++---- include/linux/libata.h | 4 ++-- 15 files changed, 38 insertions(+), 38 deletions(-) diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c index 7654a40c12b4..da74a86b70ba 100644 --- a/drivers/ata/acard-ahci.c +++ b/drivers/ata/acard-ahci.c @@ -263,7 +263,7 @@ static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc) * Setup FIS. */ if (qc->tf.protocol == ATA_PROT_PIO && qc->dma_dir == DMA_FROM_DEVICE && - !(qc->flags & ATA_QCFLAG_FAILED)) { + !(qc->flags & ATA_QCFLAG_EH)) { ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf); qc->result_tf.status = (rx_fis + RX_FIS_PIO_SETUP)[15]; } else diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 29acc35bf4a6..03aa9eb415d3 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -2068,7 +2068,7 @@ static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc) * Setup FIS. */ if (qc->tf.protocol == ATA_PROT_PIO && qc->dma_dir == DMA_FROM_DEVICE && - !(qc->flags & ATA_QCFLAG_FAILED)) { + !(qc->flags & ATA_QCFLAG_EH)) { ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf); qc->result_tf.status = (rx_fis + RX_FIS_PIO_SETUP)[15]; @@ -2138,7 +2138,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; /* make DMA engine forget about the failed command */ - if (qc->flags & ATA_QCFLAG_FAILED) + if (qc->flags & ATA_QCFLAG_EH) ahci_kick_engine(ap); } diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 884ae73b11ea..6b03bebcde50 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1590,7 +1590,7 @@ static unsigned ata_exec_internal_sg(struct ata_device *dev, ap->ops->post_internal_cmd(qc); /* perform minimal error analysis */ - if (qc->flags & ATA_QCFLAG_FAILED) { + if (qc->flags & ATA_QCFLAG_EH) { if (qc->result_tf.status & (ATA_ERR | ATA_DF)) qc->err_mask |= AC_ERR_DEV; @@ -4683,10 +4683,10 @@ void ata_qc_complete(struct ata_queued_cmd *qc) /* XXX: New EH and old EH use different mechanisms to * synchronize EH with regular execution path. * - * In new EH, a failed qc is marked with ATA_QCFLAG_FAILED. + * In new EH, a qc owned by EH is marked with ATA_QCFLAG_EH. * Normal execution path is responsible for not accessing a - * failed qc. libata core enforces the rule by returning NULL - * from ata_qc_from_tag() for failed qcs. + * qc owned by EH. libata core enforces the rule by returning NULL + * from ata_qc_from_tag() for qcs owned by EH. * * Old EH depends on ata_qc_complete() nullifying completion * requests if ATA_QCFLAG_EH_SCHEDULED is set. Old EH does @@ -4698,7 +4698,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc) struct ata_eh_info *ehi = &dev->link->eh_info; if (unlikely(qc->err_mask)) - qc->flags |= ATA_QCFLAG_FAILED; + qc->flags |= ATA_QCFLAG_EH; /* * Finish internal commands without any further processing @@ -4715,7 +4715,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc) * Non-internal qc has failed. Fill the result TF and * summon EH. */ - if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) { + if (unlikely(qc->flags & ATA_QCFLAG_EH)) { fill_result_tf(qc); trace_ata_qc_complete_failed(qc); ata_qc_schedule_eh(qc); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 34303ce67c14..8cb250930c48 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -575,7 +575,7 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, * normal completion, error completion, and SCSI timeout. * Both completions can race against SCSI timeout. When normal * completion wins, the qc never reaches EH. When error - * completion wins, the qc has ATA_QCFLAG_FAILED set. + * completion wins, the qc has ATA_QCFLAG_EH set. * * When SCSI timeout wins, things are a bit more complex. * Normal or error completion can occur after the timeout but @@ -611,10 +611,10 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, if (i < ATA_MAX_QUEUE) { /* the scmd has an associated qc */ - if (!(qc->flags & ATA_QCFLAG_FAILED)) { + if (!(qc->flags & ATA_QCFLAG_EH)) { /* which hasn't failed yet, timeout */ qc->err_mask |= AC_ERR_TIMEOUT; - qc->flags |= ATA_QCFLAG_FAILED; + qc->flags |= ATA_QCFLAG_EH; nr_timedout++; } } else { @@ -631,7 +631,7 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, * this point but the state of the controller is * unknown. Freeze the port to make sure the IRQ * handler doesn't diddle with those qcs. This must - * be done atomically w.r.t. setting QCFLAG_FAILED. + * be done atomically w.r.t. setting ATA_QCFLAG_EH. */ if (nr_timedout) __ata_port_freeze(ap); @@ -911,12 +911,12 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc) WARN_ON(!ap->ops->error_handler); - qc->flags |= ATA_QCFLAG_FAILED; + qc->flags |= ATA_QCFLAG_EH; ata_eh_set_pending(ap, 1); /* The following will fail if timeout has already expired. * ata_scsi_error() takes care of such scmds on EH entry. - * Note that ATA_QCFLAG_FAILED is unconditionally set after + * Note that ATA_QCFLAG_EH is unconditionally set after * this function completes. */ blk_abort_request(scsi_cmd_to_rq(qc->scsicmd)); @@ -994,7 +994,7 @@ static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link) /* include internal tag in iteration */ ata_qc_for_each_with_internal(ap, qc, tag) { if (qc && (!link || qc->dev->link == link)) { - qc->flags |= ATA_QCFLAG_FAILED; + qc->flags |= ATA_QCFLAG_EH; ata_qc_complete(qc); nr_aborted++; } @@ -1954,7 +1954,7 @@ static void ata_eh_link_autopsy(struct ata_link *link) all_err_mask |= ehc->i.err_mask; ata_qc_for_each_raw(ap, qc, tag) { - if (!(qc->flags & ATA_QCFLAG_FAILED) || + if (!(qc->flags & ATA_QCFLAG_EH) || qc->flags & ATA_QCFLAG_RETRY || ata_dev_phys_link(qc->dev) != link) continue; @@ -2232,7 +2232,7 @@ static void ata_eh_link_report(struct ata_link *link) desc = ehc->i.desc; ata_qc_for_each_raw(ap, qc, tag) { - if (!(qc->flags & ATA_QCFLAG_FAILED) || + if (!(qc->flags & ATA_QCFLAG_EH) || ata_dev_phys_link(qc->dev) != link || ((qc->flags & ATA_QCFLAG_QUIET) && qc->err_mask == AC_ERR_DEV)) @@ -2298,7 +2298,7 @@ static void ata_eh_link_report(struct ata_link *link) char data_buf[20] = ""; char cdb_buf[70] = ""; - if (!(qc->flags & ATA_QCFLAG_FAILED) || + if (!(qc->flags & ATA_QCFLAG_EH) || ata_dev_phys_link(qc->dev) != link || !qc->err_mask) continue; @@ -3802,7 +3802,7 @@ void ata_eh_finish(struct ata_port *ap) /* retry or finish qcs */ ata_qc_for_each_raw(ap, qc, tag) { - if (!(qc->flags & ATA_QCFLAG_FAILED)) + if (!(qc->flags & ATA_QCFLAG_EH)) continue; if (qc->err_mask) { diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index 18ef14e749a0..908f35acee1e 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -1429,7 +1429,7 @@ void ata_eh_analyze_ncq_error(struct ata_link *link) /* has LLDD analyzed already? */ ata_qc_for_each_raw(ap, qc, tag) { - if (!(qc->flags & ATA_QCFLAG_FAILED)) + if (!(qc->flags & ATA_QCFLAG_EH)) continue; if (qc->err_mask) @@ -1477,7 +1477,7 @@ void ata_eh_analyze_ncq_error(struct ata_link *link) } ata_qc_for_each_raw(ap, qc, tag) { - if (!(qc->flags & ATA_QCFLAG_FAILED) || + if (!(qc->flags & ATA_QCFLAG_EH) || ata_dev_phys_link(qc->dev) != link) continue; diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 153f49e00713..34beda28e712 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -2073,7 +2073,7 @@ void ata_sff_error_handler(struct ata_port *ap) unsigned long flags; qc = __ata_qc_from_tag(ap, ap->link.active_tag); - if (qc && !(qc->flags & ATA_QCFLAG_FAILED)) + if (qc && !(qc->flags & ATA_QCFLAG_EH)) qc = NULL; spin_lock_irqsave(ap->lock, flags); @@ -2796,7 +2796,7 @@ void ata_bmdma_error_handler(struct ata_port *ap) bool thaw = false; qc = __ata_qc_from_tag(ap, ap->link.active_tag); - if (qc && !(qc->flags & ATA_QCFLAG_FAILED)) + if (qc && !(qc->flags & ATA_QCFLAG_EH)) qc = NULL; /* reset PIO HSM and stop DMA engine */ diff --git a/drivers/ata/libata-trace.c b/drivers/ata/libata-trace.c index e0e4d0d5a100..9b5363fd0ab0 100644 --- a/drivers/ata/libata-trace.c +++ b/drivers/ata/libata-trace.c @@ -142,7 +142,7 @@ libata_trace_parse_qc_flags(struct trace_seq *p, unsigned int qc_flags) trace_seq_printf(p, "QUIET "); if (qc_flags & ATA_QCFLAG_RETRY) trace_seq_printf(p, "RETRY "); - if (qc_flags & ATA_QCFLAG_FAILED) + if (qc_flags & ATA_QCFLAG_EH) trace_seq_printf(p, "FAILED "); if (qc_flags & ATA_QCFLAG_SENSE_VALID) trace_seq_printf(p, "SENSE_VALID "); diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index b9a4f68b371d..7eab9c4e1473 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -1042,7 +1042,7 @@ static void sata_fsl_error_handler(struct ata_port *ap) static void sata_fsl_post_internal_cmd(struct ata_queued_cmd *qc) { - if (qc->flags & ATA_QCFLAG_FAILED) + if (qc->flags & ATA_QCFLAG_EH) qc->err_mask |= AC_ERR_OTHER; if (qc->err_mask) { diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 11e518f0111c..f480ff456190 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -672,7 +672,7 @@ static void inic_error_handler(struct ata_port *ap) static void inic_post_internal_cmd(struct ata_queued_cmd *qc) { /* make DMA engine forget about the failed command */ - if (qc->flags & ATA_QCFLAG_FAILED) + if (qc->flags & ATA_QCFLAG_EH) inic_reset_port(inic_port_base(qc->ap)); } diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 9cd7d8b71361..4e60e6c4c35a 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -828,7 +828,7 @@ static void pdc_post_internal_cmd(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; /* make DMA engine forget about the failed command */ - if (qc->flags & ATA_QCFLAG_FAILED) + if (qc->flags & ATA_QCFLAG_EH) pdc_reset_port(ap); } diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 2fef6ce93f07..0a01518a8d97 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -1185,7 +1185,7 @@ static void sil24_post_internal_cmd(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; /* make DMA engine forget about the failed command */ - if ((qc->flags & ATA_QCFLAG_FAILED) && sil24_init_port(ap)) + if ((qc->flags & ATA_QCFLAG_EH) && sil24_init_port(ap)) ata_eh_freeze_port(ap); } diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index ab70cbc78f96..a92c60455b1d 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -866,7 +866,7 @@ static void pdc_post_internal_cmd(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; /* make DMA engine forget about the failed command */ - if (qc->flags & ATA_QCFLAG_FAILED) + if (qc->flags & ATA_QCFLAG_EH) pdc_reset_port(ap); } diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 2022ffb45041..c68ca2218a05 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -5370,9 +5370,9 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd) continue; ipr_cmd->done = ipr_sata_eh_done; - if (!(ipr_cmd->qc->flags & ATA_QCFLAG_FAILED)) { + if (!(ipr_cmd->qc->flags & ATA_QCFLAG_EH)) { ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT; - ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED; + ipr_cmd->qc->flags |= ATA_QCFLAG_EH; } } } diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 1ccce706167a..14da33a3b6a6 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -125,7 +125,7 @@ static void sas_ata_task_done(struct sas_task *task) } else { link->eh_info.err_mask |= ac_err_mask(dev->sata_dev.fis[2]); if (unlikely(link->eh_info.err_mask)) - qc->flags |= ATA_QCFLAG_FAILED; + qc->flags |= ATA_QCFLAG_EH; } } else { ac = sas_to_ata_err(stat); @@ -136,7 +136,7 @@ static void sas_ata_task_done(struct sas_task *task) qc->err_mask = ac; } else { link->eh_info.err_mask |= AC_ERR_DEV; - qc->flags |= ATA_QCFLAG_FAILED; + qc->flags |= ATA_QCFLAG_EH; } dev->sata_dev.fis[2] = ATA_ERR | ATA_DRDY; /* tf status */ @@ -476,7 +476,7 @@ static void sas_ata_internal_abort(struct sas_task *task) static void sas_ata_post_internal(struct ata_queued_cmd *qc) { - if (qc->flags & ATA_QCFLAG_FAILED) + if (qc->flags & ATA_QCFLAG_EH) qc->err_mask |= AC_ERR_OTHER; if (qc->err_mask) { @@ -631,7 +631,7 @@ void sas_ata_task_abort(struct sas_task *task) /* Internal command, fake a timeout and complete. */ qc->flags &= ~ATA_QCFLAG_ACTIVE; - qc->flags |= ATA_QCFLAG_FAILED; + qc->flags |= ATA_QCFLAG_EH; qc->err_mask |= AC_ERR_TIMEOUT; waiting = qc->private_data; complete(waiting); diff --git a/include/linux/libata.h b/include/linux/libata.h index c9149ebe7423..7985e6e2ae0e 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -206,7 +206,7 @@ enum { ATA_QCFLAG_QUIET = (1 << 6), /* don't report device error */ ATA_QCFLAG_RETRY = (1 << 7), /* retry after failure */ - ATA_QCFLAG_FAILED = (1 << 16), /* cmd failed and is owned by EH */ + ATA_QCFLAG_EH = (1 << 16), /* cmd aborted and owned by EH */ ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */ ATA_QCFLAG_EH_SCHEDULED = (1 << 18), /* EH scheduled (obsolete) */ @@ -1756,7 +1756,7 @@ static inline struct ata_queued_cmd *ata_qc_from_tag(struct ata_port *ap, return qc; if ((qc->flags & (ATA_QCFLAG_ACTIVE | - ATA_QCFLAG_FAILED)) == ATA_QCFLAG_ACTIVE) + ATA_QCFLAG_EH)) == ATA_QCFLAG_ACTIVE) return qc; return NULL; From patchwork Thu Dec 8 10:59:18 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 633203 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9DFF0C63705 for ; Thu, 8 Dec 2022 11:03:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229558AbiLHLDQ (ORCPT ); Thu, 8 Dec 2022 06:03:16 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36960 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229893AbiLHLBt (ORCPT ); Thu, 8 Dec 2022 06:01:49 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7B4E5E20; Thu, 8 Dec 2022 03:00:47 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497247; x=1702033247; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=+2rcDb8R1vimSMhPpbJUZYO/DgWj/NmRG1DqkpYlr00=; b=TIal/gE+fTlBcW5PmyonxBcwt8aFPXL8oizijh3bLKsu198kGwSMqNpN /38WY1ZG56Y6I+IfYMb69h6dVmigrJU6woBBp6uAB9u/bEkVPzajmX/mb NeDzezpmmSt7jBeraACghDFTL1WmC0yDavM3aY4nnF2vsRpZ01Q90UQr3 z3PtYhggDvqShXaEOJoAYhsb4gtnNrqbVp+Ph7TjXnFP8/7XUtIIxxeAN smfCWu056TNFp0uWBOYIJqCpGLzyryKvkWixyPDf7AAxI5xAvyX5xcIHC lJLjqFpHfFGh49lcOMDtJYG3VJBZFwAgu/3e1giKiFLB8iazcDmrq9j09 g==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333352" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:00:47 +0800 IronPort-SDR: T773sZgtEEhsp4Yb53XJ9LUFMp0eYTVhXugqinH9jw9LxFLzl59pszY3Z6lIhzg81o4BOPIZQm PxmfAc8Zy7kd2yBw8/RK0kvK36Y+aP4h6bR71Coy2TTQ/QyLej8Dv009tLO5OU/Q59B46sPBD7 GwFTyNa31g9EFvRKJuCXS57riLIRzkHw7AQXxUj46ICSABll0wNu2n9vh4yAZ2Sf5BbopGceBX jbywvIb0J99HxDeNwiRbYWp8njqiMj4+6DC55tYINreyH8Mw+aq2nCuPq1a4fUFLdg0M2N8Nhr 2Is= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:13:32 -0800 IronPort-SDR: rwn0kGQ91q2YomI1osM1ApYS7FakkOpg4HS2A6YjuYcvEl7cU49TidaBe5n0CzoGbx/RHARXUy l+s9fRDrm9s4INy2A8WTOECC00elkgpqMQCNx/AgIadN0FzI/wPq7iQ4luNZpjZjk7l6DncNJE XZV7Z/9vC//MUTZbHwQy6Jme9AZSFI72NUvNePYhhTnIzO0QIaHG8vidWsWcl3v33E2UvbGfEk PxyeIqYjsIs91oUvVkUJgE4H63whxLn+foPMgNGxYHK7m6n41npmw3CdsmiVNNNK/qtc+3o0YB rs0= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:00:46 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Niklas Cassel , linux-ide@vger.kernel.org Subject: [PATCH 02/25] ata: libata: move NCQ related ATA_DFLAGs Date: Thu, 8 Dec 2022 11:59:18 +0100 Message-Id: <20221208105947.2399894-3-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org ata_dev_configure() starts off by clearing all flags in ATA_DFLAG_CFG_MASK: dev->flags &= ~ATA_DFLAG_CFG_MASK; ata_dev_configure() then calls ata_dev_config_lba() which calls ata_dev_config_ncq(). ata_dev_config_ncq() will set the correct ATA_DFLAGs depending on what is actually supported. Since these flags are set by ata_dev_configure(), they should be in ATA_DFLAG_CFG_MASK and not in ATA_DFLAG_INIT_MASK. ATA_DFLAG_NCQ_PRIO_ENABLED is set via sysfs, is should therefore not be in ATA_DFLAG_CFG_MASK. It also cannot be in ATA_DFLAG_INIT_MASK, because ata_eh_schedule_probe() calls ata_dev_init(), which will clear all flags in ATA_DFLAG_INIT_MASK. This means that ATA_DFLAG_NCQ_PRIO_ENABLED (the value the user sets via sysfs) would get silently cleared if ata_eh_schedule_probe() is called. While that should only happen in certain circumstances, it still doesn't seem right that it can get silently cleared. (ata_dev_config_ncq_prio() will still clear the ATA_DFLAG_NCQ_PRIO_ENABLED flag if ATA_DFLAG_NCQ_PRIO is suddenly no longer supported after a revalidation.) Because of this, move ATA_DFLAG_NCQ_PRIO_ENABLED to be outside of both ATA_DFLAG_CFG_MASK and ATA_DFLAG_INIT_MASK. Signed-off-by: Niklas Cassel --- include/linux/libata.h | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/include/linux/libata.h b/include/linux/libata.h index 7985e6e2ae0e..9bba56f6d793 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -91,22 +91,21 @@ enum { ATA_DFLAG_AN = (1 << 7), /* AN configured */ ATA_DFLAG_TRUSTED = (1 << 8), /* device supports trusted send/recv */ ATA_DFLAG_DMADIR = (1 << 10), /* device requires DMADIR */ - ATA_DFLAG_CFG_MASK = (1 << 12) - 1, + ATA_DFLAG_NCQ_SEND_RECV = (1 << 11), /* device supports NCQ SEND and RECV */ + ATA_DFLAG_NCQ_PRIO = (1 << 12), /* device supports NCQ priority */ + ATA_DFLAG_CFG_MASK = (1 << 13) - 1, - ATA_DFLAG_PIO = (1 << 12), /* device limited to PIO mode */ - ATA_DFLAG_NCQ_OFF = (1 << 13), /* device limited to non-NCQ mode */ + ATA_DFLAG_PIO = (1 << 13), /* device limited to PIO mode */ + ATA_DFLAG_NCQ_OFF = (1 << 14), /* device limited to non-NCQ mode */ ATA_DFLAG_SLEEPING = (1 << 15), /* device is sleeping */ ATA_DFLAG_DUBIOUS_XFER = (1 << 16), /* data transfer not verified */ ATA_DFLAG_NO_UNLOAD = (1 << 17), /* device doesn't support unload */ ATA_DFLAG_UNLOCK_HPA = (1 << 18), /* unlock HPA */ - ATA_DFLAG_NCQ_SEND_RECV = (1 << 19), /* device supports NCQ SEND and RECV */ - ATA_DFLAG_NCQ_PRIO = (1 << 20), /* device supports NCQ priority */ - ATA_DFLAG_NCQ_PRIO_ENABLED = (1 << 21), /* Priority cmds sent to dev */ - ATA_DFLAG_INIT_MASK = (1 << 24) - 1, + ATA_DFLAG_INIT_MASK = (1 << 19) - 1, + ATA_DFLAG_NCQ_PRIO_ENABLED = (1 << 19), /* Priority cmds sent to dev */ ATA_DFLAG_DETACH = (1 << 24), ATA_DFLAG_DETACHED = (1 << 25), - ATA_DFLAG_DA = (1 << 26), /* device supports Device Attention */ ATA_DFLAG_DEVSLP = (1 << 27), /* device supports Device Sleep */ ATA_DFLAG_ACPI_DISABLED = (1 << 28), /* ACPI for the device is disabled */ From patchwork Thu Dec 8 10:59:19 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 633201 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7D923C63717 for ; Thu, 8 Dec 2022 11:03:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229849AbiLHLDY (ORCPT ); Thu, 8 Dec 2022 06:03:24 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37008 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229974AbiLHLBv (ORCPT ); Thu, 8 Dec 2022 06:01:51 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0136B2DF5; Thu, 8 Dec 2022 03:00:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497250; x=1702033250; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=CXuEWj0t/+ca3pvx1+1tsUFw9Iuhj3X2dmAEjeH/lf8=; b=Bgkwlislhi4jOY2oO7Y1TeFZydYW3yVhhXwo9FxkhLckiDmCF8NGRhjA JJH07xKBXkOREWxHjAnMyVXQfAQJ9srZELHKCjLayhA0zjTzlqSHDhQl4 PvhZhPBapCYjzK/P1A5Ex1koBlz2ebkNDi2dOcsSKBrc6J8CwY2KeExdV EdeOYSA15Dwtih0WUTUn3xW68tWbuk17SdtBZAUsho7dam3DUIsEJqITW tUJvkKojzhbZOmWXmDGJG0cvqkpvBHrYFrRyLZE4VpWavy/FnAlTL65/9 l3vMiCvpCJ1JJfnmbEVbuSo9MoQEfUfZxtNgnY32VfRuW8TLvgRo7Pd1y A==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333361" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:00:50 +0800 IronPort-SDR: 51X5N8qzsqwC5spxG2KPdcYKgzz+Ov5oegSyz1uO+ZmlgisIiy9QEPcgYk2zMwNj4yX9EdUAtN GmycmZsme4QRdlHaxR7h/aJo6oM/5ayww659qbZuH9dcMk0NNMI131MYpvYn/OlAZblmgShHCJ AmKD//EDXhuLKCvR+SoX5Rsz8GjsPsTuE4NEff6Fi18/YR52u1od409LEn9gGhw2Mm4zvTYiMd iUen2EPd1YpXEmNjQYsoU1t9Z2BWFWqzCHagjE1WpHo1lkxMyG3bwaJEPY/qZsClV1oAUF3d27 R24= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:13:35 -0800 IronPort-SDR: lfbXW6zSWPzlYqJPzaYIKkzUpp+umrsrxkqeYpG3R8q6VH7dMS2Env6TKo3Us+vQ1eOlY6fn/g pgDhxX+NL9L1Ew/m1OUj9nK516TgxEZwfWPtno8mJT5pJJJT+ZiYJZxXImT2XGLkJZIBUGByKj zZjCn/B84zwF2JfeNNRzoRVJWQDzSsc/NKumaXNmLM26XRXFIG6olmTLjHu43WSv4W5mUsdOo5 TSA0VaNE23FmhSYXem88OTvprRZgMCWPnznDtkSsvU8cMNBdQHpI8ZN8rQSJX0lXoULubQ9Kql Buk= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:00:49 -0800 From: Niklas Cassel To: Damien Le Moal , Brian King , "James E.J. Bottomley" , "Martin K. Petersen" Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org Subject: [PATCH 03/25] ata: libata: simplify qc_fill_rtf port operation interface Date: Thu, 8 Dec 2022 11:59:19 +0100 Message-Id: <20221208105947.2399894-4-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org From: Damien Le Moal The boolean return value of the qc_fill_rtf operation is used nowhere. Simplify this operation interface by making it a void function. All drivers defining this operation are also updated. Signed-off-by: Damien Le Moal Reviewed-by: John Garry --- drivers/ata/acard-ahci.c | 6 ++---- drivers/ata/libahci.c | 6 ++---- drivers/ata/libata-sff.c | 6 +----- drivers/ata/sata_fsl.c | 3 +-- drivers/ata/sata_inic162x.c | 12 +++++------- drivers/ata/sata_sil24.c | 5 ++--- drivers/scsi/ipr.c | 7 +------ drivers/scsi/libsas/sas_ata.c | 3 +-- include/linux/libata.h | 4 ++-- 9 files changed, 17 insertions(+), 35 deletions(-) diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c index da74a86b70ba..993eadd173da 100644 --- a/drivers/ata/acard-ahci.c +++ b/drivers/ata/acard-ahci.c @@ -57,7 +57,7 @@ struct acard_sg { }; static enum ata_completion_errors acard_ahci_qc_prep(struct ata_queued_cmd *qc); -static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc); +static void acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc); static int acard_ahci_port_start(struct ata_port *ap); static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); @@ -248,7 +248,7 @@ static enum ata_completion_errors acard_ahci_qc_prep(struct ata_queued_cmd *qc) return AC_ERR_OK; } -static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc) +static void acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc) { struct ahci_port_priv *pp = qc->ap->private_data; u8 *rx_fis = pp->rx_fis; @@ -268,8 +268,6 @@ static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc) qc->result_tf.status = (rx_fis + RX_FIS_PIO_SETUP)[15]; } else ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf); - - return true; } static int acard_ahci_port_start(struct ata_port *ap) diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 03aa9eb415d3..0167aac25c34 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -55,7 +55,7 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state, static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); -static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc); +static void ahci_qc_fill_rtf(struct ata_queued_cmd *qc); static int ahci_port_start(struct ata_port *ap); static void ahci_port_stop(struct ata_port *ap); static enum ata_completion_errors ahci_qc_prep(struct ata_queued_cmd *qc); @@ -2053,7 +2053,7 @@ unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) } EXPORT_SYMBOL_GPL(ahci_qc_issue); -static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc) +static void ahci_qc_fill_rtf(struct ata_queued_cmd *qc) { struct ahci_port_priv *pp = qc->ap->private_data; u8 *rx_fis = pp->rx_fis; @@ -2087,8 +2087,6 @@ static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc) qc->result_tf.error = fis[3]; } else ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf); - - return true; } static void ahci_freeze(struct ata_port *ap) diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 34beda28e712..cd82d3b5ed14 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -1377,14 +1377,10 @@ EXPORT_SYMBOL_GPL(ata_sff_qc_issue); * * LOCKING: * spin_lock_irqsave(host lock) - * - * RETURNS: - * true indicating that result TF is successfully filled. */ -bool ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc) +void ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc) { qc->ap->ops->sff_tf_read(qc->ap, &qc->result_tf); - return true; } EXPORT_SYMBOL_GPL(ata_sff_qc_fill_rtf); diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 7eab9c4e1473..b052c5a65c17 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -566,7 +566,7 @@ static unsigned int sata_fsl_qc_issue(struct ata_queued_cmd *qc) return 0; } -static bool sata_fsl_qc_fill_rtf(struct ata_queued_cmd *qc) +static void sata_fsl_qc_fill_rtf(struct ata_queued_cmd *qc) { struct sata_fsl_port_priv *pp = qc->ap->private_data; struct sata_fsl_host_priv *host_priv = qc->ap->host->private_data; @@ -577,7 +577,6 @@ static bool sata_fsl_qc_fill_rtf(struct ata_queued_cmd *qc) cd = pp->cmdentry + tag; ata_tf_from_fis(cd->sfis, &qc->result_tf); - return true; } static int sata_fsl_scr_write(struct ata_link *link, diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index f480ff456190..2833c722118d 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -566,7 +566,7 @@ static void inic_tf_read(struct ata_port *ap, struct ata_taskfile *tf) tf->status = readb(port_base + PORT_TF_COMMAND); } -static bool inic_qc_fill_rtf(struct ata_queued_cmd *qc) +static void inic_qc_fill_rtf(struct ata_queued_cmd *qc) { struct ata_taskfile *rtf = &qc->result_tf; struct ata_taskfile tf; @@ -580,12 +580,10 @@ static bool inic_qc_fill_rtf(struct ata_queued_cmd *qc) */ inic_tf_read(qc->ap, &tf); - if (!(tf.status & ATA_ERR)) - return false; - - rtf->status = tf.status; - rtf->error = tf.error; - return true; + if (tf.status & ATA_ERR) { + rtf->status = tf.status; + rtf->error = tf.error; + } } static void inic_freeze(struct ata_port *ap) diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 0a01518a8d97..22cc9e9789dd 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -328,7 +328,7 @@ static int sil24_scr_write(struct ata_link *link, unsigned sc_reg, u32 val); static int sil24_qc_defer(struct ata_queued_cmd *qc); static enum ata_completion_errors sil24_qc_prep(struct ata_queued_cmd *qc); static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc); -static bool sil24_qc_fill_rtf(struct ata_queued_cmd *qc); +static void sil24_qc_fill_rtf(struct ata_queued_cmd *qc); static void sil24_pmp_attach(struct ata_port *ap); static void sil24_pmp_detach(struct ata_port *ap); static void sil24_freeze(struct ata_port *ap); @@ -901,10 +901,9 @@ static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc) return 0; } -static bool sil24_qc_fill_rtf(struct ata_queued_cmd *qc) +static void sil24_qc_fill_rtf(struct ata_queued_cmd *qc) { sil24_read_tf(qc->ap, qc->hw_tag, &qc->result_tf); - return true; } static void sil24_pmp_attach(struct ata_port *ap) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index c68ca2218a05..1c8040d250ea 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -7142,11 +7142,8 @@ static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc) /** * ipr_qc_fill_rtf - Read result TF * @qc: ATA queued command - * - * Return value: - * true **/ -static bool ipr_qc_fill_rtf(struct ata_queued_cmd *qc) +static void ipr_qc_fill_rtf(struct ata_queued_cmd *qc) { struct ipr_sata_port *sata_port = qc->ap->private_data; struct ipr_ioasa_gata *g = &sata_port->ioasa; @@ -7163,8 +7160,6 @@ static bool ipr_qc_fill_rtf(struct ata_queued_cmd *qc) tf->hob_lbal = g->hob_lbal; tf->hob_lbam = g->hob_lbam; tf->hob_lbah = g->hob_lbah; - - return true; } static struct ata_port_operations ipr_sata_ops = { diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 14da33a3b6a6..ac8576e7f0b7 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -226,12 +226,11 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) return ret; } -static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc) +static void sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc) { struct domain_device *dev = qc->ap->private_data; ata_tf_from_fis(dev->sata_dev.fis, &qc->result_tf); - return true; } static struct sas_internal *dev_to_sas_internal(struct domain_device *dev) diff --git a/include/linux/libata.h b/include/linux/libata.h index 9bba56f6d793..31f4eaf515e1 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -875,7 +875,7 @@ struct ata_port_operations { int (*check_atapi_dma)(struct ata_queued_cmd *qc); enum ata_completion_errors (*qc_prep)(struct ata_queued_cmd *qc); unsigned int (*qc_issue)(struct ata_queued_cmd *qc); - bool (*qc_fill_rtf)(struct ata_queued_cmd *qc); + void (*qc_fill_rtf)(struct ata_queued_cmd *qc); /* * Configuration and exception handling @@ -1935,7 +1935,7 @@ extern void ata_sff_queue_delayed_work(struct delayed_work *dwork, unsigned long delay); extern void ata_sff_queue_pio_task(struct ata_link *link, unsigned long delay); extern unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc); -extern bool ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc); +extern void ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc); extern unsigned int ata_sff_port_intr(struct ata_port *ap, struct ata_queued_cmd *qc); extern irqreturn_t ata_sff_interrupt(int irq, void *dev_instance); From patchwork Thu Dec 8 10:59:20 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 633202 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1CB78C6370C for ; Thu, 8 Dec 2022 11:03:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229751AbiLHLDW (ORCPT ); Thu, 8 Dec 2022 06:03:22 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35608 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229988AbiLHLBv (ORCPT ); Thu, 8 Dec 2022 06:01:51 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A1BCCF7B; Thu, 8 Dec 2022 03:00:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497253; x=1702033253; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Cg0mv9DrQD9PnF4SPJZRB416GhIAfBiBPoam2Ec2fMg=; b=TOMa8EDaCR/tO1klnKTCJ7UfCnh09sN6AqRr0/dBBcrMnTpBvbsLzWBd hS/xHkE+DJnCmDDHO87AwfTZqq0OrQFYsshniOnA6DUIBh7U8gQYJEBB0 pSoeay/QVVCdJXz2yhaofgMfmZoaFN03vuTU1BkGa3K7UTw4r6bRLOg0m E7C+/PeUeSxScZiqcwWdLe6AwKIm1JjR93gipiM/P4EKnvG3PNgSGBDk3 ePoYFPdT1+/QEoxs8KEtkk0IOdBRXUw2QKR4ccfEJ7oVWo1wSUVu0yO2Y a+lfcsrouO7WQeFU0BzoXL6PN67Tg5T0IVHhKyi7HZMPHOGpHwq0vmmFU Q==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333365" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:00:53 +0800 IronPort-SDR: y7Hbv7EE33lM6Qahb3zyLesQMcz8L2Y+8FyxcTb+tXxGO4Y38p/W+XGRQz3QunZaj8VwcAkIYL yAs4fm3SidVp+xjla4bt1okZfbo8pgLYFDLTVtyh433Sx67TMDFW8Vw0BUf195mhlhCEUKoqJ5 H8kqZp18VLFffJmJXZgSqCi5BMT5JZ+tOrFsO79VG7EGcjY0r0mykWx6hOYiqrckfY3th9Bhw6 OAhI7x5e4YM5SeDOGODRllW2dT+gg4FG2Yo062Xxv1r3lUhYx7yZe4DAOIHdyM7QppWoZoSk2C kiM= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:13:38 -0800 IronPort-SDR: T+J7fQw8WgSOcNDoJmDhD4sxFAvA8tJk8SCJraNFYLk8p1tf5e3JGHq5qxxLc+ym+HHzDPXaYs 95RuFp8+YC6BUDE7wHiVhgjJPQVJFRtQVV2BkJxa41t8JsUxFe3836r5Ws7fJbOQNcqyRr9zq9 oIcx3/0L69AxzqwdURTxcfxo/DjMACmAflIkcGVd9Q2vpRUMHTwE7m9PVqpL7d3EQr4NuXXl3x x88sujw23F99W7/ipJjF8gqeF4cLLtd1xZ5DRBPn6nganloKL2du2NqR77a4YNeSYvN8XkKuA1 a38= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:00:52 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Niklas Cassel , linux-ide@vger.kernel.org Subject: [PATCH 04/25] ata: libata: fix broken NCQ command status handling Date: Thu, 8 Dec 2022 11:59:20 +0100 Message-Id: <20221208105947.2399894-5-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Currently, the status is being read for each QC, inside ata_qc_complete(), which means that QCs being completed by ata_qc_complete_multiple() (i.e. multiple QCs completed during a single interrupt), can have different status and error bits set. This is because the FIS Receive Area will get updated as soon as the HBA receives a new FIS from the device in the NCQ case. Here is an example of the problem: ata14.00: ata_qc_complete_multiple: done_mask: 0x180000 qc tag: 19 cmd: 0x61 flags: 0x11b err_mask: 0x0 tf->status: 0x40 qc tag: 20 cmd: 0x61 flags: 0x11b err_mask: 0x0 tf->status: 0x43 A print in ata_qc_complete_multiple(), shows that done_mask is: 0x180000 which means that tag 19 and 20 were completed. Another print in ata_qc_complete(), after the call to fill_result_tf(), shows that tag 19 and 20 have different status values, even though they were completed in the same ata_qc_complete_multiple() call. If PMP is not enabled, simply read the status and error once, before calling ata_qc_complete() for each QC. Without PMP, we know that all QCs must share the same status and error values. If PMP is enabled, we also read the status before calling ata_qc_complete(), however, we still read the status for each QC, since the QCs can belong to different PMP links (which means that the QCs does not necessarily share the same status and error values). Do all this by introducing the new port operation .qc_ncq_fill_rtf. If set, this operation is called in ata_qc_complete_multiple() to set the result tf for all completed QCs signaled by the last SDB FIS received. QCs that have their result tf filled are marked with the new flag ATA_QCFLAG_RTF_FILLED so that any later execution of the qc_fill_rtf port operation does nothing (e.g. when called from ata_qc_complete()). Co-developed-by: Damien Le Moal Signed-off-by: Damien Le Moal Signed-off-by: Niklas Cassel --- drivers/ata/libahci.c | 90 +++++++++++++++++++++++++++++++++++++-- drivers/ata/libata-sata.c | 3 ++ include/linux/libata.h | 2 + 3 files changed, 92 insertions(+), 3 deletions(-) diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 0167aac25c34..019d74d6eb7d 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -56,6 +56,7 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state, static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); static void ahci_qc_fill_rtf(struct ata_queued_cmd *qc); +static void ahci_qc_ncq_fill_rtf(struct ata_port *ap, u64 done_mask); static int ahci_port_start(struct ata_port *ap); static void ahci_port_stop(struct ata_port *ap); static enum ata_completion_errors ahci_qc_prep(struct ata_queued_cmd *qc); @@ -157,6 +158,7 @@ struct ata_port_operations ahci_ops = { .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue, .qc_fill_rtf = ahci_qc_fill_rtf, + .qc_ncq_fill_rtf = ahci_qc_ncq_fill_rtf, .freeze = ahci_freeze, .thaw = ahci_thaw, @@ -2058,6 +2060,13 @@ static void ahci_qc_fill_rtf(struct ata_queued_cmd *qc) struct ahci_port_priv *pp = qc->ap->private_data; u8 *rx_fis = pp->rx_fis; + /* + * rtf may already be filled (e.g. for ncq commands). + * If that is the case, we have nothing to do. + */ + if (qc->flags & ATA_QCFLAG_RTF_FILLED) + return; + if (pp->fbs_enabled) rx_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ; @@ -2071,6 +2080,9 @@ static void ahci_qc_fill_rtf(struct ata_queued_cmd *qc) !(qc->flags & ATA_QCFLAG_EH)) { ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf); qc->result_tf.status = (rx_fis + RX_FIS_PIO_SETUP)[15]; + qc->flags |= ATA_QCFLAG_RTF_FILLED; + return; + } /* * For NCQ commands, we never get a D2H FIS, so reading the D2H Register @@ -2080,13 +2092,85 @@ static void ahci_qc_fill_rtf(struct ata_queued_cmd *qc) * instead. However, the SDB FIS does not contain the LBA, so we can't * use the ata_tf_from_fis() helper. */ - } else if (ata_is_ncq(qc->tf.protocol)) { + if (ata_is_ncq(qc->tf.protocol)) { const u8 *fis = rx_fis + RX_FIS_SDB; + /* + * Successful NCQ commands have been filled already. + * A failed NCQ command will read the status here. + * (Note that a failed NCQ command will get a more specific + * error when reading the NCQ Command Error log.) + */ qc->result_tf.status = fis[2]; qc->result_tf.error = fis[3]; - } else - ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf); + qc->flags |= ATA_QCFLAG_RTF_FILLED; + return; + } + + ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf); + qc->flags |= ATA_QCFLAG_RTF_FILLED; +} + +static void ahci_qc_ncq_fill_rtf(struct ata_port *ap, u64 done_mask) +{ + struct ahci_port_priv *pp = ap->private_data; + const u8 *fis; + + /* No outstanding commands. */ + if (!ap->qc_active) + return; + + /* + * FBS not enabled, so read status and error once, since they are shared + * for all QCs. + */ + if (!pp->fbs_enabled) { + u8 status, error; + + /* No outstanding NCQ commands. */ + if (!pp->active_link->sactive) + return; + + fis = pp->rx_fis + RX_FIS_SDB; + status = fis[2]; + error = fis[3]; + + while (done_mask) { + struct ata_queued_cmd *qc; + unsigned int tag = __ffs64(done_mask); + + qc = ata_qc_from_tag(ap, tag); + if (qc && ata_is_ncq(qc->tf.protocol)) { + qc->result_tf.status = status; + qc->result_tf.error = error; + qc->flags |= ATA_QCFLAG_RTF_FILLED; + } + done_mask &= ~(1ULL << tag); + } + + return; + } + + /* + * FBS enabled, so read the status and error for each QC, since the QCs + * can belong to different PMP links. (Each PMP link has its own FIS + * Receive Area.) + */ + while (done_mask) { + struct ata_queued_cmd *qc; + unsigned int tag = __ffs64(done_mask); + + qc = ata_qc_from_tag(ap, tag); + if (qc && ata_is_ncq(qc->tf.protocol)) { + fis = pp->rx_fis; + fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ; + fis += RX_FIS_SDB; + qc->result_tf.status = fis[2]; + qc->result_tf.error = fis[3]; + qc->flags |= ATA_QCFLAG_RTF_FILLED; + } + done_mask &= ~(1ULL << tag); + } } static void ahci_freeze(struct ata_port *ap) diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index 908f35acee1e..f3e7396e3191 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -655,6 +655,9 @@ int ata_qc_complete_multiple(struct ata_port *ap, u64 qc_active) return -EINVAL; } + if (ap->ops->qc_ncq_fill_rtf) + ap->ops->qc_ncq_fill_rtf(ap, done_mask); + while (done_mask) { struct ata_queued_cmd *qc; unsigned int tag = __ffs64(done_mask); diff --git a/include/linux/libata.h b/include/linux/libata.h index 31f4eaf515e1..3b7f5d9e2f87 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -199,6 +199,7 @@ enum { /* struct ata_queued_cmd flags */ ATA_QCFLAG_ACTIVE = (1 << 0), /* cmd not yet ack'd to scsi lyer */ ATA_QCFLAG_DMAMAP = (1 << 1), /* SG table is DMA mapped */ + ATA_QCFLAG_RTF_FILLED = (1 << 2), /* result TF has been filled */ ATA_QCFLAG_IO = (1 << 3), /* standard IO command */ ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */ ATA_QCFLAG_CLEAR_EXCL = (1 << 5), /* clear excl_link on completion */ @@ -876,6 +877,7 @@ struct ata_port_operations { enum ata_completion_errors (*qc_prep)(struct ata_queued_cmd *qc); unsigned int (*qc_issue)(struct ata_queued_cmd *qc); void (*qc_fill_rtf)(struct ata_queued_cmd *qc); + void (*qc_ncq_fill_rtf)(struct ata_port *ap, u64 done_mask); /* * Configuration and exception handling From patchwork Thu Dec 8 10:59:21 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 632159 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3B0CCC6370E for ; Thu, 8 Dec 2022 11:03:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229822AbiLHLDX (ORCPT ); Thu, 8 Dec 2022 06:03:23 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35562 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230041AbiLHLBx (ORCPT ); Thu, 8 Dec 2022 06:01:53 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 90948BF7E; Thu, 8 Dec 2022 03:00:55 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497255; x=1702033255; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=BTJ8LoJp6X+8/V4roeSzAaSaPwzHMewoL7aqMsmDJjg=; b=Gk6egJ1SpNj0Nr+TdEmjVn5Ye3uszoklQ+jbCuG+OehB0qkM1/ErNBZA xGyTHqngppulN0+MqLuauWEJjkEjHm/42X5Wno5tofGx82Ny0QZvzbhIn /bkn2/OAlJo+HYmHauXeGD+gDbNEvU8cOBDUyHaOpYxKstpSqk0fBxo4g 2xFnqTtld2ZUkeR8AjnCCGw9JwlzY9EOssYeeM1rQOy+v9UnqVu/3zcln hmFFdILdULjQo64+iKcWRU/7TdPp+UB2a7wjSKKtMimkObTlFNgd9n7tw iDj3lawh02fZa6mFkhxooh/m0CmqHMvpQG9OZTwWJiqLczgFASZ/C8sD2 g==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333371" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:00:55 +0800 IronPort-SDR: n5diKaqmPulEoJUFvOt2Csn7SupTuXLS/bp2J6NwISeLj1m5tIaEZYo0Lnm2X/+PBNHJonz5hB zjDnTjQBX9gx/W+hGCKx2gqBw0Uws1Ex8G3JTaFhOBDcc5t7SXvyhU6d5dpKfuEvp+BycADJmx MG8ZJO9Gy7AOZAeZaxrOioSoLdjwdt8mPTefJd8chi5EXGuCCeEodrAnc9kGZIzcTy5AIfPsey kZG4vD12EJ5D0T6SR81mfgqefjcAHxl/Nvy+17vjEOUtAOa4cInZaPojBVvWkwpybEia++0hHg D9g= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:13:40 -0800 IronPort-SDR: ajpZ+AjupHZxuJ61VkOK6TDEwkH7KZE9zOecDoMHL6D7KMrrWqXvTrG8dr7HpGj/yV5clOJERu duvMkKhrBtkq9u1OdTP5Gc4Kq/aYHxs0ahOvTpEuruQfdIOW14x6ZqLVoTmfghkuYMkb6zSXAl 3O7LkUO5emMWQQToxUY8Q2jPVtDD2dAtV+GD34N28DglaWXq2tbG6ANYoDXxkvEI8R0dv24buA PcXhQdtCsxvL1zAFq3mXYs2JWjrFzkYKbQ6X+tTkz2eZFLVgQg4hXpgCvIWnANxIxKwAVZ1IBs ZfE= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:00:54 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Niklas Cassel , linux-ide@vger.kernel.org Subject: [PATCH 05/25] ata: libata: respect successfully completed commands during errors Date: Thu, 8 Dec 2022 11:59:21 +0100 Message-Id: <20221208105947.2399894-6-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org In AHCI specification 1.3.1: "5.5.3 Processing Completed Commands" "For each port that has an interrupt pending: 1. Software determines the cause of the interrupt by reading the PxIS register. It is possible for multiple bits to be set. 2. Software clears appropriate bits in the PxIS register corresponding to the cause of the interrupt. 3. Software clears the interrupt bit in IS.IPS corresponding to the port. 4. If executing non-queued commands, software reads the PxCI register, and compares the current value to the list of commands previously issued by software that are still outstanding. If executing native queued commands, software reads the PxSACT register and compares the current value to the list of commands previously issued by software. Software completes with success any outstanding command whose corresponding bit has been cleared in the respective register. PxCI and PxSACT are volatile registers; software should only use their values to determine commands that have completed, not to determine which commands have previously been issued. 5. If there were errors, noted in the PxIS register, software performs error recovery actions (see section 6.2.2)." The documentation for the PxSACT shadow register in AHCI: "The device clears bits in this field by sending a Set Device Bits FIS to the host. The HBA clears bits in this field that are set to ‘1’ in the SActive field of the Set Device Bits FIS. The HBA only clears bits that correspond to native queued commands that have completed successfully." Additionally, in SATA specification 3.5a: "11.15 FPDMA QUEUED command protocol" "DFPDMAQ11: ERROR Halt command processing and transmit Set Device Bits FIS to host with the ERR bit in Status field set to one, Interrupt bit set to one, ATA error code set to one in the ERROR field, bits in ACT field cleared to zero for any outstanding queued commands, and bits set to one for any successfully completed queued commands that completion notification not yet delivered." I.e. even when the HBA triggers an error interrupt, the HBA will still clear successfully completed commands in PxSACT. Commands that did not complete successfully will still have its bit set in PxSACT. (Which means the command that caused the NCQ error and queued commands that had not yet finished at the time when the NCQ error occurred.) Additionally, for a HBA that does not have the libata flag AHCI_HFLAG_MULTI_MSI set, all ap->locks will point to host->lock, which means that IRQs will be disabled for one port while another port's IRQ handler is running. The HBA will still receive FISes from the device, even if IRQs on the HBA itself are disabled. What can thus e.g. receive a FIS that completes several commands successfully, followed by a FIS that does (or does not) complete additional commands with the error bit set, to indicate that at least one command was aborted. Therefore, modify ahci_handle_port_interrupt() using the new helper ahci_qc_complete() to complete the commands that have already been signaled as successfully through a regular completion SDB FIS, as not doing so would simply cause successfully completed commands to be retried for no good reason. Co-developed-by: Damien Le Moal Signed-off-by: Damien Le Moal Signed-off-by: Niklas Cassel --- drivers/ata/libahci.c | 73 +++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 019d74d6eb7d..db5ecc386657 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1849,18 +1849,47 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) ata_port_abort(ap); } -static void ahci_handle_port_interrupt(struct ata_port *ap, - void __iomem *port_mmio, u32 status) +static void ahci_qc_complete(struct ata_port *ap, void __iomem *port_mmio) { struct ata_eh_info *ehi = &ap->link.eh_info; struct ahci_port_priv *pp = ap->private_data; - struct ahci_host_priv *hpriv = ap->host->private_data; - int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING); u32 qc_active = 0; int rc; + /* + * pp->active_link is not reliable once FBS is enabled, both + * PORT_SCR_ACT and PORT_CMD_ISSUE should be checked because + * NCQ and non-NCQ commands may be in flight at the same time. + */ + if (pp->fbs_enabled) { + if (ap->qc_active) { + qc_active = readl(port_mmio + PORT_SCR_ACT); + qc_active |= readl(port_mmio + PORT_CMD_ISSUE); + } + } else { + /* pp->active_link is valid iff any command is in flight */ + if (ap->qc_active && pp->active_link->sactive) + qc_active = readl(port_mmio + PORT_SCR_ACT); + else + qc_active = readl(port_mmio + PORT_CMD_ISSUE); + } + + rc = ata_qc_complete_multiple(ap, qc_active); + if (unlikely(rc < 0 && !(ap->pflags & ATA_PFLAG_RESETTING))) { + ehi->err_mask |= AC_ERR_HSM; + ehi->action |= ATA_EH_RESET; + ata_port_freeze(ap); + } +} + +static void ahci_handle_port_interrupt(struct ata_port *ap, + void __iomem *port_mmio, u32 status) +{ + struct ahci_port_priv *pp = ap->private_data; + struct ahci_host_priv *hpriv = ap->host->private_data; + /* ignore BAD_PMP while resetting */ - if (unlikely(resetting)) + if (unlikely(ap->pflags & ATA_PFLAG_RESETTING)) status &= ~PORT_IRQ_BAD_PMP; if (sata_lpm_ignore_phy_events(&ap->link)) { @@ -1869,6 +1898,12 @@ static void ahci_handle_port_interrupt(struct ata_port *ap, } if (unlikely(status & PORT_IRQ_ERROR)) { + /* + * Before getting the error notification, we may have + * received SDB FISes notifying successful completions. + * Handle these first and then handle the error. + */ + ahci_qc_complete(ap, port_mmio); ahci_error_intr(ap, status); return; } @@ -1905,32 +1940,8 @@ static void ahci_handle_port_interrupt(struct ata_port *ap, } } - /* pp->active_link is not reliable once FBS is enabled, both - * PORT_SCR_ACT and PORT_CMD_ISSUE should be checked because - * NCQ and non-NCQ commands may be in flight at the same time. - */ - if (pp->fbs_enabled) { - if (ap->qc_active) { - qc_active = readl(port_mmio + PORT_SCR_ACT); - qc_active |= readl(port_mmio + PORT_CMD_ISSUE); - } - } else { - /* pp->active_link is valid iff any command is in flight */ - if (ap->qc_active && pp->active_link->sactive) - qc_active = readl(port_mmio + PORT_SCR_ACT); - else - qc_active = readl(port_mmio + PORT_CMD_ISSUE); - } - - - rc = ata_qc_complete_multiple(ap, qc_active); - - /* while resetting, invalid completions are expected */ - if (unlikely(rc < 0 && !resetting)) { - ehi->err_mask |= AC_ERR_HSM; - ehi->action |= ATA_EH_RESET; - ata_port_freeze(ap); - } + /* Handle completed commands */ + ahci_qc_complete(ap, port_mmio); } static void ahci_port_intr(struct ata_port *ap) From patchwork Thu Dec 8 10:59:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 632155 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9B087C63718 for ; Thu, 8 Dec 2022 11:03:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229885AbiLHLD0 (ORCPT ); Thu, 8 Dec 2022 06:03:26 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35620 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229940AbiLHLCF (ORCPT ); Thu, 8 Dec 2022 06:02:05 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F04435F73; Thu, 8 Dec 2022 03:00:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497257; x=1702033257; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=qEbSqx02Hms4e+VhyDUd/rgwE6Jtv1eQbot0wFgdMSg=; b=Fz57JeVDEbkLfm09Bh0O28B6lARe6TDFNUeKIYnSDqEwsqFIFrDC+OxL hKCyVBpASqDgZKZC/vVEPz4qvN20kqb5UGkUSbjrrdkStL5Sh/WRLPai2 /RzgxIqV12CE+71gkyoow4djCxtYPeYXo8p/kLTGsFLUouND19Am9u67W 9sqaVNARfC7ryx1Zy0H52Kygq5V/7htGqRPBcCoGH5uUwEWTSswIkErBM RiIyuLwT3fXYoI+SSta5Ld+lWE35kJa/z/S6I/Xz2fm72K7entkJfJU1p w2s+9mhyQNJ2r4T1BPPQomkRKWUgfRIJmoK6OYy0SrpwYrl25StT0O6ey A==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333375" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:00:57 +0800 IronPort-SDR: njZymEfvw3f9dz+YvmRhXbYzEEb6EV5y+X3tNKdYPYy2fA0d+4EtUtszc7MnDsYaP7lNu1Xbw6 OCTBGc1ZvG9xja4cEmFcfk6Da2wz35hBNimjr73fymtb2+vZk8qxqnpHDRrt7QJ+CI8zk2pp0c Il3opvEUTd6vOBC3jRH5fXmDyZDGjguBgvmpbwFeHFw9ym4v+LmMA8nQtAF4gZnfO9IIvgGitc G+Lo9Bn3Foe+Ks5odFvXkgNAhSP78SYbh6yHlCerDmja90HfaaFKhoEUewVtZuc59CVDzhVwN0 Cus= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:13:42 -0800 IronPort-SDR: pmnLZj8r0EJGUg9r3uyUBAul7aXJxI7Ge3x9qxANnkVZbyrANcbbFkSrThUVfQPaq+BgdVN1+F KgMpW1wcIJQBiJzPZWwcEfVQRWNfKkjAN8aRtDgSG2LWZjLSqjIiYHZxf5HFZ6/IQpGSfUItfa cfqS+u+G91sFqfWAQuoqhv9DFZcthKrDCSSDBVEg021/HzplLMliCx4pUvPBOoB9lRgSKVaeWm /sRZn5Ldq1JJ/7hVvd6dCCewRKhxxFvlTlAbczmfl/RVmg4O1e4YtaHcYBv9UAAWfZKIz9hCxm EzQ= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:00:57 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Niklas Cassel , linux-ide@vger.kernel.org Subject: [PATCH 06/25] ata: libata: allow ata_scsi_set_sense() to not set CHECK_CONDITION Date: Thu, 8 Dec 2022 11:59:22 +0100 Message-Id: <20221208105947.2399894-7-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Current ata_scsi_set_sense() calls scsi_build_sense(), which, in addition to setting the sense data, unconditionally sets the scsicmd->result to SAM_STAT_CHECK_CONDITION. For Command Duration Limits policy 0xD: The device shall complete the command without error (SAM_STAT_GOOD) with the additional sense code set to DATA CURRENTLY UNAVAILABLE. It is perfectly fine to have sense data for a command that returned completion without error. In order to support for CDL policy 0xD, we have to remove this assumption that having sense data means that the command failed (SAM_STAT_CHECK_CONDITION). Add a new parameter to ata_scsi_set_sense() to allow us to set sense data without unconditionally setting SAM_STAT_CHECK_CONDITION. This new parameter will be used in a follow-up patch. Signed-off-by: Niklas Cassel --- drivers/ata/libata-eh.c | 3 ++- drivers/ata/libata-sata.c | 4 ++-- drivers/ata/libata-scsi.c | 38 ++++++++++++++++++++------------------ drivers/ata/libata.h | 4 ++-- 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 8cb250930c48..c278366370ab 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1429,7 +1429,8 @@ static void ata_eh_request_sense(struct ata_queued_cmd *qc) /* Ignore err_mask; ATA_ERR might be set */ if (tf.status & ATA_SENSE) { if (ata_scsi_sense_is_valid(tf.lbah, tf.lbam, tf.lbal)) { - ata_scsi_set_sense(dev, cmd, tf.lbah, tf.lbam, tf.lbal); + ata_scsi_set_sense(dev, cmd, true, tf.lbah, tf.lbam, + tf.lbal); qc->flags |= ATA_QCFLAG_SENSE_VALID; } } else { diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index f3e7396e3191..414d7f8a95bf 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -1471,8 +1471,8 @@ void ata_eh_analyze_ncq_error(struct ata_link *link) asc = (qc->result_tf.auxiliary >> 8) & 0xff; ascq = qc->result_tf.auxiliary & 0xff; if (ata_scsi_sense_is_valid(sense_key, asc, ascq)) { - ata_scsi_set_sense(dev, qc->scsicmd, sense_key, asc, - ascq); + ata_scsi_set_sense(dev, qc->scsicmd, true, sense_key, + asc, ascq); ata_scsi_set_sense_information(dev, qc->scsicmd, &qc->result_tf); qc->flags |= ATA_QCFLAG_SENSE_VALID; diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index cbb3a7a50816..0e6684ca0315 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -205,14 +205,16 @@ bool ata_scsi_sense_is_valid(u8 sk, u8 asc, u8 ascq) } void ata_scsi_set_sense(struct ata_device *dev, struct scsi_cmnd *cmd, - u8 sk, u8 asc, u8 ascq) + bool check_condition, u8 sk, u8 asc, u8 ascq) { bool d_sense = (dev->flags & ATA_DFLAG_D_SENSE); if (!cmd) return; - scsi_build_sense(cmd, d_sense, sk, asc, ascq); + scsi_build_sense_buffer(d_sense, cmd->sense_buffer, sk, asc, ascq); + if (check_condition) + set_status_byte(cmd, SAM_STAT_CHECK_CONDITION); } void ata_scsi_set_sense_information(struct ata_device *dev, @@ -235,7 +237,7 @@ void ata_scsi_set_sense_information(struct ata_device *dev, static void ata_scsi_set_invalid_field(struct ata_device *dev, struct scsi_cmnd *cmd, u16 field, u8 bit) { - ata_scsi_set_sense(dev, cmd, ILLEGAL_REQUEST, 0x24, 0x0); + ata_scsi_set_sense(dev, cmd, true, ILLEGAL_REQUEST, 0x24, 0x0); /* "Invalid field in CDB" */ scsi_set_sense_field_pointer(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE, field, bit, 1); @@ -245,7 +247,7 @@ static void ata_scsi_set_invalid_parameter(struct ata_device *dev, struct scsi_cmnd *cmd, u16 field) { /* "Invalid field in parameter list" */ - ata_scsi_set_sense(dev, cmd, ILLEGAL_REQUEST, 0x26, 0x0); + ata_scsi_set_sense(dev, cmd, true, ILLEGAL_REQUEST, 0x26, 0x0); scsi_set_sense_field_pointer(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE, field, 0xff, 0); } @@ -914,7 +916,7 @@ static void ata_gen_passthru_sense(struct ata_queued_cmd *qc) tf->status & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) { ata_to_sense_error(qc->ap->print_id, tf->status, tf->error, &sense_key, &asc, &ascq, verbose); - ata_scsi_set_sense(qc->dev, cmd, sense_key, asc, ascq); + ata_scsi_set_sense(qc->dev, cmd, true, sense_key, asc, ascq); } else { /* * ATA PASS-THROUGH INFORMATION AVAILABLE @@ -1005,7 +1007,7 @@ static void ata_gen_ata_sense(struct ata_queued_cmd *qc) if (ata_dev_disabled(dev)) { /* Device disabled after error recovery */ /* LOGICAL UNIT NOT READY, HARD RESET REQUIRED */ - ata_scsi_set_sense(dev, cmd, NOT_READY, 0x04, 0x21); + ata_scsi_set_sense(dev, cmd, true, NOT_READY, 0x04, 0x21); return; } /* Use ata_to_sense_error() to map status register bits @@ -1015,12 +1017,12 @@ static void ata_gen_ata_sense(struct ata_queued_cmd *qc) tf->status & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) { ata_to_sense_error(qc->ap->print_id, tf->status, tf->error, &sense_key, &asc, &ascq, verbose); - ata_scsi_set_sense(dev, cmd, sense_key, asc, ascq); + ata_scsi_set_sense(dev, cmd, true, sense_key, asc, ascq); } else { /* Could not decode error */ ata_dev_warn(dev, "could not decode error status 0x%x err_mask 0x%x\n", tf->status, qc->err_mask); - ata_scsi_set_sense(dev, cmd, ABORTED_COMMAND, 0, 0); + ata_scsi_set_sense(dev, cmd, true, ABORTED_COMMAND, 0, 0); return; } @@ -1496,7 +1498,7 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc) return 1; out_of_range: - ata_scsi_set_sense(qc->dev, scmd, ILLEGAL_REQUEST, 0x21, 0x0); + ata_scsi_set_sense(qc->dev, scmd, true, ILLEGAL_REQUEST, 0x21, 0x0); /* "Logical Block Address out of range" */ return 1; @@ -1631,7 +1633,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) return 1; out_of_range: - ata_scsi_set_sense(qc->dev, scmd, ILLEGAL_REQUEST, 0x21, 0x0); + ata_scsi_set_sense(qc->dev, scmd, true, ILLEGAL_REQUEST, 0x21, 0x0); /* "Logical Block Address out of range" */ return 1; @@ -2380,7 +2382,7 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) return 1; saving_not_supp: - ata_scsi_set_sense(dev, args->cmd, ILLEGAL_REQUEST, 0x39, 0x0); + ata_scsi_set_sense(dev, args->cmd, true, ILLEGAL_REQUEST, 0x39, 0x0); /* "Saving parameters not supported" */ return 1; } @@ -3241,11 +3243,11 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) return 1; invalid_param_len: /* "Parameter list length error" */ - ata_scsi_set_sense(dev, scmd, ILLEGAL_REQUEST, 0x1a, 0x0); + ata_scsi_set_sense(dev, scmd, true, ILLEGAL_REQUEST, 0x1a, 0x0); return 1; invalid_opcode: /* "Invalid command operation code" */ - ata_scsi_set_sense(dev, scmd, ILLEGAL_REQUEST, 0x20, 0x0); + ata_scsi_set_sense(dev, scmd, true, ILLEGAL_REQUEST, 0x20, 0x0); return 1; } @@ -3471,7 +3473,7 @@ static unsigned int ata_scsi_zbc_in_xlat(struct ata_queued_cmd *qc) invalid_param_len: /* "Parameter list length error" */ - ata_scsi_set_sense(qc->dev, scmd, ILLEGAL_REQUEST, 0x1a, 0x0); + ata_scsi_set_sense(qc->dev, scmd, true, ILLEGAL_REQUEST, 0x1a, 0x0); return 1; } @@ -3549,7 +3551,7 @@ static unsigned int ata_scsi_zbc_out_xlat(struct ata_queued_cmd *qc) return 1; invalid_param_len: /* "Parameter list length error" */ - ata_scsi_set_sense(qc->dev, scmd, ILLEGAL_REQUEST, 0x1a, 0x0); + ata_scsi_set_sense(qc->dev, scmd, true, ILLEGAL_REQUEST, 0x1a, 0x0); return 1; } @@ -3810,7 +3812,7 @@ static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc) invalid_param_len: /* "Parameter list length error" */ - ata_scsi_set_sense(qc->dev, scmd, ILLEGAL_REQUEST, 0x1a, 0x0); + ata_scsi_set_sense(qc->dev, scmd, true, ILLEGAL_REQUEST, 0x1a, 0x0); return 1; skip: @@ -4166,7 +4168,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) break; case REQUEST_SENSE: - ata_scsi_set_sense(dev, cmd, 0, 0, 0); + ata_scsi_set_sense(dev, cmd, true, 0, 0, 0); break; /* if we reach this, then writeback caching is disabled, @@ -4198,7 +4200,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) /* all other commands */ default: - ata_scsi_set_sense(dev, cmd, ILLEGAL_REQUEST, 0x20, 0x0); + ata_scsi_set_sense(dev, cmd, true, ILLEGAL_REQUEST, 0x20, 0x0); /* "Invalid command operation code" */ break; } diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 2cd6124a01e8..5481d29bb273 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -115,8 +115,8 @@ extern int ata_scsi_add_hosts(struct ata_host *host, extern void ata_scsi_scan_host(struct ata_port *ap, int sync); extern int ata_scsi_offline_dev(struct ata_device *dev); extern bool ata_scsi_sense_is_valid(u8 sk, u8 asc, u8 ascq); -extern void ata_scsi_set_sense(struct ata_device *dev, - struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq); +extern void ata_scsi_set_sense(struct ata_device *dev, struct scsi_cmnd *cmd, + bool check_condition, u8 sk, u8 asc, u8 ascq); extern void ata_scsi_set_sense_information(struct ata_device *dev, struct scsi_cmnd *cmd, const struct ata_taskfile *tf); From patchwork Thu Dec 8 10:59:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 633199 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BAF97C63719 for ; Thu, 8 Dec 2022 11:03:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229888AbiLHLD3 (ORCPT ); Thu, 8 Dec 2022 06:03:29 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35626 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230110AbiLHLCH (ORCPT ); Thu, 8 Dec 2022 06:02:07 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 269ED813BE; Thu, 8 Dec 2022 03:01:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497260; x=1702033260; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=7OOLcX2+vM155WgZyxnafA0YBJsvwJzjjqumba4e+eQ=; b=WCKLu4rpPWjAgM22gohlf2I1/RiyGRA//4FNtc2rHoPVSXYNJ7gjR/Cq hiPBU0xpSnNmlVlXGGkl6HHt+2gS8Zp9LsPPBTiBk/FU0CDjsZEP9M0Sn ds66Dza7BRZ1ovzp//0NHVsMgr8fHz8VzcLw0gEvG9ryzxcCrJPm4xuvo vW01mgkUOF+lgbzunLe++RbjfgL/qLfb6eOzJpiJp2zjoQM12YsVokVZJ ipar2OwlIQ7v2KYpBLgWaEJWc8XgcAK0fO9QtR+9xPLVuS0BmgJbGgrQ7 10zCAygtKseeOnTg7x1TgtQnyguJazTBGMo/LY4WjV+XlEiJCLFKAlW2b Q==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333379" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:00:59 +0800 IronPort-SDR: gunyvR74Zdxnge1ER/wX0QtcLGHBNpzrWBrZp843BBn/f86H0Ug9NWqK1fkhVmY10J5dZSnd8h HVou8nLMjAmZT6xe9tZKJU4gGm61Ig2ghbmj20KzjfUmZky8Ld5kPXJhPrlVKHr4H9onjKQ/GX bTLY68VFZBHsTiGxdJz3kmPE2uKxEENU6RUPvG9hfsrgfn2sjZqrXYqz0r90NhXWnZurmGwtlR WECsmUMArNuLgHp4KPJjLPOEQRAF7CI+d65ya7szLOuZ35NVM/78YyepsvJoTLRDXySHxgnfUC f8g= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:13:45 -0800 IronPort-SDR: 85QCEAkcwvB4LVbsz1/iBs+GUc6b2Z+vpDwOKzBUOVLgRf/Kg3TQXOIJB5+YhtUWG3+gc5aCOt 9ldbNYUkSHM6u6rPzYcoTxj2th8k1avw3cV5HsA9ZADL4CI7V1vTYyURuZs0Wgn2iUIkGmSo29 oFVdCyfRsT6XP1lvHi5vZu4nxPoGepYiBOWHEEN/MaGjlCDe9M4t54O/BRr1H984bfET9I/E43 LLN+ZHbZiZWe7XAEbIOfEMC4dvZNiuVEO9Elg5T8PzdtqB5z+oWcsp37T9sO/OOi34V9HtuQno 2Jc= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:00:59 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Niklas Cassel , linux-ide@vger.kernel.org Subject: [PATCH 07/25] ata: libata: allow ata_eh_request_sense() to not set CHECK_CONDITION Date: Thu, 8 Dec 2022 11:59:23 +0100 Message-Id: <20221208105947.2399894-8-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Current ata_eh_request_sense() calls ata_scsi_set_sense() with check_condition always set to true, which, in addition to setting the sense data, unconditionally sets the scsicmd->result to SAM_STAT_CHECK_CONDITION. For Command Duration Limits policy 0xD: The device shall complete the command without error (SAM_STAT_GOOD) with the additional sense code set to DATA CURRENTLY UNAVAILABLE. It is perfectly fine to have sense data for a command that returned completion without error. In order to support for CDL policy 0xD, we have to remove this assumption that having sense data means that the command failed (SAM_STAT_CHECK_CONDITION). Add a new parameter to ata_eh_request_sense() to allow us to request sense data without unconditionally setting SAM_STAT_CHECK_CONDITION. This new parameter will be used in a follow-up patch. Signed-off-by: Niklas Cassel --- drivers/ata/libata-eh.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index c278366370ab..e05d62791e08 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1392,6 +1392,7 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key) /** * ata_eh_request_sense - perform REQUEST_SENSE_DATA_EXT * @qc: qc to perform REQUEST_SENSE_SENSE_DATA_EXT to + * @check_condition: if SAM_STAT_CHECK_CONDITION should get set * * Perform REQUEST_SENSE_DATA_EXT after the device reported CHECK * SENSE. This function is an EH helper. @@ -1399,7 +1400,8 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key) * LOCKING: * Kernel thread context (may sleep). */ -static void ata_eh_request_sense(struct ata_queued_cmd *qc) +static void ata_eh_request_sense(struct ata_queued_cmd *qc, + bool check_condition) { struct scsi_cmnd *cmd = qc->scsicmd; struct ata_device *dev = qc->dev; @@ -1429,8 +1431,8 @@ static void ata_eh_request_sense(struct ata_queued_cmd *qc) /* Ignore err_mask; ATA_ERR might be set */ if (tf.status & ATA_SENSE) { if (ata_scsi_sense_is_valid(tf.lbah, tf.lbam, tf.lbal)) { - ata_scsi_set_sense(dev, cmd, true, tf.lbah, tf.lbam, - tf.lbal); + ata_scsi_set_sense(dev, cmd, check_condition, tf.lbah, + tf.lbam, tf.lbal); qc->flags |= ATA_QCFLAG_SENSE_VALID; } } else { @@ -1587,7 +1589,7 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc) * (i.e. NCQ autosense is not supported by the device). */ if (!(qc->flags & ATA_QCFLAG_SENSE_VALID) && (stat & ATA_SENSE)) - ata_eh_request_sense(qc); + ata_eh_request_sense(qc, true); if (err & ATA_ICRC) qc->err_mask |= AC_ERR_ATA_BUS; if (err & (ATA_UNC | ATA_AMNF)) From patchwork Thu Dec 8 10:59:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 632158 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AC141C6371A for ; Thu, 8 Dec 2022 11:03:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229896AbiLHLDa (ORCPT ); Thu, 8 Dec 2022 06:03:30 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38334 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230179AbiLHLCK (ORCPT ); Thu, 8 Dec 2022 06:02:10 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4207FDEBD; Thu, 8 Dec 2022 03:01:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497262; x=1702033262; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=+USUUp7PeSIVoN4yAUogTMctUI6c9BipNMIekkoLK8k=; b=dYTgq90Z3ldIkBodnE6UGqtpsJAB2+9Y9OybGJyQWokkASSpzKhrAOtY NhjTp8os2QIDnd35zB/8t0jniZ/pLfZdnRytGtdWRgiO+1um53DuxnLdp DwShrVdPT8qJ+sd+mcWFBXtuboYr/F7PlsWv1RrZBty0YyXkXYWjvlqCl ogyxR4/hztYiqf3v9jE/UP+3gVqZX5jOSOd7BU9tb2zSx689xfbcPlMsD 5+9wAAQ268d7Mk2ZZHO5E6lRZQ3r8a9E7BTajIdzTCJsj2cCnwe2+FWc7 U7LfB6O1vPWTJRHB4/YEOmqS97Lguc3OWkR5/NVZxuH3MEqjXBk8GSXjG A==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333385" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:01:02 +0800 IronPort-SDR: mvGI4C7SjqOmDCnvT/sBCN+zXBS69rdrVSgZ7rKWk9Hz0uMw2qwbqUTivgYi74IToy9Y8WpfKk Da7KRtkjeSsRUYVkMuNmWSBpp/x//uKf46kQ+fY6BN/R2h/RFpS+XoSirldLPEw+KfqNPRPTUg kOmEh2JTsn30k6phGQwt4z8LlwTc8qkzFMIieXzEuw/Mmu18GbkX8VBmzWcbpsz3sFEwIIhq5h M7m/aVKNeMyKOrx/VrZx9amabAdL3LZTOe35uf2AQd/dD7xFECcO+eIdKZbjdcGH6Rz7RcoJjx jGs= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:13:47 -0800 IronPort-SDR: YQt0DIYLoA9BZxjZyQp0IjPDGqKP7EUZiJRW3eYS6JMEvHCkdD+RHERWjeXQzZ9Mpd29I9nZKr twF3vKCypZSITj1QQEPiJsunwhZ2H5Rx2F/Dqp0tp5lOk/fxLu5894hfykb0nU7W3ga6O9Zoms fIOd/8WP2XY/qiArxIGlBucrzuOtIfB1PzaP0b/hnAVDDhPKb1QKfoq9uv8IsXu9yh69iuDd9R cJu2rU1wleW52AICNQtna3eZFzP2ulKr0TfBPOHqwm5L8Nb6iynZdGDYenu6A1AjNPyNbTxXtx BhI= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:01:01 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Niklas Cassel , linux-ide@vger.kernel.org Subject: [PATCH 08/25] ata: libata-scsi: do not overwrite SCSI ML and status bytes Date: Thu, 8 Dec 2022 11:59:24 +0100 Message-Id: <20221208105947.2399894-9-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org For SCSI ML byte: In the case where a command is completed via libata EH: irq -> ata_qc_complete() -> ata_qc_schedule_eh() irq done ... -> ata_do_eh() -> ata_eh_link_autopsy() -> ata_eh_finish() -> ata_eh_qc_complete() -> __ata_eh_qc_complete() -> __ata_qc_complete() -> qc->complete_fn() (ata_scsi_qc_complete()) -> ata_qc_done() -> qc->scsidone() (empty stub) ... -> scsi_eh_finish_cmd() -> scsi_eh_flush_done_q() -> scsi_finish_command() ata_eh_link_autopsy() will call ata_eh_analyze_tf(), which calls scsi_check_sense(), which sets the SCSI ML byte. Since ata_scsi_qc_complete() is called after scsi_check_sense() when a command is completed via libata EH, we cannot simply overwrite the SCSI ML byte that was set earlier in the call chain. For SCSI status byte: When a SCSI command is prepared using scsi_prepare_cmd(), it sets cmd->result to 0. (SAM_STAT_GOOD is defined as 0x0). Likewise, when a command is requeued from SCSI EH, scsi_queue_insert() is called, which sets cmd->result to 0. A SCSI command thus always has a GOOD status by default when being sent to libata. If libata fetches sense data from the device, it will call ata_scsi_set_sense(), which will set the status byte to SAM_STAT_CHECK_CONDITION, if the caller deems that the status should be a check condition. ata_scsi_qc_complete() should therefore never overwrite the existing status byte, because if it is != GOOD, it was set by libata itself, for a reason. For the host byte: When libata abort commands, because of a NCQ error, it will schedule SCSI EH for all QCs using blk_abort_request(), which will all end up in scsi_timeout(), which will call scsi_abort_command(). scsi_timeout() sets DID_TIME_OUT regardless if a command was aborted or timed out. If we don't clear the DID_TIME_OUT byte for the QC that caused the NCQ error, we that QC will be reported as a timed out command, instead of being reported as a NCQ error. For a command that actually timed out, DID_TIME_OUT would be fine to keep, but libata has its own way of detecting that a command timed out (see ata_scsi_cmd_error_handler()), and sets AC_ERR_TIMEOUT if that is the case. libata will retry timed out commands. We could clear DID_TIME_OUT only for the QC that caused the NCQ error, but since libata has its own way of detecting timeouts, simply clear it always. Note that the existing ata_scsi_qc_complete() code does: cmd->result = SAM_STAT_CHECK_CONDITION or cmd->result = SAM_STAT_GOOD. This WILL clear the host byte. So us clearing the host byte unconditionally is in line with the existing libata behavior. Signed-off-by: Niklas Cassel --- drivers/ata/libata-scsi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 0e6684ca0315..ca3b92a1a6a5 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1656,7 +1656,8 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; struct scsi_cmnd *cmd = qc->scsicmd; u8 *cdb = cmd->cmnd; - int need_sense = (qc->err_mask != 0); + int need_sense = (qc->err_mask != 0) && + !(qc->flags & ATA_QCFLAG_SENSE_VALID); /* For ATA pass thru (SAT) commands, generate a sense block if * user mandated it or if there's an error. Note that if we @@ -1670,12 +1671,11 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) && ((cdb[2] & 0x20) || need_sense)) ata_gen_passthru_sense(qc); - else if (qc->flags & ATA_QCFLAG_SENSE_VALID) - cmd->result = SAM_STAT_CHECK_CONDITION; else if (need_sense) ata_gen_ata_sense(qc); else - cmd->result = SAM_STAT_GOOD; + /* Keep the SCSI ML and status byte, clear host byte. */ + cmd->result &= 0x0000ffff; if (need_sense && !ap->ops->error_handler) ata_dump_status(ap, &qc->result_tf); From patchwork Thu Dec 8 10:59:25 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 633200 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C9EDEC6371D for ; Thu, 8 Dec 2022 11:03:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229936AbiLHLDa (ORCPT ); Thu, 8 Dec 2022 06:03:30 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35636 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229840AbiLHLCN (ORCPT ); Thu, 8 Dec 2022 06:02:13 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5A67ADF01; Thu, 8 Dec 2022 03:01:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497264; x=1702033264; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=y/WCKpHJCy1/94Jl00aMjpl6YjzcQPt+Nc3cOlCy9Q0=; b=XDJ4iCPUApD6i5d/09C+gHc+y34amma9/T3T+aLTsN2kAiU9dcWifDTU 8tZilZplwvb06QY825sbaqLL1YYyggQ6mUCrsgApNkf1KglXuWdExAZXB iBQqrDOZUU6fdBG7lc+WjdnfOPClmPFq0Bszly2A2NWHNgNqSIJSFnwgF NxpqevQmN8pT9x6VXOR6mnG91fpR/hIdwVcpC1OIy5UASjmNsrYtzDZvx bF+dsmaowAhwqBDYbmcDUukC3LAWy7pw2ykeyWsTSfxZXuyqVfvF2q+oE gJ8JjpqXJpO+ThqnrBeCoeO6aRVKu18MfyT3sMkEnC8cRFu6hdI8fw+42 Q==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333388" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:01:03 +0800 IronPort-SDR: KtQLNNHyjyeU8Nikk81VTxAwj6iL4DnVw+x4bn/5aK1XUpAL08GfUmzvBA5NMHL17FmNoQ8RTC yCfu2NJA7pCEYYeUOqd8PezjoxFrXodrk6Y9ctJlyTYbFKxBtmEK7SFgOlZMXbI7Su/GvpzkWY sKTCdcJh81YUrPXmTnbuhCMglZHlbAdr88yXSQI1BSkP7Ce/3MTk/iFnQu+/RmjhRKpUSOc3Lt t+jP8/jUUXAbDjprOxaQ3mpE/HamJvDIek6R+rwbfL/nux7kwpOLgat4PjX/UVK/dJo7XM6Yh7 9yo= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:13:49 -0800 IronPort-SDR: n7DP5eOX9kGRysOgLgAi1oIsdQVJo4HAwc775L4L8cHU09TXsmFAN6ibxdiq5t7HwEyHRWJGaa RoO/bWfz238EdtakNsRvEANGFLQw/QAyrVIodDPQli/y4icTsP4rHCMFqI26kiFf/UHe/zj8rq YINyOsArb8ZXKKR8GdXpyw8+qjNFVXzC1t2d+mv+0fh7wTpeqHzlpbxHgyYdPSUVP5ibihVkhj NfUkJXh1r2UeihO09Dk0hxawX/30/4PIJj+EUDCT+aB5T1v2y0X/MFUkybJ95RbEH85melfQEs Fro= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:01:03 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org Subject: [PATCH 09/25] ata: libata-scsi: improve ata_scsiop_maint_in() Date: Thu, 8 Dec 2022 11:59:25 +0100 Message-Id: <20221208105947.2399894-10-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org From: Damien Le Moal Allow translation of REPORT_SUPPORTED_OPERATION_CODES commands using the command format 0x3, that is, checking support for commands that are identified using an opcode and a service action. Signed-off-by: Damien Le Moal --- drivers/ata/libata-scsi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index ca3b92a1a6a5..78729fd9fbfd 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3268,11 +3268,12 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf) u8 supported = 0; unsigned int err = 0; - if (cdb[2] != 1) { + if (cdb[2] != 1 && cdb[2] != 3) { ata_dev_warn(dev, "invalid command format %d\n", cdb[2]); err = 2; goto out; } + switch (cdb[3]) { case INQUIRY: case MODE_SENSE: From patchwork Thu Dec 8 10:59:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 632157 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D8BE9C6371B for ; Thu, 8 Dec 2022 11:03:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229955AbiLHLDb (ORCPT ); Thu, 8 Dec 2022 06:03:31 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39418 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229606AbiLHLCg (ORCPT ); Thu, 8 Dec 2022 06:02:36 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A4582FD25 for ; Thu, 8 Dec 2022 03:01:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497266; x=1702033266; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=XKiMYkbpIaB6YpAfx3hq/IiogWl9CJKxQI63PWbjQas=; b=IExBeISKBn7nBMuqLyFr3XL7QHsnR8KYnsETZ9Z/jWEnB8MNXPWcUi21 RKIMzVVCQziFVnjZFA31soh6s80M3lVaLykgH6wj7PmEX6qSFNt+nHUl7 p9nzDtpwaf4mKbtr6Am1bjSIyFD+Y6YOBam49j4EgltQb0m47+QhLR11D ld6N6t3a1UJ9LbNSFGVCenhrQHgHUg4KNAQNahKFayA+tLYF0ZWea/dva pu7Lfz1DOM40t956tG86nNtGdmCf+AmjkCVgFcvHKE3A6+k1/zL8Clb1w EqnaCpEfZVQ1xd8Y7ztZU1rG16C2CFbUVlw6MFgaH7LcmVUogy8CaGSPa Q==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333392" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:01:06 +0800 IronPort-SDR: 8W+L/n82upm4Cz5va6+W+QxlL4Ros4IKSYRqIyQuh8uHhhsaHryawqo6Fx+hZ09qW+tzsAxekh 7Pblqm4xnjWiU/6cTESoP1BQuwG6ScqMBBpRNK0GUtrRWAfAtqLrExBhgFlOqW6TSo1BA5cK9x 0g4dzxIG4Eappm6l4VYtYlGDAQSsIEtDyeomWxXhTwz78Hatu/pbfSGGhbgomNLjCHrCkQIC7l YBObdhtH0YkE8NEvGGPknLJ6PnUHsgmKRR4vzbNboP4I0LJi56raa329I4vLDHz/uIy/axgdEU D5g= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:13:51 -0800 IronPort-SDR: /hXsxONYLqvVuVRO5PxONQM2fSvLmMpy5w8Vnb1N6C13fgoK4Uy8BkkbvgIcnRwd/EAHODskiC fdHZExgr4sldvF6rtE5n0DqNN7Jk4Kk5PHF/ZZrDktvmU85N0m2M3SyIT0UgdNrZsbJtV9iHDe 4dWhn9HLGdqbyZM2uGa1EbrRfSNIRJJV1VSd5aIFz6Q2dVMFfq4KkdEV9orN0SfOk+8evv3LeK 0+hH5lyqhuOaM+2GXYIZ7lT4dMPivoO4JAzgea6UmXE5vWONg/nVvtIpZ8fVryea7quCQwfv3M 2Q8= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:01:05 -0800 From: Niklas Cassel To: "James E.J. Bottomley" , "Martin K. Petersen" Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Niklas Cassel Subject: [PATCH 10/25] scsi: core: allow libata to complete successful commands via EH Date: Thu, 8 Dec 2022 11:59:26 +0100 Message-Id: <20221208105947.2399894-11-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org In SCSI, we get the sense data as part of the completion, for ATA however, we need to fetch the sense data as an extra step. For an aborted ATA command the sense data is fetched via libata's ->eh_strategy_handler(). For Command Duration Limits policy 0xD: The device shall complete the command without error with the additional sense code set to DATA CURRENTLY UNAVAILABLE. In order to handle this policy in libata, we intend to send a successful command via SCSI EH, and let libata's ->eh_strategy_handler() fetch the sense data for the good command. This is similar to how we handle an aborted ATA command, just that we need to read the Successful NCQ Commands log instead of the NCQ Command Error log. When we get a SATA completion with successful commands, ATA_SENSE will be set, indicating that some commands in the completion have sense data. The sense_valid bitmask in the Sense Data for Successful NCQ Commands log will inform exactly which commands that had sense data, which might be a subset of all the commands that was completed in the same completion. (Yet all will have ATA_SENSE set, since the status is per completion.) The successful commands that have e.g. a "DATA CURRENTLY UNAVAILABLE" sense data will have a SCSI ML byte set, so scsi_eh_flush_done_q() will not set the scmd->result to DID_TIME_OUT for these commands. However, the successful commands that did not have sense data, must not get their result marked as DID_TIME_OUT by SCSI EH. Add a new flag SCMD_EH_SUCCESS_CMD, which tells SCSI EH to not mark a command as DID_TIME_OUT, even if it has scmd->result == SAM_STAT_GOOD. This will be used by libata in a follow-up patch. Signed-off-by: Niklas Cassel --- drivers/scsi/scsi_error.c | 3 ++- include/scsi/scsi_cmnd.h | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 2aa2c2aee6e7..51aa5c1e31b5 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -2165,7 +2165,8 @@ void scsi_eh_flush_done_q(struct list_head *done_q) * scsi_eh_get_sense), scmd->result is already * set, do not set DID_TIME_OUT. */ - if (!scmd->result) + if (!scmd->result && + !(scmd->flags & SCMD_EH_SUCCESS_CMD)) scmd->result |= (DID_TIME_OUT << 16); SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index c2cb5f69635c..c027648dba04 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -52,6 +52,11 @@ struct scsi_pointer { #define SCMD_TAGGED (1 << 0) #define SCMD_INITIALIZED (1 << 1) #define SCMD_LAST (1 << 2) +/* + * libata uses SCSI EH to fetch sense data for successful commands. + * SCSI EH should not overwrite scmd->result when SCMD_EH_SUCCESS_CMD is set. + */ +#define SCMD_EH_SUCCESS_CMD (1 << 3) #define SCMD_FAIL_IF_RECOVERING (1 << 4) /* flags preserved across unprep / reprep */ #define SCMD_PRESERVED_FLAGS (SCMD_INITIALIZED | SCMD_FAIL_IF_RECOVERING) From patchwork Thu Dec 8 10:59:27 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 632156 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E7554C6377E for ; Thu, 8 Dec 2022 11:03:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230006AbiLHLDc (ORCPT ); Thu, 8 Dec 2022 06:03:32 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35804 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230100AbiLHLCk (ORCPT ); Thu, 8 Dec 2022 06:02:40 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DC24B1A832 for ; Thu, 8 Dec 2022 03:01:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497268; x=1702033268; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=1yJjVrTjEzab2VnGecsAuFT78Y4qRfR29S6StL8QqBU=; b=IOX/FcEYYUyIekaM7856v5WuvRsdUGxDMhQkGgXhZnP0I/SPZdOyNs2W qr6qO6jfQK6YfQW5kI1/cM2q9/bV2SHnR1FI0PjsazKYcZtApqigO/Mvr Y57yuVCf4iDROILLNHNZ+jvVa4lN/sdnZ3cRYwNAaqIU4QPGJ4mm4vC9Y 2wTJxeYWhEdg4sRqh9sj68k6vgezrFwjtFklP+IO2+z3ApNajXVz4PY9y NunAA57wsxrm95euq5P/uFhm3eXGmFvVsYuFBWLGWhfOjXXakazcfLnPB piQ3b9CtA/UgDGubcOcQVfLUpk7sm/rCjbkCofEVvo0B/0Yn11buymNT0 A==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333394" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:01:08 +0800 IronPort-SDR: rK5MtyWWdclb6Ag0UUr+xTaBhoZkW8C0PuPCDfAymUW/KqvcA49St0apzW/89H4uTnL+IdGsrC W0fbO9bzBXMiI/3FmlTftcgaOb5MpuJ9u1YRh3t1HBlyfaDP8Xk8ronIHNOa9AQHdVj4+t4bmc HTZGiE7klkNbENFaWMBMKYjhAieyM8Fg6QdVekX7DEQxkZm0XVxhy/L9dBg9EOLBt0OqahLPHt FSPdgyybbIseYnys9mYT7mYYwXhI4bsh9CTjDBx/TmhVJTjnm4FJicQ7g43LTWuukJiEXf0dE5 EqA= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:13:53 -0800 IronPort-SDR: nA9FqdtM2Za3pgJl07RKaqIx310f20LOp+1VS+NvUt+qfMtZBVq3BmZz3aEimK06837Z1cms77 DfYtj3ODKDjm7fI1JXRXC009rqwuUoP5z9r+P3b1xBySnt+AJRt8JE4QAN1dMr2obY/U77oz5+ gRLv4oCtPr12OSETek3dhvlBXVagkq7JybC57Tyf/diV0mGj+KeQefcZp2+6prhvOAw9YW7b/p HTqePEZ1HUW6eBoJVHksHg9JKtSwoFKMoj7Pkjz6Atdj9a6srt3ydIsJl4HDUbdMbOafJBeJt5 Ju4= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:01:08 -0800 From: Niklas Cassel To: "James E.J. Bottomley" , "Martin K. Petersen" Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Niklas Cassel Subject: [PATCH 11/25] scsi: move get_scsi_ml_byte() to scsi_priv.h Date: Thu, 8 Dec 2022 11:59:27 +0100 Message-Id: <20221208105947.2399894-12-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Move get_scsi_ml_byte() to scsi_priv.h since both scsi_lib.c and scsi_error.c will need to use this helper in a follow-up patch. Signed-off-by: Niklas Cassel --- drivers/scsi/scsi_lib.c | 5 ----- drivers/scsi/scsi_priv.h | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 9ed1ebcb7443..d243ebc5ad54 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -579,11 +579,6 @@ static bool scsi_end_request(struct request *req, blk_status_t error, return false; } -static inline u8 get_scsi_ml_byte(int result) -{ - return (result >> 8) & 0xff; -} - /** * scsi_result_to_blk_status - translate a SCSI result code into blk_status_t * @result: scsi error code diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 96284a0e13fe..4f97e126c6fb 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -29,6 +29,11 @@ enum scsi_ml_status { SCSIML_STAT_TGT_FAILURE = 0x04, /* Permanent target failure */ }; +static inline u8 get_scsi_ml_byte(int result) +{ + return (result >> 8) & 0xff; +} + /* * Scsi Error Handler Flags */ From patchwork Thu Dec 8 10:59:28 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 633197 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 11CE0C64E67 for ; Thu, 8 Dec 2022 11:03:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230025AbiLHLDe (ORCPT ); Thu, 8 Dec 2022 06:03:34 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35658 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229758AbiLHLCn (ORCPT ); Thu, 8 Dec 2022 06:02:43 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9DFD083244 for ; Thu, 8 Dec 2022 03:01:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497271; x=1702033271; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=C0o70dzvp5L1imY2JoWlmSXhdbkUb91EcTTvwd5gWt8=; b=JkfhF1/FQwQRlH0HlYduRb2uCXCQSyEaCO/UHJvZEcKmFE3dQ4YIFDBI ly2o0owNNfjGQrixUmz9HHLL2ljOI4ASIHwzdfaUUS+GfecYrLKZ9CoY0 xG+4J082gElXlGkuxBtCMUr2PMncphSgxSLRq9qyFshL3rphj1Sq3W+ga Jeh1Eb5eyrfvLXGX+ZFhptyKorhwXE5xtcUeVzDCk3yTBASS8lwyCUlRu Zb+6zEnCZiMWblIUtPUJvQ4xa7pkZiOsU6fSl1inkeneS3bdByjj2K8cP Vqki4ZcUpUudzDt1wRPKCYVROQkuCufd2a0MaEbZqlR10cgGGucDbpceh g==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333397" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:01:11 +0800 IronPort-SDR: OVNPAN37wyWaRkcYdC+Bv2ONuSGM1Ytf90hrRzsHdpp2kkSnEAKy2Xlh45hZeY89c90Lf3CcTi ZRP2NeR4Iq3wmNu5AafCDXEvHabDc7A5W20A4n+MapDVIo4bexEZX+DVzvCnF5s1S008JYdEka 7uiKMFNVKL7TeyxsycJea4Xwc9xNNxV0hZ+AN5vswlck8HI53mSeXZ0v0f3hFeuylgzWt845MB Dl4kAeI2qAweYoBbo27YCovxFsfMciBuJMIBin51axzWYsQRyF0I12nBKpBh//RD4+I66m6vcf jxI= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:13:56 -0800 IronPort-SDR: ZnB4waG20WGS5oaK5nvTNxME/Vir9ZqDWcajd9GAq7LxO94zQiUIY0F1Faezw2vazownDC+lhE miD+Uz/wywaTixHTGrC3wMIosiDCNpN3Elh+xB2GOH35lvWn8lkD+uO18pxOCUVTasWZnEQfFk aWlcl5Oz3iR8qWNnhkPfXmzq7wa97SE0yWnGNUKmBhbHY6HTo3rDS4xT9wixhLeQ+KCSztJ3UX mQj6uU02gABkJHYe5XTm9MDpuf79K62FCIQ8u77QGRjYV2nTIi3mXekqGW2zr2l850GIcBOsG+ j1g= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:01:10 -0800 From: Niklas Cassel To: "James E.J. Bottomley" , "Martin K. Petersen" Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Damien Le Moal Subject: [PATCH 12/25] scsi: support retrieving sub-pages of mode pages Date: Thu, 8 Dec 2022 11:59:28 +0100 Message-Id: <20221208105947.2399894-13-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org From: Damien Le Moal Allow scsi_mode_sense() to retrieve sub-pages of mode pages by adding the subpage argument. Change all the current caller sites to specify the subpage 0. Signed-off-by: Damien Le Moal --- drivers/scsi/scsi_lib.c | 4 +++- drivers/scsi/scsi_transport_sas.c | 2 +- drivers/scsi/sd.c | 9 ++++----- drivers/scsi/sr.c | 2 +- include/scsi/scsi_device.h | 5 +++-- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index d243ebc5ad54..e64fd8f495d7 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2142,6 +2142,7 @@ EXPORT_SYMBOL_GPL(scsi_mode_select); * @sdev: SCSI device to be queried * @dbd: set to prevent mode sense from returning block descriptors * @modepage: mode page being requested + * @subpage: sub-page of the mode page being requested * @buffer: request buffer (may not be smaller than eight bytes) * @len: length of request buffer. * @timeout: command timeout @@ -2153,7 +2154,7 @@ EXPORT_SYMBOL_GPL(scsi_mode_select); * Returns zero if successful, or a negative error number on failure */ int -scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, +scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, int subpage, unsigned char *buffer, int len, int timeout, int retries, struct scsi_mode_data *data, struct scsi_sense_hdr *sshdr) { @@ -2169,6 +2170,7 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, dbd = sdev->set_dbd_for_ms ? 8 : dbd; cmd[1] = dbd & 0x18; /* allows DBD and LLBA bits */ cmd[2] = modepage; + cmd[3] = subpage; /* caller might not be interested in sense, but we need it */ if (!sshdr) diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 74b99f2b0b74..d704c484a251 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -1245,7 +1245,7 @@ int sas_read_port_mode_page(struct scsi_device *sdev) if (!buffer) return -ENOMEM; - error = scsi_mode_sense(sdev, 1, 0x19, buffer, BUF_SIZE, 30*HZ, 3, + error = scsi_mode_sense(sdev, 1, 0x19, 0, buffer, BUF_SIZE, 30*HZ, 3, &mode_data, NULL); if (error) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 47dafe6b8a66..77259716ca75 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -184,7 +184,7 @@ cache_type_store(struct device *dev, struct device_attribute *attr, return count; } - if (scsi_mode_sense(sdp, 0x08, 8, buffer, sizeof(buffer), SD_TIMEOUT, + if (scsi_mode_sense(sdp, 0x08, 8, 0, buffer, sizeof(buffer), SD_TIMEOUT, sdkp->max_retries, &data, NULL)) return -EINVAL; len = min_t(size_t, sizeof(buffer), data.length - data.header_length - @@ -2596,9 +2596,8 @@ sd_do_mode_sense(struct scsi_disk *sdkp, int dbd, int modepage, if (sdkp->device->use_10_for_ms && len < 8) len = 8; - return scsi_mode_sense(sdkp->device, dbd, modepage, buffer, len, - SD_TIMEOUT, sdkp->max_retries, data, - sshdr); + return scsi_mode_sense(sdkp->device, dbd, modepage, 0, buffer, len, + SD_TIMEOUT, sdkp->max_retries, data, sshdr); } /* @@ -2855,7 +2854,7 @@ static void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer) if (sdkp->protection_type == 0) return; - res = scsi_mode_sense(sdp, 1, 0x0a, buffer, 36, SD_TIMEOUT, + res = scsi_mode_sense(sdp, 1, 0x0a, 0, buffer, 36, SD_TIMEOUT, sdkp->max_retries, &data, &sshdr); if (res < 0 || !data.header_length || diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index a278b739d0c5..d2bbde7172ac 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -827,7 +827,7 @@ static int get_capabilities(struct scsi_cd *cd) scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr); /* ask for mode page 0x2a */ - rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, ms_len, + rc = scsi_mode_sense(cd->device, 0, 0x2a, 0, buffer, ms_len, SR_TIMEOUT, 3, &data, NULL); if (rc < 0 || data.length > ms_len || diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 3642b8e3928b..a499cdac2ce8 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -420,8 +420,9 @@ extern int scsi_track_queue_full(struct scsi_device *, int); extern int scsi_set_medium_removal(struct scsi_device *, char); extern int scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, - unsigned char *buffer, int len, int timeout, - int retries, struct scsi_mode_data *data, + int subpage, unsigned char *buffer, int len, + int timeout, int retries, + struct scsi_mode_data *data, struct scsi_sense_hdr *); extern int scsi_mode_select(struct scsi_device *sdev, int pf, int sp, unsigned char *buffer, int len, int timeout, From patchwork Thu Dec 8 10:59:29 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 633198 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0253AC6377C for ; Thu, 8 Dec 2022 11:03:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230048AbiLHLDf (ORCPT ); Thu, 8 Dec 2022 06:03:35 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35618 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230162AbiLHLCs (ORCPT ); Thu, 8 Dec 2022 06:02:48 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 41BB281D98 for ; Thu, 8 Dec 2022 03:01:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497274; x=1702033274; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=yNYIdsnzZpksEA3jejp5dI+tSwjiuvR+jdNItN4gElE=; b=O4BbbUnF3aaEKLCVhL8sJNdcQq+4HSTaAhXFFgktfpZ8P+ixJO10WvUw oZlLD6pWNtWdCvo3dp8pM2ha8K/hDJ61zBo0Oxa4ln6Jm12zmGsIheFD3 6H6KdOMMWJtJst4F4MGXPe7Vpxcu9n86Gb0Tn+u9PLyA+QZ6/Wwj9Gu3Y vfUykKRrfPPBkwvykgnYx1y8F84tSol3JWPn+6FAfrn83XfHy/7z4u+Yv ROBI4eGbLYb91xBcxfBubvhwoD4WYwyJT3j8z6IYqnMpjTRgIHb8okj/E Q7Ikro+R1iztZBUGORV+arOMI3b+L1R7r88SEppYC32YBr+ZgmjFqfHJZ Q==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333399" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:01:13 +0800 IronPort-SDR: tNXlxMRH2gk2jPwH4/lWwYdefE8Ns78Z51Hsxft/HDCBTEqoGVUiN6UcAySWhFfz0zNBTuSNIc iSrcDxOA5gZgT8LIIe4lFykHICupJMU9yRmd+NEuqlJP2wCn19SulWjZUFqSFZWbn57jx4/Kdv J3Vzo+sclSfpDHiuPc8Pru2AnS5ki7fOR+QkdaPnPjQpvolTjNZ3gS27mGPfDJteegcG4MnElm MOlnxjC2kfE/T/et0CrtJVjc1k5meslMW1yoo4XLZmsreWXxS54GSEJqLugpmxbZTgxLvsP/cl Ipk= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:13:58 -0800 IronPort-SDR: Dc0Xfk/MwDDo54ueBL5q35ERT23DcEnbEdgrwtlf9ueMeaug6ySDNwyGoW7w3xK9Hc2ao3KSEB AKurT2KeiV4uTa28nVTV3TQ47BrOW3sCtw8gv2G2EIqcx86INMkEoe94LysE3ap2m0SlobOUm7 ITUyq4xj0kaZi1tr6FT6KOsuXn+akUd0Kb6BAbtK6wflTEFn5e7KDkMbTCddqQ+rD8wkL8SMEq iXjeRI7Io6v61lA531aVWIg7TC3Buf8VvwQIAduWEYW7bBFcyD8+gQ9xYzVJ3/o3ONKsju3rfA 3nA= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:01:13 -0800 From: Niklas Cassel To: "James E.J. Bottomley" , "Martin K. Petersen" Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Damien Le Moal Subject: [PATCH 13/25] scsi: support service action in scsi_report_opcode() Date: Thu, 8 Dec 2022 11:59:29 +0100 Message-Id: <20221208105947.2399894-14-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org From: Damien Le Moal The REPORT_SUPPORTED_OPERATION_CODES command allows checking for support of commands that have the same opcode but different service actions, such as READ 32 and WRITE 32. However, the current implementation of scsi_report_opcode() only allows checking an operation code without a service action differentiation. Add the "sa" argument to scsi_report_opcode() to allow passing a service action. If a non-zero service action is specified, the reporting options field value is set to 3 to have the service action field taken into account by the device. If no service action field is specified (zero), the reporting options field is set to 1 as before. Signed-off-by: Damien Le Moal --- drivers/scsi/scsi.c | 28 +++++++++++++++++++--------- drivers/scsi/sd.c | 10 +++++----- include/scsi/scsi_device.h | 3 ++- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 1426b9b03612..e69a5dd5abd2 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -494,18 +494,22 @@ void scsi_attach_vpd(struct scsi_device *sdev) } /** - * scsi_report_opcode - Find out if a given command opcode is supported + * scsi_report_opcode - Find out if a given command is supported * @sdev: scsi device to query * @buffer: scratch buffer (must be at least 20 bytes long) * @len: length of buffer - * @opcode: opcode for command to look up - * - * Uses the REPORT SUPPORTED OPERATION CODES to look up the given - * opcode. Returns -EINVAL if RSOC fails, 0 if the command opcode is - * unsupported and 1 if the device claims to support the command. + * @opcode: opcode for the command to look up + * @sa: service action for the command to look up + * + * Uses the REPORT SUPPORTED OPERATION CODES to check support for the + * command identified with @opcode and @sa. If the command does not + * have a service action, @sa must be 0. Returns -EINVAL if RSOC fails, + * 0 if the command is not supported and 1 if the device claims to + * support the command. */ int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer, - unsigned int len, unsigned char opcode) + unsigned int len, unsigned char opcode, + unsigned short sa) { unsigned char cmd[16]; struct scsi_sense_hdr sshdr; @@ -526,8 +530,14 @@ int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer, memset(cmd, 0, 16); cmd[0] = MAINTENANCE_IN; cmd[1] = MI_REPORT_SUPPORTED_OPERATION_CODES; - cmd[2] = 1; /* One command format */ - cmd[3] = opcode; + if (!sa) { + cmd[2] = 1; /* One command format */ + cmd[3] = opcode; + } else { + cmd[2] = 3; /* One command format with service action */ + cmd[3] = opcode; + put_unaligned_be16(sa, &cmd[4]); + } put_unaligned_be32(request_len, &cmd[6]); memset(buffer, 0, len); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 77259716ca75..2b56ff4fcf8a 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -3038,7 +3038,7 @@ static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer) return; } - if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, INQUIRY) < 0) { + if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, INQUIRY, 0) < 0) { struct scsi_vpd *vpd; sdev->no_report_opcodes = 1; @@ -3054,10 +3054,10 @@ static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer) rcu_read_unlock(); } - if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, WRITE_SAME_16) == 1) + if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, WRITE_SAME_16, 0) == 1) sdkp->ws16 = 1; - if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, WRITE_SAME) == 1) + if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, WRITE_SAME, 0) == 1) sdkp->ws10 = 1; } @@ -3069,9 +3069,9 @@ static void sd_read_security(struct scsi_disk *sdkp, unsigned char *buffer) return; if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, - SECURITY_PROTOCOL_IN) == 1 && + SECURITY_PROTOCOL_IN, 0) == 1 && scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, - SECURITY_PROTOCOL_OUT) == 1) + SECURITY_PROTOCOL_OUT, 0) == 1) sdkp->security = 1; } diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index a499cdac2ce8..f6d1d9890839 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -433,7 +433,8 @@ extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout, extern int scsi_get_vpd_page(struct scsi_device *, u8 page, unsigned char *buf, int buf_len); extern int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer, - unsigned int len, unsigned char opcode); + unsigned int len, unsigned char opcode, + unsigned short sa); extern int scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state); extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type, From patchwork Thu Dec 8 10:59:30 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 633195 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2FCBBC63715 for ; Thu, 8 Dec 2022 11:04:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230260AbiLHLDw (ORCPT ); Thu, 8 Dec 2022 06:03:52 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35502 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230284AbiLHLCx (ORCPT ); Thu, 8 Dec 2022 06:02:53 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BA3865BD66; Thu, 8 Dec 2022 03:01:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497276; x=1702033276; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=fkMDbHJKptb+eHoWQREDqIKMzmlWlbmdh50ygb3ZD+w=; b=dRQVTaZ1EesjFjoqAvjNVXAcoEJcGbbNd4DeburTqEBi7mkbfgiRgcku nEvumr1j+0lUiZbWAyJ3fix8kzw3wcx04I6lXDywroE4y13Q3jta2EZjy sczA2yCilm+VwaqvGJ9oM2vIJaW5X3p4aReOSentsqIzQLoLS5qLgMwux lvx08tV+Egsn261frgZFXMPdokuzZJhUJLOTWRLiFxzk0BU/j4BlCxvyv UibxkFbOnd7ulFs1yfZGidiE7duMv25c7s+2W0Vjv6qIEbM58fohJvwym udu6ISPCYJXOxPHOzcHWVv5m4jEo949FrY+DN/tkXk79koZI99ljIgDml A==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333401" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:01:16 +0800 IronPort-SDR: ZBokXB94yfwe0hU26qR8hBoBhrFxVNfibaMDPzL4Vh98DYJNcfFdK4ZEH6RgvwpXc3HvnUQJCZ PkaTXoBLpVSwmGZtrCTcgEZXcG1JwSLkSPPjHufmQQKjNRmae4r2iuVs4qzwUgRIsIMSSbvgsS tSgSwNPdwfqxw504l8eu5AxAr2A3St+pEt6YHrfvLXxtuE1ziK1fd+C5kY3CJuZc6cNw4Wj//0 ZemBaD/rwxy2D6UXNDfozBbUKq0A97FneXm21yu/fMRQ6YTz/HLba2mqYdEzoMnHK2a1Nax+V1 nDk= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:14:01 -0800 IronPort-SDR: 5f6iq0uF0+5KUFxVzbvJEOSn9BUHltZIQiA9/o3Hata+JGC6s24sTmVidgNLX59xP3rIMtb9U7 SdudTsfEIyb+AFKwgJOPHN0cRgzalM2I/lKviYg/TlPZTIwQf58FLmc6Af8pTWEzrsIavN+qjT BOxDuNpg7zmkPzcoQCXGravX/odHCINJ6PwTYu+qCs9vHlf4HP1k22r507Y6MImlTI/SGyPVpp Ua+RY465dfudAyz2VgzkYQE3VtZgU+ejyZYB5oacRwMaX8CuPbkCFFYDkbwLwbDYXDxSuxujc2 BV8= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:01:15 -0800 From: Niklas Cassel To: Paolo Valente , Jens Axboe Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Damien Le Moal , linux-block@vger.kernel.org Subject: [PATCH 14/25] block: introduce duration-limits priority class Date: Thu, 8 Dec 2022 11:59:30 +0100 Message-Id: <20221208105947.2399894-15-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org From: Damien Le Moal Introduce the IOPRIO_CLASS_DL priority class to indicate that IOs should be executed using duration-limits targets. The duration target to apply to a command is indicated using the priority level. Up to 8 levels are supported, with level 0 indiating "no limit". This priority class has effect only if the target device supports the command duration limits feature and this feature is enabled by the user. In BFQ and mq-deadline, all requests with this new priority class are handled using the highest priority class RT and priority level 0. Signed-off-by: Damien Le Moal --- block/bfq-iosched.c | 10 ++++++++++ block/blk-ioprio.c | 3 +++ block/ioprio.c | 3 ++- block/mq-deadline.c | 1 + include/linux/ioprio.h | 2 +- include/uapi/linux/ioprio.h | 7 +++++++ 6 files changed, 24 insertions(+), 2 deletions(-) diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c index a72304c728fc..62cf7fa7e0cf 100644 --- a/block/bfq-iosched.c +++ b/block/bfq-iosched.c @@ -5384,6 +5384,14 @@ bfq_set_next_ioprio_data(struct bfq_queue *bfqq, struct bfq_io_cq *bic) bfqq->new_ioprio_class = IOPRIO_CLASS_IDLE; bfqq->new_ioprio = 7; break; + case IOPRIO_CLASS_DL: + /* + * For the duration-limits class, we want the disk to do the + * scheduling. So map all levels to the highest RT level. + */ + bfqq->new_ioprio = 0; + bfqq->new_ioprio_class = IOPRIO_CLASS_RT; + break; } if (bfqq->new_ioprio >= IOPRIO_NR_LEVELS) { @@ -5510,6 +5518,8 @@ static struct bfq_queue **bfq_async_queue_prio(struct bfq_data *bfqd, return &bfqg->async_bfqq[1][ioprio]; case IOPRIO_CLASS_IDLE: return &bfqg->async_idle_bfqq; + case IOPRIO_CLASS_DL: + return &bfqg->async_bfqq[0][0]; default: return NULL; } diff --git a/block/blk-ioprio.c b/block/blk-ioprio.c index 8bb6b8eba4ce..dfb5c3f447f4 100644 --- a/block/blk-ioprio.c +++ b/block/blk-ioprio.c @@ -27,6 +27,7 @@ * @POLICY_RESTRICT_TO_BE: modify IOPRIO_CLASS_NONE and IOPRIO_CLASS_RT into * IOPRIO_CLASS_BE. * @POLICY_ALL_TO_IDLE: change the I/O priority class into IOPRIO_CLASS_IDLE. + * @POLICY_ALL_TO_DL: change the I/O priority class into IOPRIO_CLASS_DL. * * See also . */ @@ -35,6 +36,7 @@ enum prio_policy { POLICY_NONE_TO_RT = 1, POLICY_RESTRICT_TO_BE = 2, POLICY_ALL_TO_IDLE = 3, + POLICY_ALL_TO_DL = 4, }; static const char *policy_name[] = { @@ -42,6 +44,7 @@ static const char *policy_name[] = { [POLICY_NONE_TO_RT] = "none-to-rt", [POLICY_RESTRICT_TO_BE] = "restrict-to-be", [POLICY_ALL_TO_IDLE] = "idle", + [POLICY_ALL_TO_DL] = "duration-limits", }; static struct blkcg_policy ioprio_policy; diff --git a/block/ioprio.c b/block/ioprio.c index 32a456b45804..1b3a9da82597 100644 --- a/block/ioprio.c +++ b/block/ioprio.c @@ -37,6 +37,7 @@ int ioprio_check_cap(int ioprio) switch (class) { case IOPRIO_CLASS_RT: + case IOPRIO_CLASS_DL: /* * Originally this only checked for CAP_SYS_ADMIN, * which was implicitly allowed for pid 0 by security @@ -47,7 +48,7 @@ int ioprio_check_cap(int ioprio) if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_NICE)) return -EPERM; fallthrough; - /* rt has prio field too */ + /* RT and DL have prio field too */ case IOPRIO_CLASS_BE: if (data >= IOPRIO_NR_LEVELS || data < 0) return -EINVAL; diff --git a/block/mq-deadline.c b/block/mq-deadline.c index f10c2a0d18d4..526d0ea4dbf9 100644 --- a/block/mq-deadline.c +++ b/block/mq-deadline.c @@ -113,6 +113,7 @@ static const enum dd_prio ioprio_class_to_prio[] = { [IOPRIO_CLASS_RT] = DD_RT_PRIO, [IOPRIO_CLASS_BE] = DD_BE_PRIO, [IOPRIO_CLASS_IDLE] = DD_IDLE_PRIO, + [IOPRIO_CLASS_DL] = DD_RT_PRIO, }; static inline struct rb_root * diff --git a/include/linux/ioprio.h b/include/linux/ioprio.h index 7578d4f6a969..2f3fc2fbd668 100644 --- a/include/linux/ioprio.h +++ b/include/linux/ioprio.h @@ -20,7 +20,7 @@ static inline bool ioprio_valid(unsigned short ioprio) { unsigned short class = IOPRIO_PRIO_CLASS(ioprio); - return class > IOPRIO_CLASS_NONE && class <= IOPRIO_CLASS_IDLE; + return class > IOPRIO_CLASS_NONE && class <= IOPRIO_CLASS_DL; } /* diff --git a/include/uapi/linux/ioprio.h b/include/uapi/linux/ioprio.h index f70f2596a6bf..15908b9e9d8c 100644 --- a/include/uapi/linux/ioprio.h +++ b/include/uapi/linux/ioprio.h @@ -29,6 +29,7 @@ enum { IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE, + IOPRIO_CLASS_DL, }; /* @@ -37,6 +38,12 @@ enum { #define IOPRIO_NR_LEVELS 8 #define IOPRIO_BE_NR IOPRIO_NR_LEVELS +/* + * The Duration limits class allows 8 levels: level 0 for "no limit" and levels + * 1 to 7, each corresponding to a read or write limit descriptor. + */ +#define IOPRIO_DL_NR_LEVELS 8 + enum { IOPRIO_WHO_PROCESS = 1, IOPRIO_WHO_PGRP, From patchwork Thu Dec 8 10:59:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 632154 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9D72EC6370A for ; Thu, 8 Dec 2022 11:04:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229575AbiLHLDs (ORCPT ); Thu, 8 Dec 2022 06:03:48 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38484 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230310AbiLHLC4 (ORCPT ); Thu, 8 Dec 2022 06:02:56 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F10455CD2A; Thu, 8 Dec 2022 03:01:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497278; x=1702033278; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=DL3+bdlAlVJyOHJFHmnZNgLXM8VisYLIjqtEpyzmztw=; b=iRb2dIfvFzFFEZP+QquWFc/cf3USk/BeagOQhVPdugKAd3TV3HFYzJNy D3wwb2z4L9qFODfUkkdXp/KXqZEdfBA1VUrTDz+9JQBv6sK4hyWKNGCs0 zYDbmbFUnfRaPq3Iy6M3eIi4PV89Oe9zqthiKN39T81NuZcB62Jn382Hk qiAFqs9jeU38wr+1L5+6SOzNiRGlF1Aqs61v61S7LTPZoKfSDLs6FBtIh uynxFd28B1ze4M3lwmWxvvPnKpD7ECpjqBU9ejmD/1ar2jTrSuSVLu1Yt QxJwpuPYm0da2rfyTgqCc8ULEqTBVWDXV5GqnimlsxriRMVuFCM1ig/M4 Q==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333404" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:01:18 +0800 IronPort-SDR: GGAF7BE+hXSUkIi57qZIzEk49biCE6b2dC7rUoko3DgyPsoaaeIBLtLvgLeRAK+kLl/mpPNGX8 fHXKSAaB4P/qAVHO6OxopBHjP2K9xXgFth6vlvDvED35g/1W2D3yeDUKbD7LqBGyutGX2tVBut iMHF6tqRxFR39pN3egwJ7E+31fOd6OirLwEqpLCaAisTNgx/0pnQquXVkm/9Z4g8wdfDoJNVT4 eKDN1Ug4eBjHANMDWJJ2WKSl9HSzVTOvWBr3Bse2fiymmSNS/sKtCswnPABfmD84r/UkRmcIKl xNg= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:14:03 -0800 IronPort-SDR: 1giZiys6opqWDb8rUovSg/VnLPD94zAlMtInV7HbHOLoWaD87iyxxlfppqjpzE0ZoMNCDyeCaT 7kdhnzqrdiorwEF7XLOpHWh+thTk6ZgzwsGF4paPiJ/3K5O8Fnq9Jg5yypdV1sIaZpZgFY6sEG 1AoWpEJr+zvAy/O9S+GUEcLOrTHNkUcEuSQsA80FG040YqDhFg3m1blTyt/v6HVyjSEwoIYrPc bU34Dgcn28l3wbUs3OcBd1bEFWh0y6H4Knz/wfO3QLeMiZ1G2Om9F5oJ9B5bDYpKDDKHyvzfmj Lsc= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:01:18 -0800 From: Niklas Cassel To: Jens Axboe Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Damien Le Moal , Niklas Cassel , linux-block@vger.kernel.org Subject: [PATCH 15/25] block: introduce BLK_STS_DURATION_LIMIT Date: Thu, 8 Dec 2022 11:59:31 +0100 Message-Id: <20221208105947.2399894-16-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org From: Damien Le Moal Introduce the new block IO status BLK_STS_DURATION_LIMIT for LLDDs to report command that failed due to a command duration limit being exceeded. This new status is mapped to the ETIME error code to allow users to differentiate "soft" duration limit failures from other more serious hardware related errors. Co-developed-by: Niklas Cassel Signed-off-by: Niklas Cassel Signed-off-by: Damien Le Moal --- block/blk-core.c | 3 +++ include/linux/blk_types.h | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/block/blk-core.c b/block/blk-core.c index 3866b6c4cd88..5cbb0e5f189c 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -170,6 +170,9 @@ static const struct { [BLK_STS_ZONE_OPEN_RESOURCE] = { -ETOOMANYREFS, "open zones exceeded" }, [BLK_STS_ZONE_ACTIVE_RESOURCE] = { -EOVERFLOW, "active zones exceeded" }, + /* Command duration limit device-side timeout */ + [BLK_STS_DURATION_LIMIT] = { -ETIME, "duration limit exceeded" }, + /* everything else not covered above: */ [BLK_STS_IOERR] = { -EIO, "I/O" }, }; diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index e0b098089ef2..a357bbd51546 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -166,6 +166,12 @@ typedef u16 blk_short_t; */ #define BLK_STS_OFFLINE ((__force blk_status_t)17) +/* + * BLK_STS_DURATION_LIMIT is returned from the driver when the target device + * aborted the command because it exceeded one of its Command Duration Limits. + */ +#define BLK_STS_DURATION_LIMIT ((__force blk_status_t)18) + /** * blk_path_error - returns true if error may be path related * @error: status the request was completed with From patchwork Thu Dec 8 10:59:32 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 632152 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4C6D8C63718 for ; Thu, 8 Dec 2022 11:04:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230267AbiLHLDy (ORCPT ); Thu, 8 Dec 2022 06:03:54 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35656 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230354AbiLHLDB (ORCPT ); Thu, 8 Dec 2022 06:03:01 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E458A60B68; Thu, 8 Dec 2022 03:01:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497283; x=1702033283; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=mVpZtl2tFg3Ckd5fmjDsooFADqyv2MXcG51EfFVn4Gw=; b=BPmpaQq/ifZP+ee4Ny23HIBuHoAub+7G+rLp+o4TNH2q2DwV+hTQ26tW kNya5xM2CxtHXIMI0swuxJdnTRl2PYCgrdjKjLjKyks1O71C9rpKvl8w/ rXEWqY7hCXd0JLSwAq2QB0uhoLPtM0gCNWY231fQuOUTmf/70uV1yGs6P f31EqwkrfoM4F6YJ3ynvBDPTYLbhnqa3fAoJVYgqw+y+qhoESQiTM2z9L L9+c1HXKSPwq3294cKoOqHp9g5kstNvc+gzhZwdwTbOTOeLBAEt3LUsZl y4iOu/615ssYb/PvRkqf/68UEG/WN+1lQ1f+MiUAikL48XazEyNHsUFXw g==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333406" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:01:21 +0800 IronPort-SDR: 0gjqIPQ4dXlP2OlfhqXmsP/xUstL15MpvsoQ6k2M/3d45yBo46cAZkfcAOzzPEcKQEtZqjUX9a LBpuhkfRvm7nV64s2uSXJ7x80eLlALNwqjPvp4ZdGzXnRC8YvpHeKh4VRvtOllRg2dz1bV5uGl 8BxC+Uf2JDNHK9pRQzRQ3IqxpVMO4cMaPMwPt0N3aii7IqZ+T5m+G+onotVvm09SsPt1WZ37BN RSr9BoT948V54mqnZO6CD45qCKGg3Wlzr8wf/0EvcotXTazHShMfRG5JaUUPD8sMU9qY+k79FO B9Q= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:14:06 -0800 IronPort-SDR: uzGC6IonMacszw9EqOqzPuQBHfQnyeh0/tyvolQbsjn5TVv2JgzmstWyo5s6NI47/fXGJi3iUe HEbtAqXdg4Txee4LoMBc7N8rMaN1lS7gtuiXOjMeAbHgyLc41FYJS8k9r05jywuiyMg/bbGv5P dtQZrHbNKh7WJKZ6HMlOdn4xHRsiPDhb1BsC+Ev1/DZH4jUKdNLX09dy5Aon7AmyvG//pU2SkI MyQpNrlu2GKFrKH+h/JP5lzd/OTc5C5jq5B6TNmFAG2iQkI/BeLMxd6z8OrS5ceZ6ReQPrgAQH xqY= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:01:20 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Niklas Cassel , linux-ide@vger.kernel.org Subject: [PATCH 16/25] ata: libata: detect support for command duration limits Date: Thu, 8 Dec 2022 11:59:32 +0100 Message-Id: <20221208105947.2399894-17-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org From: Damien Le Moal Use the supported capabilities identify device data log page to detect if a device supports the command duration limits feature. For devices supporting this feature, set the device flag ATA_DFLAG_CDL. To support scsi-ata translation, retrieve the command duration limits log page 18h and cache this page content using the cdl array added to the ata_device data structure. Co-developed-by: Niklas Cassel Signed-off-by: Niklas Cassel Signed-off-by: Damien Le Moal --- drivers/ata/libata-core.c | 52 ++++++++++++++++++++++++++++++++++++++- drivers/ata/libata-scsi.c | 17 ++++++------- include/linux/ata.h | 5 +++- include/linux/libata.h | 6 ++++- 4 files changed, 68 insertions(+), 12 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 6b03bebcde50..d7a602a8f59e 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2363,6 +2363,54 @@ static void ata_dev_config_trusted(struct ata_device *dev) dev->flags |= ATA_DFLAG_TRUSTED; } +static void ata_dev_config_cdl(struct ata_device *dev) +{ + struct ata_port *ap = dev->link->ap; + unsigned int err_mask; + u64 val; + + if (ata_id_major_version(dev->id) < 12) + goto not_supported; + + if (!ata_log_supported(dev, ATA_LOG_IDENTIFY_DEVICE) || + !ata_identify_page_supported(dev, ATA_LOG_SUPPORTED_CAPABILITIES)) + goto not_supported; + + err_mask = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE, + ATA_LOG_SUPPORTED_CAPABILITIES, + ap->sector_buf, 1); + if (err_mask) + goto not_supported; + + /* Check Command Duration Limit Supported bits */ + val = get_unaligned_le64(&ap->sector_buf[168]); + if (!(val & BIT_ULL(63)) || !(val & BIT_ULL(0))) + goto not_supported; + + /* Warn the user if command duration guideline is not supported */ + if (!(val & BIT_ULL(1))) + ata_dev_warn(dev, + "Command duration guideline is not supported\n"); + + /* + * Command duration limits is supported: cache the CDL log page 18h + * (command duration descriptors). + */ + err_mask = ata_read_log_page(dev, ATA_LOG_CDL, 0, ap->sector_buf, 1); + if (err_mask) { + ata_dev_warn(dev, "Read Command Duration Limits log failed\n"); + goto not_supported; + } + + memcpy(dev->cdl, ap->sector_buf, ATA_LOG_CDL_SIZE); + dev->flags |= ATA_DFLAG_CDL; + + return; + +not_supported: + dev->flags &= ~ATA_DFLAG_CDL; +} + static int ata_dev_config_lba(struct ata_device *dev) { const u16 *id = dev->id; @@ -2508,12 +2556,13 @@ static void ata_dev_print_features(struct ata_device *dev) return; ata_dev_info(dev, - "Features:%s%s%s%s%s%s\n", + "Features:%s%s%s%s%s%s%s\n", dev->flags & ATA_DFLAG_TRUSTED ? " Trust" : "", dev->flags & ATA_DFLAG_DA ? " Dev-Attention" : "", dev->flags & ATA_DFLAG_DEVSLP ? " Dev-Sleep" : "", dev->flags & ATA_DFLAG_NCQ_SEND_RECV ? " NCQ-sndrcv" : "", dev->flags & ATA_DFLAG_NCQ_PRIO ? " NCQ-prio" : "", + dev->flags & ATA_DFLAG_CDL ? " CDL" : "", dev->cpr_log ? " CPR" : ""); } @@ -2674,6 +2723,7 @@ int ata_dev_configure(struct ata_device *dev) ata_dev_config_zac(dev); ata_dev_config_trusted(dev); ata_dev_config_cpr(dev); + ata_dev_config_cdl(dev); dev->cdb_len = 32; if (print_info) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 78729fd9fbfd..042c1748815a 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -47,15 +47,14 @@ typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc); static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); -#define RW_RECOVERY_MPAGE 0x1 -#define RW_RECOVERY_MPAGE_LEN 12 -#define CACHE_MPAGE 0x8 -#define CACHE_MPAGE_LEN 20 -#define CONTROL_MPAGE 0xa -#define CONTROL_MPAGE_LEN 12 -#define ALL_MPAGES 0x3f -#define ALL_SUB_MPAGES 0xff - +#define RW_RECOVERY_MPAGE 0x1 +#define RW_RECOVERY_MPAGE_LEN 12 +#define CACHE_MPAGE 0x8 +#define CACHE_MPAGE_LEN 20 +#define CONTROL_MPAGE 0xa +#define CONTROL_MPAGE_LEN 12 +#define ALL_MPAGES 0x3f +#define ALL_SUB_MPAGES 0xff static const u8 def_rw_recovery_mpage[RW_RECOVERY_MPAGE_LEN] = { RW_RECOVERY_MPAGE, diff --git a/include/linux/ata.h b/include/linux/ata.h index 0c18499f60b6..b01e2cebe1fe 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -323,15 +323,18 @@ enum { ATA_LOG_SATA_NCQ = 0x10, ATA_LOG_NCQ_NON_DATA = 0x12, ATA_LOG_NCQ_SEND_RECV = 0x13, + ATA_LOG_CDL = 0x18, + ATA_LOG_CDL_SIZE = ATA_SECT_SIZE, ATA_LOG_IDENTIFY_DEVICE = 0x30, ATA_LOG_CONCURRENT_POSITIONING_RANGES = 0x47, /* Identify device log pages: */ + ATA_LOG_SUPPORTED_CAPABILITIES = 0x03, ATA_LOG_SECURITY = 0x06, ATA_LOG_SATA_SETTINGS = 0x08, ATA_LOG_ZONED_INFORMATION = 0x09, - /* Identify device SATA settings log:*/ + /* Identify device SATA settings log: */ ATA_LOG_DEVSLP_OFFSET = 0x30, ATA_LOG_DEVSLP_SIZE = 0x08, ATA_LOG_DEVSLP_MDAT = 0x00, diff --git a/include/linux/libata.h b/include/linux/libata.h index 3b7f5d9e2f87..2bb8027ae148 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -90,6 +90,7 @@ enum { ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */ ATA_DFLAG_AN = (1 << 7), /* AN configured */ ATA_DFLAG_TRUSTED = (1 << 8), /* device supports trusted send/recv */ + ATA_DFLAG_CDL = (1 << 9), /* supports cmd duration limits */ ATA_DFLAG_DMADIR = (1 << 10), /* device requires DMADIR */ ATA_DFLAG_NCQ_SEND_RECV = (1 << 11), /* device supports NCQ SEND and RECV */ ATA_DFLAG_NCQ_PRIO = (1 << 12), /* device supports NCQ priority */ @@ -114,7 +115,7 @@ enum { ATA_DFLAG_FEATURES_MASK = ATA_DFLAG_TRUSTED | ATA_DFLAG_DA | \ ATA_DFLAG_DEVSLP | ATA_DFLAG_NCQ_SEND_RECV | \ - ATA_DFLAG_NCQ_PRIO, + ATA_DFLAG_NCQ_PRIO | ATA_DFLAG_CDL, ATA_DEV_UNKNOWN = 0, /* unknown device */ ATA_DEV_ATA = 1, /* ATA device */ @@ -707,6 +708,9 @@ struct ata_device { /* Concurrent positioning ranges */ struct ata_cpr_log *cpr_log; + /* Command Duration Limits log support */ + u8 cdl[ATA_LOG_CDL_SIZE]; + /* error history */ int spdn_cnt; /* ering is CLEAR_END, read comment above CLEAR_END */ From patchwork Thu Dec 8 10:59:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 632151 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 95C01C6371D for ; Thu, 8 Dec 2022 11:04:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230288AbiLHLD4 (ORCPT ); Thu, 8 Dec 2022 06:03:56 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39550 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230357AbiLHLDC (ORCPT ); Thu, 8 Dec 2022 06:03:02 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0645860B7B; Thu, 8 Dec 2022 03:01:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497283; x=1702033283; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=CbISjLppXxJda0wbpgKO8tx1bXq4PqnF3kqkJG4azWc=; b=GLvW+VZd2RNNa0lzjyEYrqUF0ZV3Sp2SVquggcfs9plz7gIh5+AW7npy QWov9t86Gcy4Ubk5jhIWhxsbVAH5cqDIK/0hSf60PNlWNolXiSHtdlPkY 3Yutzm8SLE3TJ+KzCdVhxFqre0L99y5Pn96LmqQ2UjHQ6QbgaXurseqbh 2kELsDB4x4tWrUL3/xWPUpk/O72lfx/qNRTUn8QjL/FK5LQ1lJfjLdmHR LkTvdGoUQCJMKSfkbiMKoZOtICYDAZB8tQVz/QnCDMYqtVQ4E5TPXTb2d T8pcfKFWr7EZGz54EUf6zy/sOH0mfSeIaS5HwUPzBGwnhzaYyLPhCPk+u Q==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333408" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:01:23 +0800 IronPort-SDR: T97g4hz6isM4/FplK7XbgZfZ2If208TeqDLtqv4kSXG+efcHMqIZTu54cnZgdHshWyZwoPDqgH 1SLUdJ72/kFI0/3T5Sr03pWvXoMvBKKNtv8jpI6lCHd8aqEeAACJ3XEXBCxP2h98YViVgtXHWq NPEVfNyzwchXEMR+czGRucvsQpHXVHsbtsEo81piFqFtm7vjgnL4nwgXvX78Pnj+6rKFopri+I jp6RSZVrRF5qUHfR6XBmkqMYYe2CMqh/xbFjmPcaHw3QMgKJcs1bFo4bj1cBZziOXd2HTJvgoq D5U= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:14:08 -0800 IronPort-SDR: rAMMAhhop+EpmbOCz0KVGWHPIBrbVRVs5S9wV3sxQnq4zHeXZXapNTqZAD1q5ZsEl5KN9oVntM zkClnKxNxptVXjGjZ6aYscQV0zh54zms7c035Js0sDgH7a9qjWcsj60bk5klFjDr4GLXrJ0sun CLiEO5WGB4C62ev8rr+N6UNvjv2fU/pYISgwo/AOVxEHiBnDj0kgkgX/lhp0qWROiCsXeOU6mQ wuRlktVUVA3asZlUe9iuTNCaWPLFG2ihOgpmjh1FFaslO/9gSN4EBLZeDrFTW6/E8Z2sXlop8a HNk= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:01:22 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org Subject: [PATCH 17/25] ata: libata-scsi: handle CDL bits in ata_scsiop_maint_in() Date: Thu, 8 Dec 2022 11:59:33 +0100 Message-Id: <20221208105947.2399894-18-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org From: Damien Le Moal For a scsi MAINTENANCE_IN/MI_REPORT_SUPPORTED_OPERATION_CODES operation, add the translation of the rwcdlp and cdlp bits for the READ16 and WRITE16 commands. If the ATA device does not support command duration limits, these bits are always 0. If the ATA device supports command duration limits, the rwcdlp bit is set to 1 for READ16 and WRITE16 and the cdlp bits are set to 0x1 for READ16 and 0x2 for WRITE16. These correspond to the T2A mode page containing the read descriptors and to the T2B mode page containing the write descriptors, as defined in SAT-5. Signed-off-by: Damien Le Moal --- drivers/ata/libata-scsi.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 042c1748815a..2500f3ff24a5 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3264,7 +3264,7 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf) { struct ata_device *dev = args->dev; u8 *cdb = args->cmd->cmnd; - u8 supported = 0; + u8 supported = 0, cdlp = 0, rwcdlp = 0; unsigned int err = 0; if (cdb[2] != 1 && cdb[2] != 3) { @@ -3291,10 +3291,8 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf) case MAINTENANCE_IN: case READ_6: case READ_10: - case READ_16: case WRITE_6: case WRITE_10: - case WRITE_16: case ATA_12: case ATA_16: case VERIFY: @@ -3304,6 +3302,28 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf) case START_STOP: supported = 3; break; + case READ_16: + supported = 3; + if (dev->flags & ATA_DFLAG_CDL) { + /* + * CDL read descriptors map to the T2A page, that is, + * rwcdlp = 0x01 and cdlp = 0x01 + */ + rwcdlp = 0x01; + cdlp = 0x01 << 3; + } + break; + case WRITE_16: + supported = 3; + if (dev->flags & ATA_DFLAG_CDL) { + /* + * CDL write descriptors map to the T2B page, that is, + * rwcdlp = 0x01 and cdlp = 0x02 + */ + rwcdlp = 0x01; + cdlp = 0x02 << 3; + } + break; case ZBC_IN: case ZBC_OUT: if (ata_id_zoned_cap(dev->id) || @@ -3319,7 +3339,9 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf) break; } out: - rbuf[1] = supported; /* supported */ + /* One command format */ + rbuf[0] = rwcdlp; + rbuf[1] = cdlp | supported; return err; } From patchwork Thu Dec 8 10:59:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 632153 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E705DC63713 for ; Thu, 8 Dec 2022 11:04:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230240AbiLHLDt (ORCPT ); Thu, 8 Dec 2022 06:03:49 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35658 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230367AbiLHLDE (ORCPT ); Thu, 8 Dec 2022 06:03:04 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5A56A6DCE0; Thu, 8 Dec 2022 03:01:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497285; x=1702033285; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=TCe6lErYETiNPEbs2mrPRmtzoW+z5YHpIsqyXmY7qCw=; b=NAWiprYMgEwgP6iAHwCILp//eN9dBbuE/Fohk8QCx2zp07gKFKCHVYKJ aDWJgyN67ThHxStMZorQWIDPIQZH829y1ZeR18K5wRCMEu13KDbH8c/NF 62ULmDiSxbA3Vk9AbA2ZyPQjrJ5tJ7xNBDJOJL+V+tzthZo7y+3nnk9Ob G5ZIRM7DAQOAaVKcyR5L2PqyjdBu1s0Wep+/3eBTRHjOZru3HLnDdDuGK mLogzSpH1UZBPHHZ1ysDwaAItoJcIYq1ONxsA7vsMW9+3dc/6iWvm4rwg IuoSL4ruwZdp+EWnWMPqOf3+QvH57wFFTTgQv8kbyOlX32RcM7LUIN2+7 Q==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333412" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:01:25 +0800 IronPort-SDR: X0nX0bQfl5ZPhds/evxiAb99JR/YPtWPaFXn//w9eQRJVVT/GQvVN2RrRcLojFYKvM4YIKT6k3 mIEFeJfKaMAarVfmJEo3uss4saGgy26VS5BWUMucEqplXxJ5OENhwn6xeI6oJJIxwu4bwpfhwi kQINM/CcAH2GSIEV8lu9OQQMXbNmdbYU51chKciJguq2SyFBQ3MwXbfKIdSmaSJSHfEgIUkilf bu9iSggcWug73hn+Z5VqiY6prh3chWd5BonJpij/yl6mM45+iC0m+LdktJwmkqt3MIFlq4rQtH n7Y= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:14:10 -0800 IronPort-SDR: OGMJC0vRM5wxgdU/5r//pqFEMLZ101vSK5XHhfWRJG+3Du5AQJpnjwNiv1CXd/GA5Mty/EFfOk 2FZ3wlQaq8nE1FVTPpyB8GgiNosmbh2oD8t0a6xcum6JBKKoGc2q7o1QjbwI7TSvjgLP/btBgU YVfkXW1JSiRuQx/GALskhPthLaCOgqMOEK5M5mtuHfH4EqeWI7SbdjxKje+Ul+t0cXPg4Yuvh5 Y45kdThB9aeGCr3+r9k+GLgG8po0iELEr0OBcVB2fAR3mflkKR85E0Yu+0G45z2ZjgisRQmIBu czY= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:01:24 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Niklas Cassel , linux-ide@vger.kernel.org Subject: [PATCH 18/25] ata: libata-scsi: add support for CDL pages mode sense Date: Thu, 8 Dec 2022 11:59:34 +0100 Message-Id: <20221208105947.2399894-19-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org From: Damien Le Moal Modify ata_scsiop_mode_sense() and ata_msense_control() to support mode sense access to the T2A and T2B sub-pages of the control mode page. ata_msense_control() is modified to support sub-pages. The T2A sub-page is generated using the read descriptors of the command duration limits log page 18h. The T2B sub-page is generated using the write descriptors of the same log page. With the addition of these sub-pages, getting all sub-pages of the control mode page is also supported by increasing the value of ATA_SCSI_RBUF_SIZE from 576B up to 2048B to ensure that all sub-pages fit in the fill buffer. Co-developed-by: Niklas Cassel Signed-off-by: Niklas Cassel Signed-off-by: Damien Le Moal --- drivers/ata/libata-scsi.c | 150 ++++++++++++++++++++++++++++++++------ 1 file changed, 128 insertions(+), 22 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 2500f3ff24a5..456c4e553a76 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -37,7 +37,7 @@ #include "libata.h" #include "libata-transport.h" -#define ATA_SCSI_RBUF_SIZE 576 +#define ATA_SCSI_RBUF_SIZE 2048 static DEFINE_SPINLOCK(ata_scsi_rbuf_lock); static u8 ata_scsi_rbuf[ATA_SCSI_RBUF_SIZE]; @@ -55,6 +55,9 @@ static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap, #define CONTROL_MPAGE_LEN 12 #define ALL_MPAGES 0x3f #define ALL_SUB_MPAGES 0xff +#define CDL_T2A_SUB_MPAGE 0x07 +#define CDL_T2B_SUB_MPAGE 0x08 +#define CDL_T2_SUB_MPAGE_LEN 232 static const u8 def_rw_recovery_mpage[RW_RECOVERY_MPAGE_LEN] = { RW_RECOVERY_MPAGE, @@ -2199,10 +2202,98 @@ static unsigned int ata_msense_caching(u16 *id, u8 *buf, bool changeable) return sizeof(def_cache_mpage); } +/* + * Simulate MODE SENSE control mode page, sub-page 0. + */ +static unsigned int ata_msense_control_spg0(struct ata_device *dev, u8 *buf, + bool changeable) +{ + modecpy(buf, def_control_mpage, + sizeof(def_control_mpage), changeable); + if (changeable) { + /* ata_mselect_control() */ + buf[2] |= (1 << 2); + } else { + bool d_sense = (dev->flags & ATA_DFLAG_D_SENSE); + + /* descriptor format sense data */ + buf[2] |= (d_sense << 2); + } + + return sizeof(def_control_mpage); +} + +/* + * Translate an ATA duration limit in microseconds to a SCSI duration limit + * using the t2cdlunits 0xa (10ms). Since the SCSI duration limits are 2-bytes + * only, take care of overflows. + */ +static inline u16 ata_xlat_cdl_limit(u8 *buf) +{ + u32 limit = get_unaligned_le32(buf); + + return min_t(u32, limit / 10000, 65535); +} + +/* + * Simulate MODE SENSE control mode page, sub-pages 07h and 08h + * (command duration limits T2A and T2B mode pages). + */ +static unsigned int ata_msense_control_spgt2(struct ata_device *dev, u8 *buf, + u8 spg) +{ + u8 *b, *cdl = dev->cdl, *desc; + u32 policy; + int i; + + /* + * Fill the subpage. The first four bytes of the T2A/T2B mode pages + * are a header. The PAGE LENGTH field is the size of the page + * excluding the header. + */ + buf[0] = CONTROL_MPAGE; + buf[1] = spg; + put_unaligned_be16(CDL_T2_SUB_MPAGE_LEN - 4, &buf[2]); + if (spg == CDL_T2A_SUB_MPAGE) { + /* + * Read descriptors map to the T2A page: + * set perf_vs_duration_guidleine. + */ + buf[7] = (cdl[0] & 0x03) << 4; + desc = cdl + 64; + } else { + /* Write descriptors map to the T2B page */ + desc = cdl + 288; + } + + /* Fill the T2 page descriptors */ + b = &buf[8]; + policy = get_unaligned_le32(&cdl[0]); + for (i = 0; i < 7; i++, b += 32, desc += 32) { + /* t2cdlunits: fixed to 10ms */ + b[0] = 0x0a; + + /* Max inactive time and its policy */ + put_unaligned_be16(ata_xlat_cdl_limit(&desc[8]), &b[2]); + b[6] = ((policy >> 8) & 0x0f) << 4; + + /* Max active time and its policy */ + put_unaligned_be16(ata_xlat_cdl_limit(&desc[4]), &b[4]); + b[6] |= (policy >> 4) & 0x0f; + + /* Command duration guideline and its policy */ + put_unaligned_be16(ata_xlat_cdl_limit(&desc[16]), &b[10]); + b[14] = policy & 0x0f; + } + + return CDL_T2_SUB_MPAGE_LEN; +} + /** * ata_msense_control - Simulate MODE SENSE control mode page * @dev: ATA device of interest * @buf: output buffer + * @spg: sub-page code * @changeable: whether changeable parameters are requested * * Generate a generic MODE SENSE control mode page. @@ -2211,17 +2302,24 @@ static unsigned int ata_msense_caching(u16 *id, u8 *buf, bool changeable) * None. */ static unsigned int ata_msense_control(struct ata_device *dev, u8 *buf, - bool changeable) + u8 spg, bool changeable) { - modecpy(buf, def_control_mpage, sizeof(def_control_mpage), changeable); - if (changeable) { - buf[2] |= (1 << 2); /* ata_mselect_control() */ - } else { - bool d_sense = (dev->flags & ATA_DFLAG_D_SENSE); - - buf[2] |= (d_sense << 2); /* descriptor format sense data */ + unsigned int n; + + switch (spg) { + case 0: + return ata_msense_control_spg0(dev, buf, changeable); + case CDL_T2A_SUB_MPAGE: + case CDL_T2B_SUB_MPAGE: + return ata_msense_control_spgt2(dev, buf, spg); + case ALL_SUB_MPAGES: + n = ata_msense_control_spg0(dev, buf, changeable); + n += ata_msense_control_spgt2(dev, buf + n, CDL_T2A_SUB_MPAGE); + n += ata_msense_control_spgt2(dev, buf + n, CDL_T2A_SUB_MPAGE); + return n; + default: + return 0; } - return sizeof(def_control_mpage); } /** @@ -2318,13 +2416,24 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) pg = scsicmd[2] & 0x3f; spg = scsicmd[3]; + /* - * No mode subpages supported (yet) but asking for _all_ - * subpages may be valid + * Supported subpages: all subpages and sub-pages 07h and 08h of + * the control page. */ - if (spg && (spg != ALL_SUB_MPAGES)) { - fp = 3; - goto invalid_fld; + if (spg) { + switch (spg) { + case ALL_SUB_MPAGES: + break; + case CDL_T2A_SUB_MPAGE: + case CDL_T2B_SUB_MPAGE: + if (dev->flags & ATA_DFLAG_CDL && pg == CONTROL_MPAGE) + break; + fallthrough; + default: + fp = 3; + goto invalid_fld; + } } switch(pg) { @@ -2337,13 +2446,13 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) break; case CONTROL_MPAGE: - p += ata_msense_control(args->dev, p, page_control == 1); + p += ata_msense_control(args->dev, p, spg, page_control == 1); break; case ALL_MPAGES: p += ata_msense_rw_recovery(p, page_control == 1); p += ata_msense_caching(args->id, p, page_control == 1); - p += ata_msense_control(args->dev, p, page_control == 1); + p += ata_msense_control(args->dev, p, spg, page_control == 1); break; default: /* invalid page code */ @@ -2364,10 +2473,7 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) memcpy(rbuf + 4, sat_blk_desc, sizeof(sat_blk_desc)); } } else { - unsigned int output_len = p - rbuf - 2; - - rbuf[0] = output_len >> 8; - rbuf[1] = output_len; + put_unaligned_be16(p - rbuf - 2, &rbuf[0]); rbuf[3] |= dpofua; if (ebd) { rbuf[7] = sizeof(sat_blk_desc); @@ -3666,7 +3772,7 @@ static int ata_mselect_control(struct ata_queued_cmd *qc, /* * Check that read-only bits are not modified. */ - ata_msense_control(dev, mpage, false); + ata_msense_control_spg0(dev, mpage, false); for (i = 0; i < CONTROL_MPAGE_LEN - 2; i++) { if (i == 0) continue; From patchwork Thu Dec 8 10:59:35 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 633196 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5001DC63705 for ; Thu, 8 Dec 2022 11:04:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230203AbiLHLDt (ORCPT ); Thu, 8 Dec 2022 06:03:49 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35566 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230375AbiLHLDK (ORCPT ); Thu, 8 Dec 2022 06:03:10 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5404A8659C; Thu, 8 Dec 2022 03:01:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497290; x=1702033290; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=qjSOt1yilfaH6BSV7rPKPvfN99HxKUsIK2iN1RznXJQ=; b=Pp50LA/99qLZ8XQ4nvcd9a4dN4VkQXJhCGfqYloHsk3xVwgExN782ENI wYJsrHEZOODdjE7qLDuzimoUm9DyGkV5okgLQ7DryNafi68bCjzux9XqD 6+B7Z9GH0VIx/kOCE5vp1o9CpFzOMJ3ZfHTaa2pG9h58oKg2cAKyp3qiw QNvI+syNJDswSjWo8czUnQU0R8UPYUfSoVnsB9TDP88tVtKEFWMaCwahA Kg4WtLwQlBFiBcWy45doQIQsw0owG4VpGPq/DqFzDP1akWraVunfwSNTl HS3QLZBnMxUs8Gf1zEErR8dCCFD9fllsV1Is64xfyAarIzPvdQyq84yJt g==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333417" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:01:27 +0800 IronPort-SDR: C7C5tYinsW4Y19n9fhxRrh6P84pvKasc44bssi4svgth5o19ZtsK/LBJOaoENMJOqKXoNM9M7B LaPwr31tM0lKkcgr8fKV6I97hTx0+x1PqSJ0YjIwBka2f0RINKph2FVa2Y2sYFbj5GkWKw4u1V VCJQ7oAfoFWFt7+gkIm27NwVh+7gR/6KUcCh3z14cnTuXz2ZB9akhai8+m9K3r1uxO4Hj8WTNA +kixqOGoubso1Dn7t7mlwckR2NBOR/Yvmz76xKUmGFIvC7cD/mDd/Mys8xk768ePDrP9dFma/H VXI= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:14:12 -0800 IronPort-SDR: Ojy2fQxRlaRoZE5w9WR2Obh+oDkR4aS/aWTPjctNxbXw9jKrMIrl9kELCB6T8aiW9GtP135cmY 8bvnk0WnVrlYef6118qxDr35EoWkDHxEEO/965PCZVExyfNy2mtOT/clSdWHM4SY6UZoBvVZZY ww4icvu6u9RM2rBYGuuSjQw7xNGG6uvmfJbcZFjePxxoWwKG0RhoU+nnq8l/he9/hBiSG3lZi2 Xa6hv9Qm52Hf6B6gvY26gi28k6isPFJdLzVd5PmoxULpUqKpuhLQ71z124iRCmf3Z+7zkkZZI/ rUs= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:01:27 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Niklas Cassel , linux-ide@vger.kernel.org Subject: [PATCH 19/25] ata: libata: add ATA feature control sub-page translation Date: Thu, 8 Dec 2022 11:59:35 +0100 Message-Id: <20221208105947.2399894-20-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org From: Damien Le Moal Add support for the ATA feature control sub-page of the control mode page to enable/disable the command duration limits feature using the cdl_ctrl field of the ATA feature control sub-page. Both mode sense and mode select translation are supported. For mode sense, the ata device flag ATA_DFLAG_CDL_ENABLED is used to cache the status of the command duration limits feature. Enabling this feature is done using a SET FEATURES command with a cdl action set to 1 when the page cdl_ctrl field value is 0x2 (T2A and T2B pages supported). If this field is 0, CDL is disabled using the SET FEATURES command with a cdl action set to 0. Since a device CDL and NCQ priority features should not be used simultaneously, ata_mselect_control_ata_feature() returns an error when attempting to enable CDL with the device priority feature enabled. Conversely, the function ata_ncq_prio_enable_store() used to enable the use of the device NCQ priority feature through sysfs is modified to return an error if the device CDL feature is enabled. Co-developed-by: Niklas Cassel Signed-off-by: Niklas Cassel Signed-off-by: Damien Le Moal --- drivers/ata/libata-core.c | 40 ++++++++- drivers/ata/libata-sata.c | 11 ++- drivers/ata/libata-scsi.c | 167 ++++++++++++++++++++++++++++++++------ include/linux/ata.h | 3 + include/linux/libata.h | 1 + 5 files changed, 193 insertions(+), 29 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index d7a602a8f59e..70bf82f804da 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2367,13 +2367,15 @@ static void ata_dev_config_cdl(struct ata_device *dev) { struct ata_port *ap = dev->link->ap; unsigned int err_mask; + bool cdl_enabled; u64 val; if (ata_id_major_version(dev->id) < 12) goto not_supported; if (!ata_log_supported(dev, ATA_LOG_IDENTIFY_DEVICE) || - !ata_identify_page_supported(dev, ATA_LOG_SUPPORTED_CAPABILITIES)) + !ata_identify_page_supported(dev, ATA_LOG_SUPPORTED_CAPABILITIES) || + !ata_identify_page_supported(dev, ATA_LOG_CURRENT_SETTINGS)) goto not_supported; err_mask = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE, @@ -2392,6 +2394,40 @@ static void ata_dev_config_cdl(struct ata_device *dev) ata_dev_warn(dev, "Command duration guideline is not supported\n"); + /* + * If CDL is marked as enabled, make sure the feature is enabled too. + * Conversely, if CDL is disabled, make sure the feature is turned off. + */ + err_mask = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE, + ATA_LOG_CURRENT_SETTINGS, + ap->sector_buf, 1); + if (err_mask) + goto not_supported; + + val = get_unaligned_le64(&ap->sector_buf[8]); + cdl_enabled = val & BIT_ULL(63) && val & BIT_ULL(21); + if (dev->flags & ATA_DFLAG_CDL_ENABLED) { + if (!cdl_enabled) { + /* Enable CDL on the device */ + err_mask = ata_dev_set_feature(dev, SETFEATURES_CDL, 1); + if (err_mask) { + ata_dev_err(dev, + "Enable CDL feature failed\n"); + goto not_supported; + } + } + } else { + if (cdl_enabled) { + /* Disable CDL on the device */ + err_mask = ata_dev_set_feature(dev, SETFEATURES_CDL, 0); + if (err_mask) { + ata_dev_err(dev, + "Disable CDL feature failed\n"); + goto not_supported; + } + } + } + /* * Command duration limits is supported: cache the CDL log page 18h * (command duration descriptors). @@ -2408,7 +2444,7 @@ static void ata_dev_config_cdl(struct ata_device *dev) return; not_supported: - dev->flags &= ~ATA_DFLAG_CDL; + dev->flags &= ~(ATA_DFLAG_CDL | ATA_DFLAG_CDL_ENABLED); } static int ata_dev_config_lba(struct ata_device *dev) diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index 414d7f8a95bf..b12f8e9e1f86 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -907,10 +907,17 @@ static ssize_t ata_ncq_prio_enable_store(struct device *device, goto unlock; } - if (input) + if (input) { + if (dev->flags & ATA_DFLAG_CDL_ENABLED) { + ata_dev_err(dev, + "CDL must be disabled to enable NCQ priority\n"); + rc = -EINVAL; + goto unlock; + } dev->flags |= ATA_DFLAG_NCQ_PRIO_ENABLED; - else + } else { dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLED; + } unlock: spin_unlock_irq(ap->lock); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 456c4e553a76..c4c39a5db75e 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -58,6 +58,8 @@ static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap, #define CDL_T2A_SUB_MPAGE 0x07 #define CDL_T2B_SUB_MPAGE 0x08 #define CDL_T2_SUB_MPAGE_LEN 232 +#define ATA_FEATURE_SUB_MPAGE 0xf2 +#define ATA_FEATURE_SUB_MPAGE_LEN 16 static const u8 def_rw_recovery_mpage[RW_RECOVERY_MPAGE_LEN] = { RW_RECOVERY_MPAGE, @@ -2289,6 +2291,31 @@ static unsigned int ata_msense_control_spgt2(struct ata_device *dev, u8 *buf, return CDL_T2_SUB_MPAGE_LEN; } +/* + * Simulate MODE SENSE control mode page, sub-page f2h + * (ATA feature control mode page). + */ +static unsigned int ata_msense_control_ata_feature(struct ata_device *dev, + u8 *buf) +{ + /* PS=0, SPF=1 */ + buf[0] = CONTROL_MPAGE | (1 << 6); + buf[1] = ATA_FEATURE_SUB_MPAGE; + + /* + * The first four bytes of ATA Feature Control mode page are a header. + * The PAGE LENGTH field is the size of the page excluding the header. + */ + put_unaligned_be16(ATA_FEATURE_SUB_MPAGE_LEN - 4, &buf[2]); + + if (dev->flags & ATA_DFLAG_CDL) + buf[4] = 0x02; /* Support T2A and T2B pages */ + else + buf[4] = 0; + + return ATA_FEATURE_SUB_MPAGE_LEN; +} + /** * ata_msense_control - Simulate MODE SENSE control mode page * @dev: ATA device of interest @@ -2312,10 +2339,13 @@ static unsigned int ata_msense_control(struct ata_device *dev, u8 *buf, case CDL_T2A_SUB_MPAGE: case CDL_T2B_SUB_MPAGE: return ata_msense_control_spgt2(dev, buf, spg); + case ATA_FEATURE_SUB_MPAGE: + return ata_msense_control_ata_feature(dev, buf); case ALL_SUB_MPAGES: n = ata_msense_control_spg0(dev, buf, changeable); n += ata_msense_control_spgt2(dev, buf + n, CDL_T2A_SUB_MPAGE); n += ata_msense_control_spgt2(dev, buf + n, CDL_T2A_SUB_MPAGE); + n += ata_msense_control_ata_feature(dev, buf + n); return n; default: return 0; @@ -2418,7 +2448,7 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) spg = scsicmd[3]; /* - * Supported subpages: all subpages and sub-pages 07h and 08h of + * Supported subpages: all subpages and sub-pages 07h, 08h and f2h of * the control page. */ if (spg) { @@ -2427,6 +2457,7 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) break; case CDL_T2A_SUB_MPAGE: case CDL_T2B_SUB_MPAGE: + case ATA_FEATURE_SUB_MPAGE: if (dev->flags & ATA_DFLAG_CDL && pg == CONTROL_MPAGE) break; fallthrough; @@ -3737,20 +3768,11 @@ static int ata_mselect_caching(struct ata_queued_cmd *qc, return 0; } -/** - * ata_mselect_control - Simulate MODE SELECT for control page - * @qc: Storage for translated ATA taskfile - * @buf: input buffer - * @len: number of valid bytes in the input buffer - * @fp: out parameter for the failed field on error - * - * Prepare a taskfile to modify caching information for the device. - * - * LOCKING: - * None. +/* + * Simulate MODE SELECT control mode page, sub-page 0. */ -static int ata_mselect_control(struct ata_queued_cmd *qc, - const u8 *buf, int len, u16 *fp) +static int ata_mselect_control_spg0(struct ata_queued_cmd *qc, + const u8 *buf, int len, u16 *fp) { struct ata_device *dev = qc->dev; u8 mpage[CONTROL_MPAGE_LEN]; @@ -3788,6 +3810,83 @@ static int ata_mselect_control(struct ata_queued_cmd *qc, return 0; } +/* + * Translate MODE SELECT control mode page, sub-pages f2h (ATA feature mode + * page) into a SET FEATURES command. + */ +static unsigned int ata_mselect_control_ata_feature(struct ata_queued_cmd *qc, + const u8 *buf, int len, + u16 *fp) +{ + struct ata_device *dev = qc->dev; + struct ata_taskfile *tf = &qc->tf; + u8 cdl_action; + + /* + * The first four bytes of ATA Feature Control mode page are a header, + * so offsets in mpage are off by 4 compared to buf. Same for len. + */ + if (len != ATA_FEATURE_SUB_MPAGE_LEN - 4) { + *fp = min(len, ATA_FEATURE_SUB_MPAGE_LEN - 4); + return -EINVAL; + } + + /* Check cdl_ctrl */ + switch (buf[0] & 0x03) { + case 0: + /* Disable CDL */ + cdl_action = 0; + dev->flags &= ~ATA_DFLAG_CDL_ENABLED; + break; + case 0x02: + /* Enable CDL T2A/T2B: NCQ priority must be disabled */ + if (dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED) { + ata_dev_err(dev, + "NCQ priority must be disabled to enable CDL\n"); + return -EINVAL; + } + cdl_action = 1; + dev->flags |= ATA_DFLAG_CDL_ENABLED; + break; + default: + *fp = 0; + return -EINVAL; + } + + tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; + tf->protocol = ATA_PROT_NODATA; + tf->command = ATA_CMD_SET_FEATURES; + tf->feature = SETFEATURES_CDL; + tf->nsect = cdl_action; + + return 1; +} + +/** + * ata_mselect_control - Simulate MODE SELECT for control page + * @qc: Storage for translated ATA taskfile + * @buf: input buffer + * @len: number of valid bytes in the input buffer + * @fp: out parameter for the failed field on error + * + * Prepare a taskfile to modify caching information for the device. + * + * LOCKING: + * None. + */ +static int ata_mselect_control(struct ata_queued_cmd *qc, u8 spg, + const u8 *buf, int len, u16 *fp) +{ + switch (spg) { + case 0: + return ata_mselect_control_spg0(qc, buf, len, fp); + case ATA_FEATURE_SUB_MPAGE: + return ata_mselect_control_ata_feature(qc, buf, len, fp); + default: + return -EINVAL; + } +} + /** * ata_scsi_mode_select_xlat - Simulate MODE SELECT 6, 10 commands * @qc: Storage for translated ATA taskfile @@ -3805,7 +3904,7 @@ static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc) const u8 *cdb = scmd->cmnd; u8 pg, spg; unsigned six_byte, pg_len, hdr_len, bd_len; - int len; + int len, ret; u16 fp = (u16)-1; u8 bp = 0xff; u8 buffer[64]; @@ -3890,13 +3989,29 @@ static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc) } /* - * No mode subpages supported (yet) but asking for _all_ - * subpages may be valid + * Supported subpages: all subpages and ATA feature sub-page f2h of + * the control page. */ - if (spg && (spg != ALL_SUB_MPAGES)) { - fp = (p[0] & 0x40) ? 1 : 0; - fp += hdr_len + bd_len; - goto invalid_param; + if (spg) { + switch (spg) { + case ALL_SUB_MPAGES: + /* All subpages is not supported for the control page */ + if (pg == CONTROL_MPAGE) { + fp = (p[0] & 0x40) ? 1 : 0; + fp += hdr_len + bd_len; + goto invalid_param; + } + break; + case ATA_FEATURE_SUB_MPAGE: + if (qc->dev->flags & ATA_DFLAG_CDL && + pg == CONTROL_MPAGE) + break; + fallthrough; + default: + fp = (p[0] & 0x40) ? 1 : 0; + fp += hdr_len + bd_len; + goto invalid_param; + } } if (pg_len > len) goto invalid_param_len; @@ -3909,14 +4024,16 @@ static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc) } break; case CONTROL_MPAGE: - if (ata_mselect_control(qc, p, pg_len, &fp) < 0) { + ret = ata_mselect_control(qc, spg, p, pg_len, &fp); + if (ret < 0) { fp += hdr_len + bd_len; goto invalid_param; - } else { - goto skip; /* No ATA command to send */ } + if (!ret) + goto skip; /* No ATA command to send */ break; - default: /* invalid page code */ + default: + /* Invalid page code */ fp = bd_len + hdr_len; goto invalid_param; } diff --git a/include/linux/ata.h b/include/linux/ata.h index b01e2cebe1fe..a59b17d6ad11 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -330,6 +330,7 @@ enum { /* Identify device log pages: */ ATA_LOG_SUPPORTED_CAPABILITIES = 0x03, + ATA_LOG_CURRENT_SETTINGS = 0x04, ATA_LOG_SECURITY = 0x06, ATA_LOG_SATA_SETTINGS = 0x08, ATA_LOG_ZONED_INFORMATION = 0x09, @@ -419,6 +420,8 @@ enum { SETFEATURES_SATA_ENABLE = 0x10, /* Enable use of SATA feature */ SETFEATURES_SATA_DISABLE = 0x90, /* Disable use of SATA feature */ + SETFEATURES_CDL = 0x0d, /* Enable/disable cmd duration limits */ + /* SETFEATURE Sector counts for SATA features */ SATA_FPDMA_OFFSET = 0x01, /* FPDMA non-zero buffer offsets */ SATA_FPDMA_AA = 0x02, /* FPDMA Setup FIS Auto-Activate */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 2bb8027ae148..f41a96f89cd7 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -105,6 +105,7 @@ enum { ATA_DFLAG_INIT_MASK = (1 << 19) - 1, ATA_DFLAG_NCQ_PRIO_ENABLED = (1 << 19), /* Priority cmds sent to dev */ + ATA_DFLAG_CDL_ENABLED = (1 << 20), /* cmd duration limits is enabled */ ATA_DFLAG_DETACH = (1 << 24), ATA_DFLAG_DETACHED = (1 << 25), ATA_DFLAG_DA = (1 << 26), /* device supports Device Attention */ From patchwork Thu Dec 8 10:59:36 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 633194 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 718DDC6371A for ; Thu, 8 Dec 2022 11:04:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230284AbiLHLDz (ORCPT ); Thu, 8 Dec 2022 06:03:55 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39776 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229732AbiLHLDO (ORCPT ); Thu, 8 Dec 2022 06:03:14 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8928F88B62; Thu, 8 Dec 2022 03:01:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497290; x=1702033290; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=+niR1lfLubo3xlVgT4pgZA15mdDi1+PYFnKKG++F5eY=; b=aRGvAB/zL7Sx9LyPiK89Q2CxNQFObQpUd8Ud9gQg6xnk1iUPdJdYM/LF YbekHTQEx6NZVRIFWVO27oK0G0EUIrp2bRg4mPpviJ5ZGMSEUNQ0bLg93 vCFldYr0XON+JDHDAb1RpeHpltZ3ANu1G+qJEgQcRL/ozi+1x317exW/x xzx/PgbZ2Lkuv5x2tBrXUHmwg34YnXWtCK2BMFTxPR+mnCs1Tx6Jjo2Z7 AyQJJUlEExyex68fuGNLOdkcArobNXsP53cH40gVn3IPQhSn/turQwXsW DzKEYHGSHYwNPXk6iFv6byYbyNO053lM4V8xZCEoi2FvQ5BWCw209ca5Y A==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333419" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:01:30 +0800 IronPort-SDR: YQauxxZY7txmcFQe7Pwx3s9axK1gC4G3jnm0nXCPwlVfrohs5iaXblfAKKQpRwx2OsSyuIT2wZ bDmSU4gZMt6AYuVhhziPc8W7tIeNObqSodZHqJoTrk5b/Ysxi4AKm+eaY9cOpIHdrE0SCJTDNa mJo4RHJ6SdtVs4HDGsH9t1tn+pbMataRrOZlzo1Xdl8fH6w8Umyrb/pTP8p/TEM1jnczwjMp9G p9nJxvZ+5+4JWrS7eHtDfrrYKHh33gNjQZLjoXsdESTqiKMQd8v2ieMRpDZk0n9oBSmhwtbtPx 3Lg= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:14:15 -0800 IronPort-SDR: j4N1t+Kkv2DnU9PP2ymeo1HBAkQmm/kUIwHT8ZSj0D+gO/e9L9FFiBScrT/JDejEew3VKQrRFb 3Pxfo9IQwaUiEShnjaoj6Ar4M+Fau7XCH7lWi9wMV+QbOmF9bwHsHNpSKJS4lrBHf22/Ylmxp6 ujnapAB7+3Wwhz1jjVQpQEKXF3c/axlnWc6ipQHcrfXDOw17Juj1iTqT3omUvs5LbCHI2jEa2u ja9OuL5MV+sHCvnOwSO3/O9av2lp7TF9bTVd7GH5Adr1y2Qc1VOgkcnWW2vp0lRQrrdRaFOSHa zRY= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:01:29 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Niklas Cassel , linux-ide@vger.kernel.org Subject: [PATCH 20/25] ata: libata: set read/write commands CDL index Date: Thu, 8 Dec 2022 11:59:36 +0100 Message-Id: <20221208105947.2399894-21-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org From: Damien Le Moal For devices supporting the command duration limits feature, when a read or write operation has the IOPRIO_CLASS_DL priority class and the command duration limits feature is enabled, set the command duration limit index field of the command to the priority level. For unqueued read and write operations, the command duration limit index is set as the lower 2 bits of the feature field. For queued NCQ read/write commands, the index is set as the lower 2 bits of the auxiliary field. Co-developed-by: Niklas Cassel Signed-off-by: Niklas Cassel Signed-off-by: Damien Le Moal --- drivers/ata/libata-core.c | 41 +++++++++++++++++++++++++++++++++++---- drivers/ata/libata-scsi.c | 3 +-- drivers/ata/libata.h | 2 +- include/linux/libata.h | 1 + 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 70bf82f804da..c79ee38dc594 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -663,13 +663,37 @@ u64 ata_tf_read_block(const struct ata_taskfile *tf, struct ata_device *dev) return block; } +/* + * Set a taskfile CDL index. + */ +static inline void ata_set_tf_cdl(struct ata_queued_cmd *qc, int ioprio) +{ + struct ata_taskfile *tf = &qc->tf; + int cdl; + + if (IOPRIO_PRIO_CLASS(ioprio) != IOPRIO_CLASS_DL) + return; + + cdl = IOPRIO_PRIO_DATA(ioprio) & 0x07; + if (!cdl) + return; + + if (tf->protocol == ATA_PROT_NCQ) + tf->auxiliary |= cdl; + else + tf->feature |= cdl; + + /* Mark this command as having a CDL */ + qc->flags |= ATA_QCFLAG_HAS_CDL; +} + /** * ata_build_rw_tf - Build ATA taskfile for given read/write request * @qc: Metadata associated with the taskfile to build * @block: Block address * @n_block: Number of blocks * @tf_flags: RW/FUA etc... - * @class: IO priority class + * @ioprio: IO priority class and level * * LOCKING: * None. @@ -683,7 +707,7 @@ u64 ata_tf_read_block(const struct ata_taskfile *tf, struct ata_device *dev) * -EINVAL if the request is invalid. */ int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block, - unsigned int tf_flags, int class) + unsigned int tf_flags, int ioprio) { struct ata_taskfile *tf = &qc->tf; struct ata_device *dev = qc->dev; @@ -720,12 +744,21 @@ int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block, tf->device |= 1 << 7; if (dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED && - class == IOPRIO_CLASS_RT) + IOPRIO_PRIO_CLASS(ioprio) == IOPRIO_CLASS_RT) tf->hob_nsect |= ATA_PRIO_HIGH << ATA_SHIFT_PRIO; + + if (dev->flags & ATA_DFLAG_CDL_ENABLED) + ata_set_tf_cdl(qc, ioprio); + } else if (dev->flags & ATA_DFLAG_LBA) { tf->flags |= ATA_TFLAG_LBA; - if (lba_28_ok(block, n_block)) { + if (dev->flags & ATA_DFLAG_CDL_ENABLED) + ata_set_tf_cdl(qc, ioprio); + + /* a CDL index cannot be supplied with the 28-bit commands */ + if (!(qc->flags & ATA_QCFLAG_HAS_CDL) && + lba_28_ok(block, n_block)) { /* use LBA28 */ tf->device |= (block >> 24) & 0xf; } else if (lba_48_ok(block, n_block)) { diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index c4c39a5db75e..105795e867c9 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1549,7 +1549,6 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) struct scsi_cmnd *scmd = qc->scsicmd; const u8 *cdb = scmd->cmnd; struct request *rq = scsi_cmd_to_rq(scmd); - int class = IOPRIO_PRIO_CLASS(req_get_ioprio(rq)); unsigned int tf_flags = 0; u64 block; u32 n_block; @@ -1625,7 +1624,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) qc->flags |= ATA_QCFLAG_IO; qc->nbytes = n_block * scmd->device->sector_size; - rc = ata_build_rw_tf(qc, block, n_block, tf_flags, class); + rc = ata_build_rw_tf(qc, block, n_block, tf_flags, req_get_ioprio(rq)); if (likely(rc == 0)) return 0; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 5481d29bb273..339b19c0bbcf 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -45,7 +45,7 @@ static inline void ata_force_cbl(struct ata_port *ap) { } extern u64 ata_tf_to_lba(const struct ata_taskfile *tf); extern u64 ata_tf_to_lba48(const struct ata_taskfile *tf); extern int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block, - unsigned int tf_flags, int class); + unsigned int tf_flags, int ioprio); extern u64 ata_tf_read_block(const struct ata_taskfile *tf, struct ata_device *dev); extern unsigned ata_exec_internal(struct ata_device *dev, diff --git a/include/linux/libata.h b/include/linux/libata.h index f41a96f89cd7..ecdabe5647d1 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -207,6 +207,7 @@ enum { ATA_QCFLAG_CLEAR_EXCL = (1 << 5), /* clear excl_link on completion */ ATA_QCFLAG_QUIET = (1 << 6), /* don't report device error */ ATA_QCFLAG_RETRY = (1 << 7), /* retry after failure */ + ATA_QCFLAG_HAS_CDL = (1 << 8), /* qc has CDL a descriptor set */ ATA_QCFLAG_EH = (1 << 16), /* cmd aborted and owned by EH */ ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */ From patchwork Thu Dec 8 10:59:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 632150 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 78899C3A5A7 for ; Thu, 8 Dec 2022 11:04:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229684AbiLHLEX (ORCPT ); Thu, 8 Dec 2022 06:04:23 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39832 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229772AbiLHLDW (ORCPT ); Thu, 8 Dec 2022 06:03:22 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A149A60EBF for ; Thu, 8 Dec 2022 03:01:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497294; x=1702033294; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=SEAJ27bM1r5PL33b2gfdry0GN7ugAbmEH4XhqZvGyDc=; b=P2L2lQ3P/cFQbm63RGsBzE20m9hjvtJzDef3TyVGEN6xE1zip3IfgvZL 0s4ZA7nx5jTmXX0dLDBUsMBhKnw2fe2Iv3Kbro2vSglbUhkkMyocGNCl7 6HnDk7KQG54Eg9iQ7mMvzwBIDNgcXQbvjo4+NbJaNHDMSI0fs18HmAJma Xx0Qz+tWrmHnIz2Y2wFtlWjGyX9zVwqGv0BQnME8TvHjHotA9DDLLSn8j LLHbwTFalewdJPSeObov5p5WDOqWkKOAJ8jwDpDsFJlDELqwkY8VlcBeM s9XcgqdjxT4vudKYfPjaFBYQim209iRrJq/TMsS11FROziCq10pl8e2Zp g==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333424" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:01:33 +0800 IronPort-SDR: kywm4STagQWRB8ihhdPNoSa6BfClwMf2cdfkDN+irAFVy0Kzck3K+aG0MO+z7/Ot5UtX88CJ0a 1OvohcODDy0sVxB2bZyASEKT4EpHN3qtzE/HUJ8CGqJX8xYTh7T0gKFTnk/B85/8DV8rhSFj6y QmHn/5a3Lcwc8lJVGsoI3SRv5OrYhXK8ffaFRetMz4sAG3+nkcDn0J46P/elQ8C6GeDNRTsRIn GzKDtfG5fLFafYHB44EcXB5W1r0gTxmfu9x3n3HcasbyGD7Mytkidcri/8HIVlbkarN4WmwSi/ His= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:14:18 -0800 IronPort-SDR: 7+gEkGpqcMJ2U8aSVch12df9Q+9y1cFYvkQYszvkN4sCXlSLGH2KOnmtbGUM0lC3ceS2PYLy0u j15tKfzDiZuvwCCnYoa+N3PLekrdEuh72B0qVKuG6CPGPnqlV4+F01HdMWAdISO30nv41hucaB Xngzd4MftFzrJpyZnhkVCTfEBUMDZghs3MxKTn7KWS+ItuMvgrW7rq/s1nKgdJDK+WNgRyV5eY Uw1YDwyNFYqek3mlm1mm0N15O544RPY7X9E+DUxrQyRLAlUTBNEud9bWu8t/thhKg3tudzr9in BjE= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:01:32 -0800 From: Niklas Cassel To: "James E.J. Bottomley" , "Martin K. Petersen" Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Damien Le Moal Subject: [PATCH 21/25] scsi: sd: detect support for command duration limits Date: Thu, 8 Dec 2022 11:59:37 +0100 Message-Id: <20221208105947.2399894-22-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org From: Damien Le Moal Detect if a disk supports command duration limits. Support for the READ 16, WRITE 16, READ 32 and WRITE 32 commands is tested using the function scsi_report_opcode(). For a disk supporting command duration limits, the mode page indicating the command duration limits descriptors that apply to the command is indicated using the rwcdlp and cdlp bits. Support duration limits is advertizes through sysfs using the new "duration_limits" sysfs sub-directory of the generic device directory, that is, /sys/block/sdX/device/duration_limits. Within this new directory, the limit descriptors that apply to read and write operations are exposed within the read and write directories, with descriptor attributes grouped together in directories. The overall sysfs structure created is: /sys/block/sde/device/duration_limits/ ├── perf_vs_duration_guideline ├── read │   ├── 1 │   │   ├── duration_guideline │   │   ├── duration_guideline_policy │   │   ├── max_active_time │   │   ├── max_active_time_policy │   │   ├── max_inactive_time │   │   └── max_inactive_time_policy │   ├── 2 │   │   ├── duration_guideline ... │   └── page └── write ├── 1 │   ├── duration_guideline │   ├── duration_guideline_policy ... For each of the read and write descriptor directories, the page attribute file indicate the command duration limit page providing the descriptors. The possible values for the page attribute are "A", "B", "T2A" and "T2B". The new "duration_limits" attributes directory is added only for disks that supports command duration limits. Signed-off-by: Damien Le Moal --- drivers/scsi/Makefile | 2 +- drivers/scsi/sd.c | 2 + drivers/scsi/sd.h | 61 ++++ drivers/scsi/sd_cdl.c | 764 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 828 insertions(+), 1 deletion(-) create mode 100644 drivers/scsi/sd_cdl.c diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index f055bfd54a68..0e48cb6d21d6 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -170,7 +170,7 @@ scsi_mod-$(CONFIG_BLK_DEV_BSG) += scsi_bsg.o hv_storvsc-y := storvsc_drv.o -sd_mod-objs := sd.o +sd_mod-objs := sd.o sd_cdl.o sd_mod-$(CONFIG_BLK_DEV_INTEGRITY) += sd_dif.o sd_mod-$(CONFIG_BLK_DEV_ZONED) += sd_zbc.o diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 2b56ff4fcf8a..45ff44a73256 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -3306,6 +3306,7 @@ static int sd_revalidate_disk(struct gendisk *disk) sd_read_write_same(sdkp, buffer); sd_read_security(sdkp, buffer); sd_config_protection(sdkp); + sd_read_cdl(sdkp, buffer); } /* @@ -3626,6 +3627,7 @@ static void scsi_disk_release(struct device *dev) ida_free(&sd_index_ida, sdkp->index); sd_zbc_free_zone_info(sdkp); + sd_cdl_release(sdkp); put_device(&sdkp->device->sdev_gendev); free_opal_dev(sdkp->opal_dev); diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 5eea762f84d1..e60d33bd222a 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -81,6 +81,62 @@ struct zoned_disk_info { u32 zone_blocks; }; +/* + * Command duration limits sub-pages for the control mode page 0Ah. + */ +enum sd_cdlp { + SD_CDLP_A, + SD_CDLP_B, + SD_CDLP_T2A, + SD_CDLP_T2B, + SD_CDLP_NONE, + + SD_CDL_MAX_PAGES = SD_CDLP_NONE, +}; + +enum sd_cdl_cmd { + SD_CDL_READ_16, + SD_CDL_WRITE_16, + SD_CDL_READ_32, + SD_CDL_WRITE_32, + + SD_CDL_CMD_MAX, +}; + +enum sd_cdl_rw { + SD_CDL_READ, + SD_CDL_WRITE, + SD_CDL_RW, +}; + +struct sd_cdl_desc { + struct kobject kobj; + u64 max_inactive_time; + u64 max_active_time; + u64 duration; + u8 max_inactive_policy; + u8 max_active_policy; + u8 duration_policy; + u8 cdlp; +}; + +#define SD_CDL_MAX_DESC 7 + +struct sd_cdl_page { + struct kobject kobj; + bool sysfs_registered; + enum sd_cdl_rw rw; + enum sd_cdlp cdlp; + struct sd_cdl_desc descs[SD_CDL_MAX_DESC]; +}; + +struct sd_cdl { + struct kobject kobj; + bool sysfs_registered; + u8 perf_vs_duration_guideline; + struct sd_cdl_page pages[SD_CDL_RW]; +}; + struct scsi_disk { struct scsi_device *device; @@ -131,6 +187,7 @@ struct scsi_disk { u8 provisioning_mode; u8 zeroing_mode; u8 nr_actuators; /* Number of actuators */ + struct sd_cdl *cdl; unsigned ATO : 1; /* state of disk ATO bit */ unsigned cache_override : 1; /* temp override of WCE,RCD */ unsigned WCE : 1; /* state of disk WCE bit */ @@ -295,4 +352,8 @@ static inline blk_status_t sd_zbc_prepare_zone_append(struct scsi_cmnd *cmd, void sd_print_sense_hdr(struct scsi_disk *sdkp, struct scsi_sense_hdr *sshdr); void sd_print_result(const struct scsi_disk *sdkp, const char *msg, int result); +/* Command duration limits support (in sd_cdl.c) */ +void sd_read_cdl(struct scsi_disk *sdkp, unsigned char *buf); +void sd_cdl_release(struct scsi_disk *sdkp); + #endif /* _SCSI_DISK_H */ diff --git a/drivers/scsi/sd_cdl.c b/drivers/scsi/sd_cdl.c new file mode 100644 index 000000000000..513cd989f19a --- /dev/null +++ b/drivers/scsi/sd_cdl.c @@ -0,0 +1,764 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * SCSI Command Duration Limits (CDL) + * + * Copyright (C) 2021 Western Digital Corporation or its affiliates. + */ +#include +#include + +#include + +#include +#include + +#include "sd.h" + +/* + * Command duration limits sub-pages for the control mode page 0Ah. + */ +static const struct sd_cdlp_info { + u8 subpage; + char *name; +} cdl_page[SD_CDL_MAX_PAGES + 1] = { + { 0x03, "A" }, + { 0x04, "B" }, + { 0x07, "T2A" }, + { 0x08, "T2B" }, + { 0x00, "none" }, +}; + +static const struct sd_cdl_cmd_info { + u8 opcode; + u16 sa; + char *name; +} cdl_cmd[SD_CDL_CMD_MAX] = { + { READ_16, 0, "READ_16" }, + { WRITE_16, 0, "WRITE_16" }, + { VARIABLE_LENGTH_CMD, READ_32, "READ_32" }, + { VARIABLE_LENGTH_CMD, WRITE_32, "WRITE_32" }, +}; + +static const char *sd_cdl_perf_name(u8 val) +{ + switch (val) { + case 0x00: + return "0"; + case 0x01: + return "0.5"; + case 0x02: + return "1.0"; + case 0x03: + return "1.5"; + case 0x04: + return "2.0"; + case 0x05: + return "2.5"; + case 0x06: + return "3"; + case 0x07: + return "4"; + case 0x08: + return "5"; + case 0x09: + return "8"; + case 0x0A: + return "10"; + case 0x0B: + return "15"; + case 0x0C: + return "20"; + default: + return "?"; + } +} + +static const char *sd_cdl_policy_name(u8 policy) +{ + switch (policy) { + case 0x00: + return "complete-earliest"; + case 0x01: + return "continue-next-limit"; + case 0x02: + return "continue-no-limit"; + case 0x0d: + return "complete-unavailable"; + case 0x0e: + return "abort-recovery"; + case 0x0f: + return "abort"; + default: + return "?"; + } +} + +/* + * Command duration limits descriptors sysfs plumbing. + */ +struct sd_cdl_desc_sysfs_entry { + struct attribute attr; + ssize_t (*show)(struct sd_cdl_desc *desc, char *buf); +}; + +#define CDL_DESC_ATTR_RO(_name) \ + static struct sd_cdl_desc_sysfs_entry \ + cdl_desc_##_name##_entry = { \ + .attr = { .name = __stringify(_name), .mode = 0444 }, \ + .show = cdl_desc_##_name##_show, \ + } + +static ssize_t cdl_desc_max_inactive_time_show(struct sd_cdl_desc *desc, + char *buf) +{ + return sysfs_emit(buf, "%llu\n", desc->max_inactive_time); +} +CDL_DESC_ATTR_RO(max_inactive_time); + +static ssize_t cdl_desc_max_inactive_time_policy_show(struct sd_cdl_desc *desc, + char *buf) +{ + return sysfs_emit(buf, "%s\n", + sd_cdl_policy_name(desc->max_inactive_policy)); +} +CDL_DESC_ATTR_RO(max_inactive_time_policy); + +static ssize_t cdl_desc_max_active_time_show(struct sd_cdl_desc *desc, + char *buf) +{ + return sysfs_emit(buf, "%llu\n", desc->max_active_time); +} +CDL_DESC_ATTR_RO(max_active_time); + +static ssize_t cdl_desc_max_active_time_policy_show(struct sd_cdl_desc *desc, + char *buf) +{ + return sysfs_emit(buf, "%s\n", + sd_cdl_policy_name(desc->max_active_policy)); +} +CDL_DESC_ATTR_RO(max_active_time_policy); + +static ssize_t cdl_desc_duration_guideline_show(struct sd_cdl_desc *desc, + char *buf) +{ + return sysfs_emit(buf, "%llu\n", desc->duration); +} +CDL_DESC_ATTR_RO(duration_guideline); + +static ssize_t cdl_desc_duration_guideline_policy_show(struct sd_cdl_desc *desc, + char *buf) +{ + return sysfs_emit(buf, "%s\n", + sd_cdl_policy_name(desc->duration_policy)); +} +CDL_DESC_ATTR_RO(duration_guideline_policy); + +static umode_t sd_cdl_desc_attr_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct sd_cdl_desc *desc = container_of(kobj, struct sd_cdl_desc, kobj); + + /* + * Descriptors in pages A and B only have the duration guideline + * field. + */ + if ((desc->cdlp == SD_CDLP_A || desc->cdlp == SD_CDLP_B) && + (attr != &cdl_desc_duration_guideline_entry.attr)) + return 0; + + return attr->mode; +} + +static struct attribute *sd_cdl_desc_attrs[] = { + &cdl_desc_max_inactive_time_entry.attr, + &cdl_desc_max_inactive_time_policy_entry.attr, + &cdl_desc_max_active_time_entry.attr, + &cdl_desc_max_active_time_policy_entry.attr, + &cdl_desc_duration_guideline_entry.attr, + &cdl_desc_duration_guideline_policy_entry.attr, + NULL, +}; + +static const struct attribute_group sd_cdl_desc_group = { + .attrs = sd_cdl_desc_attrs, + .is_visible = sd_cdl_desc_attr_visible, +}; +__ATTRIBUTE_GROUPS(sd_cdl_desc); + +static ssize_t sd_cdl_desc_sysfs_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct sd_cdl_desc_sysfs_entry *entry = + container_of(attr, struct sd_cdl_desc_sysfs_entry, attr); + struct sd_cdl_desc *desc = container_of(kobj, struct sd_cdl_desc, kobj); + + return entry->show(desc, buf); +} + +static const struct sysfs_ops sd_cdl_desc_sysfs_ops = { + .show = sd_cdl_desc_sysfs_show, +}; + +static void sd_cdl_sysfs_nop_release(struct kobject *kobj) { } + +static struct kobj_type sd_cdl_desc_ktype = { + .sysfs_ops = &sd_cdl_desc_sysfs_ops, + .default_groups = sd_cdl_desc_groups, + .release = sd_cdl_sysfs_nop_release, +}; + +/* + * Duration limits page sysfs plumbing. + */ +struct sd_cdl_page_sysfs_entry { + struct attribute attr; + ssize_t (*show)(struct sd_cdl_page *page, char *buf); +}; + +#define CDL_PAGE_ATTR_RO(_name) \ + static struct sd_cdl_page_sysfs_entry \ + cdl_page_##_name##_entry = { \ + .attr = { .name = __stringify(_name), .mode = 0444 }, \ + .show = cdl_page_##_name##_show, \ + } + +static ssize_t cdl_page_page_show(struct sd_cdl_page *page, char *buf) +{ + return sysfs_emit(buf, "%s\n", cdl_page[page->cdlp].name); +} +CDL_PAGE_ATTR_RO(page); + +static struct attribute *sd_cdl_page_attrs[] = { + &cdl_page_page_entry.attr, + NULL, +}; + +static const struct attribute_group sd_cdl_page_group = { + .attrs = sd_cdl_page_attrs, +}; +__ATTRIBUTE_GROUPS(sd_cdl_page); + +static ssize_t sd_cdl_page_sysfs_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct sd_cdl_page_sysfs_entry *entry = + container_of(attr, struct sd_cdl_page_sysfs_entry, attr); + struct sd_cdl_page *page = container_of(kobj, struct sd_cdl_page, kobj); + + return entry->show(page, buf); +} + +static const struct sysfs_ops sd_cdl_page_sysfs_ops = { + .show = sd_cdl_page_sysfs_show, +}; + +static struct kobj_type sd_cdl_page_ktype = { + .sysfs_ops = &sd_cdl_page_sysfs_ops, + .default_groups = sd_cdl_page_groups, + .release = sd_cdl_sysfs_nop_release, +}; + +static void sd_cdl_sysfs_unregister_page(struct sd_cdl_page *page) +{ + int i; + + for (i = 0; i < SD_CDL_MAX_DESC; i++) { + if (page->sysfs_registered) + kobject_del(&page->descs[i].kobj); + kobject_put(&page->descs[i].kobj); + } + if (page->sysfs_registered) + kobject_del(&page->kobj); + kobject_put(&page->kobj); + + page->cdlp = SD_CDLP_NONE; + page->sysfs_registered = false; +} + +static int sd_cdl_sysfs_register_page(struct scsi_disk *sdkp, + struct sd_cdl_page *page) +{ + int i, ret; + + /* + * If the page is already registered, the updated page descriptors + * are already exported. + */ + if (page->sysfs_registered) + return 0; + + ret = kobject_add(&page->kobj, &sdkp->cdl->kobj, + "%s", page->rw ? "write" : "read"); + if (ret) { + kobject_put(&page->kobj); + return ret; + } + + for (i = 0; i < SD_CDL_MAX_DESC; i++) { + ret = kobject_add(&page->descs[i].kobj, &page->kobj, + "%d", i + 1); + if (ret) { + int j; + + kobject_put(&page->descs[i].kobj); + for (j = 0; j < SD_CDL_MAX_DESC; j++) { + if (j < i) + kobject_del(&page->descs[j].kobj); + kobject_put(&page->descs[j].kobj); + } + kobject_del(&page->kobj); + kobject_put(&page->kobj); + return ret; + } + } + + page->sysfs_registered = true; + + return 0; +} + +/* + * Command duration limits sysfs plumbing, top level (duration limits directory + * under the "device" sysfs directory. + */ +struct sd_cdl_sysfs_entry { + struct attribute attr; + ssize_t (*show)(struct sd_cdl *cdl, char *buf); +}; + +#define CDL_ATTR_RO(_name) \ + static struct sd_cdl_sysfs_entry cdl_##_name##_entry = { \ + .attr = { .name = __stringify(_name), .mode = 0444 }, \ + .show = cdl_##_name##_show, \ + } + +static ssize_t cdl_perf_vs_duration_guideline_show(struct sd_cdl *cdl, + char *buf) +{ + return sysfs_emit(buf, "%s\n", + sd_cdl_perf_name(cdl->perf_vs_duration_guideline)); +} +CDL_ATTR_RO(perf_vs_duration_guideline); + +static struct attribute *sd_cdl_attrs[] = { + &cdl_perf_vs_duration_guideline_entry.attr, + NULL, +}; + +static umode_t sd_cdl_attr_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct sd_cdl *cdl = container_of(kobj, struct sd_cdl, kobj); + + /* perf_vs_duration_guideline exists only if page T2A is supported */ + if (attr == &cdl_perf_vs_duration_guideline_entry.attr && + cdl->pages[SD_CDL_READ].cdlp != SD_CDLP_T2A && + cdl->pages[SD_CDL_WRITE].cdlp != SD_CDLP_T2A) + return 0; + + return attr->mode; +} + +static const struct attribute_group sd_cdl_group = { + .attrs = sd_cdl_attrs, + .is_visible = sd_cdl_attr_visible, +}; +__ATTRIBUTE_GROUPS(sd_cdl); + +static ssize_t sd_cdl_sysfs_show(struct kobject *kobj, + struct attribute *attr, char *page) +{ + struct sd_cdl_sysfs_entry *entry = + container_of(attr, struct sd_cdl_sysfs_entry, attr); + struct sd_cdl *cdl = container_of(kobj, struct sd_cdl, kobj); + + return entry->show(cdl, page); +} + +static const struct sysfs_ops sd_cdl_sysfs_ops = { + .show = sd_cdl_sysfs_show, +}; + +static void sd_cdl_sysfs_release(struct kobject *kobj) +{ + struct sd_cdl *cdl = container_of(kobj, struct sd_cdl, kobj); + + kfree(cdl); +} + +static struct kobj_type sd_cdl_ktype = { + .sysfs_ops = &sd_cdl_sysfs_ops, + .default_groups = sd_cdl_groups, + .release = sd_cdl_sysfs_release, +}; + +static void sd_cdl_sysfs_unregister(struct scsi_disk *sdkp) +{ + struct sd_cdl *cdl = NULL; + int i; + + swap(sdkp->cdl, cdl); + if (!cdl) + return; + + if (!cdl->sysfs_registered) { + kfree(cdl); + return; + } + + for (i = 0; i < SD_CDL_RW; i++) { + if (cdl->pages[i].sysfs_registered) + sd_cdl_sysfs_unregister_page(&cdl->pages[i]); + } + + kobject_del(&cdl->kobj); + kobject_put(&cdl->kobj); +} + +static void sd_cdl_sysfs_register(struct scsi_disk *sdkp) +{ + struct scsi_device *sdev = sdkp->device; + struct sd_cdl *cdl = sdkp->cdl; + struct sd_cdl_page *page; + int i, ret; + + if (!cdl->sysfs_registered) { + ret = kobject_add(&cdl->kobj, &sdev->sdev_gendev.kobj, + "duration_limits"); + if (ret) { + kobject_put(&cdl->kobj); + goto unregister; + } + + cdl->sysfs_registered = true; + } + + /* Check if the pages changed */ + for (i = 0; i < SD_CDL_RW; i++) { + page = &cdl->pages[i]; + if (page->cdlp == SD_CDLP_NONE) { + sd_cdl_sysfs_unregister_page(page); + continue; + } + + ret = sd_cdl_sysfs_register_page(sdkp, page); + if (ret) { + page->cdlp = SD_CDLP_NONE; + goto unregister; + } + } + + return; + +unregister: + sd_cdl_sysfs_unregister(sdkp); +} + +/* + * CDL pages A and B time limits in microseconds. + */ +static u64 sd_cdl_time(u8 *buf, u8 cdlunit) +{ + u64 val = get_unaligned_be16(buf); + u64 factor; + + switch (cdlunit) { + case 0x00: + return 0; + case 0x04: + /* 1 microsecond */ + factor = NSEC_PER_USEC; + break; + case 0x05: + /* 10 milliseconds */ + factor = 10ULL * USEC_PER_MSEC; + break; + case 0x06: + /* 500 milliseconds */ + factor = 500ULL * USEC_PER_MSEC; + break; + default: + return 0; + } + + return val * factor; +} + +/* + * CDL pages T2A and T2B time limits in microseconds. + */ +static u64 sd_cdl_t2time(u8 *buf, u8 t2cdlunits) +{ + u64 val = get_unaligned_be16(buf); + u64 factor; + + switch (t2cdlunits) { + case 0x00: + return 0; + case 0x06: + /* 500 nanoseconds */ + factor = 500; + break; + case 0x08: + /* 1 microsecond */ + factor = NSEC_PER_USEC; + break; + case 0x0A: + /* 10 milliseconds */ + factor = 10ULL * NSEC_PER_MSEC; + break; + case 0x0E: + /* 500 milliseconds */ + factor = 500ULL * NSEC_PER_MSEC; + break; + default: + return 0; + } + + val *= factor; + do_div(val, NSEC_PER_USEC); + + return val; +} + +static int sd_cdl_read_page(struct scsi_disk *sdkp, struct sd_cdl_page *page, + unsigned char *buf) +{ + struct sd_cdl *cdl = sdkp->cdl; + struct sd_cdl_desc *desc = &page->descs[0]; + u8 cdlp = page->cdlp; + struct scsi_mode_data data; + int i, ret; + + ret = scsi_mode_sense(sdkp->device, 0x08, 0x0a, cdl_page[cdlp].subpage, + buf, SD_BUF_SIZE, SD_TIMEOUT, sdkp->max_retries, + &data, NULL); + if (ret) { + sd_printk(KERN_ERR, sdkp, + "Command duration limits: read CDL page %s failed\n", + cdl_page[cdlp].name); + return ret; + } + buf += data.header_length + data.block_descriptor_length; + + if (cdlp == SD_CDLP_A || cdlp == SD_CDLP_B) { + buf += 8; + + for (i = 0; i < SD_CDL_MAX_DESC; i++, buf += 4, desc++) { + u8 cdlunit = (buf[0] & 0xe0) >> 5; + + desc->duration = sd_cdl_time(&buf[2], cdlunit); + desc->cdlp = cdlp; + } + } else { + /* T2A and T2B limits page */ + if (cdlp == SD_CDLP_T2A) + cdl->perf_vs_duration_guideline = buf[7] >> 4; + + buf += 8; + + for (i = 0; i < SD_CDL_MAX_DESC; i++, buf += 32, desc++) { + u8 t2cdlunits = buf[0] & 0x0f; + + desc->max_inactive_time = + sd_cdl_t2time(&buf[2], t2cdlunits); + desc->max_active_time = + sd_cdl_t2time(&buf[4], t2cdlunits); + desc->duration = + sd_cdl_t2time(&buf[10], t2cdlunits); + desc->max_inactive_policy = (buf[6] >> 4) & 0x0f; + desc->max_active_policy = buf[6] & 0x0f; + desc->duration_policy = buf[14] & 0x0f; + desc->cdlp = cdlp; + } + } + + return 0; +} + +static int sd_cdl_read_pages(struct scsi_disk *sdkp, enum sd_cdlp *rw_cdlp, + unsigned char *buf) +{ + struct sd_cdl *cdl = sdkp->cdl; + struct sd_cdl_page *page; + int i, ret; + + /* Read supported pages */ + for (i = 0; i < SD_CDL_RW; i++) { + page = &cdl->pages[i]; + page->cdlp = rw_cdlp[i]; + if (page->cdlp == SD_CDLP_NONE) + continue; + + ret = sd_cdl_read_page(sdkp, page, buf); + if (ret) { + page->cdlp = SD_CDLP_NONE; + return ret; + } + } + + return 0; +} + +static u8 sd_cdl_check_cmd_support(struct scsi_disk *sdkp, + enum sd_cdl_cmd cmd, unsigned char *buf) +{ + u8 opcode = cdl_cmd[cmd].opcode; + u16 sa = cdl_cmd[cmd].sa; + u8 cdlp; + + /* + * READ 32 and WRITE 32 are used only for disks that also support + * type 2 data protection. If the disk does not have such feature, + * ignore these commands. + */ + if ((sa == READ_32 || sa == WRITE_32) && + sdkp->protection_type != T10_PI_TYPE2_PROTECTION) + return SD_CDLP_NONE; + + /* Check operation code */ + if (scsi_report_opcode(sdkp->device, buf, SD_BUF_SIZE, opcode, sa) < 0) + return SD_CDLP_NONE; + + if ((buf[1] & 0x03) != 0x03) + return SD_CDLP_NONE; + + /* See SPC-6, one command format of REPORT SUPPORTED OPERATION CODES */ + cdlp = (buf[1] & 0x18) >> 3; + if (buf[0] & 0x01) { + /* rwcdlp == 1 */ + switch (cdlp) { + case 0x01: + return SD_CDLP_T2A; + case 0x02: + return SD_CDLP_T2B; + } + } else { + /* rwcdlp == 0 */ + switch (cdlp) { + case 0x01: + return SD_CDLP_A; + case 0x02: + return SD_CDLP_B; + } + } + + return SD_CDLP_NONE; +} + +static bool sd_cdl_supported(struct scsi_disk *sdkp, enum sd_cdlp *rw_cdlp, + unsigned char *buf) +{ + enum sd_cdlp cmd_cdlp[SD_CDL_CMD_MAX]; + int i; + + /* + * Command duration limits is supported for READ 16, WRITE 16, + * READ 32 and WRITE 32. Go through all these commands one at a time + * and check if any support duration limits. + */ + for (i = 0; i < SD_CDL_CMD_MAX; i++) + cmd_cdlp[i] = sd_cdl_check_cmd_support(sdkp, i, buf); + + /* + * Allow support only for drives that report the same CDL page for the + * read 16 and 32 variants and the same page for the write 16 and 32 + * variants. + */ + if (cmd_cdlp[SD_CDL_READ_32] != SD_CDLP_NONE && + cmd_cdlp[SD_CDL_READ_16] != SD_CDLP_NONE) { + if (cmd_cdlp[SD_CDL_READ_32] != cmd_cdlp[SD_CDL_READ_16]) + rw_cdlp[SD_CDL_READ] = SD_CDLP_NONE; + else + rw_cdlp[SD_CDL_READ] = cmd_cdlp[SD_CDL_READ_16]; + } else { + rw_cdlp[SD_CDL_READ] = cmd_cdlp[SD_CDL_READ_16]; + } + + if (cmd_cdlp[SD_CDL_WRITE_32] != SD_CDLP_NONE && + cmd_cdlp[SD_CDL_WRITE_16] != SD_CDLP_NONE) { + if (cmd_cdlp[SD_CDL_WRITE_32] != cmd_cdlp[SD_CDL_WRITE_16]) + rw_cdlp[SD_CDL_WRITE] = SD_CDLP_NONE; + else + rw_cdlp[SD_CDL_WRITE] = cmd_cdlp[SD_CDL_WRITE_16]; + } else { + rw_cdlp[SD_CDL_WRITE] = cmd_cdlp[SD_CDL_WRITE_16]; + } + + return rw_cdlp[SD_CDL_READ] != SD_CDLP_NONE || + rw_cdlp[SD_CDL_WRITE] != SD_CDLP_NONE; +} + +static struct sd_cdl *sd_cdl_alloc(void) +{ + struct sd_cdl *cdl; + struct sd_cdl_page *page; + int i, j; + + cdl = kzalloc(sizeof(struct sd_cdl), GFP_KERNEL); + if (!cdl) + return NULL; + + kobject_init(&cdl->kobj, &sd_cdl_ktype); + for (i = 0; i < SD_CDL_RW; i++) { + page = &cdl->pages[i]; + kobject_init(&page->kobj, &sd_cdl_page_ktype); + page->rw = i; + page->cdlp = SD_CDLP_NONE; + for (j = 0; j < SD_CDL_MAX_DESC; j++) + kobject_init(&page->descs[j].kobj, &sd_cdl_desc_ktype); + } + + return cdl; +} + +void sd_read_cdl(struct scsi_disk *sdkp, unsigned char *buf) +{ + struct sd_cdl *cdl = sdkp->cdl; + enum sd_cdlp rw_cdlp[SD_CDL_RW]; + + /* + * Check for CDL support. If the disk does not support duration limits, + * clear any support information that was previously registered. + */ + if (!sd_cdl_supported(sdkp, rw_cdlp, buf)) + goto unregister; + + if (!cdl) { + cdl = sd_cdl_alloc(); + if (!cdl) + return; + } + + /* + * We have CDL support: force the use of READ16/WRITE16. + * READ32 and WRITE32 will be used automatically for disks with + * T10_PI_TYPE2_PROTECTION support. + */ + sdkp->device->use_16_for_rw = 1; + sdkp->device->use_10_for_rw = 0; + + if (!sdkp->cdl) { + sd_printk(KERN_NOTICE, sdkp, + "Command duration limits supported, reads: %s, writes: %s\n", + cdl_page[rw_cdlp[SD_CDL_READ]].name, + cdl_page[rw_cdlp[SD_CDL_WRITE]].name); + sdkp->cdl = cdl; + } + + /* Update duration limits descriptor pages */ + if (sd_cdl_read_pages(sdkp, rw_cdlp, buf)) + goto unregister; + + sd_cdl_sysfs_register(sdkp); + + return; + +unregister: + sd_cdl_sysfs_unregister(sdkp); +} + +void sd_cdl_release(struct scsi_disk *sdkp) +{ + sd_cdl_sysfs_unregister(sdkp); +} From patchwork Thu Dec 8 10:59:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 633192 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 92213C63709 for ; Thu, 8 Dec 2022 11:04:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229754AbiLHLEZ (ORCPT ); Thu, 8 Dec 2022 06:04:25 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39834 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229775AbiLHLDX (ORCPT ); Thu, 8 Dec 2022 06:03:23 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AA38785669 for ; Thu, 8 Dec 2022 03:01:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497296; x=1702033296; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=cwbeswERpri7S0OvuN19RuknsWkkKg0ZDb7ceoG2q0M=; b=LpxZtJmRvrnlZP3yCOJpdJlhYw9Hl5PYGHi/ggJQ+5uekerEuz6d/401 XejCJR0+iqvRm2kEDa5jqPzzkIi7hMNoimnwyzbUiWwUIWUu8bYOi9Dhr mlpx6KLUr+h/zx7kr6hbDL9JG296Zl15sSieoWLCTdqdqxoD18RzBT9+L hXRtGqP8PcupEpNW6Mu8meb3XxtXwB75x1TWifWgudNL1VDulaCKH0zwS vVJJVbEqk68rSrp99yNF3LKY913jh7QmVDnPkFO3rTKrLGLg4GegLY5Ro CDasOqDfefnLLH/6M517hcHm6tWxV/C8opYYqNhddgnncmgqOnMIKFg2d g==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333432" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:01:36 +0800 IronPort-SDR: wgGEJ95nH18BIY1HLGBRC1cTJx2rNe08fFCOBBIPLp/JXQtYQOlH1bduNwEIVoZBD3KkfFbm3O oRpsdvTEnpm6kXfh6ZBz/ta5QX/2ZlrIuUpahBbYbds8h+50rKSpl1USNNMOVkc/y5wcmRxuTn IjAgICvgZ6SpHEtyZpBjQTKRSqSn9PFjGQN512fPsUFeNwNGc1M4Qu7imRkV5UCWx7YR40Qa3F MZ/z9CuoV0UVJpESjPQwDSPosSlDXl34dxZdOqagaJW3xDUtHItjPUDNepIPLZposGhI0AaDEP WNw= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:14:21 -0800 IronPort-SDR: 2ieOg0b5XT/IpxmBgLoB2+B4LbZMyAAus109Lf2MZM42/Oo83FFKlKmz2v/8aMXXJr+te5iko/ 1GHUUz3jo0wx/kRJsF0On4p85BvTuylIURb58sv9g4jG53qTWjfCJ6n9sWQspiAUajbLyzmnkL Tyc33qmnnXdQBBxE/LMLBLFTOTgdmHjGEZytd8IPsbKhjJs3SkaKI/GvhIQl5CFIczYHFkz8SR yBqSiguEL/ugOXBoHRwy9oUKO8jCRGSpYJYzji29ypP24l3VNdR6jcnWHQBsYOQRb9kTi80AOn leM= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:01:35 -0800 From: Niklas Cassel To: "James E.J. Bottomley" , "Martin K. Petersen" Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Damien Le Moal , Niklas Cassel Subject: [PATCH 22/25] scsi: sd: set read/write commands CDL index Date: Thu, 8 Dec 2022 11:59:38 +0100 Message-Id: <20221208105947.2399894-23-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org From: Damien Le Moal Introduce the command duration limits helper function sd_cdl_cmd_limit() to retrieve and set the DLD bits of the READ/WRITE 16 and READ/WRITE 32 commands to indicate to the device the command duration limit descriptor to apply to the command. When command duration limits are enabled, sd_cdl_cmd_limit() obtains the index of the descriptor to apply to the command for requests that have the IOPRIO_CLASS_DL priority class with a priority data sepcifying a valid descriptor index (1 to 7). The read-write sysfs attribute "enable" is introduced to control setting the command duration limits indexes. If this attribute is set to 0 (default), command duration limits specified by the user are ignored. The user must set this attribute to 1 for command duration limits to be set. Enabling and disabling the command duration limits feature for ATA devices must be done using the ATA feature sub-page of the control mode page. The sd_cdl_enable() function is introduced to check if this mode page is supported by the device and if it is, use it to enable/disable CDL. Co-developed-by: Niklas Cassel Signed-off-by: Niklas Cassel Signed-off-by: Damien Le Moal --- drivers/scsi/sd.c | 16 +++-- drivers/scsi/sd.h | 10 ++++ drivers/scsi/sd_cdl.c | 134 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 152 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 45ff44a73256..1f516910da0b 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1042,13 +1042,14 @@ static blk_status_t sd_setup_flush_cmnd(struct scsi_cmnd *cmd) static blk_status_t sd_setup_rw32_cmnd(struct scsi_cmnd *cmd, bool write, sector_t lba, unsigned int nr_blocks, - unsigned char flags) + unsigned char flags, unsigned int dld) { cmd->cmd_len = SD_EXT_CDB_SIZE; cmd->cmnd[0] = VARIABLE_LENGTH_CMD; cmd->cmnd[7] = 0x18; /* Additional CDB len */ cmd->cmnd[9] = write ? WRITE_32 : READ_32; cmd->cmnd[10] = flags; + cmd->cmnd[11] = dld & 0x07; put_unaligned_be64(lba, &cmd->cmnd[12]); put_unaligned_be32(lba, &cmd->cmnd[20]); /* Expected Indirect LBA */ put_unaligned_be32(nr_blocks, &cmd->cmnd[28]); @@ -1058,12 +1059,12 @@ static blk_status_t sd_setup_rw32_cmnd(struct scsi_cmnd *cmd, bool write, static blk_status_t sd_setup_rw16_cmnd(struct scsi_cmnd *cmd, bool write, sector_t lba, unsigned int nr_blocks, - unsigned char flags) + unsigned char flags, unsigned int dld) { cmd->cmd_len = 16; cmd->cmnd[0] = write ? WRITE_16 : READ_16; - cmd->cmnd[1] = flags; - cmd->cmnd[14] = 0; + cmd->cmnd[1] = flags | ((dld >> 2) & 0x01); + cmd->cmnd[14] = (dld & 0x03) << 6; cmd->cmnd[15] = 0; put_unaligned_be64(lba, &cmd->cmnd[2]); put_unaligned_be32(nr_blocks, &cmd->cmnd[10]); @@ -1126,6 +1127,7 @@ static blk_status_t sd_setup_read_write_cmnd(struct scsi_cmnd *cmd) unsigned int mask = logical_to_sectors(sdp, 1) - 1; bool write = rq_data_dir(rq) == WRITE; unsigned char protect, fua; + unsigned int dld = 0; blk_status_t ret; unsigned int dif; bool dix; @@ -1175,6 +1177,8 @@ static blk_status_t sd_setup_read_write_cmnd(struct scsi_cmnd *cmd) fua = rq->cmd_flags & REQ_FUA ? 0x8 : 0; dix = scsi_prot_sg_count(cmd); dif = scsi_host_dif_capable(cmd->device->host, sdkp->protection_type); + if (sd_cdl_enabled(sdkp)) + dld = sd_cdl_dld(sdkp, cmd); if (dif || dix) protect = sd_setup_protect_cmnd(cmd, dix, dif); @@ -1183,10 +1187,10 @@ static blk_status_t sd_setup_read_write_cmnd(struct scsi_cmnd *cmd) if (protect && sdkp->protection_type == T10_PI_TYPE2_PROTECTION) { ret = sd_setup_rw32_cmnd(cmd, write, lba, nr_blocks, - protect | fua); + protect | fua, dld); } else if (sdp->use_16_for_rw || (nr_blocks > 0xffff)) { ret = sd_setup_rw16_cmnd(cmd, write, lba, nr_blocks, - protect | fua); + protect | fua, dld); } else if ((nr_blocks > 0xff) || (lba > 0x1fffff) || sdp->use_10_for_rw || protect) { ret = sd_setup_rw10_cmnd(cmd, write, lba, nr_blocks, diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index e60d33bd222a..5b6b6dc4b92d 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -130,8 +130,11 @@ struct sd_cdl_page { struct sd_cdl_desc descs[SD_CDL_MAX_DESC]; }; +struct scsi_disk; + struct sd_cdl { struct kobject kobj; + struct scsi_disk *sdkp; bool sysfs_registered; u8 perf_vs_duration_guideline; struct sd_cdl_page pages[SD_CDL_RW]; @@ -188,6 +191,7 @@ struct scsi_disk { u8 zeroing_mode; u8 nr_actuators; /* Number of actuators */ struct sd_cdl *cdl; + unsigned cdl_enabled : 1; unsigned ATO : 1; /* state of disk ATO bit */ unsigned cache_override : 1; /* temp override of WCE,RCD */ unsigned WCE : 1; /* state of disk WCE bit */ @@ -355,5 +359,11 @@ void sd_print_result(const struct scsi_disk *sdkp, const char *msg, int result); /* Command duration limits support (in sd_cdl.c) */ void sd_read_cdl(struct scsi_disk *sdkp, unsigned char *buf); void sd_cdl_release(struct scsi_disk *sdkp); +int sd_cdl_dld(struct scsi_disk *sdkp, struct scsi_cmnd *scmd); + +static inline bool sd_cdl_enabled(struct scsi_disk *sdkp) +{ + return sdkp->cdl && sdkp->cdl_enabled; +} #endif /* _SCSI_DISK_H */ diff --git a/drivers/scsi/sd_cdl.c b/drivers/scsi/sd_cdl.c index 513cd989f19a..59d02dbb5ea1 100644 --- a/drivers/scsi/sd_cdl.c +++ b/drivers/scsi/sd_cdl.c @@ -93,6 +93,63 @@ static const char *sd_cdl_policy_name(u8 policy) } } +/* + * Enable/disable CDL. + */ +static int sd_cdl_enable(struct scsi_disk *sdkp, bool enable) +{ + struct scsi_device *sdp = sdkp->device; + struct scsi_mode_data data; + struct scsi_sense_hdr sshdr; + struct scsi_vpd *vpd; + bool is_ata = false; + char buf[64]; + int ret; + + rcu_read_lock(); + vpd = rcu_dereference(sdp->vpd_pg89); + if (vpd) + is_ata = true; + rcu_read_unlock(); + + /* + * For ATA devices, CDL needs to be enabled with a SET FEATURES command. + */ + if (is_ata) { + char *buf_data; + int len; + + ret = scsi_mode_sense(sdp, 0x08, 0x0a, 0xf2, buf, sizeof(buf), + SD_TIMEOUT, sdkp->max_retries, &data, + NULL); + if (ret) + return -EINVAL; + + /* Enable CDL using the ATA feature page */ + len = min_t(size_t, sizeof(buf), + data.length - data.header_length - + data.block_descriptor_length); + buf_data = buf + data.header_length + + data.block_descriptor_length; + if (enable) + buf_data[4] = 0x02; + else + buf_data[4] = 0; + + ret = scsi_mode_select(sdp, 1, 0, buf_data, len, SD_TIMEOUT, + sdkp->max_retries, &data, &sshdr); + if (ret) { + if (scsi_sense_valid(&sshdr)) + sd_print_sense_hdr(sdkp, &sshdr); + return -EINVAL; + } + } + + sdkp->cdl_enabled = enable; + + return 0; +} + /* * Command duration limits descriptors sysfs plumbing. */ @@ -324,6 +381,7 @@ static int sd_cdl_sysfs_register_page(struct scsi_disk *sdkp, struct sd_cdl_sysfs_entry { struct attribute attr; ssize_t (*show)(struct sd_cdl *cdl, char *buf); + ssize_t (*store)(struct sd_cdl *cdl, const char *buf, size_t length); }; #define CDL_ATTR_RO(_name) \ @@ -332,6 +390,13 @@ struct sd_cdl_sysfs_entry { .show = cdl_##_name##_show, \ } +#define CDL_ATTR_RW(_name) \ + static struct sd_cdl_sysfs_entry cdl_##_name##_entry = { \ + .attr = { .name = __stringify(_name), .mode = 0644 }, \ + .show = cdl_##_name##_show, \ + .store = cdl_##_name##_store, \ + } + static ssize_t cdl_perf_vs_duration_guideline_show(struct sd_cdl *cdl, char *buf) { @@ -340,8 +405,31 @@ static ssize_t cdl_perf_vs_duration_guideline_show(struct sd_cdl *cdl, } CDL_ATTR_RO(perf_vs_duration_guideline); +static ssize_t cdl_enable_show(struct sd_cdl *cdl, char *buf) +{ + return sysfs_emit(buf, "%d\n", (int)cdl->sdkp->cdl_enabled); +} + +static ssize_t cdl_enable_store(struct sd_cdl *cdl, + const char *buf, size_t count) +{ + int ret; + bool v; + + if (kstrtobool(buf, &v)) + return -EINVAL; + + ret = sd_cdl_enable(cdl->sdkp, v); + if (ret) + return ret; + + return count; +} +CDL_ATTR_RW(enable); + static struct attribute *sd_cdl_attrs[] = { &cdl_perf_vs_duration_guideline_entry.attr, + &cdl_enable_entry.attr, NULL, }; @@ -375,8 +463,25 @@ static ssize_t sd_cdl_sysfs_show(struct kobject *kobj, return entry->show(cdl, page); } +static ssize_t sd_cdl_sysfs_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t length) +{ + struct sd_cdl_sysfs_entry *entry = + container_of(attr, struct sd_cdl_sysfs_entry, attr); + struct sd_cdl *cdl = container_of(kobj, struct sd_cdl, kobj); + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (!entry->store) + return -EIO; + + return entry->store(cdl, buf, length); +} + static const struct sysfs_ops sd_cdl_sysfs_ops = { .show = sd_cdl_sysfs_show, + .store = sd_cdl_sysfs_store, }; static void sd_cdl_sysfs_release(struct kobject *kobj) @@ -411,6 +516,7 @@ static void sd_cdl_sysfs_unregister(struct scsi_disk *sdkp) sd_cdl_sysfs_unregister_page(&cdl->pages[i]); } + cdl->sdkp->cdl_enabled = 0; kobject_del(&cdl->kobj); kobject_put(&cdl->kobj); } @@ -689,7 +795,7 @@ static bool sd_cdl_supported(struct scsi_disk *sdkp, enum sd_cdlp *rw_cdlp, rw_cdlp[SD_CDL_WRITE] != SD_CDLP_NONE; } -static struct sd_cdl *sd_cdl_alloc(void) +static struct sd_cdl *sd_cdl_alloc(struct scsi_disk *sdkp) { struct sd_cdl *cdl; struct sd_cdl_page *page; @@ -699,6 +805,7 @@ static struct sd_cdl *sd_cdl_alloc(void) if (!cdl) return NULL; + cdl->sdkp = sdkp; kobject_init(&cdl->kobj, &sd_cdl_ktype); for (i = 0; i < SD_CDL_RW; i++) { page = &cdl->pages[i]; @@ -725,7 +832,7 @@ void sd_read_cdl(struct scsi_disk *sdkp, unsigned char *buf) goto unregister; if (!cdl) { - cdl = sd_cdl_alloc(); + cdl = sd_cdl_alloc(sdkp); if (!cdl) return; } @@ -762,3 +869,26 @@ void sd_cdl_release(struct scsi_disk *sdkp) { sd_cdl_sysfs_unregister(sdkp); } + +/* + * Check if a command has a duration limit set. If it does, return the + * descriptor index to use and 0 if the command has no limit set. + */ +int sd_cdl_dld(struct scsi_disk *sdkp, struct scsi_cmnd *scmd) +{ + unsigned int ioprio = req_get_ioprio(scsi_cmd_to_rq(scmd)); + unsigned int dld; + + /* + * Use "no limit" if the request ioprio class is not IOPRIO_CLASS_DL + * or if the user specified an invalid CDL descriptor index. + */ + if (IOPRIO_PRIO_CLASS(ioprio) != IOPRIO_CLASS_DL) + return 0; + + dld = IOPRIO_PRIO_DATA(ioprio); + if (dld > SD_CDL_MAX_DESC) + return 0; + + return dld; +} From patchwork Thu Dec 8 10:59:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 633193 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 69127C4332F for ; Thu, 8 Dec 2022 11:04:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229635AbiLHLEV (ORCPT ); Thu, 8 Dec 2022 06:04:21 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39840 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229902AbiLHLDa (ORCPT ); Thu, 8 Dec 2022 06:03:30 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1D14F89300 for ; Thu, 8 Dec 2022 03:01:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497299; x=1702033299; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=oLwoD0k+2ptuNw6dbgtNnXCNXdqKGfrc6HYOeC/bJcE=; b=WljUvz0i5vbq8MQl91Yjyx3FMnaKIdCIuowWWngwycOKkQlS/ap2GzMt 4ZGUh4V/6AFDG0UKhUB3HEK99z9m/uIBunGtMGaYnBwJOq7aImm8RhICb Le5kxZqsehsJrpQ2JW6MwiS0RZxM7C4m33ssEO5C8eUSwmu3JJHdnX8U6 sif44QEt8AHA/sJDC9Xkmp8OFw+OzRgCRtDBqheUc9ebIOLee9p6I1Bz9 XlLdybkm0+FrQmEPGQXDWvlOi5nmCnwy3swdd+H2lEwzIR07giak+jbau gyIEc/oQPuuf8P2sHzaLcprI062siXCzxwTrlGLYXM3/TZTOKv7wrm9qh g==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333434" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:01:38 +0800 IronPort-SDR: SPeOVw9LIP5DYoilZ9/TEdzgo2M5nZz+RdjoXwIDxvdtLYBRYyJg6d/qYAKiegdg/xV6kHVZlH HEuj6yWvt88TYf6BUPRnawo893y7Q5PKkvMKZk1skxcBxToklYpYc/69IC1D+iR9Mp3i17tae1 L5CzKVCbpr1iPqUlIuZQpiTo9CLJt7uZqNcWYFNKxnsKUtxmNXGPARpytEMpvQwCguDhDj0B+u 2kyDV74/0BOqPmxbE4SjHi78k8/UNMQ3JyAkrGqjwG/o+FPk8BRp9cr1KQIW2SgRIwHNVUZCXm hwg= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:14:24 -0800 IronPort-SDR: 0MlWO8RGTZ4JDQtZ+BueoiXAJbEftH5NYVB3l3fZdmPG9mf3hnvS5450AcoR8i18YpXSWlSeGD xTBcT8J8MayT+ci7Bxa3h+PZRmCN6U7czKaW7X/GT/iwwLXdT0jZnMP+2JWUpWSbrjnQ2aLzCq mCUmYXC+77PaHQsTZh38sXJ2Kna0xx/lgsgmeRVDIlUBxktLyCr2kq6/vdKXe6z0ViilS2hzv2 WgLcaXVZjygN3APdagSLcuhmiIUUEe+lpegXG96yfLqUkL7dTrmQxh00/mMGm6S254N30BQJhn 36w= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:01:38 -0800 From: Niklas Cassel To: "James E.J. Bottomley" , "Martin K. Petersen" Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Niklas Cassel , Damien Le Moal Subject: [PATCH 23/25] scsi: sd: handle read/write CDL timeout failures Date: Thu, 8 Dec 2022 11:59:39 +0100 Message-Id: <20221208105947.2399894-24-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Commands using a duration limit descriptor that has limit policies set to a value other than 0x0 may be failed by the device if one of the limits are exceeded. For such commands, since the failure is the result of the user duration limit configuration and workload, the commands should not be retried and terminated immediately. Furthermore, to allow the user to differentiate these "soft" failures from hard errors due to hardware problem, a different error code than EIO should be returned. There are 2 cases to consider: (1) The failure is due to a limit policy failing the command with a check condition sense key, that is, any limit policy other than 0xD. For this case, scsi_check_sense() is modified to detect failures with the ABORTED COMMAND sense key and the COMMAND TIMEOUT BEFORE PROCESSING or COMMAND TIMEOUT DURING PROCESSING or COMMAND TIMEOUT DURING PROCESSING DUE TO ERROR RECOVERY additional sense code. For these failures, a SUCCESS disposition is returned so that scsi_finish_command() is called to terminate the command. (2) The failure is due to a limit policy set to 0xD, which result in the command being terminated with a GOOD status, COMPLETED sense key, and DATA CURRENTLY UNAVAILABLE additional sense code. To handle this case, the scsi_check_sense() is modified to return a SUCCESS disposition so that scsi_finish_command() is called to terminate the command. In addition, scsi_decide_disposition() has to be modified to see if a command being terminated with GOOD status has sense data. This is as defined in SCSI Primary Commands - 6 (SPC-6), so all according to spec, even if GOOD status commands were not checked before. If scsi_check_sense() detects sense data representing a duration limit, scsi_check_sense() will set the newly introduced SCSI ML byte SCSIML_STAT_DL_TIMEOUT. This SCSI ML byte is checked in scsi_noretry_cmd(), so that a command that failed because of a CDL timeout cannot be retried. The SCSI ML byte is also checked in scsi_result_to_blk_status() to complete the command request with the BLK_STS_DURATION_LIMIT status, which result in the user seeing ETIME errors for the failed commands. Co-developed-by: Damien Le Moal Signed-off-by: Damien Le Moal Signed-off-by: Niklas Cassel --- drivers/scsi/scsi_error.c | 46 +++++++++++++++++++++++++++++++++++++++ drivers/scsi/scsi_lib.c | 4 ++++ drivers/scsi/scsi_priv.h | 1 + 3 files changed, 51 insertions(+) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 51aa5c1e31b5..1bdab5385985 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -536,6 +536,7 @@ static inline void set_scsi_ml_byte(struct scsi_cmnd *cmd, u8 status) */ enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd) { + struct request *req = scsi_cmd_to_rq(scmd); struct scsi_device *sdev = scmd->device; struct scsi_sense_hdr sshdr; @@ -595,6 +596,22 @@ enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd) if (sshdr.asc == 0x10) /* DIF */ return SUCCESS; + /* + * Check aborts due to command duration limit policy: + * ABORTED COMMAND additional sense code with the + * COMMAND TIMEOUT BEFORE PROCESSING or + * COMMAND TIMEOUT DURING PROCESSING or + * COMMAND TIMEOUT DURING PROCESSING DUE TO ERROR RECOVERY + * additional sense code qualifiers. + */ + if (sshdr.asc == 0x2e && + sshdr.ascq >= 0x01 && sshdr.ascq <= 0x03) { + set_scsi_ml_byte(scmd, SCSIML_STAT_DL_TIMEOUT); + req->cmd_flags |= REQ_FAILFAST_DEV; + req->rq_flags |= RQF_QUIET; + return SUCCESS; + } + if (sshdr.asc == 0x44 && sdev->sdev_bflags & BLIST_RETRY_ITF) return ADD_TO_MLQUEUE; if (sshdr.asc == 0xc1 && sshdr.ascq == 0x01 && @@ -691,6 +708,15 @@ enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd) } return SUCCESS; + case COMPLETED: + if (sshdr.asc == 0x55 && sshdr.ascq == 0x0a) { + set_scsi_ml_byte(scmd, SCSIML_STAT_DL_TIMEOUT); + req->cmd_flags |= REQ_FAILFAST_DEV; + req->rq_flags |= RQF_QUIET; + return SUCCESS; + } + return SUCCESS; + default: return SUCCESS; } @@ -785,6 +811,14 @@ static enum scsi_disposition scsi_eh_completed_normally(struct scsi_cmnd *scmd) switch (get_status_byte(scmd)) { case SAM_STAT_GOOD: scsi_handle_queue_ramp_up(scmd->device); + if (scmd->sense_buffer && SCSI_SENSE_VALID(scmd)) + /* + * If we have sense data, call scsi_check_sense() in + * order to set the correct SCSI ML byte (if any). + * No point in checking the return value, since the + * command has already completed successfully. + */ + scsi_check_sense(scmd); fallthrough; case SAM_STAT_COMMAND_TERMINATED: return SUCCESS; @@ -1807,6 +1841,10 @@ bool scsi_noretry_cmd(struct scsi_cmnd *scmd) return !!(req->cmd_flags & REQ_FAILFAST_DRIVER); } + /* Never retry commands aborted due to a duration limit timeout */ + if (get_scsi_ml_byte(scmd->result) == SCSIML_STAT_DL_TIMEOUT) + return true; + if (!scsi_status_is_check_condition(scmd->result)) return false; @@ -1966,6 +2004,14 @@ enum scsi_disposition scsi_decide_disposition(struct scsi_cmnd *scmd) if (scmd->cmnd[0] == REPORT_LUNS) scmd->device->sdev_target->expecting_lun_change = 0; scsi_handle_queue_ramp_up(scmd->device); + if (scmd->sense_buffer && SCSI_SENSE_VALID(scmd)) + /* + * If we have sense data, call scsi_check_sense() in + * order to set the correct SCSI ML byte (if any). + * No point in checking the return value, since the + * command has already completed successfully. + */ + scsi_check_sense(scmd); fallthrough; case SAM_STAT_COMMAND_TERMINATED: return SUCCESS; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index e64fd8f495d7..4f317c6593aa 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -602,6 +602,8 @@ static blk_status_t scsi_result_to_blk_status(int result) return BLK_STS_MEDIUM; case SCSIML_STAT_TGT_FAILURE: return BLK_STS_TARGET; + case SCSIML_STAT_DL_TIMEOUT: + return BLK_STS_DURATION_LIMIT; } switch (host_byte(result)) { @@ -799,6 +801,8 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result) blk_stat = BLK_STS_ZONE_OPEN_RESOURCE; } break; + case COMPLETED: + fallthrough; default: action = ACTION_FAIL; break; diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 4f97e126c6fb..f8da92428ff6 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -27,6 +27,7 @@ enum scsi_ml_status { SCSIML_STAT_NOSPC = 0x02, /* Space allocation on the dev failed */ SCSIML_STAT_MED_ERROR = 0x03, /* Medium error */ SCSIML_STAT_TGT_FAILURE = 0x04, /* Permanent target failure */ + SCSIML_STAT_DL_TIMEOUT = 0x05, /* Command Duration Limit timeout */ }; static inline u8 get_scsi_ml_byte(int result) From patchwork Thu Dec 8 10:59:40 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 633191 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7E458C4332F for ; Thu, 8 Dec 2022 11:05:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229989AbiLHLEy (ORCPT ); Thu, 8 Dec 2022 06:04:54 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40000 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229929AbiLHLDa (ORCPT ); Thu, 8 Dec 2022 06:03:30 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EEDBF89326; Thu, 8 Dec 2022 03:01:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497301; x=1702033301; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=FrYoQibYnNJyG9v24OMUbrROx7H4s/1w3/ha5UWQEyI=; b=bQp4Q5bYCIHecLZoavWI3dE0M5sTIjqievJK7DOiuWptewLwv7jJxWw7 ebn1Z+pK3ILrY6lTGBAz02iwOisZxssEyWFPbZY1sJ3W355Sif/rTXxK7 P/NKiT7NJ9XNxoqcsX3BsJWXNjh1QN4G9subfPYVfjiBZ3HOKz+tV5qqt UABc38VzY++gLkTUAwbsRIKRQd8QDZT3V0Xy956aE4FTPtW1hjvliz3Lg +v7McPkAZnHdiZ1GXTHj5uAVs3X5Z+8gATDY5K9JtMa6e6GgbVsDfYrDT yUFGiC5mk1dA5h2TTb5+gDes0++ehtOKggz0v2YhH3dFmmt3UAYRF6mGN w==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333437" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:01:41 +0800 IronPort-SDR: 9NB2tcLdHLGPgIpGOiAYLCmu/J1Coa0pHW3yhpZQpFvI9CX4ODosnFWVeyudWNOo15mxfQT680 JC9x8tJYLUwWVWqxuwHzPOWhnZonjlapew6u+16L33gOCawgDdt1Fd38LAtthUocpWtfsGMFR8 kheZ4DgmiPouXLfYeOZ+jV1Foq5g87p4FwajNJcOybvh+Q64fSO/4uyUIerLUYU64oDxebdDw8 DQjLnnYX6cV/b5M15A3UeVxnjMZ0wSOKNEUD1q4/MrehOh/anoEJ+i0G/BaZvQEMUR5+qJH7L7 RIo= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:14:26 -0800 IronPort-SDR: IybSnvqeacTmkLVsHZLtNuEwmHdoXhlR2S5qcFn6Ru/1TqHN6CXFiP5BL2Fzzd4tuhuX6audce 4c405FAdLjqwFits9H2xkN8vlrtU8EHKZ6cDm9b3xDY0DgAKyZN+uQMuM6Y3c1COMloOZy0wyT ci6lCoAEJp4LmqShTJaEvJLAdCHb0UM9oi0/ajXB6mNOrgucnJwhi7mB8fmy12UIoHsxxAHn+c 7GKLBtQKUP/s0bM2bHOPMxjGWKBK8khm0pQ6OROl3+CipDdLXaO1OhPv0BUc/VFXUnf54JzEa3 510= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:01:41 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Niklas Cassel , linux-ide@vger.kernel.org Subject: [PATCH 24/25] ata: libata: handle completion of CDL commands using policy 0xD Date: Thu, 8 Dec 2022 11:59:40 +0100 Message-Id: <20221208105947.2399894-25-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org A CDL timeout for policy 0xF is defined as a NCQ error, just with a CDL specific sk/asc/ascq in the sense data. Therefore, the existing code in libata does not need to be modified to handle a policy 0xF CDL timeout. For Command Duration Limits policy 0xD: The device shall complete the command without error with the additional sense code set to DATA CURRENTLY UNAVAILABLE. Since a CDL timeout for policy 0xD is not an error, we cannot use the NCQ Command Error log (10h). Instead, we need to read the Sense Data for Successful NCQ Commands log (0Fh). In the success case, just like in the error case, we cannot simply read a log page from the interrupt handler itself, since reading a log page involves sending a READ LOG DMA EXT or READ LOG EXT command. Therefore, we add a new EH action ATA_EH_GET_SUCCESS_SENSE. When a command completes without error, and when the ATA_SENSE bit is set, this new action is set as pending, and EH is scheduled. This way, similar to the NCQ error case, the log page will be read from EH context. An alternative would have been to add a new kthread or workqueue to handle this. However, extending EH can be done with minimal changes and avoids the need to synchronize a new kthread/workqueue with EH. Co-developed-by: Damien Le Moal Signed-off-by: Damien Le Moal Signed-off-by: Niklas Cassel --- drivers/ata/libata-core.c | 82 ++++++++++++++++++++++++++++- drivers/ata/libata-eh.c | 108 +++++++++++++++++++++++++++++++++++++- drivers/ata/libata-sata.c | 89 +++++++++++++++++++++++++++++++ include/linux/ata.h | 3 ++ include/linux/libata.h | 11 +++- 5 files changed, 289 insertions(+), 4 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index c79ee38dc594..78f586a21528 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -683,8 +683,12 @@ static inline void ata_set_tf_cdl(struct ata_queued_cmd *qc, int ioprio) else tf->feature |= cdl; - /* Mark this command as having a CDL */ - qc->flags |= ATA_QCFLAG_HAS_CDL; + /* + * Mark this command as having a CDL and request the result + * task file so that we can inspect the sense data available + * bit on completion. + */ + qc->flags |= ATA_QCFLAG_HAS_CDL | ATA_QCFLAG_RESULT_TF; } /** @@ -2427,6 +2431,24 @@ static void ata_dev_config_cdl(struct ata_device *dev) ata_dev_warn(dev, "Command duration guideline is not supported\n"); + /* + * We must have support for the sense data for successful NCQ commands + * log indicated by the successful NCQ command sense data supported bit. + */ + val = get_unaligned_le64(&ap->sector_buf[8]); + if (!(val & BIT_ULL(63)) || !(val & BIT_ULL(47))) { + ata_dev_warn(dev, + "CDL supported but Successful NCQ Command Sense Data is not supported\n"); + goto not_supported; + } + + /* Without NCQ autosense, the successful NCQ commands log is useless. */ + if (!ata_id_has_ncq_autosense(dev->id)) { + ata_dev_warn(dev, + "CDL supported but NCQ autosense is not supported\n"); + goto not_supported; + } + /* * If CDL is marked as enabled, make sure the feature is enabled too. * Conversely, if CDL is disabled, make sure the feature is turned off. @@ -2461,6 +2483,35 @@ static void ata_dev_config_cdl(struct ata_device *dev) } } + /* + * While CDL itself has to be enabled using sysfs, CDL requires that + * sense data for successful NCQ commands is enabled to work properly. + * Just like ata_dev_config_sense_reporting(), enable it unconditionally + * if supported. + */ + if (!(val & BIT_ULL(63)) || !(val & BIT_ULL(18))) { + err_mask = ata_dev_set_feature(dev, + SETFEATURE_SENSE_DATA_SUCC_NCQ, 0x1); + if (err_mask) { + ata_dev_warn(dev, + "failed to enable Sense Data for successful NCQ commands, Emask 0x%x\n", + err_mask); + goto not_supported; + } + } + + /* + * Allocate a buffer to handle reading the sense data for successful + * NCQ Commands log page for commands using a CDL with one of the limit + * policy set to 0xD (successful completion with sense data available + * bit set). + */ + if (!ap->ncq_sense_buf) { + ap->ncq_sense_buf = kmalloc(ATA_LOG_SENSE_NCQ_SIZE, GFP_KERNEL); + if (!ap->ncq_sense_buf) + goto not_supported; + } + /* * Command duration limits is supported: cache the CDL log page 18h * (command duration descriptors). @@ -2478,6 +2529,8 @@ static void ata_dev_config_cdl(struct ata_device *dev) not_supported: dev->flags &= ~(ATA_DFLAG_CDL | ATA_DFLAG_CDL_ENABLED); + kfree(ap->ncq_sense_buf); + ap->ncq_sense_buf = NULL; } static int ata_dev_config_lba(struct ata_device *dev) @@ -4848,6 +4901,30 @@ void ata_qc_complete(struct ata_queued_cmd *qc) fill_result_tf(qc); trace_ata_qc_complete_done(qc); + + /* + * For CDL commands that completed without an error, check if + * we have sense data (ATA_SENSE is set). If we do, then the + * command may have been aborted by the device due to a limit + * timeout using the policy 0xD. For these commands, invoke EH + * to get the command sense data. + */ + if (qc->result_tf.status & ATA_SENSE && + ((ata_is_ncq(qc->tf.protocol) && + dev->flags & ATA_DFLAG_CDL_ENABLED) || + (!(ata_is_ncq(qc->tf.protocol) && + ata_id_sense_reporting_enabled(dev->id))))) { + /* + * Tell SCSI EH to not overwrite scmd->result even if + * this command is finished with result SAM_STAT_GOOD. + */ + qc->scsicmd->flags |= SCMD_EH_SUCCESS_CMD; + qc->flags |= ATA_QCFLAG_EH_SUCCESS_CMD; + ehi->dev_action[dev->devno] |= ATA_EH_GET_SUCCESS_SENSE; + ata_qc_schedule_eh(qc); + return; + } + /* Some commands need post-processing after successful * completion. */ @@ -5480,6 +5557,7 @@ static void ata_host_release(struct kref *kref) kfree(ap->pmp_link); kfree(ap->slave_link); + kfree(ap->ncq_sense_buf); kfree(ap); host->ports[i] = NULL; } diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index e05d62791e08..d34bda7a7baa 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1910,6 +1910,102 @@ static inline bool ata_eh_quiet(struct ata_queued_cmd *qc) return qc->flags & ATA_QCFLAG_QUIET; } +static int ata_eh_read_sense_success_non_ncq(struct ata_link *link) +{ + struct ata_port *ap = link->ap; + struct ata_queued_cmd *qc; + + qc = __ata_qc_from_tag(ap, link->active_tag); + if (!qc) + return -EIO; + + if (!(qc->flags & ATA_QCFLAG_EH) || + !(qc->flags & ATA_QCFLAG_EH_SUCCESS_CMD) || + qc->err_mask) + return -EIO; + + ata_eh_request_sense(qc, false); + + if (!(qc->flags & ATA_QCFLAG_SENSE_VALID)) + return -EIO; + + /* + * If we have sense data, call scsi_check_sense() in order to set the + * correct SCSI ML byte (if any). No point in checking the return value, + * since the command has already completed successfully. + */ + scsi_check_sense(qc->scsicmd); + + return 0; +} + +static void ata_eh_get_success_sense(struct ata_link *link) +{ + struct ata_eh_context *ehc = &link->eh_context; + struct ata_device *dev = link->device; + struct ata_port *ap = link->ap; + struct ata_queued_cmd *qc; + int tag, ret = 0; + + if (!(ehc->i.dev_action[dev->devno] & ATA_EH_GET_SUCCESS_SENSE)) + return; + + /* if frozen, we can't do much */ + if (ata_port_is_frozen(ap)) { + ata_dev_warn(dev, + "successful sense data available but port frozen\n"); + goto out; + } + + /* + * If the link has sactive set, then we have outstanding NCQ commands + * and have to read the Successful NCQ Commands log to get the sense + * data. Otherwise, we are dealing with a non-NCQ command and use + * request sense ext command to retrieve the sense data. + */ + if (link->sactive) + ret = ata_eh_read_sense_success_ncq_log(link); + else + ret = ata_eh_read_sense_success_non_ncq(link); + if (ret) + goto out; + + ata_eh_done(link, dev, ATA_EH_GET_SUCCESS_SENSE); + return; + +out: + /* + * If we failed to get sense data for a successful command that ought to + * have sense data, we cannot simply return BLK_STS_OK to user space. + * This is because we can't know if the sense data that we couldn't get + * was actually "DATA CURRENTLY UNAVAILABLE". Reporting such a command + * as success to user space would result in a silent data corruption. + * Thus, add a bogus ABORTED_COMMAND sense data to such commands, such + * that SCSI will report these commands as BLK_STS_IOERR to user space. + */ + ata_qc_for_each_raw(ap, qc, tag) { + if (!(qc->flags & ATA_QCFLAG_EH) || + !(qc->flags & ATA_QCFLAG_EH_SUCCESS_CMD) || + qc->err_mask || + ata_dev_phys_link(qc->dev) != link) + continue; + + /* We managed to get sense for this success command, skip. */ + if (qc->flags & ATA_QCFLAG_SENSE_VALID) + continue; + + /* This success command did not have any sense data, skip. */ + if (!(qc->result_tf.status & ATA_SENSE)) + continue; + + /* This success command had sense data, but we failed to get. */ + ata_scsi_set_sense(dev, qc->scsicmd, true, ABORTED_COMMAND, + 0, 0); + qc->flags |= ATA_QCFLAG_SENSE_VALID; + } + ata_eh_done(link, dev, ATA_EH_GET_SUCCESS_SENSE); +} + /** * ata_eh_link_autopsy - analyze error and determine recovery action * @link: host link to perform autopsy on @@ -1950,6 +2046,14 @@ static void ata_eh_link_autopsy(struct ata_link *link) /* analyze NCQ failure */ ata_eh_analyze_ncq_error(link); + /* + * Check if this was a successful command that simply needs sense data. + * Since the sense data is not part of the completion, we need to fetch + * it using an additional command. Since this can't be done from irq + * context, the sense data for successful commands are fetched by EH. + */ + ata_eh_get_success_sense(link); + /* any real error trumps AC_ERR_OTHER */ if (ehc->i.err_mask & ~AC_ERR_OTHER) ehc->i.err_mask &= ~AC_ERR_OTHER; @@ -1959,6 +2063,7 @@ static void ata_eh_link_autopsy(struct ata_link *link) ata_qc_for_each_raw(ap, qc, tag) { if (!(qc->flags & ATA_QCFLAG_EH) || qc->flags & ATA_QCFLAG_RETRY || + qc->flags & ATA_QCFLAG_EH_SUCCESS_CMD || ata_dev_phys_link(qc->dev) != link) continue; @@ -3818,7 +3923,8 @@ void ata_eh_finish(struct ata_port *ap) else ata_eh_qc_complete(qc); } else { - if (qc->flags & ATA_QCFLAG_SENSE_VALID) { + if (qc->flags & ATA_QCFLAG_SENSE_VALID || + qc->flags & ATA_QCFLAG_EH_SUCCESS_CMD) { ata_eh_qc_complete(qc); } else { /* feed zero TF to sense generation */ diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index b12f8e9e1f86..1c85e9eee619 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -11,7 +11,9 @@ #include #include #include +#include #include +#include #include "libata.h" #include "libata-transport.h" @@ -1408,6 +1410,92 @@ static int ata_eh_read_log_10h(struct ata_device *dev, return 0; } +/** + * ata_eh_read_sense_success_ncq_log - Read the sense data for successful + * NCQ commands log + * @link: ATA link to get sense data for + * + * Read the sense data for successful NCQ commands log page to obtain + * sense data for all NCQ commands that completed successfully with + * the sense data available bit set. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int ata_eh_read_sense_success_ncq_log(struct ata_link *link) +{ + struct ata_device *dev = link->device; + struct ata_port *ap = dev->link->ap; + u8 *buf = ap->ncq_sense_buf; + struct ata_queued_cmd *qc; + unsigned int err_mask, tag; + u8 *sense, sk = 0, asc = 0, ascq = 0; + u64 sense_valid, val; + int ret = 0; + + err_mask = ata_read_log_page(dev, ATA_LOG_SENSE_NCQ, 0, buf, 2); + if (err_mask) { + ata_dev_err(dev, + "Failed to read Sense Data for Successful NCQ Commands log\n"); + return -EIO; + } + + /* Check the log header */ + val = get_unaligned_le64(&buf[0]); + if ((val & 0xffff) != 1 || ((val >> 16) & 0xff) != 0x0f) { + ata_dev_err(dev, + "Invalid Sense Data for Successful NCQ Commands log\n"); + return -EIO; + } + + sense_valid = (u64)buf[8] | ((u64)buf[9] << 8) | + ((u64)buf[10] << 16) | ((u64)buf[11] << 24); + + ata_qc_for_each_raw(ap, qc, tag) { + if (!(qc->flags & ATA_QCFLAG_EH) || + !(qc->flags & ATA_QCFLAG_EH_SUCCESS_CMD) || + qc->err_mask || + ata_dev_phys_link(qc->dev) != link) + continue; + + /* + * If the command does not have any sense data, clear ATA_SENSE. + * Keep ATA_QCFLAG_EH_SUCCESS_CMD so that command is finished. + */ + if (!(sense_valid & (1ULL << tag))) { + qc->result_tf.status &= ~ATA_SENSE; + continue; + } + + sense = &buf[32 + 24 * tag]; + sk = sense[0]; + asc = sense[1]; + ascq = sense[2]; + + if (!ata_scsi_sense_is_valid(sk, asc, ascq)) { + ret = -EIO; + continue; + } + + ata_scsi_set_sense(dev, qc->scsicmd, false, sk, asc, ascq); + qc->flags |= ATA_QCFLAG_SENSE_VALID; + + /* + * If we have sense data, call scsi_check_sense() in order to + * set the correct SCSI ML byte (if any). No point in checking + * the return value, since the command has already completed + * successfully. + */ + scsi_check_sense(qc->scsicmd); + } + + return ret; +} +EXPORT_SYMBOL_GPL(ata_eh_read_sense_success_ncq_log); + /** * ata_eh_analyze_ncq_error - analyze NCQ error * @link: ATA link to analyze NCQ error for @@ -1488,6 +1576,7 @@ void ata_eh_analyze_ncq_error(struct ata_link *link) ata_qc_for_each_raw(ap, qc, tag) { if (!(qc->flags & ATA_QCFLAG_EH) || + qc->flags & ATA_QCFLAG_EH_SUCCESS_CMD || ata_dev_phys_link(qc->dev) != link) continue; diff --git a/include/linux/ata.h b/include/linux/ata.h index a59b17d6ad11..2e2e22362096 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -326,6 +326,8 @@ enum { ATA_LOG_CDL = 0x18, ATA_LOG_CDL_SIZE = ATA_SECT_SIZE, ATA_LOG_IDENTIFY_DEVICE = 0x30, + ATA_LOG_SENSE_NCQ = 0x0F, + ATA_LOG_SENSE_NCQ_SIZE = ATA_SECT_SIZE * 2, ATA_LOG_CONCURRENT_POSITIONING_RANGES = 0x47, /* Identify device log pages: */ @@ -432,6 +434,7 @@ enum { SATA_DEVSLP = 0x09, /* Device Sleep */ SETFEATURE_SENSE_DATA = 0xC3, /* Sense Data Reporting feature */ + SETFEATURE_SENSE_DATA_SUCC_NCQ = 0xC4, /* Sense Data for successful NCQ commands */ /* feature values for SET_MAX */ ATA_SET_MAX_ADDR = 0x00, diff --git a/include/linux/libata.h b/include/linux/libata.h index ecdabe5647d1..b00bd6daacd0 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -212,6 +212,7 @@ enum { ATA_QCFLAG_EH = (1 << 16), /* cmd aborted and owned by EH */ ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */ ATA_QCFLAG_EH_SCHEDULED = (1 << 18), /* EH scheduled (obsolete) */ + ATA_QCFLAG_EH_SUCCESS_CMD = (1 << 19), /* EH should fetch sense for this successful cmd */ /* host set flags */ ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host only */ @@ -310,8 +311,10 @@ enum { ATA_EH_RESET = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, ATA_EH_ENABLE_LINK = (1 << 3), ATA_EH_PARK = (1 << 5), /* unload heads and stop I/O */ + ATA_EH_GET_SUCCESS_SENSE = (1 << 6), /* Get sense data for successful cmd */ - ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE | ATA_EH_PARK, + ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE | ATA_EH_PARK | + ATA_EH_GET_SUCCESS_SENSE, ATA_EH_ALL_ACTIONS = ATA_EH_REVALIDATE | ATA_EH_RESET | ATA_EH_ENABLE_LINK, @@ -864,6 +867,7 @@ struct ata_port { struct ata_acpi_gtm __acpi_init_gtm; /* use ata_acpi_init_gtm() */ #endif /* owned by EH */ + u8 *ncq_sense_buf; u8 sector_buf[ATA_SECT_SIZE] ____cacheline_aligned; }; @@ -1182,6 +1186,7 @@ extern int sata_link_hardreset(struct ata_link *link, bool *online, int (*check_ready)(struct ata_link *)); extern int sata_link_resume(struct ata_link *link, const unsigned long *params, unsigned long deadline); +extern int ata_eh_read_sense_success_ncq_log(struct ata_link *link); extern void ata_eh_analyze_ncq_error(struct ata_link *link); #else static inline const unsigned long * @@ -1219,6 +1224,10 @@ static inline int sata_link_resume(struct ata_link *link, { return -EOPNOTSUPP; } +static inline int ata_eh_read_sense_success_ncq_log(struct ata_link *link) +{ + return -EOPNOTSUPP; +} static inline void ata_eh_analyze_ncq_error(struct ata_link *link) { } #endif extern int sata_link_debounce(struct ata_link *link, From patchwork Thu Dec 8 10:59:41 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 632149 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 66C08C63705 for ; Thu, 8 Dec 2022 11:05:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229758AbiLHLEw (ORCPT ); Thu, 8 Dec 2022 06:04:52 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40430 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229941AbiLHLDa (ORCPT ); Thu, 8 Dec 2022 06:03:30 -0500 Received: from esa3.hgst.iphmx.com (esa3.hgst.iphmx.com [216.71.153.141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D63ED8932F; Thu, 8 Dec 2022 03:01:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1670497303; x=1702033303; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=NCnbh+fwg8DrIT+FYlYEQD8y0Pfiz4OuOe484jfsh6I=; b=WF7M/M0gZYeL85DrZtTqCfCS6zkX/+m1a+msuXiVf8QOClDHFkDREDPJ Rg1QZZy89VAuhlOntB7KooyI8ORtmKhEuz9G63FGEaKBxHFkFISUy18wW QqdwUPt3yl/yePjty68Ku9HuTgdscq94KZtFSmLt13ehMOj4I//jA9dUC FYarKEGn8QAr2+SPWRa3C+H1Dpk2i6fUcb+GEUQJnLWe5MsBzFN3D82xN xO7bFVIMqt+CjWbHZTCQGnAYzk/fLO/JTkVczAn5aJFxXYyoNOx7dltQB WREEfVF5a8He+ETJvrQkziWRXYrSeZ66k0twQmGg99KFA/HWxaBU3GvX7 g==; X-IronPort-AV: E=Sophos;i="5.96,227,1665417600"; d="scan'208";a="223333440" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 08 Dec 2022 19:01:43 +0800 IronPort-SDR: iL4Xm1jd1bTg2a5A72vHqi8XeBtI03RDF+a46ZQnPaY+pk4a3XhQCJtgiZA2OLTks5kafZXKKU 7vGglxgSzpWdr7aHaOREUygpX976NJwpPG5CnI7/1Hsa79dcwH3svQZ0D/JjxuJCoq0f3grRjk E5ZlQiXQgcs0IXQenoM8SEgr4RgUMRWSqI4Tz9JqxwnRi5VX/M8pAXfWruF9Y20CZl41rVL+sc vZCzFt7ICGEL6ZvT7SoOz3m7BLzcXK1iByoFtblD4XcstAnMZB83ZyIOfg7+571dqwYC+fZbX6 tEU= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 08 Dec 2022 02:14:28 -0800 IronPort-SDR: lH0I2LL8Td+V8zpKZDvQN2JXyuFfwFJ/WJwJHI4g3oCU4OlnnIcGij+ff7/scdguZZUCNa/fV3 oUsBUre7SroxLel2sEwxi1V83Jg+lIsxL4spr3yVrSdv0H1Zav9wKxN4Sj7goW2Uia4TE8d8vC sqcT0kHSamh1GII5KG6vz1/0ZHywU5/cpRqbSiVPJ4qpb1lhSq6plpfnDdWuweLeloSNKC4mQZ YqXRhfXkPvWAetm/yNR1oTJkSOopt0hL53YsbYGChTzrBaJGaNYg2tCMKqtr9r5o8oI61YS8n/ gkA= WDCIronportException: Internal Received: from dellx5.wdc.com (HELO x1-carbon.cphwdc) ([10.200.210.81]) by uls-op-cesaip01.wdc.com with ESMTP; 08 Dec 2022 03:01:43 -0800 From: Niklas Cassel To: linux-kernel@vger.kernel.org Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, Damien Le Moal Subject: [PATCH 25/25] Documentation: sysfs-block-device: document command duration limits Date: Thu, 8 Dec 2022 11:59:41 +0100 Message-Id: <20221208105947.2399894-26-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221208105947.2399894-1-niklas.cassel@wdc.com> References: <20221208105947.2399894-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org From: Damien Le Moal Document ABI/testing/sysfs-block-device the sysfs attributes present under /sys/block/*/device/duration_limits for ATA and SCSI devices supporting the command duration limits feature. Signed-off-by: Damien Le Moal --- Documentation/ABI/testing/sysfs-block-device | 143 +++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-block-device b/Documentation/ABI/testing/sysfs-block-device index 7ac7b19b2f72..44841f91c69b 100644 --- a/Documentation/ABI/testing/sysfs-block-device +++ b/Documentation/ABI/testing/sysfs-block-device @@ -95,3 +95,146 @@ Description: This file does not exist if the HBA driver does not implement support for the SATA NCQ priority feature, regardless of the device support for this feature. + + +What: /sys/block/*/device/duration_limits/enable +Date: Dec, 2022 +KernelVersion: v6.3 +Contact: linux-scsi@vger.kernel.org +Description: + (RW) For ATA and SCSI devices supporting the command duration + limits feature, write to the file to turn on or off the + feature. By default this feature is turned off. If the device + does not support the command duration limits feature, this + attribute does not exist (the directory + "/sys/block/*/device/duration_limits" does not exist). + Writing "1" to this file enables the use of command duration + limits for read and write commands in the kernel and turns on + the feature on the device. Writing "0" disables the feature. + + +What: /sys/block/*/device/duration_limits/read/[1-7]/* +Date: Dec, 2022 +KernelVersion: v6.3 +Contact: linux-scsi@vger.kernel.org +Description: + (RO) For ATA and SCSI devices supporting the command duration + limits feature, this shows the set of 7 command duration limits + descriptors for read commands currently set on the device. For + each of the 7 descritors, the following read-only attributes + are present: + + - duration_guideline: specifies the preferred length of time + in microseconds for the completion of a command. + + - duration_guideline_policy: specifies the policy action + taken if the duration_guideline attribute specifies a + non-zero command duration guideline that the device is + unable to achieve for a command. + + Possible values are: + + - 0x0: The device will complete the command at the + earliest possible time consistent with the + specified command duration guideline. + - 0x1: If the specified command duration guideline has + not been achieved and the command duration + guideline policy field is not the seventh command + duration limits descriptor, then the device + continues processing that command using the + command duration limits descriptor that has + the next higher number. + - 0x2: The device will continue processing the command + as with no command duration limits descriptor + being used. + - 0xD: The device will complete the command and an IO + failure will be reported to the user with the ETIME + error code. + - 0xF: Same as 0xD. + + - max_active_time: specifies an upper limit in microseconds + on the time that elapses from the time at which the device + initiates actions to access, transfer, or act upon the + specified data until the time the device returns status for + the command. + + - max_active_time_policy: specifies the policy action taken + if the time used to process a command exceeds a non-zero + time specified by the max_active_time attribute. + + Possible values are: + + - 0x0: The device will complete the command at the + earliest possible time (i.e, do nothing based on + the max limit not being met). + - 0xD: The device will complete the command and an IO + failure will be reported to the user with the ETIME + error code. + - 0xE: Same as 0xD. + - 0xF: Same as 0xD. + + - max_inactive_time: specifies an upper limit in microseconds + on the time that elapses from the time at which the device + receives the command until the time at which the device + initiates actions to access, transfer, or act upon the + specified data. + + - max_inactive_time_policy: specifies the policy action taken + if a non-zero max_inactive_time limit is not met. + + Possible values are: + + - 0x0: The device will complete the command at the + earliest possible time (i.e, do nothing based on + the time limit not being met). + - 0xD: The device will complete the command and an IO + failure will be reported to the user with the ETIME + error code. + - 0xF: Same as 0xD. + + +What: /sys/block/*/device/duration_limits/read/page +Date: Dec, 2022 +KernelVersion: v6.3 +Contact: linux-scsi@vger.kernel.org +Description: + (RO) For ATA and SCSI devices supporting the command duration + limits feature, this shows the name of the device VPD page + specifying the set of 7 command duration limits descriptors for + read commands. Possible values are "T2A" and "T2B". + + +What: /sys/block/*/device/duration_limits/write/[1-7]/* +Date: Dec, 2022 +KernelVersion: v6.3 +Contact: linux-scsi@vger.kernel.org +Description: + (RO) For ATA and SCSI devices supporting the command duration + limits feature, this shows the set of 7 command duration limits + descriptors for write commands currently set on the device. For + each of the 7 descritors, the same set of read-only attributes + as for read commands is present. + + +What: /sys/block/*/device/duration_limits/write/page +Date: Dec, 2022 +KernelVersion: v6.3 +Contact: linux-scsi@vger.kernel.org +Description: + (RO) For ATA and SCSI devices supporting the command duration + limits feature, this shows the name of the device VPD page + specifying the set of 7 command duration limits descriptors for + write commands. Possible values are "T2A" and "T2B". + + +What: /sys/block/*/device/duration_limits/perf_vs_duration_guideline +Date: Dec, 2022 +KernelVersion: v6.3 +Contact: linux-scsi@vger.kernel.org +Description: + (RO) For ATA and SCSI devices supporting the command duration + limits feature, this specifies the maximum percentage increase + in average command completion times (reduction in IOPS) that + is allowed for the device to perform actions based on the + contents of the duration guideline field in every command + duration limit descriptor for both read and write commands.