1)Manufacturing Page 11 contains parameters to control
internal firmware behavior. Based on AddlFlags2 field
FW/Driver behaviour can be changed, (flag tm_custom_handling
is used for this)

a) For PCIe device, protocol level reset should be used if
flag tm_custom_handling is 0.
Since Abort Task Set, LUN reset and Target reset will result
in a protocol level reset. Drivers should issue only one type
of this reset, if that fails then it should escalate to a controller
reset (diag reset/OCR).
b) If the driver has control over the TM reset timeout value, then
driver should use the value exposed in PCIe Device Page 2 for pcie device
(field ControllerResetTO).

Signed-off-by: Chaitra P B <chaitra.basa...@broadcom.com>
Signed-off-by: Suganath Prabu S <suganath-prabu.subram...@broadcom.com>
---
 drivers/scsi/mpt3sas/mpt3sas_base.c  | 13 ++++++
 drivers/scsi/mpt3sas/mpt3sas_base.h  | 26 ++++++++++--
 drivers/scsi/mpt3sas/mpt3sas_ctl.c   | 22 +++++++++--
 drivers/scsi/mpt3sas/mpt3sas_scsih.c | 76 ++++++++++++++++++++++++++++++------
 4 files changed, 116 insertions(+), 21 deletions(-)

diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c 
b/drivers/scsi/mpt3sas/mpt3sas_base.c
index febd858..600c717 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -4139,6 +4139,7 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc)
        Mpi2ConfigReply_t mpi_reply;
        u32 iounit_pg1_flags;
 
+       ioc->nvme_abort_timeout = 30;
        mpt3sas_config_get_manufacturing_pg0(ioc, &mpi_reply, &ioc->manu_pg0);
        if (ioc->ir_firmware)
                mpt3sas_config_get_manufacturing_pg10(ioc, &mpi_reply,
@@ -4157,6 +4158,18 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc)
                mpt3sas_config_set_manufacturing_pg11(ioc, &mpi_reply,
                    &ioc->manu_pg11);
        }
+       if (ioc->manu_pg11.AddlFlags2 & NVME_TASK_MNGT_CUSTOM_MASK)
+               ioc->tm_custom_handling = 1;
+       else {
+               ioc->tm_custom_handling = 0;
+               if (ioc->manu_pg11.NVMeAbortTO < NVME_TASK_ABORT_MIN_TIMEOUT)
+                       ioc->nvme_abort_timeout = NVME_TASK_ABORT_MIN_TIMEOUT;
+               else if (ioc->manu_pg11.NVMeAbortTO >
+                                       NVME_TASK_ABORT_MAX_TIMEOUT)
+                       ioc->nvme_abort_timeout = NVME_TASK_ABORT_MAX_TIMEOUT;
+               else
+                       ioc->nvme_abort_timeout = ioc->manu_pg11.NVMeAbortTO;
+       }
 
        mpt3sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2);
        mpt3sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h 
b/drivers/scsi/mpt3sas/mpt3sas_base.h
index 49333b9..43d66c5 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
@@ -146,8 +146,12 @@
 #define        NVME_CMD_PRP1_OFFSET            24      /* PRP1 offset in NVMe 
cmd */
 #define        NVME_CMD_PRP2_OFFSET            32      /* PRP2 offset in NVMe 
cmd */
 #define        NVME_ERROR_RESPONSE_SIZE        16      /* Max NVME Error 
Response */
+#define NVME_TASK_ABORT_MIN_TIMEOUT    6
+#define NVME_TASK_ABORT_MAX_TIMEOUT    60
+#define NVME_TASK_MNGT_CUSTOM_MASK     (0x0010)
 #define        NVME_PRP_PAGE_SIZE              4096    /* Page size */
 
+
 /*
  * reset phases
  */
@@ -363,7 +367,15 @@ struct Mpi2ManufacturingPage11_t {
        u8      EEDPTagMode;                    /* 09h */
        u8      Reserved3;                      /* 0Ah */
        u8      Reserved4;                      /* 0Bh */
-       __le32  Reserved5[23];                  /* 0Ch-60h*/
+       __le32  Reserved5[8];                   /* 0Ch-2Ch */
+       u16     AddlFlags2;                     /* 2Ch */
+       u8      AddlFlags3;                     /* 2Eh */
+       u8      Reserved6;                      /* 2Fh */
+       __le32  Reserved7[7];                   /* 30h - 4Bh */
+       u8      NVMeAbortTO;                    /* 4Ch */
+       u8      Reserved8;                      /* 4Dh */
+       u16     Reserved9;                      /* 4Eh */
+       __le32  Reserved10[4];                  /* 50h - 60h */
 };
 
 /**
@@ -573,6 +585,7 @@ struct _pcie_device {
        u8      enclosure_level;
        u8      connector_name[4];
        u8      *serial_number;
+       u8      reset_timeout;
        struct kref refcount;
 };
 /**
@@ -1211,6 +1224,10 @@ struct MPT3SAS_ADAPTER {
        void            *event_log;
        u32             event_masks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];
 
+       u8              tm_custom_handling;
+       u8              nvme_abort_timeout;
+
+
        /* static config pages */
        struct mpt3sas_facts facts;
        struct mpt3sas_port_facts *pfacts;
@@ -1470,10 +1487,11 @@ u8 mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER 
*ioc, u8 msix_index,
        u32 reply);
 void mpt3sas_scsih_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase);
 
-int mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle,
-       u64 lun, u8 type, u16 smid_task, u16 msix_task, ulong timeout);
+int mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, u64 lun,
+       u8 type, u16 smid_task, u16 msix_task, u8 timeout, u8 tr_method);
 int mpt3sas_scsih_issue_locked_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle,
-       u64 lun, u8 type, u16 smid_task, u16 msix_task, ulong timeout);
+       u64 lun, u8 type, u16 smid_task, u16 msix_task,
+       u8 timeout, u8 tr_method);
 
 void mpt3sas_scsih_set_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle);
 void mpt3sas_scsih_clear_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c 
b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
index c1b17d6..3269ef4 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
@@ -644,9 +644,10 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct 
mpt3_ioctl_command karg,
        MPI2RequestHeader_t *mpi_request = NULL, *request;
        MPI2DefaultReply_t *mpi_reply;
        Mpi26NVMeEncapsulatedRequest_t *nvme_encap_request = NULL;
+       struct _pcie_device *pcie_device = NULL;
        u32 ioc_state;
        u16 smid;
-       unsigned long timeout;
+       u8 timeout;
        u8 issue_reset;
        u32 sz, sz_arg;
        void *psge;
@@ -659,6 +660,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct 
mpt3_ioctl_command karg,
        long ret;
        u16 wait_state_count;
        u16 device_handle = MPT3SAS_INVALID_DEVICE_HANDLE;
+       u8 tr_method = MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE;
 
        issue_reset = 0;
 
@@ -1074,14 +1076,26 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct 
mpt3_ioctl_command karg,
                                ioc->name,
                                le16_to_cpu(mpi_request->FunctionDependent1));
                        mpt3sas_halt_firmware(ioc);
-                       mpt3sas_scsih_issue_locked_tm(ioc,
-                           le16_to_cpu(mpi_request->FunctionDependent1), 0,
-                           MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 0, 30);
+                       pcie_device = mpt3sas_get_pdev_by_handle(ioc,
+                               le16_to_cpu(mpi_request->FunctionDependent1));
+                       if (pcie_device && (!ioc->tm_custom_handling))
+                               mpt3sas_scsih_issue_locked_tm(ioc,
+                                 le16_to_cpu(mpi_request->FunctionDependent1),
+                                 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0,
+                                 0, pcie_device->reset_timeout,
+                                 tr_method);
+                       else
+                               mpt3sas_scsih_issue_locked_tm(ioc,
+                                 le16_to_cpu(mpi_request->FunctionDependent1),
+                                 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0,
+                                 0, 30, MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET);
                } else
                        mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
        }
 
  out:
+       if (pcie_device)
+               pcie_device_put(pcie_device);
 
        /* free memory associated with sg buffers */
        if (data_in)
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c 
b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index bc8e7f0..8ba72a2 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -1088,7 +1088,7 @@ _scsih_pcie_device_remove(struct MPT3SAS_ADAPTER *ioc,
                pcie_device->slot);
        if (pcie_device->connector_name[0] != '\0')
                pr_info(MPT3SAS_FMT
-                       "removing enclosure level(0x%04x), connector name( 
%s)\n",
+                   "removing enclosure level(0x%04x), connector name( %s)\n",
                        ioc->name, pcie_device->enclosure_level,
                        pcie_device->connector_name);
 
@@ -2632,6 +2632,7 @@ mpt3sas_scsih_clear_tm_flag(struct MPT3SAS_ADAPTER *ioc, 
u16 handle)
  * @smid_task: smid assigned to the task
  * @msix_task: MSIX table index supplied by the OS
  * @timeout: timeout in seconds
+ * @tr_method: Target Reset Method
  * Context: user
  *
  * A generic API for sending task management requests to firmware.
@@ -2642,8 +2643,8 @@ mpt3sas_scsih_clear_tm_flag(struct MPT3SAS_ADAPTER *ioc, 
u16 handle)
  * Return SUCCESS or FAILED.
  */
 int
-mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle,
-       u64 lun, u8 type, u16 smid_task, u16 msix_task, ulong timeout)
+mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, u64 lun,
+       u8 type, u16 smid_task, u16 msix_task, u8 timeout, u8 tr_method)
 {
        Mpi2SCSITaskManagementRequest_t *mpi_request;
        Mpi2SCSITaskManagementReply_t *mpi_reply;
@@ -2689,8 +2690,8 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 
handle,
        }
 
        dtmprintk(ioc, pr_info(MPT3SAS_FMT
-               "sending tm: handle(0x%04x), task_type(0x%02x), smid(%d)\n",
-               ioc->name, handle, type, smid_task));
+               "sending tm: handle(0x%04x), task_type(0x%02x), smid(%d), 
timeout(%d), tr_method(0x%x)\n",
+               ioc->name, handle, type, smid_task, timeout, tr_method));
        ioc->tm_cmds.status = MPT3_CMD_PENDING;
        mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
        ioc->tm_cmds.smid = smid;
@@ -2699,6 +2700,7 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 
handle,
        mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
        mpi_request->DevHandle = cpu_to_le16(handle);
        mpi_request->TaskType = type;
+       mpi_request->MsgFlags = tr_method;
        mpi_request->TaskMID = cpu_to_le16(smid_task);
        int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
        mpt3sas_scsih_set_tm_flag(ioc, handle);
@@ -2745,13 +2747,14 @@ out:
 }
 
 int mpt3sas_scsih_issue_locked_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle,
-       u64 lun, u8 type, u16 smid_task, u16 msix_task, ulong timeout)
+               u64 lun, u8 type, u16 smid_task, u16 msix_task,
+               u8 timeout, u8 tr_method)
 {
        int ret;
 
        mutex_lock(&ioc->tm_cmds.mutex);
        ret = mpt3sas_scsih_issue_tm(ioc, handle, lun, type, smid_task,
-                       msix_task, timeout);
+                       msix_task, timeout, tr_method);
        mutex_unlock(&ioc->tm_cmds.mutex);
 
        return ret;
@@ -2854,6 +2857,8 @@ scsih_abort(struct scsi_cmnd *scmd)
        u16 handle;
        int r;
 
+       u8 timeout = 30;
+       struct _pcie_device *pcie_device = NULL;
        sdev_printk(KERN_INFO, scmd->device,
                "attempting task abort! scmd(%p)\n", scmd);
        _scsih_tm_display_info(ioc, scmd);
@@ -2887,15 +2892,20 @@ scsih_abort(struct scsi_cmnd *scmd)
        mpt3sas_halt_firmware(ioc);
 
        handle = sas_device_priv_data->sas_target->handle;
+       pcie_device = mpt3sas_get_pdev_by_handle(ioc, handle);
+       if (pcie_device && (!ioc->tm_custom_handling))
+               timeout = ioc->nvme_abort_timeout;
        r = mpt3sas_scsih_issue_locked_tm(ioc, handle, scmd->device->lun,
                MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
-               st->smid, st->msix_io, 30);
+               st->smid, st->msix_io, timeout, 0);
        /* Command must be cleared after abort */
        if (r == SUCCESS && st->cb_idx != 0xFF)
                r = FAILED;
  out:
        sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n",
            ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+       if (pcie_device)
+               pcie_device_put(pcie_device);
        return r;
 }
 
@@ -2911,7 +2921,10 @@ scsih_dev_reset(struct scsi_cmnd *scmd)
        struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
        struct MPT3SAS_DEVICE *sas_device_priv_data;
        struct _sas_device *sas_device = NULL;
+       struct _pcie_device *pcie_device = NULL;
        u16     handle;
+       u8      tr_method = 0;
+       u8      tr_timeout = 30;
        int r;
 
        struct scsi_target *starget = scmd->device->sdev_target;
@@ -2948,8 +2961,16 @@ scsih_dev_reset(struct scsi_cmnd *scmd)
                goto out;
        }
 
+       pcie_device = mpt3sas_get_pdev_by_handle(ioc, handle);
+
+       if (pcie_device && (!ioc->tm_custom_handling)) {
+               tr_timeout = pcie_device->reset_timeout;
+               tr_method = MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE;
+       } else
+               tr_method = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
        r = mpt3sas_scsih_issue_locked_tm(ioc, handle, scmd->device->lun,
-               MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 0, 30);
+               MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 0,
+               tr_timeout, tr_method);
        /* Check for busy commands after reset */
        if (r == SUCCESS && atomic_read(&scmd->device->device_busy))
                r = FAILED;
@@ -2959,6 +2980,8 @@ scsih_dev_reset(struct scsi_cmnd *scmd)
 
        if (sas_device)
                sas_device_put(sas_device);
+       if (pcie_device)
+               pcie_device_put(pcie_device);
 
        return r;
 }
