From: Kevin Barnett <kevin.barn...@microseim.com>

Reviewed-by: Scott Benesh <scott.ben...@microsemi.com>
Signed-off-by: Kevin Barnett <kevin.barn...@microsemi.com>
Signed-off-by: Don Brace <don.br...@microsemi.com>
---
 drivers/scsi/smartpqi/smartpqi.h      |   23 +++++++++++++
 drivers/scsi/smartpqi/smartpqi_init.c |   58 ++++++++++++++++++++++++++-------
 drivers/scsi/smartpqi/smartpqi_sis.c  |   30 ++++++++++++++++-
 drivers/scsi/smartpqi/smartpqi_sis.h  |    1 +
 4 files changed, 98 insertions(+), 14 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index e164ffa..6dd0449 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -688,6 +688,28 @@ struct pqi_config_table_heartbeat {
        __le32  heartbeat_counter;
 };
 
+union pqi_reset_register {
+       struct {
+               u32     reset_type : 3;
+               u32     reserved : 2;
+               u32     reset_action : 3;
+               u32     hold_in_pd1 : 1;
+               u32     reserved2 : 23;
+       } bits;
+       u32     all_bits;
+};
+
+#define PQI_RESET_ACTION_RESET         0x1
+
+#define PQI_RESET_TYPE_NO_RESET                0x0
+#define PQI_RESET_TYPE_SOFT_RESET      0x1
+#define PQI_RESET_TYPE_FIRM_RESET      0x2
+#define PQI_RESET_TYPE_HARD_RESET      0x3
+
+#define PQI_RESET_ACTION_COMPLETED     0x2
+
+#define PQI_RESET_POLL_INTERVAL_MSECS  100
+
 #define PQI_MAX_OUTSTANDING_REQUESTS           ((u32)~0)
 #define PQI_MAX_OUTSTANDING_REQUESTS_KDUMP     32
 #define PQI_MAX_TRANSFER_SIZE                  (1024U * 1024U)
@@ -995,6 +1017,7 @@ struct pqi_ctrl_info {
        u8              inbound_spanning_supported : 1;
        u8              outbound_spanning_supported : 1;
        u8              pqi_mode_enabled : 1;
+       u8              pqi_reset_quiesce_supported : 1;
 
        struct list_head scsi_device_list;
        spinlock_t      scsi_device_list_lock;
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index cb8f886..ffdc32b 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -5889,28 +5889,62 @@ static void pqi_unregister_scsi(struct pqi_ctrl_info 
*ctrl_info)
        scsi_host_put(shost);
 }
 
-#define PQI_RESET_ACTION_RESET         0x1
+static int pqi_wait_for_pqi_reset_completion(struct pqi_ctrl_info *ctrl_info)
+{
+       int rc = 0;
+       struct pqi_device_registers __iomem *pqi_registers;
+       unsigned long timeout;
+       unsigned int timeout_msecs;
+       union pqi_reset_register reset_reg;
+
+       pqi_registers = ctrl_info->pqi_registers;
+       timeout_msecs = readw(&pqi_registers->max_reset_timeout) * 100;
+       timeout = msecs_to_jiffies(timeout_msecs) + jiffies;
+
+       while (1) {
+               msleep(PQI_RESET_POLL_INTERVAL_MSECS);
+               reset_reg.all_bits = readl(&pqi_registers->device_reset);
+               if (reset_reg.bits.reset_action == PQI_RESET_ACTION_COMPLETED)
+                       break;
+               pqi_check_ctrl_health(ctrl_info);
+               if (pqi_ctrl_offline(ctrl_info)) {
+                       rc = -ENXIO;
+                       break;
+               }
+               if (time_after(jiffies, timeout)) {
+                       rc = -ETIMEDOUT;
+                       break;
+               }
+       }
 
-#define PQI_RESET_TYPE_NO_RESET                0x0
-#define PQI_RESET_TYPE_SOFT_RESET      0x1
-#define PQI_RESET_TYPE_FIRM_RESET      0x2
-#define PQI_RESET_TYPE_HARD_RESET      0x3
+       return rc;
+}
 
 static int pqi_reset(struct pqi_ctrl_info *ctrl_info)
 {
        int rc;
-       u32 reset_params;
+       union pqi_reset_register reset_reg;
 
-       reset_params = (PQI_RESET_ACTION_RESET << 5) |
-               PQI_RESET_TYPE_HARD_RESET;
+       if (ctrl_info->pqi_reset_quiesce_supported) {
+               rc = sis_pqi_reset_quiesce(ctrl_info);
+               if (rc) {
+                       dev_err(&ctrl_info->pci_dev->dev,
+                               "PQI reset failed during quiesce with error 
%d\n",
+                               rc);
+                       return rc;
+               }
+       }
 
-       writel(reset_params,
-               &ctrl_info->pqi_registers->device_reset);
+       reset_reg.all_bits = 0;
+       reset_reg.bits.reset_type = PQI_RESET_TYPE_HARD_RESET;
+       reset_reg.bits.reset_action = PQI_RESET_ACTION_RESET;
 
-       rc = pqi_wait_for_pqi_mode_ready(ctrl_info);
+       writel(reset_reg.all_bits, &ctrl_info->pqi_registers->device_reset);
+
+       rc = pqi_wait_for_pqi_reset_completion(ctrl_info);
        if (rc)
                dev_err(&ctrl_info->pci_dev->dev,
-                       "PQI reset failed\n");
+                       "PQI reset failed with error %d\n", rc);
 
        return rc;
 }
