Commit 18365b13 authored by Sumit Saxena's avatar Sumit Saxena Committed by Martin K. Petersen

megaraid_sas: Task management support

This patch adds task management for SCSI commands. Added functions are
task abort and target reset.

1. Currently, megaraid_sas driver performs controller reset when any IO
times out.  With task management support added, task abort and target
reset will be tried to recover timed out IO. If task management fails,
then controller reset will be performaned. If the task management
request times out, fail the request and escalate to the next
level (controller reset).

2. mr_device_priv_data will be allocated for all generations of
controller, but is_tm_capable flag will never be set for
controllers (prior to Invader series) as firmware support is not
available for task management.

3. Task management capable firmware will set is_tm_capable flag in
firmware API.
Signed-off-by: default avatarSumit Saxena <sumit.saxena@avagotech.com>
Signed-off-by: default avatarKashyap Desai <kashyap.desai@avagotech.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 2c048351
...@@ -1520,6 +1520,15 @@ union megasas_frame { ...@@ -1520,6 +1520,15 @@ union megasas_frame {
u8 raw_bytes[64]; u8 raw_bytes[64];
}; };
/**
* struct MR_PRIV_DEVICE - sdev private hostdata
* @is_tm_capable: firmware managed tm_capable flag
* @tm_busy: TM request is in progress
*/
struct MR_PRIV_DEVICE {
bool is_tm_capable;
bool tm_busy;
};
struct megasas_cmd; struct megasas_cmd;
union megasas_evt_class_locale { union megasas_evt_class_locale {
...@@ -2073,4 +2082,8 @@ void megasas_return_mfi_mpt_pthr(struct megasas_instance *instance, ...@@ -2073,4 +2082,8 @@ void megasas_return_mfi_mpt_pthr(struct megasas_instance *instance,
int megasas_cmd_type(struct scsi_cmnd *cmd); int megasas_cmd_type(struct scsi_cmnd *cmd);
void megasas_setup_jbod_map(struct megasas_instance *instance); void megasas_setup_jbod_map(struct megasas_instance *instance);
void megasas_update_sdev_properties(struct scsi_device *sdev);
int megasas_reset_fusion(struct Scsi_Host *shost, int reason);
int megasas_task_abort_fusion(struct scsi_cmnd *scmd);
int megasas_reset_target_fusion(struct scsi_cmnd *scmd);
#endif /*LSI_MEGARAID_SAS_H */ #endif /*LSI_MEGARAID_SAS_H */
...@@ -189,7 +189,6 @@ int ...@@ -189,7 +189,6 @@ int
wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd, wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
int seconds); int seconds);
void megasas_reset_reply_desc(struct megasas_instance *instance); void megasas_reset_reply_desc(struct megasas_instance *instance);
int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout);
void megasas_fusion_ocr_wq(struct work_struct *work); void megasas_fusion_ocr_wq(struct work_struct *work);
static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance, static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
int initial); int initial);
...@@ -1645,6 +1644,7 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd) ...@@ -1645,6 +1644,7 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
{ {
struct megasas_instance *instance; struct megasas_instance *instance;
unsigned long flags; unsigned long flags;
struct MR_PRIV_DEVICE *mr_device_priv_data;
instance = (struct megasas_instance *) instance = (struct megasas_instance *)
scmd->device->host->hostdata; scmd->device->host->hostdata;
...@@ -1681,11 +1681,24 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd) ...@@ -1681,11 +1681,24 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
return 0; return 0;
} }
mr_device_priv_data = scmd->device->hostdata;
if (!mr_device_priv_data) {
spin_unlock_irqrestore(&instance->hba_lock, flags);
scmd->result = DID_NO_CONNECT << 16;
scmd->scsi_done(scmd);
return 0;
}
if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
spin_unlock_irqrestore(&instance->hba_lock, flags); spin_unlock_irqrestore(&instance->hba_lock, flags);
return SCSI_MLQUEUE_HOST_BUSY; return SCSI_MLQUEUE_HOST_BUSY;
} }
if (mr_device_priv_data->tm_busy) {
spin_unlock_irqrestore(&instance->hba_lock, flags);
return SCSI_MLQUEUE_DEVICE_BUSY;
}
spin_unlock_irqrestore(&instance->hba_lock, flags); spin_unlock_irqrestore(&instance->hba_lock, flags);
scmd->result = 0; scmd->result = 0;
...@@ -1736,27 +1749,39 @@ static struct megasas_instance *megasas_lookup_instance(u16 host_no) ...@@ -1736,27 +1749,39 @@ static struct megasas_instance *megasas_lookup_instance(u16 host_no)
} }
/* /*
* megasas_set_dma_alignment - Set DMA alignment for PI enabled VD * megasas_update_sdev_properties - Update sdev structure based on controller's FW capabilities
* *
* @sdev: OS provided scsi device * @sdev: OS provided scsi device
* *
* Returns void * Returns void
*/ */
static void megasas_set_dma_alignment(struct scsi_device *sdev) void megasas_update_sdev_properties(struct scsi_device *sdev)
{ {
u16 pd_index = 0;
u32 device_id, ld; u32 device_id, ld;
struct megasas_instance *instance; struct megasas_instance *instance;
struct fusion_context *fusion; struct fusion_context *fusion;
struct MR_PRIV_DEVICE *mr_device_priv_data;
struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
struct MR_LD_RAID *raid; struct MR_LD_RAID *raid;
struct MR_DRV_RAID_MAP_ALL *local_map_ptr; struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
instance = megasas_lookup_instance(sdev->host->host_no); instance = megasas_lookup_instance(sdev->host->host_no);
fusion = instance->ctrl_context; fusion = instance->ctrl_context;
mr_device_priv_data = sdev->hostdata;
if (!fusion) if (!fusion)
return; return;
if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS) { if (sdev->channel < MEGASAS_MAX_PD_CHANNELS &&
instance->use_seqnum_jbod_fp) {
pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
sdev->id;
pd_sync = (void *)fusion->pd_seq_sync
[(instance->pd_seq_map_id - 1) & 1];
mr_device_priv_data->is_tm_capable =
pd_sync->seq[pd_index].capability.tmCapable;
} else {
device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL)
+ sdev->id; + sdev->id;
local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
...@@ -1765,9 +1790,12 @@ static void megasas_set_dma_alignment(struct scsi_device *sdev) ...@@ -1765,9 +1790,12 @@ static void megasas_set_dma_alignment(struct scsi_device *sdev)
if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER)
blk_queue_update_dma_alignment(sdev->request_queue, 0x7); blk_queue_update_dma_alignment(sdev->request_queue, 0x7);
mr_device_priv_data->is_tm_capable =
raid->capability.tmCapable;
} }
} }
static int megasas_slave_configure(struct scsi_device *sdev) static int megasas_slave_configure(struct scsi_device *sdev)
{ {
u16 pd_index = 0; u16 pd_index = 0;
...@@ -1784,7 +1812,8 @@ static int megasas_slave_configure(struct scsi_device *sdev) ...@@ -1784,7 +1812,8 @@ static int megasas_slave_configure(struct scsi_device *sdev)
return -ENXIO; return -ENXIO;
} }
} }
megasas_set_dma_alignment(sdev); megasas_update_sdev_properties(sdev);
/* /*
* The RAID firmware may require extended timeouts. * The RAID firmware may require extended timeouts.
*/ */
...@@ -1798,6 +1827,7 @@ static int megasas_slave_alloc(struct scsi_device *sdev) ...@@ -1798,6 +1827,7 @@ static int megasas_slave_alloc(struct scsi_device *sdev)
{ {
u16 pd_index = 0; u16 pd_index = 0;
struct megasas_instance *instance ; struct megasas_instance *instance ;
struct MR_PRIV_DEVICE *mr_device_priv_data;
instance = megasas_lookup_instance(sdev->host->host_no); instance = megasas_lookup_instance(sdev->host->host_no);
if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) { if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
...@@ -1809,13 +1839,26 @@ static int megasas_slave_alloc(struct scsi_device *sdev) ...@@ -1809,13 +1839,26 @@ static int megasas_slave_alloc(struct scsi_device *sdev)
sdev->id; sdev->id;
if ((instance->allow_fw_scan || instance->pd_list[pd_index].driveState == if ((instance->allow_fw_scan || instance->pd_list[pd_index].driveState ==
MR_PD_STATE_SYSTEM)) { MR_PD_STATE_SYSTEM)) {
return 0; goto scan_target;
} }
return -ENXIO; return -ENXIO;
} }
scan_target:
mr_device_priv_data = kzalloc(sizeof(*mr_device_priv_data),
GFP_KERNEL);
if (!mr_device_priv_data)
return -ENOMEM;
sdev->hostdata = mr_device_priv_data;
return 0; return 0;
} }
static void megasas_slave_destroy(struct scsi_device *sdev)
{
kfree(sdev->hostdata);
sdev->hostdata = NULL;
}
/* /*
* megasas_complete_outstanding_ioctls - Complete outstanding ioctls after a * megasas_complete_outstanding_ioctls - Complete outstanding ioctls after a
* kill adapter * kill adapter
...@@ -2885,6 +2928,7 @@ static struct scsi_host_template megasas_template = { ...@@ -2885,6 +2928,7 @@ static struct scsi_host_template megasas_template = {
.proc_name = "megaraid_sas", .proc_name = "megaraid_sas",
.slave_configure = megasas_slave_configure, .slave_configure = megasas_slave_configure,
.slave_alloc = megasas_slave_alloc, .slave_alloc = megasas_slave_alloc,
.slave_destroy = megasas_slave_destroy,
.queuecommand = megasas_queue_command, .queuecommand = megasas_queue_command,
.eh_device_reset_handler = megasas_reset_device, .eh_device_reset_handler = megasas_reset_device,
.eh_bus_reset_handler = megasas_reset_bus_host, .eh_bus_reset_handler = megasas_reset_bus_host,
...@@ -5434,6 +5478,8 @@ static int megasas_io_attach(struct megasas_instance *instance) ...@@ -5434,6 +5478,8 @@ static int megasas_io_attach(struct megasas_instance *instance)
if (instance->ctrl_context) { if (instance->ctrl_context) {
host->hostt->eh_device_reset_handler = NULL; host->hostt->eh_device_reset_handler = NULL;
host->hostt->eh_bus_reset_handler = NULL; host->hostt->eh_bus_reset_handler = NULL;
host->hostt->eh_target_reset_handler = megasas_reset_target_fusion;
host->hostt->eh_abort_handler = megasas_task_abort_fusion;
} }
/* /*
......
This diff is collapsed.
...@@ -176,6 +176,7 @@ enum REGION_TYPE { ...@@ -176,6 +176,7 @@ enum REGION_TYPE {
#define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100) #define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100)
#define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004) #define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004)
#define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */ #define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */
#define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01)
#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x03) #define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x03)
#define MPI2_REQ_DESCRIPT_FLAGS_FP_IO (0x06) #define MPI2_REQ_DESCRIPT_FLAGS_FP_IO (0x06)
#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00) #define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00)
...@@ -278,6 +279,100 @@ union MPI2_SCSI_IO_CDB_UNION { ...@@ -278,6 +279,100 @@ union MPI2_SCSI_IO_CDB_UNION {
struct MPI2_SGE_SIMPLE_UNION SGE; struct MPI2_SGE_SIMPLE_UNION SGE;
}; };
/****************************************************************************
* SCSI Task Management messages
****************************************************************************/
/*SCSI Task Management Request Message */
struct MPI2_SCSI_TASK_MANAGE_REQUEST {
u16 DevHandle; /*0x00 */
u8 ChainOffset; /*0x02 */
u8 Function; /*0x03 */
u8 Reserved1; /*0x04 */
u8 TaskType; /*0x05 */
u8 Reserved2; /*0x06 */
u8 MsgFlags; /*0x07 */
u8 VP_ID; /*0x08 */
u8 VF_ID; /*0x09 */
u16 Reserved3; /*0x0A */
u8 LUN[8]; /*0x0C */
u32 Reserved4[7]; /*0x14 */
u16 TaskMID; /*0x30 */
u16 Reserved5; /*0x32 */
};
/*SCSI Task Management Reply Message */
struct MPI2_SCSI_TASK_MANAGE_REPLY {
u16 DevHandle; /*0x00 */
u8 MsgLength; /*0x02 */
u8 Function; /*0x03 */
u8 ResponseCode; /*0x04 */
u8 TaskType; /*0x05 */
u8 Reserved1; /*0x06 */
u8 MsgFlags; /*0x07 */
u8 VP_ID; /*0x08 */
u8 VF_ID; /*0x09 */
u16 Reserved2; /*0x0A */
u16 Reserved3; /*0x0C */
u16 IOCStatus; /*0x0E */
u32 IOCLogInfo; /*0x10 */
u32 TerminationCount; /*0x14 */
u32 ResponseInfo; /*0x18 */
};
struct MR_TM_REQUEST {
char request[128];
};
struct MR_TM_REPLY {
char reply[128];
};
/* SCSI Task Management Request Message */
struct MR_TASK_MANAGE_REQUEST {
/*To be type casted to struct MPI2_SCSI_TASK_MANAGE_REQUEST */
struct MR_TM_REQUEST TmRequest;
union {
struct {
#if defined(__BIG_ENDIAN_BITFIELD)
u32 reserved1:30;
u32 isTMForPD:1;
u32 isTMForLD:1;
#else
u32 isTMForLD:1;
u32 isTMForPD:1;
u32 reserved1:30;
#endif
u32 reserved2;
} tmReqFlags;
struct MR_TM_REPLY TMReply;
};
};
/* TaskType values */
#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x01)
#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x02)
#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03)
#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05)
#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06)
#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07)
#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08)
#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET (0x09)
#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT (0x0A)
/* ResponseCode values */
#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE (0x00)
#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME (0x02)
#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED (0x04)
#define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05)
#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08)
#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09)
#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG (0x0A)
#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80)
/* /*
* RAID SCSI IO Request Message * RAID SCSI IO Request Message
* Total SGE count will be one less than _MPI2_SCSI_IO_REQUEST * Total SGE count will be one less than _MPI2_SCSI_IO_REQUEST
...@@ -548,7 +643,8 @@ struct MR_SPAN_BLOCK_INFO { ...@@ -548,7 +643,8 @@ struct MR_SPAN_BLOCK_INFO {
struct MR_LD_RAID { struct MR_LD_RAID {
struct { struct {
#if defined(__BIG_ENDIAN_BITFIELD) #if defined(__BIG_ENDIAN_BITFIELD)
u32 reserved4:7; u32 reserved4:6;
u32 tmCapable:1;
u32 fpNonRWCapable:1; u32 fpNonRWCapable:1;
u32 fpReadAcrossStripe:1; u32 fpReadAcrossStripe:1;
u32 fpWriteAcrossStripe:1; u32 fpWriteAcrossStripe:1;
...@@ -570,7 +666,8 @@ struct MR_LD_RAID { ...@@ -570,7 +666,8 @@ struct MR_LD_RAID {
u32 fpWriteAcrossStripe:1; u32 fpWriteAcrossStripe:1;
u32 fpReadAcrossStripe:1; u32 fpReadAcrossStripe:1;
u32 fpNonRWCapable:1; u32 fpNonRWCapable:1;
u32 reserved4:7; u32 tmCapable:1;
u32 reserved4:6;
#endif #endif
} capability; } capability;
__le32 reserved6; __le32 reserved6;
...@@ -695,6 +792,7 @@ struct megasas_cmd_fusion { ...@@ -695,6 +792,7 @@ struct megasas_cmd_fusion {
u32 sync_cmd_idx; u32 sync_cmd_idx;
u32 index; u32 index;
u8 pd_r1_lb; u8 pd_r1_lb;
struct completion done;
}; };
struct LD_LOAD_BALANCE_INFO { struct LD_LOAD_BALANCE_INFO {
...@@ -808,9 +906,18 @@ struct MR_FW_RAID_MAP_EXT { ...@@ -808,9 +906,18 @@ struct MR_FW_RAID_MAP_EXT {
* * define MR_PD_CFG_SEQ structure for system PDs * * define MR_PD_CFG_SEQ structure for system PDs
* */ * */
struct MR_PD_CFG_SEQ { struct MR_PD_CFG_SEQ {
__le16 seqNum; u16 seqNum;
__le16 devHandle; u16 devHandle;
u8 reserved[4]; struct {
#if defined(__BIG_ENDIAN_BITFIELD)
u8 reserved:7;
u8 tmCapable:1;
#else
u8 tmCapable:1;
u8 reserved:7;
#endif
} capability;
u8 reserved[3];
} __packed; } __packed;
struct MR_PD_CFG_SEQ_NUM_SYNC { struct MR_PD_CFG_SEQ_NUM_SYNC {
......
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