19e39c5baSBill Taylor /*
29e39c5baSBill Taylor  * CDDL HEADER START
39e39c5baSBill Taylor  *
49e39c5baSBill Taylor  * The contents of this file are subject to the terms of the
59e39c5baSBill Taylor  * Common Development and Distribution License (the "License").
69e39c5baSBill Taylor  * You may not use this file except in compliance with the License.
79e39c5baSBill Taylor  *
89e39c5baSBill Taylor  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99e39c5baSBill Taylor  * or http://www.opensolaris.org/os/licensing.
109e39c5baSBill Taylor  * See the License for the specific language governing permissions
119e39c5baSBill Taylor  * and limitations under the License.
129e39c5baSBill Taylor  *
139e39c5baSBill Taylor  * When distributing Covered Code, include this CDDL HEADER in each
149e39c5baSBill Taylor  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159e39c5baSBill Taylor  * If applicable, add the following below this CDDL HEADER, with the
169e39c5baSBill Taylor  * fields enclosed by brackets "[]" replaced with your own identifying
179e39c5baSBill Taylor  * information: Portions Copyright [yyyy] [name of copyright owner]
189e39c5baSBill Taylor  *
199e39c5baSBill Taylor  * CDDL HEADER END
209e39c5baSBill Taylor  */
219e39c5baSBill Taylor 
229e39c5baSBill Taylor /*
239e39c5baSBill Taylor  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
249e39c5baSBill Taylor  * Use is subject to license terms.
259e39c5baSBill Taylor  */
269e39c5baSBill Taylor 
279e39c5baSBill Taylor /*
289e39c5baSBill Taylor  * tavor_cmd.c
299e39c5baSBill Taylor  *    Tavor Firmware Command Routines
309e39c5baSBill Taylor  *
319e39c5baSBill Taylor  *    Implements all the routines necessary for allocating, posting, and
329e39c5baSBill Taylor  *    freeing commands for the Tavor firmware.  These routines manage a
339e39c5baSBill Taylor  *    preallocated list of command mailboxes and provide interfaces to post
349e39c5baSBill Taylor  *    each of the several dozen commands to the Tavor firmware.
359e39c5baSBill Taylor  */
369e39c5baSBill Taylor 
379e39c5baSBill Taylor #include <sys/types.h>
389e39c5baSBill Taylor #include <sys/conf.h>
399e39c5baSBill Taylor #include <sys/ddi.h>
409e39c5baSBill Taylor #include <sys/sunddi.h>
419e39c5baSBill Taylor #include <sys/modctl.h>
429e39c5baSBill Taylor 
439e39c5baSBill Taylor #include <sys/ib/adapters/tavor/tavor.h>
449e39c5baSBill Taylor 
459e39c5baSBill Taylor static int tavor_impl_mbox_alloc(tavor_state_t *state, tavor_mboxlist_t *mblist,
469e39c5baSBill Taylor     tavor_mbox_t **mb, uint_t mbox_wait);
479e39c5baSBill Taylor static void tavor_impl_mbox_free(tavor_mboxlist_t *mblist, tavor_mbox_t **mb);
489e39c5baSBill Taylor static int tavor_impl_mboxlist_init(tavor_state_t *state,
499e39c5baSBill Taylor     tavor_mboxlist_t *mblist, uint_t num_mbox, tavor_rsrc_type_t type);
509e39c5baSBill Taylor static void tavor_impl_mboxlist_fini(tavor_state_t *state,
519e39c5baSBill Taylor     tavor_mboxlist_t *mblist);
529e39c5baSBill Taylor static int tavor_outstanding_cmd_alloc(tavor_state_t *state,
539e39c5baSBill Taylor     tavor_cmd_t **cmd_ptr, uint_t cmd_wait);
549e39c5baSBill Taylor static void tavor_outstanding_cmd_free(tavor_state_t *state,
559e39c5baSBill Taylor     tavor_cmd_t **cmd_ptr);
569e39c5baSBill Taylor static int tavor_write_hcr(tavor_state_t *state, tavor_cmd_post_t *cmdpost,
579e39c5baSBill Taylor     uint16_t token);
589e39c5baSBill Taylor static void tavor_mbox_sync(tavor_mbox_t *mbox, uint_t offset,
599e39c5baSBill Taylor     uint_t length, uint_t flag);
609e39c5baSBill Taylor 
619e39c5baSBill Taylor /*
629e39c5baSBill Taylor  * tavor_cmd_post()
639e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
649e39c5baSBill Taylor  *
659e39c5baSBill Taylor  *    The "cp_flags" field in cmdpost
669e39c5baSBill Taylor  *    is used to determine whether to wait for an available
679e39c5baSBill Taylor  *    outstanding command (if necessary) or to return error.
689e39c5baSBill Taylor  */
699e39c5baSBill Taylor int
tavor_cmd_post(tavor_state_t * state,tavor_cmd_post_t * cmdpost)709e39c5baSBill Taylor tavor_cmd_post(tavor_state_t *state, tavor_cmd_post_t *cmdpost)
719e39c5baSBill Taylor {
729e39c5baSBill Taylor 	tavor_cmd_t	*cmdptr;
739e39c5baSBill Taylor 	int		status;
749e39c5baSBill Taylor 	uint16_t	token;
759e39c5baSBill Taylor 
769e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdpost))
779e39c5baSBill Taylor 
789e39c5baSBill Taylor 	/* Determine if we are going to spin until completion */
799e39c5baSBill Taylor 	if (cmdpost->cp_flags == TAVOR_CMD_NOSLEEP_SPIN) {
809e39c5baSBill Taylor 
819e39c5baSBill Taylor 		/* Write the command to the HCR */
829e39c5baSBill Taylor 		status = tavor_write_hcr(state, cmdpost, 0);
839e39c5baSBill Taylor 		if (status != TAVOR_CMD_SUCCESS) {
849e39c5baSBill Taylor 			return (status);
859e39c5baSBill Taylor 		}
869e39c5baSBill Taylor 
879e39c5baSBill Taylor 		return (TAVOR_CMD_SUCCESS);
889e39c5baSBill Taylor 
899e39c5baSBill Taylor 	} else {  /* "TAVOR_CMD_SLEEP_NOSPIN" */
909e39c5baSBill Taylor 
919e39c5baSBill Taylor 		ASSERT(TAVOR_SLEEPFLAG_FOR_CONTEXT() != TAVOR_NOSLEEP);
929e39c5baSBill Taylor 
939e39c5baSBill Taylor 		/* NOTE: Expect threads to be waiting in here */
949e39c5baSBill Taylor 		status = tavor_outstanding_cmd_alloc(state, &cmdptr,
959e39c5baSBill Taylor 		    cmdpost->cp_flags);
969e39c5baSBill Taylor 		if (status != TAVOR_CMD_SUCCESS) {
979e39c5baSBill Taylor 			return (status);
989e39c5baSBill Taylor 		}
999e39c5baSBill Taylor 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdptr))
1009e39c5baSBill Taylor 
1019e39c5baSBill Taylor 		/*
1029e39c5baSBill Taylor 		 * Set status to "TAVOR_CMD_INVALID_STATUS".  It is
1039e39c5baSBill Taylor 		 * appropriate to do this here without the "cmd_comp_lock"
1049e39c5baSBill Taylor 		 * because this register is overloaded.  Later it will be
1059e39c5baSBill Taylor 		 * used to indicate - through a change from this invalid
1069e39c5baSBill Taylor 		 * value to some other value - that the condition variable
1079e39c5baSBill Taylor 		 * has been signaled.  Once it has, status will then contain
1089e39c5baSBill Taylor 		 * the _real_ completion status
1099e39c5baSBill Taylor 		 */
1109e39c5baSBill Taylor 		cmdptr->cmd_status = TAVOR_CMD_INVALID_STATUS;
1119e39c5baSBill Taylor 
1129e39c5baSBill Taylor 		/* Write the command to the HCR */
1139e39c5baSBill Taylor 		token = (uint16_t)cmdptr->cmd_indx;
1149e39c5baSBill Taylor 		status = tavor_write_hcr(state, cmdpost, token);
1159e39c5baSBill Taylor 		if (status != TAVOR_CMD_SUCCESS) {
1169e39c5baSBill Taylor 			tavor_outstanding_cmd_free(state, &cmdptr);
1179e39c5baSBill Taylor 			return (status);
1189e39c5baSBill Taylor 		}
1199e39c5baSBill Taylor 
1209e39c5baSBill Taylor 		/*
1219e39c5baSBill Taylor 		 * cv_wait() on the "command_complete" condition variable.
1229e39c5baSBill Taylor 		 * Note: We have the "__lock_lint" here to workaround warlock.
1239e39c5baSBill Taylor 		 * Since warlock doesn't know that other parts of the Tavor
1249e39c5baSBill Taylor 		 * may occasionally call this routine while holding their own
1259e39c5baSBill Taylor 		 * locks, it complains about this cv_wait.  In reality,
1269e39c5baSBill Taylor 		 * however, the rest of the driver never calls this routine
1279e39c5baSBill Taylor 		 * with a lock held unless they pass TAVOR_CMD_NOSLEEP.
1289e39c5baSBill Taylor 		 */
1299e39c5baSBill Taylor 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*cmdptr))
1309e39c5baSBill Taylor 		mutex_enter(&cmdptr->cmd_comp_lock);
1319e39c5baSBill Taylor 		while (cmdptr->cmd_status == TAVOR_CMD_INVALID_STATUS) {
1329e39c5baSBill Taylor #ifndef	__lock_lint
1339e39c5baSBill Taylor 			cv_wait(&cmdptr->cmd_comp_cv, &cmdptr->cmd_comp_lock);
1349e39c5baSBill Taylor 			/* NOTE: EXPECT SEVERAL THREADS TO BE WAITING HERE */
1359e39c5baSBill Taylor #endif
1369e39c5baSBill Taylor 		}
1379e39c5baSBill Taylor 		mutex_exit(&cmdptr->cmd_comp_lock);
1389e39c5baSBill Taylor 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdptr))
1399e39c5baSBill Taylor 
1409e39c5baSBill Taylor 		/*
1419e39c5baSBill Taylor 		 * Wake up after command completes (cv_signal).  Read status
1429e39c5baSBill Taylor 		 * from the command (success, fail, etc.).  It is appropriate
1439e39c5baSBill Taylor 		 * here (as above) to read the status field without the
1449e39c5baSBill Taylor 		 * "cmd_comp_lock" because it is no longer being used to
1459e39c5baSBill Taylor 		 * indicate whether the condition variable has been signaled
1469e39c5baSBill Taylor 		 * (i.e. at this point we are certain that it already has).
1479e39c5baSBill Taylor 		 */
1489e39c5baSBill Taylor 		status = cmdptr->cmd_status;
1499e39c5baSBill Taylor 
1509e39c5baSBill Taylor 		/* Save the "outparam" values into the cmdpost struct */
1519e39c5baSBill Taylor 		cmdpost->cp_outparm = cmdptr->cmd_outparm;
1529e39c5baSBill Taylor 
1539e39c5baSBill Taylor 		/*
1549e39c5baSBill Taylor 		 * Add the command back to the "outstanding commands list".
1559e39c5baSBill Taylor 		 * Signal the "cmd_list" condition variable, if necessary.
1569e39c5baSBill Taylor 		 */
1579e39c5baSBill Taylor 		tavor_outstanding_cmd_free(state, &cmdptr);
1589e39c5baSBill Taylor 
1599e39c5baSBill Taylor 		if (status != TAVOR_CMD_SUCCESS) {
1609e39c5baSBill Taylor 			return (status);
1619e39c5baSBill Taylor 		}
1629e39c5baSBill Taylor 
1639e39c5baSBill Taylor 		return (TAVOR_CMD_SUCCESS);
1649e39c5baSBill Taylor 	}
1659e39c5baSBill Taylor }
1669e39c5baSBill Taylor 
1679e39c5baSBill Taylor 
1689e39c5baSBill Taylor /*
1699e39c5baSBill Taylor  * tavor_mbox_alloc()
1709e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
1719e39c5baSBill Taylor  *
1729e39c5baSBill Taylor  *    The "mbox_wait" parameter is used to determine whether to
1739e39c5baSBill Taylor  *    wait for a mailbox to become available or not.
1749e39c5baSBill Taylor  */
1759e39c5baSBill Taylor int
tavor_mbox_alloc(tavor_state_t * state,tavor_mbox_info_t * mbox_info,uint_t mbox_wait)1769e39c5baSBill Taylor tavor_mbox_alloc(tavor_state_t *state, tavor_mbox_info_t *mbox_info,
1779e39c5baSBill Taylor     uint_t mbox_wait)
1789e39c5baSBill Taylor {
1799e39c5baSBill Taylor 	int			status;
1809e39c5baSBill Taylor 	uint_t			sleep_context;
1819e39c5baSBill Taylor 
1829e39c5baSBill Taylor 	sleep_context = TAVOR_SLEEPFLAG_FOR_CONTEXT();
1839e39c5baSBill Taylor 
1849e39c5baSBill Taylor 	/* Allocate an "In" mailbox */
1859e39c5baSBill Taylor 	if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_INMBOX) {
1869e39c5baSBill Taylor 		/* Determine correct mboxlist based on calling context */
1879e39c5baSBill Taylor 		if (sleep_context == TAVOR_NOSLEEP) {
1889e39c5baSBill Taylor 			status = tavor_impl_mbox_alloc(state,
1899e39c5baSBill Taylor 			    &state->ts_in_intr_mblist,
1909e39c5baSBill Taylor 			    &mbox_info->mbi_in, mbox_wait);
1919e39c5baSBill Taylor 
1929e39c5baSBill Taylor 			ASSERT(status == TAVOR_CMD_SUCCESS);
1939e39c5baSBill Taylor 		} else {
1949e39c5baSBill Taylor 			/* NOTE: Expect threads to be waiting in here */
1959e39c5baSBill Taylor 			status = tavor_impl_mbox_alloc(state,
1969e39c5baSBill Taylor 			    &state->ts_in_mblist, &mbox_info->mbi_in,
1979e39c5baSBill Taylor 			    mbox_wait);
1989e39c5baSBill Taylor 			if (status != TAVOR_CMD_SUCCESS) {
1999e39c5baSBill Taylor 				return (status);
2009e39c5baSBill Taylor 			}
2019e39c5baSBill Taylor 		}
2029e39c5baSBill Taylor 
2039e39c5baSBill Taylor 	}
2049e39c5baSBill Taylor 
2059e39c5baSBill Taylor 	/* Allocate an "Out" mailbox */
2069e39c5baSBill Taylor 	if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_OUTMBOX) {
2079e39c5baSBill Taylor 		/* Determine correct mboxlist based on calling context */
2089e39c5baSBill Taylor 		if (sleep_context == TAVOR_NOSLEEP) {
2099e39c5baSBill Taylor 			status = tavor_impl_mbox_alloc(state,
2109e39c5baSBill Taylor 			    &state->ts_out_intr_mblist,
2119e39c5baSBill Taylor 			    &mbox_info->mbi_out, mbox_wait);
2129e39c5baSBill Taylor 
2139e39c5baSBill Taylor 			ASSERT(status == TAVOR_CMD_SUCCESS);
2149e39c5baSBill Taylor 		} else {
2159e39c5baSBill Taylor 			/* NOTE: Expect threads to be waiting in here */
2169e39c5baSBill Taylor 			status = tavor_impl_mbox_alloc(state,
2179e39c5baSBill Taylor 			    &state->ts_out_mblist, &mbox_info->mbi_out,
2189e39c5baSBill Taylor 			    mbox_wait);
2199e39c5baSBill Taylor 			if (status != TAVOR_CMD_SUCCESS) {
2209e39c5baSBill Taylor 				/* If we allocated an "In" mailbox, free it */
2219e39c5baSBill Taylor 				if (mbox_info->mbi_alloc_flags &
2229e39c5baSBill Taylor 				    TAVOR_ALLOC_INMBOX) {
2239e39c5baSBill Taylor 					tavor_impl_mbox_free(
2249e39c5baSBill Taylor 					    &state->ts_in_mblist,
2259e39c5baSBill Taylor 					    &mbox_info->mbi_in);
2269e39c5baSBill Taylor 				}
2279e39c5baSBill Taylor 				return (status);
2289e39c5baSBill Taylor 			}
2299e39c5baSBill Taylor 		}
2309e39c5baSBill Taylor 	}
2319e39c5baSBill Taylor 
2329e39c5baSBill Taylor 	/* Store appropriate context in mbox_info */
2339e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(mbox_info->mbi_sleep_context))
2349e39c5baSBill Taylor 	mbox_info->mbi_sleep_context = sleep_context;
2359e39c5baSBill Taylor 
2369e39c5baSBill Taylor 	return (TAVOR_CMD_SUCCESS);
2379e39c5baSBill Taylor }
2389e39c5baSBill Taylor 
2399e39c5baSBill Taylor 
2409e39c5baSBill Taylor /*
2419e39c5baSBill Taylor  * tavor_mbox_free()
2429e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
2439e39c5baSBill Taylor  */
2449e39c5baSBill Taylor void
tavor_mbox_free(tavor_state_t * state,tavor_mbox_info_t * mbox_info)2459e39c5baSBill Taylor tavor_mbox_free(tavor_state_t *state, tavor_mbox_info_t *mbox_info)
2469e39c5baSBill Taylor {
2479e39c5baSBill Taylor 	/*
2489e39c5baSBill Taylor 	 * The mailbox has to be freed in the same context from which it was
2499e39c5baSBill Taylor 	 * allocated.  The context is stored in the mbox_info at
2509e39c5baSBill Taylor 	 * tavor_mbox_alloc() time.  We check the stored context against the
2519e39c5baSBill Taylor 	 * current context here.
2529e39c5baSBill Taylor 	 */
2539e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(mbox_info->mbi_sleep_context))
2549e39c5baSBill Taylor 	ASSERT(mbox_info->mbi_sleep_context == TAVOR_SLEEPFLAG_FOR_CONTEXT());
2559e39c5baSBill Taylor 
2569e39c5baSBill Taylor 	/* Determine correct mboxlist based on calling context */
2579e39c5baSBill Taylor 	if (mbox_info->mbi_sleep_context == TAVOR_NOSLEEP) {
2589e39c5baSBill Taylor 		/* Free the intr "In" mailbox */
2599e39c5baSBill Taylor 		if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_INMBOX) {
2609e39c5baSBill Taylor 			tavor_impl_mbox_free(&state->ts_in_intr_mblist,
2619e39c5baSBill Taylor 			    &mbox_info->mbi_in);
2629e39c5baSBill Taylor 		}
2639e39c5baSBill Taylor 
2649e39c5baSBill Taylor 		/* Free the intr "Out" mailbox */
2659e39c5baSBill Taylor 		if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_OUTMBOX) {
2669e39c5baSBill Taylor 			tavor_impl_mbox_free(&state->ts_out_intr_mblist,
2679e39c5baSBill Taylor 			    &mbox_info->mbi_out);
2689e39c5baSBill Taylor 		}
2699e39c5baSBill Taylor 	} else {
2709e39c5baSBill Taylor 		/* Free the "In" mailbox */
2719e39c5baSBill Taylor 		if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_INMBOX) {
2729e39c5baSBill Taylor 			tavor_impl_mbox_free(&state->ts_in_mblist,
2739e39c5baSBill Taylor 			    &mbox_info->mbi_in);
2749e39c5baSBill Taylor 		}
2759e39c5baSBill Taylor 
2769e39c5baSBill Taylor 		/* Free the "Out" mailbox */
2779e39c5baSBill Taylor 		if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_OUTMBOX) {
2789e39c5baSBill Taylor 			tavor_impl_mbox_free(&state->ts_out_mblist,
2799e39c5baSBill Taylor 			    &mbox_info->mbi_out);
2809e39c5baSBill Taylor 		}
2819e39c5baSBill Taylor 	}
2829e39c5baSBill Taylor }
2839e39c5baSBill Taylor 
2849e39c5baSBill Taylor 
2859e39c5baSBill Taylor /*
2869e39c5baSBill Taylor  * tavor_cmd_complete_handler()
2879e39c5baSBill Taylor  *    Context: Called only from interrupt context.
2889e39c5baSBill Taylor  */
2899e39c5baSBill Taylor int
tavor_cmd_complete_handler(tavor_state_t * state,tavor_eqhdl_t eq,tavor_hw_eqe_t * eqe)2909e39c5baSBill Taylor tavor_cmd_complete_handler(tavor_state_t *state, tavor_eqhdl_t eq,
2919e39c5baSBill Taylor     tavor_hw_eqe_t *eqe)
2929e39c5baSBill Taylor {
2939e39c5baSBill Taylor 	tavor_cmd_t		*cmdp;
2949e39c5baSBill Taylor 	uint_t			eqe_evttype;
2959e39c5baSBill Taylor 
2969e39c5baSBill Taylor 	eqe_evttype = TAVOR_EQE_EVTTYPE_GET(eq, eqe);
2979e39c5baSBill Taylor 
2989e39c5baSBill Taylor 	ASSERT(eqe_evttype == TAVOR_EVT_COMMAND_INTF_COMP ||
2999e39c5baSBill Taylor 	    eqe_evttype == TAVOR_EVT_EQ_OVERFLOW);
3009e39c5baSBill Taylor 
3019e39c5baSBill Taylor 	if (eqe_evttype == TAVOR_EVT_EQ_OVERFLOW) {
3029e39c5baSBill Taylor 		tavor_eq_overflow_handler(state, eq, eqe);
3039e39c5baSBill Taylor 
3049e39c5baSBill Taylor 		return (DDI_FAILURE);
3059e39c5baSBill Taylor 	}
3069e39c5baSBill Taylor 
3079e39c5baSBill Taylor 	/*
3089e39c5baSBill Taylor 	 * Find the outstanding command pointer based on value returned
3099e39c5baSBill Taylor 	 * in "token"
3109e39c5baSBill Taylor 	 */
3119e39c5baSBill Taylor 	cmdp = &state->ts_cmd_list.cml_cmd[TAVOR_EQE_CMDTOKEN_GET(eq, eqe)];
3129e39c5baSBill Taylor 
3139e39c5baSBill Taylor 	/* Signal the waiting thread */
3149e39c5baSBill Taylor 	mutex_enter(&cmdp->cmd_comp_lock);
3159e39c5baSBill Taylor 	cmdp->cmd_outparm = ((uint64_t)TAVOR_EQE_CMDOUTP0_GET(eq, eqe) << 32) |
3169e39c5baSBill Taylor 	    TAVOR_EQE_CMDOUTP1_GET(eq, eqe);
3179e39c5baSBill Taylor 	cmdp->cmd_status = TAVOR_EQE_CMDSTATUS_GET(eq, eqe);
3189e39c5baSBill Taylor 
3199e39c5baSBill Taylor 	cv_signal(&cmdp->cmd_comp_cv);
3209e39c5baSBill Taylor 	mutex_exit(&cmdp->cmd_comp_lock);
3219e39c5baSBill Taylor 
3229e39c5baSBill Taylor 	return (DDI_SUCCESS);
3239e39c5baSBill Taylor }
3249e39c5baSBill Taylor 
3259e39c5baSBill Taylor 
3269e39c5baSBill Taylor /*
3279e39c5baSBill Taylor  * tavor_inmbox_list_init()
3289e39c5baSBill Taylor  *    Context: Only called from attach() path context
3299e39c5baSBill Taylor  */
3309e39c5baSBill Taylor int
tavor_inmbox_list_init(tavor_state_t * state)3319e39c5baSBill Taylor tavor_inmbox_list_init(tavor_state_t *state)
3329e39c5baSBill Taylor {
3339e39c5baSBill Taylor 	int		status;
3349e39c5baSBill Taylor 	uint_t		num_inmbox;
3359e39c5baSBill Taylor 
3369e39c5baSBill Taylor 	/* Initialize the "In" mailbox list */
3379e39c5baSBill Taylor 	num_inmbox  =  (1 << state->ts_cfg_profile->cp_log_num_inmbox);
3389e39c5baSBill Taylor 	status = tavor_impl_mboxlist_init(state, &state->ts_in_mblist,
3399e39c5baSBill Taylor 	    num_inmbox, TAVOR_IN_MBOX);
3409e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
3419e39c5baSBill Taylor 		return (DDI_FAILURE);
3429e39c5baSBill Taylor 	}
3439e39c5baSBill Taylor 
3449e39c5baSBill Taylor 	return (DDI_SUCCESS);
3459e39c5baSBill Taylor }
3469e39c5baSBill Taylor 
3479e39c5baSBill Taylor 
3489e39c5baSBill Taylor /*
3499e39c5baSBill Taylor  * tavor_intr_inmbox_list_init()
3509e39c5baSBill Taylor  *    Context: Only called from attach() path context
3519e39c5baSBill Taylor  */
3529e39c5baSBill Taylor int
tavor_intr_inmbox_list_init(tavor_state_t * state)3539e39c5baSBill Taylor tavor_intr_inmbox_list_init(tavor_state_t *state)
3549e39c5baSBill Taylor {
3559e39c5baSBill Taylor 	int		status;
3569e39c5baSBill Taylor 	uint_t		num_inmbox;
3579e39c5baSBill Taylor 
3589e39c5baSBill Taylor 	/* Initialize the interrupt "In" mailbox list */
3599e39c5baSBill Taylor 	num_inmbox  =  (1 << state->ts_cfg_profile->cp_log_num_intr_inmbox);
3609e39c5baSBill Taylor 	status = tavor_impl_mboxlist_init(state, &state->ts_in_intr_mblist,
3619e39c5baSBill Taylor 	    num_inmbox, TAVOR_INTR_IN_MBOX);
3629e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
3639e39c5baSBill Taylor 		return (DDI_FAILURE);
3649e39c5baSBill Taylor 	}
3659e39c5baSBill Taylor 
3669e39c5baSBill Taylor 	return (DDI_SUCCESS);
3679e39c5baSBill Taylor }
3689e39c5baSBill Taylor 
3699e39c5baSBill Taylor 
3709e39c5baSBill Taylor /*
3719e39c5baSBill Taylor  * tavor_outmbox_list_init()
3729e39c5baSBill Taylor  *    Context: Only called from attach() path context
3739e39c5baSBill Taylor  */
3749e39c5baSBill Taylor int
tavor_outmbox_list_init(tavor_state_t * state)3759e39c5baSBill Taylor tavor_outmbox_list_init(tavor_state_t *state)
3769e39c5baSBill Taylor {
3779e39c5baSBill Taylor 	int		status;
3789e39c5baSBill Taylor 	uint_t		num_outmbox;
3799e39c5baSBill Taylor 
3809e39c5baSBill Taylor 	/* Initialize the "Out" mailbox list */
3819e39c5baSBill Taylor 	num_outmbox  =  (1 << state->ts_cfg_profile->cp_log_num_outmbox);
3829e39c5baSBill Taylor 	status = tavor_impl_mboxlist_init(state, &state->ts_out_mblist,
3839e39c5baSBill Taylor 	    num_outmbox, TAVOR_OUT_MBOX);
3849e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
3859e39c5baSBill Taylor 		return (DDI_FAILURE);
3869e39c5baSBill Taylor 	}
3879e39c5baSBill Taylor 
3889e39c5baSBill Taylor 	return (DDI_SUCCESS);
3899e39c5baSBill Taylor }
3909e39c5baSBill Taylor 
3919e39c5baSBill Taylor 
3929e39c5baSBill Taylor /*
3939e39c5baSBill Taylor  * tavor_intr_outmbox_list_init()
3949e39c5baSBill Taylor  *    Context: Only called from attach() path context
3959e39c5baSBill Taylor  */
3969e39c5baSBill Taylor int
tavor_intr_outmbox_list_init(tavor_state_t * state)3979e39c5baSBill Taylor tavor_intr_outmbox_list_init(tavor_state_t *state)
3989e39c5baSBill Taylor {
3999e39c5baSBill Taylor 	int		status;
4009e39c5baSBill Taylor 	uint_t		num_outmbox;
4019e39c5baSBill Taylor 
4029e39c5baSBill Taylor 	/* Initialize the interrupts "Out" mailbox list */
4039e39c5baSBill Taylor 	num_outmbox  =  (1 << state->ts_cfg_profile->cp_log_num_intr_outmbox);
4049e39c5baSBill Taylor 	status = tavor_impl_mboxlist_init(state, &state->ts_out_intr_mblist,
4059e39c5baSBill Taylor 	    num_outmbox, TAVOR_INTR_OUT_MBOX);
4069e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
4079e39c5baSBill Taylor 		return (DDI_FAILURE);
4089e39c5baSBill Taylor 	}
4099e39c5baSBill Taylor 
4109e39c5baSBill Taylor 	return (DDI_SUCCESS);
4119e39c5baSBill Taylor }
4129e39c5baSBill Taylor 
4139e39c5baSBill Taylor 
4149e39c5baSBill Taylor /*
4159e39c5baSBill Taylor  * tavor_inmbox_list_fini()
4169e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
4179e39c5baSBill Taylor  */
4189e39c5baSBill Taylor void
tavor_inmbox_list_fini(tavor_state_t * state)4199e39c5baSBill Taylor tavor_inmbox_list_fini(tavor_state_t *state)
4209e39c5baSBill Taylor {
4219e39c5baSBill Taylor 	/* Free up the "In" mailbox list */
4229e39c5baSBill Taylor 	tavor_impl_mboxlist_fini(state, &state->ts_in_mblist);
4239e39c5baSBill Taylor }
4249e39c5baSBill Taylor 
4259e39c5baSBill Taylor 
4269e39c5baSBill Taylor /*
4279e39c5baSBill Taylor  * tavor_intr_inmbox_list_fini()
4289e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
4299e39c5baSBill Taylor  */
4309e39c5baSBill Taylor void
tavor_intr_inmbox_list_fini(tavor_state_t * state)4319e39c5baSBill Taylor tavor_intr_inmbox_list_fini(tavor_state_t *state)
4329e39c5baSBill Taylor {
4339e39c5baSBill Taylor 	/* Free up the interupts "In" mailbox list */
4349e39c5baSBill Taylor 	tavor_impl_mboxlist_fini(state, &state->ts_in_intr_mblist);
4359e39c5baSBill Taylor }
4369e39c5baSBill Taylor 
4379e39c5baSBill Taylor 
4389e39c5baSBill Taylor /*
4399e39c5baSBill Taylor  * tavor_outmbox_list_fini()
4409e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
4419e39c5baSBill Taylor  */
4429e39c5baSBill Taylor void
tavor_outmbox_list_fini(tavor_state_t * state)4439e39c5baSBill Taylor tavor_outmbox_list_fini(tavor_state_t *state)
4449e39c5baSBill Taylor {
4459e39c5baSBill Taylor 	/* Free up the "Out" mailbox list */
4469e39c5baSBill Taylor 	tavor_impl_mboxlist_fini(state, &state->ts_out_mblist);
4479e39c5baSBill Taylor }
4489e39c5baSBill Taylor 
4499e39c5baSBill Taylor 
4509e39c5baSBill Taylor /*
4519e39c5baSBill Taylor  * tavor_intr_outmbox_list_fini()
4529e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
4539e39c5baSBill Taylor  */
4549e39c5baSBill Taylor void
tavor_intr_outmbox_list_fini(tavor_state_t * state)4559e39c5baSBill Taylor tavor_intr_outmbox_list_fini(tavor_state_t *state)
4569e39c5baSBill Taylor {
4579e39c5baSBill Taylor 	/* Free up the interrupt "Out" mailbox list */
4589e39c5baSBill Taylor 	tavor_impl_mboxlist_fini(state, &state->ts_out_intr_mblist);
4599e39c5baSBill Taylor }
4609e39c5baSBill Taylor 
4619e39c5baSBill Taylor 
4629e39c5baSBill Taylor /*
4639e39c5baSBill Taylor  * tavor_impl_mbox_alloc()
4649e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
4659e39c5baSBill Taylor  */
4669e39c5baSBill Taylor static int
tavor_impl_mbox_alloc(tavor_state_t * state,tavor_mboxlist_t * mblist,tavor_mbox_t ** mb,uint_t mbox_wait)4679e39c5baSBill Taylor tavor_impl_mbox_alloc(tavor_state_t *state, tavor_mboxlist_t *mblist,
4689e39c5baSBill Taylor     tavor_mbox_t **mb, uint_t mbox_wait)
4699e39c5baSBill Taylor {
4709e39c5baSBill Taylor 	tavor_mbox_t	*mbox_ptr;
4719e39c5baSBill Taylor 	uint_t		index, next, prev;
4729e39c5baSBill Taylor 	uint_t		count, countmax;
4739e39c5baSBill Taylor 
4749e39c5baSBill Taylor 	/*
4759e39c5baSBill Taylor 	 * If the mailbox list is empty, then wait (if appropriate in the
4769e39c5baSBill Taylor 	 * current context).  Otherwise, grab the next available mailbox.
4779e39c5baSBill Taylor 	 */
4789e39c5baSBill Taylor 	if (mbox_wait == TAVOR_NOSLEEP) {
4799e39c5baSBill Taylor 		count	 = 0;
4809e39c5baSBill Taylor 		countmax = state->ts_cfg_profile->cp_cmd_poll_max;
4819e39c5baSBill Taylor 
4829e39c5baSBill Taylor 		mutex_enter(&mblist->mbl_lock);
4839e39c5baSBill Taylor 		mblist->mbl_pollers++;
4849e39c5baSBill Taylor 		while (mblist->mbl_entries_free == 0) {
4859e39c5baSBill Taylor 			mutex_exit(&mblist->mbl_lock);
4869e39c5baSBill Taylor 			/* Delay loop polling for an available mbox */
4879e39c5baSBill Taylor 			if (++count > countmax) {
4889e39c5baSBill Taylor 				return (TAVOR_CMD_INSUFF_RSRC);
4899e39c5baSBill Taylor 			}
4909e39c5baSBill Taylor 
4919e39c5baSBill Taylor 			/* Delay before polling for mailbox again */
4929e39c5baSBill Taylor 			drv_usecwait(state->ts_cfg_profile->cp_cmd_poll_delay);
4939e39c5baSBill Taylor 			mutex_enter(&mblist->mbl_lock);
4949e39c5baSBill Taylor 		}
4959e39c5baSBill Taylor 		mblist->mbl_pollers--;
4969e39c5baSBill Taylor 
4979e39c5baSBill Taylor 	/* TAVOR_SLEEP */
4989e39c5baSBill Taylor 	} else {
4999e39c5baSBill Taylor 		/*
5009e39c5baSBill Taylor 		 * Grab lock here as we prepare to cv_wait if needed.
5019e39c5baSBill Taylor 		 */
5029e39c5baSBill Taylor 		mutex_enter(&mblist->mbl_lock);
5039e39c5baSBill Taylor 		while (mblist->mbl_entries_free == 0) {
5049e39c5baSBill Taylor 			/*
5059e39c5baSBill Taylor 			 * Wait (on cv) for a mailbox to become free.  Note:
5069e39c5baSBill Taylor 			 * Just as we do above in tavor_cmd_post(), we also
5079e39c5baSBill Taylor 			 * have the "__lock_lint" here to workaround warlock.
5089e39c5baSBill Taylor 			 * Warlock doesn't know that other parts of the Tavor
5099e39c5baSBill Taylor 			 * may occasionally call this routine while holding
5109e39c5baSBill Taylor 			 * their own locks, so it complains about this cv_wait.
5119e39c5baSBill Taylor 			 * In reality, however, the rest of the driver never
5129e39c5baSBill Taylor 			 * calls this routine with a lock held unless they pass
5139e39c5baSBill Taylor 			 * TAVOR_CMD_NOSLEEP.
5149e39c5baSBill Taylor 			 */
5159e39c5baSBill Taylor 			mblist->mbl_waiters++;
5169e39c5baSBill Taylor #ifndef	__lock_lint
5179e39c5baSBill Taylor 			cv_wait(&mblist->mbl_cv, &mblist->mbl_lock);
5189e39c5baSBill Taylor #endif
5199e39c5baSBill Taylor 		}
5209e39c5baSBill Taylor 	}
5219e39c5baSBill Taylor 
5229e39c5baSBill Taylor 	/* Grab the next available mailbox from list */
5239e39c5baSBill Taylor 	mbox_ptr = mblist->mbl_mbox;
5249e39c5baSBill Taylor 	index	 = mblist->mbl_head_indx;
5259e39c5baSBill Taylor 	next	 = mbox_ptr[index].mb_next;
5269e39c5baSBill Taylor 	prev	 = mbox_ptr[index].mb_prev;
5279e39c5baSBill Taylor 
5289e39c5baSBill Taylor 	/* Remove it from the mailbox list */
5299e39c5baSBill Taylor 	mblist->mbl_mbox[next].mb_prev	= prev;
5309e39c5baSBill Taylor 	mblist->mbl_mbox[prev].mb_next	= next;
5319e39c5baSBill Taylor 	mblist->mbl_head_indx		= next;
5329e39c5baSBill Taylor 
5339e39c5baSBill Taylor 	/* Update the "free" count and return the mailbox pointer */
5349e39c5baSBill Taylor 	mblist->mbl_entries_free--;
5359e39c5baSBill Taylor 	*mb = &mbox_ptr[index];
5369e39c5baSBill Taylor 
5379e39c5baSBill Taylor 	mutex_exit(&mblist->mbl_lock);
5389e39c5baSBill Taylor 
5399e39c5baSBill Taylor 	return (TAVOR_CMD_SUCCESS);
5409e39c5baSBill Taylor }
5419e39c5baSBill Taylor 
5429e39c5baSBill Taylor 
5439e39c5baSBill Taylor /*
5449e39c5baSBill Taylor  * tavor_impl_mbox_free()
5459e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
5469e39c5baSBill Taylor  */
5479e39c5baSBill Taylor static void
tavor_impl_mbox_free(tavor_mboxlist_t * mblist,tavor_mbox_t ** mb)5489e39c5baSBill Taylor tavor_impl_mbox_free(tavor_mboxlist_t *mblist, tavor_mbox_t **mb)
5499e39c5baSBill Taylor {
5509e39c5baSBill Taylor 	uint_t		mbox_indx;
5519e39c5baSBill Taylor 
5529e39c5baSBill Taylor 	mutex_enter(&mblist->mbl_lock);
5539e39c5baSBill Taylor 
5549e39c5baSBill Taylor 	/* Pull the "index" from mailbox entry */
5559e39c5baSBill Taylor 	mbox_indx = (*mb)->mb_indx;
5569e39c5baSBill Taylor 
5579e39c5baSBill Taylor 	/*
5589e39c5baSBill Taylor 	 * If mailbox list is not empty, then insert the entry.  Otherwise,
5599e39c5baSBill Taylor 	 * this is the only entry.  So update the pointers appropriately.
5609e39c5baSBill Taylor 	 */
5619e39c5baSBill Taylor 	if (mblist->mbl_entries_free++ != 0) {
5629e39c5baSBill Taylor 		/* Update the current mailbox */
5639e39c5baSBill Taylor 		(*mb)->mb_next = mblist->mbl_head_indx;
5649e39c5baSBill Taylor 		(*mb)->mb_prev = mblist->mbl_tail_indx;
5659e39c5baSBill Taylor 
5669e39c5baSBill Taylor 		/* Update head and tail mailboxes */
5679e39c5baSBill Taylor 		mblist->mbl_mbox[mblist->mbl_head_indx].mb_prev = mbox_indx;
5689e39c5baSBill Taylor 		mblist->mbl_mbox[mblist->mbl_tail_indx].mb_next = mbox_indx;
5699e39c5baSBill Taylor 
5709e39c5baSBill Taylor 		/* Update tail index */
5719e39c5baSBill Taylor 		mblist->mbl_tail_indx = mbox_indx;
5729e39c5baSBill Taylor 
5739e39c5baSBill Taylor 	} else {
5749e39c5baSBill Taylor 		/* Update the current mailbox */
5759e39c5baSBill Taylor 		(*mb)->mb_next = mbox_indx;
5769e39c5baSBill Taylor 		(*mb)->mb_prev = mbox_indx;
5779e39c5baSBill Taylor 
5789e39c5baSBill Taylor 		/* Update head and tail indexes */
5799e39c5baSBill Taylor 		mblist->mbl_tail_indx = mbox_indx;
5809e39c5baSBill Taylor 		mblist->mbl_head_indx = mbox_indx;
5819e39c5baSBill Taylor 	}
5829e39c5baSBill Taylor 
5839e39c5baSBill Taylor 	/*
5849e39c5baSBill Taylor 	 * Because we can have both waiters (SLEEP treads waiting for a
5859e39c5baSBill Taylor 	 * cv_signal to continue processing) and pollers (NOSLEEP treads
5869e39c5baSBill Taylor 	 * polling for a mailbox to become available), we try to share CPU time
5879e39c5baSBill Taylor 	 * between them.  We do this by signalling the waiters only every other
5889e39c5baSBill Taylor 	 * call to mbox_free.  This gives the pollers a chance to get some CPU
5899e39c5baSBill Taylor 	 * time to do their command.  If we signalled every time, the pollers
5909e39c5baSBill Taylor 	 * would have a much harder time getting CPU time.
5919e39c5baSBill Taylor 	 *
5929e39c5baSBill Taylor 	 * If there are waiters and no pollers, then we signal always.
5939e39c5baSBill Taylor 	 *
5949e39c5baSBill Taylor 	 * Otherwise, if there are either no waiters, there may in fact be
5959e39c5baSBill Taylor 	 * pollers, so we do not signal in that case.
5969e39c5baSBill Taylor 	 */
5979e39c5baSBill Taylor 	if (mblist->mbl_pollers > 0 && mblist->mbl_waiters > 0) {
5989e39c5baSBill Taylor 		/* flip the signal value */
599*2bc98732SRichard Lowe 		mblist->mbl_signal = (mblist->mbl_signal + 1) % 2;
6009e39c5baSBill Taylor 	} else if (mblist->mbl_waiters > 0) {
6019e39c5baSBill Taylor 		mblist->mbl_signal = 1;
6029e39c5baSBill Taylor 	} else {
6039e39c5baSBill Taylor 		mblist->mbl_signal = 0;
6049e39c5baSBill Taylor 	}
6059e39c5baSBill Taylor 
6069e39c5baSBill Taylor 	/*
6079e39c5baSBill Taylor 	 * Depending on the conditions in the previous check, we signal only if
6089e39c5baSBill Taylor 	 * we are supposed to.
6099e39c5baSBill Taylor 	 */
6109e39c5baSBill Taylor 	if (mblist->mbl_signal) {
6119e39c5baSBill Taylor 		mblist->mbl_waiters--;
6129e39c5baSBill Taylor 		cv_signal(&mblist->mbl_cv);
6139e39c5baSBill Taylor 	}
6149e39c5baSBill Taylor 
6159e39c5baSBill Taylor 	/* Clear out the mailbox entry pointer */
6169e39c5baSBill Taylor 	*mb = NULL;
6179e39c5baSBill Taylor 
6189e39c5baSBill Taylor 	mutex_exit(&mblist->mbl_lock);
6199e39c5baSBill Taylor }
6209e39c5baSBill Taylor 
6219e39c5baSBill Taylor 
6229e39c5baSBill Taylor /*
6239e39c5baSBill Taylor  * tavor_impl_mboxlist_init()
6249e39c5baSBill Taylor  *    Context: Only called from attach() path context
6259e39c5baSBill Taylor  */
6269e39c5baSBill Taylor static int
tavor_impl_mboxlist_init(tavor_state_t * state,tavor_mboxlist_t * mblist,uint_t num_mbox,tavor_rsrc_type_t type)6279e39c5baSBill Taylor tavor_impl_mboxlist_init(tavor_state_t *state, tavor_mboxlist_t *mblist,
6289e39c5baSBill Taylor     uint_t num_mbox, tavor_rsrc_type_t type)
6299e39c5baSBill Taylor {
6309e39c5baSBill Taylor 	tavor_rsrc_t		*rsrc;
6319e39c5baSBill Taylor 	ddi_dma_cookie_t	dma_cookie;
6329e39c5baSBill Taylor 	uint_t			dma_cookiecnt, flag, sync;
6339e39c5baSBill Taylor 	int			status, i;
6349e39c5baSBill Taylor 
6359e39c5baSBill Taylor 	/* Allocate the memory for the mailbox entries list */
6369e39c5baSBill Taylor 	mblist->mbl_list_sz = num_mbox;
6379e39c5baSBill Taylor 	mblist->mbl_mbox = kmem_zalloc(mblist->mbl_list_sz *
6389e39c5baSBill Taylor 	    sizeof (tavor_mbox_t), KM_SLEEP);
6399e39c5baSBill Taylor 
6409e39c5baSBill Taylor 	/* Initialize the mailbox entries list */
6419e39c5baSBill Taylor 	mblist->mbl_head_indx	 = 0;
6429e39c5baSBill Taylor 	mblist->mbl_tail_indx	 = mblist->mbl_list_sz - 1;
6439e39c5baSBill Taylor 	mblist->mbl_entries_free = mblist->mbl_list_sz;
6449e39c5baSBill Taylor 	mblist->mbl_waiters	 = 0;
6459e39c5baSBill Taylor 	mblist->mbl_num_alloc	 = 0;
6469e39c5baSBill Taylor 
6479e39c5baSBill Taylor 	/* Set up the mailbox list's cv and mutex */
6489e39c5baSBill Taylor 	mutex_init(&mblist->mbl_lock, NULL, MUTEX_DRIVER,
6499e39c5baSBill Taylor 	    DDI_INTR_PRI(state->ts_intrmsi_pri));
6509e39c5baSBill Taylor 	cv_init(&mblist->mbl_cv, NULL, CV_DRIVER, NULL);
6519e39c5baSBill Taylor 
6529e39c5baSBill Taylor 	/* Determine if syncs will be necessary */
6539e39c5baSBill Taylor 	sync = TAVOR_MBOX_IS_SYNC_REQ(state, type);
6549e39c5baSBill Taylor 
6559e39c5baSBill Taylor 	/* Determine whether to map DDI_DMA_STREAMING or DDI_DMA_CONSISTENT */
6569e39c5baSBill Taylor 	flag = state->ts_cfg_profile->cp_streaming_consistent;
6579e39c5baSBill Taylor 
6589e39c5baSBill Taylor 	/* Initialize the mailbox list entries */
6599e39c5baSBill Taylor 	for (i = 0; i < mblist->mbl_list_sz; i++) {
6609e39c5baSBill Taylor 		/* Allocate resources for the mailbox */
6619e39c5baSBill Taylor 		status = tavor_rsrc_alloc(state, type, 1, TAVOR_SLEEP,
6629e39c5baSBill Taylor 		    &rsrc);
6639e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
6649e39c5baSBill Taylor 			/* Jump to cleanup and return error */
6659e39c5baSBill Taylor 			goto mboxlist_init_fail;
6669e39c5baSBill Taylor 		}
6679e39c5baSBill Taylor 
6689e39c5baSBill Taylor 		/* Save away the mailbox resource info */
6699e39c5baSBill Taylor 		mblist->mbl_mbox[i].mb_rsrcptr	= rsrc;
6709e39c5baSBill Taylor 		mblist->mbl_mbox[i].mb_addr	= rsrc->tr_addr;
6719e39c5baSBill Taylor 		mblist->mbl_mbox[i].mb_acchdl	= rsrc->tr_acchdl;
6729e39c5baSBill Taylor 
6739e39c5baSBill Taylor 		/*
6749e39c5baSBill Taylor 		 * Get a PCI mapped address for each mailbox.  Note: this
6759e39c5baSBill Taylor 		 * uses the ddi_dma_handle return from the resource
6769e39c5baSBill Taylor 		 * allocation routine
6779e39c5baSBill Taylor 		 */
6789e39c5baSBill Taylor 		status = ddi_dma_addr_bind_handle(rsrc->tr_dmahdl, NULL,
6799e39c5baSBill Taylor 		    rsrc->tr_addr, rsrc->tr_len, (DDI_DMA_RDWR | flag),
6809e39c5baSBill Taylor 		    DDI_DMA_SLEEP, NULL, &dma_cookie, &dma_cookiecnt);
6819e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
6829e39c5baSBill Taylor 			/* Jump to cleanup and return error */
6839e39c5baSBill Taylor 			tavor_rsrc_free(state, &rsrc);
6849e39c5baSBill Taylor 			goto mboxlist_init_fail;
6859e39c5baSBill Taylor 		}
6869e39c5baSBill Taylor 
6879e39c5baSBill Taylor 		/* Save away the mapped address for the mailbox */
6889e39c5baSBill Taylor 		mblist->mbl_mbox[i].mb_mapaddr	= dma_cookie.dmac_laddress;
6899e39c5baSBill Taylor 
6909e39c5baSBill Taylor 		/* Set sync flag appropriately */
6919e39c5baSBill Taylor 		mblist->mbl_mbox[i].mb_sync	= sync;
6929e39c5baSBill Taylor 
6939e39c5baSBill Taylor 		/* Make each entry point to the "next" and "prev" entries */
6949e39c5baSBill Taylor 		mblist->mbl_mbox[i].mb_next	= i+1;
6959e39c5baSBill Taylor 		mblist->mbl_mbox[i].mb_prev	= i-1;
6969e39c5baSBill Taylor 		mblist->mbl_mbox[i].mb_indx	= i;
6979e39c5baSBill Taylor 		mblist->mbl_num_alloc		= i + 1;
6989e39c5baSBill Taylor 	}
6999e39c5baSBill Taylor 
7009e39c5baSBill Taylor 	/* Make the "head" and "tail" entries point to each other */
7019e39c5baSBill Taylor 	mblist->mbl_mbox[mblist->mbl_head_indx].mb_prev =
7029e39c5baSBill Taylor 	    mblist->mbl_tail_indx;
7039e39c5baSBill Taylor 	mblist->mbl_mbox[mblist->mbl_tail_indx].mb_next =
7049e39c5baSBill Taylor 	    mblist->mbl_head_indx;
7059e39c5baSBill Taylor 
7069e39c5baSBill Taylor 	return (DDI_SUCCESS);
7079e39c5baSBill Taylor 
7089e39c5baSBill Taylor mboxlist_init_fail:
7099e39c5baSBill Taylor 	tavor_impl_mboxlist_fini(state, mblist);
7109e39c5baSBill Taylor 
7119e39c5baSBill Taylor 	return (DDI_FAILURE);
7129e39c5baSBill Taylor }
7139e39c5baSBill Taylor 
7149e39c5baSBill Taylor 
7159e39c5baSBill Taylor /*
7169e39c5baSBill Taylor  * tavor_impl_mboxlist_fini()
7179e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
7189e39c5baSBill Taylor  */
7199e39c5baSBill Taylor static void
tavor_impl_mboxlist_fini(tavor_state_t * state,tavor_mboxlist_t * mblist)7209e39c5baSBill Taylor tavor_impl_mboxlist_fini(tavor_state_t *state, tavor_mboxlist_t *mblist)
7219e39c5baSBill Taylor {
7229e39c5baSBill Taylor 	tavor_rsrc_t	*rsrc;
7239e39c5baSBill Taylor 	int		i, status;
7249e39c5baSBill Taylor 
7259e39c5baSBill Taylor 	/* Release the resources for each of the mailbox list entries */
7269e39c5baSBill Taylor 	for (i = 0; i < mblist->mbl_num_alloc; i++) {
7279e39c5baSBill Taylor 		rsrc = mblist->mbl_mbox[i].mb_rsrcptr;
7289e39c5baSBill Taylor 
7299e39c5baSBill Taylor 		/*
7309e39c5baSBill Taylor 		 * First, unbind the DMA memory for the mailbox
7319e39c5baSBill Taylor 		 *
7329e39c5baSBill Taylor 		 * Note: The only way ddi_dma_unbind_handle() currently
7339e39c5baSBill Taylor 		 * can return an error is if the handle passed in is invalid.
7349e39c5baSBill Taylor 		 * Since this should never happen, we choose to return void
7359e39c5baSBill Taylor 		 * from this function!  If this does return an error,
7369e39c5baSBill Taylor 		 * however, then we print a warning message to the console.
7379e39c5baSBill Taylor 		 */
7389e39c5baSBill Taylor 		status = ddi_dma_unbind_handle(rsrc->tr_dmahdl);
7399e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
7409e39c5baSBill Taylor 			TAVOR_WARNING(state, "failed to unbind DMA mapping");
7419e39c5baSBill Taylor 			return;
7429e39c5baSBill Taylor 		}
7439e39c5baSBill Taylor 
7449e39c5baSBill Taylor 		/* Next, free the mailbox resource */
7459e39c5baSBill Taylor 		tavor_rsrc_free(state, &rsrc);
7469e39c5baSBill Taylor 	}
7479e39c5baSBill Taylor 
7489e39c5baSBill Taylor 	/* Destroy the mailbox list mutex and cv */
7499e39c5baSBill Taylor 	mutex_destroy(&mblist->mbl_lock);
7509e39c5baSBill Taylor 	cv_destroy(&mblist->mbl_cv);
7519e39c5baSBill Taylor 
7529e39c5baSBill Taylor 	/* Free up the memory for tracking the mailbox list */
7539e39c5baSBill Taylor 	kmem_free(mblist->mbl_mbox, mblist->mbl_list_sz *
7549e39c5baSBill Taylor 	    sizeof (tavor_mbox_t));
7559e39c5baSBill Taylor }
7569e39c5baSBill Taylor 
7579e39c5baSBill Taylor 
7589e39c5baSBill Taylor /*
7599e39c5baSBill Taylor  * tavor_outstanding_cmd_alloc()
7609e39c5baSBill Taylor  *    Context: Can be called only from base context.
7619e39c5baSBill Taylor  */
7629e39c5baSBill Taylor static int
tavor_outstanding_cmd_alloc(tavor_state_t * state,tavor_cmd_t ** cmd_ptr,uint_t cmd_wait)7639e39c5baSBill Taylor tavor_outstanding_cmd_alloc(tavor_state_t *state, tavor_cmd_t **cmd_ptr,
7649e39c5baSBill Taylor     uint_t cmd_wait)
7659e39c5baSBill Taylor {
7669e39c5baSBill Taylor 	tavor_cmdlist_t	*cmd_list;
7679e39c5baSBill Taylor 	uint_t		next, prev, head;
7689e39c5baSBill Taylor 
7699e39c5baSBill Taylor 	cmd_list = &state->ts_cmd_list;
7709e39c5baSBill Taylor 	mutex_enter(&cmd_list->cml_lock);
7719e39c5baSBill Taylor 
7729e39c5baSBill Taylor 	/* Ensure that outstanding commands are supported */
7739e39c5baSBill Taylor 	ASSERT(cmd_list->cml_num_alloc != 0);
7749e39c5baSBill Taylor 
7759e39c5baSBill Taylor 	/*
7769e39c5baSBill Taylor 	 * If the outstanding command list is empty, then wait (if
7779e39c5baSBill Taylor 	 * appropriate in the current context).  Otherwise, grab the
7789e39c5baSBill Taylor 	 * next available command.
7799e39c5baSBill Taylor 	 */
7809e39c5baSBill Taylor 	while (cmd_list->cml_entries_free == 0) {
7819e39c5baSBill Taylor 		/* No free commands */
7829e39c5baSBill Taylor 		if (cmd_wait == TAVOR_NOSLEEP) {
7839e39c5baSBill Taylor 			mutex_exit(&cmd_list->cml_lock);
7849e39c5baSBill Taylor 			return (TAVOR_CMD_INSUFF_RSRC);
7859e39c5baSBill Taylor 		}
7869e39c5baSBill Taylor 
7879e39c5baSBill Taylor 		/*
7889e39c5baSBill Taylor 		 * Wait (on cv) for a command to become free.  Note: Just
7899e39c5baSBill Taylor 		 * as we do above in tavor_cmd_post(), we also have the
7909e39c5baSBill Taylor 		 * "__lock_lint" here to workaround warlock.  Warlock doesn't
7919e39c5baSBill Taylor 		 * know that other parts of the Tavor may occasionally call
7929e39c5baSBill Taylor 		 * this routine while holding their own locks, so it complains
7939e39c5baSBill Taylor 		 * about this cv_wait.  In reality, however, the rest of the
7949e39c5baSBill Taylor 		 * driver never calls this routine with a lock held unless
7959e39c5baSBill Taylor 		 * they pass TAVOR_CMD_NOSLEEP.
7969e39c5baSBill Taylor 		 */
7979e39c5baSBill Taylor 		cmd_list->cml_waiters++;
7989e39c5baSBill Taylor #ifndef	__lock_lint
7999e39c5baSBill Taylor 		cv_wait(&cmd_list->cml_cv, &cmd_list->cml_lock);
8009e39c5baSBill Taylor #endif
8019e39c5baSBill Taylor 	}
8029e39c5baSBill Taylor 
8039e39c5baSBill Taylor 	/* Grab the next available command from the list */
8049e39c5baSBill Taylor 	head = cmd_list->cml_head_indx;
8059e39c5baSBill Taylor 	*cmd_ptr = &cmd_list->cml_cmd[head];
8069e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(**cmd_ptr))
8079e39c5baSBill Taylor 	next = (*cmd_ptr)->cmd_next;
8089e39c5baSBill Taylor 	prev = (*cmd_ptr)->cmd_prev;
8099e39c5baSBill Taylor 	(*cmd_ptr)->cmd_status = TAVOR_CMD_INVALID_STATUS;
8109e39c5baSBill Taylor 
8119e39c5baSBill Taylor 	/* Remove it from the command list */
8129e39c5baSBill Taylor 	cmd_list->cml_cmd[next].cmd_prev = prev;
8139e39c5baSBill Taylor 	cmd_list->cml_cmd[prev].cmd_next = next;
8149e39c5baSBill Taylor 	cmd_list->cml_head_indx		 = next;
8159e39c5baSBill Taylor 
8169e39c5baSBill Taylor 	/* Update the "free" count and return */
8179e39c5baSBill Taylor 	cmd_list->cml_entries_free--;
8189e39c5baSBill Taylor 
8199e39c5baSBill Taylor 	mutex_exit(&cmd_list->cml_lock);
8209e39c5baSBill Taylor 
8219e39c5baSBill Taylor 	return (TAVOR_CMD_SUCCESS);
8229e39c5baSBill Taylor }
8239e39c5baSBill Taylor 
8249e39c5baSBill Taylor 
8259e39c5baSBill Taylor /*
8269e39c5baSBill Taylor  * tavor_outstanding_cmd_free()
8279e39c5baSBill Taylor  *    Context: Can be called only from base context.
8289e39c5baSBill Taylor  */
8299e39c5baSBill Taylor static void
tavor_outstanding_cmd_free(tavor_state_t * state,tavor_cmd_t ** cmd_ptr)8309e39c5baSBill Taylor tavor_outstanding_cmd_free(tavor_state_t *state, tavor_cmd_t **cmd_ptr)
8319e39c5baSBill Taylor {
8329e39c5baSBill Taylor 	tavor_cmdlist_t	*cmd_list;
8339e39c5baSBill Taylor 	uint_t		cmd_indx;
8349e39c5baSBill Taylor 
8359e39c5baSBill Taylor 	cmd_list = &state->ts_cmd_list;
8369e39c5baSBill Taylor 	mutex_enter(&cmd_list->cml_lock);
8379e39c5baSBill Taylor 
8389e39c5baSBill Taylor 	/* Pull the "index" from command entry */
8399e39c5baSBill Taylor 	cmd_indx = (*cmd_ptr)->cmd_indx;
8409e39c5baSBill Taylor 
8419e39c5baSBill Taylor 	/*
8429e39c5baSBill Taylor 	 * If outstanding command list is not empty, then insert the entry.
8439e39c5baSBill Taylor 	 * Otherwise, this is the only entry.  So update the pointers
8449e39c5baSBill Taylor 	 * appropriately.
8459e39c5baSBill Taylor 	 */
8469e39c5baSBill Taylor 	if (cmd_list->cml_entries_free++ != 0) {
8479e39c5baSBill Taylor 		/* Update the current command */
8489e39c5baSBill Taylor 		(*cmd_ptr)->cmd_next = cmd_list->cml_head_indx;
8499e39c5baSBill Taylor 		(*cmd_ptr)->cmd_prev = cmd_list->cml_tail_indx;
8509e39c5baSBill Taylor 
8519e39c5baSBill Taylor 		/* Update head and tail commands */
8529e39c5baSBill Taylor 		cmd_list->cml_cmd[cmd_list->cml_head_indx].cmd_prev = cmd_indx;
8539e39c5baSBill Taylor 		cmd_list->cml_cmd[cmd_list->cml_tail_indx].cmd_next = cmd_indx;
8549e39c5baSBill Taylor 
8559e39c5baSBill Taylor 		/* Update tail index */
8569e39c5baSBill Taylor 		cmd_list->cml_tail_indx = cmd_indx;
8579e39c5baSBill Taylor 
8589e39c5baSBill Taylor 	} else {
8599e39c5baSBill Taylor 		/* Update the current command */
8609e39c5baSBill Taylor 		(*cmd_ptr)->cmd_next = cmd_indx;
8619e39c5baSBill Taylor 		(*cmd_ptr)->cmd_prev = cmd_indx;
8629e39c5baSBill Taylor 
8639e39c5baSBill Taylor 		/* Update head and tail indexes */
8649e39c5baSBill Taylor 		cmd_list->cml_head_indx = cmd_indx;
8659e39c5baSBill Taylor 		cmd_list->cml_tail_indx = cmd_indx;
8669e39c5baSBill Taylor 	}
8679e39c5baSBill Taylor 
8689e39c5baSBill Taylor 	/* If there are threads waiting, signal one of them */
8699e39c5baSBill Taylor 	if (cmd_list->cml_waiters > 0) {
8709e39c5baSBill Taylor 		cmd_list->cml_waiters--;
8719e39c5baSBill Taylor 		cv_signal(&cmd_list->cml_cv);
8729e39c5baSBill Taylor 	}
8739e39c5baSBill Taylor 
8749e39c5baSBill Taylor 	/* Clear out the command entry pointer */
8759e39c5baSBill Taylor 	*cmd_ptr = NULL;
8769e39c5baSBill Taylor 
8779e39c5baSBill Taylor 	mutex_exit(&cmd_list->cml_lock);
8789e39c5baSBill Taylor }
8799e39c5baSBill Taylor 
8809e39c5baSBill Taylor 
8819e39c5baSBill Taylor /*
8829e39c5baSBill Taylor  * tavor_write_hcr()
8839e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
8849e39c5baSBill Taylor  */
8859e39c5baSBill Taylor static int
tavor_write_hcr(tavor_state_t * state,tavor_cmd_post_t * cmdpost,uint16_t token)8869e39c5baSBill Taylor tavor_write_hcr(tavor_state_t *state, tavor_cmd_post_t *cmdpost,
8879e39c5baSBill Taylor     uint16_t token)
8889e39c5baSBill Taylor {
8899e39c5baSBill Taylor 	tavor_hw_hcr_t	*hcr;
8909e39c5baSBill Taylor 	uint_t		status, count, countmax;
8919e39c5baSBill Taylor 	uint64_t	hcrreg;
8929e39c5baSBill Taylor 
8939e39c5baSBill Taylor 	/*
8949e39c5baSBill Taylor 	 * Grab the "HCR access" lock if the driver is not in
8959e39c5baSBill Taylor 	 * fastreboot. In fastreboot, this function is called
8969e39c5baSBill Taylor 	 * with the single thread but in high interrupt context
8979e39c5baSBill Taylor 	 * (so that this mutex lock cannot be used).
8989e39c5baSBill Taylor 	 */
8999e39c5baSBill Taylor #ifdef __lock_lint
9009e39c5baSBill Taylor 	mutex_enter(&state->ts_cmd_regs.hcr_lock);
9019e39c5baSBill Taylor #else
9029e39c5baSBill Taylor 	if (!TAVOR_IN_FASTREBOOT(state)) {
9039e39c5baSBill Taylor 		mutex_enter(&state->ts_cmd_regs.hcr_lock);
9049e39c5baSBill Taylor 	}
9059e39c5baSBill Taylor #endif
9069e39c5baSBill Taylor 
9079e39c5baSBill Taylor 	hcr = state->ts_cmd_regs.hcr;
9089e39c5baSBill Taylor 
9099e39c5baSBill Taylor 	/*
9109e39c5baSBill Taylor 	 * First, check the "go" bit to see if the previous hcr usage is
9119e39c5baSBill Taylor 	 * complete.  As long as it is set then we must continue to poll.
9129e39c5baSBill Taylor 	 */
9139e39c5baSBill Taylor 	count	 = 0;
9149e39c5baSBill Taylor 	countmax = state->ts_cfg_profile->cp_cmd_poll_max;
9159e39c5baSBill Taylor 	for (;;) {
9169e39c5baSBill Taylor 		hcrreg = ddi_get32(state->ts_reg_cmdhdl, &hcr->cmd);
9179e39c5baSBill Taylor 
9189e39c5baSBill Taylor 		/* If "go" bit is clear, then done */
9199e39c5baSBill Taylor 		if ((hcrreg & TAVOR_HCR_CMD_GO_MASK) == 0) {
9209e39c5baSBill Taylor 			break;
9219e39c5baSBill Taylor 		}
9229e39c5baSBill Taylor 		/* Delay before polling the "go" bit again */
9239e39c5baSBill Taylor 		drv_usecwait(state->ts_cfg_profile->cp_cmd_poll_delay);
9249e39c5baSBill Taylor 
9259e39c5baSBill Taylor 		/*
9269e39c5baSBill Taylor 		 * If we poll more than the maximum number of times, then
9279e39c5baSBill Taylor 		 * return a "timeout" error.
9289e39c5baSBill Taylor 		 */
9299e39c5baSBill Taylor 		if (++count > countmax) {
9309e39c5baSBill Taylor #ifdef __lock_lint
9319e39c5baSBill Taylor 			mutex_exit(&state->ts_cmd_regs.hcr_lock);
9329e39c5baSBill Taylor #else
9339e39c5baSBill Taylor 			if (!TAVOR_IN_FASTREBOOT(state)) {
9349e39c5baSBill Taylor 				mutex_exit(&state->ts_cmd_regs.hcr_lock);
9359e39c5baSBill Taylor 			}
9369e39c5baSBill Taylor #endif
9379e39c5baSBill Taylor 			return (TAVOR_CMD_TIMEOUT);
9389e39c5baSBill Taylor 		}
9399e39c5baSBill Taylor 	}
9409e39c5baSBill Taylor 
9419e39c5baSBill Taylor 	/* Write "inparam" as a 64-bit quantity */
9429e39c5baSBill Taylor 	ddi_put64(state->ts_reg_cmdhdl, (uint64_t *)&hcr->in_param0,
9439e39c5baSBill Taylor 	    cmdpost->cp_inparm);
9449e39c5baSBill Taylor 
9459e39c5baSBill Taylor 	/* Write "inmod" and 32-bits of "outparam" as 64-bit */
9469e39c5baSBill Taylor 	hcrreg = ((uint64_t)cmdpost->cp_inmod << 32);
9479e39c5baSBill Taylor 	hcrreg = hcrreg | (cmdpost->cp_outparm >> 32);
9489e39c5baSBill Taylor 	ddi_put64(state->ts_reg_cmdhdl, (uint64_t *)&hcr->input_modifier,
9499e39c5baSBill Taylor 	    hcrreg);
9509e39c5baSBill Taylor 
9519e39c5baSBill Taylor 	/* Write the other 32-bits of "outparam" and "token" as 64-bit */
9529e39c5baSBill Taylor 	hcrreg = (cmdpost->cp_outparm << 32);
9539e39c5baSBill Taylor 	hcrreg = hcrreg | ((uint32_t)token << TAVOR_HCR_TOKEN_SHIFT);
9549e39c5baSBill Taylor 	ddi_put64(state->ts_reg_cmdhdl, (uint64_t *)&hcr->out_param1,
9559e39c5baSBill Taylor 	    hcrreg);
9569e39c5baSBill Taylor 
9579e39c5baSBill Taylor 	/* Then setup the final hcrreg to hit doorbell (i.e. "go" bit) */
9589e39c5baSBill Taylor 	hcrreg = TAVOR_HCR_CMD_GO_MASK;
9599e39c5baSBill Taylor 	if (cmdpost->cp_flags == TAVOR_CMD_SLEEP_NOSPIN)
9609e39c5baSBill Taylor 		hcrreg = hcrreg | TAVOR_HCR_CMD_E_MASK;
9619e39c5baSBill Taylor 	hcrreg = hcrreg | (cmdpost->cp_opmod << TAVOR_HCR_CMD_OPMOD_SHFT);
9629e39c5baSBill Taylor 	hcrreg = hcrreg | (cmdpost->cp_opcode);
9639e39c5baSBill Taylor 
9649e39c5baSBill Taylor 	/* Write the doorbell to the HCR */
9659e39c5baSBill Taylor 	ddi_put32(state->ts_reg_cmdhdl, &hcr->cmd, hcrreg);
9669e39c5baSBill Taylor 
9679e39c5baSBill Taylor 	/*
9689e39c5baSBill Taylor 	 * In the SPIN case we read the HCR and check the "go" bit.  For the
9699e39c5baSBill Taylor 	 * NOSPIN case we do not have to poll, we simply release the HCR lock
9709e39c5baSBill Taylor 	 * and return.
9719e39c5baSBill Taylor 	 */
9729e39c5baSBill Taylor 	if (cmdpost->cp_flags == TAVOR_CMD_NOSLEEP_SPIN) {
9739e39c5baSBill Taylor 		count	 = 0;
9749e39c5baSBill Taylor 		countmax = state->ts_cfg_profile->cp_cmd_poll_max;
9759e39c5baSBill Taylor 
9769e39c5baSBill Taylor 		for (;;) {
9779e39c5baSBill Taylor 			hcrreg = ddi_get32(state->ts_reg_cmdhdl, &hcr->cmd);
9789e39c5baSBill Taylor 
9799e39c5baSBill Taylor 			/* If "go" bit is clear, then done */
9809e39c5baSBill Taylor 			if ((hcrreg & TAVOR_HCR_CMD_GO_MASK) == 0) {
9819e39c5baSBill Taylor 				break;
9829e39c5baSBill Taylor 			}
9839e39c5baSBill Taylor 			/* Delay before polling the "go" bit again */
9849e39c5baSBill Taylor 			drv_usecwait(state->ts_cfg_profile->cp_cmd_poll_delay);
9859e39c5baSBill Taylor 
9869e39c5baSBill Taylor 			/*
9879e39c5baSBill Taylor 			 * If we poll more than the maximum number of times,
9889e39c5baSBill Taylor 			 * then return a "timeout" error.
9899e39c5baSBill Taylor 			 */
9909e39c5baSBill Taylor 			if (++count > countmax) {
9919e39c5baSBill Taylor #ifdef __lock_lint
9929e39c5baSBill Taylor 				mutex_exit(&state-> ts_cmd_regs.hcr_lock);
9939e39c5baSBill Taylor #else
9949e39c5baSBill Taylor 				if (!TAVOR_IN_FASTREBOOT(state)) {
9959e39c5baSBill Taylor 					mutex_exit(&state->
9969e39c5baSBill Taylor 					    ts_cmd_regs.hcr_lock);
9979e39c5baSBill Taylor 				}
9989e39c5baSBill Taylor #endif
9999e39c5baSBill Taylor 				return (TAVOR_CMD_TIMEOUT);
10009e39c5baSBill Taylor 			}
10019e39c5baSBill Taylor 		}
10029e39c5baSBill Taylor 
10039e39c5baSBill Taylor 		/* Pull out the "status" bits from the HCR */
10049e39c5baSBill Taylor 		status = (hcrreg >> TAVOR_HCR_CMD_STATUS_SHFT);
10059e39c5baSBill Taylor 
10069e39c5baSBill Taylor 		/*
10079e39c5baSBill Taylor 		 * Read the "outparam" value.  Note: we have to read "outparam"
10089e39c5baSBill Taylor 		 * as two separate 32-bit reads because the field in the HCR is
10099e39c5baSBill Taylor 		 * not 64-bit aligned.
10109e39c5baSBill Taylor 		 */
10119e39c5baSBill Taylor 		hcrreg = ddi_get32(state->ts_reg_cmdhdl, &hcr->out_param0);
10129e39c5baSBill Taylor 		cmdpost->cp_outparm = hcrreg << 32;
10139e39c5baSBill Taylor 		hcrreg = ddi_get32(state->ts_reg_cmdhdl, &hcr->out_param1);
10149e39c5baSBill Taylor 		cmdpost->cp_outparm |= hcrreg;
10159e39c5baSBill Taylor 
10169e39c5baSBill Taylor 	/* NOSPIN */
10179e39c5baSBill Taylor 	} else {
10189e39c5baSBill Taylor 		status = TAVOR_CMD_SUCCESS;
10199e39c5baSBill Taylor 	}
10209e39c5baSBill Taylor 
10219e39c5baSBill Taylor 	/* Drop the "HCR access" lock */
10229e39c5baSBill Taylor #ifdef __lock_lint
10239e39c5baSBill Taylor 	mutex_exit(&state->ts_cmd_regs.hcr_lock);
10249e39c5baSBill Taylor #else
10259e39c5baSBill Taylor 	if (!TAVOR_IN_FASTREBOOT(state)) {
10269e39c5baSBill Taylor 		mutex_exit(&state->ts_cmd_regs.hcr_lock);
10279e39c5baSBill Taylor 	}
10289e39c5baSBill Taylor #endif
10299e39c5baSBill Taylor 
10309e39c5baSBill Taylor 	return (status);
10319e39c5baSBill Taylor }
10329e39c5baSBill Taylor 
10339e39c5baSBill Taylor 
10349e39c5baSBill Taylor /*
10359e39c5baSBill Taylor  * tavor_outstanding_cmdlist_init()
10369e39c5baSBill Taylor  *    Context: Only called from attach() path context
10379e39c5baSBill Taylor  */
10389e39c5baSBill Taylor int
tavor_outstanding_cmdlist_init(tavor_state_t * state)10399e39c5baSBill Taylor tavor_outstanding_cmdlist_init(tavor_state_t *state)
10409e39c5baSBill Taylor {
10419e39c5baSBill Taylor 	uint_t		num_outstanding_cmds, head, tail;
10429e39c5baSBill Taylor 	int		i;
10439e39c5baSBill Taylor 
10449e39c5baSBill Taylor 	/*
10459e39c5baSBill Taylor 	 * Determine the number of the outstanding commands supported
10469e39c5baSBill Taylor 	 * by the Tavor device (obtained from the QUERY_FW command).  Note:
10479e39c5baSBill Taylor 	 * Because we handle both SLEEP and NOSLEEP cases around the tavor HCR,
10489e39c5baSBill Taylor 	 * we know that when an interrupt comes in it will be next on the
10499e39c5baSBill Taylor 	 * command register, and will at most have to wait one commands time.
10509e39c5baSBill Taylor 	 * We do not have to reserve an outstanding command here for
10519e39c5baSBill Taylor 	 * interrupts.
10529e39c5baSBill Taylor 	 */
10539e39c5baSBill Taylor 	num_outstanding_cmds = (1 << state->ts_fw.log_max_cmd);
10549e39c5baSBill Taylor 
10559e39c5baSBill Taylor 	/* Initialize the outstanding command list */
10569e39c5baSBill Taylor 	state->ts_cmd_list.cml_list_sz	 = num_outstanding_cmds;
10579e39c5baSBill Taylor 	state->ts_cmd_list.cml_head_indx = 0;
10589e39c5baSBill Taylor 	state->ts_cmd_list.cml_tail_indx = state->ts_cmd_list.cml_list_sz - 1;
10599e39c5baSBill Taylor 	state->ts_cmd_list.cml_entries_free = state->ts_cmd_list.cml_list_sz;
10609e39c5baSBill Taylor 	state->ts_cmd_list.cml_waiters	 = 0;
10619e39c5baSBill Taylor 	state->ts_cmd_list.cml_num_alloc = 0;
10629e39c5baSBill Taylor 
10639e39c5baSBill Taylor 	/* Allocate the memory for the outstanding command list */
10649e39c5baSBill Taylor 	if (num_outstanding_cmds) {
10659e39c5baSBill Taylor 		state->ts_cmd_list.cml_cmd =
10669e39c5baSBill Taylor 		    kmem_zalloc(state->ts_cmd_list.cml_list_sz *
10679e39c5baSBill Taylor 		    sizeof (tavor_cmd_t), KM_SLEEP);
10689e39c5baSBill Taylor 	}
10699e39c5baSBill Taylor 	mutex_init(&state->ts_cmd_list.cml_lock, NULL, MUTEX_DRIVER,
10709e39c5baSBill Taylor 	    DDI_INTR_PRI(state->ts_intrmsi_pri));
10719e39c5baSBill Taylor 	cv_init(&state->ts_cmd_list.cml_cv, NULL, CV_DRIVER, NULL);
10729e39c5baSBill Taylor 
10739e39c5baSBill Taylor 	/* Initialize the individual outstanding command list entries */
10749e39c5baSBill Taylor 	for (i = 0; i < state->ts_cmd_list.cml_list_sz; i++) {
10759e39c5baSBill Taylor 		mutex_init(&state->ts_cmd_list.cml_cmd[i].cmd_comp_lock,
10769e39c5baSBill Taylor 		    NULL, MUTEX_DRIVER, DDI_INTR_PRI(state->ts_intrmsi_pri));
10779e39c5baSBill Taylor 		cv_init(&state->ts_cmd_list.cml_cmd[i].cmd_comp_cv, NULL,
10789e39c5baSBill Taylor 		    CV_DRIVER, NULL);
10799e39c5baSBill Taylor 
10809e39c5baSBill Taylor 		state->ts_cmd_list.cml_cmd[i].cmd_next	= i+1;
10819e39c5baSBill Taylor 		state->ts_cmd_list.cml_cmd[i].cmd_prev	= i-1;
10829e39c5baSBill Taylor 		state->ts_cmd_list.cml_cmd[i].cmd_indx	= i;
10839e39c5baSBill Taylor 		state->ts_cmd_list.cml_num_alloc	= i + 1;
10849e39c5baSBill Taylor 	}
10859e39c5baSBill Taylor 	if (num_outstanding_cmds) {
10869e39c5baSBill Taylor 		head = state->ts_cmd_list.cml_head_indx;
10879e39c5baSBill Taylor 		tail = state->ts_cmd_list.cml_tail_indx;
10889e39c5baSBill Taylor 		state->ts_cmd_list.cml_cmd[head].cmd_prev =
10899e39c5baSBill Taylor 		    state->ts_cmd_list.cml_tail_indx;
10909e39c5baSBill Taylor 		state->ts_cmd_list.cml_cmd[tail].cmd_next =
10919e39c5baSBill Taylor 		    state->ts_cmd_list.cml_head_indx;
10929e39c5baSBill Taylor 	}
10939e39c5baSBill Taylor 
10949e39c5baSBill Taylor 	return (DDI_SUCCESS);
10959e39c5baSBill Taylor }
10969e39c5baSBill Taylor 
10979e39c5baSBill Taylor 
10989e39c5baSBill Taylor /*
10999e39c5baSBill Taylor  * tavor_outstanding_cmdlist_fini()
11009e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
11019e39c5baSBill Taylor  */
11029e39c5baSBill Taylor void
tavor_outstanding_cmdlist_fini(tavor_state_t * state)11039e39c5baSBill Taylor tavor_outstanding_cmdlist_fini(tavor_state_t *state)
11049e39c5baSBill Taylor {
11059e39c5baSBill Taylor 	int		i;
11069e39c5baSBill Taylor 
11079e39c5baSBill Taylor 	/* Destroy the outstanding command list entries */
11089e39c5baSBill Taylor 	for (i = 0; i < state->ts_cmd_list.cml_num_alloc; i++) {
11099e39c5baSBill Taylor 		mutex_destroy(&state->ts_cmd_list.cml_cmd[i].cmd_comp_lock);
11109e39c5baSBill Taylor 		cv_destroy(&state->ts_cmd_list.cml_cmd[i].cmd_comp_cv);
11119e39c5baSBill Taylor 	}
11129e39c5baSBill Taylor 
11139e39c5baSBill Taylor 	/* Destroy the lock (and cv) and free up memory for list */
11149e39c5baSBill Taylor 	mutex_destroy(&state->ts_cmd_list.cml_lock);
11159e39c5baSBill Taylor 	cv_destroy(&state->ts_cmd_list.cml_cv);
11169e39c5baSBill Taylor 	if (state->ts_cmd_list.cml_num_alloc) {
11179e39c5baSBill Taylor 		kmem_free(state->ts_cmd_list.cml_cmd,
11189e39c5baSBill Taylor 		    state->ts_cmd_list.cml_list_sz * sizeof (tavor_cmd_t));
11199e39c5baSBill Taylor 	}
11209e39c5baSBill Taylor 
11219e39c5baSBill Taylor }
11229e39c5baSBill Taylor 
11239e39c5baSBill Taylor 
11249e39c5baSBill Taylor /*
11259e39c5baSBill Taylor  * tavor_mbox_sync()
11269e39c5baSBill Taylor  */
11279e39c5baSBill Taylor static void
tavor_mbox_sync(tavor_mbox_t * mbox,uint_t offset,uint_t length,uint_t flag)11289e39c5baSBill Taylor tavor_mbox_sync(tavor_mbox_t *mbox, uint_t offset, uint_t length,
11299e39c5baSBill Taylor     uint_t flag)
11309e39c5baSBill Taylor {
11319e39c5baSBill Taylor 	ddi_dma_handle_t	dmahdl;
11329e39c5baSBill Taylor 	int			status;
11339e39c5baSBill Taylor 
11349e39c5baSBill Taylor 	/* Determine if mailbox needs to be synced or not */
11359e39c5baSBill Taylor 	if (mbox->mb_sync == 0) {
11369e39c5baSBill Taylor 		return;
11379e39c5baSBill Taylor 	}
11389e39c5baSBill Taylor 
11399e39c5baSBill Taylor 	/* Get the DMA handle from mailbox */
11409e39c5baSBill Taylor 	dmahdl = mbox->mb_rsrcptr->tr_dmahdl;
11419e39c5baSBill Taylor 
11429e39c5baSBill Taylor 	/* Calculate offset into mailbox */
11439e39c5baSBill Taylor 	status = ddi_dma_sync(dmahdl, (off_t)offset, (size_t)length, flag);
11449e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
11459e39c5baSBill Taylor 		return;
11469e39c5baSBill Taylor 	}
11479e39c5baSBill Taylor }
11489e39c5baSBill Taylor 
11499e39c5baSBill Taylor 
11509e39c5baSBill Taylor /*
11519e39c5baSBill Taylor  * tavor_sys_en_cmd_post()
11529e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
11539e39c5baSBill Taylor  *    (Currently called only from attach() path context)
11549e39c5baSBill Taylor  */
11559e39c5baSBill Taylor int
tavor_sys_en_cmd_post(tavor_state_t * state,uint_t flags,uint64_t * errorcode,uint_t sleepflag)11569e39c5baSBill Taylor tavor_sys_en_cmd_post(tavor_state_t *state, uint_t flags,
11579e39c5baSBill Taylor     uint64_t *errorcode, uint_t sleepflag)
11589e39c5baSBill Taylor {
11599e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
11609e39c5baSBill Taylor 	int			status;
11619e39c5baSBill Taylor 
11629e39c5baSBill Taylor 	/* Make sure we are called with the correct flag */
11639e39c5baSBill Taylor 	ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN);
11649e39c5baSBill Taylor 
11659e39c5baSBill Taylor 	/* Setup and post the Tavor "SYS_EN" command */
11669e39c5baSBill Taylor 	cmd.cp_inparm	= 0;
11679e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
11689e39c5baSBill Taylor 	cmd.cp_inmod	= 0;
11699e39c5baSBill Taylor 	cmd.cp_opcode	= SYS_EN;
11709e39c5baSBill Taylor 	cmd.cp_opmod	= flags;
11719e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
11729e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
11739e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
11749e39c5baSBill Taylor 		/*
11759e39c5baSBill Taylor 		 * When the SYS_EN command fails, the "outparam" field may
11769e39c5baSBill Taylor 		 * contain more detailed information about what caused the
11779e39c5baSBill Taylor 		 * failure.
11789e39c5baSBill Taylor 		 */
11799e39c5baSBill Taylor 		*errorcode = cmd.cp_outparm;
11809e39c5baSBill Taylor 	}
11819e39c5baSBill Taylor 
11829e39c5baSBill Taylor 	return (status);
11839e39c5baSBill Taylor }
11849e39c5baSBill Taylor 
11859e39c5baSBill Taylor 
11869e39c5baSBill Taylor /*
11879e39c5baSBill Taylor  * tavor_sys_dis_cmd_post()
11889e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
11899e39c5baSBill Taylor  *    (Currently called only from attach() and/or detach() path contexts)
11909e39c5baSBill Taylor  */
11919e39c5baSBill Taylor int
tavor_sys_dis_cmd_post(tavor_state_t * state,uint_t sleepflag)11929e39c5baSBill Taylor tavor_sys_dis_cmd_post(tavor_state_t *state, uint_t sleepflag)
11939e39c5baSBill Taylor {
11949e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
11959e39c5baSBill Taylor 	int			status;
11969e39c5baSBill Taylor 
11979e39c5baSBill Taylor 	/* Make sure we are called with the correct flag */
11989e39c5baSBill Taylor 	ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN);
11999e39c5baSBill Taylor 
12009e39c5baSBill Taylor 	/* Setup and post the Tavor "SYS_DIS" command */
12019e39c5baSBill Taylor 	cmd.cp_inparm	= 0;
12029e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
12039e39c5baSBill Taylor 	cmd.cp_inmod	= 0;
12049e39c5baSBill Taylor 	cmd.cp_opcode	= SYS_DIS;
12059e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
12069e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
12079e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
12089e39c5baSBill Taylor 
12099e39c5baSBill Taylor 	return (status);
12109e39c5baSBill Taylor }
12119e39c5baSBill Taylor 
12129e39c5baSBill Taylor 
12139e39c5baSBill Taylor /*
12149e39c5baSBill Taylor  * tavor_init_hca_cmd_post()
12159e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
12169e39c5baSBill Taylor  *    (Currently called only from attach() path context)
12179e39c5baSBill Taylor  */
12189e39c5baSBill Taylor int
tavor_init_hca_cmd_post(tavor_state_t * state,tavor_hw_initqueryhca_t * inithca,uint_t sleepflag)12199e39c5baSBill Taylor tavor_init_hca_cmd_post(tavor_state_t *state,
12209e39c5baSBill Taylor     tavor_hw_initqueryhca_t *inithca, uint_t sleepflag)
12219e39c5baSBill Taylor {
12229e39c5baSBill Taylor 	tavor_mbox_info_t	mbox_info;
12239e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
12249e39c5baSBill Taylor 	uint64_t		data;
12259e39c5baSBill Taylor 	uint_t			size;
12269e39c5baSBill Taylor 	int			status, i;
12279e39c5baSBill Taylor 
12289e39c5baSBill Taylor 	/* Make sure we are called with the correct flag */
12299e39c5baSBill Taylor 	ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN);
12309e39c5baSBill Taylor 
12319e39c5baSBill Taylor 	/* Get an "In" mailbox for the command */
12329e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
12339e39c5baSBill Taylor 	status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
12349e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
12359e39c5baSBill Taylor 		return (status);
12369e39c5baSBill Taylor 	}
12379e39c5baSBill Taylor 
12389e39c5baSBill Taylor 	/* Copy the Tavor "INIT_HCA" command into the mailbox */
12399e39c5baSBill Taylor 	size = sizeof (tavor_hw_initqueryhca_t);
12409e39c5baSBill Taylor 	for (i = 0; i < (size >> 3); i++) {
12419e39c5baSBill Taylor 		data = ((uint64_t *)inithca)[i];
12429e39c5baSBill Taylor 		ddi_put64(mbox_info.mbi_in->mb_acchdl,
12439e39c5baSBill Taylor 		    ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
12449e39c5baSBill Taylor 	}
12459e39c5baSBill Taylor 
12469e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
12479e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
12489e39c5baSBill Taylor 
12499e39c5baSBill Taylor 	/* Setup and post the Tavor "INIT_HCA" command */
12509e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
12519e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
12529e39c5baSBill Taylor 	cmd.cp_inmod	= 0;
12539e39c5baSBill Taylor 	cmd.cp_opcode	= INIT_HCA;
12549e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
12559e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
12569e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
12579e39c5baSBill Taylor 
12589e39c5baSBill Taylor 	/* Free the mailbox */
12599e39c5baSBill Taylor 	tavor_mbox_free(state, &mbox_info);
12609e39c5baSBill Taylor 
12619e39c5baSBill Taylor 	return (status);
12629e39c5baSBill Taylor }
12639e39c5baSBill Taylor 
12649e39c5baSBill Taylor 
12659e39c5baSBill Taylor /*
12669e39c5baSBill Taylor  * tavor_close_hca_cmd_post()
12679e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
12689e39c5baSBill Taylor  *    (Currently called only from attach() and/or detach() path contexts)
12699e39c5baSBill Taylor  */
12709e39c5baSBill Taylor int
tavor_close_hca_cmd_post(tavor_state_t * state,uint_t sleepflag)12719e39c5baSBill Taylor tavor_close_hca_cmd_post(tavor_state_t *state, uint_t sleepflag)
12729e39c5baSBill Taylor {
12739e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
12749e39c5baSBill Taylor 	int			status;
12759e39c5baSBill Taylor 
12769e39c5baSBill Taylor 	/* Make sure we are called with the correct flag */
12779e39c5baSBill Taylor 	ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN);
12789e39c5baSBill Taylor 
12799e39c5baSBill Taylor 	/* Setup and post the Tavor "CLOSE_HCA" command */
12809e39c5baSBill Taylor 	cmd.cp_inparm	= 0;
12819e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
12829e39c5baSBill Taylor 	cmd.cp_inmod	= 0;
12839e39c5baSBill Taylor 	cmd.cp_opcode	= CLOSE_HCA;
12849e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
12859e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
12869e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
12879e39c5baSBill Taylor 
12889e39c5baSBill Taylor 	return (status);
12899e39c5baSBill Taylor }
12909e39c5baSBill Taylor 
12919e39c5baSBill Taylor 
12929e39c5baSBill Taylor /*
12939e39c5baSBill Taylor  * tavor_init_ib_cmd_post()
12949e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
12959e39c5baSBill Taylor  *    (Currently called only from attach() path context)
12969e39c5baSBill Taylor  */
12979e39c5baSBill Taylor int
tavor_init_ib_cmd_post(tavor_state_t * state,tavor_hw_initib_t * initib,uint_t port,uint_t sleepflag)12989e39c5baSBill Taylor tavor_init_ib_cmd_post(tavor_state_t *state, tavor_hw_initib_t *initib,
12999e39c5baSBill Taylor     uint_t port, uint_t sleepflag)
13009e39c5baSBill Taylor {
13019e39c5baSBill Taylor 	tavor_mbox_info_t	mbox_info;
13029e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
13039e39c5baSBill Taylor 	uint64_t		data;
13049e39c5baSBill Taylor 	uint_t			size;
13059e39c5baSBill Taylor 	int			status, i;
13069e39c5baSBill Taylor 
13079e39c5baSBill Taylor 	/* Make sure we are called with the correct flag */
13089e39c5baSBill Taylor 	ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN);
13099e39c5baSBill Taylor 
13109e39c5baSBill Taylor 	/* Get an "In" mailbox for the command */
13119e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
13129e39c5baSBill Taylor 	status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
13139e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
13149e39c5baSBill Taylor 		return (status);
13159e39c5baSBill Taylor 	}
13169e39c5baSBill Taylor 
13179e39c5baSBill Taylor 	/* Copy the Tavor "INIT_IB" command into the mailbox */
13189e39c5baSBill Taylor 	size = sizeof (tavor_hw_initib_t);
13199e39c5baSBill Taylor 	for (i = 0; i < (size >> 3); i++) {
13209e39c5baSBill Taylor 		data = ((uint64_t *)initib)[i];
13219e39c5baSBill Taylor 		ddi_put64(mbox_info.mbi_in->mb_acchdl,
13229e39c5baSBill Taylor 		    ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
13239e39c5baSBill Taylor 	}
13249e39c5baSBill Taylor 
13259e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
13269e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
13279e39c5baSBill Taylor 
13289e39c5baSBill Taylor 	/* Setup and post the Tavor "INIT_IB" command */
13299e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
13309e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
13319e39c5baSBill Taylor 	cmd.cp_inmod	= port;
13329e39c5baSBill Taylor 	cmd.cp_opcode	= INIT_IB;
13339e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
13349e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
13359e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
13369e39c5baSBill Taylor 
13379e39c5baSBill Taylor 	/* Free the mailbox */
13389e39c5baSBill Taylor 	tavor_mbox_free(state, &mbox_info);
13399e39c5baSBill Taylor 
13409e39c5baSBill Taylor 	return (status);
13419e39c5baSBill Taylor }
13429e39c5baSBill Taylor 
13439e39c5baSBill Taylor 
13449e39c5baSBill Taylor /*
13459e39c5baSBill Taylor  * tavor_close_ib_cmd_post()
13469e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
13479e39c5baSBill Taylor  *    (Currently called only from attach() and/or detach() path contexts)
13489e39c5baSBill Taylor  */
13499e39c5baSBill Taylor int
tavor_close_ib_cmd_post(tavor_state_t * state,uint_t port,uint_t sleepflag)13509e39c5baSBill Taylor tavor_close_ib_cmd_post(tavor_state_t *state, uint_t port, uint_t sleepflag)
13519e39c5baSBill Taylor {
13529e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
13539e39c5baSBill Taylor 	int			status;
13549e39c5baSBill Taylor 
13559e39c5baSBill Taylor 	/* Setup and post the Tavor "CLOSE_IB" command */
13569e39c5baSBill Taylor 	cmd.cp_inparm	= 0;
13579e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
13589e39c5baSBill Taylor 	cmd.cp_inmod	= port;
13599e39c5baSBill Taylor 	cmd.cp_opcode	= CLOSE_IB;
13609e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
13619e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
13629e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
13639e39c5baSBill Taylor 
13649e39c5baSBill Taylor 	return (status);
13659e39c5baSBill Taylor }
13669e39c5baSBill Taylor 
13679e39c5baSBill Taylor 
13689e39c5baSBill Taylor /*
13699e39c5baSBill Taylor  * tavor_set_ib_cmd_post()
13709e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
13719e39c5baSBill Taylor  */
13729e39c5baSBill Taylor int
tavor_set_ib_cmd_post(tavor_state_t * state,uint32_t capmask,uint_t port,uint_t reset_qkey,uint_t sleepflag)13739e39c5baSBill Taylor tavor_set_ib_cmd_post(tavor_state_t *state, uint32_t capmask, uint_t port,
13749e39c5baSBill Taylor     uint_t reset_qkey, uint_t sleepflag)
13759e39c5baSBill Taylor {
13769e39c5baSBill Taylor 	tavor_mbox_info_t	mbox_info;
13779e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
13789e39c5baSBill Taylor 	int			status;
13799e39c5baSBill Taylor 
13809e39c5baSBill Taylor 	/* Get an "In" mailbox for the command */
13819e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
13829e39c5baSBill Taylor 	status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
13839e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
13849e39c5baSBill Taylor 		return (status);
13859e39c5baSBill Taylor 	}
13869e39c5baSBill Taylor 
13879e39c5baSBill Taylor 	/* Copy the Tavor "SET_IB" command into mailbox */
13889e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl,
13899e39c5baSBill Taylor 	    ((uint32_t *)mbox_info.mbi_in->mb_addr + 0), reset_qkey);
13909e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl,
13919e39c5baSBill Taylor 	    ((uint32_t *)mbox_info.mbi_in->mb_addr + 1), capmask);
13929e39c5baSBill Taylor 
13939e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
13949e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_in, 0, TAVOR_CMD_SETIB_SZ,
13959e39c5baSBill Taylor 	    DDI_DMA_SYNC_FORDEV);
13969e39c5baSBill Taylor 
13979e39c5baSBill Taylor 	/* Setup and post the Tavor "SET_IB" command */
13989e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
13999e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
14009e39c5baSBill Taylor 	cmd.cp_inmod	= port;
14019e39c5baSBill Taylor 	cmd.cp_opcode	= SET_IB;
14029e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
14039e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
14049e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
14059e39c5baSBill Taylor 
14069e39c5baSBill Taylor 	/* Free the mailbox */
14079e39c5baSBill Taylor 	tavor_mbox_free(state, &mbox_info);
14089e39c5baSBill Taylor 
14099e39c5baSBill Taylor 	return (status);
14109e39c5baSBill Taylor }
14119e39c5baSBill Taylor 
14129e39c5baSBill Taylor 
14139e39c5baSBill Taylor /*
14149e39c5baSBill Taylor  * tavor_mod_stat_cfg_cmd_post()
14159e39c5baSBill Taylor  *    Context: Can be called only from attach() path
14169e39c5baSBill Taylor  */
14179e39c5baSBill Taylor int
tavor_mod_stat_cfg_cmd_post(tavor_state_t * state)14189e39c5baSBill Taylor tavor_mod_stat_cfg_cmd_post(tavor_state_t *state)
14199e39c5baSBill Taylor {
14209e39c5baSBill Taylor 	tavor_mbox_info_t	mbox_info;
14219e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
14229e39c5baSBill Taylor 	tavor_hw_mod_stat_cfg_t	*mod;
14239e39c5baSBill Taylor 	uint64_t		data;
14249e39c5baSBill Taylor 	uint_t			size;
14259e39c5baSBill Taylor 	int			status, i;
14269e39c5baSBill Taylor 
14279e39c5baSBill Taylor 	/*
14289e39c5baSBill Taylor 	 * "MOD_STAT_CFG" needs an INMBOX parameter, to specify what operations
14299e39c5baSBill Taylor 	 * to do.  However, at the point in time that we call this command, the
14309e39c5baSBill Taylor 	 * DDR has not yet been initialized, and all INMBOX'es are located in
14319e39c5baSBill Taylor 	 * DDR.  Because we want to call MOD_STAT_CFG before QUERY_DEVLIM is
14329e39c5baSBill Taylor 	 * called, and thus call it before DDR is setup, we simply use an
14339e39c5baSBill Taylor 	 * OUTMBOX memory location here as our INMBOX parameter.
14349e39c5baSBill Taylor 	 */
14359e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = TAVOR_ALLOC_OUTMBOX;
14369e39c5baSBill Taylor 	status = tavor_mbox_alloc(state, &mbox_info, TAVOR_NOSLEEP);
14379e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
14389e39c5baSBill Taylor 		return (status);
14399e39c5baSBill Taylor 	}
14409e39c5baSBill Taylor 
14419e39c5baSBill Taylor 	/*
14429e39c5baSBill Taylor 	 * Allocate on the heap our 'mod_stat_cfg' structure.  We want to
14439e39c5baSBill Taylor 	 * ideally move all of this on to the stack in the future, but this
14449e39c5baSBill Taylor 	 * works well for now.
14459e39c5baSBill Taylor 	 */
14469e39c5baSBill Taylor 	mod = (tavor_hw_mod_stat_cfg_t *)kmem_zalloc(
14479e39c5baSBill Taylor 	    sizeof (tavor_hw_mod_stat_cfg_t), KM_SLEEP);
14489e39c5baSBill Taylor 
14499e39c5baSBill Taylor 	/* Setup "MOD_STAT_CFG" settings */
14509e39c5baSBill Taylor 	mod->srq_m	= 1;
14519e39c5baSBill Taylor 	mod->srq	= state->ts_cfg_profile->cp_srq_enable;
14529e39c5baSBill Taylor 
14539e39c5baSBill Taylor 	if (mod->srq) {
14549e39c5baSBill Taylor 		mod->log_max_srq = state->ts_cfg_profile->cp_log_num_srq;
14559e39c5baSBill Taylor 	} else {
14569e39c5baSBill Taylor 		mod->log_max_srq = 0;
14579e39c5baSBill Taylor 	}
14589e39c5baSBill Taylor 
14599e39c5baSBill Taylor 	/* Copy the "MOD_STAT_CFG" command into the "In" mailbox */
14609e39c5baSBill Taylor 	size = sizeof (tavor_hw_mod_stat_cfg_t);
14619e39c5baSBill Taylor 	for (i = 0; i < (size >> 3); i++) {
14629e39c5baSBill Taylor 		data = ((uint64_t *)mod)[i];
14639e39c5baSBill Taylor 		ddi_put64(mbox_info.mbi_out->mb_acchdl,
14649e39c5baSBill Taylor 		    ((uint64_t *)mbox_info.mbi_out->mb_addr + i), data);
14659e39c5baSBill Taylor 	}
14669e39c5baSBill Taylor 
14679e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
14689e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORDEV);
14699e39c5baSBill Taylor 
14709e39c5baSBill Taylor 	/* Setup and post the Tavor "MOD_STAT_CFG" command */
14719e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_out->mb_mapaddr;
14729e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
14739e39c5baSBill Taylor 	cmd.cp_inmod	= 0;
14749e39c5baSBill Taylor 	cmd.cp_opcode	= MOD_STAT_CFG;
14759e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
14769e39c5baSBill Taylor 	cmd.cp_flags	= TAVOR_CMD_NOSLEEP_SPIN;
14779e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
14789e39c5baSBill Taylor 
14799e39c5baSBill Taylor 	/* Free "MOD_STAT_CFG" struct */
14809e39c5baSBill Taylor 	kmem_free(mod, sizeof (tavor_hw_mod_stat_cfg_t));
14819e39c5baSBill Taylor 
14829e39c5baSBill Taylor 	/* Free the mailbox */
14839e39c5baSBill Taylor 	tavor_mbox_free(state, &mbox_info);
14849e39c5baSBill Taylor 
14859e39c5baSBill Taylor 	return (status);
14869e39c5baSBill Taylor }
14879e39c5baSBill Taylor 
14889e39c5baSBill Taylor 
14899e39c5baSBill Taylor /*
14909e39c5baSBill Taylor  * tavor_mad_ifc_cmd_post()
14919e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
14929e39c5baSBill Taylor  */
14939e39c5baSBill Taylor int
tavor_mad_ifc_cmd_post(tavor_state_t * state,uint_t port,uint_t sleepflag,uint32_t * mad,uint32_t * resp)14949e39c5baSBill Taylor tavor_mad_ifc_cmd_post(tavor_state_t *state, uint_t port,
14959e39c5baSBill Taylor     uint_t sleepflag, uint32_t *mad, uint32_t *resp)
14969e39c5baSBill Taylor {
14979e39c5baSBill Taylor 	tavor_mbox_info_t	mbox_info;
14989e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
14999e39c5baSBill Taylor 	uint_t			size;
15009e39c5baSBill Taylor 	int			status;
15019e39c5baSBill Taylor 
15029e39c5baSBill Taylor 	/* Get "In" and "Out" mailboxes for the command */
15039e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
15049e39c5baSBill Taylor 	status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
15059e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
15069e39c5baSBill Taylor 		return (status);
15079e39c5baSBill Taylor 	}
15089e39c5baSBill Taylor 
15099e39c5baSBill Taylor 	/* Copy the request MAD into the "In" mailbox */
15109e39c5baSBill Taylor 	size = TAVOR_CMD_MAD_IFC_SIZE;
15119e39c5baSBill Taylor 	bcopy(mad, mbox_info.mbi_in->mb_addr, size);
15129e39c5baSBill Taylor 
15139e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
15149e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
15159e39c5baSBill Taylor 
15169e39c5baSBill Taylor 	/* Setup the Tavor "MAD_IFC" command */
15179e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
15189e39c5baSBill Taylor 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
15199e39c5baSBill Taylor 	cmd.cp_inmod	= port;
15209e39c5baSBill Taylor 	cmd.cp_opcode	= MAD_IFC;
15219e39c5baSBill Taylor 	cmd.cp_opmod	= TAVOR_CMD_MKEY_CHECK;  /* Enable MKey checking */
15229e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
15239e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
15249e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
15259e39c5baSBill Taylor 		goto mad_ifc_fail;
15269e39c5baSBill Taylor 	}
15279e39c5baSBill Taylor 
15289e39c5baSBill Taylor 	/* Sync the mailbox to read the results */
15299e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
15309e39c5baSBill Taylor 
15319e39c5baSBill Taylor 	/* Copy the response MAD into "resp" */
15329e39c5baSBill Taylor 	bcopy(mbox_info.mbi_out->mb_addr, resp, size);
15339e39c5baSBill Taylor 
15349e39c5baSBill Taylor mad_ifc_fail:
15359e39c5baSBill Taylor 	/* Free the mailbox */
15369e39c5baSBill Taylor 	tavor_mbox_free(state, &mbox_info);
15379e39c5baSBill Taylor 
15389e39c5baSBill Taylor 	return (status);
15399e39c5baSBill Taylor }
15409e39c5baSBill Taylor 
15419e39c5baSBill Taylor 
15429e39c5baSBill Taylor /*
15439e39c5baSBill Taylor  * tavor_getportinfo_cmd_post()
15449e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
15459e39c5baSBill Taylor  */
15469e39c5baSBill Taylor int
tavor_getportinfo_cmd_post(tavor_state_t * state,uint_t port,uint_t sleepflag,sm_portinfo_t * portinfo)15479e39c5baSBill Taylor tavor_getportinfo_cmd_post(tavor_state_t *state, uint_t port,
15489e39c5baSBill Taylor     uint_t sleepflag, sm_portinfo_t *portinfo)
15499e39c5baSBill Taylor {
15509e39c5baSBill Taylor 	tavor_mbox_info_t	mbox_info;
15519e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
15529e39c5baSBill Taylor 	uint32_t		*mbox;
15539e39c5baSBill Taylor 	uint_t			size;
15549e39c5baSBill Taylor 	int			status, i;
15559e39c5baSBill Taylor 
15569e39c5baSBill Taylor 	/* Get "In" and "Out" mailboxes for the command */
15579e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
15589e39c5baSBill Taylor 	status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
15599e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
15609e39c5baSBill Taylor 		return (status);
15619e39c5baSBill Taylor 	}
15629e39c5baSBill Taylor 
15639e39c5baSBill Taylor 	/* Build the GetPortInfo request MAD in the "In" mailbox */
15649e39c5baSBill Taylor 	size = TAVOR_CMD_MAD_IFC_SIZE;
15659e39c5baSBill Taylor 	mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
15669e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], TAVOR_CMD_MADHDR0);
15679e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1);
15689e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2);
15699e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3);
15709e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_PORTINFO);
15719e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], port);
15729e39c5baSBill Taylor 	for (i = 6; i < (size >> 2); i++) {
15739e39c5baSBill Taylor 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
15749e39c5baSBill Taylor 	}
15759e39c5baSBill Taylor 
15769e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
15779e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
15789e39c5baSBill Taylor 
15799e39c5baSBill Taylor 	/* Setup the Tavor "MAD_IFC" command */
15809e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
15819e39c5baSBill Taylor 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
15829e39c5baSBill Taylor 	cmd.cp_inmod	= port;
15839e39c5baSBill Taylor 	cmd.cp_opcode	= MAD_IFC;
15849e39c5baSBill Taylor 	cmd.cp_opmod	= TAVOR_CMD_MKEY_DONTCHECK;  /* No MKey checking */
15859e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
15869e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
15879e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
15889e39c5baSBill Taylor 		goto getportinfo_fail;
15899e39c5baSBill Taylor 	}
15909e39c5baSBill Taylor 
15919e39c5baSBill Taylor 	/* Sync the mailbox to read the results */
15929e39c5baSBill Taylor 	size = sizeof (sm_portinfo_t);
15939e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_out, TAVOR_CMD_MADDATA_OFFSET,
15949e39c5baSBill Taylor 	    size, DDI_DMA_SYNC_FORCPU);
15959e39c5baSBill Taylor 
15969e39c5baSBill Taylor 	/*
15979e39c5baSBill Taylor 	 * Copy GetPortInfo response MAD into "portinfo".  Do any endian
15989e39c5baSBill Taylor 	 * swapping that may be necessary to flip any of the "portinfo"
15999e39c5baSBill Taylor 	 * fields
16009e39c5baSBill Taylor 	 */
16019e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*portinfo))
16029e39c5baSBill Taylor 	bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
16039e39c5baSBill Taylor 	    TAVOR_CMD_MADDATA_OFFSET), portinfo, size);
16049e39c5baSBill Taylor 	TAVOR_GETPORTINFO_SWAP(portinfo);
16059e39c5baSBill Taylor 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*portinfo))
16069e39c5baSBill Taylor 
16079e39c5baSBill Taylor getportinfo_fail:
16089e39c5baSBill Taylor 	/* Free the mailbox */
16099e39c5baSBill Taylor 	tavor_mbox_free(state, &mbox_info);
16109e39c5baSBill Taylor 
16119e39c5baSBill Taylor 	return (status);
16129e39c5baSBill Taylor }
16139e39c5baSBill Taylor 
16149e39c5baSBill Taylor 
16159e39c5baSBill Taylor /*
16169e39c5baSBill Taylor  * tavor_getnodeinfo_cmd_post()
16179e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
16189e39c5baSBill Taylor  *    (Currently called only from attach() and detach() path contexts)
16199e39c5baSBill Taylor  */
16209e39c5baSBill Taylor int
tavor_getnodeinfo_cmd_post(tavor_state_t * state,uint_t sleepflag,sm_nodeinfo_t * nodeinfo)16219e39c5baSBill Taylor tavor_getnodeinfo_cmd_post(tavor_state_t *state, uint_t sleepflag,
16229e39c5baSBill Taylor     sm_nodeinfo_t *nodeinfo)
16239e39c5baSBill Taylor {
16249e39c5baSBill Taylor 	tavor_mbox_info_t	mbox_info;
16259e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
16269e39c5baSBill Taylor 	uint32_t		*mbox;
16279e39c5baSBill Taylor 	uint_t			size;
16289e39c5baSBill Taylor 	int			status, i;
16299e39c5baSBill Taylor 
16309e39c5baSBill Taylor 	/* Make sure we are called with the correct flag */
16319e39c5baSBill Taylor 	ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN);
16329e39c5baSBill Taylor 
16339e39c5baSBill Taylor 	/* Get "In" and "Out" mailboxes for the command */
16349e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
16359e39c5baSBill Taylor 	status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
16369e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
16379e39c5baSBill Taylor 		return (status);
16389e39c5baSBill Taylor 	}
16399e39c5baSBill Taylor 
16409e39c5baSBill Taylor 	/* Build the GetNodeInfo request MAD into the "In" mailbox */
16419e39c5baSBill Taylor 	size = TAVOR_CMD_MAD_IFC_SIZE;
16429e39c5baSBill Taylor 	mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
16439e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], TAVOR_CMD_MADHDR0);
16449e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1);
16459e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2);
16469e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3);
16479e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_NODEINFO);
16489e39c5baSBill Taylor 	for (i = 5; i < (size >> 2); i++) {
16499e39c5baSBill Taylor 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
16509e39c5baSBill Taylor 	}
16519e39c5baSBill Taylor 
16529e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
16539e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
16549e39c5baSBill Taylor 
16559e39c5baSBill Taylor 	/* Setup the Tavor "MAD_IFC" command */
16569e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
16579e39c5baSBill Taylor 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
16589e39c5baSBill Taylor 	cmd.cp_inmod	= 1;  /* Get NodeInfo from port #1 */
16599e39c5baSBill Taylor 	cmd.cp_opcode	= MAD_IFC;
16609e39c5baSBill Taylor 	cmd.cp_opmod	= TAVOR_CMD_MKEY_DONTCHECK;  /* No MKey checking */
16619e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
16629e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
16639e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
16649e39c5baSBill Taylor 		goto getnodeinfo_fail;
16659e39c5baSBill Taylor 	}
16669e39c5baSBill Taylor 
16679e39c5baSBill Taylor 	/* Sync the mailbox to read the results */
16689e39c5baSBill Taylor 	size = sizeof (sm_nodeinfo_t);
16699e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_out, TAVOR_CMD_MADDATA_OFFSET,
16709e39c5baSBill Taylor 	    size, DDI_DMA_SYNC_FORCPU);
16719e39c5baSBill Taylor 
16729e39c5baSBill Taylor 	/*
16739e39c5baSBill Taylor 	 * Copy GetNodeInfo response MAD into "nodeinfo".  Do any endian
16749e39c5baSBill Taylor 	 * swapping that may be necessary to flip any of the "nodeinfo"
16759e39c5baSBill Taylor 	 * fields
16769e39c5baSBill Taylor 	 */
16779e39c5baSBill Taylor 	bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
16789e39c5baSBill Taylor 	    TAVOR_CMD_MADDATA_OFFSET), nodeinfo, size);
16799e39c5baSBill Taylor 	TAVOR_GETNODEINFO_SWAP(nodeinfo);
16809e39c5baSBill Taylor 
16819e39c5baSBill Taylor getnodeinfo_fail:
16829e39c5baSBill Taylor 	/* Free the mailbox */
16839e39c5baSBill Taylor 	tavor_mbox_free(state, &mbox_info);
16849e39c5baSBill Taylor 
16859e39c5baSBill Taylor 	return (status);
16869e39c5baSBill Taylor }
16879e39c5baSBill Taylor 
16889e39c5baSBill Taylor 
16899e39c5baSBill Taylor /*
16909e39c5baSBill Taylor  * tavor_getnodedesc_cmd_post()
16919e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
16929e39c5baSBill Taylor  *    (Currently called only from attach() and detach() path contexts)
16939e39c5baSBill Taylor  */
16949e39c5baSBill Taylor int
tavor_getnodedesc_cmd_post(tavor_state_t * state,uint_t sleepflag,sm_nodedesc_t * nodedesc)16959e39c5baSBill Taylor tavor_getnodedesc_cmd_post(tavor_state_t *state, uint_t sleepflag,
16969e39c5baSBill Taylor     sm_nodedesc_t *nodedesc)
16979e39c5baSBill Taylor {
16989e39c5baSBill Taylor 	tavor_mbox_info_t	mbox_info;
16999e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
17009e39c5baSBill Taylor 	uint32_t		*mbox;
17019e39c5baSBill Taylor 	uint_t			size;
17029e39c5baSBill Taylor 	int			status, i;
17039e39c5baSBill Taylor 
17049e39c5baSBill Taylor 	/* Get "In" and "Out" mailboxes for the command */
17059e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
17069e39c5baSBill Taylor 	status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
17079e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
17089e39c5baSBill Taylor 		return (status);
17099e39c5baSBill Taylor 	}
17109e39c5baSBill Taylor 
17119e39c5baSBill Taylor 	/* Build the GetNodeDesc request MAD into the "In" mailbox */
17129e39c5baSBill Taylor 	size = TAVOR_CMD_MAD_IFC_SIZE;
17139e39c5baSBill Taylor 	mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
17149e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], TAVOR_CMD_MADHDR0);
17159e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1);
17169e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2);
17179e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3);
17189e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_NODEDESC);
17199e39c5baSBill Taylor 	for (i = 5; i < (size >> 2); i++) {
17209e39c5baSBill Taylor 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
17219e39c5baSBill Taylor 	}
17229e39c5baSBill Taylor 
17239e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
17249e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
17259e39c5baSBill Taylor 
17269e39c5baSBill Taylor 	/* Setup the Tavor "MAD_IFC" command */
17279e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
17289e39c5baSBill Taylor 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
17299e39c5baSBill Taylor 	cmd.cp_inmod	= 1;  /* Get NodeDesc from port #1 */
17309e39c5baSBill Taylor 	cmd.cp_opcode	= MAD_IFC;
17319e39c5baSBill Taylor 	cmd.cp_opmod	= TAVOR_CMD_MKEY_DONTCHECK;  /* No MKey checking */
17329e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
17339e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
17349e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
17359e39c5baSBill Taylor 		goto getnodedesc_fail;
17369e39c5baSBill Taylor 	}
17379e39c5baSBill Taylor 
17389e39c5baSBill Taylor 	/* Sync the mailbox to read the results */
17399e39c5baSBill Taylor 	size = sizeof (sm_nodedesc_t);
17409e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_out, TAVOR_CMD_MADDATA_OFFSET,
17419e39c5baSBill Taylor 	    size, DDI_DMA_SYNC_FORCPU);
17429e39c5baSBill Taylor 
17439e39c5baSBill Taylor 	/* Copy GetNodeDesc response MAD into "nodedesc" */
17449e39c5baSBill Taylor 	bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
17459e39c5baSBill Taylor 	    TAVOR_CMD_MADDATA_OFFSET), nodedesc, size);
17469e39c5baSBill Taylor 
17479e39c5baSBill Taylor getnodedesc_fail:
17489e39c5baSBill Taylor 	/* Free the mailbox */
17499e39c5baSBill Taylor 	tavor_mbox_free(state, &mbox_info);
17509e39c5baSBill Taylor 
17519e39c5baSBill Taylor 	return (status);
17529e39c5baSBill Taylor }
17539e39c5baSBill Taylor 
17549e39c5baSBill Taylor 
17559e39c5baSBill Taylor /*
17569e39c5baSBill Taylor  * tavor_getguidinfo_cmd_post()
17579e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
17589e39c5baSBill Taylor  */
17599e39c5baSBill Taylor int
tavor_getguidinfo_cmd_post(tavor_state_t * state,uint_t port,uint_t guidblock,uint_t sleepflag,sm_guidinfo_t * guidinfo)17609e39c5baSBill Taylor tavor_getguidinfo_cmd_post(tavor_state_t *state, uint_t port,
17619e39c5baSBill Taylor     uint_t guidblock, uint_t sleepflag, sm_guidinfo_t *guidinfo)
17629e39c5baSBill Taylor {
17639e39c5baSBill Taylor 	tavor_mbox_info_t	mbox_info;
17649e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
17659e39c5baSBill Taylor 	uint32_t		*mbox;
17669e39c5baSBill Taylor 	uint_t			size;
17679e39c5baSBill Taylor 	int			status, i;
17689e39c5baSBill Taylor 
17699e39c5baSBill Taylor 	/* Get "In" and "Out" mailboxes for the command */
17709e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
17719e39c5baSBill Taylor 	status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
17729e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
17739e39c5baSBill Taylor 		return (status);
17749e39c5baSBill Taylor 	}
17759e39c5baSBill Taylor 
17769e39c5baSBill Taylor 	/* Build the GetGUIDInfo request MAD into the "In" mailbox */
17779e39c5baSBill Taylor 	size = TAVOR_CMD_MAD_IFC_SIZE;
17789e39c5baSBill Taylor 	mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
17799e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], TAVOR_CMD_MADHDR0);
17809e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1);
17819e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2);
17829e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3);
17839e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_GUIDINFO);
17849e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], guidblock);
17859e39c5baSBill Taylor 	for (i = 6; i < (size >> 2); i++) {
17869e39c5baSBill Taylor 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
17879e39c5baSBill Taylor 	}
17889e39c5baSBill Taylor 
17899e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
17909e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
17919e39c5baSBill Taylor 
17929e39c5baSBill Taylor 	/* Setup the Tavor "MAD_IFC" command */
17939e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
17949e39c5baSBill Taylor 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
17959e39c5baSBill Taylor 	cmd.cp_inmod	= port;
17969e39c5baSBill Taylor 	cmd.cp_opcode	= MAD_IFC;
17979e39c5baSBill Taylor 	cmd.cp_opmod	= TAVOR_CMD_MKEY_DONTCHECK;  /* No MKey checking */
17989e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
17999e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
18009e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
18019e39c5baSBill Taylor 		goto getguidinfo_fail;
18029e39c5baSBill Taylor 	}
18039e39c5baSBill Taylor 
18049e39c5baSBill Taylor 	/* Sync the mailbox to read the results */
18059e39c5baSBill Taylor 	size = sizeof (sm_guidinfo_t);
18069e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_out, TAVOR_CMD_MADDATA_OFFSET,
18079e39c5baSBill Taylor 	    size, DDI_DMA_SYNC_FORCPU);
18089e39c5baSBill Taylor 
18099e39c5baSBill Taylor 	/*
18109e39c5baSBill Taylor 	 * Copy GetGUIDInfo response MAD into "guidinfo".  Do any endian
18119e39c5baSBill Taylor 	 * swapping that may be necessary to flip the "guidinfo" fields
18129e39c5baSBill Taylor 	 */
18139e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*guidinfo))
18149e39c5baSBill Taylor 	bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
18159e39c5baSBill Taylor 	    TAVOR_CMD_MADDATA_OFFSET), guidinfo, size);
18169e39c5baSBill Taylor 	TAVOR_GETGUIDINFO_SWAP(guidinfo);
18179e39c5baSBill Taylor 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*guidinfo))
18189e39c5baSBill Taylor 
18199e39c5baSBill Taylor getguidinfo_fail:
18209e39c5baSBill Taylor 	/* Free the mailbox */
18219e39c5baSBill Taylor 	tavor_mbox_free(state, &mbox_info);
18229e39c5baSBill Taylor 
18239e39c5baSBill Taylor 	return (status);
18249e39c5baSBill Taylor }
18259e39c5baSBill Taylor 
18269e39c5baSBill Taylor 
18279e39c5baSBill Taylor /*
18289e39c5baSBill Taylor  * tavor_getpkeytable_cmd_post()
18299e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
18309e39c5baSBill Taylor  */
18319e39c5baSBill Taylor int
tavor_getpkeytable_cmd_post(tavor_state_t * state,uint_t port,uint_t pkeyblock,uint_t sleepflag,sm_pkey_table_t * pkeytable)18329e39c5baSBill Taylor tavor_getpkeytable_cmd_post(tavor_state_t *state, uint_t port,
18339e39c5baSBill Taylor     uint_t pkeyblock, uint_t sleepflag, sm_pkey_table_t *pkeytable)
18349e39c5baSBill Taylor {
18359e39c5baSBill Taylor 	tavor_mbox_info_t	mbox_info;
18369e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
18379e39c5baSBill Taylor 	uint32_t		*mbox;
18389e39c5baSBill Taylor 	uint_t			size;
18399e39c5baSBill Taylor 	int			status, i;
18409e39c5baSBill Taylor 
18419e39c5baSBill Taylor 	/* Get "In" and "Out" mailboxes for the command */
18429e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
18439e39c5baSBill Taylor 	status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
18449e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
18459e39c5baSBill Taylor 		return (status);
18469e39c5baSBill Taylor 	}
18479e39c5baSBill Taylor 
18489e39c5baSBill Taylor 	/* Build the GetPkeyTable request MAD into the "In" mailbox */
18499e39c5baSBill Taylor 	size = TAVOR_CMD_MAD_IFC_SIZE;
18509e39c5baSBill Taylor 	mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
18519e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], TAVOR_CMD_MADHDR0);
18529e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1);
18539e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2);
18549e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3);
18559e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_PKEYTBLE);
18569e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], pkeyblock);
18579e39c5baSBill Taylor 	for (i = 6; i < (size >> 2); i++) {
18589e39c5baSBill Taylor 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
18599e39c5baSBill Taylor 	}
18609e39c5baSBill Taylor 
18619e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
18629e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
18639e39c5baSBill Taylor 
18649e39c5baSBill Taylor 	/* Setup the Tavor "MAD_IFC" command */
18659e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
18669e39c5baSBill Taylor 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
18679e39c5baSBill Taylor 	cmd.cp_inmod	= port;
18689e39c5baSBill Taylor 	cmd.cp_opcode	= MAD_IFC;
18699e39c5baSBill Taylor 	cmd.cp_opmod	= TAVOR_CMD_MKEY_DONTCHECK;  /* No MKey checking */
18709e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
18719e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
18729e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
18739e39c5baSBill Taylor 		goto getpkeytable_fail;
18749e39c5baSBill Taylor 	}
18759e39c5baSBill Taylor 
18769e39c5baSBill Taylor 	/* Sync the mailbox to read the results */
18779e39c5baSBill Taylor 	size = sizeof (sm_pkey_table_t);
18789e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_out, TAVOR_CMD_MADDATA_OFFSET,
18799e39c5baSBill Taylor 	    size, DDI_DMA_SYNC_FORCPU);
18809e39c5baSBill Taylor 
18819e39c5baSBill Taylor 	/*
18829e39c5baSBill Taylor 	 * Copy GetPKeyTable response MAD into "pkeytable".  Do any endian
18839e39c5baSBill Taylor 	 * swapping that may be necessary to flip the "pkeytable" fields
18849e39c5baSBill Taylor 	 */
18859e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*pkeytable))
18869e39c5baSBill Taylor 	bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
18879e39c5baSBill Taylor 	    TAVOR_CMD_MADDATA_OFFSET), pkeytable, size);
18889e39c5baSBill Taylor 	TAVOR_GETPKEYTABLE_SWAP(pkeytable);
18899e39c5baSBill Taylor 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*pkeytable))
18909e39c5baSBill Taylor 
18919e39c5baSBill Taylor getpkeytable_fail:
18929e39c5baSBill Taylor 	/* Free the mailbox */
18939e39c5baSBill Taylor 	tavor_mbox_free(state, &mbox_info);
18949e39c5baSBill Taylor 
18959e39c5baSBill Taylor 	return (status);
18969e39c5baSBill Taylor }
18979e39c5baSBill Taylor 
18989e39c5baSBill Taylor 
18999e39c5baSBill Taylor /*
19009e39c5baSBill Taylor  * tavor_write_mtt_cmd_post()
19019e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
19029e39c5baSBill Taylor  */
19039e39c5baSBill Taylor int
tavor_write_mtt_cmd_post(tavor_state_t * state,tavor_mbox_info_t * mbox_info,uint_t num_mtt,uint_t sleepflag)19049e39c5baSBill Taylor tavor_write_mtt_cmd_post(tavor_state_t *state, tavor_mbox_info_t *mbox_info,
19059e39c5baSBill Taylor     uint_t num_mtt, uint_t sleepflag)
19069e39c5baSBill Taylor {
19079e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
19089e39c5baSBill Taylor 	uint_t			size;
19099e39c5baSBill Taylor 	int			status;
19109e39c5baSBill Taylor 
19119e39c5baSBill Taylor 	/*
19129e39c5baSBill Taylor 	 * The WRITE_MTT command is unlike the other commands we use, in that
19139e39c5baSBill Taylor 	 * we have intentionally separated the mailbox allocation step from
19149e39c5baSBill Taylor 	 * the rest of the command posting steps.  At this point (when this
19159e39c5baSBill Taylor 	 * function is called) the "In" mailbox already contains all the MTT
19169e39c5baSBill Taylor 	 * entries to be copied into the Tavor tables (starting at offset
19179e39c5baSBill Taylor 	 * 0x10) _and_ the 64-bit address of the destination for the first
19189e39c5baSBill Taylor 	 * MTT entry in the MTT table.
19199e39c5baSBill Taylor 	 */
19209e39c5baSBill Taylor 
19219e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
19229e39c5baSBill Taylor 	size = (num_mtt << TAVOR_MTT_SIZE_SHIFT) + TAVOR_CMD_WRITEMTT_RSVD_SZ;
19239e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info->mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
19249e39c5baSBill Taylor 
19259e39c5baSBill Taylor 	/* Setup and post Tavor "WRITE_MTT" command */
19269e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info->mbi_in->mb_mapaddr;
19279e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
19289e39c5baSBill Taylor 	cmd.cp_inmod	= num_mtt;
19299e39c5baSBill Taylor 	cmd.cp_opcode	= WRITE_MTT;
19309e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
19319e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
19329e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
19339e39c5baSBill Taylor 
19349e39c5baSBill Taylor 	return (status);
19359e39c5baSBill Taylor }
19369e39c5baSBill Taylor 
19379e39c5baSBill Taylor 
19389e39c5baSBill Taylor /*
19399e39c5baSBill Taylor  * tavor_sync_tpt_cmd_post()
19409e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
19419e39c5baSBill Taylor  */
19429e39c5baSBill Taylor int
tavor_sync_tpt_cmd_post(tavor_state_t * state,uint_t sleepflag)19439e39c5baSBill Taylor tavor_sync_tpt_cmd_post(tavor_state_t *state, uint_t sleepflag)
19449e39c5baSBill Taylor {
19459e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
19469e39c5baSBill Taylor 	int			status;
19479e39c5baSBill Taylor 
19489e39c5baSBill Taylor 	/* Setup and post the Tavor "SYNC_TPT" command */
19499e39c5baSBill Taylor 	cmd.cp_inparm	= 0;
19509e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
19519e39c5baSBill Taylor 	cmd.cp_inmod	= 0;
19529e39c5baSBill Taylor 	cmd.cp_opcode	= SYNC_TPT;
19539e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
19549e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
19559e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
19569e39c5baSBill Taylor 
19579e39c5baSBill Taylor 	return (status);
19589e39c5baSBill Taylor }
19599e39c5baSBill Taylor 
19609e39c5baSBill Taylor /*
19619e39c5baSBill Taylor  * tavor_map_eq_cmd_post()
19629e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
19639e39c5baSBill Taylor  *    (Currently called only from attach() and/or detach() path contexts)
19649e39c5baSBill Taylor  */
19659e39c5baSBill Taylor int
tavor_map_eq_cmd_post(tavor_state_t * state,uint_t map,uint_t eqcindx,uint64_t eqmapmask,uint_t sleepflag)19669e39c5baSBill Taylor tavor_map_eq_cmd_post(tavor_state_t *state, uint_t map, uint_t eqcindx,
19679e39c5baSBill Taylor     uint64_t eqmapmask, uint_t sleepflag)
19689e39c5baSBill Taylor {
19699e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
19709e39c5baSBill Taylor 	int			status;
19719e39c5baSBill Taylor 
19729e39c5baSBill Taylor 	/* Setup and post Tavor "MAP_EQ" command */
19739e39c5baSBill Taylor 	cmd.cp_inparm	= eqmapmask;
19749e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
19759e39c5baSBill Taylor 	cmd.cp_inmod	= eqcindx;
19769e39c5baSBill Taylor 	if (map != TAVOR_CMD_MAP_EQ_EVT_MAP) {
19779e39c5baSBill Taylor 		cmd.cp_inmod |= TAVOR_CMD_UNMAP_EQ_MASK;
19789e39c5baSBill Taylor 	}
19799e39c5baSBill Taylor 	cmd.cp_opcode	= MAP_EQ;
19809e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
19819e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
19829e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
19839e39c5baSBill Taylor 
19849e39c5baSBill Taylor 	return (status);
19859e39c5baSBill Taylor }
19869e39c5baSBill Taylor 
19879e39c5baSBill Taylor 
19889e39c5baSBill Taylor /*
19899e39c5baSBill Taylor  * tavor_resize_cq_cmd_post()
19909e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
19919e39c5baSBill Taylor  */
19929e39c5baSBill Taylor int
tavor_resize_cq_cmd_post(tavor_state_t * state,tavor_hw_cqc_t * cqc,uint_t cqcindx,uint32_t * prod_indx,uint_t sleepflag)19939e39c5baSBill Taylor tavor_resize_cq_cmd_post(tavor_state_t *state, tavor_hw_cqc_t *cqc,
19949e39c5baSBill Taylor     uint_t cqcindx, uint32_t *prod_indx, uint_t sleepflag)
19959e39c5baSBill Taylor {
19969e39c5baSBill Taylor 	tavor_mbox_info_t	mbox_info;
19979e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
19989e39c5baSBill Taylor 	uint64_t		data;
19999e39c5baSBill Taylor 	uint_t			size;
20009e39c5baSBill Taylor 	int			status, i;
20019e39c5baSBill Taylor 
20029e39c5baSBill Taylor 	/* Get an "In" mailbox for the command */
20039e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
20049e39c5baSBill Taylor 	status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
20059e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
20069e39c5baSBill Taylor 		return (status);
20079e39c5baSBill Taylor 	}
20089e39c5baSBill Taylor 
20099e39c5baSBill Taylor 	/* Copy the Tavor "RESIZE_CQ" command into mailbox */
20109e39c5baSBill Taylor 	size = sizeof (tavor_hw_cqc_t);
20119e39c5baSBill Taylor 	for (i = 0; i < (size >> 3); i++) {
20129e39c5baSBill Taylor 		data = ((uint64_t *)cqc)[i];
20139e39c5baSBill Taylor 		ddi_put64(mbox_info.mbi_in->mb_acchdl,
20149e39c5baSBill Taylor 		    ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
20159e39c5baSBill Taylor 	}
20169e39c5baSBill Taylor 
20179e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
20189e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
20199e39c5baSBill Taylor 
20209e39c5baSBill Taylor 	/* Setup and post Tavor "RESIZE_CQ" command */
20219e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
20229e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
20239e39c5baSBill Taylor 	cmd.cp_inmod	= cqcindx;
20249e39c5baSBill Taylor 	cmd.cp_opcode	= RESIZE_CQ;
20259e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
20269e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
20279e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
20289e39c5baSBill Taylor 
20299e39c5baSBill Taylor 	/*
20309e39c5baSBill Taylor 	 * New "producer index" is returned in the upper 32 bits of
20319e39c5baSBill Taylor 	 * command "outparam"
20329e39c5baSBill Taylor 	 */
20339e39c5baSBill Taylor 	*prod_indx = (cmd.cp_outparm >> 32);
20349e39c5baSBill Taylor 
20359e39c5baSBill Taylor 	/* Free the mailbox */
20369e39c5baSBill Taylor 	tavor_mbox_free(state, &mbox_info);
20379e39c5baSBill Taylor 
20389e39c5baSBill Taylor 	return (status);
20399e39c5baSBill Taylor }
20409e39c5baSBill Taylor 
20419e39c5baSBill Taylor 
20429e39c5baSBill Taylor /*
20439e39c5baSBill Taylor  * tavor_cmn_qp_cmd_post()
20449e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
20459e39c5baSBill Taylor  *
20469e39c5baSBill Taylor  *    This is the common function for posting all the various types of
20479e39c5baSBill Taylor  *    QP state transition related Tavor commands.  Since some of the
20489e39c5baSBill Taylor  *    commands differ from the others in the number (and type) of arguments
20499e39c5baSBill Taylor  *    that each require, this routine does checks based on opcode type
20509e39c5baSBill Taylor  *    (explained in more detail below).
20519e39c5baSBill Taylor  *
20529e39c5baSBill Taylor  * Note: This common function should be used only with the following
20539e39c5baSBill Taylor  *    opcodes: RTS2SQD_QP, TOERR_QP, TORST_QP, RST2INIT_QP, INIT2INIT_QP,
20549e39c5baSBill Taylor  *    INIT2RTR_QP, RTR2RTS_QP, RTS2RTS_QP, SQD2RTS_QP, and SQERR2RTS_QP.
20559e39c5baSBill Taylor  */
20569e39c5baSBill Taylor int
tavor_cmn_qp_cmd_post(tavor_state_t * state,uint_t opcode,tavor_hw_qpc_t * qp,uint_t qpindx,uint32_t opmask,uint_t sleepflag)20579e39c5baSBill Taylor tavor_cmn_qp_cmd_post(tavor_state_t *state, uint_t opcode,
20589e39c5baSBill Taylor     tavor_hw_qpc_t *qp, uint_t qpindx, uint32_t opmask,
20599e39c5baSBill Taylor     uint_t sleepflag)
20609e39c5baSBill Taylor {
20619e39c5baSBill Taylor 	tavor_mbox_info_t	mbox_info;
20629e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
20639e39c5baSBill Taylor 	uint64_t		data, in_mapaddr, out_mapaddr;
20649e39c5baSBill Taylor 	uint_t			size, flags, opmod;
20659e39c5baSBill Taylor 	int			status, i;
20669e39c5baSBill Taylor 
20679e39c5baSBill Taylor 	/*
20689e39c5baSBill Taylor 	 * Use the specified opcode type to set the appropriate parameters.
20699e39c5baSBill Taylor 	 * Specifically, we need to set in_mapaddr, out_mapaddr, flags, and
20709e39c5baSBill Taylor 	 * opmod (as necessary).  Setting these parameters may also require
20719e39c5baSBill Taylor 	 * us to allocate an "In" or "Out" mailbox depending on the command
20729e39c5baSBill Taylor 	 * type.
20739e39c5baSBill Taylor 	 */
20749e39c5baSBill Taylor 	if (opcode == RTS2SQD_QP) {
20759e39c5baSBill Taylor 		/*
20769e39c5baSBill Taylor 		 * Note: For RTS-to-SendQueueDrain state transitions we
20779e39c5baSBill Taylor 		 * always want to request the event generation from the
20789e39c5baSBill Taylor 		 * hardware.  Though we may not notify the consumer of the
20799e39c5baSBill Taylor 		 * drained event, the decision to forward (or not) is made
20809e39c5baSBill Taylor 		 * later in the SQD event handler.
20819e39c5baSBill Taylor 		 */
20829e39c5baSBill Taylor 		flags = TAVOR_CMD_REQ_SQD_EVENT;
20839e39c5baSBill Taylor 
20849e39c5baSBill Taylor 		/*
20859e39c5baSBill Taylor 		 * The RTS2SQD_QP command uses no "In" or "Out" mailboxes (and
20869e39c5baSBill Taylor 		 * has no special opcode modifiers).
20879e39c5baSBill Taylor 		 */
20889e39c5baSBill Taylor 		in_mapaddr  = 0;
20899e39c5baSBill Taylor 		out_mapaddr = 0;
20909e39c5baSBill Taylor 		opmod = 0;
20919e39c5baSBill Taylor 
20929e39c5baSBill Taylor 	} else if (opcode == TOERR_QP) {
20939e39c5baSBill Taylor 		/*
20949e39c5baSBill Taylor 		 * The TOERR_QP command uses no "In" or "Out" mailboxes, has no
20959e39c5baSBill Taylor 		 * special opcode modifiers, and takes no special flags.
20969e39c5baSBill Taylor 		 */
20979e39c5baSBill Taylor 		in_mapaddr  = 0;
20989e39c5baSBill Taylor 		out_mapaddr = 0;
20999e39c5baSBill Taylor 		opmod = 0;
21009e39c5baSBill Taylor 		flags = 0;
21019e39c5baSBill Taylor 
21029e39c5baSBill Taylor 	} else if (opcode == TORST_QP) {
21039e39c5baSBill Taylor 		/*
21049e39c5baSBill Taylor 		 * The TORST_QP command could take an "Out" mailbox, but we do
21059e39c5baSBill Taylor 		 * not require it here.  It also does not takes any special
21069e39c5baSBill Taylor 		 * flags.  It does however, take a TAVOR_CMD_DIRECT_TO_RESET
21079e39c5baSBill Taylor 		 * opcode modifier, which indicates that the transition to
21089e39c5baSBill Taylor 		 * reset should happen without first moving the QP through the
21099e39c5baSBill Taylor 		 * Error state (and, hence, without generating any unnecessary
21109e39c5baSBill Taylor 		 * "flushed-in-error" completions).
21119e39c5baSBill Taylor 		 */
21129e39c5baSBill Taylor 		in_mapaddr  = 0;
21139e39c5baSBill Taylor 		out_mapaddr = 0;
21149e39c5baSBill Taylor 		opmod = TAVOR_CMD_DIRECT_TO_RESET | TAVOR_CMD_NO_OUTMBOX;
21159e39c5baSBill Taylor 		flags = 0;
21169e39c5baSBill Taylor 
21179e39c5baSBill Taylor 	} else {
21189e39c5baSBill Taylor 		/*
21199e39c5baSBill Taylor 		 * All the other QP state transition commands (RST2INIT_QP,
21209e39c5baSBill Taylor 		 * INIT2INIT_QP, INIT2RTR_QP, RTR2RTS_QP, RTS2RTS_QP,
21219e39c5baSBill Taylor 		 * SQD2RTS_QP, and SQERR2RTS_QP) require an "In" mailbox.
21229e39c5baSBill Taylor 		 * None of these require any special flags or opcode modifiers.
21239e39c5baSBill Taylor 		 */
21249e39c5baSBill Taylor 		mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
21259e39c5baSBill Taylor 		status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
21269e39c5baSBill Taylor 		if (status != TAVOR_CMD_SUCCESS) {
21279e39c5baSBill Taylor 			return (status);
21289e39c5baSBill Taylor 		}
21299e39c5baSBill Taylor 		in_mapaddr  = mbox_info.mbi_in->mb_mapaddr;
21309e39c5baSBill Taylor 		out_mapaddr = 0;
21319e39c5baSBill Taylor 		flags = 0;
21329e39c5baSBill Taylor 		opmod = 0;
21339e39c5baSBill Taylor 
21349e39c5baSBill Taylor 		/* Copy the Tavor command into the "In" mailbox */
21359e39c5baSBill Taylor 		size = sizeof (tavor_hw_qpc_t);
21369e39c5baSBill Taylor 		for (i = 0; i < (size >> 3); i++) {
21379e39c5baSBill Taylor 			data = ((uint64_t *)qp)[i];
21389e39c5baSBill Taylor 			ddi_put64(mbox_info.mbi_in->mb_acchdl,
21399e39c5baSBill Taylor 			    ((uint64_t *)mbox_info.mbi_in->mb_addr + i + 1),
21409e39c5baSBill Taylor 			    data);
21419e39c5baSBill Taylor 		}
21429e39c5baSBill Taylor 		ddi_put32(mbox_info.mbi_in->mb_acchdl,
21439e39c5baSBill Taylor 		    ((uint32_t *)mbox_info.mbi_in->mb_addr), opmask);
21449e39c5baSBill Taylor 
21459e39c5baSBill Taylor 		/*
21469e39c5baSBill Taylor 		 * Sync the mailbox for the device to read.  We have to add
21479e39c5baSBill Taylor 		 * eight bytes here to account for "opt_param_mask" and
21489e39c5baSBill Taylor 		 * proper alignment.
21499e39c5baSBill Taylor 		 */
21509e39c5baSBill Taylor 		tavor_mbox_sync(mbox_info.mbi_in, 0, size + 8,
21519e39c5baSBill Taylor 		    DDI_DMA_SYNC_FORDEV);
21529e39c5baSBill Taylor 	}
21539e39c5baSBill Taylor 
21549e39c5baSBill Taylor 	/* Setup and post Tavor QP state transition command */
21559e39c5baSBill Taylor 	cmd.cp_inparm	= in_mapaddr;
21569e39c5baSBill Taylor 	cmd.cp_outparm	= out_mapaddr;
21579e39c5baSBill Taylor 	cmd.cp_inmod	= qpindx | flags;
21589e39c5baSBill Taylor 	cmd.cp_opcode	= opcode;
21599e39c5baSBill Taylor 	cmd.cp_opmod	= opmod;
21609e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
21619e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
21629e39c5baSBill Taylor 
21639e39c5baSBill Taylor 	/*
21649e39c5baSBill Taylor 	 * If we allocated a mailbox (either an "In" or an "Out") above,
21659e39c5baSBill Taylor 	 * then free it now before returning.
21669e39c5baSBill Taylor 	 */
21679e39c5baSBill Taylor 	if ((opcode != RTS2SQD_QP) && (opcode != TOERR_QP) &&
21689e39c5baSBill Taylor 	    (opcode != TORST_QP)) {
21699e39c5baSBill Taylor 		/* Free the mailbox */
21709e39c5baSBill Taylor 		tavor_mbox_free(state, &mbox_info);
21719e39c5baSBill Taylor 	}
21729e39c5baSBill Taylor 
21739e39c5baSBill Taylor 	return (status);
21749e39c5baSBill Taylor }
21759e39c5baSBill Taylor 
21769e39c5baSBill Taylor 
21779e39c5baSBill Taylor /*
21789e39c5baSBill Taylor  * tavor_cmn_query_cmd_post()
21799e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
21809e39c5baSBill Taylor  *
21819e39c5baSBill Taylor  *    This is the common function for posting all the various types of
21829e39c5baSBill Taylor  *    Tavor query commands.  All Tavor query commands require an "Out"
21839e39c5baSBill Taylor  *    mailbox to be allocated for the resulting queried data.
21849e39c5baSBill Taylor  *
21859e39c5baSBill Taylor  * Note: This common function should be used only with the following
21869e39c5baSBill Taylor  *    opcodes: QUERY_DEV_LIM, QUERY_FW, QUERY_DDR, QUERY_ADAPTER,
21879e39c5baSBill Taylor  *     QUERY_HCA, QUERY_MPT, QUERY_EQ, QUERY_CQ, and QUERY_QP.
21889e39c5baSBill Taylor  */
21899e39c5baSBill Taylor int
tavor_cmn_query_cmd_post(tavor_state_t * state,uint_t opcode,uint_t queryindx,void * query,uint_t size,uint_t sleepflag)21909e39c5baSBill Taylor tavor_cmn_query_cmd_post(tavor_state_t *state, uint_t opcode,
21919e39c5baSBill Taylor     uint_t queryindx, void *query, uint_t size, uint_t sleepflag)
21929e39c5baSBill Taylor {
21939e39c5baSBill Taylor 	tavor_mbox_info_t	mbox_info;
21949e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
21959e39c5baSBill Taylor 	uint64_t		data;
21969e39c5baSBill Taylor 	uint_t			offset;
21979e39c5baSBill Taylor 	int			status, i;
21989e39c5baSBill Taylor 
21999e39c5baSBill Taylor 	/* Get an "Out" mailbox for the command */
22009e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = TAVOR_ALLOC_OUTMBOX;
22019e39c5baSBill Taylor 	status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
22029e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
22039e39c5baSBill Taylor 		return (status);
22049e39c5baSBill Taylor 	}
22059e39c5baSBill Taylor 
22069e39c5baSBill Taylor 	/* Setup and post the Tavor query command */
22079e39c5baSBill Taylor 	cmd.cp_inparm	= 0;
22089e39c5baSBill Taylor 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
22099e39c5baSBill Taylor 	cmd.cp_inmod	= queryindx;
22109e39c5baSBill Taylor 	cmd.cp_opcode	= opcode;
22119e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
22129e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
22139e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
22149e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
22159e39c5baSBill Taylor 		goto cmn_query_fail;
22169e39c5baSBill Taylor 	}
22179e39c5baSBill Taylor 
22189e39c5baSBill Taylor 	/* Sync the mailbox to read the results */
22199e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
22209e39c5baSBill Taylor 
22219e39c5baSBill Taylor 	/*
22229e39c5baSBill Taylor 	 * QUERY_QP is handled somewhat differently than the other query
22239e39c5baSBill Taylor 	 * commands.  For QUERY_QP, the actual queried data is offset into
22249e39c5baSBill Taylor 	 * the mailbox (by one 64-bit word).
22259e39c5baSBill Taylor 	 */
22269e39c5baSBill Taylor 	offset = (opcode == QUERY_QP) ? 1 : 0;
22279e39c5baSBill Taylor 
22289e39c5baSBill Taylor 	/* Copy query command results into "query" */
22299e39c5baSBill Taylor 	for (i = 0; i < (size >> 3); i++) {
22309e39c5baSBill Taylor 		data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
22319e39c5baSBill Taylor 		    ((uint64_t *)mbox_info.mbi_out->mb_addr + i + offset));
22329e39c5baSBill Taylor 		((uint64_t *)query)[i] = data;
22339e39c5baSBill Taylor 	}
22349e39c5baSBill Taylor 
22359e39c5baSBill Taylor cmn_query_fail:
22369e39c5baSBill Taylor 	/* Free the mailbox */
22379e39c5baSBill Taylor 	tavor_mbox_free(state, &mbox_info);
22389e39c5baSBill Taylor 
22399e39c5baSBill Taylor 	return (status);
22409e39c5baSBill Taylor }
22419e39c5baSBill Taylor 
22429e39c5baSBill Taylor 
22439e39c5baSBill Taylor /*
22449e39c5baSBill Taylor  * tavor_cmn_ownership_cmd_post()
22459e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
22469e39c5baSBill Taylor  *
22479e39c5baSBill Taylor  *    This is the common function for posting all the various types of
22489e39c5baSBill Taylor  *    Tavor HW/SW resource ownership commands.  Since some of the commands
22499e39c5baSBill Taylor  *    differ from the others in the direction of ownership change (i.e.
22509e39c5baSBill Taylor  *    from HW ownership to SW, or vice versa), they differ in the type of
22519e39c5baSBill Taylor  *    mailbox and specific handling that each requires.  This routine does
22529e39c5baSBill Taylor  *    certain checks based on opcode type to determine the direction of
22539e39c5baSBill Taylor  *    the transition and to correctly handle the request.
22549e39c5baSBill Taylor  *
22559e39c5baSBill Taylor  * Note: This common function should be used only with the following
22569e39c5baSBill Taylor  *    opcodes: HW2SW_MPT, HW2SW_EQ, HW2SW_CQ, SW2HW_MPT, SW2HW_EQ, and
22579e39c5baSBill Taylor  *    SW2HW_CQ
22589e39c5baSBill Taylor  */
22599e39c5baSBill Taylor int
tavor_cmn_ownership_cmd_post(tavor_state_t * state,uint_t opcode,void * hwrsrc,uint_t size,uint_t hwrsrcindx,uint_t sleepflag)22609e39c5baSBill Taylor tavor_cmn_ownership_cmd_post(tavor_state_t *state, uint_t opcode,
22619e39c5baSBill Taylor     void *hwrsrc, uint_t size, uint_t hwrsrcindx, uint_t sleepflag)
22629e39c5baSBill Taylor {
22639e39c5baSBill Taylor 	tavor_mbox_info_t	mbox_info;
22649e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
22659e39c5baSBill Taylor 	uint64_t		data, in_mapaddr, out_mapaddr;
22669e39c5baSBill Taylor 	uint_t			direction, opmod;
22679e39c5baSBill Taylor 	int			status, i;
22689e39c5baSBill Taylor 
22699e39c5baSBill Taylor 	/*
22709e39c5baSBill Taylor 	 * Determine the direction of the ownership transfer based on the
22719e39c5baSBill Taylor 	 * provided opcode
22729e39c5baSBill Taylor 	 */
22739e39c5baSBill Taylor 	if ((opcode == HW2SW_MPT) || (opcode == HW2SW_EQ) ||
22749e39c5baSBill Taylor 	    (opcode == HW2SW_CQ) || (opcode == HW2SW_SRQ)) {
22759e39c5baSBill Taylor 		direction = TAVOR_CMD_RSRC_HW2SW;
22769e39c5baSBill Taylor 
22779e39c5baSBill Taylor 	} else if ((opcode == SW2HW_MPT) || (opcode == SW2HW_EQ) ||
22789e39c5baSBill Taylor 	    (opcode == SW2HW_CQ) || (opcode == SW2HW_SRQ)) {
22799e39c5baSBill Taylor 		direction = TAVOR_CMD_RSRC_SW2HW;
22809e39c5baSBill Taylor 
22819e39c5baSBill Taylor 	} else {
22829e39c5baSBill Taylor 		return (TAVOR_CMD_INVALID_STATUS);
22839e39c5baSBill Taylor 	}
22849e39c5baSBill Taylor 
22859e39c5baSBill Taylor 	/*
22869e39c5baSBill Taylor 	 * If hwrsrc is NULL then we do not allocate a mailbox.  This is used
22879e39c5baSBill Taylor 	 * in the case of memory deregister where the out mailbox is not
22889e39c5baSBill Taylor 	 * needed.  In the case of re-register, we do use the hwrsrc.
22899e39c5baSBill Taylor 	 *
22909e39c5baSBill Taylor 	 * Otherwise, If ownership transfer is going from hardware to software,
22919e39c5baSBill Taylor 	 * then allocate an "Out" mailbox.  This will be filled in later as a
22929e39c5baSBill Taylor 	 * result of the Tavor command.
22939e39c5baSBill Taylor 	 *
22949e39c5baSBill Taylor 	 * And if the ownership transfer is going from software to hardware,
22959e39c5baSBill Taylor 	 * then we need an "In" mailbox, and we need to fill it in and sync it
22969e39c5baSBill Taylor 	 * (if necessary).  Then the mailbox can be passed to the Tavor
22979e39c5baSBill Taylor 	 * firmware.
22989e39c5baSBill Taylor 	 *
22999e39c5baSBill Taylor 	 * For the HW2SW (dereg) case, we only use an out mbox if hwrsrc is !=
23009e39c5baSBill Taylor 	 * NULL.  This implies a re-reg, and the out mbox must be used.  If
23019e39c5baSBill Taylor 	 * hwrsrc is == NULL, then we can save some time and resources by not
23029e39c5baSBill Taylor 	 * using an out mbox at all.  We must set opmod to TAVOR_CMD_DO_OUTMBOX
23039e39c5baSBill Taylor 	 * and TAVOR_CMD_NO_OUTMBOX appropriately in this case.
23049e39c5baSBill Taylor 	 *
23059e39c5baSBill Taylor 	 * For the SW2HW (reg) case, no out mbox is possible.  We set opmod to
23069e39c5baSBill Taylor 	 * 0 anyway, but this field is not used in this case.
23079e39c5baSBill Taylor 	 */
23089e39c5baSBill Taylor 	if (direction == TAVOR_CMD_RSRC_HW2SW) {
23099e39c5baSBill Taylor 		if (hwrsrc != NULL) {
23109e39c5baSBill Taylor 			mbox_info.mbi_alloc_flags = TAVOR_ALLOC_OUTMBOX;
23119e39c5baSBill Taylor 			status = tavor_mbox_alloc(state, &mbox_info,
23129e39c5baSBill Taylor 			    sleepflag);
23139e39c5baSBill Taylor 			if (status != TAVOR_CMD_SUCCESS) {
23149e39c5baSBill Taylor 				return (status);
23159e39c5baSBill Taylor 			}
23169e39c5baSBill Taylor 			in_mapaddr  = 0;
23179e39c5baSBill Taylor 			out_mapaddr = mbox_info.mbi_out->mb_mapaddr;
23189e39c5baSBill Taylor 			opmod = TAVOR_CMD_DO_OUTMBOX;
23199e39c5baSBill Taylor 		} else {
23209e39c5baSBill Taylor 			in_mapaddr = 0;
23219e39c5baSBill Taylor 			out_mapaddr = 0;
23229e39c5baSBill Taylor 			opmod = TAVOR_CMD_NO_OUTMBOX;
23239e39c5baSBill Taylor 		}
23249e39c5baSBill Taylor 	} else {  /* TAVOR_CMD_RSRC_SW2HW */
23259e39c5baSBill Taylor 		mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
23269e39c5baSBill Taylor 		status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
23279e39c5baSBill Taylor 		if (status != TAVOR_CMD_SUCCESS) {
23289e39c5baSBill Taylor 			return (status);
23299e39c5baSBill Taylor 		}
23309e39c5baSBill Taylor 
23319e39c5baSBill Taylor 		/* Copy the SW2HW ownership command into mailbox */
23329e39c5baSBill Taylor 		for (i = 0; i < (size >> 3); i++) {
23339e39c5baSBill Taylor 			data = ((uint64_t *)hwrsrc)[i];
23349e39c5baSBill Taylor 			ddi_put64(mbox_info.mbi_in->mb_acchdl,
23359e39c5baSBill Taylor 			    ((uint64_t *)mbox_info.mbi_in->mb_addr + i),
23369e39c5baSBill Taylor 			    data);
23379e39c5baSBill Taylor 		}
23389e39c5baSBill Taylor 
23399e39c5baSBill Taylor 		/* Sync the mailbox for the device to read */
23409e39c5baSBill Taylor 		tavor_mbox_sync(mbox_info.mbi_in, 0, size,
23419e39c5baSBill Taylor 		    DDI_DMA_SYNC_FORDEV);
23429e39c5baSBill Taylor 
23439e39c5baSBill Taylor 		in_mapaddr  = mbox_info.mbi_in->mb_mapaddr;
23449e39c5baSBill Taylor 		out_mapaddr = 0;
23459e39c5baSBill Taylor 		opmod = 0;
23469e39c5baSBill Taylor 	}
23479e39c5baSBill Taylor 
23489e39c5baSBill Taylor 
23499e39c5baSBill Taylor 	/* Setup and post the Tavor ownership command */
23509e39c5baSBill Taylor 	cmd.cp_inparm	= in_mapaddr;
23519e39c5baSBill Taylor 	cmd.cp_outparm	= out_mapaddr;
23529e39c5baSBill Taylor 	cmd.cp_inmod	= hwrsrcindx;
23539e39c5baSBill Taylor 	cmd.cp_opcode	= opcode;
23549e39c5baSBill Taylor 	cmd.cp_opmod	= opmod;
23559e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
23569e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
23579e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
23589e39c5baSBill Taylor 		goto cmn_ownership_fail;
23599e39c5baSBill Taylor 	}
23609e39c5baSBill Taylor 
23619e39c5baSBill Taylor 	/*
23629e39c5baSBill Taylor 	 * As mentioned above, for HW2SW ownership transfers we need to
23639e39c5baSBill Taylor 	 * sync (if necessary) and copy out the resulting data from the
23649e39c5baSBill Taylor 	 * "Out" mailbox" (assuming the above command was successful).
23659e39c5baSBill Taylor 	 */
23669e39c5baSBill Taylor 	if (direction == TAVOR_CMD_RSRC_HW2SW && hwrsrc != NULL) {
23679e39c5baSBill Taylor 		/* Sync the mailbox to read the results */
23689e39c5baSBill Taylor 		tavor_mbox_sync(mbox_info.mbi_out, 0, size,
23699e39c5baSBill Taylor 		    DDI_DMA_SYNC_FORCPU);
23709e39c5baSBill Taylor 
23719e39c5baSBill Taylor 		/* Copy HW2SW ownership command results into "hwrsrc" */
23729e39c5baSBill Taylor 		for (i = 0; i < (size >> 3); i++) {
23739e39c5baSBill Taylor 			data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
23749e39c5baSBill Taylor 			    ((uint64_t *)mbox_info.mbi_out->mb_addr + i));
23759e39c5baSBill Taylor 			((uint64_t *)hwrsrc)[i] = data;
23769e39c5baSBill Taylor 		}
23779e39c5baSBill Taylor 	}
23789e39c5baSBill Taylor 
23799e39c5baSBill Taylor cmn_ownership_fail:
23809e39c5baSBill Taylor 	if (hwrsrc != NULL) {
23819e39c5baSBill Taylor 		/* Free the mailbox */
23829e39c5baSBill Taylor 		tavor_mbox_free(state, &mbox_info);
23839e39c5baSBill Taylor 	}
23849e39c5baSBill Taylor 
23859e39c5baSBill Taylor 	return (status);
23869e39c5baSBill Taylor }
23879e39c5baSBill Taylor 
23889e39c5baSBill Taylor 
23899e39c5baSBill Taylor /*
23909e39c5baSBill Taylor  * tavor_conf_special_qp_cmd_post()
23919e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
23929e39c5baSBill Taylor  */
23939e39c5baSBill Taylor int
tavor_conf_special_qp_cmd_post(tavor_state_t * state,uint_t qpindx,uint_t qptype,uint_t sleepflag)23949e39c5baSBill Taylor tavor_conf_special_qp_cmd_post(tavor_state_t *state, uint_t qpindx,
23959e39c5baSBill Taylor     uint_t qptype, uint_t sleepflag)
23969e39c5baSBill Taylor {
23979e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
23989e39c5baSBill Taylor 	int			status;
23999e39c5baSBill Taylor 
24009e39c5baSBill Taylor 	/* Setup and post Tavor "CONF_SPECIAL_QP" command */
24019e39c5baSBill Taylor 	cmd.cp_inparm	= 0;
24029e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
24039e39c5baSBill Taylor 	cmd.cp_inmod	= qpindx;
24049e39c5baSBill Taylor 	cmd.cp_opcode	= CONF_SPECIAL_QP;
24059e39c5baSBill Taylor 	cmd.cp_opmod	= qptype;
24069e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
24079e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
24089e39c5baSBill Taylor 
24099e39c5baSBill Taylor 	return (status);
24109e39c5baSBill Taylor }
24119e39c5baSBill Taylor 
24129e39c5baSBill Taylor 
24139e39c5baSBill Taylor /*
24149e39c5baSBill Taylor  * tavor_mgid_hash_cmd_post()
24159e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
24169e39c5baSBill Taylor  */
24179e39c5baSBill Taylor int
tavor_mgid_hash_cmd_post(tavor_state_t * state,uint64_t mgid_h,uint64_t mgid_l,uint64_t * mgid_hash,uint_t sleepflag)24189e39c5baSBill Taylor tavor_mgid_hash_cmd_post(tavor_state_t *state, uint64_t mgid_h,
24199e39c5baSBill Taylor     uint64_t mgid_l, uint64_t *mgid_hash, uint_t sleepflag)
24209e39c5baSBill Taylor {
24219e39c5baSBill Taylor 	tavor_mbox_info_t	mbox_info;
24229e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
24239e39c5baSBill Taylor 	int			status;
24249e39c5baSBill Taylor 
24259e39c5baSBill Taylor 	/* Get an "In" mailbox for the command */
24269e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
24279e39c5baSBill Taylor 	status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
24289e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
24299e39c5baSBill Taylor 		return (status);
24309e39c5baSBill Taylor 	}
24319e39c5baSBill Taylor 
24329e39c5baSBill Taylor 	/* Copy the Tavor "MGID_HASH" command into mailbox */
24339e39c5baSBill Taylor 	ddi_put64(mbox_info.mbi_in->mb_acchdl,
24349e39c5baSBill Taylor 	    ((uint64_t *)mbox_info.mbi_in->mb_addr + 0), mgid_h);
24359e39c5baSBill Taylor 	ddi_put64(mbox_info.mbi_in->mb_acchdl,
24369e39c5baSBill Taylor 	    ((uint64_t *)mbox_info.mbi_in->mb_addr + 1), mgid_l);
24379e39c5baSBill Taylor 
24389e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
24399e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_in, 0, TAVOR_CMD_MGIDHASH_SZ,
24409e39c5baSBill Taylor 	    DDI_DMA_SYNC_FORDEV);
24419e39c5baSBill Taylor 
24429e39c5baSBill Taylor 	/* Setup and post the Tavor "MGID_HASH" command */
24439e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
24449e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
24459e39c5baSBill Taylor 	cmd.cp_inmod	= 0;
24469e39c5baSBill Taylor 	cmd.cp_opcode	= MGID_HASH;
24479e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
24489e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
24499e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
24509e39c5baSBill Taylor 
24519e39c5baSBill Taylor 	/* MGID hash value is returned in command "outparam" */
24529e39c5baSBill Taylor 	*mgid_hash = cmd.cp_outparm;
24539e39c5baSBill Taylor 
24549e39c5baSBill Taylor 	/* Free the mailbox */
24559e39c5baSBill Taylor 	tavor_mbox_free(state, &mbox_info);
24569e39c5baSBill Taylor 
24579e39c5baSBill Taylor 	return (status);
24589e39c5baSBill Taylor }
24599e39c5baSBill Taylor 
24609e39c5baSBill Taylor 
24619e39c5baSBill Taylor /*
24629e39c5baSBill Taylor  * tavor_read_mgm_cmd_post()
24639e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
24649e39c5baSBill Taylor  *
24659e39c5baSBill Taylor  * Note: It is assumed that the "mcg" parameter is actually a pointer to a
24669e39c5baSBill Taylor  *    "tavor_hw_mcg_t" struct and some number of "tavor_hw_mcg_qp_list_t"
24679e39c5baSBill Taylor  *    structs.  Combined size should be equal to result of TAVOR_MCGMEM_SZ()
24689e39c5baSBill Taylor  *    macro.
24699e39c5baSBill Taylor  */
24709e39c5baSBill Taylor int
tavor_read_mgm_cmd_post(tavor_state_t * state,tavor_hw_mcg_t * mcg,uint_t mcgindx,uint_t sleepflag)24719e39c5baSBill Taylor tavor_read_mgm_cmd_post(tavor_state_t *state, tavor_hw_mcg_t *mcg,
24729e39c5baSBill Taylor     uint_t mcgindx, uint_t sleepflag)
24739e39c5baSBill Taylor {
24749e39c5baSBill Taylor 	tavor_mbox_info_t	mbox_info;
24759e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
24769e39c5baSBill Taylor 	uint64_t		data;
24779e39c5baSBill Taylor 	uint_t			size, hdrsz, qplistsz;
24789e39c5baSBill Taylor 	int			status, i;
24799e39c5baSBill Taylor 
24809e39c5baSBill Taylor 	/* Get an "Out" mailbox for the results */
24819e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = TAVOR_ALLOC_OUTMBOX;
24829e39c5baSBill Taylor 	status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
24839e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
24849e39c5baSBill Taylor 		return (status);
24859e39c5baSBill Taylor 	}
24869e39c5baSBill Taylor 
24879e39c5baSBill Taylor 	/* Setup and post Tavor "READ_MGM" command */
24889e39c5baSBill Taylor 	cmd.cp_inparm	= 0;
24899e39c5baSBill Taylor 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
24909e39c5baSBill Taylor 	cmd.cp_inmod	= mcgindx;
24919e39c5baSBill Taylor 	cmd.cp_opcode	= READ_MGM;
24929e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
24939e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
24949e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
24959e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
24969e39c5baSBill Taylor 		goto read_mgm_fail;
24979e39c5baSBill Taylor 	}
24989e39c5baSBill Taylor 
24999e39c5baSBill Taylor 	/* Sync the mailbox to read the results */
25009e39c5baSBill Taylor 	size = TAVOR_MCGMEM_SZ(state);
25019e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
25029e39c5baSBill Taylor 
25039e39c5baSBill Taylor 	/* Copy the READ_MGM command results into "mcg" */
25049e39c5baSBill Taylor 	hdrsz = sizeof (tavor_hw_mcg_t);
25059e39c5baSBill Taylor 	for (i = 0; i < (hdrsz >> 3); i++) {
25069e39c5baSBill Taylor 		data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
25079e39c5baSBill Taylor 		    ((uint64_t *)mbox_info.mbi_out->mb_addr + i));
25089e39c5baSBill Taylor 		((uint64_t *)mcg)[i] = data;
25099e39c5baSBill Taylor 	}
25109e39c5baSBill Taylor 	qplistsz = size - hdrsz;
25119e39c5baSBill Taylor 	for (i = 0; i < (qplistsz >> 2); i++) {
25129e39c5baSBill Taylor 		data = ddi_get32(mbox_info.mbi_out->mb_acchdl,
25139e39c5baSBill Taylor 		    ((uint32_t *)mbox_info.mbi_out->mb_addr + i + 8));
25149e39c5baSBill Taylor 		((uint32_t *)mcg)[i + 8] = data;
25159e39c5baSBill Taylor 	}
25169e39c5baSBill Taylor 
25179e39c5baSBill Taylor read_mgm_fail:
25189e39c5baSBill Taylor 	/* Free the mailbox */
25199e39c5baSBill Taylor 	tavor_mbox_free(state, &mbox_info);
25209e39c5baSBill Taylor 
25219e39c5baSBill Taylor 	return (status);
25229e39c5baSBill Taylor }
25239e39c5baSBill Taylor 
25249e39c5baSBill Taylor 
25259e39c5baSBill Taylor /*
25269e39c5baSBill Taylor  * tavor_write_mgm_cmd_post()
25279e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
25289e39c5baSBill Taylor  *
25299e39c5baSBill Taylor  * Note: It is assumed that the "mcg" parameter is actually a pointer to a
25309e39c5baSBill Taylor  *    "tavor_hw_mcg_t" struct and some number of "tavor_hw_mcg_qp_list_t"
25319e39c5baSBill Taylor  *    structs.  Combined size should be equal to result of TAVOR_MCGMEM_SZ()
25329e39c5baSBill Taylor  *    macro.
25339e39c5baSBill Taylor  */
25349e39c5baSBill Taylor int
tavor_write_mgm_cmd_post(tavor_state_t * state,tavor_hw_mcg_t * mcg,uint_t mcgindx,uint_t sleepflag)25359e39c5baSBill Taylor tavor_write_mgm_cmd_post(tavor_state_t *state, tavor_hw_mcg_t *mcg,
25369e39c5baSBill Taylor     uint_t mcgindx, uint_t sleepflag)
25379e39c5baSBill Taylor {
25389e39c5baSBill Taylor 	tavor_mbox_info_t	mbox_info;
25399e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
25409e39c5baSBill Taylor 	uint64_t		data;
25419e39c5baSBill Taylor 	uint_t			size, hdrsz, qplistsz;
25429e39c5baSBill Taylor 	int			status, i;
25439e39c5baSBill Taylor 
25449e39c5baSBill Taylor 	/* Get an "In" mailbox for the command */
25459e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
25469e39c5baSBill Taylor 	status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
25479e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
25489e39c5baSBill Taylor 		return (status);
25499e39c5baSBill Taylor 	}
25509e39c5baSBill Taylor 
25519e39c5baSBill Taylor 	/* Copy the Tavor "WRITE_MGM" command into mailbox */
25529e39c5baSBill Taylor 	size  = TAVOR_MCGMEM_SZ(state);
25539e39c5baSBill Taylor 	hdrsz = sizeof (tavor_hw_mcg_t);
25549e39c5baSBill Taylor 	for (i = 0; i < (hdrsz >> 3); i++) {
25559e39c5baSBill Taylor 		data = ((uint64_t *)mcg)[i];
25569e39c5baSBill Taylor 		ddi_put64(mbox_info.mbi_in->mb_acchdl,
25579e39c5baSBill Taylor 		    ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
25589e39c5baSBill Taylor 	}
25599e39c5baSBill Taylor 	qplistsz = size - hdrsz;
25609e39c5baSBill Taylor 	for (i = 0; i < (qplistsz >> 2); i++) {
25619e39c5baSBill Taylor 		data = ((uint32_t *)mcg)[i + 8];
25629e39c5baSBill Taylor 		ddi_put32(mbox_info.mbi_in->mb_acchdl,
25639e39c5baSBill Taylor 		    ((uint32_t *)mbox_info.mbi_in->mb_addr + i + 8), data);
25649e39c5baSBill Taylor 	}
25659e39c5baSBill Taylor 
25669e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
25679e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
25689e39c5baSBill Taylor 
25699e39c5baSBill Taylor 	/* Setup and post Tavor "WRITE_MGM" command */
25709e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
25719e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
25729e39c5baSBill Taylor 	cmd.cp_inmod	= mcgindx;
25739e39c5baSBill Taylor 	cmd.cp_opcode	= WRITE_MGM;
25749e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
25759e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
25769e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
25779e39c5baSBill Taylor 
25789e39c5baSBill Taylor 	/* Free the mailbox */
25799e39c5baSBill Taylor 	tavor_mbox_free(state, &mbox_info);
25809e39c5baSBill Taylor 
25819e39c5baSBill Taylor 	return (status);
25829e39c5baSBill Taylor 
25839e39c5baSBill Taylor }
25849e39c5baSBill Taylor 
25859e39c5baSBill Taylor 
25869e39c5baSBill Taylor /*
25879e39c5baSBill Taylor  * tavor_modify_mpt_cmd_post()
25889e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
25899e39c5baSBill Taylor  */
25909e39c5baSBill Taylor int
tavor_modify_mpt_cmd_post(tavor_state_t * state,tavor_hw_mpt_t * mpt,uint_t mptindx,uint_t flags,uint_t sleepflag)25919e39c5baSBill Taylor tavor_modify_mpt_cmd_post(tavor_state_t *state, tavor_hw_mpt_t *mpt,
25929e39c5baSBill Taylor     uint_t mptindx, uint_t flags, uint_t sleepflag)
25939e39c5baSBill Taylor {
25949e39c5baSBill Taylor 	tavor_mbox_info_t	mbox_info;
25959e39c5baSBill Taylor 	tavor_cmd_post_t	cmd;
25969e39c5baSBill Taylor 	uint64_t		data;
25979e39c5baSBill Taylor 	uint_t			size;
25989e39c5baSBill Taylor 	int			status, i;
25999e39c5baSBill Taylor 
26009e39c5baSBill Taylor 	/* Get an "In" mailbox for the command */
26019e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
26029e39c5baSBill Taylor 	status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
26039e39c5baSBill Taylor 	if (status != TAVOR_CMD_SUCCESS) {
26049e39c5baSBill Taylor 		return (status);
26059e39c5baSBill Taylor 	}
26069e39c5baSBill Taylor 
26079e39c5baSBill Taylor 	/* Copy the Tavor "MODIFY_MPT" command into mailbox */
26089e39c5baSBill Taylor 	size = sizeof (tavor_hw_mpt_t);
26099e39c5baSBill Taylor 	for (i = 0; i < (size >> 3); i++) {
26109e39c5baSBill Taylor 		data = ((uint64_t *)mpt)[i];
26119e39c5baSBill Taylor 		ddi_put64(mbox_info.mbi_in->mb_acchdl,
26129e39c5baSBill Taylor 		    ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
26139e39c5baSBill Taylor 	}
26149e39c5baSBill Taylor 
26159e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
26169e39c5baSBill Taylor 	tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
26179e39c5baSBill Taylor 
26189e39c5baSBill Taylor 	/* Setup and post Tavor "MODIFY_MPT" command */
26199e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
26209e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
26219e39c5baSBill Taylor 	cmd.cp_inmod	= mptindx;
26229e39c5baSBill Taylor 	cmd.cp_opcode	= MODIFY_MPT;
26239e39c5baSBill Taylor 	cmd.cp_opmod	= flags;
26249e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
26259e39c5baSBill Taylor 	status = tavor_cmd_post(state, &cmd);
26269e39c5baSBill Taylor 
26279e39c5baSBill Taylor 	/* Free the mailbox */
26289e39c5baSBill Taylor 	tavor_mbox_free(state, &mbox_info);
26299e39c5baSBill Taylor 
26309e39c5baSBill Taylor 	return (status);
26319e39c5baSBill Taylor }
2632e9dc6bffSRamaswamy Tummala 
2633e9dc6bffSRamaswamy Tummala /*
2634e9dc6bffSRamaswamy Tummala  * tavor_getpefcntr_cmd_post()
2635e9dc6bffSRamaswamy Tummala  *    Context: Can be called from interrupt or base context.
2636e9dc6bffSRamaswamy Tummala  *
2637e9dc6bffSRamaswamy Tummala  * If reset is zero, read the performance counters of the specified port and
2638e9dc6bffSRamaswamy Tummala  * copy them into perfinfo.
2639e9dc6bffSRamaswamy Tummala  * If reset is non-zero reset the performance counters of the specified port.
2640e9dc6bffSRamaswamy Tummala  */
2641e9dc6bffSRamaswamy Tummala int
tavor_getperfcntr_cmd_post(tavor_state_t * state,uint_t port,uint_t sleepflag,tavor_hw_sm_perfcntr_t * perfinfo,int reset)2642e9dc6bffSRamaswamy Tummala tavor_getperfcntr_cmd_post(tavor_state_t *state, uint_t port,
2643e9dc6bffSRamaswamy Tummala     uint_t sleepflag, tavor_hw_sm_perfcntr_t *perfinfo, int reset)
2644e9dc6bffSRamaswamy Tummala {
2645e9dc6bffSRamaswamy Tummala 	tavor_mbox_info_t	mbox_info;
2646e9dc6bffSRamaswamy Tummala 	tavor_cmd_post_t	cmd;
2647e9dc6bffSRamaswamy Tummala 	uint64_t		data;
2648e9dc6bffSRamaswamy Tummala 	uint32_t		*mbox;
2649e9dc6bffSRamaswamy Tummala 	uint_t			size;
2650e9dc6bffSRamaswamy Tummala 	int			status, i;
2651e9dc6bffSRamaswamy Tummala 
2652e9dc6bffSRamaswamy Tummala 	bzero((void *)&cmd, sizeof (tavor_cmd_post_t));
2653e9dc6bffSRamaswamy Tummala 
2654e9dc6bffSRamaswamy Tummala 	/* Get "In" and "Out" mailboxes for the command */
2655e9dc6bffSRamaswamy Tummala 	mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
2656e9dc6bffSRamaswamy Tummala 	status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
2657e9dc6bffSRamaswamy Tummala 	if (status != TAVOR_CMD_SUCCESS) {
2658e9dc6bffSRamaswamy Tummala 		return (status);
2659e9dc6bffSRamaswamy Tummala 	}
2660e9dc6bffSRamaswamy Tummala 
2661e9dc6bffSRamaswamy Tummala 	/* Build request MAD in the "In" mailbox */
2662e9dc6bffSRamaswamy Tummala 	size = TAVOR_CMD_MAD_IFC_SIZE;
2663e9dc6bffSRamaswamy Tummala 	mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2664e9dc6bffSRamaswamy Tummala 
2665e9dc6bffSRamaswamy Tummala 	if (reset) {
2666e9dc6bffSRamaswamy Tummala 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0],
2667e9dc6bffSRamaswamy Tummala 		    TAVOR_CMD_PERF_SET);
2668e9dc6bffSRamaswamy Tummala 	} else {
2669e9dc6bffSRamaswamy Tummala 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0],
2670e9dc6bffSRamaswamy Tummala 		    TAVOR_CMD_PERF_GET);
2671e9dc6bffSRamaswamy Tummala 	}
2672e9dc6bffSRamaswamy Tummala 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1);
2673e9dc6bffSRamaswamy Tummala 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2);
2674e9dc6bffSRamaswamy Tummala 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3);
2675e9dc6bffSRamaswamy Tummala 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_PERFCNTRS);
2676e9dc6bffSRamaswamy Tummala 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], TAVOR_CMD_PERFATTR);
2677e9dc6bffSRamaswamy Tummala 
2678e9dc6bffSRamaswamy Tummala 	if (reset) {
2679e9dc6bffSRamaswamy Tummala 		/* reset counters for XmitData, RcvData, XmitPkts, RcvPkts */
2680e9dc6bffSRamaswamy Tummala 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16],
2681e9dc6bffSRamaswamy Tummala 		    ((port << 16) | 0xf000));
2682e9dc6bffSRamaswamy Tummala 
2683e9dc6bffSRamaswamy Tummala 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[22], 0);
2684e9dc6bffSRamaswamy Tummala 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[23], 0);
2685e9dc6bffSRamaswamy Tummala 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[24], 0);
2686e9dc6bffSRamaswamy Tummala 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[25], 0);
2687e9dc6bffSRamaswamy Tummala 	} else
2688e9dc6bffSRamaswamy Tummala 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16], (port << 16));
2689e9dc6bffSRamaswamy Tummala 
2690e9dc6bffSRamaswamy Tummala 	/* Sync the mailbox for the device to read */
2691e9dc6bffSRamaswamy Tummala 	tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2692e9dc6bffSRamaswamy Tummala 
2693e9dc6bffSRamaswamy Tummala 	/* Setup the Hermon "MAD_IFC" command */
2694e9dc6bffSRamaswamy Tummala 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
2695e9dc6bffSRamaswamy Tummala 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
2696e9dc6bffSRamaswamy Tummala 	cmd.cp_inmod	= port;
2697e9dc6bffSRamaswamy Tummala 	cmd.cp_opcode	= MAD_IFC;
2698e9dc6bffSRamaswamy Tummala 	/* No MKey and BKey checking */
2699e9dc6bffSRamaswamy Tummala 	cmd.cp_opmod	= TAVOR_CMD_MKEY_DONTCHECK | TAVOR_CMD_BKEY_DONTCHECK;
2700e9dc6bffSRamaswamy Tummala 	cmd.cp_flags	= TAVOR_CMD_NOSLEEP_SPIN; /* NO SLEEP */
2701e9dc6bffSRamaswamy Tummala 	status = tavor_cmd_post(state, &cmd);
2702e9dc6bffSRamaswamy Tummala 	if (status != TAVOR_CMD_SUCCESS) {
2703e9dc6bffSRamaswamy Tummala 		goto getperfinfo_fail;
2704e9dc6bffSRamaswamy Tummala 	}
2705e9dc6bffSRamaswamy Tummala 
2706e9dc6bffSRamaswamy Tummala 	/* Sync the mailbox to read the results */
2707e9dc6bffSRamaswamy Tummala 	size = TAVOR_CMD_MAD_IFC_SIZE;
2708e9dc6bffSRamaswamy Tummala 	tavor_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
2709e9dc6bffSRamaswamy Tummala 
2710e9dc6bffSRamaswamy Tummala 	if (reset == 0) {
2711e9dc6bffSRamaswamy Tummala 		size = sizeof (tavor_hw_sm_perfcntr_t); /* for the copy */
2712e9dc6bffSRamaswamy Tummala 		/*
2713e9dc6bffSRamaswamy Tummala 		 * Copy Perfcounters into "perfinfo".  We can discard the MAD
2714e9dc6bffSRamaswamy Tummala 		 * header and the 8 Quadword reserved area of the PERM mgmt
2715e9dc6bffSRamaswamy Tummala 		 * class MAD
2716e9dc6bffSRamaswamy Tummala 		 */
2717e9dc6bffSRamaswamy Tummala 
2718e9dc6bffSRamaswamy Tummala 		for (i = 0; i < size >> 3; i++) {
2719e9dc6bffSRamaswamy Tummala 			data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2720e9dc6bffSRamaswamy Tummala 			    ((uint64_t *)mbox_info.mbi_out->mb_addr + i + 8));
2721e9dc6bffSRamaswamy Tummala 			((uint64_t *)(void *)perfinfo)[i] = data;
2722e9dc6bffSRamaswamy Tummala 		}
2723e9dc6bffSRamaswamy Tummala 	}
2724e9dc6bffSRamaswamy Tummala 
2725e9dc6bffSRamaswamy Tummala getperfinfo_fail:
2726e9dc6bffSRamaswamy Tummala 	/* Free the mailbox */
2727e9dc6bffSRamaswamy Tummala 	tavor_mbox_free(state, &mbox_info);
2728e9dc6bffSRamaswamy Tummala 	return (status);
2729e9dc6bffSRamaswamy Tummala }
2730