Print this page
8368 remove warlock leftovers from usr/src/uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/ib/adapters/hermon/hermon_fm.c
+++ new/usr/src/uts/common/io/ib/adapters/hermon/hermon_fm.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26 /*
27 27 * hermon_fm.c
28 28 * Hermon (InfiniBand) HCA Driver Fault Management Routines
29 29 *
30 30 * [Hermon FM Implementation]
31 31 *
32 32 * Hermon FM recovers the system from a HW error situation and/or isolates a
33 33 * HW error by calling the FMA acc handle check functions. (calling
34 34 * ddi_fm_acc_err_get()) If a HW error is detected when either
35 35 * ddi_fm_acc_err_get() is called, to determine whether or not the error is
36 36 * transient, the I/O operation causing the error will retry up to three times.
37 37 *
38 38 * (Basic HW error recovery)
39 39 *
40 40 * |
41 41 * .---->*
42 42 * | |
43 43 * | issue an I/O request via PIO
44 44 * | |
45 45 * | |
46 46 * | check acc handle
47 47 * | |
48 48 * | |
49 49 * `--< a HW error detected && retry count < 3 >
50 50 * |
51 51 * v
52 52 *
53 53 * When a HW error is detected, to provide the error information for users to
54 54 * isolate the faulted HW, Hermon FM issues Solaris FMA ereports as follows.
55 55 *
56 56 * * PIO transient error
57 57 * invalid_state => unaffected
58 58 *
59 59 * * PIO persistent error
60 60 * invalid_state => lost
61 61 *
62 62 * * PIO fatal error
63 63 * invalid_state => lost => panic
64 64 *
65 65 * * Hermon HCA firmware error
66 66 * invalid_state => degraded
67 67 *
68 68 * * Other Hermon HCA specific errors
69 69 * uncorrect => unaffected
70 70 * or
71 71 * correct => unaffected
72 72 *
73 73 * (Restrictions)
74 74 *
75 75 * The current implementation has the following restrictions.
76 76 * * No runtime check/protection
77 77 * * No detach time check/protection
78 78 * * No DMA check/protection
79 79 *
80 80 * See the Hermon FMA portfolio in detail.
81 81 */
82 82
83 83 #include <sys/types.h>
84 84 #include <sys/conf.h>
85 85 #include <sys/ddi.h>
86 86 #include <sys/sunddi.h>
87 87 #include <sys/sysmacros.h>
88 88 #include <sys/list.h>
89 89 #include <sys/modhash.h>
90 90
91 91 #include <sys/ib/adapters/hermon/hermon.h>
92 92
93 93 /*
94 94 * Hermon driver has to disable its FM functionality
95 95 * if this "fm_capable" variable is defined or has a value
96 96 * in /kernel/drv/hermon.conf.
97 97 */
98 98 static char *fm_cap = "fm-capable"; /* FM capability */
99 99
100 100 static hermon_hca_fm_t hca_fm; /* Hermon HCA FM Structure */
101 101
102 102 static void i_hca_fm_ereport(dev_info_t *, int, char *);
103 103 static void i_hca_fm_init(struct i_hca_fm *);
104 104 static void i_hca_fm_fini(struct i_hca_fm *);
105 105 static int i_hca_regs_map_setup(struct i_hca_fm *, dev_info_t *, uint_t,
106 106 caddr_t *, offset_t, offset_t, ddi_device_acc_attr_t *, ddi_acc_handle_t *);
107 107 static void i_hca_regs_map_free(struct i_hca_fm *, ddi_acc_handle_t *);
108 108 static int i_hca_pci_config_setup(struct i_hca_fm *, dev_info_t *,
109 109 ddi_acc_handle_t *);
110 110 static void i_hca_pci_config_teardown(struct i_hca_fm *, ddi_acc_handle_t *);
111 111 static int i_hca_pio_start(dev_info_t *, struct i_hca_acc_handle *,
112 112 hermon_test_t *);
113 113 static int i_hca_pio_end(dev_info_t *, struct i_hca_acc_handle *, int *,
114 114 hermon_test_t *);
115 115 static struct i_hca_acc_handle *i_hca_get_acc_handle(struct i_hca_fm *,
116 116 ddi_acc_handle_t);
117 117
118 118 /* forward declaration for hermon_fm_{init, fini}() */
119 119 #ifdef FMA_TEST
120 120 static void i_hca_test_init(mod_hash_t **, mod_hash_t **);
121 121 static void i_hca_test_fini(mod_hash_t **, mod_hash_t **);
122 122 #endif /* FMA_TEST */
123 123
124 124 /*
125 125 * Hermon FM Functions
126 126 *
127 127 * These functions are based on the HCA FM common interface
128 128 * defined below, but specific to the Hermon HCA FM capabilities.
129 129 */
130 130
131 131 /*
132 132 * void
133 133 * hermon_hca_fm_init(hermon_state_t *state, hermon_hca_fm_t *hca)
134 134 *
135 135 * Overview
136 136 * hermon_hca_fm_init() initializes the Hermon FM resources.
137 137 *
138 138 * Argument
139 139 * state: pointer to Hermon state structure
140 140 * hca: pointer to Hermon FM structure
141 141 *
142 142 * Return value
143 143 * Nothing
144 144 *
145 145 * Caller's context
146 146 * hermon_hca_fm_init() can be called in user or kernel context only.
147 147 */
148 148 static void
149 149 hermon_hca_fm_init(hermon_state_t *state, hermon_hca_fm_t *hca_fm)
150 150 {
151 151 state->hs_fm_hca_fm = hca_fm;
152 152 i_hca_fm_init((struct i_hca_fm *)hca_fm);
153 153 }
154 154
155 155
156 156 /*
157 157 * void
158 158 * hermon_hca_fm_fini(hermon_state_t *state)
159 159 *
160 160 * Overview
161 161 * hermon_hca_fm_fini() releases the Hermon FM resources.
162 162 *
163 163 * Argument
164 164 * state: pointer to Hermon state structure
165 165 *
166 166 * Return value
167 167 * Nothing
168 168 *
169 169 * Caller's context
170 170 * hermon_hca_fm_fini() can be called in user or kernel context only.
171 171 */
172 172 static void
173 173 hermon_hca_fm_fini(hermon_state_t *state)
174 174 {
175 175 i_hca_fm_fini((struct i_hca_fm *)state->hs_fm_hca_fm);
176 176 state->hs_fm_hca_fm = NULL;
177 177 }
178 178
179 179 /*
180 180 * void
181 181 * hermon_clr_state_nolock(hermon_state_t *state, int fm_state)
182 182 *
183 183 * Overview
184 184 * hermon_clr_state() drops the specified state from Hermon FM state
185 185 * without the mutex locks.
186 186 *
187 187 * Argument
188 188 * state: pointer to Hermon state structure
189 189 * fm_state: Hermon FM state, which is composed of:
190 190 * HCA_NO_FM Hermom FM is not supported
191 191 * HCA_PIO_FM PIO is fma-protected
192 192 * HCA_DMA_FM DMA is fma-protected
193 193 * HCA_EREPORT_FM FMA ereport is available
194 194 * HCA_ERRCB_FM FMA error callback is supported
195 195 * HCA_ATTCH_FM HCA FM attach mode
196 196 * HCA_RUNTM_FM HCA FM runtime mode
197 197 *
198 198 * Return value
199 199 * Nothing
200 200 *
201 201 * Caller's context
202 202 * hermon_clr_state() can be called in user, kernel, interrupt context
203 203 * or high interrupt context.
204 204 */
205 205 void
206 206 hermon_clr_state_nolock(hermon_state_t *state, int fm_state)
207 207 {
208 208 extern void membar_sync(void);
209 209
210 210 state->hs_fm_state &= ~fm_state;
211 211 membar_sync();
212 212 }
213 213
214 214
215 215 /*
216 216 * void
217 217 * hermon_clr_state(hermon_state_t *state, int fm_state)
218 218 *
219 219 * Overview
220 220 * hermon_clr_state() drops the specified state from Hermon FM state.
221 221 *
222 222 * Argument
223 223 * state: pointer to Hermon state structure
224 224 * fm_state: Hermon FM state, which is composed of:
225 225 * HCA_NO_FM Hermom FM is not supported
226 226 * HCA_PIO_FM PIO is fma-protected
227 227 * HCA_DMA_FM DMA is fma-protected
228 228 * HCA_EREPORT_FM FMA ereport is available
229 229 * HCA_ERRCB_FM FMA error callback is supported
230 230 * HCA_ATTCH_FM HCA FM attach mode
231 231 * HCA_RUNTM_FM HCA FM runtime mode
232 232 *
233 233 * Return value
234 234 * Nothing
235 235 *
236 236 * Caller's context
237 237 * hermon_clr_state() can be called in user, kernel or interrupt context.
238 238 */
239 239 static void
240 240 hermon_clr_state(hermon_state_t *state, int fm_state)
241 241 {
242 242 ASSERT(fm_state != HCA_NO_FM);
243 243
244 244 mutex_enter(&state->hs_fm_lock);
245 245 hermon_clr_state_nolock(state, fm_state);
246 246 mutex_exit(&state->hs_fm_lock);
247 247 }
248 248
249 249
250 250 /*
251 251 * void
252 252 * hermon_set_state(hermon_state_t *state, int fm_state)
253 253 *
254 254 * Overview
255 255 * hermon_set_state() sets Hermon FM state.
256 256 *
257 257 * Argument
258 258 * state: pointer to Hermon state structure
259 259 * fm_state: Hermon FM state, which is composed of:
260 260 * HCA_NO_FM Hermom FM is not supported
261 261 * HCA_PIO_FM PIO is fma-protected
262 262 * HCA_DMA_FM DMA is fma-protected
263 263 * HCA_EREPORT_FM FMA ereport is available
264 264 * HCA_ERRCB_FM FMA error callback is supported
265 265 * HCA_ATTCH_FM HCA FM attach mode
266 266 * HCA_RUNTM_FM HCA FM runtime mode
267 267 *
268 268 * Return value
269 269 * Nothing
270 270 *
271 271 * Caller's context
272 272 * hermon_set_state() can be called in user, kernel or interrupt context.
273 273 */
274 274 static void
275 275 hermon_set_state(hermon_state_t *state, int fm_state)
276 276 {
277 277 extern void membar_sync(void);
278 278
279 279 mutex_enter(&state->hs_fm_lock);
280 280 if (fm_state == HCA_NO_FM) {
281 281 state->hs_fm_state = HCA_NO_FM;
282 282 } else {
283 283 state->hs_fm_state |= fm_state;
284 284 }
285 285 membar_sync();
286 286 mutex_exit(&state->hs_fm_lock);
287 287 }
288 288
289 289
290 290 /*
291 291 * int
292 292 * hermon_get_state(hermon_state_t *state)
293 293 *
294 294 * Overview
295 295 * hermon_get_state() returns the current Hermon FM state.
296 296 *
297 297 * Argument
298 298 * state: pointer to Hermon state structure
299 299 *
300 300 * Return value
301 301 * fm_state: Hermon FM state, which is composed of:
302 302 * HCA_NO_FM Hermom FM is not supported
303 303 * HCA_PIO_FM PIO is fma-protected
304 304 * HCA_DMA_FM DMA is fma-protected
305 305 * HCA_EREPORT_FM FMA ereport is available
306 306 * HCA_ERRCB_FM FMA error callback is supported
307 307 * HCA_ATTCH_FM HCA FM attach mode
308 308 * HCA_RUNTM_FM HCA FM runtime mode
309 309 *
310 310 * Caller's context
311 311 * hermon_get_state() can be called in user, kernel or interrupt context.
312 312 */
313 313 int
314 314 hermon_get_state(hermon_state_t *state)
315 315 {
316 316 return (state->hs_fm_state);
317 317 }
318 318
319 319
320 320 /*
321 321 * void
322 322 * hermon_fm_init(hermon_state_t *state)
323 323 *
324 324 * Overview
325 325 * hermon_fm_init() is a Hermon FM initialization function which registers
326 326 * some FMA functions such as the ereport and the acc check capabilities
327 327 * for Hermon. If the "fm_disable" property in /kernel/drv/hermon.conf is
328 328 * defined (and/or its value is set), then the Hermon FM capabilities will
329 329 * drop, and only the default capabilities (the ereport and error callback
330 330 * capabilities) are available (and the action against HW errors is
331 331 * issuing an ereport then panicking the system).
332 332 *
333 333 * Argument
334 334 * state: pointer to Hermon state structure
335 335 *
336 336 * Return value
337 337 * Nothing
338 338 *
339 339 * Caller's context
340 340 * hermon_fm_init() can be called in user or kernel context only.
341 341 */
342 342 void
343 343 hermon_fm_init(hermon_state_t *state)
344 344 {
345 345 ddi_iblock_cookie_t iblk;
346 346
347 347 /*
348 348 * Check the "fm_disable" property. If it's defined,
349 349 * use the Solaris FMA default action for Hermon.
350 350 */
351 351 if (ddi_getprop(DDI_DEV_T_NONE, state->hs_dip, DDI_PROP_DONTPASS,
352 352 "fm_disable", 0) != 0) {
353 353 state->hs_fm_disable = 1;
354 354 }
355 355
356 356 /* If hs_fm_diable is set, then skip the rest */
357 357 if (state->hs_fm_disable) {
358 358 hermon_set_state(state, HCA_NO_FM);
359 359 return;
360 360 }
361 361
362 362 /* Set the Hermon FM attach mode */
363 363 hermon_set_state(state, HCA_ATTCH_FM);
364 364
365 365 /* Initialize the Solaris FMA capabilities for the Hermon FM support */
366 366 state->hs_fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY,
367 367 state->hs_dip, DDI_PROP_DONTPASS, fm_cap,
368 368 DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE);
369 369
370 370 /*
371 371 * The Hermon FM uses the ereport and acc check capabilites only,
372 372 * but both of them should be available. If either is not, turn
373 373 * hs_fm_disable on and behave in the same way as the "fm_diable"
374 374 * property is set.
375 375 */
376 376 if (state->hs_fm_capabilities !=
377 377 (DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE)) {
378 378 state->hs_fm_disable = 1;
379 379 hermon_set_state(state, HCA_NO_FM);
380 380 HERMON_ATTACH_MSG(state->hs_attach_buf,
381 381 "Hermon FM capability fails");
382 382 return;
383 383 }
384 384
385 385 /* Initialize the HCA FM resources */
386 386 hermon_hca_fm_init(state, &hca_fm);
387 387
388 388 /* Initialize the fm state lock */
389 389 mutex_init(&state->hs_fm_lock, NULL, MUTEX_DRIVER, NULL);
390 390
391 391 /* Register the capabilities with the IO fault services */
392 392 ddi_fm_init(state->hs_dip, &state->hs_fm_capabilities, &iblk);
393 393
394 394 /* Set up the pci ereport capabilities if the ereport is capable */
395 395 if (DDI_FM_EREPORT_CAP(state->hs_fm_capabilities)) {
396 396 pci_ereport_setup(state->hs_dip);
397 397 }
398 398
399 399 /* Set the Hermon FM state */
400 400 hermon_set_state(state, HCA_PIO_FM | HCA_EREPORT_FM);
401 401
402 402 #ifdef FMA_TEST
403 403 i_hca_test_init(&state->hs_fm_test_hash, &state->hs_fm_id_hash);
404 404 #endif /* FMA_TEST */
405 405 }
406 406
407 407
408 408 /*
409 409 * void
410 410 * hermon_fm_fini(hermon_state_t *state)
411 411 *
412 412 * Overview
413 413 * hermon_fm_fini() is a Hermon FM finalization function which de-registers
414 414 * Solaris FMA functions set to Hermon.
415 415 *
416 416 * Argument
417 417 * state: pointer to Hermon state structure
418 418 *
419 419 * Return value
420 420 * Nothing
421 421 *
422 422 * Caller's context
423 423 * hermon_fm_fini() can be called in user or kernel context only.
424 424 */
425 425 void
426 426 hermon_fm_fini(hermon_state_t *state)
427 427 {
428 428 /*
429 429 * If hermon_fm_diable is set or there is no FM service provided,
430 430 * then skip the rest.
431 431 */
432 432 if (state->hs_fm_disable || hermon_get_state(state) == HCA_NO_FM) {
433 433 return;
434 434 }
435 435
436 436 ASSERT(!(hermon_get_state(state) & HCA_ERRCB_FM));
437 437
438 438 #ifdef FMA_TEST
439 439 i_hca_test_fini(&state->hs_fm_test_hash, &state->hs_fm_id_hash);
440 440 #endif /* FMA_TEST */
441 441
442 442 /* Set the Hermon FM state to no support */
443 443 hermon_set_state(state, HCA_NO_FM);
444 444
445 445 /* Release HCA FM resources */
446 446 hermon_hca_fm_fini(state);
447 447
448 448 /*
449 449 * Release any resources allocated by pci_ereport_setup()
450 450 */
451 451 if (DDI_FM_EREPORT_CAP(state->hs_fm_capabilities)) {
452 452 pci_ereport_teardown(state->hs_dip);
453 453 }
454 454
455 455 /* De-register the Hermon FM from the IO fault services */
456 456 ddi_fm_fini(state->hs_dip);
457 457 }
458 458
459 459
460 460 /*
461 461 * int
462 462 * hermon_fm_ereport_init(hermon_state_t *state)
463 463 *
464 464 * Overview
465 465 * hermon_fm_ereport_init() changes the Hermon FM state to the ereport
466 466 * only mode during the driver attach.
467 467 *
468 468 * Argument
469 469 * state: pointer to Hermon state structure
470 470 *
471 471 * Return value
472 472 * DDI_SUCCESS
473 473 * DDI_FAILURE
474 474 *
475 475 * Caller's context
476 476 * hermon_fm_ereport_init() can be called in user or kernel context only.
477 477 */
478 478 int
479 479 hermon_fm_ereport_init(hermon_state_t *state)
480 480 {
481 481 ddi_iblock_cookie_t iblk;
482 482 hermon_cfg_profile_t *cfgprof;
483 483 hermon_hw_querydevlim_t *devlim;
484 484 hermon_rsrc_hw_entry_info_t entry_info;
485 485 hermon_rsrc_pool_info_t *rsrc_pool;
486 486 uint64_t offset, num, max, num_prealloc;
487 487 ddi_device_acc_attr_t dev_attr = {
488 488 DDI_DEVICE_ATTR_V0,
489 489 DDI_STRUCTURE_LE_ACC,
490 490 DDI_STRICTORDER_ACC,
491 491 DDI_DEFAULT_ACC
492 492 };
493 493 char *rsrc_name;
494 494 extern void membar_sync(void);
495 495
496 496 /* Stop the poll thread while the FM state is being changed */
497 497 state->hs_fm_poll_suspend = B_TRUE;
498 498 membar_sync();
499 499
500 500 /*
501 501 * Disable the Hermon interrupt after the interrupt capability flag
502 502 * is checked.
503 503 */
504 504 if (state->hs_intrmsi_cap & DDI_INTR_FLAG_BLOCK) {
505 505 if (ddi_intr_block_disable
506 506 (&state->hs_intrmsi_hdl[0], 1) != DDI_SUCCESS) {
507 507 return (DDI_FAILURE);
508 508 }
509 509 } else {
510 510 if (ddi_intr_disable
511 511 (state->hs_intrmsi_hdl[0]) != DDI_SUCCESS) {
512 512 return (DDI_FAILURE);
513 513 }
514 514 }
515 515
516 516 /*
517 517 * Release any resources allocated by pci_ereport_setup()
518 518 */
519 519 if (DDI_FM_EREPORT_CAP(state->hs_fm_capabilities)) {
520 520 pci_ereport_teardown(state->hs_dip);
521 521 }
522 522
523 523 /* De-register the Hermon FM from the IO fault services */
524 524 ddi_fm_fini(state->hs_dip);
525 525
526 526 /* Re-initialize fm ereport with the ereport only */
527 527 state->hs_fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY,
528 528 state->hs_dip, DDI_PROP_DONTPASS, fm_cap,
529 529 DDI_FM_EREPORT_CAPABLE);
530 530
531 531 /*
532 532 * Now that the Hermon FM uses the ereport capability only,
533 533 * If it's not set, turn hs_fm_disable on and behave in the
534 534 * same way as the "fm_diable" property is set.
535 535 */
536 536 if (state->hs_fm_capabilities != DDI_FM_EREPORT_CAPABLE) {
537 537 HERMON_ATTACH_MSG(state->hs_attach_buf,
538 538 "Hermon FM ereport fails (ereport mode)");
539 539 goto error;
540 540 }
541 541
542 542 /* Re-register the ereport capability with the IO fault services */
543 543 ddi_fm_init(state->hs_dip, &state->hs_fm_capabilities, &iblk);
544 544
545 545 /* Initialize the pci ereport capabilities if the ereport is capable */
546 546 if (DDI_FM_EREPORT_CAP(state->hs_fm_capabilities)) {
547 547 pci_ereport_setup(state->hs_dip);
548 548 }
549 549
550 550 /* Setup for PCI config read/write of HCA device */
551 551 if (pci_config_setup(state->hs_dip, &state->hs_reg_pcihdl) !=
552 552 DDI_SUCCESS) {
553 553 HERMON_ATTACH_MSG(state->hs_attach_buf,
554 554 "PCI config mapping fails (ereport mode)");
555 555 goto error;
556 556 }
557 557
558 558 /* Allocate the regular access handle for MSI-X tables */
559 559 if (ddi_regs_map_setup(state->hs_dip, state->hs_msix_tbl_rnumber,
560 560 (caddr_t *)&state->hs_msix_tbl_addr, state->hs_msix_tbl_offset,
561 561 state->hs_msix_tbl_size, &dev_attr,
562 562 &state->hs_reg_msix_tblhdl) != DDI_SUCCESS) {
563 563 HERMON_ATTACH_MSG(state->hs_attach_buf,
564 564 "MSI-X Table mapping fails (ereport mode)");
565 565 goto error;
566 566 }
567 567
568 568 /* Allocate the regular access handle for MSI-X PBA */
569 569 if (ddi_regs_map_setup(state->hs_dip, state->hs_msix_pba_rnumber,
570 570 (caddr_t *)&state->hs_msix_pba_addr, state->hs_msix_pba_offset,
571 571 state->hs_msix_pba_size, &dev_attr,
572 572 &state->hs_reg_msix_pbahdl) != DDI_SUCCESS) {
573 573 HERMON_ATTACH_MSG(state->hs_attach_buf,
574 574 "MSI-X PBA mapping fails (ereport mode)");
575 575 goto error;
576 576 }
577 577
578 578 /* Allocate the regular access handle for Hermon CMD I/O space */
579 579 if (ddi_regs_map_setup(state->hs_dip, HERMON_CMD_BAR,
580 580 &state->hs_reg_cmd_baseaddr, 0, 0, &state->hs_reg_accattr,
581 581 &state->hs_reg_cmdhdl) != DDI_SUCCESS) {
582 582 HERMON_ATTACH_MSG(state->hs_attach_buf,
583 583 "CMD_BAR mapping fails (ereport mode)");
584 584 goto error;
585 585 }
586 586
587 587 /* Reset the host command register */
588 588 state->hs_cmd_regs.hcr = (hermon_hw_hcr_t *)
589 589 ((uintptr_t)state->hs_reg_cmd_baseaddr + HERMON_CMD_HCR_OFFSET);
590 590
591 591 /* Reset the software reset register */
592 592 state->hs_cmd_regs.sw_reset = (uint32_t *)
593 593 ((uintptr_t)state->hs_reg_cmd_baseaddr +
594 594 HERMON_CMD_SW_RESET_OFFSET);
595 595
596 596 /* Reset the software reset register semaphore */
597 597 state->hs_cmd_regs.sw_semaphore = (uint32_t *)
598 598 ((uintptr_t)state->hs_reg_cmd_baseaddr +
599 599 HERMON_CMD_SW_SEMAPHORE_OFFSET);
600 600
601 601 /* Calculate the clear interrupt register offset */
602 602 offset = state->hs_fw.clr_intr_offs & HERMON_CMD_OFFSET_MASK;
603 603
604 604 /* Reset the clear interrupt address */
605 605 state->hs_cmd_regs.clr_intr = (uint64_t *)
606 606 (uintptr_t)(state->hs_reg_cmd_baseaddr + offset);
607 607
608 608 /* Reset the internal error buffer address */
609 609 state->hs_cmd_regs.fw_err_buf = (uint32_t *)(uintptr_t)
610 610 (state->hs_reg_cmd_baseaddr + state->hs_fw.error_buf_addr);
611 611
612 612 /* Check if the blue flame is enabled, and set the offset value */
613 613 if (state->hs_devlim.blu_flm) {
614 614 offset = (uint64_t)1 <<
615 615 (state->hs_devlim.log_max_uar_sz + 20);
616 616 } else {
617 617 offset = 0;
618 618 }
619 619
620 620 /* Allocate the regular access handle for Hermon UAR I/O space */
621 621 if (ddi_regs_map_setup(state->hs_dip, HERMON_UAR_BAR,
622 622 &state->hs_reg_uar_baseaddr, 0, offset,
623 623 &state->hs_reg_accattr, &state->hs_reg_uarhdl) != DDI_SUCCESS) {
624 624 HERMON_ATTACH_MSG(state->hs_attach_buf,
625 625 "UAR BAR mapping fails (ereport mode)");
626 626 goto error;
627 627 }
628 628
629 629 hermon_eq_reset_uar_baseaddr(state);
630 630
631 631 /* Drop the Hermon FM Attach Mode */
632 632 hermon_clr_state(state, HCA_ATTCH_FM);
633 633
634 634 /* Set the Hermon FM Runtime Mode */
635 635 hermon_set_state(state, HCA_RUNTM_FM);
636 636
637 637 /* Free up Hermon UAR page #1 */
638 638 hermon_rsrc_free(state, &state->hs_uarkpg_rsrc);
639 639
640 640 /* Free up the UAR pool */
641 641 entry_info.hwi_rsrcpool = &state->hs_rsrc_hdl[HERMON_UARPG];
642 642 hermon_rsrc_hw_entries_fini(state, &entry_info);
643 643
644 644 /* Re-allocate the UAR pool */
645 645 cfgprof = state->hs_cfg_profile;
646 646 devlim = &state->hs_devlim;
647 647 num = ((uint64_t)1 << cfgprof->cp_log_num_uar);
648 648 max = num;
649 649 num_prealloc = max(devlim->num_rsvd_uar, 128);
650 650 rsrc_pool = &state->hs_rsrc_hdl[HERMON_UARPG];
651 651 rsrc_pool->rsrc_type = HERMON_UARPG;
652 652 rsrc_pool->rsrc_loc = HERMON_IN_UAR;
653 653 rsrc_pool->rsrc_pool_size = (num << PAGESHIFT);
654 654 rsrc_pool->rsrc_shift = PAGESHIFT;
655 655 rsrc_pool->rsrc_quantum = (uint_t)PAGESIZE;
656 656 rsrc_pool->rsrc_align = PAGESIZE;
657 657 rsrc_pool->rsrc_state = state;
658 658 rsrc_pool->rsrc_start = (void *)state->hs_reg_uar_baseaddr;
659 659 rsrc_name = (char *)kmem_zalloc(HERMON_RSRC_NAME_MAXLEN, KM_SLEEP);
660 660 HERMON_RSRC_NAME(rsrc_name, HERMON_UAR_PAGE_VMEM_RUNTM);
661 661 entry_info.hwi_num = num;
662 662 entry_info.hwi_max = max;
663 663 entry_info.hwi_prealloc = num_prealloc;
664 664 entry_info.hwi_rsrcpool = rsrc_pool;
665 665 entry_info.hwi_rsrcname = rsrc_name;
666 666 if (hermon_rsrc_hw_entries_init(state, &entry_info) != DDI_SUCCESS) {
667 667 kmem_free(rsrc_name, HERMON_RSRC_NAME_MAXLEN);
668 668 goto error;
669 669 }
670 670 kmem_free(rsrc_name, HERMON_RSRC_NAME_MAXLEN);
671 671
672 672 /* Re-allocate the kernel UAR page */
673 673 if (hermon_rsrc_alloc(state, HERMON_UARPG, 1, HERMON_SLEEP,
674 674 &state->hs_uarkpg_rsrc) != DDI_SUCCESS) {
675 675 goto error;
676 676 }
677 677
678 678 /* Setup pointer to kernel UAR page */
679 679 state->hs_uar = (hermon_hw_uar_t *)state->hs_uarkpg_rsrc->hr_addr;
680 680
681 681 /* Now drop the the Hermon PIO FM */
682 682 hermon_clr_state(state, HCA_PIO_FM);
683 683
684 684 /* Release the MSI-X Table access handle */
685 685 if (state->hs_fm_msix_tblhdl) {
686 686 hermon_regs_map_free(state, &state->hs_fm_msix_tblhdl);
687 687 state->hs_fm_msix_tblhdl = NULL;
688 688 }
689 689
690 690 /* Release the MSI-X PBA access handle */
691 691 if (state->hs_fm_msix_pbahdl) {
692 692 hermon_regs_map_free(state, &state->hs_fm_msix_pbahdl);
693 693 state->hs_fm_msix_pbahdl = NULL;
694 694 }
695 695
696 696 /* Release the pci config space access handle */
697 697 if (state->hs_fm_pcihdl) {
698 698 hermon_regs_map_free(state, &state->hs_fm_pcihdl);
699 699 state->hs_fm_pcihdl = NULL;
700 700 }
701 701
702 702 /* Release the cmd protected access handle */
703 703 if (state->hs_fm_cmdhdl) {
704 704 hermon_regs_map_free(state, &state->hs_fm_cmdhdl);
705 705 state->hs_fm_cmdhdl = NULL;
706 706 }
707 707
708 708 /* Release the uar fma-protected access handle */
709 709 if (state->hs_fm_uarhdl) {
710 710 hermon_regs_map_free(state, &state->hs_fm_uarhdl);
711 711 state->hs_fm_uarhdl = NULL;
712 712 }
713 713
714 714 /* Enable the Hermon interrupt again */
715 715 if (state->hs_intrmsi_cap & DDI_INTR_FLAG_BLOCK) {
716 716 if (ddi_intr_block_enable
717 717 (&state->hs_intrmsi_hdl[0], 1) != DDI_SUCCESS) {
718 718 return (DDI_FAILURE);
719 719 }
720 720 } else {
721 721 if (ddi_intr_enable
722 722 (state->hs_intrmsi_hdl[0]) != DDI_SUCCESS) {
723 723 return (DDI_FAILURE);
724 724 }
725 725 }
726 726
727 727 /* Restart the poll thread */
728 728 state->hs_fm_poll_suspend = B_FALSE;
729 729
730 730 return (DDI_SUCCESS);
731 731
732 732 error:
733 733 /* Enable the Hermon interrupt again */
734 734 if (state->hs_intrmsi_cap & DDI_INTR_FLAG_BLOCK) {
735 735 (void) ddi_intr_block_enable(&state->hs_intrmsi_hdl[0], 1);
736 736 } else {
737 737 (void) ddi_intr_enable(state->hs_intrmsi_hdl[0]);
738 738 }
739 739 return (DDI_FAILURE);
740 740 }
741 741
742 742
743 743 /*
744 744 * int
745 745 * hermon_regs_map_setup(hermon_state_t *state, uint_t rnumber, caddr_t *addrp,
746 746 * offset_t offset, offset_t len, ddi_device_acc_attr_t *accattrp,
747 747 * ddi_acc_handle_t *handle)
748 748 *
749 749 * Overview
750 750 * This is a wrapper function of i_hca_regs_map_setup() for Hermon FM so
751 751 * that it calls i_hca_regs_map_setup() inside after it checks the
752 752 * "fm_disable" configuration property. If the "fm_disable" is described
753 753 * in /kernel/drv/hermon.conf, the function calls ddi_regs_map_setup()
754 754 * directly instead.
755 755 * See i_hca_regs_map_setup() in detail.
756 756 *
757 757 * Argument
758 758 * state: pointer to Hermon state structure
759 759 * rnumber: index number to the register address space set
760 760 * addrp: platform-dependent value (same as ddi_regs_map_setup())
761 761 * offset: offset into the register address space
762 762 * len: address space length to be mapped
763 763 * accattrp: pointer to device access attribute structure
764 764 * handle: pointer to ddi_acc_handle_t used for HCA FM
765 765 *
766 766 * Return value
767 767 * ddi function status value which are:
768 768 * DDI_SUCCESS
769 769 * DDI_FAILURE
770 770 * DDI_ME_RNUMBER_RNGE
771 771 * DDI_REGS_ACC_CONFLICT
772 772 *
773 773 * Caller's context
774 774 * hermon_regs_map_setup() can be called in user or kernel context only.
775 775 */
776 776 int
777 777 hermon_regs_map_setup(hermon_state_t *state, uint_t rnumber, caddr_t *addrp,
778 778 offset_t offset, offset_t len, ddi_device_acc_attr_t *accattrp,
779 779 ddi_acc_handle_t *handle)
780 780 {
781 781 if (state->hs_fm_disable) {
782 782 return (ddi_regs_map_setup(state->hs_dip, rnumber, addrp,
783 783 offset, len, accattrp, handle));
784 784 } else {
785 785 return (i_hca_regs_map_setup(state->hs_fm_hca_fm, state->hs_dip,
786 786 rnumber, addrp, offset, len, accattrp, handle));
787 787 }
788 788 }
789 789
790 790
791 791 /*
792 792 * void
793 793 * hermon_regs_map_free(hermon_state_t *state, ddi_acc_handle_t *handlep)
794 794 *
795 795 * Overview
796 796 * This is a wrapper function of i_hca_regs_map_free() for Hermon FM so
797 797 * that it calls i_hca_regs_map_free() inside after it checks the
798 798 * "fm_disable" configuration property. If the "fm_disable" is described
799 799 * in /kernel/drv/hermon.conf, the function calls ddi_regs_map_fre()
800 800 * directly instead. See i_hca_regs_map_free() in detail.
801 801 *
802 802 * Argument
803 803 * state: pointer to Hermon state structure
804 804 * handle: pointer to ddi_acc_handle_t used for HCA FM
805 805 *
806 806 * Return value
807 807 * Nothing
808 808 *
809 809 * Caller's context
810 810 * hermon_regs_map_free() can be called in user or kernel context only.
811 811 *
812 812 * Note that the handle passed to hermon_regs_map_free() is NULL-cleared
813 813 * after this function is called.
814 814 */
815 815 void
816 816 hermon_regs_map_free(hermon_state_t *state, ddi_acc_handle_t *handle)
817 817 {
818 818 if (state->hs_fm_disable) {
819 819 ddi_regs_map_free(handle);
820 820 *handle = NULL;
821 821 } else {
822 822 i_hca_regs_map_free(state->hs_fm_hca_fm, handle);
823 823 }
824 824 }
825 825
826 826
827 827 /*
828 828 * int
829 829 * hermon_pci_config_setup(hermon_state_t *state, ddi_acc_handle_t *handle)
830 830 *
831 831 * Overview
832 832 * This is a wrapper function of i_hca_pci_config_setup() for Hermon FM so
833 833 * that it calls i_hca_pci_config_setup() inside after it checks the
834 834 * "fm-disable" configuration property. If the "fm_disable" is described
835 835 * in /kernel/drv/hermon.conf, the function calls pci_config_setup()
836 836 * directly instead. See i_hca_pci_config_setup() in detail.
837 837 *
838 838 * Argument
839 839 * state: pointer to Hermon state structure
840 840 * handle: pointer to ddi_acc_handle_t used for HCA FM
841 841 *
842 842 * Return value
843 843 * ddi function status value which are:
844 844 * DDI_SUCCESS
845 845 * DDI_FAILURE
846 846 *
847 847 * Caller's context
848 848 * hermon_pci_config_setup() can be called in user or kernel context only.
849 849 */
850 850 int
851 851 hermon_pci_config_setup(hermon_state_t *state, ddi_acc_handle_t *handle)
852 852 {
853 853 if (state->hs_fm_disable) {
854 854 return (pci_config_setup(state->hs_dip, handle));
855 855 } else {
856 856 /* Check Hermon FM and Solaris FMA capability flags */
857 857 ASSERT((hermon_get_state(state) & HCA_PIO_FM &&
858 858 DDI_FM_ACC_ERR_CAP(ddi_fm_capable(state->hs_dip))) ||
859 859 (!(hermon_get_state(state) & HCA_PIO_FM) &&
860 860 !DDI_FM_ACC_ERR_CAP(ddi_fm_capable(state->hs_dip))));
861 861 return (i_hca_pci_config_setup(state->hs_fm_hca_fm,
862 862 state->hs_dip, handle));
863 863 }
864 864 }
865 865
866 866
867 867 /*
868 868 * void
869 869 * hermon_pci_config_teardown(hermon_state_t *state, ddi_acc_handle_t *handle)
870 870 *
871 871 * Overview
872 872 * This is a wrapper function of i_hca_pci_config_teardown() for Hermon
873 873 * FM so that it calls i_hca_pci_config_teardown() inside after it checks
874 874 * the "fm-disable" configuration property. If the "fm_disable" is
875 875 * described in /kernel/drv/hermon.conf, the function calls
876 876 * pci_config_teardown() directly instead.
877 877 * See i_hca_pci_config_teardown() in detail.
878 878 *
879 879 * Argument
880 880 * state: pointer to Hermon state structure
881 881 * handle: pointer to ddi_acc_handle_t used for HCA FM
882 882 *
883 883 * Return value
884 884 * Nothing
885 885 *
886 886 * Caller's context
887 887 * hermon_pci_config_teardown() can be called in user or kernel context
888 888 * only.
889 889 */
890 890 void
891 891 hermon_pci_config_teardown(hermon_state_t *state, ddi_acc_handle_t *handle)
892 892 {
893 893 if (state->hs_fm_disable) {
894 894 pci_config_teardown(handle);
895 895 *handle = NULL;
896 896 } else {
897 897 i_hca_pci_config_teardown(state->hs_fm_hca_fm, handle);
898 898 }
899 899 }
900 900
901 901
902 902 /*
903 903 * boolean_t
904 904 * hermon_init_failure(hermon_state_t *state)
905 905 *
906 906 * Overview
907 907 * hermon_init_failure() tells if HW errors are detected in
908 908 * the Hermon driver attach.
909 909 *
910 910 * Argument
911 911 * state: pointer to Hermon state structure
912 912 *
913 913 * Return value
914 914 * B_TRUE HW errors detected during attach
915 915 * B_FALSE No HW errors during attach
916 916 *
917 917 * Caller's context
918 918 * hermon_init_failure() can be called in user, kernel, interrupt
919 919 * context or high interrupt context.
920 920 */
921 921 boolean_t
922 922 hermon_init_failure(hermon_state_t *state)
923 923 {
924 924 ddi_acc_handle_t hdl;
925 925 ddi_fm_error_t derr;
926 926
927 927 if (!(hermon_get_state(state) & HCA_PIO_FM))
928 928 return (B_FALSE);
929 929
930 930 /* check if fatal errors occur during attach */
931 931 if (state->hs_fm_async_fatal)
932 932 return (B_TRUE);
933 933
934 934 hdl = hermon_get_uarhdl(state);
935 935 /* Get the PIO error against UAR I/O space */
936 936 ddi_fm_acc_err_get(hdl, &derr, DDI_FME_VERSION);
937 937 if (derr.fme_status != DDI_FM_OK) {
938 938 return (B_TRUE);
939 939 }
940 940
941 941 hdl = hermon_get_cmdhdl(state);
942 942 /* Get the PIO error againsts CMD I/O space */
943 943 ddi_fm_acc_err_get(hdl, &derr, DDI_FME_VERSION);
944 944 if (derr.fme_status != DDI_FM_OK) {
945 945 return (B_TRUE);
946 946 }
947 947
948 948 return (B_FALSE);
949 949 }
950 950
951 951
952 952 /*
953 953 * void
954 954 * hermon_fm_ereport(hermon_state_t *state, int type, int detail)
955 955 *
956 956 * Overview
957 957 * hermon_fm_ereport() is a Hermon FM ereport function used
958 958 * to issue a Solaris FMA ereport. See Hermon FM comments at the
959 959 * beginning of this file in detail.
960 960 *
961 961 * Argument
962 962 * state: pointer to Hermon state structure
963 963 * type: error type
964 964 * HCA_SYS_ERR FMA reporting HW error
965 965 * HCA_IBA_ERR HCA specific HW error
966 966 * detail: HW error hint implying which ereport is issued
967 967 * HCA_ERR_TRANSIENT HW transienet error
968 968 * HCA_ERR_NON_FATAL HW persistent error
969 969 * HCA_ERR_FATAL HW fatal error
970 970 * HCA_ERR_SRV_LOST IB service lost due to HW error
971 971 * HCA_ERR_DEGRADED Hermon driver and/or uDAPL degraded
972 972 * due to HW error
973 973 * HCA_ERR_IOCTL HW error detected in user conetxt
974 974 * (especially in ioctl())
975 975 *
976 976 * Return value
977 977 * Nothing
978 978 *
979 979 * Caller's context
980 980 * hermon_fm_ereport() can be called in user, kernel, interrupt context
981 981 * or high interrupt context.
982 982 */
983 983 void
984 984 hermon_fm_ereport(hermon_state_t *state, int type, int detail)
985 985 {
986 986 /*
987 987 * If hermon_fm_diable is set or there is no FM ereport service
988 988 * provided, then skip the rest.
989 989 */
990 990 if (state->hs_fm_disable ||
991 991 !(hermon_get_state(state) & HCA_EREPORT_FM)) {
992 992 return;
993 993 }
994 994
995 995 switch (type) {
996 996
997 997 case HCA_SYS_ERR:
998 998 switch (detail) {
999 999 case HCA_ERR_TRANSIENT:
1000 1000 case HCA_ERR_IOCTL:
1001 1001 ddi_fm_service_impact(state->hs_dip,
1002 1002 DDI_SERVICE_UNAFFECTED);
1003 1003 break;
1004 1004 case HCA_ERR_NON_FATAL:
1005 1005 /* Nothing */
1006 1006 break;
1007 1007 case HCA_ERR_SRV_LOST:
1008 1008 ddi_fm_service_impact(state->hs_dip,
1009 1009 DDI_SERVICE_LOST);
1010 1010 break;
1011 1011 case HCA_ERR_DEGRADED:
1012 1012 switch (state->hs_fm_degraded_reason) {
1013 1013 case HCA_FW_CORRUPT:
1014 1014 i_hca_fm_ereport(state->hs_dip, type,
1015 1015 DDI_FM_DEVICE_FW_CORRUPT);
1016 1016 break;
1017 1017 case HCA_FW_MISMATCH:
1018 1018 i_hca_fm_ereport(state->hs_dip, type,
1019 1019 DDI_FM_DEVICE_FW_MISMATCH);
1020 1020 break;
1021 1021 case HCA_FW_MISC:
1022 1022 default:
1023 1023 i_hca_fm_ereport(state->hs_dip, type,
1024 1024 DDI_FM_DEVICE_INTERN_UNCORR);
1025 1025 break;
1026 1026 }
1027 1027 ddi_fm_service_impact(state->hs_dip,
1028 1028 DDI_SERVICE_DEGRADED);
1029 1029 break;
1030 1030 case HCA_ERR_FATAL:
1031 1031 ddi_fm_service_impact(state->hs_dip,
1032 1032 DDI_SERVICE_LOST);
1033 1033 state->hs_fm_async_fatal = B_TRUE;
1034 1034 break;
1035 1035 default:
1036 1036 cmn_err(CE_WARN, "hermon_fm_ereport: Unknown error. "
1037 1037 "type = %d, detail = %d\n.", type, detail);
1038 1038 }
1039 1039 break;
1040 1040
1041 1041 case HCA_IBA_ERR:
1042 1042 switch (detail) {
1043 1043 case HCA_ERR_TRANSIENT:
1044 1044 i_hca_fm_ereport(state->hs_dip, type,
1045 1045 DDI_FM_DEVICE_INTERN_UNCORR);
1046 1046 ddi_fm_service_impact(state->hs_dip,
1047 1047 DDI_SERVICE_UNAFFECTED);
1048 1048 break;
1049 1049 case HCA_ERR_SRV_LOST:
1050 1050 cmn_err(CE_WARN, "hermon_fm_ereport: not supported "
1051 1051 "error. type = %d, detail = %d\n.", type, detail);
1052 1052 break;
1053 1053 case HCA_ERR_DEGRADED:
1054 1054 switch (state->hs_fm_degraded_reason) {
1055 1055 case HCA_FW_CORRUPT:
1056 1056 i_hca_fm_ereport(state->hs_dip, type,
1057 1057 DDI_FM_DEVICE_FW_CORRUPT);
1058 1058 break;
1059 1059 case HCA_FW_MISMATCH:
1060 1060 i_hca_fm_ereport(state->hs_dip, type,
1061 1061 DDI_FM_DEVICE_FW_MISMATCH);
1062 1062 break;
1063 1063 case HCA_FW_MISC:
1064 1064 default:
1065 1065 i_hca_fm_ereport(state->hs_dip, type,
1066 1066 DDI_FM_DEVICE_INTERN_UNCORR);
1067 1067 break;
1068 1068 }
1069 1069 ddi_fm_service_impact(state->hs_dip,
1070 1070 DDI_SERVICE_DEGRADED);
1071 1071 break;
1072 1072 case HCA_ERR_IOCTL:
1073 1073 case HCA_ERR_NON_FATAL:
1074 1074 i_hca_fm_ereport(state->hs_dip, type,
1075 1075 DDI_FM_DEVICE_INTERN_UNCORR);
1076 1076 ddi_fm_service_impact(state->hs_dip,
1077 1077 DDI_SERVICE_UNAFFECTED);
1078 1078 break;
1079 1079 case HCA_ERR_FATAL:
1080 1080 if (hermon_get_state(state) & HCA_PIO_FM) {
1081 1081 if (servicing_interrupt()) {
1082 1082 atomic_inc_32(&state->
1083 1083 hs_fm_async_errcnt);
1084 1084 } else {
1085 1085 i_hca_fm_ereport(state->hs_dip, type,
1086 1086 DDI_FM_DEVICE_INTERN_UNCORR);
1087 1087 ddi_fm_service_impact(state->hs_dip,
1088 1088 DDI_SERVICE_LOST);
1089 1089 }
1090 1090 state->hs_fm_async_fatal = B_TRUE;
1091 1091 } else {
1092 1092 i_hca_fm_ereport(state->hs_dip, type,
1093 1093 DDI_FM_DEVICE_INTERN_UNCORR);
1094 1094 ddi_fm_service_impact(state->hs_dip,
1095 1095 DDI_SERVICE_LOST);
1096 1096 cmn_err(CE_PANIC,
1097 1097 "Hermon Fatal Internal Error. "
1098 1098 "Hermon state=0x%p", (void *)state);
1099 1099 }
1100 1100 break;
1101 1101 default:
1102 1102 cmn_err(CE_WARN, "hermon_fm_ereport: Unknown error. "
1103 1103 "type = %d, detail = %d\n.", type, detail);
1104 1104 }
1105 1105 break;
1106 1106
1107 1107 default:
1108 1108 cmn_err(CE_WARN, "hermon_fm_ereport: Unknown type "
1109 1109 "type = %d, detail = %d\n.", type, detail);
1110 1110 break;
1111 1111 }
1112 1112 }
1113 1113
1114 1114
1115 1115 /*
1116 1116 * uchar_t
1117 1117 * hermon_devacc_attr_version(hermon_state_t *)
1118 1118 *
1119 1119 * Overview
1120 1120 * hermon_devacc_attr_version() returns the ddi device attribute
1121 1121 * version.
1122 1122 *
1123 1123 * Argument
1124 1124 * state: pointer to Hermon state structure
1125 1125 *
1126 1126 * Return value
1127 1127 * dev_acc_attr_version value
1128 1128 * DDI_DEVICE_ATTR_V0 Hermon FM disabled
1129 1129 * DDI_DEVICE_ATTR_V1 Hermon FM enabled
1130 1130 *
1131 1131 * Caller's context
1132 1132 * hermon_devacc_attr_version() can be called in user, kernel, interrupt
1133 1133 * context or high interrupt context.
1134 1134 */
1135 1135 ushort_t
1136 1136 hermon_devacc_attr_version(hermon_state_t *state)
1137 1137 {
1138 1138 if (state->hs_fm_disable) {
1139 1139 return (DDI_DEVICE_ATTR_V0);
1140 1140 } else {
1141 1141 return (DDI_DEVICE_ATTR_V1);
1142 1142 }
1143 1143 }
1144 1144
1145 1145
1146 1146 /*
1147 1147 * uchar_t
1148 1148 * hermon_devacc_attr_access(hermon_state_t *)
1149 1149 *
1150 1150 * Overview
1151 1151 * hermon_devacc_attr_access() returns devacc_attr_access error
1152 1152 * protection types.
1153 1153 *
1154 1154 * Argument
1155 1155 * state: pointer to Hermon state structure
1156 1156 *
1157 1157 * Return value
1158 1158 * dev_acc_attr_access error protection type
1159 1159 * DDI_DEFAULT_ACC Hermon FM disabled for PIO
1160 1160 * DDI_FLAGERR_ACC Hermon FM enabled for PIO
1161 1161 *
1162 1162 * Caller's context
1163 1163 * hermon_devacc_attr_access() can be called in user, kernel, interrupt
1164 1164 * context or high interrupt context.
1165 1165 */
1166 1166 uchar_t
1167 1167 hermon_devacc_attr_access(hermon_state_t *state)
1168 1168 {
1169 1169 if (state->hs_fm_disable) {
1170 1170 return (DDI_DEFAULT_ACC);
1171 1171 } else {
1172 1172 return (DDI_FLAGERR_ACC);
1173 1173 }
1174 1174 }
1175 1175
1176 1176
1177 1177 /*
1178 1178 * int
1179 1179 * hermon_PIO_start(hermon_state_t *state, ddi_acc_handle_t handle,
1180 1180 * hermon_test_t *tst)
1181 1181 *
1182 1182 * Overview
1183 1183 * hermon_PIO_start() should be called before Hermon driver issues PIOs
1184 1184 * against I/O space. If Hermon FM is disabled, this function returns
1185 1185 * HCA_PIO_OK always. See i_hca_pio_start() in detail.
1186 1186 *
1187 1187 * Argument
1188 1188 * state: pointer to Hermon state structure
1189 1189 * handle: pointer to ddi_acc_handle_t used for HCA FM
1190 1190 * tst: pointer to HCA FM function test structure. If the structure
1191 1191 * is not used, the NULL value must be passed instead.
1192 1192 *
1193 1193 * Return value
1194 1194 * error status showing whether or not this error can retry
1195 1195 * HCA_PIO_OK No HW errors
1196 1196 * HCA_PIO_TRANSIENT This error could be transient
1197 1197 * HCA_PIO_PERSISTENT This error is persistent
1198 1198 *
1199 1199 * Caller's context
1200 1200 * hermon_PIO_start() can be called in user, kernel or interrupt context.
1201 1201 */
1202 1202 int
1203 1203 hermon_PIO_start(hermon_state_t *state, ddi_acc_handle_t handle,
1204 1204 hermon_test_t *tst)
1205 1205 {
1206 1206 if (state->hs_fm_disable) {
1207 1207 return (HCA_PIO_OK);
1208 1208 } else {
1209 1209 struct i_hca_acc_handle *handlep =
1210 1210 i_hca_get_acc_handle(state->hs_fm_hca_fm, handle);
1211 1211 ASSERT(handlep != NULL);
1212 1212 return (i_hca_pio_start(state->hs_dip, handlep, tst));
1213 1213 }
1214 1214 }
1215 1215
1216 1216
1217 1217 /*
1218 1218 * int
1219 1219 * hermon_PIO_end(hermon_state_t *state, ddi_acc_handle_t handle, int *cnt,
1220 1220 * hermon_test_t *tst)
1221 1221 *
1222 1222 * Overview
1223 1223 * hermon_PIO_end() should be called after Hermon driver issues PIOs
1224 1224 * against I/O space. If Hermon FM is disabled, this function returns
1225 1225 * HCA_PIO_OK always. See i_hca_pio_end() in detail.
1226 1226 *
1227 1227 * Argument
1228 1228 * state: pointer to Hermon state structure
1229 1229 * handle: pointer to ddi_acc_handle_t used for HCA FM
1230 1230 * cnt: pointer to the counter variable which holds the nubmer of retry
1231 1231 * (HCA_PIO_RETRY_CNT) when a HW error is detected.
1232 1232 * tst: pointer to HCA FM function test structure. If the structure
1233 1233 * is not used, the NULL value must be passed instead.
1234 1234 *
1235 1235 * Return value
1236 1236 * error status showing whether or not this error can retry
1237 1237 * HCA_PIO_OK No HW errors
1238 1238 * HCA_PIO_TRANSIENT This error could be transient
1239 1239 * HCA_PIO_PERSISTENT This error is persistent
1240 1240 *
1241 1241 * Caller's context
1242 1242 * hermon_PIO_end() can be called in user, kernel or interrupt context.
1243 1243 */
1244 1244 int
1245 1245 hermon_PIO_end(hermon_state_t *state, ddi_acc_handle_t handle, int *cnt,
1246 1246 hermon_test_t *tst)
1247 1247 {
1248 1248 if (state->hs_fm_disable) {
1249 1249 return (HCA_PIO_OK);
1250 1250 } else {
1251 1251 struct i_hca_acc_handle *handlep =
1252 1252 i_hca_get_acc_handle(state->hs_fm_hca_fm, handle);
1253 1253 ASSERT(handlep != NULL);
1254 1254 return (i_hca_pio_end(state->hs_dip, handlep, cnt, tst));
1255 1255 }
1256 1256 }
1257 1257
1258 1258
1259 1259 /*
1260 1260 * ddi_acc_handle_t
1261 1261 * hermon_get_cmdhdl(hermon_state_t *state)
1262 1262 *
1263 1263 * Overview
1264 1264 * hermon_get_cmdhdl() returns either the fma-protected access handle or
1265 1265 * the regular ddi-access handle depending on the Hermon FM state for
1266 1266 * Hermon command I/O space.
1267 1267 *
1268 1268 * Argument
1269 1269 * state: pointer to Hermon state structure
1270 1270 *
1271 1271 * Return value
1272 1272 * the access handle for pio requests
1273 1273 *
1274 1274 * Caller's context
1275 1275 * hermon_get_cmdhdl() can be called in user, kernel, interrupt context
1276 1276 * or high interrupt context.
1277 1277 */
1278 1278 ddi_acc_handle_t
1279 1279 hermon_get_cmdhdl(hermon_state_t *state)
1280 1280 {
1281 1281 return (state->hs_fm_disable || hermon_get_state(state) & HCA_PIO_FM ?
1282 1282 state->hs_fm_cmdhdl : state->hs_reg_cmdhdl);
1283 1283 }
1284 1284
1285 1285
1286 1286 /*
1287 1287 * ddi_acc_handle_t
1288 1288 * hermon_get_uarhdl(hermon_state_t *state)
1289 1289 *
1290 1290 * Overview
1291 1291 * hermon_get_uarhdl() returns either the fma-protected access handle or
1292 1292 * the regular ddi-access handle depending on the Hermon FM state for
1293 1293 * Hermon UAR I/O space.
1294 1294 *
1295 1295 * Argument
1296 1296 * state: pointer to Hermon state structure
1297 1297 *
1298 1298 * Return value
1299 1299 * the access handle for pio requests
1300 1300 *
1301 1301 * Caller's context
1302 1302 * hermon_get_uarhdl() can be called in user, kernel, interrupt context
1303 1303 * or high interrupt context.
1304 1304 */
1305 1305 ddi_acc_handle_t
1306 1306 hermon_get_uarhdl(hermon_state_t *state)
1307 1307 {
1308 1308 return (state->hs_fm_disable || hermon_get_state(state) & HCA_PIO_FM ?
1309 1309 state->hs_fm_uarhdl : state->hs_reg_uarhdl);
1310 1310 }
1311 1311
1312 1312
1313 1313 /*
1314 1314 * ddi_acc_handle_t
1315 1315 * hermon_rsrc_alloc_uarhdl(hermon_state_t *state)
1316 1316 *
1317 1317 * Overview
1318 1318 * hermon_rsrc_alloc_uarhdl() returns either the fma-protected access
1319 1319 * handle or the regular ddi-access handle depending on the Hermon FM
1320 1320 * state for Hermon UAR I/O space as well as hermon_get_uarhdl(), but
1321 1321 * this function is dedicated to the UAR resource allocator.
1322 1322 *
1323 1323 * Argument
1324 1324 * state: pointer to Hermon state structure
1325 1325 *
1326 1326 * Return value
1327 1327 * the access handle for pio requests
1328 1328 *
1329 1329 * Caller's context
1330 1330 * hermon_rsrc_alloc_uarhdl() can be called in user, kernel, interrupt
1331 1331 * or high interrupt context.
1332 1332 */
1333 1333 ddi_acc_handle_t
1334 1334 hermon_rsrc_alloc_uarhdl(hermon_state_t *state)
1335 1335 {
1336 1336 return (state->hs_fm_disable || hermon_get_state(state) & HCA_ATTCH_FM ?
1337 1337 state->hs_fm_uarhdl : state->hs_reg_uarhdl);
1338 1338 }
1339 1339
1340 1340 /*
1341 1341 * ddi_acc_handle_t
1342 1342 * hermon_get_pcihdl(hermon_state_t *state)
1343 1343 *
1344 1344 * Overview
1345 1345 * hermon_get_pcihdl() returns either the fma-protected access
1346 1346 * handle or the regular ddi-access handle to access the PCI config
1347 1347 * space. Whether or not which handle is returned at the moment depends
1348 1348 * on the Hermon FM state.
1349 1349 *
1350 1350 * Argument
1351 1351 * state: pointer to Hermon state structure
1352 1352 *
1353 1353 * Return value
1354 1354 * the access handle to PCI config space
1355 1355 *
1356 1356 * Caller's context
1357 1357 * hermon_get_pcihdl() can be called in user, kernel, interrupt
1358 1358 * or high interrupt context.
1359 1359 */
1360 1360 ddi_acc_handle_t
1361 1361 hermon_get_pcihdl(hermon_state_t *state)
1362 1362 {
1363 1363 return (state->hs_fm_disable || hermon_get_state(state) & HCA_ATTCH_FM ?
1364 1364 state->hs_fm_pcihdl : state->hs_reg_pcihdl);
1365 1365 }
1366 1366
1367 1367
1368 1368 /*
1369 1369 * ddi_acc_handle_t
1370 1370 * hermon_get_msix_tblhdl(hermon_state_t *state)
1371 1371 *
1372 1372 * Overview
1373 1373 * hermon_get_msix_tblhdl() returns either the fma-protected access
1374 1374 * handle or the regular ddi-access handle to access the MSI-X tables.
1375 1375 * Whether or not which handle is returned at the moment depends on
1376 1376 * the Hermon FM state.
1377 1377 *
1378 1378 * Argument
1379 1379 * state: pointer to Hermon state structure
1380 1380 *
1381 1381 * Return value
1382 1382 * the access handle to MSI-X tables
1383 1383 *
1384 1384 * Caller's context
1385 1385 * hermon_get_msix_tblhdl() can be called in user, kernel, interrupt
1386 1386 * context or high interrupt context.
1387 1387 */
1388 1388 ddi_acc_handle_t
1389 1389 hermon_get_msix_tblhdl(hermon_state_t *state)
1390 1390 {
1391 1391 return (state->hs_fm_disable || hermon_get_state(state) & HCA_ATTCH_FM ?
1392 1392 state->hs_fm_msix_tblhdl : state->hs_reg_msix_tblhdl);
1393 1393 }
1394 1394
1395 1395
1396 1396 /*
1397 1397 * ddi_acc_handle_t
1398 1398 * hermon_get_msix_pbahdl(hermon_state_t *state)
1399 1399 *
1400 1400 * Overview
1401 1401 * hermon_get_msix_pbahdl() returns either the fma-protected access
1402 1402 * handle or the regular ddi-access handle to access the MSI-X PBA.
1403 1403 * Whether or not which handle is returned at the moment depends on
1404 1404 * the Hermon FM state.
1405 1405 *
1406 1406 * Argument
1407 1407 * state: pointer to Hermon state structure
1408 1408 *
1409 1409 * Return value
1410 1410 * the access handle to MSI-X PBA
1411 1411 *
1412 1412 * Caller's context
1413 1413 * hermon_get_msix_pbahdl() can be called in user, kernel, interrupt
1414 1414 * context or high interrupt context.
1415 1415 */
1416 1416 ddi_acc_handle_t
1417 1417 hermon_get_msix_pbahdl(hermon_state_t *state)
1418 1418 {
1419 1419 return (state->hs_fm_disable || hermon_get_state(state) & HCA_ATTCH_FM ?
1420 1420 state->hs_fm_msix_pbahdl : state->hs_reg_msix_pbahdl);
1421 1421 }
1422 1422
1423 1423
1424 1424 /*
1425 1425 * void
1426 1426 * hermon_inter_err_chk(void *arg)
1427 1427 *
1428 1428 * Overview
1429 1429 * hermon_inter_err_chk() periodically checks the internal error buffer
1430 1430 * to pick up a Hermon asynchronous internal error.
1431 1431 *
1432 1432 * Note that this internal error can be notified if the interrupt is
1433 1433 * registered, but even so there are some cases that an interrupt against
1434 1434 * it cannot be raised so that Hermon RPM recommeds to poll this internal
1435 1435 * error buffer periodically instead. This function is invoked at
1436 1436 * 10ms interval in kernel context though the function itself can be
1437 1437 * called in interrupt context.
1438 1438 *
1439 1439 * Argument
1440 1440 * arg: pointer to Hermon state structure
1441 1441 *
1442 1442 * Return value
1443 1443 * Nothing
1444 1444 *
1445 1445 * Caller's context
1446 1446 * hermon_inter_err_chk() can be called in user, kernel, interrupt
1447 1447 * context or high interrupt context.
1448 1448 *
1449 1449 */
1450 1450 void
1451 1451 hermon_inter_err_chk(void *arg)
1452 1452 {
1453 1453 uint32_t word;
1454 1454 ddi_acc_handle_t cmdhdl;
1455 1455 hermon_state_t *state = (hermon_state_t *)arg;
1456 1456
1457 1457 /* initialize the FMA retry loop */
1458 1458 hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
1459 1459
1460 1460 #ifdef FMA_TEST
1461 1461 if (hermon_test_num != 0) {
1462 1462 return;
1463 1463 }
1464 1464 #endif
1465 1465 if (state->hs_fm_poll_suspend) {
1466 1466 return;
1467 1467 }
1468 1468
1469 1469 /* Get the access handle for Hermon CMD I/O space */
1470 1470 cmdhdl = hermon_get_cmdhdl(state);
1471 1471
1472 1472 /* the FMA retry loop starts. */
1473 1473 hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
1474 1474 fm_test);
1475 1475
1476 1476 word = ddi_get32(cmdhdl, state->hs_cmd_regs.fw_err_buf);
1477 1477
1478 1478 /* the FMA retry loop ends. */
1479 1479 hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
1480 1480 fm_test);
1481 1481
1482 1482 if (word != 0) {
1483 1483 HERMON_FMANOTE(state, HERMON_FMA_INTERNAL);
1484 1484 /* if fm_disable is on, Hermon FM functions don't work */
1485 1485 if (state->hs_fm_disable) {
1486 1486 cmn_err(CE_PANIC,
1487 1487 "Hermon Fatal Internal Error. "
1488 1488 "Hermon state=0x%p", (void *)state);
1489 1489 } else {
1490 1490 hermon_fm_ereport(state, HCA_IBA_ERR, HCA_ERR_FATAL);
1491 1491 }
1492 1492 }
1493 1493
1494 1494 /* issue the ereport pended in the interrupt context */
1495 1495 if (state->hs_fm_async_errcnt > 0) {
1496 1496 hermon_fm_ereport(state, HCA_IBA_ERR, HCA_ERR_FATAL);
1497 1497 atomic_dec_32(&state->hs_fm_async_errcnt);
1498 1498 }
1499 1499
1500 1500 return;
1501 1501
1502 1502 pio_error:
1503 1503 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_FATAL);
1504 1504 }
1505 1505
1506 1506
1507 1507 /*
1508 1508 * boolean_t
1509 1509 * hermon_cmd_retry_ok(hermon_cmd_post_t *cmd, int status)
1510 1510 *
1511 1511 * Overview
1512 1512 * In the case that a HW error is detected, if it can be isolated
1513 1513 * enough, Hermon FM retries the operation which caused the error.
1514 1514 * However, this retry can induce another error; since the retry is
1515 1515 * achieved as a block basis, not a statement basis, once the state
1516 1516 * was set inside the Hermon HW already in the previous operation, the
1517 1517 * retry can cause for example, a CMD_BAD_SYS_STATE error, as a result.
1518 1518 * In this case, CMD_BAD_SYS_STATE should be taken as a side effect
1519 1519 * but a harmless result. hermon_cmd_retry_ok() checks this kind of
1520 1520 * situation then returns if the state Hermon CMD returns is OK or not.
1521 1521 *
1522 1522 * Argument
1523 1523 * cmd: pointer to hermon_cmd_post_t structure
1524 1524 * status: Hermon CMD status
1525 1525 *
1526 1526 * Return value
1527 1527 * B_TRUE this state is no problem
1528 1528 * B_FALSE this state should be taken as an error
1529 1529 *
1530 1530 * Caller's context
1531 1531 * hermon_cmd_retry_ok() can be called in user, kernel, interrupt
1532 1532 * context or high interrupt context.
1533 1533 *
1534 1534 * Note that status except for HERMON_CMD_SUCCESS shouldn't be accepted
1535 1535 * in the debug module to catch a hidden software bug, so that ASSERT()
1536 1536 * is enabled in the case.
1537 1537 */
1538 1538 boolean_t
1539 1539 hermon_cmd_retry_ok(hermon_cmd_post_t *cmd, int status)
1540 1540 {
1541 1541 if (status == HERMON_CMD_SUCCESS)
1542 1542 return (B_TRUE);
1543 1543
1544 1544 /*
1545 1545 * The wrong status such as HERMON_CMD_BAD_SYS_STATE or
1546 1546 * HERMON_CMD_BAD_RES_STATE can return as a side effect
1547 1547 * because of the Hermon FM operation retry when a PIO
1548 1548 * error is detected during the I/O transaction. In the
1549 1549 * case, the driver may set the same value in Hermon
1550 1550 * though it was set already, then Hermon returns HERMON_
1551 1551 * CMD_BAD_{RES,SYS}_STATE as a result, which should be
1552 1552 * taken as OK.
1553 1553 */
1554 1554 switch (cmd->cp_opcode) {
1555 1555 case INIT_HCA:
1556 1556 /*
1557 1557 * HERMON_CMD_BAD_SYS_STATE can be gotten in case of
1558 1558 * ICM not mapped or HCA already initialized.
1559 1559 */
1560 1560 if (status == HERMON_CMD_BAD_SYS_STATE)
1561 1561 return (B_TRUE);
1562 1562 return (B_FALSE);
1563 1563
1564 1564 case CLOSE_HCA:
1565 1565 /*
1566 1566 * HERMON_CMD_BAD_SYS_STATE can be gotten in case of Firmware
1567 1567 * area is not mapped or HCA already closed.
1568 1568 */
1569 1569 if (status == HERMON_CMD_BAD_SYS_STATE)
1570 1570 return (B_TRUE);
1571 1571 return (B_FALSE);
1572 1572
1573 1573 case CLOSE_PORT:
1574 1574 /*
1575 1575 * HERMON_CMD_BAD_SYS_STATE can be gotten in case of HCA not
1576 1576 * initialized or in case that IB ports are already down.
1577 1577 */
1578 1578 if (status == HERMON_CMD_BAD_SYS_STATE)
1579 1579 return (B_TRUE);
1580 1580 return (B_FALSE);
1581 1581
1582 1582 case SW2HW_MPT:
1583 1583 /*
1584 1584 * HERMON_CMD_BAD_RES_STATE can be gotten in case of MPT
1585 1585 * entry already in hardware ownership.
1586 1586 */
1587 1587 if (status == HERMON_CMD_BAD_RES_STATE)
1588 1588 return (B_TRUE);
1589 1589 return (B_FALSE);
1590 1590
1591 1591 case HW2SW_MPT:
1592 1592 /*
1593 1593 * HERMON_CMD_BAD_RES_STATE can be gotten in case of MPT
1594 1594 * entry already in software ownership.
1595 1595 */
1596 1596 if (status == HERMON_CMD_BAD_RES_STATE)
1597 1597 return (B_TRUE);
1598 1598 return (B_FALSE);
1599 1599
1600 1600 case SW2HW_EQ:
1601 1601 /*
1602 1602 * HERMON_CMD_BAD_RES_STATE can be gotten in case of EQ
1603 1603 * entry already in hardware ownership.
1604 1604 */
1605 1605 if (status == HERMON_CMD_BAD_RES_STATE)
1606 1606 return (B_TRUE);
1607 1607 return (B_FALSE);
1608 1608
1609 1609 case HW2SW_EQ:
1610 1610 /*
1611 1611 * HERMON_CMD_BAD_RES_STATE can be gotten in case of EQ
1612 1612 * entry already in software ownership.
1613 1613 */
1614 1614 if (status == HERMON_CMD_BAD_RES_STATE)
1615 1615 return (B_TRUE);
1616 1616 return (B_FALSE);
1617 1617
1618 1618 case SW2HW_CQ:
1619 1619 /*
1620 1620 * HERMON_CMD_BAD_RES_STATE can be gotten in case of CQ
1621 1621 * entry already in hardware ownership.
1622 1622 */
1623 1623 if (status == HERMON_CMD_BAD_RES_STATE)
1624 1624 return (B_TRUE);
1625 1625 return (B_FALSE);
1626 1626
1627 1627 case HW2SW_CQ:
1628 1628 /*
1629 1629 * HERMON_CMD_BAD_RES_STATE can be gotten in case of CQ
1630 1630 * entry already in software ownership.
1631 1631 */
1632 1632 if (status == HERMON_CMD_BAD_RES_STATE)
1633 1633 return (B_TRUE);
1634 1634 return (B_FALSE);
1635 1635
1636 1636 case SW2HW_SRQ:
1637 1637 /*
1638 1638 * HERMON_CMD_BAD_RES_STATE can be gotten in case of SRQ
1639 1639 * entry already in hardware ownership.
1640 1640 */
1641 1641 if (status == HERMON_CMD_BAD_RES_STATE)
1642 1642 return (B_TRUE);
1643 1643 return (B_FALSE);
1644 1644
1645 1645 case HW2SW_SRQ:
1646 1646 /*
1647 1647 * HERMON_CMD_BAD_RES_STATE can be gotten in case of SRQ
1648 1648 * entry already in software ownership.
1649 1649 */
1650 1650 if (status == HERMON_CMD_BAD_RES_STATE)
1651 1651 return (B_TRUE);
1652 1652 return (B_FALSE);
1653 1653 default:
1654 1654 break;
1655 1655 }
1656 1656
1657 1657 /* other cases */
1658 1658 return (B_FALSE);
1659 1659 }
1660 1660
1661 1661
1662 1662 #ifdef FMA_TEST
1663 1663
1664 1664 /*
1665 1665 * Hermon FMA test variables
1666 1666 */
1667 1667 #define FMA_TEST_HASHSZ 64
1668 1668 int hermon_test_num; /* predefined testset */
1669 1669
1670 1670 static struct i_hca_fm_test *i_hca_test_register(char *, int, int,
1671 1671 void (*)(struct i_hca_fm_test *, ddi_fm_error_t *),
1672 1672 void *, mod_hash_t *, mod_hash_t *, int);
1673 1673 static void i_hca_test_free_item(mod_hash_val_t);
1674 1674 static void i_hca_test_set_item(int, struct i_hca_fm_test *);
1675 1675 static void hermon_trigger_pio_error(hermon_test_t *, ddi_fm_error_t *);
1676 1676
1677 1677 /*
1678 1678 * Hermon FMA Function Test Interface
1679 1679 */
1680 1680
1681 1681 /* Attach Errors */
1682 1682
1683 1683 #define ATTACH_TS (HCA_TEST_TRANSIENT | HCA_TEST_ATTACH | HCA_TEST_START)
1684 1684 #define ATTACH_TE (HCA_TEST_TRANSIENT | HCA_TEST_ATTACH | HCA_TEST_END)
1685 1685
1686 1686 #define ATTACH_PS (HCA_TEST_PERSISTENT | HCA_TEST_ATTACH | HCA_TEST_START)
1687 1687 #define ATTACH_PE (HCA_TEST_PERSISTENT | HCA_TEST_ATTACH | HCA_TEST_END)
1688 1688
1689 1689 static hermon_test_t testset[] = {
1690 1690 /* Initial Value */
1691 1691 {0, 0, 0, NULL, 0, 0, NULL, NULL, NULL}, /* 0 */
1692 1692
1693 1693 /* PIO Transient Errors */
1694 1694 {0, HCA_TEST_PIO, ATTACH_TS, NULL, /* attach/transient/start/propagate */
1695 1695 HCA_PIO_RETRY_CNT, 0, NULL, NULL, NULL}, /* 1 */
1696 1696 {0, HCA_TEST_PIO, ATTACH_TE, NULL, /* attach/transient/end/propagate */
1697 1697 HCA_PIO_RETRY_CNT, 0, NULL, NULL, NULL}, /* 2 */
1698 1698
1699 1699 /* PIO Persistent Errors */
1700 1700 {0, HCA_TEST_PIO, ATTACH_PS, NULL, /* attach/persistent/start/propagate */
1701 1701 0, 0, NULL, NULL, NULL}, /* 3 */
1702 1702 {0, HCA_TEST_PIO, ATTACH_PE, NULL, /* attach/persistent/end/propagate */
1703 1703 0, 0, NULL, NULL, NULL}, /* 4 */
1704 1704
1705 1705 };
1706 1706
1707 1707
1708 1708 /*
1709 1709 * void
1710 1710 * hermon_trigger_pio_error(hermon_test_t *tst, ddi_fm_error_t *derr)
1711 1711 *
1712 1712 * Overview
1713 1713 * hermon_trigger_pio_error() is a PIO error injection function
1714 1714 * to cause a pseduo PIO error.
1715 1715 *
1716 1716 * Argument
1717 1717 * tst: pointer to HCA FM function test structure. If the structure
1718 1718 * is not used, the NULL value must be passed instead.
1719 1719 * derr: pointer to ddi_fm_error_t structure
1720 1720 *
1721 1721 * Return value
1722 1722 * Nothing
1723 1723 *
1724 1724 * Caller's context
1725 1725 * hermon_trigger_pio_error() can be called in user, kernel, interrupt
1726 1726 * context or high interrupt context.
1727 1727 */
1728 1728 static void
1729 1729 hermon_trigger_pio_error(hermon_test_t *tst, ddi_fm_error_t *derr)
1730 1730 {
1731 1731 hermon_state_t *state = (hermon_state_t *)tst->private;
1732 1732 derr->fme_status = DDI_FM_OK;
1733 1733
1734 1734 if (tst->type != HCA_TEST_PIO) {
1735 1735 return;
1736 1736 }
1737 1737
1738 1738 if ((tst->trigger & HCA_TEST_ATTACH &&
1739 1739 i_ddi_node_state(state->hs_dip) < DS_ATTACHED &&
1740 1740 hermon_get_state(state) & HCA_PIO_FM)) {
1741 1741 if (tst->trigger & HCA_TEST_PERSISTENT) {
1742 1742 i_hca_fm_ereport(state->hs_dip, HCA_IBA_ERR,
1743 1743 DDI_FM_DEVICE_INVAL_STATE);
1744 1744 derr->fme_status = DDI_FM_NONFATAL;
1745 1745 return;
1746 1746 } else if (tst->trigger & HCA_TEST_TRANSIENT &&
1747 1747 tst->errcnt) {
1748 1748 i_hca_fm_ereport(state->hs_dip, HCA_IBA_ERR,
1749 1749 DDI_FM_DEVICE_INVAL_STATE);
1750 1750 derr->fme_status = DDI_FM_NONFATAL;
1751 1751 tst->errcnt--;
1752 1752 return;
1753 1753 }
1754 1754 }
1755 1755 }
1756 1756
1757 1757
1758 1758 /*
1759 1759 * struct hermon_fm_test *
1760 1760 * hermon_test_register(hermon_state_t *state, char *filename, int linenum,
1761 1761 * int type)
1762 1762 *
1763 1763 * Overview
1764 1764 * hermon_test_register() registers a Hermon FM test item for the
1765 1765 * function test.
1766 1766 *
1767 1767 * Argument
1768 1768 * state: pointer to Hermon state structure
1769 1769 * filename: source file name where the function call is implemented
1770 1770 * This value is usually a __FILE__ pre-defined macro.
1771 1771 * linenum: line number where the function call is described in the
1772 1772 * file specified above.
1773 1773 * This value is usually a __LINE__ pre-defined macro.
1774 1774 * type: HW error type
1775 1775 * HCA_TEST_PIO pio error
1776 1776 * HCA_TEST_IBA ib specific error
1777 1777 *
1778 1778 * Return value
1779 1779 * pointer to Hermon FM function test structure registered.
1780 1780 *
1781 1781 * Caller's context
1782 1782 * hermon_test_register() can be called in user, kernel or interrupt
1783 1783 * context.
1784 1784 *
1785 1785 * Note that no test item is registered if Hermon FM is disabled.
1786 1786 */
1787 1787 hermon_test_t *
1788 1788 hermon_test_register(hermon_state_t *state, char *filename, int linenum,
1789 1789 int type)
1790 1790 {
1791 1791 void (*pio_injection)(struct i_hca_fm_test *, ddi_fm_error_t *) =
1792 1792 (void (*)(struct i_hca_fm_test *, ddi_fm_error_t *))
1793 1793 hermon_trigger_pio_error;
1794 1794
1795 1795 if (state->hs_fm_disable)
1796 1796 return (NULL);
1797 1797
1798 1798 return ((hermon_test_t *)i_hca_test_register(filename, linenum, type,
1799 1799 pio_injection, (void *)state, state->hs_fm_test_hash,
1800 1800 state->hs_fm_id_hash, hermon_test_num));
1801 1801 }
1802 1802 #endif /* FMA_TEST */
1803 1803
1804 1804
1805 1805 /*
1806 1806 * HCA FM Common Interface
1807 1807 *
1808 1808 * These functions should be used for any HCA drivers, but probably
1809 1809 * customized for their own HW design and/or FM implementation.
1810 1810 * Customized functins should have the driver name prefix such as
1811 1811 * hermon_xxxx() and be defined separately but whose functions should
1812 1812 * call the common interface inside.
1813 1813 */
1814 1814
1815 1815 /*
1816 1816 * void
1817 1817 * i_hca_fm_init(struct i_hca_fm *hca_fm)
1818 1818 *
1819 1819 * Overview
1820 1820 * i_hca_fm_init() is an initialization function which sets up the acc
1821 1821 * handle kmem_cache if this function is called the first time.
1822 1822 *
1823 1823 * Argument
1824 1824 * hca_fm: pointer to HCA FM structure
1825 1825 *
1826 1826 * Return value
1827 1827 * Nothing
1828 1828 *
1829 1829 * Caller's context
1830 1830 * i_hca_fm_init() can be called in user or kernel context, but cannot
1831 1831 * be called in interrupt context.
1832 1832 */
1833 1833 static void
1834 1834 i_hca_fm_init(struct i_hca_fm *hca_fm)
1835 1835 {
1836 1836
1837 1837 mutex_enter(&hca_fm->lock);
1838 1838
1839 1839 ++hca_fm->ref_cnt;
1840 1840 if (hca_fm->fm_acc_cache == NULL) {
1841 1841 hca_fm->fm_acc_cache = kmem_cache_create("hca_fm_acc_handle",
1842 1842 sizeof (struct i_hca_acc_handle), 0, NULL,
1843 1843 NULL, NULL, NULL, NULL, 0);
1844 1844 }
1845 1845
1846 1846 mutex_exit(&hca_fm->lock);
1847 1847 }
1848 1848
1849 1849
1850 1850 /*
1851 1851 * void
1852 1852 * i_hca_fm_fini(struct i_hca_fm *hca_fm)
1853 1853 *
1854 1854 * Overview
1855 1855 * i_hca_fm_fini() is a finalization function which frees up the acc
1856 1856 * handle kmem_cache if this function is called the last time.
1857 1857 *
1858 1858 * Argument
1859 1859 * hca_fm: pointer to HCA FM structure
1860 1860 *
1861 1861 * Return value
1862 1862 * Nothing
1863 1863 *
1864 1864 * Caller's context
1865 1865 * i_hca_fm_fini() can be called in user or kernel context, but cannot
1866 1866 * be called in interrupt context.
1867 1867 */
1868 1868 static void
1869 1869 i_hca_fm_fini(struct i_hca_fm *hca_fm)
1870 1870 {
1871 1871 mutex_enter(&hca_fm->lock);
1872 1872
1873 1873 if (--hca_fm->ref_cnt == 0) {
1874 1874
1875 1875 if (hca_fm->fm_acc_cache) {
1876 1876 kmem_cache_destroy(hca_fm->fm_acc_cache);
1877 1877 hca_fm->fm_acc_cache = NULL;
1878 1878 }
1879 1879 }
1880 1880
1881 1881 mutex_exit(&hca_fm->lock);
1882 1882 }
1883 1883
1884 1884
1885 1885 /*
1886 1886 * void
1887 1887 * i_hca_fm_ereport(dev_info_t *dip, int type, char *detail)
1888 1888 *
1889 1889 * Overview
1890 1890 * i_hca_fm_ereport() is a wrapper function of ddi_fm_ereport_post() but
1891 1891 * generates an ena before it calls ddi_fm_ereport_post() for HCA
1892 1892 * specific HW errors.
1893 1893 *
1894 1894 * Argument
1895 1895 * dip: pointer to this device dev_info structure
1896 1896 * type: error type
1897 1897 * HCA_SYS_ERR FMA reporting HW error
1898 1898 * HCA_IBA_ERR HCA specific HW error
1899 1899 * detail: definition of leaf driver detected ereports which is one of:
1900 1900 * DDI_FM_DEVICE_INVAL_STATE
1901 1901 * DDI_FM_DEVICE_NO_RESPONSE
1902 1902 * DDI_FM_DEVICE_STALL
1903 1903 * DDI_FM_DEVICE_BADINT_LIMIT
1904 1904 * DDI_FM_DEVICE_INTERN_CORR
1905 1905 * DDI_FM_DEVICE_INTERN_UNCORR
1906 1906 *
1907 1907 * Return value
1908 1908 * Nothing
1909 1909 *
1910 1910 * Caller's context
1911 1911 * i_hca_fm_ereport() can be called in user, kernel or interrupt context.
1912 1912 */
1913 1913 static void
1914 1914 i_hca_fm_ereport(dev_info_t *dip, int type, char *detail)
1915 1915 {
1916 1916 uint64_t ena;
1917 1917 char buf[FM_MAX_CLASS];
1918 1918
1919 1919 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
1920 1920
1921 1921 ena = fm_ena_generate(0, FM_ENA_FMT1);
1922 1922 if (type == HCA_IBA_ERR) {
1923 1923 /* this is an error of its own */
1924 1924 ena = fm_ena_increment(ena);
1925 1925 }
1926 1926
1927 1927 ddi_fm_ereport_post(dip, buf, ena, DDI_NOSLEEP,
1928 1928 FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL);
1929 1929 }
1930 1930
1931 1931
1932 1932 /*
1933 1933 * struct i_hca_acc_handle *
1934 1934 * i_hca_get_acc_handle(struct i_hca_fm *hca_fm, ddi_acc_handle_t handle)
1935 1935 *
1936 1936 * Overview
1937 1937 * i_hca_get_acc_handle() returns ddi_acc_handle_t used for HCA FM.
1938 1938 *
1939 1939 * Argument
1940 1940 * hca_fm: pointer to HCA FM structure
1941 1941 * handle: ddi_acc_handle_t
1942 1942 *
1943 1943 * Return value
1944 1944 * handle: pointer to ddi_acc_handle_t used for HCA FM
1945 1945 *
1946 1946 * Caller's context
1947 1947 * i_hca_get_acc_handle() can be called in user, kernel or interrupt
1948 1948 * context.
1949 1949 */
1950 1950 static struct i_hca_acc_handle *
1951 1951 i_hca_get_acc_handle(struct i_hca_fm *hca_fm, ddi_acc_handle_t handle)
1952 1952 {
1953 1953 struct i_hca_acc_handle *hdlp;
1954 1954
1955 1955 /* Retrieve the HCA FM access handle */
1956 1956 mutex_enter(&hca_fm->lock);
1957 1957
1958 1958 for (hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) {
1959 1959 if (hdlp->save_hdl == handle) {
1960 1960 mutex_exit(&hca_fm->lock);
1961 1961 return (hdlp);
1962 1962 }
1963 1963 }
1964 1964
1965 1965 mutex_exit(&hca_fm->lock);
1966 1966 return (hdlp);
1967 1967 }
1968 1968
1969 1969
1970 1970 /*
1971 1971 * int
1972 1972 * i_hca_regs_map_setup(struct i_hca_fm *hca_fm, dev_info_t *dip,
1973 1973 * uint_t rnumber, caddr_t *addrp, offset_t offset, offset_t len,
1974 1974 * ddi_device_acc_attr_t *accattrp, ddi_acc_handle_t *handle)
1975 1975 *
1976 1976 * Overview
1977 1977 * i_hca_regs_map_setup() is a wrapper function of ddi_regs_map_setup(),
1978 1978 * but allocates the HCA FM acc handle structure and initializes it.
1979 1979 *
1980 1980 * Argument
1981 1981 * hca_fm: pointer to HCA FM structure
1982 1982 * dip: pointer to this device dev_info structure
1983 1983 * rnumber: index number to the register address space set
1984 1984 * addrp: platform-dependent value (same as ddi_regs_map_setup())
1985 1985 * offset: offset into the register address space
1986 1986 * len: address space length to be mapped
1987 1987 * accattrp: pointer to device access attribute structure
1988 1988 * handle: pointer to ddi_acc_handle_t used for HCA FM
1989 1989 *
1990 1990 * Return value
1991 1991 * ddi function status value which are:
1992 1992 * DDI_SUCCESS
1993 1993 * DDI_FAILURE
1994 1994 * DDI_ME_RNUMBER_RNGE
1995 1995 * DDI_REGS_ACC_CONFLICT
1996 1996 *
1997 1997 * Caller's context
1998 1998 * i_hca_regs_map_setup() can be called in user or kernel context only.
1999 1999 */
2000 2000 static int
2001 2001 i_hca_regs_map_setup(struct i_hca_fm *hca_fm, dev_info_t *dip, uint_t rnumber,
2002 2002 caddr_t *addrp, offset_t offset, offset_t len,
2003 2003 ddi_device_acc_attr_t *accattrp, ddi_acc_handle_t *handle)
2004 2004 {
2005 2005 int status;
2006 2006 struct i_hca_acc_handle *handlep, *hdlp, *last;
2007 2007
↓ open down ↓ |
2007 lines elided |
↑ open up ↑ |
2008 2008 /* Allocate an access handle */
2009 2009 if ((status = ddi_regs_map_setup(dip, rnumber, addrp, offset,
2010 2010 len, accattrp, handle)) != DDI_SUCCESS) {
2011 2011 return (status);
2012 2012 }
2013 2013
2014 2014 /* Allocate HCA FM acc handle structure */
2015 2015 handlep = kmem_cache_alloc(hca_fm->fm_acc_cache, KM_SLEEP);
2016 2016
2017 2017 /* Initialize fields */
2018 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*handlep))
2019 2018 handlep->next = NULL;
2020 2019 handlep->save_hdl = (*handle);
2021 2020 handlep->thread_cnt = 0;
2022 2021 mutex_init(&handlep->lock, NULL, MUTEX_DRIVER, NULL);
2023 2022
2024 2023 /* Register this handle */
2025 2024 mutex_enter(&hca_fm->lock);
2026 2025 for (last = hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) {
2027 2026 last = hdlp;
2028 2027 }
2029 2028 if (last == NULL) {
2030 2029 hca_fm->hdl = handlep;
2031 2030 } else {
2032 2031 last->next = handlep;
2033 2032 }
2034 2033 mutex_exit(&hca_fm->lock);
2035 2034
2036 2035 return (status);
2037 2036 }
2038 2037
2039 2038
2040 2039 /*
2041 2040 * void
2042 2041 * i_hca_regs_map_free(struct i_hca_fm *hca_fm, ddi_acc_handle_t *handlep)
2043 2042 *
2044 2043 * Overview
2045 2044 * i_hca_regs_map_setup() is a wrapper function of ddi_regs_map_free(),
2046 2045 * and frees the HCA FM acc handle structure allocated by
2047 2046 * i_hca_regs_map_setup().
2048 2047 *
2049 2048 * Argument
2050 2049 * hca_fm: pointer to HCA FM structure
2051 2050 * handle: pointer to ddi_acc_handle_t used for HCA FM
2052 2051 *
2053 2052 * Return value
2054 2053 * Nothing
2055 2054 *
2056 2055 * Caller's context
2057 2056 * i_hca_regs_map_free() can be called in user or kernel context only.
2058 2057 *
2059 2058 * Note that the handle passed to i_hca_regs_map_free() is NULL-cleared
2060 2059 * after this function is called.
2061 2060 */
2062 2061 static void
2063 2062 i_hca_regs_map_free(struct i_hca_fm *hca_fm, ddi_acc_handle_t *handle)
2064 2063 {
2065 2064 struct i_hca_acc_handle *handlep, *hdlp, *prev;
2066 2065
2067 2066 /* De-register this handle */
2068 2067 mutex_enter(&hca_fm->lock);
2069 2068 for (prev = hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) {
2070 2069 if (hdlp->save_hdl == *handle)
2071 2070 break;
2072 2071 prev = hdlp;
2073 2072 }
2074 2073 ASSERT(prev != NULL && hdlp != NULL);
2075 2074 if (hdlp != prev) {
2076 2075 prev->next = hdlp->next;
2077 2076 } else {
2078 2077 hca_fm->hdl = hdlp->next;
2079 2078 }
2080 2079 handlep = hdlp;
2081 2080 mutex_exit(&hca_fm->lock);
2082 2081
2083 2082 mutex_destroy(&handlep->lock);
2084 2083 handlep->save_hdl = NULL;
2085 2084 kmem_cache_free(hca_fm->fm_acc_cache, handlep);
2086 2085
2087 2086 /* Release this handle */
2088 2087 ddi_regs_map_free(handle);
2089 2088 *handle = NULL;
2090 2089 }
2091 2090
2092 2091
2093 2092 /*
2094 2093 * int
2095 2094 * i_hca_pci_config_setup(struct i_hca_fm *hca_fm, dev_info_t *dip,
2096 2095 * ddi_acc_handle_t *handle, boolean_t fm_protect)
2097 2096 *
2098 2097 * Overview
2099 2098 * i_hca_pci_config_setup() is a wrapper function of pci_config_setup(),
2100 2099 * but allocates the HCA FM acc handle structure and initializes it.
2101 2100 *
2102 2101 * Argument
2103 2102 * hca_fm: pointer to HCA FM structure
2104 2103 * dip: pointer to this device dev_info structure
2105 2104 * handle: pointer to ddi_acc_handle_t used for HCA PCI config space
2106 2105 * with FMA
2107 2106 * fm_protect: flag to tell if an fma-protected access handle should
2108 2107 * be used
2109 2108 *
2110 2109 * Return value
2111 2110 * ddi function status value which are:
2112 2111 * DDI_SUCCESS
2113 2112 * DDI_FAILURE
2114 2113 *
2115 2114 * Caller's context
2116 2115 * i_hca_pci_config_setup() can be called in user or kernel context only.
2117 2116 */
2118 2117 static int
2119 2118 i_hca_pci_config_setup(struct i_hca_fm *hca_fm, dev_info_t *dip,
2120 2119 ddi_acc_handle_t *handle)
2121 2120 {
2122 2121 int status;
2123 2122 struct i_hca_acc_handle *handlep, *hdlp, *last;
↓ open down ↓ |
95 lines elided |
↑ open up ↑ |
2124 2123
2125 2124 /* Allocate an access handle */
2126 2125 if ((status = pci_config_setup(dip, handle)) != DDI_SUCCESS) {
2127 2126 return (status);
2128 2127 }
2129 2128
2130 2129 /* Allocate HCA FM acc handle structure */
2131 2130 handlep = kmem_cache_alloc(hca_fm->fm_acc_cache, KM_SLEEP);
2132 2131
2133 2132 /* Initialize fields */
2134 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*handlep))
2135 2133 handlep->next = NULL;
2136 2134 handlep->save_hdl = (*handle);
2137 2135 handlep->thread_cnt = 0;
2138 2136 mutex_init(&handlep->lock, NULL, MUTEX_DRIVER, NULL);
2139 2137
2140 2138 /* Register this handle */
2141 2139 mutex_enter(&hca_fm->lock);
2142 2140 for (last = hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) {
2143 2141 last = hdlp;
2144 2142 }
2145 2143 if (last == NULL) {
2146 2144 hca_fm->hdl = handlep;
2147 2145 } else {
2148 2146 last->next = handlep;
2149 2147 }
2150 2148 mutex_exit(&hca_fm->lock);
2151 2149
2152 2150 return (status);
2153 2151 }
2154 2152
2155 2153
2156 2154 /*
2157 2155 * void
2158 2156 * i_hca_pci_config_teardown(struct i_hca_fm *hca_fm,
2159 2157 * ddi_acc_handle_t *handlep)
2160 2158 *
2161 2159 * Overview
2162 2160 * i_hca_pci_config_teardown() is a wrapper function of
2163 2161 * pci_config_teardown(), and frees the HCA FM acc handle structure
2164 2162 * allocated by i_hca_pci_config_setup().
2165 2163 *
2166 2164 * Argument
2167 2165 * hca_fm: pointer to HCA FM structure
2168 2166 * handle: pointer to ddi_acc_handle_t used for HCA FM
2169 2167 *
2170 2168 * Return value
2171 2169 * Nothing
2172 2170 *
2173 2171 * Caller's context
2174 2172 * i_hca_pci_config_teardown() can be called in user or kernel context
2175 2173 * only.
2176 2174 *
2177 2175 * Note that the handle passed to i_hca_pci_config_teardown() is NULL-cleared
2178 2176 * after this function is called.
2179 2177 */
2180 2178 static void
2181 2179 i_hca_pci_config_teardown(struct i_hca_fm *hca_fm, ddi_acc_handle_t *handle)
2182 2180 {
2183 2181 struct i_hca_acc_handle *handlep, *hdlp, *prev;
2184 2182
2185 2183 /* De-register this handle */
2186 2184 mutex_enter(&hca_fm->lock);
2187 2185 for (prev = hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) {
2188 2186 if (hdlp->save_hdl == *handle)
2189 2187 break;
2190 2188 prev = hdlp;
2191 2189 }
2192 2190 ASSERT(prev != NULL && hdlp != NULL);
2193 2191 if (hdlp != prev) {
2194 2192 prev->next = hdlp->next;
2195 2193 } else {
2196 2194 hca_fm->hdl = hdlp->next;
2197 2195 }
2198 2196 handlep = hdlp;
2199 2197 mutex_exit(&hca_fm->lock);
2200 2198
2201 2199 mutex_destroy(&handlep->lock);
2202 2200 handlep->save_hdl = NULL;
2203 2201 kmem_cache_free(hca_fm->fm_acc_cache, handlep);
2204 2202
2205 2203 /* Release this handle */
2206 2204 pci_config_teardown(handle);
2207 2205 *handle = NULL;
2208 2206 }
2209 2207
2210 2208
2211 2209 /*
2212 2210 * int
2213 2211 * i_hca_pio_start(dev_info_t *dip, struct i_acc_handle *handle,
2214 2212 * struct i_hca_fm_test *tst)
2215 2213 *
2216 2214 * Overview
2217 2215 * i_hca_pio_start() is one of a pair of HCA FM fuctions for PIO, which
2218 2216 * should be called before HCA drivers issue PIOs against I/O space.
2219 2217 * See HCA FM comments at the beginning of this file in detail.
2220 2218 *
2221 2219 * Argument
2222 2220 * dip: pointer to this device dev_info structure
2223 2221 * handle: pointer to ddi_acc_handle_t used for HCA FM
2224 2222 * tst: pointer to HCA FM function test structure. If the structure
2225 2223 * is not used, the NULL value must be passed instead.
2226 2224 *
2227 2225 * Return value
2228 2226 * error status showing whether or not this error can retry
2229 2227 * HCA_PIO_OK No HW errors
2230 2228 * HCA_PIO_TRANSIENT This error could be transient
2231 2229 * HCA_PIO_PERSISTENT This error is persistent
2232 2230 *
2233 2231 * Caller's context
2234 2232 * i_hca_pio_start() can be called in user, kernel or interrupt context.
2235 2233 */
2236 2234 /* ARGSUSED */
2237 2235 static int
2238 2236 i_hca_pio_start(dev_info_t *dip, struct i_hca_acc_handle *hdlp,
2239 2237 struct i_hca_fm_test *tst)
2240 2238 {
2241 2239 ddi_fm_error_t derr;
2242 2240
2243 2241 /* Count up the number of threads issuing this PIO */
2244 2242 mutex_enter(&hdlp->lock);
2245 2243 hdlp->thread_cnt++;
2246 2244 mutex_exit(&hdlp->lock);
2247 2245
2248 2246 /* Get the PIO error via FMA */
2249 2247 ddi_fm_acc_err_get(fm_acc_hdl(hdlp), &derr, DDI_FME_VERSION);
2250 2248
2251 2249 #ifdef FMA_TEST
2252 2250 /* Trigger PIO errors */
2253 2251 if (tst != NULL && tst->trigger & HCA_TEST_START) {
2254 2252 (*tst->pio_injection)(tst, &derr);
2255 2253 }
2256 2254 #endif /* FMA_TEST */
2257 2255
2258 2256 switch (derr.fme_status) {
2259 2257 case DDI_FM_OK:
2260 2258 /* Not have to clear the fma error log */
2261 2259 return (HCA_PIO_OK);
2262 2260
2263 2261 case DDI_FM_NONFATAL:
2264 2262 /* Now clear this error */
2265 2263 ddi_fm_acc_err_clear(fm_acc_hdl(hdlp), DDI_FME_VERSION);
2266 2264
2267 2265 /* Log this error and notify it as a persistent error */
2268 2266 ddi_fm_service_impact(dip, DDI_SERVICE_LOST);
2269 2267 return (HCA_PIO_PERSISTENT);
2270 2268
2271 2269 /* In theory, this shouldn't happen */
2272 2270 case DDI_FM_FATAL:
2273 2271 case DDI_FM_UNKNOWN:
2274 2272 default:
2275 2273 cmn_err(CE_WARN, "Unknown HCA HW error status (%d)",
2276 2274 derr.fme_status);
2277 2275 /* Return this as a persistent error */
2278 2276 return (HCA_PIO_PERSISTENT);
2279 2277 }
2280 2278 }
2281 2279
2282 2280
2283 2281 /*
2284 2282 * int
2285 2283 * i_hca_pio_end(dev_info_t *dip, ddi_acc_handle_t handle, int *cnt,
2286 2284 * struct i_hca_fm_test *tst)
2287 2285 *
2288 2286 * Overview
2289 2287 * i_hca_pio_end() is the other of a pair of HCA FM fuctions for PIO,
2290 2288 * which should be called after HCA drivers issue PIOs against I/O space.
2291 2289 * See HCA FM comments at the beginning of this file in detail.
2292 2290 *
2293 2291 * Argument
2294 2292 * dip: pointer to this device dev_info structure
2295 2293 * handle: pointer to ddi_acc_handle_t used for HCA FM
2296 2294 * cnt: pointer to the counter variable which holds the nubmer of retry
2297 2295 * when a HW error is detected.
2298 2296 * tst: pointer to HCA FM function test structure. If the structure
2299 2297 * is not used, the NULL value must be passed instead.
2300 2298 *
2301 2299 * Return value
2302 2300 * error status showing whether or not this error can retry
2303 2301 * HCA_PIO_OK No HW errors
2304 2302 * HCA_PIO_TRANSIENT This error could be transient
2305 2303 * HCA_PIO_PERSISTENT This error is persistent
2306 2304 *
2307 2305 * Caller's context
2308 2306 * i_hca_pio_end() can be called in user, kernel or interrupt context.
2309 2307 */
2310 2308 /* ARGSUSED */
2311 2309 static int
2312 2310 i_hca_pio_end(dev_info_t *dip, struct i_hca_acc_handle *hdlp, int *cnt,
2313 2311 struct i_hca_fm_test *tst)
2314 2312 {
2315 2313 ddi_fm_error_t derr;
2316 2314
2317 2315 /* Get the PIO error via FMA */
2318 2316 ddi_fm_acc_err_get(fm_acc_hdl(hdlp), &derr, DDI_FME_VERSION);
2319 2317
2320 2318 #ifdef FMA_TEST
2321 2319 /* Trigger PIO errors */
2322 2320 if (tst != NULL && tst->trigger & HCA_TEST_END) {
2323 2321 (*tst->pio_injection)(tst, &derr);
2324 2322 }
2325 2323 #endif /* FMA_TEST */
2326 2324
2327 2325 /* Evaluate the PIO error */
2328 2326 switch (derr.fme_status) {
2329 2327 case DDI_FM_OK:
2330 2328 /* Count down the number of threads issuing this PIO */
2331 2329 mutex_enter(&hdlp->lock);
2332 2330 hdlp->thread_cnt--;
2333 2331 mutex_exit(&hdlp->lock);
2334 2332
2335 2333 /* Not have to clear the fma error log */
2336 2334 return (HCA_PIO_OK);
2337 2335
2338 2336 case DDI_FM_NONFATAL:
2339 2337 /* Now clear this error */
2340 2338 ddi_fm_acc_err_clear(fm_acc_hdl(hdlp), DDI_FME_VERSION);
2341 2339
2342 2340 /*
2343 2341 * Check if this error comes from another thread running
2344 2342 * with the same handle almost at the same time.
2345 2343 */
2346 2344 mutex_enter(&hdlp->lock);
2347 2345 if (hdlp->thread_cnt > 1) {
2348 2346 /* Count down the number of threads */
2349 2347 hdlp->thread_cnt--;
2350 2348 mutex_exit(&hdlp->lock);
2351 2349
2352 2350 /* Return this as a persistent error */
2353 2351 return (HCA_PIO_PERSISTENT);
2354 2352 }
2355 2353 mutex_exit(&hdlp->lock);
2356 2354
2357 2355 /* Now determine if this error is persistent or not */
2358 2356 if (--(*cnt) >= 0) {
2359 2357 return (HCA_PIO_TRANSIENT);
2360 2358 } else {
2361 2359 /* Count down the number of threads */
2362 2360 mutex_enter(&hdlp->lock);
2363 2361 hdlp->thread_cnt--;
2364 2362 mutex_exit(&hdlp->lock);
2365 2363 return (HCA_PIO_PERSISTENT);
2366 2364 }
2367 2365
2368 2366 /* In theory, this shouldn't happen */
2369 2367 case DDI_FM_FATAL:
2370 2368 case DDI_FM_UNKNOWN:
2371 2369 default:
2372 2370 cmn_err(CE_WARN, "Unknown HCA HW error status (%d)",
2373 2371 derr.fme_status);
2374 2372 /* Return this as a persistent error */
2375 2373 return (HCA_PIO_PERSISTENT);
2376 2374 }
2377 2375 }
2378 2376
2379 2377
2380 2378 /*
2381 2379 * HCA FM Test Interface
2382 2380 *
2383 2381 * These functions should be used for any HCA drivers, but probably
2384 2382 * customized for their own HW design and/or FM implementation.
2385 2383 * Customized functins should have the driver name prefix such as
2386 2384 * hermon_xxxx() and be defined separately but whose function should
2387 2385 * call the common interface inside.
2388 2386 */
2389 2387
2390 2388 #ifdef FMA_TEST
2391 2389 static int test_num; /* serial number */
2392 2390 static kmutex_t i_hca_test_lock; /* lock for serial numer */
2393 2391
2394 2392 /*
2395 2393 * void
2396 2394 * i_hca_test_init(mod_hash_t **strHashp, mod_hash_t **idHashp)
2397 2395 *
2398 2396 * Overview
2399 2397 * i_hca_test_init() creates two hash tables, one of which is for string,
2400 2398 * and the other of which is for ID, then saves pointers to arguments
2401 2399 * passed. This function uses the mod_hash utilities to manage the
2402 2400 * hash tables. About the mod_hash, see common/os/modhash.c.
2403 2401 *
2404 2402 * Argument
2405 2403 * strHashp: pointer to String hash table pointer
2406 2404 * idHashp: pointer to ID hash table pointer
2407 2405 *
2408 2406 * Return value
2409 2407 * Nothing
2410 2408 *
2411 2409 * Caller's context
2412 2410 * i_hca_test_init() can be called in user or kernel context only.
2413 2411 */
2414 2412 static void
2415 2413 i_hca_test_init(mod_hash_t **strHashp, mod_hash_t **idHashp)
2416 2414 {
2417 2415 *idHashp = mod_hash_create_idhash("HCA_FMA_id_hash",
2418 2416 FMA_TEST_HASHSZ, mod_hash_null_valdtor);
2419 2417
2420 2418 *strHashp = mod_hash_create_strhash("HCA_FMA_test_hash",
2421 2419 FMA_TEST_HASHSZ, i_hca_test_free_item);
2422 2420 }
2423 2421
2424 2422
2425 2423 /*
2426 2424 * void
2427 2425 * i_hca_test_fini(mod_hash_t **strHashp, mod_hash_t **idHashp)
2428 2426 *
2429 2427 * Overview
2430 2428 * i_hca_test_fini() releases two hash tables used for HCA FM test.
2431 2429 *
2432 2430 * Argument
2433 2431 * strHashp: pointer to String hash table pointer
2434 2432 * idHashp: pointer to ID hash table pointer
2435 2433 *
2436 2434 * Return value
2437 2435 * Nothing
2438 2436 *
2439 2437 * Caller's context
2440 2438 * i_hca_test_fini() can be called in user, kernel or interrupt context.
2441 2439 *
2442 2440 */
2443 2441 static void
2444 2442 i_hca_test_fini(mod_hash_t **strHashp, mod_hash_t **idHashp)
2445 2443 {
2446 2444 mod_hash_destroy_hash(*strHashp);
2447 2445 *strHashp = NULL;
2448 2446
2449 2447 mod_hash_destroy_hash(*idHashp);
2450 2448 *idHashp = NULL;
2451 2449 }
2452 2450
2453 2451
2454 2452 /*
2455 2453 * struct i_hca_fm_test *
2456 2454 * i_hca_test_register(char *filename, int linenum, int type,
2457 2455 * void (*pio_injection)(struct i_hca_fm_test *, ddi_fm_error_t *),
2458 2456 * void *private, mod_hash_t *strHash, mod_hash_t *idHash, int preTestNum)
2459 2457 *
2460 2458 * Overview
2461 2459 * i_hca_test_register() registers an HCA FM test item against HCA FM
2462 2460 * function callings specified with the file name and the line number
2463 2461 * (passed as the arguments).
2464 2462 *
2465 2463 * Argument
2466 2464 * filename: source file name where the function call is implemented
2467 2465 * This value is usually a __FILE__ pre-defined macro.
2468 2466 * linenum: line number where the function call is described in the
2469 2467 * file specified above.
2470 2468 * This value is usually a __LINE__ pre-defined macro.
2471 2469 * type: HW error type
2472 2470 * HCA_TEST_PIO pio error
2473 2471 * HCA_TEST_IBA ib specific error
2474 2472 * pio_injection: pio error injection callback function invoked when the
2475 2473 * function specified above (with the file name and the
2476 2474 * line number) is executed. If the function is not a PIO,
2477 2475 * request, this parameter should be NULL.
2478 2476 * private: the argument passed to either of injection functions when
2479 2477 * they're invoked.
2480 2478 * strHashp: pointer to String hash table
2481 2479 * idHashp: pointer to ID hash table
2482 2480 * preTestNum: the index of the pre-defined testset for this test item.
2483 2481 *
2484 2482 * Return value
2485 2483 * pointer to HCA FM function test structure registered.
2486 2484 *
2487 2485 * Caller's context
2488 2486 * i_hca_test_register() can be called in user, kernel or interrupt
2489 2487 * context.
2490 2488 *
2491 2489 */
2492 2490 static struct i_hca_fm_test *
2493 2491 i_hca_test_register(char *filename, int linenum, int type,
2494 2492 void (*pio_injection)(struct i_hca_fm_test *, ddi_fm_error_t *),
2495 2493 void *private, mod_hash_t *strHash, mod_hash_t *idHash, int preTestNum)
2496 2494 {
2497 2495 struct i_hca_fm_test *t_item;
2498 2496 char key_buf[255], *hash_key;
2499 2497 int status;
2500 2498
2501 2499 (void) sprintf(key_buf, "%s:%d", filename, linenum);
2502 2500 hash_key = kmem_zalloc(strlen(key_buf) + 1, KM_NOSLEEP);
2503 2501
2504 2502 if (hash_key == NULL)
2505 2503 cmn_err(CE_PANIC, "No memory for HCA FMA Test.");
2506 2504
2507 2505 bcopy(key_buf, hash_key, strlen(key_buf));
2508 2506
2509 2507 status = mod_hash_find(strHash, (mod_hash_key_t)hash_key,
2510 2508 (mod_hash_val_t *)&t_item);
2511 2509
2512 2510 switch (status) {
2513 2511 case MH_ERR_NOTFOUND:
2514 2512 t_item = (struct i_hca_fm_test *)
2515 2513 kmem_alloc(sizeof (struct i_hca_fm_test), KM_NOSLEEP);
2516 2514 if (t_item == NULL)
2517 2515 cmn_err(CE_PANIC, "No memory for HCA FMA Test.");
2518 2516
2519 2517 /* Set the error number */
2520 2518 mutex_enter(&i_hca_test_lock);
2521 2519 t_item->num = test_num++;
2522 2520 mutex_exit(&i_hca_test_lock);
2523 2521
2524 2522 /* Set type and other static information */
2525 2523 t_item->type = type;
2526 2524 t_item->line_num = linenum;
2527 2525 t_item->file_name = filename;
2528 2526 t_item->hash_key = hash_key;
2529 2527 t_item->private = private;
2530 2528 t_item->pio_injection = pio_injection;
2531 2529
2532 2530 /* Set the pre-defined hermon test item */
2533 2531 i_hca_test_set_item(preTestNum, (struct i_hca_fm_test *)t_item);
2534 2532
2535 2533 status = mod_hash_insert(strHash, (mod_hash_key_t)
2536 2534 hash_key, (mod_hash_val_t)t_item);
2537 2535 ASSERT(status == 0);
2538 2536
2539 2537 status = mod_hash_insert(idHash, (mod_hash_key_t)
2540 2538 (uintptr_t)t_item->num, (mod_hash_val_t)t_item);
2541 2539 ASSERT(status == 0);
2542 2540 break;
2543 2541
2544 2542 case MH_ERR_NOMEM:
2545 2543 cmn_err(CE_PANIC, "No memory for HCA FMA Test.");
2546 2544 break;
2547 2545
2548 2546 case MH_ERR_DUPLICATE:
2549 2547 cmn_err(CE_PANIC, "HCA FMA Test Internal Error.");
2550 2548 break;
2551 2549 default:
2552 2550 /* OK, this is already registered. */
2553 2551 kmem_free(hash_key, strlen(key_buf) + 1);
2554 2552 break;
2555 2553 }
2556 2554 return (t_item);
2557 2555 }
2558 2556
2559 2557
2560 2558 /*
2561 2559 * void
2562 2560 * i_hca_test_set_item(int num, struct i_hca_fm_test *t_item)
2563 2561 *
2564 2562 * Overview
2565 2563 * i_hca_test_set_item() is a private function used in
2566 2564 * i_hca_test_register() above. This function sets the testset specified
2567 2565 * (with the index number) to HCA FM function test structure.
2568 2566 *
2569 2567 * Argument
2570 2568 * num: index to test set (testset structure array)
2571 2569 * t_item: pointer to HCA fM function test structure
2572 2570 *
2573 2571 * Return value
2574 2572 * Nothing
2575 2573 *
2576 2574 * Caller's context
2577 2575 * i_hca_test_set_item() can be called in user, kernel, interrupt
2578 2576 * context or hight interrupt context.
2579 2577 *
2580 2578 */
2581 2579 static void
2582 2580 i_hca_test_set_item(int num, struct i_hca_fm_test *t_item)
2583 2581 {
2584 2582 if (num < 0 || num >= sizeof (testset) / sizeof (hermon_test_t) ||
2585 2583 testset[num].type != t_item->type) {
2586 2584 t_item->trigger = testset[0].trigger;
2587 2585 t_item->errcnt = testset[0].errcnt;
2588 2586 return;
2589 2587 }
2590 2588
2591 2589 /* Set the testsuite */
2592 2590 t_item->trigger = testset[num].trigger;
2593 2591 t_item->errcnt = testset[num].errcnt;
2594 2592 }
2595 2593
2596 2594
2597 2595 /*
2598 2596 * void
2599 2597 * i_hca_test_free_item(mod_hash_val_t val)
2600 2598 *
2601 2599 * Overview
2602 2600 * i_hca_test_free_item() is a private function used to free HCA FM
2603 2601 * function test structure when i_hca_test_fini() is called. This function
2604 2602 * is registered as a destructor when the hash table is created in
2605 2603 * i_hca_test_init().
2606 2604 *
2607 2605 * Argument
2608 2606 * val: pointer to the value stored in hash table (pointer to HCA FM
2609 2607 * function test structure)
2610 2608 *
2611 2609 * Return value
2612 2610 * Nothing
2613 2611 *
2614 2612 * Caller's context
2615 2613 * i_hca_test_free_item() can be called in user, kernel or interrupt
2616 2614 * context.
2617 2615 *
2618 2616 */
2619 2617 static void
2620 2618 i_hca_test_free_item(mod_hash_val_t val)
2621 2619 {
2622 2620 struct i_hca_fm_test *t_item = (struct i_hca_fm_test *)val;
2623 2621 kmem_free(t_item, sizeof (struct i_hca_fm_test));
2624 2622 }
2625 2623 #endif /* FMA_TEST */
↓ open down ↓ |
481 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX