Commit 336b6819 authored by Kevin Barnett's avatar Kevin Barnett Committed by Martin K. Petersen

scsi: smartpqi: add pqi reset quiesce support

Reviewed-by: default avatarScott Benesh <scott.benesh@microsemi.com>
Signed-off-by: default avatarKevin Barnett <kevin.barnett@microsemi.com>
Signed-off-by: default avatarDon Brace <don.brace@microsemi.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 0b7250f9
...@@ -688,6 +688,28 @@ struct pqi_config_table_heartbeat { ...@@ -688,6 +688,28 @@ struct pqi_config_table_heartbeat {
__le32 heartbeat_counter; __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 ((u32)~0)
#define PQI_MAX_OUTSTANDING_REQUESTS_KDUMP 32 #define PQI_MAX_OUTSTANDING_REQUESTS_KDUMP 32
#define PQI_MAX_TRANSFER_SIZE (1024U * 1024U) #define PQI_MAX_TRANSFER_SIZE (1024U * 1024U)
...@@ -995,6 +1017,7 @@ struct pqi_ctrl_info { ...@@ -995,6 +1017,7 @@ struct pqi_ctrl_info {
u8 inbound_spanning_supported : 1; u8 inbound_spanning_supported : 1;
u8 outbound_spanning_supported : 1; u8 outbound_spanning_supported : 1;
u8 pqi_mode_enabled : 1; u8 pqi_mode_enabled : 1;
u8 pqi_reset_quiesce_supported : 1;
struct list_head scsi_device_list; struct list_head scsi_device_list;
spinlock_t scsi_device_list_lock; spinlock_t scsi_device_list_lock;
......
...@@ -5889,28 +5889,62 @@ static void pqi_unregister_scsi(struct pqi_ctrl_info *ctrl_info) ...@@ -5889,28 +5889,62 @@ static void pqi_unregister_scsi(struct pqi_ctrl_info *ctrl_info)
scsi_host_put(shost); 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 return rc;
#define PQI_RESET_TYPE_SOFT_RESET 0x1 }
#define PQI_RESET_TYPE_FIRM_RESET 0x2
#define PQI_RESET_TYPE_HARD_RESET 0x3
static int pqi_reset(struct pqi_ctrl_info *ctrl_info) static int pqi_reset(struct pqi_ctrl_info *ctrl_info)
{ {
int rc; int rc;
u32 reset_params; union pqi_reset_register reset_reg;
reset_params = (PQI_RESET_ACTION_RESET << 5) | if (ctrl_info->pqi_reset_quiesce_supported) {
PQI_RESET_TYPE_HARD_RESET; 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, reset_reg.all_bits = 0;
&ctrl_info->pqi_registers->device_reset); 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) if (rc)
dev_err(&ctrl_info->pci_dev->dev, dev_err(&ctrl_info->pci_dev->dev,
"PQI reset failed\n"); "PQI reset failed with error %d\n", rc);
return rc; return rc;
} }
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#define SIS_ENABLE_INTX 0x80 #define SIS_ENABLE_INTX 0x80
#define SIS_SOFT_RESET 0x100 #define SIS_SOFT_RESET 0x100
#define SIS_TRIGGER_SHUTDOWN 0x800000 #define SIS_TRIGGER_SHUTDOWN 0x800000
#define SIS_PQI_RESET_QUIESCE 0x1000000
#define SIS_CMD_READY 0x200 #define SIS_CMD_READY 0x200
#define SIS_CMD_COMPLETE 0x1000 #define SIS_CMD_COMPLETE 0x1000
#define SIS_CLEAR_CTRL_TO_HOST_DOORBELL 0x1000 #define SIS_CLEAR_CTRL_TO_HOST_DOORBELL 0x1000
...@@ -47,6 +48,7 @@ ...@@ -47,6 +48,7 @@
#define SIS_EXTENDED_PROPERTIES_SUPPORTED 0x800000 #define SIS_EXTENDED_PROPERTIES_SUPPORTED 0x800000
#define SIS_SMARTARRAY_FEATURES_SUPPORTED 0x2 #define SIS_SMARTARRAY_FEATURES_SUPPORTED 0x2
#define SIS_PQI_MODE_SUPPORTED 0x4 #define SIS_PQI_MODE_SUPPORTED 0x4
#define SIS_PQI_RESET_QUIESCE_SUPPORTED 0x8
#define SIS_REQUIRED_EXTENDED_PROPERTIES \ #define SIS_REQUIRED_EXTENDED_PROPERTIES \
(SIS_SMARTARRAY_FEATURES_SUPPORTED | SIS_PQI_MODE_SUPPORTED) (SIS_SMARTARRAY_FEATURES_SUPPORTED | SIS_PQI_MODE_SUPPORTED)
...@@ -258,6 +260,9 @@ int sis_get_ctrl_properties(struct pqi_ctrl_info *ctrl_info) ...@@ -258,6 +260,9 @@ int sis_get_ctrl_properties(struct pqi_ctrl_info *ctrl_info)
SIS_REQUIRED_EXTENDED_PROPERTIES) SIS_REQUIRED_EXTENDED_PROPERTIES)
return -ENODEV; return -ENODEV;
if (extended_properties & SIS_PQI_RESET_QUIESCE_SUPPORTED)
ctrl_info->pqi_reset_quiesce_supported = true;
return 0; return 0;
} }
...@@ -336,9 +341,10 @@ int sis_init_base_struct_addr(struct pqi_ctrl_info *ctrl_info) ...@@ -336,9 +341,10 @@ int sis_init_base_struct_addr(struct pqi_ctrl_info *ctrl_info)
#define SIS_DOORBELL_BIT_CLEAR_TIMEOUT_SECS 30 #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) struct pqi_ctrl_info *ctrl_info, u32 bit)
{ {
int rc = 0;
u32 doorbell_register; u32 doorbell_register;
unsigned long timeout; unsigned long timeout;
...@@ -350,16 +356,21 @@ static void sis_wait_for_doorbell_bit_to_clear( ...@@ -350,16 +356,21 @@ static void sis_wait_for_doorbell_bit_to_clear(
if ((doorbell_register & bit) == 0) if ((doorbell_register & bit) == 0)
break; break;
if (readl(&ctrl_info->registers->sis_firmware_status) & if (readl(&ctrl_info->registers->sis_firmware_status) &
SIS_CTRL_KERNEL_PANIC) SIS_CTRL_KERNEL_PANIC) {
rc = -ENODEV;
break; break;
}
if (time_after(jiffies, timeout)) { if (time_after(jiffies, timeout)) {
dev_err(&ctrl_info->pci_dev->dev, dev_err(&ctrl_info->pci_dev->dev,
"doorbell register bit 0x%x not cleared\n", "doorbell register bit 0x%x not cleared\n",
bit); bit);
rc = -ETIMEDOUT;
break; break;
} }
usleep_range(1000, 2000); usleep_range(1000, 2000);
} }
return rc;
} }
/* Enable MSI-X interrupts on the controller. */ /* Enable MSI-X interrupts on the controller. */
...@@ -434,6 +445,21 @@ void sis_shutdown_ctrl(struct pqi_ctrl_info *ctrl_info) ...@@ -434,6 +445,21 @@ void sis_shutdown_ctrl(struct pqi_ctrl_info *ctrl_info)
&ctrl_info->registers->sis_host_to_ctrl_doorbell); &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 #define SIS_MODE_READY_TIMEOUT_SECS 30
int sis_reenable_sis_mode(struct pqi_ctrl_info *ctrl_info) int sis_reenable_sis_mode(struct pqi_ctrl_info *ctrl_info)
......
...@@ -32,6 +32,7 @@ void sis_enable_intx(struct pqi_ctrl_info *ctrl_info); ...@@ -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_disable_intx(struct pqi_ctrl_info *ctrl_info);
void sis_soft_reset(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); 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); int sis_reenable_sis_mode(struct pqi_ctrl_info *ctrl_info);
void sis_write_driver_scratch(struct pqi_ctrl_info *ctrl_info, u32 value); void sis_write_driver_scratch(struct pqi_ctrl_info *ctrl_info, u32 value);
u32 sis_read_driver_scratch(struct pqi_ctrl_info *ctrl_info); u32 sis_read_driver_scratch(struct pqi_ctrl_info *ctrl_info);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment