Print this page
5083 avoid undefined order of operations in assignments
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/ib/adapters/hermon/hermon_cmd.c
+++ new/usr/src/uts/common/io/ib/adapters/hermon/hermon_cmd.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_cmd.c
28 28 * Hermon Firmware Command Routines
29 29 *
30 30 * Implements all the routines necessary for allocating, posting, and
31 31 * freeing commands for the Hermon firmware. These routines manage a
32 32 * preallocated list of command mailboxes and provide interfaces to post
33 33 * each of the several dozen commands to the Hermon firmware.
34 34 */
35 35
36 36 #include <sys/types.h>
37 37 #include <sys/conf.h>
38 38 #include <sys/ddi.h>
39 39 #include <sys/sunddi.h>
40 40 #include <sys/modctl.h>
41 41 #include <sys/bitmap.h>
42 42
43 43 #include <sys/ib/adapters/hermon/hermon.h>
44 44
45 45 static int hermon_impl_mbox_alloc(hermon_state_t *state,
46 46 hermon_mboxlist_t *mblist, hermon_mbox_t **mb, uint_t mbox_wait);
47 47 static void hermon_impl_mbox_free(hermon_mboxlist_t *mblist,
48 48 hermon_mbox_t **mb);
49 49 static int hermon_impl_mboxlist_init(hermon_state_t *state,
50 50 hermon_mboxlist_t *mblist, uint_t num_mbox, hermon_rsrc_type_t type);
51 51 static void hermon_impl_mboxlist_fini(hermon_state_t *state,
52 52 hermon_mboxlist_t *mblist);
53 53 static int hermon_outstanding_cmd_alloc(hermon_state_t *state,
54 54 hermon_cmd_t **cmd_ptr, uint_t cmd_wait);
55 55 static void hermon_outstanding_cmd_free(hermon_state_t *state,
56 56 hermon_cmd_t **cmd_ptr);
57 57 static int hermon_write_hcr(hermon_state_t *state, hermon_cmd_post_t *cmdpost,
58 58 uint16_t token, int *hwerr);
59 59 static void hermon_mbox_sync(hermon_mbox_t *mbox, uint_t offset,
60 60 uint_t length, uint_t flag);
61 61 static void hermon_cmd_check_status(hermon_state_t *state, int status);
62 62
63 63 /*
64 64 * hermon_cmd_post()
65 65 * Context: Can be called from interrupt or base context.
66 66 *
67 67 * The "cp_flags" field in cmdpost
68 68 * is used to determine whether to wait for an available
69 69 * outstanding command (if necessary) or to return error.
70 70 */
71 71 int
72 72 hermon_cmd_post(hermon_state_t *state, hermon_cmd_post_t *cmdpost)
73 73 {
74 74 hermon_cmd_t *cmdptr;
75 75 int status, retry_cnt, retry_cnt2, hw_err;
76 76 uint16_t token;
77 77
78 78 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdpost))
79 79
80 80 /* Determine if we are going to spin until completion */
81 81 if (cmdpost->cp_flags == HERMON_CMD_NOSLEEP_SPIN) {
82 82
83 83 /* Write the command to the HCR */
84 84 retry_cnt = HCA_PIO_RETRY_CNT;
85 85 do {
86 86 status = hermon_write_hcr(state, cmdpost, 0, &hw_err);
87 87 } while (status == HERMON_CMD_INTERNAL_ERR && retry_cnt-- > 0);
88 88
89 89 /* Check if there is an error status in hermon_write_hcr() */
90 90 if (status != HERMON_CMD_SUCCESS) {
91 91 /*
92 92 * If there is a HW error, call hermon_cmd_retry_ok()
93 93 * to check the side-effect of the operation retry.
94 94 */
95 95 if ((retry_cnt == HCA_PIO_RETRY_CNT &&
96 96 hw_err == HCA_PIO_OK) ||
97 97 !hermon_cmd_retry_ok(cmdpost, status)) {
98 98 hermon_cmd_check_status(state, status);
99 99 return (status);
100 100 }
101 101 /* Check if there is a transient internal error */
102 102 } else if (retry_cnt != HCA_PIO_RETRY_CNT) {
103 103 hermon_fm_ereport(state, HCA_IBA_ERR,
104 104 HCA_ERR_TRANSIENT);
105 105 }
106 106
107 107 } else { /* "HERMON_CMD_SLEEP_NOSPIN" */
108 108 ASSERT(HERMON_SLEEPFLAG_FOR_CONTEXT() != HERMON_NOSLEEP);
109 109
110 110 /* NOTE: Expect threads to be waiting in here */
111 111 status = hermon_outstanding_cmd_alloc(state, &cmdptr,
112 112 cmdpost->cp_flags);
113 113 if (status != HERMON_CMD_SUCCESS) {
114 114 return (status);
115 115 }
116 116 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdptr))
117 117
118 118 retry_cnt = HCA_PIO_RETRY_CNT;
119 119 retry:
120 120 /*
121 121 * Set status to "HERMON_CMD_INVALID_STATUS". It is
122 122 * appropriate to do this here without the "cmd_comp_lock"
123 123 * because this register is overloaded. Later it will be
124 124 * used to indicate - through a change from this invalid
125 125 * value to some other value - that the condition variable
126 126 * has been signaled. Once it has, status will then contain
127 127 * the _real_ completion status
128 128 */
129 129 cmdptr->cmd_status = HERMON_CMD_INVALID_STATUS;
130 130
131 131 /* Write the command to the HCR */
132 132 token = (uint16_t)cmdptr->cmd_indx;
133 133 retry_cnt2 = HCA_PIO_RETRY_CNT;
134 134 do {
135 135 status = hermon_write_hcr(state, cmdpost, token,
136 136 &hw_err);
137 137 } while (status == HERMON_CMD_INTERNAL_ERR && retry_cnt2-- > 0);
138 138
139 139 /* Check if there is an error status in hermon_write_hcr() */
140 140 if (status != HERMON_CMD_SUCCESS) {
141 141 /*
142 142 * If there is a HW error, call hermon_cmd_retry_ok()
143 143 * to check the side-effect of the operation retry.
144 144 */
145 145 if ((retry_cnt == HCA_PIO_RETRY_CNT &&
146 146 hw_err == HCA_PIO_OK) ||
147 147 !hermon_cmd_retry_ok(cmdpost, status)) {
148 148 hermon_cmd_check_status(state, status);
149 149 hermon_outstanding_cmd_free(state, &cmdptr);
150 150 return (status);
151 151 }
152 152 /* Check if there is a transient internal error */
153 153 } else if (retry_cnt2 != HCA_PIO_RETRY_CNT) {
154 154 hermon_fm_ereport(state, HCA_IBA_ERR,
155 155 HCA_ERR_TRANSIENT);
156 156 }
157 157
158 158 /*
159 159 * cv_wait() on the "command_complete" condition variable.
160 160 * Note: We have the "__lock_lint" here to workaround warlock.
161 161 * Since warlock doesn't know that other parts of the Hermon
162 162 * may occasionally call this routine while holding their own
163 163 * locks, it complains about this cv_wait. In reality,
164 164 * however, the rest of the driver never calls this routine
165 165 * with a lock held unless they pass HERMON_CMD_NOSLEEP.
166 166 */
167 167 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*cmdptr))
168 168 mutex_enter(&cmdptr->cmd_comp_lock);
169 169 while (cmdptr->cmd_status == HERMON_CMD_INVALID_STATUS) {
170 170 #ifndef __lock_lint
171 171 cv_wait(&cmdptr->cmd_comp_cv, &cmdptr->cmd_comp_lock);
172 172 /* NOTE: EXPECT SEVERAL THREADS TO BE WAITING HERE */
173 173 #endif
174 174 }
175 175 mutex_exit(&cmdptr->cmd_comp_lock);
176 176 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdptr))
177 177
178 178 /*
179 179 * Wake up after command completes (cv_signal). Read status
180 180 * from the command (success, fail, etc.). It is appropriate
181 181 * here (as above) to read the status field without the
182 182 * "cmd_comp_lock" because it is no longer being used to
183 183 * indicate whether the condition variable has been signaled
184 184 * (i.e. at this point we are certain that it already has).
185 185 */
186 186 status = cmdptr->cmd_status;
187 187
188 188 /* retry the operation if an internal error occurs */
189 189 if (status == HERMON_CMD_INTERNAL_ERR && retry_cnt-- > 0)
190 190 goto retry;
191 191
192 192 /* Save the "outparam" values into the cmdpost struct */
193 193 cmdpost->cp_outparm = cmdptr->cmd_outparm;
194 194
195 195 /*
196 196 * Add the command back to the "outstanding commands list".
197 197 * Signal the "cmd_list" condition variable, if necessary.
198 198 */
199 199 hermon_outstanding_cmd_free(state, &cmdptr);
200 200
201 201 /* Check if there is an error status in hermon_write_hcr() */
202 202 if (status != HERMON_CMD_SUCCESS) {
203 203 /*
204 204 * If there is a HW error, call hermon_cmd_retry_ok()
205 205 * to check the side-effect of the operation retry.
206 206 */
207 207 if ((retry_cnt == HCA_PIO_RETRY_CNT &&
208 208 hw_err == HCA_PIO_OK) ||
209 209 !hermon_cmd_retry_ok(cmdpost, status)) {
210 210 hermon_cmd_check_status(state, status);
211 211 cmn_err(CE_NOTE, "hermon%d: post cmd failed "
212 212 "opcode (0x%x) status (0x%x)\n",
213 213 state->hs_instance, cmdpost->cp_opcode,
214 214 status);
215 215 return (status);
216 216 }
217 217 /* Check if there is a transient internal error */
218 218 } else if (retry_cnt != HCA_PIO_RETRY_CNT) {
219 219 hermon_fm_ereport(state, HCA_IBA_ERR,
220 220 HCA_ERR_TRANSIENT);
221 221 }
222 222 }
223 223
224 224 return (HERMON_CMD_SUCCESS);
225 225 }
226 226
227 227 /*
228 228 * hermon_cmd_check_status()
229 229 * Context: Can be called from interrupt or base
230 230 *
231 231 * checks the status returned from write_hcr and does the right
232 232 * notice to the console, if any
233 233 */
234 234 static void
235 235 hermon_cmd_check_status(hermon_state_t *state, int status)
236 236 {
237 237 switch (status) {
238 238 case HERMON_CMD_TIMEOUT_TOGGLE:
239 239 HERMON_FMANOTE(state, HERMON_FMA_TOTOG);
240 240 hermon_fm_ereport(state, HCA_IBA_ERR,
241 241 HCA_ERR_NON_FATAL);
242 242 break;
243 243
244 244 case HERMON_CMD_TIMEOUT_GOBIT:
245 245 HERMON_FMANOTE(state, HERMON_FMA_GOBIT);
246 246 hermon_fm_ereport(state, HCA_IBA_ERR,
247 247 HCA_ERR_NON_FATAL);
248 248 break;
249 249
250 250 case HERMON_CMD_INSUFF_RSRC:
251 251 HERMON_FMANOTE(state, HERMON_FMA_RSRC);
252 252 break;
253 253
254 254 case HERMON_CMD_INVALID_STATUS:
255 255 HERMON_FMANOTE(state, HERMON_FMA_CMDINV);
256 256 hermon_fm_ereport(state, HCA_IBA_ERR,
257 257 HCA_ERR_NON_FATAL);
258 258 break;
259 259
260 260 case HERMON_CMD_INTERNAL_ERR:
261 261 HERMON_FMANOTE(state, HERMON_FMA_HCRINT);
262 262 hermon_fm_ereport(state, HCA_IBA_ERR,
263 263 HCA_ERR_NON_FATAL);
264 264 break;
265 265
266 266 case HERMON_CMD_BAD_NVMEM:
267 267 /*
268 268 * No need of an ereport here since this case
269 269 * is treated as a degradation later.
270 270 */
271 271 HERMON_FMANOTE(state, HERMON_FMA_NVMEM);
272 272 break;
273 273
274 274 default:
275 275 break;
276 276 }
277 277 }
278 278
279 279 /*
280 280 * hermon_mbox_alloc()
281 281 * Context: Can be called from interrupt or base context.
282 282 *
283 283 * The "mbox_wait" parameter is used to determine whether to
284 284 * wait for a mailbox to become available or not.
285 285 */
286 286 int
287 287 hermon_mbox_alloc(hermon_state_t *state, hermon_mbox_info_t *mbox_info,
288 288 uint_t mbox_wait)
289 289 {
290 290 int status;
291 291 uint_t sleep_context;
292 292
293 293 sleep_context = HERMON_SLEEPFLAG_FOR_CONTEXT();
294 294
295 295 /* Allocate an "In" mailbox */
296 296 if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_INMBOX) {
297 297 /* Determine correct mboxlist based on calling context */
298 298 if (sleep_context == HERMON_NOSLEEP) {
299 299 status = hermon_impl_mbox_alloc(state,
300 300 &state->hs_in_intr_mblist,
301 301 &mbox_info->mbi_in, mbox_wait);
302 302
303 303 ASSERT(status == HERMON_CMD_SUCCESS);
304 304 } else {
305 305 /* NOTE: Expect threads to be waiting in here */
306 306 status = hermon_impl_mbox_alloc(state,
307 307 &state->hs_in_mblist, &mbox_info->mbi_in,
308 308 mbox_wait);
309 309 if (status != HERMON_CMD_SUCCESS) {
310 310 return (status);
311 311 }
312 312 }
313 313
314 314 }
315 315
316 316 /* Allocate an "Out" mailbox */
317 317 if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_OUTMBOX) {
318 318 /* Determine correct mboxlist based on calling context */
319 319 if (sleep_context == HERMON_NOSLEEP) {
320 320 status = hermon_impl_mbox_alloc(state,
321 321 &state->hs_out_intr_mblist,
322 322 &mbox_info->mbi_out, mbox_wait);
323 323
324 324 ASSERT(status == HERMON_CMD_SUCCESS);
325 325 } else {
326 326 /* NOTE: Expect threads to be waiting in here */
327 327 status = hermon_impl_mbox_alloc(state,
328 328 &state->hs_out_mblist, &mbox_info->mbi_out,
329 329 mbox_wait);
330 330 if (status != HERMON_CMD_SUCCESS) {
331 331 /* If we allocated an "In" mailbox, free it */
332 332 if (mbox_info->mbi_alloc_flags &
333 333 HERMON_ALLOC_INMBOX) {
334 334 hermon_impl_mbox_free(
335 335 &state->hs_in_mblist,
336 336 &mbox_info->mbi_in);
337 337 }
338 338 return (status);
339 339 }
340 340 }
341 341 }
342 342
343 343 /* Store appropriate context in mbox_info */
344 344 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(mbox_info->mbi_sleep_context))
345 345 mbox_info->mbi_sleep_context = sleep_context;
346 346
347 347 return (HERMON_CMD_SUCCESS);
348 348 }
349 349
350 350
351 351 /*
352 352 * hermon_mbox_free()
353 353 * Context: Can be called from interrupt or base context.
354 354 */
355 355 void
356 356 hermon_mbox_free(hermon_state_t *state, hermon_mbox_info_t *mbox_info)
357 357 {
358 358 /*
359 359 * The mailbox has to be freed in the same context from which it was
360 360 * allocated. The context is stored in the mbox_info at
361 361 * hermon_mbox_alloc() time. We check the stored context against the
362 362 * current context here.
363 363 */
364 364 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(mbox_info->mbi_sleep_context))
365 365 ASSERT(mbox_info->mbi_sleep_context == HERMON_SLEEPFLAG_FOR_CONTEXT());
366 366
367 367 /* Determine correct mboxlist based on calling context */
368 368 if (mbox_info->mbi_sleep_context == HERMON_NOSLEEP) {
369 369 /* Free the intr "In" mailbox */
370 370 if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_INMBOX) {
371 371 hermon_impl_mbox_free(&state->hs_in_intr_mblist,
372 372 &mbox_info->mbi_in);
373 373 }
374 374
375 375 /* Free the intr "Out" mailbox */
376 376 if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_OUTMBOX) {
377 377 hermon_impl_mbox_free(&state->hs_out_intr_mblist,
378 378 &mbox_info->mbi_out);
379 379 }
380 380 } else {
381 381 /* Free the "In" mailbox */
382 382 if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_INMBOX) {
383 383 hermon_impl_mbox_free(&state->hs_in_mblist,
384 384 &mbox_info->mbi_in);
385 385 }
386 386
387 387 /* Free the "Out" mailbox */
388 388 if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_OUTMBOX) {
389 389 hermon_impl_mbox_free(&state->hs_out_mblist,
390 390 &mbox_info->mbi_out);
391 391 }
392 392 }
393 393 }
394 394
395 395
396 396
397 397 /*
398 398 * hermon_cmd_complete_handler()
399 399 * Context: Called only from interrupt context.
400 400 */
401 401 /* ARGSUSED */
402 402 int
403 403 hermon_cmd_complete_handler(hermon_state_t *state, hermon_eqhdl_t eq,
404 404 hermon_hw_eqe_t *eqe)
405 405 {
406 406 hermon_cmd_t *cmdp;
407 407
408 408 /*
409 409 * Find the outstanding command pointer based on value returned
410 410 * in "token"
411 411 */
412 412 cmdp = &state->hs_cmd_list.cml_cmd[HERMON_EQE_CMDTOKEN_GET(eq, eqe)];
413 413
414 414 /* Signal the waiting thread */
415 415 mutex_enter(&cmdp->cmd_comp_lock);
416 416 cmdp->cmd_outparm = ((uint64_t)HERMON_EQE_CMDOUTP0_GET(eq, eqe) << 32) |
417 417 HERMON_EQE_CMDOUTP1_GET(eq, eqe);
418 418 cmdp->cmd_status = HERMON_EQE_CMDSTATUS_GET(eq, eqe);
419 419
420 420 cv_signal(&cmdp->cmd_comp_cv);
421 421 mutex_exit(&cmdp->cmd_comp_lock);
422 422
423 423 return (DDI_SUCCESS);
424 424 }
425 425
426 426
427 427 /*
428 428 * hermon_inmbox_list_init()
429 429 * Context: Only called from attach() path context
430 430 */
431 431 int
432 432 hermon_inmbox_list_init(hermon_state_t *state)
433 433 {
434 434 int status;
435 435 uint_t num_inmbox;
436 436
437 437 /* Initialize the "In" mailbox list */
438 438 num_inmbox = (1 << state->hs_cfg_profile->cp_log_num_inmbox);
439 439 status = hermon_impl_mboxlist_init(state, &state->hs_in_mblist,
440 440 num_inmbox, HERMON_IN_MBOX);
441 441 if (status != DDI_SUCCESS) {
442 442 return (DDI_FAILURE);
443 443 }
444 444
445 445 return (DDI_SUCCESS);
446 446 }
447 447
448 448
449 449 /*
450 450 * hermon_intr_inmbox_list_init()
451 451 * Context: Only called from attach() path context
452 452 */
453 453 int
454 454 hermon_intr_inmbox_list_init(hermon_state_t *state)
455 455 {
456 456 int status;
457 457 uint_t num_inmbox;
458 458
459 459 /* Initialize the interrupt "In" mailbox list */
460 460 num_inmbox = (1 << state->hs_cfg_profile->cp_log_num_intr_inmbox);
461 461 status = hermon_impl_mboxlist_init(state, &state->hs_in_intr_mblist,
462 462 num_inmbox, HERMON_INTR_IN_MBOX);
463 463 if (status != DDI_SUCCESS) {
464 464 return (DDI_FAILURE);
465 465 }
466 466
467 467 return (DDI_SUCCESS);
468 468 }
469 469
470 470
471 471 /*
472 472 * hermon_outmbox_list_init()
473 473 * Context: Only called from attach() path context
474 474 */
475 475 int
476 476 hermon_outmbox_list_init(hermon_state_t *state)
477 477 {
478 478 int status;
479 479 uint_t num_outmbox;
480 480
481 481 /* Initialize the "Out" mailbox list */
482 482 num_outmbox = (1 << state->hs_cfg_profile->cp_log_num_outmbox);
483 483 status = hermon_impl_mboxlist_init(state, &state->hs_out_mblist,
484 484 num_outmbox, HERMON_OUT_MBOX);
485 485 if (status != DDI_SUCCESS) {
486 486 return (DDI_FAILURE);
487 487 }
488 488
489 489 return (DDI_SUCCESS);
490 490 }
491 491
492 492
493 493 /*
494 494 * hermon_intr_outmbox_list_init()
495 495 * Context: Only called from attach() path context
496 496 */
497 497 int
498 498 hermon_intr_outmbox_list_init(hermon_state_t *state)
499 499 {
500 500 int status;
501 501 uint_t num_outmbox;
502 502
503 503 /* Initialize the interrupts "Out" mailbox list */
504 504 num_outmbox = (1 << state->hs_cfg_profile->cp_log_num_intr_outmbox);
505 505 status = hermon_impl_mboxlist_init(state, &state->hs_out_intr_mblist,
506 506 num_outmbox, HERMON_INTR_OUT_MBOX);
507 507 if (status != DDI_SUCCESS) {
508 508 return (DDI_FAILURE);
509 509 }
510 510
511 511 return (DDI_SUCCESS);
512 512 }
513 513
514 514
515 515 /*
516 516 * hermon_inmbox_list_fini()
517 517 * Context: Only called from attach() and/or detach() path contexts
518 518 */
519 519 void
520 520 hermon_inmbox_list_fini(hermon_state_t *state)
521 521 {
522 522 /* Free up the "In" mailbox list */
523 523 hermon_impl_mboxlist_fini(state, &state->hs_in_mblist);
524 524 }
525 525
526 526
527 527 /*
528 528 * hermon_intr_inmbox_list_fini()
529 529 * Context: Only called from attach() and/or detach() path contexts
530 530 */
531 531 void
532 532 hermon_intr_inmbox_list_fini(hermon_state_t *state)
533 533 {
534 534 /* Free up the interupts "In" mailbox list */
535 535 hermon_impl_mboxlist_fini(state, &state->hs_in_intr_mblist);
536 536 }
537 537
538 538
539 539 /*
540 540 * hermon_outmbox_list_fini()
541 541 * Context: Only called from attach() and/or detach() path contexts
542 542 */
543 543 void
544 544 hermon_outmbox_list_fini(hermon_state_t *state)
545 545 {
546 546 /* Free up the "Out" mailbox list */
547 547 hermon_impl_mboxlist_fini(state, &state->hs_out_mblist);
548 548 }
549 549
550 550
551 551 /*
552 552 * hermon_intr_outmbox_list_fini()
553 553 * Context: Only called from attach() and/or detach() path contexts
554 554 */
555 555 void
556 556 hermon_intr_outmbox_list_fini(hermon_state_t *state)
557 557 {
558 558 /* Free up the interrupt "Out" mailbox list */
559 559 hermon_impl_mboxlist_fini(state, &state->hs_out_intr_mblist);
560 560 }
561 561
562 562
563 563 /*
564 564 * hermon_impl_mbox_alloc()
565 565 * Context: Can be called from interrupt or base context.
566 566 */
567 567 static int
568 568 hermon_impl_mbox_alloc(hermon_state_t *state, hermon_mboxlist_t *mblist,
569 569 hermon_mbox_t **mb, uint_t mbox_wait)
570 570 {
571 571 hermon_mbox_t *mbox_ptr;
572 572 uint_t index, next, prev;
573 573 uint_t count, countmax;
574 574
575 575 /*
576 576 * If the mailbox list is empty, then wait (if appropriate in the
577 577 * current context). Otherwise, grab the next available mailbox.
578 578 */
579 579 if (mbox_wait == HERMON_NOSLEEP) {
580 580 count = 0;
581 581 countmax = state->hs_cfg_profile->cp_cmd_poll_max;
582 582
583 583 mutex_enter(&mblist->mbl_lock);
584 584 mblist->mbl_pollers++;
585 585 while (mblist->mbl_entries_free == 0) {
586 586 mutex_exit(&mblist->mbl_lock);
587 587 /* Delay loop polling for an available mbox */
588 588 if (++count > countmax) {
589 589 return (HERMON_CMD_INSUFF_RSRC);
590 590 }
591 591
592 592 /* Delay before polling for mailbox again */
593 593 drv_usecwait(state->hs_cfg_profile->cp_cmd_poll_delay);
594 594 mutex_enter(&mblist->mbl_lock);
595 595 }
596 596 mblist->mbl_pollers--;
597 597
598 598 /* HERMON_SLEEP */
599 599 } else {
600 600 /*
601 601 * Grab lock here as we prepare to cv_wait if needed.
602 602 */
603 603 mutex_enter(&mblist->mbl_lock);
604 604 while (mblist->mbl_entries_free == 0) {
605 605 /*
606 606 * Wait (on cv) for a mailbox to become free. Note:
607 607 * Just as we do above in hermon_cmd_post(), we also
608 608 * have the "__lock_lint" here to workaround warlock.
609 609 * Warlock doesn't know that other parts of the Hermon
610 610 * may occasionally call this routine while holding
611 611 * their own locks, so it complains about this cv_wait.
612 612 * In reality, however, the rest of the driver never
613 613 * calls this routine with a lock held unless they pass
614 614 * HERMON_CMD_NOSLEEP.
615 615 */
616 616 mblist->mbl_waiters++;
617 617 #ifndef __lock_lint
618 618 cv_wait(&mblist->mbl_cv, &mblist->mbl_lock);
619 619 #endif
620 620 }
621 621 }
622 622
623 623 /* Grab the next available mailbox from list */
624 624 mbox_ptr = mblist->mbl_mbox;
625 625 index = mblist->mbl_head_indx;
626 626 next = mbox_ptr[index].mb_next;
627 627 prev = mbox_ptr[index].mb_prev;
628 628
629 629 /* Remove it from the mailbox list */
630 630 mblist->mbl_mbox[next].mb_prev = prev;
631 631 mblist->mbl_mbox[prev].mb_next = next;
632 632 mblist->mbl_head_indx = next;
633 633
634 634 /* Update the "free" count and return the mailbox pointer */
635 635 mblist->mbl_entries_free--;
636 636 *mb = &mbox_ptr[index];
637 637
638 638 mutex_exit(&mblist->mbl_lock);
639 639
640 640 return (HERMON_CMD_SUCCESS);
641 641 }
642 642
643 643
644 644 /*
645 645 * hermon_impl_mbox_free()
646 646 * Context: Can be called from interrupt or base context.
647 647 */
648 648 static void
649 649 hermon_impl_mbox_free(hermon_mboxlist_t *mblist, hermon_mbox_t **mb)
650 650 {
651 651 uint_t mbox_indx;
652 652
653 653 mutex_enter(&mblist->mbl_lock);
654 654
655 655 /* Pull the "index" from mailbox entry */
656 656 mbox_indx = (*mb)->mb_indx;
657 657
658 658 /*
659 659 * If mailbox list is not empty, then insert the entry. Otherwise,
660 660 * this is the only entry. So update the pointers appropriately.
661 661 */
662 662 if (mblist->mbl_entries_free++ != 0) {
663 663 /* Update the current mailbox */
664 664 (*mb)->mb_next = mblist->mbl_head_indx;
665 665 (*mb)->mb_prev = mblist->mbl_tail_indx;
666 666
667 667 /* Update head and tail mailboxes */
668 668 mblist->mbl_mbox[mblist->mbl_head_indx].mb_prev = mbox_indx;
669 669 mblist->mbl_mbox[mblist->mbl_tail_indx].mb_next = mbox_indx;
670 670
671 671 /* Update tail index */
672 672 mblist->mbl_tail_indx = mbox_indx;
673 673
674 674 } else {
675 675 /* Update the current mailbox */
676 676 (*mb)->mb_next = mbox_indx;
677 677 (*mb)->mb_prev = mbox_indx;
678 678
679 679 /* Update head and tail indexes */
680 680 mblist->mbl_tail_indx = mbox_indx;
681 681 mblist->mbl_head_indx = mbox_indx;
682 682 }
683 683
684 684 /*
685 685 * Because we can have both waiters (SLEEP treads waiting for a
686 686 * cv_signal to continue processing) and pollers (NOSLEEP treads
687 687 * polling for a mailbox to become available), we try to share CPU time
688 688 * between them. We do this by signalling the waiters only every other
689 689 * call to mbox_free. This gives the pollers a chance to get some CPU
↓ open down ↓ |
689 lines elided |
↑ open up ↑ |
690 690 * time to do their command. If we signalled every time, the pollers
691 691 * would have a much harder time getting CPU time.
692 692 *
693 693 * If there are waiters and no pollers, then we signal always.
694 694 *
695 695 * Otherwise, if there are either no waiters, there may in fact be
696 696 * pollers, so we do not signal in that case.
697 697 */
698 698 if (mblist->mbl_pollers > 0 && mblist->mbl_waiters > 0) {
699 699 /* flip the signal value */
700 - mblist->mbl_signal = (++mblist->mbl_signal) % 2;
700 + mblist->mbl_signal = (mblist->mbl_signal + 1) % 2;
701 701 } else if (mblist->mbl_waiters > 0) {
702 702 mblist->mbl_signal = 1;
703 703 } else {
704 704 mblist->mbl_signal = 0;
705 705 }
706 706
707 707 /*
708 708 * Depending on the conditions in the previous check, we signal only if
709 709 * we are supposed to.
710 710 */
711 711 if (mblist->mbl_signal) {
712 712 mblist->mbl_waiters--;
713 713 cv_signal(&mblist->mbl_cv);
714 714 }
715 715
716 716 /* Clear out the mailbox entry pointer */
717 717 *mb = NULL;
718 718
719 719 mutex_exit(&mblist->mbl_lock);
720 720 }
721 721
722 722
723 723 /*
724 724 * hermon_impl_mboxlist_init()
725 725 * Context: Only called from attach() path context
726 726 */
727 727 static int
728 728 hermon_impl_mboxlist_init(hermon_state_t *state, hermon_mboxlist_t *mblist,
729 729 uint_t num_mbox, hermon_rsrc_type_t type)
730 730 {
731 731 hermon_rsrc_t *rsrc;
732 732 ddi_dma_cookie_t dma_cookie;
733 733 uint_t dma_cookiecnt;
734 734 int status, i;
735 735
736 736 /* Allocate the memory for the mailbox entries list */
737 737 mblist->mbl_list_sz = num_mbox;
738 738 mblist->mbl_mbox = kmem_zalloc(mblist->mbl_list_sz *
739 739 sizeof (hermon_mbox_t), KM_SLEEP);
740 740
741 741 /* Initialize the mailbox entries list */
742 742 mblist->mbl_head_indx = 0;
743 743 mblist->mbl_tail_indx = mblist->mbl_list_sz - 1;
744 744 mblist->mbl_entries_free = mblist->mbl_list_sz;
745 745 mblist->mbl_waiters = 0;
746 746 mblist->mbl_num_alloc = 0;
747 747
748 748 /* Set up the mailbox list's cv and mutex */
749 749 mutex_init(&mblist->mbl_lock, NULL, MUTEX_DRIVER,
750 750 DDI_INTR_PRI(state->hs_intrmsi_pri));
751 751 cv_init(&mblist->mbl_cv, NULL, CV_DRIVER, NULL);
752 752
753 753 /* Initialize the mailbox list entries */
754 754 for (i = 0; i < mblist->mbl_list_sz; i++) {
755 755 /* Allocate resources for the mailbox */
756 756 status = hermon_rsrc_alloc(state, type, 1, HERMON_SLEEP,
757 757 &rsrc);
758 758 if (status != DDI_SUCCESS) {
759 759 /* Jump to cleanup and return error */
760 760 goto mboxlist_init_fail;
761 761 }
762 762
763 763 /* Save away the mailbox resource info */
764 764 mblist->mbl_mbox[i].mb_rsrcptr = rsrc;
765 765 mblist->mbl_mbox[i].mb_addr = rsrc->hr_addr;
766 766 mblist->mbl_mbox[i].mb_acchdl = rsrc->hr_acchdl;
767 767
768 768 /*
769 769 * Get a PCI mapped address for each mailbox. Note: this
770 770 * uses the ddi_dma_handle return from the resource
771 771 * allocation routine
772 772 */
773 773 status = ddi_dma_addr_bind_handle(rsrc->hr_dmahdl, NULL,
774 774 rsrc->hr_addr, rsrc->hr_len,
775 775 (DDI_DMA_RDWR | DDI_DMA_CONSISTENT),
776 776 DDI_DMA_SLEEP, NULL, &dma_cookie, &dma_cookiecnt);
777 777 if (status != DDI_SUCCESS) {
778 778 /* Jump to cleanup and return error */
779 779 hermon_rsrc_free(state, &rsrc);
780 780 goto mboxlist_init_fail;
781 781 }
782 782
783 783 /* Save away the mapped address for the mailbox */
784 784 mblist->mbl_mbox[i].mb_mapaddr = dma_cookie.dmac_laddress;
785 785
786 786 /* Make each entry point to the "next" and "prev" entries */
787 787 mblist->mbl_mbox[i].mb_next = i+1;
788 788 mblist->mbl_mbox[i].mb_prev = i-1;
789 789 mblist->mbl_mbox[i].mb_indx = i;
790 790 mblist->mbl_num_alloc = i + 1;
791 791 }
792 792
793 793 /* Make the "head" and "tail" entries point to each other */
794 794 mblist->mbl_mbox[mblist->mbl_head_indx].mb_prev =
795 795 mblist->mbl_tail_indx;
796 796 mblist->mbl_mbox[mblist->mbl_tail_indx].mb_next =
797 797 mblist->mbl_head_indx;
798 798
799 799 return (DDI_SUCCESS);
800 800
801 801 mboxlist_init_fail:
802 802 hermon_impl_mboxlist_fini(state, mblist);
803 803
804 804 return (DDI_FAILURE);
805 805 }
806 806
807 807
808 808 /*
809 809 * hermon_impl_mboxlist_fini()
810 810 * Context: Only called from attach() and/or detach() path contexts
811 811 */
812 812 static void
813 813 hermon_impl_mboxlist_fini(hermon_state_t *state, hermon_mboxlist_t *mblist)
814 814 {
815 815 hermon_rsrc_t *rsrc;
816 816 int i, status;
817 817
818 818 /* Release the resources for each of the mailbox list entries */
819 819 for (i = 0; i < mblist->mbl_num_alloc; i++) {
820 820 rsrc = mblist->mbl_mbox[i].mb_rsrcptr;
821 821
822 822 /*
823 823 * First, unbind the DMA memory for the mailbox
824 824 *
825 825 * Note: The only way ddi_dma_unbind_handle() currently
826 826 * can return an error is if the handle passed in is invalid.
827 827 * Since this should never happen, we choose to return void
828 828 * from this function! If this does return an error,
829 829 * however, then we print a warning message to the console.
830 830 */
831 831 status = ddi_dma_unbind_handle(rsrc->hr_dmahdl);
832 832 if (status != DDI_SUCCESS) {
833 833 HERMON_WARNING(state, "failed to unbind DMA mapping");
834 834 return;
835 835 }
836 836
837 837 /* Next, free the mailbox resource */
838 838 hermon_rsrc_free(state, &rsrc);
839 839 }
840 840
841 841 /* Destroy the mailbox list mutex and cv */
842 842 mutex_destroy(&mblist->mbl_lock);
843 843 cv_destroy(&mblist->mbl_cv);
844 844
845 845 /* Free up the memory for tracking the mailbox list */
846 846 kmem_free(mblist->mbl_mbox, mblist->mbl_list_sz *
847 847 sizeof (hermon_mbox_t));
848 848 }
849 849
850 850
851 851 /*
852 852 * hermon_outstanding_cmd_alloc()
853 853 * Context: Can be called only from base context.
854 854 */
855 855 static int
856 856 hermon_outstanding_cmd_alloc(hermon_state_t *state, hermon_cmd_t **cmd_ptr,
857 857 uint_t cmd_wait)
858 858 {
859 859 hermon_cmdlist_t *cmd_list;
860 860 uint_t next, prev, head;
861 861
862 862 cmd_list = &state->hs_cmd_list;
863 863 mutex_enter(&cmd_list->cml_lock);
864 864
865 865 /* Ensure that outstanding commands are supported */
866 866 ASSERT(cmd_list->cml_num_alloc != 0);
867 867
868 868 /*
869 869 * If the outstanding command list is empty, then wait (if
870 870 * appropriate in the current context). Otherwise, grab the
871 871 * next available command.
872 872 */
873 873 while (cmd_list->cml_entries_free == 0) {
874 874 /* No free commands */
875 875 if (cmd_wait == HERMON_NOSLEEP) {
876 876 mutex_exit(&cmd_list->cml_lock);
877 877 return (HERMON_CMD_INSUFF_RSRC);
878 878 }
879 879
880 880 /*
881 881 * Wait (on cv) for a command to become free. Note: Just
882 882 * as we do above in hermon_cmd_post(), we also have the
883 883 * "__lock_lint" here to workaround warlock. Warlock doesn't
884 884 * know that other parts of the Hermon may occasionally call
885 885 * this routine while holding their own locks, so it complains
886 886 * about this cv_wait. In reality, however, the rest of the
887 887 * driver never calls this routine with a lock held unless
888 888 * they pass HERMON_CMD_NOSLEEP.
889 889 */
890 890 cmd_list->cml_waiters++;
891 891 #ifndef __lock_lint
892 892 cv_wait(&cmd_list->cml_cv, &cmd_list->cml_lock);
893 893 #endif
894 894 }
895 895
896 896 /* Grab the next available command from the list */
897 897 head = cmd_list->cml_head_indx;
898 898 *cmd_ptr = &cmd_list->cml_cmd[head];
899 899 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(**cmd_ptr))
900 900 next = (*cmd_ptr)->cmd_next;
901 901 prev = (*cmd_ptr)->cmd_prev;
902 902 (*cmd_ptr)->cmd_status = HERMON_CMD_INVALID_STATUS;
903 903
904 904 /* Remove it from the command list */
905 905 cmd_list->cml_cmd[next].cmd_prev = prev;
906 906 cmd_list->cml_cmd[prev].cmd_next = next;
907 907 cmd_list->cml_head_indx = next;
908 908
909 909 /* Update the "free" count and return */
910 910 cmd_list->cml_entries_free--;
911 911
912 912 mutex_exit(&cmd_list->cml_lock);
913 913
914 914 return (HERMON_CMD_SUCCESS);
915 915 }
916 916
917 917
918 918 /*
919 919 * hermon_outstanding_cmd_free()
920 920 * Context: Can be called only from base context.
921 921 */
922 922 static void
923 923 hermon_outstanding_cmd_free(hermon_state_t *state, hermon_cmd_t **cmd_ptr)
924 924 {
925 925 hermon_cmdlist_t *cmd_list;
926 926 uint_t cmd_indx;
927 927
928 928 cmd_list = &state->hs_cmd_list;
929 929 mutex_enter(&cmd_list->cml_lock);
930 930
931 931 /* Pull the "index" from command entry */
932 932 cmd_indx = (*cmd_ptr)->cmd_indx;
933 933
934 934 /*
935 935 * If outstanding command list is not empty, then insert the entry.
936 936 * Otherwise, this is the only entry. So update the pointers
937 937 * appropriately.
938 938 */
939 939 if (cmd_list->cml_entries_free++ != 0) {
940 940 /* Update the current command */
941 941 (*cmd_ptr)->cmd_next = cmd_list->cml_head_indx;
942 942 (*cmd_ptr)->cmd_prev = cmd_list->cml_tail_indx;
943 943
944 944 /* Update head and tail commands */
945 945 cmd_list->cml_cmd[cmd_list->cml_head_indx].cmd_prev = cmd_indx;
946 946 cmd_list->cml_cmd[cmd_list->cml_tail_indx].cmd_next = cmd_indx;
947 947
948 948 /* Update tail index */
949 949 cmd_list->cml_tail_indx = cmd_indx;
950 950
951 951 } else {
952 952 /* Update the current command */
953 953 (*cmd_ptr)->cmd_next = cmd_indx;
954 954 (*cmd_ptr)->cmd_prev = cmd_indx;
955 955
956 956 /* Update head and tail indexes */
957 957 cmd_list->cml_head_indx = cmd_indx;
958 958 cmd_list->cml_tail_indx = cmd_indx;
959 959 }
960 960
961 961 /* If there are threads waiting, signal one of them */
962 962 if (cmd_list->cml_waiters > 0) {
963 963 cmd_list->cml_waiters--;
964 964 cv_signal(&cmd_list->cml_cv);
965 965 }
966 966
967 967 /* Clear out the command entry pointer */
968 968 *cmd_ptr = NULL;
969 969
970 970 mutex_exit(&cmd_list->cml_lock);
971 971 }
972 972
973 973
974 974 /*
975 975 * hermon_write_hcr()
976 976 * Context: Can be called from interrupt or base context.
977 977 */
978 978 static int
979 979 hermon_write_hcr(hermon_state_t *state, hermon_cmd_post_t *cmdpost,
980 980 uint16_t token, int *hw_err)
981 981 {
982 982 hermon_hw_hcr_t *hcr;
983 983 uint_t status, count, countmax;
984 984 uint64_t hcrreg;
985 985 uint64_t togmask;
986 986 ddi_acc_handle_t cmdhdl = hermon_get_cmdhdl(state);
987 987 boolean_t hw_error = B_FALSE;
988 988
989 989 /* initialize the FMA retry loop */
990 990 hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
991 991
992 992 /*
993 993 * Grab the "HCR access" lock if the driver is not in
994 994 * fastreboot. In fastreboot, this function is called
995 995 * with the single thread but in high interrupt context
996 996 * (so that this mutex lock cannot be used).
997 997 */
998 998 #ifdef __lock_lint
999 999 mutex_enter(&state->hs_cmd_regs.hcr_lock);
1000 1000 #else
1001 1001 if (!HERMON_IN_FASTREBOOT(state)) {
1002 1002 mutex_enter(&state->hs_cmd_regs.hcr_lock);
1003 1003 }
1004 1004 #endif
1005 1005 hcr = state->hs_cmd_regs.hcr;
1006 1006
1007 1007 /*
1008 1008 * First, check the "go" bit to see if any previous hcr usage is
1009 1009 * complete. As long as it is set then we must continue to poll.
1010 1010 */
1011 1011
1012 1012 countmax = state->hs_cfg_profile->cp_cmd_poll_max;
1013 1013 togmask = (state->hs_cmd_toggle & 0x01) << HERMON_HCR_CMD_T_SHFT;
1014 1014
1015 1015 /* the FMA retry loop starts. */
1016 1016 hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
1017 1017 fm_test);
1018 1018
1019 1019 count = 0;
1020 1020 for (;;) {
1021 1021 hcrreg = ddi_get32(cmdhdl, &hcr->cmd);
1022 1022
1023 1023 /* If "go" bit is clear and toggle reset, then done */
1024 1024 if (((hcrreg & HERMON_HCR_CMD_GO_MASK) == 0) &&
1025 1025 ((hcrreg & HERMON_HCR_CMD_T_MASK) == togmask)) {
1026 1026 break;
1027 1027 }
1028 1028 /* Delay before polling the "go" bit again */
1029 1029 drv_usecwait(state->hs_cfg_profile->cp_cmd_poll_delay);
1030 1030
1031 1031 /*
1032 1032 * If we poll more than the maximum number of times, then
1033 1033 * return a "timeout" error.
1034 1034 */
1035 1035 if (++count > countmax) {
1036 1036 #ifdef __lock_lint
1037 1037 mutex_exit(&state->hs_cmd_regs.hcr_lock);
1038 1038 #else
1039 1039 if (!HERMON_IN_FASTREBOOT(state)) {
1040 1040 mutex_exit(&state->hs_cmd_regs.hcr_lock);
1041 1041 }
1042 1042 #endif
1043 1043 cmn_err(CE_NOTE, "write_hcr: cannot start cmd");
1044 1044 return (HERMON_CMD_TIMEOUT_GOBIT);
1045 1045 }
1046 1046 }
1047 1047
1048 1048 /* the FMA retry loop ends. */
1049 1049 hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
1050 1050 fm_test);
1051 1051
1052 1052 /* check if there is a transient error */
1053 1053 if (fm_loop_cnt != HCA_PIO_RETRY_CNT) {
1054 1054 hw_error = B_TRUE;
1055 1055 }
1056 1056
1057 1057 /* succeeded, so update the cmd counter for this cmd's completion */
1058 1058 state->hs_cmd_toggle++;
1059 1059 togmask = (state->hs_cmd_toggle & 0x01) << HERMON_HCR_CMD_T_SHFT;
1060 1060
1061 1061 /* the FMA retry loop starts. */
1062 1062 hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
1063 1063 fm_test);
1064 1064
1065 1065 /* Write "inparam" as a 64-bit quantity */
1066 1066 ddi_put64(cmdhdl, (uint64_t *)(void *)&hcr->in_param0,
1067 1067 cmdpost->cp_inparm);
1068 1068
1069 1069 /* Write "inmod" and 32-bits of "outparam" as 64-bit */
1070 1070 hcrreg = ((uint64_t)cmdpost->cp_inmod << 32);
1071 1071 hcrreg = hcrreg | (cmdpost->cp_outparm >> 32);
1072 1072
1073 1073 ddi_put64(cmdhdl, (uint64_t *)(void *)&hcr->input_modifier, hcrreg);
1074 1074
1075 1075 /* Write the other 32-bits of "outparam" and "token" as 64-bit */
1076 1076 hcrreg = (cmdpost->cp_outparm << 32);
1077 1077 hcrreg = hcrreg | ((uint32_t)token << HERMON_HCR_TOKEN_SHIFT);
1078 1078
1079 1079 ddi_put64(cmdhdl, (uint64_t *)(void *)&hcr->out_param1, hcrreg);
1080 1080
1081 1081 /* Then setup the final hcrreg to hit doorbell (i.e. "go" bit) */
1082 1082 hcrreg = HERMON_HCR_CMD_GO_MASK;
1083 1083 /* Then set the toggle bit for this command */
1084 1084 hcrreg |= (state->hs_cmd_toggle & 0x01) << HERMON_HCR_CMD_T_SHFT;
1085 1085 if (cmdpost->cp_flags == HERMON_CMD_SLEEP_NOSPIN) {
1086 1086 hcrreg = hcrreg | HERMON_HCR_CMD_E_MASK;
1087 1087 }
1088 1088 hcrreg = hcrreg | (cmdpost->cp_opmod << HERMON_HCR_CMD_OPMOD_SHFT);
1089 1089 hcrreg = hcrreg | (cmdpost->cp_opcode);
1090 1090
1091 1091 /* Write the doorbell to the HCR */
1092 1092 ddi_put32(cmdhdl, &hcr->cmd, hcrreg);
1093 1093
1094 1094 /* the FMA retry loop ends. */
1095 1095 hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
1096 1096 fm_test);
1097 1097
1098 1098 /* check if there is a transient error */
1099 1099 if (fm_loop_cnt != HCA_PIO_RETRY_CNT) {
1100 1100 hw_error = B_TRUE;
1101 1101 }
1102 1102
1103 1103 /*
1104 1104 * In the SPIN case we read the HCR and check the "go" bit. For the
1105 1105 * NOSPIN case we do not have to poll, we simply release the HCR lock
1106 1106 * and return.
1107 1107 */
1108 1108 if (cmdpost->cp_flags == HERMON_CMD_NOSLEEP_SPIN) {
1109 1109
1110 1110 countmax = (state->hs_cfg_profile->cp_cmd_poll_max << 4);
1111 1111
1112 1112 /* the FMA retry loop starts. */
1113 1113 hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt,
1114 1114 fm_status, fm_test);
1115 1115
1116 1116 count = 0;
1117 1117 for (;;) {
1118 1118 hcrreg = ddi_get32(cmdhdl, &hcr->cmd);
1119 1119
1120 1120 /* If "go" bit is clear and toggle reset, then done */
1121 1121 if (((hcrreg & HERMON_HCR_CMD_GO_MASK) == 0) &&
1122 1122 ((hcrreg & HERMON_HCR_CMD_T_MASK) == togmask)) {
1123 1123 break;
1124 1124 }
1125 1125 /* Delay before polling the "go" bit again */
1126 1126 drv_usecwait(state->hs_cfg_profile->cp_cmd_poll_delay);
1127 1127
1128 1128 /*
1129 1129 * If we poll more than the maximum number of times,
1130 1130 * then return a "timeout" error.
1131 1131 */
1132 1132 if (++count > countmax) {
1133 1133 #ifdef __lock_lint
1134 1134 mutex_exit(&state-> hs_cmd_regs.hcr_lock);
1135 1135 #else
1136 1136 if (!HERMON_IN_FASTREBOOT(state)) {
1137 1137 mutex_exit(&state->
1138 1138 hs_cmd_regs.hcr_lock);
1139 1139 }
1140 1140 #endif
1141 1141 cmn_err(CE_NOTE,
1142 1142 "write_hcr: cannot complete cmd");
1143 1143 return (HERMON_CMD_TIMEOUT_GOBIT);
1144 1144 }
1145 1145 }
1146 1146
1147 1147 /* Pull out the "status" bits from the HCR */
1148 1148 status = (hcrreg >> HERMON_HCR_CMD_STATUS_SHFT);
1149 1149
1150 1150 /*
1151 1151 * Read the "outparam" value. Note: we have to read "outparam"
1152 1152 * as two separate 32-bit reads because the field in the HCR is
1153 1153 * not 64-bit aligned.
1154 1154 */
1155 1155 hcrreg = ddi_get32(cmdhdl, &hcr->out_param0);
1156 1156 cmdpost->cp_outparm = hcrreg << 32;
1157 1157 hcrreg = ddi_get32(cmdhdl, &hcr->out_param1);
1158 1158 cmdpost->cp_outparm |= hcrreg;
1159 1159
1160 1160 /* the FMA retry loop ends. */
1161 1161 hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
1162 1162 fm_test);
1163 1163
1164 1164 /* check if there is a transient error */
1165 1165 if (fm_loop_cnt != HCA_PIO_RETRY_CNT) {
1166 1166 hw_error = B_TRUE;
1167 1167 }
1168 1168
1169 1169 /* END SPIN */
1170 1170 } else { /* NOSPIN */
1171 1171 status = HERMON_CMD_SUCCESS;
1172 1172 }
1173 1173
1174 1174 /* Drop the "HCR access" lock */
1175 1175 #ifdef __lock_lint
1176 1176 mutex_exit(&state->hs_cmd_regs.hcr_lock);
1177 1177 #else
1178 1178 if (!HERMON_IN_FASTREBOOT(state)) {
1179 1179 mutex_exit(&state->hs_cmd_regs.hcr_lock);
1180 1180 }
1181 1181 #endif
1182 1182 if (hw_error == B_TRUE) {
1183 1183 *hw_err = HCA_PIO_TRANSIENT;
1184 1184 } else {
1185 1185 *hw_err = HCA_PIO_OK;
1186 1186 }
1187 1187 #ifdef FMA_TEST
1188 1188 if (hermon_test_num == -3) {
1189 1189 status = HERMON_CMD_INTERNAL_ERR;
1190 1190 }
1191 1191 #endif
1192 1192 return (status);
1193 1193
1194 1194 pio_error:
1195 1195 #ifdef __lock_lint
1196 1196 mutex_exit(&state->hs_cmd_regs.hcr_lock);
1197 1197 #else
1198 1198 if (!HERMON_IN_FASTREBOOT(state)) {
1199 1199 mutex_exit(&state->hs_cmd_regs.hcr_lock);
1200 1200 }
1201 1201 #endif
1202 1202 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_NON_FATAL);
1203 1203 *hw_err = HCA_PIO_PERSISTENT;
1204 1204 return (HERMON_CMD_INVALID_STATUS);
1205 1205 }
1206 1206
1207 1207
1208 1208 /*
1209 1209 * hermon_outstanding_cmdlist_init()
1210 1210 * Context: Only called from attach() path context
1211 1211 */
1212 1212 int
1213 1213 hermon_outstanding_cmdlist_init(hermon_state_t *state)
1214 1214 {
1215 1215 uint_t num_outstanding_cmds, head, tail;
1216 1216 int i;
1217 1217
1218 1218 /*
1219 1219 * Determine the number of the outstanding commands supported
1220 1220 * by the Hermon device (obtained from the QUERY_FW command). Note:
1221 1221 * Because we handle both SLEEP and NOSLEEP cases around the hermon HCR,
1222 1222 * we know that when an interrupt comes in it will be next on the
1223 1223 * command register, and will at most have to wait one commands time.
1224 1224 * We do not have to reserve an outstanding command here for
1225 1225 * interrupts.
1226 1226 */
1227 1227 num_outstanding_cmds = (1 << state->hs_fw.log_max_cmd);
1228 1228
1229 1229 /* Initialize the outstanding command list */
1230 1230 state->hs_cmd_list.cml_list_sz = num_outstanding_cmds;
1231 1231 state->hs_cmd_list.cml_head_indx = 0;
1232 1232 state->hs_cmd_list.cml_tail_indx = state->hs_cmd_list.cml_list_sz - 1;
1233 1233 state->hs_cmd_list.cml_entries_free = state->hs_cmd_list.cml_list_sz;
1234 1234 state->hs_cmd_list.cml_waiters = 0;
1235 1235 state->hs_cmd_list.cml_num_alloc = 0;
1236 1236
1237 1237 /* Allocate the memory for the outstanding command list */
1238 1238 if (num_outstanding_cmds) {
1239 1239 state->hs_cmd_list.cml_cmd =
1240 1240 kmem_zalloc(state->hs_cmd_list.cml_list_sz *
1241 1241 sizeof (hermon_cmd_t), KM_SLEEP);
1242 1242 }
1243 1243 mutex_init(&state->hs_cmd_list.cml_lock, NULL, MUTEX_DRIVER,
1244 1244 DDI_INTR_PRI(state->hs_intrmsi_pri));
1245 1245 cv_init(&state->hs_cmd_list.cml_cv, NULL, CV_DRIVER, NULL);
1246 1246
1247 1247 /* Initialize the individual outstanding command list entries */
1248 1248 for (i = 0; i < state->hs_cmd_list.cml_list_sz; i++) {
1249 1249 mutex_init(&state->hs_cmd_list.cml_cmd[i].cmd_comp_lock,
1250 1250 NULL, MUTEX_DRIVER, DDI_INTR_PRI(state->hs_intrmsi_pri));
1251 1251 cv_init(&state->hs_cmd_list.cml_cmd[i].cmd_comp_cv, NULL,
1252 1252 CV_DRIVER, NULL);
1253 1253
1254 1254 state->hs_cmd_list.cml_cmd[i].cmd_next = i+1;
1255 1255 state->hs_cmd_list.cml_cmd[i].cmd_prev = i-1;
1256 1256 state->hs_cmd_list.cml_cmd[i].cmd_indx = i;
1257 1257 state->hs_cmd_list.cml_num_alloc = i + 1;
1258 1258 }
1259 1259 if (num_outstanding_cmds) {
1260 1260 head = state->hs_cmd_list.cml_head_indx;
1261 1261 tail = state->hs_cmd_list.cml_tail_indx;
1262 1262 state->hs_cmd_list.cml_cmd[head].cmd_prev =
1263 1263 state->hs_cmd_list.cml_tail_indx;
1264 1264 state->hs_cmd_list.cml_cmd[tail].cmd_next =
1265 1265 state->hs_cmd_list.cml_head_indx;
1266 1266 }
1267 1267
1268 1268 return (DDI_SUCCESS);
1269 1269 }
1270 1270
1271 1271
1272 1272 /*
1273 1273 * hermon_outstanding_cmdlist_fini()
1274 1274 * Context: Only called from attach() and/or detach() path contexts
1275 1275 */
1276 1276 void
1277 1277 hermon_outstanding_cmdlist_fini(hermon_state_t *state)
1278 1278 {
1279 1279 int i;
1280 1280
1281 1281 /* Destroy the outstanding command list entries */
1282 1282 for (i = 0; i < state->hs_cmd_list.cml_num_alloc; i++) {
1283 1283 mutex_destroy(&state->hs_cmd_list.cml_cmd[i].cmd_comp_lock);
1284 1284 cv_destroy(&state->hs_cmd_list.cml_cmd[i].cmd_comp_cv);
1285 1285 }
1286 1286
1287 1287 /* Destroy the lock (and cv) and free up memory for list */
1288 1288 mutex_destroy(&state->hs_cmd_list.cml_lock);
1289 1289 cv_destroy(&state->hs_cmd_list.cml_cv);
1290 1290 if (state->hs_cmd_list.cml_num_alloc) {
1291 1291 kmem_free(state->hs_cmd_list.cml_cmd,
1292 1292 state->hs_cmd_list.cml_list_sz * sizeof (hermon_cmd_t));
1293 1293 }
1294 1294 }
1295 1295
1296 1296
1297 1297 /*
1298 1298 * hermon_mbox_sync()
1299 1299 */
1300 1300 static void
1301 1301 hermon_mbox_sync(hermon_mbox_t *mbox, uint_t offset, uint_t length,
1302 1302 uint_t flag)
1303 1303 {
1304 1304 ddi_dma_handle_t dmahdl;
1305 1305 int status;
1306 1306
1307 1307 /* Get the DMA handle from mailbox */
1308 1308 dmahdl = mbox->mb_rsrcptr->hr_dmahdl;
1309 1309
1310 1310 /* Calculate offset into mailbox */
1311 1311 status = ddi_dma_sync(dmahdl, (off_t)offset, (size_t)length, flag);
1312 1312 if (status != DDI_SUCCESS) {
1313 1313 return;
1314 1314 }
1315 1315 }
1316 1316
1317 1317
1318 1318 /*
1319 1319 * hermon_init_hca_cmd_post()
1320 1320 * Context: Can be called from interrupt or base context.
1321 1321 * (Currently called only from attach() path context)
1322 1322 */
1323 1323 int
1324 1324 hermon_init_hca_cmd_post(hermon_state_t *state,
1325 1325 hermon_hw_initqueryhca_t *inithca, uint_t sleepflag)
1326 1326 {
1327 1327 hermon_mbox_info_t mbox_info;
1328 1328 hermon_cmd_post_t cmd;
1329 1329 uint64_t data;
1330 1330 uint_t size;
1331 1331 int status, i;
1332 1332
1333 1333 /* Make sure we are called with the correct flag */
1334 1334 ASSERT(sleepflag == HERMON_CMD_NOSLEEP_SPIN);
1335 1335
1336 1336 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1337 1337
1338 1338 /* Get an "In" mailbox for the command */
1339 1339 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
1340 1340 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
1341 1341 if (status != HERMON_CMD_SUCCESS) {
1342 1342 return (status);
1343 1343 }
1344 1344
1345 1345 /* Copy the Hermon "INIT_HCA" command into the mailbox */
1346 1346 size = sizeof (hermon_hw_initqueryhca_t);
1347 1347 for (i = 0; i < (size >> 3); i++) {
1348 1348 data = ((uint64_t *)inithca)[i];
1349 1349 ddi_put64(mbox_info.mbi_in->mb_acchdl,
1350 1350 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
1351 1351 }
1352 1352
1353 1353 /* Sync the mailbox for the device to read */
1354 1354 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
1355 1355
1356 1356 /* Setup and post the Hermon "INIT_HCA" command */
1357 1357 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
1358 1358 cmd.cp_outparm = 0;
1359 1359 cmd.cp_inmod = 0;
1360 1360 cmd.cp_opcode = INIT_HCA;
1361 1361 cmd.cp_opmod = 0;
1362 1362 cmd.cp_flags = sleepflag;
1363 1363 status = hermon_cmd_post(state, &cmd);
1364 1364
1365 1365 /* Free the mailbox */
1366 1366 hermon_mbox_free(state, &mbox_info);
1367 1367 return (status);
1368 1368 }
1369 1369
1370 1370
1371 1371 /*
1372 1372 * hermon_close_hca_cmd_post()
1373 1373 * Context: Can be called from interrupt or base context.
1374 1374 * (Currently called only from attach() and/or detach() path contexts)
1375 1375 */
1376 1376 int
1377 1377 hermon_close_hca_cmd_post(hermon_state_t *state, uint_t sleepflag)
1378 1378 {
1379 1379 hermon_cmd_post_t cmd;
1380 1380 int status;
1381 1381
1382 1382 /* Make sure we are called with the correct flag */
1383 1383 ASSERT(sleepflag == HERMON_CMD_NOSLEEP_SPIN);
1384 1384
1385 1385 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1386 1386
1387 1387
1388 1388 /* Setup and post the Hermon "CLOSE_HCA" command */
1389 1389 cmd.cp_inparm = 0;
1390 1390 cmd.cp_outparm = 0;
1391 1391 cmd.cp_inmod = 0;
1392 1392 cmd.cp_opcode = CLOSE_HCA;
1393 1393 cmd.cp_opmod = 0;
1394 1394 cmd.cp_flags = sleepflag;
1395 1395 status = hermon_cmd_post(state, &cmd);
1396 1396 return (status);
1397 1397 }
1398 1398
1399 1399
1400 1400 /*
1401 1401 * hermon_set_port_cmd_post()
1402 1402 * Context: Can be called from interrupt or base context.
1403 1403 * (Currently called only from attach() path context)
1404 1404 */
1405 1405 int
1406 1406 hermon_set_port_cmd_post(hermon_state_t *state, hermon_hw_set_port_t *initport,
1407 1407 uint_t port, uint_t sleepflag)
1408 1408 {
1409 1409 hermon_mbox_info_t mbox_info;
1410 1410 hermon_cmd_post_t cmd;
1411 1411 uint64_t data;
1412 1412 uint_t size;
1413 1413 int status, i;
1414 1414
1415 1415 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1416 1416
1417 1417 /* Get an "In" mailbox for the command */
1418 1418 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
1419 1419 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
1420 1420 if (status != HERMON_CMD_SUCCESS) {
1421 1421 return (status);
1422 1422 }
1423 1423
1424 1424 /* Copy the Hermon "INIT_PORT" command into the mailbox */
1425 1425 size = sizeof (hermon_hw_set_port_t);
1426 1426 for (i = 0; i < (size >> 3); i++) {
1427 1427 data = ((uint64_t *)initport)[i];
1428 1428 ddi_put64(mbox_info.mbi_in->mb_acchdl,
1429 1429 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
1430 1430 }
1431 1431
1432 1432 /* Sync the mailbox for the device to read */
1433 1433 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
1434 1434
1435 1435 /* Setup and post the Hermon "SET_PORT" command */
1436 1436 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
1437 1437 cmd.cp_outparm = 0;
1438 1438 cmd.cp_inmod = port;
1439 1439 cmd.cp_opcode = SET_PORT;
1440 1440 cmd.cp_opmod = 0;
1441 1441 cmd.cp_flags = sleepflag;
1442 1442 status = hermon_cmd_post(state, &cmd);
1443 1443
1444 1444 /* Free the mailbox */
1445 1445 hermon_mbox_free(state, &mbox_info);
1446 1446 return (status);
1447 1447 }
1448 1448
1449 1449
1450 1450 /*
1451 1451 * hermon_init_port_cmd_post()
1452 1452 * Context: Can be called from interrupt or base context.
1453 1453 * (Currently called only from attach() and/or detach() path contexts)
1454 1454 */
1455 1455 int
1456 1456 hermon_init_port_cmd_post(hermon_state_t *state, uint_t port, uint_t sleepflag)
1457 1457 {
1458 1458 hermon_cmd_post_t cmd;
1459 1459 int status;
1460 1460
1461 1461 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1462 1462
1463 1463 /* Setup and post the Hermon "INIT_PORT" command */
1464 1464 cmd.cp_inparm = 0;
1465 1465 cmd.cp_outparm = 0;
1466 1466 cmd.cp_inmod = port;
1467 1467 cmd.cp_opcode = INIT_PORT;
1468 1468 cmd.cp_opmod = 0;
1469 1469 cmd.cp_flags = sleepflag;
1470 1470 status = hermon_cmd_post(state, &cmd);
1471 1471
1472 1472 return (status);
1473 1473 }
1474 1474
1475 1475
1476 1476 /*
1477 1477 * hermon_close_port_cmd_post()
1478 1478 * Context: Can be called from interrupt or base context.
1479 1479 * (Currently called only from attach() and/or detach() path contexts)
1480 1480 */
1481 1481 int
1482 1482 hermon_close_port_cmd_post(hermon_state_t *state, uint_t port, uint_t sleepflag)
1483 1483 {
1484 1484 hermon_cmd_post_t cmd;
1485 1485 int status;
1486 1486
1487 1487 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1488 1488
1489 1489 /* Setup and post the Hermon "CLOSE_PORT" command */
1490 1490 cmd.cp_inparm = 0;
1491 1491 cmd.cp_outparm = 0;
1492 1492 cmd.cp_inmod = port;
1493 1493 cmd.cp_opcode = CLOSE_PORT;
1494 1494 cmd.cp_opmod = 0;
1495 1495 cmd.cp_flags = sleepflag;
1496 1496 status = hermon_cmd_post(state, &cmd);
1497 1497 return (status);
1498 1498 }
1499 1499
1500 1500
1501 1501 /*
1502 1502 * hermon_mod_stat_cfg_cmd_post()
1503 1503 * Context: Can be called only from attach() path
1504 1504 *
1505 1505 * This routine was initially implemented to enable SRQ. That's no longer needed
1506 1506 * in hermon, and the code is conditionally compiled OUT, but left here because
1507 1507 * there are other static configuration parameters we might one day want to set
1508 1508 */
1509 1509 #ifdef HERMON_NO_MOD_STAT_CFG
1510 1510 int
1511 1511 hermon_mod_stat_cfg_cmd_post(hermon_state_t *state)
1512 1512 {
1513 1513 hermon_mbox_info_t mbox_info;
1514 1514 hermon_cmd_post_t cmd;
1515 1515 hermon_hw_mod_stat_cfg_t *mod;
1516 1516 hermon_hw_msg_in_mod_t inmod;
1517 1517 uint64_t data;
1518 1518 uint_t size;
1519 1519 int status, i;
1520 1520
1521 1521 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1522 1522
1523 1523 /*
1524 1524 * "MOD_STAT_CFG" needs an INMBOX parameter, to specify what operations
1525 1525 * to do. However, at the point in time that we call this command, the
1526 1526 * DDR has not yet been initialized, and all INMBOX'es are located in
1527 1527 * DDR. Because we want to call MOD_STAT_CFG before QUERY_DEVLIM is
1528 1528 * called, and thus call it before DDR is setup, we simply use an
1529 1529 * OUTMBOX memory location here as our INMBOX parameter.
1530 1530 */
1531 1531 mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
1532 1532 status = hermon_mbox_alloc(state, &mbox_info, HERMON_NOSLEEP);
1533 1533 if (status != HERMON_CMD_SUCCESS) {
1534 1534 return (status);
1535 1535 }
1536 1536
1537 1537 /*
1538 1538 * Allocate on the heap our 'mod_stat_cfg' structure. We want to
1539 1539 * ideally move all of this on to the stack in the future, but this
1540 1540 * works well for now.
1541 1541 */
1542 1542 mod = (hermon_hw_mod_stat_cfg_t *)kmem_zalloc(
1543 1543 sizeof (hermon_hw_mod_stat_cfg_t), KM_SLEEP);
1544 1544
1545 1545 /* Setup "MOD_STAT_CFG" settings */
1546 1546 mod->srq_m = 1;
1547 1547 mod->srq = state->hs_cfg_profile->cp_srq_enable;
1548 1548
1549 1549 if (mod->srq) {
1550 1550 /* use DEV_LIMS num srq */
1551 1551 mod->log_max_srq = state->hs_cfg_profile->cp_log_num_srq;
1552 1552 } else {
1553 1553 mod->log_max_srq = 0;
1554 1554 }
1555 1555
1556 1556 /* Copy the "MOD_STAT_CFG" command into the "In" mailbox */
1557 1557 size = sizeof (hermon_hw_mod_stat_cfg_t);
1558 1558 for (i = 0; i < (size >> 3); i++) {
1559 1559 data = ((uint64_t *)mod)[i];
1560 1560 ddi_put64(mbox_info.mbi_in->mb_acchdl,
1561 1561 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
1562 1562 }
1563 1563
1564 1564 /* Sync the mailbox for the device to read */
1565 1565 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
1566 1566
1567 1567 /* Setup and post the Hermon "MOD_STAT_CFG" command */
1568 1568 cmd.cp_inparm = mbox_info.mbi_out->mb_mapaddr;
1569 1569 cmd.cp_outparm = 0;
1570 1570 cmd.cp_inmod = 0;
1571 1571 cmd.cp_opcode = MOD_STAT_CFG;
1572 1572 cmd.cp_opmod = HERMON_MOD_STAT_CFG_PTR;
1573 1573 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
1574 1574 status = hermon_cmd_post(state, &cmd);
1575 1575
1576 1576 /* Free "MOD_STAT_CFG" struct */
1577 1577 kmem_free(mod, sizeof (hermon_hw_mod_stat_cfg_t));
1578 1578
1579 1579 /* Free the mailbox */
1580 1580 hermon_mbox_free(state, &mbox_info);
1581 1581 return (status);
1582 1582 }
1583 1583 #endif
1584 1584
1585 1585
1586 1586 /*
1587 1587 * hermon_map_cmd_post()
1588 1588 * Context: Can be called only from user or kernel context
1589 1589 *
1590 1590 * Generic routine to map FW, ICMA, and ICM.
1591 1591 */
1592 1592 int
1593 1593 hermon_map_cmd_post(hermon_state_t *state, hermon_dma_info_t *dma,
1594 1594 uint16_t opcode, ddi_dma_cookie_t cookie, uint_t ccount)
1595 1595 {
1596 1596 hermon_mbox_info_t mbox_info;
1597 1597 hermon_cmd_post_t cmd;
1598 1598 hermon_hw_vpm_t vpm;
1599 1599 uint64_t data;
1600 1600 uint64_t paddr, vaddr;
1601 1601 uint_t size;
1602 1602 int status, i, j, k = 0;
1603 1603 int max_mailbox_size;
1604 1604 int cookie_num_icm_pages;
1605 1605 int num_vpm_entries;
1606 1606 int log2_npages;
1607 1607 int npages;
1608 1608
1609 1609 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1610 1610
1611 1611 /* Allocate an IN mailbox */
1612 1612 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
1613 1613 status = hermon_mbox_alloc(state, &mbox_info, HERMON_SLEEP);
1614 1614 if (status != HERMON_CMD_SUCCESS) {
1615 1615 return (status);
1616 1616 }
1617 1617
1618 1618 /* Initialize cmd parameters */
1619 1619 cmd.cp_outparm = 0;
1620 1620 cmd.cp_opcode = opcode;
1621 1621 cmd.cp_opmod = 0;
1622 1622 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
1623 1623
1624 1624 /*
1625 1625 * Allocate a list of VPM (Virtual Physical Mapping) structures.
1626 1626 * A VPM encodes a power-of-2 number of DMA pages that have been
1627 1627 * allocated and are passed in the dma_info. We need to break up
1628 1628 * the DMA cookies that are in the dma_info into power-of-2 page
1629 1629 * mappings. We also need to keep track of the number of VPMs we
1630 1630 * have total, as it is used as the inmod for this command.
1631 1631 */
1632 1632
1633 1633 /* Start with the ICM address passed and the first cookie */
1634 1634 vaddr = dma->icmaddr;
1635 1635
1636 1636 /* Initialize the VPM count and the VPM struct */
1637 1637 num_vpm_entries = 0;
1638 1638 size = sizeof (hermon_hw_vpm_t);
1639 1639 bzero(&vpm, size);
1640 1640
1641 1641 /*
1642 1642 * Establish a max mailbox size (in VPM entries). If we reach this,
1643 1643 * we must post a MAP command, reinitialzie num_vpm_entries, and
1644 1644 * continue.
1645 1645 */
1646 1646 max_mailbox_size = HERMON_MBOX_SIZE / size;
1647 1647
1648 1648 /*
1649 1649 * First, walk through the DMA cookies and build VPMs from them.
1650 1650 */
1651 1651 while (ccount-- > 0) {
1652 1652
1653 1653 /* Determine the number of ICM pages in this cookie. */
1654 1654 cookie_num_icm_pages = cookie.dmac_size / HERMON_PAGESIZE;
1655 1655
1656 1656 /* Initialize this set of VPM's starting physical address. */
1657 1657 paddr = cookie.dmac_laddress;
1658 1658
1659 1659 /*
1660 1660 * Now build a set of VPMs for this cookie's memory, breaking
1661 1661 * up the cookies into multiple VPMs if necessary to achieve
1662 1662 * the required power-of-2 number of pages per VPM. Once each
1663 1663 * VPM is constructed, write it out to the mailbox memory.
1664 1664 */
1665 1665 for (i = cookie_num_icm_pages; i > 0; i -= npages) {
1666 1666 log2_npages = highbit(i) - 1;
1667 1667 npages = (1 << log2_npages);
1668 1668 /* Ensure this chunk is aligned on it's own size */
1669 1669 while (((npages * HERMON_PAGESIZE - 1) & paddr) != 0) {
1670 1670 log2_npages--;
1671 1671 npages = (1 << log2_npages);
1672 1672 }
1673 1673 vpm.log2sz = log2_npages;
1674 1674
1675 1675 vpm.paddr_l = (uint32_t)(paddr >> 12);
1676 1676 vpm.paddr_h = (uint32_t)(paddr >> 32);
1677 1677 /* Increment the paddr for the next VPM */
1678 1678 paddr += npages * HERMON_PAGESIZE;
1679 1679
1680 1680 if (opcode == MAP_ICM) {
1681 1681 vpm.vaddr_l = (uint32_t)(vaddr >> 12);
1682 1682 vpm.vaddr_h = (uint32_t)(vaddr >> 32);
1683 1683 /* Increment the ICM address for the next VPM */
1684 1684 vaddr += npages * HERMON_PAGESIZE;
1685 1685 }
1686 1686
1687 1687 /*
1688 1688 * Copy this VPM into the "In" mailbox. Note we're
1689 1689 * using 'k' as the offset from mb_addr for this cmd.
1690 1690 */
1691 1691 for (j = 0; j < (size >> 3); j++, k++) {
1692 1692 data = ((uint64_t *)(void *)&vpm)[j];
1693 1693 ddi_put64(mbox_info.mbi_in->mb_acchdl,
1694 1694 ((uint64_t *)mbox_info.mbi_in->mb_addr + k),
1695 1695 data);
1696 1696 }
1697 1697
1698 1698 /*
1699 1699 * Increment the number of VPM entries and check
1700 1700 * against max mailbox size. If we have reached
1701 1701 * the maximum mailbox size, post the map cmd.
1702 1702 */
1703 1703 if (++num_vpm_entries == max_mailbox_size) {
1704 1704
1705 1705 /* Sync the mailbox for the device to read */
1706 1706 hermon_mbox_sync(mbox_info.mbi_in, 0, (size *
1707 1707 num_vpm_entries), DDI_DMA_SYNC_FORDEV);
1708 1708
1709 1709 /* Setup and post the command */
1710 1710 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
1711 1711 cmd.cp_inmod = num_vpm_entries;
1712 1712 status = hermon_cmd_post(state, &cmd);
1713 1713 if (status != HERMON_CMD_SUCCESS) {
1714 1714 cmn_err(CE_NOTE, "hermon%d: %s cmd "
1715 1715 "failed (0x%x)", state->hs_instance,
1716 1716 opcode == MAP_FA ? "MAP_FA" :
1717 1717 opcode == MAP_ICM ? "MAP_ICM" :
1718 1718 opcode == MAP_ICM_AUX ? "MAP_ICMA" :
1719 1719 "UNKNOWN", status);
1720 1720 goto map_fail;
1721 1721 }
1722 1722
1723 1723 /*
1724 1724 * Reinitialize num_vpm_entries, and the
1725 1725 * mb_addr offset
1726 1726 */
1727 1727 num_vpm_entries = k = 0;
1728 1728 }
1729 1729 }
1730 1730
1731 1731 /* If count remains, move onto the next cookie */
1732 1732 if (ccount != 0) {
1733 1733 ddi_dma_nextcookie(dma->dma_hdl, &cookie);
1734 1734 }
1735 1735 }
1736 1736
1737 1737 if (num_vpm_entries) {
1738 1738
1739 1739 /* Sync the mailbox for the device to read */
1740 1740 hermon_mbox_sync(mbox_info.mbi_in, 0, (size * num_vpm_entries),
1741 1741 DDI_DMA_SYNC_FORDEV);
1742 1742
1743 1743 /* Setup and post the command */
1744 1744 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
1745 1745 cmd.cp_inmod = num_vpm_entries;
1746 1746 status = hermon_cmd_post(state, &cmd);
1747 1747 if (status != HERMON_CMD_SUCCESS) {
1748 1748 cmn_err(CE_NOTE, "hermon%d: %s cmd "
1749 1749 "failed (0x%x)", state->hs_instance,
1750 1750 opcode == MAP_FA ? "MAP_FA" :
1751 1751 opcode == MAP_ICM ? "MAP_ICM" :
1752 1752 opcode == MAP_ICM_AUX ? "MAP_ICMA" :
1753 1753 "UNKNOWN", status);
1754 1754 goto map_fail;
1755 1755 }
1756 1756 }
1757 1757
1758 1758 map_fail:
1759 1759 /* Free the mailbox */
1760 1760 hermon_mbox_free(state, &mbox_info);
1761 1761 return (status);
1762 1762 }
1763 1763
1764 1764
1765 1765 /*
1766 1766 * hermon_unmap_fa_cmd_post()
1767 1767 * Context: Can be called only from attach() path
1768 1768 */
1769 1769 int
1770 1770 hermon_unmap_fa_cmd_post(hermon_state_t *state)
1771 1771 {
1772 1772 hermon_cmd_post_t cmd;
1773 1773 int status;
1774 1774
1775 1775 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1776 1776
1777 1777 /* Setup and post the Hermon "UNMAP_FA" command */
1778 1778 cmd.cp_inparm = 0;
1779 1779 cmd.cp_outparm = 0;
1780 1780 cmd.cp_inmod = 0;
1781 1781 cmd.cp_opcode = UNMAP_FA;
1782 1782 cmd.cp_opmod = 0;
1783 1783 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
1784 1784 status = hermon_cmd_post(state, &cmd);
1785 1785
1786 1786 return (status);
1787 1787 }
1788 1788
1789 1789
1790 1790 /*
1791 1791 * hermon_run_fw_cmd_post()
1792 1792 * Context: Can be called only from attach() path
1793 1793 */
1794 1794 int
1795 1795 hermon_run_fw_cmd_post(hermon_state_t *state)
1796 1796 {
1797 1797 hermon_cmd_post_t cmd;
1798 1798 int status;
1799 1799
1800 1800 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1801 1801
1802 1802 /* Setup and post the Hermon "RUN_FW" command */
1803 1803 cmd.cp_inparm = 0;
1804 1804 cmd.cp_outparm = 0;
1805 1805 cmd.cp_inmod = 0;
1806 1806 cmd.cp_opcode = RUN_FW;
1807 1807 cmd.cp_opmod = 0;
1808 1808 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
1809 1809
1810 1810 status = hermon_cmd_post(state, &cmd);
1811 1811 #ifdef FMA_TEST
1812 1812 if (hermon_test_num == -2) {
1813 1813 status = HERMON_CMD_BAD_NVMEM;
1814 1814 /*
1815 1815 * No need of an ereport here since this case
1816 1816 * is treated as a degradation later.
1817 1817 */
1818 1818 HERMON_FMANOTE(state, HERMON_FMA_BADNVMEM);
1819 1819 }
1820 1820 #endif
1821 1821 return (status);
1822 1822 }
1823 1823
1824 1824
1825 1825 /*
1826 1826 * hermon_set_icm_size_cmd_post()
1827 1827 * Context: Can be called only from attach() path
1828 1828 */
1829 1829 int
1830 1830 hermon_set_icm_size_cmd_post(hermon_state_t *state)
1831 1831 {
1832 1832 hermon_cmd_post_t cmd;
1833 1833 int status;
1834 1834
1835 1835 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1836 1836
1837 1837 /* Setup and post the Hermon "SET_ICM_SIZE" command */
1838 1838 cmd.cp_inparm = (uint64_t)state->hs_icm_sz;
1839 1839 cmd.cp_outparm = 0;
1840 1840 cmd.cp_inmod = 0;
1841 1841 cmd.cp_opcode = SET_ICM_SIZE;
1842 1842 cmd.cp_opmod = 0;
1843 1843 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
1844 1844 status = hermon_cmd_post(state, &cmd);
1845 1845
1846 1846 /*
1847 1847 * Aux ICM size in 4K pages returned in output param
1848 1848 * convert it to bytes
1849 1849 */
1850 1850 state->hs_icma_sz = (uint64_t)(cmd.cp_outparm << HERMON_PAGESHIFT);
1851 1851 return (status);
1852 1852 }
1853 1853
1854 1854
1855 1855 /*
1856 1856 * hermon_unmap_icm_aux_cmd_post()
1857 1857 * Context: Can be called only from attach() path
1858 1858 */
1859 1859 int
1860 1860 hermon_unmap_icm_aux_cmd_post(hermon_state_t *state)
1861 1861 {
1862 1862 hermon_cmd_post_t cmd;
1863 1863 int status;
1864 1864
1865 1865 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1866 1866
1867 1867 /* Setup and post the Hermon "UNMAP_ICM_AUX" command */
1868 1868 cmd.cp_inparm = 0;
1869 1869 cmd.cp_outparm = 0;
1870 1870 cmd.cp_inmod = 0;
1871 1871 cmd.cp_opcode = UNMAP_ICM_AUX;
1872 1872 cmd.cp_opmod = 0;
1873 1873 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
1874 1874 status = hermon_cmd_post(state, &cmd);
1875 1875 return (status);
1876 1876 }
1877 1877
1878 1878
1879 1879 /*
1880 1880 * hermon_unmap_icm_cmd_post()
1881 1881 * Context: Can be called from base or attach context
1882 1882 */
1883 1883 int
1884 1884 hermon_unmap_icm_cmd_post(hermon_state_t *state, hermon_dma_info_t *dma_info)
1885 1885 {
1886 1886 hermon_cmd_post_t cmd;
1887 1887 uint64_t addr;
1888 1888 uint32_t npages;
1889 1889 int status;
1890 1890
1891 1891 /*
1892 1892 * Setup and post the Hermon "UNMAP_ICM" command. If a
1893 1893 * hermon_dma_info_t was passed, we want to unmap a set
1894 1894 * of pages. Otherwise, unmap all of ICM.
1895 1895 */
1896 1896 if (dma_info != NULL) {
1897 1897 addr = dma_info->icmaddr;
1898 1898 npages = dma_info->length / HERMON_PAGESIZE;
1899 1899 } else {
1900 1900 addr = 0;
1901 1901 npages = state->hs_icm_sz / HERMON_PAGESIZE;
1902 1902 }
1903 1903
1904 1904 /* Setup and post the Hermon "UNMAP_ICM" command */
1905 1905 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1906 1906 cmd.cp_inparm = addr;
1907 1907 cmd.cp_outparm = 0;
1908 1908 cmd.cp_inmod = npages;
1909 1909 cmd.cp_opcode = UNMAP_ICM;
1910 1910 cmd.cp_opmod = 0;
1911 1911 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
1912 1912 status = hermon_cmd_post(state, &cmd);
1913 1913 return (status);
1914 1914 }
1915 1915
1916 1916
1917 1917 /*
1918 1918 * hermon_mad_ifc_cmd_post()
1919 1919 * Context: Can be called from interrupt or base context.
1920 1920 */
1921 1921 int
1922 1922 hermon_mad_ifc_cmd_post(hermon_state_t *state, uint_t port,
1923 1923 uint_t sleepflag, uint32_t *mad, uint32_t *resp)
1924 1924 {
1925 1925 hermon_mbox_info_t mbox_info;
1926 1926 hermon_cmd_post_t cmd;
1927 1927 uint_t size;
1928 1928 int status;
1929 1929
1930 1930 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1931 1931
1932 1932 /* Get "In" and "Out" mailboxes for the command */
1933 1933 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
1934 1934 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
1935 1935 if (status != HERMON_CMD_SUCCESS) {
1936 1936 return (status);
1937 1937 }
1938 1938
1939 1939 /* Copy the request MAD into the "In" mailbox */
1940 1940 size = HERMON_CMD_MAD_IFC_SIZE;
1941 1941 bcopy(mad, mbox_info.mbi_in->mb_addr, size);
1942 1942
1943 1943 /* Sync the mailbox for the device to read */
1944 1944 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
1945 1945
1946 1946 /* Setup the Hermon "MAD_IFC" command */
1947 1947 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
1948 1948 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
1949 1949 cmd.cp_inmod = port;
1950 1950 cmd.cp_opcode = MAD_IFC;
1951 1951 cmd.cp_opmod = HERMON_CMD_MKEY_CHECK; /* Enable MKey checking */
1952 1952 cmd.cp_flags = sleepflag;
1953 1953 status = hermon_cmd_post(state, &cmd);
1954 1954 if (status != HERMON_CMD_SUCCESS) {
1955 1955 goto mad_ifc_fail;
1956 1956 }
1957 1957
1958 1958 /* Sync the mailbox to read the results */
1959 1959 hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
1960 1960
1961 1961 /* Copy the response MAD into "resp" */
1962 1962 bcopy(mbox_info.mbi_out->mb_addr, resp, size);
1963 1963
1964 1964 mad_ifc_fail:
1965 1965 /* Free the mailbox */
1966 1966 hermon_mbox_free(state, &mbox_info);
1967 1967 return (status);
1968 1968 }
1969 1969
1970 1970
1971 1971 /*
1972 1972 * hermon_getportinfo_cmd_post()
1973 1973 * Context: Can be called from interrupt or base context.
1974 1974 */
1975 1975 int
1976 1976 hermon_getportinfo_cmd_post(hermon_state_t *state, uint_t port,
1977 1977 uint_t sleepflag, sm_portinfo_t *portinfo)
1978 1978 {
1979 1979 hermon_mbox_info_t mbox_info;
1980 1980 hermon_cmd_post_t cmd;
1981 1981 uint32_t *mbox;
1982 1982 uint_t size;
1983 1983 int status, i;
1984 1984
1985 1985 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1986 1986
1987 1987 /* Get "In" and "Out" mailboxes for the command */
1988 1988 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
1989 1989 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
1990 1990 if (status != HERMON_CMD_SUCCESS) {
1991 1991 return (status);
1992 1992 }
1993 1993
1994 1994 /* Build the GetPortInfo request MAD in the "In" mailbox */
1995 1995 size = HERMON_CMD_MAD_IFC_SIZE;
1996 1996 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
1997 1997 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
1998 1998 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
1999 1999 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2000 2000 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2001 2001 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_PORTINFO);
2002 2002 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], port);
2003 2003 for (i = 6; i < (size >> 2); i++) {
2004 2004 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
2005 2005 }
2006 2006
2007 2007 /* Sync the mailbox for the device to read */
2008 2008 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2009 2009
2010 2010 /* Setup the Hermon "MAD_IFC" command */
2011 2011 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2012 2012 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
2013 2013 cmd.cp_inmod = port;
2014 2014 cmd.cp_opcode = MAD_IFC;
2015 2015 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK; /* No MKey checking */
2016 2016 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN; /* NO SLEEP */
2017 2017 status = hermon_cmd_post(state, &cmd);
2018 2018 if (status != HERMON_CMD_SUCCESS) {
2019 2019 goto getportinfo_fail;
2020 2020 }
2021 2021
2022 2022 /* Sync the mailbox to read the results */
2023 2023 size = sizeof (sm_portinfo_t);
2024 2024 hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
2025 2025 size, DDI_DMA_SYNC_FORCPU);
2026 2026
2027 2027 /*
2028 2028 * Copy GetPortInfo response MAD into "portinfo". Do any endian
2029 2029 * swapping that may be necessary to flip any of the "portinfo"
2030 2030 * fields
2031 2031 */
2032 2032 bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
2033 2033 HERMON_CMD_MADDATA_OFFSET), portinfo, size);
2034 2034 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*portinfo))
2035 2035 HERMON_GETPORTINFO_SWAP(portinfo);
2036 2036
2037 2037 getportinfo_fail:
2038 2038 /* Free the mailbox */
2039 2039 hermon_mbox_free(state, &mbox_info);
2040 2040 return (status);
2041 2041 }
2042 2042
2043 2043 /*
2044 2044 * hermon_is_ext_port_counters_supported()
2045 2045 *
2046 2046 * Determine weather extended port counters are supported or not by sending
2047 2047 * ClassPortInfo perf mgmt class MAD.
2048 2048 */
2049 2049 int
2050 2050 hermon_is_ext_port_counters_supported(hermon_state_t *state, uint_t port,
2051 2051 uint_t sleepflag, int *ext_width_supported)
2052 2052 {
2053 2053 hermon_mbox_info_t mbox_info;
2054 2054 hermon_cmd_post_t cmd;
2055 2055 uint64_t data;
2056 2056 uint32_t *mbox;
2057 2057 int status;
2058 2058
2059 2059 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2060 2060
2061 2061 /* Get "In" and "Out" mailboxes for the command */
2062 2062 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2063 2063 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2064 2064 if (status != HERMON_CMD_SUCCESS) {
2065 2065 return (status);
2066 2066 }
2067 2067
2068 2068 /* Build the ClassPortInfo request MAD in the "In" mailbox */
2069 2069 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2070 2070
2071 2071 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_PERF_GET);
2072 2072 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2073 2073 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2074 2074 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2075 2075 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4],
2076 2076 HERMON_CMD_CLASSPORTINFO);
2077 2077 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], HERMON_CMD_PERFATTR);
2078 2078
2079 2079 /* Sync the mailbox for the device to read */
2080 2080 hermon_mbox_sync(mbox_info.mbi_in, 0, HERMON_CMD_MAD_IFC_SIZE,
2081 2081 DDI_DMA_SYNC_FORDEV);
2082 2082
2083 2083 /* Setup the Hermon "MAD_IFC" command */
2084 2084 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2085 2085 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
2086 2086 cmd.cp_inmod = port;
2087 2087 cmd.cp_opcode = MAD_IFC;
2088 2088 /* No MKey and BKey checking */
2089 2089 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK | HERMON_CMD_BKEY_DONTCHECK;
2090 2090 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN; /* NO SLEEP */
2091 2091 status = hermon_cmd_post(state, &cmd);
2092 2092 if (status != HERMON_CMD_SUCCESS) {
2093 2093 goto fail;
2094 2094 }
2095 2095
2096 2096 /* Sync the mailbox to read the results */
2097 2097 hermon_mbox_sync(mbox_info.mbi_out, 0, HERMON_CMD_MAD_IFC_SIZE,
2098 2098 DDI_DMA_SYNC_FORCPU);
2099 2099
2100 2100 /*
2101 2101 * We can discard the MAD header and the reserved area of the
2102 2102 * perf mgmt class MAD
2103 2103 */
2104 2104 data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2105 2105 ((uint64_t *)mbox_info.mbi_out->mb_addr + 8));
2106 2106 *ext_width_supported = (data & (HERMON_IS_EXT_WIDTH_SUPPORTED |
2107 2107 HERMON_IS_EXT_WIDTH_SUPPORTED_NOIETF)) ? 1 : 0;
2108 2108
2109 2109 fail:
2110 2110 /* Free the mailbox */
2111 2111 hermon_mbox_free(state, &mbox_info);
2112 2112 return (status);
2113 2113 }
2114 2114
2115 2115 /*
2116 2116 * hermon_getextpefcntr_cmd_post()
2117 2117 *
2118 2118 * Read the extended performance counters of the specified port and
2119 2119 * copy them into perfinfo.
2120 2120 */
2121 2121 int
2122 2122 hermon_getextperfcntr_cmd_post(hermon_state_t *state, uint_t port,
2123 2123 uint_t sleepflag, hermon_hw_sm_extperfcntr_t *perfinfo)
2124 2124 {
2125 2125 hermon_mbox_info_t mbox_info;
2126 2126 hermon_cmd_post_t cmd;
2127 2127 uint64_t data;
2128 2128 uint32_t *mbox;
2129 2129 int status, i;
2130 2130
2131 2131 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2132 2132
2133 2133 /* Get "In" and "Out" mailboxes for the command */
2134 2134 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2135 2135 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2136 2136 if (status != HERMON_CMD_SUCCESS) {
2137 2137 return (status);
2138 2138 }
2139 2139
2140 2140 /* Build PortCountersExtended request MAD in the "In" mailbox */
2141 2141 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2142 2142
2143 2143 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_PERF_GET);
2144 2144 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2145 2145 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2146 2146 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2147 2147 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4],
2148 2148 HERMON_CMD_EXTPERFCNTRS);
2149 2149 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], HERMON_CMD_PERFATTR);
2150 2150 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16], (port << 16));
2151 2151
2152 2152 /* Sync the mailbox for the device to read */
2153 2153 hermon_mbox_sync(mbox_info.mbi_in, 0, HERMON_CMD_MAD_IFC_SIZE,
2154 2154 DDI_DMA_SYNC_FORDEV);
2155 2155
2156 2156 /* Setup the Hermon "MAD_IFC" command */
2157 2157 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2158 2158 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
2159 2159 cmd.cp_inmod = port;
2160 2160 cmd.cp_opcode = MAD_IFC;
2161 2161 /* No MKey and BKey checking */
2162 2162 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK | HERMON_CMD_BKEY_DONTCHECK;
2163 2163 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN; /* NO SLEEP */
2164 2164 status = hermon_cmd_post(state, &cmd);
2165 2165 if (status != HERMON_CMD_SUCCESS) {
2166 2166 goto fail;
2167 2167 }
2168 2168
2169 2169 /* Sync the mailbox to read the results */
2170 2170 hermon_mbox_sync(mbox_info.mbi_out, 0, HERMON_CMD_MAD_IFC_SIZE,
2171 2171 DDI_DMA_SYNC_FORCPU);
2172 2172
2173 2173 /*
2174 2174 * Copy Perfcounters into "perfinfo". We can discard the MAD
2175 2175 * header and the reserved area of the perf mgmt class MAD.
2176 2176 */
2177 2177 for (i = 0; i < (sizeof (hermon_hw_sm_extperfcntr_t) >> 3); i++) {
2178 2178 data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2179 2179 ((uint64_t *)mbox_info.mbi_out->mb_addr + i + 8));
2180 2180 ((uint64_t *)(void *)perfinfo)[i] = data;
2181 2181 }
2182 2182
2183 2183 fail:
2184 2184 /* Free the mailbox */
2185 2185 hermon_mbox_free(state, &mbox_info);
2186 2186 return (status);
2187 2187 }
2188 2188
2189 2189 /*
2190 2190 * hermon_getpefcntr_cmd_post()
2191 2191 * Context: Can be called from interrupt or base context.
2192 2192 *
2193 2193 * If reset is zero, read the performance counters of the specified port and
2194 2194 * copy them into perfinfo.
2195 2195 * If reset is non-zero reset the performance counters of the specified port.
2196 2196 */
2197 2197 int
2198 2198 hermon_getperfcntr_cmd_post(hermon_state_t *state, uint_t port,
2199 2199 uint_t sleepflag, hermon_hw_sm_perfcntr_t *perfinfo, int reset)
2200 2200 {
2201 2201 hermon_mbox_info_t mbox_info;
2202 2202 hermon_cmd_post_t cmd;
2203 2203 uint64_t data;
2204 2204 uint32_t *mbox;
2205 2205 uint_t size;
2206 2206 int status, i;
2207 2207
2208 2208 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2209 2209
2210 2210 /* Get "In" and "Out" mailboxes for the command */
2211 2211 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2212 2212 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2213 2213 if (status != HERMON_CMD_SUCCESS) {
2214 2214 return (status);
2215 2215 }
2216 2216
2217 2217 /* Build the GetPortInfo request MAD in the "In" mailbox */
2218 2218 size = HERMON_CMD_MAD_IFC_SIZE;
2219 2219 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2220 2220
2221 2221 if (reset) {
2222 2222 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0],
2223 2223 HERMON_CMD_PERF_SET);
2224 2224 } else {
2225 2225 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0],
2226 2226 HERMON_CMD_PERF_GET);
2227 2227 }
2228 2228 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2229 2229 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2230 2230 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2231 2231 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_PERFCNTRS);
2232 2232 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], HERMON_CMD_PERFATTR);
2233 2233
2234 2234 if (reset) {
2235 2235 /* reset counters for XmitData, RcvData, XmitPkts, RcvPkts */
2236 2236 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16],
2237 2237 ((port << 16) | 0xf000));
2238 2238
2239 2239 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[22], 0);
2240 2240 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[23], 0);
2241 2241 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[24], 0);
2242 2242 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[25], 0);
2243 2243 } else
2244 2244 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16], (port << 16));
2245 2245
2246 2246 /* Sync the mailbox for the device to read */
2247 2247 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2248 2248
2249 2249 /* Setup the Hermon "MAD_IFC" command */
2250 2250 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2251 2251 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
2252 2252 cmd.cp_inmod = port;
2253 2253 cmd.cp_opcode = MAD_IFC;
2254 2254 /* No MKey and BKey checking */
2255 2255 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK | HERMON_CMD_BKEY_DONTCHECK;
2256 2256 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN; /* NO SLEEP */
2257 2257 status = hermon_cmd_post(state, &cmd);
2258 2258 if (status != HERMON_CMD_SUCCESS) {
2259 2259 goto getperfinfo_fail;
2260 2260 }
2261 2261
2262 2262 /* Sync the mailbox to read the results */
2263 2263 size = HERMON_CMD_MAD_IFC_SIZE;
2264 2264 hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
2265 2265
2266 2266 if (reset == 0) {
2267 2267 size = sizeof (hermon_hw_sm_perfcntr_t); /* for the copy */
2268 2268 /*
2269 2269 * Copy Perfcounters into "perfinfo". We can discard the MAD
2270 2270 * header and the 8 Quadword reserved area of the PERM mgmt
2271 2271 * class MAD
2272 2272 */
2273 2273
2274 2274 for (i = 0; i < size >> 3; i++) {
2275 2275 data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2276 2276 ((uint64_t *)mbox_info.mbi_out->mb_addr + i + 8));
2277 2277 ((uint64_t *)(void *)perfinfo)[i] = data;
2278 2278 }
2279 2279 }
2280 2280
2281 2281 getperfinfo_fail:
2282 2282 /* Free the mailbox */
2283 2283 hermon_mbox_free(state, &mbox_info);
2284 2284 return (status);
2285 2285 }
2286 2286
2287 2287
2288 2288
2289 2289 /*
2290 2290 * hermon_getnodeinfo_cmd_post()
2291 2291 * Context: Can be called from interrupt or base context.
2292 2292 * (Currently called only from attach() and detach() path contexts)
2293 2293 */
2294 2294 int
2295 2295 hermon_getnodeinfo_cmd_post(hermon_state_t *state, uint_t sleepflag,
2296 2296 sm_nodeinfo_t *nodeinfo)
2297 2297 {
2298 2298 hermon_mbox_info_t mbox_info;
2299 2299 hermon_cmd_post_t cmd;
2300 2300 uint32_t *mbox;
2301 2301 uint_t size;
2302 2302 int status, i;
2303 2303
2304 2304 /* Make sure we are called with the correct flag */
2305 2305 ASSERT(sleepflag == HERMON_CMD_NOSLEEP_SPIN);
2306 2306
2307 2307 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2308 2308
2309 2309 /* Get "In" and "Out" mailboxes for the command */
2310 2310 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2311 2311 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2312 2312 if (status != HERMON_CMD_SUCCESS) {
2313 2313 return (status);
2314 2314 }
2315 2315
2316 2316 /* Build the GetNodeInfo request MAD into the "In" mailbox */
2317 2317 size = HERMON_CMD_MAD_IFC_SIZE;
2318 2318 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2319 2319 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
2320 2320 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2321 2321 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2322 2322 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2323 2323 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_NODEINFO);
2324 2324 for (i = 5; i < (size >> 2); i++) {
2325 2325 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
2326 2326 }
2327 2327
2328 2328 /* Sync the mailbox for the device to read */
2329 2329 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2330 2330
2331 2331 /* Setup the Hermon "MAD_IFC" command */
2332 2332 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2333 2333 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
2334 2334 cmd.cp_inmod = 1; /* Get NodeInfo from port #1 */
2335 2335 cmd.cp_opcode = MAD_IFC;
2336 2336 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK; /* No MKey checking */
2337 2337 cmd.cp_flags = sleepflag;
2338 2338 status = hermon_cmd_post(state, &cmd);
2339 2339 if (status != HERMON_CMD_SUCCESS) {
2340 2340 goto getnodeinfo_fail;
2341 2341 }
2342 2342
2343 2343 /* Sync the mailbox to read the results */
2344 2344 size = sizeof (sm_nodeinfo_t);
2345 2345 hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
2346 2346 size, DDI_DMA_SYNC_FORCPU);
2347 2347
2348 2348 /*
2349 2349 * Copy GetNodeInfo response MAD into "nodeinfo". Do any endian
2350 2350 * swapping that may be necessary to flip any of the "nodeinfo"
2351 2351 * fields
2352 2352 */
2353 2353 bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
2354 2354 HERMON_CMD_MADDATA_OFFSET), nodeinfo, size);
2355 2355 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*nodeinfo))
2356 2356 HERMON_GETNODEINFO_SWAP(nodeinfo);
2357 2357
2358 2358 getnodeinfo_fail:
2359 2359 /* Free the mailbox */
2360 2360 hermon_mbox_free(state, &mbox_info);
2361 2361 return (status);
2362 2362 }
2363 2363
2364 2364
2365 2365 /*
2366 2366 * hermon_getnodedesc_cmd_post()
2367 2367 * Context: Can be called from interrupt or base context.
2368 2368 * (Currently called only from attach() and detach() path contexts)
2369 2369 */
2370 2370 int
2371 2371 hermon_getnodedesc_cmd_post(hermon_state_t *state, uint_t sleepflag,
2372 2372 sm_nodedesc_t *nodedesc)
2373 2373 {
2374 2374 hermon_mbox_info_t mbox_info;
2375 2375 hermon_cmd_post_t cmd;
2376 2376 uint32_t *mbox;
2377 2377 uint_t size;
2378 2378 int status, i;
2379 2379
2380 2380 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2381 2381
2382 2382 /* Get "In" and "Out" mailboxes for the command */
2383 2383 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2384 2384 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2385 2385 if (status != HERMON_CMD_SUCCESS) {
2386 2386 return (status);
2387 2387 }
2388 2388
2389 2389 /* Build the GetNodeDesc request MAD into the "In" mailbox */
2390 2390 size = HERMON_CMD_MAD_IFC_SIZE;
2391 2391 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2392 2392 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
2393 2393 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2394 2394 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2395 2395 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2396 2396 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_NODEDESC);
2397 2397 for (i = 5; i < (size >> 2); i++) {
2398 2398 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
2399 2399 }
2400 2400
2401 2401 /* Sync the mailbox for the device to read */
2402 2402 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2403 2403
2404 2404 /* Setup the Hermon "MAD_IFC" command */
2405 2405 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2406 2406 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
2407 2407 cmd.cp_inmod = 1; /* Get NodeDesc from port #1 */
2408 2408 cmd.cp_opcode = MAD_IFC;
2409 2409 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK; /* No MKey checking */
2410 2410 cmd.cp_flags = sleepflag;
2411 2411 status = hermon_cmd_post(state, &cmd);
2412 2412 if (status != HERMON_CMD_SUCCESS) {
2413 2413 goto getnodedesc_fail;
2414 2414 }
2415 2415
2416 2416 /* Sync the mailbox to read the results */
2417 2417 size = sizeof (sm_nodedesc_t);
2418 2418 hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
2419 2419 size, DDI_DMA_SYNC_FORCPU);
2420 2420
2421 2421 /* Copy GetNodeDesc response MAD into "nodedesc" */
2422 2422 bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
2423 2423 HERMON_CMD_MADDATA_OFFSET), nodedesc, size);
2424 2424
2425 2425 getnodedesc_fail:
2426 2426 /* Free the mailbox */
2427 2427 hermon_mbox_free(state, &mbox_info);
2428 2428 return (status);
2429 2429 }
2430 2430
2431 2431
2432 2432 /*
2433 2433 * hermon_getguidinfo_cmd_post()
2434 2434 * Context: Can be called from interrupt or base context.
2435 2435 */
2436 2436 int
2437 2437 hermon_getguidinfo_cmd_post(hermon_state_t *state, uint_t port,
2438 2438 uint_t guidblock, uint_t sleepflag, sm_guidinfo_t *guidinfo)
2439 2439 {
2440 2440 hermon_mbox_info_t mbox_info;
2441 2441 hermon_cmd_post_t cmd;
2442 2442 uint32_t *mbox;
2443 2443 uint_t size;
2444 2444 int status, i;
2445 2445
2446 2446 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2447 2447
2448 2448 /* Get "In" and "Out" mailboxes for the command */
2449 2449 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2450 2450 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2451 2451 if (status != HERMON_CMD_SUCCESS) {
2452 2452 return (status);
2453 2453 }
2454 2454
2455 2455 /* Build the GetGUIDInfo request MAD into the "In" mailbox */
2456 2456 size = HERMON_CMD_MAD_IFC_SIZE;
2457 2457 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2458 2458 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
2459 2459 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2460 2460 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2461 2461 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2462 2462 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_GUIDINFO);
2463 2463 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], guidblock);
2464 2464 for (i = 6; i < (size >> 2); i++) {
2465 2465 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
2466 2466 }
2467 2467
2468 2468 /* Sync the mailbox for the device to read */
2469 2469 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2470 2470
2471 2471 /* Setup the Hermon "MAD_IFC" command */
2472 2472 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2473 2473 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
2474 2474 cmd.cp_inmod = port;
2475 2475 cmd.cp_opcode = MAD_IFC;
2476 2476 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK; /* No MKey checking */
2477 2477 cmd.cp_flags = sleepflag;
2478 2478 status = hermon_cmd_post(state, &cmd);
2479 2479 if (status != HERMON_CMD_SUCCESS) {
2480 2480 goto getguidinfo_fail;
2481 2481 }
2482 2482
2483 2483 /* Sync the mailbox to read the results */
2484 2484 size = sizeof (sm_guidinfo_t);
2485 2485 hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
2486 2486 size, DDI_DMA_SYNC_FORCPU);
2487 2487
2488 2488 /*
2489 2489 * Copy GetGUIDInfo response MAD into "guidinfo". Do any endian
2490 2490 * swapping that may be necessary to flip the "guidinfo" fields
2491 2491 */
2492 2492 bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
2493 2493 HERMON_CMD_MADDATA_OFFSET), guidinfo, size);
2494 2494 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*guidinfo))
2495 2495 HERMON_GETGUIDINFO_SWAP(guidinfo);
2496 2496
2497 2497 getguidinfo_fail:
2498 2498 /* Free the mailbox */
2499 2499 hermon_mbox_free(state, &mbox_info);
2500 2500 return (status);
2501 2501 }
2502 2502
2503 2503
2504 2504 /*
2505 2505 * hermon_getpkeytable_cmd_post()
2506 2506 * Context: Can be called from interrupt or base context.
2507 2507 */
2508 2508 int
2509 2509 hermon_getpkeytable_cmd_post(hermon_state_t *state, uint_t port,
2510 2510 uint_t pkeyblock, uint_t sleepflag, sm_pkey_table_t *pkeytable)
2511 2511 {
2512 2512 hermon_mbox_info_t mbox_info;
2513 2513 hermon_cmd_post_t cmd;
2514 2514 uint32_t *mbox;
2515 2515 uint_t size;
2516 2516 int status, i;
2517 2517
2518 2518 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2519 2519
2520 2520 /* Get "In" and "Out" mailboxes for the command */
2521 2521 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2522 2522 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2523 2523 if (status != HERMON_CMD_SUCCESS) {
2524 2524 return (status);
2525 2525 }
2526 2526
2527 2527 /* Build the GetPkeyTable request MAD into the "In" mailbox */
2528 2528 size = HERMON_CMD_MAD_IFC_SIZE;
2529 2529 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2530 2530 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
2531 2531 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2532 2532 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2533 2533 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2534 2534 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_PKEYTBLE);
2535 2535 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], pkeyblock);
2536 2536 for (i = 6; i < (size >> 2); i++) {
2537 2537 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
2538 2538 }
2539 2539
2540 2540 /* Sync the mailbox for the device to read */
2541 2541 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2542 2542
2543 2543 /* Setup the Hermon "MAD_IFC" command */
2544 2544 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2545 2545 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
2546 2546 cmd.cp_inmod = port;
2547 2547 cmd.cp_opcode = MAD_IFC;
2548 2548 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK; /* No MKey checking */
2549 2549 cmd.cp_flags = sleepflag;
2550 2550 status = hermon_cmd_post(state, &cmd);
2551 2551 if (status != HERMON_CMD_SUCCESS) {
2552 2552 goto getpkeytable_fail;
2553 2553 }
2554 2554
2555 2555 /* Sync the mailbox to read the results */
2556 2556 size = sizeof (sm_pkey_table_t);
2557 2557 hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
2558 2558 size, DDI_DMA_SYNC_FORCPU);
2559 2559
2560 2560 /*
2561 2561 * Copy GetPKeyTable response MAD into "pkeytable". Do any endian
2562 2562 * swapping that may be necessary to flip the "pkeytable" fields
2563 2563 */
2564 2564 bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
2565 2565 HERMON_CMD_MADDATA_OFFSET), pkeytable, size);
2566 2566 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*pkeytable))
2567 2567 HERMON_GETPKEYTABLE_SWAP(pkeytable);
2568 2568
2569 2569 getpkeytable_fail:
2570 2570 /* Free the mailbox */
2571 2571 hermon_mbox_free(state, &mbox_info);
2572 2572 return (status);
2573 2573 }
2574 2574
2575 2575
2576 2576 /*
2577 2577 * hermon_write_mtt_cmd_post()
2578 2578 * Context: Can be called from interrupt or base context.
2579 2579 */
2580 2580 int
2581 2581 hermon_write_mtt_cmd_post(hermon_state_t *state, hermon_rsrc_t *mtt,
2582 2582 uint64_t start_addr, uint_t nummtt, uint_t sleepflag)
2583 2583 {
2584 2584 hermon_mbox_info_t mbox_info;
2585 2585 hermon_cmd_post_t cmd;
2586 2586 uint64_t data;
2587 2587 uint_t size;
2588 2588 int status;
2589 2589 int i;
2590 2590
2591 2591 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2592 2592
2593 2593 /* Get an "In" mailbox for the command */
2594 2594 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
2595 2595 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2596 2596 if (status != HERMON_CMD_SUCCESS) {
2597 2597 return (status);
2598 2598 }
2599 2599
2600 2600 /*
2601 2601 * The WRITE_MTT command input parameter contains the 64-bit addr of
2602 2602 * the first target MTT, followed by 64 bits reserved, followed by an
2603 2603 * array of MTT entries.
2604 2604 *
2605 2605 */
2606 2606 ddi_put64(mbox_info.mbi_in->mb_acchdl,
2607 2607 ((uint64_t *)mbox_info.mbi_in->mb_addr),
2608 2608 start_addr);
2609 2609
2610 2610 ddi_put64(mbox_info.mbi_in->mb_acchdl,
2611 2611 ((uint64_t *)mbox_info.mbi_in->mb_addr + 1), 0x0);
2612 2612
2613 2613 for (i = 0; i < nummtt; i++) {
2614 2614 data = ((uint64_t *)mtt->hr_addr)[i];
2615 2615 ddi_put64(mbox_info.mbi_in->mb_acchdl,
2616 2616 ((uint64_t *)mbox_info.mbi_in->mb_addr + i + 2), data);
2617 2617 }
2618 2618
2619 2619 /* Sync the mailbox for the device to read */
2620 2620 size = (nummtt << HERMON_MTT_SIZE_SHIFT) + HERMON_CMD_WRITEMTT_RSVD_SZ;
2621 2621 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2622 2622
2623 2623 /* Setup and post Hermon "WRITE_MTT" command */
2624 2624 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2625 2625 cmd.cp_outparm = 0;
2626 2626 cmd.cp_inmod = nummtt;
2627 2627 cmd.cp_opcode = WRITE_MTT;
2628 2628 cmd.cp_opmod = 0;
2629 2629 cmd.cp_flags = sleepflag;
2630 2630 status = hermon_cmd_post(state, &cmd);
2631 2631 if (status != HERMON_CMD_SUCCESS) {
2632 2632 cmn_err(CE_CONT, "WRITE_MTT failed (0x%x)\n", status);
2633 2633 }
2634 2634
2635 2635 /* Free the mailbox */
2636 2636 hermon_mbox_free(state, &mbox_info);
2637 2637 return (status);
2638 2638 }
2639 2639
2640 2640
2641 2641 /*
2642 2642 * hermon_sync_tpt_cmd_post()
2643 2643 * Context: Can be called from interrupt or base context.
2644 2644 */
2645 2645 int
2646 2646 hermon_sync_tpt_cmd_post(hermon_state_t *state, uint_t sleepflag)
2647 2647 {
2648 2648 hermon_cmd_post_t cmd;
2649 2649 int status;
2650 2650
2651 2651 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2652 2652
2653 2653 /* Setup and post the Hermon "SYNC_TPT" command */
2654 2654 cmd.cp_inparm = 0;
2655 2655 cmd.cp_outparm = 0;
2656 2656 cmd.cp_inmod = 0;
2657 2657 cmd.cp_opcode = SYNC_TPT;
2658 2658 cmd.cp_opmod = 0;
2659 2659 cmd.cp_flags = sleepflag;
2660 2660 status = hermon_cmd_post(state, &cmd);
2661 2661
2662 2662 return (status);
2663 2663 }
2664 2664
2665 2665 /*
2666 2666 * hermon_map_eq_cmd_post()
2667 2667 * Context: Can be called from interrupt or base context.
2668 2668 * (Currently called only from attach() and/or detach() path contexts)
2669 2669 */
2670 2670 int
2671 2671 hermon_map_eq_cmd_post(hermon_state_t *state, uint_t map, uint_t eqcindx,
2672 2672 uint64_t eqmapmask, uint_t sleepflag)
2673 2673 {
2674 2674 hermon_cmd_post_t cmd;
2675 2675 int status;
2676 2676
2677 2677 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2678 2678
2679 2679 /* Setup and post Hermon "MAP_EQ" command */
2680 2680 cmd.cp_inparm = eqmapmask;
2681 2681 cmd.cp_outparm = 0;
2682 2682 cmd.cp_inmod = eqcindx;
2683 2683 if (map != HERMON_CMD_MAP_EQ_EVT_MAP) {
2684 2684 cmd.cp_inmod |= HERMON_CMD_UNMAP_EQ_MASK;
2685 2685 }
2686 2686 cmd.cp_opcode = MAP_EQ;
2687 2687 cmd.cp_opmod = 0;
2688 2688 cmd.cp_flags = sleepflag;
2689 2689 status = hermon_cmd_post(state, &cmd);
2690 2690 return (status);
2691 2691 }
2692 2692
2693 2693
2694 2694 /*
2695 2695 * hermon_resize_cq_cmd_post()
2696 2696 * Context: Can be called from interrupt or base context.
2697 2697 */
2698 2698 int
2699 2699 hermon_resize_cq_cmd_post(hermon_state_t *state, hermon_hw_cqc_t *cqc,
2700 2700 uint_t cqcindx, uint32_t *prod_indx, uint_t sleepflag)
2701 2701 {
2702 2702 hermon_mbox_info_t mbox_info;
2703 2703 hermon_cmd_post_t cmd;
2704 2704 uint64_t data;
2705 2705 uint_t size;
2706 2706 int status, i;
2707 2707
2708 2708 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2709 2709
2710 2710 /* Get an "In" mailbox for the command */
2711 2711 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
2712 2712 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2713 2713 if (status != HERMON_CMD_SUCCESS) {
2714 2714 return (status);
2715 2715 }
2716 2716
2717 2717 /* Copy the Hermon "MODIFY_CQ" command into mailbox */
2718 2718 size = sizeof (hermon_hw_cqc_t);
2719 2719 for (i = 0; i < (size >> 3); i++) {
2720 2720 data = ((uint64_t *)(void *)cqc)[i];
2721 2721 ddi_put64(mbox_info.mbi_in->mb_acchdl,
2722 2722 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
2723 2723 }
2724 2724
2725 2725 /* Sync the mailbox for the device to read */
2726 2726 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2727 2727
2728 2728 /* Setup and post Hermon "MODIFY_CQ" command */
2729 2729 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2730 2730 cmd.cp_outparm = 0; /* resize cq */
2731 2731 cmd.cp_inmod = cqcindx;
2732 2732 cmd.cp_opcode = MODIFY_CQ;
2733 2733 cmd.cp_opmod = RESIZE_CQ;
2734 2734 cmd.cp_flags = sleepflag;
2735 2735 status = hermon_cmd_post(state, &cmd);
2736 2736
2737 2737 /*
2738 2738 * New "producer index" is returned in the upper 32 bits of
2739 2739 * command "outparam"
2740 2740 */
2741 2741 *prod_indx = (cmd.cp_outparm >> 32);
2742 2742
2743 2743 /* Free the mailbox */
2744 2744 hermon_mbox_free(state, &mbox_info);
2745 2745 return (status);
2746 2746 }
2747 2747
2748 2748
2749 2749 /*
2750 2750 * hermon_modify_cq_cmd_post()
2751 2751 * Context: Can be called from interrupt or base context.
2752 2752 */
2753 2753 int
2754 2754 hermon_modify_cq_cmd_post(hermon_state_t *state, hermon_hw_cqc_t *cqc,
2755 2755 uint_t cqcindx, uint_t opmod, uint_t sleepflag)
2756 2756 {
2757 2757 hermon_mbox_info_t mbox_info;
2758 2758 hermon_cmd_post_t cmd;
2759 2759 uint64_t data;
2760 2760 uint_t size;
2761 2761 int status, i;
2762 2762
2763 2763 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2764 2764
2765 2765 /* Get an "In" mailbox for the command */
2766 2766 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
2767 2767 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2768 2768 if (status != HERMON_CMD_SUCCESS) {
2769 2769 return (status);
2770 2770 }
2771 2771
2772 2772 /* Copy the Hermon "MODIFY_CQ" command into mailbox */
2773 2773 size = sizeof (hermon_hw_cqc_t);
2774 2774 for (i = 0; i < (size >> 3); i++) {
2775 2775 data = ((uint64_t *)(void *)cqc)[i];
2776 2776 ddi_put64(mbox_info.mbi_in->mb_acchdl,
2777 2777 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
2778 2778 }
2779 2779
2780 2780 /* Sync the mailbox for the device to read */
2781 2781 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2782 2782
2783 2783 /* Setup and post Hermon "MODIFY_CQ" command */
2784 2784 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
2785 2785 cmd.cp_outparm = 0;
2786 2786 cmd.cp_inmod = cqcindx;
2787 2787 cmd.cp_opcode = MODIFY_CQ;
2788 2788 cmd.cp_opmod = (uint16_t)opmod;
2789 2789 cmd.cp_flags = sleepflag;
2790 2790 status = hermon_cmd_post(state, &cmd);
2791 2791
2792 2792 /* Free the mailbox */
2793 2793 hermon_mbox_free(state, &mbox_info);
2794 2794 return (status);
2795 2795 }
2796 2796
2797 2797
2798 2798 /*
2799 2799 * hermon_cmn_qp_cmd_post()
2800 2800 * Context: Can be called from interrupt or base context.
2801 2801 *
2802 2802 * This is the common function for posting all the various types of
2803 2803 * QP state transition related Hermon commands. Since some of the
2804 2804 * commands differ from the others in the number (and type) of arguments
2805 2805 * that each require, this routine does checks based on opcode type
2806 2806 * (explained in more detail below).
2807 2807 *
2808 2808 * Note: This common function should be used only with the following
2809 2809 * opcodes: RTS2SQD_QP, TOERR_QP, TORST_QP, RST2INIT_QP, INIT2INIT_QP,
2810 2810 * INIT2RTR_QP, RTR2RTS_QP, RTS2RTS_QP, SQD2RTS_QP, and SQERR2RTS_QP.
2811 2811 */
2812 2812 int
2813 2813 hermon_cmn_qp_cmd_post(hermon_state_t *state, uint_t opcode,
2814 2814 hermon_hw_qpc_t *qp, uint_t qpindx, uint32_t opmask,
2815 2815 uint_t sleepflag)
2816 2816 {
2817 2817 hermon_mbox_info_t mbox_info;
2818 2818 hermon_cmd_post_t cmd;
2819 2819 uint64_t data, in_mapaddr, out_mapaddr;
2820 2820 uint_t size, flags, opmod;
2821 2821 int status, i;
2822 2822
2823 2823 /*
2824 2824 * Use the specified opcode type to set the appropriate parameters.
2825 2825 * Specifically, we need to set in_mapaddr, out_mapaddr, flags, and
2826 2826 * opmod (as necessary). Setting these parameters may also require
2827 2827 * us to allocate an "In" or "Out" mailbox depending on the command
2828 2828 * type.
2829 2829 */
2830 2830
2831 2831 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2832 2832
2833 2833 if (opcode == RTS2SQD_QP) {
2834 2834 /*
2835 2835 * Note: For RTS-to-SendQueueDrain state transitions we
2836 2836 * always want to request the event generation from the
2837 2837 * hardware. Though we may not notify the consumer of the
2838 2838 * drained event, the decision to forward (or not) is made
2839 2839 * later in the SQD event handler.
2840 2840 */
2841 2841 flags = HERMON_CMD_REQ_SQD_EVENT;
2842 2842
2843 2843 /*
2844 2844 * The RTS2SQD_QP command uses no "In" or "Out" mailboxes (and
2845 2845 * has no special opcode modifiers).
2846 2846 */
2847 2847 in_mapaddr = 0;
2848 2848 out_mapaddr = 0;
2849 2849 opmod = 0;
2850 2850
2851 2851 } else if (opcode == TOERR_QP) {
2852 2852 /*
2853 2853 * The TOERR_QP command uses no "In" or "Out" mailboxes, has no
2854 2854 * special opcode modifiers, and takes no special flags.
2855 2855 */
2856 2856 in_mapaddr = 0;
2857 2857 out_mapaddr = 0;
2858 2858 opmod = 0;
2859 2859 flags = 0;
2860 2860
2861 2861 } else if (opcode == TORST_QP) {
2862 2862 /*
2863 2863 * The TORST_QP command could take an "Out" mailbox, but we do
2864 2864 * not require it here. It also does not takes any special
2865 2865 * flags. It does however, take a HERMON_CMD_DIRECT_TO_RESET
2866 2866 * opcode modifier, which indicates that the transition to
2867 2867 * reset should happen without first moving the QP through the
2868 2868 * Error state (and, hence, without generating any unnecessary
2869 2869 * "flushed-in-error" completions).
2870 2870 */
2871 2871 in_mapaddr = 0;
2872 2872 out_mapaddr = 0;
2873 2873 opmod = HERMON_CMD_DIRECT_TO_RESET | HERMON_CMD_NO_OUTMBOX;
2874 2874 flags = 0;
2875 2875
2876 2876 } else {
2877 2877 /*
2878 2878 * All the other QP state transition commands (RST2INIT_QP,
2879 2879 * INIT2INIT_QP, INIT2RTR_QP, RTR2RTS_QP, RTS2RTS_QP,
2880 2880 * SQD2RTS_QP, and SQERR2RTS_QP) require an "In" mailbox.
2881 2881 * None of these require any special flags or opcode modifiers.
2882 2882 */
2883 2883 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
2884 2884 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2885 2885 if (status != HERMON_CMD_SUCCESS) {
2886 2886 return (status);
2887 2887 }
2888 2888 in_mapaddr = mbox_info.mbi_in->mb_mapaddr;
2889 2889 out_mapaddr = 0;
2890 2890 flags = 0;
2891 2891 opmod = 0;
2892 2892
2893 2893 /* Copy the Hermon command into the "In" mailbox */
2894 2894 size = sizeof (hermon_hw_qpc_t);
2895 2895 for (i = 0; i < (size >> 3); i++) {
2896 2896 data = ((uint64_t *)(void *)qp)[i];
2897 2897 ddi_put64(mbox_info.mbi_in->mb_acchdl,
2898 2898 ((uint64_t *)mbox_info.mbi_in->mb_addr + i + 1),
2899 2899 data);
2900 2900 }
2901 2901 ddi_put32(mbox_info.mbi_in->mb_acchdl,
2902 2902 ((uint32_t *)mbox_info.mbi_in->mb_addr), opmask);
2903 2903
2904 2904 /*
2905 2905 * Sync the mailbox for the device to read. We have to add
2906 2906 * eight bytes here to account for "opt_param_mask" and
2907 2907 * proper alignment.
2908 2908 */
2909 2909 hermon_mbox_sync(mbox_info.mbi_in, 0, size + 8,
2910 2910 DDI_DMA_SYNC_FORDEV);
2911 2911 }
2912 2912
2913 2913 /* Setup and post Hermon QP state transition command */
2914 2914 cmd.cp_inparm = in_mapaddr;
2915 2915 cmd.cp_outparm = out_mapaddr;
2916 2916 cmd.cp_inmod = qpindx | flags;
2917 2917 cmd.cp_opcode = (uint16_t)opcode;
2918 2918 cmd.cp_opmod = (uint16_t)opmod;
2919 2919 cmd.cp_flags = sleepflag;
2920 2920 status = hermon_cmd_post(state, &cmd);
2921 2921
2922 2922 /*
2923 2923 * If we allocated a mailbox (either an "In" or an "Out") above,
2924 2924 * then free it now before returning.
2925 2925 */
2926 2926 if ((opcode != RTS2SQD_QP) && (opcode != TOERR_QP) &&
2927 2927 (opcode != TORST_QP)) {
2928 2928 /* Free the mailbox */
2929 2929 hermon_mbox_free(state, &mbox_info);
2930 2930 }
2931 2931 return (status);
2932 2932 }
2933 2933
2934 2934
2935 2935 /*
2936 2936 * hermon_cmn_query_cmd_post()
2937 2937 * Context: Can be called from interrupt or base context.
2938 2938 *
2939 2939 * This is the common function for posting all the various types of
2940 2940 * Hermon query commands. All Hermon query commands require an "Out"
2941 2941 * mailbox to be allocated for the resulting queried data.
2942 2942 *
2943 2943 * Note: This common function should be used only with the following
2944 2944 * opcodes: QUERY_DEV_LIM, QUERY_FW, QUERY_DDR, QUERY_ADAPTER, QUERY_PORT
2945 2945 * QUERY_HCA, QUERY_MPT, QUERY_EQ, QUERY_CQ, and QUERY_QP.
2946 2946 * With support of FCoIB, this also supports QUERY_FC.
2947 2947 */
2948 2948 int
2949 2949 hermon_cmn_query_cmd_post(hermon_state_t *state, uint_t opcode, uint_t opmod,
2950 2950 uint_t queryindx, void *query, uint_t size, uint_t sleepflag)
2951 2951 {
2952 2952 hermon_mbox_info_t mbox_info;
2953 2953 hermon_cmd_post_t cmd;
2954 2954 uint64_t data;
2955 2955 uint_t offset;
2956 2956 int status, i;
2957 2957
2958 2958 bzero(&cmd, sizeof (hermon_cmd_post_t));
2959 2959
2960 2960 /* Get an "Out" mailbox for the command */
2961 2961 mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
2962 2962 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2963 2963 if (status != HERMON_CMD_SUCCESS) {
2964 2964 return (status);
2965 2965 }
2966 2966
2967 2967 /* Setup and post the Hermon query command */
2968 2968 cmd.cp_inparm = 0;
2969 2969 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
2970 2970 cmd.cp_inmod = queryindx;
2971 2971 cmd.cp_opcode = (uint16_t)opcode;
2972 2972 cmd.cp_opmod = (uint16_t)opmod;
2973 2973 cmd.cp_flags = sleepflag;
2974 2974 status = hermon_cmd_post(state, &cmd);
2975 2975 if (status != HERMON_CMD_SUCCESS) {
2976 2976 goto cmn_query_fail;
2977 2977 }
2978 2978
2979 2979 /* Sync the mailbox to read the results */
2980 2980 hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
2981 2981
2982 2982 /*
2983 2983 * QUERY_QP is handled somewhat differently than the other query
2984 2984 * commands. For QUERY_QP, the actual queried data is offset into
2985 2985 * the mailbox (by one 64-bit word).
2986 2986 */
2987 2987 offset = (opcode == QUERY_QP) ? 1 : 0;
2988 2988
2989 2989 /* Copy query command results into "query" */
2990 2990 for (i = 0; i < (size >> 3); i++) {
2991 2991 data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2992 2992 ((uint64_t *)mbox_info.mbi_out->mb_addr + i + offset));
2993 2993 ((uint64_t *)query)[i] = data;
2994 2994 }
2995 2995
2996 2996 cmn_query_fail:
2997 2997 /* Free the mailbox */
2998 2998 hermon_mbox_free(state, &mbox_info);
2999 2999 return (status);
3000 3000 }
3001 3001
3002 3002
3003 3003 /*
3004 3004 * hermon_cmn_ownership_cmd_post()
3005 3005 * Context: Can be called from interrupt or base context.
3006 3006 *
3007 3007 * This is the common function for posting all the various types of
3008 3008 * Hermon HW/SW resource ownership commands. Since some of the commands
3009 3009 * differ from the others in the direction of ownership change (i.e.
3010 3010 * from HW ownership to SW, or vice versa), they differ in the type of
3011 3011 * mailbox and specific handling that each requires. This routine does
3012 3012 * certain checks based on opcode type to determine the direction of
3013 3013 * the transition and to correctly handle the request.
3014 3014 *
3015 3015 * Note: This common function should be used only with the following
3016 3016 * opcodes: HW2SW_MPT, HW2SW_EQ, HW2SW_CQ, SW2HW_MPT, SW2HW_EQ, and
3017 3017 * SW2HW_CQ
3018 3018 */
3019 3019 int
3020 3020 hermon_cmn_ownership_cmd_post(hermon_state_t *state, uint_t opcode,
3021 3021 void *hwrsrc, uint_t size, uint_t hwrsrcindx, uint_t sleepflag)
3022 3022 {
3023 3023 hermon_mbox_info_t mbox_info;
3024 3024 hermon_cmd_post_t cmd;
3025 3025 uint64_t data, in_mapaddr, out_mapaddr;
3026 3026 uint_t direction, opmod;
3027 3027 int status, i;
3028 3028
3029 3029 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3030 3030
3031 3031 /*
3032 3032 * Determine the direction of the ownership transfer based on the
3033 3033 * provided opcode
3034 3034 */
3035 3035 if ((opcode == HW2SW_MPT) || (opcode == HW2SW_EQ) ||
3036 3036 (opcode == HW2SW_CQ) || (opcode == HW2SW_SRQ)) {
3037 3037 direction = HERMON_CMD_RSRC_HW2SW;
3038 3038
3039 3039 } else if ((opcode == SW2HW_MPT) || (opcode == SW2HW_EQ) ||
3040 3040 (opcode == SW2HW_CQ) || (opcode == SW2HW_SRQ)) {
3041 3041 direction = HERMON_CMD_RSRC_SW2HW;
3042 3042
3043 3043 } else {
3044 3044 return (HERMON_CMD_INVALID_STATUS);
3045 3045 }
3046 3046
3047 3047 /*
3048 3048 * If hwrsrc is NULL then we do not allocate a mailbox. This is used
3049 3049 * in the case of memory deregister where the out mailbox is not
3050 3050 * needed. In the case of re-register, we do use the hwrsrc.
3051 3051 *
3052 3052 * Otherwise, If ownership transfer is going from hardware to software,
3053 3053 * then allocate an "Out" mailbox. This will be filled in later as a
3054 3054 * result of the Hermon command.
3055 3055 *
3056 3056 * And if the ownership transfer is going from software to hardware,
3057 3057 * then we need an "In" mailbox, and we need to fill it in and sync it
3058 3058 * (if necessary). Then the mailbox can be passed to the Hermon
3059 3059 * firmware.
3060 3060 *
3061 3061 * For the HW2SW (dereg) case, we only use an out mbox if hwrsrc is !=
3062 3062 * NULL. This implies a re-reg, and the out mbox must be used. If
3063 3063 * hwrsrc is == NULL, then we can save some time and resources by not
3064 3064 * using an out mbox at all. We must set opmod to HERMON_CMD_DO_OUTMBOX
3065 3065 * and HERMON_CMD_NO_OUTMBOX appropriately in this case.
3066 3066 *
3067 3067 * For the SW2HW (reg) case, no out mbox is possible. We set opmod to
3068 3068 * 0 anyway, but this field is not used in this case.
3069 3069 */
3070 3070 if (direction == HERMON_CMD_RSRC_HW2SW) {
3071 3071 if (hwrsrc != NULL) {
3072 3072 mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
3073 3073 status = hermon_mbox_alloc(state, &mbox_info,
3074 3074 sleepflag);
3075 3075 if (status != HERMON_CMD_SUCCESS) {
3076 3076 return (status);
3077 3077 }
3078 3078 in_mapaddr = 0;
3079 3079 out_mapaddr = mbox_info.mbi_out->mb_mapaddr;
3080 3080 opmod = HERMON_CMD_DO_OUTMBOX;
3081 3081 } else {
3082 3082 in_mapaddr = 0;
3083 3083 out_mapaddr = 0;
3084 3084 opmod = HERMON_CMD_NO_OUTMBOX;
3085 3085 }
3086 3086 } else { /* HERMON_CMD_RSRC_SW2HW */
3087 3087 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3088 3088 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3089 3089 if (status != HERMON_CMD_SUCCESS) {
3090 3090 return (status);
3091 3091 }
3092 3092
3093 3093 /* Copy the SW2HW ownership command into mailbox */
3094 3094 for (i = 0; i < (size >> 3); i++) {
3095 3095 data = ((uint64_t *)hwrsrc)[i];
3096 3096 ddi_put64(mbox_info.mbi_in->mb_acchdl,
3097 3097 ((uint64_t *)mbox_info.mbi_in->mb_addr + i),
3098 3098 data);
3099 3099 }
3100 3100
3101 3101 /* Sync the mailbox for the device to read */
3102 3102 hermon_mbox_sync(mbox_info.mbi_in, 0, size,
3103 3103 DDI_DMA_SYNC_FORDEV);
3104 3104
3105 3105 in_mapaddr = mbox_info.mbi_in->mb_mapaddr;
3106 3106 out_mapaddr = 0;
3107 3107 opmod = 0;
3108 3108 }
3109 3109
3110 3110 /* Setup and post the Hermon ownership command */
3111 3111 cmd.cp_inparm = in_mapaddr;
3112 3112 cmd.cp_outparm = out_mapaddr;
3113 3113 cmd.cp_inmod = hwrsrcindx;
3114 3114 cmd.cp_opcode = (uint16_t)opcode;
3115 3115 cmd.cp_opmod = (uint16_t)opmod;
3116 3116 cmd.cp_flags = sleepflag;
3117 3117 status = hermon_cmd_post(state, &cmd);
3118 3118 if (status != HERMON_CMD_SUCCESS) {
3119 3119 goto cmn_ownership_fail;
3120 3120 }
3121 3121
3122 3122 /*
3123 3123 * As mentioned above, for HW2SW ownership transfers we need to
3124 3124 * sync (if necessary) and copy out the resulting data from the
3125 3125 * "Out" mailbox" (assuming the above command was successful).
3126 3126 */
3127 3127 if (direction == HERMON_CMD_RSRC_HW2SW && hwrsrc != NULL) {
3128 3128
3129 3129 /* Sync the mailbox to read the results */
3130 3130 hermon_mbox_sync(mbox_info.mbi_out, 0, size,
3131 3131 DDI_DMA_SYNC_FORCPU);
3132 3132
3133 3133 /* Copy HW2SW ownership command results into "hwrsrc" */
3134 3134 for (i = 0; i < (size >> 3); i++) {
3135 3135 data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
3136 3136 ((uint64_t *)mbox_info.mbi_out->mb_addr + i));
3137 3137 ((uint64_t *)hwrsrc)[i] = data;
3138 3138 }
3139 3139 }
3140 3140
3141 3141 cmn_ownership_fail:
3142 3142 if (hwrsrc != NULL) {
3143 3143 /* Free the mailbox */
3144 3144 hermon_mbox_free(state, &mbox_info);
3145 3145 }
3146 3146 return (status);
3147 3147 }
3148 3148
3149 3149
3150 3150 /*
3151 3151 * hermon_conf_special_qp_cmd_post()
3152 3152 * Context: Can be called from interrupt or base context.
3153 3153 */
3154 3154 /*ARGSUSED*/
3155 3155 int
3156 3156 hermon_conf_special_qp_cmd_post(hermon_state_t *state, uint_t qpindx,
3157 3157 uint_t qptype, uint_t sleepflag, uint_t opmod)
3158 3158 {
3159 3159 hermon_cmd_post_t cmd;
3160 3160 int status;
3161 3161
3162 3162 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3163 3163
3164 3164 /* Setup and post Hermon "CONF_SPECIAL_QP" command */
3165 3165 cmd.cp_inparm = 0;
3166 3166 cmd.cp_outparm = 0;
3167 3167 cmd.cp_inmod = qpindx & 0x00FFFFF8; /* mask off low 3 bits */
3168 3168 cmd.cp_opcode = CONF_SPECIAL_QP;
3169 3169 cmd.cp_opmod = (uint16_t)opmod;
3170 3170 cmd.cp_flags = sleepflag;
3171 3171 status = hermon_cmd_post(state, &cmd);
3172 3172
3173 3173 return (status);
3174 3174 }
3175 3175
3176 3176
3177 3177 /*
3178 3178 * hermon_get_heart_beat_rq_cmd_post()
3179 3179 * Context: Can be called only from kernel or interrupt context
3180 3180 */
3181 3181 int
3182 3182 hermon_get_heart_beat_rq_cmd_post(hermon_state_t *state, uint_t qpindx,
3183 3183 uint64_t *outparm)
3184 3184 {
3185 3185 hermon_cmd_post_t cmd;
3186 3186 int status;
3187 3187
3188 3188 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3189 3189
3190 3190 /* Setup and post the Hermon "HEART_BEAT_RQ" command */
3191 3191 cmd.cp_inparm = 0;
3192 3192 cmd.cp_outparm = 0;
3193 3193 cmd.cp_inmod = qpindx;
3194 3194 cmd.cp_opcode = HEART_BEAT_RQ;
3195 3195 cmd.cp_opmod = 0;
3196 3196 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
3197 3197 status = hermon_cmd_post(state, &cmd);
3198 3198
3199 3199 /*
3200 3200 * Return immediate out param through argument pointer.
3201 3201 */
3202 3202 *outparm = cmd.cp_outparm;
3203 3203 return (status);
3204 3204 }
3205 3205
3206 3206
3207 3207 /*
3208 3208 * hermon_mgid_hash_cmd_post()
3209 3209 * Context: Can be called from interrupt or base context.
3210 3210 */
3211 3211 int
3212 3212 hermon_mgid_hash_cmd_post(hermon_state_t *state, uint64_t mgid_h,
3213 3213 uint64_t mgid_l, uint64_t *mgid_hash, uint_t sleepflag)
3214 3214 {
3215 3215 hermon_mbox_info_t mbox_info;
3216 3216 hermon_cmd_post_t cmd;
3217 3217 int status;
3218 3218
3219 3219 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3220 3220
3221 3221 /* Get an "In" mailbox for the command */
3222 3222 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3223 3223 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3224 3224 if (status != HERMON_CMD_SUCCESS) {
3225 3225 return (status);
3226 3226 }
3227 3227
3228 3228 /* Copy the Hermon "MGID_HASH" command into mailbox */
3229 3229 ddi_put64(mbox_info.mbi_in->mb_acchdl,
3230 3230 ((uint64_t *)mbox_info.mbi_in->mb_addr + 0), mgid_h);
3231 3231 ddi_put64(mbox_info.mbi_in->mb_acchdl,
3232 3232 ((uint64_t *)mbox_info.mbi_in->mb_addr + 1), mgid_l);
3233 3233
3234 3234 /* Sync the mailbox for the device to read */
3235 3235 hermon_mbox_sync(mbox_info.mbi_in, 0, HERMON_CMD_MGIDHASH_SZ,
3236 3236 DDI_DMA_SYNC_FORDEV);
3237 3237
3238 3238 /* Setup and post the Hermon "MGID_HASH" command */
3239 3239 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
3240 3240 cmd.cp_outparm = 0;
3241 3241 cmd.cp_inmod = 0;
3242 3242 cmd.cp_opcode = MGID_HASH;
3243 3243 cmd.cp_opmod = 0;
3244 3244 cmd.cp_flags = sleepflag;
3245 3245 status = hermon_cmd_post(state, &cmd);
3246 3246
3247 3247 /* MGID hash value is returned in command "outparam" */
3248 3248 *mgid_hash = cmd.cp_outparm;
3249 3249
3250 3250 /* Free the mailbox */
3251 3251 hermon_mbox_free(state, &mbox_info);
3252 3252 return (status);
3253 3253 }
3254 3254
3255 3255
3256 3256 /*
3257 3257 * hermon_read_mgm_cmd_post()
3258 3258 * Context: Can be called from interrupt or base context.
3259 3259 *
3260 3260 * Note: It is assumed that the "mcg" parameter is actually a pointer to a
3261 3261 * "hermon_hw_mcg_t" struct and some number of "hermon_hw_mcg_qp_list_t"
3262 3262 * structs. Combined size should be equal to result of HERMON_MCGMEM_SZ()
3263 3263 * macro.
3264 3264 */
3265 3265 int
3266 3266 hermon_read_mgm_cmd_post(hermon_state_t *state, hermon_hw_mcg_t *mcg,
3267 3267 uint_t mcgindx, uint_t sleepflag)
3268 3268 {
3269 3269 hermon_mbox_info_t mbox_info;
3270 3270 hermon_cmd_post_t cmd;
3271 3271 uint64_t data;
3272 3272 uint32_t data32;
3273 3273 uint_t size, hdrsz, qplistsz;
3274 3274 int status, i;
3275 3275
3276 3276 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3277 3277
3278 3278 /* Get an "Out" mailbox for the results */
3279 3279 mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
3280 3280 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3281 3281 if (status != HERMON_CMD_SUCCESS) {
3282 3282 return (status);
3283 3283 }
3284 3284
3285 3285 /* Setup and post Hermon "READ_MGM" command */
3286 3286 cmd.cp_inparm = 0;
3287 3287 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
3288 3288 cmd.cp_inmod = mcgindx;
3289 3289 cmd.cp_opcode = READ_MGM;
3290 3290 cmd.cp_opmod = 0;
3291 3291 cmd.cp_flags = sleepflag;
3292 3292 status = hermon_cmd_post(state, &cmd);
3293 3293 if (status != HERMON_CMD_SUCCESS) {
3294 3294 goto read_mgm_fail;
3295 3295 }
3296 3296
3297 3297 /* Sync the mailbox to read the results */
3298 3298 size = HERMON_MCGMEM_SZ(state);
3299 3299 hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
3300 3300
3301 3301 /* Copy the READ_MGM command results into "mcg" */
3302 3302 hdrsz = sizeof (hermon_hw_mcg_t);
3303 3303 for (i = 0; i < (hdrsz >> 3); i++) {
3304 3304 data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
3305 3305 ((uint64_t *)mbox_info.mbi_out->mb_addr + i));
3306 3306 ((uint64_t *)mcg)[i] = data;
3307 3307 }
3308 3308 qplistsz = size - hdrsz;
3309 3309 for (i = 0; i < (qplistsz >> 2); i++) {
3310 3310 data32 = ddi_get32(mbox_info.mbi_out->mb_acchdl,
3311 3311 ((uint32_t *)mbox_info.mbi_out->mb_addr + i + 8));
3312 3312 ((uint32_t *)mcg)[i + 8] = data32;
3313 3313 }
3314 3314
3315 3315 read_mgm_fail:
3316 3316 /* Free the mailbox */
3317 3317 hermon_mbox_free(state, &mbox_info);
3318 3318 return (status);
3319 3319 }
3320 3320
3321 3321
3322 3322 /*
3323 3323 * hermon_write_mgm_cmd_post()
3324 3324 * Context: Can be called from interrupt or base context.
3325 3325 *
3326 3326 * Note: It is assumed that the "mcg" parameter is actually a pointer to a
3327 3327 * "hermon_hw_mcg_t" struct and some number of "hermon_hw_mcg_qp_list_t"
3328 3328 * structs. Combined size should be equal to result of HERMON_MCGMEM_SZ()
3329 3329 * macro.
3330 3330 */
3331 3331 int
3332 3332 hermon_write_mgm_cmd_post(hermon_state_t *state, hermon_hw_mcg_t *mcg,
3333 3333 uint_t mcgindx, uint_t sleepflag)
3334 3334 {
3335 3335 hermon_mbox_info_t mbox_info;
3336 3336 hermon_cmd_post_t cmd;
3337 3337 uint64_t data;
3338 3338 uint_t size, hdrsz, qplistsz;
3339 3339 int status, i;
3340 3340
3341 3341 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3342 3342
3343 3343 /* Get an "In" mailbox for the command */
3344 3344 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3345 3345 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3346 3346 if (status != HERMON_CMD_SUCCESS) {
3347 3347 return (status);
3348 3348 }
3349 3349
3350 3350 /* Copy the Hermon "WRITE_MGM" command into mailbox */
3351 3351 size = HERMON_MCGMEM_SZ(state);
3352 3352 hdrsz = sizeof (hermon_hw_mcg_t);
3353 3353 for (i = 0; i < (hdrsz >> 3); i++) {
3354 3354 data = ((uint64_t *)mcg)[i];
3355 3355 ddi_put64(mbox_info.mbi_in->mb_acchdl,
3356 3356 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
3357 3357 }
3358 3358 qplistsz = size - hdrsz;
3359 3359 for (i = 0; i < (qplistsz >> 2); i++) {
3360 3360 data = ((uint32_t *)mcg)[i + 8];
3361 3361 ddi_put32(mbox_info.mbi_in->mb_acchdl,
3362 3362 ((uint32_t *)mbox_info.mbi_in->mb_addr + i + 8), data);
3363 3363 }
3364 3364
3365 3365 /* Sync the mailbox for the device to read */
3366 3366 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
3367 3367
3368 3368 /* Setup and post Hermon "WRITE_MGM" command */
3369 3369 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
3370 3370 cmd.cp_outparm = 0;
3371 3371 cmd.cp_inmod = mcgindx;
3372 3372 cmd.cp_opcode = WRITE_MGM;
3373 3373 cmd.cp_opmod = 0;
3374 3374 cmd.cp_flags = sleepflag;
3375 3375 status = hermon_cmd_post(state, &cmd);
3376 3376
3377 3377 /* Free the mailbox */
3378 3378 hermon_mbox_free(state, &mbox_info);
3379 3379 return (status);
3380 3380 }
3381 3381
3382 3382 /*
3383 3383 * hermon_resize_srq_cmd_post()
3384 3384 * Context: Can be called from interrupt or base context.
3385 3385 */
3386 3386
3387 3387 int hermon_resize_srq_cmd_post(hermon_state_t *state, hermon_hw_srqc_t *srq,
3388 3388 uint_t srqnum, uint_t sleepflag)
3389 3389 {
3390 3390 hermon_mbox_info_t mbox_info;
3391 3391 hermon_cmd_post_t cmd;
3392 3392 uint64_t data;
3393 3393 uint_t size;
3394 3394 int status, i;
3395 3395
3396 3396 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3397 3397
3398 3398 /* Get an "In" mailbox for the command */
3399 3399 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3400 3400 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3401 3401 if (status != HERMON_CMD_SUCCESS) {
3402 3402 return (status);
3403 3403 }
3404 3404
3405 3405 /* Copy the Hermon "RESIZE_SRQ" command into mailbox */
3406 3406 size = sizeof (hermon_hw_srqc_t);
3407 3407 for (i = 0; i < (size >> 3); i++) {
3408 3408 data = ((uint64_t *)(void *)srq)[i];
3409 3409 ddi_put64(mbox_info.mbi_in->mb_acchdl,
3410 3410 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
3411 3411 }
3412 3412
3413 3413 /* Sync the mailbox for the device to read */
3414 3414 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
3415 3415
3416 3416 /* Setup and post Hermon "RESIZE_SRQ" command */
3417 3417 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
3418 3418 cmd.cp_outparm = 0;
3419 3419 cmd.cp_inmod = srqnum;
3420 3420 cmd.cp_opcode = RESIZE_SRQ;
3421 3421 cmd.cp_opmod = 0;
3422 3422 cmd.cp_flags = sleepflag;
3423 3423 status = hermon_cmd_post(state, &cmd);
3424 3424
3425 3425 /* Free the mailbox */
3426 3426 hermon_mbox_free(state, &mbox_info);
3427 3427 return (status);
3428 3428 }
3429 3429 /*
3430 3430 * hermon_modify_mpt_cmd_post()
3431 3431 * Context: Can be called from interrupt or base context.
3432 3432 */
3433 3433 int
3434 3434 hermon_modify_mpt_cmd_post(hermon_state_t *state, hermon_hw_dmpt_t *mpt,
3435 3435 uint_t mptindx, uint_t flags, uint_t sleepflag)
3436 3436 {
3437 3437 hermon_mbox_info_t mbox_info;
3438 3438 hermon_cmd_post_t cmd;
3439 3439 uint64_t data;
3440 3440 uint_t size;
3441 3441 int status, i;
3442 3442
3443 3443 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3444 3444
3445 3445 /* Get an "In" mailbox for the command */
3446 3446 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3447 3447 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3448 3448 if (status != HERMON_CMD_SUCCESS) {
3449 3449 return (status);
3450 3450 }
3451 3451
3452 3452 /* Copy the Hermon "MODIFY_MPT" command into mailbox */
3453 3453 size = sizeof (hermon_hw_dmpt_t);
3454 3454 for (i = 0; i < (size >> 3); i++) {
3455 3455 data = ((uint64_t *)mpt)[i];
3456 3456 ddi_put64(mbox_info.mbi_in->mb_acchdl,
3457 3457 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
3458 3458 }
3459 3459
3460 3460 /* Sync the mailbox for the device to read */
3461 3461 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
3462 3462
3463 3463 /* Setup and post Hermon "MODIFY_MPT" command */
3464 3464 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
3465 3465 cmd.cp_outparm = 0;
3466 3466 cmd.cp_inmod = mptindx;
3467 3467 cmd.cp_opcode = MODIFY_MPT;
3468 3468 cmd.cp_opmod = (uint16_t)flags;
3469 3469 cmd.cp_flags = sleepflag;
3470 3470 status = hermon_cmd_post(state, &cmd);
3471 3471
3472 3472 /* Free the mailbox */
3473 3473 hermon_mbox_free(state, &mbox_info);
3474 3474 return (status);
3475 3475 }
3476 3476
3477 3477
3478 3478 /*
3479 3479 * hermon_config_fc_cmd_post()
3480 3480 * Context: Can be called from user or kernel context.
3481 3481 * This can do either a basic config passing in
3482 3482 * *hermon_hw_config_fc_basic_s, or config the N_Port table.
3483 3483 * passing in pointer to an array of 32-bit id's
3484 3484 * Note that either one needs to be cast to void *
3485 3485 */
3486 3486 int
3487 3487 hermon_config_fc_cmd_post(hermon_state_t *state, void *cfginfo, int enable,
3488 3488 int selector, int n_ports, int portnum, uint_t sleepflag)
3489 3489 {
3490 3490 hermon_mbox_info_t mbox_info;
3491 3491 hermon_cmd_post_t cmd;
3492 3492 uint64_t data;
3493 3493 uint32_t portid;
3494 3494 uint_t size;
3495 3495 int status, i;
3496 3496
3497 3497 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3498 3498
3499 3499 /* Get an "In" mailbox for the command */
3500 3500 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3501 3501 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3502 3502 if (status != HERMON_CMD_SUCCESS) {
3503 3503 return (status);
3504 3504 }
3505 3505
3506 3506 /* Copy the appropriate info into mailbox */
3507 3507 if (selector == HERMON_HW_FC_CONF_BASIC) { /* basic info */
3508 3508 size = sizeof (hermon_hw_config_fc_basic_t);
3509 3509 for (i = 0; i < (size >> 3); i++) {
3510 3510 data = ((uint64_t *)cfginfo)[i];
3511 3511 ddi_put64(mbox_info.mbi_in->mb_acchdl,
3512 3512 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
3513 3513 }
3514 3514 } else { /* NPort config */
3515 3515 ASSERT(selector == HERMON_HW_FC_CONF_NPORT);
3516 3516 size = n_ports * sizeof (uint32_t);
3517 3517 /*
3518 3518 * n_ports must == number queried from card
3519 3519 *
3520 3520 * passed in is an array but for little endian needs to
3521 3521 * be rearranged in the mbox
3522 3522 */
3523 3523 for (i = 0; i < (size >> 3); i++) {
3524 3524 portid = ((uint32_t *)cfginfo)[i * 2];
3525 3525 data = (uint64_t)portid << 32;
3526 3526 if (i * 2 < n_ports) {
3527 3527 portid = ((uint32_t *)cfginfo)[i * 2 + 1];
3528 3528 data |= portid;
3529 3529 }
3530 3530 ddi_put64(mbox_info.mbi_in->mb_acchdl,
3531 3531 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
3532 3532 }
3533 3533 }
3534 3534
3535 3535 /* Sync the mailbox for the device to read */
3536 3536 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
3537 3537
3538 3538 /* Setup and post Hermon "CONFIG_FC" command */
3539 3539 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
3540 3540 cmd.cp_outparm = 0;
3541 3541 cmd.cp_inmod = (uint32_t)(selector | portnum);
3542 3542 cmd.cp_opcode = CONFIG_FC;
3543 3543 cmd.cp_opmod = (uint16_t)enable;
3544 3544 cmd.cp_flags = sleepflag;
3545 3545 status = hermon_cmd_post(state, &cmd);
3546 3546
3547 3547 /* Free the mailbox */
3548 3548 hermon_mbox_free(state, &mbox_info);
3549 3549 return (status);
3550 3550 }
3551 3551
3552 3552 /*
3553 3553 * hermon_sense_port_post() - used to send protocol running on a port
3554 3554 * Context: Can be called from interrupt or base context
3555 3555 */
3556 3556
3557 3557 int
3558 3558 hermon_sense_port_post(hermon_state_t *state, uint_t portnum,
3559 3559 uint32_t *protocol)
3560 3560 {
3561 3561 hermon_cmd_post_t cmd;
3562 3562 int status;
3563 3563
3564 3564 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3565 3565
3566 3566 /* Setup and post Hermon "CMD_NOP" command */
3567 3567 cmd.cp_inparm = 0;
3568 3568 cmd.cp_outparm = 0;
3569 3569 cmd.cp_inmod = (uint32_t)portnum;
3570 3570 cmd.cp_opcode = SENSE_PORT;
3571 3571 cmd.cp_opmod = 0;
3572 3572 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
3573 3573 status = hermon_cmd_post(state, &cmd);
3574 3574 if (status == HERMON_CMD_SUCCESS) *protocol = (uint32_t)cmd.cp_outparm;
3575 3575 return (status);
3576 3576 }
3577 3577
3578 3578
3579 3579 /*
3580 3580 * CONFIG_INT_MOD - used to configure INTERRUPT moderation
3581 3581 * if command fails, *health is invalid/undefined
3582 3582 */
3583 3583 int
3584 3584 hermon_config_int_mod(hermon_state_t *state, uint_t min_delay, uint_t vector)
3585 3585 {
3586 3586 hermon_cmd_post_t cmd;
3587 3587 int status;
3588 3588 uint64_t inparm = 0;
3589 3589
3590 3590 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3591 3591
3592 3592 /* Setup and post Hermon "CONFIG_INT_MOD" command */
3593 3593 inparm = (((uint64_t)min_delay & 0xFFFF) << 48) ||
3594 3594 (((uint64_t)vector & 0xFFFF) << 32);
3595 3595
3596 3596 cmd.cp_inparm = inparm;
3597 3597 cmd.cp_outparm = 0;
3598 3598 cmd.cp_inmod = 0;
3599 3599 cmd.cp_opcode = CONFIG_INT_MOD;
3600 3600 cmd.cp_opmod = 0;
3601 3601 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
3602 3602 status = hermon_cmd_post(state, &cmd);
3603 3603 return (status);
3604 3604 }
3605 3605
3606 3606
3607 3607 int
3608 3608 hermon_nop_post(hermon_state_t *state, uint_t interval, uint_t sleep)
3609 3609 {
3610 3610 hermon_cmd_post_t cmd;
3611 3611 int status;
3612 3612
3613 3613 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3614 3614
3615 3615 /* Setup and post Hermon "CMD_NOP" command */
3616 3616 cmd.cp_inparm = 0;
3617 3617 cmd.cp_outparm = 0;
3618 3618 cmd.cp_inmod = interval;
3619 3619 cmd.cp_opcode = CMD_NOP;
3620 3620 cmd.cp_opmod = 0;
3621 3621 cmd.cp_flags = HERMON_CMD_SLEEP_NOSPIN;
3622 3622 if (sleep) cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
3623 3623 status = hermon_cmd_post(state, &cmd);
3624 3624 return (status);
3625 3625 }
3626 3626
3627 3627 int
3628 3628 hermon_hw_health_check(hermon_state_t *state, int *health)
3629 3629 {
3630 3630 hermon_cmd_post_t cmd;
3631 3631 int status;
3632 3632
3633 3633 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3634 3634
3635 3635 /* Setup and post Hermon "CMD_NOP" command */
3636 3636 cmd.cp_inparm = 0;
3637 3637 cmd.cp_outparm = 0;
3638 3638 cmd.cp_inmod = 0;
3639 3639 cmd.cp_opcode = HW_HEALTH_CHECK;
3640 3640 cmd.cp_opmod = 0;
3641 3641 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
3642 3642 status = hermon_cmd_post(state, &cmd);
3643 3643 *health = (int)cmd.cp_outparm;
3644 3644 return (status);
3645 3645 }
3646 3646
3647 3647 int
3648 3648 hermon_setdebug_post(hermon_state_t *state)
3649 3649 {
3650 3650 hermon_cmd_post_t cmd;
3651 3651 int status;
3652 3652
3653 3653 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3654 3654
3655 3655 /* Setup and post Hermon "CMD_NOP" command */
3656 3656 cmd.cp_inparm = 0xFFFFFFFFFFFFFFFF;
3657 3657 cmd.cp_outparm = 0;
3658 3658 cmd.cp_inmod = 0;
3659 3659 cmd.cp_opcode = SET_DEBUG_MSG;
3660 3660 cmd.cp_opmod = 0;
3661 3661 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
3662 3662 status = hermon_cmd_post(state, &cmd);
3663 3663 return (status);
3664 3664 }
3665 3665
3666 3666
3667 3667 int
3668 3668 hermon_read_mtt_cmd_post(hermon_state_t *state, uint64_t mtt_addr,
3669 3669 hermon_hw_mtt_t *mtt)
3670 3670 {
3671 3671
3672 3672 hermon_cmd_post_t cmd;
3673 3673 hermon_mbox_info_t mbox_info;
3674 3674 int i, status;
3675 3675 uint_t size;
3676 3676 uint64_t data;
3677 3677
3678 3678 bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3679 3679
3680 3680 /* Get an "Out" mailbox for the command */
3681 3681 mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
3682 3682 status = hermon_mbox_alloc(state, &mbox_info, HERMON_CMD_SLEEP_NOSPIN);
3683 3683 if (status != HERMON_CMD_SUCCESS) {
3684 3684 return (status);
3685 3685 }
3686 3686
3687 3687 /* Setup and post the "READ_MTT" command */
3688 3688 cmd.cp_inparm = mtt_addr;
3689 3689 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
3690 3690 cmd.cp_inmod = 1;
3691 3691 cmd.cp_opcode = READ_MTT;
3692 3692 cmd.cp_opmod = 0;
3693 3693 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
3694 3694 status = hermon_cmd_post(state, &cmd);
3695 3695 if (status != HERMON_CMD_SUCCESS) {
3696 3696 return (status);
3697 3697 }
3698 3698
3699 3699 /* Sync the mailbox to read the results */
3700 3700 size = sizeof (hermon_hw_mtt_t);
3701 3701 hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
3702 3702
3703 3703 /* Copy mtt read out */
3704 3704 for (i = 0; i < (size >> 3); i++) {
3705 3705 data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
3706 3706 ((uint64_t *)mbox_info.mbi_out->mb_addr + i));
3707 3707 ((uint64_t *)(void *)mtt)[i] = data;
3708 3708 }
3709 3709
3710 3710 /* Free the mailbox */
3711 3711 hermon_mbox_free(state, &mbox_info);
3712 3712 return (status);
3713 3713 }
↓ open down ↓ |
3003 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX