]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
scsi: pm80xx: Improve debugging for aborted commands
authorVishakha Channapattan <vishakhavc@google.com>
Tue, 26 Nov 2024 22:55:46 +0000 (22:55 +0000)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 4 Dec 2024 19:50:50 +0000 (14:50 -0500)
Improves the debugging capabilities of the driver by adding more context to
debug messages:

 1. Introduce a new function to show pending commands.

 2. Include the tag number in NCQ EH path debug messages.

 3. Add logging for ata_tag along with pm80xx tag to map I/Os aborted with
    ATA logs.

Signed-off-by: Vishakha Channapattan <vishakhavc@google.com>
Signed-off-by: Salomon Dushimirimana <salomondush@google.com>
Link: https://lore.kernel.org/r/20241126225546.975441-1-salomondush@google.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/pm8001/pm8001_hwi.c
drivers/scsi/pm8001/pm8001_sas.c
drivers/scsi/pm8001/pm8001_sas.h
drivers/scsi/pm8001/pm80xx_hwi.c

index dec1e2d380f171c2d61d399bc2de21ac5075dcbc..42a4eeac24c941c4477cd8799dd0641cc28ee0df 100644 (file)
@@ -3472,12 +3472,13 @@ int pm8001_mpi_task_abort_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
                           status, tag, scp);
        switch (status) {
        case IO_SUCCESS:
-               pm8001_dbg(pm8001_ha, EH, "IO_SUCCESS\n");
+               pm8001_dbg(pm8001_ha, FAIL, "ABORT IO_SUCCESS for tag %#x\n",
+                          tag);
                ts->resp = SAS_TASK_COMPLETE;
                ts->stat = SAS_SAM_STAT_GOOD;
                break;
        case IO_NOT_VALID:
-               pm8001_dbg(pm8001_ha, EH, "IO_NOT_VALID\n");
+               pm8001_dbg(pm8001_ha, FAIL, "IO_NOT_VALID for tag %#x\n", tag);
                ts->resp = TMF_RESP_FUNC_FAILED;
                break;
        }
index a5b72c03b6a859da4593934b04f89c9cd8eb2678..183ce00aa671eace46dbdc5ef202601c9b7413d3 100644 (file)
@@ -101,6 +101,63 @@ int pm8001_tag_alloc(struct pm8001_hba_info *pm8001_ha, u32 *tag_out)
        return 0;
 }
 
