From patchwork Thu Jan 12 14:03:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 13098061 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 86A83C61DB3 for ; Thu, 12 Jan 2023 14:06:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231924AbjALOG5 (ORCPT ); Thu, 12 Jan 2023 09:06:57 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60654 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232964AbjALOFy (ORCPT ); Thu, 12 Jan 2023 09:05:54 -0500 Received: from esa1.hgst.iphmx.com (esa1.hgst.iphmx.com [68.232.141.245]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 39344551DC; Thu, 12 Jan 2023 06:04:22 -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=1673532262; x=1705068262; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=KhDiB7z5zRoUamoxOmDJuECgZy6X7QOah0MaQzKH+cg=; b=IDAqFdDeQsPRAE2GvmunsdoGGK2B/nJt9BrEBdIZORdQXR1iePjZwiHD EI+BzWajxoyVk2p5YxNJew0vzMMPfNKRgfDwvruSfnnOOVgGDlnIXeQCp 4AXryx0VPDjvzpOh7KKvFhTy5y7o5rgvGTNHzz13ZzsAg3IXCqycpsYlU dYspvZM2KeyGGByMtFraIBMqs6SASOysJLcKdml73h2qz+zGUVfgTgbuE JOlhq/30ErQLWlqZYfWpEiBBMOnR3UdHwT4hpcKeKlatlkkH/6HIH1BDG 7rCJwVliGTnVY1UDIAgw6D77ctHId2R5cQV/IuiGuIGTLLbQr+pXRgO38 A==; X-IronPort-AV: E=Sophos;i="5.97,211,1669046400"; d="scan'208";a="332632645" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 12 Jan 2023 22:04:21 +0800 IronPort-SDR: BzEngncKbA3/Ue0MoESLlW6p1XQdMP2mKxArCeuMgfiv3ToQsSaNf9F1TNp0XUqls3xtF2AwPh ghP58WlCCng4J9bNJ1dePiDl/lkJdtiyz99V0DHTojvU9K4i3pKJPxuhQiKMXp6s6x1A4/yGF/ jIj/4EUNI5aY2aTsmQYaAd4qFo/arMekEfMegXlO02B4ijxza2pNeqGsJTCRdWLPG+Hj27W0dN fCwz24/u1N9EXTmSs8sQn5ELOAGT3xj2HNtakvXyE0ARVVpYzeejerRJyHy18unxMMXXozH83L nYw= 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; 12 Jan 2023 05:16:24 -0800 IronPort-SDR: iIeJxRAXL2vPPAsQtvwWJGqKJV8Jd2braiQDeBorBQDYunnoIvrPG4AXrl1tk4A/newp8IYI40 JWBx/OsedPDMjxyjc1FOsKBF4ay6Qx8tv9dlq5HZ4puoMWHYU7V+P1s+CjjWydhgUuscszmY9m c6ojclBFLQrJffLLwEeTOptBjjU7tpfMEy+ljRHzSJ0b8Sgy32PeOCKRHHzEtDxeDXEg48lcmz YfKbFBxvVJDcCs2AT97z10wgBhrW0d6XwD8jARNtHgLiM4udDUP25z4hiQoKMcHU+CXBFxd6WF WZE= WDCIronportException: Internal Received: from unknown (HELO x1-carbon.wdc.com) ([10.225.164.12]) by uls-op-cesaip01.wdc.com with ESMTP; 12 Jan 2023 06:04:21 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org, linux-block@vger.kernel.org, Niklas Cassel Subject: [PATCH v2 01/18] ata: libata: allow ata_scsi_set_sense() to not set CHECK_CONDITION Date: Thu, 12 Jan 2023 15:03:50 +0100 Message-Id: <20230112140412.667308-2-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230112140412.667308-1-niklas.cassel@wdc.com> References: <20230112140412.667308-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@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 Reviewed-by: Hannes Reinecke --- 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 a6c901811802..3521f3f67f5a 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1432,7 +1432,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 aa338f10cef2..6d4ee296450e 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; @@ -2354,7 +2356,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; } @@ -3215,11 +3217,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; } @@ -3446,7 +3448,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; } @@ -3524,7 +3526,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; } @@ -3785,7 +3787,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: @@ -4141,7 +4143,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, @@ -4173,7 +4175,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 Jan 12 14:03:51 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 13098062 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 C150CC63797 for ; Thu, 12 Jan 2023 14:07:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230081AbjALOG7 (ORCPT ); Thu, 12 Jan 2023 09:06:59 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57826 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233591AbjALOF5 (ORCPT ); Thu, 12 Jan 2023 09:05:57 -0500 Received: from esa1.hgst.iphmx.com (esa1.hgst.iphmx.com [68.232.141.245]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7DF6555642; Thu, 12 Jan 2023 06:04: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=1673532264; x=1705068264; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=7+Ziz+mTsWX/A3ryVhHzi3SXwdqtLJ92byM5egPbRU4=; b=BvkujPgJYAlSKpBhPBLHQLxd6Sh3qmvYR5DlqXvPJ2VSPGgyQxZd5zib EoJFV2wblxsw1pUWbea+KTeoCyZQhMYUdEtXc2OdNzcbpjq4s9TGhKEL6 asORO1MbBqAgDoUOuI8sDFr+6GAgmwLsyd+2Co58AaIy83r/bFggnVd7y ODybvyWhlGT205zcDWrbZhLLBcnuQ3kpyZCBsPUK0iu8MYYBO5R6wDNHX cU9Mk0hAv6mZpfotZdpn5eXCRk6L0aYZkqZvmrN/nbOMMK0UCIIDVYi1E rm2xhtV+l3NmXRUiz8980hUNDhZlRscnpDBnDItTDpFl6tNQjiksm2dni A==; X-IronPort-AV: E=Sophos;i="5.97,211,1669046400"; d="scan'208";a="332632651" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 12 Jan 2023 22:04:24 +0800 IronPort-SDR: +vB6C2ygxnShTcPinnd3lKQw4Aun6LpusgzxXt+cIY8gcfmScJBLa+8AO9HuthUhB+cEdjXlBY 9e6bww5beASj4Kwo/SGo8KlMLne5lp1oawd1+xpquVZ9T+vW8UGaHJY0RYwwPjBWq2WOHBn2L3 Sp1bdMxHnXl4GfCHyU76s4zqcDLX7ix1YNqkLZ0v2iO8lJFW3Q0Xgvvmd6r7suwoju5ER88aSi uSB7+8k1+H44KNOyC+pcyQDYb1r+gxDlR+smAmAYsPvXxzZa0EFh0d4zMbOmfhjWLRcVAWjLR+ kKE= 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; 12 Jan 2023 05:16:27 -0800 IronPort-SDR: AGyUwv9qHhJI5gkBnROEGO3Hmn5U39CGteeD4NpXgaaneQHphvi6CCV7fjYtv9QI5dCxGmfz/v 5ZZ9bHwShW5fDfUiYc1fytYSAKP1KebsQN5ShPbuUNGv1SqV5Rj84PyfbDmQzUPyKRRVyt5pik G8nWw540Nft3NEamPC0/2JbwWKaVDIyHkm7vsfFU2uVT9cVoAbRo/IsZUTHDahUGNpNhHmfHMj cDdht9f934BDn75j1pi57SV/mvbqRJAKmvdYVDCwX+iyimYnuWNkjHZ8CMG5Jr0lqaAVhisdqs osA= WDCIronportException: Internal Received: from unknown (HELO x1-carbon.wdc.com) ([10.225.164.12]) by uls-op-cesaip01.wdc.com with ESMTP; 12 Jan 2023 06:04:23 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org, linux-block@vger.kernel.org, Niklas Cassel Subject: [PATCH v2 02/18] ata: libata: allow ata_eh_request_sense() to not set CHECK_CONDITION Date: Thu, 12 Jan 2023 15:03:51 +0100 Message-Id: <20230112140412.667308-3-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230112140412.667308-1-niklas.cassel@wdc.com> References: <20230112140412.667308-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@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 Reviewed-by: Hannes Reinecke --- 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 3521f3f67f5a..1c3d55fc1cae 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1395,6 +1395,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. @@ -1402,7 +1403,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; @@ -1432,8 +1434,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 { @@ -1590,7 +1592,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 Jan 12 14:03:52 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 13098063 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 49C57C54EBD for ; Thu, 12 Jan 2023 14:07:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232907AbjALOHh (ORCPT ); Thu, 12 Jan 2023 09:07:37 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58404 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229721AbjALOGF (ORCPT ); Thu, 12 Jan 2023 09:06:05 -0500 Received: from esa1.hgst.iphmx.com (esa1.hgst.iphmx.com [68.232.141.245]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9FC5355661; Thu, 12 Jan 2023 06:04:27 -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=1673532267; x=1705068267; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=F9K8UlbUQaCt9yu3CDBLk5hS36H2slNxvfvKG0Z1kr0=; b=UiqKKlUCetzuCRKx2SlxdgHpMzDRbImu2WAfJDheMFs1UFCUygKYsdwk EVEguK4Pd9qYjcBi259qAjXVvaIql4Hzzrgtu/8HGiAdjAUWLtWN17I8K 4l9njEO5XTj+OGZnGc2XAgT9RlIz2SlYHGtAGn/kxG3LL4r41DsGmhg+j aTXqNPnE8qRmczHCq0NZYhngOC9QF14CgZLvgb/66miLAPeh6KAaG4sdM MFEwlkkgnT0j4imtcbrkHVxLZjFfFgrjBLI+zTa8dGk4MYkmtN9fjKUFU /0/+6GMVGIlBfMUzn0SBupiAQ8IsbvBlN9zmYy3ieynBIdb7CJhfZkcJO A==; X-IronPort-AV: E=Sophos;i="5.97,211,1669046400"; d="scan'208";a="332632659" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 12 Jan 2023 22:04:26 +0800 IronPort-SDR: NR/5hGAVbOAhC5RoJpFVB1Qsx0bBSzO2FfsJtCwOl+MP5n0d4+v8KStp0WAvteNVvudf+AcBnh blJvh4x5HNOZmCc1Y4XZMYCq2PUhTxI/rcjHqpjBIWdjq/9rTe6XkXUnDaGXXxUy4QZWLzqh8k xrmWWgEM59wEuz9v0EjLoltIS/Zf3Ljq43O5+h7IHs8Y0wq+b3pDvL1VKo7S5G14dszw/lnhVY eyS6a4Dl6ZpnyDXr6mBX94GZc95PEVw9ZocaisXle5UcRgDesHIdToxQoZxXYjB4a/dDlkJm57 Ou8= 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; 12 Jan 2023 05:16:30 -0800 IronPort-SDR: KtQEdFnIlYaQykIdtAujuvNHlsrHCDk1nMRU1ckKiCfM3LtrgG4ZMreHHHTMddkwHJmOToIjcl XQspkQVKU5XBXOxkK80/YsK4XISKZrqYmZ9qnBSopwIE+bfSi0o1nPnFZcjIHLLlRy+MOhP+9Z w0k1TVGsgDAwTCbU28blpF0rcms0CfpGkNZ2zZCw+DkaTT84Oc8lPWPO5xXZy/gbpl2a+hVGOA hiuio/dERNGak/G/s6k3SrE8HlZgBAxcH6p9pAroG88nqif8PCIpbYxNB/v0yj7SvgL7DasiQT a+A= WDCIronportException: Internal Received: from unknown (HELO x1-carbon.wdc.com) ([10.225.164.12]) by uls-op-cesaip01.wdc.com with ESMTP; 12 Jan 2023 06:04:25 -0800 From: Niklas Cassel To: "James E.J. Bottomley" , "Martin K. Petersen" Cc: Hannes Reinecke , Damien Le Moal , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org, linux-block@vger.kernel.org, Niklas Cassel Subject: [PATCH v2 03/18] scsi: core: allow libata to complete successful commands via EH Date: Thu, 12 Jan 2023 15:03:52 +0100 Message-Id: <20230112140412.667308-4-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230112140412.667308-1-niklas.cassel@wdc.com> References: <20230112140412.667308-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@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 Reviewed-by: Hannes Reinecke --- 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 Jan 12 14:03:53 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 13098064 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 446CDC54EBC for ; Thu, 12 Jan 2023 14:07:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231382AbjALOH6 (ORCPT ); Thu, 12 Jan 2023 09:07:58 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60564 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234214AbjALOGi (ORCPT ); Thu, 12 Jan 2023 09:06:38 -0500 Received: from esa1.hgst.iphmx.com (esa1.hgst.iphmx.com [68.232.141.245]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 54A0555870; Thu, 12 Jan 2023 06:04: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=1673532270; x=1705068270; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=vXjbAsivCptBqGfobKyamSaEPiil8gDg9M1lnUQl7dI=; b=I0ipD01fEJURSUHs0qqCMZ2FqmBePM4OE43ZM0va7OSBMG/iTEvfEBzn UYiIUrcJT/VXxJhZFoHQCRQd2vrKU08kcP8vvVGV8zLuQ7ndVg4k4msX3 ZSksnV4Du2LJD1JF1rAdZKoNrBmiLQmqDctTPwNGSkb3BDV7J36TuNNIL pU3Y9oZ9LkzxffYvgc8aQ8AcxbwNAi1LopmrFliOqV4j1ytOhOFIBzkkr o0GmgCz7i8JYIzsUjoi1UGzzhRKD5bd6kL8gojauoI+3VmpFIRTPgXTcD g2LWvmSWrZK09DhQZi2cq7LwKvAUOYgTbQO8slHN77xrBme+HIbCWCUs5 A==; X-IronPort-AV: E=Sophos;i="5.97,211,1669046400"; d="scan'208";a="332632668" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 12 Jan 2023 22:04:29 +0800 IronPort-SDR: l8A+raCaDnl2JvBM7tUf+O+pZByX7lCpwWRGhblBLLXigseMYyag1oXX3g0N2EhYLFQK+HfgJx E+Ec0sc+oYWLIwx23TY4em+u/VduftqFuOwbPWL54kIs28LA9W9bh35389LNYfR47hMyj2J1s4 T2OPaiGZE4FmKja0LrwEbVggc8WtuRCqRRynI+LnHvdnKg99Ig10DMbY4wV/xkbWGVqM5ytGB1 x7NGyF29QE8K8edotvjZBHhcRZ+nW31h9mt/294TSTECaa9dHQIl/J3RGXTDTUfmj4i16Yw5rh SfM= 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; 12 Jan 2023 05:16:32 -0800 IronPort-SDR: AF9gdHCDV2EoJHxs9oYkf+GCiA3c7YvN0bBJjrGSm0wb6s6IFrVyBIYth8mKBngJ7eP+4RecYU vIzTPJC1ooOoS6kcFO9yO6ZM+ZskRUJwvgLNE6Rou2JMmnuYfY8RxcqRmJC8pvfoukH57HazMu wiSg7lkXdbokZvoSoxr3VOiqZSc3s/bfTTaJ5P7D8NBXmaCEaw8cHfJq4cvwqnC9FjKRrHAsFD FaWFp3YoT4PpBQmhX2rY3hiE32USZzyb6mU5IFZMUI4En0VpipZZNY4zmthKImkeSN5vSStwJQ byM= WDCIronportException: Internal Received: from unknown (HELO x1-carbon.wdc.com) ([10.225.164.12]) by uls-op-cesaip01.wdc.com with ESMTP; 12 Jan 2023 06:04:28 -0800 From: Niklas Cassel To: "James E.J. Bottomley" , "Martin K. Petersen" Cc: Hannes Reinecke , Damien Le Moal , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org, linux-block@vger.kernel.org, Niklas Cassel Subject: [PATCH v2 04/18] scsi: rename and move get_scsi_ml_byte() Date: Thu, 12 Jan 2023 15:03:53 +0100 Message-Id: <20230112140412.667308-5-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230112140412.667308-1-niklas.cassel@wdc.com> References: <20230112140412.667308-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org SCSI has two different getters: - get_XXX_byte() (in scsi_cmnd.h) which takes a struct scsi_cmnd *, and - XXX_byte() (in scsi.h) which takes a scmd->result. The proper name for get_scsi_ml_byte() should thus be without the get_ prefix, as it takes a scmd->result. Rename the function to rectify this. Additionally, 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 Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig --- drivers/scsi/scsi_lib.c | 7 +------ drivers/scsi/scsi_priv.h | 5 +++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 9ed1ebcb7443..6630a36b873e 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 @@ -596,7 +591,7 @@ static blk_status_t scsi_result_to_blk_status(int result) * Check the scsi-ml byte first in case we converted a host or status * byte. */ - switch (get_scsi_ml_byte(result)) { + switch (scsi_ml_byte(result)) { case SCSIML_STAT_OK: break; case SCSIML_STAT_RESV_CONFLICT: diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 96284a0e13fe..74324fba4281 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 scsi_ml_byte(int result) +{ + return (result >> 8) & 0xff; +} + /* * Scsi Error Handler Flags */ From patchwork Thu Jan 12 14:03:54 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 13098065 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 B6CDCC54EBD for ; Thu, 12 Jan 2023 14:08:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234571AbjALOIM (ORCPT ); Thu, 12 Jan 2023 09:08:12 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60596 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234969AbjALOGm (ORCPT ); Thu, 12 Jan 2023 09:06:42 -0500 Received: from esa1.hgst.iphmx.com (esa1.hgst.iphmx.com [68.232.141.245]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4AC19559C2; Thu, 12 Jan 2023 06:04: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=1673532274; x=1705068274; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=QNXbTQtYuwTypo6ZVaz9AMEzjAItPRnZYKMlV+efXS4=; b=fbB/mJgNk+yNprM2DQesSrffUskfX5z7ptxtNQHNDxPfs7kzwA9JEAxK DljgNKEaJHRJGBLnD4JVTlhktkFUIsmeLKiTqdBnfmh4fRLZlPiItHuCB FxnaKJxBFVzS95w0fp0SRdBCwLBwNAUwfDaIY2R86s01QRpdjclVuN0ld H73OOZb9kkiM+7Wo2WfXqQNNuLchkYfl8DmnmSMmZN+BzTmLRBXSvOIXI O3+nbzpvUgRoxrufbpMIe0AR5AGpxNUlKaN8KXS2d/qabHXTt32yAWIp4 TuCUPUKOeF5BhGsBvWJiuxj/W6MdR7TIO3mDazYWIj9AKiB2nYufXCKdk A==; X-IronPort-AV: E=Sophos;i="5.97,211,1669046400"; d="scan'208";a="332632678" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 12 Jan 2023 22:04:33 +0800 IronPort-SDR: iOqDsIJ+tKWBqIol5n3iI9mPAmuEeF40/fyyLIKTeKBfYa/kj26zbnmgUwEyepMMNiq3UDgsXj vYG5QdBw+ztgTdQgAF4/NB3bY3CanNM8nkZMiSsAqqF/ky2gp6xuiwoTeLfVxdETtC2UUslHhB jEPqC61yQCfmKZgsJGtxI67AShhfVGJY2ANQWiUG3n6fkwQ2UFx38P5SYzGTEIB4rzaI6hsutK njwHxnC/cZh9IKrrW3uJehZIlHgaxOfnxxYqJZ6q5E4q8KY7TJlBwdsrpth88BrlEdVXFoxPMO fSo= 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; 12 Jan 2023 05:16:36 -0800 IronPort-SDR: OGMRGmlaNGcpfAB8WqD99uf0554Os8AK/xatQH8t8tF5MwoYqdVz4ONfqpGkuLOhMYo0UfiGGv QkDFf13zDyN3gehxzjNSjcnTbQB6pQsV9ly/FZb7qP1BjDkZXq74FI0As2AzHTwBjGJ53RQ46u ldSlmPEboF43TtBTmwKRMGmEx/2YYlohHL9KTicijn0T2F2JXpSmjxyqoWSSz/Esm65goakPk+ s2cGGH6VhNc5yUa+3YQWufq8J4pDsvaWptyjkzIVR+R9NlDCrxg6QbTkH9Wcb0l1DZIUMaMcqq M44= WDCIronportException: Internal Received: from unknown (HELO x1-carbon.wdc.com) ([10.225.164.12]) by uls-op-cesaip01.wdc.com with ESMTP; 12 Jan 2023 06:04:31 -0800 From: Niklas Cassel To: "James E.J. Bottomley" , "Martin K. Petersen" Cc: Hannes Reinecke , Damien Le Moal , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org, linux-block@vger.kernel.org, Niklas Cassel Subject: [PATCH v2 05/18] scsi: support retrieving sub-pages of mode pages Date: Thu, 12 Jan 2023 15:03:54 +0100 Message-Id: <20230112140412.667308-6-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230112140412.667308-1-niklas.cassel@wdc.com> References: <20230112140412.667308-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@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 Signed-off-by: Niklas Cassel Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig --- 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 6630a36b873e..79cece5eff5d 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 Jan 12 14:03:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 13098066 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 7015DC54EBD for ; Thu, 12 Jan 2023 14:08:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232029AbjALOIk (ORCPT ); Thu, 12 Jan 2023 09:08:40 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58278 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234628AbjALOHY (ORCPT ); Thu, 12 Jan 2023 09:07:24 -0500 Received: from esa1.hgst.iphmx.com (esa1.hgst.iphmx.com [68.232.141.245]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B8951564CC; Thu, 12 Jan 2023 06:04: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=1673532277; x=1705068277; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=bvXG9ZKQSiEllpoR85N9tuwg0/TWaplIVvgDn0WwKUw=; b=hDXMjxyqZNPCoMQBfAFLM2J/DkNenT5+o0S2z6GtEZEXqs5/RMUe0bdI BIxUt7Yr7woKAN/1zt8ecThPnwzBIqseWEI657Jon9CYLIJZu7RBMma45 Peus6Go7/XEJ2NyN2dMwXArj3kozwpOQ6LLB8CVphPNniewsS4YciD1qM BPfdb40JUTRFjCHLJszVW2Db3UEmwQTTMxYbGjpoNpbagk7mA3cYUSJFZ wNL8uSufyRqsynmPOIKc+N7xS7zc77Y36kke5ogRG8wQiaGb0K3gIycgd Y/bwupGnYSdmOMlN60M3JFzZ/sZJIVjAVaspqvWmH01wMRwYeEAhS6+EH g==; X-IronPort-AV: E=Sophos;i="5.97,211,1669046400"; d="scan'208";a="332632684" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 12 Jan 2023 22:04:36 +0800 IronPort-SDR: FhahIpHVmXJCHTuxxiau7Wr4elj/+KkHSABRc3NFzi+xwHYBAJa2fiE2bfDDYV1Ca1ep42F1ab o0YxOmXYXjjt8qExqgNAQBGNKks2SaOTFWlWl4kpTbPDmD39o//U7POGoFJLY6vcM44uWW232v mcg4/MFZNygEj2uDcMx3lASPZFuYPzlfZUzLz1OB6q9YkpvXkRu9/x4jUhKHWGz/wC/PSfgOT7 879ZusDOOy28Ig2zYy0O2TrQpxU14RTc2z5LS6fx+ZfFLVoNOHwE7KDtdMau8o/ttpFIHBTZYC ylU= 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; 12 Jan 2023 05:16:39 -0800 IronPort-SDR: UxXrHYWS+zbqmTFMagVZURc4C+sG4jfhhshLX9vukxS5TuhYJKJ0Mv8FMbua31E2YJX0/45gmr cpzxXcSWGiVXzkMG1V4Yw4SgGl5LXLAUDUdiFPMbhz9P7E4k/0xtQ9dUD6BAbRbyPc8WSn0Rrn pTgY91zmOThoSxBEMgrDh56DHmwoMPZIgAu22z0QHncZKRNM0PdsrBoI4fFh7hC/JcnV+ZI8JX YRnluDL65csgn9Mhn1nOrbqs0qd43hxFnHeSBRYzyNUftM1928nCxacOASDLwV7IOPhqIwK7Qx NmU= WDCIronportException: Internal Received: from unknown (HELO x1-carbon.wdc.com) ([10.225.164.12]) by uls-op-cesaip01.wdc.com with ESMTP; 12 Jan 2023 06:04:35 -0800 From: Niklas Cassel To: "James E.J. Bottomley" , "Martin K. Petersen" Cc: Hannes Reinecke , Damien Le Moal , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org, linux-block@vger.kernel.org, Niklas Cassel Subject: [PATCH v2 06/18] scsi: support service action in scsi_report_opcode() Date: Thu, 12 Jan 2023 15:03:55 +0100 Message-Id: <20230112140412.667308-7-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230112140412.667308-1-niklas.cassel@wdc.com> References: <20230112140412.667308-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@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 Signed-off-by: Niklas Cassel Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig --- 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 Jan 12 14:03:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 13098067 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 26320C67871 for ; Thu, 12 Jan 2023 14:08:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232050AbjALOIl (ORCPT ); Thu, 12 Jan 2023 09:08:41 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58106 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235089AbjALOHl (ORCPT ); Thu, 12 Jan 2023 09:07:41 -0500 Received: from esa1.hgst.iphmx.com (esa1.hgst.iphmx.com [68.232.141.245]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D5BDA559E9; Thu, 12 Jan 2023 06:04:42 -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=1673532282; x=1705068282; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=TvFJrrRGb6/CjlxRBQb19gVXCyf7apsABVJeIRcea14=; b=QCL4K3+IEk8d9T6apG+sNBd0ZRS3lSFWETfjCemzCh4fR1cLaDUxXmv7 Dcaz54U4Vtd7jAWZR0xIgQsKifIt2CULW6UY7FaDCBC65SGzn7BJth6/g HDUr4CtITBLHIevpKtmsoleYvT6g3sYdUDLiaVrx8+rxIj4vV7fItHqXk 5NHst50ymeyAorHXdXulpkn0/K/uvOGczJoFYMnGawR8ZXxj6bmyJQTfq Wn5kGAY+1jwH+G4ivUfg+22HnbbBCCIuqYqOSiPYTGoYhWP2AKinB7RIh Lymfg8oAezBounlG/31ZdQ0dqIJi4UT3aHwqjeyMIjP4APS204L0IOnbp g==; X-IronPort-AV: E=Sophos;i="5.97,211,1669046400"; d="scan'208";a="332632695" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 12 Jan 2023 22:04:39 +0800 IronPort-SDR: IlvPRu+er7jnBBaD2b32m3880nC2mV8lryCCbn8P9P9/Rx3bpYU76Z/6uqGuRmob/pHYRG/DUY XeJdPkzhzFGV2rjHxqW79Hzi9Uf30VLHD+Q/wxG5xq9PX9mUFK+OXN4ucQapLlyjbhV+vOGpDv v6u3g/AZKBxIHdZBxh22eL1X+U2Q8zd3BPiXVYjm7MowySXZ2MUWYtaMkkiFLgtwz8mlIZ7HTo dv4C6yN7ajUs/wilVwyLQJdgL+1C/s5uKJBp63ytlBiuXBImFFKdpTtxzeQWUHD+axYY1tFTei p0A= 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; 12 Jan 2023 05:16:42 -0800 IronPort-SDR: 2mvmYa0yJHI6Njz/eHZob4gcI7ntL+n5eqtA8TlWFCJRzaTgM6VlxTNT7MJ1A/eKbK5YBGtVg6 RrM1QS5sL6N1dhKkQDeDHHKCEjFsjKTAuYMTpt0gqK0P9ZyYtqYbc14T0ixx2vka09z5D4dy+N ApUX+WrTb9JBZsQ8z4vO5QVqXX0AEQkhMYdamsZmMvcNdNCjBDQ6WyPNbiI68nraY6ZUij/3k2 ayn6pA7sdMqiPNS6KA/v8F4c6glVjDsENkn5XnZp5IkuUXV4YGBo99XgiQquOJo86vHZ/wRh2n ErE= WDCIronportException: Internal Received: from unknown (HELO x1-carbon.wdc.com) ([10.225.164.12]) by uls-op-cesaip01.wdc.com with ESMTP; 12 Jan 2023 06:04:38 -0800 From: Niklas Cassel To: Paolo Valente , Jens Axboe Cc: Hannes Reinecke , Damien Le Moal , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org, linux-block@vger.kernel.org, Niklas Cassel Subject: [PATCH v2 07/18] block: introduce duration-limits priority class Date: Thu, 12 Jan 2023 15:03:56 +0100 Message-Id: <20230112140412.667308-8-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230112140412.667308-1-niklas.cassel@wdc.com> References: <20230112140412.667308-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@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 Signed-off-by: Niklas Cassel --- 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 815b884d6c5a..7add9346c585 100644 --- a/block/bfq-iosched.c +++ b/block/bfq-iosched.c @@ -5545,6 +5545,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) { @@ -5673,6 +5681,8 @@ static struct bfq_queue **bfq_async_queue_prio(struct bfq_data *bfqd, return &bfqg->async_bfqq[1][ioprio][act_idx]; case IOPRIO_CLASS_IDLE: return &bfqg->async_idle_bfqq[act_idx]; + case IOPRIO_CLASS_DL: + return &bfqg->async_bfqq[0][0][act_idx]; 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 Jan 12 14:03:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 13098068 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 CA88BC678D6 for ; Thu, 12 Jan 2023 14:08:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233728AbjALOIn (ORCPT ); Thu, 12 Jan 2023 09:08:43 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60578 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234214AbjALOIK (ORCPT ); Thu, 12 Jan 2023 09:08:10 -0500 Received: from esa1.hgst.iphmx.com (esa1.hgst.iphmx.com [68.232.141.245]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8E9D2574C9; Thu, 12 Jan 2023 06:04: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=1673532285; x=1705068285; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=jYaFDhh8prQmCrmVXggIFHs2nnp6urNckK64rTfhyRc=; b=mfVqK6lmLHn/2M8/AszwyPdglTW38OXtpl1UvOgYBQ0PoJ1mwMLxLnrc YQW++gdP744qGe2LPFAa1RfaverU+PcI7vVWUGNDnRDlgW2iEZymgj4hF 0rb+8rdcP97Ev05O3j10bR/MMySecbNT7Kb1csTfjkFVdUDgTU2gSr5Qh q30LyBOnfuOvEjtuxEui/x1tlwR5exPkldlBk/UhaSz16B8pJzqZaigYu w/1bOY1lPEBMNOdxqVpJ1UrJWjYrxIvVos8CLYBAf0XsGTHEOPFNqEIv8 K0GqD0datyvz90CGFPDAHXjEQKSo+Pf/7CYnFIYl4UbWCCRRk2HZnUSEM A==; X-IronPort-AV: E=Sophos;i="5.97,211,1669046400"; d="scan'208";a="332632701" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 12 Jan 2023 22:04:42 +0800 IronPort-SDR: bqkMKgMXYctnGlNdWc/uu75GW30Yr5+wvazsAOnQoEkUDywWE5Vwh4ZLtNqoKsb9ZEg5eH/xzt AiVVCNUJcYRiV2bejKc78ZIxy+qUgmdYryietEr/TKh4lKCDvG3NgIMgQeFZNTTmItv872n7Dn DI/SJslnLS2wamYFDUJWhcRky4W2a50RSKKpOgO5j7MTxgXSbiSLD3XaBv8mvsJNkEH2cpKOpM 2a1lCgNI8bB7OaE1pgLl0bd/7LzW6Q3ZL7bkL4Hzovw2kwB80bhDUe5PIi2v7oVIAg+Y3fW1ZG U1M= 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; 12 Jan 2023 05:16:45 -0800 IronPort-SDR: ZqBHdFHrjKoZiTEqVO2HFKZEpYZuinkz+jg66JqGY4RfH02vO+/7/i/tkUczplo1CWpgBHUeCh MIvyQ49vxMEjSVQiIvrHIj5QhMs4qL/eB4myEFZQD4EvmgCXMnN15OgFqWzyGe87Z5l88dB3Ab vFb+AY4bA4ah58yed8NmcS2wyDE0ARCkCCHt47F2VXkNE6PNM7afv84TBk9Bco3Rl+mb/j0U2L oK4HR4Poeyq3TSUY0sj8rVBpu+93pUUqvWVUozqQIYc+1XXnEjZ6De5n29CHEZI1x4hWQ+yXmH oMo= WDCIronportException: Internal Received: from unknown (HELO x1-carbon.wdc.com) ([10.225.164.12]) by uls-op-cesaip01.wdc.com with ESMTP; 12 Jan 2023 06:04:41 -0800 From: Niklas Cassel To: Jens Axboe Cc: Hannes Reinecke , Damien Le Moal , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org, linux-block@vger.kernel.org, Niklas Cassel Subject: [PATCH v2 08/18] block: introduce BLK_STS_DURATION_LIMIT Date: Thu, 12 Jan 2023 15:03:57 +0100 Message-Id: <20230112140412.667308-9-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230112140412.667308-1-niklas.cassel@wdc.com> References: <20230112140412.667308-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@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. Signed-off-by: Damien Le Moal Co-developed-by: Niklas Cassel Signed-off-by: Niklas Cassel Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig --- 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 b5098355d8b2..67b0b24aa171 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 99be590f952f..cde997590765 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 Jan 12 14:03:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 13098069 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 596E1C54EBC for ; Thu, 12 Jan 2023 14:08:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229779AbjALOIs (ORCPT ); Thu, 12 Jan 2023 09:08:48 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35544 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231465AbjALOIQ (ORCPT ); Thu, 12 Jan 2023 09:08:16 -0500 Received: from esa1.hgst.iphmx.com (esa1.hgst.iphmx.com [68.232.141.245]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 77A9F2618; Thu, 12 Jan 2023 06:04:49 -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=1673532289; x=1705068289; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=+U3NQ21Wje+POXdlQhtP/jWLO/Mjz9z16b/YMISBe5E=; b=O6oHsyHCGhG+rMxWdtpwObSEBjaSjQxzQG4q1SHjAoHxUeevDNbeP7Cz tBC+6XnJ7DWi96JveQaL1DHHPJ6VIlLtPj3fIKAeZJV3XcbHhnxCj+rjK tr/txAccnFn0FdJWMkb/pKHDmQAnswZa7ZRRo0AGYbACUIk51pT7DQ8dS yid9Bhk5BBbtSoTmOVgzRIEtQ3nK88eFJ6eQXqJ7dm5NnJI2eujWGXzQI lVFArhENiMxTTqj4wcWAutcvyoGltrnzuTFPO29Bw6WsbDNVzfjp/6zD+ nN4QcZXlcdmtSyVx+0QMRXVWwJ0R/lLO5zyrf0izz15MNkuwqboxdk2qa g==; X-IronPort-AV: E=Sophos;i="5.97,211,1669046400"; d="scan'208";a="332632706" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 12 Jan 2023 22:04:45 +0800 IronPort-SDR: 2ZyiSXPuq0CsIr/JoXHPvFq61y6P2szTjaBnJvVkYzxQYCThUzg5qT9jCE3UdiNrtY2e6nCLNr QBnKhIyz6xU2MG9mLJ/1gD2/i+N/0U1SqLOPxL6o3rfq5dCUO0AvEFD/wO6OnUZfx2K1EiMZQw k+2oLHEpqOivhWNokKvXCLJWk5za3q0QaF68VtF7oEnAwx29olINjK4cVUqSG85qpoK66ZfkyJ 1NUaS4lcC6RuP5iHjzJlqSVIODmzvs6wkiRsxz3Uljl5d+4sQ7BfPiAGudQuoR5H8SAHdlfMNK Pq4= 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; 12 Jan 2023 05:16:48 -0800 IronPort-SDR: i8UEcD9aT7utC6B4xug7WhS0g248lmyTYShwdVEe/6ov2V3OvSRThz0kpPluOxTOVPcc+41Mta ejmSWt27hu82RRQrxwW4iA+m0OIIIbKouMBjVE01FE4bqN7VgjzxetbVlVsaHxDmS4QbVo5dmi VXmmPV3pMBzU3EmSJsihSPS75almgWYSqV1SvrpJwewwqwMI4jVUOLgOyAr6RjoKmZbcbp6TiY NsryAmEM/xlOJPHyNxUTG8602xfrwzsaTY+wwLtKW0PyYghqMzyw+a8mmNZU9DFjfParfs4NGt nnM= WDCIronportException: Internal Received: from unknown (HELO x1-carbon.wdc.com) ([10.225.164.12]) by uls-op-cesaip01.wdc.com with ESMTP; 12 Jan 2023 06:04:44 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org, linux-block@vger.kernel.org, Niklas Cassel Subject: [PATCH v2 09/18] ata: libata: detect support for command duration limits Date: Thu, 12 Jan 2023 15:03:58 +0100 Message-Id: <20230112140412.667308-10-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230112140412.667308-1-niklas.cassel@wdc.com> References: <20230112140412.667308-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@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. Signed-off-by: Damien Le Moal Co-developed-by: Niklas Cassel Signed-off-by: Niklas Cassel Reviewed-by: Hannes Reinecke --- drivers/ata/libata-core.c | 52 ++++++++++++++++++++++++++++++++++++++- drivers/ata/libata-scsi.c | 17 ++++++------- include/linux/ata.h | 5 +++- include/linux/libata.h | 29 +++++++++++++--------- 4 files changed, 80 insertions(+), 23 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 36c1aca310e9..17e32b0a6364 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2367,6 +2367,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; @@ -2534,13 +2582,14 @@ static void ata_dev_print_features(struct ata_device *dev) return; ata_dev_info(dev, - "Features:%s%s%s%s%s%s%s\n", + "Features:%s%s%s%s%s%s%s%s\n", dev->flags & ATA_DFLAG_FUA ? " FUA" : "", 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" : ""); } @@ -2702,6 +2751,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 6d4ee296450e..c64bd3095ea6 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 a759dfbdcc91..2b17d6c99a37 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -94,17 +94,18 @@ enum { 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 */ - ATA_DFLAG_CFG_MASK = (1 << 13) - 1, - - 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_INIT_MASK = (1 << 19) - 1, - - ATA_DFLAG_NCQ_PRIO_ENABLED = (1 << 19), /* Priority cmds sent to dev */ + ATA_DFLAG_CDL = (1 << 13), /* supports cmd duration limits */ + ATA_DFLAG_CFG_MASK = (1 << 14) - 1, + + ATA_DFLAG_PIO = (1 << 14), /* device limited to PIO mode */ + ATA_DFLAG_NCQ_OFF = (1 << 15), /* device limited to non-NCQ mode */ + ATA_DFLAG_SLEEPING = (1 << 16), /* device is sleeping */ + ATA_DFLAG_DUBIOUS_XFER = (1 << 17), /* data transfer not verified */ + ATA_DFLAG_NO_UNLOAD = (1 << 18), /* device doesn't support unload */ + ATA_DFLAG_UNLOCK_HPA = (1 << 19), /* unlock HPA */ + ATA_DFLAG_INIT_MASK = (1 << 20) - 1, + + ATA_DFLAG_NCQ_PRIO_ENABLED = (1 << 20), /* Priority cmds sent to dev */ ATA_DFLAG_DETACH = (1 << 24), ATA_DFLAG_DETACHED = (1 << 25), ATA_DFLAG_DA = (1 << 26), /* device supports Device Attention */ @@ -115,7 +116,8 @@ 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_FUA), + ATA_DFLAG_NCQ_PRIO | ATA_DFLAG_FUA | \ + ATA_DFLAG_CDL), ATA_DEV_UNKNOWN = 0, /* unknown device */ ATA_DEV_ATA = 1, /* ATA device */ @@ -709,6 +711,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 Jan 12 14:03:59 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 13098070 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 4E99FC61DB3 for ; Thu, 12 Jan 2023 14:09:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234726AbjALOJd (ORCPT ); Thu, 12 Jan 2023 09:09:33 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59292 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235312AbjALOId (ORCPT ); Thu, 12 Jan 2023 09:08:33 -0500 Received: from esa1.hgst.iphmx.com (esa1.hgst.iphmx.com [68.232.141.245]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F011E51333; Thu, 12 Jan 2023 06:04: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=1673532295; x=1705068295; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=5t4qxzc/zrv3C8pNJB5KvGBTE/TWY/w17sZhvF/MQAs=; b=IEIqDOCwvSdFJ3ZkYpiAKEW/yXf0TUv32HdO8nKu8VkYy+X1dI80K0WD 0YumjKZ2Iyu5zJrKhwmbXuuN4fm4q3r5VungbTpTsJFS7hGIrn1wpUWEh YJh9vaTK5Ws+jCMqso1oh0hR/7gCzKQRJ3OoYG6iZIPmwyZAYED/S99ds vqc4QZcE1wy2H+OpmicieE0mdU9+3vjANCpgqjI6MhdIwEb2K97+FXZ75 LDOfj/D103zHnOgk9HUTxi6oVAqQLqFoc5fzQIlTeGsAHPfgGUilJZJqv 8mrbukcCtlLP3e8TSfiSIBDxoT88iHI4qNoaNDAd7mnL3Y9a1qlqPOwF7 A==; X-IronPort-AV: E=Sophos;i="5.97,211,1669046400"; d="scan'208";a="332632708" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 12 Jan 2023 22:04:47 +0800 IronPort-SDR: 9hXgCHhF94OxeqjT3XlzQQeoJd4/nWOODRm16P6qyKDrfUnPe9dTVJrRAqSxwZ/fUUp9CvgzjR unOCBPz5aB6cS7c9JJ7gTeM/lcv5VqG164kVUCSH8kSMHTU3VTCJflmzgupeEMAFzgnvwKVzEv 0rq7wUUd/4vYh2K9ydUwOQbXuG7mxVcGup+wRPZ7jmtjdk84YQPgqoySEiU90/w4KLlhJDwlcl LUA/OyMJ+mMQzMzHvqy26AQoI2J9fGOcYHKRez9n5Z6eXMXKh2nr8zfCS4hECsVrhtSbNiy3aP Lcg= 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; 12 Jan 2023 05:16:50 -0800 IronPort-SDR: Sm3ze1XWmoOBEkEfw6oKuqyfwvaB59GArBW9ulz/LdirLH+I8L4ZZNLGWvKDejs6+wD1lDH3XG IPVvjeoeyJ1ogMiQElHyyn7XTm1PWhtqiYX2qKsxSMpsUglJoonFtyEofxW2XvwExKIpiZ3wNj 4K+FWfD0cvsqUli4ku06duUpNCb8jSGGDcCL7m0dt3vcplvg8WXccJVZyfX6yLth8MMRsG4U6y II19dxRvkCNm8UDF3+d62DdsNbd6dWFUOX0sqXShKaMK8FTvGei0YWcHazxKn4wovHmL8Vuwd+ zHk= WDCIronportException: Internal Received: from unknown (HELO x1-carbon.wdc.com) ([10.225.164.12]) by uls-op-cesaip01.wdc.com with ESMTP; 12 Jan 2023 06:04:46 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org, linux-block@vger.kernel.org, Niklas Cassel Subject: [PATCH v2 10/18] ata: libata-scsi: handle CDL bits in ata_scsiop_maint_in() Date: Thu, 12 Jan 2023 15:03:59 +0100 Message-Id: <20230112140412.667308-11-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230112140412.667308-1-niklas.cassel@wdc.com> References: <20230112140412.667308-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@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 Signed-off-by: Niklas Cassel --- 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 c64bd3095ea6..b0a6778e852f 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3238,7 +3238,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) { @@ -3265,10 +3265,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: @@ -3278,6 +3276,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) || @@ -3293,7 +3313,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 Jan 12 14:04:00 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 13098071 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 1161FC54EBC for ; Thu, 12 Jan 2023 14:09:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235192AbjALOJq (ORCPT ); Thu, 12 Jan 2023 09:09:46 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60586 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231431AbjALOIk (ORCPT ); Thu, 12 Jan 2023 09:08:40 -0500 Received: from esa1.hgst.iphmx.com (esa1.hgst.iphmx.com [68.232.141.245]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 46DAE52C6F; Thu, 12 Jan 2023 06:04:58 -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=1673532299; x=1705068299; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=udBzXd/IavY1W2ZwHk17GUi/St/IdRIo1THFRJU+cdc=; b=OrahpBn5q/1+AEkyQI5ZOcFRINwqll3OIwCS5Ifk/BywJa4rqWiYRDl2 pwdqDIOezGs1DcKlkg6fiAEKUekE9o6NQ6Qmz1Alx3y99Wl66MabRowdo WbXX5Us759hpF14fVTbDcVkZyiOowyQyNj8LiqQkyS0K/rje/HVQbUGkJ feJp7cwujjSIMueqAoXt99dbYQdZzYBPYSdLVjk415wpy/dypkpwa4S+a 8ulGBVp6Ag/aSA1twmFDvQp8qeMzW8FE5AiOrR7roozgBm7ZAQQf3ogfY PBNDeNgZeUpKIk94s5SXNBGeY/kGUybeB0Kd+2+Dq/EMxPFvLqUIODBUu A==; X-IronPort-AV: E=Sophos;i="5.97,211,1669046400"; d="scan'208";a="332632714" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 12 Jan 2023 22:04:50 +0800 IronPort-SDR: 4sS05T9KzlPfyP2yBRJTJn7X02GudxNxg7PHcY3wzTo5xN5EmKdsMbvo4qRSkDmPzXSKiULTN6 I0lMENBR66Ia86BTixuPJizVWNS7WSo4z7hJn/YC6uyB83+l6zgkNujk2YAm6W6ZYhVFDaqiBp yGeaxXaklieYH1P6qW6ctoZ/qsZSoQPLwqXOyjk30THkQs3GV/gq5devYHocbniKUxJtE6pGS2 xEjHRMZi18jO/x1dNtY9zS5gI+iEKadkVRorzDrLLMXXYOfBO3PbxXIWHk4SQoXwDsbvOXf/gH CwY= 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; 12 Jan 2023 05:16:53 -0800 IronPort-SDR: fjgiBVGVYxWYAPHxR+wrN/fCcXiKc9pny9ARL9v/PuX1RrtqSBVMFq+Lwq42e1b6micgzNFaaQ ZWGQj2qnfL/D5tdz4kwmbzRZ5qRDhAmL/BgYMy/gv0XB3ptc+Ke2Ynwj84IWjAEabsQU/fPBmx W8Ob4O/TKV//peiRDTZCanOeO6zqyvWfKLEFewEEkq54zb3xTysIfUwKjyVKt9wiZI2FjIIMFJ w6XWqPUfKLEwNbEMtWhrSUbCF0Qkk5UxuHoKLoi+Vze9oOCiEzeXYmYMiPWrqPyfUPYPdfuqh/ rTY= WDCIronportException: Internal Received: from unknown (HELO x1-carbon.wdc.com) ([10.225.164.12]) by uls-op-cesaip01.wdc.com with ESMTP; 12 Jan 2023 06:04:49 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org, linux-block@vger.kernel.org, Niklas Cassel Subject: [PATCH v2 11/18] ata: libata-scsi: add support for CDL pages mode sense Date: Thu, 12 Jan 2023 15:04:00 +0100 Message-Id: <20230112140412.667308-12-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230112140412.667308-1-niklas.cassel@wdc.com> References: <20230112140412.667308-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@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. Signed-off-by: Damien Le Moal Co-developed-by: Niklas Cassel Signed-off-by: Niklas Cassel --- 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 b0a6778e852f..91fb19e72856 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); } /** @@ -2294,13 +2392,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) { @@ -2313,13 +2422,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 */ @@ -2338,10 +2447,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); @@ -3640,7 +3746,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 Jan 12 14:04:01 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 13098072 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 5E64CC677F1 for ; Thu, 12 Jan 2023 14:10:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235171AbjALOJ7 (ORCPT ); Thu, 12 Jan 2023 09:09:59 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35544 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234195AbjALOIp (ORCPT ); Thu, 12 Jan 2023 09:08:45 -0500 Received: from esa1.hgst.iphmx.com (esa1.hgst.iphmx.com [68.232.141.245]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 251CC58339; Thu, 12 Jan 2023 06:05: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=1673532301; x=1705068301; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=sjG5RozfauwJd1wO4keQmfCG0dQTzovuAVSH+JoulAI=; b=nV2ZlpYb5c0qtAWW2knOnq7miIueRVBnlDGQ1Bs9ET6mmUedLEsyK3kz UvmuVS4I6kO69MzOw2iZt/Foih1SsArmhuh+TT+oMMx8eB2jCHlG7LgYX rWqjnkslvBIAwVafryMSSsQn2QOrgjOM8C3Csd23LD4tK79WNFSltJmcr 4j4vYWFDIxz0PqFEMd0C0p2tb2SOIEkm6FQEfFsjOeXhkR+76JLqC9i87 BfON913hVEfSUCDrH1Jt2TP6/u84U1sxXk/vJyP4YZ6zIS6xL7xNiAi2p rSHADq3AZmQ5bKab6171QmnAdXzUX2l/pjrOFcr04hspKHaOriUfJijD4 Q==; X-IronPort-AV: E=Sophos;i="5.97,211,1669046400"; d="scan'208";a="332632723" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 12 Jan 2023 22:04:53 +0800 IronPort-SDR: IKH444nunOwmtbBmtUkXNM4FYiNf15s6Z1/G0cY/By26unWa/9Ei+29aYrZX5M5HigL2NYwP6C nqUnpXYd9RxNemfkI2+tCXqS7FqDHSshie/pUi+4lgtXkfwQTXFoFdUaWRJhvygGJCpihGlto/ byPqBbIZuV0/X00M6bcZKXJSjNiabAhapdW0+/dcez0TWZaau3JwUEttT+6WFQ45qV9Z+VuP8P apeDYIw/xizOTc4icWzYXDA2VZO6xRim7AnufZUOs/iS10XuQml5XU+imTH7YWwoZ5otvGdNcr pxs= 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; 12 Jan 2023 05:16:56 -0800 IronPort-SDR: 2rd7Sdy/huuNexCyF8mL3DmIZt7/h36Z9Rb/AMTevuD/E/HS6cCGEXfdROEbEVaA99WYZd5Yrg BfciiIuPws9VYuvLyR7agNC/Pysc9ZjxEUHfzjcY2imAkuj7a+5YMqSSo0P1IuH7aQpxx0BBRD SH2AS5RgXxgCsI07RqmGS1Ksb4PuZXnp5GnYIchoOc+jJmfO+3x5h/jnDjl9600OtrnY4T/fpT hkn0rCtQZwX1oB0SVhFMMwTW7/g2sUGYzrNtAhFssn9G0AVdu9vLxF4a0ronNjC+7GV3qxI4H0 sEs= WDCIronportException: Internal Received: from unknown (HELO x1-carbon.wdc.com) ([10.225.164.12]) by uls-op-cesaip01.wdc.com with ESMTP; 12 Jan 2023 06:04:52 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org, linux-block@vger.kernel.org, Niklas Cassel Subject: [PATCH v2 12/18] ata: libata: add ATA feature control sub-page translation Date: Thu, 12 Jan 2023 15:04:01 +0100 Message-Id: <20230112140412.667308-13-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230112140412.667308-1-niklas.cassel@wdc.com> References: <20230112140412.667308-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@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. Signed-off-by: Damien Le Moal Co-developed-by: Niklas Cassel Signed-off-by: Niklas Cassel --- 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 17e32b0a6364..9aa49eab2b95 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2371,13 +2371,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, @@ -2396,6 +2398,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). @@ -2412,7 +2448,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 91fb19e72856..0f843512fe04 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; @@ -2394,7 +2424,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) { @@ -2403,6 +2433,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; @@ -3711,20 +3742,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]; @@ -3762,6 +3784,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 @@ -3779,7 +3878,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]; @@ -3864,13 +3963,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; @@ -3883,14 +3998,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 2b17d6c99a37..d7fe735e6322 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -106,6 +106,7 @@ enum { ATA_DFLAG_INIT_MASK = (1 << 20) - 1, ATA_DFLAG_NCQ_PRIO_ENABLED = (1 << 20), /* Priority cmds sent to dev */ + ATA_DFLAG_CDL_ENABLED = (1 << 21), /* 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 Jan 12 14:04:02 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 13098073 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 39B2CC677F1 for ; Thu, 12 Jan 2023 14:10:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233937AbjALOKN (ORCPT ); Thu, 12 Jan 2023 09:10:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37344 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231578AbjALOJb (ORCPT ); Thu, 12 Jan 2023 09:09:31 -0500 Received: from esa1.hgst.iphmx.com (esa1.hgst.iphmx.com [68.232.141.245]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8F4E158310; Thu, 12 Jan 2023 06:05: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=1673532306; x=1705068306; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=DxPLUnFEiqHGirdA3rRfvoSUO8OEmt2q6ZMTmQXO9l8=; b=KzC0MkxOV1AJKrdyf5bqpwsFG/nQZ6RCwjUopfCAUe34Ujphz3JKQh7K cUnTZbomfCNWjqLBYJrPLNGKKwtJrkji13AKHgaEgIa/03xWth0EJ7MWj pIhuX1RDFANK+szKWjkhZdLj5AWKP8tv446ZSjhggLDg25vXU/HRPVNlA uvf19eEpmfEl7z9hlU6YlU2+EwhVQD8l7XzgLu2KosAHHWaBOJB75JiFo QUUzfp28CSuI5zIEpYB2csa/TWxI38KJrc09dHNoXTrl5QUcJHPOdmOv1 WtejAIw0RknxFdXN1pVZEGRQA5/sj40/0dqBOxid4ieHFpE3RLqNeQa+1 g==; X-IronPort-AV: E=Sophos;i="5.97,211,1669046400"; d="scan'208";a="332632732" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 12 Jan 2023 22:04:55 +0800 IronPort-SDR: kk5bTt8T+bvwxxuL+/R3Uqnvu9fSIfq0tWZ3hXCj/FWXnn2RT6qZl0eKAD4pGrEsFK+zpgW7Pt 0UjBr9UXV10eSQpZkNd1rKzjSz5tsHbiIW4rLnYUU2uRZOhLNEW4EvpHanL3ca/8Vby3G9Rsw/ uJ4SnZRx9FQgtNvwr1HyqSodUDL9Xc4BkBsWFnm8QgX3wBy7AVVrzcF/wpiSZBrrJ2Ie7Pwcg0 0Uo3RiJaakkS+TN4mLRiDKaJh6ehCWcPRf5mzKri7rNDRjNk3sy5r1p0g/7cJTYclzACJuB5RY 5iM= 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; 12 Jan 2023 05:16:58 -0800 IronPort-SDR: 7e4NJz2fXykpSZnGf3ZJD6LZsVszcB21v2kcy8K3sKznj/6niHfD8CuHjKzAlUnLX5onCW2nbj 1NfevQR4YazMGDs/Wd89WmPVmERxqyGcGvXoCOjWdxDgsbmLwjUBxkYkqxBvKqA6TOzU/Nj2bQ aP0NduMY9TauW2GieL9IM/DSr6yDf6TMnc+k71M5VKwDYsf3AmZ5KneC8zV6uaoLWIm1fFJvY7 wnHsFe+MDzFy1OYScHNtRP78Fq96u38sbZ+Q2BpNhJDYiVO0ENrZ7PIN9R6M1GdaTYT9ban3Bq czI= WDCIronportException: Internal Received: from unknown (HELO x1-carbon.wdc.com) ([10.225.164.12]) by uls-op-cesaip01.wdc.com with ESMTP; 12 Jan 2023 06:04:55 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org, linux-block@vger.kernel.org, Niklas Cassel Subject: [PATCH v2 13/18] ata: libata: set read/write commands CDL index Date: Thu, 12 Jan 2023 15:04:02 +0100 Message-Id: <20230112140412.667308-14-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230112140412.667308-1-niklas.cassel@wdc.com> References: <20230112140412.667308-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@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. Signed-off-by: Damien Le Moal Co-developed-by: Niklas Cassel Signed-off-by: Niklas Cassel --- drivers/ata/libata-core.c | 43 ++++++++++++++++++++++++++++++++++----- drivers/ata/libata-scsi.c | 3 +-- drivers/ata/libata.h | 2 +- include/linux/libata.h | 1 + 4 files changed, 41 insertions(+), 8 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 9aa49eab2b95..2c1531ef169d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -665,13 +665,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. @@ -685,7 +709,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; @@ -722,13 +746,22 @@ 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; - /* We need LBA48 for FUA writes */ - if (!(tf->flags & ATA_TFLAG_FUA) && lba_28_ok(block, n_block)) { + if (dev->flags & ATA_DFLAG_CDL_ENABLED) + ata_set_tf_cdl(qc, ioprio); + + /* Both FUA writes and a CDL index require 48-bit commands */ + if (!(tf->flags & ATA_TFLAG_FUA) && + !(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 0f843512fe04..b8caecd875cd 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 d7fe735e6322..ab8b62036c12 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -209,6 +209,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 Jan 12 14:04:03 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 13098075 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 889C7C61DB3 for ; Thu, 12 Jan 2023 14:10:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235265AbjALOKq (ORCPT ); Thu, 12 Jan 2023 09:10:46 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60674 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233591AbjALOJ6 (ORCPT ); Thu, 12 Jan 2023 09:09:58 -0500 Received: from esa1.hgst.iphmx.com (esa1.hgst.iphmx.com [68.232.141.245]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A083F517EE; Thu, 12 Jan 2023 06:05: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=1673532316; x=1705068316; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=kigI8xABdMP1xwtDT4vgVnuAAix5zSZ65zwoSPiYgck=; b=FYlxYe66Ov53c+5oDY34ta97mrEcWgRvM+JSHsg3YZzAZ0ehQq6W9924 j6JmPNV0tRpebPVx4WqvTt9i7T7BpL5GFyKyLl1jh4freuK1VYFocm5Vn wyDOcDWSijmWer7tr1iY0r2H+EONAyTJJoBY5BROiUvgvsdIa2zu6urLk 5z/E7lUy/XKOhkxtd6VuZOdOo0uFet6aFDF7kHGUy9m7ZlPIBKzEZN18s kyh0fs+EWp7JmQda48fTJsKkqaL1L9pCWJ/2X3+sUsTiwfzm5p/dyr43j vTWGfuaIJ/xVFnEHbWjC3WKd4QjcHv7c2NbgmcUGWcISGU1WXYnlAqFPu g==; X-IronPort-AV: E=Sophos;i="5.97,211,1669046400"; d="scan'208";a="332632740" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 12 Jan 2023 22:04:59 +0800 IronPort-SDR: i7Faa++nr6qxlk8F8mhlWzrnmXWD4h8nItyP+1N0R1+NuoM5NMw0L6bTdqt/SPa7x0AZPwfhgJ VT+aEJMHHls/V8jFEMpGDrvx5+iKOXkrqIn4ETafJGAqYurckSsEQOvt45z6VD3udbNJ9EniQn oyPc6qkqeydIPmIfImQ5s/0S3UI/1g3PaLLBdwfcn+myqfZQ+E87DXiei2jEG1QrfQ/C6k2fic rXZcg5Mlngu9D+oNUHGjPNxCAbqiY2++iGZzcS08I4pgQ/VaHzJjqYGo0YsIo6XYtcxtwt4mPO SoE= 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; 12 Jan 2023 05:17:02 -0800 IronPort-SDR: 3zET9HnOI/MQpp2mvHmnMNPUo1z4S64D5TPxnaGkLpUB+4kRiU1Kuz0SHLUpKLYdDM3ZnXVPt9 VIp/rLo13bXo7DGWwp5nWUolk5e/f+agFq1OUmt58y8h6+ztryG+lf4PoS8gAmaiYyQL2XwyC/ pdDoKkIdSUKo4thDl5bZ4nbRzj7mM+sHpu0aGv/FL7JvrkQxxx3eM81BgbuA0eTQIpTSun/ifN mbLuJXnBUolBSfyOLgSR7uDCZco1kqIm/Uw2/c8yuHec7hz9pQvwiF4W0qkZs9RbTO4HrF/yYa S9A= WDCIronportException: Internal Received: from unknown (HELO x1-carbon.wdc.com) ([10.225.164.12]) by uls-op-cesaip01.wdc.com with ESMTP; 12 Jan 2023 06:04:58 -0800 From: Niklas Cassel To: "James E.J. Bottomley" , "Martin K. Petersen" Cc: Hannes Reinecke , Damien Le Moal , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org, linux-block@vger.kernel.org, Niklas Cassel Subject: [PATCH v2 14/18] scsi: sd: detect support for command duration limits Date: Thu, 12 Jan 2023 15:04:03 +0100 Message-Id: <20230112140412.667308-15-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230112140412.667308-1-niklas.cassel@wdc.com> References: <20230112140412.667308-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@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 Signed-off-by: Niklas Cassel --- 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 Jan 12 14:04:04 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 13098074 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 B57E5C677F1 for ; Thu, 12 Jan 2023 14:10:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235143AbjALOKo (ORCPT ); Thu, 12 Jan 2023 09:10:44 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37490 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235307AbjALOJt (ORCPT ); Thu, 12 Jan 2023 09:09:49 -0500 Received: from esa1.hgst.iphmx.com (esa1.hgst.iphmx.com [68.232.141.245]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EA9C753297; Thu, 12 Jan 2023 06:05: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=1673532316; x=1705068316; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=SEUFLMMv1bvIqZcfMqZ9YR2cwVYziWf0i0Fg8/frt/w=; b=je66jWqpu4d1nYwGb0BkgnTm2t3LBWtG07tBJnpK24lt4tAKF+rYwpSu o9IN0VYkKxyYMhUXp3XNU8RHFGMC9ziaqUKLGNAtBJAoPaY7zfzonzxrT /PugkWw5d4/00V6SjDGAQBwSzeny/bp3ghleTG1lrXBeoa+LRMRjkSqRH x6BGb5CSYXd/9lRNKms9hUeNk0Mu6aerCE9alJgRBhIHBeGz9uhrn2Lou ctCHz8Dl1W0t/tkXmPdGgTSlvkfOo2xHljcMoxisz7pMaBJP1k7hIkuf/ NmMAQajNND+X9jOkNIE5scwOdBExmxCNXk2E+G1C8ed390VIyp+dVK+B6 A==; X-IronPort-AV: E=Sophos;i="5.97,211,1669046400"; d="scan'208";a="332632745" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 12 Jan 2023 22:05:02 +0800 IronPort-SDR: JMtDB2Qjn+hrTwZkFt5R92BlaMsbGbzr+moKXg8VC/lWBIA3YESkJ25WlJWLEAB9A8nAx0abMt evFTd6ZKhIaA8jY+MZEC68w3K0Wm4rVCvPrDCEknlkVvfqCAzfqoTrc2NzrX1FX/xgIcu55F/9 j0IAdW9aFaQpVgQP9AAvHIxCo3sR+Yori2MBxtaYz2q6xy7IBXWQI8TiePZl1Mqivq7OZ3EHrW 63ZttrnVksLf8OA7+MmsAuceIquMVVq0uLC52G2bWjWecVmmp2v4I1U/beLSIpRlr3NbYZM/bE U7g= 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; 12 Jan 2023 05:17:06 -0800 IronPort-SDR: B3sIjMDvQE8k4ElTpgLsOhWdVXd6fZ3wO5Rc6C8Nj3Q16aADV3W10IyRO4j2MNc1q3YcrR5Z3H uuyWiPhSxxc4Qw/nsliTKy3Nc1ZE/KRMn06YF8TSu4UasCDTgeWi2vqCOkOJyFcpd3dp76v166 AOXEdU6b2D7/S7uR/HymM5Cu+4hQ5JdIQ7Qz+Fdi6PLcXPTo6eIL6Ti0Mm3Ul97GlvOoSZYE8J It6i/KGeAPB1f0nkeCRcVJjporXoU8VF5t7PHI3k5qBXOENMyAL6outghIQ3P35x96pdi5vUaV +FE= WDCIronportException: Internal Received: from unknown (HELO x1-carbon.wdc.com) ([10.225.164.12]) by uls-op-cesaip01.wdc.com with ESMTP; 12 Jan 2023 06:05:01 -0800 From: Niklas Cassel To: "James E.J. Bottomley" , "Martin K. Petersen" Cc: Hannes Reinecke , Damien Le Moal , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org, linux-block@vger.kernel.org, Niklas Cassel Subject: [PATCH v2 15/18] scsi: sd: set read/write commands CDL index Date: Thu, 12 Jan 2023 15:04:04 +0100 Message-Id: <20230112140412.667308-16-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230112140412.667308-1-niklas.cassel@wdc.com> References: <20230112140412.667308-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@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. Signed-off-by: Damien Le Moal Co-developed-by: Niklas Cassel Signed-off-by: Niklas Cassel --- 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 Jan 12 14:04:05 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 13098076 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 D903FC54EBC for ; Thu, 12 Jan 2023 14:10:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234146AbjALOKs (ORCPT ); Thu, 12 Jan 2023 09:10:48 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35544 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230497AbjALOJ6 (ORCPT ); Thu, 12 Jan 2023 09:09:58 -0500 Received: from esa1.hgst.iphmx.com (esa1.hgst.iphmx.com [68.232.141.245]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 18B6658D10; Thu, 12 Jan 2023 06:05:19 -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=1673532319; x=1705068319; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=1f7zHLpGMm9g1WnrgGxTA6e76XFBUATSXLYVFXzagpA=; b=EuETioCMypNA5iAv05LvpYkrFt6AJajPyOPRqE1NrmOHYGXG792mQcX3 SSgCAHKr2hAC/BhmM7ihw5DJYnC7f4Y2/7or/L5X5zdBCjZBCGZVycSEK n2LnKquQCOhw4Cqk/zVutz7xvCGiYZxhwoiPdYH1RSPVA75/e32lPR9jU xy2AEbu6TPVLFd1IHah+jipiAk/2pLTGgaR5NS8tk5pBBbc4dwQejMpjv /BHjMS2CD8Zpv8mlub6S1UgAAcloREmOPh1ydB3ynexElm4Gz/PhYxP8n 7aE2m7J3/IUjcB3P6MN7tHhNdqOwZlYVacwhCN/7fMm0c9H/4qQ6VvFY2 g==; X-IronPort-AV: E=Sophos;i="5.97,211,1669046400"; d="scan'208";a="332632749" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 12 Jan 2023 22:05:05 +0800 IronPort-SDR: PC+hahFSnhm7oGzGfLE7OfxADTo+uL5WeCvT4JSG4WQxCd7S0sscAGIuiNLK4WtprygUeGlS9t EnBB8pMyU9nSGoRdQIaLRfXw2wPJbRIvpJNfH6QhWqhBm1DFeXNE7y+ur1hC9nKq14H1OIWPsf jdiHKaB6CSWrfK631D/KXlgDZlTclWN75eJskpaLDNb/BQCQKBdUOyKj1vqQI0n35vBm7H4pWr xtKAq2ILgjMZz+IIWxM8i6Q+Bd5Xe6imdFJD+pvRjoPmdtx4lNTLmTytYoh6D7q+3xfRW4zOCc Q8I= 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; 12 Jan 2023 05:17:09 -0800 IronPort-SDR: tPnPlSHdk/WuxeYIpwzgwjgcaZ4zbIwxsapujAwRoPQAmIymye0ZDQacuzoG9ZbHlxWg13HrrC ugzdDVuT7z2OjLNAA2UXFKSPKq4CJVGf0qlD/1oOq+cT40jTGNk7FQSKxYju90ar2s3Joq73OF rDDrViqVgM6RriubwKhDQPKYLi+zrZObc4XfebJ9hy6qgRdtwAHmftncvEITOtson4A9/hOqEb 2N1NYAHYlDqpnkf6pkJ3I6O0OnmyytimpEqpWz9hP0GBgfG14d9/X5MEAbB/4hZ/qTsxaFxVLl Z0k= WDCIronportException: Internal Received: from unknown (HELO x1-carbon.wdc.com) ([10.225.164.12]) by uls-op-cesaip01.wdc.com with ESMTP; 12 Jan 2023 06:05:04 -0800 From: Niklas Cassel To: "James E.J. Bottomley" , "Martin K. Petersen" Cc: Hannes Reinecke , Damien Le Moal , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org, linux-block@vger.kernel.org, Niklas Cassel Subject: [PATCH v2 16/18] scsi: sd: handle read/write CDL timeout failures Date: Thu, 12 Jan 2023 15:04:05 +0100 Message-Id: <20230112140412.667308-17-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230112140412.667308-1-niklas.cassel@wdc.com> References: <20230112140412.667308-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@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..e7103bf3ab23 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 (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 79cece5eff5d..5923873f09e5 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 74324fba4281..f42388ecb024 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 scsi_ml_byte(int result) From patchwork Thu Jan 12 14:04:06 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 13098101 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 E5053C677F1 for ; Thu, 12 Jan 2023 14:11:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235011AbjALOLx (ORCPT ); Thu, 12 Jan 2023 09:11:53 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37382 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235397AbjALOKc (ORCPT ); Thu, 12 Jan 2023 09:10:32 -0500 Received: from esa1.hgst.iphmx.com (esa1.hgst.iphmx.com [68.232.141.245]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 56540544C1; Thu, 12 Jan 2023 06:05:26 -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=1673532326; x=1705068326; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=yOuCIr+MGJ77HOgz5DJNZUGIKNaNk6JE5lDe7dZCNr8=; b=rRFYwcd2qrTF8kOUYxGko7HOl8otgYyaFZShNhJ1kUylQCgB5H6E1thg OOn85ZJkZQWOqSz1V/qDgwwNGlWdsG5LJlpfkTiZ5pWEZt1HaNdVyvrUL UvU6txJgpIaLRO8st8Ei2ITZ1cObInyTtyVn1Vs2OOC+9AMqFt/WSX2SI bhOYQptHgQ9qSViWobDDVN3Cwb0zoRtGeTAEj+BmkSl9FFnN2Oi30COpj bHGoABW+XN7bpfSPZtWQHU95+mI6IhnqQrqfYkfYgA2cnBitkCw0XhsRe Zg39yY+vSzNo3uDV2NTa8FcCOUDrPzdxhthRfKsouH7h7yTSnmzLYPxrS A==; X-IronPort-AV: E=Sophos;i="5.97,211,1669046400"; d="scan'208";a="332632753" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 12 Jan 2023 22:05:09 +0800 IronPort-SDR: Nw8N7r/djYigBYlfD+VtHWHx07D/vEpC/nePQ9bSNprhJJKGAVOo5IbsHKXcIvrgN476CSleFw h5nKRQ5qNsvhXEw+McB7VV/+05dm/5LswQ2h63WxXSIihv9CCoSqvJheqsgpIAkp0T/mPF74Md CDubYrmzs9XBHU8sJZqi/tA17vIP7Ft2FYJSCLEhjc6YZcQWlvBotgCnSkR3j4aG6KU5OXMAYr mNl+mNdcg+K5tsvqoNOmASp8772ZyvUa+xW273RCCLcA/lxsi3JXn2UTSZqb1yv95Z9KJxUFOw 0DE= 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; 12 Jan 2023 05:17:12 -0800 IronPort-SDR: HpqW0dArthAk5b8cFme+MWpyR2rUdjnEdU3mtCqxs3oUCKR0FancJcFFnynNyDhJJCMLW9qjs0 JKzDVn5QnYxQwXuRtDCQChIiTS3upbakScslq80lrGNIRY9mgpIjm9t2bpXDJkuuw3eMKyaXQ5 b7xMzykdggHt1dqjkhwbjJ3yx/M7DhI+qMPCHeBag3fRyshxWchjGHx9HGqePm7zbhrShjWrTY ZaYsyUtWvmuBNmr1jfBeIx3ytZLVfds6HtYTLUIixUJWB2szz8hQzPdzbIW47PCjfAVquPSwMj 1ps= WDCIronportException: Internal Received: from unknown (HELO x1-carbon.wdc.com) ([10.225.164.12]) by uls-op-cesaip01.wdc.com with ESMTP; 12 Jan 2023 06:05:08 -0800 From: Niklas Cassel To: Damien Le Moal Cc: Hannes Reinecke , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org, linux-block@vger.kernel.org, Niklas Cassel Subject: [PATCH v2 17/18] ata: libata: handle completion of CDL commands using policy 0xD Date: Thu, 12 Jan 2023 15:04:06 +0100 Message-Id: <20230112140412.667308-18-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230112140412.667308-1-niklas.cassel@wdc.com> References: <20230112140412.667308-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@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 | 88 ++++++++++++++++++++++++++++++- 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, 295 insertions(+), 4 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 2c1531ef169d..e46258dfaa8e 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -685,8 +685,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; } /** @@ -2431,6 +2435,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. @@ -2465,6 +2487,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). @@ -2482,6 +2533,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) @@ -4882,6 +4935,36 @@ 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; + + /* + * set pending so that ata_qc_schedule_eh() does not + * trigger fast drain, and freeze the port. + */ + ap->pflags |= ATA_PFLAG_EH_PENDING; + ata_qc_schedule_eh(qc); + return; + } + /* Some commands need post-processing after successful * completion. */ @@ -5514,6 +5597,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 1c3d55fc1cae..c1d08753301c 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1913,6 +1913,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 @@ -1953,6 +2049,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; @@ -1962,6 +2066,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; @@ -3821,7 +3926,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 ab8b62036c12..70ac635fe5d7 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -214,6 +214,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 */ @@ -312,8 +313,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, @@ -867,6 +870,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; }; @@ -1185,6 +1189,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 * @@ -1222,6 +1227,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 Jan 12 14:04:07 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Cassel X-Patchwork-Id: 13098100 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 2A6B4C54EBD for ; Thu, 12 Jan 2023 14:11:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235441AbjALOLu (ORCPT ); Thu, 12 Jan 2023 09:11:50 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37362 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234352AbjALOK2 (ORCPT ); Thu, 12 Jan 2023 09:10:28 -0500 Received: from esa1.hgst.iphmx.com (esa1.hgst.iphmx.com [68.232.141.245]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C0C5B58D2F; Thu, 12 Jan 2023 06:05:26 -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=1673532326; x=1705068326; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=iJuqTlHbB+r3PzdoLMxijeGItAuqi1spp9PVHEVw1+Q=; b=BB+ZEaRH048ynRkNCF6qZEDWEHQVFxHpjVczowpFFkVSrzGzAUGjchmi VdYNx8Key3AyHS+JdOBGj0jnH1oqwuhNap2GNcCjvYTvYuhNuNJPuq5i0 YMYGyrXA/GVKtEUUI+w8JI7no5CT04FbfDK7aZvAzyWbnvujb3QTAgnlS qopJdWv3EwZss+bFSDQg9YEF8A+UMdTvCfqiaJhHBe0CBaTBVFtR8NFwu peI8GSBOlAkicyVQNthI6hW8IpiEu9Mo3sjjVH2Wj4TrbbBcDT23vuPAn gQ/mef8cYJCZuaS+Rxc2ypAZVuuCRFQ8ub87KMq4IEq99Zlj2HUOJx22R A==; X-IronPort-AV: E=Sophos;i="5.97,211,1669046400"; d="scan'208";a="332632758" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 12 Jan 2023 22:05:11 +0800 IronPort-SDR: 22K2g1Z8G7SXmFvm94GpnZ7kqixbQVzvSEyFyHhykCFwL0cdcUUpJ9BesneZAzy8au7IpZJHJd A4maT8dAUvq20aYBQyLug5R1OeRZF3Vcgzq3pwRVvfjZa1+D09xTI4B9HghdC9gS6bVOzpFuMa athrdrRBEEADbTcprihRV1ivrYjbUHwe1owQiNQyxgjH6lF+RM/LUPapnKzXYSfoKJrAkgI6YD tVdgAdPAlRngnav3ygh2YuacPuRiMv2xeXkffCtPWClrJNl0tXWx6ecrzCd+SkeXQfdLXAhwBp AkI= 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; 12 Jan 2023 05:17:15 -0800 IronPort-SDR: mJE5jswxrS6xxVKtsQhZZpLT6y1e0Rb01aQCv8cd82+fdSPygaN36UdtAPmGHiVsiXI7cQphlY bkUYjmvKmoVoNPdT9itS62M+rlmp69nkf+xhYqc59a8A/76yRaVBMNQeSJeE+8uQ/OLA+z28g0 Yvn80elQQrR1aPyAwNCRJkSUhdhq/EpsN4b3v6C/nkQKnMcJAKxpqoQ2MPLrp5/9tKGpDf4dRi cOEb1Yxiy8fGRTGV+G+pAXEtNFU46a/q9U12kfTmFvY+9tdI8pyk+v+tWchCkgtoF9fp48t9ey txs= WDCIronportException: Internal Received: from unknown (HELO x1-carbon.wdc.com) ([10.225.164.12]) by uls-op-cesaip01.wdc.com with ESMTP; 12 Jan 2023 06:05:10 -0800 From: Niklas Cassel To: linux-kernel@vger.kernel.org Cc: Hannes Reinecke , Damien Le Moal , linux-scsi@vger.kernel.org, linux-ide@vger.kernel.org, linux-block@vger.kernel.org, Niklas Cassel Subject: [PATCH v2 18/18] Documentation: sysfs-block-device: document command duration limits Date: Thu, 12 Jan 2023 15:04:07 +0100 Message-Id: <20230112140412.667308-19-niklas.cassel@wdc.com> X-Mailer: git-send-email 2.39.0 In-Reply-To: <20230112140412.667308-1-niklas.cassel@wdc.com> References: <20230112140412.667308-1-niklas.cassel@wdc.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-block@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 Signed-off-by: Niklas Cassel --- Documentation/ABI/testing/sysfs-block-device | 150 +++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-block-device b/Documentation/ABI/testing/sysfs-block-device index 7ac7b19b2f72..3a32c86942f5 100644 --- a/Documentation/ABI/testing/sysfs-block-device +++ b/Documentation/ABI/testing/sysfs-block-device @@ -95,3 +95,153 @@ 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 in 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 + 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. + + - 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 max + 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.