scsi: libsas: Add sas_execute_ata_cmd()
authorJohn Garry <john.garry@huawei.com>
Tue, 22 Feb 2022 12:50:59 +0000 (20:50 +0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 23 Feb 2022 02:11:02 +0000 (21:11 -0500)
Add a function to execute an ATA command using the TMF code, and use in the
hisi_sas driver. That driver needs to be able to issue the command on a
specific phy, so add an interface for that.

With that, hisi_sas_exec_internal_tmf_task() may be deleted.

Link: https://lore.kernel.org/r/1645534259-27068-19-git-send-email-john.garry@huawei.com
Tested-by: Yihang Li <liyihang6@hisilicon.com>
Tested-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/hisi_sas/hisi_sas_main.c
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
drivers/scsi/libsas/sas_ata.c
drivers/scsi/libsas/sas_scsi_host.c
include/scsi/libsas.h
include/scsi/sas_ata.h

index 34ed4f8..efedfb3 100644 (file)
@@ -1239,124 +1239,7 @@ static void hisi_sas_tmf_timedout(struct timer_list *t)
                complete(&task->slow_task->completion);
 }
 
-#define TASK_TIMEOUT                   (20 * HZ)
-#define TASK_RETRY                     3
 #define INTERNAL_ABORT_TIMEOUT         (6 * HZ)
-static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
-                                          void *parameter, u32 para_len,
-                                          struct sas_tmf_task *tmf)
-{
-       struct hisi_sas_device *sas_dev = device->lldd_dev;
-       struct hisi_hba *hisi_hba = sas_dev->hisi_hba;
-       struct device *dev = hisi_hba->dev;
-       struct sas_task *task;
-       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 = device->tproto;
-
-               if (dev_is_sata(device)) {
-                       task->ata_task.device_control_reg_update = 1;
-                       memcpy(&task->ata_task.fis, parameter, para_len);
-               } else {
-                       memcpy(&task->ssp_task, parameter, para_len);
-               }
-               task->task_done = hisi_sas_task_done;
-
-               task->slow_task->timer.function = hisi_sas_tmf_timedout;
-               task->slow_task->timer.expires = jiffies + TASK_TIMEOUT;
-               add_timer(&task->slow_task->timer);
-
-               task->tmf = tmf;
-
-               res = hisi_sas_queue_command(task, GFP_KERNEL);
-               if (res) {
-                       del_timer_sync(&task->slow_task->timer);
-                       dev_err(dev, "abort tmf: executing internal task failed: %d\n",
-                               res);
-                       goto ex_err;
-               }
-
-               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)) {
-                       if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
-                               struct hisi_sas_slot *slot = task->lldd_task;
-
-                               dev_err(dev, "abort tmf: TMF task timeout and not done\n");
-                               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;
-                               }
-
-                               goto ex_err;
-                       } else
-                               dev_err(dev, "abort tmf: TMF task timeout\n");
-               }
-
-               if (task->task_status.resp == SAS_TASK_COMPLETE &&
-                    task->task_status.stat == TMF_RESP_FUNC_COMPLETE) {
-                       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;
-               }
-
-               if (task->task_status.resp == SAS_TASK_COMPLETE &&
-                     task->task_status.stat == SAS_DATA_UNDERRUN) {
-                       /* no error, but return the number of bytes of
-                        * underrun
-                        */
-                       dev_warn(dev, "abort tmf: task to dev %016llx resp: 0x%x sts 0x%x underrun\n",
-                                SAS_ADDR(device->sas_addr),
-                                task->task_status.resp,
-                                task->task_status.stat);
-                       res = task->task_status.residual;
-                       break;
-               }
-
-               if (task->task_status.resp == SAS_TASK_COMPLETE &&
-                       task->task_status.stat == SAS_DATA_OVERRUN) {
-                       dev_warn(dev, "abort tmf: blocked task error\n");
-                       res = -EMSGSIZE;
-                       break;
-               }
-
-               if (task->task_status.resp == SAS_TASK_COMPLETE &&
-                   task->task_status.stat == SAS_OPEN_REJECT) {
-                       dev_warn(dev, "abort tmf: open reject failed\n");
-                       res = -EIO;
-               } else {
-                       dev_warn(dev, "abort tmf: task to dev %016llx resp: 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;
-       }
-ex_err:
-       if (retry == TASK_RETRY)
-               dev_warn(dev, "abort tmf: executing internal task failed!\n");
-       sas_free_task(task);
-       return res;
-}
 
 static void hisi_sas_fill_ata_reset_cmd(struct ata_device *dev,
                bool reset, int pmp, u8 *fis)
@@ -1380,14 +1263,12 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device)
        int rc = TMF_RESP_FUNC_FAILED;
        struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
        struct device *dev = hisi_hba->dev;
-       int s = sizeof(struct host_to_dev_fis);
-       struct sas_tmf_task tmf = {};
 
        ata_for_each_link(link, ap, EDGE) {
                int pmp = sata_srst_pmp(link);
 
                hisi_sas_fill_ata_reset_cmd(link->device, 1, pmp, fis);
-               rc = hisi_sas_exec_internal_tmf_task(device, fis, s, &tmf);
+               rc = sas_execute_ata_cmd(device, fis, -1);
                if (rc != TMF_RESP_FUNC_COMPLETE)
                        break;
        }
@@ -1397,8 +1278,7 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device)
                        int pmp = sata_srst_pmp(link);
 
                        hisi_sas_fill_ata_reset_cmd(link->device, 0, pmp, fis);
