From 058311b72f54890de824b063feb603942269b732 Mon Sep 17 00:00:00 2001 From: Murthy Bhat Date: Tue, 27 Aug 2024 13:54:55 -0500 Subject: [PATCH 1/7] scsi: smartpqi: Add fw log to kdump Add controller logs to kdump. Driver allocates DMA memory and communicates this address to FW. In the event of system crash, host driver notifies the firmware about the crash and firmware posts all the necessary logs in the pre-allocated host buffer for firmware debugging. Once firmware notifies the completion of the log uploading to the host memory and host continues with the OS crash dump saving. This is a "feature" driven capability and is backward compatible with existing controller FW. Rename 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. 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. Reviewed-by: Scott Benesh Reviewed-by: Mike McGowen Signed-off-by: Murthy Bhat Signed-off-by: Don Brace Link: https://lore.kernel.org/r/20240827185501.692804-2-don.brace@microchip.com Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi.h | 32 ++- drivers/scsi/smartpqi/smartpqi_init.c | 396 +++++++++++++++----------- drivers/scsi/smartpqi/smartpqi_sis.c | 60 ++++ drivers/scsi/smartpqi/smartpqi_sis.h | 3 + 4 files changed, 306 insertions(+), 185 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h index 023fbce04e7a..f493006bee9d 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; @@ -1357,6 +1367,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 +1409,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..54f7fe843445 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -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); @@ -3634,7 +3634,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 +3645,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 +3655,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 +3670,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 +3711,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: @@ -7883,6 +7883,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 +7991,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 +8098,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 +8239,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 +8253,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 +8440,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 +8629,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 +8834,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 +8860,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 +8867,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, 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; From 4c76114932d1d6fad2e72823e7898a3c960cf2a7 Mon Sep 17 00:00:00 2001 From: Mahesh Rajashekhara Date: Tue, 27 Aug 2024 13:54:56 -0500 Subject: [PATCH 2/7] scsi: smartpqi: correct stream detection Correct stream detection by initializing the structure pqi_scsi_dev_raid_map_data to 0s. When the OS issues SCSI READ commands, the driver erroneously considers them as SCSI WRITES. If they are identified as sequential IOs, the driver then submits those requests via the RAID path instead of the AIO path. The 'is_write' flag might be set for SCSI READ commands also. The driver may interpret SCSI READ commands as SCSI WRITE commands, resulting in IOs being submitted through the RAID path. Note: This does not cause data corruption. Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Reviewed-by: Mike McGowen Signed-off-by: Mahesh Rajashekhara Signed-off-by: Don Brace Link: https://lore.kernel.org/r/20240827185501.692804-3-don.brace@microchip.com Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 54f7fe843445..8e2e71ab49ae 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -5942,7 +5942,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; From 283dcc1b142ebd60786f8f5e3fbbd53a51035739 Mon Sep 17 00:00:00 2001 From: Mahesh Rajashekhara Date: Tue, 27 Aug 2024 13:54:57 -0500 Subject: [PATCH 3/7] scsi: smartpqi: add counter for parity write stream requests Add sysfs entry to check for write stream requests. Move existing raid_bypass_cnt into a structure named pqi_raid_io_stats and add member write_stream_cnt. These two counters are related because write stream detection is only checked if an I/O request is eligible for bypass (AIO). Example usage: lsscsi [15:1:0:0] disk Adaptec LOGICAL VOLUME 0129 /dev/sdae cat /sys/block/sdae/device/ssd_smart_path_enabled 1 ^ | +---- NOTE: here bypass has been enabled on device sdae To read the counter for parity write stream requests: cat /sys/block/sdae/device/write_stream_cnt 0x60cd507 Reviewed-by: Scott Benesh Reviewed-by: Mike McGowen Signed-off-by: Mahesh Rajashekhara Co-developed-by: Kevin Barnett Signed-off-by: Kevin Barnett Signed-off-by: Don Brace Link: https://lore.kernel.org/r/20240827185501.692804-4-don.brace@microchip.com Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi.h | 7 ++- drivers/scsi/smartpqi/smartpqi_init.c | 62 +++++++++++++++++++++------ 2 files changed, 55 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h index f493006bee9d..fae6db20a6e9 100644 --- a/drivers/scsi/smartpqi/smartpqi.h +++ b/drivers/scsi/smartpqi/smartpqi.h @@ -1106,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 */ @@ -1168,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]; }; diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 8e2e71ab49ae..6a941735c982 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -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); } @@ -5984,6 +5984,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 +6017,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 +6063,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) @@ -7363,7 +7362,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 +7379,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 +7469,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 +7516,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 +7528,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 }; From dbc39b84540f746cc814e69b21e53e6d3e12329a Mon Sep 17 00:00:00 2001 From: David Strahan Date: Tue, 27 Aug 2024 13:54:58 -0500 Subject: [PATCH 4/7] scsi: smartpqi: add new controller PCI IDs All PCI ID entries in Hex. Add new cisco pci ids: VID / DID / SVID / SDID ---- ---- ---- ---- 9005 028f 1137 02fe 9005 028f 1137 02ff 9005 028f 1137 0300 Add new h3c pci ids: VID / DID / SVID / SDID ---- ---- ---- ---- 9005 028f 193d 0462 9005 028f 193d 8462 Add new ieit pci ids: VID / DID / SVID / SDID ---- ---- ---- ---- 9005 028f 1ff9 00a3 Reviewed-by: Scott Benesh Reviewed-by: Mike McGowen Signed-off-by: David Strahan Signed-off-by: Don Brace Link: https://lore.kernel.org/r/20240827185501.692804-5-don.brace@microchip.com Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 6a941735c982..46bef2cf95c4 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -9548,6 +9548,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) @@ -9588,6 +9592,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) @@ -10296,6 +10304,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) @@ -10472,6 +10492,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) From 4e0a51716dae782822b5df6c3b29cc0915a9f802 Mon Sep 17 00:00:00 2001 From: Murthy Bhat Date: Tue, 27 Aug 2024 13:54:59 -0500 Subject: [PATCH 5/7] scsi: smartpqi: fix rare system hang during LUN reset Correct a rare case where in a LUN reset occurs on a device and I/O requests for other devices persist in the driver's internal request queue. Part of a LUN reset involves waiting for our internal request queue to empty before proceeding. The internal request queue contains requests not yet sent down to the controller. We were clearing the requests queued for the LUN undergoing a reset, but not all of the queued requests. Causing a hang. 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. Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Reviewed-by: Mike McGowen Signed-off-by: Murthy Bhat Signed-off-by: Don Brace Link: https://lore.kernel.org/r/20240827185501.692804-6-don.brace@microchip.com Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 46bef2cf95c4..d1d117d5d08d 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -6200,14 +6200,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); From 07dde72ff173742137546cb4e5e9264c8e1ba2ba Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 27 Aug 2024 13:55:00 -0500 Subject: [PATCH 6/7] scsi: smartpqi: fix volume size updates Correct logical volume size changes by moving the check for a volume rescan outside of the check for a queue depth change. Signed-off-by: Don Brace Link: https://lore.kernel.org/r/20240827185501.692804-7-don.brace@microchip.com Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index d1d117d5d08d..0dab30753f0a 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -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); } } From bda1c931e2993cbd43515dccec8bdd200a39cbf0 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 27 Aug 2024 13:55:01 -0500 Subject: [PATCH 7/7] scsi: smartpqi: update driver version to 2.1.30-031 Update driver version to 2.1.30-031. Reviewed-by: David Strahan Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Reviewed-by: Mike McGowen Reviewed-by: Gerry Morong Signed-off-by: Don Brace Link: https://lore.kernel.org/r/20240827185501.692804-8-don.brace@microchip.com Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 0dab30753f0a..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 ")"