[SCSI] megaraid_sas: Add High Availability clustering support using shared Logical Disks

Signed-off-by: Adam Radford <aradford@gmail.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
adam radford 2013-09-06 15:27:14 -07:00 committed by James Bottomley
parent 9807b4d949
commit 21c9e160a5
5 changed files with 204 additions and 29 deletions

View File

@ -170,6 +170,7 @@
#define MR_DCMD_CTRL_GET_INFO 0x01010000
#define MR_DCMD_LD_GET_LIST 0x03010000
#define MR_DCMD_LD_LIST_QUERY 0x03010100
#define MR_DCMD_CTRL_CACHE_FLUSH 0x01101000
#define MR_FLUSH_CTRL_CACHE 0x01
@ -345,6 +346,15 @@ enum MR_PD_QUERY_TYPE {
MR_PD_QUERY_TYPE_EXPOSED_TO_HOST = 5,
};
enum MR_LD_QUERY_TYPE {
MR_LD_QUERY_TYPE_ALL = 0,
MR_LD_QUERY_TYPE_EXPOSED_TO_HOST = 1,
MR_LD_QUERY_TYPE_USED_TGT_IDS = 2,
MR_LD_QUERY_TYPE_CLUSTER_ACCESS = 3,
MR_LD_QUERY_TYPE_CLUSTER_LOCALE = 4,
};
#define MR_EVT_CFG_CLEARED 0x0004
#define MR_EVT_LD_STATE_CHANGE 0x0051
#define MR_EVT_PD_INSERTED 0x005b
@ -435,6 +445,14 @@ struct MR_LD_LIST {
} ldList[MAX_LOGICAL_DRIVES];
} __packed;
struct MR_LD_TARGETID_LIST {
u32 size;
u32 count;
u8 pad[3];
u8 targetId[MAX_LOGICAL_DRIVES];
};
/*
* SAS controller properties
*/
@ -863,7 +881,7 @@ struct megasas_ctrl_info {
* ===============================
*/
#define MEGASAS_MAX_PD_CHANNELS 2
#define MEGASAS_MAX_LD_CHANNELS 2
#define MEGASAS_MAX_LD_CHANNELS 1
#define MEGASAS_MAX_CHANNELS (MEGASAS_MAX_PD_CHANNELS + \
MEGASAS_MAX_LD_CHANNELS)
#define MEGASAS_MAX_DEV_PER_CHANNEL 128
@ -1656,4 +1674,16 @@ struct megasas_mgmt_info {
int max_index;
};
u8
MR_BuildRaidContext(struct megasas_instance *instance,
struct IO_REQUEST_INFO *io_info,
struct RAID_CONTEXT *pRAID_Context,
struct MR_FW_RAID_MAP_ALL *map, u8 **raidLUN);
u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map);
struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_FW_RAID_MAP_ALL *map);
u16 MR_ArPdGet(u32 ar, u32 arm, struct MR_FW_RAID_MAP_ALL *map);
u16 MR_LdSpanArrayGet(u32 ld, u32 span, struct MR_FW_RAID_MAP_ALL *map);
u16 MR_PdDevHandleGet(u32 pd, struct MR_FW_RAID_MAP_ALL *map);
u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map);
#endif /*LSI_MEGARAID_SAS_H */

View File

