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