diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h index 023fbce04e7a..fae6db20a6e9 100644 --- a/drivers/scsi/smartpqi/smartpqi.h +++ b/drivers/scsi/smartpqi/smartpqi.h @@ -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; }; diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index b5396d722d52..7fd5a8c813dc 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -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) diff --git a/drivers/scsi/smartpqi/smartpqi_sis.c b/drivers/scsi/smartpqi/smartpqi_sis.c index 673437c7152b..ca1df36b83f7 100644 --- a/drivers/scsi/smartpqi/smartpqi_sis.c +++ b/drivers/scsi/smartpqi/smartpqi_sis.c @@ -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, diff --git a/drivers/scsi/smartpqi/smartpqi_sis.h b/drivers/scsi/smartpqi/smartpqi_sis.h index 0c97626d87d4..7e0eac3d07de 100644 --- a/drivers/scsi/smartpqi/smartpqi_sis.h +++ b/drivers/scsi/smartpqi/smartpqi_sis.h @@ -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;