[PATCH 4/5] megaraid_sas: Add Dell PowerEdge VRTX SR-IOV VF support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



James/linux-scsi,

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@xxxxxxxxx>

diff -Naur scsi-misc.old/drivers/scsi/megaraid/megaraid_sas_base.c
scsi-misc.new/drivers/scsi/megaraid/megaraid_sas_base.c
--- scsi-misc.old/drivers/scsi/megaraid/megaraid_sas_base.c 2014-03-09
21:07:03.892980883 -0700
+++ scsi-misc.new/drivers/scsi/megaraid/megaraid_sas_base.c 2014-03-10
01:12:05.516855851 -0700
@@ -75,6 +75,10 @@
 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 @@
  /* 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 @@
 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 @@
 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 @@
  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 @@
 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 @@
  /*
  * 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 @@

  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 @@
  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 @@
  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 @@
  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 @@
  * 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 @@
  (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)) {
@@ -2773,6 +3120,8 @@
     (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)) {
@@ -2798,6 +3147,8 @@
  (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)) {
@@ -2806,6 +3157,8 @@
  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 @@
  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 @@
  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 @@

  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 @@
  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;
@@ -3825,6 +4182,7 @@
  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) {
@@ -3837,6 +4195,20 @@
  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;
@@ -3869,6 +4241,17 @@
  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:
@@ -4181,6 +4564,7 @@

  /* 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;
@@ -4306,6 +4690,7 @@

  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:
  {
@@ -4402,6 +4787,7 @@
  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);
@@ -4414,6 +4800,26 @@
  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
@@ -4508,6 +4914,7 @@
  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);
@@ -4641,6 +5048,10 @@
  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);

@@ -4727,6 +5138,7 @@

  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:
  {
@@ -4792,6 +5204,17 @@
  }
  }

+ /* 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;

@@ -4846,6 +5269,10 @@
  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);
@@ -4891,6 +5318,7 @@

  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);
@@ -4917,6 +5345,24 @@
  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);
@@ -5205,6 +5651,16 @@
  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;
@@ -5514,7 +5970,7 @@
  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) {
@@ -5522,6 +5978,23 @@
  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) {
@@ -5588,65 +6061,64 @@
  case MR_EVT_LD_OFFLINE:
  case MR_EVT_CFG_CLEARED:
  case MR_EVT_LD_DELETED:
- 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,
- MEGASAS_MAX_PD_CHANNELS + i,
- j,
- 0);
-
- if (instance->ld_ids[ld_index] != 0xff) {
- if (sdev1) {
- scsi_device_put(sdev1);
- }
- } else {
- if (sdev1) {
- scsi_remove_device(sdev1);
- scsi_device_put(sdev1);
+ 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++) {
+
+ 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_device_put(sdev1);
+ } else {
+ if (sdev1) {
+ scsi_remove_device(sdev1);
+ scsi_device_put(sdev1);
+ }
+ }
  }
  }
- }
+ doscan = 0;
  }
- doscan = 0;
  break;
  case MR_EVT_LD_CREATED:
- 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,
- 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->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++) {
+ 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);
  }
- }
- if (sdev1) {
- scsi_device_put(sdev1);
+ if (sdev1)
+ scsi_device_put(sdev1);
  }
  }
+ doscan = 0;
  }
- doscan = 0;
  break;
  case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
  case MR_EVT_FOREIGN_CFG_IMPORTED:
@@ -5664,7 +6136,8 @@
  }

  if (doscan) {
- printk(KERN_INFO "scanning ...\n");
+ printk(KERN_INFO "megaraid_sas: scanning for scsi%d...\n",
+       instance->host->host_no);
  megasas_get_pd_list(instance);
  for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
  for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
@@ -5686,28 +6159,31 @@
  }
  }

- 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;
+ 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++) {
+ 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);
+ 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
+ scsi_device_put(sdev1);
  } else {
- scsi_device_put(sdev1);
- }
- } else {
- if (sdev1) {
- scsi_remove_device(sdev1);
- scsi_device_put(sdev1);
+ if (sdev1) {
+ scsi_remove_device(sdev1);
+ scsi_device_put(sdev1);
+ }
  }
  }
  }
diff -Naur scsi-misc.old/drivers/scsi/megaraid/megaraid_sas_fusion.c
scsi-misc.new/drivers/scsi/megaraid/megaraid_sas_fusion.c
--- scsi-misc.old/drivers/scsi/megaraid/megaraid_sas_fusion.c
2014-03-09 21:46:54.385918392 -0700
+++ scsi-misc.new/drivers/scsi/megaraid/megaraid_sas_fusion.c
2014-03-10 01:13:30.065856275 -0700
@@ -62,7 +62,8 @@
      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 @@
 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 @@
  * 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
@@ -669,7 +678,7 @@
  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) {
@@ -1769,7 +1778,8 @@

  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;
@@ -2037,8 +2047,11 @@
  /* 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;
@@ -2209,9 +2222,10 @@
 }

 /* 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++) {
@@ -2220,18 +2234,49 @@
  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)
  goto out;

  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);
  }
@@ -2240,7 +2285,8 @@

  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:
@@ -2262,10 +2308,34 @@
  reply_desc->Words = ULLONG_MAX;
 }

+/* Check for a second path that is currently UP */
+int megasas_check_mpio_paths(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd)
+{
+ 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 megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
 {
- int retval = SUCCESS, i, j, retry = 0;
+ int retval = SUCCESS, i, j, retry = 0, convert = 0;
  struct megasas_instance *instance;
  struct megasas_cmd_fusion *cmd_fusion;
  struct fusion_context *fusion;
@@ -2276,28 +2346,39 @@
  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);
@@ -2312,13 +2393,67 @@
     (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,
@@ -2345,7 +2480,9 @@
  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;
  }
  }
@@ -2367,7 +2504,8 @@
  if (retry++ == 1000) {
  printk(KERN_WARNING "megaraid_sas: "
        "Diag reset adapter never "
-       "cleared!\n");
+       "cleared for scsi%d!\n",
+ instance->host->host_no);
  break;
  }
  }
@@ -2389,29 +2527,29 @@
  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];
@@ -2435,7 +2573,8 @@
  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);
@@ -2453,6 +2592,11 @@
  }
  }

+ 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)
@@ -2461,19 +2605,39 @@
  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;
@@ -2490,7 +2654,7 @@
  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 = {
diff -Naur scsi-misc.old/drivers/scsi/megaraid/megaraid_sas_fusion.h
scsi-misc.new/drivers/scsi/megaraid/megaraid_sas_fusion.h
--- scsi-misc.old/drivers/scsi/megaraid/megaraid_sas_fusion.h
2014-03-09 14:53:05.000000000 -0700
+++ scsi-misc.new/drivers/scsi/megaraid/megaraid_sas_fusion.h
2014-03-10 00:28:34.934856617 -0700
@@ -485,6 +485,9 @@
 #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;
diff -Naur scsi-misc.old/drivers/scsi/megaraid/megaraid_sas.h
scsi-misc.new/drivers/scsi/megaraid/megaraid_sas.h
--- scsi-misc.old/drivers/scsi/megaraid/megaraid_sas.h 2014-03-09
21:06:56.499856130 -0700
+++ scsi-misc.new/drivers/scsi/megaraid/megaraid_sas.h 2014-03-10
00:28:04.993856106 -0700
@@ -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 @@
  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 {                                /*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 @@


  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 @@
  } 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 @@

 #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 @@
  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 @@
  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 @@
  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,
 };

Attachment: megaraid_sas.patch4
Description: Binary data


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux