mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-29 09:13:38 +00:00
Merge patch series "smartpqi updates"
Don Brace <don.brace@microchip.com> says: These patches are based on Martin Petersen's 6.12/scsi-queue tree https://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git 6.12/scsi-queue There are two functional changes: smartpqi-add-fw-log-to-kdump smartpqi-add-counter-for-parity-write-stream-requests There are three minor bug fixes: smartpqi-fix-stream-detection smartpqi-fix-rare-system-hang-during-LUN-reset smartpqi-fix-volume-size-updates The other two patches add PCI-IDs for new controllers and change the driver version. This set of changes consists of: * smartpqi-add-fw-log-to-kdump During a kdump, the driver tells the controller to copy its logging information to some pre-allocated buffers that can be analyzed later. This is a "feature" driven capability and is backward compatible with existing controller FW. This patch renames some prefixes for OFA (Online-Firmware Activation ofa_*) buffers to host_memory_*. So, not a lot of actual functional changes to smartpqi_init.c, mainly determining the memory size allocation. We added a function to notify the controller to copy debug data into host memory before continuing kdump. Most of the functional changes are in smartpqi_sis.c where the actual handshaking is done. * smartpqi-fix-stream-detection Correct some false write-stream detections. The data structure used to check for write-streams was not initialized to all 0's causing some false write stream detections. The driver sends down streamed requests to the raid engine instead of using AIO bypass for some extra performance. (Potential full-stripe write verses Read Modify Write). False detections have not caused any data corruption. Found by internal testing. No known externally reported bugs. * smartpqi-add-counter-for-parity-write-stream-requests Adding some counters for raid_bypass and write streams. These two counters are related because write stream detection is only checked if an I/O request is eligible for bypass (AIO). The bypass counter (raid_bypass_cnt) was moved into a common structure (pqi_raid_io_stats) and changed to type __percpu. The write stream counter is (write_stream_cnt) has been added to this same structure. These counters are __percpu counters for performance. We added a sysfs entry to show the write stream count. The raid bypass counter sysfs entry already exists. Useful for checking streaming writes. The change in the sysfs entry write_stream_cnt can be checked during AIO eligible write operations. * smartpqi-add-new-controller-PCI-IDs Adding support for new controller HW. No functional changes. * smartpqi-fix-rare-system-hang-during-LUN-reset We found a rare race condition that can occur during a LUN reset. We were not emptying our internal queue completely. There have been some rare conditions where our internal request queue has requests for multiple LUNs and a reset comes in for one of the LUNs. The driver waits for this internal queue to empty. We were only clearing out the requests for the LUN being reset so the request queue was never empty causing a hang. The Fix: For all requests in our internal request queue: Complete requests with DID_RESET for queued requests for the device undergoing a reset. Complete requests with DID_REQUEUE for all other queued requests. Found by internal testing. No known externally reported bugs. * smartpqi-fix-volume-size-updates The current code only checks for a size change if there is also a queue depth change. We are separating the check for queue depth and the size changes. Found by internal testing. No known bugs were filed. * smartpqi-update-version-to-2.1.30-031 No functional changes. Link: https://lore.kernel.org/r/20240827185501.692804-1-don.brace@microchip.com Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
commit
cff06a799d
@ -505,7 +505,7 @@ struct pqi_vendor_general_request {
|
||||
__le64 buffer_address;
|
||||
__le32 buffer_length;
|
||||
u8 reserved[40];
|
||||
} ofa_memory_allocation;
|
||||
} host_memory_allocation;
|
||||
} data;
|
||||
};
|
||||
|
||||
@ -517,21 +517,30 @@ struct pqi_vendor_general_response {
|
||||
u8 reserved[2];
|
||||
};
|
||||
|
||||
#define PQI_VENDOR_GENERAL_CONFIG_TABLE_UPDATE 0
|
||||
#define PQI_VENDOR_GENERAL_HOST_MEMORY_UPDATE 1
|
||||
#define PQI_VENDOR_GENERAL_CONFIG_TABLE_UPDATE 0
|
||||
#define PQI_VENDOR_GENERAL_OFA_MEMORY_UPDATE 1
|
||||
#define PQI_VENDOR_GENERAL_CTRL_LOG_MEMORY_UPDATE 2
|
||||
|
||||
#define PQI_OFA_VERSION 1
|
||||
#define PQI_OFA_SIGNATURE "OFA_QRM"
|
||||
#define PQI_OFA_MAX_SG_DESCRIPTORS 64
|
||||
#define PQI_CTRL_LOG_VERSION 1
|
||||
#define PQI_CTRL_LOG_SIGNATURE "FW_DATA"
|
||||
#define PQI_HOST_MAX_SG_DESCRIPTORS 64
|
||||
|
||||
struct pqi_ofa_memory {
|
||||
__le64 signature; /* "OFA_QRM" */
|
||||
struct pqi_host_memory {
|
||||
__le64 signature; /* "OFA_QRM", "FW_DATA", etc. */
|
||||
__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[PQI_OFA_MAX_SG_DESCRIPTORS];
|
||||
struct pqi_sg_descriptor sg_descriptor[PQI_HOST_MAX_SG_DESCRIPTORS];
|
||||
};
|
||||
|
||||
struct pqi_host_memory_descriptor {
|
||||
struct pqi_host_memory *host_memory;
|
||||
dma_addr_t host_memory_dma_handle;
|
||||
void **host_chunk_virt_address;
|
||||
};
|
||||
|
||||
struct pqi_aio_error_info {
|
||||
@ -867,7 +876,8 @@ struct pqi_config_table_firmware_features {
|
||||
#define PQI_FIRMWARE_FEATURE_FW_TRIAGE 17
|
||||
#define PQI_FIRMWARE_FEATURE_RPL_EXTENDED_FORMAT_4_5 18
|
||||
#define PQI_FIRMWARE_FEATURE_MULTI_LUN_DEVICE_SUPPORT 21
|
||||
#define PQI_FIRMWARE_FEATURE_MAXIMUM 21
|
||||
#define PQI_FIRMWARE_FEATURE_CTRL_LOGGING 22
|
||||
#define PQI_FIRMWARE_FEATURE_MAXIMUM 22
|
||||
|
||||
struct pqi_config_table_debug {
|
||||
struct pqi_config_table_section_header header;
|
||||
@ -1096,6 +1106,11 @@ struct pqi_tmf_work {
|
||||
u8 scsi_opcode;
|
||||
};
|
||||
|
||||
struct pqi_raid_io_stats {
|
||||
u64 raid_bypass_cnt;
|
||||
u64 write_stream_cnt;
|
||||
};
|
||||
|
||||
struct pqi_scsi_dev {
|
||||
int devtype; /* as reported by INQUIRY command */
|
||||
u8 device_type; /* as reported by */
|
||||
@ -1158,7 +1173,7 @@ struct pqi_scsi_dev {
|
||||
|
||||
struct pqi_stream_data stream_data[NUM_STREAMS_PER_LUN];
|
||||
atomic_t scsi_cmds_outstanding[PQI_MAX_LUNS_PER_DEVICE];
|
||||
u64 __percpu *raid_bypass_cnt;
|
||||
struct pqi_raid_io_stats __percpu *raid_io_stats;
|
||||
|
||||
struct pqi_tmf_work tmf_work[PQI_MAX_LUNS_PER_DEVICE];
|
||||
};
|
||||
@ -1357,6 +1372,7 @@ struct pqi_ctrl_info {
|
||||
u8 firmware_triage_supported : 1;
|
||||
u8 rpl_extended_format_4_5_supported : 1;
|
||||
u8 multi_lun_device_supported : 1;
|
||||
u8 ctrl_logging_supported : 1;
|
||||
u8 enable_r1_writes : 1;
|
||||
u8 enable_r5_writes : 1;
|
||||
u8 enable_r6_writes : 1;
|
||||
@ -1398,13 +1414,12 @@ struct pqi_ctrl_info {
|
||||
wait_queue_head_t block_requests_wait;
|
||||
|
||||
struct mutex ofa_mutex;
|
||||
struct pqi_ofa_memory *pqi_ofa_mem_virt_addr;
|
||||
dma_addr_t pqi_ofa_mem_dma_handle;
|
||||
void **pqi_ofa_chunk_virt_addr;
|
||||
struct work_struct ofa_memory_alloc_work;
|
||||
struct work_struct ofa_quiesce_work;
|
||||
u32 ofa_bytes_requested;
|
||||
u16 ofa_cancel_reason;
|
||||
struct pqi_host_memory_descriptor ofa_memory;
|
||||
struct pqi_host_memory_descriptor ctrl_log_memory;
|
||||
enum pqi_ctrl_removal_state ctrl_removal_state;
|
||||
};
|
||||
|
||||
|
@ -33,11 +33,11 @@
|
||||
#define BUILD_TIMESTAMP
|
||||
#endif
|
||||
|
||||
#define DRIVER_VERSION "2.1.28-025"
|
||||
#define DRIVER_VERSION "2.1.30-031"
|
||||
#define DRIVER_MAJOR 2
|
||||
#define DRIVER_MINOR 1
|
||||
#define DRIVER_RELEASE 28
|
||||
#define DRIVER_REVISION 25
|
||||
#define DRIVER_RELEASE 30
|
||||
#define DRIVER_REVISION 31
|
||||
|
||||
#define DRIVER_NAME "Microchip SmartPQI Driver (v" \
|
||||
DRIVER_VERSION BUILD_TIMESTAMP ")"
|
||||
@ -92,9 +92,9 @@ static int pqi_aio_submit_r56_write_io(struct pqi_ctrl_info *ctrl_info,
|
||||
static void pqi_ofa_ctrl_quiesce(struct pqi_ctrl_info *ctrl_info);
|
||||
static void pqi_ofa_ctrl_unquiesce(struct pqi_ctrl_info *ctrl_info);
|
||||
static int pqi_ofa_ctrl_restart(struct pqi_ctrl_info *ctrl_info, unsigned int delay_secs);
|
||||
static void pqi_ofa_setup_host_buffer(struct pqi_ctrl_info *ctrl_info);
|
||||
static void pqi_ofa_free_host_buffer(struct pqi_ctrl_info *ctrl_info);
|
||||
static int pqi_ofa_host_memory_update(struct pqi_ctrl_info *ctrl_info);
|
||||
static void pqi_host_setup_buffer(struct pqi_ctrl_info *ctrl_info, struct pqi_host_memory_descriptor *host_memory_descriptor, u32 total_size, u32 min_size);
|
||||
static void pqi_host_free_buffer(struct pqi_ctrl_info *ctrl_info, struct pqi_host_memory_descriptor *host_memory_descriptor);
|
||||
static int pqi_host_memory_update(struct pqi_ctrl_info *ctrl_info, struct pqi_host_memory_descriptor *host_memory_descriptor, u16 function_code);
|
||||
static int pqi_device_wait_for_pending_io(struct pqi_ctrl_info *ctrl_info,
|
||||
struct pqi_scsi_dev *device, u8 lun, unsigned long timeout_msecs);
|
||||
static void pqi_fail_all_outstanding_requests(struct pqi_ctrl_info *ctrl_info);
|
||||
@ -1508,8 +1508,8 @@ static int pqi_get_raid_map(struct pqi_ctrl_info *ctrl_info,
|
||||
if (rc)
|
||||
goto error;
|
||||
|
||||
device->raid_bypass_cnt = alloc_percpu(u64);
|
||||
if (!device->raid_bypass_cnt) {
|
||||
device->raid_io_stats = alloc_percpu(struct pqi_raid_io_stats);
|
||||
if (!device->raid_io_stats) {
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
@ -2105,9 +2105,9 @@ static void pqi_scsi_update_device(struct pqi_ctrl_info *ctrl_info,
|
||||
/* To prevent this from being freed later. */
|
||||
new_device->raid_map = NULL;
|
||||
}
|
||||
if (new_device->raid_bypass_enabled && existing_device->raid_bypass_cnt == NULL) {
|
||||
existing_device->raid_bypass_cnt = new_device->raid_bypass_cnt;
|
||||
new_device->raid_bypass_cnt = NULL;
|
||||
if (new_device->raid_bypass_enabled && existing_device->raid_io_stats == NULL) {
|
||||
existing_device->raid_io_stats = new_device->raid_io_stats;
|
||||
new_device->raid_io_stats = NULL;
|
||||
}
|
||||
existing_device->raid_bypass_configured = new_device->raid_bypass_configured;
|
||||
existing_device->raid_bypass_enabled = new_device->raid_bypass_enabled;
|
||||
@ -2131,7 +2131,7 @@ static void pqi_scsi_update_device(struct pqi_ctrl_info *ctrl_info,
|
||||
static inline void pqi_free_device(struct pqi_scsi_dev *device)
|
||||
{
|
||||
if (device) {
|
||||
free_percpu(device->raid_bypass_cnt);
|
||||
free_percpu(device->raid_io_stats);
|
||||
kfree(device->raid_map);
|
||||
kfree(device);
|
||||
}
|
||||
@ -2303,17 +2303,23 @@ static void pqi_update_device_list(struct pqi_ctrl_info *ctrl_info,
|
||||
* queue depth, device size.
|
||||
*/
|
||||
list_for_each_entry(device, &ctrl_info->scsi_device_list, scsi_device_list_entry) {
|
||||
/*
|
||||
* Check for queue depth change.
|
||||
*/
|
||||
if (device->sdev && device->queue_depth != device->advertised_queue_depth) {
|
||||
device->advertised_queue_depth = device->queue_depth;
|
||||
scsi_change_queue_depth(device->sdev, device->advertised_queue_depth);
|
||||
spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags);
|
||||
if (pqi_volume_rescan_needed(device)) {
|
||||
device->rescan = false;
|
||||
spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
|
||||
scsi_rescan_device(device->sdev);
|
||||
} else {
|
||||
spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
|
||||
}
|
||||
}
|
||||
spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags);
|
||||
/*
|
||||
* Check for changes in the device, such as size.
|
||||
*/
|
||||
if (pqi_volume_rescan_needed(device)) {
|
||||
device->rescan = false;
|
||||
spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
|
||||
scsi_rescan_device(device->sdev);
|
||||
} else {
|
||||
spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3634,7 +3640,7 @@ static void pqi_process_soft_reset(struct pqi_ctrl_info *ctrl_info)
|
||||
ctrl_info->pqi_mode_enabled = false;
|
||||
pqi_save_ctrl_mode(ctrl_info, SIS_MODE);
|
||||
rc = pqi_ofa_ctrl_restart(ctrl_info, delay_secs);
|
||||
pqi_ofa_free_host_buffer(ctrl_info);
|
||||
pqi_host_free_buffer(ctrl_info, &ctrl_info->ofa_memory);
|
||||
pqi_ctrl_ofa_done(ctrl_info);
|
||||
dev_info(&ctrl_info->pci_dev->dev,
|
||||
"Online Firmware Activation: %s\n",
|
||||
@ -3645,7 +3651,7 @@ static void pqi_process_soft_reset(struct pqi_ctrl_info *ctrl_info)
|
||||
"Online Firmware Activation ABORTED\n");
|
||||
if (ctrl_info->soft_reset_handshake_supported)
|
||||
pqi_clear_soft_reset_status(ctrl_info);
|
||||
pqi_ofa_free_host_buffer(ctrl_info);
|
||||
pqi_host_free_buffer(ctrl_info, &ctrl_info->ofa_memory);
|
||||
pqi_ctrl_ofa_done(ctrl_info);
|
||||
pqi_ofa_ctrl_unquiesce(ctrl_info);
|
||||
break;
|
||||
@ -3655,7 +3661,7 @@ static void pqi_process_soft_reset(struct pqi_ctrl_info *ctrl_info)
|
||||
dev_err(&ctrl_info->pci_dev->dev,
|
||||
"unexpected Online Firmware Activation reset status: 0x%x\n",
|
||||
reset_status);
|
||||
pqi_ofa_free_host_buffer(ctrl_info);
|
||||
pqi_host_free_buffer(ctrl_info, &ctrl_info->ofa_memory);
|
||||
pqi_ctrl_ofa_done(ctrl_info);
|
||||
pqi_ofa_ctrl_unquiesce(ctrl_info);
|
||||
pqi_take_ctrl_offline(ctrl_info, PQI_OFA_RESPONSE_TIMEOUT);
|
||||
@ -3670,8 +3676,8 @@ static void pqi_ofa_memory_alloc_worker(struct work_struct *work)
|
||||
ctrl_info = container_of(work, struct pqi_ctrl_info, ofa_memory_alloc_work);
|
||||
|
||||
pqi_ctrl_ofa_start(ctrl_info);
|
||||
pqi_ofa_setup_host_buffer(ctrl_info);
|
||||
pqi_ofa_host_memory_update(ctrl_info);
|
||||
pqi_host_setup_buffer(ctrl_info, &ctrl_info->ofa_memory, ctrl_info->ofa_bytes_requested, ctrl_info->ofa_bytes_requested);
|
||||
pqi_host_memory_update(ctrl_info, &ctrl_info->ofa_memory, PQI_VENDOR_GENERAL_OFA_MEMORY_UPDATE);
|
||||
}
|
||||
|
||||
static void pqi_ofa_quiesce_worker(struct work_struct *work)
|
||||
@ -3711,7 +3717,7 @@ static bool pqi_ofa_process_event(struct pqi_ctrl_info *ctrl_info,
|
||||
dev_info(&ctrl_info->pci_dev->dev,
|
||||
"received Online Firmware Activation cancel request: reason: %u\n",
|
||||
ctrl_info->ofa_cancel_reason);
|
||||
pqi_ofa_free_host_buffer(ctrl_info);
|
||||
pqi_host_free_buffer(ctrl_info, &ctrl_info->ofa_memory);
|
||||
pqi_ctrl_ofa_done(ctrl_info);
|
||||
break;
|
||||
default:
|
||||
@ -5942,7 +5948,7 @@ static bool pqi_is_parity_write_stream(struct pqi_ctrl_info *ctrl_info,
|
||||
int rc;
|
||||
struct pqi_scsi_dev *device;
|
||||
struct pqi_stream_data *pqi_stream_data;
|
||||
struct pqi_scsi_dev_raid_map_data rmd;
|
||||
struct pqi_scsi_dev_raid_map_data rmd = { 0 };
|
||||
|
||||
if (!ctrl_info->enable_stream_detection)
|
||||
return false;
|
||||
@ -5984,6 +5990,7 @@ static bool pqi_is_parity_write_stream(struct pqi_ctrl_info *ctrl_info,
|
||||
pqi_stream_data->next_lba = rmd.first_block +
|
||||
rmd.block_cnt;
|
||||
pqi_stream_data->last_accessed = jiffies;
|
||||
per_cpu_ptr(device->raid_io_stats, smp_processor_id())->write_stream_cnt++;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -6016,7 +6023,6 @@ static int pqi_scsi_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scm
|
||||
u16 hw_queue;
|
||||
struct pqi_queue_group *queue_group;
|
||||
bool raid_bypassed;
|
||||
u64 *raid_bypass_cnt;
|
||||
u8 lun;
|
||||
|
||||
scmd->host_scribble = PQI_NO_COMPLETION;
|
||||
@ -6063,8 +6069,7 @@ static int pqi_scsi_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scm
|
||||
rc = pqi_raid_bypass_submit_scsi_cmd(ctrl_info, device, scmd, queue_group);
|
||||
if (rc == 0 || rc == SCSI_MLQUEUE_HOST_BUSY) {
|
||||
raid_bypassed = true;
|
||||
raid_bypass_cnt = per_cpu_ptr(device->raid_bypass_cnt, smp_processor_id());
|
||||
(*raid_bypass_cnt)++;
|
||||
per_cpu_ptr(device->raid_io_stats, smp_processor_id())->raid_bypass_cnt++;
|
||||
}
|
||||
}
|
||||
if (!raid_bypassed)
|
||||
@ -6201,14 +6206,12 @@ static void pqi_fail_io_queued_for_device(struct pqi_ctrl_info *ctrl_info,
|
||||
continue;
|
||||
|
||||
scsi_device = scmd->device->hostdata;
|
||||
if (scsi_device != device)
|
||||
continue;
|
||||
|
||||
if ((u8)scmd->device->lun != lun)
|
||||
continue;
|
||||
|
||||
list_del(&io_request->request_list_entry);
|
||||
set_host_byte(scmd, DID_RESET);
|
||||
if (scsi_device == device && (u8)scmd->device->lun == lun)
|
||||
set_host_byte(scmd, DID_RESET);
|
||||
else
|
||||
set_host_byte(scmd, DID_REQUEUE);
|
||||
pqi_free_io_request(io_request);
|
||||
scsi_dma_unmap(scmd);
|
||||
pqi_scsi_done(scmd);
|
||||
@ -7363,7 +7366,6 @@ static ssize_t pqi_raid_bypass_cnt_show(struct device *dev,
|
||||
unsigned long flags;
|
||||
u64 raid_bypass_cnt;
|
||||
int cpu;
|
||||
u64 *per_cpu_bypass_cnt_ptr;
|
||||
|
||||
sdev = to_scsi_device(dev);
|
||||
ctrl_info = shost_to_hba(sdev->host);
|
||||
@ -7381,10 +7383,9 @@ static ssize_t pqi_raid_bypass_cnt_show(struct device *dev,
|
||||
|
||||
raid_bypass_cnt = 0;
|
||||
|
||||
if (device->raid_bypass_cnt) {
|
||||
if (device->raid_io_stats) {
|
||||
for_each_online_cpu(cpu) {
|
||||
per_cpu_bypass_cnt_ptr = per_cpu_ptr(device->raid_bypass_cnt, cpu);
|
||||
raid_bypass_cnt += *per_cpu_bypass_cnt_ptr;
|
||||
raid_bypass_cnt += per_cpu_ptr(device->raid_io_stats, cpu)->raid_bypass_cnt;
|
||||
}
|
||||
}
|
||||
|
||||
@ -7472,6 +7473,43 @@ static ssize_t pqi_numa_node_show(struct device *dev,
|
||||
return scnprintf(buffer, PAGE_SIZE, "%d\n", ctrl_info->numa_node);
|
||||
}
|
||||
|
||||
static ssize_t pqi_write_stream_cnt_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buffer)
|
||||
{
|
||||
struct pqi_ctrl_info *ctrl_info;
|
||||
struct scsi_device *sdev;
|
||||
struct pqi_scsi_dev *device;
|
||||
unsigned long flags;
|
||||
u64 write_stream_cnt;
|
||||
int cpu;
|
||||
|
||||
sdev = to_scsi_device(dev);
|
||||
ctrl_info = shost_to_hba(sdev->host);
|
||||
|
||||
if (pqi_ctrl_offline(ctrl_info))
|
||||
return -ENODEV;
|
||||
|
||||
spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags);
|
||||
|
||||
device = sdev->hostdata;
|
||||
if (!device) {
|
||||
spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
write_stream_cnt = 0;
|
||||
|
||||
if (device->raid_io_stats) {
|
||||
for_each_online_cpu(cpu) {
|
||||
write_stream_cnt += per_cpu_ptr(device->raid_io_stats, cpu)->write_stream_cnt;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
|
||||
|
||||
return scnprintf(buffer, PAGE_SIZE, "0x%llx\n", write_stream_cnt);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(lunid, 0444, pqi_lunid_show, NULL);
|
||||
static DEVICE_ATTR(unique_id, 0444, pqi_unique_id_show, NULL);
|
||||
static DEVICE_ATTR(path_info, 0444, pqi_path_info_show, NULL);
|
||||
@ -7482,6 +7520,7 @@ static DEVICE_ATTR(raid_bypass_cnt, 0444, pqi_raid_bypass_cnt_show, NULL);
|
||||
static DEVICE_ATTR(sas_ncq_prio_enable, 0644,
|
||||
pqi_sas_ncq_prio_enable_show, pqi_sas_ncq_prio_enable_store);
|
||||
static DEVICE_ATTR(numa_node, 0444, pqi_numa_node_show, NULL);
|
||||
static DEVICE_ATTR(write_stream_cnt, 0444, pqi_write_stream_cnt_show, NULL);
|
||||
|
||||
static struct attribute *pqi_sdev_attrs[] = {
|
||||
&dev_attr_lunid.attr,
|
||||
@ -7493,6 +7532,7 @@ static struct attribute *pqi_sdev_attrs[] = {
|
||||
&dev_attr_raid_bypass_cnt.attr,
|
||||
&dev_attr_sas_ncq_prio_enable.attr,
|
||||
&dev_attr_numa_node.attr,
|
||||
&dev_attr_write_stream_cnt.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -7883,6 +7923,9 @@ static void pqi_ctrl_update_feature_flags(struct pqi_ctrl_info *ctrl_info,
|
||||
case PQI_FIRMWARE_FEATURE_MULTI_LUN_DEVICE_SUPPORT:
|
||||
ctrl_info->multi_lun_device_supported = firmware_feature->enabled;
|
||||
break;
|
||||
case PQI_FIRMWARE_FEATURE_CTRL_LOGGING:
|
||||
ctrl_info->ctrl_logging_supported = firmware_feature->enabled;
|
||||
break;
|
||||
}
|
||||
|
||||
pqi_firmware_feature_status(ctrl_info, firmware_feature);
|
||||
@ -7988,6 +8031,11 @@ static struct pqi_firmware_feature pqi_firmware_features[] = {
|
||||
.feature_bit = PQI_FIRMWARE_FEATURE_MULTI_LUN_DEVICE_SUPPORT,
|
||||
.feature_status = pqi_ctrl_update_feature_flags,
|
||||
},
|
||||
{
|
||||
.feature_name = "Controller Data Logging",
|
||||
.feature_bit = PQI_FIRMWARE_FEATURE_CTRL_LOGGING,
|
||||
.feature_status = pqi_ctrl_update_feature_flags,
|
||||
},
|
||||
};
|
||||
|
||||
static void pqi_process_firmware_features(
|
||||
@ -8090,6 +8138,7 @@ static void pqi_ctrl_reset_config(struct pqi_ctrl_info *ctrl_info)
|
||||
ctrl_info->firmware_triage_supported = false;
|
||||
ctrl_info->rpl_extended_format_4_5_supported = false;
|
||||
ctrl_info->multi_lun_device_supported = false;
|
||||
ctrl_info->ctrl_logging_supported = false;
|
||||
}
|
||||
|
||||
static int pqi_process_config_table(struct pqi_ctrl_info *ctrl_info)
|
||||
@ -8230,6 +8279,9 @@ static void pqi_perform_lockup_action(void)
|
||||
}
|
||||
}
|
||||
|
||||
#define PQI_CTRL_LOG_TOTAL_SIZE (4 * 1024 * 1024)
|
||||
#define PQI_CTRL_LOG_MIN_SIZE (PQI_CTRL_LOG_TOTAL_SIZE / PQI_HOST_MAX_SG_DESCRIPTORS)
|
||||
|
||||
static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
|
||||
{
|
||||
int rc;
|
||||
@ -8241,6 +8293,12 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
if (sis_is_ctrl_logging_supported(ctrl_info)) {
|
||||
sis_notify_kdump(ctrl_info);
|
||||
rc = sis_wait_for_ctrl_logging_completion(ctrl_info);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
sis_soft_reset(ctrl_info);
|
||||
ssleep(PQI_POST_RESET_DELAY_SECS);
|
||||
} else {
|
||||
@ -8422,6 +8480,11 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (ctrl_info->ctrl_logging_supported && !reset_devices) {
|
||||
pqi_host_setup_buffer(ctrl_info, &ctrl_info->ctrl_log_memory, PQI_CTRL_LOG_TOTAL_SIZE, PQI_CTRL_LOG_MIN_SIZE);
|
||||
pqi_host_memory_update(ctrl_info, &ctrl_info->ctrl_log_memory, PQI_VENDOR_GENERAL_CTRL_LOG_MEMORY_UPDATE);
|
||||
}
|
||||
|
||||
rc = pqi_get_ctrl_product_details(ctrl_info);
|
||||
if (rc) {
|
||||
dev_err(&ctrl_info->pci_dev->dev,
|
||||
@ -8606,8 +8669,22 @@ static int pqi_ctrl_init_resume(struct pqi_ctrl_info *ctrl_info)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (pqi_ofa_in_progress(ctrl_info))
|
||||
if (pqi_ofa_in_progress(ctrl_info)) {
|
||||
pqi_ctrl_unblock_scan(ctrl_info);
|
||||
if (ctrl_info->ctrl_logging_supported) {
|
||||
if (!ctrl_info->ctrl_log_memory.host_memory)
|
||||
pqi_host_setup_buffer(ctrl_info,
|
||||
&ctrl_info->ctrl_log_memory,
|
||||
PQI_CTRL_LOG_TOTAL_SIZE,
|
||||
PQI_CTRL_LOG_MIN_SIZE);
|
||||
pqi_host_memory_update(ctrl_info,
|
||||
&ctrl_info->ctrl_log_memory, PQI_VENDOR_GENERAL_CTRL_LOG_MEMORY_UPDATE);
|
||||
} else {
|
||||
if (ctrl_info->ctrl_log_memory.host_memory)
|
||||
pqi_host_free_buffer(ctrl_info,
|
||||
&ctrl_info->ctrl_log_memory);
|
||||
}
|
||||
}
|
||||
|
||||
pqi_scan_scsi_devices(ctrl_info);
|
||||
|
||||
@ -8797,6 +8874,7 @@ static void pqi_remove_ctrl(struct pqi_ctrl_info *ctrl_info)
|
||||
pqi_fail_all_outstanding_requests(ctrl_info);
|
||||
ctrl_info->pqi_mode_enabled = false;
|
||||
}
|
||||
pqi_host_free_buffer(ctrl_info, &ctrl_info->ctrl_log_memory);
|
||||
pqi_unregister_scsi(ctrl_info);
|
||||
if (ctrl_info->pqi_mode_enabled)
|
||||
pqi_revert_to_sis_mode(ctrl_info);
|
||||
@ -8822,170 +8900,6 @@ static void pqi_ofa_ctrl_unquiesce(struct pqi_ctrl_info *ctrl_info)
|
||||
pqi_ctrl_unblock_scan(ctrl_info);
|
||||
}
|
||||
|
||||
static int pqi_ofa_alloc_mem(struct pqi_ctrl_info *ctrl_info, u32 total_size, u32 chunk_size)
|
||||
{
|
||||
int i;
|
||||
u32 sg_count;
|
||||
struct device *dev;
|
||||
struct pqi_ofa_memory *ofap;
|
||||
struct pqi_sg_descriptor *mem_descriptor;
|
||||
dma_addr_t dma_handle;
|
||||
|
||||
ofap = ctrl_info->pqi_ofa_mem_virt_addr;
|
||||
|
||||
sg_count = DIV_ROUND_UP(total_size, chunk_size);
|
||||
if (sg_count == 0 || sg_count > PQI_OFA_MAX_SG_DESCRIPTORS)
|
||||
goto out;
|
||||
|
||||
ctrl_info->pqi_ofa_chunk_virt_addr = kmalloc_array(sg_count, sizeof(void *), GFP_KERNEL);
|
||||
if (!ctrl_info->pqi_ofa_chunk_virt_addr)
|
||||
goto out;
|
||||
|
||||
dev = &ctrl_info->pci_dev->dev;
|
||||
|
||||
for (i = 0; i < sg_count; i++) {
|
||||
ctrl_info->pqi_ofa_chunk_virt_addr[i] =
|
||||
dma_alloc_coherent(dev, chunk_size, &dma_handle, GFP_KERNEL);
|
||||
if (!ctrl_info->pqi_ofa_chunk_virt_addr[i])
|
||||
goto out_free_chunks;
|
||||
mem_descriptor = &ofap->sg_descriptor[i];
|
||||
put_unaligned_le64((u64)dma_handle, &mem_descriptor->address);
|
||||
put_unaligned_le32(chunk_size, &mem_descriptor->length);
|
||||
}
|
||||
|
||||
put_unaligned_le32(CISS_SG_LAST, &mem_descriptor->flags);
|
||||
put_unaligned_le16(sg_count, &ofap->num_memory_descriptors);
|
||||
put_unaligned_le32(sg_count * chunk_size, &ofap->bytes_allocated);
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_chunks:
|
||||
while (--i >= 0) {
|
||||
mem_descriptor = &ofap->sg_descriptor[i];
|
||||
dma_free_coherent(dev, chunk_size,
|
||||
ctrl_info->pqi_ofa_chunk_virt_addr[i],
|
||||
get_unaligned_le64(&mem_descriptor->address));
|
||||
}
|
||||
kfree(ctrl_info->pqi_ofa_chunk_virt_addr);
|
||||
|
||||
out:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int pqi_ofa_alloc_host_buffer(struct pqi_ctrl_info *ctrl_info)
|
||||
{
|
||||
u32 total_size;
|
||||
u32 chunk_size;
|
||||
u32 min_chunk_size;
|
||||
|
||||
if (ctrl_info->ofa_bytes_requested == 0)
|
||||
return 0;
|
||||
|
||||
total_size = PAGE_ALIGN(ctrl_info->ofa_bytes_requested);
|
||||
min_chunk_size = DIV_ROUND_UP(total_size, PQI_OFA_MAX_SG_DESCRIPTORS);
|
||||
min_chunk_size = PAGE_ALIGN(min_chunk_size);
|
||||
|
||||
for (chunk_size = total_size; chunk_size >= min_chunk_size;) {
|
||||
if (pqi_ofa_alloc_mem(ctrl_info, total_size, chunk_size) == 0)
|
||||
return 0;
|
||||
chunk_size /= 2;
|
||||
chunk_size = PAGE_ALIGN(chunk_size);
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void pqi_ofa_setup_host_buffer(struct pqi_ctrl_info *ctrl_info)
|
||||
{
|
||||
struct device *dev;
|
||||
struct pqi_ofa_memory *ofap;
|
||||
|
||||
dev = &ctrl_info->pci_dev->dev;
|
||||
|
||||
ofap = dma_alloc_coherent(dev, sizeof(*ofap),
|
||||
&ctrl_info->pqi_ofa_mem_dma_handle, GFP_KERNEL);
|
||||
if (!ofap)
|
||||
return;
|
||||
|
||||
ctrl_info->pqi_ofa_mem_virt_addr = ofap;
|
||||
|
||||
if (pqi_ofa_alloc_host_buffer(ctrl_info) < 0) {
|
||||
dev_err(dev,
|
||||
"failed to allocate host buffer for Online Firmware Activation\n");
|
||||
dma_free_coherent(dev, sizeof(*ofap), ofap, ctrl_info->pqi_ofa_mem_dma_handle);
|
||||
ctrl_info->pqi_ofa_mem_virt_addr = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
put_unaligned_le16(PQI_OFA_VERSION, &ofap->version);
|
||||
memcpy(&ofap->signature, PQI_OFA_SIGNATURE, sizeof(ofap->signature));
|
||||
}
|
||||
|
||||
static void pqi_ofa_free_host_buffer(struct pqi_ctrl_info *ctrl_info)
|
||||
{
|
||||
unsigned int i;
|
||||
struct device *dev;
|
||||
struct pqi_ofa_memory *ofap;
|
||||
struct pqi_sg_descriptor *mem_descriptor;
|
||||
unsigned int num_memory_descriptors;
|
||||
|
||||
ofap = ctrl_info->pqi_ofa_mem_virt_addr;
|
||||
if (!ofap)
|
||||
return;
|
||||
|
||||
dev = &ctrl_info->pci_dev->dev;
|
||||
|
||||
if (get_unaligned_le32(&ofap->bytes_allocated) == 0)
|
||||
goto out;
|
||||
|
||||
mem_descriptor = ofap->sg_descriptor;
|
||||
num_memory_descriptors =
|
||||
get_unaligned_le16(&ofap->num_memory_descriptors);
|
||||
|
||||
for (i = 0; i < num_memory_descriptors; i++) {
|
||||
dma_free_coherent(dev,
|
||||
get_unaligned_le32(&mem_descriptor[i].length),
|
||||
ctrl_info->pqi_ofa_chunk_virt_addr[i],
|
||||
get_unaligned_le64(&mem_descriptor[i].address));
|
||||
}
|
||||
kfree(ctrl_info->pqi_ofa_chunk_virt_addr);
|
||||
|
||||
out:
|
||||
dma_free_coherent(dev, sizeof(*ofap), ofap,
|
||||
ctrl_info->pqi_ofa_mem_dma_handle);
|
||||
ctrl_info->pqi_ofa_mem_virt_addr = NULL;
|
||||
}
|
||||
|
||||
static int pqi_ofa_host_memory_update(struct pqi_ctrl_info *ctrl_info)
|
||||
{
|
||||
u32 buffer_length;
|
||||
struct pqi_vendor_general_request request;
|
||||
struct pqi_ofa_memory *ofap;
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
|
||||
request.header.iu_type = PQI_REQUEST_IU_VENDOR_GENERAL;
|
||||
put_unaligned_le16(sizeof(request) - PQI_REQUEST_HEADER_LENGTH,
|
||||
&request.header.iu_length);
|
||||
put_unaligned_le16(PQI_VENDOR_GENERAL_HOST_MEMORY_UPDATE,
|
||||
&request.function_code);
|
||||
|
||||
ofap = ctrl_info->pqi_ofa_mem_virt_addr;
|
||||
|
||||
if (ofap) {
|
||||
buffer_length = offsetof(struct pqi_ofa_memory, sg_descriptor) +
|
||||
get_unaligned_le16(&ofap->num_memory_descriptors) *
|
||||
sizeof(struct pqi_sg_descriptor);
|
||||
|
||||
put_unaligned_le64((u64)ctrl_info->pqi_ofa_mem_dma_handle,
|
||||
&request.data.ofa_memory_allocation.buffer_address);
|
||||
put_unaligned_le32(buffer_length,
|
||||
&request.data.ofa_memory_allocation.buffer_length);
|
||||
}
|
||||
|
||||
return pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0, NULL);
|
||||
}
|
||||
|
||||
static int pqi_ofa_ctrl_restart(struct pqi_ctrl_info *ctrl_info, unsigned int delay_secs)
|
||||
{
|
||||
ssleep(delay_secs);
|
||||
@ -8993,6 +8907,180 @@ static int pqi_ofa_ctrl_restart(struct pqi_ctrl_info *ctrl_info, unsigned int de
|
||||
return pqi_ctrl_init_resume(ctrl_info);
|
||||
}
|
||||
|
||||
static int pqi_host_alloc_mem(struct pqi_ctrl_info *ctrl_info,
|
||||
struct pqi_host_memory_descriptor *host_memory_descriptor,
|
||||
u32 total_size, u32 chunk_size)
|
||||
{
|
||||
int i;
|
||||
u32 sg_count;
|
||||
struct device *dev;
|
||||
struct pqi_host_memory *host_memory;
|
||||
struct pqi_sg_descriptor *mem_descriptor;
|
||||
dma_addr_t dma_handle;
|
||||
|
||||
sg_count = DIV_ROUND_UP(total_size, chunk_size);
|
||||
if (sg_count == 0 || sg_count > PQI_HOST_MAX_SG_DESCRIPTORS)
|
||||
goto out;
|
||||
|
||||
host_memory_descriptor->host_chunk_virt_address = kmalloc(sg_count * sizeof(void *), GFP_KERNEL);
|
||||
if (!host_memory_descriptor->host_chunk_virt_address)
|
||||
goto out;
|
||||
|
||||
dev = &ctrl_info->pci_dev->dev;
|
||||
host_memory = host_memory_descriptor->host_memory;
|
||||
|
||||
for (i = 0; i < sg_count; i++) {
|
||||
host_memory_descriptor->host_chunk_virt_address[i] = dma_alloc_coherent(dev, chunk_size, &dma_handle, GFP_KERNEL);
|
||||
if (!host_memory_descriptor->host_chunk_virt_address[i])
|
||||
goto out_free_chunks;
|
||||
mem_descriptor = &host_memory->sg_descriptor[i];
|
||||
put_unaligned_le64((u64)dma_handle, &mem_descriptor->address);
|
||||
put_unaligned_le32(chunk_size, &mem_descriptor->length);
|
||||
}
|
||||
|
||||
put_unaligned_le32(CISS_SG_LAST, &mem_descriptor->flags);
|
||||
put_unaligned_le16(sg_count, &host_memory->num_memory_descriptors);
|
||||
put_unaligned_le32(sg_count * chunk_size, &host_memory->bytes_allocated);
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_chunks:
|
||||
while (--i >= 0) {
|
||||
mem_descriptor = &host_memory->sg_descriptor[i];
|
||||
dma_free_coherent(dev, chunk_size,
|
||||
host_memory_descriptor->host_chunk_virt_address[i],
|
||||
get_unaligned_le64(&mem_descriptor->address));
|
||||
}
|
||||
kfree(host_memory_descriptor->host_chunk_virt_address);
|
||||
out:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int pqi_host_alloc_buffer(struct pqi_ctrl_info *ctrl_info,
|
||||
struct pqi_host_memory_descriptor *host_memory_descriptor,
|
||||
u32 total_required_size, u32 min_required_size)
|
||||
{
|
||||
u32 chunk_size;
|
||||
u32 min_chunk_size;
|
||||
|
||||
if (total_required_size == 0 || min_required_size == 0)
|
||||
return 0;
|
||||
|
||||
total_required_size = PAGE_ALIGN(total_required_size);
|
||||
min_required_size = PAGE_ALIGN(min_required_size);
|
||||
min_chunk_size = DIV_ROUND_UP(total_required_size, PQI_HOST_MAX_SG_DESCRIPTORS);
|
||||
min_chunk_size = PAGE_ALIGN(min_chunk_size);
|
||||
|
||||
while (total_required_size >= min_required_size) {
|
||||
for (chunk_size = total_required_size; chunk_size >= min_chunk_size;) {
|
||||
if (pqi_host_alloc_mem(ctrl_info,
|
||||
host_memory_descriptor, total_required_size,
|
||||
chunk_size) == 0)
|
||||
return 0;
|
||||
chunk_size /= 2;
|
||||
chunk_size = PAGE_ALIGN(chunk_size);
|
||||
}
|
||||
total_required_size /= 2;
|
||||
total_required_size = PAGE_ALIGN(total_required_size);
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void pqi_host_setup_buffer(struct pqi_ctrl_info *ctrl_info,
|
||||
struct pqi_host_memory_descriptor *host_memory_descriptor,
|
||||
u32 total_size, u32 min_size)
|
||||
{
|
||||
struct device *dev;
|
||||
struct pqi_host_memory *host_memory;
|
||||
|
||||
dev = &ctrl_info->pci_dev->dev;
|
||||
|
||||
host_memory = dma_alloc_coherent(dev, sizeof(*host_memory),
|
||||
&host_memory_descriptor->host_memory_dma_handle, GFP_KERNEL);
|
||||
if (!host_memory)
|
||||
return;
|
||||
|
||||
host_memory_descriptor->host_memory = host_memory;
|
||||
|
||||
if (pqi_host_alloc_buffer(ctrl_info, host_memory_descriptor,
|
||||
total_size, min_size) < 0) {
|
||||
dev_err(dev, "failed to allocate firmware usable host buffer\n");
|
||||
dma_free_coherent(dev, sizeof(*host_memory), host_memory,
|
||||
host_memory_descriptor->host_memory_dma_handle);
|
||||
host_memory_descriptor->host_memory = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void pqi_host_free_buffer(struct pqi_ctrl_info *ctrl_info,
|
||||
struct pqi_host_memory_descriptor *host_memory_descriptor)
|
||||
{
|
||||
unsigned int i;
|
||||
struct device *dev;
|
||||
struct pqi_host_memory *host_memory;
|
||||
struct pqi_sg_descriptor *mem_descriptor;
|
||||
unsigned int num_memory_descriptors;
|
||||
|
||||
host_memory = host_memory_descriptor->host_memory;
|
||||
if (!host_memory)
|
||||
return;
|
||||
|
||||
dev = &ctrl_info->pci_dev->dev;
|
||||
|
||||
if (get_unaligned_le32(&host_memory->bytes_allocated) == 0)
|
||||
goto out;
|
||||
|
||||
mem_descriptor = host_memory->sg_descriptor;
|
||||
num_memory_descriptors = get_unaligned_le16(&host_memory->num_memory_descriptors);
|
||||
|
||||
for (i = 0; i < num_memory_descriptors; i++) {
|
||||
dma_free_coherent(dev,
|
||||
get_unaligned_le32(&mem_descriptor[i].length),
|
||||
host_memory_descriptor->host_chunk_virt_address[i],
|
||||
get_unaligned_le64(&mem_descriptor[i].address));
|
||||
}
|
||||
kfree(host_memory_descriptor->host_chunk_virt_address);
|
||||
|
||||
out:
|
||||
dma_free_coherent(dev, sizeof(*host_memory), host_memory,
|
||||
host_memory_descriptor->host_memory_dma_handle);
|
||||
host_memory_descriptor->host_memory = NULL;
|
||||
}
|
||||
|
||||
static int pqi_host_memory_update(struct pqi_ctrl_info *ctrl_info,
|
||||
struct pqi_host_memory_descriptor *host_memory_descriptor,
|
||||
u16 function_code)
|
||||
{
|
||||
u32 buffer_length;
|
||||
struct pqi_vendor_general_request request;
|
||||
struct pqi_host_memory *host_memory;
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
|
||||
request.header.iu_type = PQI_REQUEST_IU_VENDOR_GENERAL;
|
||||
put_unaligned_le16(sizeof(request) - PQI_REQUEST_HEADER_LENGTH, &request.header.iu_length);
|
||||
put_unaligned_le16(function_code, &request.function_code);
|
||||
|
||||
host_memory = host_memory_descriptor->host_memory;
|
||||
|
||||
if (host_memory) {
|
||||
buffer_length = offsetof(struct pqi_host_memory, sg_descriptor) + get_unaligned_le16(&host_memory->num_memory_descriptors) * sizeof(struct pqi_sg_descriptor);
|
||||
put_unaligned_le64((u64)host_memory_descriptor->host_memory_dma_handle, &request.data.host_memory_allocation.buffer_address);
|
||||
put_unaligned_le32(buffer_length, &request.data.host_memory_allocation.buffer_length);
|
||||
|
||||
if (function_code == PQI_VENDOR_GENERAL_OFA_MEMORY_UPDATE) {
|
||||
put_unaligned_le16(PQI_OFA_VERSION, &host_memory->version);
|
||||
memcpy(&host_memory->signature, PQI_OFA_SIGNATURE, sizeof(host_memory->signature));
|
||||
} else if (function_code == PQI_VENDOR_GENERAL_CTRL_LOG_MEMORY_UPDATE) {
|
||||
put_unaligned_le16(PQI_CTRL_LOG_VERSION, &host_memory->version);
|
||||
memcpy(&host_memory->signature, PQI_CTRL_LOG_SIGNATURE, sizeof(host_memory->signature));
|
||||
}
|
||||
}
|
||||
|
||||
return pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0, NULL);
|
||||
}
|
||||
|
||||
static struct pqi_raid_error_info pqi_ctrl_offline_raid_error_info = {
|
||||
.data_out_result = PQI_DATA_IN_OUT_HARDWARE_ERROR,
|
||||
.status = SAM_STAT_CHECK_CONDITION,
|
||||
@ -9464,6 +9552,10 @@ static const struct pci_device_id pqi_pci_id_table[] = {
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x152d, 0x8a37)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x193d, 0x0462)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x193d, 0x1104)
|
||||
@ -9504,6 +9596,10 @@ static const struct pci_device_id pqi_pci_id_table[] = {
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x193d, 0x8461)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x193d, 0x8462)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x193d, 0xc460)
|
||||
@ -10212,6 +10308,18 @@ static const struct pci_device_id pqi_pci_id_table[] = {
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x1137, 0x02fa)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x1137, 0x02fe)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x1137, 0x02ff)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x1137, 0x0300)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x1ff9, 0x0045)
|
||||
@ -10388,6 +10496,10 @@ static const struct pci_device_id pqi_pci_id_table[] = {
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x1f51, 0x1045)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x1ff9, 0x00a3)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
PCI_ANY_ID, PCI_ANY_ID)
|
||||
|
@ -29,6 +29,7 @@
|
||||
#define SIS_ENABLE_INTX 0x80
|
||||
#define SIS_SOFT_RESET 0x100
|
||||
#define SIS_CMD_READY 0x200
|
||||
#define SIS_NOTIFY_KDUMP 0x400
|
||||
#define SIS_TRIGGER_SHUTDOWN 0x800000
|
||||
#define SIS_PQI_RESET_QUIESCE 0x1000000
|
||||
|
||||
@ -52,6 +53,8 @@
|
||||
#define SIS_BASE_STRUCT_ALIGNMENT 16
|
||||
|
||||
#define SIS_CTRL_KERNEL_FW_TRIAGE 0x3
|
||||
#define SIS_CTRL_KERNEL_CTRL_LOGGING 0x4
|
||||
#define SIS_CTRL_KERNEL_CTRL_LOGGING_STATUS 0x18
|
||||
#define SIS_CTRL_KERNEL_UP 0x80
|
||||
#define SIS_CTRL_KERNEL_PANIC 0x100
|
||||
#define SIS_CTRL_READY_TIMEOUT_SECS 180
|
||||
@ -65,6 +68,13 @@ enum sis_fw_triage_status {
|
||||
FW_TRIAGE_COMPLETED
|
||||
};
|
||||
|
||||
enum sis_ctrl_logging_status {
|
||||
CTRL_LOGGING_NOT_STARTED = 0,
|
||||
CTRL_LOGGING_STARTED,
|
||||
CTRL_LOGGING_COND_INVALID,
|
||||
CTRL_LOGGING_COMPLETED
|
||||
};
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
/* for use with SIS_CMD_INIT_BASE_STRUCT_ADDRESS command */
|
||||
@ -442,6 +452,21 @@ static inline enum sis_fw_triage_status
|
||||
SIS_CTRL_KERNEL_FW_TRIAGE));
|
||||
}
|
||||
|
||||
bool sis_is_ctrl_logging_supported(struct pqi_ctrl_info *ctrl_info)
|
||||
{
|
||||
return readl(&ctrl_info->registers->sis_firmware_status) & SIS_CTRL_KERNEL_CTRL_LOGGING;
|
||||
}
|
||||
|
||||
void sis_notify_kdump(struct pqi_ctrl_info *ctrl_info)
|
||||
{
|
||||
sis_set_doorbell_bit(ctrl_info, SIS_NOTIFY_KDUMP);
|
||||
}
|
||||
|
||||
static inline enum sis_ctrl_logging_status sis_read_ctrl_logging_status(struct pqi_ctrl_info *ctrl_info)
|
||||
{
|
||||
return ((enum sis_ctrl_logging_status)((readl(&ctrl_info->registers->sis_firmware_status) & SIS_CTRL_KERNEL_CTRL_LOGGING_STATUS) >> 3));
|
||||
}
|
||||
|
||||
void sis_soft_reset(struct pqi_ctrl_info *ctrl_info)
|
||||
{
|
||||
writel(SIS_SOFT_RESET,
|
||||
@ -484,6 +509,41 @@ int sis_wait_for_fw_triage_completion(struct pqi_ctrl_info *ctrl_info)
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define SIS_CTRL_LOGGING_STATUS_TIMEOUT_SECS 180
|
||||
#define SIS_CTRL_LOGGING_STATUS_POLL_INTERVAL_SECS 1
|
||||
|
||||
int sis_wait_for_ctrl_logging_completion(struct pqi_ctrl_info *ctrl_info)
|
||||
{
|
||||
int rc;
|
||||
enum sis_ctrl_logging_status status;
|
||||
unsigned long timeout;
|
||||
|
||||
timeout = (SIS_CTRL_LOGGING_STATUS_TIMEOUT_SECS * HZ) + jiffies;
|
||||
while (1) {
|
||||
status = sis_read_ctrl_logging_status(ctrl_info);
|
||||
if (status == CTRL_LOGGING_COND_INVALID) {
|
||||
dev_err(&ctrl_info->pci_dev->dev,
|
||||
"controller data logging condition invalid\n");
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
} else if (status == CTRL_LOGGING_COMPLETED) {
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_err(&ctrl_info->pci_dev->dev,
|
||||
"timed out waiting for controller data logging status\n");
|
||||
rc = -ETIMEDOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
ssleep(SIS_CTRL_LOGGING_STATUS_POLL_INTERVAL_SECS);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void sis_verify_structures(void)
|
||||
{
|
||||
BUILD_BUG_ON(offsetof(struct sis_base_struct,
|
||||
|
@ -31,6 +31,9 @@ u32 sis_read_driver_scratch(struct pqi_ctrl_info *ctrl_info);
|
||||
void sis_soft_reset(struct pqi_ctrl_info *ctrl_info);
|
||||
u32 sis_get_product_id(struct pqi_ctrl_info *ctrl_info);
|
||||
int sis_wait_for_fw_triage_completion(struct pqi_ctrl_info *ctrl_info);
|
||||
bool sis_is_ctrl_logging_supported(struct pqi_ctrl_info *ctrl_info);
|
||||
void sis_notify_kdump(struct pqi_ctrl_info *ctrl_info);
|
||||
int sis_wait_for_ctrl_logging_completion(struct pqi_ctrl_info *ctrl_info);
|
||||
|
||||
extern unsigned int sis_ctrl_ready_timeout_secs;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user