@ -92,6 +92,8 @@ MODULE_DESCRIPTION("LSI MegaRAID SAS Driver");
int megasas_transition_to_ready(struct megasas_instance *instance, int ocr);
static int megasas_get_pd_list(struct megasas_instance *instance);
static int megasas_ld_list_query(struct megasas_instance *instance,
u8 query_type);
static int megasas_issue_init_mfi(struct megasas_instance *instance);
static int megasas_register_aen(struct megasas_instance *instance,
u32 seq_num, u32 class_locale_word);
@ -3270,6 +3272,84 @@ megasas_get_ld_list(struct megasas_instance *instance)
return ret;
}
/**
* megasas_ld_list_query - Returns FW's ld_list structure
* @instance: Adapter soft state
* @ld_list: ld_list structure
*
* Issues an internal command (DCMD) to get the FW's controller PD
* list structure. This information is mainly used to find out SYSTEM
* supported by the FW.
*/
static int
megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
{
int ret = 0, ld_index = 0, ids = 0;
struct megasas_cmd *cmd;
struct megasas_dcmd_frame *dcmd;
struct MR_LD_TARGETID_LIST *ci;
dma_addr_t ci_h = 0;
cmd = megasas_get_cmd(instance);
if (!cmd) {
printk(KERN_WARNING
"megasas:(megasas_ld_list_query): Failed to get cmd\n");
return -ENOMEM;
}
dcmd = &cmd->frame->dcmd;
ci = pci_alloc_consistent(instance->pdev,
sizeof(struct MR_LD_TARGETID_LIST), &ci_h);
if (!ci) {
printk(KERN_WARNING
"megasas: Failed to alloc mem for ld_list_query\n");
megasas_return_cmd(instance, cmd);
return -ENOMEM;
}
memset(ci, 0, sizeof(*ci));
memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
dcmd->mbox.b[0] = query_type;
dcmd->cmd = MFI_CMD_DCMD;
dcmd->cmd_status = 0xFF;
dcmd->sge_count = 1;
dcmd->flags = MFI_FRAME_DIR_READ;
dcmd->timeout = 0;
dcmd->data_xfer_len = sizeof(struct MR_LD_TARGETID_LIST);
dcmd->opcode = MR_DCMD_LD_LIST_QUERY;
dcmd->sgl.sge32[0].phys_addr = ci_h;
dcmd->sgl.sge32[0].length = sizeof(struct MR_LD_TARGETID_LIST);
dcmd->pad_0 = 0;
if (!megasas_issue_polled(instance, cmd) && !dcmd->cmd_status) {
ret = 0;
} else {
/* On failure, call older LD list DCMD */
ret = 1;
}
if ((ret == 0) && (ci->count <= (MAX_LOGICAL_DRIVES))) {
memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
for (ld_index = 0; ld_index < ci->count; ld_index++) {
ids = ci->targetId[ld_index];
instance->ld_ids[ids] = ci->targetId[ld_index];
}
}
pci_free_consistent(instance->pdev, sizeof(struct MR_LD_TARGETID_LIST),
ci, ci_h);
megasas_return_cmd(instance, cmd);
return ret;
}
/**
* megasas_get_controller_info - Returns FW's controller structure
* @instance: Adapter soft state
@ -3648,7 +3728,9 @@ static int megasas_init_fw(struct megasas_instance *instance)
megasas_get_pd_list(instance);
memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
megasas_get_ld_list(instance);
if (megasas_ld_list_query(instance,
MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
megasas_get_ld_list(instance);
ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL);
@ -5389,7 +5471,9 @@ megasas_aen_polling(struct work_struct *work)
case MR_EVT_LD_OFFLINE:
case MR_EVT_CFG_CLEARED:
case MR_EVT_LD_DELETED:
megasas_get_ld_list(instance);
if (megasas_ld_list_query(instance,
MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
megasas_get_ld_list(instance);
for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
for (j = 0;
j < MEGASAS_MAX_DEV_PER_CHANNEL;
@ -5399,7 +5483,7 @@ megasas_aen_polling(struct work_struct *work)
(i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
sdev1 = scsi_device_lookup(host,
i + MEGASAS_MAX_LD_CHANNELS,
MEGASAS_MAX_PD_CHANNELS + i,
j,
0);
@ -5418,7 +5502,9 @@ megasas_aen_polling(struct work_struct *work)
doscan = 0;
break;
case MR_EVT_LD_CREATED:
megasas_get_ld_list(instance);
if (megasas_ld_list_query(instance,
MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
megasas_get_ld_list(instance);
for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
for (j = 0;
j < MEGASAS_MAX_DEV_PER_CHANNEL;
@ -5427,14 +5513,14 @@ megasas_aen_polling(struct work_struct *work)
(i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
sdev1 = scsi_device_lookup(host,
i+MEGASAS_MAX_LD_CHANNELS,
MEGASAS_MAX_PD_CHANNELS + i,
j, 0);
if (instance->ld_ids[ld_index] !=
0xff) {
if (!sdev1) {
scsi_add_device(host,
i + 2,
MEGASAS_MAX_PD_CHANNELS + i,
j, 0);
}
}
@ -5483,18 +5569,20 @@ megasas_aen_polling(struct work_struct *work)
}
}
megasas_get_ld_list(instance);
if (megasas_ld_list_query(instance,
MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
megasas_get_ld_list(instance);
for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
ld_index =
(i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
sdev1 = scsi_device_lookup(host,
i+MEGASAS_MAX_LD_CHANNELS, j, 0);
MEGASAS_MAX_PD_CHANNELS + i, j, 0);
if (instance->ld_ids[ld_index] != 0xff) {
if (!sdev1) {
scsi_add_device(host,
i+2,
MEGASAS_MAX_PD_CHANNELS + i,
j, 0);
} else {
scsi_device_put(sdev1);

View File

@ -126,17 +126,17 @@ static u8 MR_LdDataArmGet(u32 ld, u32 armIdx, struct MR_FW_RAID_MAP_ALL *map)
return map->raidMap.ldSpanMap[ld].dataArmMap[armIdx];
}
static u16 MR_ArPdGet(u32 ar, u32 arm, struct MR_FW_RAID_MAP_ALL *map)
u16 MR_ArPdGet(u32 ar, u32 arm, struct MR_FW_RAID_MAP_ALL *map)
{
return map->raidMap.arMapInfo[ar].pd[arm];
}
static u16 MR_LdSpanArrayGet(u32 ld, u32 span, struct MR_FW_RAID_MAP_ALL *map)
u16 MR_LdSpanArrayGet(u32 ld, u32 span, struct MR_FW_RAID_MAP_ALL *map)
{
return map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef;
}
static u16 MR_PdDevHandleGet(u32 pd, struct MR_FW_RAID_MAP_ALL *map)
u16 MR_PdDevHandleGet(u32 pd, struct MR_FW_RAID_MAP_ALL *map)
{
return map->raidMap.devHndlInfo[pd].curDevHdl;
}
@ -784,7 +784,7 @@ u8
MR_BuildRaidContext(struct megasas_instance *instance,
struct IO_REQUEST_INFO *io_info,
struct RAID_CONTEXT *pRAID_Context,
struct MR_FW_RAID_MAP_ALL *map)
struct MR_FW_RAID_MAP_ALL *map, u8 **raidLUN)
{
struct MR_LD_RAID *raid;
u32 ld, stripSize, stripe_mask;
@ -977,6 +977,9 @@ MR_BuildRaidContext(struct megasas_instance *instance,
pRAID_Context->regLockRowLBA = regStart;
pRAID_Context->regLockLength = regSize;
pRAID_Context->configSeqNum = raid->seqNum;
/* save pointer to raid->LUN array */
*raidLUN = raid->LUN;
/*Get Phy Params only if FP capable, or else leave it to MR firmware
to do the calculation.*/