@@ -2975,7 +2998,10 @@ scsih_target_reset(struct scsi_cmnd *scmd)
        struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
        struct MPT3SAS_DEVICE *sas_device_priv_data;
        struct _sas_device *sas_device = NULL;
+       struct _pcie_device *pcie_device = NULL;
        u16     handle;
+       u8      tr_method = 0;
+       u8      tr_timeout = 30;
        int r;
        struct scsi_target *starget = scmd->device->sdev_target;
        struct MPT3SAS_TARGET *target_priv_data = starget->hostdata;
@@ -3011,8 +3037,16 @@ scsih_target_reset(struct scsi_cmnd *scmd)
                goto out;
        }
 
+       pcie_device = mpt3sas_get_pdev_by_handle(ioc, handle);
+
+       if (pcie_device && (!ioc->tm_custom_handling)) {
+               tr_timeout = pcie_device->reset_timeout;
+               tr_method = MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE;
+       } else
+               tr_method = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
        r = mpt3sas_scsih_issue_locked_tm(ioc, handle, 0,
-               MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 0, 30);
+               MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 0,
+           tr_timeout, tr_method);
        /* Check for busy commands after reset */
        if (r == SUCCESS && atomic_read(&starget->target_busy))
                r = FAILED;
@@ -3022,7 +3056,8 @@ scsih_target_reset(struct scsi_cmnd *scmd)
 
        if (sas_device)
                sas_device_put(sas_device);
-
+       if (pcie_device)
+               pcie_device_put(pcie_device);
        return r;
 }
 
@@ -3556,6 +3591,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
        unsigned long flags;
        struct _tr_list *delayed_tr;
        u32 ioc_state;
+       u8 tr_method = 0;
 
        if (ioc->pci_error_recovery) {
                dewtprintk(ioc, pr_info(MPT3SAS_FMT
@@ -3598,6 +3634,11 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 
handle)
                        sas_address = pcie_device->wwid;
                }
                spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
+               if (pcie_device && (!ioc->tm_custom_handling))
+                       tr_method =
+                           MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE;
+               else
+                       tr_method = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
        }
        if (sas_target_priv_data) {
                dewtprintk(ioc, pr_info(MPT3SAS_FMT
@@ -3661,6 +3702,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
        mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
        mpi_request->DevHandle = cpu_to_le16(handle);
        mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
+       mpi_request->MsgFlags = tr_method;
        set_bit(handle, ioc->device_remove_in_progress);
        mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
        mpt3sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL);
@@ -6935,6 +6977,11 @@ _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 
handle)
        }
        pcie_device->nvme_mdts =
                le32_to_cpu(pcie_device_pg2.MaximumDataTransferSize);
+       if (pcie_device_pg2.ControllerResetTO)
+               pcie_device->reset_timeout =
+                       pcie_device_pg2.ControllerResetTO;
+       else
+               pcie_device->reset_timeout = 30;
 
        if (ioc->wait_for_discovery_to_complete)
                _scsih_pcie_device_init_add(ioc, pcie_device);
@@ -7187,6 +7234,9 @@ _scsih_pcie_device_status_change_event_debug(struct 
MPT3SAS_ADAPTER *ioc,
        case MPI26_EVENT_PCIDEV_STAT_RC_ASYNC_NOTIFICATION:
                reason_str = "internal async notification";
                break;
+       case MPI26_EVENT_PCIDEV_STAT_RC_PCIE_HOT_RESET_FAILED:
+               reason_str = "pcie hot reset failed";
+               break;
        default:
                reason_str = "unknown reason";
                break;
@@ -7441,7 +7491,7 @@ _scsih_sas_broadcast_primitive_event(struct 
MPT3SAS_ADAPTER *ioc,
                spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
                r = mpt3sas_scsih_issue_tm(ioc, handle, lun,
                        MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, st->smid,
-                       st->msix_io, 30);
+                       st->msix_io, 30, 0);
                if (r == FAILED) {
                        sdev_printk(KERN_WARNING, sdev,
                            "mpt3sas_scsih_issue_tm: FAILED when sending "
@@ -7482,7 +7532,7 @@ _scsih_sas_broadcast_primitive_event(struct 
MPT3SAS_ADAPTER *ioc,
 
                r = mpt3sas_scsih_issue_tm(ioc, handle, sdev->lun,
                        MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, st->smid,
-                       st->msix_io, 30);
+                       st->msix_io, 30, 0);
                if (r == FAILED || st->cb_idx != 0xFF) {
                        sdev_printk(KERN_WARNING, sdev,
                            "mpt3sas_scsih_issue_tm: ABORT_TASK: FAILED : "
-- 
1.8.3.1

Reply via email to