diff --git a/drivers/scsi/smartpqi/smartpqi_sis.c 
b/drivers/scsi/smartpqi/smartpqi_sis.c
index e55dfcf..9abbace 100644
--- a/drivers/scsi/smartpqi/smartpqi_sis.c
+++ b/drivers/scsi/smartpqi/smartpqi_sis.c
@@ -36,6 +36,7 @@
 #define SIS_ENABLE_INTX                                0x80
 #define SIS_SOFT_RESET                         0x100
 #define SIS_TRIGGER_SHUTDOWN                   0x800000
+#define SIS_PQI_RESET_QUIESCE                  0x1000000
 #define SIS_CMD_READY                          0x200
 #define SIS_CMD_COMPLETE                       0x1000
 #define SIS_CLEAR_CTRL_TO_HOST_DOORBELL                0x1000
@@ -47,6 +48,7 @@
 #define SIS_EXTENDED_PROPERTIES_SUPPORTED      0x800000
 #define SIS_SMARTARRAY_FEATURES_SUPPORTED      0x2
 #define SIS_PQI_MODE_SUPPORTED                 0x4
+#define SIS_PQI_RESET_QUIESCE_SUPPORTED                0x8
 #define SIS_REQUIRED_EXTENDED_PROPERTIES       \
        (SIS_SMARTARRAY_FEATURES_SUPPORTED | SIS_PQI_MODE_SUPPORTED)
 
@@ -258,6 +260,9 @@ int sis_get_ctrl_properties(struct pqi_ctrl_info *ctrl_info)
                SIS_REQUIRED_EXTENDED_PROPERTIES)
                return -ENODEV;
 
+       if (extended_properties & SIS_PQI_RESET_QUIESCE_SUPPORTED)
+               ctrl_info->pqi_reset_quiesce_supported = true;
+
        return 0;
 }
 
@@ -336,9 +341,10 @@ int sis_init_base_struct_addr(struct pqi_ctrl_info 
*ctrl_info)
 
 #define SIS_DOORBELL_BIT_CLEAR_TIMEOUT_SECS    30
 
-static void sis_wait_for_doorbell_bit_to_clear(
+static int sis_wait_for_doorbell_bit_to_clear(
        struct pqi_ctrl_info *ctrl_info, u32 bit)
 {
+       int rc = 0;
        u32 doorbell_register;
        unsigned long timeout;
 
@@ -350,16 +356,21 @@ static void sis_wait_for_doorbell_bit_to_clear(
                if ((doorbell_register & bit) == 0)
                        break;
                if (readl(&ctrl_info->registers->sis_firmware_status) &
-                       SIS_CTRL_KERNEL_PANIC)
+                       SIS_CTRL_KERNEL_PANIC) {
+                       rc = -ENODEV;
                        break;
+               }
                if (time_after(jiffies, timeout)) {
                        dev_err(&ctrl_info->pci_dev->dev,
                                "doorbell register bit 0x%x not cleared\n",
                                bit);
+                       rc = -ETIMEDOUT;
                        break;
                }
                usleep_range(1000, 2000);
        }
+
+       return rc;
 }
 
 /* Enable MSI-X interrupts on the controller. */
@@ -434,6 +445,21 @@ void sis_shutdown_ctrl(struct pqi_ctrl_info *ctrl_info)
                &ctrl_info->registers->sis_host_to_ctrl_doorbell);
 }
 
+int sis_pqi_reset_quiesce(struct pqi_ctrl_info *ctrl_info)
+{
+       u32 doorbell_register;
+
+       doorbell_register =
+               readl(&ctrl_info->registers->sis_host_to_ctrl_doorbell);
+       doorbell_register |= SIS_PQI_RESET_QUIESCE;
+
+       writel(doorbell_register,
+               &ctrl_info->registers->sis_host_to_ctrl_doorbell);
+
+       return sis_wait_for_doorbell_bit_to_clear(ctrl_info,
+               SIS_PQI_RESET_QUIESCE);
+}
+
 #define SIS_MODE_READY_TIMEOUT_SECS    30
 
 int sis_reenable_sis_mode(struct pqi_ctrl_info *ctrl_info)
diff --git a/drivers/scsi/smartpqi/smartpqi_sis.h 
b/drivers/scsi/smartpqi/smartpqi_sis.h
index 983184b..394b16e 100644
--- a/drivers/scsi/smartpqi/smartpqi_sis.h
+++ b/drivers/scsi/smartpqi/smartpqi_sis.h
@@ -32,6 +32,7 @@ void sis_enable_intx(struct pqi_ctrl_info *ctrl_info);
 void sis_disable_intx(struct pqi_ctrl_info *ctrl_info);
 void sis_soft_reset(struct pqi_ctrl_info *ctrl_info);
 void sis_shutdown_ctrl(struct pqi_ctrl_info *ctrl_info);
+int sis_pqi_reset_quiesce(struct pqi_ctrl_info *ctrl_info);
 int sis_reenable_sis_mode(struct pqi_ctrl_info *ctrl_info);
 void sis_write_driver_scratch(struct pqi_ctrl_info *ctrl_info, u32 value);
 u32 sis_read_driver_scratch(struct pqi_ctrl_info *ctrl_info);

Reply via email to