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 	HERMON_GETPORTINFO_SWAP(portinfo);
2042 
2043 getportinfo_fail:
2044 	/* Free the mailbox */
2045 	hermon_mbox_free(state, &mbox_info);
2046 	return (status);
2047 }
2048 
2049 
2050 /*
2051  * hermon_getpefcntr_cmd_post()
2052  *    Context: Can be called from interrupt or base context.
2053  */
2054 int
2055 hermon_getperfcntr_cmd_post(hermon_state_t *state, uint_t port,
2056     uint_t sleepflag, hermon_hw_sm_perfcntr_t *perfinfo)
2057 {
2058 	hermon_mbox_info_t	mbox_info;
2059 	hermon_cmd_post_t	cmd;
2060 	uint64_t		data;
2061 	uint32_t		*mbox;
2062 	uint_t			size;
2063 	int			status, i;
2064 
2065 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2066 
2067 	/* Get "In" and "Out" mailboxes for the command */
2068 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2069 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2070 	if (status != HERMON_CMD_SUCCESS) {
2071 		return (status);
2072 	}
2073 
2074 	/* Build the GetPortInfo request MAD in the "In" mailbox */
2075 	size = HERMON_CMD_MAD_IFC_SIZE;
2076 	mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2077 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_PERFHDR0);
2078 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2079 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2080 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2081 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_PERFCNTRS);
2082 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], HERMON_CMD_PERFATTR);
2083 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16], (port << 16));
2084 
2085 	/* Sync the mailbox for the device to read */
2086 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2087 
2088 	/* Setup the Hermon "MAD_IFC" command */
2089 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
2090 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
2091 	cmd.cp_inmod	= port;
2092 	cmd.cp_opcode	= MAD_IFC;
2093 	cmd.cp_opmod	= HERMON_CMD_MKEY_DONTCHECK;  	/* No MKey checking */
2094 	cmd.cp_opmod	= 0x03;			/* temp, no bkey either */
2095 	cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN; /* NO SLEEP */
2096 	status = hermon_cmd_post(state, &cmd);
2097 	if (status != HERMON_CMD_SUCCESS) {
2098 		goto getperfinfo_fail;
2099 	}
2100 
2101 	/* Sync the mailbox to read the results */
2102 	size = HERMON_CMD_MAD_IFC_SIZE;
2103 	hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
2104 
2105 	size = sizeof (hermon_hw_sm_perfcntr_t);	/* for the copy */
2106 	/*
2107 	 * Copy Perfcounters into "perfinfo".  We can discard the MAD header and
2108 	 * the 8 Quadword reserved area of the PERM mgmt class MAD
2109 	 */
2110 
2111 	for (i = 0; i < size >> 3; i++) {
2112 		data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2113 		    ((uint64_t *)mbox_info.mbi_out->mb_addr + i + 8));
2114 		((uint64_t *)(void *)perfinfo)[i] = data;
2115 	}
2116 
2117 getperfinfo_fail:
2118 	/* Free the mailbox */
2119 	hermon_mbox_free(state, &mbox_info);
2120 	return (status);
2121 }
2122 
2123 
2124 
2125 /*
2126  * hermon_getnodeinfo_cmd_post()
2127  *    Context: Can be called from interrupt or base context.
2128  *    (Currently called only from attach() and detach() path contexts)
2129  */
2130 int
2131 hermon_getnodeinfo_cmd_post(hermon_state_t *state, uint_t sleepflag,
2132     sm_nodeinfo_t *nodeinfo)
2133 {
2134 	hermon_mbox_info_t	mbox_info;
2135 	hermon_cmd_post_t	cmd;
2136 	uint32_t		*mbox;
2137 	uint_t			size;
2138 	int			status, i;
2139 
2140 	/* Make sure we are called with the correct flag */
2141 	ASSERT(sleepflag == HERMON_CMD_NOSLEEP_SPIN);
2142 
2143 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2144 
2145 	/* Get "In" and "Out" mailboxes for the command */
2146 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2147 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2148 	if (status != HERMON_CMD_SUCCESS) {
2149 		return (status);
2150 	}
2151 
2152 	/* Build the GetNodeInfo request MAD into the "In" mailbox */
2153 	size = HERMON_CMD_MAD_IFC_SIZE;
2154 	mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2155 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
2156 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2157 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2158 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2159 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_NODEINFO);
2160 	for (i = 5; i < (size >> 2); i++) {
2161 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
2162 	}
2163 
2164 	/* Sync the mailbox for the device to read */
2165 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2166 
2167 	/* Setup the Hermon "MAD_IFC" command */
2168 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
2169 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
2170 	cmd.cp_inmod	= 1;  /* Get NodeInfo from port #1 */
2171 	cmd.cp_opcode	= MAD_IFC;
2172 	cmd.cp_opmod	= HERMON_CMD_MKEY_DONTCHECK;  /* No MKey checking */
2173 	cmd.cp_flags	= sleepflag;
2174 	status = hermon_cmd_post(state, &cmd);
2175 	if (status != HERMON_CMD_SUCCESS) {
2176 		goto getnodeinfo_fail;
2177 	}
2178 
2179 	/* Sync the mailbox to read the results */
2180 	size = sizeof (sm_nodeinfo_t);
2181 	hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
2182 	    size, DDI_DMA_SYNC_FORCPU);
2183 
2184 	/*
2185 	 * Copy GetNodeInfo response MAD into "nodeinfo".  Do any endian
2186 	 * swapping that may be necessary to flip any of the "nodeinfo"
2187 	 * fields
2188 	 */
2189 	bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
2190 	    HERMON_CMD_MADDATA_OFFSET), nodeinfo, size);
2191 	HERMON_GETNODEINFO_SWAP(nodeinfo);
2192 
2193 getnodeinfo_fail:
2194 	/* Free the mailbox */
2195 	hermon_mbox_free(state, &mbox_info);
2196 	return (status);
2197 }
2198 
2199 
2200 /*
2201  * hermon_getnodedesc_cmd_post()
2202  *    Context: Can be called from interrupt or base context.
2203  *    (Currently called only from attach() and detach() path contexts)
2204  */
2205 int
2206 hermon_getnodedesc_cmd_post(hermon_state_t *state, uint_t sleepflag,
2207     sm_nodedesc_t *nodedesc)
2208 {
2209 	hermon_mbox_info_t	mbox_info;
2210 	hermon_cmd_post_t	cmd;
2211 	uint32_t		*mbox;
2212 	uint_t			size;
2213 	int			status, i;
2214 
2215 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2216 
2217 	/* Get "In" and "Out" mailboxes for the command */
2218 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2219 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2220 	if (status != HERMON_CMD_SUCCESS) {
2221 		return (status);
2222 	}
2223 
2224 	/* Build the GetNodeDesc request MAD into the "In" mailbox */
2225 	size = HERMON_CMD_MAD_IFC_SIZE;
2226 	mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2227 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
2228 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2229 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2230 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2231 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_NODEDESC);
2232 	for (i = 5; i < (size >> 2); i++) {
2233 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
2234 	}
2235 
2236 	/* Sync the mailbox for the device to read */
2237 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2238 
2239 	/* Setup the Hermon "MAD_IFC" command */
2240 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
2241 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
2242 	cmd.cp_inmod	= 1;  /* Get NodeDesc from port #1 */
2243 	cmd.cp_opcode	= MAD_IFC;
2244 	cmd.cp_opmod	= HERMON_CMD_MKEY_DONTCHECK;  /* No MKey checking */
2245 	cmd.cp_flags	= sleepflag;
2246 	status = hermon_cmd_post(state, &cmd);
2247 	if (status != HERMON_CMD_SUCCESS) {
2248 		goto getnodedesc_fail;
2249 	}
2250 
2251 	/* Sync the mailbox to read the results */
2252 	size = sizeof (sm_nodedesc_t);
2253 	hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
2254 	    size, DDI_DMA_SYNC_FORCPU);
2255 
2256 	/* Copy GetNodeDesc response MAD into "nodedesc" */
2257 	bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
2258 	    HERMON_CMD_MADDATA_OFFSET), nodedesc, size);
2259 
2260 getnodedesc_fail:
2261 	/* Free the mailbox */
2262 	hermon_mbox_free(state, &mbox_info);
2263 	return (status);
2264 }
2265 
2266 
2267 /*
2268  * hermon_getguidinfo_cmd_post()
2269  *    Context: Can be called from interrupt or base context.
2270  */
2271 int
2272 hermon_getguidinfo_cmd_post(hermon_state_t *state, uint_t port,
2273     uint_t guidblock, uint_t sleepflag, sm_guidinfo_t *guidinfo)
2274 {
2275 	hermon_mbox_info_t	mbox_info;
2276 	hermon_cmd_post_t	cmd;
2277 	uint32_t		*mbox;
2278 	uint_t			size;
2279 	int			status, i;
2280 
2281 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2282 
2283 	/* Get "In" and "Out" mailboxes for the command */
2284 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2285 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2286 	if (status != HERMON_CMD_SUCCESS) {
2287 		return (status);
2288 	}
2289 
2290 	/* Build the GetGUIDInfo request MAD into the "In" mailbox */
2291 	size = HERMON_CMD_MAD_IFC_SIZE;
2292 	mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2293 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
2294 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2295 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2296 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2297 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_GUIDINFO);
2298 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], guidblock);
2299 	for (i = 6; i < (size >> 2); i++) {
2300 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
2301 	}
2302 
2303 	/* Sync the mailbox for the device to read */
2304 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2305 
2306 	/* Setup the Hermon "MAD_IFC" command */
2307 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
2308 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
2309 	cmd.cp_inmod	= port;
2310 	cmd.cp_opcode	= MAD_IFC;
2311 	cmd.cp_opmod	= HERMON_CMD_MKEY_DONTCHECK;  /* No MKey checking */
2312 	cmd.cp_flags	= sleepflag;
2313 	status = hermon_cmd_post(state, &cmd);
2314 	if (status != HERMON_CMD_SUCCESS) {
2315 		goto getguidinfo_fail;
2316 	}
2317 
2318 	/* Sync the mailbox to read the results */
2319 	size = sizeof (sm_guidinfo_t);
2320 	hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
2321 	    size, DDI_DMA_SYNC_FORCPU);
2322 
2323 	/*
2324 	 * Copy GetGUIDInfo response MAD into "guidinfo".  Do any endian
2325 	 * swapping that may be necessary to flip the "guidinfo" fields
2326 	 */
2327 	bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
2328 	    HERMON_CMD_MADDATA_OFFSET), guidinfo, size);
2329 	HERMON_GETGUIDINFO_SWAP(guidinfo);
2330 
2331 getguidinfo_fail:
2332 	/* Free the mailbox */
2333 	hermon_mbox_free(state, &mbox_info);
2334 	return (status);
2335 }
2336 
2337 
2338 /*
2339  * hermon_getpkeytable_cmd_post()
2340  *    Context: Can be called from interrupt or base context.
2341  */
2342 int
2343 hermon_getpkeytable_cmd_post(hermon_state_t *state, uint_t port,
2344     uint_t pkeyblock, uint_t sleepflag, sm_pkey_table_t *pkeytable)
2345 {
2346 	hermon_mbox_info_t	mbox_info;
2347 	hermon_cmd_post_t	cmd;
2348 	uint32_t		*mbox;
2349 	uint_t			size;
2350 	int			status, i;
2351 
2352 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2353 
2354 	/* Get "In" and "Out" mailboxes for the command */
2355 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2356 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2357 	if (status != HERMON_CMD_SUCCESS) {
2358 		return (status);
2359 	}
2360 
2361 	/* Build the GetPkeyTable request MAD into the "In" mailbox */
2362 	size = HERMON_CMD_MAD_IFC_SIZE;
2363 	mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2364 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
2365 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2366 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2367 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2368 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_PKEYTBLE);
2369 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], pkeyblock);
2370 	for (i = 6; i < (size >> 2); i++) {
2371 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
2372 	}
2373 
2374 	/* Sync the mailbox for the device to read */
2375 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2376 
2377 	/* Setup the Hermon "MAD_IFC" command */
2378 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
2379 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
2380 	cmd.cp_inmod	= port;
2381 	cmd.cp_opcode	= MAD_IFC;
2382 	cmd.cp_opmod	= HERMON_CMD_MKEY_DONTCHECK;  /* No MKey checking */
2383 	cmd.cp_flags	= sleepflag;
2384 	status = hermon_cmd_post(state, &cmd);
2385 	if (status != HERMON_CMD_SUCCESS) {
2386 		goto getpkeytable_fail;
2387 	}
2388 
2389 	/* Sync the mailbox to read the results */
2390 	size = sizeof (sm_pkey_table_t);
2391 	hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
2392 	    size, DDI_DMA_SYNC_FORCPU);
2393 
2394 	/*
2395 	 * Copy GetPKeyTable response MAD into "pkeytable".  Do any endian
2396 	 * swapping that may be necessary to flip the "pkeytable" fields
2397 	 */
2398 	bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
2399 	    HERMON_CMD_MADDATA_OFFSET), pkeytable, size);
2400 	HERMON_GETPKEYTABLE_SWAP(pkeytable);
2401 
2402 getpkeytable_fail:
2403 	/* Free the mailbox */
2404 	hermon_mbox_free(state, &mbox_info);
2405 	return (status);
2406 }
2407 
2408 
2409 /*
2410  * hermon_write_mtt_cmd_post()
2411  *    Context: Can be called from interrupt or base context.
2412  */
2413 int
2414 hermon_write_mtt_cmd_post(hermon_state_t *state, hermon_rsrc_t *mtt,
2415     uint64_t start_addr, uint_t nummtt, uint_t sleepflag)
2416 {
2417 	hermon_mbox_info_t	mbox_info;
2418 	hermon_cmd_post_t	cmd;
2419 	uint64_t		data;
2420 	uint_t			size;
2421 	int			status;
2422 	int			i;
2423 
2424 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2425 
2426 	/* Get an "In" mailbox for the command */
2427 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
2428 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2429 	if (status != HERMON_CMD_SUCCESS) {
2430 		return (status);
2431 	}
2432 
2433 	/*
2434 	 * The WRITE_MTT command input parameter contains the 64-bit addr of
2435 	 * the first target MTT, followed by 64 bits reserved, followed by an
2436 	 * array of MTT entries.
2437 	 *
2438 	 */
2439 	ddi_put64(mbox_info.mbi_in->mb_acchdl,
2440 	    ((uint64_t *)mbox_info.mbi_in->mb_addr),
2441 	    start_addr);
2442 
2443 	ddi_put64(mbox_info.mbi_in->mb_acchdl,
2444 	    ((uint64_t *)mbox_info.mbi_in->mb_addr + 1), 0x0);
2445 
2446 	for (i = 0; i < nummtt; i++) {
2447 		data = ((uint64_t *)mtt->hr_addr)[i];
2448 		ddi_put64(mbox_info.mbi_in->mb_acchdl,
2449 		    ((uint64_t *)mbox_info.mbi_in->mb_addr + i + 2), data);
2450 	}
2451 
2452 	/* Sync the mailbox for the device to read */
2453 	size = (nummtt << HERMON_MTT_SIZE_SHIFT) + HERMON_CMD_WRITEMTT_RSVD_SZ;
2454 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2455 
2456 	/* Setup and post Hermon "WRITE_MTT" command */
2457 	cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
2458 	cmd.cp_outparm  = 0;
2459 	cmd.cp_inmod    = nummtt;
2460 	cmd.cp_opcode   = WRITE_MTT;
2461 	cmd.cp_opmod    = 0;
2462 	cmd.cp_flags    = sleepflag;
2463 	status = hermon_cmd_post(state, &cmd);
2464 	if (status != HERMON_CMD_SUCCESS) {
2465 		cmn_err(CE_CONT, "WRITE_MTT failed (0x%x)\n", status);
2466 	}
2467 
2468 	/* Free the mailbox */
2469 	hermon_mbox_free(state, &mbox_info);
2470 	return (status);
2471 }
2472 
2473 
2474 /*
2475  * hermon_sync_tpt_cmd_post()
2476  *    Context: Can be called from interrupt or base context.
2477  */
2478 int
2479 hermon_sync_tpt_cmd_post(hermon_state_t *state, uint_t sleepflag)
2480 {
2481 	hermon_cmd_post_t	cmd;
2482 	int			status;
2483 
2484 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2485 
2486 	/* Setup and post the Hermon "SYNC_TPT" command */
2487 	cmd.cp_inparm	= 0;
2488 	cmd.cp_outparm	= 0;
2489 	cmd.cp_inmod	= 0;
2490 	cmd.cp_opcode	= SYNC_TPT;
2491 	cmd.cp_opmod	= 0;
2492 	cmd.cp_flags	= sleepflag;
2493 	status = hermon_cmd_post(state, &cmd);
2494 
2495 	return (status);
2496 }
2497 
2498 /*
2499  * hermon_map_eq_cmd_post()
2500  *    Context: Can be called from interrupt or base context.
2501  *    (Currently called only from attach() and/or detach() path contexts)
2502  */
2503 int
2504 hermon_map_eq_cmd_post(hermon_state_t *state, uint_t map, uint_t eqcindx,
2505     uint64_t eqmapmask, uint_t sleepflag)
2506 {
2507 	hermon_cmd_post_t	cmd;
2508 	int			status;
2509 
2510 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2511 
2512 	/* Setup and post Hermon "MAP_EQ" command */
2513 	cmd.cp_inparm	= eqmapmask;
2514 	cmd.cp_outparm	= 0;
2515 	cmd.cp_inmod	= eqcindx;
2516 	if (map != HERMON_CMD_MAP_EQ_EVT_MAP) {
2517 		cmd.cp_inmod |= HERMON_CMD_UNMAP_EQ_MASK;
2518 	}
2519 	cmd.cp_opcode	= MAP_EQ;
2520 	cmd.cp_opmod	= 0;
2521 	cmd.cp_flags	= sleepflag;
2522 	status = hermon_cmd_post(state, &cmd);
2523 	return (status);
2524 }
2525 
2526 
2527 /*
2528  * hermon_resize_cq_cmd_post()
2529  *    Context: Can be called from interrupt or base context.
2530  */
2531 int
2532 hermon_resize_cq_cmd_post(hermon_state_t *state, hermon_hw_cqc_t *cqc,
2533     uint_t cqcindx, uint32_t *prod_indx, uint_t sleepflag)
2534 {
2535 	hermon_mbox_info_t	mbox_info;
2536 	hermon_cmd_post_t	cmd;
2537 	uint64_t		data;
2538 	uint_t			size;
2539 	int			status, i;
2540 
2541 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2542 
2543 	/* Get an "In" mailbox for the command */
2544 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
2545 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2546 	if (status != HERMON_CMD_SUCCESS) {
2547 		return (status);
2548 	}
2549 
2550 	/* Copy the Hermon "MODIFY_CQ" command into mailbox */
2551 	size = sizeof (hermon_hw_cqc_t);
2552 	for (i = 0; i < (size >> 3); i++) {
2553 		data = ((uint64_t *)(void *)cqc)[i];
2554 		ddi_put64(mbox_info.mbi_in->mb_acchdl,
2555 		    ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
2556 	}
2557 
2558 	/* Sync the mailbox for the device to read */
2559 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2560 
2561 	/* Setup and post Hermon "MODIFY_CQ" command */
2562 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
2563 	cmd.cp_outparm	= 0;	/* resize cq */
2564 	cmd.cp_inmod	= cqcindx;
2565 	cmd.cp_opcode	= MODIFY_CQ;
2566 	cmd.cp_opmod	= RESIZE_CQ;
2567 	cmd.cp_flags	= sleepflag;
2568 	status = hermon_cmd_post(state, &cmd);
2569 
2570 	/*
2571 	 * New "producer index" is returned in the upper 32 bits of
2572 	 * command "outparam"
2573 	 */
2574 	*prod_indx = (cmd.cp_outparm >> 32);
2575 
2576 	/* Free the mailbox */
2577 	hermon_mbox_free(state, &mbox_info);
2578 	return (status);
2579 }
2580 
2581 
2582 /*
2583  * hermon_modify_cq_cmd_post()
2584  *    Context: Can be called from interrupt or base context.
2585  */
2586 int
2587 hermon_modify_cq_cmd_post(hermon_state_t *state, hermon_hw_cqc_t *cqc,
2588     uint_t cqcindx, uint_t opmod, uint_t sleepflag)
2589 {
2590 	hermon_mbox_info_t	mbox_info;
2591 	hermon_cmd_post_t	cmd;
2592 	uint64_t		data;
2593 	uint_t			size;
2594 	int			status, i;
2595 
2596 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2597 
2598 	/* Get an "In" mailbox for the command */
2599 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
2600 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2601 	if (status != HERMON_CMD_SUCCESS) {
2602 		return (status);
2603 	}
2604 
2605 	/* Copy the Hermon "MODIFY_CQ" command into mailbox */
2606 	size = sizeof (hermon_hw_cqc_t);
2607 	for (i = 0; i < (size >> 3); i++) {
2608 		data = ((uint64_t *)(void *)cqc)[i];
2609 		ddi_put64(mbox_info.mbi_in->mb_acchdl,
2610 		    ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
2611 	}
2612 
2613 	/* Sync the mailbox for the device to read */
2614 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2615 
2616 	/* Setup and post Hermon "MODIFY_CQ" command */
2617 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
2618 	cmd.cp_outparm	= 0;
2619 	cmd.cp_inmod	= cqcindx;
2620 	cmd.cp_opcode	= MODIFY_CQ;
2621 	cmd.cp_opmod	= (uint16_t)opmod;
2622 	cmd.cp_flags	= sleepflag;
2623 	status = hermon_cmd_post(state, &cmd);
2624 
2625 	/* Free the mailbox */
2626 	hermon_mbox_free(state, &mbox_info);
2627 	return (status);
2628 }
2629 
2630 
2631 /*
2632  * hermon_cmn_qp_cmd_post()
2633  *    Context: Can be called from interrupt or base context.
2634  *
2635  *    This is the common function for posting all the various types of
2636  *    QP state transition related Hermon commands.  Since some of the
2637  *    commands differ from the others in the number (and type) of arguments
2638  *    that each require, this routine does checks based on opcode type
2639  *    (explained in more detail below).
2640  *
2641  * Note: This common function should be used only with the following
2642  *    opcodes: RTS2SQD_QP, TOERR_QP, TORST_QP, RST2INIT_QP, INIT2INIT_QP,
2643  *    INIT2RTR_QP, RTR2RTS_QP, RTS2RTS_QP, SQD2RTS_QP, and SQERR2RTS_QP.
2644  */
2645 int
2646 hermon_cmn_qp_cmd_post(hermon_state_t *state, uint_t opcode,
2647     hermon_hw_qpc_t *qp, uint_t qpindx, uint32_t opmask,
2648     uint_t sleepflag)
2649 {
2650 	hermon_mbox_info_t	mbox_info;
2651 	hermon_cmd_post_t	cmd;
2652 	uint64_t		data, in_mapaddr, out_mapaddr;
2653 	uint_t			size, flags, opmod;
2654 	int			status, i;
2655 
2656 	/*
2657 	 * Use the specified opcode type to set the appropriate parameters.
2658 	 * Specifically, we need to set in_mapaddr, out_mapaddr, flags, and
2659 	 * opmod (as necessary).  Setting these parameters may also require
2660 	 * us to allocate an "In" or "Out" mailbox depending on the command
2661 	 * type.
2662 	 */
2663 
2664 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2665 
2666 	if (opcode == RTS2SQD_QP) {
2667 		/*
2668 		 * Note: For RTS-to-SendQueueDrain state transitions we
2669 		 * always want to request the event generation from the
2670 		 * hardware.  Though we may not notify the consumer of the
2671 		 * drained event, the decision to forward (or not) is made
2672 		 * later in the SQD event handler.
2673 		 */
2674 		flags = HERMON_CMD_REQ_SQD_EVENT;
2675 
2676 		/*
2677 		 * The RTS2SQD_QP command uses no "In" or "Out" mailboxes (and
2678 		 * has no special opcode modifiers).
2679 		 */
2680 		in_mapaddr  = 0;
2681 		out_mapaddr = 0;
2682 		opmod = 0;
2683 
2684 	} else if (opcode == TOERR_QP) {
2685 		/*
2686 		 * The TOERR_QP command uses no "In" or "Out" mailboxes, has no
2687 		 * special opcode modifiers, and takes no special flags.
2688 		 */
2689 		in_mapaddr  = 0;
2690 		out_mapaddr = 0;
2691 		opmod = 0;
2692 		flags = 0;
2693 
2694 	} else if (opcode == TORST_QP) {
2695 		/*
2696 		 * The TORST_QP command could take an "Out" mailbox, but we do
2697 		 * not require it here.  It also does not takes any special
2698 		 * flags.  It does however, take a HERMON_CMD_DIRECT_TO_RESET
2699 		 * opcode modifier, which indicates that the transition to
2700 		 * reset should happen without first moving the QP through the
2701 		 * Error state (and, hence, without generating any unnecessary
2702 		 * "flushed-in-error" completions).
2703 		 */
2704 		in_mapaddr  = 0;
2705 		out_mapaddr = 0;
2706 		opmod = HERMON_CMD_DIRECT_TO_RESET | HERMON_CMD_NO_OUTMBOX;
2707 		flags = 0;
2708 
2709 	} else {
2710 		/*
2711 		 * All the other QP state transition commands (RST2INIT_QP,
2712 		 * INIT2INIT_QP, INIT2RTR_QP, RTR2RTS_QP, RTS2RTS_QP,
2713 		 * SQD2RTS_QP, and SQERR2RTS_QP) require an "In" mailbox.
2714 		 * None of these require any special flags or opcode modifiers.
2715 		 */
2716 		mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
2717 		status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2718 		if (status != HERMON_CMD_SUCCESS) {
2719 			return (status);
2720 		}
2721 		in_mapaddr  = mbox_info.mbi_in->mb_mapaddr;
2722 		out_mapaddr = 0;
2723 		flags = 0;
2724 		opmod = 0;
2725 
2726 		/* Copy the Hermon command into the "In" mailbox */
2727 		size = sizeof (hermon_hw_qpc_t);
2728 		for (i = 0; i < (size >> 3); i++) {
2729 			data = ((uint64_t *)(void *)qp)[i];
2730 			ddi_put64(mbox_info.mbi_in->mb_acchdl,
2731 			    ((uint64_t *)mbox_info.mbi_in->mb_addr + i + 1),
2732 			    data);
2733 		}
2734 		ddi_put32(mbox_info.mbi_in->mb_acchdl,
2735 		    ((uint32_t *)mbox_info.mbi_in->mb_addr), opmask);
2736 
2737 		/*
2738 		 * Sync the mailbox for the device to read.  We have to add
2739 		 * eight bytes here to account for "opt_param_mask" and
2740 		 * proper alignment.
2741 		 */
2742 		hermon_mbox_sync(mbox_info.mbi_in, 0, size + 8,
2743 		    DDI_DMA_SYNC_FORDEV);
2744 	}
2745 
2746 	/* Setup and post Hermon QP state transition command */
2747 	cmd.cp_inparm	= in_mapaddr;
2748 	cmd.cp_outparm	= out_mapaddr;
2749 	cmd.cp_inmod	= qpindx | flags;
2750 	cmd.cp_opcode	= (uint16_t)opcode;
2751 	cmd.cp_opmod	= (uint16_t)opmod;
2752 	cmd.cp_flags	= sleepflag;
2753 	status = hermon_cmd_post(state, &cmd);
2754 
2755 	/*
2756 	 * If we allocated a mailbox (either an "In" or an "Out") above,
2757 	 * then free it now before returning.
2758 	 */
2759 	if ((opcode != RTS2SQD_QP) && (opcode != TOERR_QP) &&
2760 	    (opcode != TORST_QP)) {
2761 		/* Free the mailbox */
2762 		hermon_mbox_free(state, &mbox_info);
2763 	}
2764 	return (status);
2765 }
2766 
2767 
2768 /*
2769  * hermon_cmn_query_cmd_post()
2770  *    Context: Can be called from interrupt or base context.
2771  *
2772  *    This is the common function for posting all the various types of
2773  *    Hermon query commands.  All Hermon query commands require an "Out"
2774  *    mailbox to be allocated for the resulting queried data.
2775  *
2776  * Note: This common function should be used only with the following
2777  *    opcodes: QUERY_DEV_LIM, QUERY_FW, QUERY_DDR, QUERY_ADAPTER, QUERY_PORT
2778  *     QUERY_HCA, QUERY_MPT, QUERY_EQ, QUERY_CQ, and QUERY_QP.
2779  */
2780 int
2781 hermon_cmn_query_cmd_post(hermon_state_t *state, uint_t opcode, uint_t opmod,
2782     uint_t queryindx, void *query, uint_t size, uint_t sleepflag)
2783 {
2784 	hermon_mbox_info_t	mbox_info;
2785 	hermon_cmd_post_t	cmd;
2786 	uint64_t		data;
2787 	uint_t			offset;
2788 	int			status, i;
2789 
2790 	bzero(&cmd, sizeof (hermon_cmd_post_t));
2791 
2792 	/* Get an "Out" mailbox for the command */
2793 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
2794 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2795 	if (status != HERMON_CMD_SUCCESS) {
2796 		return (status);
2797 	}
2798 
2799 	/* Setup and post the Hermon query command */
2800 	cmd.cp_inparm	= 0;
2801 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
2802 	cmd.cp_inmod	= queryindx;
2803 	cmd.cp_opcode	= (uint16_t)opcode;
2804 	cmd.cp_opmod	= (uint16_t)opmod;
2805 	cmd.cp_flags	= sleepflag;
2806 	status = hermon_cmd_post(state, &cmd);
2807 	if (status != HERMON_CMD_SUCCESS) {
2808 		goto cmn_query_fail;
2809 	}
2810 
2811 	/* Sync the mailbox to read the results */
2812 	hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
2813 
2814 	/*
2815 	 * QUERY_QP is handled somewhat differently than the other query
2816 	 * commands.  For QUERY_QP, the actual queried data is offset into
2817 	 * the mailbox (by one 64-bit word).
2818 	 */
2819 	offset = (opcode == QUERY_QP) ? 1 : 0;
2820 
2821 	/* Copy query command results into "query" */
2822 	for (i = 0; i < (size >> 3); i++) {
2823 		data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2824 		    ((uint64_t *)mbox_info.mbi_out->mb_addr + i + offset));
2825 		((uint64_t *)query)[i] = data;
2826 	}
2827 
2828 cmn_query_fail:
2829 	/* Free the mailbox */
2830 	hermon_mbox_free(state, &mbox_info);
2831 	return (status);
2832 }
2833 
2834 
2835 /*
2836  * hermon_cmn_ownership_cmd_post()
2837  *    Context: Can be called from interrupt or base context.
2838  *
2839  *    This is the common function for posting all the various types of
2840  *    Hermon HW/SW resource ownership commands.  Since some of the commands
2841  *    differ from the others in the direction of ownership change (i.e.
2842  *    from HW ownership to SW, or vice versa), they differ in the type of
2843  *    mailbox and specific handling that each requires.  This routine does
2844  *    certain checks based on opcode type to determine the direction of
2845  *    the transition and to correctly handle the request.
2846  *
2847  * Note: This common function should be used only with the following
2848  *    opcodes: HW2SW_MPT, HW2SW_EQ, HW2SW_CQ, SW2HW_MPT, SW2HW_EQ, and
2849  *    SW2HW_CQ
2850  */
2851 int
2852 hermon_cmn_ownership_cmd_post(hermon_state_t *state, uint_t opcode,
2853     void *hwrsrc, uint_t size, uint_t hwrsrcindx, uint_t sleepflag)
2854 {
2855 	hermon_mbox_info_t	mbox_info;
2856 	hermon_cmd_post_t	cmd;
2857 	uint64_t		data, in_mapaddr, out_mapaddr;
2858 	uint_t			direction, opmod;
2859 	int			status, i;
2860 
2861 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2862 
2863 	/*
2864 	 * Determine the direction of the ownership transfer based on the
2865 	 * provided opcode
2866 	 */
2867 	if ((opcode == HW2SW_MPT) || (opcode == HW2SW_EQ) ||
2868 	    (opcode == HW2SW_CQ) || (opcode == HW2SW_SRQ)) {
2869 		direction = HERMON_CMD_RSRC_HW2SW;
2870 
2871 	} else if ((opcode == SW2HW_MPT) || (opcode == SW2HW_EQ) ||
2872 	    (opcode == SW2HW_CQ) || (opcode == SW2HW_SRQ)) {
2873 		direction = HERMON_CMD_RSRC_SW2HW;
2874 
2875 	} else {
2876 		return (HERMON_CMD_INVALID_STATUS);
2877 	}
2878 
2879 	/*
2880 	 * If hwrsrc is NULL then we do not allocate a mailbox.  This is used
2881 	 * in the case of memory deregister where the out mailbox is not
2882 	 * needed.  In the case of re-register, we do use the hwrsrc.
2883 	 *
2884 	 * Otherwise, If ownership transfer is going from hardware to software,
2885 	 * then allocate an "Out" mailbox.  This will be filled in later as a
2886 	 * result of the Hermon command.
2887 	 *
2888 	 * And if the ownership transfer is going from software to hardware,
2889 	 * then we need an "In" mailbox, and we need to fill it in and sync it
2890 	 * (if necessary).  Then the mailbox can be passed to the Hermon
2891 	 * firmware.
2892 	 *
2893 	 * For the HW2SW (dereg) case, we only use an out mbox if hwrsrc is !=
2894 	 * NULL.  This implies a re-reg, and the out mbox must be used.  If
2895 	 * hwrsrc is == NULL, then we can save some time and resources by not
2896 	 * using an out mbox at all.  We must set opmod to HERMON_CMD_DO_OUTMBOX
2897 	 * and HERMON_CMD_NO_OUTMBOX appropriately in this case.
2898 	 *
2899 	 * For the SW2HW (reg) case, no out mbox is possible.  We set opmod to
2900 	 * 0 anyway, but this field is not used in this case.
2901 	 */
2902 	if (direction == HERMON_CMD_RSRC_HW2SW) {
2903 		if (hwrsrc != NULL) {
2904 			mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
2905 			status = hermon_mbox_alloc(state, &mbox_info,
2906 			    sleepflag);
2907 			if (status != HERMON_CMD_SUCCESS) {
2908 				return (status);
2909 			}
2910 			in_mapaddr  = 0;
2911 			out_mapaddr = mbox_info.mbi_out->mb_mapaddr;
2912 			opmod = HERMON_CMD_DO_OUTMBOX;
2913 		} else {
2914 			in_mapaddr = 0;
2915 			out_mapaddr = 0;
2916 			opmod = HERMON_CMD_NO_OUTMBOX;
2917 		}
2918 	} else {  /* HERMON_CMD_RSRC_SW2HW */
2919 		mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
2920 		status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2921 		if (status != HERMON_CMD_SUCCESS) {
2922 			return (status);
2923 		}
2924 
2925 		/* Copy the SW2HW ownership command into mailbox */
2926 		for (i = 0; i < (size >> 3); i++) {
2927 			data = ((uint64_t *)hwrsrc)[i];
2928 			ddi_put64(mbox_info.mbi_in->mb_acchdl,
2929 			    ((uint64_t *)mbox_info.mbi_in->mb_addr + i),
2930 			    data);
2931 		}
2932 
2933 		/* Sync the mailbox for the device to read */
2934 		hermon_mbox_sync(mbox_info.mbi_in, 0, size,
2935 		    DDI_DMA_SYNC_FORDEV);
2936 
2937 		in_mapaddr  = mbox_info.mbi_in->mb_mapaddr;
2938 		out_mapaddr = 0;
2939 		opmod = 0;
2940 	}
2941 
2942 	/* Setup and post the Hermon ownership command */
2943 	cmd.cp_inparm	= in_mapaddr;
2944 	cmd.cp_outparm	= out_mapaddr;
2945 	cmd.cp_inmod	= hwrsrcindx;
2946 	cmd.cp_opcode	= (uint16_t)opcode;
2947 	cmd.cp_opmod	= (uint16_t)opmod;
2948 	cmd.cp_flags	= sleepflag;
2949 	status = hermon_cmd_post(state, &cmd);
2950 	if (status != HERMON_CMD_SUCCESS) {
2951 		goto cmn_ownership_fail;
2952 	}
2953 
2954 	/*
2955 	 * As mentioned above, for HW2SW ownership transfers we need to
2956 	 * sync (if necessary) and copy out the resulting data from the
2957 	 * "Out" mailbox" (assuming the above command was successful).
2958 	 */
2959 	if (direction == HERMON_CMD_RSRC_HW2SW && hwrsrc != NULL) {
2960 
2961 		/* Sync the mailbox to read the results */
2962 		hermon_mbox_sync(mbox_info.mbi_out, 0, size,
2963 		    DDI_DMA_SYNC_FORCPU);
2964 
2965 		/* Copy HW2SW ownership command results into "hwrsrc" */
2966 		for (i = 0; i < (size >> 3); i++) {
2967 			data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2968 			    ((uint64_t *)mbox_info.mbi_out->mb_addr + i));
2969 			((uint64_t *)hwrsrc)[i] = data;
2970 		}
2971 	}
2972 
2973 cmn_ownership_fail:
2974 	if (hwrsrc != NULL) {
2975 		/* Free the mailbox */
2976 		hermon_mbox_free(state, &mbox_info);
2977 	}
2978 	return (status);
2979 }
2980 
2981 
2982 /*
2983  * hermon_conf_special_qp_cmd_post()
2984  *    Context: Can be called from interrupt or base context.
2985  */
2986 /*ARGSUSED*/
2987 int
2988 hermon_conf_special_qp_cmd_post(hermon_state_t *state, uint_t qpindx,
2989     uint_t qptype, uint_t sleepflag, uint_t opmod)
2990 {
2991 	hermon_cmd_post_t	cmd;
2992 	int			status;
2993 
2994 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2995 
2996 	/* Setup and post Hermon "CONF_SPECIAL_QP" command */
2997 	cmd.cp_inparm	= 0;
2998 	cmd.cp_outparm	= 0;
2999 	cmd.cp_inmod	= qpindx & 0x00FFFFF8;	/* mask off low 3 bits */
3000 	cmd.cp_opcode	= CONF_SPECIAL_QP;
3001 	cmd.cp_opmod	= (uint16_t)opmod;
3002 	cmd.cp_flags	= sleepflag;
3003 	status = hermon_cmd_post(state, &cmd);
3004 
3005 	return (status);
3006 }
3007 
3008 
3009 /*
3010  * hermon_mgid_hash_cmd_post()
3011  *    Context: Can be called from interrupt or base context.
3012  */
3013 int
3014 hermon_mgid_hash_cmd_post(hermon_state_t *state, uint64_t mgid_h,
3015     uint64_t mgid_l, uint64_t *mgid_hash, uint_t sleepflag)
3016 {
3017 	hermon_mbox_info_t	mbox_info;
3018 	hermon_cmd_post_t	cmd;
3019 	int			status;
3020 
3021 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3022 
3023 	/* Get an "In" mailbox for the command */
3024 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3025 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3026 	if (status != HERMON_CMD_SUCCESS) {
3027 		return (status);
3028 	}
3029 
3030 	/* Copy the Hermon "MGID_HASH" command into mailbox */
3031 	ddi_put64(mbox_info.mbi_in->mb_acchdl,
3032 	    ((uint64_t *)mbox_info.mbi_in->mb_addr + 0), mgid_h);
3033 	ddi_put64(mbox_info.mbi_in->mb_acchdl,
3034 	    ((uint64_t *)mbox_info.mbi_in->mb_addr + 1), mgid_l);
3035 
3036 	/* Sync the mailbox for the device to read */
3037 	hermon_mbox_sync(mbox_info.mbi_in, 0, HERMON_CMD_MGIDHASH_SZ,
3038 	    DDI_DMA_SYNC_FORDEV);
3039 
3040 	/* Setup and post the Hermon "MGID_HASH" command */
3041 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
3042 	cmd.cp_outparm	= 0;
3043 	cmd.cp_inmod	= 0;
3044 	cmd.cp_opcode	= MGID_HASH;
3045 	cmd.cp_opmod	= 0;
3046 	cmd.cp_flags	= sleepflag;
3047 	status = hermon_cmd_post(state, &cmd);
3048 
3049 	/* MGID hash value is returned in command "outparam" */
3050 	*mgid_hash = cmd.cp_outparm;
3051 
3052 	/* Free the mailbox */
3053 	hermon_mbox_free(state, &mbox_info);
3054 	return (status);
3055 }
3056 
3057 
3058 /*
3059  * hermon_read_mgm_cmd_post()
3060  *    Context: Can be called from interrupt or base context.
3061  *
3062  * Note: It is assumed that the "mcg" parameter is actually a pointer to a
3063  *    "hermon_hw_mcg_t" struct and some number of "hermon_hw_mcg_qp_list_t"
3064  *    structs.  Combined size should be equal to result of HERMON_MCGMEM_SZ()
3065  *    macro.
3066  */
3067 int
3068 hermon_read_mgm_cmd_post(hermon_state_t *state, hermon_hw_mcg_t *mcg,
3069     uint_t mcgindx, uint_t sleepflag)
3070 {
3071 	hermon_mbox_info_t	mbox_info;
3072 	hermon_cmd_post_t	cmd;
3073 	uint64_t		data;
3074 	uint32_t		data32;
3075 	uint_t			size, hdrsz, qplistsz;
3076 	int			status, i;
3077 
3078 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3079 
3080 	/* Get an "Out" mailbox for the results */
3081 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
3082 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3083 	if (status != HERMON_CMD_SUCCESS) {
3084 		return (status);
3085 	}
3086 
3087 	/* Setup and post Hermon "READ_MGM" command */
3088 	cmd.cp_inparm	= 0;
3089 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
3090 	cmd.cp_inmod	= mcgindx;
3091 	cmd.cp_opcode	= READ_MGM;
3092 	cmd.cp_opmod	= 0;
3093 	cmd.cp_flags	= sleepflag;
3094 	status = hermon_cmd_post(state, &cmd);
3095 	if (status != HERMON_CMD_SUCCESS) {
3096 		goto read_mgm_fail;
3097 	}
3098 
3099 	/* Sync the mailbox to read the results */
3100 	size = HERMON_MCGMEM_SZ(state);
3101 	hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
3102 
3103 	/* Copy the READ_MGM command results into "mcg" */
3104 	hdrsz = sizeof (hermon_hw_mcg_t);
3105 	for (i = 0; i < (hdrsz >> 3); i++) {
3106 		data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
3107 		    ((uint64_t *)mbox_info.mbi_out->mb_addr + i));
3108 		((uint64_t *)mcg)[i] = data;
3109 	}
3110 	qplistsz = size - hdrsz;
3111 	for (i = 0; i < (qplistsz >> 2); i++) {
3112 		data32 = ddi_get32(mbox_info.mbi_out->mb_acchdl,
3113 		    ((uint32_t *)mbox_info.mbi_out->mb_addr + i + 8));
3114 		((uint32_t *)mcg)[i + 8] = data32;
3115 	}
3116 
3117 read_mgm_fail:
3118 	/* Free the mailbox */
3119 	hermon_mbox_free(state, &mbox_info);
3120 	return (status);
3121 }
3122 
3123 
3124 /*
3125  * hermon_write_mgm_cmd_post()
3126  *    Context: Can be called from interrupt or base context.
3127  *
3128  * Note: It is assumed that the "mcg" parameter is actually a pointer to a
3129  *    "hermon_hw_mcg_t" struct and some number of "hermon_hw_mcg_qp_list_t"
3130  *    structs.  Combined size should be equal to result of HERMON_MCGMEM_SZ()
3131  *    macro.
3132  */
3133 int
3134 hermon_write_mgm_cmd_post(hermon_state_t *state, hermon_hw_mcg_t *mcg,
3135     uint_t mcgindx, uint_t sleepflag)
3136 {
3137 	hermon_mbox_info_t	mbox_info;
3138 	hermon_cmd_post_t	cmd;
3139 	uint64_t		data;
3140 	uint_t			size, hdrsz, qplistsz;
3141 	int			status, i;
3142 
3143 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3144 
3145 	/* Get an "In" mailbox for the command */
3146 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3147 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3148 	if (status != HERMON_CMD_SUCCESS) {
3149 		return (status);
3150 	}
3151 
3152 	/* Copy the Hermon "WRITE_MGM" command into mailbox */
3153 	size  = HERMON_MCGMEM_SZ(state);
3154 	hdrsz = sizeof (hermon_hw_mcg_t);
3155 	for (i = 0; i < (hdrsz >> 3); i++) {
3156 		data = ((uint64_t *)mcg)[i];
3157 		ddi_put64(mbox_info.mbi_in->mb_acchdl,
3158 		    ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
3159 	}
3160 	qplistsz = size - hdrsz;
3161 	for (i = 0; i < (qplistsz >> 2); i++) {
3162 		data = ((uint32_t *)mcg)[i + 8];
3163 		ddi_put32(mbox_info.mbi_in->mb_acchdl,
3164 		    ((uint32_t *)mbox_info.mbi_in->mb_addr + i + 8), data);
3165 	}
3166 
3167 	/* Sync the mailbox for the device to read */
3168 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
3169 
3170 	/* Setup and post Hermon "WRITE_MGM" command */
3171 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
3172 	cmd.cp_outparm	= 0;
3173 	cmd.cp_inmod	= mcgindx;
3174 	cmd.cp_opcode	= WRITE_MGM;
3175 	cmd.cp_opmod	= 0;
3176 	cmd.cp_flags	= sleepflag;
3177 	status = hermon_cmd_post(state, &cmd);
3178 
3179 	/* Free the mailbox */
3180 	hermon_mbox_free(state, &mbox_info);
3181 	return (status);
3182 }
3183 
3184 /*
3185  * hermon_resize_srq_cmd_post()
3186  *    Context: Can be called from interrupt or base context.
3187  */
3188 
3189 int hermon_resize_srq_cmd_post(hermon_state_t *state, hermon_hw_srqc_t *srq,
3190     uint_t srqnum, uint_t sleepflag)
3191 {
3192 	hermon_mbox_info_t	mbox_info;
3193 	hermon_cmd_post_t	cmd;
3194 	uint64_t		data;
3195 	uint_t			size;
3196 	int			status, i;
3197 
3198 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3199 
3200 	/* Get an "In" mailbox for the command */
3201 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3202 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3203 	if (status != HERMON_CMD_SUCCESS) {
3204 		return (status);
3205 	}
3206 
3207 	/* Copy the Hermon "RESIZE_SRQ" command into mailbox */
3208 	size = sizeof (hermon_hw_srqc_t);
3209 	for (i = 0; i < (size >> 3); i++) {
3210 		data = ((uint64_t *)(void *)srq)[i];
3211 		ddi_put64(mbox_info.mbi_in->mb_acchdl,
3212 		    ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
3213 	}
3214 
3215 	/* Sync the mailbox for the device to read */
3216 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
3217 
3218 	/* Setup and post Hermon "RESIZE_SRQ" command */
3219 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
3220 	cmd.cp_outparm	= 0;
3221 	cmd.cp_inmod	= srqnum;
3222 	cmd.cp_opcode	= RESIZE_SRQ;
3223 	cmd.cp_opmod	= 0;
3224 	cmd.cp_flags	= sleepflag;
3225 	status = hermon_cmd_post(state, &cmd);
3226 
3227 	/* Free the mailbox */
3228 	hermon_mbox_free(state, &mbox_info);
3229 	return (status);
3230 }
3231 /*
3232  * hermon_modify_mpt_cmd_post()
3233  *    Context: Can be called from interrupt or base context.
3234  */
3235 int
3236 hermon_modify_mpt_cmd_post(hermon_state_t *state, hermon_hw_dmpt_t *mpt,
3237     uint_t mptindx, uint_t flags, uint_t sleepflag)
3238 {
3239 	hermon_mbox_info_t	mbox_info;
3240 	hermon_cmd_post_t	cmd;
3241 	uint64_t		data;
3242 	uint_t			size;
3243 	int			status, i;
3244 
3245 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3246 
3247 	/* Get an "In" mailbox for the command */
3248 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3249 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3250 	if (status != HERMON_CMD_SUCCESS) {
3251 		return (status);
3252 	}
3253 
3254 	/* Copy the Hermon "MODIFY_MPT" command into mailbox */
3255 	size = sizeof (hermon_hw_dmpt_t);
3256 	for (i = 0; i < (size >> 3); i++) {
3257 		data = ((uint64_t *)mpt)[i];
3258 		ddi_put64(mbox_info.mbi_in->mb_acchdl,
3259 		    ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
3260 	}
3261 
3262 	/* Sync the mailbox for the device to read */
3263 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
3264 
3265 	/* Setup and post Hermon "MODIFY_MPT" command */
3266 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
3267 	cmd.cp_outparm	= 0;
3268 	cmd.cp_inmod	= mptindx;
3269 	cmd.cp_opcode	= MODIFY_MPT;
3270 	cmd.cp_opmod	= (uint16_t)flags;
3271 	cmd.cp_flags	= sleepflag;
3272 	status = hermon_cmd_post(state, &cmd);
3273 
3274 	/* Free the mailbox */
3275 	hermon_mbox_free(state, &mbox_info);
3276 	return (status);
3277 }
3278 
3279 
3280 int
3281 hermon_nop_post(hermon_state_t *state, uint_t interval, uint_t sleep)
3282 {
3283 	hermon_cmd_post_t	cmd;
3284 	int			status;
3285 
3286 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3287 
3288 	/* Setup and post Hermon "CMD_NOP" command */
3289 	cmd.cp_inparm	= 0;
3290 	cmd.cp_outparm	= 0;
3291 	cmd.cp_inmod	= interval;
3292 	cmd.cp_opcode	= CMD_NOP;
3293 	cmd.cp_opmod	= 0;
3294 	cmd.cp_flags	= HERMON_CMD_SLEEP_NOSPIN;
3295 	if (sleep) cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN;
3296 	status = hermon_cmd_post(state, &cmd);
3297 	return (status);
3298 }
3299 
3300 int
3301 hermon_setdebug_post(hermon_state_t *state)
3302 {
3303 	hermon_cmd_post_t	cmd;
3304 	int			status;
3305 
3306 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3307 
3308 	/* Setup and post Hermon "CMD_NOP" command */
3309 	cmd.cp_inparm	= 0xFFFFFFFFFFFFFFFF;
3310 	cmd.cp_outparm	= 0;
3311 	cmd.cp_inmod	= 0;
3312 	cmd.cp_opcode	= SET_DEBUG_MSG;
3313 	cmd.cp_opmod	= 0;
3314 	cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN;
3315 	status = hermon_cmd_post(state, &cmd);
3316 	return (status);
3317 }
3318 
3319 
3320 int
3321 hermon_read_mtt_cmd_post(hermon_state_t *state, uint64_t mtt_addr,
3322 	hermon_hw_mtt_t *mtt)
3323 {
3324 
3325 	hermon_cmd_post_t	cmd;
3326 	hermon_mbox_info_t	mbox_info;
3327 	int			i, status;
3328 	uint_t			size;
3329 	uint64_t		data;
3330 
3331 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3332 
3333 	/* Get an "Out" mailbox for the command */
3334 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
3335 	status = hermon_mbox_alloc(state, &mbox_info, HERMON_CMD_SLEEP_NOSPIN);
3336 	if (status != HERMON_CMD_SUCCESS) {
3337 		return (status);
3338 	}
3339 
3340 	/* Setup and post the "READ_MTT" command */
3341 	cmd.cp_inparm	= mtt_addr;
3342 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
3343 	cmd.cp_inmod	= 1;
3344 	cmd.cp_opcode	= READ_MTT;
3345 	cmd.cp_opmod	= 0;
3346 	cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN;
3347 	status = hermon_cmd_post(state, &cmd);
3348 	if (status != HERMON_CMD_SUCCESS) {
3349 		return (status);
3350 	}
3351 
3352 	/* Sync the mailbox to read the results */
3353 	size = sizeof (hermon_hw_mtt_t);
3354 	hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
3355 
3356 	/* Copy mtt read out */
3357 	for (i = 0; i < (size >> 3); i++) {
3358 		data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
3359 		    ((uint64_t *)mbox_info.mbi_out->mb_addr + i));
3360 		((uint64_t *)(void *)mtt)[i] = data;
3361 	}
3362 
3363 	/* Free the mailbox */
3364 	hermon_mbox_free(state, &mbox_info);
3365 	return (status);
3366 }
3367