megaraid_sas: Print critical firmware event messages
[firefly-linux-kernel-4.4.55.git] / drivers / scsi / megaraid / megaraid_sas_base.c
index eaa81e552fd26f715122da4ee5e38427bb4ddb72..b72dce6035492275bb932fa2f154be400873c025 100644 (file)
@@ -260,6 +260,66 @@ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
 
 }
 
+static const char *
+format_timestamp(uint32_t timestamp)
+{
+       static char buffer[32];
+
+       if ((timestamp & 0xff000000) == 0xff000000)
+               snprintf(buffer, sizeof(buffer), "boot + %us", timestamp &
+               0x00ffffff);
+       else
+               snprintf(buffer, sizeof(buffer), "%us", timestamp);
+       return buffer;
+}
+
+static const char *
+format_class(int8_t class)
+{
+       static char buffer[6];
+
+       switch (class) {
+       case MFI_EVT_CLASS_DEBUG:
+               return "debug";
+       case MFI_EVT_CLASS_PROGRESS:
+               return "progress";
+       case MFI_EVT_CLASS_INFO:
+               return "info";
+       case MFI_EVT_CLASS_WARNING:
+               return "WARN";
+       case MFI_EVT_CLASS_CRITICAL:
+               return "CRIT";
+       case MFI_EVT_CLASS_FATAL:
+               return "FATAL";
+       case MFI_EVT_CLASS_DEAD:
+               return "DEAD";
+       default:
+               snprintf(buffer, sizeof(buffer), "%d", class);
+               return buffer;
+       }
+}
+
+/**
+  * megasas_decode_evt: Decode FW AEN event and print critical event
+  * for information.
+  * @instance:                 Adapter soft state
+  */
+static void
+megasas_decode_evt(struct megasas_instance *instance)
+{
+       struct megasas_evt_detail *evt_detail = instance->evt_detail;
+       union megasas_evt_class_locale class_locale;
+       class_locale.word = le32_to_cpu(evt_detail->cl.word);
+
+       if (class_locale.members.class >= MFI_EVT_CLASS_CRITICAL)
+               dev_info(&instance->pdev->dev, "%d (%s/0x%04x/%s) - %s\n",
+                       le32_to_cpu(evt_detail->seq_num),
+                       format_timestamp(le32_to_cpu(evt_detail->time_stamp)),
+                       (class_locale.members.locale),
+                       format_class(class_locale.members.class),
+                       evt_detail->description);
+}
+
 /**
 *      The following functions are defined for xscale
 *      (deviceid : 1064R, PERC5) controllers
@@ -2837,7 +2897,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
        struct megasas_header *hdr = &cmd->frame->hdr;
        unsigned long flags;
        struct fusion_context *fusion = instance->ctrl_context;
-       u32 opcode;
+       u32 opcode, status;
 
        /* flag for the retry reset */
        cmd->retry_for_fw_reset = 0;
@@ -2945,6 +3005,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
                        && (cmd->frame->dcmd.mbox.b[1] == 1)) {
                        fusion->fast_path_io = 0;
                        spin_lock_irqsave(instance->host->host_lock, flags);
+                       instance->map_update_cmd = NULL;
                        if (cmd->frame->hdr.cmd_status != 0) {
                                if (cmd->frame->hdr.cmd_status !=
                                    MFI_STAT_NOT_FOUND)
@@ -2982,6 +3043,27 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
                        spin_unlock_irqrestore(&poll_aen_lock, flags);
                }
 
+               /* FW has an updated PD sequence */
+               if ((opcode == MR_DCMD_SYSTEM_PD_MAP_GET_INFO) &&
+                       (cmd->frame->dcmd.mbox.b[0] == 1)) {
+
+                       spin_lock_irqsave(instance->host->host_lock, flags);
+                       status = cmd->frame->hdr.cmd_status;
+                       instance->jbod_seq_cmd = NULL;
+                       megasas_return_cmd(instance, cmd);
+
+                       if (status == MFI_STAT_OK) {
+                               instance->pd_seq_map_id++;
+                               /* Re-register a pd sync seq num cmd */
+                               if (megasas_sync_pd_seq_num(instance, true))
+                                       instance->use_seqnum_jbod_fp = false;
+                       } else
+                               instance->use_seqnum_jbod_fp = false;
+
+                       spin_unlock_irqrestore(instance->host->host_lock, flags);
+                       break;
+               }
+
                /*
                 * See if got an event notification
                 */
@@ -4136,6 +4218,8 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
                le32_to_cpus((u32 *)&ctrl_info->adapterOperations2);
                le32_to_cpus((u32 *)&ctrl_info->adapterOperations3);
                megasas_update_ext_vd_details(instance);
+               instance->use_seqnum_jbod_fp =
+                       ctrl_info->adapterOperations3.useSeqNumJbodFP;
                instance->is_imr = (ctrl_info->memory_size ? 0 : 1);
                dev_info(&instance->pdev->dev,
                                "controller type\t: %s(%dMB)\n",
@@ -4480,6 +4564,62 @@ megasas_destroy_irqs(struct megasas_instance *instance) {
                free_irq(instance->pdev->irq, &instance->irq_context[0]);
 }
 
+/**
+ * megasas_setup_jbod_map -    setup jbod map for FP seq_number.
+ * @instance:                          Adapter soft state
+ * @is_probe:                          Driver probe check
+ *
+ * Return 0 on success.
+ */
+void
+megasas_setup_jbod_map(struct megasas_instance *instance)
+{
+       int i;
+       struct fusion_context *fusion = instance->ctrl_context;
+       u32 pd_seq_map_sz;
+
+       pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) +
+               (sizeof(struct MR_PD_CFG_SEQ) * (MAX_PHYSICAL_DEVICES - 1));
+
+       if (reset_devices || !fusion ||
+               !instance->ctrl_info->adapterOperations3.useSeqNumJbodFP) {
+               dev_info(&instance->pdev->dev,
+                       "Jbod map is not supported %s %d\n",
+                       __func__, __LINE__);
+               instance->use_seqnum_jbod_fp = false;
+               return;
+       }
+
+       if (fusion->pd_seq_sync[0])
+               goto skip_alloc;
+
+       for (i = 0; i < JBOD_MAPS_COUNT; i++) {
+               fusion->pd_seq_sync[i] = dma_alloc_coherent
+                       (&instance->pdev->dev, pd_seq_map_sz,
+                       &fusion->pd_seq_phys[i], GFP_KERNEL);
+               if (!fusion->pd_seq_sync[i]) {
+                       dev_err(&instance->pdev->dev,
+                               "Failed to allocate memory from %s %d\n",
+                               __func__, __LINE__);
+                       if (i == 1) {
+                               dma_free_coherent(&instance->pdev->dev,
+                                       pd_seq_map_sz, fusion->pd_seq_sync[0],
+                                       fusion->pd_seq_phys[0]);
+                               fusion->pd_seq_sync[0] = NULL;
+                       }
+                       instance->use_seqnum_jbod_fp = false;
+                       return;
+               }
+       }
+
+skip_alloc:
+       if (!megasas_sync_pd_seq_num(instance, false) &&
+               !megasas_sync_pd_seq_num(instance, true))
+               instance->use_seqnum_jbod_fp = true;
+       else
+               instance->use_seqnum_jbod_fp = false;
+}
+
 /**
  * megasas_init_fw -   Initializes the FW
  * @instance:          Adapter soft state
@@ -4653,6 +4793,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
 
        dev_err(&instance->pdev->dev, "INIT adapter done\n");
 
+       megasas_setup_jbod_map(instance);
+
        /** for passthrough
         * the following function will get the PD LIST.
         */
@@ -4749,6 +4891,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
                instance->crash_dump_drv_support ? "yes" : "no");
        dev_info(&instance->pdev->dev, "secure jbod             : %s\n",
                instance->secure_jbod_support ? "yes" : "no");
