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 /*
2317a2b317SBill Taylor  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
249e39c5baSBill Taylor  */
259e39c5baSBill Taylor 
269e39c5baSBill Taylor /*
279e39c5baSBill Taylor  * hermon_cmd.c
289e39c5baSBill Taylor  *    Hermon Firmware Command Routines
299e39c5baSBill Taylor  *
309e39c5baSBill Taylor  *    Implements all the routines necessary for allocating, posting, and
319e39c5baSBill Taylor  *    freeing commands for the Hermon firmware.  These routines manage a
329e39c5baSBill Taylor  *    preallocated list of command mailboxes and provide interfaces to post
339e39c5baSBill Taylor  *    each of the several dozen commands to the Hermon firmware.
349e39c5baSBill Taylor  */
359e39c5baSBill Taylor 
369e39c5baSBill Taylor #include <sys/types.h>
379e39c5baSBill Taylor #include <sys/conf.h>
389e39c5baSBill Taylor #include <sys/ddi.h>
399e39c5baSBill Taylor #include <sys/sunddi.h>
409e39c5baSBill Taylor #include <sys/modctl.h>
419e39c5baSBill Taylor #include <sys/bitmap.h>
429e39c5baSBill Taylor 
439e39c5baSBill Taylor #include <sys/ib/adapters/hermon/hermon.h>
449e39c5baSBill Taylor 
459e39c5baSBill Taylor static int hermon_impl_mbox_alloc(hermon_state_t *state,
469e39c5baSBill Taylor     hermon_mboxlist_t *mblist, hermon_mbox_t **mb, uint_t mbox_wait);
479e39c5baSBill Taylor static void hermon_impl_mbox_free(hermon_mboxlist_t *mblist,
489e39c5baSBill Taylor     hermon_mbox_t **mb);
499e39c5baSBill Taylor static int hermon_impl_mboxlist_init(hermon_state_t *state,
509e39c5baSBill Taylor     hermon_mboxlist_t *mblist, uint_t num_mbox, hermon_rsrc_type_t type);
519e39c5baSBill Taylor static void hermon_impl_mboxlist_fini(hermon_state_t *state,
529e39c5baSBill Taylor     hermon_mboxlist_t *mblist);
539e39c5baSBill Taylor static int hermon_outstanding_cmd_alloc(hermon_state_t *state,
549e39c5baSBill Taylor     hermon_cmd_t **cmd_ptr, uint_t cmd_wait);
559e39c5baSBill Taylor static void hermon_outstanding_cmd_free(hermon_state_t *state,
569e39c5baSBill Taylor     hermon_cmd_t **cmd_ptr);
579e39c5baSBill Taylor static int hermon_write_hcr(hermon_state_t *state, hermon_cmd_post_t *cmdpost,
589e39c5baSBill Taylor     uint16_t token, int *hwerr);
599e39c5baSBill Taylor static void hermon_mbox_sync(hermon_mbox_t *mbox, uint_t offset,
609e39c5baSBill Taylor     uint_t length, uint_t flag);
619e39c5baSBill Taylor static void hermon_cmd_check_status(hermon_state_t *state, int status);
629e39c5baSBill Taylor 
639e39c5baSBill Taylor /*
649e39c5baSBill Taylor  * hermon_cmd_post()
659e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
669e39c5baSBill Taylor  *
679e39c5baSBill Taylor  *    The "cp_flags" field in cmdpost
689e39c5baSBill Taylor  *    is used to determine whether to wait for an available
699e39c5baSBill Taylor  *    outstanding command (if necessary) or to return error.
709e39c5baSBill Taylor  */
719e39c5baSBill Taylor int
hermon_cmd_post(hermon_state_t * state,hermon_cmd_post_t * cmdpost)729e39c5baSBill Taylor hermon_cmd_post(hermon_state_t *state, hermon_cmd_post_t *cmdpost)
739e39c5baSBill Taylor {
749e39c5baSBill Taylor 	hermon_cmd_t	*cmdptr;
759e39c5baSBill Taylor 	int		status, retry_cnt, retry_cnt2, hw_err;
769e39c5baSBill Taylor 	uint16_t	token;
779e39c5baSBill Taylor 
789e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdpost))
799e39c5baSBill Taylor 
809e39c5baSBill Taylor 	/* Determine if we are going to spin until completion */
819e39c5baSBill Taylor 	if (cmdpost->cp_flags == HERMON_CMD_NOSLEEP_SPIN) {
829e39c5baSBill Taylor 
839e39c5baSBill Taylor 		/* Write the command to the HCR */
849e39c5baSBill Taylor 		retry_cnt = HCA_PIO_RETRY_CNT;
859e39c5baSBill Taylor 		do {
869e39c5baSBill Taylor 			status = hermon_write_hcr(state, cmdpost, 0, &hw_err);
879e39c5baSBill Taylor 		} while (status == HERMON_CMD_INTERNAL_ERR && retry_cnt-- > 0);
889e39c5baSBill Taylor 
899e39c5baSBill Taylor 		/* Check if there is an error status in hermon_write_hcr() */
909e39c5baSBill Taylor 		if (status != HERMON_CMD_SUCCESS) {
919e39c5baSBill Taylor 			/*
929e39c5baSBill Taylor 			 * If there is a HW error, call hermon_cmd_retry_ok()
939e39c5baSBill Taylor 			 * to check the side-effect of the operation retry.
949e39c5baSBill Taylor 			 */
959e39c5baSBill Taylor 			if ((retry_cnt == HCA_PIO_RETRY_CNT &&
969e39c5baSBill Taylor 			    hw_err == HCA_PIO_OK) ||
979e39c5baSBill Taylor 			    !hermon_cmd_retry_ok(cmdpost, status)) {
989e39c5baSBill Taylor 				hermon_cmd_check_status(state, status);
999e39c5baSBill Taylor 				return (status);
1009e39c5baSBill Taylor 			}
1019e39c5baSBill Taylor 		/* Check if there is a transient internal error */
1029e39c5baSBill Taylor 		} else if (retry_cnt != HCA_PIO_RETRY_CNT) {
1039e39c5baSBill Taylor 			hermon_fm_ereport(state, HCA_IBA_ERR,
1049e39c5baSBill Taylor 			    HCA_ERR_TRANSIENT);
1059e39c5baSBill Taylor 		}
1069e39c5baSBill Taylor 
1079e39c5baSBill Taylor 	} else {  /* "HERMON_CMD_SLEEP_NOSPIN" */
1089e39c5baSBill Taylor 		ASSERT(HERMON_SLEEPFLAG_FOR_CONTEXT() != HERMON_NOSLEEP);
1099e39c5baSBill Taylor 
1109e39c5baSBill Taylor 		/* NOTE: Expect threads to be waiting in here */
1119e39c5baSBill Taylor 		status = hermon_outstanding_cmd_alloc(state, &cmdptr,
1129e39c5baSBill Taylor 		    cmdpost->cp_flags);
1139e39c5baSBill Taylor 		if (status != HERMON_CMD_SUCCESS) {
1149e39c5baSBill Taylor 			return (status);
1159e39c5baSBill Taylor 		}
1169e39c5baSBill Taylor 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdptr))
1179e39c5baSBill Taylor 
1189e39c5baSBill Taylor 		retry_cnt = HCA_PIO_RETRY_CNT;
1199e39c5baSBill Taylor retry:
1209e39c5baSBill Taylor 		/*
1219e39c5baSBill Taylor 		 * Set status to "HERMON_CMD_INVALID_STATUS".  It is
1229e39c5baSBill Taylor 		 * appropriate to do this here without the "cmd_comp_lock"
1239e39c5baSBill Taylor 		 * because this register is overloaded.  Later it will be
1249e39c5baSBill Taylor 		 * used to indicate - through a change from this invalid
1259e39c5baSBill Taylor 		 * value to some other value - that the condition variable
1269e39c5baSBill Taylor 		 * has been signaled.  Once it has, status will then contain
1279e39c5baSBill Taylor 		 * the _real_ completion status
1289e39c5baSBill Taylor 		 */
1299e39c5baSBill Taylor 		cmdptr->cmd_status = HERMON_CMD_INVALID_STATUS;
1309e39c5baSBill Taylor 
1319e39c5baSBill Taylor 		/* Write the command to the HCR */
1329e39c5baSBill Taylor 		token = (uint16_t)cmdptr->cmd_indx;
1339e39c5baSBill Taylor 		retry_cnt2 = HCA_PIO_RETRY_CNT;
1349e39c5baSBill Taylor 		do {
1359e39c5baSBill Taylor 			status = hermon_write_hcr(state, cmdpost, token,
1369e39c5baSBill Taylor 			    &hw_err);
1379e39c5baSBill Taylor 		} while (status == HERMON_CMD_INTERNAL_ERR && retry_cnt2-- > 0);
1389e39c5baSBill Taylor 
1399e39c5baSBill Taylor 		/* Check if there is an error status in hermon_write_hcr() */
1409e39c5baSBill Taylor 		if (status != HERMON_CMD_SUCCESS) {
1419e39c5baSBill Taylor 			/*
1429e39c5baSBill Taylor 			 * If there is a HW error, call hermon_cmd_retry_ok()
1439e39c5baSBill Taylor 			 * to check the side-effect of the operation retry.
1449e39c5baSBill Taylor 			 */
1459e39c5baSBill Taylor 			if ((retry_cnt == HCA_PIO_RETRY_CNT &&
1469e39c5baSBill Taylor 			    hw_err == HCA_PIO_OK) ||
1479e39c5baSBill Taylor 			    !hermon_cmd_retry_ok(cmdpost, status)) {
1489e39c5baSBill Taylor 				hermon_cmd_check_status(state, status);
1499e39c5baSBill Taylor 				hermon_outstanding_cmd_free(state, &cmdptr);
1509e39c5baSBill Taylor 				return (status);
1519e39c5baSBill Taylor 			}
1529e39c5baSBill Taylor 		/* Check if there is a transient internal error */
1539e39c5baSBill Taylor 		} else if (retry_cnt2 != HCA_PIO_RETRY_CNT) {
1549e39c5baSBill Taylor 			hermon_fm_ereport(state, HCA_IBA_ERR,
1559e39c5baSBill Taylor 			    HCA_ERR_TRANSIENT);
1569e39c5baSBill Taylor 		}
1579e39c5baSBill Taylor 
1589e39c5baSBill Taylor 		/*
1599e39c5baSBill Taylor 		 * cv_wait() on the "command_complete" condition variable.
1609e39c5baSBill Taylor 		 * Note: We have the "__lock_lint" here to workaround warlock.
1619e39c5baSBill Taylor 		 * Since warlock doesn't know that other parts of the Hermon
1629e39c5baSBill Taylor 		 * may occasionally call this routine while holding their own
1639e39c5baSBill Taylor 		 * locks, it complains about this cv_wait.  In reality,
1649e39c5baSBill Taylor 		 * however, the rest of the driver never calls this routine
1659e39c5baSBill Taylor 		 * with a lock held unless they pass HERMON_CMD_NOSLEEP.
1669e39c5baSBill Taylor 		 */
1679e39c5baSBill Taylor 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*cmdptr))
1689e39c5baSBill Taylor 		mutex_enter(&cmdptr->cmd_comp_lock);
1699e39c5baSBill Taylor 		while (cmdptr->cmd_status == HERMON_CMD_INVALID_STATUS) {
1709e39c5baSBill Taylor #ifndef	__lock_lint
1719e39c5baSBill Taylor 			cv_wait(&cmdptr->cmd_comp_cv, &cmdptr->cmd_comp_lock);
1729e39c5baSBill Taylor 			/* NOTE: EXPECT SEVERAL THREADS TO BE WAITING HERE */
1739e39c5baSBill Taylor #endif
1749e39c5baSBill Taylor 		}
1759e39c5baSBill Taylor 		mutex_exit(&cmdptr->cmd_comp_lock);
1769e39c5baSBill Taylor 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdptr))
1779e39c5baSBill Taylor 
1789e39c5baSBill Taylor 		/*
1799e39c5baSBill Taylor 		 * Wake up after command completes (cv_signal).  Read status
1809e39c5baSBill Taylor 		 * from the command (success, fail, etc.).  It is appropriate
1819e39c5baSBill Taylor 		 * here (as above) to read the status field without the
1829e39c5baSBill Taylor 		 * "cmd_comp_lock" because it is no longer being used to
1839e39c5baSBill Taylor 		 * indicate whether the condition variable has been signaled
1849e39c5baSBill Taylor 		 * (i.e. at this point we are certain that it already has).
1859e39c5baSBill Taylor 		 */
1869e39c5baSBill Taylor 		status = cmdptr->cmd_status;
1879e39c5baSBill Taylor 
1889e39c5baSBill Taylor 		/* retry the operation if an internal error occurs */
1899e39c5baSBill Taylor 		if (status == HERMON_CMD_INTERNAL_ERR && retry_cnt-- > 0)
1909e39c5baSBill Taylor 			goto retry;
1919e39c5baSBill Taylor 
1929e39c5baSBill Taylor 		/* Save the "outparam" values into the cmdpost struct */
1939e39c5baSBill Taylor 		cmdpost->cp_outparm = cmdptr->cmd_outparm;
1949e39c5baSBill Taylor 
1959e39c5baSBill Taylor 		/*
1969e39c5baSBill Taylor 		 * Add the command back to the "outstanding commands list".
1979e39c5baSBill Taylor 		 * Signal the "cmd_list" condition variable, if necessary.
1989e39c5baSBill Taylor 		 */
1999e39c5baSBill Taylor 		hermon_outstanding_cmd_free(state, &cmdptr);
2009e39c5baSBill Taylor 
2019e39c5baSBill Taylor 		/* Check if there is an error status in hermon_write_hcr() */
2029e39c5baSBill Taylor 		if (status != HERMON_CMD_SUCCESS) {
2039e39c5baSBill Taylor 			/*
2049e39c5baSBill Taylor 			 * If there is a HW error, call hermon_cmd_retry_ok()
2059e39c5baSBill Taylor 			 * to check the side-effect of the operation retry.
2069e39c5baSBill Taylor 			 */
2079e39c5baSBill Taylor 			if ((retry_cnt == HCA_PIO_RETRY_CNT &&
2089e39c5baSBill Taylor 			    hw_err == HCA_PIO_OK) ||
2099e39c5baSBill Taylor 			    !hermon_cmd_retry_ok(cmdpost, status)) {
2109e39c5baSBill Taylor 				hermon_cmd_check_status(state, status);
2119e39c5baSBill Taylor 				cmn_err(CE_NOTE, "hermon%d: post cmd failed "
2129e39c5baSBill Taylor 				    "opcode (0x%x) status (0x%x)\n",
2139e39c5baSBill Taylor 				    state->hs_instance, cmdpost->cp_opcode,
2149e39c5baSBill Taylor 				    status);
2159e39c5baSBill Taylor 				return (status);
2169e39c5baSBill Taylor 			}
2179e39c5baSBill Taylor 		/* Check if there is a transient internal error */
2189e39c5baSBill Taylor 		} else if (retry_cnt != HCA_PIO_RETRY_CNT) {
2199e39c5baSBill Taylor 			hermon_fm_ereport(state, HCA_IBA_ERR,
2209e39c5baSBill Taylor 			    HCA_ERR_TRANSIENT);
2219e39c5baSBill Taylor 		}
2229e39c5baSBill Taylor 	}
2239e39c5baSBill Taylor 
2249e39c5baSBill Taylor 	return (HERMON_CMD_SUCCESS);
2259e39c5baSBill Taylor }
2269e39c5baSBill Taylor 
2279e39c5baSBill Taylor /*
2289e39c5baSBill Taylor  * hermon_cmd_check_status()
2299e39c5baSBill Taylor  *	Context:  Can be called from interrupt or base
2309e39c5baSBill Taylor  *
2319e39c5baSBill Taylor  * checks the status returned from write_hcr and does the right
2329e39c5baSBill Taylor  * notice to the console, if any
2339e39c5baSBill Taylor  */
2349e39c5baSBill Taylor static void
hermon_cmd_check_status(hermon_state_t * state,int status)2359e39c5baSBill Taylor hermon_cmd_check_status(hermon_state_t *state, int status)
2369e39c5baSBill Taylor {
2379e39c5baSBill Taylor 	switch (status) {
2389e39c5baSBill Taylor 		case HERMON_CMD_TIMEOUT_TOGGLE:
2399e39c5baSBill Taylor 			HERMON_FMANOTE(state, HERMON_FMA_TOTOG);
2409e39c5baSBill Taylor 			hermon_fm_ereport(state, HCA_IBA_ERR,
2419e39c5baSBill Taylor 			    HCA_ERR_NON_FATAL);
2429e39c5baSBill Taylor 			break;
2439e39c5baSBill Taylor 
2449e39c5baSBill Taylor 		case HERMON_CMD_TIMEOUT_GOBIT:
2459e39c5baSBill Taylor 			HERMON_FMANOTE(state, HERMON_FMA_GOBIT);
2469e39c5baSBill Taylor 			hermon_fm_ereport(state, HCA_IBA_ERR,
2479e39c5baSBill Taylor 			    HCA_ERR_NON_FATAL);
2489e39c5baSBill Taylor 			break;
2499e39c5baSBill Taylor 
2509e39c5baSBill Taylor 		case HERMON_CMD_INSUFF_RSRC:
2519e39c5baSBill Taylor 			HERMON_FMANOTE(state, HERMON_FMA_RSRC);
2529e39c5baSBill Taylor 			break;
2539e39c5baSBill Taylor 
2549e39c5baSBill Taylor 		case HERMON_CMD_INVALID_STATUS:
2559e39c5baSBill Taylor 			HERMON_FMANOTE(state, HERMON_FMA_CMDINV);
2569e39c5baSBill Taylor 			hermon_fm_ereport(state, HCA_IBA_ERR,
2579e39c5baSBill Taylor 			    HCA_ERR_NON_FATAL);
2589e39c5baSBill Taylor 			break;
2599e39c5baSBill Taylor 
2609e39c5baSBill Taylor 		case HERMON_CMD_INTERNAL_ERR:
2619e39c5baSBill Taylor 			HERMON_FMANOTE(state, HERMON_FMA_HCRINT);
2629e39c5baSBill Taylor 			hermon_fm_ereport(state, HCA_IBA_ERR,
2639e39c5baSBill Taylor 			    HCA_ERR_NON_FATAL);
2649e39c5baSBill Taylor 			break;
2659e39c5baSBill Taylor 
2669e39c5baSBill Taylor 		case HERMON_CMD_BAD_NVMEM:
26732c5adfdSEiji Ota 			/*
26832c5adfdSEiji Ota 			 * No need of an ereport here since this case
26932c5adfdSEiji Ota 			 * is treated as a degradation later.
27032c5adfdSEiji Ota 			 */
2719e39c5baSBill Taylor 			HERMON_FMANOTE(state, HERMON_FMA_NVMEM);
2729e39c5baSBill Taylor 			break;
2739e39c5baSBill Taylor 
2749e39c5baSBill Taylor 		default:
2759e39c5baSBill Taylor 			break;
2769e39c5baSBill Taylor 	}
2779e39c5baSBill Taylor }
2789e39c5baSBill Taylor 
2799e39c5baSBill Taylor /*
2809e39c5baSBill Taylor  * hermon_mbox_alloc()
2819e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
2829e39c5baSBill Taylor  *
2839e39c5baSBill Taylor  *    The "mbox_wait" parameter is used to determine whether to
2849e39c5baSBill Taylor  *    wait for a mailbox to become available or not.
2859e39c5baSBill Taylor  */
2869e39c5baSBill Taylor int
hermon_mbox_alloc(hermon_state_t * state,hermon_mbox_info_t * mbox_info,uint_t mbox_wait)2879e39c5baSBill Taylor hermon_mbox_alloc(hermon_state_t *state, hermon_mbox_info_t *mbox_info,
2889e39c5baSBill Taylor     uint_t mbox_wait)
2899e39c5baSBill Taylor {
2909e39c5baSBill Taylor 	int		status;
2919e39c5baSBill Taylor 	uint_t		sleep_context;
2929e39c5baSBill Taylor 
2939e39c5baSBill Taylor 	sleep_context = HERMON_SLEEPFLAG_FOR_CONTEXT();
2949e39c5baSBill Taylor 
2959e39c5baSBill Taylor 	/* Allocate an "In" mailbox */
2969e39c5baSBill Taylor 	if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_INMBOX) {
2979e39c5baSBill Taylor 		/* Determine correct mboxlist based on calling context */
2989e39c5baSBill Taylor 		if (sleep_context == HERMON_NOSLEEP) {
2999e39c5baSBill Taylor 			status = hermon_impl_mbox_alloc(state,
3009e39c5baSBill Taylor 			    &state->hs_in_intr_mblist,
3019e39c5baSBill Taylor 			    &mbox_info->mbi_in, mbox_wait);
3029e39c5baSBill Taylor 
3039e39c5baSBill Taylor 			ASSERT(status == HERMON_CMD_SUCCESS);
3049e39c5baSBill Taylor 		} else {
3059e39c5baSBill Taylor 			/* NOTE: Expect threads to be waiting in here */
3069e39c5baSBill Taylor 			status = hermon_impl_mbox_alloc(state,
3079e39c5baSBill Taylor 			    &state->hs_in_mblist, &mbox_info->mbi_in,
3089e39c5baSBill Taylor 			    mbox_wait);
3099e39c5baSBill Taylor 			if (status != HERMON_CMD_SUCCESS) {
3109e39c5baSBill Taylor 				return (status);
3119e39c5baSBill Taylor 			}
3129e39c5baSBill Taylor 		}
3139e39c5baSBill Taylor 
3149e39c5baSBill Taylor 	}
3159e39c5baSBill Taylor 
3169e39c5baSBill Taylor 	/* Allocate an "Out" mailbox */
3179e39c5baSBill Taylor 	if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_OUTMBOX) {
3189e39c5baSBill Taylor 		/* Determine correct mboxlist based on calling context */
3199e39c5baSBill Taylor 		if (sleep_context == HERMON_NOSLEEP) {
3209e39c5baSBill Taylor 			status = hermon_impl_mbox_alloc(state,
3219e39c5baSBill Taylor 			    &state->hs_out_intr_mblist,
3229e39c5baSBill Taylor 			    &mbox_info->mbi_out, mbox_wait);
3239e39c5baSBill Taylor 
3249e39c5baSBill Taylor 			ASSERT(status == HERMON_CMD_SUCCESS);
3259e39c5baSBill Taylor 		} else {
3269e39c5baSBill Taylor 			/* NOTE: Expect threads to be waiting in here */
3279e39c5baSBill Taylor 			status = hermon_impl_mbox_alloc(state,
3289e39c5baSBill Taylor 			    &state->hs_out_mblist, &mbox_info->mbi_out,
3299e39c5baSBill Taylor 			    mbox_wait);
3309e39c5baSBill Taylor 			if (status != HERMON_CMD_SUCCESS) {
3319e39c5baSBill Taylor 				/* If we allocated an "In" mailbox, free it */
3329e39c5baSBill Taylor 				if (mbox_info->mbi_alloc_flags &
3339e39c5baSBill Taylor 				    HERMON_ALLOC_INMBOX) {
3349e39c5baSBill Taylor 					hermon_impl_mbox_free(
3359e39c5baSBill Taylor 					    &state->hs_in_mblist,
3369e39c5baSBill Taylor 					    &mbox_info->mbi_in);
3379e39c5baSBill Taylor 				}
3389e39c5baSBill Taylor 				return (status);
3399e39c5baSBill Taylor 			}
3409e39c5baSBill Taylor 		}
3419e39c5baSBill Taylor 	}
3429e39c5baSBill Taylor 
3439e39c5baSBill Taylor 	/* Store appropriate context in mbox_info */
3449e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(mbox_info->mbi_sleep_context))
3459e39c5baSBill Taylor 	mbox_info->mbi_sleep_context = sleep_context;
3469e39c5baSBill Taylor 
3479e39c5baSBill Taylor 	return (HERMON_CMD_SUCCESS);
3489e39c5baSBill Taylor }
3499e39c5baSBill Taylor 
3509e39c5baSBill Taylor 
3519e39c5baSBill Taylor /*
3529e39c5baSBill Taylor  * hermon_mbox_free()
3539e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
3549e39c5baSBill Taylor  */
3559e39c5baSBill Taylor void
hermon_mbox_free(hermon_state_t * state,hermon_mbox_info_t * mbox_info)3569e39c5baSBill Taylor hermon_mbox_free(hermon_state_t *state, hermon_mbox_info_t *mbox_info)
3579e39c5baSBill Taylor {
3589e39c5baSBill Taylor 	/*
3599e39c5baSBill Taylor 	 * The mailbox has to be freed in the same context from which it was
3609e39c5baSBill Taylor 	 * allocated.  The context is stored in the mbox_info at
3619e39c5baSBill Taylor 	 * hermon_mbox_alloc() time.  We check the stored context against the
3629e39c5baSBill Taylor 	 * current context here.
3639e39c5baSBill Taylor 	 */
3649e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(mbox_info->mbi_sleep_context))
3659e39c5baSBill Taylor 	ASSERT(mbox_info->mbi_sleep_context == HERMON_SLEEPFLAG_FOR_CONTEXT());
3669e39c5baSBill Taylor 
3679e39c5baSBill Taylor 	/* Determine correct mboxlist based on calling context */
3689e39c5baSBill Taylor 	if (mbox_info->mbi_sleep_context == HERMON_NOSLEEP) {
3699e39c5baSBill Taylor 		/* Free the intr "In" mailbox */
3709e39c5baSBill Taylor 		if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_INMBOX) {
3719e39c5baSBill Taylor 			hermon_impl_mbox_free(&state->hs_in_intr_mblist,
3729e39c5baSBill Taylor 			    &mbox_info->mbi_in);
3739e39c5baSBill Taylor 		}
3749e39c5baSBill Taylor 
3759e39c5baSBill Taylor 		/* Free the intr "Out" mailbox */
3769e39c5baSBill Taylor 		if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_OUTMBOX) {
3779e39c5baSBill Taylor 			hermon_impl_mbox_free(&state->hs_out_intr_mblist,
3789e39c5baSBill Taylor 			    &mbox_info->mbi_out);
3799e39c5baSBill Taylor 		}
3809e39c5baSBill Taylor 	} else {
3819e39c5baSBill Taylor 		/* Free the "In" mailbox */
3829e39c5baSBill Taylor 		if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_INMBOX) {
3839e39c5baSBill Taylor 			hermon_impl_mbox_free(&state->hs_in_mblist,
3849e39c5baSBill Taylor 			    &mbox_info->mbi_in);
3859e39c5baSBill Taylor 		}
3869e39c5baSBill Taylor 
3879e39c5baSBill Taylor 		/* Free the "Out" mailbox */
3889e39c5baSBill Taylor 		if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_OUTMBOX) {
3899e39c5baSBill Taylor 			hermon_impl_mbox_free(&state->hs_out_mblist,
3909e39c5baSBill Taylor 			    &mbox_info->mbi_out);
3919e39c5baSBill Taylor 		}
3929e39c5baSBill Taylor 	}
3939e39c5baSBill Taylor }
3949e39c5baSBill Taylor 
3959e39c5baSBill Taylor 
3969e39c5baSBill Taylor 
3979e39c5baSBill Taylor /*
3989e39c5baSBill Taylor  * hermon_cmd_complete_handler()
3999e39c5baSBill Taylor  *    Context: Called only from interrupt context.
4009e39c5baSBill Taylor  */
40117a2b317SBill Taylor /* ARGSUSED */
4029e39c5baSBill Taylor int
hermon_cmd_complete_handler(hermon_state_t * state,hermon_eqhdl_t eq,hermon_hw_eqe_t * eqe)4039e39c5baSBill Taylor hermon_cmd_complete_handler(hermon_state_t *state, hermon_eqhdl_t eq,
4049e39c5baSBill Taylor     hermon_hw_eqe_t *eqe)
4059e39c5baSBill Taylor {
4069e39c5baSBill Taylor 	hermon_cmd_t		*cmdp;
4079e39c5baSBill Taylor 
4089e39c5baSBill Taylor 	/*
4099e39c5baSBill Taylor 	 * Find the outstanding command pointer based on value returned
4109e39c5baSBill Taylor 	 * in "token"
4119e39c5baSBill Taylor 	 */
4129e39c5baSBill Taylor 	cmdp = &state->hs_cmd_list.cml_cmd[HERMON_EQE_CMDTOKEN_GET(eq, eqe)];
4139e39c5baSBill Taylor 
4149e39c5baSBill Taylor 	/* Signal the waiting thread */
4159e39c5baSBill Taylor 	mutex_enter(&cmdp->cmd_comp_lock);
4169e39c5baSBill Taylor 	cmdp->cmd_outparm = ((uint64_t)HERMON_EQE_CMDOUTP0_GET(eq, eqe) << 32) |
4179e39c5baSBill Taylor 	    HERMON_EQE_CMDOUTP1_GET(eq, eqe);
4189e39c5baSBill Taylor 	cmdp->cmd_status = HERMON_EQE_CMDSTATUS_GET(eq, eqe);
4199e39c5baSBill Taylor 
4209e39c5baSBill Taylor 	cv_signal(&cmdp->cmd_comp_cv);
4219e39c5baSBill Taylor 	mutex_exit(&cmdp->cmd_comp_lock);
4229e39c5baSBill Taylor 
4239e39c5baSBill Taylor 	return (DDI_SUCCESS);
4249e39c5baSBill Taylor }
4259e39c5baSBill Taylor 
4269e39c5baSBill Taylor 
4279e39c5baSBill Taylor /*
4289e39c5baSBill Taylor  * hermon_inmbox_list_init()
4299e39c5baSBill Taylor  *    Context: Only called from attach() path context
4309e39c5baSBill Taylor  */
4319e39c5baSBill Taylor int
hermon_inmbox_list_init(hermon_state_t * state)4329e39c5baSBill Taylor hermon_inmbox_list_init(hermon_state_t *state)
4339e39c5baSBill Taylor {
4349e39c5baSBill Taylor 	int		status;
4359e39c5baSBill Taylor 	uint_t		num_inmbox;
4369e39c5baSBill Taylor 
4379e39c5baSBill Taylor 	/* Initialize the "In" mailbox list */
4389e39c5baSBill Taylor 	num_inmbox  =  (1 << state->hs_cfg_profile->cp_log_num_inmbox);
4399e39c5baSBill Taylor 	status = hermon_impl_mboxlist_init(state, &state->hs_in_mblist,
4409e39c5baSBill Taylor 	    num_inmbox, HERMON_IN_MBOX);
4419e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
4429e39c5baSBill Taylor 		return (DDI_FAILURE);
4439e39c5baSBill Taylor 	}
4449e39c5baSBill Taylor 
4459e39c5baSBill Taylor 	return (DDI_SUCCESS);
4469e39c5baSBill Taylor }
4479e39c5baSBill Taylor 
4489e39c5baSBill Taylor 
4499e39c5baSBill Taylor /*
4509e39c5baSBill Taylor  * hermon_intr_inmbox_list_init()
4519e39c5baSBill Taylor  *    Context: Only called from attach() path context
4529e39c5baSBill Taylor  */
4539e39c5baSBill Taylor int
hermon_intr_inmbox_list_init(hermon_state_t * state)4549e39c5baSBill Taylor hermon_intr_inmbox_list_init(hermon_state_t *state)
4559e39c5baSBill Taylor {
4569e39c5baSBill Taylor 	int		status;
4579e39c5baSBill Taylor 	uint_t		num_inmbox;
4589e39c5baSBill Taylor 
4599e39c5baSBill Taylor 	/* Initialize the interrupt "In" mailbox list */
4609e39c5baSBill Taylor 	num_inmbox  =  (1 << state->hs_cfg_profile->cp_log_num_intr_inmbox);
4619e39c5baSBill Taylor 	status = hermon_impl_mboxlist_init(state, &state->hs_in_intr_mblist,
4629e39c5baSBill Taylor 	    num_inmbox, HERMON_INTR_IN_MBOX);
4639e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
4649e39c5baSBill Taylor 		return (DDI_FAILURE);
4659e39c5baSBill Taylor 	}
4669e39c5baSBill Taylor 
4679e39c5baSBill Taylor 	return (DDI_SUCCESS);
4689e39c5baSBill Taylor }
4699e39c5baSBill Taylor 
4709e39c5baSBill Taylor 
4719e39c5baSBill Taylor /*
4729e39c5baSBill Taylor  * hermon_outmbox_list_init()
4739e39c5baSBill Taylor  *    Context: Only called from attach() path context
4749e39c5baSBill Taylor  */
4759e39c5baSBill Taylor int
hermon_outmbox_list_init(hermon_state_t * state)4769e39c5baSBill Taylor hermon_outmbox_list_init(hermon_state_t *state)
4779e39c5baSBill Taylor {
4789e39c5baSBill Taylor 	int		status;
4799e39c5baSBill Taylor 	uint_t		num_outmbox;
4809e39c5baSBill Taylor 
4819e39c5baSBill Taylor 	/* Initialize the "Out" mailbox list */
4829e39c5baSBill Taylor 	num_outmbox  =  (1 << state->hs_cfg_profile->cp_log_num_outmbox);
4839e39c5baSBill Taylor 	status = hermon_impl_mboxlist_init(state, &state->hs_out_mblist,
4849e39c5baSBill Taylor 	    num_outmbox, HERMON_OUT_MBOX);
4859e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
4869e39c5baSBill Taylor 		return (DDI_FAILURE);
4879e39c5baSBill Taylor 	}
4889e39c5baSBill Taylor 
4899e39c5baSBill Taylor 	return (DDI_SUCCESS);
4909e39c5baSBill Taylor }
4919e39c5baSBill Taylor 
4929e39c5baSBill Taylor 
4939e39c5baSBill Taylor /*
4949e39c5baSBill Taylor  * hermon_intr_outmbox_list_init()
4959e39c5baSBill Taylor  *    Context: Only called from attach() path context
4969e39c5baSBill Taylor  */
4979e39c5baSBill Taylor int
hermon_intr_outmbox_list_init(hermon_state_t * state)4989e39c5baSBill Taylor hermon_intr_outmbox_list_init(hermon_state_t *state)
4999e39c5baSBill Taylor {
5009e39c5baSBill Taylor 	int		status;
5019e39c5baSBill Taylor 	uint_t		num_outmbox;
5029e39c5baSBill Taylor 
5039e39c5baSBill Taylor 	/* Initialize the interrupts "Out" mailbox list */
5049e39c5baSBill Taylor 	num_outmbox  =  (1 << state->hs_cfg_profile->cp_log_num_intr_outmbox);
5059e39c5baSBill Taylor 	status = hermon_impl_mboxlist_init(state, &state->hs_out_intr_mblist,
5069e39c5baSBill Taylor 	    num_outmbox, HERMON_INTR_OUT_MBOX);
5079e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
5089e39c5baSBill Taylor 		return (DDI_FAILURE);
5099e39c5baSBill Taylor 	}
5109e39c5baSBill Taylor 
5119e39c5baSBill Taylor 	return (DDI_SUCCESS);
5129e39c5baSBill Taylor }
5139e39c5baSBill Taylor 
5149e39c5baSBill Taylor 
5159e39c5baSBill Taylor /*
5169e39c5baSBill Taylor  * hermon_inmbox_list_fini()
5179e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
5189e39c5baSBill Taylor  */
5199e39c5baSBill Taylor void
hermon_inmbox_list_fini(hermon_state_t * state)5209e39c5baSBill Taylor hermon_inmbox_list_fini(hermon_state_t *state)
5219e39c5baSBill Taylor {
5229e39c5baSBill Taylor 	/* Free up the "In" mailbox list */
5239e39c5baSBill Taylor 	hermon_impl_mboxlist_fini(state, &state->hs_in_mblist);
5249e39c5baSBill Taylor }
5259e39c5baSBill Taylor 
5269e39c5baSBill Taylor 
5279e39c5baSBill Taylor /*
5289e39c5baSBill Taylor  * hermon_intr_inmbox_list_fini()
5299e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
5309e39c5baSBill Taylor  */
5319e39c5baSBill Taylor void
hermon_intr_inmbox_list_fini(hermon_state_t * state)5329e39c5baSBill Taylor hermon_intr_inmbox_list_fini(hermon_state_t *state)
5339e39c5baSBill Taylor {
5349e39c5baSBill Taylor 	/* Free up the interupts "In" mailbox list */
5359e39c5baSBill Taylor 	hermon_impl_mboxlist_fini(state, &state->hs_in_intr_mblist);
5369e39c5baSBill Taylor }
5379e39c5baSBill Taylor 
5389e39c5baSBill Taylor 
5399e39c5baSBill Taylor /*
5409e39c5baSBill Taylor  * hermon_outmbox_list_fini()
5419e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
5429e39c5baSBill Taylor  */
5439e39c5baSBill Taylor void
hermon_outmbox_list_fini(hermon_state_t * state)5449e39c5baSBill Taylor hermon_outmbox_list_fini(hermon_state_t *state)
5459e39c5baSBill Taylor {
5469e39c5baSBill Taylor 	/* Free up the "Out" mailbox list */
5479e39c5baSBill Taylor 	hermon_impl_mboxlist_fini(state, &state->hs_out_mblist);
5489e39c5baSBill Taylor }
5499e39c5baSBill Taylor 
5509e39c5baSBill Taylor 
5519e39c5baSBill Taylor /*
5529e39c5baSBill Taylor  * hermon_intr_outmbox_list_fini()
5539e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
5549e39c5baSBill Taylor  */
5559e39c5baSBill Taylor void
hermon_intr_outmbox_list_fini(hermon_state_t * state)5569e39c5baSBill Taylor hermon_intr_outmbox_list_fini(hermon_state_t *state)
5579e39c5baSBill Taylor {
5589e39c5baSBill Taylor 	/* Free up the interrupt "Out" mailbox list */
5599e39c5baSBill Taylor 	hermon_impl_mboxlist_fini(state, &state->hs_out_intr_mblist);
5609e39c5baSBill Taylor }
5619e39c5baSBill Taylor 
5629e39c5baSBill Taylor 
5639e39c5baSBill Taylor /*
5649e39c5baSBill Taylor  * hermon_impl_mbox_alloc()
5659e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
5669e39c5baSBill Taylor  */
5679e39c5baSBill Taylor static int
hermon_impl_mbox_alloc(hermon_state_t * state,hermon_mboxlist_t * mblist,hermon_mbox_t ** mb,uint_t mbox_wait)5689e39c5baSBill Taylor hermon_impl_mbox_alloc(hermon_state_t *state, hermon_mboxlist_t *mblist,
5699e39c5baSBill Taylor     hermon_mbox_t **mb, uint_t mbox_wait)
5709e39c5baSBill Taylor {
5719e39c5baSBill Taylor 	hermon_mbox_t	*mbox_ptr;
5729e39c5baSBill Taylor 	uint_t		index, next, prev;
5739e39c5baSBill Taylor 	uint_t		count, countmax;
5749e39c5baSBill Taylor 
5759e39c5baSBill Taylor 	/*
5769e39c5baSBill Taylor 	 * If the mailbox list is empty, then wait (if appropriate in the
5779e39c5baSBill Taylor 	 * current context).  Otherwise, grab the next available mailbox.
5789e39c5baSBill Taylor 	 */
5799e39c5baSBill Taylor 	if (mbox_wait == HERMON_NOSLEEP) {
5809e39c5baSBill Taylor 		count	 = 0;
5819e39c5baSBill Taylor 		countmax = state->hs_cfg_profile->cp_cmd_poll_max;
5829e39c5baSBill Taylor 
5839e39c5baSBill Taylor 		mutex_enter(&mblist->mbl_lock);
5849e39c5baSBill Taylor 		mblist->mbl_pollers++;
5859e39c5baSBill Taylor 		while (mblist->mbl_entries_free == 0) {
5869e39c5baSBill Taylor 			mutex_exit(&mblist->mbl_lock);
5879e39c5baSBill Taylor 			/* Delay loop polling for an available mbox */
5889e39c5baSBill Taylor 			if (++count > countmax) {
5899e39c5baSBill Taylor 				return (HERMON_CMD_INSUFF_RSRC);
5909e39c5baSBill Taylor 			}
5919e39c5baSBill Taylor 
5929e39c5baSBill Taylor 			/* Delay before polling for mailbox again */
5939e39c5baSBill Taylor 			drv_usecwait(state->hs_cfg_profile->cp_cmd_poll_delay);
5949e39c5baSBill Taylor 			mutex_enter(&mblist->mbl_lock);
5959e39c5baSBill Taylor 		}
5969e39c5baSBill Taylor 		mblist->mbl_pollers--;
5979e39c5baSBill Taylor 
5989e39c5baSBill Taylor 	/* HERMON_SLEEP */
5999e39c5baSBill Taylor 	} else {
6009e39c5baSBill Taylor 		/*
6019e39c5baSBill Taylor 		 * Grab lock here as we prepare to cv_wait if needed.
6029e39c5baSBill Taylor 		 */
6039e39c5baSBill Taylor 		mutex_enter(&mblist->mbl_lock);
6049e39c5baSBill Taylor 		while (mblist->mbl_entries_free == 0) {
6059e39c5baSBill Taylor 			/*
6069e39c5baSBill Taylor 			 * Wait (on cv) for a mailbox to become free.  Note:
6079e39c5baSBill Taylor 			 * Just as we do above in hermon_cmd_post(), we also
6089e39c5baSBill Taylor 			 * have the "__lock_lint" here to workaround warlock.
6099e39c5baSBill Taylor 			 * Warlock doesn't know that other parts of the Hermon
6109e39c5baSBill Taylor 			 * may occasionally call this routine while holding
6119e39c5baSBill Taylor 			 * their own locks, so it complains about this cv_wait.
6129e39c5baSBill Taylor 			 * In reality, however, the rest of the driver never
6139e39c5baSBill Taylor 			 * calls this routine with a lock held unless they pass
6149e39c5baSBill Taylor 			 * HERMON_CMD_NOSLEEP.
6159e39c5baSBill Taylor 			 */
6169e39c5baSBill Taylor 			mblist->mbl_waiters++;
6179e39c5baSBill Taylor #ifndef	__lock_lint
6189e39c5baSBill Taylor 			cv_wait(&mblist->mbl_cv, &mblist->mbl_lock);
6199e39c5baSBill Taylor #endif
6209e39c5baSBill Taylor 		}
6219e39c5baSBill Taylor 	}
6229e39c5baSBill Taylor 
6239e39c5baSBill Taylor 	/* Grab the next available mailbox from list */
6249e39c5baSBill Taylor 	mbox_ptr = mblist->mbl_mbox;
6259e39c5baSBill Taylor 	index	 = mblist->mbl_head_indx;
6269e39c5baSBill Taylor 	next	 = mbox_ptr[index].mb_next;
6279e39c5baSBill Taylor 	prev	 = mbox_ptr[index].mb_prev;
6289e39c5baSBill Taylor 
6299e39c5baSBill Taylor 	/* Remove it from the mailbox list */
6309e39c5baSBill Taylor 	mblist->mbl_mbox[next].mb_prev	= prev;
6319e39c5baSBill Taylor 	mblist->mbl_mbox[prev].mb_next	= next;
6329e39c5baSBill Taylor 	mblist->mbl_head_indx		= next;
6339e39c5baSBill Taylor 
6349e39c5baSBill Taylor 	/* Update the "free" count and return the mailbox pointer */
6359e39c5baSBill Taylor 	mblist->mbl_entries_free--;
6369e39c5baSBill Taylor 	*mb = &mbox_ptr[index];
6379e39c5baSBill Taylor 
6389e39c5baSBill Taylor 	mutex_exit(&mblist->mbl_lock);
6399e39c5baSBill Taylor 
6409e39c5baSBill Taylor 	return (HERMON_CMD_SUCCESS);
6419e39c5baSBill Taylor }
6429e39c5baSBill Taylor 
6439e39c5baSBill Taylor 
6449e39c5baSBill Taylor /*
6459e39c5baSBill Taylor  * hermon_impl_mbox_free()
6469e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
6479e39c5baSBill Taylor  */
6489e39c5baSBill Taylor static void
hermon_impl_mbox_free(hermon_mboxlist_t * mblist,hermon_mbox_t ** mb)6499e39c5baSBill Taylor hermon_impl_mbox_free(hermon_mboxlist_t *mblist, hermon_mbox_t **mb)
6509e39c5baSBill Taylor {
6519e39c5baSBill Taylor 	uint_t		mbox_indx;
6529e39c5baSBill Taylor 
6539e39c5baSBill Taylor 	mutex_enter(&mblist->mbl_lock);
6549e39c5baSBill Taylor 
6559e39c5baSBill Taylor 	/* Pull the "index" from mailbox entry */
6569e39c5baSBill Taylor 	mbox_indx = (*mb)->mb_indx;
6579e39c5baSBill Taylor 
6589e39c5baSBill Taylor 	/*
6599e39c5baSBill Taylor 	 * If mailbox list is not empty, then insert the entry.  Otherwise,
6609e39c5baSBill Taylor 	 * this is the only entry.  So update the pointers appropriately.
6619e39c5baSBill Taylor 	 */
6629e39c5baSBill Taylor 	if (mblist->mbl_entries_free++ != 0) {
6639e39c5baSBill Taylor 		/* Update the current mailbox */
6649e39c5baSBill Taylor 		(*mb)->mb_next = mblist->mbl_head_indx;
6659e39c5baSBill Taylor 		(*mb)->mb_prev = mblist->mbl_tail_indx;
6669e39c5baSBill Taylor 
6679e39c5baSBill Taylor 		/* Update head and tail mailboxes */
6689e39c5baSBill Taylor 		mblist->mbl_mbox[mblist->mbl_head_indx].mb_prev = mbox_indx;
6699e39c5baSBill Taylor 		mblist->mbl_mbox[mblist->mbl_tail_indx].mb_next = mbox_indx;
6709e39c5baSBill Taylor 
6719e39c5baSBill Taylor 		/* Update tail index */
6729e39c5baSBill Taylor 		mblist->mbl_tail_indx = mbox_indx;
6739e39c5baSBill Taylor 
6749e39c5baSBill Taylor 	} else {
6759e39c5baSBill Taylor 		/* Update the current mailbox */
6769e39c5baSBill Taylor 		(*mb)->mb_next = mbox_indx;
6779e39c5baSBill Taylor 		(*mb)->mb_prev = mbox_indx;
6789e39c5baSBill Taylor 
6799e39c5baSBill Taylor 		/* Update head and tail indexes */
6809e39c5baSBill Taylor 		mblist->mbl_tail_indx = mbox_indx;
6819e39c5baSBill Taylor 		mblist->mbl_head_indx = mbox_indx;
6829e39c5baSBill Taylor 	}
6839e39c5baSBill Taylor 
6849e39c5baSBill Taylor 	/*
6859e39c5baSBill Taylor 	 * Because we can have both waiters (SLEEP treads waiting for a
6869e39c5baSBill Taylor 	 * cv_signal to continue processing) and pollers (NOSLEEP treads
6879e39c5baSBill Taylor 	 * polling for a mailbox to become available), we try to share CPU time
6889e39c5baSBill Taylor 	 * between them.  We do this by signalling the waiters only every other
6899e39c5baSBill Taylor 	 * call to mbox_free.  This gives the pollers a chance to get some CPU
6909e39c5baSBill Taylor 	 * time to do their command.  If we signalled every time, the pollers
6919e39c5baSBill Taylor 	 * would have a much harder time getting CPU time.
6929e39c5baSBill Taylor 	 *
6939e39c5baSBill Taylor 	 * If there are waiters and no pollers, then we signal always.
6949e39c5baSBill Taylor 	 *
6959e39c5baSBill Taylor 	 * Otherwise, if there are either no waiters, there may in fact be
6969e39c5baSBill Taylor 	 * pollers, so we do not signal in that case.
6979e39c5baSBill Taylor 	 */
6989e39c5baSBill Taylor 	if (mblist->mbl_pollers > 0 && mblist->mbl_waiters > 0) {
6999e39c5baSBill Taylor 		/* flip the signal value */
700*2bc98732SRichard Lowe 		mblist->mbl_signal = (mblist->mbl_signal + 1) % 2;
7019e39c5baSBill Taylor 	} else if (mblist->mbl_waiters > 0) {
7029e39c5baSBill Taylor 		mblist->mbl_signal = 1;
7039e39c5baSBill Taylor 	} else {
7049e39c5baSBill Taylor 		mblist->mbl_signal = 0;
7059e39c5baSBill Taylor 	}
7069e39c5baSBill Taylor 
7079e39c5baSBill Taylor 	/*
7089e39c5baSBill Taylor 	 * Depending on the conditions in the previous check, we signal only if
7099e39c5baSBill Taylor 	 * we are supposed to.
7109e39c5baSBill Taylor 	 */
7119e39c5baSBill Taylor 	if (mblist->mbl_signal) {
7129e39c5baSBill Taylor 		mblist->mbl_waiters--;
7139e39c5baSBill Taylor 		cv_signal(&mblist->mbl_cv);
7149e39c5baSBill Taylor 	}
7159e39c5baSBill Taylor 
7169e39c5baSBill Taylor 	/* Clear out the mailbox entry pointer */
7179e39c5baSBill Taylor 	*mb = NULL;
7189e39c5baSBill Taylor 
7199e39c5baSBill Taylor 	mutex_exit(&mblist->mbl_lock);
7209e39c5baSBill Taylor }
7219e39c5baSBill Taylor 
7229e39c5baSBill Taylor 
7239e39c5baSBill Taylor /*
7249e39c5baSBill Taylor  * hermon_impl_mboxlist_init()
7259e39c5baSBill Taylor  *    Context: Only called from attach() path context
7269e39c5baSBill Taylor  */
7279e39c5baSBill Taylor static int
hermon_impl_mboxlist_init(hermon_state_t * state,hermon_mboxlist_t * mblist,uint_t num_mbox,hermon_rsrc_type_t type)7289e39c5baSBill Taylor hermon_impl_mboxlist_init(hermon_state_t *state, hermon_mboxlist_t *mblist,
7299e39c5baSBill Taylor     uint_t num_mbox, hermon_rsrc_type_t type)
7309e39c5baSBill Taylor {
7319e39c5baSBill Taylor 	hermon_rsrc_t		*rsrc;
7329e39c5baSBill Taylor 	ddi_dma_cookie_t	dma_cookie;
7339e39c5baSBill Taylor 	uint_t			dma_cookiecnt;
7349e39c5baSBill Taylor 	int			status, i;
7359e39c5baSBill Taylor 
7369e39c5baSBill Taylor 	/* Allocate the memory for the mailbox entries list */
7379e39c5baSBill Taylor 	mblist->mbl_list_sz = num_mbox;
7389e39c5baSBill Taylor 	mblist->mbl_mbox = kmem_zalloc(mblist->mbl_list_sz *
7399e39c5baSBill Taylor 	    sizeof (hermon_mbox_t), KM_SLEEP);
7409e39c5baSBill Taylor 
7419e39c5baSBill Taylor 	/* Initialize the mailbox entries list */
7429e39c5baSBill Taylor 	mblist->mbl_head_indx	 = 0;
7439e39c5baSBill Taylor 	mblist->mbl_tail_indx	 = mblist->mbl_list_sz - 1;
7449e39c5baSBill Taylor 	mblist->mbl_entries_free = mblist->mbl_list_sz;
7459e39c5baSBill Taylor 	mblist->mbl_waiters	 = 0;
7469e39c5baSBill Taylor 	mblist->mbl_num_alloc	 = 0;
7479e39c5baSBill Taylor 
7489e39c5baSBill Taylor 	/* Set up the mailbox list's cv and mutex */
7499e39c5baSBill Taylor 	mutex_init(&mblist->mbl_lock, NULL, MUTEX_DRIVER,
7509e39c5baSBill Taylor 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
7519e39c5baSBill Taylor 	cv_init(&mblist->mbl_cv, NULL, CV_DRIVER, NULL);
7529e39c5baSBill Taylor 
7539e39c5baSBill Taylor 	/* Initialize the mailbox list entries */
7549e39c5baSBill Taylor 	for (i = 0; i < mblist->mbl_list_sz; i++) {
7559e39c5baSBill Taylor 		/* Allocate resources for the mailbox */
7569e39c5baSBill Taylor 		status = hermon_rsrc_alloc(state, type, 1, HERMON_SLEEP,
7579e39c5baSBill Taylor 		    &rsrc);
7589e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
7599e39c5baSBill Taylor 			/* Jump to cleanup and return error */
7609e39c5baSBill Taylor 			goto mboxlist_init_fail;
7619e39c5baSBill Taylor 		}
7629e39c5baSBill Taylor 
7639e39c5baSBill Taylor 		/* Save away the mailbox resource info */
7649e39c5baSBill Taylor 		mblist->mbl_mbox[i].mb_rsrcptr	= rsrc;
7659e39c5baSBill Taylor 		mblist->mbl_mbox[i].mb_addr	= rsrc->hr_addr;
7669e39c5baSBill Taylor 		mblist->mbl_mbox[i].mb_acchdl	= rsrc->hr_acchdl;
7679e39c5baSBill Taylor 
7689e39c5baSBill Taylor 		/*
7699e39c5baSBill Taylor 		 * Get a PCI mapped address for each mailbox.  Note: this
7709e39c5baSBill Taylor 		 * uses the ddi_dma_handle return from the resource
7719e39c5baSBill Taylor 		 * allocation routine
7729e39c5baSBill Taylor 		 */
7739e39c5baSBill Taylor 		status = ddi_dma_addr_bind_handle(rsrc->hr_dmahdl, NULL,
7749e39c5baSBill Taylor 		    rsrc->hr_addr, rsrc->hr_len,
7759e39c5baSBill Taylor 		    (DDI_DMA_RDWR | DDI_DMA_CONSISTENT),
7769e39c5baSBill Taylor 		    DDI_DMA_SLEEP, NULL, &dma_cookie, &dma_cookiecnt);
7779e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
7789e39c5baSBill Taylor 			/* Jump to cleanup and return error */
7799e39c5baSBill Taylor 			hermon_rsrc_free(state, &rsrc);
7809e39c5baSBill Taylor 			goto mboxlist_init_fail;
7819e39c5baSBill Taylor 		}
7829e39c5baSBill Taylor 
7839e39c5baSBill Taylor 		/* Save away the mapped address for the mailbox */
7849e39c5baSBill Taylor 		mblist->mbl_mbox[i].mb_mapaddr	= dma_cookie.dmac_laddress;
7859e39c5baSBill Taylor 
7869e39c5baSBill Taylor 		/* Make each entry point to the "next" and "prev" entries */
7879e39c5baSBill Taylor 		mblist->mbl_mbox[i].mb_next	= i+1;
7889e39c5baSBill Taylor 		mblist->mbl_mbox[i].mb_prev	= i-1;
7899e39c5baSBill Taylor 		mblist->mbl_mbox[i].mb_indx	= i;
7909e39c5baSBill Taylor 		mblist->mbl_num_alloc		= i + 1;
7919e39c5baSBill Taylor 	}
7929e39c5baSBill Taylor 
7939e39c5baSBill Taylor 	/* Make the "head" and "tail" entries point to each other */
7949e39c5baSBill Taylor 	mblist->mbl_mbox[mblist->mbl_head_indx].mb_prev =
7959e39c5baSBill Taylor 	    mblist->mbl_tail_indx;
7969e39c5baSBill Taylor 	mblist->mbl_mbox[mblist->mbl_tail_indx].mb_next =
7979e39c5baSBill Taylor 	    mblist->mbl_head_indx;
7989e39c5baSBill Taylor 
7999e39c5baSBill Taylor 	return (DDI_SUCCESS);
8009e39c5baSBill Taylor 
8019e39c5baSBill Taylor mboxlist_init_fail:
8029e39c5baSBill Taylor 	hermon_impl_mboxlist_fini(state, mblist);
8039e39c5baSBill Taylor 
8049e39c5baSBill Taylor 	return (DDI_FAILURE);
8059e39c5baSBill Taylor }
8069e39c5baSBill Taylor 
8079e39c5baSBill Taylor 
8089e39c5baSBill Taylor /*
8099e39c5baSBill Taylor  * hermon_impl_mboxlist_fini()
8109e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
8119e39c5baSBill Taylor  */
8129e39c5baSBill Taylor static void
hermon_impl_mboxlist_fini(hermon_state_t * state,hermon_mboxlist_t * mblist)8139e39c5baSBill Taylor hermon_impl_mboxlist_fini(hermon_state_t *state, hermon_mboxlist_t *mblist)
8149e39c5baSBill Taylor {
8159e39c5baSBill Taylor 	hermon_rsrc_t	*rsrc;
8169e39c5baSBill Taylor 	int		i, status;
8179e39c5baSBill Taylor 
8189e39c5baSBill Taylor 	/* Release the resources for each of the mailbox list entries */
8199e39c5baSBill Taylor 	for (i = 0; i < mblist->mbl_num_alloc; i++) {
8209e39c5baSBill Taylor 		rsrc = mblist->mbl_mbox[i].mb_rsrcptr;
8219e39c5baSBill Taylor 
8229e39c5baSBill Taylor 		/*
8239e39c5baSBill Taylor 		 * First, unbind the DMA memory for the mailbox
8249e39c5baSBill Taylor 		 *
8259e39c5baSBill Taylor 		 * Note: The only way ddi_dma_unbind_handle() currently
8269e39c5baSBill Taylor 		 * can return an error is if the handle passed in is invalid.
8279e39c5baSBill Taylor 		 * Since this should never happen, we choose to return void
8289e39c5baSBill Taylor 		 * from this function!  If this does return an error,
8299e39c5baSBill Taylor 		 * however, then we print a warning message to the console.
8309e39c5baSBill Taylor 		 */
8319e39c5baSBill Taylor 		status = ddi_dma_unbind_handle(rsrc->hr_dmahdl);
8329e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
8339e39c5baSBill Taylor 			HERMON_WARNING(state, "failed to unbind DMA mapping");
8349e39c5baSBill Taylor 			return;
8359e39c5baSBill Taylor 		}
8369e39c5baSBill Taylor 
8379e39c5baSBill Taylor 		/* Next, free the mailbox resource */
8389e39c5baSBill Taylor 		hermon_rsrc_free(state, &rsrc);
8399e39c5baSBill Taylor 	}
8409e39c5baSBill Taylor 
8419e39c5baSBill Taylor 	/* Destroy the mailbox list mutex and cv */
8429e39c5baSBill Taylor 	mutex_destroy(&mblist->mbl_lock);
8439e39c5baSBill Taylor 	cv_destroy(&mblist->mbl_cv);
8449e39c5baSBill Taylor 
8459e39c5baSBill Taylor 	/* Free up the memory for tracking the mailbox list */
8469e39c5baSBill Taylor 	kmem_free(mblist->mbl_mbox, mblist->mbl_list_sz *
8479e39c5baSBill Taylor 	    sizeof (hermon_mbox_t));
8489e39c5baSBill Taylor }
8499e39c5baSBill Taylor 
8509e39c5baSBill Taylor 
8519e39c5baSBill Taylor /*
8529e39c5baSBill Taylor  * hermon_outstanding_cmd_alloc()
8539e39c5baSBill Taylor  *    Context: Can be called only from base context.
8549e39c5baSBill Taylor  */
8559e39c5baSBill Taylor static int
hermon_outstanding_cmd_alloc(hermon_state_t * state,hermon_cmd_t ** cmd_ptr,uint_t cmd_wait)8569e39c5baSBill Taylor hermon_outstanding_cmd_alloc(hermon_state_t *state, hermon_cmd_t **cmd_ptr,
8579e39c5baSBill Taylor     uint_t cmd_wait)
8589e39c5baSBill Taylor {
8599e39c5baSBill Taylor 	hermon_cmdlist_t	*cmd_list;
8609e39c5baSBill Taylor 	uint_t		next, prev, head;
8619e39c5baSBill Taylor 
8629e39c5baSBill Taylor 	cmd_list = &state->hs_cmd_list;
8639e39c5baSBill Taylor 	mutex_enter(&cmd_list->cml_lock);
8649e39c5baSBill Taylor 
8659e39c5baSBill Taylor 	/* Ensure that outstanding commands are supported */
8669e39c5baSBill Taylor 	ASSERT(cmd_list->cml_num_alloc != 0);
8679e39c5baSBill Taylor 
8689e39c5baSBill Taylor 	/*
8699e39c5baSBill Taylor 	 * If the outstanding command list is empty, then wait (if
8709e39c5baSBill Taylor 	 * appropriate in the current context).  Otherwise, grab the
8719e39c5baSBill Taylor 	 * next available command.
8729e39c5baSBill Taylor 	 */
8739e39c5baSBill Taylor 	while (cmd_list->cml_entries_free == 0) {
8749e39c5baSBill Taylor 		/* No free commands */
8759e39c5baSBill Taylor 		if (cmd_wait == HERMON_NOSLEEP) {
8769e39c5baSBill Taylor 			mutex_exit(&cmd_list->cml_lock);
8779e39c5baSBill Taylor 			return (HERMON_CMD_INSUFF_RSRC);
8789e39c5baSBill Taylor 		}
8799e39c5baSBill Taylor 
8809e39c5baSBill Taylor 		/*
8819e39c5baSBill Taylor 		 * Wait (on cv) for a command to become free.  Note: Just
8829e39c5baSBill Taylor 		 * as we do above in hermon_cmd_post(), we also have the
8839e39c5baSBill Taylor 		 * "__lock_lint" here to workaround warlock.  Warlock doesn't
8849e39c5baSBill Taylor 		 * know that other parts of the Hermon may occasionally call
8859e39c5baSBill Taylor 		 * this routine while holding their own locks, so it complains
8869e39c5baSBill Taylor 		 * about this cv_wait.  In reality, however, the rest of the
8879e39c5baSBill Taylor 		 * driver never calls this routine with a lock held unless
8889e39c5baSBill Taylor 		 * they pass HERMON_CMD_NOSLEEP.
8899e39c5baSBill Taylor 		 */
8909e39c5baSBill Taylor 		cmd_list->cml_waiters++;
8919e39c5baSBill Taylor #ifndef	__lock_lint
8929e39c5baSBill Taylor 		cv_wait(&cmd_list->cml_cv, &cmd_list->cml_lock);
8939e39c5baSBill Taylor #endif
8949e39c5baSBill Taylor 	}
8959e39c5baSBill Taylor 
8969e39c5baSBill Taylor 	/* Grab the next available command from the list */
8979e39c5baSBill Taylor 	head = cmd_list->cml_head_indx;
8989e39c5baSBill Taylor 	*cmd_ptr = &cmd_list->cml_cmd[head];
8999e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(**cmd_ptr))
9009e39c5baSBill Taylor 	next = (*cmd_ptr)->cmd_next;
9019e39c5baSBill Taylor 	prev = (*cmd_ptr)->cmd_prev;
9029e39c5baSBill Taylor 	(*cmd_ptr)->cmd_status = HERMON_CMD_INVALID_STATUS;
9039e39c5baSBill Taylor 
9049e39c5baSBill Taylor 	/* Remove it from the command list */
9059e39c5baSBill Taylor 	cmd_list->cml_cmd[next].cmd_prev = prev;
9069e39c5baSBill Taylor 	cmd_list->cml_cmd[prev].cmd_next = next;
9079e39c5baSBill Taylor 	cmd_list->cml_head_indx		 = next;
9089e39c5baSBill Taylor 
9099e39c5baSBill Taylor 	/* Update the "free" count and return */
9109e39c5baSBill Taylor 	cmd_list->cml_entries_free--;
9119e39c5baSBill Taylor 
9129e39c5baSBill Taylor 	mutex_exit(&cmd_list->cml_lock);
9139e39c5baSBill Taylor 
9149e39c5baSBill Taylor 	return (HERMON_CMD_SUCCESS);
9159e39c5baSBill Taylor }
9169e39c5baSBill Taylor 
9179e39c5baSBill Taylor 
9189e39c5baSBill Taylor /*
9199e39c5baSBill Taylor  * hermon_outstanding_cmd_free()
9209e39c5baSBill Taylor  *    Context: Can be called only from base context.
9219e39c5baSBill Taylor  */
9229e39c5baSBill Taylor static void
hermon_outstanding_cmd_free(hermon_state_t * state,hermon_cmd_t ** cmd_ptr)9239e39c5baSBill Taylor hermon_outstanding_cmd_free(hermon_state_t *state, hermon_cmd_t **cmd_ptr)
9249e39c5baSBill Taylor {
9259e39c5baSBill Taylor 	hermon_cmdlist_t	*cmd_list;
9269e39c5baSBill Taylor 	uint_t		cmd_indx;
9279e39c5baSBill Taylor 
9289e39c5baSBill Taylor 	cmd_list = &state->hs_cmd_list;
9299e39c5baSBill Taylor 	mutex_enter(&cmd_list->cml_lock);
9309e39c5baSBill Taylor 
9319e39c5baSBill Taylor 	/* Pull the "index" from command entry */
9329e39c5baSBill Taylor 	cmd_indx = (*cmd_ptr)->cmd_indx;
9339e39c5baSBill Taylor 
9349e39c5baSBill Taylor 	/*
9359e39c5baSBill Taylor 	 * If outstanding command list is not empty, then insert the entry.
9369e39c5baSBill Taylor 	 * Otherwise, this is the only entry.  So update the pointers
9379e39c5baSBill Taylor 	 * appropriately.
9389e39c5baSBill Taylor 	 */
9399e39c5baSBill Taylor 	if (cmd_list->cml_entries_free++ != 0) {
9409e39c5baSBill Taylor 		/* Update the current command */
9419e39c5baSBill Taylor 		(*cmd_ptr)->cmd_next = cmd_list->cml_head_indx;
9429e39c5baSBill Taylor 		(*cmd_ptr)->cmd_prev = cmd_list->cml_tail_indx;
9439e39c5baSBill Taylor 
9449e39c5baSBill Taylor 		/* Update head and tail commands */
9459e39c5baSBill Taylor 		cmd_list->cml_cmd[cmd_list->cml_head_indx].cmd_prev = cmd_indx;
9469e39c5baSBill Taylor 		cmd_list->cml_cmd[cmd_list->cml_tail_indx].cmd_next = cmd_indx;
9479e39c5baSBill Taylor 
9489e39c5baSBill Taylor 		/* Update tail index */
9499e39c5baSBill Taylor 		cmd_list->cml_tail_indx = cmd_indx;
9509e39c5baSBill Taylor 
9519e39c5baSBill Taylor 	} else {
9529e39c5baSBill Taylor 		/* Update the current command */
9539e39c5baSBill Taylor 		(*cmd_ptr)->cmd_next = cmd_indx;
9549e39c5baSBill Taylor 		(*cmd_ptr)->cmd_prev = cmd_indx;
9559e39c5baSBill Taylor 
9569e39c5baSBill Taylor 		/* Update head and tail indexes */
9579e39c5baSBill Taylor 		cmd_list->cml_head_indx = cmd_indx;
9589e39c5baSBill Taylor 		cmd_list->cml_tail_indx = cmd_indx;
9599e39c5baSBill Taylor 	}
9609e39c5baSBill Taylor 
9619e39c5baSBill Taylor 	/* If there are threads waiting, signal one of them */
9629e39c5baSBill Taylor 	if (cmd_list->cml_waiters > 0) {
9639e39c5baSBill Taylor 		cmd_list->cml_waiters--;
9649e39c5baSBill Taylor 		cv_signal(&cmd_list->cml_cv);
9659e39c5baSBill Taylor 	}
9669e39c5baSBill Taylor 
9679e39c5baSBill Taylor 	/* Clear out the command entry pointer */
9689e39c5baSBill Taylor 	*cmd_ptr = NULL;
9699e39c5baSBill Taylor 
9709e39c5baSBill Taylor 	mutex_exit(&cmd_list->cml_lock);
9719e39c5baSBill Taylor }
9729e39c5baSBill Taylor 
9739e39c5baSBill Taylor 
9749e39c5baSBill Taylor /*
9759e39c5baSBill Taylor  * hermon_write_hcr()
9769e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
9779e39c5baSBill Taylor  */
9789e39c5baSBill Taylor static int
hermon_write_hcr(hermon_state_t * state,hermon_cmd_post_t * cmdpost,uint16_t token,int * hw_err)9799e39c5baSBill Taylor hermon_write_hcr(hermon_state_t *state, hermon_cmd_post_t *cmdpost,
9809e39c5baSBill Taylor     uint16_t token, int *hw_err)
9819e39c5baSBill Taylor {
9829e39c5baSBill Taylor 	hermon_hw_hcr_t	*hcr;
9839e39c5baSBill Taylor 	uint_t		status, count, countmax;
9849e39c5baSBill Taylor 	uint64_t	hcrreg;
9859e39c5baSBill Taylor 	uint64_t	togmask;
9869e39c5baSBill Taylor 	ddi_acc_handle_t cmdhdl = hermon_get_cmdhdl(state);
9879e39c5baSBill Taylor 	boolean_t	hw_error = B_FALSE;
9889e39c5baSBill Taylor 
9899e39c5baSBill Taylor 	/* initialize the FMA retry loop */
9909e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
9919e39c5baSBill Taylor 
9929e39c5baSBill Taylor 	/*
9939e39c5baSBill Taylor 	 * Grab the "HCR access" lock if the driver is not in
9949e39c5baSBill Taylor 	 * fastreboot. In fastreboot, this function is called
9959e39c5baSBill Taylor 	 * with the single thread but in high interrupt context
9969e39c5baSBill Taylor 	 * (so that this mutex lock cannot be used).
9979e39c5baSBill Taylor 	 */
9989e39c5baSBill Taylor #ifdef __lock_lint
9999e39c5baSBill Taylor 	mutex_enter(&state->hs_cmd_regs.hcr_lock);
10009e39c5baSBill Taylor #else
10019e39c5baSBill Taylor 	if (!HERMON_IN_FASTREBOOT(state)) {
10029e39c5baSBill Taylor 		mutex_enter(&state->hs_cmd_regs.hcr_lock);
10039e39c5baSBill Taylor 	}
10049e39c5baSBill Taylor #endif
10059e39c5baSBill Taylor 	hcr = state->hs_cmd_regs.hcr;
10069e39c5baSBill Taylor 
10079e39c5baSBill Taylor 	/*
10089e39c5baSBill Taylor 	 * First, check the "go" bit to see if any previous hcr usage is
10099e39c5baSBill Taylor 	 * complete.  As long as it is set then we must continue to poll.
10109e39c5baSBill Taylor 	 */
10119e39c5baSBill Taylor 
10129e39c5baSBill Taylor 	countmax = state->hs_cfg_profile->cp_cmd_poll_max;
10139e39c5baSBill Taylor 	togmask = (state->hs_cmd_toggle & 0x01) << HERMON_HCR_CMD_T_SHFT;
10149e39c5baSBill Taylor 
10159e39c5baSBill Taylor 	/* the FMA retry loop starts. */
10169e39c5baSBill Taylor 	hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
10179e39c5baSBill Taylor 	    fm_test);
10189e39c5baSBill Taylor 
10199e39c5baSBill Taylor 	count	 = 0;
10209e39c5baSBill Taylor 	for (;;) {
10219e39c5baSBill Taylor 		hcrreg = ddi_get32(cmdhdl, &hcr->cmd);
10229e39c5baSBill Taylor 
10239e39c5baSBill Taylor 		/* If "go" bit is clear and toggle reset, then done */
10249e39c5baSBill Taylor 		if (((hcrreg & HERMON_HCR_CMD_GO_MASK) == 0) &&
10259e39c5baSBill Taylor 		    ((hcrreg & HERMON_HCR_CMD_T_MASK)  == togmask)) {
10269e39c5baSBill Taylor 			break;
10279e39c5baSBill Taylor 		}
10289e39c5baSBill Taylor 		/* Delay before polling the "go" bit again */
10299e39c5baSBill Taylor 		drv_usecwait(state->hs_cfg_profile->cp_cmd_poll_delay);
10309e39c5baSBill Taylor 
10319e39c5baSBill Taylor 		/*
10329e39c5baSBill Taylor 		 * If we poll more than the maximum number of times, then
10339e39c5baSBill Taylor 		 * return a "timeout" error.
10349e39c5baSBill Taylor 		 */
10359e39c5baSBill Taylor 		if (++count > countmax) {
10369e39c5baSBill Taylor #ifdef __lock_lint
10379e39c5baSBill Taylor 			mutex_exit(&state->hs_cmd_regs.hcr_lock);
10389e39c5baSBill Taylor #else
10399e39c5baSBill Taylor 			if (!HERMON_IN_FASTREBOOT(state)) {
10409e39c5baSBill Taylor 				mutex_exit(&state->hs_cmd_regs.hcr_lock);
10419e39c5baSBill Taylor 			}
10429e39c5baSBill Taylor #endif
10439e39c5baSBill Taylor 			cmn_err(CE_NOTE, "write_hcr: cannot start cmd");
10449e39c5baSBill Taylor 			return (HERMON_CMD_TIMEOUT_GOBIT);
10459e39c5baSBill Taylor 		}
10469e39c5baSBill Taylor 	}
10479e39c5baSBill Taylor 
10489e39c5baSBill Taylor 	/* the FMA retry loop ends. */
10499e39c5baSBill Taylor 	hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
10509e39c5baSBill Taylor 	    fm_test);
10519e39c5baSBill Taylor 
10529e39c5baSBill Taylor 	/* check if there is a transient error */
10539e39c5baSBill Taylor 	if (fm_loop_cnt != HCA_PIO_RETRY_CNT) {
10549e39c5baSBill Taylor 		hw_error = B_TRUE;
10559e39c5baSBill Taylor 	}
10569e39c5baSBill Taylor 
10579e39c5baSBill Taylor 	/* succeeded, so update the cmd counter for this cmd's completion */
10589e39c5baSBill Taylor 	state->hs_cmd_toggle++;
10599e39c5baSBill Taylor 	togmask = (state->hs_cmd_toggle & 0x01) << HERMON_HCR_CMD_T_SHFT;
10609e39c5baSBill Taylor 
10619e39c5baSBill Taylor 	/* the FMA retry loop starts. */
10629e39c5baSBill Taylor 	hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
10639e39c5baSBill Taylor 	    fm_test);
10649e39c5baSBill Taylor 
10659e39c5baSBill Taylor 	/* Write "inparam" as a 64-bit quantity */
10669e39c5baSBill Taylor 	ddi_put64(cmdhdl, (uint64_t *)(void *)&hcr->in_param0,
10679e39c5baSBill Taylor 	    cmdpost->cp_inparm);
10689e39c5baSBill Taylor 
10699e39c5baSBill Taylor 	/* Write "inmod" and 32-bits of "outparam" as 64-bit */
10709e39c5baSBill Taylor 	hcrreg = ((uint64_t)cmdpost->cp_inmod << 32);
10719e39c5baSBill Taylor 	hcrreg = hcrreg | (cmdpost->cp_outparm >> 32);
10729e39c5baSBill Taylor 
10739e39c5baSBill Taylor 	ddi_put64(cmdhdl, (uint64_t *)(void *)&hcr->input_modifier, hcrreg);
10749e39c5baSBill Taylor 
10759e39c5baSBill Taylor 	/* Write the other 32-bits of "outparam" and "token" as 64-bit */
10769e39c5baSBill Taylor 	hcrreg = (cmdpost->cp_outparm << 32);
10779e39c5baSBill Taylor 	hcrreg = hcrreg | ((uint32_t)token << HERMON_HCR_TOKEN_SHIFT);
10789e39c5baSBill Taylor 
10799e39c5baSBill Taylor 	ddi_put64(cmdhdl, (uint64_t *)(void *)&hcr->out_param1, hcrreg);
10809e39c5baSBill Taylor 
10819e39c5baSBill Taylor 	/* Then setup the final hcrreg to hit doorbell (i.e. "go" bit) */
10829e39c5baSBill Taylor 	hcrreg = HERMON_HCR_CMD_GO_MASK;
10839e39c5baSBill Taylor 	/* Then set the toggle bit for this command */
10849e39c5baSBill Taylor 	hcrreg |= (state->hs_cmd_toggle & 0x01) << HERMON_HCR_CMD_T_SHFT;
10859e39c5baSBill Taylor 	if (cmdpost->cp_flags == HERMON_CMD_SLEEP_NOSPIN) {
10869e39c5baSBill Taylor 		hcrreg = hcrreg | HERMON_HCR_CMD_E_MASK;
10879e39c5baSBill Taylor 	}
10889e39c5baSBill Taylor 	hcrreg = hcrreg | (cmdpost->cp_opmod << HERMON_HCR_CMD_OPMOD_SHFT);
10899e39c5baSBill Taylor 	hcrreg = hcrreg | (cmdpost->cp_opcode);
10909e39c5baSBill Taylor 
10919e39c5baSBill Taylor 	/* Write the doorbell to the HCR */
10929e39c5baSBill Taylor 	ddi_put32(cmdhdl, &hcr->cmd, hcrreg);
10939e39c5baSBill Taylor 
10949e39c5baSBill Taylor 	/* the FMA retry loop ends. */
10959e39c5baSBill Taylor 	hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
10969e39c5baSBill Taylor 	    fm_test);
10979e39c5baSBill Taylor 
10989e39c5baSBill Taylor 	/* check if there is a transient error */
10999e39c5baSBill Taylor 	if (fm_loop_cnt != HCA_PIO_RETRY_CNT) {
11009e39c5baSBill Taylor 		hw_error = B_TRUE;
11019e39c5baSBill Taylor 	}
11029e39c5baSBill Taylor 
11039e39c5baSBill Taylor 	/*
11049e39c5baSBill Taylor 	 * In the SPIN case we read the HCR and check the "go" bit.  For the
11059e39c5baSBill Taylor 	 * NOSPIN case we do not have to poll, we simply release the HCR lock
11069e39c5baSBill Taylor 	 * and return.
11079e39c5baSBill Taylor 	 */
11089e39c5baSBill Taylor 	if (cmdpost->cp_flags == HERMON_CMD_NOSLEEP_SPIN) {
11099e39c5baSBill Taylor 
11109e39c5baSBill Taylor 		countmax = (state->hs_cfg_profile->cp_cmd_poll_max << 4);
11119e39c5baSBill Taylor 
11129e39c5baSBill Taylor 		/* the FMA retry loop starts. */
11139e39c5baSBill Taylor 		hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt,
11149e39c5baSBill Taylor 		    fm_status, fm_test);
11159e39c5baSBill Taylor 
11169e39c5baSBill Taylor 		count	 = 0;
11179e39c5baSBill Taylor 		for (;;) {
11189e39c5baSBill Taylor 			hcrreg = ddi_get32(cmdhdl, &hcr->cmd);
11199e39c5baSBill Taylor 
11209e39c5baSBill Taylor 			/* If "go" bit is clear and toggle reset, then done */
11219e39c5baSBill Taylor 			if (((hcrreg & HERMON_HCR_CMD_GO_MASK) == 0) &&
11229e39c5baSBill Taylor 			    ((hcrreg & HERMON_HCR_CMD_T_MASK)  == togmask)) {
11239e39c5baSBill Taylor 				break;
11249e39c5baSBill Taylor 			}
11259e39c5baSBill Taylor 			/* Delay before polling the "go" bit again */
11269e39c5baSBill Taylor 			drv_usecwait(state->hs_cfg_profile->cp_cmd_poll_delay);
11279e39c5baSBill Taylor 
11289e39c5baSBill Taylor 			/*
11299e39c5baSBill Taylor 			 * If we poll more than the maximum number of times,
11309e39c5baSBill Taylor 			 * then return a "timeout" error.
11319e39c5baSBill Taylor 			 */
11329e39c5baSBill Taylor 			if (++count > countmax) {
11339e39c5baSBill Taylor #ifdef __lock_lint
11349e39c5baSBill Taylor 				mutex_exit(&state-> hs_cmd_regs.hcr_lock);
11359e39c5baSBill Taylor #else
11369e39c5baSBill Taylor 				if (!HERMON_IN_FASTREBOOT(state)) {
11379e39c5baSBill Taylor 					mutex_exit(&state->
11389e39c5baSBill Taylor 					    hs_cmd_regs.hcr_lock);
11399e39c5baSBill Taylor 				}
11409e39c5baSBill Taylor #endif
11419e39c5baSBill Taylor 				cmn_err(CE_NOTE,
11429e39c5baSBill Taylor 				    "write_hcr: cannot complete cmd");
11439e39c5baSBill Taylor 				return (HERMON_CMD_TIMEOUT_GOBIT);
11449e39c5baSBill Taylor 			}
11459e39c5baSBill Taylor 		}
11469e39c5baSBill Taylor 
11479e39c5baSBill Taylor 		/* Pull out the "status" bits from the HCR */
11489e39c5baSBill Taylor 		status = (hcrreg >> HERMON_HCR_CMD_STATUS_SHFT);
11499e39c5baSBill Taylor 
11509e39c5baSBill Taylor 		/*
11519e39c5baSBill Taylor 		 * Read the "outparam" value.  Note: we have to read "outparam"
11529e39c5baSBill Taylor 		 * as two separate 32-bit reads because the field in the HCR is
11539e39c5baSBill Taylor 		 * not 64-bit aligned.
11549e39c5baSBill Taylor 		 */
11559e39c5baSBill Taylor 		hcrreg = ddi_get32(cmdhdl, &hcr->out_param0);
11569e39c5baSBill Taylor 		cmdpost->cp_outparm = hcrreg << 32;
11579e39c5baSBill Taylor 		hcrreg = ddi_get32(cmdhdl, &hcr->out_param1);
11589e39c5baSBill Taylor 		cmdpost->cp_outparm |= hcrreg;
11599e39c5baSBill Taylor 
11609e39c5baSBill Taylor 		/* the FMA retry loop ends. */
11619e39c5baSBill Taylor 		hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
11629e39c5baSBill Taylor 		    fm_test);
11639e39c5baSBill Taylor 
11649e39c5baSBill Taylor 		/* check if there is a transient error */
11659e39c5baSBill Taylor 		if (fm_loop_cnt != HCA_PIO_RETRY_CNT) {
11669e39c5baSBill Taylor 			hw_error = B_TRUE;
11679e39c5baSBill Taylor 		}
11689e39c5baSBill Taylor 
11699e39c5baSBill Taylor 	/* END SPIN */
11709e39c5baSBill Taylor 	} else {		/* NOSPIN */
11719e39c5baSBill Taylor 		status = HERMON_CMD_SUCCESS;
11729e39c5baSBill Taylor 	}
11739e39c5baSBill Taylor 
11749e39c5baSBill Taylor 	/* Drop the "HCR access" lock */
11759e39c5baSBill Taylor #ifdef __lock_lint
11769e39c5baSBill Taylor 	mutex_exit(&state->hs_cmd_regs.hcr_lock);
11779e39c5baSBill Taylor #else
11789e39c5baSBill Taylor 	if (!HERMON_IN_FASTREBOOT(state)) {
11799e39c5baSBill Taylor 		mutex_exit(&state->hs_cmd_regs.hcr_lock);
11809e39c5baSBill Taylor 	}
11819e39c5baSBill Taylor #endif
11829e39c5baSBill Taylor 	if (hw_error == B_TRUE) {
11839e39c5baSBill Taylor 		*hw_err = HCA_PIO_TRANSIENT;
11849e39c5baSBill Taylor 	} else {
11859e39c5baSBill Taylor 		*hw_err = HCA_PIO_OK;
11869e39c5baSBill Taylor 	}
11879e39c5baSBill Taylor #ifdef FMA_TEST
11889e39c5baSBill Taylor 	if (hermon_test_num == -3) {
11899e39c5baSBill Taylor 		status = HERMON_CMD_INTERNAL_ERR;
11909e39c5baSBill Taylor 	}
11919e39c5baSBill Taylor #endif
11929e39c5baSBill Taylor 	return (status);
11939e39c5baSBill Taylor 
11949e39c5baSBill Taylor pio_error:
11959e39c5baSBill Taylor #ifdef __lock_lint
11969e39c5baSBill Taylor 	mutex_exit(&state->hs_cmd_regs.hcr_lock);
11979e39c5baSBill Taylor #else
11989e39c5baSBill Taylor 	if (!HERMON_IN_FASTREBOOT(state)) {
11999e39c5baSBill Taylor 		mutex_exit(&state->hs_cmd_regs.hcr_lock);
12009e39c5baSBill Taylor 	}
12019e39c5baSBill Taylor #endif
12029e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_NON_FATAL);
12039e39c5baSBill Taylor 	*hw_err = HCA_PIO_PERSISTENT;
12049e39c5baSBill Taylor 	return (HERMON_CMD_INVALID_STATUS);
12059e39c5baSBill Taylor }
12069e39c5baSBill Taylor 
12079e39c5baSBill Taylor 
12089e39c5baSBill Taylor /*
12099e39c5baSBill Taylor  * hermon_outstanding_cmdlist_init()
12109e39c5baSBill Taylor  *    Context: Only called from attach() path context
12119e39c5baSBill Taylor  */
12129e39c5baSBill Taylor int
hermon_outstanding_cmdlist_init(hermon_state_t * state)12139e39c5baSBill Taylor hermon_outstanding_cmdlist_init(hermon_state_t *state)
12149e39c5baSBill Taylor {
12159e39c5baSBill Taylor 	uint_t		num_outstanding_cmds, head, tail;
12169e39c5baSBill Taylor 	int		i;
12179e39c5baSBill Taylor 
12189e39c5baSBill Taylor 	/*
12199e39c5baSBill Taylor 	 * Determine the number of the outstanding commands supported
12209e39c5baSBill Taylor 	 * by the Hermon device (obtained from the QUERY_FW command).  Note:
12219e39c5baSBill Taylor 	 * Because we handle both SLEEP and NOSLEEP cases around the hermon HCR,
12229e39c5baSBill Taylor 	 * we know that when an interrupt comes in it will be next on the
12239e39c5baSBill Taylor 	 * command register, and will at most have to wait one commands time.
12249e39c5baSBill Taylor 	 * We do not have to reserve an outstanding command here for
12259e39c5baSBill Taylor 	 * interrupts.
12269e39c5baSBill Taylor 	 */
12279e39c5baSBill Taylor 	num_outstanding_cmds = (1 << state->hs_fw.log_max_cmd);
12289e39c5baSBill Taylor 
12299e39c5baSBill Taylor 	/* Initialize the outstanding command list */
12309e39c5baSBill Taylor 	state->hs_cmd_list.cml_list_sz	 = num_outstanding_cmds;
12319e39c5baSBill Taylor 	state->hs_cmd_list.cml_head_indx = 0;
12329e39c5baSBill Taylor 	state->hs_cmd_list.cml_tail_indx = state->hs_cmd_list.cml_list_sz - 1;
12339e39c5baSBill Taylor 	state->hs_cmd_list.cml_entries_free = state->hs_cmd_list.cml_list_sz;
12349e39c5baSBill Taylor 	state->hs_cmd_list.cml_waiters	 = 0;
12359e39c5baSBill Taylor 	state->hs_cmd_list.cml_num_alloc = 0;
12369e39c5baSBill Taylor 
12379e39c5baSBill Taylor 	/* Allocate the memory for the outstanding command list */
12389e39c5baSBill Taylor 	if (num_outstanding_cmds) {
12399e39c5baSBill Taylor 		state->hs_cmd_list.cml_cmd =
12409e39c5baSBill Taylor 		    kmem_zalloc(state->hs_cmd_list.cml_list_sz *
12419e39c5baSBill Taylor 		    sizeof (hermon_cmd_t), KM_SLEEP);
12429e39c5baSBill Taylor 	}
12439e39c5baSBill Taylor 	mutex_init(&state->hs_cmd_list.cml_lock, NULL, MUTEX_DRIVER,
12449e39c5baSBill Taylor 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
12459e39c5baSBill Taylor 	cv_init(&state->hs_cmd_list.cml_cv, NULL, CV_DRIVER, NULL);
12469e39c5baSBill Taylor 
12479e39c5baSBill Taylor 	/* Initialize the individual outstanding command list entries */
12489e39c5baSBill Taylor 	for (i = 0; i < state->hs_cmd_list.cml_list_sz; i++) {
12499e39c5baSBill Taylor 		mutex_init(&state->hs_cmd_list.cml_cmd[i].cmd_comp_lock,
12509e39c5baSBill Taylor 		    NULL, MUTEX_DRIVER, DDI_INTR_PRI(state->hs_intrmsi_pri));
12519e39c5baSBill Taylor 		cv_init(&state->hs_cmd_list.cml_cmd[i].cmd_comp_cv, NULL,
12529e39c5baSBill Taylor 		    CV_DRIVER, NULL);
12539e39c5baSBill Taylor 
12549e39c5baSBill Taylor 		state->hs_cmd_list.cml_cmd[i].cmd_next	= i+1;
12559e39c5baSBill Taylor 		state->hs_cmd_list.cml_cmd[i].cmd_prev	= i-1;
12569e39c5baSBill Taylor 		state->hs_cmd_list.cml_cmd[i].cmd_indx	= i;
12579e39c5baSBill Taylor 		state->hs_cmd_list.cml_num_alloc	= i + 1;
12589e39c5baSBill Taylor 	}
12599e39c5baSBill Taylor 	if (num_outstanding_cmds) {
12609e39c5baSBill Taylor 		head = state->hs_cmd_list.cml_head_indx;
12619e39c5baSBill Taylor 		tail = state->hs_cmd_list.cml_tail_indx;
12629e39c5baSBill Taylor 		state->hs_cmd_list.cml_cmd[head].cmd_prev =
12639e39c5baSBill Taylor 		    state->hs_cmd_list.cml_tail_indx;
12649e39c5baSBill Taylor 		state->hs_cmd_list.cml_cmd[tail].cmd_next =
12659e39c5baSBill Taylor 		    state->hs_cmd_list.cml_head_indx;
12669e39c5baSBill Taylor 	}
12679e39c5baSBill Taylor 
12689e39c5baSBill Taylor 	return (DDI_SUCCESS);
12699e39c5baSBill Taylor }
12709e39c5baSBill Taylor 
12719e39c5baSBill Taylor 
12729e39c5baSBill Taylor /*
12739e39c5baSBill Taylor  * hermon_outstanding_cmdlist_fini()
12749e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
12759e39c5baSBill Taylor  */
12769e39c5baSBill Taylor void
hermon_outstanding_cmdlist_fini(hermon_state_t * state)12779e39c5baSBill Taylor hermon_outstanding_cmdlist_fini(hermon_state_t *state)
12789e39c5baSBill Taylor {
12799e39c5baSBill Taylor 	int		i;
12809e39c5baSBill Taylor 
12819e39c5baSBill Taylor 	/* Destroy the outstanding command list entries */
12829e39c5baSBill Taylor 	for (i = 0; i < state->hs_cmd_list.cml_num_alloc; i++) {
12839e39c5baSBill Taylor 		mutex_destroy(&state->hs_cmd_list.cml_cmd[i].cmd_comp_lock);
12849e39c5baSBill Taylor 		cv_destroy(&state->hs_cmd_list.cml_cmd[i].cmd_comp_cv);
12859e39c5baSBill Taylor 	}
12869e39c5baSBill Taylor 
12879e39c5baSBill Taylor 	/* Destroy the lock (and cv) and free up memory for list */
12889e39c5baSBill Taylor 	mutex_destroy(&state->hs_cmd_list.cml_lock);
12899e39c5baSBill Taylor 	cv_destroy(&state->hs_cmd_list.cml_cv);
12909e39c5baSBill Taylor 	if (state->hs_cmd_list.cml_num_alloc) {
12919e39c5baSBill Taylor 		kmem_free(state->hs_cmd_list.cml_cmd,
12929e39c5baSBill Taylor 		    state->hs_cmd_list.cml_list_sz * sizeof (hermon_cmd_t));
12939e39c5baSBill Taylor 	}
12949e39c5baSBill Taylor }
12959e39c5baSBill Taylor 
12969e39c5baSBill Taylor 
12979e39c5baSBill Taylor /*
12989e39c5baSBill Taylor  * hermon_mbox_sync()
12999e39c5baSBill Taylor  */
13009e39c5baSBill Taylor static void
hermon_mbox_sync(hermon_mbox_t * mbox,uint_t offset,uint_t length,uint_t flag)13019e39c5baSBill Taylor hermon_mbox_sync(hermon_mbox_t *mbox, uint_t offset, uint_t length,
13029e39c5baSBill Taylor     uint_t flag)
13039e39c5baSBill Taylor {
13049e39c5baSBill Taylor 	ddi_dma_handle_t	dmahdl;
13059e39c5baSBill Taylor 	int			status;
13069e39c5baSBill Taylor 
13079e39c5baSBill Taylor 	/* Get the DMA handle from mailbox */
13089e39c5baSBill Taylor 	dmahdl = mbox->mb_rsrcptr->hr_dmahdl;
13099e39c5baSBill Taylor 
13109e39c5baSBill Taylor 	/* Calculate offset into mailbox */
13119e39c5baSBill Taylor 	status = ddi_dma_sync(dmahdl, (off_t)offset, (size_t)length, flag);
13129e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
13139e39c5baSBill Taylor 		return;
13149e39c5baSBill Taylor 	}
13159e39c5baSBill Taylor }
13169e39c5baSBill Taylor 
13179e39c5baSBill Taylor 
13189e39c5baSBill Taylor /*
13199e39c5baSBill Taylor  * hermon_init_hca_cmd_post()
13209e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
13219e39c5baSBill Taylor  *    (Currently called only from attach() path context)
13229e39c5baSBill Taylor  */
13239e39c5baSBill Taylor int
hermon_init_hca_cmd_post(hermon_state_t * state,hermon_hw_initqueryhca_t * inithca,uint_t sleepflag)13249e39c5baSBill Taylor hermon_init_hca_cmd_post(hermon_state_t *state,
13259e39c5baSBill Taylor     hermon_hw_initqueryhca_t *inithca, uint_t sleepflag)
13269e39c5baSBill Taylor {
13279e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
13289e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
13299e39c5baSBill Taylor 	uint64_t		data;
13309e39c5baSBill Taylor 	uint_t			size;
13319e39c5baSBill Taylor 	int			status, i;
13329e39c5baSBill Taylor 
13339e39c5baSBill Taylor 	/* Make sure we are called with the correct flag */
13349e39c5baSBill Taylor 	ASSERT(sleepflag == HERMON_CMD_NOSLEEP_SPIN);
13359e39c5baSBill Taylor 
13369e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
13379e39c5baSBill Taylor 
13389e39c5baSBill Taylor 	/* Get an "In" mailbox for the command */
13399e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
13409e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
13419e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
13429e39c5baSBill Taylor 		return (status);
13439e39c5baSBill Taylor 	}
13449e39c5baSBill Taylor 
13459e39c5baSBill Taylor 	/* Copy the Hermon "INIT_HCA" command into the mailbox */
13469e39c5baSBill Taylor 	size = sizeof (hermon_hw_initqueryhca_t);
13479e39c5baSBill Taylor 	for (i = 0; i < (size >> 3); i++) {
13489e39c5baSBill Taylor 		data = ((uint64_t *)inithca)[i];
13499e39c5baSBill Taylor 		ddi_put64(mbox_info.mbi_in->mb_acchdl,
13509e39c5baSBill Taylor 		    ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
13519e39c5baSBill Taylor 	}
13529e39c5baSBill Taylor 
13539e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
13549e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
13559e39c5baSBill Taylor 
13569e39c5baSBill Taylor 	/* Setup and post the Hermon "INIT_HCA" command */
13579e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
13589e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
13599e39c5baSBill Taylor 	cmd.cp_inmod	= 0;
13609e39c5baSBill Taylor 	cmd.cp_opcode	= INIT_HCA;
13619e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
13629e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
13639e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
13649e39c5baSBill Taylor 
13659e39c5baSBill Taylor 	/* Free the mailbox */
13669e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
13679e39c5baSBill Taylor 	return (status);
13689e39c5baSBill Taylor }
13699e39c5baSBill Taylor 
13709e39c5baSBill Taylor 
13719e39c5baSBill Taylor /*
13729e39c5baSBill Taylor  * hermon_close_hca_cmd_post()
13739e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
13749e39c5baSBill Taylor  *    (Currently called only from attach() and/or detach() path contexts)
13759e39c5baSBill Taylor  */
13769e39c5baSBill Taylor int
hermon_close_hca_cmd_post(hermon_state_t * state,uint_t sleepflag)13779e39c5baSBill Taylor hermon_close_hca_cmd_post(hermon_state_t *state, uint_t sleepflag)
13789e39c5baSBill Taylor {
13799e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
13809e39c5baSBill Taylor 	int			status;
13819e39c5baSBill Taylor 
13829e39c5baSBill Taylor 	/* Make sure we are called with the correct flag */
13839e39c5baSBill Taylor 	ASSERT(sleepflag == HERMON_CMD_NOSLEEP_SPIN);
13849e39c5baSBill Taylor 
13859e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
13869e39c5baSBill Taylor 
13879e39c5baSBill Taylor 
13889e39c5baSBill Taylor 	/* Setup and post the Hermon "CLOSE_HCA" command */
13899e39c5baSBill Taylor 	cmd.cp_inparm	= 0;
13909e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
13919e39c5baSBill Taylor 	cmd.cp_inmod	= 0;
13929e39c5baSBill Taylor 	cmd.cp_opcode	= CLOSE_HCA;
13939e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
13949e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
13959e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
13969e39c5baSBill Taylor 	return (status);
13979e39c5baSBill Taylor }
13989e39c5baSBill Taylor 
13999e39c5baSBill Taylor 
14009e39c5baSBill Taylor /*
14019e39c5baSBill Taylor  * hermon_set_port_cmd_post()
14029e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
14039e39c5baSBill Taylor  *    (Currently called only from attach() path context)
14049e39c5baSBill Taylor  */
14059e39c5baSBill Taylor int
hermon_set_port_cmd_post(hermon_state_t * state,hermon_hw_set_port_t * initport,uint_t port,uint_t sleepflag)14069e39c5baSBill Taylor hermon_set_port_cmd_post(hermon_state_t *state, hermon_hw_set_port_t *initport,
14079e39c5baSBill Taylor     uint_t port, uint_t sleepflag)
14089e39c5baSBill Taylor {
14099e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
14109e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
14119e39c5baSBill Taylor 	uint64_t		data;
14129e39c5baSBill Taylor 	uint_t			size;
14139e39c5baSBill Taylor 	int			status, i;
14149e39c5baSBill Taylor 
14159e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
14169e39c5baSBill Taylor 
14179e39c5baSBill Taylor 	/* Get an "In" mailbox for the command */
14189e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
14199e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
14209e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
14219e39c5baSBill Taylor 		return (status);
14229e39c5baSBill Taylor 	}
14239e39c5baSBill Taylor 
14249e39c5baSBill Taylor 	/* Copy the Hermon "INIT_PORT" command into the mailbox */
14259e39c5baSBill Taylor 	size = sizeof (hermon_hw_set_port_t);
14269e39c5baSBill Taylor 	for (i = 0; i < (size >> 3); i++) {
14279e39c5baSBill Taylor 		data = ((uint64_t *)initport)[i];
14289e39c5baSBill Taylor 		ddi_put64(mbox_info.mbi_in->mb_acchdl,
14299e39c5baSBill Taylor 		    ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
14309e39c5baSBill Taylor 	}
14319e39c5baSBill Taylor 
14329e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
14339e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
14349e39c5baSBill Taylor 
14359e39c5baSBill Taylor 	/* Setup and post the Hermon "SET_PORT" command */
14369e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
14379e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
14389e39c5baSBill Taylor 	cmd.cp_inmod	= port;
14399e39c5baSBill Taylor 	cmd.cp_opcode	= SET_PORT;
14409e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
14419e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
14429e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
14439e39c5baSBill Taylor 
14449e39c5baSBill Taylor 	/* Free the mailbox */
14459e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
14469e39c5baSBill Taylor 	return (status);
14479e39c5baSBill Taylor }
14489e39c5baSBill Taylor 
14499e39c5baSBill Taylor 
14509e39c5baSBill Taylor /*
14519e39c5baSBill Taylor  * hermon_init_port_cmd_post()
14529e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
14539e39c5baSBill Taylor  *    (Currently called only from attach() and/or detach() path contexts)
14549e39c5baSBill Taylor  */
14559e39c5baSBill Taylor int
hermon_init_port_cmd_post(hermon_state_t * state,uint_t port,uint_t sleepflag)14569e39c5baSBill Taylor hermon_init_port_cmd_post(hermon_state_t *state, uint_t port, uint_t sleepflag)
14579e39c5baSBill Taylor {
14589e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
14599e39c5baSBill Taylor 	int			status;
14609e39c5baSBill Taylor 
14619e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
14629e39c5baSBill Taylor 
14639e39c5baSBill Taylor 	/* Setup and post the Hermon "INIT_PORT" command */
14649e39c5baSBill Taylor 	cmd.cp_inparm	= 0;
14659e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
14669e39c5baSBill Taylor 	cmd.cp_inmod	= port;
14679e39c5baSBill Taylor 	cmd.cp_opcode	= INIT_PORT;
14689e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
14699e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
14709e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
14719e39c5baSBill Taylor 
14729e39c5baSBill Taylor 	return (status);
14739e39c5baSBill Taylor }
14749e39c5baSBill Taylor 
14759e39c5baSBill Taylor 
14769e39c5baSBill Taylor /*
14779e39c5baSBill Taylor  * hermon_close_port_cmd_post()
14789e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
14799e39c5baSBill Taylor  *    (Currently called only from attach() and/or detach() path contexts)
14809e39c5baSBill Taylor  */
14819e39c5baSBill Taylor int
hermon_close_port_cmd_post(hermon_state_t * state,uint_t port,uint_t sleepflag)14829e39c5baSBill Taylor hermon_close_port_cmd_post(hermon_state_t *state, uint_t port, uint_t sleepflag)
14839e39c5baSBill Taylor {
14849e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
14859e39c5baSBill Taylor 	int			status;
14869e39c5baSBill Taylor 
14879e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
14889e39c5baSBill Taylor 
14899e39c5baSBill Taylor 	/* Setup and post the Hermon "CLOSE_PORT" command */
14909e39c5baSBill Taylor 	cmd.cp_inparm	= 0;
14919e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
14929e39c5baSBill Taylor 	cmd.cp_inmod	= port;
14939e39c5baSBill Taylor 	cmd.cp_opcode	= CLOSE_PORT;
14949e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
14959e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
14969e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
14979e39c5baSBill Taylor 	return (status);
14989e39c5baSBill Taylor }
14999e39c5baSBill Taylor 
15009e39c5baSBill Taylor 
15019e39c5baSBill Taylor /*
15029e39c5baSBill Taylor  * hermon_mod_stat_cfg_cmd_post()
15039e39c5baSBill Taylor  *    Context: Can be called only from attach() path
15049e39c5baSBill Taylor  *
15059e39c5baSBill Taylor  * This routine was initially implemented to enable SRQ. That's no longer needed
15069e39c5baSBill Taylor  * in hermon, and the code is conditionally compiled OUT, but left here because
15079e39c5baSBill Taylor  * there are other static configuration parameters we might one day want to set
15089e39c5baSBill Taylor  */
15099e39c5baSBill Taylor #ifdef HERMON_NO_MOD_STAT_CFG
15109e39c5baSBill Taylor int
hermon_mod_stat_cfg_cmd_post(hermon_state_t * state)15119e39c5baSBill Taylor hermon_mod_stat_cfg_cmd_post(hermon_state_t *state)
15129e39c5baSBill Taylor {
15139e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
15149e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
15159e39c5baSBill Taylor 	hermon_hw_mod_stat_cfg_t	*mod;
15169e39c5baSBill Taylor 	hermon_hw_msg_in_mod_t	inmod;
15179e39c5baSBill Taylor 	uint64_t		data;
15189e39c5baSBill Taylor 	uint_t			size;
15199e39c5baSBill Taylor 	int			status, i;
15209e39c5baSBill Taylor 
15219e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
15229e39c5baSBill Taylor 
15239e39c5baSBill Taylor 	/*
15249e39c5baSBill Taylor 	 * "MOD_STAT_CFG" needs an INMBOX parameter, to specify what operations
15259e39c5baSBill Taylor 	 * to do.  However, at the point in time that we call this command, the
15269e39c5baSBill Taylor 	 * DDR has not yet been initialized, and all INMBOX'es are located in
15279e39c5baSBill Taylor 	 * DDR.  Because we want to call MOD_STAT_CFG before QUERY_DEVLIM is
15289e39c5baSBill Taylor 	 * called, and thus call it before DDR is setup, we simply use an
15299e39c5baSBill Taylor 	 * OUTMBOX memory location here as our INMBOX parameter.
15309e39c5baSBill Taylor 	 */
15319e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
15329e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, HERMON_NOSLEEP);
15339e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
15349e39c5baSBill Taylor 		return (status);
15359e39c5baSBill Taylor 	}
15369e39c5baSBill Taylor 
15379e39c5baSBill Taylor 	/*
15389e39c5baSBill Taylor 	 * Allocate on the heap our 'mod_stat_cfg' structure.  We want to
15399e39c5baSBill Taylor 	 * ideally move all of this on to the stack in the future, but this
15409e39c5baSBill Taylor 	 * works well for now.
15419e39c5baSBill Taylor 	 */
15429e39c5baSBill Taylor 	mod = (hermon_hw_mod_stat_cfg_t *)kmem_zalloc(
15439e39c5baSBill Taylor 	    sizeof (hermon_hw_mod_stat_cfg_t), KM_SLEEP);
15449e39c5baSBill Taylor 
15459e39c5baSBill Taylor 	/* Setup "MOD_STAT_CFG" settings */
15469e39c5baSBill Taylor 	mod->srq_m	= 1;
15479e39c5baSBill Taylor 	mod->srq	= state->hs_cfg_profile->cp_srq_enable;
15489e39c5baSBill Taylor 
15499e39c5baSBill Taylor 	if (mod->srq) {
15509e39c5baSBill Taylor 		/*  use DEV_LIMS num srq */
15519e39c5baSBill Taylor 		mod->log_max_srq = state->hs_cfg_profile->cp_log_num_srq;
15529e39c5baSBill Taylor 	} else {
15539e39c5baSBill Taylor 		mod->log_max_srq = 0;
15549e39c5baSBill Taylor 	}
15559e39c5baSBill Taylor 
15569e39c5baSBill Taylor 	/* Copy the "MOD_STAT_CFG" command into the "In" mailbox */
15579e39c5baSBill Taylor 	size = sizeof (hermon_hw_mod_stat_cfg_t);
15589e39c5baSBill Taylor 	for (i = 0; i < (size >> 3); i++) {
15599e39c5baSBill Taylor 		data = ((uint64_t *)mod)[i];
15609e39c5baSBill Taylor 		ddi_put64(mbox_info.mbi_in->mb_acchdl,
15619e39c5baSBill Taylor 		    ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
15629e39c5baSBill Taylor 	}
15639e39c5baSBill Taylor 
15649e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
15659e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
15669e39c5baSBill Taylor 
15679e39c5baSBill Taylor 	/* Setup and post the Hermon "MOD_STAT_CFG" command */
15689e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_out->mb_mapaddr;
15699e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
15709e39c5baSBill Taylor 	cmd.cp_inmod	= 0;
15719e39c5baSBill Taylor 	cmd.cp_opcode	= MOD_STAT_CFG;
15729e39c5baSBill Taylor 	cmd.cp_opmod	= HERMON_MOD_STAT_CFG_PTR;
15739e39c5baSBill Taylor 	cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN;
15749e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
15759e39c5baSBill Taylor 
15769e39c5baSBill Taylor 	/* Free "MOD_STAT_CFG" struct */
15779e39c5baSBill Taylor 	kmem_free(mod, sizeof (hermon_hw_mod_stat_cfg_t));
15789e39c5baSBill Taylor 
15799e39c5baSBill Taylor 	/* Free the mailbox */
15809e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
15819e39c5baSBill Taylor 	return (status);
15829e39c5baSBill Taylor }
15839e39c5baSBill Taylor #endif
15849e39c5baSBill Taylor 
15859e39c5baSBill Taylor 
15869e39c5baSBill Taylor /*
15879e39c5baSBill Taylor  * hermon_map_cmd_post()
158817a2b317SBill Taylor  *    Context: Can be called only from user or kernel context
15899e39c5baSBill Taylor  *
15909e39c5baSBill Taylor  * Generic routine to map FW, ICMA, and ICM.
15919e39c5baSBill Taylor  */
15929e39c5baSBill Taylor int
hermon_map_cmd_post(hermon_state_t * state,hermon_dma_info_t * dma,uint16_t opcode,ddi_dma_cookie_t cookie,uint_t ccount)15939e39c5baSBill Taylor hermon_map_cmd_post(hermon_state_t *state, hermon_dma_info_t *dma,
15949e39c5baSBill Taylor     uint16_t opcode, ddi_dma_cookie_t cookie, uint_t ccount)
15959e39c5baSBill Taylor {
15969e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
15979e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
15989e39c5baSBill Taylor 	hermon_hw_vpm_t		vpm;
15999e39c5baSBill Taylor 	uint64_t		data;
16009e39c5baSBill Taylor 	uint64_t		paddr, vaddr;
16019e39c5baSBill Taylor 	uint_t			size;
16029e39c5baSBill Taylor 	int			status, i, j, k = 0;
16039e39c5baSBill Taylor 	int			max_mailbox_size;
16049e39c5baSBill Taylor 	int			cookie_num_icm_pages;
16059e39c5baSBill Taylor 	int			num_vpm_entries;
16069e39c5baSBill Taylor 	int			log2_npages;
16079e39c5baSBill Taylor 	int			npages;
16089e39c5baSBill Taylor 
16099e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
16109e39c5baSBill Taylor 
16119e39c5baSBill Taylor 	/* Allocate an IN mailbox */
16129e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
16139e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, HERMON_SLEEP);
16149e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
16159e39c5baSBill Taylor 		return (status);
16169e39c5baSBill Taylor 	}
16179e39c5baSBill Taylor 
16189e39c5baSBill Taylor 	/* Initialize cmd parameters */
16199e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
16209e39c5baSBill Taylor 	cmd.cp_opcode	= opcode;
16219e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
16229e39c5baSBill Taylor 	cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN;
16239e39c5baSBill Taylor 
16249e39c5baSBill Taylor 	/*
16259e39c5baSBill Taylor 	 * Allocate a list of VPM (Virtual Physical Mapping) structures.
16269e39c5baSBill Taylor 	 * A VPM encodes a power-of-2 number of DMA pages that have been
16279e39c5baSBill Taylor 	 * allocated and are passed in the dma_info. We need to break up
16289e39c5baSBill Taylor 	 * the DMA cookies that are in the dma_info into power-of-2 page
16299e39c5baSBill Taylor 	 * mappings. We also need to keep track of the number of VPMs we
16309e39c5baSBill Taylor 	 * have total, as it is used as the inmod for this command.
16319e39c5baSBill Taylor 	 */
16329e39c5baSBill Taylor 
16339e39c5baSBill Taylor 	/* Start with the ICM address passed and the first cookie */
16349e39c5baSBill Taylor 	vaddr  = dma->icmaddr;
16359e39c5baSBill Taylor 
16369e39c5baSBill Taylor 	/* Initialize the VPM count and the VPM struct */
16379e39c5baSBill Taylor 	num_vpm_entries = 0;
16389e39c5baSBill Taylor 	size = sizeof (hermon_hw_vpm_t);
16399e39c5baSBill Taylor 	bzero(&vpm, size);
16409e39c5baSBill Taylor 
16419e39c5baSBill Taylor 	/*
16429e39c5baSBill Taylor 	 * Establish a max mailbox size (in VPM entries). If we reach this,
16439e39c5baSBill Taylor 	 * we must post a MAP command, reinitialzie num_vpm_entries, and
16449e39c5baSBill Taylor 	 * continue.
16459e39c5baSBill Taylor 	 */
16469e39c5baSBill Taylor 	max_mailbox_size = HERMON_MBOX_SIZE / size;
16479e39c5baSBill Taylor 
16489e39c5baSBill Taylor 	/*
16499e39c5baSBill Taylor 	 * First, walk through the DMA cookies and build VPMs from them.
16509e39c5baSBill Taylor 	 */
16519e39c5baSBill Taylor 	while (ccount-- > 0) {
16529e39c5baSBill Taylor 
16539e39c5baSBill Taylor 		/* Determine the number of ICM pages in this cookie. */
16549e39c5baSBill Taylor 		cookie_num_icm_pages = cookie.dmac_size / HERMON_PAGESIZE;
16559e39c5baSBill Taylor 
16569e39c5baSBill Taylor 		/* Initialize this set of VPM's starting physical address. */
16579e39c5baSBill Taylor 		paddr = cookie.dmac_laddress;
16589e39c5baSBill Taylor 
16599e39c5baSBill Taylor 		/*
16609e39c5baSBill Taylor 		 * Now build a set of VPMs for this cookie's memory, breaking
16619e39c5baSBill Taylor 		 * up the cookies into multiple VPMs if necessary to achieve
16629e39c5baSBill Taylor 		 * the required power-of-2 number of pages per VPM. Once each
16639e39c5baSBill Taylor 		 * VPM is constructed, write it out to the mailbox memory.
16649e39c5baSBill Taylor 		 */
16659e39c5baSBill Taylor 		for (i = cookie_num_icm_pages; i > 0; i -= npages) {
16669e39c5baSBill Taylor 			log2_npages = highbit(i) - 1;
16679e39c5baSBill Taylor 			npages	    = (1 << log2_npages);
16689e39c5baSBill Taylor 			/* Ensure this chunk is aligned on it's own size */
16699e39c5baSBill Taylor 			while (((npages * HERMON_PAGESIZE - 1) & paddr) != 0) {
16709e39c5baSBill Taylor 				log2_npages--;
16719e39c5baSBill Taylor 				npages = (1 << log2_npages);
16729e39c5baSBill Taylor 			}
16739e39c5baSBill Taylor 			vpm.log2sz    = log2_npages;
16749e39c5baSBill Taylor 
16759e39c5baSBill Taylor 			vpm.paddr_l = (uint32_t)(paddr >> 12);
16769e39c5baSBill Taylor 			vpm.paddr_h = (uint32_t)(paddr >> 32);
16779e39c5baSBill Taylor 			/* Increment the paddr for the next VPM */
16789e39c5baSBill Taylor 			paddr += npages * HERMON_PAGESIZE;
16799e39c5baSBill Taylor 
16809e39c5baSBill Taylor 			if (opcode == MAP_ICM) {
16819e39c5baSBill Taylor 				vpm.vaddr_l = (uint32_t)(vaddr >> 12);
16829e39c5baSBill Taylor 				vpm.vaddr_h = (uint32_t)(vaddr >> 32);
16839e39c5baSBill Taylor 				/* Increment the ICM address for the next VPM */
16849e39c5baSBill Taylor 				vaddr += npages * HERMON_PAGESIZE;
16859e39c5baSBill Taylor 			}
16869e39c5baSBill Taylor 
16879e39c5baSBill Taylor 			/*
16889e39c5baSBill Taylor 			 * Copy this VPM into the "In" mailbox. Note we're
16899e39c5baSBill Taylor 			 * using 'k' as the offset from mb_addr for this cmd.
16909e39c5baSBill Taylor 			 */
16919e39c5baSBill Taylor 			for (j = 0; j < (size >> 3); j++, k++) {
16929e39c5baSBill Taylor 				data = ((uint64_t *)(void *)&vpm)[j];
16939e39c5baSBill Taylor 				ddi_put64(mbox_info.mbi_in->mb_acchdl,
16949e39c5baSBill Taylor 				    ((uint64_t *)mbox_info.mbi_in->mb_addr + k),
16959e39c5baSBill Taylor 				    data);
16969e39c5baSBill Taylor 			}
16979e39c5baSBill Taylor 
16989e39c5baSBill Taylor 			/*
16999e39c5baSBill Taylor 			 * Increment the number of VPM entries and check
17009e39c5baSBill Taylor 			 * against max mailbox size. If we have reached
17019e39c5baSBill Taylor 			 * the maximum mailbox size, post the map cmd.
17029e39c5baSBill Taylor 			 */
17039e39c5baSBill Taylor 			if (++num_vpm_entries == max_mailbox_size) {
17049e39c5baSBill Taylor 
17059e39c5baSBill Taylor 				/* Sync the mailbox for the device to read */
17069e39c5baSBill Taylor 				hermon_mbox_sync(mbox_info.mbi_in, 0, (size *
17079e39c5baSBill Taylor 				    num_vpm_entries), DDI_DMA_SYNC_FORDEV);
17089e39c5baSBill Taylor 
17099e39c5baSBill Taylor 				/* Setup and post the command */
17109e39c5baSBill Taylor 				cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
17119e39c5baSBill Taylor 				cmd.cp_inmod	= num_vpm_entries;
17129e39c5baSBill Taylor 				status = hermon_cmd_post(state, &cmd);
17139e39c5baSBill Taylor 				if (status != HERMON_CMD_SUCCESS) {
17149e39c5baSBill Taylor 					cmn_err(CE_NOTE, "hermon%d: %s cmd "
17159e39c5baSBill Taylor 					    "failed (0x%x)", state->hs_instance,
17169e39c5baSBill Taylor 					    opcode == MAP_FA ? "MAP_FA" :
17179e39c5baSBill Taylor 					    opcode == MAP_ICM ? "MAP_ICM" :
17189e39c5baSBill Taylor 					    opcode == MAP_ICM_AUX ? "MAP_ICMA" :
17199e39c5baSBill Taylor 					    "UNKNOWN", status);
17209e39c5baSBill Taylor 					goto map_fail;
17219e39c5baSBill Taylor 				}
17229e39c5baSBill Taylor 
17239e39c5baSBill Taylor 				/*
17249e39c5baSBill Taylor 				 * Reinitialize num_vpm_entries, and the
17259e39c5baSBill Taylor 				 * mb_addr offset
17269e39c5baSBill Taylor 				 */
17279e39c5baSBill Taylor 				num_vpm_entries = k = 0;
17289e39c5baSBill Taylor 			}
17299e39c5baSBill Taylor 		}
17309e39c5baSBill Taylor 
17319e39c5baSBill Taylor 		/* If count remains, move onto the next cookie */
17329e39c5baSBill Taylor 		if (ccount != 0) {
17339e39c5baSBill Taylor 			ddi_dma_nextcookie(dma->dma_hdl, &cookie);
17349e39c5baSBill Taylor 		}
17359e39c5baSBill Taylor 	}
17369e39c5baSBill Taylor 
17379e39c5baSBill Taylor 	if (num_vpm_entries) {
17389e39c5baSBill Taylor 
17399e39c5baSBill Taylor 		/* Sync the mailbox for the device to read */
17409e39c5baSBill Taylor 		hermon_mbox_sync(mbox_info.mbi_in, 0, (size * num_vpm_entries),
17419e39c5baSBill Taylor 		    DDI_DMA_SYNC_FORDEV);
17429e39c5baSBill Taylor 
17439e39c5baSBill Taylor 		/* Setup and post the command */
17449e39c5baSBill Taylor 		cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
17459e39c5baSBill Taylor 		cmd.cp_inmod	= num_vpm_entries;
17469e39c5baSBill Taylor 		status = hermon_cmd_post(state, &cmd);
17479e39c5baSBill Taylor 		if (status != HERMON_CMD_SUCCESS) {
17489e39c5baSBill Taylor 			cmn_err(CE_NOTE, "hermon%d: %s cmd "
17499e39c5baSBill Taylor 			    "failed (0x%x)", state->hs_instance,
17509e39c5baSBill Taylor 			    opcode == MAP_FA ? "MAP_FA" :
17519e39c5baSBill Taylor 			    opcode == MAP_ICM ? "MAP_ICM" :
17529e39c5baSBill Taylor 			    opcode == MAP_ICM_AUX ? "MAP_ICMA" :
17539e39c5baSBill Taylor 			    "UNKNOWN", status);
17549e39c5baSBill Taylor 			goto map_fail;
17559e39c5baSBill Taylor 		}
17569e39c5baSBill Taylor 	}
17579e39c5baSBill Taylor 
17589e39c5baSBill Taylor map_fail:
17599e39c5baSBill Taylor 	/* Free the mailbox */
17609e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
17619e39c5baSBill Taylor 	return (status);
17629e39c5baSBill Taylor }
17639e39c5baSBill Taylor 
17649e39c5baSBill Taylor 
17659e39c5baSBill Taylor /*
17669e39c5baSBill Taylor  * hermon_unmap_fa_cmd_post()
17679e39c5baSBill Taylor  *    Context: Can be called only from attach() path
17689e39c5baSBill Taylor  */
17699e39c5baSBill Taylor int
hermon_unmap_fa_cmd_post(hermon_state_t * state)17709e39c5baSBill Taylor hermon_unmap_fa_cmd_post(hermon_state_t *state)
17719e39c5baSBill Taylor {
17729e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
17739e39c5baSBill Taylor 	int			status;
17749e39c5baSBill Taylor 
17759e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
17769e39c5baSBill Taylor 
17779e39c5baSBill Taylor 	/* Setup and post the Hermon "UNMAP_FA" command */
17789e39c5baSBill Taylor 	cmd.cp_inparm	= 0;
17799e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
17809e39c5baSBill Taylor 	cmd.cp_inmod	= 0;
17819e39c5baSBill Taylor 	cmd.cp_opcode	= UNMAP_FA;
17829e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
17839e39c5baSBill Taylor 	cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN;
17849e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
17859e39c5baSBill Taylor 
17869e39c5baSBill Taylor 	return (status);
17879e39c5baSBill Taylor }
17889e39c5baSBill Taylor 
17899e39c5baSBill Taylor 
17909e39c5baSBill Taylor /*
17919e39c5baSBill Taylor  * hermon_run_fw_cmd_post()
17929e39c5baSBill Taylor  *    Context: Can be called only from attach() path
17939e39c5baSBill Taylor  */
17949e39c5baSBill Taylor int
hermon_run_fw_cmd_post(hermon_state_t * state)17959e39c5baSBill Taylor hermon_run_fw_cmd_post(hermon_state_t *state)
17969e39c5baSBill Taylor {
17979e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
17989e39c5baSBill Taylor 	int			status;
17999e39c5baSBill Taylor 
18009e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
18019e39c5baSBill Taylor 
18029e39c5baSBill Taylor 	/* Setup and post the Hermon "RUN_FW" command */
18039e39c5baSBill Taylor 	cmd.cp_inparm	= 0;
18049e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
18059e39c5baSBill Taylor 	cmd.cp_inmod	= 0;
18069e39c5baSBill Taylor 	cmd.cp_opcode	= RUN_FW;
18079e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
18089e39c5baSBill Taylor 	cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN;
18099e39c5baSBill Taylor 
18109e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
18119e39c5baSBill Taylor #ifdef FMA_TEST
18129e39c5baSBill Taylor 	if (hermon_test_num == -2) {
18139e39c5baSBill Taylor 		status = HERMON_CMD_BAD_NVMEM;
181432c5adfdSEiji Ota 		/*
181532c5adfdSEiji Ota 		 * No need of an ereport here since this case
181632c5adfdSEiji Ota 		 * is treated as a degradation later.
181732c5adfdSEiji Ota 		 */
18189e39c5baSBill Taylor 		HERMON_FMANOTE(state, HERMON_FMA_BADNVMEM);
18199e39c5baSBill Taylor 	}
18209e39c5baSBill Taylor #endif
18219e39c5baSBill Taylor 	return (status);
18229e39c5baSBill Taylor }
18239e39c5baSBill Taylor 
18249e39c5baSBill Taylor 
18259e39c5baSBill Taylor /*
18269e39c5baSBill Taylor  * hermon_set_icm_size_cmd_post()
18279e39c5baSBill Taylor  *    Context: Can be called only from attach() path
18289e39c5baSBill Taylor  */
18299e39c5baSBill Taylor int
hermon_set_icm_size_cmd_post(hermon_state_t * state)18309e39c5baSBill Taylor hermon_set_icm_size_cmd_post(hermon_state_t *state)
18319e39c5baSBill Taylor {
18329e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
18339e39c5baSBill Taylor 	int			status;
18349e39c5baSBill Taylor 
18359e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
18369e39c5baSBill Taylor 
18379e39c5baSBill Taylor 	/* Setup and post the Hermon "SET_ICM_SIZE" command */
18389e39c5baSBill Taylor 	cmd.cp_inparm	= (uint64_t)state->hs_icm_sz;
18399e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
18409e39c5baSBill Taylor 	cmd.cp_inmod	= 0;
18419e39c5baSBill Taylor 	cmd.cp_opcode	= SET_ICM_SIZE;
18429e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
18439e39c5baSBill Taylor 	cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN;
18449e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
18459e39c5baSBill Taylor 
18469e39c5baSBill Taylor 	/*
18479e39c5baSBill Taylor 	 * Aux ICM size in 4K pages returned in output param
18489e39c5baSBill Taylor 	 * convert it to bytes
18499e39c5baSBill Taylor 	 */
18509e39c5baSBill Taylor 	state->hs_icma_sz = (uint64_t)(cmd.cp_outparm << HERMON_PAGESHIFT);
18519e39c5baSBill Taylor 	return (status);
18529e39c5baSBill Taylor }
18539e39c5baSBill Taylor 
18549e39c5baSBill Taylor 
18559e39c5baSBill Taylor /*
18569e39c5baSBill Taylor  * hermon_unmap_icm_aux_cmd_post()
18579e39c5baSBill Taylor  *    Context: Can be called only from attach() path
18589e39c5baSBill Taylor  */
18599e39c5baSBill Taylor int
hermon_unmap_icm_aux_cmd_post(hermon_state_t * state)18609e39c5baSBill Taylor hermon_unmap_icm_aux_cmd_post(hermon_state_t *state)
18619e39c5baSBill Taylor {
18629e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
18639e39c5baSBill Taylor 	int			status;
18649e39c5baSBill Taylor 
18659e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
18669e39c5baSBill Taylor 
18679e39c5baSBill Taylor 	/* Setup and post the Hermon "UNMAP_ICM_AUX" command */
18689e39c5baSBill Taylor 	cmd.cp_inparm	= 0;
18699e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
18709e39c5baSBill Taylor 	cmd.cp_inmod	= 0;
18719e39c5baSBill Taylor 	cmd.cp_opcode	= UNMAP_ICM_AUX;
18729e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
18739e39c5baSBill Taylor 	cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN;
18749e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
18759e39c5baSBill Taylor 	return (status);
18769e39c5baSBill Taylor }
18779e39c5baSBill Taylor 
18789e39c5baSBill Taylor 
18799e39c5baSBill Taylor /*
18809e39c5baSBill Taylor  * hermon_unmap_icm_cmd_post()
18819e39c5baSBill Taylor  *    Context: Can be called from base or attach context
18829e39c5baSBill Taylor  */
18839e39c5baSBill Taylor int
hermon_unmap_icm_cmd_post(hermon_state_t * state,hermon_dma_info_t * dma_info)18849e39c5baSBill Taylor hermon_unmap_icm_cmd_post(hermon_state_t *state, hermon_dma_info_t *dma_info)
18859e39c5baSBill Taylor {
18869e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
18879e39c5baSBill Taylor 	uint64_t		addr;
18889e39c5baSBill Taylor 	uint32_t		npages;
18899e39c5baSBill Taylor 	int			status;
18909e39c5baSBill Taylor 
18919e39c5baSBill Taylor 	/*
18929e39c5baSBill Taylor 	 * Setup and post the Hermon "UNMAP_ICM" command. If a
18939e39c5baSBill Taylor 	 * hermon_dma_info_t was passed, we want to unmap a set
18949e39c5baSBill Taylor 	 * of pages. Otherwise, unmap all of ICM.
18959e39c5baSBill Taylor 	 */
18969e39c5baSBill Taylor 	if (dma_info != NULL) {
18979e39c5baSBill Taylor 		addr   = dma_info->icmaddr;
18989e39c5baSBill Taylor 		npages = dma_info->length / HERMON_PAGESIZE;
18999e39c5baSBill Taylor 	} else {
19009e39c5baSBill Taylor 		addr   = 0;
19019e39c5baSBill Taylor 		npages = state->hs_icm_sz / HERMON_PAGESIZE;
19029e39c5baSBill Taylor 	}
19039e39c5baSBill Taylor 
19049e39c5baSBill Taylor 	/* Setup and post the Hermon "UNMAP_ICM" command */
19059e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
19069e39c5baSBill Taylor 	cmd.cp_inparm	= addr;
19079e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
19089e39c5baSBill Taylor 	cmd.cp_inmod	= npages;
19099e39c5baSBill Taylor 	cmd.cp_opcode	= UNMAP_ICM;
19109e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
19119e39c5baSBill Taylor 	cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN;
19129e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
19139e39c5baSBill Taylor 	return (status);
19149e39c5baSBill Taylor }
19159e39c5baSBill Taylor 
19169e39c5baSBill Taylor 
19179e39c5baSBill Taylor /*
19189e39c5baSBill Taylor  * hermon_mad_ifc_cmd_post()
19199e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
19209e39c5baSBill Taylor  */
19219e39c5baSBill Taylor int
hermon_mad_ifc_cmd_post(hermon_state_t * state,uint_t port,uint_t sleepflag,uint32_t * mad,uint32_t * resp)19229e39c5baSBill Taylor hermon_mad_ifc_cmd_post(hermon_state_t *state, uint_t port,
19239e39c5baSBill Taylor     uint_t sleepflag, uint32_t *mad, uint32_t *resp)
19249e39c5baSBill Taylor {
19259e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
19269e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
19279e39c5baSBill Taylor 	uint_t			size;
19289e39c5baSBill Taylor 	int			status;
19299e39c5baSBill Taylor 
19309e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
19319e39c5baSBill Taylor 
19329e39c5baSBill Taylor 	/* Get "In" and "Out" mailboxes for the command */
19339e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
19349e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
19359e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
19369e39c5baSBill Taylor 		return (status);
19379e39c5baSBill Taylor 	}
19389e39c5baSBill Taylor 
19399e39c5baSBill Taylor 	/* Copy the request MAD into the "In" mailbox */
19409e39c5baSBill Taylor 	size = HERMON_CMD_MAD_IFC_SIZE;
19419e39c5baSBill Taylor 	bcopy(mad, mbox_info.mbi_in->mb_addr, size);
19429e39c5baSBill Taylor 
19439e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
19449e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
19459e39c5baSBill Taylor 
19469e39c5baSBill Taylor 	/* Setup the Hermon "MAD_IFC" command */
19479e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
19489e39c5baSBill Taylor 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
19499e39c5baSBill Taylor 	cmd.cp_inmod	= port;
19509e39c5baSBill Taylor 	cmd.cp_opcode	= MAD_IFC;
19519e39c5baSBill Taylor 	cmd.cp_opmod	= HERMON_CMD_MKEY_CHECK;  /* Enable MKey checking */
19529e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
19539e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
19549e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
19559e39c5baSBill Taylor 		goto mad_ifc_fail;
19569e39c5baSBill Taylor 	}
19579e39c5baSBill Taylor 
19589e39c5baSBill Taylor 	/* Sync the mailbox to read the results */
19599e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
19609e39c5baSBill Taylor 
19619e39c5baSBill Taylor 	/* Copy the response MAD into "resp" */
19629e39c5baSBill Taylor 	bcopy(mbox_info.mbi_out->mb_addr, resp, size);
19639e39c5baSBill Taylor 
19649e39c5baSBill Taylor mad_ifc_fail:
19659e39c5baSBill Taylor 	/* Free the mailbox */
19669e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
19679e39c5baSBill Taylor 	return (status);
19689e39c5baSBill Taylor }
19699e39c5baSBill Taylor 
19709e39c5baSBill Taylor 
19719e39c5baSBill Taylor /*
19729e39c5baSBill Taylor  * hermon_getportinfo_cmd_post()
19739e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
19749e39c5baSBill Taylor  */
19759e39c5baSBill Taylor int
hermon_getportinfo_cmd_post(hermon_state_t * state,uint_t port,uint_t sleepflag,sm_portinfo_t * portinfo)19769e39c5baSBill Taylor hermon_getportinfo_cmd_post(hermon_state_t *state, uint_t port,
19779e39c5baSBill Taylor     uint_t sleepflag, sm_portinfo_t *portinfo)
19789e39c5baSBill Taylor {
19799e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
19809e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
19819e39c5baSBill Taylor 	uint32_t		*mbox;
19829e39c5baSBill Taylor 	uint_t			size;
19839e39c5baSBill Taylor 	int			status, i;
19849e39c5baSBill Taylor 
19859e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
19869e39c5baSBill Taylor 
19879e39c5baSBill Taylor 	/* Get "In" and "Out" mailboxes for the command */
19889e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
19899e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
19909e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
19919e39c5baSBill Taylor 		return (status);
19929e39c5baSBill Taylor 	}
19939e39c5baSBill Taylor 
19949e39c5baSBill Taylor 	/* Build the GetPortInfo request MAD in the "In" mailbox */
19959e39c5baSBill Taylor 	size = HERMON_CMD_MAD_IFC_SIZE;
19969e39c5baSBill Taylor 	mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
19979e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
19989e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
19999e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
20009e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
20019e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_PORTINFO);
20029e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], port);
20039e39c5baSBill Taylor 	for (i = 6; i < (size >> 2); i++) {
20049e39c5baSBill Taylor 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
20059e39c5baSBill Taylor 	}
20069e39c5baSBill Taylor 
20079e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
20089e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
20099e39c5baSBill Taylor 
20109e39c5baSBill Taylor 	/* Setup the Hermon "MAD_IFC" command */
20119e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
20129e39c5baSBill Taylor 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
20139e39c5baSBill Taylor 	cmd.cp_inmod	= port;
20149e39c5baSBill Taylor 	cmd.cp_opcode	= MAD_IFC;
20159e39c5baSBill Taylor 	cmd.cp_opmod	= HERMON_CMD_MKEY_DONTCHECK;  /* No MKey checking */
20169e39c5baSBill Taylor 	cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN; /* NO SLEEP */
20179e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
20189e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
20199e39c5baSBill Taylor 		goto getportinfo_fail;
20209e39c5baSBill Taylor 	}
20219e39c5baSBill Taylor 
20229e39c5baSBill Taylor 	/* Sync the mailbox to read the results */
20239e39c5baSBill Taylor 	size = sizeof (sm_portinfo_t);
20249e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
20259e39c5baSBill Taylor 	    size, DDI_DMA_SYNC_FORCPU);
20269e39c5baSBill Taylor 
20279e39c5baSBill Taylor 	/*
20289e39c5baSBill Taylor 	 * Copy GetPortInfo response MAD into "portinfo".  Do any endian
20299e39c5baSBill Taylor 	 * swapping that may be necessary to flip any of the "portinfo"
20309e39c5baSBill Taylor 	 * fields
20319e39c5baSBill Taylor 	 */
20329e39c5baSBill Taylor 	bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
20339e39c5baSBill Taylor 	    HERMON_CMD_MADDATA_OFFSET), portinfo, size);
203476c04273SRajkumar Sivaprakasam 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*portinfo))
20359e39c5baSBill Taylor 	HERMON_GETPORTINFO_SWAP(portinfo);
20369e39c5baSBill Taylor 
20379e39c5baSBill Taylor getportinfo_fail:
20389e39c5baSBill Taylor 	/* Free the mailbox */
20399e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
20409e39c5baSBill Taylor 	return (status);
20419e39c5baSBill Taylor }
20429e39c5baSBill Taylor 
204330e01c53SRamaswamy Tummala /*
204430e01c53SRamaswamy Tummala  * hermon_is_ext_port_counters_supported()
204530e01c53SRamaswamy Tummala  *
204630e01c53SRamaswamy Tummala  * Determine weather extended port counters are supported or not by sending
204730e01c53SRamaswamy Tummala  * ClassPortInfo perf mgmt class MAD.
204830e01c53SRamaswamy Tummala  */
204930e01c53SRamaswamy Tummala int
hermon_is_ext_port_counters_supported(hermon_state_t * state,uint_t port,uint_t sleepflag,int * ext_width_supported)205030e01c53SRamaswamy Tummala hermon_is_ext_port_counters_supported(hermon_state_t *state, uint_t port,
205130e01c53SRamaswamy Tummala     uint_t sleepflag, int *ext_width_supported)
205230e01c53SRamaswamy Tummala {
205330e01c53SRamaswamy Tummala 	hermon_mbox_info_t	mbox_info;
205430e01c53SRamaswamy Tummala 	hermon_cmd_post_t	cmd;
205530e01c53SRamaswamy Tummala 	uint64_t		data;
205630e01c53SRamaswamy Tummala 	uint32_t		*mbox;
205730e01c53SRamaswamy Tummala 	int			status;
205830e01c53SRamaswamy Tummala 
205930e01c53SRamaswamy Tummala 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
206030e01c53SRamaswamy Tummala 
206130e01c53SRamaswamy Tummala 	/* Get "In" and "Out" mailboxes for the command */
206230e01c53SRamaswamy Tummala 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
206330e01c53SRamaswamy Tummala 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
206430e01c53SRamaswamy Tummala 	if (status != HERMON_CMD_SUCCESS) {
206530e01c53SRamaswamy Tummala 		return (status);
206630e01c53SRamaswamy Tummala 	}
206730e01c53SRamaswamy Tummala 
206830e01c53SRamaswamy Tummala 	/* Build the ClassPortInfo request MAD in the "In" mailbox */
206930e01c53SRamaswamy Tummala 	mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
207030e01c53SRamaswamy Tummala 
207130e01c53SRamaswamy Tummala 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_PERF_GET);
207230e01c53SRamaswamy Tummala 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
207330e01c53SRamaswamy Tummala 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
207430e01c53SRamaswamy Tummala 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
207530e01c53SRamaswamy Tummala 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4],
207630e01c53SRamaswamy Tummala 	    HERMON_CMD_CLASSPORTINFO);
207730e01c53SRamaswamy Tummala 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], HERMON_CMD_PERFATTR);
207830e01c53SRamaswamy Tummala 
207930e01c53SRamaswamy Tummala 	/* Sync the mailbox for the device to read */
208030e01c53SRamaswamy Tummala 	hermon_mbox_sync(mbox_info.mbi_in, 0, HERMON_CMD_MAD_IFC_SIZE,
208130e01c53SRamaswamy Tummala 	    DDI_DMA_SYNC_FORDEV);
208230e01c53SRamaswamy Tummala 
208330e01c53SRamaswamy Tummala 	/* Setup the Hermon "MAD_IFC" command */
208430e01c53SRamaswamy Tummala 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
208530e01c53SRamaswamy Tummala 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
208630e01c53SRamaswamy Tummala 	cmd.cp_inmod	= port;
208730e01c53SRamaswamy Tummala 	cmd.cp_opcode	= MAD_IFC;
208830e01c53SRamaswamy Tummala 	/* No MKey and BKey checking */
208930e01c53SRamaswamy Tummala 	cmd.cp_opmod	= HERMON_CMD_MKEY_DONTCHECK | HERMON_CMD_BKEY_DONTCHECK;
209030e01c53SRamaswamy Tummala 	cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN; /* NO SLEEP */
209130e01c53SRamaswamy Tummala 	status = hermon_cmd_post(state, &cmd);
209230e01c53SRamaswamy Tummala 	if (status != HERMON_CMD_SUCCESS) {
209330e01c53SRamaswamy Tummala 		goto fail;
209430e01c53SRamaswamy Tummala 	}
209530e01c53SRamaswamy Tummala 
209630e01c53SRamaswamy Tummala 	/* Sync the mailbox to read the results */
209730e01c53SRamaswamy Tummala 	hermon_mbox_sync(mbox_info.mbi_out, 0, HERMON_CMD_MAD_IFC_SIZE,
209830e01c53SRamaswamy Tummala 	    DDI_DMA_SYNC_FORCPU);
209930e01c53SRamaswamy Tummala 
210030e01c53SRamaswamy Tummala 	/*
210130e01c53SRamaswamy Tummala 	 * We can discard the MAD header and the reserved area of the
210230e01c53SRamaswamy Tummala 	 * perf mgmt class MAD
210330e01c53SRamaswamy Tummala 	 */
210430e01c53SRamaswamy Tummala 	data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
210530e01c53SRamaswamy Tummala 	    ((uint64_t *)mbox_info.mbi_out->mb_addr + 8));
210630e01c53SRamaswamy Tummala 	*ext_width_supported = (data & (HERMON_IS_EXT_WIDTH_SUPPORTED |
210730e01c53SRamaswamy Tummala 	    HERMON_IS_EXT_WIDTH_SUPPORTED_NOIETF)) ? 1 : 0;
210830e01c53SRamaswamy Tummala 
210930e01c53SRamaswamy Tummala fail:
211030e01c53SRamaswamy Tummala 	/* Free the mailbox */
211130e01c53SRamaswamy Tummala 	hermon_mbox_free(state, &mbox_info);
211230e01c53SRamaswamy Tummala 	return (status);
211330e01c53SRamaswamy Tummala }
211430e01c53SRamaswamy Tummala 
211530e01c53SRamaswamy Tummala /*
211630e01c53SRamaswamy Tummala  * hermon_getextpefcntr_cmd_post()
211730e01c53SRamaswamy Tummala  *
211830e01c53SRamaswamy Tummala  * Read the extended performance counters of the specified port and
211930e01c53SRamaswamy Tummala  * copy them into perfinfo.
212030e01c53SRamaswamy Tummala  */
212130e01c53SRamaswamy Tummala int
hermon_getextperfcntr_cmd_post(hermon_state_t * state,uint_t port,uint_t sleepflag,hermon_hw_sm_extperfcntr_t * perfinfo)212230e01c53SRamaswamy Tummala hermon_getextperfcntr_cmd_post(hermon_state_t *state, uint_t port,
212330e01c53SRamaswamy Tummala     uint_t sleepflag, hermon_hw_sm_extperfcntr_t *perfinfo)
212430e01c53SRamaswamy Tummala {
212530e01c53SRamaswamy Tummala 	hermon_mbox_info_t	mbox_info;
212630e01c53SRamaswamy Tummala 	hermon_cmd_post_t	cmd;
212730e01c53SRamaswamy Tummala 	uint64_t		data;
212830e01c53SRamaswamy Tummala 	uint32_t		*mbox;
212930e01c53SRamaswamy Tummala 	int			status, i;
213030e01c53SRamaswamy Tummala 
213130e01c53SRamaswamy Tummala 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
213230e01c53SRamaswamy Tummala 
213330e01c53SRamaswamy Tummala 	/* Get "In" and "Out" mailboxes for the command */
213430e01c53SRamaswamy Tummala 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
213530e01c53SRamaswamy Tummala 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
213630e01c53SRamaswamy Tummala 	if (status != HERMON_CMD_SUCCESS) {
213730e01c53SRamaswamy Tummala 		return (status);
213830e01c53SRamaswamy Tummala 	}
213930e01c53SRamaswamy Tummala 
214030e01c53SRamaswamy Tummala 	/* Build PortCountersExtended request MAD in the "In" mailbox */
214130e01c53SRamaswamy Tummala 	mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
214230e01c53SRamaswamy Tummala 
214330e01c53SRamaswamy Tummala 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_PERF_GET);
214430e01c53SRamaswamy Tummala 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
214530e01c53SRamaswamy Tummala 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
214630e01c53SRamaswamy Tummala 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
214730e01c53SRamaswamy Tummala 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4],
214830e01c53SRamaswamy Tummala 	    HERMON_CMD_EXTPERFCNTRS);
214930e01c53SRamaswamy Tummala 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], HERMON_CMD_PERFATTR);
215030e01c53SRamaswamy Tummala 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16], (port << 16));
215130e01c53SRamaswamy Tummala 
215230e01c53SRamaswamy Tummala 	/* Sync the mailbox for the device to read */
215330e01c53SRamaswamy Tummala 	hermon_mbox_sync(mbox_info.mbi_in, 0, HERMON_CMD_MAD_IFC_SIZE,
215430e01c53SRamaswamy Tummala 	    DDI_DMA_SYNC_FORDEV);
215530e01c53SRamaswamy Tummala 
215630e01c53SRamaswamy Tummala 	/* Setup the Hermon "MAD_IFC" command */
215730e01c53SRamaswamy Tummala 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
215830e01c53SRamaswamy Tummala 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
215930e01c53SRamaswamy Tummala 	cmd.cp_inmod	= port;
216030e01c53SRamaswamy Tummala 	cmd.cp_opcode	= MAD_IFC;
216130e01c53SRamaswamy Tummala 	/* No MKey and BKey checking */
216230e01c53SRamaswamy Tummala 	cmd.cp_opmod	= HERMON_CMD_MKEY_DONTCHECK | HERMON_CMD_BKEY_DONTCHECK;
216330e01c53SRamaswamy Tummala 	cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN; /* NO SLEEP */
216430e01c53SRamaswamy Tummala 	status = hermon_cmd_post(state, &cmd);
216530e01c53SRamaswamy Tummala 	if (status != HERMON_CMD_SUCCESS) {
216630e01c53SRamaswamy Tummala 		goto fail;
216730e01c53SRamaswamy Tummala 	}
216830e01c53SRamaswamy Tummala 
216930e01c53SRamaswamy Tummala 	/* Sync the mailbox to read the results */
217030e01c53SRamaswamy Tummala 	hermon_mbox_sync(mbox_info.mbi_out, 0, HERMON_CMD_MAD_IFC_SIZE,
217130e01c53SRamaswamy Tummala 	    DDI_DMA_SYNC_FORCPU);
217230e01c53SRamaswamy Tummala 
217330e01c53SRamaswamy Tummala 	/*
217430e01c53SRamaswamy Tummala 	 * Copy Perfcounters into "perfinfo". We can discard the MAD
217530e01c53SRamaswamy Tummala 	 * header and the reserved area of the perf mgmt class MAD.
217630e01c53SRamaswamy Tummala 	 */
217730e01c53SRamaswamy Tummala 	for (i = 0; i < (sizeof (hermon_hw_sm_extperfcntr_t) >> 3); i++) {
217830e01c53SRamaswamy Tummala 		data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
217930e01c53SRamaswamy Tummala 		    ((uint64_t *)mbox_info.mbi_out->mb_addr + i + 8));
218030e01c53SRamaswamy Tummala 		((uint64_t *)(void *)perfinfo)[i] = data;
218130e01c53SRamaswamy Tummala 	}
218230e01c53SRamaswamy Tummala 
218330e01c53SRamaswamy Tummala fail:
218430e01c53SRamaswamy Tummala 	/* Free the mailbox */
218530e01c53SRamaswamy Tummala 	hermon_mbox_free(state, &mbox_info);
218630e01c53SRamaswamy Tummala 	return (status);
218730e01c53SRamaswamy Tummala }
218830e01c53SRamaswamy Tummala 
21899e39c5baSBill Taylor /*
21909e39c5baSBill Taylor  * hermon_getpefcntr_cmd_post()
21919e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
2192d1a5c838SRamaswamy Tummala  *
2193d1a5c838SRamaswamy Tummala  * If reset is zero, read the performance counters of the specified port and
2194d1a5c838SRamaswamy Tummala  * copy them into perfinfo.
2195d1a5c838SRamaswamy Tummala  * If reset is non-zero reset the performance counters of the specified port.
21969e39c5baSBill Taylor  */
21979e39c5baSBill Taylor int
hermon_getperfcntr_cmd_post(hermon_state_t * state,uint_t port,uint_t sleepflag,hermon_hw_sm_perfcntr_t * perfinfo,int reset)21989e39c5baSBill Taylor hermon_getperfcntr_cmd_post(hermon_state_t *state, uint_t port,
2199d1a5c838SRamaswamy Tummala     uint_t sleepflag, hermon_hw_sm_perfcntr_t *perfinfo, int reset)
22009e39c5baSBill Taylor {
22019e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
22029e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
22039e39c5baSBill Taylor 	uint64_t		data;
22049e39c5baSBill Taylor 	uint32_t		*mbox;
22059e39c5baSBill Taylor 	uint_t			size;
22069e39c5baSBill Taylor 	int			status, i;
22079e39c5baSBill Taylor 
22089e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
22099e39c5baSBill Taylor 
22109e39c5baSBill Taylor 	/* Get "In" and "Out" mailboxes for the command */
22119e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
22129e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
22139e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
22149e39c5baSBill Taylor 		return (status);
22159e39c5baSBill Taylor 	}
22169e39c5baSBill Taylor 
22179e39c5baSBill Taylor 	/* Build the GetPortInfo request MAD in the "In" mailbox */
22189e39c5baSBill Taylor 	size = HERMON_CMD_MAD_IFC_SIZE;
22199e39c5baSBill Taylor 	mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2220d1a5c838SRamaswamy Tummala 
2221d1a5c838SRamaswamy Tummala 	if (reset) {
2222d1a5c838SRamaswamy Tummala 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0],
2223d1a5c838SRamaswamy Tummala 		    HERMON_CMD_PERF_SET);
2224d1a5c838SRamaswamy Tummala 	} else {
2225d1a5c838SRamaswamy Tummala 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0],
2226d1a5c838SRamaswamy Tummala 		    HERMON_CMD_PERF_GET);
2227d1a5c838SRamaswamy Tummala 	}
22289e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
22299e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
22309e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
22319e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_PERFCNTRS);
22329e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], HERMON_CMD_PERFATTR);
2233d1a5c838SRamaswamy Tummala 
2234d1a5c838SRamaswamy Tummala 	if (reset) {
2235d1a5c838SRamaswamy Tummala 		/* reset counters for XmitData, RcvData, XmitPkts, RcvPkts */
2236d1a5c838SRamaswamy Tummala 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16],
2237d1a5c838SRamaswamy Tummala 		    ((port << 16) | 0xf000));
2238d1a5c838SRamaswamy Tummala 
2239d1a5c838SRamaswamy Tummala 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[22], 0);
2240d1a5c838SRamaswamy Tummala 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[23], 0);
2241d1a5c838SRamaswamy Tummala 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[24], 0);
2242d1a5c838SRamaswamy Tummala 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[25], 0);
2243d1a5c838SRamaswamy Tummala 	} else
2244d1a5c838SRamaswamy Tummala 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16], (port << 16));
22459e39c5baSBill Taylor 
22469e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
22479e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
22489e39c5baSBill Taylor 
22499e39c5baSBill Taylor 	/* Setup the Hermon "MAD_IFC" command */
22509e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
22519e39c5baSBill Taylor 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
22529e39c5baSBill Taylor 	cmd.cp_inmod	= port;
22539e39c5baSBill Taylor 	cmd.cp_opcode	= MAD_IFC;
225430e01c53SRamaswamy Tummala 	/* No MKey and BKey checking */
225530e01c53SRamaswamy Tummala 	cmd.cp_opmod	= HERMON_CMD_MKEY_DONTCHECK | HERMON_CMD_BKEY_DONTCHECK;
22569e39c5baSBill Taylor 	cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN; /* NO SLEEP */
22579e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
22589e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
22599e39c5baSBill Taylor 		goto getperfinfo_fail;
22609e39c5baSBill Taylor 	}
22619e39c5baSBill Taylor 
22629e39c5baSBill Taylor 	/* Sync the mailbox to read the results */
22639e39c5baSBill Taylor 	size = HERMON_CMD_MAD_IFC_SIZE;
22649e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
22659e39c5baSBill Taylor 
2266d1a5c838SRamaswamy Tummala 	if (reset == 0) {
2267d1a5c838SRamaswamy Tummala 		size = sizeof (hermon_hw_sm_perfcntr_t); /* for the copy */
2268d1a5c838SRamaswamy Tummala 		/*
2269d1a5c838SRamaswamy Tummala 		 * Copy Perfcounters into "perfinfo".  We can discard the MAD
2270d1a5c838SRamaswamy Tummala 		 * header and the 8 Quadword reserved area of the PERM mgmt
2271d1a5c838SRamaswamy Tummala 		 * class MAD
2272d1a5c838SRamaswamy Tummala 		 */
22739e39c5baSBill Taylor 
2274d1a5c838SRamaswamy Tummala 		for (i = 0; i < size >> 3; i++) {
2275d1a5c838SRamaswamy Tummala 			data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2276d1a5c838SRamaswamy Tummala 			    ((uint64_t *)mbox_info.mbi_out->mb_addr + i + 8));
2277d1a5c838SRamaswamy Tummala 			((uint64_t *)(void *)perfinfo)[i] = data;
2278d1a5c838SRamaswamy Tummala 		}
22799e39c5baSBill Taylor 	}
22809e39c5baSBill Taylor 
22819e39c5baSBill Taylor getperfinfo_fail:
22829e39c5baSBill Taylor 	/* Free the mailbox */
22839e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
22849e39c5baSBill Taylor 	return (status);
22859e39c5baSBill Taylor }
22869e39c5baSBill Taylor 
22879e39c5baSBill Taylor 
22889e39c5baSBill Taylor 
22899e39c5baSBill Taylor /*
22909e39c5baSBill Taylor  * hermon_getnodeinfo_cmd_post()
22919e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
22929e39c5baSBill Taylor  *    (Currently called only from attach() and detach() path contexts)
22939e39c5baSBill Taylor  */
22949e39c5baSBill Taylor int
hermon_getnodeinfo_cmd_post(hermon_state_t * state,uint_t sleepflag,sm_nodeinfo_t * nodeinfo)22959e39c5baSBill Taylor hermon_getnodeinfo_cmd_post(hermon_state_t *state, uint_t sleepflag,
22969e39c5baSBill Taylor     sm_nodeinfo_t *nodeinfo)
22979e39c5baSBill Taylor {
22989e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
22999e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
23009e39c5baSBill Taylor 	uint32_t		*mbox;
23019e39c5baSBill Taylor 	uint_t			size;
23029e39c5baSBill Taylor 	int			status, i;
23039e39c5baSBill Taylor 
23049e39c5baSBill Taylor 	/* Make sure we are called with the correct flag */
23059e39c5baSBill Taylor 	ASSERT(sleepflag == HERMON_CMD_NOSLEEP_SPIN);
23069e39c5baSBill Taylor 
23079e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
23089e39c5baSBill Taylor 
23099e39c5baSBill Taylor 	/* Get "In" and "Out" mailboxes for the command */
23109e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
23119e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
23129e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
23139e39c5baSBill Taylor 		return (status);
23149e39c5baSBill Taylor 	}
23159e39c5baSBill Taylor 
23169e39c5baSBill Taylor 	/* Build the GetNodeInfo request MAD into the "In" mailbox */
23179e39c5baSBill Taylor 	size = HERMON_CMD_MAD_IFC_SIZE;
23189e39c5baSBill Taylor 	mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
23199e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
23209e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
23219e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
23229e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
23239e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_NODEINFO);
23249e39c5baSBill Taylor 	for (i = 5; i < (size >> 2); i++) {
23259e39c5baSBill Taylor 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
23269e39c5baSBill Taylor 	}
23279e39c5baSBill Taylor 
23289e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
23299e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
23309e39c5baSBill Taylor 
23319e39c5baSBill Taylor 	/* Setup the Hermon "MAD_IFC" command */
23329e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
23339e39c5baSBill Taylor 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
23349e39c5baSBill Taylor 	cmd.cp_inmod	= 1;  /* Get NodeInfo from port #1 */
23359e39c5baSBill Taylor 	cmd.cp_opcode	= MAD_IFC;
23369e39c5baSBill Taylor 	cmd.cp_opmod	= HERMON_CMD_MKEY_DONTCHECK;  /* No MKey checking */
23379e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
23389e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
23399e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
23409e39c5baSBill Taylor 		goto getnodeinfo_fail;
23419e39c5baSBill Taylor 	}
23429e39c5baSBill Taylor 
23439e39c5baSBill Taylor 	/* Sync the mailbox to read the results */
23449e39c5baSBill Taylor 	size = sizeof (sm_nodeinfo_t);
23459e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
23469e39c5baSBill Taylor 	    size, DDI_DMA_SYNC_FORCPU);
23479e39c5baSBill Taylor 
23489e39c5baSBill Taylor 	/*
23499e39c5baSBill Taylor 	 * Copy GetNodeInfo response MAD into "nodeinfo".  Do any endian
23509e39c5baSBill Taylor 	 * swapping that may be necessary to flip any of the "nodeinfo"
23519e39c5baSBill Taylor 	 * fields
23529e39c5baSBill Taylor 	 */
23539e39c5baSBill Taylor 	bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
23549e39c5baSBill Taylor 	    HERMON_CMD_MADDATA_OFFSET), nodeinfo, size);
235576c04273SRajkumar Sivaprakasam 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*nodeinfo))
23569e39c5baSBill Taylor 	HERMON_GETNODEINFO_SWAP(nodeinfo);
23579e39c5baSBill Taylor 
23589e39c5baSBill Taylor getnodeinfo_fail:
23599e39c5baSBill Taylor 	/* Free the mailbox */
23609e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
23619e39c5baSBill Taylor 	return (status);
23629e39c5baSBill Taylor }
23639e39c5baSBill Taylor 
23649e39c5baSBill Taylor 
23659e39c5baSBill Taylor /*
23669e39c5baSBill Taylor  * hermon_getnodedesc_cmd_post()
23679e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
23689e39c5baSBill Taylor  *    (Currently called only from attach() and detach() path contexts)
23699e39c5baSBill Taylor  */
23709e39c5baSBill Taylor int
hermon_getnodedesc_cmd_post(hermon_state_t * state,uint_t sleepflag,sm_nodedesc_t * nodedesc)23719e39c5baSBill Taylor hermon_getnodedesc_cmd_post(hermon_state_t *state, uint_t sleepflag,
23729e39c5baSBill Taylor     sm_nodedesc_t *nodedesc)
23739e39c5baSBill Taylor {
23749e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
23759e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
23769e39c5baSBill Taylor 	uint32_t		*mbox;
23779e39c5baSBill Taylor 	uint_t			size;
23789e39c5baSBill Taylor 	int			status, i;
23799e39c5baSBill Taylor 
23809e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
23819e39c5baSBill Taylor 
23829e39c5baSBill Taylor 	/* Get "In" and "Out" mailboxes for the command */
23839e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
23849e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
23859e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
23869e39c5baSBill Taylor 		return (status);
23879e39c5baSBill Taylor 	}
23889e39c5baSBill Taylor 
23899e39c5baSBill Taylor 	/* Build the GetNodeDesc request MAD into the "In" mailbox */
23909e39c5baSBill Taylor 	size = HERMON_CMD_MAD_IFC_SIZE;
23919e39c5baSBill Taylor 	mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
23929e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
23939e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
23949e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
23959e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
23969e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_NODEDESC);
23979e39c5baSBill Taylor 	for (i = 5; i < (size >> 2); i++) {
23989e39c5baSBill Taylor 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
23999e39c5baSBill Taylor 	}
24009e39c5baSBill Taylor 
24019e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
24029e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
24039e39c5baSBill Taylor 
24049e39c5baSBill Taylor 	/* Setup the Hermon "MAD_IFC" command */
24059e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
24069e39c5baSBill Taylor 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
24079e39c5baSBill Taylor 	cmd.cp_inmod	= 1;  /* Get NodeDesc from port #1 */
24089e39c5baSBill Taylor 	cmd.cp_opcode	= MAD_IFC;
24099e39c5baSBill Taylor 	cmd.cp_opmod	= HERMON_CMD_MKEY_DONTCHECK;  /* No MKey checking */
24109e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
24119e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
24129e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
24139e39c5baSBill Taylor 		goto getnodedesc_fail;
24149e39c5baSBill Taylor 	}
24159e39c5baSBill Taylor 
24169e39c5baSBill Taylor 	/* Sync the mailbox to read the results */
24179e39c5baSBill Taylor 	size = sizeof (sm_nodedesc_t);
24189e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
24199e39c5baSBill Taylor 	    size, DDI_DMA_SYNC_FORCPU);
24209e39c5baSBill Taylor 
24219e39c5baSBill Taylor 	/* Copy GetNodeDesc response MAD into "nodedesc" */
24229e39c5baSBill Taylor 	bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
24239e39c5baSBill Taylor 	    HERMON_CMD_MADDATA_OFFSET), nodedesc, size);
24249e39c5baSBill Taylor 
24259e39c5baSBill Taylor getnodedesc_fail:
24269e39c5baSBill Taylor 	/* Free the mailbox */
24279e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
24289e39c5baSBill Taylor 	return (status);
24299e39c5baSBill Taylor }
24309e39c5baSBill Taylor 
24319e39c5baSBill Taylor 
24329e39c5baSBill Taylor /*
24339e39c5baSBill Taylor  * hermon_getguidinfo_cmd_post()
24349e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
24359e39c5baSBill Taylor  */
24369e39c5baSBill Taylor int
hermon_getguidinfo_cmd_post(hermon_state_t * state,uint_t port,uint_t guidblock,uint_t sleepflag,sm_guidinfo_t * guidinfo)24379e39c5baSBill Taylor hermon_getguidinfo_cmd_post(hermon_state_t *state, uint_t port,
24389e39c5baSBill Taylor     uint_t guidblock, uint_t sleepflag, sm_guidinfo_t *guidinfo)
24399e39c5baSBill Taylor {
24409e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
24419e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
24429e39c5baSBill Taylor 	uint32_t		*mbox;
24439e39c5baSBill Taylor 	uint_t			size;
24449e39c5baSBill Taylor 	int			status, i;
24459e39c5baSBill Taylor 
24469e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
24479e39c5baSBill Taylor 
24489e39c5baSBill Taylor 	/* Get "In" and "Out" mailboxes for the command */
24499e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
24509e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
24519e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
24529e39c5baSBill Taylor 		return (status);
24539e39c5baSBill Taylor 	}
24549e39c5baSBill Taylor 
24559e39c5baSBill Taylor 	/* Build the GetGUIDInfo request MAD into the "In" mailbox */
24569e39c5baSBill Taylor 	size = HERMON_CMD_MAD_IFC_SIZE;
24579e39c5baSBill Taylor 	mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
24589e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
24599e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
24609e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
24619e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
24629e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_GUIDINFO);
24639e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], guidblock);
24649e39c5baSBill Taylor 	for (i = 6; i < (size >> 2); i++) {
24659e39c5baSBill Taylor 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
24669e39c5baSBill Taylor 	}
24679e39c5baSBill Taylor 
24689e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
24699e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
24709e39c5baSBill Taylor 
24719e39c5baSBill Taylor 	/* Setup the Hermon "MAD_IFC" command */
24729e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
24739e39c5baSBill Taylor 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
24749e39c5baSBill Taylor 	cmd.cp_inmod	= port;
24759e39c5baSBill Taylor 	cmd.cp_opcode	= MAD_IFC;
24769e39c5baSBill Taylor 	cmd.cp_opmod	= HERMON_CMD_MKEY_DONTCHECK;  /* No MKey checking */
24779e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
24789e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
24799e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
24809e39c5baSBill Taylor 		goto getguidinfo_fail;
24819e39c5baSBill Taylor 	}
24829e39c5baSBill Taylor 
24839e39c5baSBill Taylor 	/* Sync the mailbox to read the results */
24849e39c5baSBill Taylor 	size = sizeof (sm_guidinfo_t);
24859e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
24869e39c5baSBill Taylor 	    size, DDI_DMA_SYNC_FORCPU);
24879e39c5baSBill Taylor 
24889e39c5baSBill Taylor 	/*
24899e39c5baSBill Taylor 	 * Copy GetGUIDInfo response MAD into "guidinfo".  Do any endian
24909e39c5baSBill Taylor 	 * swapping that may be necessary to flip the "guidinfo" fields
24919e39c5baSBill Taylor 	 */
24929e39c5baSBill Taylor 	bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
24939e39c5baSBill Taylor 	    HERMON_CMD_MADDATA_OFFSET), guidinfo, size);
249476c04273SRajkumar Sivaprakasam 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*guidinfo))
24959e39c5baSBill Taylor 	HERMON_GETGUIDINFO_SWAP(guidinfo);
24969e39c5baSBill Taylor 
24979e39c5baSBill Taylor getguidinfo_fail:
24989e39c5baSBill Taylor 	/* Free the mailbox */
24999e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
25009e39c5baSBill Taylor 	return (status);
25019e39c5baSBill Taylor }
25029e39c5baSBill Taylor 
25039e39c5baSBill Taylor 
25049e39c5baSBill Taylor /*
25059e39c5baSBill Taylor  * hermon_getpkeytable_cmd_post()
25069e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
25079e39c5baSBill Taylor  */
25089e39c5baSBill Taylor int
hermon_getpkeytable_cmd_post(hermon_state_t * state,uint_t port,uint_t pkeyblock,uint_t sleepflag,sm_pkey_table_t * pkeytable)25099e39c5baSBill Taylor hermon_getpkeytable_cmd_post(hermon_state_t *state, uint_t port,
25109e39c5baSBill Taylor     uint_t pkeyblock, uint_t sleepflag, sm_pkey_table_t *pkeytable)
25119e39c5baSBill Taylor {
25129e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
25139e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
25149e39c5baSBill Taylor 	uint32_t		*mbox;
25159e39c5baSBill Taylor 	uint_t			size;
25169e39c5baSBill Taylor 	int			status, i;
25179e39c5baSBill Taylor 
25189e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
25199e39c5baSBill Taylor 
25209e39c5baSBill Taylor 	/* Get "In" and "Out" mailboxes for the command */
25219e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
25229e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
25239e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
25249e39c5baSBill Taylor 		return (status);
25259e39c5baSBill Taylor 	}
25269e39c5baSBill Taylor 
25279e39c5baSBill Taylor 	/* Build the GetPkeyTable request MAD into the "In" mailbox */
25289e39c5baSBill Taylor 	size = HERMON_CMD_MAD_IFC_SIZE;
25299e39c5baSBill Taylor 	mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
25309e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
25319e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
25329e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
25339e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
25349e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_PKEYTBLE);
25359e39c5baSBill Taylor 	ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], pkeyblock);
25369e39c5baSBill Taylor 	for (i = 6; i < (size >> 2); i++) {
25379e39c5baSBill Taylor 		ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
25389e39c5baSBill Taylor 	}
25399e39c5baSBill Taylor 
25409e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
25419e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
25429e39c5baSBill Taylor 
25439e39c5baSBill Taylor 	/* Setup the Hermon "MAD_IFC" command */
25449e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
25459e39c5baSBill Taylor 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
25469e39c5baSBill Taylor 	cmd.cp_inmod	= port;
25479e39c5baSBill Taylor 	cmd.cp_opcode	= MAD_IFC;
25489e39c5baSBill Taylor 	cmd.cp_opmod	= HERMON_CMD_MKEY_DONTCHECK;  /* No MKey checking */
25499e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
25509e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
25519e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
25529e39c5baSBill Taylor 		goto getpkeytable_fail;
25539e39c5baSBill Taylor 	}
25549e39c5baSBill Taylor 
25559e39c5baSBill Taylor 	/* Sync the mailbox to read the results */
25569e39c5baSBill Taylor 	size = sizeof (sm_pkey_table_t);
25579e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
25589e39c5baSBill Taylor 	    size, DDI_DMA_SYNC_FORCPU);
25599e39c5baSBill Taylor 
25609e39c5baSBill Taylor 	/*
25619e39c5baSBill Taylor 	 * Copy GetPKeyTable response MAD into "pkeytable".  Do any endian
25629e39c5baSBill Taylor 	 * swapping that may be necessary to flip the "pkeytable" fields
25639e39c5baSBill Taylor 	 */
25649e39c5baSBill Taylor 	bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
25659e39c5baSBill Taylor 	    HERMON_CMD_MADDATA_OFFSET), pkeytable, size);
256676c04273SRajkumar Sivaprakasam 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*pkeytable))
25679e39c5baSBill Taylor 	HERMON_GETPKEYTABLE_SWAP(pkeytable);
25689e39c5baSBill Taylor 
25699e39c5baSBill Taylor getpkeytable_fail:
25709e39c5baSBill Taylor 	/* Free the mailbox */
25719e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
25729e39c5baSBill Taylor 	return (status);
25739e39c5baSBill Taylor }
25749e39c5baSBill Taylor 
25759e39c5baSBill Taylor 
25769e39c5baSBill Taylor /*
25779e39c5baSBill Taylor  * hermon_write_mtt_cmd_post()
25789e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
25799e39c5baSBill Taylor  */
25809e39c5baSBill Taylor int
hermon_write_mtt_cmd_post(hermon_state_t * state,hermon_rsrc_t * mtt,uint64_t start_addr,uint_t nummtt,uint_t sleepflag)25819e39c5baSBill Taylor hermon_write_mtt_cmd_post(hermon_state_t *state, hermon_rsrc_t *mtt,
25829e39c5baSBill Taylor     uint64_t start_addr, uint_t nummtt, uint_t sleepflag)
25839e39c5baSBill Taylor {
25849e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
25859e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
25869e39c5baSBill Taylor 	uint64_t		data;
25879e39c5baSBill Taylor 	uint_t			size;
25889e39c5baSBill Taylor 	int			status;
25899e39c5baSBill Taylor 	int			i;
25909e39c5baSBill Taylor 
25919e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
25929e39c5baSBill Taylor 
25939e39c5baSBill Taylor 	/* Get an "In" mailbox for the command */
25949e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
25959e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
25969e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
25979e39c5baSBill Taylor 		return (status);
25989e39c5baSBill Taylor 	}
25999e39c5baSBill Taylor 
26009e39c5baSBill Taylor 	/*
26019e39c5baSBill Taylor 	 * The WRITE_MTT command input parameter contains the 64-bit addr of
26029e39c5baSBill Taylor 	 * the first target MTT, followed by 64 bits reserved, followed by an
26039e39c5baSBill Taylor 	 * array of MTT entries.
26049e39c5baSBill Taylor 	 *
26059e39c5baSBill Taylor 	 */
26069e39c5baSBill Taylor 	ddi_put64(mbox_info.mbi_in->mb_acchdl,
26079e39c5baSBill Taylor 	    ((uint64_t *)mbox_info.mbi_in->mb_addr),
26089e39c5baSBill Taylor 	    start_addr);
26099e39c5baSBill Taylor 
26109e39c5baSBill Taylor 	ddi_put64(mbox_info.mbi_in->mb_acchdl,
26119e39c5baSBill Taylor 	    ((uint64_t *)mbox_info.mbi_in->mb_addr + 1), 0x0);
26129e39c5baSBill Taylor 
26139e39c5baSBill Taylor 	for (i = 0; i < nummtt; i++) {
26149e39c5baSBill Taylor 		data = ((uint64_t *)mtt->hr_addr)[i];
26159e39c5baSBill Taylor 		ddi_put64(mbox_info.mbi_in->mb_acchdl,
26169e39c5baSBill Taylor 		    ((uint64_t *)mbox_info.mbi_in->mb_addr + i + 2), data);
26179e39c5baSBill Taylor 	}
26189e39c5baSBill Taylor 
26199e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
26209e39c5baSBill Taylor 	size = (nummtt << HERMON_MTT_SIZE_SHIFT) + HERMON_CMD_WRITEMTT_RSVD_SZ;
26219e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
26229e39c5baSBill Taylor 
26239e39c5baSBill Taylor 	/* Setup and post Hermon "WRITE_MTT" command */
26249e39c5baSBill Taylor 	cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
26259e39c5baSBill Taylor 	cmd.cp_outparm  = 0;
26269e39c5baSBill Taylor 	cmd.cp_inmod    = nummtt;
26279e39c5baSBill Taylor 	cmd.cp_opcode   = WRITE_MTT;
26289e39c5baSBill Taylor 	cmd.cp_opmod    = 0;
26299e39c5baSBill Taylor 	cmd.cp_flags    = sleepflag;
26309e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
26319e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
26329e39c5baSBill Taylor 		cmn_err(CE_CONT, "WRITE_MTT failed (0x%x)\n", status);
26339e39c5baSBill Taylor 	}
26349e39c5baSBill Taylor 
26359e39c5baSBill Taylor 	/* Free the mailbox */
26369e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
26379e39c5baSBill Taylor 	return (status);
26389e39c5baSBill Taylor }
26399e39c5baSBill Taylor 
26409e39c5baSBill Taylor 
26419e39c5baSBill Taylor /*
26429e39c5baSBill Taylor  * hermon_sync_tpt_cmd_post()
26439e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
26449e39c5baSBill Taylor  */
26459e39c5baSBill Taylor int
hermon_sync_tpt_cmd_post(hermon_state_t * state,uint_t sleepflag)26469e39c5baSBill Taylor hermon_sync_tpt_cmd_post(hermon_state_t *state, uint_t sleepflag)
26479e39c5baSBill Taylor {
26489e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
26499e39c5baSBill Taylor 	int			status;
26509e39c5baSBill Taylor 
26519e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
26529e39c5baSBill Taylor 
26539e39c5baSBill Taylor 	/* Setup and post the Hermon "SYNC_TPT" command */
26549e39c5baSBill Taylor 	cmd.cp_inparm	= 0;
26559e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
26569e39c5baSBill Taylor 	cmd.cp_inmod	= 0;
26579e39c5baSBill Taylor 	cmd.cp_opcode	= SYNC_TPT;
26589e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
26599e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
26609e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
26619e39c5baSBill Taylor 
26629e39c5baSBill Taylor 	return (status);
26639e39c5baSBill Taylor }
26649e39c5baSBill Taylor 
26659e39c5baSBill Taylor /*
26669e39c5baSBill Taylor  * hermon_map_eq_cmd_post()
26679e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
26689e39c5baSBill Taylor  *    (Currently called only from attach() and/or detach() path contexts)
26699e39c5baSBill Taylor  */
26709e39c5baSBill Taylor int
hermon_map_eq_cmd_post(hermon_state_t * state,uint_t map,uint_t eqcindx,uint64_t eqmapmask,uint_t sleepflag)26719e39c5baSBill Taylor hermon_map_eq_cmd_post(hermon_state_t *state, uint_t map, uint_t eqcindx,
26729e39c5baSBill Taylor     uint64_t eqmapmask, uint_t sleepflag)
26739e39c5baSBill Taylor {
26749e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
26759e39c5baSBill Taylor 	int			status;
26769e39c5baSBill Taylor 
26779e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
26789e39c5baSBill Taylor 
26799e39c5baSBill Taylor 	/* Setup and post Hermon "MAP_EQ" command */
26809e39c5baSBill Taylor 	cmd.cp_inparm	= eqmapmask;
26819e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
26829e39c5baSBill Taylor 	cmd.cp_inmod	= eqcindx;
26839e39c5baSBill Taylor 	if (map != HERMON_CMD_MAP_EQ_EVT_MAP) {
26849e39c5baSBill Taylor 		cmd.cp_inmod |= HERMON_CMD_UNMAP_EQ_MASK;
26859e39c5baSBill Taylor 	}
26869e39c5baSBill Taylor 	cmd.cp_opcode	= MAP_EQ;
26879e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
26889e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
26899e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
26909e39c5baSBill Taylor 	return (status);
26919e39c5baSBill Taylor }
26929e39c5baSBill Taylor 
26939e39c5baSBill Taylor 
26949e39c5baSBill Taylor /*
26959e39c5baSBill Taylor  * hermon_resize_cq_cmd_post()
26969e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
26979e39c5baSBill Taylor  */
26989e39c5baSBill Taylor int
hermon_resize_cq_cmd_post(hermon_state_t * state,hermon_hw_cqc_t * cqc,uint_t cqcindx,uint32_t * prod_indx,uint_t sleepflag)26999e39c5baSBill Taylor hermon_resize_cq_cmd_post(hermon_state_t *state, hermon_hw_cqc_t *cqc,
27009e39c5baSBill Taylor     uint_t cqcindx, uint32_t *prod_indx, uint_t sleepflag)
27019e39c5baSBill Taylor {
27029e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
27039e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
27049e39c5baSBill Taylor 	uint64_t		data;
27059e39c5baSBill Taylor 	uint_t			size;
27069e39c5baSBill Taylor 	int			status, i;
27079e39c5baSBill Taylor 
27089e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
27099e39c5baSBill Taylor 
27109e39c5baSBill Taylor 	/* Get an "In" mailbox for the command */
27119e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
27129e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
27139e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
27149e39c5baSBill Taylor 		return (status);
27159e39c5baSBill Taylor 	}
27169e39c5baSBill Taylor 
27179e39c5baSBill Taylor 	/* Copy the Hermon "MODIFY_CQ" command into mailbox */
27189e39c5baSBill Taylor 	size = sizeof (hermon_hw_cqc_t);
27199e39c5baSBill Taylor 	for (i = 0; i < (size >> 3); i++) {
27209e39c5baSBill Taylor 		data = ((uint64_t *)(void *)cqc)[i];
27219e39c5baSBill Taylor 		ddi_put64(mbox_info.mbi_in->mb_acchdl,
27229e39c5baSBill Taylor 		    ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
27239e39c5baSBill Taylor 	}
27249e39c5baSBill Taylor 
27259e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
27269e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
27279e39c5baSBill Taylor 
27289e39c5baSBill Taylor 	/* Setup and post Hermon "MODIFY_CQ" command */
27299e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
27309e39c5baSBill Taylor 	cmd.cp_outparm	= 0;	/* resize cq */
27319e39c5baSBill Taylor 	cmd.cp_inmod	= cqcindx;
27329e39c5baSBill Taylor 	cmd.cp_opcode	= MODIFY_CQ;
27339e39c5baSBill Taylor 	cmd.cp_opmod	= RESIZE_CQ;
27349e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
27359e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
27369e39c5baSBill Taylor 
27379e39c5baSBill Taylor 	/*
27389e39c5baSBill Taylor 	 * New "producer index" is returned in the upper 32 bits of
27399e39c5baSBill Taylor 	 * command "outparam"
27409e39c5baSBill Taylor 	 */
27419e39c5baSBill Taylor 	*prod_indx = (cmd.cp_outparm >> 32);
27429e39c5baSBill Taylor 
27439e39c5baSBill Taylor 	/* Free the mailbox */
27449e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
27459e39c5baSBill Taylor 	return (status);
27469e39c5baSBill Taylor }
27479e39c5baSBill Taylor 
27489e39c5baSBill Taylor 
27499e39c5baSBill Taylor /*
27509e39c5baSBill Taylor  * hermon_modify_cq_cmd_post()
27519e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
27529e39c5baSBill Taylor  */
27539e39c5baSBill Taylor int
hermon_modify_cq_cmd_post(hermon_state_t * state,hermon_hw_cqc_t * cqc,uint_t cqcindx,uint_t opmod,uint_t sleepflag)27549e39c5baSBill Taylor hermon_modify_cq_cmd_post(hermon_state_t *state, hermon_hw_cqc_t *cqc,
27559e39c5baSBill Taylor     uint_t cqcindx, uint_t opmod, uint_t sleepflag)
27569e39c5baSBill Taylor {
27579e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
27589e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
27599e39c5baSBill Taylor 	uint64_t		data;
27609e39c5baSBill Taylor 	uint_t			size;
27619e39c5baSBill Taylor 	int			status, i;
27629e39c5baSBill Taylor 
27639e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
27649e39c5baSBill Taylor 
27659e39c5baSBill Taylor 	/* Get an "In" mailbox for the command */
27669e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
27679e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
27689e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
27699e39c5baSBill Taylor 		return (status);
27709e39c5baSBill Taylor 	}
27719e39c5baSBill Taylor 
27729e39c5baSBill Taylor 	/* Copy the Hermon "MODIFY_CQ" command into mailbox */
27739e39c5baSBill Taylor 	size = sizeof (hermon_hw_cqc_t);
27749e39c5baSBill Taylor 	for (i = 0; i < (size >> 3); i++) {
27759e39c5baSBill Taylor 		data = ((uint64_t *)(void *)cqc)[i];
27769e39c5baSBill Taylor 		ddi_put64(mbox_info.mbi_in->mb_acchdl,
27779e39c5baSBill Taylor 		    ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
27789e39c5baSBill Taylor 	}
27799e39c5baSBill Taylor 
27809e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
27819e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
27829e39c5baSBill Taylor 
27839e39c5baSBill Taylor 	/* Setup and post Hermon "MODIFY_CQ" command */
27849e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
27859e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
27869e39c5baSBill Taylor 	cmd.cp_inmod	= cqcindx;
27879e39c5baSBill Taylor 	cmd.cp_opcode	= MODIFY_CQ;
27889e39c5baSBill Taylor 	cmd.cp_opmod	= (uint16_t)opmod;
27899e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
27909e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
27919e39c5baSBill Taylor 
27929e39c5baSBill Taylor 	/* Free the mailbox */
27939e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
27949e39c5baSBill Taylor 	return (status);
27959e39c5baSBill Taylor }
27969e39c5baSBill Taylor 
27979e39c5baSBill Taylor 
27989e39c5baSBill Taylor /*
27999e39c5baSBill Taylor  * hermon_cmn_qp_cmd_post()
28009e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
28019e39c5baSBill Taylor  *
28029e39c5baSBill Taylor  *    This is the common function for posting all the various types of
28039e39c5baSBill Taylor  *    QP state transition related Hermon commands.  Since some of the
28049e39c5baSBill Taylor  *    commands differ from the others in the number (and type) of arguments
28059e39c5baSBill Taylor  *    that each require, this routine does checks based on opcode type
28069e39c5baSBill Taylor  *    (explained in more detail below).
28079e39c5baSBill Taylor  *
28089e39c5baSBill Taylor  * Note: This common function should be used only with the following
28099e39c5baSBill Taylor  *    opcodes: RTS2SQD_QP, TOERR_QP, TORST_QP, RST2INIT_QP, INIT2INIT_QP,
28109e39c5baSBill Taylor  *    INIT2RTR_QP, RTR2RTS_QP, RTS2RTS_QP, SQD2RTS_QP, and SQERR2RTS_QP.
28119e39c5baSBill Taylor  */
28129e39c5baSBill Taylor int
hermon_cmn_qp_cmd_post(hermon_state_t * state,uint_t opcode,hermon_hw_qpc_t * qp,uint_t qpindx,uint32_t opmask,uint_t sleepflag)28139e39c5baSBill Taylor hermon_cmn_qp_cmd_post(hermon_state_t *state, uint_t opcode,
28149e39c5baSBill Taylor     hermon_hw_qpc_t *qp, uint_t qpindx, uint32_t opmask,
28159e39c5baSBill Taylor     uint_t sleepflag)
28169e39c5baSBill Taylor {
28179e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
28189e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
28199e39c5baSBill Taylor 	uint64_t		data, in_mapaddr, out_mapaddr;
28209e39c5baSBill Taylor 	uint_t			size, flags, opmod;
28219e39c5baSBill Taylor 	int			status, i;
28229e39c5baSBill Taylor 
28239e39c5baSBill Taylor 	/*
28249e39c5baSBill Taylor 	 * Use the specified opcode type to set the appropriate parameters.
28259e39c5baSBill Taylor 	 * Specifically, we need to set in_mapaddr, out_mapaddr, flags, and
28269e39c5baSBill Taylor 	 * opmod (as necessary).  Setting these parameters may also require
28279e39c5baSBill Taylor 	 * us to allocate an "In" or "Out" mailbox depending on the command
28289e39c5baSBill Taylor 	 * type.
28299e39c5baSBill Taylor 	 */
28309e39c5baSBill Taylor 
28319e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
28329e39c5baSBill Taylor 
28339e39c5baSBill Taylor 	if (opcode == RTS2SQD_QP) {
28349e39c5baSBill Taylor 		/*
28359e39c5baSBill Taylor 		 * Note: For RTS-to-SendQueueDrain state transitions we
28369e39c5baSBill Taylor 		 * always want to request the event generation from the
28379e39c5baSBill Taylor 		 * hardware.  Though we may not notify the consumer of the
28389e39c5baSBill Taylor 		 * drained event, the decision to forward (or not) is made
28399e39c5baSBill Taylor 		 * later in the SQD event handler.
28409e39c5baSBill Taylor 		 */
28419e39c5baSBill Taylor 		flags = HERMON_CMD_REQ_SQD_EVENT;
28429e39c5baSBill Taylor 
28439e39c5baSBill Taylor 		/*
28449e39c5baSBill Taylor 		 * The RTS2SQD_QP command uses no "In" or "Out" mailboxes (and
28459e39c5baSBill Taylor 		 * has no special opcode modifiers).
28469e39c5baSBill Taylor 		 */
28479e39c5baSBill Taylor 		in_mapaddr  = 0;
28489e39c5baSBill Taylor 		out_mapaddr = 0;
28499e39c5baSBill Taylor 		opmod = 0;
28509e39c5baSBill Taylor 
28519e39c5baSBill Taylor 	} else if (opcode == TOERR_QP) {
28529e39c5baSBill Taylor 		/*
28539e39c5baSBill Taylor 		 * The TOERR_QP command uses no "In" or "Out" mailboxes, has no
28549e39c5baSBill Taylor 		 * special opcode modifiers, and takes no special flags.
28559e39c5baSBill Taylor 		 */
28569e39c5baSBill Taylor 		in_mapaddr  = 0;
28579e39c5baSBill Taylor 		out_mapaddr = 0;
28589e39c5baSBill Taylor 		opmod = 0;
28599e39c5baSBill Taylor 		flags = 0;
28609e39c5baSBill Taylor 
28619e39c5baSBill Taylor 	} else if (opcode == TORST_QP) {
28629e39c5baSBill Taylor 		/*
28639e39c5baSBill Taylor 		 * The TORST_QP command could take an "Out" mailbox, but we do
28649e39c5baSBill Taylor 		 * not require it here.  It also does not takes any special
28659e39c5baSBill Taylor 		 * flags.  It does however, take a HERMON_CMD_DIRECT_TO_RESET
28669e39c5baSBill Taylor 		 * opcode modifier, which indicates that the transition to
28679e39c5baSBill Taylor 		 * reset should happen without first moving the QP through the
28689e39c5baSBill Taylor 		 * Error state (and, hence, without generating any unnecessary
28699e39c5baSBill Taylor 		 * "flushed-in-error" completions).
28709e39c5baSBill Taylor 		 */
28719e39c5baSBill Taylor 		in_mapaddr  = 0;
28729e39c5baSBill Taylor 		out_mapaddr = 0;
28739e39c5baSBill Taylor 		opmod = HERMON_CMD_DIRECT_TO_RESET | HERMON_CMD_NO_OUTMBOX;
28749e39c5baSBill Taylor 		flags = 0;
28759e39c5baSBill Taylor 
28769e39c5baSBill Taylor 	} else {
28779e39c5baSBill Taylor 		/*
28789e39c5baSBill Taylor 		 * All the other QP state transition commands (RST2INIT_QP,
28799e39c5baSBill Taylor 		 * INIT2INIT_QP, INIT2RTR_QP, RTR2RTS_QP, RTS2RTS_QP,
28809e39c5baSBill Taylor 		 * SQD2RTS_QP, and SQERR2RTS_QP) require an "In" mailbox.
28819e39c5baSBill Taylor 		 * None of these require any special flags or opcode modifiers.
28829e39c5baSBill Taylor 		 */
28839e39c5baSBill Taylor 		mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
28849e39c5baSBill Taylor 		status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
28859e39c5baSBill Taylor 		if (status != HERMON_CMD_SUCCESS) {
28869e39c5baSBill Taylor 			return (status);
28879e39c5baSBill Taylor 		}
28889e39c5baSBill Taylor 		in_mapaddr  = mbox_info.mbi_in->mb_mapaddr;
28899e39c5baSBill Taylor 		out_mapaddr = 0;
28909e39c5baSBill Taylor 		flags = 0;
28919e39c5baSBill Taylor 		opmod = 0;
28929e39c5baSBill Taylor 
28939e39c5baSBill Taylor 		/* Copy the Hermon command into the "In" mailbox */
28949e39c5baSBill Taylor 		size = sizeof (hermon_hw_qpc_t);
28959e39c5baSBill Taylor 		for (i = 0; i < (size >> 3); i++) {
28969e39c5baSBill Taylor 			data = ((uint64_t *)(void *)qp)[i];
28979e39c5baSBill Taylor 			ddi_put64(mbox_info.mbi_in->mb_acchdl,
28989e39c5baSBill Taylor 			    ((uint64_t *)mbox_info.mbi_in->mb_addr + i + 1),
28999e39c5baSBill Taylor 			    data);
29009e39c5baSBill Taylor 		}
29019e39c5baSBill Taylor 		ddi_put32(mbox_info.mbi_in->mb_acchdl,
29029e39c5baSBill Taylor 		    ((uint32_t *)mbox_info.mbi_in->mb_addr), opmask);
29039e39c5baSBill Taylor 
29049e39c5baSBill Taylor 		/*
29059e39c5baSBill Taylor 		 * Sync the mailbox for the device to read.  We have to add
29069e39c5baSBill Taylor 		 * eight bytes here to account for "opt_param_mask" and
29079e39c5baSBill Taylor 		 * proper alignment.
29089e39c5baSBill Taylor 		 */
29099e39c5baSBill Taylor 		hermon_mbox_sync(mbox_info.mbi_in, 0, size + 8,
29109e39c5baSBill Taylor 		    DDI_DMA_SYNC_FORDEV);
29119e39c5baSBill Taylor 	}
29129e39c5baSBill Taylor 
29139e39c5baSBill Taylor 	/* Setup and post Hermon QP state transition command */
29149e39c5baSBill Taylor 	cmd.cp_inparm	= in_mapaddr;
29159e39c5baSBill Taylor 	cmd.cp_outparm	= out_mapaddr;
29169e39c5baSBill Taylor 	cmd.cp_inmod	= qpindx | flags;
29179e39c5baSBill Taylor 	cmd.cp_opcode	= (uint16_t)opcode;
29189e39c5baSBill Taylor 	cmd.cp_opmod	= (uint16_t)opmod;
29199e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
29209e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
29219e39c5baSBill Taylor 
29229e39c5baSBill Taylor 	/*
29239e39c5baSBill Taylor 	 * If we allocated a mailbox (either an "In" or an "Out") above,
29249e39c5baSBill Taylor 	 * then free it now before returning.
29259e39c5baSBill Taylor 	 */
29269e39c5baSBill Taylor 	if ((opcode != RTS2SQD_QP) && (opcode != TOERR_QP) &&
29279e39c5baSBill Taylor 	    (opcode != TORST_QP)) {
29289e39c5baSBill Taylor 		/* Free the mailbox */
29299e39c5baSBill Taylor 		hermon_mbox_free(state, &mbox_info);
29309e39c5baSBill Taylor 	}
29319e39c5baSBill Taylor 	return (status);
29329e39c5baSBill Taylor }
29339e39c5baSBill Taylor 
29349e39c5baSBill Taylor 
29359e39c5baSBill Taylor /*
29369e39c5baSBill Taylor  * hermon_cmn_query_cmd_post()
29379e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
29389e39c5baSBill Taylor  *
29399e39c5baSBill Taylor  *    This is the common function for posting all the various types of
29409e39c5baSBill Taylor  *    Hermon query commands.  All Hermon query commands require an "Out"
29419e39c5baSBill Taylor  *    mailbox to be allocated for the resulting queried data.
29429e39c5baSBill Taylor  *
29439e39c5baSBill Taylor  * Note: This common function should be used only with the following
29449e39c5baSBill Taylor  *    opcodes: QUERY_DEV_LIM, QUERY_FW, QUERY_DDR, QUERY_ADAPTER, QUERY_PORT
29459e39c5baSBill Taylor  *     QUERY_HCA, QUERY_MPT, QUERY_EQ, QUERY_CQ, and QUERY_QP.
294617a2b317SBill Taylor  *	With support of FCoIB, this also supports QUERY_FC.
29479e39c5baSBill Taylor  */
29489e39c5baSBill Taylor int
hermon_cmn_query_cmd_post(hermon_state_t * state,uint_t opcode,uint_t opmod,uint_t queryindx,void * query,uint_t size,uint_t sleepflag)29499e39c5baSBill Taylor hermon_cmn_query_cmd_post(hermon_state_t *state, uint_t opcode, uint_t opmod,
29509e39c5baSBill Taylor     uint_t queryindx, void *query, uint_t size, uint_t sleepflag)
29519e39c5baSBill Taylor {
29529e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
29539e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
29549e39c5baSBill Taylor 	uint64_t		data;
29559e39c5baSBill Taylor 	uint_t			offset;
29569e39c5baSBill Taylor 	int			status, i;
29579e39c5baSBill Taylor 
29589e39c5baSBill Taylor 	bzero(&cmd, sizeof (hermon_cmd_post_t));
29599e39c5baSBill Taylor 
29609e39c5baSBill Taylor 	/* Get an "Out" mailbox for the command */
29619e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
29629e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
29639e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
29649e39c5baSBill Taylor 		return (status);
29659e39c5baSBill Taylor 	}
29669e39c5baSBill Taylor 
29679e39c5baSBill Taylor 	/* Setup and post the Hermon query command */
29689e39c5baSBill Taylor 	cmd.cp_inparm	= 0;
29699e39c5baSBill Taylor 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
29709e39c5baSBill Taylor 	cmd.cp_inmod	= queryindx;
29719e39c5baSBill Taylor 	cmd.cp_opcode	= (uint16_t)opcode;
29729e39c5baSBill Taylor 	cmd.cp_opmod	= (uint16_t)opmod;
29739e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
29749e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
29759e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
29769e39c5baSBill Taylor 		goto cmn_query_fail;
29779e39c5baSBill Taylor 	}
29789e39c5baSBill Taylor 
29799e39c5baSBill Taylor 	/* Sync the mailbox to read the results */
29809e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
29819e39c5baSBill Taylor 
29829e39c5baSBill Taylor 	/*
29839e39c5baSBill Taylor 	 * QUERY_QP is handled somewhat differently than the other query
29849e39c5baSBill Taylor 	 * commands.  For QUERY_QP, the actual queried data is offset into
29859e39c5baSBill Taylor 	 * the mailbox (by one 64-bit word).
29869e39c5baSBill Taylor 	 */
29879e39c5baSBill Taylor 	offset = (opcode == QUERY_QP) ? 1 : 0;
29889e39c5baSBill Taylor 
29899e39c5baSBill Taylor 	/* Copy query command results into "query" */
29909e39c5baSBill Taylor 	for (i = 0; i < (size >> 3); i++) {
29919e39c5baSBill Taylor 		data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
29929e39c5baSBill Taylor 		    ((uint64_t *)mbox_info.mbi_out->mb_addr + i + offset));
29939e39c5baSBill Taylor 		((uint64_t *)query)[i] = data;
29949e39c5baSBill Taylor 	}
29959e39c5baSBill Taylor 
29969e39c5baSBill Taylor cmn_query_fail:
29979e39c5baSBill Taylor 	/* Free the mailbox */
29989e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
29999e39c5baSBill Taylor 	return (status);
30009e39c5baSBill Taylor }
30019e39c5baSBill Taylor 
30029e39c5baSBill Taylor 
30039e39c5baSBill Taylor /*
30049e39c5baSBill Taylor  * hermon_cmn_ownership_cmd_post()
30059e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
30069e39c5baSBill Taylor  *
30079e39c5baSBill Taylor  *    This is the common function for posting all the various types of
30089e39c5baSBill Taylor  *    Hermon HW/SW resource ownership commands.  Since some of the commands
30099e39c5baSBill Taylor  *    differ from the others in the direction of ownership change (i.e.
30109e39c5baSBill Taylor  *    from HW ownership to SW, or vice versa), they differ in the type of
30119e39c5baSBill Taylor  *    mailbox and specific handling that each requires.  This routine does
30129e39c5baSBill Taylor  *    certain checks based on opcode type to determine the direction of
30139e39c5baSBill Taylor  *    the transition and to correctly handle the request.
30149e39c5baSBill Taylor  *
30159e39c5baSBill Taylor  * Note: This common function should be used only with the following
30169e39c5baSBill Taylor  *    opcodes: HW2SW_MPT, HW2SW_EQ, HW2SW_CQ, SW2HW_MPT, SW2HW_EQ, and
30179e39c5baSBill Taylor  *    SW2HW_CQ
30189e39c5baSBill Taylor  */
30199e39c5baSBill Taylor int
hermon_cmn_ownership_cmd_post(hermon_state_t * state,uint_t opcode,void * hwrsrc,uint_t size,uint_t hwrsrcindx,uint_t sleepflag)30209e39c5baSBill Taylor hermon_cmn_ownership_cmd_post(hermon_state_t *state, uint_t opcode,
30219e39c5baSBill Taylor     void *hwrsrc, uint_t size, uint_t hwrsrcindx, uint_t sleepflag)
30229e39c5baSBill Taylor {
30239e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
30249e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
30259e39c5baSBill Taylor 	uint64_t		data, in_mapaddr, out_mapaddr;
30269e39c5baSBill Taylor 	uint_t			direction, opmod;
30279e39c5baSBill Taylor 	int			status, i;
30289e39c5baSBill Taylor 
30299e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
30309e39c5baSBill Taylor 
30319e39c5baSBill Taylor 	/*
30329e39c5baSBill Taylor 	 * Determine the direction of the ownership transfer based on the
30339e39c5baSBill Taylor 	 * provided opcode
30349e39c5baSBill Taylor 	 */
30359e39c5baSBill Taylor 	if ((opcode == HW2SW_MPT) || (opcode == HW2SW_EQ) ||
30369e39c5baSBill Taylor 	    (opcode == HW2SW_CQ) || (opcode == HW2SW_SRQ)) {
30379e39c5baSBill Taylor 		direction = HERMON_CMD_RSRC_HW2SW;
30389e39c5baSBill Taylor 
30399e39c5baSBill Taylor 	} else if ((opcode == SW2HW_MPT) || (opcode == SW2HW_EQ) ||
30409e39c5baSBill Taylor 	    (opcode == SW2HW_CQ) || (opcode == SW2HW_SRQ)) {
30419e39c5baSBill Taylor 		direction = HERMON_CMD_RSRC_SW2HW;
30429e39c5baSBill Taylor 
30439e39c5baSBill Taylor 	} else {
30449e39c5baSBill Taylor 		return (HERMON_CMD_INVALID_STATUS);
30459e39c5baSBill Taylor 	}
30469e39c5baSBill Taylor 
30479e39c5baSBill Taylor 	/*
30489e39c5baSBill Taylor 	 * If hwrsrc is NULL then we do not allocate a mailbox.  This is used
30499e39c5baSBill Taylor 	 * in the case of memory deregister where the out mailbox is not
30509e39c5baSBill Taylor 	 * needed.  In the case of re-register, we do use the hwrsrc.
30519e39c5baSBill Taylor 	 *
30529e39c5baSBill Taylor 	 * Otherwise, If ownership transfer is going from hardware to software,
30539e39c5baSBill Taylor 	 * then allocate an "Out" mailbox.  This will be filled in later as a
30549e39c5baSBill Taylor 	 * result of the Hermon command.
30559e39c5baSBill Taylor 	 *
30569e39c5baSBill Taylor 	 * And if the ownership transfer is going from software to hardware,
30579e39c5baSBill Taylor 	 * then we need an "In" mailbox, and we need to fill it in and sync it
30589e39c5baSBill Taylor 	 * (if necessary).  Then the mailbox can be passed to the Hermon
30599e39c5baSBill Taylor 	 * firmware.
30609e39c5baSBill Taylor 	 *
30619e39c5baSBill Taylor 	 * For the HW2SW (dereg) case, we only use an out mbox if hwrsrc is !=
30629e39c5baSBill Taylor 	 * NULL.  This implies a re-reg, and the out mbox must be used.  If
30639e39c5baSBill Taylor 	 * hwrsrc is == NULL, then we can save some time and resources by not
30649e39c5baSBill Taylor 	 * using an out mbox at all.  We must set opmod to HERMON_CMD_DO_OUTMBOX
30659e39c5baSBill Taylor 	 * and HERMON_CMD_NO_OUTMBOX appropriately in this case.
30669e39c5baSBill Taylor 	 *
30679e39c5baSBill Taylor 	 * For the SW2HW (reg) case, no out mbox is possible.  We set opmod to
30689e39c5baSBill Taylor 	 * 0 anyway, but this field is not used in this case.
30699e39c5baSBill Taylor 	 */
30709e39c5baSBill Taylor 	if (direction == HERMON_CMD_RSRC_HW2SW) {
30719e39c5baSBill Taylor 		if (hwrsrc != NULL) {
30729e39c5baSBill Taylor 			mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
30739e39c5baSBill Taylor 			status = hermon_mbox_alloc(state, &mbox_info,
30749e39c5baSBill Taylor 			    sleepflag);
30759e39c5baSBill Taylor 			if (status != HERMON_CMD_SUCCESS) {
30769e39c5baSBill Taylor 				return (status);
30779e39c5baSBill Taylor 			}
30789e39c5baSBill Taylor 			in_mapaddr  = 0;
30799e39c5baSBill Taylor 			out_mapaddr = mbox_info.mbi_out->mb_mapaddr;
30809e39c5baSBill Taylor 			opmod = HERMON_CMD_DO_OUTMBOX;
30819e39c5baSBill Taylor 		} else {
30829e39c5baSBill Taylor 			in_mapaddr = 0;
30839e39c5baSBill Taylor 			out_mapaddr = 0;
30849e39c5baSBill Taylor 			opmod = HERMON_CMD_NO_OUTMBOX;
30859e39c5baSBill Taylor 		}
30869e39c5baSBill Taylor 	} else {  /* HERMON_CMD_RSRC_SW2HW */
30879e39c5baSBill Taylor 		mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
30889e39c5baSBill Taylor 		status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
30899e39c5baSBill Taylor 		if (status != HERMON_CMD_SUCCESS) {
30909e39c5baSBill Taylor 			return (status);
30919e39c5baSBill Taylor 		}
30929e39c5baSBill Taylor 
30939e39c5baSBill Taylor 		/* Copy the SW2HW ownership command into mailbox */
30949e39c5baSBill Taylor 		for (i = 0; i < (size >> 3); i++) {
30959e39c5baSBill Taylor 			data = ((uint64_t *)hwrsrc)[i];
30969e39c5baSBill Taylor 			ddi_put64(mbox_info.mbi_in->mb_acchdl,
30979e39c5baSBill Taylor 			    ((uint64_t *)mbox_info.mbi_in->mb_addr + i),
30989e39c5baSBill Taylor 			    data);
30999e39c5baSBill Taylor 		}
31009e39c5baSBill Taylor 
31019e39c5baSBill Taylor 		/* Sync the mailbox for the device to read */
31029e39c5baSBill Taylor 		hermon_mbox_sync(mbox_info.mbi_in, 0, size,
31039e39c5baSBill Taylor 		    DDI_DMA_SYNC_FORDEV);
31049e39c5baSBill Taylor 
31059e39c5baSBill Taylor 		in_mapaddr  = mbox_info.mbi_in->mb_mapaddr;
31069e39c5baSBill Taylor 		out_mapaddr = 0;
31079e39c5baSBill Taylor 		opmod = 0;
31089e39c5baSBill Taylor 	}
31099e39c5baSBill Taylor 
31109e39c5baSBill Taylor 	/* Setup and post the Hermon ownership command */
31119e39c5baSBill Taylor 	cmd.cp_inparm	= in_mapaddr;
31129e39c5baSBill Taylor 	cmd.cp_outparm	= out_mapaddr;
31139e39c5baSBill Taylor 	cmd.cp_inmod	= hwrsrcindx;
31149e39c5baSBill Taylor 	cmd.cp_opcode	= (uint16_t)opcode;
31159e39c5baSBill Taylor 	cmd.cp_opmod	= (uint16_t)opmod;
31169e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
31179e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
31189e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
31199e39c5baSBill Taylor 		goto cmn_ownership_fail;
31209e39c5baSBill Taylor 	}
31219e39c5baSBill Taylor 
31229e39c5baSBill Taylor 	/*
31239e39c5baSBill Taylor 	 * As mentioned above, for HW2SW ownership transfers we need to
31249e39c5baSBill Taylor 	 * sync (if necessary) and copy out the resulting data from the
31259e39c5baSBill Taylor 	 * "Out" mailbox" (assuming the above command was successful).
31269e39c5baSBill Taylor 	 */
31279e39c5baSBill Taylor 	if (direction == HERMON_CMD_RSRC_HW2SW && hwrsrc != NULL) {
31289e39c5baSBill Taylor 
31299e39c5baSBill Taylor 		/* Sync the mailbox to read the results */
31309e39c5baSBill Taylor 		hermon_mbox_sync(mbox_info.mbi_out, 0, size,
31319e39c5baSBill Taylor 		    DDI_DMA_SYNC_FORCPU);
31329e39c5baSBill Taylor 
31339e39c5baSBill Taylor 		/* Copy HW2SW ownership command results into "hwrsrc" */
31349e39c5baSBill Taylor 		for (i = 0; i < (size >> 3); i++) {
31359e39c5baSBill Taylor 			data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
31369e39c5baSBill Taylor 			    ((uint64_t *)mbox_info.mbi_out->mb_addr + i));
31379e39c5baSBill Taylor 			((uint64_t *)hwrsrc)[i] = data;
31389e39c5baSBill Taylor 		}
31399e39c5baSBill Taylor 	}
31409e39c5baSBill Taylor 
31419e39c5baSBill Taylor cmn_ownership_fail:
31429e39c5baSBill Taylor 	if (hwrsrc != NULL) {
31439e39c5baSBill Taylor 		/* Free the mailbox */
31449e39c5baSBill Taylor 		hermon_mbox_free(state, &mbox_info);
31459e39c5baSBill Taylor 	}
31469e39c5baSBill Taylor 	return (status);
31479e39c5baSBill Taylor }
31489e39c5baSBill Taylor 
31499e39c5baSBill Taylor 
31509e39c5baSBill Taylor /*
31519e39c5baSBill Taylor  * hermon_conf_special_qp_cmd_post()
31529e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
31539e39c5baSBill Taylor  */
31549e39c5baSBill Taylor /*ARGSUSED*/
31559e39c5baSBill Taylor int
hermon_conf_special_qp_cmd_post(hermon_state_t * state,uint_t qpindx,uint_t qptype,uint_t sleepflag,uint_t opmod)31569e39c5baSBill Taylor hermon_conf_special_qp_cmd_post(hermon_state_t *state, uint_t qpindx,
31579e39c5baSBill Taylor     uint_t qptype, uint_t sleepflag, uint_t opmod)
31589e39c5baSBill Taylor {
31599e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
31609e39c5baSBill Taylor 	int			status;
31619e39c5baSBill Taylor 
31629e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
31639e39c5baSBill Taylor 
31649e39c5baSBill Taylor 	/* Setup and post Hermon "CONF_SPECIAL_QP" command */
31659e39c5baSBill Taylor 	cmd.cp_inparm	= 0;
31669e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
31679e39c5baSBill Taylor 	cmd.cp_inmod	= qpindx & 0x00FFFFF8;	/* mask off low 3 bits */
31689e39c5baSBill Taylor 	cmd.cp_opcode	= CONF_SPECIAL_QP;
31699e39c5baSBill Taylor 	cmd.cp_opmod	= (uint16_t)opmod;
31709e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
31719e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
31729e39c5baSBill Taylor 
31739e39c5baSBill Taylor 	return (status);
31749e39c5baSBill Taylor }
31759e39c5baSBill Taylor 
31769e39c5baSBill Taylor 
317717a2b317SBill Taylor /*
317817a2b317SBill Taylor  * hermon_get_heart_beat_rq_cmd_post()
317917a2b317SBill Taylor  *    Context: Can be called only from kernel or interrupt context
318017a2b317SBill Taylor  */
318117a2b317SBill Taylor int
hermon_get_heart_beat_rq_cmd_post(hermon_state_t * state,uint_t qpindx,uint64_t * outparm)318217a2b317SBill Taylor hermon_get_heart_beat_rq_cmd_post(hermon_state_t *state, uint_t qpindx,
318317a2b317SBill Taylor     uint64_t *outparm)
318417a2b317SBill Taylor {
318517a2b317SBill Taylor 	hermon_cmd_post_t	cmd;
318617a2b317SBill Taylor 	int			status;
318717a2b317SBill Taylor 
318817a2b317SBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
318917a2b317SBill Taylor 
319017a2b317SBill Taylor 	/* Setup and post the Hermon "HEART_BEAT_RQ" command */
319117a2b317SBill Taylor 	cmd.cp_inparm	= 0;
319217a2b317SBill Taylor 	cmd.cp_outparm	= 0;
319317a2b317SBill Taylor 	cmd.cp_inmod	= qpindx;
319417a2b317SBill Taylor 	cmd.cp_opcode	= HEART_BEAT_RQ;
319517a2b317SBill Taylor 	cmd.cp_opmod	= 0;
319617a2b317SBill Taylor 	cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN;
319717a2b317SBill Taylor 	status = hermon_cmd_post(state, &cmd);
319817a2b317SBill Taylor 
319917a2b317SBill Taylor 	/*
320017a2b317SBill Taylor 	 * Return immediate out param through argument pointer.
320117a2b317SBill Taylor 	 */
320217a2b317SBill Taylor 	*outparm = cmd.cp_outparm;
320317a2b317SBill Taylor 	return (status);
320417a2b317SBill Taylor }
320517a2b317SBill Taylor 
320617a2b317SBill Taylor 
32079e39c5baSBill Taylor /*
32089e39c5baSBill Taylor  * hermon_mgid_hash_cmd_post()
32099e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
32109e39c5baSBill Taylor  */
32119e39c5baSBill Taylor int
hermon_mgid_hash_cmd_post(hermon_state_t * state,uint64_t mgid_h,uint64_t mgid_l,uint64_t * mgid_hash,uint_t sleepflag)32129e39c5baSBill Taylor hermon_mgid_hash_cmd_post(hermon_state_t *state, uint64_t mgid_h,
32139e39c5baSBill Taylor     uint64_t mgid_l, uint64_t *mgid_hash, uint_t sleepflag)
32149e39c5baSBill Taylor {
32159e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
32169e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
32179e39c5baSBill Taylor 	int			status;
32189e39c5baSBill Taylor 
32199e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
32209e39c5baSBill Taylor 
32219e39c5baSBill Taylor 	/* Get an "In" mailbox for the command */
32229e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
32239e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
32249e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
32259e39c5baSBill Taylor 		return (status);
32269e39c5baSBill Taylor 	}
32279e39c5baSBill Taylor 
32289e39c5baSBill Taylor 	/* Copy the Hermon "MGID_HASH" command into mailbox */
32299e39c5baSBill Taylor 	ddi_put64(mbox_info.mbi_in->mb_acchdl,
32309e39c5baSBill Taylor 	    ((uint64_t *)mbox_info.mbi_in->mb_addr + 0), mgid_h);
32319e39c5baSBill Taylor 	ddi_put64(mbox_info.mbi_in->mb_acchdl,
32329e39c5baSBill Taylor 	    ((uint64_t *)mbox_info.mbi_in->mb_addr + 1), mgid_l);
32339e39c5baSBill Taylor 
32349e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
32359e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_in, 0, HERMON_CMD_MGIDHASH_SZ,
32369e39c5baSBill Taylor 	    DDI_DMA_SYNC_FORDEV);
32379e39c5baSBill Taylor 
32389e39c5baSBill Taylor 	/* Setup and post the Hermon "MGID_HASH" command */
32399e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
32409e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
32419e39c5baSBill Taylor 	cmd.cp_inmod	= 0;
32429e39c5baSBill Taylor 	cmd.cp_opcode	= MGID_HASH;
32439e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
32449e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
32459e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
32469e39c5baSBill Taylor 
32479e39c5baSBill Taylor 	/* MGID hash value is returned in command "outparam" */
32489e39c5baSBill Taylor 	*mgid_hash = cmd.cp_outparm;
32499e39c5baSBill Taylor 
32509e39c5baSBill Taylor 	/* Free the mailbox */
32519e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
32529e39c5baSBill Taylor 	return (status);
32539e39c5baSBill Taylor }
32549e39c5baSBill Taylor 
32559e39c5baSBill Taylor 
32569e39c5baSBill Taylor /*
32579e39c5baSBill Taylor  * hermon_read_mgm_cmd_post()
32589e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
32599e39c5baSBill Taylor  *
32609e39c5baSBill Taylor  * Note: It is assumed that the "mcg" parameter is actually a pointer to a
32619e39c5baSBill Taylor  *    "hermon_hw_mcg_t" struct and some number of "hermon_hw_mcg_qp_list_t"
32629e39c5baSBill Taylor  *    structs.  Combined size should be equal to result of HERMON_MCGMEM_SZ()
32639e39c5baSBill Taylor  *    macro.
32649e39c5baSBill Taylor  */
32659e39c5baSBill Taylor int
hermon_read_mgm_cmd_post(hermon_state_t * state,hermon_hw_mcg_t * mcg,uint_t mcgindx,uint_t sleepflag)32669e39c5baSBill Taylor hermon_read_mgm_cmd_post(hermon_state_t *state, hermon_hw_mcg_t *mcg,
32679e39c5baSBill Taylor     uint_t mcgindx, uint_t sleepflag)
32689e39c5baSBill Taylor {
32699e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
32709e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
32719e39c5baSBill Taylor 	uint64_t		data;
32729e39c5baSBill Taylor 	uint32_t		data32;
32739e39c5baSBill Taylor 	uint_t			size, hdrsz, qplistsz;
32749e39c5baSBill Taylor 	int			status, i;
32759e39c5baSBill Taylor 
32769e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
32779e39c5baSBill Taylor 
32789e39c5baSBill Taylor 	/* Get an "Out" mailbox for the results */
32799e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
32809e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
32819e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
32829e39c5baSBill Taylor 		return (status);
32839e39c5baSBill Taylor 	}
32849e39c5baSBill Taylor 
32859e39c5baSBill Taylor 	/* Setup and post Hermon "READ_MGM" command */
32869e39c5baSBill Taylor 	cmd.cp_inparm	= 0;
32879e39c5baSBill Taylor 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
32889e39c5baSBill Taylor 	cmd.cp_inmod	= mcgindx;
32899e39c5baSBill Taylor 	cmd.cp_opcode	= READ_MGM;
32909e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
32919e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
32929e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
32939e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
32949e39c5baSBill Taylor 		goto read_mgm_fail;
32959e39c5baSBill Taylor 	}
32969e39c5baSBill Taylor 
32979e39c5baSBill Taylor 	/* Sync the mailbox to read the results */
32989e39c5baSBill Taylor 	size = HERMON_MCGMEM_SZ(state);
32999e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
33009e39c5baSBill Taylor 
33019e39c5baSBill Taylor 	/* Copy the READ_MGM command results into "mcg" */
33029e39c5baSBill Taylor 	hdrsz = sizeof (hermon_hw_mcg_t);
33039e39c5baSBill Taylor 	for (i = 0; i < (hdrsz >> 3); i++) {
33049e39c5baSBill Taylor 		data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
33059e39c5baSBill Taylor 		    ((uint64_t *)mbox_info.mbi_out->mb_addr + i));
33069e39c5baSBill Taylor 		((uint64_t *)mcg)[i] = data;
33079e39c5baSBill Taylor 	}
33089e39c5baSBill Taylor 	qplistsz = size - hdrsz;
33099e39c5baSBill Taylor 	for (i = 0; i < (qplistsz >> 2); i++) {
33109e39c5baSBill Taylor 		data32 = ddi_get32(mbox_info.mbi_out->mb_acchdl,
33119e39c5baSBill Taylor 		    ((uint32_t *)mbox_info.mbi_out->mb_addr + i + 8));
33129e39c5baSBill Taylor 		((uint32_t *)mcg)[i + 8] = data32;
33139e39c5baSBill Taylor 	}
33149e39c5baSBill Taylor 
33159e39c5baSBill Taylor read_mgm_fail:
33169e39c5baSBill Taylor 	/* Free the mailbox */
33179e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
33189e39c5baSBill Taylor 	return (status);
33199e39c5baSBill Taylor }
33209e39c5baSBill Taylor 
33219e39c5baSBill Taylor 
33229e39c5baSBill Taylor /*
33239e39c5baSBill Taylor  * hermon_write_mgm_cmd_post()
33249e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
33259e39c5baSBill Taylor  *
33269e39c5baSBill Taylor  * Note: It is assumed that the "mcg" parameter is actually a pointer to a
33279e39c5baSBill Taylor  *    "hermon_hw_mcg_t" struct and some number of "hermon_hw_mcg_qp_list_t"
33289e39c5baSBill Taylor  *    structs.  Combined size should be equal to result of HERMON_MCGMEM_SZ()
33299e39c5baSBill Taylor  *    macro.
33309e39c5baSBill Taylor  */
33319e39c5baSBill Taylor int
hermon_write_mgm_cmd_post(hermon_state_t * state,hermon_hw_mcg_t * mcg,uint_t mcgindx,uint_t sleepflag)33329e39c5baSBill Taylor hermon_write_mgm_cmd_post(hermon_state_t *state, hermon_hw_mcg_t *mcg,
33339e39c5baSBill Taylor     uint_t mcgindx, uint_t sleepflag)
33349e39c5baSBill Taylor {
33359e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
33369e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
33379e39c5baSBill Taylor 	uint64_t		data;
33389e39c5baSBill Taylor 	uint_t			size, hdrsz, qplistsz;
33399e39c5baSBill Taylor 	int			status, i;
33409e39c5baSBill Taylor 
33419e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
33429e39c5baSBill Taylor 
33439e39c5baSBill Taylor 	/* Get an "In" mailbox for the command */
33449e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
33459e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
33469e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
33479e39c5baSBill Taylor 		return (status);
33489e39c5baSBill Taylor 	}
33499e39c5baSBill Taylor 
33509e39c5baSBill Taylor 	/* Copy the Hermon "WRITE_MGM" command into mailbox */
33519e39c5baSBill Taylor 	size  = HERMON_MCGMEM_SZ(state);
33529e39c5baSBill Taylor 	hdrsz = sizeof (hermon_hw_mcg_t);
33539e39c5baSBill Taylor 	for (i = 0; i < (hdrsz >> 3); i++) {
33549e39c5baSBill Taylor 		data = ((uint64_t *)mcg)[i];
33559e39c5baSBill Taylor 		ddi_put64(mbox_info.mbi_in->mb_acchdl,
33569e39c5baSBill Taylor 		    ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
33579e39c5baSBill Taylor 	}
33589e39c5baSBill Taylor 	qplistsz = size - hdrsz;
33599e39c5baSBill Taylor 	for (i = 0; i < (qplistsz >> 2); i++) {
33609e39c5baSBill Taylor 		data = ((uint32_t *)mcg)[i + 8];
33619e39c5baSBill Taylor 		ddi_put32(mbox_info.mbi_in->mb_acchdl,
33629e39c5baSBill Taylor 		    ((uint32_t *)mbox_info.mbi_in->mb_addr + i + 8), data);
33639e39c5baSBill Taylor 	}
33649e39c5baSBill Taylor 
33659e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
33669e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
33679e39c5baSBill Taylor 
33689e39c5baSBill Taylor 	/* Setup and post Hermon "WRITE_MGM" command */
33699e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
33709e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
33719e39c5baSBill Taylor 	cmd.cp_inmod	= mcgindx;
33729e39c5baSBill Taylor 	cmd.cp_opcode	= WRITE_MGM;
33739e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
33749e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
33759e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
33769e39c5baSBill Taylor 
33779e39c5baSBill Taylor 	/* Free the mailbox */
33789e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
33799e39c5baSBill Taylor 	return (status);
33809e39c5baSBill Taylor }
33819e39c5baSBill Taylor 
33829e39c5baSBill Taylor /*
33839e39c5baSBill Taylor  * hermon_resize_srq_cmd_post()
33849e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
33859e39c5baSBill Taylor  */
33869e39c5baSBill Taylor 
hermon_resize_srq_cmd_post(hermon_state_t * state,hermon_hw_srqc_t * srq,uint_t srqnum,uint_t sleepflag)33879e39c5baSBill Taylor int hermon_resize_srq_cmd_post(hermon_state_t *state, hermon_hw_srqc_t *srq,
33889e39c5baSBill Taylor     uint_t srqnum, uint_t sleepflag)
33899e39c5baSBill Taylor {
33909e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
33919e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
33929e39c5baSBill Taylor 	uint64_t		data;
33939e39c5baSBill Taylor 	uint_t			size;
33949e39c5baSBill Taylor 	int			status, i;
33959e39c5baSBill Taylor 
33969e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
33979e39c5baSBill Taylor 
33989e39c5baSBill Taylor 	/* Get an "In" mailbox for the command */
33999e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
34009e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
34019e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
34029e39c5baSBill Taylor 		return (status);
34039e39c5baSBill Taylor 	}
34049e39c5baSBill Taylor 
34059e39c5baSBill Taylor 	/* Copy the Hermon "RESIZE_SRQ" command into mailbox */
34069e39c5baSBill Taylor 	size = sizeof (hermon_hw_srqc_t);
34079e39c5baSBill Taylor 	for (i = 0; i < (size >> 3); i++) {
34089e39c5baSBill Taylor 		data = ((uint64_t *)(void *)srq)[i];
34099e39c5baSBill Taylor 		ddi_put64(mbox_info.mbi_in->mb_acchdl,
34109e39c5baSBill Taylor 		    ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
34119e39c5baSBill Taylor 	}
34129e39c5baSBill Taylor 
34139e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
34149e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
34159e39c5baSBill Taylor 
34169e39c5baSBill Taylor 	/* Setup and post Hermon "RESIZE_SRQ" command */
34179e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
34189e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
34199e39c5baSBill Taylor 	cmd.cp_inmod	= srqnum;
34209e39c5baSBill Taylor 	cmd.cp_opcode	= RESIZE_SRQ;
34219e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
34229e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
34239e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
34249e39c5baSBill Taylor 
34259e39c5baSBill Taylor 	/* Free the mailbox */
34269e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
34279e39c5baSBill Taylor 	return (status);
34289e39c5baSBill Taylor }
34299e39c5baSBill Taylor /*
34309e39c5baSBill Taylor  * hermon_modify_mpt_cmd_post()
34319e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
34329e39c5baSBill Taylor  */
34339e39c5baSBill Taylor int
hermon_modify_mpt_cmd_post(hermon_state_t * state,hermon_hw_dmpt_t * mpt,uint_t mptindx,uint_t flags,uint_t sleepflag)34349e39c5baSBill Taylor hermon_modify_mpt_cmd_post(hermon_state_t *state, hermon_hw_dmpt_t *mpt,
34359e39c5baSBill Taylor     uint_t mptindx, uint_t flags, uint_t sleepflag)
34369e39c5baSBill Taylor {
34379e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
34389e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
34399e39c5baSBill Taylor 	uint64_t		data;
34409e39c5baSBill Taylor 	uint_t			size;
34419e39c5baSBill Taylor 	int			status, i;
34429e39c5baSBill Taylor 
34439e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
34449e39c5baSBill Taylor 
34459e39c5baSBill Taylor 	/* Get an "In" mailbox for the command */
34469e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
34479e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
34489e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
34499e39c5baSBill Taylor 		return (status);
34509e39c5baSBill Taylor 	}
34519e39c5baSBill Taylor 
34529e39c5baSBill Taylor 	/* Copy the Hermon "MODIFY_MPT" command into mailbox */
34539e39c5baSBill Taylor 	size = sizeof (hermon_hw_dmpt_t);
34549e39c5baSBill Taylor 	for (i = 0; i < (size >> 3); i++) {
34559e39c5baSBill Taylor 		data = ((uint64_t *)mpt)[i];
34569e39c5baSBill Taylor 		ddi_put64(mbox_info.mbi_in->mb_acchdl,
34579e39c5baSBill Taylor 		    ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
34589e39c5baSBill Taylor 	}
34599e39c5baSBill Taylor 
34609e39c5baSBill Taylor 	/* Sync the mailbox for the device to read */
34619e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
34629e39c5baSBill Taylor 
34639e39c5baSBill Taylor 	/* Setup and post Hermon "MODIFY_MPT" command */
34649e39c5baSBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
34659e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
34669e39c5baSBill Taylor 	cmd.cp_inmod	= mptindx;
34679e39c5baSBill Taylor 	cmd.cp_opcode	= MODIFY_MPT;
34689e39c5baSBill Taylor 	cmd.cp_opmod	= (uint16_t)flags;
34699e39c5baSBill Taylor 	cmd.cp_flags	= sleepflag;
34709e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
34719e39c5baSBill Taylor 
34729e39c5baSBill Taylor 	/* Free the mailbox */
34739e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
34749e39c5baSBill Taylor 	return (status);
34759e39c5baSBill Taylor }
34769e39c5baSBill Taylor 
34779e39c5baSBill Taylor 
347817a2b317SBill Taylor /*
347917a2b317SBill Taylor  * hermon_config_fc_cmd_post()
348017a2b317SBill Taylor  *    	Context: Can be called from user or kernel context.
348117a2b317SBill Taylor  *	This can do either a basic config passing in
348217a2b317SBill Taylor  * 	*hermon_hw_config_fc_basic_s, or config the N_Port table.
348317a2b317SBill Taylor  *	passing in pointer to an array of 32-bit id's
348417a2b317SBill Taylor  *	Note that either one needs to be cast to void *
348517a2b317SBill Taylor  */
348617a2b317SBill Taylor int
hermon_config_fc_cmd_post(hermon_state_t * state,void * cfginfo,int enable,int selector,int n_ports,int portnum,uint_t sleepflag)348717a2b317SBill Taylor hermon_config_fc_cmd_post(hermon_state_t *state, void *cfginfo, int enable,
348817a2b317SBill Taylor     int selector, int n_ports, int portnum, uint_t sleepflag)
348917a2b317SBill Taylor {
349017a2b317SBill Taylor 	hermon_mbox_info_t	mbox_info;
349117a2b317SBill Taylor 	hermon_cmd_post_t	cmd;
349217a2b317SBill Taylor 	uint64_t		data;
349317a2b317SBill Taylor 	uint32_t		portid;
349417a2b317SBill Taylor 	uint_t			size;
349517a2b317SBill Taylor 	int			status, i;
349617a2b317SBill Taylor 
349717a2b317SBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
349817a2b317SBill Taylor 
349917a2b317SBill Taylor 	/* Get an "In" mailbox for the command */
350017a2b317SBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
350117a2b317SBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
350217a2b317SBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
350317a2b317SBill Taylor 		return (status);
350417a2b317SBill Taylor 	}
350517a2b317SBill Taylor 
350617a2b317SBill Taylor 	/* Copy the appropriate info into mailbox */
350717a2b317SBill Taylor 	if (selector == HERMON_HW_FC_CONF_BASIC) {	/* basic info */
350817a2b317SBill Taylor 		size = sizeof (hermon_hw_config_fc_basic_t);
350917a2b317SBill Taylor 		for (i = 0; i < (size >> 3); i++) {
351017a2b317SBill Taylor 			data = ((uint64_t *)cfginfo)[i];
351117a2b317SBill Taylor 			ddi_put64(mbox_info.mbi_in->mb_acchdl,
351217a2b317SBill Taylor 			    ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
351317a2b317SBill Taylor 		}
351417a2b317SBill Taylor 	} else {					/* NPort config */
351517a2b317SBill Taylor 		ASSERT(selector == HERMON_HW_FC_CONF_NPORT);
351617a2b317SBill Taylor 		size = n_ports * sizeof (uint32_t);
351717a2b317SBill Taylor 		/*
351817a2b317SBill Taylor 		 * n_ports must == number queried from card
351917a2b317SBill Taylor 		 *
352017a2b317SBill Taylor 		 * passed in is an array but for little endian needs to
352117a2b317SBill Taylor 		 * be rearranged in the mbox
352217a2b317SBill Taylor 		 */
352317a2b317SBill Taylor 		for (i = 0; i < (size >> 3); i++) {
352417a2b317SBill Taylor 			portid = ((uint32_t *)cfginfo)[i * 2];
352517a2b317SBill Taylor 			data = (uint64_t)portid << 32;
352617a2b317SBill Taylor 			if (i * 2 < n_ports) {
352717a2b317SBill Taylor 				portid = ((uint32_t *)cfginfo)[i * 2 + 1];
352817a2b317SBill Taylor 				data |= portid;
352917a2b317SBill Taylor 			}
353017a2b317SBill Taylor 			ddi_put64(mbox_info.mbi_in->mb_acchdl,
353117a2b317SBill Taylor 			    ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
353217a2b317SBill Taylor 		}
353317a2b317SBill Taylor 	}
353417a2b317SBill Taylor 
353517a2b317SBill Taylor 	/* Sync the mailbox for the device to read */
353617a2b317SBill Taylor 	hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
353717a2b317SBill Taylor 
353817a2b317SBill Taylor 	/* Setup and post Hermon "CONFIG_FC" command */
353917a2b317SBill Taylor 	cmd.cp_inparm	= mbox_info.mbi_in->mb_mapaddr;
354017a2b317SBill Taylor 	cmd.cp_outparm	= 0;
354117a2b317SBill Taylor 	cmd.cp_inmod	= (uint32_t)(selector | portnum);
354217a2b317SBill Taylor 	cmd.cp_opcode	= CONFIG_FC;
354317a2b317SBill Taylor 	cmd.cp_opmod	= (uint16_t)enable;
354417a2b317SBill Taylor 	cmd.cp_flags	= sleepflag;
354517a2b317SBill Taylor 	status = hermon_cmd_post(state, &cmd);
354617a2b317SBill Taylor 
354717a2b317SBill Taylor 	/* Free the mailbox */
354817a2b317SBill Taylor 	hermon_mbox_free(state, &mbox_info);
354917a2b317SBill Taylor 	return (status);
355017a2b317SBill Taylor }
355117a2b317SBill Taylor 
355217a2b317SBill Taylor /*
355317a2b317SBill Taylor  * hermon_sense_port_post() - used to send protocol running on a port
355417a2b317SBill Taylor  *	Context: Can be called from interrupt or base context
355517a2b317SBill Taylor  */
355617a2b317SBill Taylor 
355717a2b317SBill Taylor int
hermon_sense_port_post(hermon_state_t * state,uint_t portnum,uint32_t * protocol)355817a2b317SBill Taylor hermon_sense_port_post(hermon_state_t *state, uint_t portnum,
355917a2b317SBill Taylor     uint32_t *protocol)
356017a2b317SBill Taylor {
356117a2b317SBill Taylor 	hermon_cmd_post_t	cmd;
356217a2b317SBill Taylor 	int			status;
356317a2b317SBill Taylor 
356417a2b317SBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
356517a2b317SBill Taylor 
356617a2b317SBill Taylor 	/* Setup and post Hermon "CMD_NOP" command */
356717a2b317SBill Taylor 	cmd.cp_inparm	= 0;
356817a2b317SBill Taylor 	cmd.cp_outparm	= 0;
356917a2b317SBill Taylor 	cmd.cp_inmod	= (uint32_t)portnum;
357017a2b317SBill Taylor 	cmd.cp_opcode	= SENSE_PORT;
357117a2b317SBill Taylor 	cmd.cp_opmod	= 0;
357217a2b317SBill Taylor 	cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN;
357317a2b317SBill Taylor 	status = hermon_cmd_post(state, &cmd);
357417a2b317SBill Taylor 	if (status == HERMON_CMD_SUCCESS) *protocol = (uint32_t)cmd.cp_outparm;
357517a2b317SBill Taylor 	return (status);
357617a2b317SBill Taylor }
357717a2b317SBill Taylor 
357817a2b317SBill Taylor 
357917a2b317SBill Taylor /*
358017a2b317SBill Taylor  * CONFIG_INT_MOD - used to configure INTERRUPT moderation
358117a2b317SBill Taylor  *	if command fails, *health is invalid/undefined
358217a2b317SBill Taylor  */
358317a2b317SBill Taylor int
hermon_config_int_mod(hermon_state_t * state,uint_t min_delay,uint_t vector)358417a2b317SBill Taylor hermon_config_int_mod(hermon_state_t *state, uint_t min_delay, uint_t vector)
358517a2b317SBill Taylor {
358617a2b317SBill Taylor 	hermon_cmd_post_t	cmd;
358717a2b317SBill Taylor 	int			status;
358817a2b317SBill Taylor 	uint64_t		inparm = 0;
358917a2b317SBill Taylor 
359017a2b317SBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
359117a2b317SBill Taylor 
359217a2b317SBill Taylor 	/* Setup and post Hermon "CONFIG_INT_MOD" command */
359317a2b317SBill Taylor 	inparm = (((uint64_t)min_delay & 0xFFFF) << 48) ||
359417a2b317SBill Taylor 	    (((uint64_t)vector & 0xFFFF) << 32);
359517a2b317SBill Taylor 
359617a2b317SBill Taylor 	cmd.cp_inparm	= inparm;
359717a2b317SBill Taylor 	cmd.cp_outparm	= 0;
359817a2b317SBill Taylor 	cmd.cp_inmod	= 0;
359917a2b317SBill Taylor 	cmd.cp_opcode	= CONFIG_INT_MOD;
360017a2b317SBill Taylor 	cmd.cp_opmod	= 0;
360117a2b317SBill Taylor 	cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN;
360217a2b317SBill Taylor 	status = hermon_cmd_post(state, &cmd);
360317a2b317SBill Taylor 	return (status);
360417a2b317SBill Taylor }
360517a2b317SBill Taylor 
360617a2b317SBill Taylor 
36079e39c5baSBill Taylor int
hermon_nop_post(hermon_state_t * state,uint_t interval,uint_t sleep)36089e39c5baSBill Taylor hermon_nop_post(hermon_state_t *state, uint_t interval, uint_t sleep)
36099e39c5baSBill Taylor {
36109e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
36119e39c5baSBill Taylor 	int			status;
36129e39c5baSBill Taylor 
36139e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
36149e39c5baSBill Taylor 
36159e39c5baSBill Taylor 	/* Setup and post Hermon "CMD_NOP" command */
36169e39c5baSBill Taylor 	cmd.cp_inparm	= 0;
36179e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
36189e39c5baSBill Taylor 	cmd.cp_inmod	= interval;
36199e39c5baSBill Taylor 	cmd.cp_opcode	= CMD_NOP;
36209e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
36219e39c5baSBill Taylor 	cmd.cp_flags	= HERMON_CMD_SLEEP_NOSPIN;
36229e39c5baSBill Taylor 	if (sleep) cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN;
36239e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
36249e39c5baSBill Taylor 	return (status);
36259e39c5baSBill Taylor }
36269e39c5baSBill Taylor 
362717a2b317SBill Taylor int
hermon_hw_health_check(hermon_state_t * state,int * health)362817a2b317SBill Taylor hermon_hw_health_check(hermon_state_t *state, int *health)
362917a2b317SBill Taylor {
363017a2b317SBill Taylor 	hermon_cmd_post_t	cmd;
363117a2b317SBill Taylor 	int			status;
363217a2b317SBill Taylor 
363317a2b317SBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
363417a2b317SBill Taylor 
363517a2b317SBill Taylor 	/* Setup and post Hermon "CMD_NOP" command */
363617a2b317SBill Taylor 	cmd.cp_inparm	= 0;
363717a2b317SBill Taylor 	cmd.cp_outparm	= 0;
363817a2b317SBill Taylor 	cmd.cp_inmod	= 0;
363917a2b317SBill Taylor 	cmd.cp_opcode	= HW_HEALTH_CHECK;
364017a2b317SBill Taylor 	cmd.cp_opmod	= 0;
364117a2b317SBill Taylor 	cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN;
364217a2b317SBill Taylor 	status = hermon_cmd_post(state, &cmd);
364317a2b317SBill Taylor 	*health = (int)cmd.cp_outparm;
364417a2b317SBill Taylor 	return (status);
364517a2b317SBill Taylor }
364617a2b317SBill Taylor 
36479e39c5baSBill Taylor int
hermon_setdebug_post(hermon_state_t * state)36489e39c5baSBill Taylor hermon_setdebug_post(hermon_state_t *state)
36499e39c5baSBill Taylor {
36509e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
36519e39c5baSBill Taylor 	int			status;
36529e39c5baSBill Taylor 
36539e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
36549e39c5baSBill Taylor 
36559e39c5baSBill Taylor 	/* Setup and post Hermon "CMD_NOP" command */
36569e39c5baSBill Taylor 	cmd.cp_inparm	= 0xFFFFFFFFFFFFFFFF;
36579e39c5baSBill Taylor 	cmd.cp_outparm	= 0;
36589e39c5baSBill Taylor 	cmd.cp_inmod	= 0;
36599e39c5baSBill Taylor 	cmd.cp_opcode	= SET_DEBUG_MSG;
36609e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
36619e39c5baSBill Taylor 	cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN;
36629e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
36639e39c5baSBill Taylor 	return (status);
36649e39c5baSBill Taylor }
36659e39c5baSBill Taylor 
36669e39c5baSBill Taylor 
36679e39c5baSBill Taylor int
hermon_read_mtt_cmd_post(hermon_state_t * state,uint64_t mtt_addr,hermon_hw_mtt_t * mtt)36689e39c5baSBill Taylor hermon_read_mtt_cmd_post(hermon_state_t *state, uint64_t mtt_addr,
36699e39c5baSBill Taylor 	hermon_hw_mtt_t *mtt)
36709e39c5baSBill Taylor {
36719e39c5baSBill Taylor 
36729e39c5baSBill Taylor 	hermon_cmd_post_t	cmd;
36739e39c5baSBill Taylor 	hermon_mbox_info_t	mbox_info;
36749e39c5baSBill Taylor 	int			i, status;
36759e39c5baSBill Taylor 	uint_t			size;
36769e39c5baSBill Taylor 	uint64_t		data;
36779e39c5baSBill Taylor 
36789e39c5baSBill Taylor 	bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
36799e39c5baSBill Taylor 
36809e39c5baSBill Taylor 	/* Get an "Out" mailbox for the command */
36819e39c5baSBill Taylor 	mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
36829e39c5baSBill Taylor 	status = hermon_mbox_alloc(state, &mbox_info, HERMON_CMD_SLEEP_NOSPIN);
36839e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
36849e39c5baSBill Taylor 		return (status);
36859e39c5baSBill Taylor 	}
36869e39c5baSBill Taylor 
36879e39c5baSBill Taylor 	/* Setup and post the "READ_MTT" command */
36889e39c5baSBill Taylor 	cmd.cp_inparm	= mtt_addr;
36899e39c5baSBill Taylor 	cmd.cp_outparm	= mbox_info.mbi_out->mb_mapaddr;
36909e39c5baSBill Taylor 	cmd.cp_inmod	= 1;
36919e39c5baSBill Taylor 	cmd.cp_opcode	= READ_MTT;
36929e39c5baSBill Taylor 	cmd.cp_opmod	= 0;
36939e39c5baSBill Taylor 	cmd.cp_flags	= HERMON_CMD_NOSLEEP_SPIN;
36949e39c5baSBill Taylor 	status = hermon_cmd_post(state, &cmd);
36959e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
36969e39c5baSBill Taylor 		return (status);
36979e39c5baSBill Taylor 	}
36989e39c5baSBill Taylor 
36999e39c5baSBill Taylor 	/* Sync the mailbox to read the results */
37009e39c5baSBill Taylor 	size = sizeof (hermon_hw_mtt_t);
37019e39c5baSBill Taylor 	hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
37029e39c5baSBill Taylor 
37039e39c5baSBill Taylor 	/* Copy mtt read out */
37049e39c5baSBill Taylor 	for (i = 0; i < (size >> 3); i++) {
37059e39c5baSBill Taylor 		data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
37069e39c5baSBill Taylor 		    ((uint64_t *)mbox_info.mbi_out->mb_addr + i));
37079e39c5baSBill Taylor 		((uint64_t *)(void *)mtt)[i] = data;
37089e39c5baSBill Taylor 	}
37099e39c5baSBill Taylor 
37109e39c5baSBill Taylor 	/* Free the mailbox */
37119e39c5baSBill Taylor 	hermon_mbox_free(state, &mbox_info);
37129e39c5baSBill Taylor 	return (status);
37139e39c5baSBill Taylor }
3714