Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

scsi: mpi3mr: HDB allocation and posting for hardware and firmware buffers

To be able to debug controller problems it is beneficial to allocate and
configure system/host memory buffers which can be used to capture hardware
and firmware diagnostic information.

Add functions required to allocate and post firmware and hardware
diagnostic buffers to the controller and to set up automatic diagnostic
capture triggers.

Captures will be triggered under the following circumstances:

1. Firmware is in FAULT state.

2. Admin commands time out.

3. Controller reset caused due to I/O timeout

Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202405151758.7xrJz6rp-lkp@intel.com/
Co-developed-by: Sathya Prakash <sathya.prakash@broadcom.com>
Signed-off-by: Sathya Prakash <sathya.prakash@broadcom.com>
Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
Link: https://lore.kernel.org/r/20240626102646.14298-2-ranjan.kumar@broadcom.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Ranjan Kumar and committed by
Martin K. Petersen
fc444494 1613e604

+790 -1
+44
drivers/scsi/mpi3mr/mpi/mpi30_tool.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* 3 + * Copyright 2016-2024 Broadcom Inc. All rights reserved. 4 + */ 5 + #ifndef MPI30_TOOL_H 6 + #define MPI30_TOOL_H 1 7 + 8 + #define MPI3_DIAG_BUFFER_TYPE_TRACE (0x01) 9 + #define MPI3_DIAG_BUFFER_TYPE_FW (0x02) 10 + #define MPI3_DIAG_BUFFER_ACTION_RELEASE (0x01) 11 + 12 + struct mpi3_diag_buffer_post_request { 13 + __le16 host_tag; 14 + u8 ioc_use_only02; 15 + u8 function; 16 + __le16 ioc_use_only04; 17 + u8 ioc_use_only06; 18 + u8 msg_flags; 19 + __le16 change_count; 20 + __le16 reserved0a; 21 + u8 type; 22 + u8 reserved0d; 23 + __le16 reserved0e; 24 + __le64 address; 25 + __le32 length; 26 + __le32 reserved1c; 27 + }; 28 + 29 + struct mpi3_diag_buffer_manage_request { 30 + __le16 host_tag; 31 + u8 ioc_use_only02; 32 + u8 function; 33 + __le16 ioc_use_only04; 34 + u8 ioc_use_only06; 35 + u8 msg_flags; 36 + __le16 change_count; 37 + __le16 reserved0a; 38 + u8 type; 39 + u8 action; 40 + __le16 reserved0e; 41 + }; 42 + 43 + 44 + #endif
+74
drivers/scsi/mpi3mr/mpi3mr.h
··· 47 47 #include "mpi/mpi30_ioc.h" 48 48 #include "mpi/mpi30_sas.h" 49 49 #include "mpi/mpi30_pci.h" 50 + #include "mpi/mpi30_tool.h" 50 51 #include "mpi3mr_debug.h" 51 52 52 53 /* Global list and lock for storing multiple adapters managed by the driver */ ··· 188 187 #define MPI3MR_HARD_SECURE_DEVICE 0x08 189 188 #define MPI3MR_TAMPERED_DEVICE 0x0C 190 189 190 + #define MPI3MR_DEFAULT_HDB_MAX_SZ (4 * 1024 * 1024) 191 + #define MPI3MR_DEFAULT_HDB_DEC_SZ (1 * 1024 * 1024) 192 + #define MPI3MR_DEFAULT_HDB_MIN_SZ (2 * 1024 * 1024) 193 + #define MPI3MR_MAX_NUM_HDB 2 194 + 195 + #define MPI3MR_HDB_TRIGGER_TYPE_GLOBAL 3 196 + 191 197 /* SGE Flag definition */ 192 198 #define MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST \ 193 199 (MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | MPI3_SGE_FLAGS_DLAS_SYSTEM | \ ··· 217 209 218 210 #define MPI3MR_WRITE_SAME_MAX_LEN_256_BLKS 256 219 211 #define MPI3MR_WRITE_SAME_MAX_LEN_2048_BLKS 2048 212 + 220 213 221 214 /** 222 215 * struct mpi3mr_nvme_pt_sge - Structure to store SGEs for NVMe ··· 298 289 MPI3MR_RESET_FROM_PELABORT_TIMEOUT = 22, 299 290 MPI3MR_RESET_FROM_SYSFS = 23, 300 291 MPI3MR_RESET_FROM_SYSFS_TIMEOUT = 24, 292 + MPI3MR_RESET_FROM_DIAG_BUFFER_POST_TIMEOUT = 25, 293 + MPI3MR_RESET_FROM_DIAG_BUFFER_RELEASE_TIMEOUT = 26, 301 294 MPI3MR_RESET_FROM_FIRMWARE = 27, 302 295 MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT = 29, 303 296 MPI3MR_RESET_FROM_SAS_TRANSPORT_TIMEOUT = 30, ··· 338 327 u32 ioc_capabilities; 339 328 struct mpi3mr_compimg_ver fw_ver; 340 329 u32 mpi_version; 330 + u32 diag_trace_sz; 331 + u32 diag_fw_sz; 332 + u32 diag_drvr_sz; 341 333 u16 max_reqs; 342 334 u16 product_id; 343 335 u16 op_req_sz; ··· 867 853 }; 868 854 869 855 /** 856 + * union mpi3mr_trigger_data - Trigger data information 857 + * @fault: Fault code 858 + * @global: Global trigger data 859 + * @element: element trigger data 860 + */ 861 + union mpi3mr_trigger_data { 862 + u16 fault; 863 + u64 global; 864 + union mpi3_driver2_trigger_element element; 865 + }; 866 + 867 + /** 868 + * struct diag_buffer_desc - memory descriptor structure to 869 + * store virtual, dma addresses, size, buffer status for host 870 + * diagnostic buffers. 871 + * 872 + * @type: Buffer type 873 + * @trigger_data: Trigger data 874 + * @trigger_type: Trigger type 875 + * @status: Buffer status 876 + * @size: Buffer size 877 + * @addr: Virtual address 878 + * @dma_addr: Buffer DMA address 879 + */ 880 + struct diag_buffer_desc { 881 + u8 type; 882 + union mpi3mr_trigger_data trigger_data; 883 + u8 trigger_type; 884 + u8 status; 885 + u32 size; 886 + void *addr; 887 + dma_addr_t dma_addr; 888 + }; 889 + 890 + /** 870 891 * struct dma_memory_desc - memory descriptor structure to store 871 892 * virtual address, dma address and size for any generic dma 872 893 * memory allocations in the driver. ··· 1103 1054 * @sas_node_lock: Lock to protect SAS node list 1104 1055 * @hba_port_table_list: List of HBA Ports 1105 1056 * @enclosure_list: List of Enclosure objects 1057 + * @diag_buffers: Host diagnostic buffers 1058 + * @driver_pg2: Driver page 2 pointer 1059 + * @reply_trigger_present: Reply trigger present flag 1060 + * @event_trigger_present: Event trigger present flag 1061 + * @scsisense_trigger_present: Scsi sense trigger present flag 1106 1062 * @ioctl_dma_pool: DMA pool for IOCTL data buffers 1107 1063 * @ioctl_sge: DMA buffer descriptors for IOCTL data 1108 1064 * @ioctl_chain_sge: DMA buffer descriptor for IOCTL chain ··· 1304 1250 struct dma_memory_desc ioctl_chain_sge; 1305 1251 struct dma_memory_desc ioctl_resp_sge; 1306 1252 bool ioctl_sges_allocated; 1253 + bool reply_trigger_present; 1254 + bool event_trigger_present; 1255 + bool scsisense_trigger_present; 1256 + struct diag_buffer_desc diag_buffers[MPI3MR_MAX_NUM_HDB]; 1257 + struct mpi3_driver_page2 *driver_pg2; 1258 + spinlock_t trigger_lock; 1307 1259 }; 1308 1260 1309 1261 /** ··· 1466 1406 struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz); 1467 1407 int mpi3mr_cfg_get_driver_pg1(struct mpi3mr_ioc *mrioc, 1468 1408 struct mpi3_driver_page1 *driver_pg1, u16 pg_sz); 1409 + int mpi3mr_cfg_get_driver_pg2(struct mpi3mr_ioc *mrioc, 1410 + struct mpi3_driver_page2 *driver_pg2, u16 pg_sz, u8 page_type); 1469 1411 1470 1412 u8 mpi3mr_is_expander_device(u16 device_info); 1471 1413 int mpi3mr_expander_add(struct mpi3mr_ioc *mrioc, u16 handle); ··· 1501 1439 int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc); 1502 1440 void mpi3mr_expander_node_remove(struct mpi3mr_ioc *mrioc, 1503 1441 struct mpi3mr_sas_node *sas_expander); 1442 + void mpi3mr_alloc_diag_bufs(struct mpi3mr_ioc *mrioc); 1443 + int mpi3mr_post_diag_bufs(struct mpi3mr_ioc *mrioc); 1444 + int mpi3mr_issue_diag_buf_release(struct mpi3mr_ioc *mrioc, 1445 + struct diag_buffer_desc *diag_buffer); 1446 + void mpi3mr_release_diag_bufs(struct mpi3mr_ioc *mrioc, u8 skip_rel_action); 1447 + void mpi3mr_set_trigger_data_in_hdb(struct diag_buffer_desc *hdb, 1448 + u8 type, union mpi3mr_trigger_data *trigger_data, bool force); 1449 + int mpi3mr_refresh_trigger(struct mpi3mr_ioc *mrioc, u8 page_type); 1450 + struct diag_buffer_desc *mpi3mr_diag_buffer_for_type(struct mpi3mr_ioc *mrioc, 1451 + u8 buf_type); 1452 + int mpi3mr_issue_diag_buf_post(struct mpi3mr_ioc *mrioc, 1453 + struct diag_buffer_desc *diag_buffer); 1504 1454 #endif /*MPI3MR_H_INCLUDED*/
+480
drivers/scsi/mpi3mr/mpi3mr_app.c
··· 12 12 #include <uapi/scsi/scsi_bsg_mpi3mr.h> 13 13 14 14 /** 15 + * mpi3mr_alloc_trace_buffer: Allocate trace buffer 16 + * @mrioc: Adapter instance reference 17 + * @trace_size: Trace buffer size 18 + * 19 + * Allocate trace buffer 20 + * Return: 0 on success, non-zero on failure. 21 + */ 22 + static int mpi3mr_alloc_trace_buffer(struct mpi3mr_ioc *mrioc, u32 trace_size) 23 + { 24 + struct diag_buffer_desc *diag_buffer = &mrioc->diag_buffers[0]; 25 + 26 + diag_buffer->addr = dma_alloc_coherent(&mrioc->pdev->dev, 27 + trace_size, &diag_buffer->dma_addr, GFP_KERNEL); 28 + if (diag_buffer->addr) { 29 + dprint_init(mrioc, "trace diag buffer is allocated successfully\n"); 30 + return 0; 31 + } 32 + return -1; 33 + } 34 + 35 + /** 36 + * mpi3mr_alloc_diag_bufs - Allocate memory for diag buffers 37 + * @mrioc: Adapter instance reference 38 + * 39 + * This functions checks whether the driver defined buffer sizes 40 + * are greater than IOCFacts provided controller local buffer 41 + * sizes and if the driver defined sizes are more then the 42 + * driver allocates the specific buffer by reading driver page1 43 + * 44 + * Return: Nothing. 45 + */ 46 + void mpi3mr_alloc_diag_bufs(struct mpi3mr_ioc *mrioc) 47 + { 48 + struct diag_buffer_desc *diag_buffer; 49 + struct mpi3_driver_page1 driver_pg1; 50 + u32 trace_dec_size, trace_min_size, fw_dec_size, fw_min_size, 51 + trace_size, fw_size; 52 + u16 pg_sz = sizeof(driver_pg1); 53 + int retval = 0; 54 + bool retry = false; 55 + 56 + if (mrioc->diag_buffers[0].addr || mrioc->diag_buffers[1].addr) 57 + return; 58 + 59 + retval = mpi3mr_cfg_get_driver_pg1(mrioc, &driver_pg1, pg_sz); 60 + if (retval) { 61 + ioc_warn(mrioc, 62 + "%s: driver page 1 read failed, allocating trace\n" 63 + "and firmware diag buffers of default size\n", __func__); 64 + trace_size = fw_size = MPI3MR_DEFAULT_HDB_MAX_SZ; 65 + trace_dec_size = fw_dec_size = MPI3MR_DEFAULT_HDB_DEC_SZ; 66 + trace_min_size = fw_min_size = MPI3MR_DEFAULT_HDB_MIN_SZ; 67 + 68 + } else { 69 + trace_size = driver_pg1.host_diag_trace_max_size * 1024; 70 + trace_dec_size = driver_pg1.host_diag_trace_decrement_size 71 + * 1024; 72 + trace_min_size = driver_pg1.host_diag_trace_min_size * 1024; 73 + fw_size = driver_pg1.host_diag_fw_max_size * 1024; 74 + fw_dec_size = driver_pg1.host_diag_fw_decrement_size * 1024; 75 + fw_min_size = driver_pg1.host_diag_fw_min_size * 1024; 76 + dprint_init(mrioc, 77 + "%s:trace diag buffer sizes read from driver\n" 78 + "page1: maximum size = %dKB, decrement size = %dKB\n" 79 + ", minimum size = %dKB\n", __func__, driver_pg1.host_diag_trace_max_size, 80 + driver_pg1.host_diag_trace_decrement_size, 81 + driver_pg1.host_diag_trace_min_size); 82 + dprint_init(mrioc, 83 + "%s:firmware diag buffer sizes read from driver\n" 84 + "page1: maximum size = %dKB, decrement size = %dKB\n" 85 + ", minimum size = %dKB\n", __func__, driver_pg1.host_diag_fw_max_size, 86 + driver_pg1.host_diag_fw_decrement_size, 87 + driver_pg1.host_diag_fw_min_size); 88 + if ((trace_size == 0) && (fw_size == 0)) 89 + return; 90 + } 91 + 92 + 93 + retry_trace: 94 + diag_buffer = &mrioc->diag_buffers[0]; 95 + diag_buffer->type = MPI3_DIAG_BUFFER_TYPE_TRACE; 96 + diag_buffer->status = MPI3MR_HDB_BUFSTATUS_NOT_ALLOCATED; 97 + if ((mrioc->facts.diag_trace_sz < trace_size) && (trace_size >= 98 + trace_min_size)) { 99 + if (!retry) 100 + dprint_init(mrioc, 101 + "trying to allocate trace diag buffer of size = %dKB\n", 102 + trace_size / 1024); 103 + if (mpi3mr_alloc_trace_buffer(mrioc, trace_size)) { 104 + retry = true; 105 + trace_size -= trace_dec_size; 106 + dprint_init(mrioc, "trace diag buffer allocation failed\n" 107 + "retrying smaller size %dKB\n", trace_size / 1024); 108 + goto retry_trace; 109 + } else 110 + diag_buffer->size = trace_size; 111 + } 112 + 113 + retry = false; 114 + retry_fw: 115 + 116 + diag_buffer = &mrioc->diag_buffers[1]; 117 + 118 + diag_buffer->type = MPI3_DIAG_BUFFER_TYPE_FW; 119 + diag_buffer->status = MPI3MR_HDB_BUFSTATUS_NOT_ALLOCATED; 120 + if ((mrioc->facts.diag_fw_sz < fw_size) && (fw_size >= fw_min_size)) { 121 + diag_buffer->addr = dma_alloc_coherent(&mrioc->pdev->dev, 122 + fw_size, &diag_buffer->dma_addr, GFP_KERNEL); 123 + if (!retry) 124 + dprint_init(mrioc, 125 + "%s:trying to allocate firmware diag buffer of size = %dKB\n", 126 + __func__, fw_size / 1024); 127 + if (diag_buffer->addr) { 128 + dprint_init(mrioc, "%s:firmware diag buffer allocated successfully\n", 129 + __func__); 130 + diag_buffer->size = fw_size; 131 + } else { 132 + retry = true; 133 + fw_size -= fw_dec_size; 134 + dprint_init(mrioc, "%s:trace diag buffer allocation failed,\n" 135 + "retrying smaller size %dKB\n", 136 + __func__, fw_size / 1024); 137 + goto retry_fw; 138 + } 139 + } 140 + } 141 + 142 + /** 143 + * mpi3mr_issue_diag_buf_post - Send diag buffer post req 144 + * @mrioc: Adapter instance reference 145 + * @diag_buffer: Diagnostic buffer descriptor 146 + * 147 + * Issue diagnostic buffer post MPI request through admin queue 148 + * and wait for the completion of it or time out. 149 + * 150 + * Return: 0 on success, non-zero on failures. 151 + */ 152 + int mpi3mr_issue_diag_buf_post(struct mpi3mr_ioc *mrioc, 153 + struct diag_buffer_desc *diag_buffer) 154 + { 155 + struct mpi3_diag_buffer_post_request diag_buf_post_req; 156 + u8 prev_status; 157 + int retval = 0; 158 + 159 + memset(&diag_buf_post_req, 0, sizeof(diag_buf_post_req)); 160 + mutex_lock(&mrioc->init_cmds.mutex); 161 + if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 162 + dprint_bsg_err(mrioc, "%s: command is in use\n", __func__); 163 + mutex_unlock(&mrioc->init_cmds.mutex); 164 + return -1; 165 + } 166 + mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 167 + mrioc->init_cmds.is_waiting = 1; 168 + mrioc->init_cmds.callback = NULL; 169 + diag_buf_post_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 170 + diag_buf_post_req.function = MPI3_FUNCTION_DIAG_BUFFER_POST; 171 + diag_buf_post_req.type = diag_buffer->type; 172 + diag_buf_post_req.address = le64_to_cpu(diag_buffer->dma_addr); 173 + diag_buf_post_req.length = le32_to_cpu(diag_buffer->size); 174 + 175 + dprint_bsg_info(mrioc, "%s: posting diag buffer type %d\n", __func__, 176 + diag_buffer->type); 177 + prev_status = diag_buffer->status; 178 + diag_buffer->status = MPI3MR_HDB_BUFSTATUS_POSTED_UNPAUSED; 179 + init_completion(&mrioc->init_cmds.done); 180 + retval = mpi3mr_admin_request_post(mrioc, &diag_buf_post_req, 181 + sizeof(diag_buf_post_req), 1); 182 + if (retval) { 183 + dprint_bsg_err(mrioc, "%s: admin request post failed\n", 184 + __func__); 185 + goto out_unlock; 186 + } 187 + wait_for_completion_timeout(&mrioc->init_cmds.done, 188 + (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 189 + if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 190 + mrioc->init_cmds.is_waiting = 0; 191 + dprint_bsg_err(mrioc, "%s: command timedout\n", __func__); 192 + mpi3mr_check_rh_fault_ioc(mrioc, 193 + MPI3MR_RESET_FROM_DIAG_BUFFER_POST_TIMEOUT); 194 + retval = -1; 195 + goto out_unlock; 196 + } 197 + if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 198 + != MPI3_IOCSTATUS_SUCCESS) { 199 + dprint_bsg_err(mrioc, 200 + "%s: command failed, buffer_type (%d) ioc_status(0x%04x) log_info(0x%08x)\n", 201 + __func__, diag_buffer->type, 202 + (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 203 + mrioc->init_cmds.ioc_loginfo); 204 + retval = -1; 205 + goto out_unlock; 206 + } 207 + dprint_bsg_info(mrioc, "%s: diag buffer type %d posted successfully\n", 208 + __func__, diag_buffer->type); 209 + 210 + out_unlock: 211 + if (retval) 212 + diag_buffer->status = prev_status; 213 + mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 214 + mutex_unlock(&mrioc->init_cmds.mutex); 215 + return retval; 216 + } 217 + 218 + /** 219 + * mpi3mr_post_diag_bufs - Post diag buffers to the controller 220 + * @mrioc: Adapter instance reference 221 + * 222 + * This function calls helper function to post both trace and 223 + * firmware buffers to the controller. 224 + * 225 + * Return: None 226 + */ 227 + int mpi3mr_post_diag_bufs(struct mpi3mr_ioc *mrioc) 228 + { 229 + u8 i; 230 + struct diag_buffer_desc *diag_buffer; 231 + 232 + for (i = 0; i < MPI3MR_MAX_NUM_HDB; i++) { 233 + diag_buffer = &mrioc->diag_buffers[i]; 234 + if (!(diag_buffer->addr)) 235 + continue; 236 + if (mpi3mr_issue_diag_buf_post(mrioc, diag_buffer)) 237 + return -1; 238 + } 239 + return 0; 240 + } 241 + 242 + /** 243 + * mpi3mr_issue_diag_buf_release - Send diag buffer release req 244 + * @mrioc: Adapter instance reference 245 + * @diag_buffer: Diagnostic buffer descriptor 246 + * 247 + * Issue diagnostic buffer manage MPI request with release 248 + * action request through admin queue and wait for the 249 + * completion of it or time out. 250 + * 251 + * Return: 0 on success, non-zero on failures. 252 + */ 253 + int mpi3mr_issue_diag_buf_release(struct mpi3mr_ioc *mrioc, 254 + struct diag_buffer_desc *diag_buffer) 255 + { 256 + struct mpi3_diag_buffer_manage_request diag_buf_manage_req; 257 + int retval = 0; 258 + 259 + if ((diag_buffer->status != MPI3MR_HDB_BUFSTATUS_POSTED_UNPAUSED) && 260 + (diag_buffer->status != MPI3MR_HDB_BUFSTATUS_POSTED_PAUSED)) 261 + return retval; 262 + 263 + memset(&diag_buf_manage_req, 0, sizeof(diag_buf_manage_req)); 264 + mutex_lock(&mrioc->init_cmds.mutex); 265 + if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { 266 + dprint_reset(mrioc, "%s: command is in use\n", __func__); 267 + mutex_unlock(&mrioc->init_cmds.mutex); 268 + return -1; 269 + } 270 + mrioc->init_cmds.state = MPI3MR_CMD_PENDING; 271 + mrioc->init_cmds.is_waiting = 1; 272 + mrioc->init_cmds.callback = NULL; 273 + diag_buf_manage_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); 274 + diag_buf_manage_req.function = MPI3_FUNCTION_DIAG_BUFFER_MANAGE; 275 + diag_buf_manage_req.type = diag_buffer->type; 276 + diag_buf_manage_req.action = MPI3_DIAG_BUFFER_ACTION_RELEASE; 277 + 278 + 279 + dprint_reset(mrioc, "%s: releasing diag buffer type %d\n", __func__, 280 + diag_buffer->type); 281 + init_completion(&mrioc->init_cmds.done); 282 + retval = mpi3mr_admin_request_post(mrioc, &diag_buf_manage_req, 283 + sizeof(diag_buf_manage_req), 1); 284 + if (retval) { 285 + dprint_reset(mrioc, "%s: admin request post failed\n", __func__); 286 + mpi3mr_set_trigger_data_in_hdb(diag_buffer, 287 + MPI3MR_HDB_TRIGGER_TYPE_UNKNOWN, NULL, 1); 288 + goto out_unlock; 289 + } 290 + wait_for_completion_timeout(&mrioc->init_cmds.done, 291 + (MPI3MR_INTADMCMD_TIMEOUT * HZ)); 292 + if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { 293 + mrioc->init_cmds.is_waiting = 0; 294 + dprint_reset(mrioc, "%s: command timedout\n", __func__); 295 + mpi3mr_check_rh_fault_ioc(mrioc, 296 + MPI3MR_RESET_FROM_DIAG_BUFFER_RELEASE_TIMEOUT); 297 + retval = -1; 298 + goto out_unlock; 299 + } 300 + if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 301 + != MPI3_IOCSTATUS_SUCCESS) { 302 + dprint_reset(mrioc, 303 + "%s: command failed, buffer_type (%d) ioc_status(0x%04x) log_info(0x%08x)\n", 304 + __func__, diag_buffer->type, 305 + (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 306 + mrioc->init_cmds.ioc_loginfo); 307 + retval = -1; 308 + goto out_unlock; 309 + } 310 + dprint_reset(mrioc, "%s: diag buffer type %d released successfully\n", 311 + __func__, diag_buffer->type); 312 + 313 + out_unlock: 314 + mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 315 + mutex_unlock(&mrioc->init_cmds.mutex); 316 + return retval; 317 + } 318 + 319 + /** 320 + * mpi3mr_get_num_trigger - Gets number of HDB triggers 321 + * @mrioc: Adapter instance reference 322 + * @num_triggers: Number of triggers 323 + * @page_action: Page action 324 + * 325 + * This function reads number of triggers by reading driver page 326 + * 2 327 + * 328 + * Return: 0 on success and proper error codes on failure 329 + */ 330 + static int mpi3mr_get_num_trigger(struct mpi3mr_ioc *mrioc, u8 *num_triggers, 331 + u8 page_action) 332 + { 333 + struct mpi3_driver_page2 drvr_page2; 334 + int retval = 0; 335 + 336 + *num_triggers = 0; 337 + 338 + retval = mpi3mr_cfg_get_driver_pg2(mrioc, &drvr_page2, 339 + sizeof(struct mpi3_driver_page2), page_action); 340 + 341 + if (retval) { 342 + dprint_init(mrioc, "%s: driver page 2 read failed\n", __func__); 343 + return retval; 344 + } 345 + *num_triggers = drvr_page2.num_triggers; 346 + return retval; 347 + } 348 + 349 + /** 350 + * mpi3mr_refresh_trigger - Handler for Refresh trigger BSG 351 + * @mrioc: Adapter instance reference 352 + * @page_action: Page action 353 + * 354 + * This function caches the driver page 2 in the driver's memory 355 + * by reading driver page 2 from the controller for a given page 356 + * type and updates the HDB trigger values 357 + * 358 + * Return: 0 on success and proper error codes on failure 359 + */ 360 + int mpi3mr_refresh_trigger(struct mpi3mr_ioc *mrioc, u8 page_action) 361 + { 362 + u16 pg_sz = sizeof(struct mpi3_driver_page2); 363 + struct mpi3_driver_page2 *drvr_page2 = NULL; 364 + u8 trigger_type, num_triggers; 365 + int retval; 366 + int i = 0; 367 + unsigned long flags; 368 + 369 + retval = mpi3mr_get_num_trigger(mrioc, &num_triggers, page_action); 370 + 371 + if (retval) 372 + goto out; 373 + 374 + pg_sz = offsetof(struct mpi3_driver_page2, trigger) + 375 + (num_triggers * sizeof(union mpi3_driver2_trigger_element)); 376 + drvr_page2 = kzalloc(pg_sz, GFP_KERNEL); 377 + if (!drvr_page2) { 378 + retval = -ENOMEM; 379 + goto out; 380 + } 381 + 382 + retval = mpi3mr_cfg_get_driver_pg2(mrioc, drvr_page2, pg_sz, page_action); 383 + if (retval) { 384 + dprint_init(mrioc, "%s: driver page 2 read failed\n", __func__); 385 + kfree(drvr_page2); 386 + goto out; 387 + } 388 + spin_lock_irqsave(&mrioc->trigger_lock, flags); 389 + kfree(mrioc->driver_pg2); 390 + mrioc->driver_pg2 = drvr_page2; 391 + mrioc->reply_trigger_present = false; 392 + mrioc->event_trigger_present = false; 393 + mrioc->scsisense_trigger_present = false; 394 + 395 + for (i = 0; (i < mrioc->driver_pg2->num_triggers); i++) { 396 + trigger_type = mrioc->driver_pg2->trigger[i].event.type; 397 + switch (trigger_type) { 398 + case MPI3_DRIVER2_TRIGGER_TYPE_REPLY: 399 + mrioc->reply_trigger_present = true; 400 + break; 401 + case MPI3_DRIVER2_TRIGGER_TYPE_EVENT: 402 + mrioc->event_trigger_present = true; 403 + break; 404 + case MPI3_DRIVER2_TRIGGER_TYPE_SCSI_SENSE: 405 + mrioc->scsisense_trigger_present = true; 406 + break; 407 + default: 408 + break; 409 + } 410 + } 411 + spin_unlock_irqrestore(&mrioc->trigger_lock, flags); 412 + out: 413 + return retval; 414 + } 415 + 416 + /** 417 + * mpi3mr_release_diag_bufs - Release diag buffers 418 + * @mrioc: Adapter instance reference 419 + * @skip_rel_action: Skip release action and set buffer state 420 + * 421 + * This function calls helper function to release both trace and 422 + * firmware buffers from the controller. 423 + * 424 + * Return: None 425 + */ 426 + void mpi3mr_release_diag_bufs(struct mpi3mr_ioc *mrioc, u8 skip_rel_action) 427 + { 428 + u8 i; 429 + struct diag_buffer_desc *diag_buffer; 430 + 431 + for (i = 0; i < MPI3MR_MAX_NUM_HDB; i++) { 432 + diag_buffer = &mrioc->diag_buffers[i]; 433 + if (!(diag_buffer->addr)) 434 + continue; 435 + if (diag_buffer->status == MPI3MR_HDB_BUFSTATUS_RELEASED) 436 + continue; 437 + if (!skip_rel_action) 438 + mpi3mr_issue_diag_buf_release(mrioc, diag_buffer); 439 + diag_buffer->status = MPI3MR_HDB_BUFSTATUS_RELEASED; 440 + atomic64_inc(&event_counter); 441 + } 442 + } 443 + 444 + /** 445 + * mpi3mr_set_trigger_data_in_hdb - Updates HDB trigger type and 446 + * trigger data 447 + * 448 + * @hdb: HDB pointer 449 + * @type: Trigger type 450 + * @data: Trigger data 451 + * @force: Trigger overwrite flag 452 + * @trigger_data: pointer to trigger data information 453 + * 454 + * Updates trigger type and trigger data based on parameter 455 + * passed to this function 456 + * 457 + * Return: Nothing 458 + */ 459 + void mpi3mr_set_trigger_data_in_hdb(struct diag_buffer_desc *hdb, 460 + u8 type, union mpi3mr_trigger_data *trigger_data, bool force) 461 + { 462 + if ((!force) && (hdb->trigger_type != MPI3MR_HDB_TRIGGER_TYPE_UNKNOWN)) 463 + return; 464 + hdb->trigger_type = type; 465 + if (!trigger_data) 466 + memset(&hdb->trigger_data, 0, sizeof(*trigger_data)); 467 + else 468 + memcpy(&hdb->trigger_data, trigger_data, sizeof(*trigger_data)); 469 + } 470 + 471 + /** 472 + * mpi3mr_diag_buffer_for_type - returns buffer desc for type 473 + * @mrioc: Adapter instance reference 474 + * @buf_type: Diagnostic buffer type 475 + * 476 + * Identifies matching diag descriptor from mrioc for given diag 477 + * buffer type. 478 + * 479 + * Return: diag buffer descriptor on success, NULL on failures. 480 + */ 481 + 482 + struct diag_buffer_desc * 483 + mpi3mr_diag_buffer_for_type(struct mpi3mr_ioc *mrioc, u8 buf_type) 484 + { 485 + u8 i; 486 + 487 + for (i = 0; i < MPI3MR_MAX_NUM_HDB; i++) { 488 + if (mrioc->diag_buffers[i].type == buf_type) 489 + return &mrioc->diag_buffers[i]; 490 + } 491 + return NULL; 492 + } 493 + 494 + /** 15 495 * mpi3mr_bsg_pel_abort - sends PEL abort request 16 496 * @mrioc: Adapter instance reference 17 497 *
+192 -1
drivers/scsi/mpi3mr/mpi3mr_fw.c
··· 3003 3003 mrioc->facts.sge_mod_shift = facts_data->sge_modifier_shift; 3004 3004 mrioc->facts.shutdown_timeout = 3005 3005 le16_to_cpu(facts_data->shutdown_timeout); 3006 - 3006 + mrioc->facts.diag_trace_sz = 3007 + le32_to_cpu(facts_data->diag_trace_size); 3008 + mrioc->facts.diag_fw_sz = 3009 + le32_to_cpu(facts_data->diag_fw_size); 3010 + mrioc->facts.diag_drvr_sz = le32_to_cpu(facts_data->diag_driver_size); 3007 3011 mrioc->facts.max_dev_per_tg = 3008 3012 facts_data->max_devices_per_throttle_group; 3009 3013 mrioc->facts.io_throttle_data_length = ··· 3686 3682 }; 3687 3683 3688 3684 /** 3685 + * mpi3mr_repost_diag_bufs - repost host diag buffers 3686 + * @mrioc: Adapter instance reference 3687 + * 3688 + * repost firmware and trace diag buffers based on global 3689 + * trigger flag from driver page 2 3690 + * 3691 + * Return: 0 on success, non-zero on failures. 3692 + */ 3693 + static int mpi3mr_repost_diag_bufs(struct mpi3mr_ioc *mrioc) 3694 + { 3695 + u64 global_trigger; 3696 + union mpi3mr_trigger_data prev_trigger_data; 3697 + struct diag_buffer_desc *trace_hdb = NULL; 3698 + struct diag_buffer_desc *fw_hdb = NULL; 3699 + int retval = 0; 3700 + bool trace_repost_needed = false; 3701 + bool fw_repost_needed = false; 3702 + u8 prev_trigger_type; 3703 + 3704 + retval = mpi3mr_refresh_trigger(mrioc, MPI3_CONFIG_ACTION_READ_CURRENT); 3705 + if (retval) 3706 + return -1; 3707 + 3708 + trace_hdb = mpi3mr_diag_buffer_for_type(mrioc, 3709 + MPI3_DIAG_BUFFER_TYPE_TRACE); 3710 + 3711 + if (trace_hdb && 3712 + trace_hdb->status != MPI3MR_HDB_BUFSTATUS_NOT_ALLOCATED && 3713 + trace_hdb->trigger_type != MPI3MR_HDB_TRIGGER_TYPE_GLOBAL && 3714 + trace_hdb->trigger_type != MPI3MR_HDB_TRIGGER_TYPE_ELEMENT) 3715 + trace_repost_needed = true; 3716 + 3717 + fw_hdb = mpi3mr_diag_buffer_for_type(mrioc, MPI3_DIAG_BUFFER_TYPE_FW); 3718 + 3719 + if (fw_hdb && fw_hdb->status != MPI3MR_HDB_BUFSTATUS_NOT_ALLOCATED && 3720 + fw_hdb->trigger_type != MPI3MR_HDB_TRIGGER_TYPE_GLOBAL && 3721 + fw_hdb->trigger_type != MPI3MR_HDB_TRIGGER_TYPE_ELEMENT) 3722 + fw_repost_needed = true; 3723 + 3724 + if (trace_repost_needed || fw_repost_needed) { 3725 + global_trigger = le64_to_cpu(mrioc->driver_pg2->global_trigger); 3726 + if (global_trigger & 3727 + MPI3_DRIVER2_GLOBALTRIGGER_POST_DIAG_TRACE_DISABLED) 3728 + trace_repost_needed = false; 3729 + if (global_trigger & 3730 + MPI3_DRIVER2_GLOBALTRIGGER_POST_DIAG_FW_DISABLED) 3731 + fw_repost_needed = false; 3732 + } 3733 + 3734 + if (trace_repost_needed) { 3735 + prev_trigger_type = trace_hdb->trigger_type; 3736 + memcpy(&prev_trigger_data, &trace_hdb->trigger_data, 3737 + sizeof(trace_hdb->trigger_data)); 3738 + retval = mpi3mr_issue_diag_buf_post(mrioc, trace_hdb); 3739 + if (!retval) { 3740 + dprint_init(mrioc, "trace diag buffer reposted"); 3741 + mpi3mr_set_trigger_data_in_hdb(trace_hdb, 3742 + MPI3MR_HDB_TRIGGER_TYPE_UNKNOWN, NULL, 1); 3743 + } else { 3744 + trace_hdb->trigger_type = prev_trigger_type; 3745 + memcpy(&trace_hdb->trigger_data, &prev_trigger_data, 3746 + sizeof(prev_trigger_data)); 3747 + ioc_err(mrioc, "trace diag buffer repost failed"); 3748 + return -1; 3749 + } 3750 + } 3751 + 3752 + if (fw_repost_needed) { 3753 + prev_trigger_type = fw_hdb->trigger_type; 3754 + memcpy(&prev_trigger_data, &fw_hdb->trigger_data, 3755 + sizeof(fw_hdb->trigger_data)); 3756 + retval = mpi3mr_issue_diag_buf_post(mrioc, fw_hdb); 3757 + if (!retval) { 3758 + dprint_init(mrioc, "firmware diag buffer reposted"); 3759 + mpi3mr_set_trigger_data_in_hdb(fw_hdb, 3760 + MPI3MR_HDB_TRIGGER_TYPE_UNKNOWN, NULL, 1); 3761 + } else { 3762 + fw_hdb->trigger_type = prev_trigger_type; 3763 + memcpy(&fw_hdb->trigger_data, &prev_trigger_data, 3764 + sizeof(prev_trigger_data)); 3765 + ioc_err(mrioc, "firmware diag buffer repost failed"); 3766 + return -1; 3767 + } 3768 + } 3769 + return retval; 3770 + } 3771 + 3772 + /** 3689 3773 * mpi3mr_print_ioc_info - Display controller information 3690 3774 * @mrioc: Adapter instance reference 3691 3775 * ··· 4081 3989 } 4082 3990 } 4083 3991 3992 + dprint_init(mrioc, "allocating host diag buffers\n"); 3993 + mpi3mr_alloc_diag_bufs(mrioc); 3994 + 4084 3995 dprint_init(mrioc, "allocating ioctl dma buffers\n"); 4085 3996 mpi3mr_alloc_ioctl_dma_memory(mrioc); 3997 + 3998 + dprint_init(mrioc, "posting host diag buffers\n"); 3999 + retval = mpi3mr_post_diag_bufs(mrioc); 4000 + 4001 + if (retval) 4002 + ioc_warn(mrioc, "failed to post host diag buffers\n"); 4086 4003 4087 4004 if (!mrioc->init_cmds.reply) { 4088 4005 retval = mpi3mr_alloc_reply_sense_bufs(mrioc); ··· 4244 4143 } 4245 4144 4246 4145 mpi3mr_print_ioc_info(mrioc); 4146 + 4147 + if (is_resume) { 4148 + dprint_reset(mrioc, "posting host diag buffers\n"); 4149 + retval = mpi3mr_post_diag_bufs(mrioc); 4150 + if (retval) 4151 + ioc_warn(mrioc, "failed to post host diag buffers\n"); 4152 + } else { 4153 + retval = mpi3mr_repost_diag_bufs(mrioc); 4154 + if (retval) 4155 + ioc_warn(mrioc, "failed to re post host diag buffers\n"); 4156 + } 4247 4157 4248 4158 dprint_reset(mrioc, "sending ioc_init\n"); 4249 4159 retval = mpi3mr_issue_iocinit(mrioc); ··· 4521 4409 { 4522 4410 u16 i; 4523 4411 struct mpi3mr_intr_info *intr_info; 4412 + struct diag_buffer_desc *diag_buffer; 4524 4413 4525 4414 mpi3mr_free_enclosure_list(mrioc); 4526 4415 mpi3mr_free_ioctl_dma_memory(mrioc); ··· 4654 4541 dma_free_coherent(&mrioc->pdev->dev, mrioc->pel_seqnum_sz, 4655 4542 mrioc->pel_seqnum_virt, mrioc->pel_seqnum_dma); 4656 4543 mrioc->pel_seqnum_virt = NULL; 4544 + } 4545 + 4546 + for (i = 0; i < MPI3MR_MAX_NUM_HDB; i++) { 4547 + diag_buffer = &mrioc->diag_buffers[i]; 4548 + if (diag_buffer->addr) { 4549 + dma_free_coherent(&mrioc->pdev->dev, 4550 + diag_buffer->size, diag_buffer->addr, 4551 + diag_buffer->dma_addr); 4552 + diag_buffer->addr = NULL; 4553 + diag_buffer->size = 0; 4554 + diag_buffer->type = 0; 4555 + diag_buffer->status = 0; 4556 + } 4657 4557 } 4658 4558 4659 4559 kfree(mrioc->throttle_groups); ··· 5142 5016 if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) && 5143 5017 (reset_reason != MPI3MR_RESET_FROM_FIRMWARE) && 5144 5018 (reset_reason != MPI3MR_RESET_FROM_CIACTIV_FAULT)) { 5019 + dprint_reset(mrioc, 5020 + "soft_reset_handler: releasing host diagnostic buffers\n"); 5021 + mpi3mr_release_diag_bufs(mrioc, 0); 5145 5022 for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 5146 5023 mrioc->event_masks[i] = -1; 5147 5024 ··· 5204 5075 mrioc->prepare_for_reset_timeout_counter = 0; 5205 5076 } 5206 5077 mpi3mr_memset_buffers(mrioc); 5078 + mpi3mr_release_diag_bufs(mrioc, 1); 5207 5079 retval = mpi3mr_reinit_ioc(mrioc, 0); 5208 5080 if (retval) { 5209 5081 pr_err(IOCNAME "reinit after soft reset failed: reason %d\n", ··· 6084 5954 out_failed: 6085 5955 return -1; 6086 5956 } 5957 + 5958 + /** 5959 + * mpi3mr_cfg_get_driver_pg2 - Read current driver page2 5960 + * @mrioc: Adapter instance reference 5961 + * @driver_pg2: Pointer to return driver page 2 5962 + * @pg_sz: Size of the memory allocated to the page pointer 5963 + * @page_action: Page action 5964 + * 5965 + * This is handler for config page read for the driver page2. 5966 + * This routine checks ioc_status to decide whether the page 5967 + * read is success or not. 5968 + * 5969 + * Return: 0 on success, non-zero on failure. 5970 + */ 5971 + int mpi3mr_cfg_get_driver_pg2(struct mpi3mr_ioc *mrioc, 5972 + struct mpi3_driver_page2 *driver_pg2, u16 pg_sz, u8 page_action) 5973 + { 5974 + struct mpi3_config_page_header cfg_hdr; 5975 + struct mpi3_config_request cfg_req; 5976 + u16 ioc_status = 0; 5977 + 5978 + memset(driver_pg2, 0, pg_sz); 5979 + memset(&cfg_hdr, 0, sizeof(cfg_hdr)); 5980 + memset(&cfg_req, 0, sizeof(cfg_req)); 5981 + 5982 + cfg_req.function = MPI3_FUNCTION_CONFIG; 5983 + cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER; 5984 + cfg_req.page_type = MPI3_CONFIG_PAGETYPE_DRIVER; 5985 + cfg_req.page_number = 2; 5986 + cfg_req.page_address = 0; 5987 + cfg_req.page_version = MPI3_DRIVER2_PAGEVERSION; 5988 + 5989 + if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL, 5990 + MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) { 5991 + ioc_err(mrioc, "driver page2 header read failed\n"); 5992 + goto out_failed; 5993 + } 5994 + if (ioc_status != MPI3_IOCSTATUS_SUCCESS) { 5995 + ioc_err(mrioc, "driver page2 header read failed with\n" 5996 + "ioc_status(0x%04x)\n", 5997 + ioc_status); 5998 + goto out_failed; 5999 + } 6000 + cfg_req.action = page_action; 6001 + 6002 + if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr, 6003 + MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, driver_pg2, pg_sz)) { 6004 + ioc_err(mrioc, "driver page2 read failed\n"); 6005 + goto out_failed; 6006 + } 6007 + if (ioc_status != MPI3_IOCSTATUS_SUCCESS) { 6008 + ioc_err(mrioc, "driver page2 read failed with\n" 6009 + "ioc_status(0x%04x)\n", 6010 + ioc_status); 6011 + goto out_failed; 6012 + } 6013 + return 0; 6014 + out_failed: 6015 + return -1; 6016 + } 6017 +