+static void pm80xx_get_tag_opcodes(struct sas_task *task, int *ata_op,
+                                                                  int *ata_tag, bool *task_aborted)
+{
+       unsigned long flags;
+       struct ata_queued_cmd *qc = NULL;
+
+       *ata_op = 0;
+       *ata_tag = -1;
+       *task_aborted = false;
+
+       if (!task)
+               return;
+
+       spin_lock_irqsave(&task->task_state_lock, flags);
+       if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED)))
+               *task_aborted = true;
+       spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+       if (task->task_proto == SAS_PROTOCOL_STP) {
+               // sas_ata_qc_issue path uses SAS_PROTOCOL_STP.
+               // This only works for scsi + libsas + libata users.
+               qc = task->uldd_task;
+               if (qc) {
+                       *ata_op = qc->tf.command;
+                       *ata_tag = qc->tag;
+               }
+       }
+}
+
+void pm80xx_show_pending_commands(struct pm8001_hba_info *pm8001_ha,
+                                 struct pm8001_device *target_pm8001_dev)
+{
+       int i = 0, ata_op = 0, ata_tag = -1;
+       struct pm8001_ccb_info *ccb = NULL;
+       struct sas_task *task = NULL;
+       struct pm8001_device *pm8001_dev = NULL;
+       bool task_aborted;
+
+       for (i = 0; i < pm8001_ha->ccb_count; i++) {
+               ccb = &pm8001_ha->ccb_info[i];
+               if (ccb->ccb_tag == PM8001_INVALID_TAG)
+                       continue;
+               pm8001_dev = ccb->device;
+               if (target_pm8001_dev && pm8001_dev &&
+                   target_pm8001_dev != pm8001_dev)
+                       continue;
+               task = ccb->task;
+               pm80xx_get_tag_opcodes(task, &ata_op, &ata_tag, &task_aborted);
+               pm8001_dbg(pm8001_ha, FAIL,
+                       "tag %#x, device %#x task %p task aborted %d ata opcode %#x ata tag %d\n",
+                       ccb->ccb_tag,
+                       (pm8001_dev ? pm8001_dev->device_id : 0),
+                       task, task_aborted,
+                       ata_op, ata_tag);
+       }
+}
+
 /**
  * pm8001_mem_alloc - allocate memory for pm8001.
  * @pdev: pci device.
index 42c7b3f7afbf1bfcdf89ae46a2cb6a93674122aa..a349cf50770c2ca6bb7a2a42608615fa5ae5c182 100644 (file)
@@ -787,6 +787,8 @@ static inline void pm8001_ccb_task_free_done(struct pm8001_hba_info *pm8001_ha,
 }
 void pm8001_setds_completion(struct domain_device *dev);
 void pm8001_tmf_aborted(struct sas_task *task);
+void pm80xx_show_pending_commands(struct pm8001_hba_info *pm8001_ha,
+                                 struct pm8001_device *dev);
 
 #endif
 
index 898eb0549ee98843da6169f24b3f80e7abc81c6c..5b373c53c0369e7a83e057e316da475551d46fb6 100644 (file)
@@ -2246,7 +2246,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha,
        u32 param;
        u32 status;
        u32 tag;
-       int i, j;
+       int i, j, ata_tag = -1;
        u8 sata_addr_low[4];
        u32 temp_sata_addr_low, temp_sata_addr_hi;
        u8 sata_addr_hi[4];
@@ -2256,6 +2256,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha,
        u32 *sata_resp;
        struct pm8001_device *pm8001_dev;
        unsigned long flags;
+       struct ata_queued_cmd *qc;
 
        psataPayload = (struct sata_completion_resp *)(piomb + 4);
        status = le32_to_cpu(psataPayload->status);
@@ -2267,8 +2268,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha,
        pm8001_dev = ccb->device;
 
        if (t) {
-               if (t->dev && (t->dev->lldd_dev))
+               if (t->dev && (t->dev->lldd_dev)) {
                        pm8001_dev = t->dev->lldd_dev;
+                       qc = t->uldd_task;
+                       ata_tag = qc ? qc->tag : -1;
+               }
        } else {
                pm8001_dbg(pm8001_ha, FAIL, "task null, freeing CCB tag %d\n",
                           ccb->ccb_tag);
@@ -2276,16 +2280,14 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha,
                return;
        }
 
-
        if (pm8001_dev && unlikely(!t->lldd_task || !t->dev))
                return;
 
        ts = &t->task_status;
-
        if (status != IO_SUCCESS) {
                pm8001_dbg(pm8001_ha, FAIL,
-                       "IO failed device_id %u status 0x%x tag %d\n",
-                       pm8001_dev->device_id, status, tag);
+                       "IO failed status %#x pm80xx tag %#x ata tag %d\n",
+                       status, tag, ata_tag);
        }
 
        /* Print sas address of IO failed device */
@@ -2667,13 +2669,19 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha,
 
        /* Check if this is NCQ error */
        if (event == IO_XFER_ERROR_ABORTED_NCQ_MODE) {
+               /* tag value is invalid with this event */
+               pm8001_dbg(pm8001_ha, FAIL, "NCQ ERROR for device %#x tag %#x\n",
+                       dev_id, tag);
+
                /* find device using device id */
                pm8001_dev = pm8001_find_dev(pm8001_ha, dev_id);
                /* send read log extension by aborting the link - libata does what we want */
-               if (pm8001_dev)
+               if (pm8001_dev) {
+                       pm80xx_show_pending_commands(pm8001_ha, pm8001_dev);
                        pm8001_handle_event(pm8001_ha,
                                pm8001_dev,
                                IO_XFER_ERROR_ABORTED_NCQ_MODE);
+               }
                return;
        }