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