-                       rc = hisi_sas_exec_internal_tmf_task(device, fis,
-                                                            s, &tmf);
+                       rc = sas_execute_ata_cmd(device, fis, -1);
                        if (rc != TMF_RESP_FUNC_COMPLETE)
                                dev_err(dev, "ata disk %016llx de-reset failed\n",
                                        SAS_ADDR(device->sas_addr));
@@ -1508,10 +1388,8 @@ static void hisi_sas_send_ata_reset_each_phy(struct hisi_hba *hisi_hba,
                                             struct asd_sas_port *sas_port,
                                             struct domain_device *device)
 {
-       struct sas_tmf_task tmf_task = { .force_phy = 1 };
        struct ata_port *ap = device->sata_dev.ap;
        struct device *dev = hisi_hba->dev;
-       int s = sizeof(struct host_to_dev_fis);
        int rc = TMF_RESP_FUNC_FAILED;
        struct ata_link *link;
        u8 fis[20] = {0};
@@ -1524,10 +1402,8 @@ static void hisi_sas_send_ata_reset_each_phy(struct hisi_hba *hisi_hba,
                ata_for_each_link(link, ap, EDGE) {
                        int pmp = sata_srst_pmp(link);
 
-                       tmf_task.phy_id = i;
                        hisi_sas_fill_ata_reset_cmd(link->device, 1, pmp, fis);
-                       rc = hisi_sas_exec_internal_tmf_task(device, fis, s,
-                                                            &tmf_task);
+                       rc = sas_execute_ata_cmd(device, fis, i);
                        if (rc != TMF_RESP_FUNC_COMPLETE) {
                                dev_err(dev, "phy%d ata reset failed rc=%d\n",
                                        i, rc);
index 5bab51d..441ac4b 100644 (file)
@@ -2491,6 +2491,7 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba,
        struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
        struct asd_sas_port *sas_port = device->port;
        struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
+       struct sas_ata_task *ata_task = &task->ata_task;
        struct sas_tmf_task *tmf = slot->tmf;
        u8 *buf_cmd;
        int has_data = 0, hdr_tag = 0;
@@ -2504,9 +2505,9 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba,
        else
                dw0 |= 4 << CMD_HDR_CMD_OFF;
 
-       if (tmf && tmf->force_phy) {
+       if (tmf && ata_task->force_phy) {
                dw0 |= CMD_HDR_FORCE_PHY_MSK;
-               dw0 |= (1 << tmf->phy_id) << CMD_HDR_PHY_ID_OFF;
+               dw0 |= (1 << ata_task->force_phy_id) << CMD_HDR_PHY_ID_OFF;
        }
 
        hdr->dw0 = cpu_to_le32(dw0);
index 71b42fe..d89ffb3 100644 (file)
@@ -852,3 +852,11 @@ void sas_ata_wait_eh(struct domain_device *dev)
        ap = dev->sata_dev.ap;
        ata_port_wait_eh(ap);
 }
+
+int sas_execute_ata_cmd(struct domain_device *device, u8 *fis, int force_phy_id)
+{
+       struct sas_tmf_task tmf_task = {};
+       return sas_execute_tmf(device, fis, sizeof(struct host_to_dev_fis),
+                              force_phy_id, &tmf_task);
+}
+EXPORT_SYMBOL_GPL(sas_execute_ata_cmd);
index 87dd18a..5b5747e 100644 (file)
@@ -937,8 +937,16 @@ int sas_execute_tmf(struct domain_device *device, void *parameter,
                task->dev = device;
                task->task_proto = device->tproto;
 
-               if (!dev_is_sata(device))
+               if (dev_is_sata(device)) {
+                       task->ata_task.device_control_reg_update = 1;
+                       if (force_phy_id >= 0) {
+                               task->ata_task.force_phy = true;
+                               task->ata_task.force_phy_id = force_phy_id;
+                       }
+                       memcpy(&task->ata_task.fis, parameter, para_len);
+               } else {
                        memcpy(&task->ssp_task, parameter, para_len);
+               }
 
                task->task_done = sas_task_internal_done;
                task->tmf = tmf;
index 4ea964d..dc529cc 100644 (file)
@@ -552,6 +552,9 @@ struct sas_ata_task {
        u8     stp_affil_pol:1;
 
        u8     device_control_reg_update:1;
+
+       bool   force_phy;
+       int    force_phy_id;
 };
 
 struct sas_smp_task {
@@ -579,10 +582,6 @@ struct sas_ssp_task {
 struct sas_tmf_task {
        u8 tmf;
        u16 tag_of_task_to_be_managed;
-
-       /* Temp */
-       int force_phy;
-       int phy_id;
 };
 
 struct sas_task {
index 21e7c10..d47dea7 100644 (file)
@@ -32,6 +32,8 @@ void sas_probe_sata(struct asd_sas_port *port);
 void sas_suspend_sata(struct asd_sas_port *port);
 void sas_resume_sata(struct asd_sas_port *port);
 void sas_ata_end_eh(struct ata_port *ap);
+int sas_execute_ata_cmd(struct domain_device *device, u8 *fis,
+                       int force_phy_id);
 #else
 
 
@@ -83,6 +85,12 @@ static inline int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy
 static inline void sas_ata_end_eh(struct ata_port *ap)
 {
 }
+
+static inline int sas_execute_ata_cmd(struct domain_device *device, u8 *fis,
+                                     int force_phy_id)
+{
+       return 0;
+}
 #endif
 
 #endif /* _SAS_ATA_H_ */