View File

@ -72,17 +72,6 @@ megasas_clear_intr_fusion(struct megasas_register_set __iomem *regs);
int
megasas_issue_polled(struct megasas_instance *instance,
struct megasas_cmd *cmd);
u8
MR_BuildRaidContext(struct megasas_instance *instance,
struct IO_REQUEST_INFO *io_info,
struct RAID_CONTEXT *pRAID_Context,
struct MR_FW_RAID_MAP_ALL *map);
u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map);
struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_FW_RAID_MAP_ALL *map);
u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map);
void
megasas_check_and_restore_queue_depth(struct megasas_instance *instance);
@ -652,6 +641,10 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
(instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
init_frame->driver_operations.
mfi_capabilities.support_additional_msix = 1;
/* driver supports HA / Remote LUN over Fast Path interface */
init_frame->driver_operations.mfi_capabilities.support_fp_remote_lun
= 1;
init_frame->queue_info_new_phys_addr_lo = ioc_init_handle;
init_frame->data_xfer_len = sizeof(struct MPI2_IOC_INIT_REQUEST);
@ -1410,6 +1403,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
struct IO_REQUEST_INFO io_info;
struct fusion_context *fusion;
struct MR_FW_RAID_MAP_ALL *local_map_ptr;
u8 *raidLUN;
device_id = MEGASAS_DEV_INDEX(instance, scp);
@ -1494,7 +1488,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
} else {
if (MR_BuildRaidContext(instance, &io_info,
&io_request->RaidContext,
local_map_ptr))
local_map_ptr, &raidLUN))
fp_possible = io_info.fpOkForIo;
}
@ -1537,6 +1531,8 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
scp->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG;
cmd->request_desc->SCSIIO.DevHandle = io_info.devHandle;
io_request->DevHandle = io_info.devHandle;
/* populate the LUN field */
memcpy(io_request->LUN, raidLUN, 8);
} else {
io_request->RaidContext.timeoutValue =
local_map_ptr->raidMap.fpPdIoTimeoutSec;
@ -1579,6 +1575,11 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance,
u16 pd_index = 0;
struct MR_FW_RAID_MAP_ALL *local_map_ptr;
struct fusion_context *fusion = instance->ctrl_context;
u8 span, physArm;
u16 devHandle;
u32 ld, arRef, pd;
struct MR_LD_RAID *raid;
struct RAID_CONTEXT *pRAID_Context;
io_request = cmd->io_request;
device_id = MEGASAS_DEV_INDEX(instance, scmd);
@ -1586,6 +1587,9 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance,
+scmd->device->id;
local_map_ptr = fusion->ld_map[(instance->map_id & 1)];
io_request->DataLength = scsi_bufflen(scmd);
/* Check if this is a system PD I/O */
if (scmd->device->channel < MEGASAS_MAX_PD_CHANNELS &&
instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) {
@ -1623,6 +1627,54 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance,
scmd->request->timeout / HZ;
}
} else {
if (scmd->device->channel < MEGASAS_MAX_PD_CHANNELS)
goto NonFastPath;
ld = MR_TargetIdToLdGet(device_id, local_map_ptr);
if ((ld >= MAX_LOGICAL_DRIVES) || (!fusion->fast_path_io))
goto NonFastPath;
raid = MR_LdRaidGet(ld, local_map_ptr);
/* check if this LD is FP capable */
if (!(raid->capability.fpNonRWCapable))
/* not FP capable, send as non-FP */
goto NonFastPath;
/* get RAID_Context pointer */
pRAID_Context = &io_request->RaidContext;
/* set RAID context values */
pRAID_Context->regLockFlags = REGION_TYPE_SHARED_READ;
pRAID_Context->timeoutValue = raid->fpIoTimeoutForLd;
pRAID_Context->VirtualDiskTgtId = device_id;
pRAID_Context->regLockRowLBA = 0;
pRAID_Context->regLockLength = 0;
pRAID_Context->configSeqNum = raid->seqNum;
/* get the DevHandle for the PD (since this is
fpNonRWCapable, this is a single disk RAID0) */
span = physArm = 0;
arRef = MR_LdSpanArrayGet(ld, span, local_map_ptr);
pd = MR_ArPdGet(arRef, physArm, local_map_ptr);
devHandle = MR_PdDevHandleGet(pd, local_map_ptr);
/* build request descriptor */
cmd->request_desc->SCSIIO.RequestFlags =
(MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
cmd->request_desc->SCSIIO.DevHandle = devHandle;
/* populate the LUN field */
memcpy(io_request->LUN, raid->LUN, 8);
/* build the raidScsiIO structure */
io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
io_request->DevHandle = devHandle;
return;
NonFastPath:
io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
io_request->DevHandle = device_id;
cmd->request_desc->SCSIIO.RequestFlags =
@ -1631,7 +1683,6 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance,
}
io_request->RaidContext.VirtualDiskTgtId = device_id;
io_request->LUN[1] = scmd->device->lun;
io_request->DataLength = scsi_bufflen(scmd);
}
/**

View File

@ -527,7 +527,8 @@ struct MR_LD_RAID {
u32 fpReadCapable:1;
u32 fpWriteAcrossStripe:1;
u32 fpReadAcrossStripe:1;
u32 reserved4:8;
u32 fpNonRWCapable:1;
u32 reserved4:7;
} capability;
u32 reserved6;
u64 size;
@ -551,7 +552,9 @@ struct MR_LD_RAID {
u32 reserved:31;
} flags;
u8 reserved3[0x5C];
u8 LUN[8]; /* 0x24 8 byte LUN field used for SCSI IO's */
u8 fpIoTimeoutForLd;/*0x2C timeout value used by driver in FP IO*/
u8 reserved3[0x80-0x2D]; /* 0x2D */
};
struct MR_LD_SPAN_MAP {