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.basappa@xxxxxxxxxxxx> Signed-off-by: Suganath Prabu S <suganath-prabu.subramani@xxxxxxxxxxxx> --- 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 7f438be..eaeace0 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 20fe90d..6a9657e 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 2f27d5c..80f528d 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -647,9 +647,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; @@ -662,6 +663,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; @@ -1077,14 +1079,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 2f9121e..f3e1dc7 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); @@ -6942,6 +6984,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); @@ -7194,6 +7241,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; @@ -7448,7 +7498,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 " @@ -7489,7 +7539,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