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