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