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