Commit e9495e2d authored by Shivasharan S's avatar Shivasharan S Committed by Martin K. Petersen

scsi: megaraid_sas: Support FW provided TM timeout values

Firmware provides drive specific target reset and task abort timeout
values. Driver needs to use these timeout values during task management
calls. If FW does not provide these values, fall back to using earlier
default timeout of 50 seconds for TM.

[mkp: clarified comment]
Signed-off-by: default avatarSumit Saxena <sumit.saxena@broadcom.com>
Signed-off-by: default avatarShivasharan S <shivasharan.srikanteshwara@broadcom.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 9c9db8b7
...@@ -709,7 +709,8 @@ struct MR_TARGET_PROPERTIES { ...@@ -709,7 +709,8 @@ struct MR_TARGET_PROPERTIES {
u32 max_io_size_kb; u32 max_io_size_kb;
u32 device_qdepth; u32 device_qdepth;
u32 sector_size; u32 sector_size;
u8 reserved[500]; u8 reset_tmo;
u8 reserved[499];
} __packed; } __packed;
/* /*
...@@ -1400,6 +1401,19 @@ struct megasas_ctrl_info { ...@@ -1400,6 +1401,19 @@ struct megasas_ctrl_info {
#endif #endif
} adapter_operations4; } adapter_operations4;
u8 pad[0x800 - 0x7FE]; /* 0x7FE pad to 2K for expansion */ u8 pad[0x800 - 0x7FE]; /* 0x7FE pad to 2K for expansion */
u32 size;
u32 pad1;
u8 reserved6[64];
u32 rsvdForAdptOp[64];
u8 reserved7[3];
u8 TaskAbortTO; /* Timeout value in seconds used by Abort Task TM */
u8 MaxResetTO; /* Max Supported Reset timeout in seconds. */
u8 reserved8[3];
} __packed; } __packed;
/* /*
...@@ -1472,6 +1486,7 @@ enum FW_BOOT_CONTEXT { ...@@ -1472,6 +1486,7 @@ enum FW_BOOT_CONTEXT {
#define MEGASAS_DEFAULT_CMD_TIMEOUT 90 #define MEGASAS_DEFAULT_CMD_TIMEOUT 90
#define MEGASAS_THROTTLE_QUEUE_DEPTH 16 #define MEGASAS_THROTTLE_QUEUE_DEPTH 16
#define MEGASAS_BLOCKED_CMD_TIMEOUT 60 #define MEGASAS_BLOCKED_CMD_TIMEOUT 60
#define MEGASAS_DEFAULT_TM_TIMEOUT 50
/* /*
* FW reports the maximum of number of commands that it can accept (maximum * FW reports the maximum of number of commands that it can accept (maximum
* commands that can be outstanding) at any time. The driver must report a * commands that can be outstanding) at any time. The driver must report a
...@@ -1915,7 +1930,9 @@ struct MR_PRIV_DEVICE { ...@@ -1915,7 +1930,9 @@ struct MR_PRIV_DEVICE {
bool is_tm_capable; bool is_tm_capable;
bool tm_busy; bool tm_busy;
atomic_t r1_ldio_hint; atomic_t r1_ldio_hint;
u8 interface_type; u8 interface_type;
u8 task_abort_tmo;
u8 target_reset_tmo;
}; };
struct megasas_cmd; struct megasas_cmd;
...@@ -2291,6 +2308,8 @@ struct megasas_instance { ...@@ -2291,6 +2308,8 @@ struct megasas_instance {
u8 adapter_type; u8 adapter_type;
bool consistent_mask_64bit; bool consistent_mask_64bit;
bool support_nvme_passthru; bool support_nvme_passthru;
u8 task_abort_tmo;
u8 max_reset_tmo;
}; };
struct MR_LD_VF_MAP { struct MR_LD_VF_MAP {
u32 size; u32 size;
...@@ -2512,7 +2531,11 @@ int megasas_get_ctrl_info(struct megasas_instance *instance); ...@@ -2512,7 +2531,11 @@ int megasas_get_ctrl_info(struct megasas_instance *instance);
/* PD sequence */ /* PD sequence */
int int
megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend); megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend);
void megasas_set_dynamic_target_properties(struct scsi_device *sdev); void megasas_set_dynamic_target_properties(struct scsi_device *sdev,
bool is_target_prop);
int megasas_get_target_prop(struct megasas_instance *instance,
struct scsi_device *sdev);
int megasas_set_crash_dump_params(struct megasas_instance *instance, int megasas_set_crash_dump_params(struct megasas_instance *instance,
u8 crash_buf_state); u8 crash_buf_state);
void megasas_free_host_crash_buffer(struct megasas_instance *instance); void megasas_free_host_crash_buffer(struct megasas_instance *instance);
......
...@@ -120,8 +120,7 @@ static int megasas_register_aen(struct megasas_instance *instance, ...@@ -120,8 +120,7 @@ static int megasas_register_aen(struct megasas_instance *instance,
u32 seq_num, u32 class_locale_word); u32 seq_num, u32 class_locale_word);
static void megasas_get_pd_info(struct megasas_instance *instance, static void megasas_get_pd_info(struct megasas_instance *instance,
struct scsi_device *sdev); struct scsi_device *sdev);
static int megasas_get_target_prop(struct megasas_instance *instance,
struct scsi_device *sdev);
/* /*
* PCI ID table for all supported controllers * PCI ID table for all supported controllers
*/ */
...@@ -1794,7 +1793,8 @@ static struct megasas_instance *megasas_lookup_instance(u16 host_no) ...@@ -1794,7 +1793,8 @@ static struct megasas_instance *megasas_lookup_instance(u16 host_no)
* *
* Returns void * Returns void
*/ */
void megasas_set_dynamic_target_properties(struct scsi_device *sdev) void megasas_set_dynamic_target_properties(struct scsi_device *sdev,
bool is_target_prop)
{ {
u16 pd_index = 0, ld; u16 pd_index = 0, ld;
u32 device_id; u32 device_id;
...@@ -1834,6 +1834,22 @@ void megasas_set_dynamic_target_properties(struct scsi_device *sdev) ...@@ -1834,6 +1834,22 @@ void megasas_set_dynamic_target_properties(struct scsi_device *sdev)
mr_device_priv_data->is_tm_capable = mr_device_priv_data->is_tm_capable =
pd_sync->seq[pd_index].capability.tmCapable; pd_sync->seq[pd_index].capability.tmCapable;
} }
if (is_target_prop && instance->tgt_prop->reset_tmo) {
/*
* If FW provides a target reset timeout value, driver will use
* it. If not set, fallback to default values.
*/
mr_device_priv_data->target_reset_tmo =
min_t(u8, instance->max_reset_tmo,
instance->tgt_prop->reset_tmo);
mr_device_priv_data->task_abort_tmo = instance->task_abort_tmo;
} else {
mr_device_priv_data->target_reset_tmo =
MEGASAS_DEFAULT_TM_TIMEOUT;
mr_device_priv_data->task_abort_tmo =
MEGASAS_DEFAULT_TM_TIMEOUT;
}
} }
/* /*
...@@ -1967,10 +1983,10 @@ static int megasas_slave_configure(struct scsi_device *sdev) ...@@ -1967,10 +1983,10 @@ static int megasas_slave_configure(struct scsi_device *sdev)
is_target_prop = (ret_target_prop == DCMD_SUCCESS) ? true : false; is_target_prop = (ret_target_prop == DCMD_SUCCESS) ? true : false;
megasas_set_static_target_properties(sdev, is_target_prop); megasas_set_static_target_properties(sdev, is_target_prop);
mutex_unlock(&instance->reset_mutex);
/* This sdev property may change post OCR */ /* This sdev property may change post OCR */
megasas_set_dynamic_target_properties(sdev); megasas_set_dynamic_target_properties(sdev, is_target_prop);
mutex_unlock(&instance->reset_mutex);
return 0; return 0;
} }
...@@ -4720,6 +4736,8 @@ megasas_get_ctrl_info(struct megasas_instance *instance) ...@@ -4720,6 +4736,8 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
ci->adapter_operations4.support_pd_map_target_id; ci->adapter_operations4.support_pd_map_target_id;
instance->support_nvme_passthru = instance->support_nvme_passthru =
ci->adapter_operations4.support_nvme_passthru; ci->adapter_operations4.support_nvme_passthru;
instance->task_abort_tmo = ci->TaskAbortTO;
instance->max_reset_tmo = ci->MaxResetTO;
/*Check whether controller is iMR or MR */ /*Check whether controller is iMR or MR */
instance->is_imr = (ci->memory_size ? 0 : 1); instance->is_imr = (ci->memory_size ? 0 : 1);
...@@ -4738,6 +4756,10 @@ megasas_get_ctrl_info(struct megasas_instance *instance) ...@@ -4738,6 +4756,10 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
instance->secure_jbod_support ? "Yes" : "No"); instance->secure_jbod_support ? "Yes" : "No");
dev_info(&instance->pdev->dev, "NVMe passthru support\t: %s\n", dev_info(&instance->pdev->dev, "NVMe passthru support\t: %s\n",
instance->support_nvme_passthru ? "Yes" : "No"); instance->support_nvme_passthru ? "Yes" : "No");
dev_info(&instance->pdev->dev,
"FW provided TM TaskAbort/Reset timeout\t: %d secs/%d secs\n",
instance->task_abort_tmo, instance->max_reset_tmo);
break; break;
case DCMD_TIMEOUT: case DCMD_TIMEOUT:
...@@ -5832,7 +5854,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num, ...@@ -5832,7 +5854,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
* *
* Returns 0 on success non-zero on failure. * Returns 0 on success non-zero on failure.
*/ */
static int int
megasas_get_target_prop(struct megasas_instance *instance, megasas_get_target_prop(struct megasas_instance *instance,
struct scsi_device *sdev) struct scsi_device *sdev)
{ {
......
...@@ -4108,7 +4108,8 @@ megasas_tm_response_code(struct megasas_instance *instance, ...@@ -4108,7 +4108,8 @@ megasas_tm_response_code(struct megasas_instance *instance,
*/ */
static int static int
megasas_issue_tm(struct megasas_instance *instance, u16 device_handle, megasas_issue_tm(struct megasas_instance *instance, u16 device_handle,
uint channel, uint id, u16 smid_task, u8 type) uint channel, uint id, u16 smid_task, u8 type,
struct MR_PRIV_DEVICE *mr_device_priv_data)
{ {
struct MR_TASK_MANAGE_REQUEST *mr_request; struct MR_TASK_MANAGE_REQUEST *mr_request;
struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_request; struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_request;
...@@ -4119,6 +4120,7 @@ megasas_issue_tm(struct megasas_instance *instance, u16 device_handle, ...@@ -4119,6 +4120,7 @@ megasas_issue_tm(struct megasas_instance *instance, u16 device_handle,
struct fusion_context *fusion = NULL; struct fusion_context *fusion = NULL;
struct megasas_cmd_fusion *scsi_lookup; struct megasas_cmd_fusion *scsi_lookup;
int rc; int rc;
int timeout = MEGASAS_DEFAULT_TM_TIMEOUT;
struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply; struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply;
fusion = instance->ctrl_context; fusion = instance->ctrl_context;
...@@ -4170,7 +4172,16 @@ megasas_issue_tm(struct megasas_instance *instance, u16 device_handle, ...@@ -4170,7 +4172,16 @@ megasas_issue_tm(struct megasas_instance *instance, u16 device_handle,
init_completion(&cmd_fusion->done); init_completion(&cmd_fusion->done);
megasas_fire_cmd_fusion(instance, req_desc); megasas_fire_cmd_fusion(instance, req_desc);
timeleft = wait_for_completion_timeout(&cmd_fusion->done, 50 * HZ); switch (type) {
case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
timeout = mr_device_priv_data->task_abort_tmo;
break;
case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
timeout = mr_device_priv_data->target_reset_tmo;
break;
}
timeleft = wait_for_completion_timeout(&cmd_fusion->done, timeout * HZ);
if (!timeleft) { if (!timeleft) {
dev_err(&instance->pdev->dev, dev_err(&instance->pdev->dev,
...@@ -4363,7 +4374,8 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd) ...@@ -4363,7 +4374,8 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd)
mr_device_priv_data->tm_busy = 1; mr_device_priv_data->tm_busy = 1;
ret = megasas_issue_tm(instance, devhandle, ret = megasas_issue_tm(instance, devhandle,
scmd->device->channel, scmd->device->id, smid, scmd->device->channel, scmd->device->id, smid,
MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK); MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
mr_device_priv_data);
mr_device_priv_data->tm_busy = 0; mr_device_priv_data->tm_busy = 0;
mutex_unlock(&instance->reset_mutex); mutex_unlock(&instance->reset_mutex);
...@@ -4435,7 +4447,8 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd) ...@@ -4435,7 +4447,8 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
mr_device_priv_data->tm_busy = 1; mr_device_priv_data->tm_busy = 1;
ret = megasas_issue_tm(instance, devhandle, ret = megasas_issue_tm(instance, devhandle,
scmd->device->channel, scmd->device->id, 0, scmd->device->channel, scmd->device->id, 0,
MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET); MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
mr_device_priv_data);
mr_device_priv_data->tm_busy = 0; mr_device_priv_data->tm_busy = 0;
mutex_unlock(&instance->reset_mutex); mutex_unlock(&instance->reset_mutex);
out: out:
...@@ -4490,6 +4503,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) ...@@ -4490,6 +4503,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
u32 io_timeout_in_crash_mode = 0; u32 io_timeout_in_crash_mode = 0;
struct scsi_cmnd *scmd_local = NULL; struct scsi_cmnd *scmd_local = NULL;
struct scsi_device *sdev; struct scsi_device *sdev;
int ret_target_prop = DCMD_FAILED;
bool is_target_prop = false;
instance = (struct megasas_instance *)shost->hostdata; instance = (struct megasas_instance *)shost->hostdata;
fusion = instance->ctrl_context; fusion = instance->ctrl_context;
...@@ -4661,9 +4676,6 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) ...@@ -4661,9 +4676,6 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
megasas_setup_jbod_map(instance); megasas_setup_jbod_map(instance);
shost_for_each_device(sdev, shost)
megasas_set_dynamic_target_properties(sdev);
/* reset stream detection array */ /* reset stream detection array */
if (instance->adapter_type == VENTURA_SERIES) { if (instance->adapter_type == VENTURA_SERIES) {
for (j = 0; j < MAX_LOGICAL_DRIVES_EXT; ++j) { for (j = 0; j < MAX_LOGICAL_DRIVES_EXT; ++j) {
...@@ -4677,6 +4689,16 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) ...@@ -4677,6 +4689,16 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
clear_bit(MEGASAS_FUSION_IN_RESET, clear_bit(MEGASAS_FUSION_IN_RESET,
&instance->reset_flags); &instance->reset_flags);
instance->instancet->enable_intr(instance); instance->instancet->enable_intr(instance);
shost_for_each_device(sdev, shost) {
if ((instance->tgt_prop) &&
(instance->nvme_page_size))
ret_target_prop = megasas_get_target_prop(instance, sdev);
is_target_prop = (ret_target_prop == DCMD_SUCCESS) ? true : false;
megasas_set_dynamic_target_properties(sdev, is_target_prop);
}
atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL); atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
dev_info(&instance->pdev->dev, "Interrupts are enabled and" dev_info(&instance->pdev->dev, "Interrupts are enabled and"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment