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