+       dev_info(&instance->pdev->dev, "jbod sync map           : %s\n",
+               instance->use_seqnum_jbod_fp ? "yes" : "no");
 
 
        instance->max_sectors_per_req = instance->max_num_sge *
@@ -5506,10 +5650,14 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
 
        if (instance->aen_cmd)
                megasas_issue_blocked_abort_cmd(instance,
-                       instance->aen_cmd, 30);
+                       instance->aen_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT);
        if (instance->map_update_cmd)
                megasas_issue_blocked_abort_cmd(instance,
-                       instance->map_update_cmd, 30);
+                       instance->map_update_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT);
+       if (instance->jbod_seq_cmd)
+               megasas_issue_blocked_abort_cmd(instance,
+                       instance->jbod_seq_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT);
+
        dcmd = &cmd->frame->dcmd;
 
        memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
@@ -5674,6 +5822,7 @@ megasas_resume(struct pci_dev *pdev)
        }
 
        instance->instancet->enable_intr(instance);
+       megasas_setup_jbod_map(instance);
        instance->unload = 0;
 
        /*
@@ -5721,6 +5870,7 @@ static void megasas_detach_one(struct pci_dev *pdev)
        struct Scsi_Host *host;
        struct megasas_instance *instance;
        struct fusion_context *fusion;
+       u32 pd_seq_map_sz;
 
        instance = pci_get_drvdata(pdev);
        instance->unload = 1;
@@ -5775,6 +5925,9 @@ static void megasas_detach_one(struct pci_dev *pdev)
        case PCI_DEVICE_ID_LSI_INVADER:
        case PCI_DEVICE_ID_LSI_FURY:
                megasas_release_fusion(instance);
+                       pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) +
+                               (sizeof(struct MR_PD_CFG_SEQ) *
+                                       (MAX_PHYSICAL_DEVICES - 1));
                for (i = 0; i < 2 ; i++) {
                        if (fusion->ld_map[i])
                                dma_free_coherent(&instance->pdev->dev,
@@ -5784,6 +5937,11 @@ static void megasas_detach_one(struct pci_dev *pdev)
                        if (fusion->ld_drv_map[i])
                                free_pages((ulong)fusion->ld_drv_map[i],
                                        fusion->drv_map_pages);
+                               if (fusion->pd_seq_sync)
+                                       dma_free_coherent(&instance->pdev->dev,
+                                               pd_seq_map_sz,
+                                               fusion->pd_seq_sync[i],
+                                               fusion->pd_seq_phys[i]);
                }
                free_pages((ulong)instance->ctrl_context,
                        instance->ctrl_context_pages);
@@ -6504,6 +6662,7 @@ megasas_aen_polling(struct work_struct *work)
        instance->ev = NULL;
        host = instance->host;
        if (instance->evt_detail) {
+               megasas_decode_evt(instance);
 
                switch (le32_to_cpu(instance->evt_detail->code)) {
                case MR_EVT_PD_INSERTED: