Commit 4fd22c13 authored by Mahesh Rajashekhara's avatar Mahesh Rajashekhara Committed by Martin K. Petersen

scsi: smartpqi: add ofa support

- when OFA event occurs, driver will stop traffic to RAID/HBA path. Driver
  waits for all the outstanding requests to complete.
- Driver sends OFA event acknowledgment to firmware.
- Driver will wait until the new firmware is up and running.
- Driver will free up the resources.
- Driver calls SIS/PQI initialization and rescans the device list.
- Driver will resume the traffic to RAID/HBA path.
Reviewed-by: default avatarMurthy Bhat <murthy.bhat@microsemi.com>
Signed-off-by: default avatarMahesh Rajashekhara <mahesh.rajashekhara@microsemi.com>
Signed-off-by: default avatarDon Brace <don.brace@microsemi.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 65111785
...@@ -100,6 +100,12 @@ struct pqi_ctrl_registers { ...@@ -100,6 +100,12 @@ struct pqi_ctrl_registers {
struct pqi_device_registers pqi_registers; /* 4000h */ struct pqi_device_registers pqi_registers; /* 4000h */
}; };
#if ((HZ) < 1000)
#define PQI_HZ 1000
#else
#define PQI_HZ (HZ)
#endif
#define PQI_DEVICE_REGISTERS_OFFSET 0x4000 #define PQI_DEVICE_REGISTERS_OFFSET 0x4000
enum pqi_io_path { enum pqi_io_path {
...@@ -350,6 +356,10 @@ struct pqi_event_config { ...@@ -350,6 +356,10 @@ struct pqi_event_config {
#define PQI_MAX_EVENT_DESCRIPTORS 255 #define PQI_MAX_EVENT_DESCRIPTORS 255
#define PQI_EVENT_OFA_MEMORY_ALLOCATION 0x0
#define PQI_EVENT_OFA_QUIESCE 0x1
#define PQI_EVENT_OFA_CANCELLED 0x2
struct pqi_event_response { struct pqi_event_response {
struct pqi_iu_header header; struct pqi_iu_header header;
u8 event_type; u8 event_type;
...@@ -357,7 +367,17 @@ struct pqi_event_response { ...@@ -357,7 +367,17 @@ struct pqi_event_response {
u8 request_acknowlege : 1; u8 request_acknowlege : 1;
__le16 event_id; __le16 event_id;
__le32 additional_event_id; __le32 additional_event_id;
u8 data[16]; union {
struct {
__le32 bytes_requested;
u8 reserved[12];
} ofa_memory_allocation;
struct {
__le16 reason; /* reason for cancellation */
u8 reserved[14];
} ofa_cancelled;
} data;
}; };
struct pqi_event_acknowledge_request { struct pqi_event_acknowledge_request {
...@@ -420,6 +440,25 @@ struct pqi_vendor_general_response { ...@@ -420,6 +440,25 @@ struct pqi_vendor_general_response {
}; };
#define PQI_VENDOR_GENERAL_CONFIG_TABLE_UPDATE 0 #define PQI_VENDOR_GENERAL_CONFIG_TABLE_UPDATE 0
#define PQI_VENDOR_GENERAL_HOST_MEMORY_UPDATE 1
#define PQI_OFA_VERSION 1
#define PQI_OFA_SIGNATURE "OFA_QRM"
#define PQI_OFA_MAX_SG_DESCRIPTORS 64
#define PQI_OFA_MEMORY_DESCRIPTOR_LENGTH \
(offsetof(struct pqi_ofa_memory, sg_descriptor) + \
(PQI_OFA_MAX_SG_DESCRIPTORS * sizeof(struct pqi_sg_descriptor)))
struct pqi_ofa_memory {
__le64 signature; /* "OFA_QRM" */
__le16 version; /* version of this struct(1 = 1st version) */
u8 reserved[62];
__le32 bytes_allocated; /* total allocated memory in bytes */
__le16 num_memory_descriptors;
u8 reserved1[2];
struct pqi_sg_descriptor sg_descriptor[1];
};
struct pqi_aio_error_info { struct pqi_aio_error_info {
u8 status; u8 status;
...@@ -526,6 +565,7 @@ struct pqi_raid_error_info { ...@@ -526,6 +565,7 @@ struct pqi_raid_error_info {
#define PQI_EVENT_TYPE_HARDWARE 0x2 #define PQI_EVENT_TYPE_HARDWARE 0x2
#define PQI_EVENT_TYPE_PHYSICAL_DEVICE 0x4 #define PQI_EVENT_TYPE_PHYSICAL_DEVICE 0x4
#define PQI_EVENT_TYPE_LOGICAL_DEVICE 0x5 #define PQI_EVENT_TYPE_LOGICAL_DEVICE 0x5
#define PQI_EVENT_TYPE_OFA 0xfb
#define PQI_EVENT_TYPE_AIO_STATE_CHANGE 0xfd #define PQI_EVENT_TYPE_AIO_STATE_CHANGE 0xfd
#define PQI_EVENT_TYPE_AIO_CONFIG_CHANGE 0xfe #define PQI_EVENT_TYPE_AIO_CONFIG_CHANGE 0xfe
...@@ -685,6 +725,7 @@ struct pqi_encryption_info { ...@@ -685,6 +725,7 @@ struct pqi_encryption_info {
#define PQI_CONFIG_TABLE_SECTION_FIRMWARE_ERRATA 2 #define PQI_CONFIG_TABLE_SECTION_FIRMWARE_ERRATA 2
#define PQI_CONFIG_TABLE_SECTION_DEBUG 3 #define PQI_CONFIG_TABLE_SECTION_DEBUG 3
#define PQI_CONFIG_TABLE_SECTION_HEARTBEAT 4 #define PQI_CONFIG_TABLE_SECTION_HEARTBEAT 4
#define PQI_CONFIG_TABLE_SECTION_SOFT_RESET 5
struct pqi_config_table { struct pqi_config_table {
u8 signature[8]; /* "CFGTABLE" */ u8 signature[8]; /* "CFGTABLE" */
...@@ -724,8 +765,9 @@ struct pqi_config_table_firmware_features { ...@@ -724,8 +765,9 @@ struct pqi_config_table_firmware_features {
/* u8 features_enabled[]; */ /* u8 features_enabled[]; */
}; };
#define PQI_FIRMWARE_FEATURE_OFA 0 #define PQI_FIRMWARE_FEATURE_OFA 0
#define PQI_FIRMWARE_FEATURE_SMP 1 #define PQI_FIRMWARE_FEATURE_SMP 1
#define PQI_FIRMWARE_FEATURE_SOFT_RESET_HANDSHAKE 11
struct pqi_config_table_debug { struct pqi_config_table_debug {
struct pqi_config_table_section_header header; struct pqi_config_table_section_header header;
...@@ -737,6 +779,22 @@ struct pqi_config_table_heartbeat { ...@@ -737,6 +779,22 @@ struct pqi_config_table_heartbeat {
__le32 heartbeat_counter; __le32 heartbeat_counter;
}; };
struct pqi_config_table_soft_reset {
struct pqi_config_table_section_header header;
u8 soft_reset_status;
};
#define PQI_SOFT_RESET_INITIATE 0x1
#define PQI_SOFT_RESET_ABORT 0x2
enum pqi_soft_reset_status {
RESET_INITIATE_FIRMWARE,
RESET_INITIATE_DRIVER,
RESET_ABORT,
RESET_NORESPONSE,
RESET_TIMEDOUT
};
union pqi_reset_register { union pqi_reset_register {
struct { struct {
u32 reset_type : 3; u32 reset_type : 3;
...@@ -1000,13 +1058,15 @@ struct pqi_io_request { ...@@ -1000,13 +1058,15 @@ struct pqi_io_request {
struct list_head request_list_entry; struct list_head request_list_entry;
}; };
#define PQI_NUM_SUPPORTED_EVENTS 6 #define PQI_NUM_SUPPORTED_EVENTS 7
struct pqi_event { struct pqi_event {
bool pending; bool pending;
u8 event_type; u8 event_type;
__le16 event_id; __le16 event_id;
__le32 additional_event_id; __le32 additional_event_id;
__le32 ofa_bytes_requested;
__le16 ofa_cancel_reason;
}; };
#define PQI_RESERVED_IO_SLOTS_LUN_RESET 1 #define PQI_RESERVED_IO_SLOTS_LUN_RESET 1
...@@ -1067,13 +1127,16 @@ struct pqi_ctrl_info { ...@@ -1067,13 +1127,16 @@ struct pqi_ctrl_info {
struct mutex scan_mutex; struct mutex scan_mutex;
struct mutex lun_reset_mutex; struct mutex lun_reset_mutex;
struct mutex ofa_mutex; /* serialize ofa */
bool controller_online; bool controller_online;
bool block_requests; bool block_requests;
bool in_shutdown; bool in_shutdown;
bool in_ofa;
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; u8 pqi_reset_quiesce_supported : 1;
u8 soft_reset_handshake_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;
...@@ -1094,6 +1157,7 @@ struct pqi_ctrl_info { ...@@ -1094,6 +1157,7 @@ struct pqi_ctrl_info {
int previous_num_interrupts; int previous_num_interrupts;
u32 previous_heartbeat_count; u32 previous_heartbeat_count;
__le32 __iomem *heartbeat_counter; __le32 __iomem *heartbeat_counter;
u8 __iomem *soft_reset_status;
struct timer_list heartbeat_timer; struct timer_list heartbeat_timer;
struct work_struct ctrl_offline_work; struct work_struct ctrl_offline_work;
...@@ -1105,6 +1169,10 @@ struct pqi_ctrl_info { ...@@ -1105,6 +1169,10 @@ struct pqi_ctrl_info {
struct list_head raid_bypass_retry_list; struct list_head raid_bypass_retry_list;
spinlock_t raid_bypass_retry_list_lock; spinlock_t raid_bypass_retry_list_lock;
struct work_struct raid_bypass_retry_work; struct work_struct raid_bypass_retry_work;
struct pqi_ofa_memory *pqi_ofa_mem_virt_addr;
dma_addr_t pqi_ofa_mem_dma_handle;
void **pqi_ofa_chunk_virt_addr;
}; };
enum pqi_ctrl_mode { enum pqi_ctrl_mode {
......
This diff is collapsed.
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#define SIS_REENABLE_SIS_MODE 0x1 #define SIS_REENABLE_SIS_MODE 0x1
#define SIS_ENABLE_MSIX 0x40 #define SIS_ENABLE_MSIX 0x40
#define SIS_ENABLE_INTX 0x80 #define SIS_ENABLE_INTX 0x80
#define SIS_SOFT_RESET 0x100
#define SIS_CMD_READY 0x200 #define SIS_CMD_READY 0x200
#define SIS_TRIGGER_SHUTDOWN 0x800000 #define SIS_TRIGGER_SHUTDOWN 0x800000
#define SIS_PQI_RESET_QUIESCE 0x1000000 #define SIS_PQI_RESET_QUIESCE 0x1000000
...@@ -90,7 +91,7 @@ static int sis_wait_for_ctrl_ready_with_timeout(struct pqi_ctrl_info *ctrl_info, ...@@ -90,7 +91,7 @@ static int sis_wait_for_ctrl_ready_with_timeout(struct pqi_ctrl_info *ctrl_info,
unsigned long timeout; unsigned long timeout;
u32 status; u32 status;
timeout = (timeout_secs * HZ) + jiffies; timeout = (timeout_secs * PQI_HZ) + jiffies;
while (1) { while (1) {
status = readl(&ctrl_info->registers->sis_firmware_status); status = readl(&ctrl_info->registers->sis_firmware_status);
...@@ -202,7 +203,7 @@ static int sis_send_sync_cmd(struct pqi_ctrl_info *ctrl_info, ...@@ -202,7 +203,7 @@ static int sis_send_sync_cmd(struct pqi_ctrl_info *ctrl_info,
* the top of the loop in order to give the controller time to start * the top of the loop in order to give the controller time to start
* processing the command before we start polling. * processing the command before we start polling.
*/ */
timeout = (SIS_CMD_COMPLETE_TIMEOUT_SECS * HZ) + jiffies; timeout = (SIS_CMD_COMPLETE_TIMEOUT_SECS * PQI_HZ) + jiffies;
while (1) { while (1) {
msleep(SIS_CMD_COMPLETE_POLL_INTERVAL_MSECS); msleep(SIS_CMD_COMPLETE_POLL_INTERVAL_MSECS);
doorbell = readl(&registers->sis_ctrl_to_host_doorbell); doorbell = readl(&registers->sis_ctrl_to_host_doorbell);
...@@ -348,7 +349,7 @@ static int sis_wait_for_doorbell_bit_to_clear( ...@@ -348,7 +349,7 @@ static int sis_wait_for_doorbell_bit_to_clear(
u32 doorbell_register; u32 doorbell_register;
unsigned long timeout; unsigned long timeout;
timeout = (SIS_DOORBELL_BIT_CLEAR_TIMEOUT_SECS * HZ) + jiffies; timeout = (SIS_DOORBELL_BIT_CLEAR_TIMEOUT_SECS * PQI_HZ) + jiffies;
while (1) { while (1) {
doorbell_register = doorbell_register =
...@@ -420,6 +421,12 @@ u32 sis_read_driver_scratch(struct pqi_ctrl_info *ctrl_info) ...@@ -420,6 +421,12 @@ u32 sis_read_driver_scratch(struct pqi_ctrl_info *ctrl_info)
return readl(&ctrl_info->registers->sis_driver_scratch); return readl(&ctrl_info->registers->sis_driver_scratch);
} }
void sis_soft_reset(struct pqi_ctrl_info *ctrl_info)
{
writel(SIS_SOFT_RESET,
&ctrl_info->registers->sis_host_to_ctrl_doorbell);
}
static void __attribute__((unused)) verify_structures(void) static void __attribute__((unused)) verify_structures(void)
{ {
BUILD_BUG_ON(offsetof(struct sis_base_struct, BUILD_BUG_ON(offsetof(struct sis_base_struct,
......
...@@ -33,5 +33,6 @@ int sis_pqi_reset_quiesce(struct pqi_ctrl_info *ctrl_info); ...@@ -33,5 +33,6 @@ 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);
void sis_soft_reset(struct pqi_ctrl_info *ctrl_info);
#endif /* _SMARTPQI_SIS_H */ #endif /* _SMARTPQI_SIS_H */
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