diff options
-rw-r--r-- | drivers/net/qlge/qlge.h | 6 | ||||
-rw-r--r-- | drivers/net/qlge/qlge_dbg.c | 523 | ||||
-rw-r--r-- | drivers/net/qlge/qlge_main.c | 20 | ||||
-rw-r--r-- | drivers/net/qlge/qlge_mpi.c | 73 |
4 files changed, 622 insertions, 0 deletions
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index a265325abb15..bbdd388aa9b7 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h | |||
@@ -2211,6 +2211,7 @@ extern int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit, | |||
2211 | void ql_queue_fw_error(struct ql_adapter *qdev); | 2211 | void ql_queue_fw_error(struct ql_adapter *qdev); |
2212 | void ql_mpi_work(struct work_struct *work); | 2212 | void ql_mpi_work(struct work_struct *work); |
2213 | void ql_mpi_reset_work(struct work_struct *work); | 2213 | void ql_mpi_reset_work(struct work_struct *work); |
2214 | void ql_mpi_core_to_log(struct work_struct *work); | ||
2214 | int ql_wait_reg_rdy(struct ql_adapter *qdev, u32 reg, u32 bit, u32 ebit); | 2215 | int ql_wait_reg_rdy(struct ql_adapter *qdev, u32 reg, u32 bit, u32 ebit); |
2215 | void ql_queue_asic_error(struct ql_adapter *qdev); | 2216 | void ql_queue_asic_error(struct ql_adapter *qdev); |
2216 | u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr); | 2217 | u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr); |
@@ -2221,6 +2222,11 @@ void ql_mpi_port_cfg_work(struct work_struct *work); | |||
2221 | int ql_mb_get_fw_state(struct ql_adapter *qdev); | 2222 | int ql_mb_get_fw_state(struct ql_adapter *qdev); |
2222 | int ql_cam_route_initialize(struct ql_adapter *qdev); | 2223 | int ql_cam_route_initialize(struct ql_adapter *qdev); |
2223 | int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data); | 2224 | int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data); |
2225 | int ql_write_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 data); | ||
2226 | int ql_unpause_mpi_risc(struct ql_adapter *qdev); | ||
2227 | int ql_pause_mpi_risc(struct ql_adapter *qdev); | ||
2228 | int ql_core_dump(struct ql_adapter *qdev, | ||
2229 | struct ql_mpi_coredump *mpi_coredump); | ||
2224 | int ql_mb_about_fw(struct ql_adapter *qdev); | 2230 | int ql_mb_about_fw(struct ql_adapter *qdev); |
2225 | int ql_wol(struct ql_adapter *qdev); | 2231 | int ql_wol(struct ql_adapter *qdev); |
2226 | int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol); | 2232 | int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol); |
diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c index 9f58c4710761..1d026141b78d 100644 --- a/drivers/net/qlge/qlge_dbg.c +++ b/drivers/net/qlge/qlge_dbg.c | |||
@@ -91,6 +91,179 @@ err: | |||
91 | return status; | 91 | return status; |
92 | } | 92 | } |
93 | 93 | ||
94 | /* Read the MPI Processor shadow registers */ | ||
95 | static int ql_get_mpi_shadow_regs(struct ql_adapter *qdev, u32 * buf) | ||
96 | { | ||
97 | u32 i; | ||
98 | int status; | ||
99 | |||
100 | for (i = 0; i < MPI_CORE_SH_REGS_CNT; i++, buf++) { | ||
101 | status = ql_write_mpi_reg(qdev, RISC_124, | ||
102 | (SHADOW_OFFSET | i << SHADOW_REG_SHIFT)); | ||
103 | if (status) | ||
104 | goto end; | ||
105 | status = ql_read_mpi_reg(qdev, RISC_127, buf); | ||
106 | if (status) | ||
107 | goto end; | ||
108 | } | ||
109 | end: | ||
110 | return status; | ||
111 | } | ||
112 | |||
113 | /* Read the MPI Processor core registers */ | ||
114 | static int ql_get_mpi_regs(struct ql_adapter *qdev, u32 * buf, | ||
115 | u32 offset, u32 count) | ||
116 | { | ||
117 | int i, status = 0; | ||
118 | for (i = 0; i < count; i++, buf++) { | ||
119 | status = ql_read_mpi_reg(qdev, offset + i, buf); | ||
120 | if (status) | ||
121 | return status; | ||
122 | } | ||
123 | return status; | ||
124 | } | ||
125 | |||
126 | |||
127 | /* Read out the routing index registers */ | ||
128 | static int ql_get_routing_index_registers(struct ql_adapter *qdev, u32 *buf) | ||
129 | { | ||
130 | int status; | ||
131 | u32 type, index, index_max; | ||
132 | u32 result_index; | ||
133 | u32 result_data; | ||
134 | u32 val; | ||
135 | |||
136 | status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK); | ||
137 | if (status) | ||
138 | return status; | ||
139 | |||
140 | for (type = 0; type < 4; type++) { | ||
141 | if (type < 2) | ||
142 | index_max = 8; | ||
143 | else | ||
144 | index_max = 16; | ||
145 | for (index = 0; index < index_max; index++) { | ||
146 | val = RT_IDX_RS | ||
147 | | (type << RT_IDX_TYPE_SHIFT) | ||
148 | | (index << RT_IDX_IDX_SHIFT); | ||
149 | ql_write32(qdev, RT_IDX, val); | ||
150 | result_index = 0; | ||
151 | while ((result_index & RT_IDX_MR) == 0) | ||
152 | result_index = ql_read32(qdev, RT_IDX); | ||
153 | result_data = ql_read32(qdev, RT_DATA); | ||
154 | *buf = type; | ||
155 | buf++; | ||
156 | *buf = index; | ||
157 | buf++; | ||
158 | *buf = result_index; | ||
159 | buf++; | ||
160 | *buf = result_data; | ||
161 | buf++; | ||
162 | } | ||
163 | } | ||
164 | ql_sem_unlock(qdev, SEM_RT_IDX_MASK); | ||
165 | return status; | ||
166 | } | ||
167 | |||
168 | /* Read out the MAC protocol registers */ | ||
169 | static void ql_get_mac_protocol_registers(struct ql_adapter *qdev, u32 *buf) | ||
170 | { | ||
171 | u32 result_index, result_data; | ||
172 | u32 type; | ||
173 | u32 index; | ||
174 | u32 offset; | ||
175 | u32 val; | ||
176 | u32 initial_val = MAC_ADDR_RS; | ||
177 | u32 max_index; | ||
178 | u32 max_offset; | ||
179 | |||
180 | for (type = 0; type < MAC_ADDR_TYPE_COUNT; type++) { | ||
181 | switch (type) { | ||
182 | |||
183 | case 0: /* CAM */ | ||
184 | initial_val |= MAC_ADDR_ADR; | ||
185 | max_index = MAC_ADDR_MAX_CAM_ENTRIES; | ||
186 | max_offset = MAC_ADDR_MAX_CAM_WCOUNT; | ||
187 | break; | ||
188 | case 1: /* Multicast MAC Address */ | ||
189 | max_index = MAC_ADDR_MAX_CAM_WCOUNT; | ||
190 | max_offset = MAC_ADDR_MAX_CAM_WCOUNT; | ||
191 | break; | ||
192 | case 2: /* VLAN filter mask */ | ||
193 | case 3: /* MC filter mask */ | ||
194 | max_index = MAC_ADDR_MAX_CAM_WCOUNT; | ||
195 | max_offset = MAC_ADDR_MAX_CAM_WCOUNT; | ||
196 | break; | ||
197 | case 4: /* FC MAC addresses */ | ||
198 | max_index = MAC_ADDR_MAX_FC_MAC_ENTRIES; | ||
199 | max_offset = MAC_ADDR_MAX_FC_MAC_WCOUNT; | ||
200 | break; | ||
201 | case 5: /* Mgmt MAC addresses */ | ||
202 | max_index = MAC_ADDR_MAX_MGMT_MAC_ENTRIES; | ||
203 | max_offset = MAC_ADDR_MAX_MGMT_MAC_WCOUNT; | ||
204 | break; | ||
205 | case 6: /* Mgmt VLAN addresses */ | ||
206 | max_index = MAC_ADDR_MAX_MGMT_VLAN_ENTRIES; | ||
207 | max_offset = MAC_ADDR_MAX_MGMT_VLAN_WCOUNT; | ||
208 | break; | ||
209 | case 7: /* Mgmt IPv4 address */ | ||
210 | max_index = MAC_ADDR_MAX_MGMT_V4_ENTRIES; | ||
211 | max_offset = MAC_ADDR_MAX_MGMT_V4_WCOUNT; | ||
212 | break; | ||
213 | case 8: /* Mgmt IPv6 address */ | ||
214 | max_index = MAC_ADDR_MAX_MGMT_V6_ENTRIES; | ||
215 | max_offset = MAC_ADDR_MAX_MGMT_V6_WCOUNT; | ||
216 | break; | ||
217 | case 9: /* Mgmt TCP/UDP Dest port */ | ||
218 | max_index = MAC_ADDR_MAX_MGMT_TU_DP_ENTRIES; | ||
219 | max_offset = MAC_ADDR_MAX_MGMT_TU_DP_WCOUNT; | ||
220 | break; | ||
221 | default: | ||
222 | printk(KERN_ERR"Bad type!!! 0x%08x\n", type); | ||
223 | max_index = 0; | ||
224 | max_offset = 0; | ||
225 | break; | ||
226 | } | ||
227 | for (index = 0; index < max_index; index++) { | ||
228 | for (offset = 0; offset < max_offset; offset++) { | ||
229 | val = initial_val | ||
230 | | (type << MAC_ADDR_TYPE_SHIFT) | ||
231 | | (index << MAC_ADDR_IDX_SHIFT) | ||
232 | | (offset); | ||
233 | ql_write32(qdev, MAC_ADDR_IDX, val); | ||
234 | result_index = 0; | ||
235 | while ((result_index & MAC_ADDR_MR) == 0) { | ||
236 | result_index = ql_read32(qdev, | ||
237 | MAC_ADDR_IDX); | ||
238 | } | ||
239 | result_data = ql_read32(qdev, MAC_ADDR_DATA); | ||
240 | *buf = result_index; | ||
241 | buf++; | ||
242 | *buf = result_data; | ||
243 | buf++; | ||
244 | } | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | |||
249 | static void ql_get_sem_registers(struct ql_adapter *qdev, u32 *buf) | ||
250 | { | ||
251 | u32 func_num, reg, reg_val; | ||
252 | int status; | ||
253 | |||
254 | for (func_num = 0; func_num < MAX_SEMAPHORE_FUNCTIONS ; func_num++) { | ||
255 | reg = MPI_NIC_REG_BLOCK | ||
256 | | (func_num << MPI_NIC_FUNCTION_SHIFT) | ||
257 | | (SEM / 4); | ||
258 | status = ql_read_mpi_reg(qdev, reg, ®_val); | ||
259 | *buf = reg_val; | ||
260 | /* if the read failed then dead fill the element. */ | ||
261 | if (!status) | ||
262 | *buf = 0xdeadbeef; | ||
263 | buf++; | ||
264 | } | ||
265 | } | ||
266 | |||
94 | /* Create a coredump segment header */ | 267 | /* Create a coredump segment header */ |
95 | static void ql_build_coredump_seg_header( | 268 | static void ql_build_coredump_seg_header( |
96 | struct mpi_coredump_segment_header *seg_hdr, | 269 | struct mpi_coredump_segment_header *seg_hdr, |
@@ -103,6 +276,329 @@ static void ql_build_coredump_seg_header( | |||
103 | memcpy(seg_hdr->description, desc, (sizeof(seg_hdr->description)) - 1); | 276 | memcpy(seg_hdr->description, desc, (sizeof(seg_hdr->description)) - 1); |
104 | } | 277 | } |
105 | 278 | ||
279 | /* | ||
280 | * This function should be called when a coredump / probedump | ||
281 | * is to be extracted from the HBA. It is assumed there is a | ||
282 | * qdev structure that contains the base address of the register | ||
283 | * space for this function as well as a coredump structure that | ||
284 | * will contain the dump. | ||
285 | */ | ||
286 | int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) | ||
287 | { | ||
288 | int status; | ||
289 | int i; | ||
290 | |||
291 | if (!mpi_coredump) { | ||
292 | QPRINTK(qdev, DRV, ERR, | ||
293 | "No memory available.\n"); | ||
294 | return -ENOMEM; | ||
295 | } | ||
296 | |||
297 | /* Try to get the spinlock, but dont worry if | ||
298 | * it isn't available. If the firmware died it | ||
299 | * might be holding the sem. | ||
300 | */ | ||
301 | ql_sem_spinlock(qdev, SEM_PROC_REG_MASK); | ||
302 | |||
303 | status = ql_pause_mpi_risc(qdev); | ||
304 | if (status) { | ||
305 | QPRINTK(qdev, DRV, ERR, | ||
306 | "Failed RISC pause. Status = 0x%.08x\n", status); | ||
307 | goto err; | ||
308 | } | ||
309 | |||
310 | /* Insert the global header */ | ||
311 | memset(&(mpi_coredump->mpi_global_header), 0, | ||
312 | sizeof(struct mpi_coredump_global_header)); | ||
313 | mpi_coredump->mpi_global_header.cookie = MPI_COREDUMP_COOKIE; | ||
314 | mpi_coredump->mpi_global_header.headerSize = | ||
315 | sizeof(struct mpi_coredump_global_header); | ||
316 | mpi_coredump->mpi_global_header.imageSize = | ||
317 | sizeof(struct ql_mpi_coredump); | ||
318 | memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump", | ||
319 | sizeof(mpi_coredump->mpi_global_header.idString)); | ||
320 | |||
321 | /* Get generic NIC reg dump */ | ||
322 | ql_build_coredump_seg_header(&mpi_coredump->nic_regs_seg_hdr, | ||
323 | NIC1_CONTROL_SEG_NUM, | ||
324 | sizeof(struct mpi_coredump_segment_header) + | ||
325 | sizeof(mpi_coredump->nic_regs), "NIC1 Registers"); | ||
326 | |||
327 | if (qdev->func & 1) { | ||
328 | /* Odd means our function is NIC 2 */ | ||
329 | for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++) | ||
330 | mpi_coredump->nic2_regs[i] = | ||
331 | ql_read32(qdev, i * sizeof(u32)); | ||
332 | } else { | ||
333 | /* Even means our function is NIC 1 */ | ||
334 | for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++) | ||
335 | mpi_coredump->nic_regs[i] = | ||
336 | ql_read32(qdev, i * sizeof(u32)); | ||
337 | } | ||
338 | |||
339 | ql_build_coredump_seg_header(&mpi_coredump->core_regs_seg_hdr, | ||
340 | CORE_SEG_NUM, | ||
341 | sizeof(mpi_coredump->core_regs_seg_hdr) + | ||
342 | sizeof(mpi_coredump->mpi_core_regs) + | ||
343 | sizeof(mpi_coredump->mpi_core_sh_regs), | ||
344 | "Core Registers"); | ||
345 | |||
346 | /* Get the MPI Core Registers */ | ||
347 | status = ql_get_mpi_regs(qdev, &mpi_coredump->mpi_core_regs[0], | ||
348 | MPI_CORE_REGS_ADDR, MPI_CORE_REGS_CNT); | ||
349 | if (status) | ||
350 | goto err; | ||
351 | /* Get the 16 MPI shadow registers */ | ||
352 | status = ql_get_mpi_shadow_regs(qdev, | ||
353 | &mpi_coredump->mpi_core_sh_regs[0]); | ||
354 | if (status) | ||
355 | goto err; | ||
356 | |||
357 | /* Get the Test Logic Registers */ | ||
358 | ql_build_coredump_seg_header(&mpi_coredump->test_logic_regs_seg_hdr, | ||
359 | TEST_LOGIC_SEG_NUM, | ||
360 | sizeof(struct mpi_coredump_segment_header) | ||
361 | + sizeof(mpi_coredump->test_logic_regs), | ||
362 | "Test Logic Regs"); | ||
363 | status = ql_get_mpi_regs(qdev, &mpi_coredump->test_logic_regs[0], | ||
364 | TEST_REGS_ADDR, TEST_REGS_CNT); | ||
365 | if (status) | ||
366 | goto err; | ||
367 | |||
368 | /* Get the RMII Registers */ | ||
369 | ql_build_coredump_seg_header(&mpi_coredump->rmii_regs_seg_hdr, | ||
370 | RMII_SEG_NUM, | ||
371 | sizeof(struct mpi_coredump_segment_header) | ||
372 | + sizeof(mpi_coredump->rmii_regs), | ||
373 | "RMII Registers"); | ||
374 | status = ql_get_mpi_regs(qdev, &mpi_coredump->rmii_regs[0], | ||
375 | RMII_REGS_ADDR, RMII_REGS_CNT); | ||
376 | if (status) | ||
377 | goto err; | ||
378 | |||
379 | /* Get the FCMAC1 Registers */ | ||
380 | ql_build_coredump_seg_header(&mpi_coredump->fcmac1_regs_seg_hdr, | ||
381 | FCMAC1_SEG_NUM, | ||
382 | sizeof(struct mpi_coredump_segment_header) | ||
383 | + sizeof(mpi_coredump->fcmac1_regs), | ||
384 | "FCMAC1 Registers"); | ||
385 | status = ql_get_mpi_regs(qdev, &mpi_coredump->fcmac1_regs[0], | ||
386 | FCMAC1_REGS_ADDR, FCMAC_REGS_CNT); | ||
387 | if (status) | ||
388 | goto err; | ||
389 | |||
390 | /* Get the FCMAC2 Registers */ | ||
391 | |||
392 | ql_build_coredump_seg_header(&mpi_coredump->fcmac2_regs_seg_hdr, | ||
393 | FCMAC2_SEG_NUM, | ||
394 | sizeof(struct mpi_coredump_segment_header) | ||
395 | + sizeof(mpi_coredump->fcmac2_regs), | ||
396 | "FCMAC2 Registers"); | ||
397 | |||
398 | status = ql_get_mpi_regs(qdev, &mpi_coredump->fcmac2_regs[0], | ||
399 | FCMAC2_REGS_ADDR, FCMAC_REGS_CNT); | ||
400 | if (status) | ||
401 | goto err; | ||
402 | |||
403 | /* Get the FC1 MBX Registers */ | ||
404 | ql_build_coredump_seg_header(&mpi_coredump->fc1_mbx_regs_seg_hdr, | ||
405 | FC1_MBOX_SEG_NUM, | ||
406 | sizeof(struct mpi_coredump_segment_header) | ||
407 | + sizeof(mpi_coredump->fc1_mbx_regs), | ||
408 | "FC1 MBox Regs"); | ||
409 | status = ql_get_mpi_regs(qdev, &mpi_coredump->fc1_mbx_regs[0], | ||
410 | FC1_MBX_REGS_ADDR, FC_MBX_REGS_CNT); | ||
411 | if (status) | ||
412 | goto err; | ||
413 | |||
414 | /* Get the IDE Registers */ | ||
415 | ql_build_coredump_seg_header(&mpi_coredump->ide_regs_seg_hdr, | ||
416 | IDE_SEG_NUM, | ||
417 | sizeof(struct mpi_coredump_segment_header) | ||
418 | + sizeof(mpi_coredump->ide_regs), | ||
419 | "IDE Registers"); | ||
420 | status = ql_get_mpi_regs(qdev, &mpi_coredump->ide_regs[0], | ||
421 | IDE_REGS_ADDR, IDE_REGS_CNT); | ||
422 | if (status) | ||
423 | goto err; | ||
424 | |||
425 | /* Get the NIC1 MBX Registers */ | ||
426 | ql_build_coredump_seg_header(&mpi_coredump->nic1_mbx_regs_seg_hdr, | ||
427 | NIC1_MBOX_SEG_NUM, | ||
428 | sizeof(struct mpi_coredump_segment_header) | ||
429 | + sizeof(mpi_coredump->nic1_mbx_regs), | ||
430 | "NIC1 MBox Regs"); | ||
431 | status = ql_get_mpi_regs(qdev, &mpi_coredump->nic1_mbx_regs[0], | ||
432 | NIC1_MBX_REGS_ADDR, NIC_MBX_REGS_CNT); | ||
433 | if (status) | ||
434 | goto err; | ||
435 | |||
436 | /* Get the SMBus Registers */ | ||
437 | ql_build_coredump_seg_header(&mpi_coredump->smbus_regs_seg_hdr, | ||
438 | SMBUS_SEG_NUM, | ||
439 | sizeof(struct mpi_coredump_segment_header) | ||
440 | + sizeof(mpi_coredump->smbus_regs), | ||
441 | "SMBus Registers"); | ||
442 | status = ql_get_mpi_regs(qdev, &mpi_coredump->smbus_regs[0], | ||
443 | SMBUS_REGS_ADDR, SMBUS_REGS_CNT); | ||
444 | if (status) | ||
445 | goto err; | ||
446 | |||
447 | /* Get the FC2 MBX Registers */ | ||
448 | ql_build_coredump_seg_header(&mpi_coredump->fc2_mbx_regs_seg_hdr, | ||
449 | FC2_MBOX_SEG_NUM, | ||
450 | sizeof(struct mpi_coredump_segment_header) | ||
451 | + sizeof(mpi_coredump->fc2_mbx_regs), | ||
452 | "FC2 MBox Regs"); | ||
453 | status = ql_get_mpi_regs(qdev, &mpi_coredump->fc2_mbx_regs[0], | ||
454 | FC2_MBX_REGS_ADDR, FC_MBX_REGS_CNT); | ||
455 | if (status) | ||
456 | goto err; | ||
457 | |||
458 | /* Get the NIC2 MBX Registers */ | ||
459 | ql_build_coredump_seg_header(&mpi_coredump->nic2_mbx_regs_seg_hdr, | ||
460 | NIC2_MBOX_SEG_NUM, | ||
461 | sizeof(struct mpi_coredump_segment_header) | ||
462 | + sizeof(mpi_coredump->nic2_mbx_regs), | ||
463 | "NIC2 MBox Regs"); | ||
464 | status = ql_get_mpi_regs(qdev, &mpi_coredump->nic2_mbx_regs[0], | ||
465 | NIC2_MBX_REGS_ADDR, NIC_MBX_REGS_CNT); | ||
466 | if (status) | ||
467 | goto err; | ||
468 | |||
469 | /* Get the I2C Registers */ | ||
470 | ql_build_coredump_seg_header(&mpi_coredump->i2c_regs_seg_hdr, | ||
471 | I2C_SEG_NUM, | ||
472 | sizeof(struct mpi_coredump_segment_header) | ||
473 | + sizeof(mpi_coredump->i2c_regs), | ||
474 | "I2C Registers"); | ||
475 | status = ql_get_mpi_regs(qdev, &mpi_coredump->i2c_regs[0], | ||
476 | I2C_REGS_ADDR, I2C_REGS_CNT); | ||
477 | if (status) | ||
478 | goto err; | ||
479 | |||
480 | /* Get the MEMC Registers */ | ||
481 | ql_build_coredump_seg_header(&mpi_coredump->memc_regs_seg_hdr, | ||
482 | MEMC_SEG_NUM, | ||
483 | sizeof(struct mpi_coredump_segment_header) | ||
484 | + sizeof(mpi_coredump->memc_regs), | ||
485 | "MEMC Registers"); | ||
486 | status = ql_get_mpi_regs(qdev, &mpi_coredump->memc_regs[0], | ||
487 | MEMC_REGS_ADDR, MEMC_REGS_CNT); | ||
488 | if (status) | ||
489 | goto err; | ||
490 | |||
491 | /* Get the PBus Registers */ | ||
492 | ql_build_coredump_seg_header(&mpi_coredump->pbus_regs_seg_hdr, | ||
493 | PBUS_SEG_NUM, | ||
494 | sizeof(struct mpi_coredump_segment_header) | ||
495 | + sizeof(mpi_coredump->pbus_regs), | ||
496 | "PBUS Registers"); | ||
497 | status = ql_get_mpi_regs(qdev, &mpi_coredump->pbus_regs[0], | ||
498 | PBUS_REGS_ADDR, PBUS_REGS_CNT); | ||
499 | if (status) | ||
500 | goto err; | ||
501 | |||
502 | /* Get the MDE Registers */ | ||
503 | ql_build_coredump_seg_header(&mpi_coredump->mde_regs_seg_hdr, | ||
504 | MDE_SEG_NUM, | ||
505 | sizeof(struct mpi_coredump_segment_header) | ||
506 | + sizeof(mpi_coredump->mde_regs), | ||
507 | "MDE Registers"); | ||
508 | status = ql_get_mpi_regs(qdev, &mpi_coredump->mde_regs[0], | ||
509 | MDE_REGS_ADDR, MDE_REGS_CNT); | ||
510 | if (status) | ||
511 | goto err; | ||
512 | |||
513 | ql_build_coredump_seg_header(&mpi_coredump->misc_nic_seg_hdr, | ||
514 | MISC_NIC_INFO_SEG_NUM, | ||
515 | sizeof(struct mpi_coredump_segment_header) | ||
516 | + sizeof(mpi_coredump->misc_nic_info), | ||
517 | "MISC NIC INFO"); | ||
518 | mpi_coredump->misc_nic_info.rx_ring_count = qdev->rx_ring_count; | ||
519 | mpi_coredump->misc_nic_info.tx_ring_count = qdev->tx_ring_count; | ||
520 | mpi_coredump->misc_nic_info.intr_count = qdev->intr_count; | ||
521 | mpi_coredump->misc_nic_info.function = qdev->func; | ||
522 | |||
523 | /* Segment 31 */ | ||
524 | /* Get indexed register values. */ | ||
525 | ql_build_coredump_seg_header(&mpi_coredump->intr_states_seg_hdr, | ||
526 | INTR_STATES_SEG_NUM, | ||
527 | sizeof(struct mpi_coredump_segment_header) | ||
528 | + sizeof(mpi_coredump->intr_states), | ||
529 | "INTR States"); | ||
530 | ql_get_intr_states(qdev, &mpi_coredump->intr_states[0]); | ||
531 | |||
532 | ql_build_coredump_seg_header(&mpi_coredump->cam_entries_seg_hdr, | ||
533 | CAM_ENTRIES_SEG_NUM, | ||
534 | sizeof(struct mpi_coredump_segment_header) | ||
535 | + sizeof(mpi_coredump->cam_entries), | ||
536 | "CAM Entries"); | ||
537 | status = ql_get_cam_entries(qdev, &mpi_coredump->cam_entries[0]); | ||
538 | if (status) | ||
539 | goto err; | ||
540 | |||
541 | ql_build_coredump_seg_header(&mpi_coredump->nic_routing_words_seg_hdr, | ||
542 | ROUTING_WORDS_SEG_NUM, | ||
543 | sizeof(struct mpi_coredump_segment_header) | ||
544 | + sizeof(mpi_coredump->nic_routing_words), | ||
545 | "Routing Words"); | ||
546 | status = ql_get_routing_entries(qdev, | ||
547 | &mpi_coredump->nic_routing_words[0]); | ||
548 | if (status) | ||
549 | goto err; | ||
550 | |||
551 | /* Segment 34 (Rev C. step 23) */ | ||
552 | ql_build_coredump_seg_header(&mpi_coredump->ets_seg_hdr, | ||
553 | ETS_SEG_NUM, | ||
554 | sizeof(struct mpi_coredump_segment_header) | ||
555 | + sizeof(mpi_coredump->ets), | ||
556 | "ETS Registers"); | ||
557 | status = ql_get_ets_regs(qdev, &mpi_coredump->ets[0]); | ||
558 | if (status) | ||
559 | goto err; | ||
560 | |||
561 | ql_build_coredump_seg_header(&mpi_coredump->routing_reg_seg_hdr, | ||
562 | ROUTING_INDEX_SEG_NUM, | ||
563 | sizeof(struct mpi_coredump_segment_header) | ||
564 | + sizeof(mpi_coredump->routing_regs), | ||
565 | "Routing Regs"); | ||
566 | status = ql_get_routing_index_registers(qdev, | ||
567 | &mpi_coredump->routing_regs[0]); | ||
568 | if (status) | ||
569 | goto err; | ||
570 | |||
571 | ql_build_coredump_seg_header(&mpi_coredump->mac_prot_reg_seg_hdr, | ||
572 | MAC_PROTOCOL_SEG_NUM, | ||
573 | sizeof(struct mpi_coredump_segment_header) | ||
574 | + sizeof(mpi_coredump->mac_prot_regs), | ||
575 | "MAC Prot Regs"); | ||
576 | ql_get_mac_protocol_registers(qdev, &mpi_coredump->mac_prot_regs[0]); | ||
577 | |||
578 | /* Get the semaphore registers for all 5 functions */ | ||
579 | ql_build_coredump_seg_header(&mpi_coredump->sem_regs_seg_hdr, | ||
580 | SEM_REGS_SEG_NUM, | ||
581 | sizeof(struct mpi_coredump_segment_header) + | ||
582 | sizeof(mpi_coredump->sem_regs), "Sem Registers"); | ||
583 | |||
584 | ql_get_sem_registers(qdev, &mpi_coredump->sem_regs[0]); | ||
585 | |||
586 | /* Prevent the mpi restarting while we dump the memory.*/ | ||
587 | ql_write_mpi_reg(qdev, MPI_TEST_FUNC_RST_STS, MPI_TEST_FUNC_RST_FRC); | ||
588 | |||
589 | /* clear the pause */ | ||
590 | status = ql_unpause_mpi_risc(qdev); | ||
591 | if (status) { | ||
592 | QPRINTK(qdev, DRV, ERR, | ||
593 | "Failed RISC unpause. Status = 0x%.08x\n", status); | ||
594 | goto err; | ||
595 | } | ||
596 | err: | ||
597 | ql_sem_unlock(qdev, SEM_PROC_REG_MASK); /* does flush too */ | ||
598 | return status; | ||
599 | |||
600 | } | ||
601 | |||
106 | void ql_gen_reg_dump(struct ql_adapter *qdev, | 602 | void ql_gen_reg_dump(struct ql_adapter *qdev, |
107 | struct ql_reg_dump *mpi_coredump) | 603 | struct ql_reg_dump *mpi_coredump) |
108 | { | 604 | { |
@@ -180,6 +676,33 @@ void ql_gen_reg_dump(struct ql_adapter *qdev, | |||
180 | return; | 676 | return; |
181 | } | 677 | } |
182 | 678 | ||
679 | /* Coredump to messages log file using separate worker thread */ | ||
680 | void ql_mpi_core_to_log(struct work_struct *work) | ||
681 | { | ||
682 | struct ql_adapter *qdev = | ||
683 | container_of(work, struct ql_adapter, mpi_core_to_log.work); | ||
684 | u32 *tmp, count; | ||
685 | int i; | ||
686 | |||
687 | count = sizeof(struct ql_mpi_coredump) / sizeof(u32); | ||
688 | tmp = (u32 *)qdev->mpi_coredump; | ||
689 | QPRINTK(qdev, DRV, DEBUG, "Core is dumping to log file!\n"); | ||
690 | |||
691 | for (i = 0; i < count; i += 8) { | ||
692 | printk(KERN_ERR "%.08x: %.08x %.08x %.08x %.08x %.08x " | ||
693 | "%.08x %.08x %.08x \n", i, | ||
694 | tmp[i + 0], | ||
695 | tmp[i + 1], | ||
696 | tmp[i + 2], | ||
697 | tmp[i + 3], | ||
698 | tmp[i + 4], | ||
699 | tmp[i + 5], | ||
700 | tmp[i + 6], | ||
701 | tmp[i + 7]); | ||
702 | msleep(5); | ||
703 | } | ||
704 | } | ||
705 | |||
183 | #ifdef QL_REG_DUMP | 706 | #ifdef QL_REG_DUMP |
184 | static void ql_dump_intr_states(struct ql_adapter *qdev) | 707 | static void ql_dump_intr_states(struct ql_adapter *qdev) |
185 | { | 708 | { |
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 167a3dab2f18..e58892304e19 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c | |||
@@ -73,6 +73,13 @@ static int qlge_irq_type = MSIX_IRQ; | |||
73 | module_param(qlge_irq_type, int, MSIX_IRQ); | 73 | module_param(qlge_irq_type, int, MSIX_IRQ); |
74 | MODULE_PARM_DESC(qlge_irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy."); | 74 | MODULE_PARM_DESC(qlge_irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy."); |
75 | 75 | ||
76 | static int qlge_mpi_coredump; | ||
77 | module_param(qlge_mpi_coredump, int, 0); | ||
78 | MODULE_PARM_DESC(qlge_mpi_coredump, | ||
79 | "Option to enable MPI firmware dump. " | ||
80 | "Default is OFF - Do Not allocate memory. " | ||
81 | "Do not perform firmware coredump."); | ||
82 | |||
76 | static DEFINE_PCI_DEVICE_TABLE(qlge_pci_tbl) = { | 83 | static DEFINE_PCI_DEVICE_TABLE(qlge_pci_tbl) = { |
77 | {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8012)}, | 84 | {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8012)}, |
78 | {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8000)}, | 85 | {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8000)}, |
@@ -3842,6 +3849,7 @@ static int ql_adapter_down(struct ql_adapter *qdev) | |||
3842 | cancel_delayed_work_sync(&qdev->mpi_reset_work); | 3849 | cancel_delayed_work_sync(&qdev->mpi_reset_work); |
3843 | cancel_delayed_work_sync(&qdev->mpi_work); | 3850 | cancel_delayed_work_sync(&qdev->mpi_work); |
3844 | cancel_delayed_work_sync(&qdev->mpi_idc_work); | 3851 | cancel_delayed_work_sync(&qdev->mpi_idc_work); |
3852 | cancel_delayed_work_sync(&qdev->mpi_core_to_log); | ||
3845 | cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); | 3853 | cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); |
3846 | 3854 | ||
3847 | for (i = 0; i < qdev->rss_ring_count; i++) | 3855 | for (i = 0; i < qdev->rss_ring_count; i++) |
@@ -4398,6 +4406,7 @@ static void ql_release_all(struct pci_dev *pdev) | |||
4398 | iounmap(qdev->reg_base); | 4406 | iounmap(qdev->reg_base); |
4399 | if (qdev->doorbell_area) | 4407 | if (qdev->doorbell_area) |
4400 | iounmap(qdev->doorbell_area); | 4408 | iounmap(qdev->doorbell_area); |
4409 | vfree(qdev->mpi_coredump); | ||
4401 | pci_release_regions(pdev); | 4410 | pci_release_regions(pdev); |
4402 | pci_set_drvdata(pdev, NULL); | 4411 | pci_set_drvdata(pdev, NULL); |
4403 | } | 4412 | } |
@@ -4479,6 +4488,15 @@ static int __devinit ql_init_device(struct pci_dev *pdev, | |||
4479 | spin_lock_init(&qdev->hw_lock); | 4488 | spin_lock_init(&qdev->hw_lock); |
4480 | spin_lock_init(&qdev->stats_lock); | 4489 | spin_lock_init(&qdev->stats_lock); |
4481 | 4490 | ||
4491 | if (qlge_mpi_coredump) { | ||
4492 | qdev->mpi_coredump = | ||
4493 | vmalloc(sizeof(struct ql_mpi_coredump)); | ||
4494 | if (qdev->mpi_coredump == NULL) { | ||
4495 | dev_err(&pdev->dev, "Coredump alloc failed.\n"); | ||
4496 | err = -ENOMEM; | ||
4497 | goto err_out; | ||
4498 | } | ||
4499 | } | ||
4482 | /* make sure the EEPROM is good */ | 4500 | /* make sure the EEPROM is good */ |
4483 | err = qdev->nic_ops->get_flash(qdev); | 4501 | err = qdev->nic_ops->get_flash(qdev); |
4484 | if (err) { | 4502 | if (err) { |
@@ -4508,6 +4526,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev, | |||
4508 | INIT_DELAYED_WORK(&qdev->mpi_work, ql_mpi_work); | 4526 | INIT_DELAYED_WORK(&qdev->mpi_work, ql_mpi_work); |
4509 | INIT_DELAYED_WORK(&qdev->mpi_port_cfg_work, ql_mpi_port_cfg_work); | 4527 | INIT_DELAYED_WORK(&qdev->mpi_port_cfg_work, ql_mpi_port_cfg_work); |
4510 | INIT_DELAYED_WORK(&qdev->mpi_idc_work, ql_mpi_idc_work); | 4528 | INIT_DELAYED_WORK(&qdev->mpi_idc_work, ql_mpi_idc_work); |
4529 | INIT_DELAYED_WORK(&qdev->mpi_core_to_log, ql_mpi_core_to_log); | ||
4511 | init_completion(&qdev->ide_completion); | 4530 | init_completion(&qdev->ide_completion); |
4512 | 4531 | ||
4513 | if (!cards_found) { | 4532 | if (!cards_found) { |
@@ -4630,6 +4649,7 @@ static void ql_eeh_close(struct net_device *ndev) | |||
4630 | cancel_delayed_work_sync(&qdev->mpi_reset_work); | 4649 | cancel_delayed_work_sync(&qdev->mpi_reset_work); |
4631 | cancel_delayed_work_sync(&qdev->mpi_work); | 4650 | cancel_delayed_work_sync(&qdev->mpi_work); |
4632 | cancel_delayed_work_sync(&qdev->mpi_idc_work); | 4651 | cancel_delayed_work_sync(&qdev->mpi_idc_work); |
4652 | cancel_delayed_work_sync(&qdev->mpi_core_to_log); | ||
4633 | cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); | 4653 | cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); |
4634 | 4654 | ||
4635 | for (i = 0; i < qdev->rss_ring_count; i++) | 4655 | for (i = 0; i < qdev->rss_ring_count; i++) |
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index e2b2286102d4..242b1ea955e4 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c | |||
@@ -1,5 +1,35 @@ | |||
1 | #include "qlge.h" | 1 | #include "qlge.h" |
2 | 2 | ||
3 | int ql_unpause_mpi_risc(struct ql_adapter *qdev) | ||
4 | { | ||
5 | u32 tmp; | ||
6 | |||
7 | /* Un-pause the RISC */ | ||
8 | tmp = ql_read32(qdev, CSR); | ||
9 | if (!(tmp & CSR_RP)) | ||
10 | return -EIO; | ||
11 | |||
12 | ql_write32(qdev, CSR, CSR_CMD_CLR_PAUSE); | ||
13 | return 0; | ||
14 | } | ||
15 | |||
16 | int ql_pause_mpi_risc(struct ql_adapter *qdev) | ||
17 | { | ||
18 | u32 tmp; | ||
19 | int count = UDELAY_COUNT; | ||
20 | |||
21 | /* Pause the RISC */ | ||
22 | ql_write32(qdev, CSR, CSR_CMD_SET_PAUSE); | ||
23 | do { | ||
24 | tmp = ql_read32(qdev, CSR); | ||
25 | if (tmp & CSR_RP) | ||
26 | break; | ||
27 | mdelay(UDELAY_DELAY); | ||
28 | count--; | ||
29 | } while (count); | ||
30 | return (count == 0) ? -ETIMEDOUT : 0; | ||
31 | } | ||
32 | |||
3 | int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data) | 33 | int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data) |
4 | { | 34 | { |
5 | int status; | 35 | int status; |
@@ -45,6 +75,35 @@ int ql_soft_reset_mpi_risc(struct ql_adapter *qdev) | |||
45 | return status; | 75 | return status; |
46 | } | 76 | } |
47 | 77 | ||
78 | /* Determine if we are in charge of the firwmare. If | ||
79 | * we are the lower of the 2 NIC pcie functions, or if | ||
80 | * we are the higher function and the lower function | ||
81 | * is not enabled. | ||
82 | */ | ||
83 | int ql_own_firmware(struct ql_adapter *qdev) | ||
84 | { | ||
85 | u32 temp; | ||
86 | |||
87 | /* If we are the lower of the 2 NIC functions | ||
88 | * on the chip the we are responsible for | ||
89 | * core dump and firmware reset after an error. | ||
90 | */ | ||
91 | if (qdev->func < qdev->alt_func) | ||
92 | return 1; | ||
93 | |||
94 | /* If we are the higher of the 2 NIC functions | ||
95 | * on the chip and the lower function is not | ||
96 | * enabled, then we are responsible for | ||
97 | * core dump and firmware reset after an error. | ||
98 | */ | ||
99 | temp = ql_read32(qdev, STS); | ||
100 | if (!(temp & (1 << (8 + qdev->alt_func)))) | ||
101 | return 1; | ||
102 | |||
103 | return 0; | ||
104 | |||
105 | } | ||
106 | |||
48 | static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp) | 107 | static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp) |
49 | { | 108 | { |
50 | int i, status; | 109 | int i, status; |
@@ -1143,5 +1202,19 @@ void ql_mpi_reset_work(struct work_struct *work) | |||
1143 | cancel_delayed_work_sync(&qdev->mpi_work); | 1202 | cancel_delayed_work_sync(&qdev->mpi_work); |
1144 | cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); | 1203 | cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); |
1145 | cancel_delayed_work_sync(&qdev->mpi_idc_work); | 1204 | cancel_delayed_work_sync(&qdev->mpi_idc_work); |
1205 | /* If we're not the dominant NIC function, | ||
1206 | * then there is nothing to do. | ||
1207 | */ | ||
1208 | if (!ql_own_firmware(qdev)) { | ||
1209 | QPRINTK(qdev, DRV, ERR, "Don't own firmware!\n"); | ||
1210 | return; | ||
1211 | } | ||
1212 | |||
1213 | if (!ql_core_dump(qdev, qdev->mpi_coredump)) { | ||
1214 | QPRINTK(qdev, DRV, ERR, "Core is dumped!\n"); | ||
1215 | qdev->core_is_dumped = 1; | ||
1216 | queue_delayed_work(qdev->workqueue, | ||
1217 | &qdev->mpi_core_to_log, 5 * HZ); | ||
1218 | } | ||
1146 | ql_soft_reset_mpi_risc(qdev); | 1219 | ql_soft_reset_mpi_risc(qdev); |
1147 | } | 1220 | } |