From patchwork Fri Mar 11 12:23:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Garry X-Patchwork-Id: 550888 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 E70A9C433EF for ; Fri, 11 Mar 2022 12:29:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348561AbiCKMau (ORCPT ); Fri, 11 Mar 2022 07:30:50 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38252 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348530AbiCKMas (ORCPT ); Fri, 11 Mar 2022 07:30:48 -0500 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1804E1BE82; Fri, 11 Mar 2022 04:29:45 -0800 (PST) Received: from fraeml738-chm.china.huawei.com (unknown [172.18.147.201]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4KFQFL4Vfmz6H6jl; Fri, 11 Mar 2022 20:28:06 +0800 (CST) Received: from lhreml724-chm.china.huawei.com (10.201.108.75) by fraeml738-chm.china.huawei.com (10.206.15.219) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2308.21; Fri, 11 Mar 2022 13:29:43 +0100 Received: from localhost.localdomain (10.69.192.58) by lhreml724-chm.china.huawei.com (10.201.108.75) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2308.21; Fri, 11 Mar 2022 12:29:38 +0000 From: John Garry To: , , , CC: , , , , , , , , John Garry Subject: [PATCH v2 1/4] scsi: libsas: Add sas_execute_internal_abort_single() Date: Fri, 11 Mar 2022 20:23:49 +0800 Message-ID: <1647001432-239276-2-git-send-email-john.garry@huawei.com> X-Mailer: git-send-email 2.8.1 In-Reply-To: <1647001432-239276-1-git-send-email-john.garry@huawei.com> References: <1647001432-239276-1-git-send-email-john.garry@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.69.192.58] X-ClientProxiedBy: dggems705-chm.china.huawei.com (10.3.19.182) To lhreml724-chm.china.huawei.com (10.201.108.75) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org The internal abort feature is common to hisi_sas and pm8001 HBAs, and the driver support is similar also, so add a common handler. Two modes of operation will be supported: - single: Abort a single tagged command - device: Abort all commands associated with a specific domain device A new protocol is added, SAS_PROTOCOL_INTERNAL_ABORT, so the common queue command API may be re-used. Only add "single" support as a first step. Signed-off-by: John Garry Tested-by: Damien Le Moal --- drivers/scsi/libsas/sas_scsi_host.c | 74 +++++++++++++++++++++++++++++ include/scsi/libsas.h | 14 ++++++ include/scsi/sas.h | 2 + 3 files changed, 90 insertions(+) diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 5b5747e33dbd..bb6baa52264d 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -920,6 +920,80 @@ void sas_task_internal_timedout(struct timer_list *t) #define TASK_TIMEOUT (20 * HZ) #define TASK_RETRY 3 +static int sas_execute_internal_abort(struct domain_device *device, + enum sas_internal_abort type, u16 tag, + unsigned int qid, void *data) +{ + struct sas_ha_struct *ha = device->port->ha; + struct sas_internal *i = to_sas_internal(ha->core.shost->transportt); + struct sas_task *task = NULL; + int res, retry; + + for (retry = 0; retry < TASK_RETRY; retry++) { + task = sas_alloc_slow_task(GFP_KERNEL); + if (!task) + return -ENOMEM; + + task->dev = device; + task->task_proto = SAS_PROTOCOL_INTERNAL_ABORT; + task->task_done = sas_task_internal_done; + task->slow_task->timer.function = sas_task_internal_timedout; + task->slow_task->timer.expires = jiffies + TASK_TIMEOUT; + add_timer(&task->slow_task->timer); + + task->abort_task.tag = tag; + task->abort_task.type = type; + + res = i->dft->lldd_execute_task(task, GFP_KERNEL); + if (res) { + del_timer_sync(&task->slow_task->timer); + pr_err("Executing internal abort failed %016llx (%d)\n", + SAS_ADDR(device->sas_addr), res); + break; + } + + wait_for_completion(&task->slow_task->completion); + res = TMF_RESP_FUNC_FAILED; + + /* Even if the internal abort timed out, return direct. */ + if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { + pr_err("Internal abort: timeout %016llx\n", + SAS_ADDR(device->sas_addr)); + res = -EIO; + break; + } + + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == SAS_SAM_STAT_GOOD) { + res = TMF_RESP_FUNC_COMPLETE; + break; + } + + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == TMF_RESP_FUNC_SUCC) { + res = TMF_RESP_FUNC_SUCC; + break; + } + + pr_err("Internal abort: task to dev %016llx response: 0x%x status 0x%x\n", + SAS_ADDR(device->sas_addr), task->task_status.resp, + task->task_status.stat); + sas_free_task(task); + task = NULL; + } + BUG_ON(retry == TASK_RETRY && task != NULL); + sas_free_task(task); + return res; +} + +int sas_execute_internal_abort_single(struct domain_device *device, u16 tag, + unsigned int qid, void *data) +{ + return sas_execute_internal_abort(device, SAS_INTERNAL_ABORT_SINGLE, + tag, qid, data); +} +EXPORT_SYMBOL_GPL(sas_execute_internal_abort_single); + int sas_execute_tmf(struct domain_device *device, void *parameter, int para_len, int force_phy_id, struct sas_tmf_task *tmf) diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index df2c8fc43429..2d30d57916e5 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -557,6 +557,16 @@ struct sas_ata_task { int force_phy_id; }; +/* LLDDs rely on these values */ +enum sas_internal_abort { + SAS_INTERNAL_ABORT_SINGLE = 0, +}; + +struct sas_internal_abort_task { + enum sas_internal_abort type; + u16 tag; +}; + struct sas_smp_task { struct scatterlist smp_req; struct scatterlist smp_resp; @@ -596,6 +606,7 @@ struct sas_task { struct sas_ata_task ata_task; struct sas_smp_task smp_task; struct sas_ssp_task ssp_task; + struct sas_internal_abort_task abort_task; }; struct scatterlist *scatter; @@ -683,6 +694,9 @@ extern int sas_slave_configure(struct scsi_device *); extern int sas_change_queue_depth(struct scsi_device *, int new_depth); extern int sas_bios_param(struct scsi_device *, struct block_device *, sector_t capacity, int *hsc); +int sas_execute_internal_abort_single(struct domain_device *device, + u16 tag, unsigned int qid, + void *data); extern struct scsi_transport_template * sas_domain_attach_transport(struct sas_domain_function_template *); extern struct device_attribute dev_attr_phy_event_threshold; diff --git a/include/scsi/sas.h b/include/scsi/sas.h index 332a463d08ef..acfc69fd72d0 100644 --- a/include/scsi/sas.h +++ b/include/scsi/sas.h @@ -95,6 +95,8 @@ enum sas_protocol { SAS_PROTOCOL_SSP = 0x08, SAS_PROTOCOL_ALL = 0x0E, SAS_PROTOCOL_STP_ALL = SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA, + /* these are internal to libsas */ + SAS_PROTOCOL_INTERNAL_ABORT = 0x10, }; /* From the spec; local phys only */ From patchwork Fri Mar 11 12:23:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Garry X-Patchwork-Id: 550707 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 7DC46C433F5 for ; Fri, 11 Mar 2022 12:29:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348583AbiCKMa6 (ORCPT ); Fri, 11 Mar 2022 07:30:58 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38316 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348568AbiCKMaw (ORCPT ); Fri, 11 Mar 2022 07:30:52 -0500 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 426A71C910; Fri, 11 Mar 2022 04:29:49 -0800 (PST) Received: from fraeml736-chm.china.huawei.com (unknown [172.18.147.226]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4KFQGd4n4gz688Wb; Fri, 11 Mar 2022 20:29:13 +0800 (CST) Received: from lhreml724-chm.china.huawei.com (10.201.108.75) by fraeml736-chm.china.huawei.com (10.206.15.217) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2308.21; Fri, 11 Mar 2022 13:29:46 +0100 Received: from localhost.localdomain (10.69.192.58) by lhreml724-chm.china.huawei.com (10.201.108.75) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2308.21; Fri, 11 Mar 2022 12:29:42 +0000 From: John Garry To: , , , CC: , , , , , , , , John Garry Subject: [PATCH v2 2/4] scsi: libsas: Add sas_execute_internal_abort_dev() Date: Fri, 11 Mar 2022 20:23:50 +0800 Message-ID: <1647001432-239276-3-git-send-email-john.garry@huawei.com> X-Mailer: git-send-email 2.8.1 In-Reply-To: <1647001432-239276-1-git-send-email-john.garry@huawei.com> References: <1647001432-239276-1-git-send-email-john.garry@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.69.192.58] X-ClientProxiedBy: dggems705-chm.china.huawei.com (10.3.19.182) To lhreml724-chm.china.huawei.com (10.201.108.75) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Add support for a "device" variant of internal abort, which will abort all pending IOs for a specific device. Signed-off-by: John Garry Tested-by: Damien Le Moal --- drivers/scsi/libsas/sas_scsi_host.c | 8 ++++++++ include/scsi/libsas.h | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index bb6baa52264d..13142ec97f1d 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -994,6 +994,14 @@ int sas_execute_internal_abort_single(struct domain_device *device, u16 tag, } EXPORT_SYMBOL_GPL(sas_execute_internal_abort_single); +int sas_execute_internal_abort_dev(struct domain_device *device, + unsigned int qid, void *data) +{ + return sas_execute_internal_abort(device, SAS_INTERNAL_ABORT_DEV, + SCSI_NO_TAG, qid, data); +} +EXPORT_SYMBOL_GPL(sas_execute_internal_abort_dev); + int sas_execute_tmf(struct domain_device *device, void *parameter, int para_len, int force_phy_id, struct sas_tmf_task *tmf) diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 2d30d57916e5..71f632b2d2bd 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -560,6 +560,7 @@ struct sas_ata_task { /* LLDDs rely on these values */ enum sas_internal_abort { SAS_INTERNAL_ABORT_SINGLE = 0, + SAS_INTERNAL_ABORT_DEV = 1, }; struct sas_internal_abort_task { @@ -641,6 +642,11 @@ extern struct sas_task *sas_alloc_task(gfp_t flags); extern struct sas_task *sas_alloc_slow_task(gfp_t flags); extern void sas_free_task(struct sas_task *task); +static inline bool sas_is_internal_abort(struct sas_task *task) +{ + return task->task_proto == SAS_PROTOCOL_INTERNAL_ABORT; +} + struct sas_domain_function_template { /* The class calls these to notify the LLDD of an event. */ void (*lldd_port_formed)(struct asd_sas_phy *); @@ -697,6 +703,8 @@ extern int sas_bios_param(struct scsi_device *, struct block_device *, int sas_execute_internal_abort_single(struct domain_device *device, u16 tag, unsigned int qid, void *data); +int sas_execute_internal_abort_dev(struct domain_device *device, + unsigned int qid, void *data); extern struct scsi_transport_template * sas_domain_attach_transport(struct sas_domain_function_template *); extern struct device_attribute dev_attr_phy_event_threshold; From patchwork Fri Mar 11 12:23:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Garry X-Patchwork-Id: 550706 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 7575AC433FE for ; Fri, 11 Mar 2022 12:30:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348573AbiCKMbF (ORCPT ); Fri, 11 Mar 2022 07:31:05 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38684 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348587AbiCKMbC (ORCPT ); Fri, 11 Mar 2022 07:31:02 -0500 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7BE2B1B3086; Fri, 11 Mar 2022 04:29:58 -0800 (PST) Received: from fraeml737-chm.china.huawei.com (unknown [172.18.147.200]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4KFQFp5c3Cz687Dc; Fri, 11 Mar 2022 20:28:30 +0800 (CST) Received: from lhreml724-chm.china.huawei.com (10.201.108.75) by fraeml737-chm.china.huawei.com (10.206.15.218) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2308.21; Fri, 11 Mar 2022 13:29:50 +0100 Received: from localhost.localdomain (10.69.192.58) by lhreml724-chm.china.huawei.com (10.201.108.75) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2308.21; Fri, 11 Mar 2022 12:29:46 +0000 From: John Garry To: , , , CC: , , , , , , , , John Garry Subject: [PATCH v2 3/4] scsi: pm8001: Use libsas internal abort support Date: Fri, 11 Mar 2022 20:23:51 +0800 Message-ID: <1647001432-239276-4-git-send-email-john.garry@huawei.com> X-Mailer: git-send-email 2.8.1 In-Reply-To: <1647001432-239276-1-git-send-email-john.garry@huawei.com> References: <1647001432-239276-1-git-send-email-john.garry@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.69.192.58] X-ClientProxiedBy: dggems705-chm.china.huawei.com (10.3.19.182) To lhreml724-chm.china.huawei.com (10.201.108.75) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org New special handling is added for SAS_PROTOCOL_INTERNAL_ABORT proto so that we may use the common queue command API. Signed-off-by: John Garry Tested-by: Damien Le Moal --- drivers/scsi/pm8001/pm8001_hwi.c | 27 +++-- drivers/scsi/pm8001/pm8001_hwi.h | 5 - drivers/scsi/pm8001/pm8001_sas.c | 178 ++++++++++--------------------- drivers/scsi/pm8001/pm8001_sas.h | 6 +- drivers/scsi/pm8001/pm80xx_hwi.h | 5 - 5 files changed, 74 insertions(+), 147 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 048ff41852c9..f7466a895d3b 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -4477,22 +4477,25 @@ pm8001_chip_isr(struct pm8001_hba_info *pm8001_ha, u8 vec) } static int send_task_abort(struct pm8001_hba_info *pm8001_ha, u32 opc, - u32 dev_id, u8 flag, u32 task_tag, u32 cmd_tag) + u32 dev_id, enum sas_internal_abort type, u32 task_tag, u32 cmd_tag) { struct task_abort_req task_abort; memset(&task_abort, 0, sizeof(task_abort)); - if (ABORT_SINGLE == (flag & ABORT_MASK)) { + if (type == SAS_INTERNAL_ABORT_SINGLE) { task_abort.abort_all = 0; task_abort.device_id = cpu_to_le32(dev_id); task_abort.tag_to_abort = cpu_to_le32(task_tag); - task_abort.tag = cpu_to_le32(cmd_tag); - } else if (ABORT_ALL == (flag & ABORT_MASK)) { + } else if (type == SAS_INTERNAL_ABORT_DEV) { task_abort.abort_all = cpu_to_le32(1); task_abort.device_id = cpu_to_le32(dev_id); - task_abort.tag = cpu_to_le32(cmd_tag); + } else { + pm8001_dbg(pm8001_ha, EH, "unknown type (%d)\n", type); + return -EIO; } + task_abort.tag = cpu_to_le32(cmd_tag); + return pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &task_abort, sizeof(task_abort), 0); } @@ -4501,12 +4504,16 @@ static int send_task_abort(struct pm8001_hba_info *pm8001_ha, u32 opc, * pm8001_chip_abort_task - SAS abort task when error or exception happened. */ int pm8001_chip_abort_task(struct pm8001_hba_info *pm8001_ha, - struct pm8001_device *pm8001_dev, u8 flag, u32 task_tag, u32 cmd_tag) + struct pm8001_ccb_info *ccb) { - u32 opc, device_id; + struct sas_task *task = ccb->task; + struct sas_internal_abort_task *abort = &task->abort_task; + struct pm8001_device *pm8001_dev = ccb->device; int rc = TMF_RESP_FUNC_FAILED; + u32 opc, device_id; + pm8001_dbg(pm8001_ha, EH, "cmd_tag = %x, abort task tag = 0x%x\n", - cmd_tag, task_tag); + ccb->ccb_tag, abort->tag); if (pm8001_dev->dev_type == SAS_END_DEVICE) opc = OPC_INB_SSP_ABORT; else if (pm8001_dev->dev_type == SAS_SATA_DEV) @@ -4514,8 +4521,8 @@ int pm8001_chip_abort_task(struct pm8001_hba_info *pm8001_ha, else opc = OPC_INB_SMP_ABORT;/* SMP */ device_id = pm8001_dev->device_id; - rc = send_task_abort(pm8001_ha, opc, device_id, flag, - task_tag, cmd_tag); + rc = send_task_abort(pm8001_ha, opc, device_id, abort->type, + abort->tag, ccb->ccb_tag); if (rc != TMF_RESP_FUNC_COMPLETE) pm8001_dbg(pm8001_ha, EH, "rc= %d\n", rc); return rc; diff --git a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h index d1f3aa93325b..961d0465b923 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.h +++ b/drivers/scsi/pm8001/pm8001_hwi.h @@ -434,11 +434,6 @@ struct task_abort_req { u32 reserved[11]; } __attribute__((packed, aligned(4))); -/* These flags used for SSP SMP & SATA Abort */ -#define ABORT_MASK 0x3 -#define ABORT_SINGLE 0x0 -#define ABORT_ALL 0x1 - /** * brief the data structure of SSP SATA SMP Abort Response * use to describe SSP SMP & SATA Abort Response ( 64 bytes) diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index ac9c40c95070..3a863d776724 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -324,6 +324,18 @@ static int pm8001_task_prep_ata(struct pm8001_hba_info *pm8001_ha, return PM8001_CHIP_DISP->sata_req(pm8001_ha, ccb); } +/** + * pm8001_task_prep_internal_abort - the dispatcher function, prepare data + * for internal abort task + * @pm8001_ha: our hba card information + * @ccb: the ccb which attached to sata task + */ +static int pm8001_task_prep_internal_abort(struct pm8001_hba_info *pm8001_ha, + struct pm8001_ccb_info *ccb) +{ + return PM8001_CHIP_DISP->task_abort(pm8001_ha, ccb); +} + /** * pm8001_task_prep_ssp_tm - the dispatcher function, prepare task management data * @pm8001_ha: our hba card information @@ -367,6 +379,35 @@ static int sas_find_local_port_id(struct domain_device *dev) #define DEV_IS_GONE(pm8001_dev) \ ((!pm8001_dev || (pm8001_dev->dev_type == SAS_PHY_UNUSED))) + +static int pm8001_deliver_command(struct pm8001_hba_info *pm8001_ha, + struct pm8001_ccb_info *ccb) +{ + struct sas_task *task = ccb->task; + enum sas_protocol task_proto = task->task_proto; + struct sas_tmf_task *tmf = task->tmf; + int is_tmf = !!tmf; + + switch (task_proto) { + case SAS_PROTOCOL_SMP: + return pm8001_task_prep_smp(pm8001_ha, ccb); + case SAS_PROTOCOL_SSP: + if (is_tmf) + return pm8001_task_prep_ssp_tm(pm8001_ha, ccb, tmf); + return pm8001_task_prep_ssp(pm8001_ha, ccb); + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: + return pm8001_task_prep_ata(pm8001_ha, ccb); + case SAS_PROTOCOL_INTERNAL_ABORT: + return pm8001_task_prep_internal_abort(pm8001_ha, ccb); + default: + dev_err(pm8001_ha->dev, "unknown sas_task proto: 0x%x\n", + task_proto); + } + + return -EINVAL; +} + /** * pm8001_queue_command - register for upper layer used, all IO commands sent * to HBA are from this interface. @@ -379,16 +420,15 @@ int pm8001_queue_command(struct sas_task *task, gfp_t gfp_flags) enum sas_protocol task_proto = task->task_proto; struct domain_device *dev = task->dev; struct pm8001_device *pm8001_dev = dev->lldd_dev; + bool internal_abort = sas_is_internal_abort(task); struct pm8001_hba_info *pm8001_ha; struct pm8001_port *port = NULL; struct pm8001_ccb_info *ccb; - struct sas_tmf_task *tmf = task->tmf; - int is_tmf = !!task->tmf; unsigned long flags; u32 n_elem = 0; int rc = 0; - if (!dev->port) { + if (!internal_abort && !dev->port) { ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_PHY_DOWN; if (dev->dev_type != SAS_SATA_DEV) @@ -410,7 +450,8 @@ int pm8001_queue_command(struct sas_task *task, gfp_t gfp_flags) pm8001_dev = dev->lldd_dev; port = &pm8001_ha->port[sas_find_local_port_id(dev)]; - if (DEV_IS_GONE(pm8001_dev) || !port->port_attached) { + if (!internal_abort && + (DEV_IS_GONE(pm8001_dev) || !port->port_attached)) { ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_PHY_DOWN; if (sas_protocol_ata(task_proto)) { @@ -448,27 +489,7 @@ int pm8001_queue_command(struct sas_task *task, gfp_t gfp_flags) atomic_inc(&pm8001_dev->running_req); - switch (task_proto) { - case SAS_PROTOCOL_SMP: - rc = pm8001_task_prep_smp(pm8001_ha, ccb); - break; - case SAS_PROTOCOL_SSP: - if (is_tmf) - rc = pm8001_task_prep_ssp_tm(pm8001_ha, ccb, tmf); - else - rc = pm8001_task_prep_ssp(pm8001_ha, ccb); - break; - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - rc = pm8001_task_prep_ata(pm8001_ha, ccb); - break; - default: - dev_printk(KERN_ERR, pm8001_ha->dev, - "unknown sas_task proto: 0x%x\n", task_proto); - rc = -EINVAL; - break; - } - + rc = pm8001_deliver_command(pm8001_ha, ccb); if (rc) { atomic_dec(&pm8001_dev->running_req); if (!sas_protocol_ata(task_proto) && n_elem) @@ -668,87 +689,7 @@ void pm8001_task_done(struct sas_task *task) complete(&task->slow_task->completion); } -static void pm8001_tmf_timedout(struct timer_list *t) -{ - struct sas_task_slow *slow = from_timer(slow, t, timer); - struct sas_task *task = slow->task; - unsigned long flags; - - spin_lock_irqsave(&task->task_state_lock, flags); - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { - task->task_state_flags |= SAS_TASK_STATE_ABORTED; - complete(&task->slow_task->completion); - } - spin_unlock_irqrestore(&task->task_state_lock, flags); -} - #define PM8001_TASK_TIMEOUT 20 -static int -pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha, - struct pm8001_device *pm8001_dev, struct domain_device *dev, u32 flag, - u32 task_tag) -{ - int res, retry; - struct pm8001_ccb_info *ccb; - struct sas_task *task = NULL; - - for (retry = 0; retry < 3; retry++) { - task = sas_alloc_slow_task(GFP_KERNEL); - if (!task) - return -ENOMEM; - - task->dev = dev; - task->task_proto = dev->tproto; - task->task_done = pm8001_task_done; - task->slow_task->timer.function = pm8001_tmf_timedout; - task->slow_task->timer.expires = - jiffies + PM8001_TASK_TIMEOUT * HZ; - add_timer(&task->slow_task->timer); - - ccb = pm8001_ccb_alloc(pm8001_ha, pm8001_dev, task); - if (!ccb) { - res = -SAS_QUEUE_FULL; - break; - } - - res = PM8001_CHIP_DISP->task_abort(pm8001_ha, pm8001_dev, flag, - task_tag, ccb->ccb_tag); - if (res) { - del_timer(&task->slow_task->timer); - pm8001_dbg(pm8001_ha, FAIL, - "Executing internal task failed\n"); - pm8001_ccb_free(pm8001_ha, ccb); - break; - } - - wait_for_completion(&task->slow_task->completion); - res = TMF_RESP_FUNC_FAILED; - - /* Even TMF timed out, return direct. */ - if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { - pm8001_dbg(pm8001_ha, FAIL, "TMF task timeout.\n"); - break; - } - - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAS_SAM_STAT_GOOD) { - res = TMF_RESP_FUNC_COMPLETE; - break; - } - - pm8001_dbg(pm8001_ha, EH, - " Task to dev %016llx response: 0x%x status 0x%x\n", - SAS_ADDR(dev->sas_addr), - task->task_status.resp, - task->task_status.stat); - sas_free_task(task); - task = NULL; - } - - BUG_ON(retry == 3 && task != NULL); - sas_free_task(task); - return res; -} /** * pm8001_dev_gone_notify - see the comments for "pm8001_dev_found_notify" @@ -769,8 +710,7 @@ static void pm8001_dev_gone_notify(struct domain_device *dev) pm8001_dev->device_id, pm8001_dev->dev_type); if (atomic_read(&pm8001_dev->running_req)) { spin_unlock_irqrestore(&pm8001_ha->lock, flags); - pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev, - dev, 1, 0); + sas_execute_internal_abort_dev(dev, 0, NULL); while (atomic_read(&pm8001_dev->running_req)) msleep(20); spin_lock_irqsave(&pm8001_ha->lock, flags); @@ -893,8 +833,7 @@ int pm8001_I_T_nexus_reset(struct domain_device *dev) goto out; } msleep(2000); - rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev, - dev, 1, 0); + rc = sas_execute_internal_abort_dev(dev, 0, NULL); if (rc) { pm8001_dbg(pm8001_ha, EH, "task abort failed %x\n" "with rc %d\n", pm8001_dev->device_id, rc); @@ -939,8 +878,7 @@ int pm8001_I_T_nexus_event_handler(struct domain_device *dev) goto out; } /* send internal ssp/sata/smp abort command to FW */ - rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev, - dev, 1, 0); + sas_execute_internal_abort_dev(dev, 0, NULL); msleep(100); /* deregister the target device */ @@ -955,8 +893,7 @@ int pm8001_I_T_nexus_event_handler(struct domain_device *dev) wait_for_completion(&completion_setstate); } else { /* send internal ssp/sata/smp abort command to FW */ - rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev, - dev, 1, 0); + sas_execute_internal_abort_dev(dev, 0, NULL); msleep(100); /* deregister the target device */ @@ -983,8 +920,7 @@ int pm8001_lu_reset(struct domain_device *dev, u8 *lun) DECLARE_COMPLETION_ONSTACK(completion_setstate); if (dev_is_sata(dev)) { struct sas_phy *phy = sas_get_local_phy(dev); - rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev, - dev, 1, 0); + sas_execute_internal_abort_dev(dev, 0, NULL); rc = sas_phy_reset(phy, 1); sas_put_local_phy(phy); pm8001_dev->setds_completion = &completion_setstate; @@ -1084,8 +1020,7 @@ int pm8001_abort_task(struct sas_task *task) spin_unlock_irqrestore(&task->task_state_lock, flags); if (task->task_proto & SAS_PROTOCOL_SSP) { rc = sas_abort_task(task, tag); - pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev, - pm8001_dev->sas_device, 0, tag); + sas_execute_internal_abort_single(dev, tag, 0, NULL); } else if (task->task_proto & SAS_PROTOCOL_SATA || task->task_proto & SAS_PROTOCOL_STP) { if (pm8001_ha->chip_id == chip_8006) { @@ -1158,8 +1093,7 @@ int pm8001_abort_task(struct sas_task *task) * is removed from the ccb. on success the caller is * going to free the task. */ - ret = pm8001_exec_internal_task_abort(pm8001_ha, - pm8001_dev, pm8001_dev->sas_device, 1, tag); + ret = sas_execute_internal_abort_dev(dev, 0, NULL); if (ret) goto out; ret = wait_for_completion_timeout( @@ -1175,14 +1109,12 @@ int pm8001_abort_task(struct sas_task *task) pm8001_dev, DS_OPERATIONAL); wait_for_completion(&completion); } else { - rc = pm8001_exec_internal_task_abort(pm8001_ha, - pm8001_dev, pm8001_dev->sas_device, 0, tag); + ret = sas_execute_internal_abort_single(dev, tag, 0, NULL); } rc = TMF_RESP_FUNC_COMPLETE; } else if (task->task_proto & SAS_PROTOCOL_SMP) { /* SMP */ - rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev, - pm8001_dev->sas_device, 0, tag); + rc = sas_execute_internal_abort_single(dev, tag, 0, NULL); } out: diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index d522bd0bb46b..060ab680a7ed 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -196,8 +196,7 @@ struct pm8001_dispatch { int (*phy_ctl_req)(struct pm8001_hba_info *pm8001_ha, u32 phy_id, u32 phy_op); int (*task_abort)(struct pm8001_hba_info *pm8001_ha, - struct pm8001_device *pm8001_dev, u8 flag, u32 task_tag, - u32 cmd_tag); + struct pm8001_ccb_info *ccb); int (*ssp_tm_req)(struct pm8001_hba_info *pm8001_ha, struct pm8001_ccb_info *ccb, struct sas_tmf_task *tmf); int (*get_nvmd_req)(struct pm8001_hba_info *pm8001_ha, void *payload); @@ -683,8 +682,7 @@ int pm8001_chip_ssp_tm_req(struct pm8001_hba_info *pm8001_ha, struct pm8001_ccb_info *ccb, struct sas_tmf_task *tmf); int pm8001_chip_abort_task(struct pm8001_hba_info *pm8001_ha, - struct pm8001_device *pm8001_dev, - u8 flag, u32 task_tag, u32 cmd_tag); + struct pm8001_ccb_info *ccb); int pm8001_chip_dereg_dev_req(struct pm8001_hba_info *pm8001_ha, u32 device_id); void pm8001_chip_make_sg(struct scatterlist *scatter, int nr, void *prd); void pm8001_work_fn(struct work_struct *work); diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h index b9d9d113809b..acf6e3005b84 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.h +++ b/drivers/scsi/pm8001/pm80xx_hwi.h @@ -672,11 +672,6 @@ struct task_abort_req { u32 reserved[27]; } __attribute__((packed, aligned(4))); -/* These flags used for SSP SMP & SATA Abort */ -#define ABORT_MASK 0x3 -#define ABORT_SINGLE 0x0 -#define ABORT_ALL 0x1 - /** * brief the data structure of SSP SATA SMP Abort Response * use to describe SSP SMP & SATA Abort Response ( 64 bytes) From patchwork Fri Mar 11 12:23:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Garry X-Patchwork-Id: 550887 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 5DDBBC433EF for ; Fri, 11 Mar 2022 12:30:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348601AbiCKMbC (ORCPT ); Fri, 11 Mar 2022 07:31:02 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38518 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348586AbiCKMbA (ORCPT ); Fri, 11 Mar 2022 07:31:00 -0500 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5D5044A922; Fri, 11 Mar 2022 04:29:56 -0800 (PST) Received: from fraeml735-chm.china.huawei.com (unknown [172.18.147.206]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4KFQFY6pVFz67bXj; Fri, 11 Mar 2022 20:28:17 +0800 (CST) Received: from lhreml724-chm.china.huawei.com (10.201.108.75) by fraeml735-chm.china.huawei.com (10.206.15.216) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2308.21; Fri, 11 Mar 2022 13:29:54 +0100 Received: from localhost.localdomain (10.69.192.58) by lhreml724-chm.china.huawei.com (10.201.108.75) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2308.21; Fri, 11 Mar 2022 12:29:50 +0000 From: John Garry To: , , , CC: , , , , , , , , John Garry Subject: [PATCH v2 4/4] scsi: hisi_sas: Use libsas internal abort support Date: Fri, 11 Mar 2022 20:23:52 +0800 Message-ID: <1647001432-239276-5-git-send-email-john.garry@huawei.com> X-Mailer: git-send-email 2.8.1 In-Reply-To: <1647001432-239276-1-git-send-email-john.garry@huawei.com> References: <1647001432-239276-1-git-send-email-john.garry@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.69.192.58] X-ClientProxiedBy: dggems705-chm.china.huawei.com (10.3.19.182) To lhreml724-chm.china.huawei.com (10.201.108.75) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Use the common libsas internal abort functionality. In addition, this driver has special handling for internal abort timeouts - specifically whether to reset the controller in that instance, so extend the API for that. Timeout is now increased to 20 * Hz from 6 * Hz. We also retry for failure now, but this should not make a difference. Signed-off-by: John Garry Tested-by: Damien Le Moal --- drivers/scsi/hisi_sas/hisi_sas.h | 8 +- drivers/scsi/hisi_sas/hisi_sas_main.c | 453 +++++++++---------------- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 11 +- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 18 +- drivers/scsi/libsas/sas_scsi_host.c | 13 +- include/scsi/libsas.h | 2 + 6 files changed, 183 insertions(+), 322 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 99ceffad4bd9..24c83bc4f5dc 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -133,11 +133,6 @@ struct hisi_sas_rst { bool done; }; -struct hisi_sas_internal_abort { - unsigned int flag; - unsigned int tag; -}; - #define HISI_SAS_RST_WORK_INIT(r, c) \ { .hisi_hba = hisi_hba, \ .completion = &c, \ @@ -325,8 +320,7 @@ struct hisi_sas_hw { void (*prep_stp)(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot); void (*prep_abort)(struct hisi_hba *hisi_hba, - struct hisi_sas_slot *slot, - int device_id, int abort_flag, int tag_to_abort); + struct hisi_sas_slot *slot); void (*phys_init)(struct hisi_hba *hisi_hba); void (*phy_start)(struct hisi_hba *hisi_hba, int phy_no); void (*phy_disable)(struct hisi_hba *hisi_hba, int phy_no); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index cd8ec851e760..461ef8a76c4c 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -10,10 +10,6 @@ #define DEV_IS_GONE(dev) \ ((!dev) || (dev->dev_type == SAS_PHY_UNUSED)) -static int -hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, - struct domain_device *device, - int abort_flag, int tag, bool rst_to_recover); static int hisi_sas_softreset_ata_disk(struct domain_device *device); static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, void *funcdata); @@ -21,6 +17,10 @@ static void hisi_sas_release_task(struct hisi_hba *hisi_hba, struct domain_device *device); static void hisi_sas_dev_gone(struct domain_device *device); +struct hisi_sas_internal_abort_data { + bool rst_ha_timeout; /* reset the HA for timeout */ +}; + u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction) { switch (fis->command) { @@ -263,11 +263,9 @@ static void hisi_sas_task_prep_ata(struct hisi_hba *hisi_hba, } static void hisi_sas_task_prep_abort(struct hisi_hba *hisi_hba, - struct hisi_sas_internal_abort *abort, - struct hisi_sas_slot *slot, int device_id) + struct hisi_sas_slot *slot) { - hisi_hba->hw->prep_abort(hisi_hba, slot, - device_id, abort->flag, abort->tag); + hisi_hba->hw->prep_abort(hisi_hba, slot); } static void hisi_sas_dma_unmap(struct hisi_hba *hisi_hba, @@ -397,8 +395,7 @@ static void hisi_sas_task_deliver(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot, struct hisi_sas_dq *dq, - struct hisi_sas_device *sas_dev, - struct hisi_sas_internal_abort *abort) + struct hisi_sas_device *sas_dev) { struct hisi_sas_cmd_hdr *cmd_hdr_base; int dlvry_queue_slot, dlvry_queue; @@ -439,19 +436,15 @@ void hisi_sas_task_deliver(struct hisi_hba *hisi_hba, break; case SAS_PROTOCOL_SATA: case SAS_PROTOCOL_STP: - case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: + case SAS_PROTOCOL_STP_ALL: hisi_sas_task_prep_ata(hisi_hba, slot); break; - case SAS_PROTOCOL_NONE: - if (abort) { - hisi_sas_task_prep_abort(hisi_hba, abort, slot, sas_dev->device_id); - break; - } + case SAS_PROTOCOL_INTERNAL_ABORT: + hisi_sas_task_prep_abort(hisi_hba, slot); + break; fallthrough; default: - dev_err(hisi_hba->dev, "task prep: unknown/unsupported proto (0x%x)\n", - task->task_proto); - break; + return; } WRITE_ONCE(slot->ready, 1); @@ -467,6 +460,7 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) struct domain_device *device = task->dev; struct asd_sas_port *sas_port = device->port; struct hisi_sas_device *sas_dev = device->lldd_dev; + bool internal_abort = sas_is_internal_abort(task); struct scsi_cmnd *scmd = NULL; struct hisi_sas_dq *dq = NULL; struct hisi_sas_port *port; @@ -484,7 +478,7 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) * libsas will use dev->port, should * not call task_done for sata */ - if (device->dev_type != SAS_SATA_DEV) + if (device->dev_type != SAS_SATA_DEV && !internal_abort) task->task_done(task); return -ECOMM; } @@ -492,59 +486,85 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) hisi_hba = dev_to_hisi_hba(device); dev = hisi_hba->dev; - if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) { - if (!gfpflags_allow_blocking(gfp_flags)) - return -EINVAL; + switch (task->task_proto) { + case SAS_PROTOCOL_SSP: + case SAS_PROTOCOL_SMP: + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: + case SAS_PROTOCOL_STP_ALL: + if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) { + if (!gfpflags_allow_blocking(gfp_flags)) + return -EINVAL; - down(&hisi_hba->sem); - up(&hisi_hba->sem); - } + down(&hisi_hba->sem); + up(&hisi_hba->sem); + } - if (DEV_IS_GONE(sas_dev)) { - if (sas_dev) - dev_info(dev, "task prep: device %d not ready\n", - sas_dev->device_id); - else - dev_info(dev, "task prep: device %016llx not ready\n", - SAS_ADDR(device->sas_addr)); + if (DEV_IS_GONE(sas_dev)) { + if (sas_dev) + dev_info(dev, "task prep: device %d not ready\n", + sas_dev->device_id); + else + dev_info(dev, "task prep: device %016llx not ready\n", + SAS_ADDR(device->sas_addr)); - return -ECOMM; - } + return -ECOMM; + } - if (task->uldd_task) { - struct ata_queued_cmd *qc; + port = to_hisi_sas_port(sas_port); + if (!port->port_attached) { + dev_info(dev, "task prep: %s port%d not attach device\n", + dev_is_sata(device) ? "SATA/STP" : "SAS", + device->port->id); - if (dev_is_sata(device)) { - qc = task->uldd_task; - scmd = qc->scsicmd; - } else { - scmd = task->uldd_task; + return -ECOMM; } - } - if (scmd) { - unsigned int dq_index; - u32 blk_tag; + if (task->uldd_task) { + struct ata_queued_cmd *qc; - blk_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd)); - dq_index = blk_mq_unique_tag_to_hwq(blk_tag); - dq = &hisi_hba->dq[dq_index]; - } else { - struct Scsi_Host *shost = hisi_hba->shost; - struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT]; - int queue = qmap->mq_map[raw_smp_processor_id()]; + if (dev_is_sata(device)) { + qc = task->uldd_task; + scmd = qc->scsicmd; + } else { + scmd = task->uldd_task; + } + } - dq = &hisi_hba->dq[queue]; - } + if (scmd) { + unsigned int dq_index; + u32 blk_tag; - port = to_hisi_sas_port(sas_port); - if (port && !port->port_attached) { - dev_info(dev, "task prep: %s port%d not attach device\n", - (dev_is_sata(device)) ? - "SATA/STP" : "SAS", - device->port->id); + blk_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd)); + dq_index = blk_mq_unique_tag_to_hwq(blk_tag); + dq = &hisi_hba->dq[dq_index]; + } else { + struct Scsi_Host *shost = hisi_hba->shost; + struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT]; + int queue = qmap->mq_map[raw_smp_processor_id()]; - return -ECOMM; + dq = &hisi_hba->dq[queue]; + } + break; + case SAS_PROTOCOL_INTERNAL_ABORT: + if (!hisi_hba->hw->prep_abort) + return TMF_RESP_FUNC_FAILED; + + if (test_bit(HISI_SAS_HW_FAULT_BIT, &hisi_hba->flags)) + return -EIO; + + hisi_hba = dev_to_hisi_hba(device); + + if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) + return -EINVAL; + + port = to_hisi_sas_port(sas_port); + dq = &hisi_hba->dq[task->abort_task.qid]; + break; + default: + dev_err(hisi_hba->dev, "task prep: unknown/unsupported proto (0x%x)\n", + task->task_proto); + return -EINVAL; } rc = hisi_sas_dma_map(hisi_hba, task, &n_elem, @@ -558,7 +578,7 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) goto err_out_dma_unmap; } - if (hisi_hba->hw->slot_index_alloc) + if (!internal_abort && hisi_hba->hw->slot_index_alloc) rc = hisi_hba->hw->slot_index_alloc(hisi_hba, device); else rc = hisi_sas_slot_index_alloc(hisi_hba, scmd); @@ -573,10 +593,10 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) slot->port = port; slot->tmf = task->tmf; - slot->is_internal = task->tmf; + slot->is_internal = !!task->tmf || internal_abort; /* protect task_prep and start_delivery sequence */ - hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, NULL); + hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev); return 0; @@ -1088,6 +1108,29 @@ static void hisi_sas_dereg_device(struct hisi_hba *hisi_hba, hisi_hba->hw->dereg_device(hisi_hba, device); } +static int +hisi_sas_internal_task_abort_dev(struct hisi_sas_device *sas_dev, + bool rst_ha_timeout) +{ + struct hisi_sas_internal_abort_data data = { rst_ha_timeout }; + struct domain_device *device = sas_dev->sas_device; + struct hisi_hba *hisi_hba = sas_dev->hisi_hba; + int i, rc; + + for (i = 0; i < hisi_hba->cq_nvecs; i++) { + struct hisi_sas_cq *cq = &hisi_hba->cq[i]; + const struct cpumask *mask = cq->irq_mask; + + if (mask && !cpumask_intersects(cpu_online_mask, mask)) + continue; + rc = sas_execute_internal_abort_dev(device, i, &data); + if (rc) + return rc; + } + + return 0; +} + static void hisi_sas_dev_gone(struct domain_device *device) { struct hisi_sas_device *sas_dev = device->lldd_dev; @@ -1100,8 +1143,7 @@ static void hisi_sas_dev_gone(struct domain_device *device) down(&hisi_hba->sem); if (!test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) { - hisi_sas_internal_task_abort(hisi_hba, device, - HISI_SAS_INT_ABT_DEV, 0, true); + hisi_sas_internal_task_abort_dev(sas_dev, true); hisi_sas_dereg_device(hisi_hba, device); @@ -1216,32 +1258,6 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, return ret; } -static void hisi_sas_task_done(struct sas_task *task) -{ - del_timer_sync(&task->slow_task->timer); - complete(&task->slow_task->completion); -} - -static void hisi_sas_tmf_timedout(struct timer_list *t) -{ - struct sas_task_slow *slow = from_timer(slow, t, timer); - struct sas_task *task = slow->task; - unsigned long flags; - bool is_completed = true; - - spin_lock_irqsave(&task->task_state_lock, flags); - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { - task->task_state_flags |= SAS_TASK_STATE_ABORTED; - is_completed = false; - } - spin_unlock_irqrestore(&task->task_state_lock, flags); - - if (!is_completed) - complete(&task->slow_task->completion); -} - -#define INTERNAL_ABORT_TIMEOUT (6 * HZ) - static void hisi_sas_fill_ata_reset_cmd(struct ata_device *dev, bool reset, int pmp, u8 *fis) { @@ -1426,9 +1442,7 @@ static void hisi_sas_terminate_stp_reject(struct hisi_hba *hisi_hba) if ((sas_dev->dev_type == SAS_PHY_UNUSED) || !device) continue; - rc = hisi_sas_internal_task_abort(hisi_hba, device, - HISI_SAS_INT_ABT_DEV, 0, - false); + rc = hisi_sas_internal_task_abort_dev(sas_dev, false); if (rc < 0) dev_err(dev, "STP reject: abort dev failed %d\n", rc); } @@ -1536,6 +1550,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) static int hisi_sas_abort_task(struct sas_task *task) { + struct hisi_sas_internal_abort_data internal_abort_data = { false }; struct domain_device *device = task->dev; struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_hba *hisi_hba; @@ -1575,9 +1590,8 @@ static int hisi_sas_abort_task(struct sas_task *task) int rc2; rc = sas_abort_task(task, tag); - rc2 = hisi_sas_internal_task_abort(hisi_hba, device, - HISI_SAS_INT_ABT_CMD, tag, - false); + rc2 = sas_execute_internal_abort_single(device, tag, + slot->dlvry_queue, &internal_abort_data); if (rc2 < 0) { dev_err(dev, "abort task: internal abort (%d)\n", rc2); return TMF_RESP_FUNC_FAILED; @@ -1597,9 +1611,7 @@ static int hisi_sas_abort_task(struct sas_task *task) } else if (task->task_proto & SAS_PROTOCOL_SATA || task->task_proto & SAS_PROTOCOL_STP) { if (task->dev->dev_type == SAS_SATA_DEV) { - rc = hisi_sas_internal_task_abort(hisi_hba, device, - HISI_SAS_INT_ABT_DEV, - 0, false); + rc = hisi_sas_internal_task_abort_dev(sas_dev, false); if (rc < 0) { dev_err(dev, "abort task: internal abort failed\n"); goto out; @@ -1613,9 +1625,9 @@ static int hisi_sas_abort_task(struct sas_task *task) u32 tag = slot->idx; struct hisi_sas_cq *cq = &hisi_hba->cq[slot->dlvry_queue]; - rc = hisi_sas_internal_task_abort(hisi_hba, device, - HISI_SAS_INT_ABT_CMD, tag, - false); + rc = sas_execute_internal_abort_single(device, + tag, slot->dlvry_queue, + &internal_abort_data); if (((rc < 0) || (rc == TMF_RESP_FUNC_FAILED)) && task->lldd_task) { /* @@ -1635,12 +1647,12 @@ static int hisi_sas_abort_task(struct sas_task *task) static int hisi_sas_abort_task_set(struct domain_device *device, u8 *lun) { + struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct device *dev = hisi_hba->dev; int rc; - rc = hisi_sas_internal_task_abort(hisi_hba, device, - HISI_SAS_INT_ABT_DEV, 0, false); + rc = hisi_sas_internal_task_abort_dev(sas_dev, false); if (rc < 0) { dev_err(dev, "abort task set: internal abort rc=%d\n", rc); return TMF_RESP_FUNC_FAILED; @@ -1713,12 +1725,12 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device) static int hisi_sas_I_T_nexus_reset(struct domain_device *device) { + struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct device *dev = hisi_hba->dev; int rc; - rc = hisi_sas_internal_task_abort(hisi_hba, device, - HISI_SAS_INT_ABT_DEV, 0, false); + rc = hisi_sas_internal_task_abort_dev(sas_dev, false); if (rc < 0) { dev_err(dev, "I_T nexus reset: internal abort (%d)\n", rc); return TMF_RESP_FUNC_FAILED; @@ -1766,8 +1778,7 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun) int rc = TMF_RESP_FUNC_FAILED; /* Clear internal IO and then lu reset */ - rc = hisi_sas_internal_task_abort(hisi_hba, device, - HISI_SAS_INT_ABT_DEV, 0, false); + rc = hisi_sas_internal_task_abort_dev(sas_dev, false); if (rc < 0) { dev_err(dev, "lu_reset: internal abort failed\n"); goto out; @@ -1862,203 +1873,48 @@ static int hisi_sas_query_task(struct sas_task *task) return rc; } -static int -hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, - struct hisi_sas_internal_abort *abort, - struct sas_task *task, - struct hisi_sas_dq *dq) +static bool hisi_sas_internal_abort_timeout(struct sas_task *task, + void *data) { struct domain_device *device = task->dev; - struct hisi_sas_device *sas_dev = device->lldd_dev; - struct device *dev = hisi_hba->dev; - struct hisi_sas_port *port; - struct asd_sas_port *sas_port = device->port; - struct hisi_sas_slot *slot; - int slot_idx; - - if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) - return -EINVAL; - - if (!device->port) - return -1; - - port = to_hisi_sas_port(sas_port); - - /* simply get a slot and send abort command */ - slot_idx = hisi_sas_slot_index_alloc(hisi_hba, NULL); - if (slot_idx < 0) - goto err_out; - - slot = &hisi_hba->slot_info[slot_idx]; - slot->n_elem = 0; - slot->task = task; - slot->port = port; - slot->is_internal = true; - - hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, abort); - - return 0; - -err_out: - dev_err(dev, "internal abort task prep: failed[%d]!\n", slot_idx); - - return slot_idx; -} - -/** - * _hisi_sas_internal_task_abort -- execute an internal - * abort command for single IO command or a device - * @hisi_hba: host controller struct - * @device: domain device - * @abort_flag: mode of operation, device or single IO - * @tag: tag of IO to be aborted (only relevant to single - * IO mode) - * @dq: delivery queue for this internal abort command - * @rst_to_recover: If rst_to_recover set, queue a controller - * reset if an internal abort times out. - */ -static int -_hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, - struct domain_device *device, int abort_flag, - int tag, struct hisi_sas_dq *dq, bool rst_to_recover) -{ - struct sas_task *task; - struct hisi_sas_device *sas_dev = device->lldd_dev; - struct hisi_sas_internal_abort abort = { - .flag = abort_flag, - .tag = tag, - }; - struct device *dev = hisi_hba->dev; - int res; - /* - * The interface is not realized means this HW don't support internal - * abort, or don't need to do internal abort. Then here, we return - * TMF_RESP_FUNC_FAILED and let other steps go on, which depends that - * the internal abort has been executed and returned CQ. - */ - if (!hisi_hba->hw->prep_abort) - return TMF_RESP_FUNC_FAILED; - - if (test_bit(HISI_SAS_HW_FAULT_BIT, &hisi_hba->flags)) - return -EIO; - - task = sas_alloc_slow_task(GFP_KERNEL); - if (!task) - return -ENOMEM; - - task->dev = device; - task->task_proto = SAS_PROTOCOL_NONE; - task->task_done = hisi_sas_task_done; - task->slow_task->timer.function = hisi_sas_tmf_timedout; - task->slow_task->timer.expires = jiffies + INTERNAL_ABORT_TIMEOUT; - add_timer(&task->slow_task->timer); - - res = hisi_sas_internal_abort_task_exec(hisi_hba, sas_dev->device_id, - &abort, task, dq); - if (res) { - del_timer_sync(&task->slow_task->timer); - dev_err(dev, "internal task abort: executing internal task failed: %d\n", - res); - goto exit; - } - wait_for_completion(&task->slow_task->completion); - res = TMF_RESP_FUNC_FAILED; - - /* Internal abort timed out */ - if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { - if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct) - queue_work(hisi_hba->wq, &hisi_hba->debugfs_work); - - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { - struct hisi_sas_slot *slot = task->lldd_task; - - set_bit(HISI_SAS_HW_FAULT_BIT, &hisi_hba->flags); - - if (slot) { - struct hisi_sas_cq *cq = - &hisi_hba->cq[slot->dlvry_queue]; - /* - * sync irq to avoid free'ing task - * before using task in IO completion - */ - synchronize_irq(cq->irq_no); - slot->task = NULL; - } - - if (rst_to_recover) { - dev_err(dev, "internal task abort: timeout and not done. Queuing reset.\n"); - queue_work(hisi_hba->wq, &hisi_hba->rst_work); - } else { - dev_err(dev, "internal task abort: timeout and not done.\n"); - } - - res = -EIO; - goto exit; - } else - dev_err(dev, "internal task abort: timeout.\n"); - } - - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == TMF_RESP_FUNC_COMPLETE) { - res = TMF_RESP_FUNC_COMPLETE; - goto exit; - } + struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); + struct hisi_sas_internal_abort_data *timeout = data; - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == TMF_RESP_FUNC_SUCC) { - res = TMF_RESP_FUNC_SUCC; - goto exit; - } + if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct) + queue_work(hisi_hba->wq, &hisi_hba->debugfs_work); -exit: - dev_dbg(dev, "internal task abort: task to dev %016llx task=%pK resp: 0x%x sts 0x%x\n", - SAS_ADDR(device->sas_addr), task, - task->task_status.resp, /* 0 is complete, -1 is undelivered */ - task->task_status.stat); - sas_free_task(task); + if (task->task_state_flags & SAS_TASK_STATE_DONE) { + pr_err("Internal abort: timeout %016llx\n", + SAS_ADDR(device->sas_addr)); + } else { + struct hisi_sas_slot *slot = task->lldd_task; - return res; -} + set_bit(HISI_SAS_HW_FAULT_BIT, &hisi_hba->flags); -static int -hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, - struct domain_device *device, - int abort_flag, int tag, bool rst_to_recover) -{ - struct hisi_sas_slot *slot; - struct device *dev = hisi_hba->dev; - struct hisi_sas_dq *dq; - int i, rc; + if (slot) { + struct hisi_sas_cq *cq = + &hisi_hba->cq[slot->dlvry_queue]; + /* + * sync irq to avoid free'ing task + * before using task in IO completion + */ + synchronize_irq(cq->irq_no); + slot->task = NULL; + } - switch (abort_flag) { - case HISI_SAS_INT_ABT_CMD: - slot = &hisi_hba->slot_info[tag]; - dq = &hisi_hba->dq[slot->dlvry_queue]; - return _hisi_sas_internal_task_abort(hisi_hba, device, - abort_flag, tag, dq, - rst_to_recover); - case HISI_SAS_INT_ABT_DEV: - for (i = 0; i < hisi_hba->cq_nvecs; i++) { - struct hisi_sas_cq *cq = &hisi_hba->cq[i]; - const struct cpumask *mask = cq->irq_mask; - - if (mask && !cpumask_intersects(cpu_online_mask, mask)) - continue; - dq = &hisi_hba->dq[i]; - rc = _hisi_sas_internal_task_abort(hisi_hba, device, - abort_flag, tag, - dq, rst_to_recover); - if (rc) - return rc; + if (timeout->rst_ha_timeout) { + pr_err("Internal abort: timeout and not done %016llx. Queuing reset.\n", + SAS_ADDR(device->sas_addr)); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); + } else { + pr_err("Internal abort: timeout and not done %016llx.\n", + SAS_ADDR(device->sas_addr)); } - break; - default: - dev_err(dev, "Unrecognised internal abort flag (%d)\n", - abort_flag); - return -EINVAL; + + return true; } - return 0; + return false; } static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy) @@ -2176,6 +2032,7 @@ static struct sas_domain_function_template hisi_sas_transport_ops = { .lldd_port_formed = hisi_sas_port_formed, .lldd_write_gpio = hisi_sas_write_gpio, .lldd_tmf_aborted = hisi_sas_tmf_aborted, + .lldd_abort_timeout = hisi_sas_internal_abort_timeout, }; void hisi_sas_init_mem(struct hisi_hba *hisi_hba) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 441ac4b6f1f4..455d49299ddf 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2603,14 +2603,15 @@ static void hisi_sas_internal_abort_quirk_timeout(struct timer_list *t) } static void prep_abort_v2_hw(struct hisi_hba *hisi_hba, - struct hisi_sas_slot *slot, - int device_id, int abort_flag, int tag_to_abort) + struct hisi_sas_slot *slot) { struct sas_task *task = slot->task; + struct sas_internal_abort_task *abort = &task->abort_task; struct domain_device *dev = task->dev; struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; struct hisi_sas_port *port = slot->port; struct timer_list *timer = &slot->internal_abort_timer; + struct hisi_sas_device *sas_dev = dev->lldd_dev; /* setup the quirk timer */ timer_setup(timer, hisi_sas_internal_abort_quirk_timeout, 0); @@ -2622,13 +2623,13 @@ static void prep_abort_v2_hw(struct hisi_hba *hisi_hba, (port->id << CMD_HDR_PORT_OFF) | (dev_is_sata(dev) << CMD_HDR_ABORT_DEVICE_TYPE_OFF) | - (abort_flag << CMD_HDR_ABORT_FLAG_OFF)); + (abort->type << CMD_HDR_ABORT_FLAG_OFF)); /* dw1 */ - hdr->dw1 = cpu_to_le32(device_id << CMD_HDR_DEV_ID_OFF); + hdr->dw1 = cpu_to_le32(sas_dev->device_id << CMD_HDR_DEV_ID_OFF); /* dw7 */ - hdr->dw7 = cpu_to_le32(tag_to_abort << CMD_HDR_ABORT_IPTT_OFF); + hdr->dw7 = cpu_to_le32(abort->tag << CMD_HDR_ABORT_IPTT_OFF); hdr->transfer_tags = cpu_to_le32(slot->idx); } diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 914ae4e82f5e..79f87d7c3e68 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -1452,28 +1452,28 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba, } static void prep_abort_v3_hw(struct hisi_hba *hisi_hba, - struct hisi_sas_slot *slot, - int device_id, int abort_flag, int tag_to_abort) + struct hisi_sas_slot *slot) { struct sas_task *task = slot->task; + struct sas_internal_abort_task *abort = &task->abort_task; struct domain_device *dev = task->dev; struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; struct hisi_sas_port *port = slot->port; + struct hisi_sas_device *sas_dev = dev->lldd_dev; + bool sata = dev_is_sata(dev); /* dw0 */ - hdr->dw0 = cpu_to_le32((5U << CMD_HDR_CMD_OFF) | /*abort*/ + hdr->dw0 = cpu_to_le32((5U << CMD_HDR_CMD_OFF) | /* abort */ (port->id << CMD_HDR_PORT_OFF) | - (dev_is_sata(dev) - << CMD_HDR_ABORT_DEVICE_TYPE_OFF) | - (abort_flag - << CMD_HDR_ABORT_FLAG_OFF)); + (sata << CMD_HDR_ABORT_DEVICE_TYPE_OFF) | + (abort->type << CMD_HDR_ABORT_FLAG_OFF)); /* dw1 */ - hdr->dw1 = cpu_to_le32(device_id + hdr->dw1 = cpu_to_le32(sas_dev->device_id << CMD_HDR_DEV_ID_OFF); /* dw7 */ - hdr->dw7 = cpu_to_le32(tag_to_abort << CMD_HDR_ABORT_IPTT_OFF); + hdr->dw7 = cpu_to_le32(abort->tag << CMD_HDR_ABORT_IPTT_OFF); hdr->transfer_tags = cpu_to_le32(slot->idx); } diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 13142ec97f1d..9c82e5dc4fcc 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -943,6 +943,7 @@ static int sas_execute_internal_abort(struct domain_device *device, task->abort_task.tag = tag; task->abort_task.type = type; + task->abort_task.qid = qid; res = i->dft->lldd_execute_task(task, GFP_KERNEL); if (res) { @@ -957,10 +958,16 @@ static int sas_execute_internal_abort(struct domain_device *device, /* Even if the internal abort timed out, return direct. */ if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { - pr_err("Internal abort: timeout %016llx\n", - SAS_ADDR(device->sas_addr)); + bool quit = true; + + if (i->dft->lldd_abort_timeout) + quit = i->dft->lldd_abort_timeout(task, data); + else + pr_err("Internal abort: timeout %016llx\n", + SAS_ADDR(device->sas_addr)); res = -EIO; - break; + if (quit) + break; } if (task->task_status.resp == SAS_TASK_COMPLETE && diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 71f632b2d2bd..ff04eb6d250b 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -565,6 +565,7 @@ enum sas_internal_abort { struct sas_internal_abort_task { enum sas_internal_abort type; + unsigned int qid; u16 tag; }; @@ -671,6 +672,7 @@ struct sas_domain_function_template { /* Special TMF callbacks */ void (*lldd_tmf_exec_complete)(struct domain_device *dev); void (*lldd_tmf_aborted)(struct sas_task *task); + bool (*lldd_abort_timeout)(struct sas_task *task, void *data); /* Port and Adapter management */ int (*lldd_clear_nexus_port)(struct asd_sas_port *);