[SCSI] megaraid_sas: Add Dell PowerEdge VRTX SR-IOV VF support

The following patch for megaraid_sas adds Dell PowerEdge VRTS SR-IOV VF
support (Device ID 0x002f).

This patch has some > 80 column lines that need to be left in place
for code readability purposes.

Signed-off-by: Adam Radford <aradford@gmail.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
adam radford 2014-03-10 02:51:56 -07:00 committed by James Bottomley
parent 3d0c24cd9b
commit 229fe47cd0
4 changed files with 853 additions and 120 deletions

View file

@ -48,6 +48,7 @@
#define PCI_DEVICE_ID_LSI_SAS0073SKINNY 0x0073
#define PCI_DEVICE_ID_LSI_SAS0071SKINNY 0x0071
#define PCI_DEVICE_ID_LSI_FUSION 0x005b
#define PCI_DEVICE_ID_LSI_PLASMA 0x002f
#define PCI_DEVICE_ID_LSI_INVADER 0x005d
#define PCI_DEVICE_ID_LSI_FURY 0x005f
@ -559,7 +560,8 @@ struct megasas_ctrl_info {
u8 PCIE:1;
u8 iSCSI:1;
u8 SAS_3G:1;
u8 reserved_0:4;
u8 SRIOV:1;
u8 reserved_0:3;
u8 reserved_1[6];
u8 port_count;
u64 port_addr[8];
@ -839,7 +841,12 @@ struct megasas_ctrl_info {
struct { /*7A4h */
#if defined(__BIG_ENDIAN_BITFIELD)
u32 reserved:11;
u32 reserved:5;
u32 activePassive:2;
u32 supportConfigAutoBalance:1;
u32 mpio:1;
u32 supportDataLDonSSCArray:1;
u32 supportPointInTimeProgress:1;
u32 supportUnevenSpans:1;
u32 dedicatedHotSparesLimited:1;
u32 headlessMode:1;
@ -886,7 +893,12 @@ struct megasas_ctrl_info {
u32 supportUnevenSpans:1;
u32 reserved:11;
u32 supportPointInTimeProgress:1;
u32 supportDataLDonSSCArray:1;
u32 mpio:1;
u32 supportConfigAutoBalance:1;
u32 activePassive:2;
u32 reserved:5;
#endif
} adapterOperations2;
@ -914,8 +926,14 @@ struct megasas_ctrl_info {
} cluster;
char clusterId[16]; /*7D4h */
struct {
u8 maxVFsSupported; /*0x7E4*/
u8 numVFsEnabled; /*0x7E5*/
u8 requestorId; /*0x7E6 0:PF, 1:VF1, 2:VF2*/
u8 reserved; /*0x7E7*/
} iov;
u8 pad[0x800-0x7E4]; /*7E4 */
u8 pad[0x800-0x7E8]; /*0x7E8 pad to 2k */
} __packed;
/*
@ -986,7 +1004,9 @@ struct megasas_ctrl_info {
#define MFI_OB_INTR_STATUS_MASK 0x00000002
#define MFI_POLL_TIMEOUT_SECS 60
#define MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF (5 * HZ)
#define MEGASAS_OCR_SETTLE_TIME_VF (1000 * 30)
#define MEGASAS_ROUTINE_WAIT_TIME_VF 300
#define MFI_REPLY_1078_MESSAGE_INTERRUPT 0x80000000
#define MFI_REPLY_GEN2_MESSAGE_INTERRUPT 0x00000001
#define MFI_GEN2_ENABLE_INTERRUPT_MASK (0x00000001 | 0x00000004)
@ -1529,6 +1549,12 @@ struct megasas_instance {
dma_addr_t producer_h;
u32 *consumer;
dma_addr_t consumer_h;
struct MR_LD_VF_AFFILIATION *vf_affiliation;
dma_addr_t vf_affiliation_h;
struct MR_LD_VF_AFFILIATION_111 *vf_affiliation_111;
dma_addr_t vf_affiliation_111_h;
struct MR_CTRL_HB_HOST_MEM *hb_host_mem;
dma_addr_t hb_host_mem_h;
u32 *reply_queue;
dma_addr_t reply_queue_h;
@ -1604,10 +1630,73 @@ struct megasas_instance {
unsigned long bar;
long reset_flags;
struct mutex reset_mutex;
struct timer_list sriov_heartbeat_timer;
char skip_heartbeat_timer_del;
u8 requestorId;
u64 initiator_sas_address;
u64 ld_sas_address[64];
char PlasmaFW111;
char mpio;
int throttlequeuedepth;
u8 mask_interrupts;
u8 is_imr;
};
struct MR_LD_VF_MAP {
u32 size;
union MR_LD_REF ref;
u8 ldVfCount;
u8 reserved[6];
u8 policy[1];
};
struct MR_LD_VF_AFFILIATION {
u32 size;
u8 ldCount;
u8 vfCount;
u8 thisVf;
u8 reserved[9];
struct MR_LD_VF_MAP map[1];
};
/* Plasma 1.11 FW backward compatibility structures */
#define IOV_111_OFFSET 0x7CE
#define MAX_VIRTUAL_FUNCTIONS 8
struct IOV_111 {
u8 maxVFsSupported;
u8 numVFsEnabled;
u8 requestorId;
u8 reserved[5];
};
struct MR_LD_VF_MAP_111 {
u8 targetId;
u8 reserved[3];
u8 policy[MAX_VIRTUAL_FUNCTIONS];
};
struct MR_LD_VF_AFFILIATION_111 {
u8 vdCount;
u8 vfCount;
u8 thisVf;
u8 reserved[5];
struct MR_LD_VF_MAP_111 map[MAX_LOGICAL_DRIVES];
};
struct MR_CTRL_HB_HOST_MEM {
struct {
u32 fwCounter; /* Firmware heart beat counter */
struct {
u32 debugmode:1; /* 1=Firmware is in debug mode.
Heart beat will not be updated. */
u32 reserved:31;
} debug;
u32 reserved_fw[6];
u32 driverCounter; /* Driver heart beat counter. 0x20 */
u32 reserved_driver[7];
} HB;
u8 pad[0x400-0x40];
};
enum {
MEGASAS_HBA_OPERATIONAL = 0,
@ -1615,6 +1704,7 @@ enum {
MEGASAS_ADPRESET_SM_FW_RESET_SUCCESS = 2,
MEGASAS_ADPRESET_SM_OPERATIONAL = 3,
MEGASAS_HW_CRITICAL_ERROR = 4,
MEGASAS_ADPRESET_SM_POLLING = 5,
MEGASAS_ADPRESET_INPROG_SIGN = 0xDEADDEAD,
};

View file

@ -75,6 +75,10 @@ static unsigned int msix_vectors;
module_param(msix_vectors, int, S_IRUGO);
MODULE_PARM_DESC(msix_vectors, "MSI-X max vector count. Default: Set by FW");
static int allow_vf_ioctls;
module_param(allow_vf_ioctls, int, S_IRUGO);
MODULE_PARM_DESC(allow_vf_ioctls, "Allow ioctls in SR-IOV VF mode. Default: 0");
static int throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH;
module_param(throttlequeuedepth, int, S_IRUGO);
MODULE_PARM_DESC(throttlequeuedepth,
@ -122,6 +126,8 @@ static struct pci_device_id megasas_pci_table[] = {
/* xscale IOP */
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FUSION)},
/* Fusion */
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_PLASMA)},
/* Plasma */
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INVADER)},
/* Invader */
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FURY)},
@ -132,7 +138,7 @@ static struct pci_device_id megasas_pci_table[] = {
MODULE_DEVICE_TABLE(pci, megasas_pci_table);
static int megasas_mgmt_majorno;
static struct megasas_mgmt_info megasas_mgmt_info;
struct megasas_mgmt_info megasas_mgmt_info;
static struct fasync_struct *megasas_async_queue;
static DEFINE_MUTEX(megasas_async_queue_mutex);
@ -171,10 +177,15 @@ megasas_get_map_info(struct megasas_instance *instance);
int
megasas_sync_map_info(struct megasas_instance *instance);
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);
void megasas_reset_reply_desc(struct megasas_instance *instance);
int megasas_reset_fusion(struct Scsi_Host *shost);
int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout);
void megasas_fusion_ocr_wq(struct work_struct *work);
static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
int initial);
int megasas_check_mpio_paths(struct megasas_instance *instance,
struct scsi_cmnd *scmd);
void
megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
@ -224,6 +235,7 @@ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
cmd->scmd = NULL;
cmd->frame_count = 0;
if ((instance->pdev->device != PCI_DEVICE_ID_LSI_FUSION) &&
(instance->pdev->device != PCI_DEVICE_ID_LSI_PLASMA) &&
(instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER) &&
(instance->pdev->device != PCI_DEVICE_ID_LSI_FURY) &&
(reset_devices))
@ -877,6 +889,7 @@ extern struct megasas_instance_template megasas_instance_template_fusion;
int
megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
{
int seconds;
struct megasas_header *frame_hdr = &cmd->frame->hdr;
@ -891,7 +904,11 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
/*
* Wait for cmd_status to change
*/
return wait_and_poll(instance, cmd);
if (instance->requestorId)
seconds = MEGASAS_ROUTINE_WAIT_TIME_VF;
else
seconds = MFI_POLL_TIMEOUT_SECS;
return wait_and_poll(instance, cmd, seconds);
}
/**
@ -1532,9 +1549,23 @@ megasas_queue_command_lck(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd
spin_lock_irqsave(&instance->hba_lock, flags);
/* Check for an mpio path and adjust behavior */
if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
if (megasas_check_mpio_paths(instance, scmd) ==
(DID_RESET << 16)) {
spin_unlock_irqrestore(&instance->hba_lock, flags);
return SCSI_MLQUEUE_HOST_BUSY;
} else {
spin_unlock_irqrestore(&instance->hba_lock, flags);
scmd->result = DID_NO_CONNECT << 16;
done(scmd);
return 0;
}
}
if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
spin_unlock_irqrestore(&instance->hba_lock, flags);
scmd->result = DID_ERROR << 16;
scmd->result = DID_NO_CONNECT << 16;
done(scmd);
return 0;
}
@ -1659,9 +1690,14 @@ void megaraid_sas_kill_hba(struct megasas_instance *instance)
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
writel(MFI_STOP_ADP, &instance->reg_set->doorbell);
/* Flush */
readl(&instance->reg_set->doorbell);
if (instance->mpio && instance->requestorId)
memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
} else {
writel(MFI_STOP_ADP, &instance->reg_set->inbound_doorbell);
}
@ -1748,6 +1784,25 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
megasas_check_and_restore_queue_depth(instance);
}
/**
* megasas_start_timer - Initializes a timer object
* @instance: Adapter soft state
* @timer: timer object to be initialized
* @fn: timer function
* @interval: time interval between timer function call
*
*/
void megasas_start_timer(struct megasas_instance *instance,
struct timer_list *timer,
void *fn, unsigned long interval)
{
init_timer(timer);
timer->expires = jiffies + interval;
timer->data = (unsigned long)instance;
timer->function = fn;
add_timer(timer);
}
static void
megasas_internal_reset_defer_cmds(struct megasas_instance *instance);
@ -1770,6 +1825,295 @@ void megasas_do_ocr(struct megasas_instance *instance)
process_fw_state_change_wq(&instance->work_init);
}
/* This function will get the current SR-IOV LD/VF affiliation */
static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
int initial)
{
struct megasas_cmd *cmd;
struct megasas_dcmd_frame *dcmd;
struct MR_LD_VF_AFFILIATION *new_affiliation = NULL;
struct MR_LD_VF_AFFILIATION_111 *new_affiliation_111 = NULL;
struct MR_LD_VF_MAP *newmap = NULL, *savedmap = NULL;
dma_addr_t new_affiliation_h;
dma_addr_t new_affiliation_111_h;
int ld, retval = 0;
u8 thisVf;
cmd = megasas_get_cmd(instance);
if (!cmd) {
printk(KERN_DEBUG "megasas: megasas_get_ld_vf_"
"affiliation: Failed to get cmd for scsi%d.\n",
instance->host->host_no);
return -ENOMEM;
}
dcmd = &cmd->frame->dcmd;
if (!instance->vf_affiliation && !instance->vf_affiliation_111) {
printk(KERN_WARNING "megasas: SR-IOV: Couldn't get LD/VF "
"affiliation for scsi%d.\n", instance->host->host_no);
megasas_return_cmd(instance, cmd);
return -ENOMEM;
}
if (initial)
if (instance->PlasmaFW111)
memset(instance->vf_affiliation_111, 0,
sizeof(struct MR_LD_VF_AFFILIATION_111));
else
memset(instance->vf_affiliation, 0,
(MAX_LOGICAL_DRIVES + 1) *
sizeof(struct MR_LD_VF_AFFILIATION));
else {
if (instance->PlasmaFW111)
new_affiliation_111 =
pci_alloc_consistent(instance->pdev,
sizeof(struct MR_LD_VF_AFFILIATION_111),
&new_affiliation_111_h);
else
new_affiliation =
pci_alloc_consistent(instance->pdev,
(MAX_LOGICAL_DRIVES + 1) *
sizeof(struct MR_LD_VF_AFFILIATION),
&new_affiliation_h);
if (!new_affiliation && !new_affiliation_111) {
printk(KERN_DEBUG "megasas: SR-IOV: Couldn't allocate "
"memory for new affiliation for scsi%d.\n",
instance->host->host_no);
megasas_return_cmd(instance, cmd);
return -ENOMEM;
}
if (instance->PlasmaFW111)
memset(new_affiliation_111, 0,
sizeof(struct MR_LD_VF_AFFILIATION_111));
else
memset(new_affiliation, 0, (MAX_LOGICAL_DRIVES + 1) *
sizeof(struct MR_LD_VF_AFFILIATION));
}
memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
dcmd->cmd = MFI_CMD_DCMD;
dcmd->cmd_status = 0xFF;
dcmd->sge_count = 1;
dcmd->flags = MFI_FRAME_DIR_BOTH;
dcmd->timeout = 0;
dcmd->pad_0 = 0;
if (instance->PlasmaFW111) {
dcmd->data_xfer_len = sizeof(struct MR_LD_VF_AFFILIATION_111);
dcmd->opcode = MR_DCMD_LD_VF_MAP_GET_ALL_LDS_111;
} else {
dcmd->data_xfer_len = (MAX_LOGICAL_DRIVES + 1) *
sizeof(struct MR_LD_VF_AFFILIATION);
dcmd->opcode = MR_DCMD_LD_VF_MAP_GET_ALL_LDS;
}
if (initial) {
if (instance->PlasmaFW111)
dcmd->sgl.sge32[0].phys_addr =
instance->vf_affiliation_111_h;
else
dcmd->sgl.sge32[0].phys_addr =
instance->vf_affiliation_h;
} else {
if (instance->PlasmaFW111)
dcmd->sgl.sge32[0].phys_addr = new_affiliation_111_h;
else
dcmd->sgl.sge32[0].phys_addr = new_affiliation_h;
}
if (instance->PlasmaFW111)
dcmd->sgl.sge32[0].length =
sizeof(struct MR_LD_VF_AFFILIATION_111);
else
dcmd->sgl.sge32[0].length = (MAX_LOGICAL_DRIVES + 1) *
sizeof(struct MR_LD_VF_AFFILIATION);
printk(KERN_WARNING "megasas: SR-IOV: Getting LD/VF affiliation for "
"scsi%d\n", instance->host->host_no);
megasas_issue_blocked_cmd(instance, cmd, 0);
if (dcmd->cmd_status) {
printk(KERN_WARNING "megasas: SR-IOV: LD/VF affiliation DCMD"
" failed with status 0x%x for scsi%d.\n",
dcmd->cmd_status, instance->host->host_no);
retval = 1; /* Do a scan if we couldn't get affiliation */
goto out;
}
if (!initial) {
if (instance->PlasmaFW111) {
if (!new_affiliation_111->vdCount) {
printk(KERN_WARNING "megasas: SR-IOV: Got new "
"LD/VF affiliation for passive path "
"for scsi%d.\n",
instance->host->host_no);
retval = 1;
goto out;
}
thisVf = new_affiliation_111->thisVf;
for (ld = 0 ; ld < new_affiliation_111->vdCount; ld++)
if (instance->vf_affiliation_111->map[ld].policy[thisVf] != new_affiliation_111->map[ld].policy[thisVf]) {
printk(KERN_WARNING "megasas: SR-IOV: "
"Got new LD/VF affiliation "
"for scsi%d.\n",
instance->host->host_no);
memcpy(instance->vf_affiliation_111,
new_affiliation_111,
sizeof(struct MR_LD_VF_AFFILIATION_111));
retval = 1;
goto out;
}
} else {
if (!new_affiliation->ldCount) {
printk(KERN_WARNING "megasas: SR-IOV: Got new "
"LD/VF affiliation for passive "
"path for scsi%d.\n",
instance->host->host_no);
retval = 1;
goto out;
}
newmap = new_affiliation->map;
savedmap = instance->vf_affiliation->map;
thisVf = new_affiliation->thisVf;
for (ld = 0 ; ld < new_affiliation->ldCount; ld++) {
if (savedmap->policy[thisVf] !=
newmap->policy[thisVf]) {
printk(KERN_WARNING "megasas: SR-IOV: "
"Got new LD/VF affiliation "
"for scsi%d.\n",
instance->host->host_no);
memcpy(instance->vf_affiliation,
new_affiliation,
new_affiliation->size);
retval = 1;
goto out;
}
savedmap = (struct MR_LD_VF_MAP *)
((unsigned char *)savedmap +
savedmap->size);
newmap = (struct MR_LD_VF_MAP *)
((unsigned char *)newmap +
newmap->size);
}
}
}
out:
if (new_affiliation) {
if (instance->PlasmaFW111)
pci_free_consistent(instance->pdev,
sizeof(struct MR_LD_VF_AFFILIATION_111),
new_affiliation_111,
new_affiliation_111_h);
else
pci_free_consistent(instance->pdev,
(MAX_LOGICAL_DRIVES + 1) *
sizeof(struct MR_LD_VF_AFFILIATION),
new_affiliation, new_affiliation_h);
}
megasas_return_cmd(instance, cmd);
return retval;
}
/* This function will tell FW to start the SR-IOV heartbeat */
int megasas_sriov_start_heartbeat(struct megasas_instance *instance,
int initial)
{
struct megasas_cmd *cmd;
struct megasas_dcmd_frame *dcmd;
int retval = 0;
cmd = megasas_get_cmd(instance);
if (!cmd) {
printk(KERN_DEBUG "megasas: megasas_sriov_start_heartbeat: "
"Failed to get cmd for scsi%d.\n",
instance->host->host_no);
return -ENOMEM;
}
dcmd = &cmd->frame->dcmd;
if (initial) {
instance->hb_host_mem =
pci_alloc_consistent(instance->pdev,
sizeof(struct MR_CTRL_HB_HOST_MEM),
&instance->hb_host_mem_h);
if (!instance->hb_host_mem) {
printk(KERN_DEBUG "megasas: SR-IOV: Couldn't allocate"
" memory for heartbeat host memory for "
"scsi%d.\n", instance->host->host_no);
retval = -ENOMEM;
goto out;
}
memset(instance->hb_host_mem, 0,
sizeof(struct MR_CTRL_HB_HOST_MEM));
}
memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
dcmd->mbox.s[0] = sizeof(struct MR_CTRL_HB_HOST_MEM);
dcmd->cmd = MFI_CMD_DCMD;
dcmd->cmd_status = 0xFF;
dcmd->sge_count = 1;
dcmd->flags = MFI_FRAME_DIR_BOTH;
dcmd->timeout = 0;
dcmd->pad_0 = 0;
dcmd->data_xfer_len = sizeof(struct MR_CTRL_HB_HOST_MEM);
dcmd->opcode = MR_DCMD_CTRL_SHARED_HOST_MEM_ALLOC;
dcmd->sgl.sge32[0].phys_addr = instance->hb_host_mem_h;
dcmd->sgl.sge32[0].length = sizeof(struct MR_CTRL_HB_HOST_MEM);
printk(KERN_WARNING "megasas: SR-IOV: Starting heartbeat for scsi%d\n",
instance->host->host_no);
if (!megasas_issue_polled(instance, cmd)) {
retval = 0;
} else {
printk(KERN_WARNING "megasas: SR-IOV: MR_DCMD_CTRL_SHARED_HOST"
"_MEM_ALLOC DCMD timed out for scsi%d\n",
instance->host->host_no);
retval = 1;
goto out;
}
if (dcmd->cmd_status) {
printk(KERN_WARNING "megasas: SR-IOV: MR_DCMD_CTRL_SHARED_HOST"
"_MEM_ALLOC DCMD failed with status 0x%x for scsi%d\n",
dcmd->cmd_status,
instance->host->host_no);
retval = 1;
goto out;
}
out:
megasas_return_cmd(instance, cmd);
return retval;
}
/* Handler for SR-IOV heartbeat */
void megasas_sriov_heartbeat_handler(unsigned long instance_addr)
{
struct megasas_instance *instance =
(struct megasas_instance *)instance_addr;
if (instance->hb_host_mem->HB.fwCounter !=
instance->hb_host_mem->HB.driverCounter) {
instance->hb_host_mem->HB.driverCounter =
instance->hb_host_mem->HB.fwCounter;
mod_timer(&instance->sriov_heartbeat_timer,
jiffies + MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
} else {
printk(KERN_WARNING "megasas: SR-IOV: Heartbeat never "
"completed for scsi%d\n", instance->host->host_no);
schedule_work(&instance->work_init);
}
}
/**
* megasas_wait_for_outstanding - Wait for all outstanding cmds
* @instance: Adapter soft state
@ -2032,9 +2376,10 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
* First wait for all commands to complete
*/
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
ret = megasas_reset_fusion(scmd->device->host);
ret = megasas_reset_fusion(scmd->device->host, 1);
else
ret = megasas_generic_reset(scmd);
@ -2749,6 +3094,8 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_FUSION) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_PLASMA) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_FURY)) {
@ -2772,6 +3119,8 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_FUSION) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_PLASMA) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device ==
@ -2797,6 +3146,8 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
(instance->pdev->device
== PCI_DEVICE_ID_LSI_FUSION) ||
(instance->pdev->device
== PCI_DEVICE_ID_LSI_PLASMA) ||
(instance->pdev->device
== PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device
@ -2806,6 +3157,8 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
if ((instance->pdev->device ==
PCI_DEVICE_ID_LSI_FUSION) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_PLASMA) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_FURY)) {
@ -3032,6 +3385,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
cmd->frame->io.context = cpu_to_le32(cmd->index);
cmd->frame->io.pad_0 = 0;
if ((instance->pdev->device != PCI_DEVICE_ID_LSI_FUSION) &&
(instance->pdev->device != PCI_DEVICE_ID_LSI_PLASMA) &&
(instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER) &&
(instance->pdev->device != PCI_DEVICE_ID_LSI_FURY) &&
(reset_devices))
@ -3638,6 +3992,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
struct megasas_ctrl_info *ctrl_info;
unsigned long bar_list;
int i, loop, fw_msix_count = 0;
struct IOV_111 *iovPtr;
/* Find first memory bar */
bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM);
@ -3660,6 +4015,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
switch (instance->pdev->device) {
case PCI_DEVICE_ID_LSI_FUSION:
case PCI_DEVICE_ID_LSI_PLASMA:
case PCI_DEVICE_ID_LSI_INVADER:
case PCI_DEVICE_ID_LSI_FURY:
instance->instancet = &megasas_instance_template_fusion;
@ -3714,7 +4070,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
scratch_pad_2 = readl
(&instance->reg_set->outbound_scratch_pad_2);
/* Check max MSI-X vectors */
if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) {
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA)) {
instance->msix_vectors = (scratch_pad_2
& MR_MAX_REPLY_QUEUES_OFFSET) + 1;
fw_msix_count = instance->msix_vectors;
@ -3828,6 +4185,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
/* adapterOperations2 are converted into CPU arch*/
le32_to_cpus((u32 *)&ctrl_info->adapterOperations2);
instance->mpio = ctrl_info->adapterOperations2.mpio;
instance->UnevenSpanSupport =
ctrl_info->adapterOperations2.supportUnevenSpans;
if (instance->UnevenSpanSupport) {
@ -3840,6 +4198,20 @@ static int megasas_init_fw(struct megasas_instance *instance)
fusion->fast_path_io = 0;
}
if (ctrl_info->host_interface.SRIOV) {
if (!ctrl_info->adapterOperations2.activePassive)
instance->PlasmaFW111 = 1;
if (!instance->PlasmaFW111)
instance->requestorId =
ctrl_info->iov.requestorId;
else {
iovPtr = (struct IOV_111 *)((unsigned char *)ctrl_info + IOV_111_OFFSET);
instance->requestorId = iovPtr->requestorId;
}
printk(KERN_WARNING "megaraid_sas: I am VF "
"requestorId %d\n", instance->requestorId);
}
}
instance->max_sectors_per_req = instance->max_num_sge *
PAGE_SIZE / 512;
@ -3872,6 +4244,17 @@ static int megasas_init_fw(struct megasas_instance *instance)
tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
(unsigned long)instance);
/* Launch SR-IOV heartbeat timer */
if (instance->requestorId) {
if (!megasas_sriov_start_heartbeat(instance, 1))
megasas_start_timer(instance,
&instance->sriov_heartbeat_timer,
megasas_sriov_heartbeat_handler,
MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
else
instance->skip_heartbeat_timer_del = 1;
}
return 0;
fail_init_adapter:
@ -4184,6 +4567,7 @@ static int megasas_io_attach(struct megasas_instance *instance)
/* Fusion only supports host reset */
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
host->hostt->eh_device_reset_handler = NULL;
@ -4309,6 +4693,7 @@ static int megasas_probe_one(struct pci_dev *pdev,
switch (instance->pdev->device) {
case PCI_DEVICE_ID_LSI_FUSION:
case PCI_DEVICE_ID_LSI_PLASMA:
case PCI_DEVICE_ID_LSI_INVADER:
case PCI_DEVICE_ID_LSI_FURY:
{
@ -4405,6 +4790,7 @@ static int megasas_probe_one(struct pci_dev *pdev,
instance->UnevenSpanSupport = 0;
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq);
@ -4417,6 +4803,26 @@ static int megasas_probe_one(struct pci_dev *pdev,
if (megasas_init_fw(instance))
goto fail_init_mfi;
if (instance->requestorId) {
if (instance->PlasmaFW111) {
instance->vf_affiliation_111 =
pci_alloc_consistent(pdev, sizeof(struct MR_LD_VF_AFFILIATION_111),
&instance->vf_affiliation_111_h);
if (!instance->vf_affiliation_111)
printk(KERN_WARNING "megasas: Can't allocate "
"memory for VF affiliation buffer\n");
} else {
instance->vf_affiliation =
pci_alloc_consistent(pdev,
(MAX_LOGICAL_DRIVES + 1) *
sizeof(struct MR_LD_VF_AFFILIATION),
&instance->vf_affiliation_h);
if (!instance->vf_affiliation)
printk(KERN_WARNING "megasas: Can't allocate "
"memory for VF affiliation buffer\n");
}
}
retry_irq_register:
/*
* Register IRQ
@ -4511,6 +4917,7 @@ static int megasas_probe_one(struct pci_dev *pdev,
free_irq(instance->pdev->irq, &instance->irq_context[0]);
fail_irq:
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
megasas_release_fusion(instance);
@ -4644,6 +5051,10 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
host = instance->host;
instance->unload = 1;
/* Shutdown SR-IOV heartbeat timer */
if (instance->requestorId && !instance->skip_heartbeat_timer_del)
del_timer_sync(&instance->sriov_heartbeat_timer);
megasas_flush_cache(instance);
megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN);
@ -4730,6 +5141,7 @@ megasas_resume(struct pci_dev *pdev)
switch (instance->pdev->device) {
case PCI_DEVICE_ID_LSI_FUSION:
case PCI_DEVICE_ID_LSI_PLASMA:
case PCI_DEVICE_ID_LSI_INVADER:
case PCI_DEVICE_ID_LSI_FURY:
{
@ -4795,6 +5207,17 @@ megasas_resume(struct pci_dev *pdev)
}
}
/* Re-launch SR-IOV heartbeat timer */
if (instance->requestorId) {
if (!megasas_sriov_start_heartbeat(instance, 0))
megasas_start_timer(instance,
&instance->sriov_heartbeat_timer,
megasas_sriov_heartbeat_handler,
MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
else
instance->skip_heartbeat_timer_del = 1;
}
instance->instancet->enable_intr(instance);
instance->unload = 0;
@ -4849,6 +5272,10 @@ static void megasas_detach_one(struct pci_dev *pdev)
host = instance->host;
fusion = instance->ctrl_context;
/* Shutdown SR-IOV heartbeat timer */
if (instance->requestorId && !instance->skip_heartbeat_timer_del)
del_timer_sync(&instance->sriov_heartbeat_timer);
scsi_remove_host(instance->host);
megasas_flush_cache(instance);
megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
@ -4894,6 +5321,7 @@ static void megasas_detach_one(struct pci_dev *pdev)
switch (instance->pdev->device) {
case PCI_DEVICE_ID_LSI_FUSION:
case PCI_DEVICE_ID_LSI_PLASMA:
case PCI_DEVICE_ID_LSI_INVADER:
case PCI_DEVICE_ID_LSI_FURY:
megasas_release_fusion(instance);
@ -4920,6 +5348,24 @@ static void megasas_detach_one(struct pci_dev *pdev)
if (instance->evt_detail)
pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
instance->evt_detail, instance->evt_detail_h);
if (instance->vf_affiliation)
pci_free_consistent(pdev, (MAX_LOGICAL_DRIVES + 1) *
sizeof(struct MR_LD_VF_AFFILIATION),
instance->vf_affiliation,
instance->vf_affiliation_h);
if (instance->vf_affiliation_111)
pci_free_consistent(pdev,
sizeof(struct MR_LD_VF_AFFILIATION_111),
instance->vf_affiliation_111,
instance->vf_affiliation_111_h);
if (instance->hb_host_mem)
pci_free_consistent(pdev, sizeof(struct MR_CTRL_HB_HOST_MEM),
instance->hb_host_mem,
instance->hb_host_mem_h);
scsi_host_put(host);
pci_disable_device(pdev);
@ -5208,6 +5654,16 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
goto out_kfree_ioc;
}
/* Adjust ioctl wait time for VF mode */
if (instance->requestorId)
wait_time = MEGASAS_ROUTINE_WAIT_TIME_VF;
/* Block ioctls in VF mode */
if (instance->requestorId && !allow_vf_ioctls) {
error = -ENODEV;
goto out_kfree_ioc;
}
if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
printk(KERN_ERR "Controller in crit error\n");
error = -ENODEV;
@ -5517,7 +5973,7 @@ megasas_aen_polling(struct work_struct *work)
u16 pd_index = 0;
u16 ld_index = 0;
int i, j, doscan = 0;
u32 seq_num;
u32 seq_num, wait_time = MEGASAS_RESET_WAIT_TIME;
int error;
if (!instance) {
@ -5525,6 +5981,23 @@ megasas_aen_polling(struct work_struct *work)
kfree(ev);
return;
}
/* Adjust event workqueue thread wait time for VF mode */
if (instance->requestorId)
wait_time = MEGASAS_ROUTINE_WAIT_TIME_VF;
/* Don't run the event workqueue thread if OCR is running */
for (i = 0; i < wait_time; i++) {
if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL)
break;
if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
printk(KERN_NOTICE "megasas: %s waiting for "
"controller reset to finish for scsi%d\n",
__func__, instance->host->host_no);
}
msleep(1000);
}
instance->ev = NULL;
host = instance->host;
if (instance->evt_detail) {
@ -5591,6 +6064,9 @@ megasas_aen_polling(struct work_struct *work)
case MR_EVT_LD_OFFLINE:
case MR_EVT_CFG_CLEARED:
case MR_EVT_LD_DELETED:
if (!instance->requestorId ||
(instance->requestorId &&
megasas_get_ld_vf_affiliation(instance, 0))) {
if (megasas_ld_list_query(instance,
MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
megasas_get_ld_list(instance);
@ -5602,15 +6078,12 @@ megasas_aen_polling(struct work_struct *work)
ld_index =
(i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
sdev1 = scsi_device_lookup(host,
MEGASAS_MAX_PD_CHANNELS + i,
j,
0);
sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
if (instance->ld_ids[ld_index] != 0xff) {
if (sdev1) {
if (instance->ld_ids[ld_index]
!= 0xff) {
if (sdev1)
scsi_device_put(sdev1);
}
} else {
if (sdev1) {
scsi_remove_device(sdev1);
@ -5620,8 +6093,12 @@ megasas_aen_polling(struct work_struct *work)
}
}
doscan = 0;
}
break;
case MR_EVT_LD_CREATED:
if (!instance->requestorId ||
(instance->requestorId &&
megasas_get_ld_vf_affiliation(instance, 0))) {
if (megasas_ld_list_query(instance,
MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
megasas_get_ld_list(instance);
@ -5632,24 +6109,19 @@ megasas_aen_polling(struct work_struct *work)
ld_index =
(i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
sdev1 = scsi_device_lookup(host,
MEGASAS_MAX_PD_CHANNELS + i,
j, 0);
sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
if (instance->ld_ids[ld_index] !=
0xff) {
if (!sdev1) {
scsi_add_device(host,
MEGASAS_MAX_PD_CHANNELS + i,
j, 0);
if (instance->ld_ids[ld_index]
!= 0xff) {
if (!sdev1)
scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
}
}
if (sdev1) {
if (sdev1)
scsi_device_put(sdev1);
}
}
}
doscan = 0;
}
break;
case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
case MR_EVT_FOREIGN_CFG_IMPORTED:
@ -5667,7 +6139,8 @@ megasas_aen_polling(struct work_struct *work)
}
if (doscan) {
printk(KERN_INFO "scanning ...\n");
printk(KERN_INFO "megaraid_sas: scanning for scsi%d...\n",
instance->host->host_no);
if (megasas_get_pd_list(instance) == 0) {
for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
@ -5690,24 +6163,26 @@ megasas_aen_polling(struct work_struct *work)
}
}
if (!instance->requestorId ||
(instance->requestorId &&
megasas_get_ld_vf_affiliation(instance, 0))) {
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++) {
for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL;
j++) {
ld_index =
(i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
sdev1 = scsi_device_lookup(host,
MEGASAS_MAX_PD_CHANNELS + i, j, 0);
if (instance->ld_ids[ld_index] != 0xff) {
if (!sdev1) {
scsi_add_device(host,
MEGASAS_MAX_PD_CHANNELS + i,
j, 0);
} else {
if (instance->ld_ids[ld_index]
!= 0xff) {
if (!sdev1)
scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
else
scsi_device_put(sdev1);
}
} else {
if (sdev1) {
scsi_remove_device(sdev1);
@ -5717,6 +6192,7 @@ megasas_aen_polling(struct work_struct *work)
}
}
}
}
if ( instance->aen_cmd != NULL ) {
kfree(ev);

View file

@ -62,7 +62,8 @@ megasas_complete_cmd(struct megasas_instance *instance,
struct megasas_cmd *cmd, u8 alt_status);
int megasas_is_ldio(struct scsi_cmnd *cmd);
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);
void
megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd);
@ -81,6 +82,13 @@ int megasas_transition_to_ready(struct megasas_instance *instance, int ocr);
void megaraid_sas_kill_hba(struct megasas_instance *instance);
extern u32 megasas_dbg_lvl;
void megasas_sriov_heartbeat_handler(unsigned long instance_addr);
int megasas_sriov_start_heartbeat(struct megasas_instance *instance,
int initial);
void megasas_start_timer(struct megasas_instance *instance,
struct timer_list *timer,
void *fn, unsigned long interval);
extern struct megasas_mgmt_info megasas_mgmt_info;
extern int resetwaittime;
/**
@ -549,12 +557,13 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance)
* For polling, MFI requires the cmd_status to be set to 0xFF before posting.
*/
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 i;
struct megasas_header *frame_hdr = &cmd->frame->hdr;
u32 msecs = MFI_POLL_TIMEOUT_SECS * 1000;
u32 msecs = seconds * 1000;
/*
* Wait for cmd_status to change
@ -672,7 +681,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
instance->instancet->fire_cmd(instance, req_desc.u.low,
req_desc.u.high, instance->reg_set);
wait_and_poll(instance, cmd);
wait_and_poll(instance, cmd, MFI_POLL_TIMEOUT_SECS);
frame_hdr = &cmd->frame->hdr;
if (frame_hdr->cmd_status != 0) {
@ -1772,7 +1781,8 @@ megasas_get_request_descriptor(struct megasas_instance *instance, u16 index)
if (index >= instance->max_fw_cmds) {
printk(KERN_ERR "megasas: Invalid SMID (0x%x)request for "
"descriptor\n", index);
"descriptor for scsi%d\n", index,
instance->host->host_no);
return NULL;
}
fusion = instance->ctrl_context;
@ -2040,9 +2050,12 @@ irqreturn_t megasas_isr_fusion(int irq, void *devp)
/* If we didn't complete any commands, check for FW fault */
fw_state = instance->instancet->read_fw_status_reg(
instance->reg_set) & MFI_STATE_MASK;
if (fw_state == MFI_STATE_FAULT)
if (fw_state == MFI_STATE_FAULT) {
printk(KERN_WARNING "megaraid_sas: Iop2SysDoorbellInt"
"for scsi%d\n", instance->host->host_no);
schedule_work(&instance->work_init);
}
}
return IRQ_HANDLED;
}
@ -2212,9 +2225,10 @@ megasas_check_reset_fusion(struct megasas_instance *instance,
}
/* This function waits for outstanding commands on fusion to complete */
int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance)
int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
int iotimeout, int *convert)
{
int i, outstanding, retval = 0;
int i, outstanding, retval = 0, hb_seconds_missed = 0;
u32 fw_state;
for (i = 0; i < resetwaittime; i++) {
@ -2223,10 +2237,40 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance)
instance->reg_set) & MFI_STATE_MASK;
if (fw_state == MFI_STATE_FAULT) {
printk(KERN_WARNING "megasas: Found FW in FAULT state,"
" will reset adapter.\n");
" will reset adapter scsi%d.\n",
instance->host->host_no);
retval = 1;
goto out;
}
/* If SR-IOV VF mode & heartbeat timeout, don't wait */
if (instance->requestorId && !iotimeout) {
retval = 1;
goto out;
}
/* If SR-IOV VF mode & I/O timeout, check for HB timeout */
if (instance->requestorId && iotimeout) {
if (instance->hb_host_mem->HB.fwCounter !=
instance->hb_host_mem->HB.driverCounter) {
instance->hb_host_mem->HB.driverCounter =
instance->hb_host_mem->HB.fwCounter;
hb_seconds_missed = 0;
} else {
hb_seconds_missed++;
if (hb_seconds_missed ==
(MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF/HZ)) {
printk(KERN_WARNING "megasas: SR-IOV:"
" Heartbeat never completed "
" while polling during I/O "
" timeout handling for "
"scsi%d.\n",
instance->host->host_no);
*convert = 1;
retval = 1;
goto out;
}
}
}
outstanding = atomic_read(&instance->fw_outstanding);
if (!outstanding)
@ -2234,7 +2278,8 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance)
if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
printk(KERN_NOTICE "megasas: [%2d]waiting for %d "
"commands to complete\n", i, outstanding);
"commands to complete for scsi%d\n", i,
outstanding, instance->host->host_no);
megasas_complete_cmd_dpc_fusion(
(unsigned long)instance);
}
@ -2243,7 +2288,8 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance)
if (atomic_read(&instance->fw_outstanding)) {
printk("megaraid_sas: pending commands remain after waiting, "
"will reset adapter.\n");
"will reset adapter scsi%d.\n",
instance->host->host_no);
retval = 1;
}
out:
@ -2265,10 +2311,34 @@ void megasas_reset_reply_desc(struct megasas_instance *instance)
reply_desc->Words = ULLONG_MAX;
}
/* Core fusion reset function */
int megasas_reset_fusion(struct Scsi_Host *shost)
/* Check for a second path that is currently UP */
int megasas_check_mpio_paths(struct megasas_instance *instance,
struct scsi_cmnd *scmd)
{
int retval = SUCCESS, i, j, retry = 0;
int i, j, retval = (DID_RESET << 16);
if (instance->mpio && instance->requestorId) {
for (i = 0 ; i < MAX_MGMT_ADAPTERS ; i++)
for (j = 0 ; j < MAX_LOGICAL_DRIVES; j++)
if (megasas_mgmt_info.instance[i] &&
(megasas_mgmt_info.instance[i] != instance) &&
megasas_mgmt_info.instance[i]->mpio &&
megasas_mgmt_info.instance[i]->requestorId
&&
(megasas_mgmt_info.instance[i]->ld_ids[j]
== scmd->device->id)) {
retval = (DID_NO_CONNECT << 16);
goto out;
}
}
out:
return retval;
}
/* Core fusion reset function */
int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
{
int retval = SUCCESS, i, j, retry = 0, convert = 0;
struct megasas_instance *instance;
struct megasas_cmd_fusion *cmd_fusion;
struct fusion_context *fusion;
@ -2279,28 +2349,39 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
instance = (struct megasas_instance *)shost->hostdata;
fusion = instance->ctrl_context;
mutex_lock(&instance->reset_mutex);
if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
printk(KERN_WARNING "megaraid_sas: Hardware critical error, "
"returning FAILED.\n");
"returning FAILED for scsi%d.\n",
instance->host->host_no);
return FAILED;
}
mutex_lock(&instance->reset_mutex);
if (instance->requestorId && !instance->skip_heartbeat_timer_del)
del_timer_sync(&instance->sriov_heartbeat_timer);
set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
instance->adprecovery = MEGASAS_ADPRESET_SM_POLLING;
instance->instancet->disable_intr(instance);
msleep(1000);
/* First try waiting for commands to complete */
if (megasas_wait_for_outstanding_fusion(instance)) {
if (megasas_wait_for_outstanding_fusion(instance, iotimeout,
&convert)) {
instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
printk(KERN_WARNING "megaraid_sas: resetting fusion "
"adapter.\n");
"adapter scsi%d.\n", instance->host->host_no);
if (convert)
iotimeout = 0;
/* Now return commands back to the OS */
for (i = 0 ; i < instance->max_fw_cmds; i++) {
cmd_fusion = fusion->cmd_list[i];
if (cmd_fusion->scmd) {
scsi_dma_unmap(cmd_fusion->scmd);
cmd_fusion->scmd->result = (DID_RESET << 16);
cmd_fusion->scmd->result =
megasas_check_mpio_paths(instance,
cmd_fusion->scmd);
cmd_fusion->scmd->scsi_done(cmd_fusion->scmd);
megasas_return_cmd_fusion(instance, cmd_fusion);
atomic_dec(&instance->fw_outstanding);
@ -2315,13 +2396,67 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
(abs_state == MFI_STATE_FAULT && !reset_adapter)) {
/* Reset not supported, kill adapter */
printk(KERN_WARNING "megaraid_sas: Reset not supported"
", killing adapter.\n");
", killing adapter scsi%d.\n",
instance->host->host_no);
megaraid_sas_kill_hba(instance);
instance->skip_heartbeat_timer_del = 1;
instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
retval = FAILED;
goto out;
}
/* Let SR-IOV VF & PF sync up if there was a HB failure */
if (instance->requestorId && !iotimeout) {
msleep(MEGASAS_OCR_SETTLE_TIME_VF);
/* Look for a late HB update after VF settle time */
if (abs_state == MFI_STATE_OPERATIONAL &&
(instance->hb_host_mem->HB.fwCounter !=
instance->hb_host_mem->HB.driverCounter)) {
instance->hb_host_mem->HB.driverCounter =
instance->hb_host_mem->HB.fwCounter;
printk(KERN_WARNING "megasas: SR-IOV:"
"Late FW heartbeat update for "
"scsi%d.\n",
instance->host->host_no);
} else {
/* In VF mode, first poll for FW ready */
for (i = 0;
i < (MEGASAS_RESET_WAIT_TIME * 1000);
i += 20) {
status_reg =
instance->instancet->
read_fw_status_reg(
instance->reg_set);
abs_state = status_reg &
MFI_STATE_MASK;
if (abs_state == MFI_STATE_READY) {
printk(KERN_WARNING "megasas"
": SR-IOV: FW was found"
"to be in ready state "
"for scsi%d.\n",
instance->host->host_no);
break;
}
msleep(20);
}
if (abs_state != MFI_STATE_READY) {
printk(KERN_WARNING "megasas: SR-IOV: "
"FW not in ready state after %d"
" seconds for scsi%d, status_reg = "
"0x%x.\n",
MEGASAS_RESET_WAIT_TIME,
instance->host->host_no,
status_reg);
megaraid_sas_kill_hba(instance);
instance->skip_heartbeat_timer_del = 1;
instance->adprecovery =
MEGASAS_HW_CRITICAL_ERROR;
retval = FAILED;
goto out;
}
}
}
/* Now try to reset the chip */
for (i = 0; i < MEGASAS_FUSION_MAX_RESET_TRIES; i++) {
writel(MPI2_WRSEQ_FLUSH_KEY_VALUE,
@ -2348,7 +2483,9 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
readl(&instance->reg_set->fusion_host_diag);
if (retry++ == 100) {
printk(KERN_WARNING "megaraid_sas: "
"Host diag unlock failed!\n");
"Host diag unlock failed! "
"for scsi%d\n",
instance->host->host_no);
break;
}
}
@ -2370,7 +2507,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
if (retry++ == 1000) {
printk(KERN_WARNING "megaraid_sas: "
"Diag reset adapter never "
"cleared!\n");
"cleared for scsi%d!\n",
instance->host->host_no);
break;
}
}
@ -2392,29 +2530,29 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
if (abs_state <= MFI_STATE_FW_INIT) {
printk(KERN_WARNING "megaraid_sas: firmware "
"state < MFI_STATE_FW_INIT, state = "
"0x%x\n", abs_state);
"0x%x for scsi%d\n", abs_state,
instance->host->host_no);
continue;
}
/* Wait for FW to become ready */
if (megasas_transition_to_ready(instance, 1)) {
printk(KERN_WARNING "megaraid_sas: Failed to "
"transition controller to ready.\n");
"transition controller to ready "
"for scsi%d.\n",
instance->host->host_no);
continue;
}
megasas_reset_reply_desc(instance);
if (megasas_ioc_init_fusion(instance)) {
printk(KERN_WARNING "megaraid_sas: "
"megasas_ioc_init_fusion() failed!\n");
"megasas_ioc_init_fusion() failed!"
" for scsi%d\n",
instance->host->host_no);
continue;
}
clear_bit(MEGASAS_FUSION_IN_RESET,
&instance->reset_flags);
instance->instancet->enable_intr(instance);
instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
/* Re-fire management commands */
for (j = 0 ; j < instance->max_fw_cmds; j++) {
cmd_fusion = fusion->cmd_list[j];
@ -2438,7 +2576,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
if (!req_desc) {
printk(KERN_WARNING
"req_desc NULL"
"\n");
" for scsi%d\n",
instance->host->host_no);
/* Return leaked MPT
frame */
megasas_return_cmd_fusion(instance, cmd_fusion);
@ -2456,6 +2595,11 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
}
}
clear_bit(MEGASAS_FUSION_IN_RESET,
&instance->reset_flags);
instance->instancet->enable_intr(instance);
instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
/* Reset load balance info */
memset(fusion->load_balance_info, 0,
sizeof(struct LD_LOAD_BALANCE_INFO)
@ -2464,19 +2608,39 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
if (!megasas_get_map_info(instance))
megasas_sync_map_info(instance);
/* Restart SR-IOV heartbeat */
if (instance->requestorId) {
if (!megasas_sriov_start_heartbeat(instance, 0))
megasas_start_timer(instance,
&instance->sriov_heartbeat_timer,
megasas_sriov_heartbeat_handler,
MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
else
instance->skip_heartbeat_timer_del = 1;
}
/* Adapter reset completed successfully */
printk(KERN_WARNING "megaraid_sas: Reset "
"successful.\n");
"successful for scsi%d.\n",
instance->host->host_no);
retval = SUCCESS;
goto out;
}
/* Reset failed, kill the adapter */
printk(KERN_WARNING "megaraid_sas: Reset failed, killing "
"adapter.\n");
"adapter scsi%d.\n", instance->host->host_no);
megaraid_sas_kill_hba(instance);
instance->skip_heartbeat_timer_del = 1;
instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
retval = FAILED;
} else {
/* For VF: Restart HB timer if we didn't OCR */
if (instance->requestorId) {
megasas_start_timer(instance,
&instance->sriov_heartbeat_timer,
megasas_sriov_heartbeat_handler,
MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
}
clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
instance->instancet->enable_intr(instance);
instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
@ -2493,7 +2657,7 @@ void megasas_fusion_ocr_wq(struct work_struct *work)
struct megasas_instance *instance =
container_of(work, struct megasas_instance, work_init);
megasas_reset_fusion(instance->host);
megasas_reset_fusion(instance->host, 0);
}
struct megasas_instance_template megasas_instance_template_fusion = {

View file

@ -485,6 +485,9 @@ struct MPI2_IOC_INIT_REQUEST {
#define MAX_PHYSICAL_DEVICES 256
#define MAX_RAIDMAP_PHYSICAL_DEVICES (MAX_PHYSICAL_DEVICES)
#define MR_DCMD_LD_MAP_GET_INFO 0x0300e101
#define MR_DCMD_CTRL_SHARED_HOST_MEM_ALLOC 0x010e8485 /* SR-IOV HB alloc*/
#define MR_DCMD_LD_VF_MAP_GET_ALL_LDS_111 0x03200200
#define MR_DCMD_LD_VF_MAP_GET_ALL_LDS 0x03150200
struct MR_DEV_HANDLE_INFO {
u16 curDevHdl;