From: Kevin Barnett
Reviewed-by: Scott Benesh
Signed-off-by: Kevin Barnett
Signed-off-by: Don Brace
---
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_RESET0x0
+#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(_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(_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_RESET0x0
-#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(_info->pci_dev->dev,
+ "PQI reset failed during quiesce with error
%d\n",
+ rc);
+ return rc;
+ }
+ }
- writel(reset_params,
- _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, _info->pqi_registers->device_reset);
+
+ rc = pqi_wait_for_pqi_reset_completion(ctrl_info);
if (rc)
dev_err(_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