scsi: smartpqi: ensure controller is in SIS mode at init
authorKevin Barnett <kevin.barnett@hpe.com>
Wed, 3 May 2017 23:52:46 +0000 (18:52 -0500)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 13 Jun 2017 00:48:02 +0000 (20:48 -0400)
put in SIS mode during initialization.
support kexec/kdump

Reviewed-by: Scott Benesh <scott.benesh@microsemi.com>
Reviewed-by: Scott Teel <scott.teel@microsemi.com>
Signed-off-by: Kevin Barnett <kevin.barnett@microsemi.com>
Signed-off-by: Don Brace <don.brace@microsemi.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/smartpqi/smartpqi.h
drivers/scsi/smartpqi/smartpqi_init.c
drivers/scsi/smartpqi/smartpqi_sis.c
drivers/scsi/smartpqi/smartpqi_sis.h

index 73754caa016116fc8a7e64cd8f12f34479c387f9..62045c1990c7141d40a90f30dd28177dddaa6074 100644 (file)
@@ -964,7 +964,7 @@ struct pqi_ctrl_info {
 };
 
 enum pqi_ctrl_mode {
-       UNKNOWN,
+       SIS_MODE = 0,
        PQI_MODE
 };
 
index 14d74e157eb54ff8c69d74ac5f9f2d751b08800c..5a5b9abe501f2cb424e29179c8b694bc6fc8f570 100644 (file)
@@ -5245,38 +5245,50 @@ out:
        return rc;
 }
 
-static int pqi_kdump_init(struct pqi_ctrl_info *ctrl_info)
+/* Switches the controller from PQI mode back into SIS mode. */
+
+static int pqi_revert_to_sis_mode(struct pqi_ctrl_info *ctrl_info)
+{
+       int rc;
+
+       sis_disable_msix(ctrl_info);
+       rc = pqi_reset(ctrl_info);
+       if (rc)
+               return rc;
+       sis_reenable_sis_mode(ctrl_info);
+       pqi_save_ctrl_mode(ctrl_info, SIS_MODE);
+
+       return 0;
+}
+
+/*
+ * If the controller isn't already in SIS mode, this function forces it into
+ * SIS mode.
+ */
+
+static int pqi_force_sis_mode(struct pqi_ctrl_info *ctrl_info)
 {
        if (!sis_is_firmware_running(ctrl_info))
                return -ENXIO;
 
-       if (pqi_get_ctrl_mode(ctrl_info) == PQI_MODE) {
-               sis_disable_msix(ctrl_info);
-               if (pqi_reset(ctrl_info) == 0)
-                       sis_reenable_sis_mode(ctrl_info);
+       if (pqi_get_ctrl_mode(ctrl_info) == SIS_MODE)
+               return 0;
+
+       if (sis_is_kernel_up(ctrl_info)) {
+               pqi_save_ctrl_mode(ctrl_info, SIS_MODE);
+               return 0;
        }
 
-       return 0;
+       return pqi_revert_to_sis_mode(ctrl_info);
 }
 
 static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
 {
        int rc;
 
-       if (reset_devices) {
-               rc = pqi_kdump_init(ctrl_info);
-               if (rc)
-                       return rc;
-       }
-
-       /*
-        * When the controller comes out of reset, it is always running
-        * in legacy SIS mode.  This is so that it can be compatible
-        * with legacy drivers shipped with OSes.  So we have to talk
-        * to it using SIS commands at first.  Once we are satisified
-        * that the controller supports PQI, we transition it into PQI
-        * mode.
-        */
+       rc = pqi_force_sis_mode(ctrl_info);
+       if (rc)
+               return rc;
 
        /*
         * Wait until the controller is ready to start accepting SIS
@@ -5594,12 +5606,8 @@ static void pqi_remove_ctrl(struct pqi_ctrl_info *ctrl_info)
        cancel_delayed_work_sync(&ctrl_info->update_time_work);
        pqi_remove_all_scsi_devices(ctrl_info);
        pqi_unregister_scsi(ctrl_info);
-
-       if (ctrl_info->pqi_mode_enabled) {
-               sis_disable_msix(ctrl_info);
-               if (pqi_reset(ctrl_info) == 0)
-                       sis_reenable_sis_mode(ctrl_info);
-       }
+       if (ctrl_info->pqi_mode_enabled)
+               pqi_revert_to_sis_mode(ctrl_info);
        pqi_free_ctrl_resources(ctrl_info);
 }
 
index c7d9ea10b02a6ecb7639c536bad72ac6bebe0646..c5325a4d0f0f7441a97d8d1ede919944b2c1742b 100644 (file)
@@ -127,6 +127,12 @@ bool sis_is_firmware_running(struct pqi_ctrl_info *ctrl_info)
        return running;
 }
 
+bool sis_is_kernel_up(struct pqi_ctrl_info *ctrl_info)
+{
+       return readl(&ctrl_info->registers->sis_firmware_status) &
+                               SIS_CTRL_KERNEL_UP;
+}
+
 /* used for passing command parameters/results when issuing SIS commands */
 struct sis_sync_cmd_params {
        u32     mailbox[6];     /* mailboxes 0-5 */
index 7f7b68ca0bd26960b9a4ce93f654a6ce39e14ca1..157768d939a99f13c6f33bf98e54a55fc6b78490 100644 (file)
@@ -21,6 +21,7 @@
 
 int sis_wait_for_ctrl_ready(struct pqi_ctrl_info *ctrl_info);
 bool sis_is_firmware_running(struct pqi_ctrl_info *ctrl_info);
+bool sis_is_kernel_up(struct pqi_ctrl_info *ctrl_info);
 int sis_get_ctrl_properties(struct pqi_ctrl_info *ctrl_info);
 int sis_get_pqi_capabilities(struct pqi_ctrl_info *ctrl_info);
 int sis_init_base_struct_addr(struct pqi_ctrl_info *ctrl_info);