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