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.
24*48bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
259e39c5baSBill Taylor  */
269e39c5baSBill Taylor 
279e39c5baSBill Taylor /*
289e39c5baSBill Taylor  * hermon_qpmod.c
299e39c5baSBill Taylor  *    Hermon Queue Pair Modify Routines
309e39c5baSBill Taylor  *
319e39c5baSBill Taylor  *    This contains all the routines necessary to implement the
329e39c5baSBill Taylor  *    ModifyQP() verb.  This includes all the code for legal
339e39c5baSBill Taylor  *    transitions to and from Reset, Init, RTR, RTS, SQD, SQErr,
349e39c5baSBill Taylor  *    and Error.
359e39c5baSBill Taylor  */
369e39c5baSBill Taylor 
37de710d24SJosef 'Jeff' Sipek #include <sys/sysmacros.h>
389e39c5baSBill Taylor #include <sys/types.h>
399e39c5baSBill Taylor #include <sys/conf.h>
409e39c5baSBill Taylor #include <sys/ddi.h>
419e39c5baSBill Taylor #include <sys/sunddi.h>
429e39c5baSBill Taylor #include <sys/modctl.h>
439e39c5baSBill Taylor #include <sys/bitmap.h>
449e39c5baSBill Taylor 
459e39c5baSBill Taylor #include <sys/ib/adapters/hermon/hermon.h>
469e39c5baSBill Taylor #include <sys/ib/ib_pkt_hdrs.h>
479e39c5baSBill Taylor 
489e39c5baSBill Taylor static int hermon_qp_reset2init(hermon_state_t *state, hermon_qphdl_t qp,
499e39c5baSBill Taylor     ibt_qp_info_t *info_p);
509e39c5baSBill Taylor static int hermon_qp_init2init(hermon_state_t *state, hermon_qphdl_t qp,
519e39c5baSBill Taylor     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
529e39c5baSBill Taylor static int hermon_qp_init2rtr(hermon_state_t *state, hermon_qphdl_t qp,
539e39c5baSBill Taylor     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
549e39c5baSBill Taylor static int hermon_qp_rtr2rts(hermon_state_t *state, hermon_qphdl_t qp,
559e39c5baSBill Taylor     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
569e39c5baSBill Taylor static int hermon_qp_rts2rts(hermon_state_t *state, hermon_qphdl_t qp,
579e39c5baSBill Taylor     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
589e39c5baSBill Taylor #ifdef HERMON_NOTNOW
599e39c5baSBill Taylor static int hermon_qp_rts2sqd(hermon_state_t *state, hermon_qphdl_t qp,
609e39c5baSBill Taylor     ibt_cep_modify_flags_t flags);
619e39c5baSBill Taylor #endif
629e39c5baSBill Taylor static int hermon_qp_sqd2rts(hermon_state_t *state, hermon_qphdl_t qp,
639e39c5baSBill Taylor     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
649e39c5baSBill Taylor static int hermon_qp_sqd2sqd(hermon_state_t *state, hermon_qphdl_t qp,
659e39c5baSBill Taylor     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
669e39c5baSBill Taylor static int hermon_qp_sqerr2rts(hermon_state_t *state, hermon_qphdl_t qp,
679e39c5baSBill Taylor     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
689e39c5baSBill Taylor static int hermon_qp_to_error(hermon_state_t *state, hermon_qphdl_t qp);
699e39c5baSBill Taylor static int hermon_qp_reset2err(hermon_state_t *state, hermon_qphdl_t qp);
709e39c5baSBill Taylor 
719e39c5baSBill Taylor static uint_t hermon_check_rdma_enable_flags(ibt_cep_modify_flags_t flags,
729e39c5baSBill Taylor     ibt_qp_info_t *info_p, hermon_hw_qpc_t *qpc);
739e39c5baSBill Taylor static int hermon_qp_validate_resp_rsrc(hermon_state_t *state,
749e39c5baSBill Taylor     ibt_qp_rc_attr_t *rc, uint_t *rra_max);
759e39c5baSBill Taylor static int hermon_qp_validate_init_depth(hermon_state_t *state,
769e39c5baSBill Taylor     ibt_qp_rc_attr_t *rc, uint_t *sra_max);
779e39c5baSBill Taylor static int hermon_qp_validate_mtu(hermon_state_t *state, uint_t mtu);
789e39c5baSBill Taylor 
799e39c5baSBill Taylor /*
809e39c5baSBill Taylor  * hermon_qp_modify()
819e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
829e39c5baSBill Taylor  */
839e39c5baSBill Taylor /* ARGSUSED */
849e39c5baSBill Taylor int
hermon_qp_modify(hermon_state_t * state,hermon_qphdl_t qp,ibt_cep_modify_flags_t flags,ibt_qp_info_t * info_p,ibt_queue_sizes_t * actual_sz)859e39c5baSBill Taylor hermon_qp_modify(hermon_state_t *state, hermon_qphdl_t qp,
869e39c5baSBill Taylor     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p,
879e39c5baSBill Taylor     ibt_queue_sizes_t *actual_sz)
889e39c5baSBill Taylor {
899e39c5baSBill Taylor 	ibt_cep_state_t		cur_state, mod_state;
909e39c5baSBill Taylor 	ibt_cep_modify_flags_t	okflags;
919e39c5baSBill Taylor 	int			status;
929e39c5baSBill Taylor 
939e39c5baSBill Taylor 	/*
949e39c5baSBill Taylor 	 * TODO add support for SUSPEND and RESUME
959e39c5baSBill Taylor 	 */
969e39c5baSBill Taylor 
979e39c5baSBill Taylor 	/*
989e39c5baSBill Taylor 	 * Lock the QP so that we can modify it atomically.  After grabbing
999e39c5baSBill Taylor 	 * the lock, get the current QP state.  We will use this current QP
1009e39c5baSBill Taylor 	 * state to determine the legal transitions (and the checks that need
1019e39c5baSBill Taylor 	 * to be performed.)
1029e39c5baSBill Taylor 	 * Below is a case for every possible QP state.  In each case, we
1039e39c5baSBill Taylor 	 * check that no flags are set which are not valid for the possible
1049e39c5baSBill Taylor 	 * transitions from that state.  If these tests pass and the
1059e39c5baSBill Taylor 	 * state transition we are attempting is legal, then we call one
1069e39c5baSBill Taylor 	 * of the helper functions.  Each of these functions does some
1079e39c5baSBill Taylor 	 * additional setup before posting the firmware command for the
1089e39c5baSBill Taylor 	 * appropriate state transition.
1099e39c5baSBill Taylor 	 */
1109e39c5baSBill Taylor 	mutex_enter(&qp->qp_lock);
1119e39c5baSBill Taylor 
1129e39c5baSBill Taylor 	/*
1139e39c5baSBill Taylor 	 * Verify that the transport type matches between the serv_type and the
1149e39c5baSBill Taylor 	 * qp_trans.  A caller to IBT must specify the qp_trans field as
1159e39c5baSBill Taylor 	 * IBT_UD_SRV, IBT_RC_SRV, or IBT_UC_SRV, depending on the QP.  We
1169e39c5baSBill Taylor 	 * check here that the correct value was specified, based on our
1179e39c5baSBill Taylor 	 * understanding of the QP serv type.
1189e39c5baSBill Taylor 	 *
1199e39c5baSBill Taylor 	 * Because callers specify part of a 'union' based on what QP type they
1209e39c5baSBill Taylor 	 * think they're working with, this ensures that we do not pickup bogus
1219e39c5baSBill Taylor 	 * data if the caller thought they were working with a different QP
1229e39c5baSBill Taylor 	 * type.
1239e39c5baSBill Taylor 	 */
1249e39c5baSBill Taylor 	if (!(HERMON_QP_TYPE_VALID(info_p->qp_trans, qp->qp_serv_type))) {
1259e39c5baSBill Taylor 		mutex_exit(&qp->qp_lock);
1269e39c5baSBill Taylor 		return (IBT_QP_SRV_TYPE_INVALID);
1279e39c5baSBill Taylor 	}
1289e39c5baSBill Taylor 
1299e39c5baSBill Taylor 	/*
1309e39c5baSBill Taylor 	 * If this is a transition to RTS (which is valid from RTR, RTS,
1319e39c5baSBill Taylor 	 * SQError, and SQ Drain) then we should honor the "current QP state"
1329e39c5baSBill Taylor 	 * specified by the consumer.  This means converting the IBTF QP state
1339e39c5baSBill Taylor 	 * in "info_p->qp_current_state" to an Hermon QP state.  Otherwise, we
1349e39c5baSBill Taylor 	 * assume that we already know the current state (i.e. whatever it was
1359e39c5baSBill Taylor 	 * last modified to or queried as - in "qp->qp_state").
1369e39c5baSBill Taylor 	 */
1379e39c5baSBill Taylor 	mod_state = info_p->qp_state;
1389e39c5baSBill Taylor 
1399e39c5baSBill Taylor 	if (flags & IBT_CEP_SET_RTR_RTS) {
1409e39c5baSBill Taylor 		cur_state = HERMON_QP_RTR;		/* Ready to Receive */
1419e39c5baSBill Taylor 
1429e39c5baSBill Taylor 	} else if ((flags & IBT_CEP_SET_STATE) &&
1439e39c5baSBill Taylor 	    (mod_state == IBT_STATE_RTS)) {
1449e39c5baSBill Taylor 
1459e39c5baSBill Taylor 		/* Convert the current IBTF QP state to an Hermon QP state */
1469e39c5baSBill Taylor 		switch (info_p->qp_current_state) {
1479e39c5baSBill Taylor 		case IBT_STATE_RTR:
1489e39c5baSBill Taylor 			cur_state = HERMON_QP_RTR;	/* Ready to Receive */
1499e39c5baSBill Taylor 			break;
1509e39c5baSBill Taylor 		case IBT_STATE_RTS:
1519e39c5baSBill Taylor 			cur_state = HERMON_QP_RTS;	/* Ready to Send */
1529e39c5baSBill Taylor 			break;
1539e39c5baSBill Taylor 		case IBT_STATE_SQE:
1549e39c5baSBill Taylor 			cur_state = HERMON_QP_SQERR;	/* Send Queue Error */
1559e39c5baSBill Taylor 			break;
1569e39c5baSBill Taylor 		case IBT_STATE_SQD:
1579e39c5baSBill Taylor 			cur_state = HERMON_QP_SQD;	/* SQ Drained */
1589e39c5baSBill Taylor 			break;
1599e39c5baSBill Taylor 		default:
1609e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
1619e39c5baSBill Taylor 			return (IBT_QP_STATE_INVALID);
1629e39c5baSBill Taylor 		}
1639e39c5baSBill Taylor 	} else {
1649e39c5baSBill Taylor 		cur_state = qp->qp_state;
1659e39c5baSBill Taylor 	}
1669e39c5baSBill Taylor 
1679e39c5baSBill Taylor 	switch (cur_state) {
1689e39c5baSBill Taylor 	case HERMON_QP_RESET:
1699e39c5baSBill Taylor 		okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_RESET_INIT |
1709e39c5baSBill Taylor 		    IBT_CEP_SET_RDMA_R | IBT_CEP_SET_RDMA_W |
1719e39c5baSBill Taylor 		    IBT_CEP_SET_ATOMIC | IBT_CEP_SET_PKEY_IX |
1729e39c5baSBill Taylor 		    IBT_CEP_SET_PORT | IBT_CEP_SET_QKEY);
1739e39c5baSBill Taylor 
1749e39c5baSBill Taylor 		/*
1759e39c5baSBill Taylor 		 * Check for attempts to modify invalid attributes from the
1769e39c5baSBill Taylor 		 * "Reset" state
1779e39c5baSBill Taylor 		 */
1789e39c5baSBill Taylor 		if (flags & ~okflags) {
1799e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
1809e39c5baSBill Taylor 			status = IBT_QP_ATTR_RO;
1819e39c5baSBill Taylor 			goto qpmod_fail;
1829e39c5baSBill Taylor 		}
1839e39c5baSBill Taylor 
1849e39c5baSBill Taylor 		/*
1859e39c5baSBill Taylor 		 * Verify state transition is to either "Init", back to
1869e39c5baSBill Taylor 		 * "Reset", or to "Error".
1879e39c5baSBill Taylor 		 */
1889e39c5baSBill Taylor 		if ((flags & IBT_CEP_SET_RESET_INIT) &&
1899e39c5baSBill Taylor 		    (flags & IBT_CEP_SET_STATE) &&
1909e39c5baSBill Taylor 		    (mod_state != IBT_STATE_INIT)) {
1919e39c5baSBill Taylor 			/* Invalid transition - ambiguous flags */
1929e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
1939e39c5baSBill Taylor 			status = IBT_QP_STATE_INVALID;
1949e39c5baSBill Taylor 			goto qpmod_fail;
1959e39c5baSBill Taylor 
1969e39c5baSBill Taylor 		} else if ((flags & IBT_CEP_SET_RESET_INIT) ||
1979e39c5baSBill Taylor 		    ((flags & IBT_CEP_SET_STATE) &&
1989e39c5baSBill Taylor 		    (mod_state == IBT_STATE_INIT))) {
1999e39c5baSBill Taylor 			/*
2009e39c5baSBill Taylor 			 * Attempt to transition from "Reset" to "Init"
2019e39c5baSBill Taylor 			 */
2029e39c5baSBill Taylor 			status = hermon_qp_reset2init(state, qp, info_p);
2039e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
2049e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
2059e39c5baSBill Taylor 				goto qpmod_fail;
2069e39c5baSBill Taylor 			}
2079e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_INIT;
20817a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_INIT);
2099e39c5baSBill Taylor 
2109e39c5baSBill Taylor 		} else if ((flags & IBT_CEP_SET_STATE) &&
2119e39c5baSBill Taylor 		    (mod_state == IBT_STATE_RESET)) {
2129e39c5baSBill Taylor 			/*
2139e39c5baSBill Taylor 			 * Attempt to transition from "Reset" back to "Reset"
2149e39c5baSBill Taylor 			 *    Nothing to do here really... just drop the lock
2159e39c5baSBill Taylor 			 *    and return success.  The qp->qp_state should
2169e39c5baSBill Taylor 			 *    already be set to HERMON_QP_RESET.
2179e39c5baSBill Taylor 			 *
2189e39c5baSBill Taylor 			 * Note: We return here because we do not want to fall
2199e39c5baSBill Taylor 			 *    through to the hermon_wrid_from_reset_handling()
2209e39c5baSBill Taylor 			 *    routine below (since we are not really moving
2219e39c5baSBill Taylor 			 *    _out_ of the "Reset" state.
2229e39c5baSBill Taylor 			 */
2239e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
2249e39c5baSBill Taylor 			return (DDI_SUCCESS);
2259e39c5baSBill Taylor 
2269e39c5baSBill Taylor 		} else if ((flags & IBT_CEP_SET_STATE) &&
2279e39c5baSBill Taylor 		    (mod_state == IBT_STATE_ERROR)) {
2289e39c5baSBill Taylor 			/*
2299e39c5baSBill Taylor 			 * Attempt to transition from "Reset" to "Error"
2309e39c5baSBill Taylor 			 */
2319e39c5baSBill Taylor 			status = hermon_qp_reset2err(state, qp);
2329e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
2339e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
2349e39c5baSBill Taylor 				goto qpmod_fail;
2359e39c5baSBill Taylor 			}
2369e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_ERR;
23717a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
2389e39c5baSBill Taylor 
2399e39c5baSBill Taylor 		} else {
2409e39c5baSBill Taylor 			/* Invalid transition - return error */
2419e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
2429e39c5baSBill Taylor 			status = IBT_QP_STATE_INVALID;
2439e39c5baSBill Taylor 			goto qpmod_fail;
2449e39c5baSBill Taylor 		}
2459e39c5baSBill Taylor 
2469e39c5baSBill Taylor 		/*
2479e39c5baSBill Taylor 		 * Do any additional handling necessary here for the transition
2489e39c5baSBill Taylor 		 * from the "Reset" state (e.g. re-initialize the workQ WRID
2499e39c5baSBill Taylor 		 * lists).  Note: If hermon_wrid_from_reset_handling() fails,
2509e39c5baSBill Taylor 		 * then we attempt to transition the QP back to the "Reset"
2519e39c5baSBill Taylor 		 * state.  If that fails, then it is an indication of a serious
2529e39c5baSBill Taylor 		 * problem (either HW or SW).  So we print out a warning
2539e39c5baSBill Taylor 		 * message and return failure.
2549e39c5baSBill Taylor 		 */
2559e39c5baSBill Taylor 		status = hermon_wrid_from_reset_handling(state, qp);
2569e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
2579e39c5baSBill Taylor 			if (hermon_qp_to_reset(state, qp) != DDI_SUCCESS) {
2589e39c5baSBill Taylor 				HERMON_WARNING(state, "failed to reset QP");
2599e39c5baSBill Taylor 			}
2609e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_RESET;
26117a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
2629e39c5baSBill Taylor 
2639e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
2649e39c5baSBill Taylor 			goto qpmod_fail;
2659e39c5baSBill Taylor 		}
2669e39c5baSBill Taylor 		break;
2679e39c5baSBill Taylor 
2689e39c5baSBill Taylor 	case HERMON_QP_INIT:
2699e39c5baSBill Taylor 		okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_INIT_RTR |
2709e39c5baSBill Taylor 		    IBT_CEP_SET_ADDS_VECT | IBT_CEP_SET_RDMARA_IN |
2719e39c5baSBill Taylor 		    IBT_CEP_SET_MIN_RNR_NAK | IBT_CEP_SET_ALT_PATH |
2729e39c5baSBill Taylor 		    IBT_CEP_SET_RDMA_R | IBT_CEP_SET_RDMA_W |
2739e39c5baSBill Taylor 		    IBT_CEP_SET_ATOMIC | IBT_CEP_SET_PKEY_IX |
2749e39c5baSBill Taylor 		    IBT_CEP_SET_QKEY | IBT_CEP_SET_PORT);
2759e39c5baSBill Taylor 
2769e39c5baSBill Taylor 		/*
2779e39c5baSBill Taylor 		 * Check for attempts to modify invalid attributes from the
2789e39c5baSBill Taylor 		 * "Init" state
2799e39c5baSBill Taylor 		 */
2809e39c5baSBill Taylor 		if (flags & ~okflags) {
2819e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
2829e39c5baSBill Taylor 			status = IBT_QP_ATTR_RO;
2839e39c5baSBill Taylor 			goto qpmod_fail;
2849e39c5baSBill Taylor 		}
2859e39c5baSBill Taylor 
2869e39c5baSBill Taylor 		/*
2879e39c5baSBill Taylor 		 * Verify state transition is to either "RTR", back to "Init",
2889e39c5baSBill Taylor 		 * to "Reset", or to "Error"
2899e39c5baSBill Taylor 		 */
2909e39c5baSBill Taylor 		if ((flags & IBT_CEP_SET_INIT_RTR) &&
2919e39c5baSBill Taylor 		    (flags & IBT_CEP_SET_STATE) &&
2929e39c5baSBill Taylor 		    (mod_state != IBT_STATE_RTR)) {
2939e39c5baSBill Taylor 			/* Invalid transition - ambiguous flags */
2949e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
2959e39c5baSBill Taylor 			status = IBT_QP_STATE_INVALID;
2969e39c5baSBill Taylor 			goto qpmod_fail;
2979e39c5baSBill Taylor 
2989e39c5baSBill Taylor 		} else if ((flags & IBT_CEP_SET_INIT_RTR) ||
2999e39c5baSBill Taylor 		    ((flags & IBT_CEP_SET_STATE) &&
3009e39c5baSBill Taylor 		    (mod_state == IBT_STATE_RTR))) {
3019e39c5baSBill Taylor 			/*
3029e39c5baSBill Taylor 			 * Attempt to transition from "Init" to "RTR"
3039e39c5baSBill Taylor 			 */
3049e39c5baSBill Taylor 			status = hermon_qp_init2rtr(state, qp, flags, info_p);
3059e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
3069e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
3079e39c5baSBill Taylor 				goto qpmod_fail;
3089e39c5baSBill Taylor 			}
3099e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_RTR;
31017a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTR);
3119e39c5baSBill Taylor 
3129e39c5baSBill Taylor 		} else if ((flags & IBT_CEP_SET_STATE) &&
3139e39c5baSBill Taylor 		    (mod_state == IBT_STATE_INIT)) {
3149e39c5baSBill Taylor 			/*
3159e39c5baSBill Taylor 			 * Attempt to transition from "Init" to "Init"
3169e39c5baSBill Taylor 			 */
3179e39c5baSBill Taylor 			status = hermon_qp_init2init(state, qp, flags, info_p);
3189e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
3199e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
3209e39c5baSBill Taylor 				goto qpmod_fail;
3219e39c5baSBill Taylor 			}
3229e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_INIT;
32317a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_INIT);
3249e39c5baSBill Taylor 
3259e39c5baSBill Taylor 		} else if ((flags & IBT_CEP_SET_STATE) &&
3269e39c5baSBill Taylor 		    (mod_state == IBT_STATE_RESET)) {
3279e39c5baSBill Taylor 			/*
3289e39c5baSBill Taylor 			 * Attempt to transition from "Init" to "Reset"
3299e39c5baSBill Taylor 			 */
3309e39c5baSBill Taylor 			status = hermon_qp_to_reset(state, qp);
3319e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
3329e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
3339e39c5baSBill Taylor 				goto qpmod_fail;
3349e39c5baSBill Taylor 			}
3359e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_RESET;
33617a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
3379e39c5baSBill Taylor 
3389e39c5baSBill Taylor 			/*
3399e39c5baSBill Taylor 			 * Do any additional handling necessary for the
3409e39c5baSBill Taylor 			 * transition _to_ the "Reset" state (e.g. update the
3419e39c5baSBill Taylor 			 * workQ WRID lists)
3429e39c5baSBill Taylor 			 */
3439e39c5baSBill Taylor 			status = hermon_wrid_to_reset_handling(state, qp);
3449e39c5baSBill Taylor 			if (status != IBT_SUCCESS) {
3459e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
3469e39c5baSBill Taylor 				goto qpmod_fail;
3479e39c5baSBill Taylor 			}
3489e39c5baSBill Taylor 
3499e39c5baSBill Taylor 		} else if ((flags & IBT_CEP_SET_STATE) &&
3509e39c5baSBill Taylor 		    (mod_state == IBT_STATE_ERROR)) {
3519e39c5baSBill Taylor 			/*
3529e39c5baSBill Taylor 			 * Attempt to transition from "Init" to "Error"
3539e39c5baSBill Taylor 			 */
3549e39c5baSBill Taylor 			status = hermon_qp_to_error(state, qp);
3559e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
3569e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
3579e39c5baSBill Taylor 				goto qpmod_fail;
3589e39c5baSBill Taylor 			}
3599e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_ERR;
36017a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
3619e39c5baSBill Taylor 
3629e39c5baSBill Taylor 		} else {
3639e39c5baSBill Taylor 			/* Invalid transition - return error */
3649e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
3659e39c5baSBill Taylor 			status = IBT_QP_STATE_INVALID;
3669e39c5baSBill Taylor 			goto qpmod_fail;
3679e39c5baSBill Taylor 		}
3689e39c5baSBill Taylor 		break;
3699e39c5baSBill Taylor 
3709e39c5baSBill Taylor 	case HERMON_QP_RTR:
3719e39c5baSBill Taylor 		okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_RTR_RTS |
3729e39c5baSBill Taylor 		    IBT_CEP_SET_TIMEOUT | IBT_CEP_SET_RETRY |
3739e39c5baSBill Taylor 		    IBT_CEP_SET_RNR_NAK_RETRY | IBT_CEP_SET_RDMARA_OUT |
3749e39c5baSBill Taylor 		    IBT_CEP_SET_RDMA_R | IBT_CEP_SET_RDMA_W |
3759e39c5baSBill Taylor 		    IBT_CEP_SET_ATOMIC | IBT_CEP_SET_QKEY |
3769e39c5baSBill Taylor 		    IBT_CEP_SET_ALT_PATH | IBT_CEP_SET_MIG |
3779e39c5baSBill Taylor 		    IBT_CEP_SET_MIN_RNR_NAK);
3789e39c5baSBill Taylor 
3799e39c5baSBill Taylor 		/*
3809e39c5baSBill Taylor 		 * Check for attempts to modify invalid attributes from the
3819e39c5baSBill Taylor 		 * "RTR" state
3829e39c5baSBill Taylor 		 */
3839e39c5baSBill Taylor 		if (flags & ~okflags) {
3849e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
3859e39c5baSBill Taylor 			status = IBT_QP_ATTR_RO;
3869e39c5baSBill Taylor 			goto qpmod_fail;
3879e39c5baSBill Taylor 		}
3889e39c5baSBill Taylor 
3899e39c5baSBill Taylor 		/*
3909e39c5baSBill Taylor 		 * Verify state transition is to either "RTS", "Reset",
3919e39c5baSBill Taylor 		 * or "Error"
3929e39c5baSBill Taylor 		 */
3939e39c5baSBill Taylor 		if ((flags & IBT_CEP_SET_RTR_RTS) &&
3949e39c5baSBill Taylor 		    (flags & IBT_CEP_SET_STATE) &&
3959e39c5baSBill Taylor 		    (mod_state != IBT_STATE_RTS)) {
3969e39c5baSBill Taylor 			/* Invalid transition - ambiguous flags */
3979e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
3989e39c5baSBill Taylor 			status = IBT_QP_STATE_INVALID;
3999e39c5baSBill Taylor 			goto qpmod_fail;
4009e39c5baSBill Taylor 
4019e39c5baSBill Taylor 		} else if ((flags & IBT_CEP_SET_RTR_RTS) ||
4029e39c5baSBill Taylor 		    ((flags & IBT_CEP_SET_STATE) &&
4039e39c5baSBill Taylor 		    (mod_state == IBT_STATE_RTS))) {
4049e39c5baSBill Taylor 			/*
4059e39c5baSBill Taylor 			 * Attempt to transition from "RTR" to "RTS"
4069e39c5baSBill Taylor 			 */
4079e39c5baSBill Taylor 			status = hermon_qp_rtr2rts(state, qp, flags, info_p);
4089e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
4099e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
4109e39c5baSBill Taylor 				goto qpmod_fail;
4119e39c5baSBill Taylor 			}
4129e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_RTS;
41317a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTS);
4149e39c5baSBill Taylor 
4159e39c5baSBill Taylor 		} else if ((flags & IBT_CEP_SET_STATE) &&
4169e39c5baSBill Taylor 		    (mod_state == IBT_STATE_RESET)) {
4179e39c5baSBill Taylor 			/*
4189e39c5baSBill Taylor 			 * Attempt to transition from "RTR" to "Reset"
4199e39c5baSBill Taylor 			 */
4209e39c5baSBill Taylor 			status = hermon_qp_to_reset(state, qp);
4219e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
4229e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
4239e39c5baSBill Taylor 				goto qpmod_fail;
4249e39c5baSBill Taylor 			}
4259e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_RESET;
42617a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
4279e39c5baSBill Taylor 
4289e39c5baSBill Taylor 			/*
4299e39c5baSBill Taylor 			 * Do any additional handling necessary for the
4309e39c5baSBill Taylor 			 * transition _to_ the "Reset" state (e.g. update the
4319e39c5baSBill Taylor 			 * workQ WRID lists)
4329e39c5baSBill Taylor 			 */
4339e39c5baSBill Taylor 			status = hermon_wrid_to_reset_handling(state, qp);
4349e39c5baSBill Taylor 			if (status != IBT_SUCCESS) {
4359e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
4369e39c5baSBill Taylor 				goto qpmod_fail;
4379e39c5baSBill Taylor 			}
4389e39c5baSBill Taylor 
4399e39c5baSBill Taylor 		} else if ((flags & IBT_CEP_SET_STATE) &&
4409e39c5baSBill Taylor 		    (mod_state == IBT_STATE_ERROR)) {
4419e39c5baSBill Taylor 			/*
4429e39c5baSBill Taylor 			 * Attempt to transition from "RTR" to "Error"
4439e39c5baSBill Taylor 			 */
4449e39c5baSBill Taylor 			status = hermon_qp_to_error(state, qp);
4459e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
4469e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
4479e39c5baSBill Taylor 				goto qpmod_fail;
4489e39c5baSBill Taylor 			}
4499e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_ERR;
45017a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
4519e39c5baSBill Taylor 
4529e39c5baSBill Taylor 		} else {
4539e39c5baSBill Taylor 			/* Invalid transition - return error */
4549e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
4559e39c5baSBill Taylor 			status = IBT_QP_STATE_INVALID;
4569e39c5baSBill Taylor 			goto qpmod_fail;
4579e39c5baSBill Taylor 		}
4589e39c5baSBill Taylor 		break;
4599e39c5baSBill Taylor 
4609e39c5baSBill Taylor 	case HERMON_QP_RTS:
4619e39c5baSBill Taylor 		okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_RDMA_R |
4629e39c5baSBill Taylor 		    IBT_CEP_SET_RDMA_W | IBT_CEP_SET_ATOMIC |
4639e39c5baSBill Taylor 		    IBT_CEP_SET_QKEY | IBT_CEP_SET_ALT_PATH |
4649e39c5baSBill Taylor 		    IBT_CEP_SET_MIG | IBT_CEP_SET_MIN_RNR_NAK |
4659e39c5baSBill Taylor 		    IBT_CEP_SET_SQD_EVENT);
4669e39c5baSBill Taylor 
4679e39c5baSBill Taylor 		/*
4689e39c5baSBill Taylor 		 * Check for attempts to modify invalid attributes from the
4699e39c5baSBill Taylor 		 * "RTS" state
4709e39c5baSBill Taylor 		 */
4719e39c5baSBill Taylor 		if (flags & ~okflags) {
4729e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
4739e39c5baSBill Taylor 			status = IBT_QP_ATTR_RO;
4749e39c5baSBill Taylor 			goto qpmod_fail;
4759e39c5baSBill Taylor 		}
4769e39c5baSBill Taylor 
4779e39c5baSBill Taylor 		/*
4789e39c5baSBill Taylor 		 * Verify state transition is to either "RTS", "SQD", "Reset",
4799e39c5baSBill Taylor 		 * or "Error"
4809e39c5baSBill Taylor 		 */
4819e39c5baSBill Taylor 		if ((flags & IBT_CEP_SET_STATE) &&
4829e39c5baSBill Taylor 		    (mod_state == IBT_STATE_RTS)) {
4839e39c5baSBill Taylor 			/*
4849e39c5baSBill Taylor 			 * Attempt to transition from "RTS" to "RTS"
4859e39c5baSBill Taylor 			 */
4869e39c5baSBill Taylor 			status = hermon_qp_rts2rts(state, qp, flags, info_p);
4879e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
4889e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
4899e39c5baSBill Taylor 				goto qpmod_fail;
4909e39c5baSBill Taylor 			}
4919e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_RTS;
49217a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTS);
4939e39c5baSBill Taylor 
4949e39c5baSBill Taylor 		} else if ((flags & IBT_CEP_SET_STATE) &&
4959e39c5baSBill Taylor 		    (mod_state == IBT_STATE_SQD)) {
4969e39c5baSBill Taylor #ifdef HERMON_NOTNOW
4979e39c5baSBill Taylor 			/*
4989e39c5baSBill Taylor 			 * Attempt to transition from "RTS" to "SQD"
4999e39c5baSBill Taylor 			 */
5009e39c5baSBill Taylor 			status = hermon_qp_rts2sqd(state, qp, flags);
5019e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
5029e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
5039e39c5baSBill Taylor 				goto qpmod_fail;
5049e39c5baSBill Taylor 			}
5059e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_SQD;
50617a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_SQD);
5079e39c5baSBill Taylor #else
5089e39c5baSBill Taylor 			/* hack because of the lack of fw support for SQD */
5099e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
5109e39c5baSBill Taylor 			status = IBT_QP_STATE_INVALID;
5119e39c5baSBill Taylor 			goto qpmod_fail;
5129e39c5baSBill Taylor #endif
5139e39c5baSBill Taylor 
5149e39c5baSBill Taylor 		} else if ((flags & IBT_CEP_SET_STATE) &&
5159e39c5baSBill Taylor 		    (mod_state == IBT_STATE_RESET)) {
5169e39c5baSBill Taylor 			/*
5179e39c5baSBill Taylor 			 * Attempt to transition from "RTS" to "Reset"
5189e39c5baSBill Taylor 			 */
5199e39c5baSBill Taylor 			status = hermon_qp_to_reset(state, qp);
5209e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
5219e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
5229e39c5baSBill Taylor 				goto qpmod_fail;
5239e39c5baSBill Taylor 			}
5249e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_RESET;
52517a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
5269e39c5baSBill Taylor 
5279e39c5baSBill Taylor 			/*
5289e39c5baSBill Taylor 			 * Do any additional handling necessary for the
5299e39c5baSBill Taylor 			 * transition _to_ the "Reset" state (e.g. update the
5309e39c5baSBill Taylor 			 * workQ WRID lists)
5319e39c5baSBill Taylor 			 */
5329e39c5baSBill Taylor 			status = hermon_wrid_to_reset_handling(state, qp);
5339e39c5baSBill Taylor 			if (status != IBT_SUCCESS) {
5349e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
5359e39c5baSBill Taylor 				goto qpmod_fail;
5369e39c5baSBill Taylor 			}
5379e39c5baSBill Taylor 
5389e39c5baSBill Taylor 		} else if ((flags & IBT_CEP_SET_STATE) &&
5399e39c5baSBill Taylor 		    (mod_state == IBT_STATE_ERROR)) {
5409e39c5baSBill Taylor 			/*
5419e39c5baSBill Taylor 			 * Attempt to transition from "RTS" to "Error"
5429e39c5baSBill Taylor 			 */
5439e39c5baSBill Taylor 			status = hermon_qp_to_error(state, qp);
5449e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
5459e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
5469e39c5baSBill Taylor 				goto qpmod_fail;
5479e39c5baSBill Taylor 			}
5489e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_ERR;
54917a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
5509e39c5baSBill Taylor 
5519e39c5baSBill Taylor 		} else {
5529e39c5baSBill Taylor 			/* Invalid transition - return error */
5539e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
5549e39c5baSBill Taylor 			status = IBT_QP_STATE_INVALID;
5559e39c5baSBill Taylor 			goto qpmod_fail;
5569e39c5baSBill Taylor 		}
5579e39c5baSBill Taylor 		break;
5589e39c5baSBill Taylor 
5599e39c5baSBill Taylor 	case HERMON_QP_SQERR:
5609e39c5baSBill Taylor 		okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_RDMA_R |
5619e39c5baSBill Taylor 		    IBT_CEP_SET_RDMA_W | IBT_CEP_SET_ATOMIC |
5629e39c5baSBill Taylor 		    IBT_CEP_SET_QKEY | IBT_CEP_SET_MIN_RNR_NAK);
5639e39c5baSBill Taylor 
5649e39c5baSBill Taylor 		/*
5659e39c5baSBill Taylor 		 * Check for attempts to modify invalid attributes from the
5669e39c5baSBill Taylor 		 * "SQErr" state
5679e39c5baSBill Taylor 		 */
5689e39c5baSBill Taylor 		if (flags & ~okflags) {
5699e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
5709e39c5baSBill Taylor 			status = IBT_QP_ATTR_RO;
5719e39c5baSBill Taylor 			goto qpmod_fail;
5729e39c5baSBill Taylor 		}
5739e39c5baSBill Taylor 
5749e39c5baSBill Taylor 		/*
5759e39c5baSBill Taylor 		 * Verify state transition is to either "RTS", "Reset", or
5769e39c5baSBill Taylor 		 * "Error"
5779e39c5baSBill Taylor 		 */
5789e39c5baSBill Taylor 		if ((flags & IBT_CEP_SET_STATE) &&
5799e39c5baSBill Taylor 		    (mod_state == IBT_STATE_RTS)) {
5809e39c5baSBill Taylor 			/*
5819e39c5baSBill Taylor 			 * Attempt to transition from "SQErr" to "RTS"
5829e39c5baSBill Taylor 			 */
5839e39c5baSBill Taylor 			status = hermon_qp_sqerr2rts(state, qp, flags, info_p);
5849e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
5859e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
5869e39c5baSBill Taylor 				goto qpmod_fail;
5879e39c5baSBill Taylor 			}
5889e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_RTS;
58917a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTS);
5909e39c5baSBill Taylor 
5919e39c5baSBill Taylor 		} else if ((flags & IBT_CEP_SET_STATE) &&
5929e39c5baSBill Taylor 		    (mod_state == IBT_STATE_RESET)) {
5939e39c5baSBill Taylor 			/*
5949e39c5baSBill Taylor 			 * Attempt to transition from "SQErr" to "Reset"
5959e39c5baSBill Taylor 			 */
5969e39c5baSBill Taylor 			status = hermon_qp_to_reset(state, qp);
5979e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
5989e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
5999e39c5baSBill Taylor 				goto qpmod_fail;
6009e39c5baSBill Taylor 			}
6019e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_RESET;
60217a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
6039e39c5baSBill Taylor 
6049e39c5baSBill Taylor 			/*
6059e39c5baSBill Taylor 			 * Do any additional handling necessary for the
6069e39c5baSBill Taylor 			 * transition _to_ the "Reset" state (e.g. update the
6079e39c5baSBill Taylor 			 * workQ WRID lists)
6089e39c5baSBill Taylor 			 */
6099e39c5baSBill Taylor 			status = hermon_wrid_to_reset_handling(state, qp);
6109e39c5baSBill Taylor 			if (status != IBT_SUCCESS) {
6119e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
6129e39c5baSBill Taylor 				goto qpmod_fail;
6139e39c5baSBill Taylor 			}
6149e39c5baSBill Taylor 
6159e39c5baSBill Taylor 		} else if ((flags & IBT_CEP_SET_STATE) &&
6169e39c5baSBill Taylor 		    (mod_state == IBT_STATE_ERROR)) {
6179e39c5baSBill Taylor 			/*
6189e39c5baSBill Taylor 			 * Attempt to transition from "SQErr" to "Error"
6199e39c5baSBill Taylor 			 */
6209e39c5baSBill Taylor 			status = hermon_qp_to_error(state, qp);
6219e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
6229e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
6239e39c5baSBill Taylor 				goto qpmod_fail;
6249e39c5baSBill Taylor 			}
6259e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_ERR;
62617a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
6279e39c5baSBill Taylor 
6289e39c5baSBill Taylor 		} else {
6299e39c5baSBill Taylor 			/* Invalid transition - return error */
6309e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
6319e39c5baSBill Taylor 			status = IBT_QP_STATE_INVALID;
6329e39c5baSBill Taylor 			goto qpmod_fail;
6339e39c5baSBill Taylor 		}
6349e39c5baSBill Taylor 		break;
6359e39c5baSBill Taylor 
6369e39c5baSBill Taylor 	case HERMON_QP_SQD:
6379e39c5baSBill Taylor 		okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_ADDS_VECT |
6389e39c5baSBill Taylor 		    IBT_CEP_SET_ALT_PATH | IBT_CEP_SET_MIG |
6399e39c5baSBill Taylor 		    IBT_CEP_SET_RDMARA_OUT | IBT_CEP_SET_RDMARA_IN |
6409e39c5baSBill Taylor 		    IBT_CEP_SET_QKEY | IBT_CEP_SET_PKEY_IX |
6419e39c5baSBill Taylor 		    IBT_CEP_SET_TIMEOUT | IBT_CEP_SET_RETRY |
6429e39c5baSBill Taylor 		    IBT_CEP_SET_RNR_NAK_RETRY | IBT_CEP_SET_PORT |
6439e39c5baSBill Taylor 		    IBT_CEP_SET_MIN_RNR_NAK | IBT_CEP_SET_RDMA_R |
6449e39c5baSBill Taylor 		    IBT_CEP_SET_RDMA_W | IBT_CEP_SET_ATOMIC);
6459e39c5baSBill Taylor 
6469e39c5baSBill Taylor 		/*
6479e39c5baSBill Taylor 		 * Check for attempts to modify invalid attributes from the
6489e39c5baSBill Taylor 		 * "SQD" state
6499e39c5baSBill Taylor 		 */
6509e39c5baSBill Taylor 		if (flags & ~okflags) {
6519e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
6529e39c5baSBill Taylor 			status = IBT_QP_ATTR_RO;
6539e39c5baSBill Taylor 			goto qpmod_fail;
6549e39c5baSBill Taylor 		}
6559e39c5baSBill Taylor 
6569e39c5baSBill Taylor 		/*
6579e39c5baSBill Taylor 		 * Verify state transition is to either "SQD", "RTS", "Reset",
6589e39c5baSBill Taylor 		 * or "Error"
6599e39c5baSBill Taylor 		 */
6609e39c5baSBill Taylor 
6619e39c5baSBill Taylor 		if ((flags & IBT_CEP_SET_STATE) &&
6629e39c5baSBill Taylor 		    (mod_state == IBT_STATE_SQD)) {
6639e39c5baSBill Taylor 			/*
6649e39c5baSBill Taylor 			 * Attempt to transition from "SQD" to "SQD"
6659e39c5baSBill Taylor 			 */
6669e39c5baSBill Taylor 			status = hermon_qp_sqd2sqd(state, qp, flags, info_p);
6679e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
6689e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
6699e39c5baSBill Taylor 				goto qpmod_fail;
6709e39c5baSBill Taylor 			}
6719e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_SQD;
67217a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_SQD);
6739e39c5baSBill Taylor 
6749e39c5baSBill Taylor 		} else if ((flags & IBT_CEP_SET_STATE) &&
6759e39c5baSBill Taylor 		    (mod_state == IBT_STATE_RTS)) {
6769e39c5baSBill Taylor 			/*
6779e39c5baSBill Taylor 			 * If still draining SQ, then fail transition attempt
6789e39c5baSBill Taylor 			 * to RTS, even though this is now done is two steps
6799e39c5baSBill Taylor 			 * (see below) if the consumer has tried this before
680*48bbca81SDaniel Hoffman 			 * it's drained, let it fail and wait appropriately
6819e39c5baSBill Taylor 			 */
6829e39c5baSBill Taylor 			if (qp->qp_sqd_still_draining) {
6839e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
6849e39c5baSBill Taylor 				goto qpmod_fail;
6859e39c5baSBill Taylor 			}
6869e39c5baSBill Taylor 			/*
6879e39c5baSBill Taylor 			 * IBA 1.2 has changed - most/all the things that were
6889e39c5baSBill Taylor 			 * done in SQD2RTS can be done in SQD2SQD.  So make this
6899e39c5baSBill Taylor 			 * a 2-step process.  First, set any attributes requsted
6909e39c5baSBill Taylor 			 * w/ SQD2SQD, but no real transition.
6919e39c5baSBill Taylor 			 *
6929e39c5baSBill Taylor 			 * First, Attempt to transition from "SQD" to "SQD"
6939e39c5baSBill Taylor 			 */
6949e39c5baSBill Taylor 			status = hermon_qp_sqd2sqd(state, qp, flags, info_p);
6959e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
6969e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
6979e39c5baSBill Taylor 				goto qpmod_fail;
6989e39c5baSBill Taylor 			}
6999e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_SQD;
70017a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_SQD);
7019e39c5baSBill Taylor 
7029e39c5baSBill Taylor 			/*
7039e39c5baSBill Taylor 			 * The, attempt to transition from "SQD" to "RTS", but
7049e39c5baSBill Taylor 			 * request only the state transition, no attributes
7059e39c5baSBill Taylor 			 */
7069e39c5baSBill Taylor 
7079e39c5baSBill Taylor 			status = hermon_qp_sqd2rts(state, qp,
7089e39c5baSBill Taylor 			    IBT_CEP_SET_STATE, info_p);
7099e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
7109e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
7119e39c5baSBill Taylor 				goto qpmod_fail;
7129e39c5baSBill Taylor 			}
7139e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_RTS;
71417a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTS);
7159e39c5baSBill Taylor 
7169e39c5baSBill Taylor 		} else if ((flags & IBT_CEP_SET_STATE) &&
7179e39c5baSBill Taylor 		    (mod_state == IBT_STATE_RESET)) {
7189e39c5baSBill Taylor 			/*
7199e39c5baSBill Taylor 			 * Attempt to transition from "SQD" to "Reset"
7209e39c5baSBill Taylor 			 */
7219e39c5baSBill Taylor 			status = hermon_qp_to_reset(state, qp);
7229e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
7239e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
7249e39c5baSBill Taylor 				goto qpmod_fail;
7259e39c5baSBill Taylor 			}
7269e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_RESET;
72717a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
7289e39c5baSBill Taylor 
7299e39c5baSBill Taylor 			/*
7309e39c5baSBill Taylor 			 * Do any additional handling necessary for the
7319e39c5baSBill Taylor 			 * transition _to_ the "Reset" state (e.g. update the
7329e39c5baSBill Taylor 			 * workQ WRID lists)
7339e39c5baSBill Taylor 			 */
7349e39c5baSBill Taylor 			status = hermon_wrid_to_reset_handling(state, qp);
7359e39c5baSBill Taylor 			if (status != IBT_SUCCESS) {
7369e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
7379e39c5baSBill Taylor 				goto qpmod_fail;
7389e39c5baSBill Taylor 			}
7399e39c5baSBill Taylor 
7409e39c5baSBill Taylor 		} else if ((flags & IBT_CEP_SET_STATE) &&
7419e39c5baSBill Taylor 		    (mod_state == IBT_STATE_ERROR)) {
7429e39c5baSBill Taylor 			/*
7439e39c5baSBill Taylor 			 * Attempt to transition from "SQD" to "Error"
7449e39c5baSBill Taylor 			 */
7459e39c5baSBill Taylor 			status = hermon_qp_to_error(state, qp);
7469e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
7479e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
7489e39c5baSBill Taylor 				goto qpmod_fail;
7499e39c5baSBill Taylor 			}
7509e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_ERR;
75117a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
7529e39c5baSBill Taylor 
7539e39c5baSBill Taylor 		} else {
7549e39c5baSBill Taylor 			/* Invalid transition - return error */
7559e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
7569e39c5baSBill Taylor 			status = IBT_QP_STATE_INVALID;
7579e39c5baSBill Taylor 			goto qpmod_fail;
7589e39c5baSBill Taylor 		}
7599e39c5baSBill Taylor 		break;
7609e39c5baSBill Taylor 
7619e39c5baSBill Taylor 	case HERMON_QP_ERR:
7629e39c5baSBill Taylor 		/*
7639e39c5baSBill Taylor 		 * Verify state transition is to either "Reset" or back to
7649e39c5baSBill Taylor 		 * "Error"
7659e39c5baSBill Taylor 		 */
7669e39c5baSBill Taylor 		if ((flags & IBT_CEP_SET_STATE) &&
7679e39c5baSBill Taylor 		    (mod_state == IBT_STATE_RESET)) {
7689e39c5baSBill Taylor 			/*
7699e39c5baSBill Taylor 			 * Attempt to transition from "Error" to "Reset"
7709e39c5baSBill Taylor 			 */
7719e39c5baSBill Taylor 			status = hermon_qp_to_reset(state, qp);
7729e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
7739e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
7749e39c5baSBill Taylor 				goto qpmod_fail;
7759e39c5baSBill Taylor 			}
7769e39c5baSBill Taylor 			qp->qp_state = HERMON_QP_RESET;
77717a2b317SBill Taylor 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
7789e39c5baSBill Taylor 
7799e39c5baSBill Taylor 			/*
7809e39c5baSBill Taylor 			 * Do any additional handling necessary for the
7819e39c5baSBill Taylor 			 * transition _to_ the "Reset" state (e.g. update the
7829e39c5baSBill Taylor 			 * workQ WRID lists)
7839e39c5baSBill Taylor 			 */
7849e39c5baSBill Taylor 			status = hermon_wrid_to_reset_handling(state, qp);
7859e39c5baSBill Taylor 			if (status != IBT_SUCCESS) {
7869e39c5baSBill Taylor 				mutex_exit(&qp->qp_lock);
7879e39c5baSBill Taylor 				goto qpmod_fail;
7889e39c5baSBill Taylor 			}
7899e39c5baSBill Taylor 
7909e39c5baSBill Taylor 		} else if ((flags & IBT_CEP_SET_STATE) &&
7919e39c5baSBill Taylor 		    (mod_state == IBT_STATE_ERROR)) {
7929e39c5baSBill Taylor 			/*
7939e39c5baSBill Taylor 			 * Attempt to transition from "Error" back to "Error"
7949e39c5baSBill Taylor 			 *    Nothing to do here really... just drop the lock
7959e39c5baSBill Taylor 			 *    and return success.  The qp->qp_state should
7969e39c5baSBill Taylor 			 *    already be set to HERMON_QP_ERR.
7979e39c5baSBill Taylor 			 *
7989e39c5baSBill Taylor 			 */
7999e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
8009e39c5baSBill Taylor 			return (DDI_SUCCESS);
8019e39c5baSBill Taylor 
8029e39c5baSBill Taylor 		} else {
8039e39c5baSBill Taylor 			/* Invalid transition - return error */
8049e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
8059e39c5baSBill Taylor 			status = IBT_QP_STATE_INVALID;
8069e39c5baSBill Taylor 			goto qpmod_fail;
8079e39c5baSBill Taylor 		}
8089e39c5baSBill Taylor 		break;
8099e39c5baSBill Taylor 
8109e39c5baSBill Taylor 	default:
8119e39c5baSBill Taylor 		/*
8129e39c5baSBill Taylor 		 * Invalid QP state.  If we got here then it's a warning of
8139e39c5baSBill Taylor 		 * a probably serious problem.  So print a message and return
8149e39c5baSBill Taylor 		 * failure
8159e39c5baSBill Taylor 		 */
8169e39c5baSBill Taylor 		mutex_exit(&qp->qp_lock);
8179e39c5baSBill Taylor 		HERMON_WARNING(state, "unknown QP state in modify");
8189e39c5baSBill Taylor 		status = IBT_QP_STATE_INVALID;
8199e39c5baSBill Taylor 		goto qpmod_fail;
8209e39c5baSBill Taylor 	}
8219e39c5baSBill Taylor 
8229e39c5baSBill Taylor 	mutex_exit(&qp->qp_lock);
8239e39c5baSBill Taylor 	return (DDI_SUCCESS);
8249e39c5baSBill Taylor 
8259e39c5baSBill Taylor qpmod_fail:
8269e39c5baSBill Taylor 	return (status);
8279e39c5baSBill Taylor }
8289e39c5baSBill Taylor 
8299e39c5baSBill Taylor 
8309e39c5baSBill Taylor /*
8319e39c5baSBill Taylor  * hermon_qp_reset2init()
8329e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
8339e39c5baSBill Taylor  */
8349e39c5baSBill Taylor static int
hermon_qp_reset2init(hermon_state_t * state,hermon_qphdl_t qp,ibt_qp_info_t * info_p)8359e39c5baSBill Taylor hermon_qp_reset2init(hermon_state_t *state, hermon_qphdl_t qp,
8369e39c5baSBill Taylor     ibt_qp_info_t *info_p)
8379e39c5baSBill Taylor {
8389e39c5baSBill Taylor 	hermon_hw_qpc_t		*qpc;
8399e39c5baSBill Taylor 	ibt_qp_rc_attr_t	*rc;
8409e39c5baSBill Taylor 	ibt_qp_ud_attr_t	*ud;
8419e39c5baSBill Taylor 	ibt_qp_uc_attr_t	*uc;
8429e39c5baSBill Taylor 	uint_t			portnum, pkeyindx;
8439e39c5baSBill Taylor 	int			status;
8449e39c5baSBill Taylor 	uint32_t		cqnmask;
84517a2b317SBill Taylor 	int			qp_srq_en;
8469e39c5baSBill Taylor 
8479e39c5baSBill Taylor 	ASSERT(MUTEX_HELD(&qp->qp_lock));
8489e39c5baSBill Taylor 
8499e39c5baSBill Taylor 	/*
8509e39c5baSBill Taylor 	 * Grab the temporary QPC entry from QP software state
8519e39c5baSBill Taylor 	 */
8529e39c5baSBill Taylor 	qpc = &qp->qpc;
8539e39c5baSBill Taylor 
8549e39c5baSBill Taylor 	/*
8559e39c5baSBill Taylor 	 * Fill in the common fields in the QPC
8569e39c5baSBill Taylor 	 */
8579e39c5baSBill Taylor 
8589e39c5baSBill Taylor 	if (qp->qp_is_special) {
8599e39c5baSBill Taylor 		qpc->serv_type	= HERMON_QP_MLX;
8609e39c5baSBill Taylor 	} else {
8619e39c5baSBill Taylor 		qpc->serv_type	= qp->qp_serv_type;
8629e39c5baSBill Taylor 	}
8639e39c5baSBill Taylor 	qpc->pm_state		= HERMON_QP_PMSTATE_MIGRATED;
8649e39c5baSBill Taylor 
8659e39c5baSBill Taylor 	qpc->pd			= qp->qp_pdhdl->pd_pdnum;
8669e39c5baSBill Taylor 
8679e39c5baSBill Taylor 	qpc->log_sq_stride	= qp->qp_sq_log_wqesz - 4;
8689e39c5baSBill Taylor 	qpc->log_rq_stride	= qp->qp_rq_log_wqesz - 4;
8699e39c5baSBill Taylor 	qpc->sq_no_prefetch	= qp->qp_no_prefetch;
8709e39c5baSBill Taylor 	qpc->log_sq_size	= highbit(qp->qp_sq_bufsz) - 1;
8719e39c5baSBill Taylor 	qpc->log_rq_size	= highbit(qp->qp_rq_bufsz) - 1;
8729e39c5baSBill Taylor 
8739e39c5baSBill Taylor 	qpc->usr_page		= qp->qp_uarpg;
8749e39c5baSBill Taylor 
8759e39c5baSBill Taylor 	cqnmask = (1 << state->hs_cfg_profile->cp_log_num_cq) - 1;
87617a2b317SBill Taylor 	qpc->cqn_snd		=
87717a2b317SBill Taylor 	    (qp->qp_sq_cqhdl == NULL) ? 0 : qp->qp_sq_cqhdl->cq_cqnum & cqnmask;
8789e39c5baSBill Taylor 	qpc->page_offs		= qp->qp_wqinfo.qa_pgoffs >> 6;
87917a2b317SBill Taylor 	qpc->cqn_rcv		=
88017a2b317SBill Taylor 	    (qp->qp_rq_cqhdl == NULL) ? 0 : qp->qp_rq_cqhdl->cq_cqnum & cqnmask;
8819e39c5baSBill Taylor 
8829e39c5baSBill Taylor 	/* dbr is now an address, not an index */
8839e39c5baSBill Taylor 	qpc->dbr_addrh		= ((uint64_t)qp->qp_rq_pdbr >> 32);
8849e39c5baSBill Taylor 	qpc->dbr_addrl		= ((uint64_t)qp->qp_rq_pdbr & 0xFFFFFFFC) >> 2;
8859e39c5baSBill Taylor 	qpc->sq_wqe_counter	= 0;
8869e39c5baSBill Taylor 	qpc->rq_wqe_counter	= 0;
8879e39c5baSBill Taylor 	/*
8889e39c5baSBill Taylor 	 * HERMON:
8899e39c5baSBill Taylor 	 * qpc->wqe_baseaddr is replaced by LKey from the cMPT, and
8909e39c5baSBill Taylor 	 * page_offset, mtt_base_addr_h/l, and log2_page_size will
8919e39c5baSBill Taylor 	 * be used to map the WQE buffer
8929e39c5baSBill Taylor 	 * NOTE that the cMPT is created implicitly when the QP is
8939e39c5baSBill Taylor 	 * transitioned from reset to init
8949e39c5baSBill Taylor 	 */
8959e39c5baSBill Taylor 	qpc->log2_pgsz		= qp->qp_mrhdl->mr_log2_pgsz;
8969e39c5baSBill Taylor 	qpc->mtt_base_addrl	= (qp->qp_mrhdl->mr_mttaddr) >> 3;
8979e39c5baSBill Taylor 	qpc->mtt_base_addrh	= (uint32_t)((qp->qp_mrhdl->mr_mttaddr >> 32) &
8989e39c5baSBill Taylor 	    0xFF);
89917a2b317SBill Taylor 	qp_srq_en		= (qp->qp_alloc_flags & IBT_QP_USES_SRQ) != 0;
90017a2b317SBill Taylor 	qpc->srq_en		= qp_srq_en;
9019e39c5baSBill Taylor 
90217a2b317SBill Taylor 	if (qp_srq_en) {
9039e39c5baSBill Taylor 		qpc->srq_number	= qp->qp_srqhdl->srq_srqnum;
9049e39c5baSBill Taylor 	} else {
9059e39c5baSBill Taylor 		qpc->srq_number = 0;
9069e39c5baSBill Taylor 	}
9079e39c5baSBill Taylor 
90817a2b317SBill Taylor 	/*
90917a2b317SBill Taylor 	 * Fast Registration Work Requests and Reserved Lkey are enabled
91017a2b317SBill Taylor 	 * with the single IBT bit stored in qp_rlky.
91117a2b317SBill Taylor 	 */
91217a2b317SBill Taylor 	qpc->fre		= qp->qp_rlky;
9139e39c5baSBill Taylor 	qpc->rlky		= qp->qp_rlky;
91417a2b317SBill Taylor 
91517a2b317SBill Taylor 	/* 1.2 verbs extensions disabled for now */
91617a2b317SBill Taylor 	qpc->header_sep		= 0; /* disable header separation for now */
91717a2b317SBill Taylor 	qpc->rss		= qp->qp_alloc_flags & IBT_QP_USES_RSS ? 1 : 0;
9189e39c5baSBill Taylor 	qpc->inline_scatter	= 0; /* disable inline scatter for now */
9199e39c5baSBill Taylor 
9209e39c5baSBill Taylor 	/*
9219e39c5baSBill Taylor 	 * Now fill in the QPC fields which are specific to transport type
9229e39c5baSBill Taylor 	 */
92317a2b317SBill Taylor 	if (qp->qp_type == IBT_UD_RQP) {
92417a2b317SBill Taylor 		int my_fc_id_idx, exch_base;
92517a2b317SBill Taylor 
9269e39c5baSBill Taylor 		ud = &info_p->qp_transport.ud;
9279e39c5baSBill Taylor 
9289e39c5baSBill Taylor 		/* Set the QKey */
9299e39c5baSBill Taylor 		qpc->qkey = ud->ud_qkey;
9309e39c5baSBill Taylor 
9319e39c5baSBill Taylor 		/*
9329e39c5baSBill Taylor 		 * Set MTU and message max. Hermon checks the QPC
9339e39c5baSBill Taylor 		 * MTU settings rather than just the port MTU,
9349e39c5baSBill Taylor 		 * so set it to maximum size.
9359e39c5baSBill Taylor 		 */
9369e39c5baSBill Taylor 		qpc->mtu = HERMON_MAX_MTU;
9379e39c5baSBill Taylor 		if (qp->qp_uses_lso)
9389e39c5baSBill Taylor 			qpc->msg_max = state->hs_devlim.log_max_gso_sz;
93917a2b317SBill Taylor 		else if (qp->qp_is_special)
94017a2b317SBill Taylor 			qpc->msg_max = HERMON_MAX_MTU + 6;
9419e39c5baSBill Taylor 		else
9429e39c5baSBill Taylor 			qpc->msg_max = HERMON_QP_LOG_MAX_MSGSZ;
9439e39c5baSBill Taylor 
9449e39c5baSBill Taylor 		/* Check for valid port number and fill it in */
9459e39c5baSBill Taylor 		portnum = ud->ud_port;
9469e39c5baSBill Taylor 		if (hermon_portnum_is_valid(state, portnum)) {
9479e39c5baSBill Taylor 			qp->qp_portnum = portnum - 1;
9489e39c5baSBill Taylor 			qpc->pri_addr_path.sched_q =
9499e39c5baSBill Taylor 			    HERMON_QP_SCHEDQ_GET(portnum - 1,
9509e39c5baSBill Taylor 			    0, qp->qp_is_special);
9519e39c5baSBill Taylor 		} else {
9529e39c5baSBill Taylor 			return (IBT_HCA_PORT_INVALID);
9539e39c5baSBill Taylor 		}
9549e39c5baSBill Taylor 
9559e39c5baSBill Taylor 
9569e39c5baSBill Taylor 		/* Check for valid PKey index and fill it in */
9579e39c5baSBill Taylor 		pkeyindx = ud->ud_pkey_ix;
9589e39c5baSBill Taylor 		if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
9599e39c5baSBill Taylor 			qpc->pri_addr_path.pkey_indx = pkeyindx;
9609e39c5baSBill Taylor 			qp->qp_pkeyindx = pkeyindx;
9619e39c5baSBill Taylor 		} else {
9629e39c5baSBill Taylor 			return (IBT_PKEY_IX_ILLEGAL);
9639e39c5baSBill Taylor 		}
9649e39c5baSBill Taylor 
96517a2b317SBill Taylor 		/* fill in the RSS fields */
96617a2b317SBill Taylor 		if (qpc->rss) {
96717a2b317SBill Taylor 			struct hermon_hw_rss_s *rssp;
96817a2b317SBill Taylor 			ibt_rss_flags_t flags = ud->ud_rss.rss_flags;
96917a2b317SBill Taylor 
97017a2b317SBill Taylor 			rssp = (struct hermon_hw_rss_s *)&qpc->pri_addr_path;
97117a2b317SBill Taylor 			rssp->log2_tbl_sz = ud->ud_rss.rss_log2_table;
97217a2b317SBill Taylor 			rssp->base_qpn = ud->ud_rss.rss_base_qpn;
97317a2b317SBill Taylor 			rssp->default_qpn = ud->ud_rss.rss_def_qpn;
97417a2b317SBill Taylor 			if (flags & IBT_RSS_ALG_XOR)
97517a2b317SBill Taylor 				rssp->hash_fn = 0;	/* XOR Hash Function */
97617a2b317SBill Taylor 			else if (flags & IBT_RSS_ALG_TPL)
97717a2b317SBill Taylor 				rssp->hash_fn = 1;	/* Toeplitz Hash Fn */
97817a2b317SBill Taylor 			else
97917a2b317SBill Taylor 				return (IBT_INVALID_PARAM);
98017a2b317SBill Taylor 			rssp->ipv4 = (flags & IBT_RSS_HASH_IPV4) != 0;
98117a2b317SBill Taylor 			rssp->tcp_ipv4 = (flags & IBT_RSS_HASH_TCP_IPV4) != 0;
98217a2b317SBill Taylor 			rssp->ipv6 = (flags & IBT_RSS_HASH_IPV6) != 0;
98317a2b317SBill Taylor 			rssp->tcp_ipv4 = (flags & IBT_RSS_HASH_TCP_IPV6) != 0;
98417a2b317SBill Taylor 			bcopy(ud->ud_rss.rss_toe_key, rssp->rss_key, 40);
98517a2b317SBill Taylor 		} else if (qp->qp_serv_type == HERMON_QP_RFCI) {
98617a2b317SBill Taylor 			status = hermon_fcoib_set_id(state, portnum,
98717a2b317SBill Taylor 			    qp->qp_qpnum, ud->ud_fc.fc_src_id);
98817a2b317SBill Taylor 			if (status != DDI_SUCCESS)
98917a2b317SBill Taylor 				return (status);
99017a2b317SBill Taylor 			qp->qp_fc_attr = ud->ud_fc;
99117a2b317SBill Taylor 		} else if (qp->qp_serv_type == HERMON_QP_FEXCH) {
99217a2b317SBill Taylor 			my_fc_id_idx = hermon_fcoib_get_id_idx(state,
99317a2b317SBill Taylor 			    portnum, &ud->ud_fc);
99417a2b317SBill Taylor 			if (my_fc_id_idx == -1)
99517a2b317SBill Taylor 				return (IBT_INVALID_PARAM);
99617a2b317SBill Taylor 			qpc->my_fc_id_idx = my_fc_id_idx;
99717a2b317SBill Taylor 
99817a2b317SBill Taylor 			status = hermon_fcoib_fexch_mkey_init(state,
99917a2b317SBill Taylor 			    qp->qp_pdhdl, ud->ud_fc.fc_hca_port,
100017a2b317SBill Taylor 			    qp->qp_qpnum, HERMON_CMD_NOSLEEP_SPIN);
100117a2b317SBill Taylor 			if (status != DDI_SUCCESS)
100217a2b317SBill Taylor 				return (status);
100317a2b317SBill Taylor 			qp->qp_fc_attr = ud->ud_fc;
100417a2b317SBill Taylor 		} else if (qp->qp_serv_type == HERMON_QP_FCMND) {
100517a2b317SBill Taylor 			my_fc_id_idx = hermon_fcoib_get_id_idx(state,
100617a2b317SBill Taylor 			    portnum, &ud->ud_fc);
100717a2b317SBill Taylor 			if (my_fc_id_idx == -1)
100817a2b317SBill Taylor 				return (IBT_INVALID_PARAM);
100917a2b317SBill Taylor 			qpc->my_fc_id_idx = my_fc_id_idx;
101017a2b317SBill Taylor 			exch_base = hermon_fcoib_check_exch_base_off(state,
101117a2b317SBill Taylor 			    portnum, &ud->ud_fc);
101217a2b317SBill Taylor 			if (exch_base == -1)
101317a2b317SBill Taylor 				return (IBT_INVALID_PARAM);
101417a2b317SBill Taylor 			qpc->exch_base = exch_base;
101517a2b317SBill Taylor 			qpc->exch_size = ud->ud_fc.fc_exch_log2_sz;
101617a2b317SBill Taylor 			qp->qp_fc_attr = ud->ud_fc;
101717a2b317SBill Taylor 		}
101817a2b317SBill Taylor 
10199e39c5baSBill Taylor 	} else if (qp->qp_serv_type == HERMON_QP_RC) {
10209e39c5baSBill Taylor 		rc = &info_p->qp_transport.rc;
10219e39c5baSBill Taylor 
10229e39c5baSBill Taylor 		/* Set the RDMA (recv) enable/disable flags */
10239e39c5baSBill Taylor 		qpc->rre = (info_p->qp_flags & IBT_CEP_RDMA_RD) ? 1 : 0;
10249e39c5baSBill Taylor 		qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
10259e39c5baSBill Taylor 		qpc->rae = (info_p->qp_flags & IBT_CEP_ATOMIC)  ? 1 : 0;
10269e39c5baSBill Taylor 
10279e39c5baSBill Taylor 		/* Check for valid port number and fill it in */
10289e39c5baSBill Taylor 		portnum = rc->rc_path.cep_hca_port_num;
10299e39c5baSBill Taylor 		if (hermon_portnum_is_valid(state, portnum)) {
10309e39c5baSBill Taylor 			qp->qp_portnum = portnum - 1;
10319e39c5baSBill Taylor 			qpc->pri_addr_path.sched_q =
10329e39c5baSBill Taylor 			    HERMON_QP_SCHEDQ_GET(portnum - 1,
10339e39c5baSBill Taylor 			    0, qp->qp_is_special);
10349e39c5baSBill Taylor 		} else {
10359e39c5baSBill Taylor 			return (IBT_HCA_PORT_INVALID);
10369e39c5baSBill Taylor 		}
10379e39c5baSBill Taylor 
10389e39c5baSBill Taylor 		/* Check for valid PKey index and fill it in */
10399e39c5baSBill Taylor 		pkeyindx = rc->rc_path.cep_pkey_ix;
10409e39c5baSBill Taylor 		if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
10419e39c5baSBill Taylor 			qpc->pri_addr_path.pkey_indx = pkeyindx;
10429e39c5baSBill Taylor 		} else {
10439e39c5baSBill Taylor 			return (IBT_PKEY_IX_ILLEGAL);
10449e39c5baSBill Taylor 		}
10459e39c5baSBill Taylor 
10469e39c5baSBill Taylor 	} else if (qp->qp_serv_type == HERMON_QP_UC) {
10479e39c5baSBill Taylor 		uc = &info_p->qp_transport.uc;
10489e39c5baSBill Taylor 
10499e39c5baSBill Taylor 		/*
10509e39c5baSBill Taylor 		 * Set the RDMA (recv) enable/disable flags.  Note: RDMA Read
10519e39c5baSBill Taylor 		 * and Atomic are ignored by default.
10529e39c5baSBill Taylor 		 */
10539e39c5baSBill Taylor 		qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
10549e39c5baSBill Taylor 
10559e39c5baSBill Taylor 		/* Check for valid port number and fill it in */
10569e39c5baSBill Taylor 		portnum = uc->uc_path.cep_hca_port_num;
10579e39c5baSBill Taylor 		if (hermon_portnum_is_valid(state, portnum)) {
10589e39c5baSBill Taylor 			qp->qp_portnum = portnum - 1;
10599e39c5baSBill Taylor 			qpc->pri_addr_path.sched_q =
10609e39c5baSBill Taylor 			    HERMON_QP_SCHEDQ_GET(portnum - 1,
10619e39c5baSBill Taylor 			    0, qp->qp_is_special);
10629e39c5baSBill Taylor 		} else {
10639e39c5baSBill Taylor 			return (IBT_HCA_PORT_INVALID);
10649e39c5baSBill Taylor 		}
10659e39c5baSBill Taylor 
10669e39c5baSBill Taylor 		/* Check for valid PKey index and fill it in */
10679e39c5baSBill Taylor 		pkeyindx = uc->uc_path.cep_pkey_ix;
10689e39c5baSBill Taylor 		if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
10699e39c5baSBill Taylor 			qpc->pri_addr_path.pkey_indx = pkeyindx;
10709e39c5baSBill Taylor 		} else {
10719e39c5baSBill Taylor 			return (IBT_PKEY_IX_ILLEGAL);
10729e39c5baSBill Taylor 		}
10739e39c5baSBill Taylor 
10749e39c5baSBill Taylor 	} else {
10759e39c5baSBill Taylor 		/*
10769e39c5baSBill Taylor 		 * Invalid QP transport type. If we got here then it's a
10779e39c5baSBill Taylor 		 * warning of a probably serious problem.  So print a message
10789e39c5baSBill Taylor 		 * and return failure
10799e39c5baSBill Taylor 		 */
10809e39c5baSBill Taylor 		HERMON_WARNING(state, "unknown QP transport type in rst2init");
10819e39c5baSBill Taylor 		return (ibc_get_ci_failure(0));
10829e39c5baSBill Taylor 	}
10839e39c5baSBill Taylor 
10849e39c5baSBill Taylor 	/*
10859e39c5baSBill Taylor 	 * Post the RST2INIT_QP command to the Hermon firmware
10869e39c5baSBill Taylor 	 *
10879e39c5baSBill Taylor 	 * We do a HERMON_NOSLEEP here because we are still holding the
10889e39c5baSBill Taylor 	 * "qp_lock".  If we got raised to interrupt level by priority
10899e39c5baSBill Taylor 	 * inversion, we do not want to block in this routine waiting for
10909e39c5baSBill Taylor 	 * success.
10919e39c5baSBill Taylor 	 */
10929e39c5baSBill Taylor 	status = hermon_cmn_qp_cmd_post(state, RST2INIT_QP, qpc, qp->qp_qpnum,
10939e39c5baSBill Taylor 	    0, HERMON_CMD_NOSLEEP_SPIN);
10949e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
10959e39c5baSBill Taylor 		cmn_err(CE_NOTE, "hermon%d: RST2INIT_QP command failed: %08x\n",
10969e39c5baSBill Taylor 		    state->hs_instance, status);
10979e39c5baSBill Taylor 		if (status == HERMON_CMD_INVALID_STATUS) {
10989e39c5baSBill Taylor 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
10999e39c5baSBill Taylor 		}
11009e39c5baSBill Taylor 		return (ibc_get_ci_failure(0));
11019e39c5baSBill Taylor 	}
11029e39c5baSBill Taylor 
11039e39c5baSBill Taylor 	return (DDI_SUCCESS);
11049e39c5baSBill Taylor }
11059e39c5baSBill Taylor 
11069e39c5baSBill Taylor 
11079e39c5baSBill Taylor /*
11089e39c5baSBill Taylor  * hermon_qp_init2init()
11099e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
11109e39c5baSBill Taylor  */
11119e39c5baSBill Taylor static int
hermon_qp_init2init(hermon_state_t * state,hermon_qphdl_t qp,ibt_cep_modify_flags_t flags,ibt_qp_info_t * info_p)11129e39c5baSBill Taylor hermon_qp_init2init(hermon_state_t *state, hermon_qphdl_t qp,
11139e39c5baSBill Taylor     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
11149e39c5baSBill Taylor {
11159e39c5baSBill Taylor 	hermon_hw_qpc_t		*qpc;
11169e39c5baSBill Taylor 	ibt_qp_rc_attr_t	*rc;
11179e39c5baSBill Taylor 	ibt_qp_ud_attr_t	*ud;
11189e39c5baSBill Taylor 	ibt_qp_uc_attr_t	*uc;
11199e39c5baSBill Taylor 	uint_t			portnum, pkeyindx;
11209e39c5baSBill Taylor 	uint32_t		opmask = 0;
11219e39c5baSBill Taylor 	int			status;
11229e39c5baSBill Taylor 
11239e39c5baSBill Taylor 	ASSERT(MUTEX_HELD(&qp->qp_lock));
11249e39c5baSBill Taylor 
11259e39c5baSBill Taylor 	/*
11269e39c5baSBill Taylor 	 * Grab the temporary QPC entry from QP software state
11279e39c5baSBill Taylor 	 */
11289e39c5baSBill Taylor 	qpc = &qp->qpc;
11299e39c5baSBill Taylor 
11309e39c5baSBill Taylor 	/*
11319e39c5baSBill Taylor 	 * Since there are no common fields to be filled in for this command,
11329e39c5baSBill Taylor 	 * we begin with the QPC fields which are specific to transport type.
11339e39c5baSBill Taylor 	 */
113417a2b317SBill Taylor 	if (qp->qp_type == IBT_UD_RQP) {
11359e39c5baSBill Taylor 		ud = &info_p->qp_transport.ud;
11369e39c5baSBill Taylor 
11379e39c5baSBill Taylor 		/*
11389e39c5baSBill Taylor 		 * If we are attempting to modify the port for this QP, then
11399e39c5baSBill Taylor 		 * check for valid port number and fill it in.  Also set the
11409e39c5baSBill Taylor 		 * appropriate flag in the "opmask" parameter.
11419e39c5baSBill Taylor 		 */
11429e39c5baSBill Taylor 	/*
11439e39c5baSBill Taylor 	 * set port is not supported in init2init - however, in init2rtr it will
11449e39c5baSBill Taylor 	 * take the entire qpc, including the embedded sched_q in the path
11459e39c5baSBill Taylor 	 * structure - so, we can just skip setting the opmask for it explicitly
11469e39c5baSBill Taylor 	 * and allow it to be set later on
11479e39c5baSBill Taylor 	 */
11489e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_PORT) {
11499e39c5baSBill Taylor 			portnum = ud->ud_port;
11509e39c5baSBill Taylor 			if (hermon_portnum_is_valid(state, portnum)) {
11519e39c5baSBill Taylor 				qp->qp_portnum = portnum - 1; /* save it away */
11529e39c5baSBill Taylor 				qpc->pri_addr_path.sched_q =
11539e39c5baSBill Taylor 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
11549e39c5baSBill Taylor 				    0, qp->qp_is_special);
11559e39c5baSBill Taylor 			} else {
11569e39c5baSBill Taylor 				return (IBT_HCA_PORT_INVALID);
11579e39c5baSBill Taylor 			}
11589e39c5baSBill Taylor 		}
11599e39c5baSBill Taylor 
11609e39c5baSBill Taylor 		/*
11619e39c5baSBill Taylor 		 * If we are attempting to modify the PKey index for this QP,
11629e39c5baSBill Taylor 		 * then check for valid PKey index and fill it in.  Also set
11639e39c5baSBill Taylor 		 * the appropriate flag in the "opmask" parameter.
11649e39c5baSBill Taylor 		 */
11659e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_PKEY_IX) {
11669e39c5baSBill Taylor 			pkeyindx = ud->ud_pkey_ix;
11679e39c5baSBill Taylor 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
11689e39c5baSBill Taylor 				qpc->pri_addr_path.pkey_indx = pkeyindx;
11699e39c5baSBill Taylor 				opmask |= HERMON_CMD_OP_PKEYINDX;
11709e39c5baSBill Taylor 				qp->qp_pkeyindx = pkeyindx;
11719e39c5baSBill Taylor 			} else {
11729e39c5baSBill Taylor 				return (IBT_PKEY_IX_ILLEGAL);
11739e39c5baSBill Taylor 			}
11749e39c5baSBill Taylor 		}
11759e39c5baSBill Taylor 
11769e39c5baSBill Taylor 		/*
11779e39c5baSBill Taylor 		 * If we are attempting to modify the QKey for this QP, then
11789e39c5baSBill Taylor 		 * fill it in and set the appropriate flag in the "opmask"
11799e39c5baSBill Taylor 		 * parameter.
11809e39c5baSBill Taylor 		 */
11819e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_QKEY) {
11829e39c5baSBill Taylor 			qpc->qkey = ud->ud_qkey;
11839e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_QKEY;
11849e39c5baSBill Taylor 		}
11859e39c5baSBill Taylor 
11869e39c5baSBill Taylor 	} else if (qp->qp_serv_type == HERMON_QP_RC) {
11879e39c5baSBill Taylor 		rc = &info_p->qp_transport.rc;
11889e39c5baSBill Taylor 
11899e39c5baSBill Taylor 		/*
11909e39c5baSBill Taylor 		 * If we are attempting to modify the port for this QP, then
11919e39c5baSBill Taylor 		 * check for valid port number and fill it in.  Also set the
11929e39c5baSBill Taylor 		 * appropriate flag in the "opmask" parameter.
11939e39c5baSBill Taylor 		 */
11949e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_PORT) {
11959e39c5baSBill Taylor 			portnum = rc->rc_path.cep_hca_port_num;
11969e39c5baSBill Taylor 			if (hermon_portnum_is_valid(state, portnum)) {
11979e39c5baSBill Taylor 				qp->qp_portnum = portnum - 1;
11989e39c5baSBill Taylor 				qpc->pri_addr_path.sched_q =
11999e39c5baSBill Taylor 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
12009e39c5baSBill Taylor 				    0, qp->qp_is_special);
12019e39c5baSBill Taylor 			} else {
12029e39c5baSBill Taylor 				return (IBT_HCA_PORT_INVALID);
12039e39c5baSBill Taylor 			}
12049e39c5baSBill Taylor 
12059e39c5baSBill Taylor 		}
12069e39c5baSBill Taylor 
12079e39c5baSBill Taylor 		/*
12089e39c5baSBill Taylor 		 * If we are attempting to modify the PKey index for this QP,
12099e39c5baSBill Taylor 		 * then check for valid PKey index and fill it in.  Also set
12109e39c5baSBill Taylor 		 * the appropriate flag in the "opmask" parameter.
12119e39c5baSBill Taylor 		 */
12129e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_PKEY_IX) {
12139e39c5baSBill Taylor 			pkeyindx = rc->rc_path.cep_pkey_ix;
12149e39c5baSBill Taylor 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
12159e39c5baSBill Taylor 				qpc->pri_addr_path.pkey_indx = pkeyindx;
12169e39c5baSBill Taylor 				opmask |= HERMON_CMD_OP_PKEYINDX;
12179e39c5baSBill Taylor 			} else {
12189e39c5baSBill Taylor 				return (IBT_PKEY_IX_ILLEGAL);
12199e39c5baSBill Taylor 			}
12209e39c5baSBill Taylor 		}
12219e39c5baSBill Taylor 
12229e39c5baSBill Taylor 		/*
12239e39c5baSBill Taylor 		 * Check if any of the flags indicate a change in the RDMA
12249e39c5baSBill Taylor 		 * (recv) enable/disable flags and set the appropriate flag in
12259e39c5baSBill Taylor 		 * the "opmask" parameter
12269e39c5baSBill Taylor 		 */
12279e39c5baSBill Taylor 		opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
12289e39c5baSBill Taylor 
12299e39c5baSBill Taylor 	} else if (qp->qp_serv_type == HERMON_QP_UC) {
12309e39c5baSBill Taylor 		uc = &info_p->qp_transport.uc;
12319e39c5baSBill Taylor 
12329e39c5baSBill Taylor 		/*
12339e39c5baSBill Taylor 		 * If we are attempting to modify the port for this QP, then
12349e39c5baSBill Taylor 		 * check for valid port number and fill it in.  Also set the
12359e39c5baSBill Taylor 		 * appropriate flag in the "opmask" parameter.
12369e39c5baSBill Taylor 		 */
12379e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_PORT) {
12389e39c5baSBill Taylor 			portnum = uc->uc_path.cep_hca_port_num;
12399e39c5baSBill Taylor 			if (hermon_portnum_is_valid(state, portnum)) {
12409e39c5baSBill Taylor 				qp->qp_portnum = portnum - 1;
12419e39c5baSBill Taylor 				qpc->pri_addr_path.sched_q =
12429e39c5baSBill Taylor 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
12439e39c5baSBill Taylor 				    0, qp->qp_is_special);
12449e39c5baSBill Taylor 			} else {
12459e39c5baSBill Taylor 				return (IBT_HCA_PORT_INVALID);
12469e39c5baSBill Taylor 			}
12479e39c5baSBill Taylor 		/* port# cannot be set in this transition - defer to init2rtr */
12489e39c5baSBill Taylor 		}
12499e39c5baSBill Taylor 
12509e39c5baSBill Taylor 		/*
12519e39c5baSBill Taylor 		 * If we are attempting to modify the PKey index for this QP,
12529e39c5baSBill Taylor 		 * then check for valid PKey index and fill it in.  Also set
12539e39c5baSBill Taylor 		 * the appropriate flag in the "opmask" parameter.
12549e39c5baSBill Taylor 		 */
12559e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_PKEY_IX) {
12569e39c5baSBill Taylor 			pkeyindx = uc->uc_path.cep_pkey_ix;
12579e39c5baSBill Taylor 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
12589e39c5baSBill Taylor 				qpc->pri_addr_path.pkey_indx = pkeyindx;
12599e39c5baSBill Taylor 				opmask |= HERMON_CMD_OP_PKEYINDX;
12609e39c5baSBill Taylor 			} else {
12619e39c5baSBill Taylor 				return (IBT_PKEY_IX_ILLEGAL);
12629e39c5baSBill Taylor 			}
12639e39c5baSBill Taylor 		}
12649e39c5baSBill Taylor 
12659e39c5baSBill Taylor 		/*
12669e39c5baSBill Taylor 		 * Check if any of the flags indicate a change in the RDMA
12679e39c5baSBill Taylor 		 * Write (recv) enable/disable and set the appropriate flag
12689e39c5baSBill Taylor 		 * in the "opmask" parameter. Note: RDMA Read and Atomic are
12699e39c5baSBill Taylor 		 * not valid for UC transport.
12709e39c5baSBill Taylor 		 */
12719e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_RDMA_W) {
12729e39c5baSBill Taylor 			qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
12739e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_RWE;
12749e39c5baSBill Taylor 		}
12759e39c5baSBill Taylor 	} else {
12769e39c5baSBill Taylor 		/*
12779e39c5baSBill Taylor 		 * Invalid QP transport type. If we got here then it's a
12789e39c5baSBill Taylor 		 * warning of a probably serious problem.  So print a message
12799e39c5baSBill Taylor 		 * and return failure
12809e39c5baSBill Taylor 		 */
12819e39c5baSBill Taylor 		HERMON_WARNING(state, "unknown QP transport type in init2init");
12829e39c5baSBill Taylor 		return (ibc_get_ci_failure(0));
12839e39c5baSBill Taylor 	}
12849e39c5baSBill Taylor 
12859e39c5baSBill Taylor 	/*
12869e39c5baSBill Taylor 	 * Post the INIT2INIT_QP command to the Hermon firmware
12879e39c5baSBill Taylor 	 *
12889e39c5baSBill Taylor 	 * We do a HERMON_NOSLEEP here because we are still holding the
12899e39c5baSBill Taylor 	 * "qp_lock".  If we got raised to interrupt level by priority
12909e39c5baSBill Taylor 	 * inversion, we do not want to block in this routine waiting for
12919e39c5baSBill Taylor 	 * success.
12929e39c5baSBill Taylor 	 */
12939e39c5baSBill Taylor 	status = hermon_cmn_qp_cmd_post(state, INIT2INIT_QP, qpc, qp->qp_qpnum,
12949e39c5baSBill Taylor 	    opmask, HERMON_CMD_NOSLEEP_SPIN);
12959e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
12969e39c5baSBill Taylor 		if (status != HERMON_CMD_BAD_QP_STATE) {
12979e39c5baSBill Taylor 			cmn_err(CE_NOTE, "hermon%d: INIT2INIT_QP command "
12989e39c5baSBill Taylor 			    "failed: %08x\n", state->hs_instance, status);
12999e39c5baSBill Taylor 			if (status == HERMON_CMD_INVALID_STATUS) {
13009e39c5baSBill Taylor 				hermon_fm_ereport(state, HCA_SYS_ERR,
13019e39c5baSBill Taylor 				    HCA_ERR_SRV_LOST);
13029e39c5baSBill Taylor 			}
13039e39c5baSBill Taylor 			return (ibc_get_ci_failure(0));
13049e39c5baSBill Taylor 		} else {
13059e39c5baSBill Taylor 			return (IBT_QP_STATE_INVALID);
13069e39c5baSBill Taylor 		}
13079e39c5baSBill Taylor 	}
13089e39c5baSBill Taylor 
13099e39c5baSBill Taylor 	return (DDI_SUCCESS);
13109e39c5baSBill Taylor }
13119e39c5baSBill Taylor 
13129e39c5baSBill Taylor 
13139e39c5baSBill Taylor /*
13149e39c5baSBill Taylor  * hermon_qp_init2rtr()
13159e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
13169e39c5baSBill Taylor  */
13179e39c5baSBill Taylor static int
hermon_qp_init2rtr(hermon_state_t * state,hermon_qphdl_t qp,ibt_cep_modify_flags_t flags,ibt_qp_info_t * info_p)13189e39c5baSBill Taylor hermon_qp_init2rtr(hermon_state_t *state, hermon_qphdl_t qp,
13199e39c5baSBill Taylor     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
13209e39c5baSBill Taylor {
13219e39c5baSBill Taylor 	hermon_hw_qpc_t		*qpc;
13229e39c5baSBill Taylor 	ibt_qp_rc_attr_t	*rc;
13239e39c5baSBill Taylor 	ibt_qp_ud_attr_t	*ud;
13249e39c5baSBill Taylor 	ibt_qp_uc_attr_t	*uc;
13259e39c5baSBill Taylor 	hermon_hw_addr_path_t	*qpc_path;
13269e39c5baSBill Taylor 	ibt_adds_vect_t		*adds_vect;
13279e39c5baSBill Taylor 	uint_t			portnum, pkeyindx, rra_max;
13289e39c5baSBill Taylor 	uint_t			mtu;
13299e39c5baSBill Taylor 	uint32_t		opmask = 0;
13309e39c5baSBill Taylor 	int			status;
13319e39c5baSBill Taylor 
13329e39c5baSBill Taylor 	ASSERT(MUTEX_HELD(&qp->qp_lock));
13339e39c5baSBill Taylor 
13349e39c5baSBill Taylor 	/*
13359e39c5baSBill Taylor 	 * Grab the temporary QPC entry from QP software state
13369e39c5baSBill Taylor 	 */
13379e39c5baSBill Taylor 	qpc = &qp->qpc;
13389e39c5baSBill Taylor 
13399e39c5baSBill Taylor 	/*
13409e39c5baSBill Taylor 	 * Since there are few common fields to be filled in for this command,
13419e39c5baSBill Taylor 	 * we just do the QPC fields that are specific to transport type.
13429e39c5baSBill Taylor 	 */
134317a2b317SBill Taylor 	if (qp->qp_type == IBT_UD_RQP) {
13449e39c5baSBill Taylor 		ud = &info_p->qp_transport.ud;
13459e39c5baSBill Taylor 
13469e39c5baSBill Taylor 		/*
13479e39c5baSBill Taylor 		 * If this UD QP is also a "special QP" (QP0 or QP1), then
13489e39c5baSBill Taylor 		 * the MTU is 256 bytes.  However, Hermon checks the QPC
13499e39c5baSBill Taylor 		 * MTU settings rather than just the port MTU, so we will
13509e39c5baSBill Taylor 		 * set it to maximum size for all UD.
13519e39c5baSBill Taylor 		 */
13529e39c5baSBill Taylor 		qpc->mtu = HERMON_MAX_MTU;
13539e39c5baSBill Taylor 		if (qp->qp_uses_lso)
13549e39c5baSBill Taylor 			qpc->msg_max = state->hs_devlim.log_max_gso_sz;
13559e39c5baSBill Taylor 		else
13569e39c5baSBill Taylor 			qpc->msg_max = HERMON_QP_LOG_MAX_MSGSZ;
13579e39c5baSBill Taylor 
13589e39c5baSBill Taylor 		/*
13599e39c5baSBill Taylor 		 * Save away the MTU value.  This is used in future sqd2sqd
13609e39c5baSBill Taylor 		 * transitions, as the MTU must remain the same in future
13619e39c5baSBill Taylor 		 * changes.
13629e39c5baSBill Taylor 		 */
13639e39c5baSBill Taylor 		qp->qp_save_mtu = qpc->mtu;
13649e39c5baSBill Taylor 
13659e39c5baSBill Taylor 		/*
13669e39c5baSBill Taylor 		 * If we are attempting to modify the PKey index for this QP,
13679e39c5baSBill Taylor 		 * then check for valid PKey index and fill it in.  Also set
13689e39c5baSBill Taylor 		 * the appropriate flag in the "opmask" parameter.
13699e39c5baSBill Taylor 		 */
13709e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_PKEY_IX) {
13719e39c5baSBill Taylor 			pkeyindx = ud->ud_pkey_ix;
13729e39c5baSBill Taylor 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
13739e39c5baSBill Taylor 				qpc->pri_addr_path.pkey_indx = pkeyindx;
13749e39c5baSBill Taylor 				opmask |= HERMON_CMD_OP_PKEYINDX;
13759e39c5baSBill Taylor 				qp->qp_pkeyindx = pkeyindx;
13769e39c5baSBill Taylor 			} else {
13779e39c5baSBill Taylor 				return (IBT_PKEY_IX_ILLEGAL);
13789e39c5baSBill Taylor 			}
13799e39c5baSBill Taylor 		}
13809e39c5baSBill Taylor 
13819e39c5baSBill Taylor 		/*
13829e39c5baSBill Taylor 		 * If we are attempting to modify the QKey for this QP, then
13839e39c5baSBill Taylor 		 * fill it in and set the appropriate flag in the "opmask"
13849e39c5baSBill Taylor 		 * parameter.
13859e39c5baSBill Taylor 		 */
13869e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_QKEY) {
13879e39c5baSBill Taylor 			qpc->qkey = ud->ud_qkey;
13889e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_QKEY;
13899e39c5baSBill Taylor 		}
13909e39c5baSBill Taylor 
13919e39c5baSBill Taylor 	} else if (qp->qp_serv_type == HERMON_QP_RC) {
13929e39c5baSBill Taylor 		rc = &info_p->qp_transport.rc;
13939e39c5baSBill Taylor 		qpc_path = &qpc->pri_addr_path;
13949e39c5baSBill Taylor 		adds_vect = &rc->rc_path.cep_adds_vect;
13959e39c5baSBill Taylor 
13969e39c5baSBill Taylor 		/*
13979e39c5baSBill Taylor 		 * Set the common primary address path fields
13989e39c5baSBill Taylor 		 */
13999e39c5baSBill Taylor 		status = hermon_set_addr_path(state, adds_vect, qpc_path,
14009e39c5baSBill Taylor 		    HERMON_ADDRPATH_QP);
14019e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
14029e39c5baSBill Taylor 			return (status);
14039e39c5baSBill Taylor 		}
14049e39c5baSBill Taylor 		/* set the primary port number/sched_q */
14059e39c5baSBill Taylor 		portnum = qp->qp_portnum + 1;
14069e39c5baSBill Taylor 		if (hermon_portnum_is_valid(state, portnum)) {
14079e39c5baSBill Taylor 			qpc->pri_addr_path.sched_q  =
14089e39c5baSBill Taylor 			    HERMON_QP_SCHEDQ_GET(qp->qp_portnum,
14099e39c5baSBill Taylor 			    adds_vect->av_srvl, qp->qp_is_special);
14109e39c5baSBill Taylor 		} else {
14119e39c5baSBill Taylor 			return (IBT_HCA_PORT_INVALID);
14129e39c5baSBill Taylor 		}
14139e39c5baSBill Taylor 
14149e39c5baSBill Taylor 		/*
14159e39c5baSBill Taylor 		 * The following values are apparently "required" here (as
14169e39c5baSBill Taylor 		 * they are part of the IBA-defined "Remote Node Address
14179e39c5baSBill Taylor 		 * Vector").  However, they are also going to be "required"
14189e39c5baSBill Taylor 		 * later - at RTR2RTS_QP time.  Not sure why.  But we set
14199e39c5baSBill Taylor 		 * them here anyway.
14209e39c5baSBill Taylor 		 */
14219e39c5baSBill Taylor 		qpc->rnr_retry		= rc->rc_rnr_retry_cnt;
14229e39c5baSBill Taylor 		qpc->retry_cnt		= rc->rc_retry_cnt;
14239e39c5baSBill Taylor 		qpc_path->ack_timeout	= rc->rc_path.cep_timeout;
14249e39c5baSBill Taylor 
14259e39c5baSBill Taylor 		/*
14269e39c5baSBill Taylor 		 * Setup the destination QP, recv PSN, MTU, max msg size,etc.
14279e39c5baSBill Taylor 		 * Note max message size is defined to be the maximum IB
14289e39c5baSBill Taylor 		 * allowed message size (which is 2^31 bytes).  Also max
14299e39c5baSBill Taylor 		 * MTU is defined by HCA port properties.
14309e39c5baSBill Taylor 		 */
14319e39c5baSBill Taylor 		qpc->rem_qpn	  = rc->rc_dst_qpn;
14329e39c5baSBill Taylor 		qpc->next_rcv_psn = rc->rc_rq_psn;
14339e39c5baSBill Taylor 		qpc->msg_max	  = HERMON_QP_LOG_MAX_MSGSZ;
14349e39c5baSBill Taylor 		qpc->ric	  = 0;
14359e39c5baSBill Taylor 		mtu		  = rc->rc_path_mtu;
14369e39c5baSBill Taylor 
14379e39c5baSBill Taylor 		if (hermon_qp_validate_mtu(state, mtu) != DDI_SUCCESS) {
14389e39c5baSBill Taylor 			return (IBT_HCA_PORT_MTU_EXCEEDED);
14399e39c5baSBill Taylor 		}
14409e39c5baSBill Taylor 		qpc->mtu = mtu;
14419e39c5baSBill Taylor 
14429e39c5baSBill Taylor 		/*
14439e39c5baSBill Taylor 		 * Save away the MTU value.  This is used in future sqd2sqd
14449e39c5baSBill Taylor 		 * transitions, as the MTU must remain the same in future
14459e39c5baSBill Taylor 		 * changes.
14469e39c5baSBill Taylor 		 */
14479e39c5baSBill Taylor 		qp->qp_save_mtu = qpc->mtu;
14489e39c5baSBill Taylor 
14499e39c5baSBill Taylor 		/*
14509e39c5baSBill Taylor 		 * Though it is a "required" parameter, "min_rnr_nak" is
14519e39c5baSBill Taylor 		 * optionally specifiable in Hermon.  So we force the
14529e39c5baSBill Taylor 		 * optional flag here.
14539e39c5baSBill Taylor 		 */
14549e39c5baSBill Taylor 		qpc->min_rnr_nak = rc->rc_min_rnr_nak;
14559e39c5baSBill Taylor 		opmask |= HERMON_CMD_OP_MINRNRNAK;
14569e39c5baSBill Taylor 
14579e39c5baSBill Taylor 		/*
14589e39c5baSBill Taylor 		 * Check that the number of specified "incoming RDMA resources"
14599e39c5baSBill Taylor 		 * is valid.  And if it is, then setup the "rra_max
14609e39c5baSBill Taylor 		 */
14619e39c5baSBill Taylor 		if (hermon_qp_validate_resp_rsrc(state, rc, &rra_max) !=
14629e39c5baSBill Taylor 		    DDI_SUCCESS) {
14639e39c5baSBill Taylor 			return (IBT_INVALID_PARAM);
14649e39c5baSBill Taylor 		}
14659e39c5baSBill Taylor 		qpc->rra_max = rra_max;
14669e39c5baSBill Taylor 
14679e39c5baSBill Taylor 		/* don't need to set up ra_buff_indx, implicit for hermon */
14689e39c5baSBill Taylor 
14699e39c5baSBill Taylor 		/*
14709e39c5baSBill Taylor 		 * If we are attempting to modify the PKey index for this QP,
14719e39c5baSBill Taylor 		 * then check for valid PKey index and fill it in.  Also set
14729e39c5baSBill Taylor 		 * the appropriate flag in the "opmask" parameter.
14739e39c5baSBill Taylor 		 */
14749e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_PKEY_IX) {
14759e39c5baSBill Taylor 			pkeyindx = rc->rc_path.cep_pkey_ix;
14769e39c5baSBill Taylor 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
14779e39c5baSBill Taylor 				qpc->pri_addr_path.pkey_indx = pkeyindx;
14789e39c5baSBill Taylor 				opmask |= HERMON_CMD_OP_PKEYINDX;
14799e39c5baSBill Taylor 			} else {
14809e39c5baSBill Taylor 				return (IBT_PKEY_IX_ILLEGAL);
14819e39c5baSBill Taylor 			}
14829e39c5baSBill Taylor 		}
14839e39c5baSBill Taylor 
14849e39c5baSBill Taylor 		/*
14859e39c5baSBill Taylor 		 * Check if any of the flags indicate a change in the RDMA
14869e39c5baSBill Taylor 		 * (recv) enable/disable flags and set the appropriate flag in
14879e39c5baSBill Taylor 		 * the "opmask" parameter
14889e39c5baSBill Taylor 		 */
14899e39c5baSBill Taylor 		opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
14909e39c5baSBill Taylor 
14919e39c5baSBill Taylor 		/*
14929e39c5baSBill Taylor 		 * Check for optional alternate path and fill in the
14939e39c5baSBill Taylor 		 * appropriate QPC fields if one is specified
14949e39c5baSBill Taylor 		 */
14959e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_ALT_PATH) {
14969e39c5baSBill Taylor 			qpc_path = &qpc->alt_addr_path;
14979e39c5baSBill Taylor 			adds_vect = &rc->rc_alt_path.cep_adds_vect;
14989e39c5baSBill Taylor 
14999e39c5baSBill Taylor 			/* Set the common alternate address path fields */
15009e39c5baSBill Taylor 			status = hermon_set_addr_path(state, adds_vect,
15019e39c5baSBill Taylor 			    qpc_path, HERMON_ADDRPATH_QP);
15029e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
15039e39c5baSBill Taylor 				return (status);
15049e39c5baSBill Taylor 			}
15059e39c5baSBill Taylor 			qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
15069e39c5baSBill Taylor 
15079e39c5baSBill Taylor 
15089e39c5baSBill Taylor 			/*
15099e39c5baSBill Taylor 			 * Check for valid alternate path port number and fill
15109e39c5baSBill Taylor 			 * it in
15119e39c5baSBill Taylor 			 */
15129e39c5baSBill Taylor 			portnum = rc->rc_alt_path.cep_hca_port_num;
15139e39c5baSBill Taylor 			if (hermon_portnum_is_valid(state, portnum)) {
15149e39c5baSBill Taylor 				qp->qp_portnum_alt = portnum - 1;
15159e39c5baSBill Taylor 				qpc->alt_addr_path.sched_q =
15169e39c5baSBill Taylor 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
15179e39c5baSBill Taylor 				    adds_vect->av_srvl, qp->qp_is_special);
15189e39c5baSBill Taylor 			} else {
15199e39c5baSBill Taylor 				return (IBT_HCA_PORT_INVALID);
15209e39c5baSBill Taylor 			}
15219e39c5baSBill Taylor 			/*
15229e39c5baSBill Taylor 			 * Check for valid alternate path PKey index and fill
15239e39c5baSBill Taylor 			 * it in
15249e39c5baSBill Taylor 			 */
15259e39c5baSBill Taylor 			pkeyindx = rc->rc_alt_path.cep_pkey_ix;
15269e39c5baSBill Taylor 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
15279e39c5baSBill Taylor 				qpc->alt_addr_path.pkey_indx = pkeyindx;
15289e39c5baSBill Taylor 			} else {
15299e39c5baSBill Taylor 				return (IBT_PKEY_IX_ILLEGAL);
15309e39c5baSBill Taylor 			}
15319e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_ALT_PATH;
15329e39c5baSBill Taylor 		}
15339e39c5baSBill Taylor 
15349e39c5baSBill Taylor 	} else if (qp->qp_serv_type == HERMON_QP_UC) {
15359e39c5baSBill Taylor 		uc = &info_p->qp_transport.uc;
15369e39c5baSBill Taylor 		qpc_path = &qpc->pri_addr_path;
15379e39c5baSBill Taylor 		adds_vect = &uc->uc_path.cep_adds_vect;
15389e39c5baSBill Taylor 
15399e39c5baSBill Taylor 		/*
15409e39c5baSBill Taylor 		 * Set the common primary address path fields
15419e39c5baSBill Taylor 		 */
15429e39c5baSBill Taylor 		status = hermon_set_addr_path(state, adds_vect, qpc_path,
15439e39c5baSBill Taylor 		    HERMON_ADDRPATH_QP);
15449e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
15459e39c5baSBill Taylor 			return (status);
15469e39c5baSBill Taylor 		}
15479e39c5baSBill Taylor 
15489e39c5baSBill Taylor 		/* set the primary port num/schedq */
15499e39c5baSBill Taylor 		portnum = qp->qp_portnum + 1;
15509e39c5baSBill Taylor 		if (hermon_portnum_is_valid(state, portnum)) {
15519e39c5baSBill Taylor 			qpc->pri_addr_path.sched_q  =
15529e39c5baSBill Taylor 			    HERMON_QP_SCHEDQ_GET(qp->qp_portnum,
15539e39c5baSBill Taylor 			    adds_vect->av_srvl, qp->qp_is_special);
15549e39c5baSBill Taylor 		} else {
15559e39c5baSBill Taylor 			return (IBT_HCA_PORT_INVALID);
15569e39c5baSBill Taylor 		}
15579e39c5baSBill Taylor 
15589e39c5baSBill Taylor 		/*
15599e39c5baSBill Taylor 		 * Setup the destination QP, recv PSN, MTU, max msg size,etc.
15609e39c5baSBill Taylor 		 * Note max message size is defined to be the maximum IB
15619e39c5baSBill Taylor 		 * allowed message size (which is 2^31 bytes).  Also max
15629e39c5baSBill Taylor 		 * MTU is defined by HCA port properties.
15639e39c5baSBill Taylor 		 */
15649e39c5baSBill Taylor 		qpc->rem_qpn	  = uc->uc_dst_qpn;
15659e39c5baSBill Taylor 		qpc->next_rcv_psn = uc->uc_rq_psn;
15669e39c5baSBill Taylor 		qpc->msg_max	  = HERMON_QP_LOG_MAX_MSGSZ;
15679e39c5baSBill Taylor 		mtu = uc->uc_path_mtu;
15689e39c5baSBill Taylor 		if (hermon_qp_validate_mtu(state, mtu) != DDI_SUCCESS) {
15699e39c5baSBill Taylor 			return (IBT_HCA_PORT_MTU_EXCEEDED);
15709e39c5baSBill Taylor 		}
15719e39c5baSBill Taylor 		qpc->mtu = mtu;
15729e39c5baSBill Taylor 
15739e39c5baSBill Taylor 		/*
15749e39c5baSBill Taylor 		 * Save away the MTU value.  This is used in future sqd2sqd
15759e39c5baSBill Taylor 		 * transitions, as the MTU must remain the same in future
15769e39c5baSBill Taylor 		 * changes.
15779e39c5baSBill Taylor 		 */
15789e39c5baSBill Taylor 		qp->qp_save_mtu = qpc->mtu;
15799e39c5baSBill Taylor 
15809e39c5baSBill Taylor 		/*
15819e39c5baSBill Taylor 		 * If we are attempting to modify the PKey index for this QP,
15829e39c5baSBill Taylor 		 * then check for valid PKey index and fill it in.  Also set
15839e39c5baSBill Taylor 		 * the appropriate flag in the "opmask" parameter.
15849e39c5baSBill Taylor 		 */
15859e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_PKEY_IX) {
15869e39c5baSBill Taylor 			pkeyindx = uc->uc_path.cep_pkey_ix;
15879e39c5baSBill Taylor 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
15889e39c5baSBill Taylor 				qpc->pri_addr_path.pkey_indx = pkeyindx;
15899e39c5baSBill Taylor 				opmask |= HERMON_CMD_OP_PKEYINDX;
15909e39c5baSBill Taylor 			} else {
15919e39c5baSBill Taylor 				return (IBT_PKEY_IX_ILLEGAL);
15929e39c5baSBill Taylor 			}
15939e39c5baSBill Taylor 		}
15949e39c5baSBill Taylor 
15959e39c5baSBill Taylor 		/*
15969e39c5baSBill Taylor 		 * Check if any of the flags indicate a change in the RDMA
15979e39c5baSBill Taylor 		 * Write (recv) enable/disable and set the appropriate flag
15989e39c5baSBill Taylor 		 * in the "opmask" parameter. Note: RDMA Read and Atomic are
15999e39c5baSBill Taylor 		 * not valid for UC transport.
16009e39c5baSBill Taylor 		 */
16019e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_RDMA_W) {
16029e39c5baSBill Taylor 			qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
16039e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_RWE;
16049e39c5baSBill Taylor 		}
16059e39c5baSBill Taylor 
16069e39c5baSBill Taylor 		/*
16079e39c5baSBill Taylor 		 * Check for optional alternate path and fill in the
16089e39c5baSBill Taylor 		 * appropriate QPC fields if one is specified
16099e39c5baSBill Taylor 		 */
16109e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_ALT_PATH) {
16119e39c5baSBill Taylor 			qpc_path = &qpc->alt_addr_path;
16129e39c5baSBill Taylor 			adds_vect = &uc->uc_alt_path.cep_adds_vect;
16139e39c5baSBill Taylor 
16149e39c5baSBill Taylor 			/* Set the common alternate address path fields */
16159e39c5baSBill Taylor 			status = hermon_set_addr_path(state, adds_vect,
16169e39c5baSBill Taylor 			    qpc_path, HERMON_ADDRPATH_QP);
16179e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
16189e39c5baSBill Taylor 				return (status);
16199e39c5baSBill Taylor 			}
16209e39c5baSBill Taylor 
16219e39c5baSBill Taylor 			qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
16229e39c5baSBill Taylor 
16239e39c5baSBill Taylor 			/*
16249e39c5baSBill Taylor 			 * Check for valid alternate path port number and fill
16259e39c5baSBill Taylor 			 * it in
16269e39c5baSBill Taylor 			 */
16279e39c5baSBill Taylor 			portnum = uc->uc_alt_path.cep_hca_port_num;
16289e39c5baSBill Taylor 			if (hermon_portnum_is_valid(state, portnum)) {
16299e39c5baSBill Taylor 				qp->qp_portnum_alt = portnum - 1;
16309e39c5baSBill Taylor 				qpc->alt_addr_path.sched_q =
16319e39c5baSBill Taylor 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
16329e39c5baSBill Taylor 				    adds_vect->av_srvl, qp->qp_is_special);
16339e39c5baSBill Taylor 			} else {
16349e39c5baSBill Taylor 				return (IBT_HCA_PORT_INVALID);
16359e39c5baSBill Taylor 			}
16369e39c5baSBill Taylor 
16379e39c5baSBill Taylor 			/*
16389e39c5baSBill Taylor 			 * Check for valid alternate path PKey index and fill
16399e39c5baSBill Taylor 			 * it in
16409e39c5baSBill Taylor 			 */
16419e39c5baSBill Taylor 			pkeyindx = uc->uc_alt_path.cep_pkey_ix;
16429e39c5baSBill Taylor 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
16439e39c5baSBill Taylor 				qpc->alt_addr_path.pkey_indx = pkeyindx;
16449e39c5baSBill Taylor 			} else {
16459e39c5baSBill Taylor 				return (IBT_PKEY_IX_ILLEGAL);
16469e39c5baSBill Taylor 			}
16479e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_ALT_PATH;
16489e39c5baSBill Taylor 		}
16499e39c5baSBill Taylor 	} else {
16509e39c5baSBill Taylor 		/*
16519e39c5baSBill Taylor 		 * Invalid QP transport type. If we got here then it's a
16529e39c5baSBill Taylor 		 * warning of a probably serious problem.  So print a message
16539e39c5baSBill Taylor 		 * and return failure
16549e39c5baSBill Taylor 		 */
16559e39c5baSBill Taylor 		HERMON_WARNING(state, "unknown QP transport type in init2rtr");
16569e39c5baSBill Taylor 		return (ibc_get_ci_failure(0));
16579e39c5baSBill Taylor 	}
16589e39c5baSBill Taylor 
16599e39c5baSBill Taylor 	/*
16609e39c5baSBill Taylor 	 * Post the INIT2RTR_QP command to the Hermon firmware
16619e39c5baSBill Taylor 	 *
16629e39c5baSBill Taylor 	 * We do a HERMON_NOSLEEP here because we are still holding the
16639e39c5baSBill Taylor 	 * "qp_lock".  If we got raised to interrupt level by priority
16649e39c5baSBill Taylor 	 * inversion, we do not want to block in this routine waiting for
16659e39c5baSBill Taylor 	 * success.
16669e39c5baSBill Taylor 	 */
16679e39c5baSBill Taylor 	status = hermon_cmn_qp_cmd_post(state, INIT2RTR_QP, qpc, qp->qp_qpnum,
16689e39c5baSBill Taylor 	    opmask, HERMON_CMD_NOSLEEP_SPIN);
16699e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
16709e39c5baSBill Taylor 		if (status != HERMON_CMD_BAD_QP_STATE) {
16719e39c5baSBill Taylor 			cmn_err(CE_NOTE, "hermon%d: INIT2RTR_QP command "
16729e39c5baSBill Taylor 			    "failed: %08x\n", state->hs_instance, status);
16739e39c5baSBill Taylor 			if (status == HERMON_CMD_INVALID_STATUS) {
16749e39c5baSBill Taylor 				hermon_fm_ereport(state, HCA_SYS_ERR,
16759e39c5baSBill Taylor 				    HCA_ERR_SRV_LOST);
16769e39c5baSBill Taylor 			}
16779e39c5baSBill Taylor 			return (ibc_get_ci_failure(0));
16789e39c5baSBill Taylor 		} else {
16799e39c5baSBill Taylor 			return (IBT_QP_STATE_INVALID);
16809e39c5baSBill Taylor 		}
16819e39c5baSBill Taylor 	}
16829e39c5baSBill Taylor 
16839e39c5baSBill Taylor 	return (DDI_SUCCESS);
16849e39c5baSBill Taylor }
16859e39c5baSBill Taylor 
16869e39c5baSBill Taylor 
16879e39c5baSBill Taylor /*
16889e39c5baSBill Taylor  * hermon_qp_rtr2rts()
16899e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
16909e39c5baSBill Taylor  */
16919e39c5baSBill Taylor static int
hermon_qp_rtr2rts(hermon_state_t * state,hermon_qphdl_t qp,ibt_cep_modify_flags_t flags,ibt_qp_info_t * info_p)16929e39c5baSBill Taylor hermon_qp_rtr2rts(hermon_state_t *state, hermon_qphdl_t qp,
16939e39c5baSBill Taylor     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
16949e39c5baSBill Taylor {
16959e39c5baSBill Taylor 	hermon_hw_qpc_t		*qpc;
16969e39c5baSBill Taylor 	ibt_qp_rc_attr_t	*rc;
16979e39c5baSBill Taylor 	ibt_qp_ud_attr_t	*ud;
16989e39c5baSBill Taylor 	ibt_qp_uc_attr_t	*uc;
16999e39c5baSBill Taylor 	hermon_hw_addr_path_t	*qpc_path;
17009e39c5baSBill Taylor 	ibt_adds_vect_t		*adds_vect;
17019e39c5baSBill Taylor 	uint_t			portnum, pkeyindx, sra_max;
17029e39c5baSBill Taylor 	uint32_t		opmask = 0;
17039e39c5baSBill Taylor 	int			status;
17049e39c5baSBill Taylor 
17059e39c5baSBill Taylor 	ASSERT(MUTEX_HELD(&qp->qp_lock));
17069e39c5baSBill Taylor 
17079e39c5baSBill Taylor 	/*
17089e39c5baSBill Taylor 	 * Grab the temporary QPC entry from QP software state
17099e39c5baSBill Taylor 	 */
17109e39c5baSBill Taylor 	qpc = &qp->qpc;
17119e39c5baSBill Taylor 
17129e39c5baSBill Taylor 	/*
17139e39c5baSBill Taylor 	 * Now fill in the QPC fields which are specific to transport type
17149e39c5baSBill Taylor 	 */
171517a2b317SBill Taylor 	if (qp->qp_type == IBT_UD_RQP) {
17169e39c5baSBill Taylor 		ud = &info_p->qp_transport.ud;
17179e39c5baSBill Taylor 
17189e39c5baSBill Taylor 		/* Set the send PSN */
17199e39c5baSBill Taylor 		qpc->next_snd_psn = ud->ud_sq_psn;
17209e39c5baSBill Taylor 
17219e39c5baSBill Taylor 		/*
17229e39c5baSBill Taylor 		 * If we are attempting to modify the QKey for this QP, then
17239e39c5baSBill Taylor 		 * fill it in and set the appropriate flag in the "opmask"
17249e39c5baSBill Taylor 		 * parameter.
17259e39c5baSBill Taylor 		 */
17269e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_QKEY) {
17279e39c5baSBill Taylor 			qpc->qkey = ud->ud_qkey;
17289e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_QKEY;
17299e39c5baSBill Taylor 		}
17309e39c5baSBill Taylor 
17319e39c5baSBill Taylor 	} else if (qp->qp_serv_type == HERMON_QP_RC) {
17329e39c5baSBill Taylor 		rc = &info_p->qp_transport.rc;
17339e39c5baSBill Taylor 		qpc_path = &qpc->pri_addr_path;
17349e39c5baSBill Taylor 
17359e39c5baSBill Taylor 		/*
17369e39c5baSBill Taylor 		 * Setup the send PSN, ACK timeout, and retry counts
17379e39c5baSBill Taylor 		 */
17389e39c5baSBill Taylor 		qpc->next_snd_psn	= rc->rc_sq_psn;
17399e39c5baSBill Taylor 		qpc_path->ack_timeout	= rc->rc_path.cep_timeout;
17409e39c5baSBill Taylor 		qpc->rnr_retry		= rc->rc_rnr_retry_cnt;
17419e39c5baSBill Taylor 						/* in qpc now, not path */
17429e39c5baSBill Taylor 		qpc->retry_cnt		= rc->rc_retry_cnt;
17439e39c5baSBill Taylor 
17449e39c5baSBill Taylor 		/*
17459e39c5baSBill Taylor 		 * Set "ack_req_freq" based on the configuration variable
17469e39c5baSBill Taylor 		 */
17479e39c5baSBill Taylor 		qpc->ack_req_freq = state->hs_cfg_profile->cp_ackreq_freq;
17489e39c5baSBill Taylor 
17499e39c5baSBill Taylor 		/*
17509e39c5baSBill Taylor 		 * Check that the number of specified "outgoing RDMA resources"
17519e39c5baSBill Taylor 		 * is valid.  And if it is, then setup the "sra_max"
17529e39c5baSBill Taylor 		 * appropriately
17539e39c5baSBill Taylor 		 */
17549e39c5baSBill Taylor 		if (hermon_qp_validate_init_depth(state, rc, &sra_max) !=
17559e39c5baSBill Taylor 		    DDI_SUCCESS) {
17569e39c5baSBill Taylor 			return (IBT_INVALID_PARAM);
17579e39c5baSBill Taylor 		}
17589e39c5baSBill Taylor 		qpc->sra_max = sra_max;
17599e39c5baSBill Taylor 
17609e39c5baSBill Taylor 
17619e39c5baSBill Taylor 		/*
17629e39c5baSBill Taylor 		 * Check if any of the flags indicate a change in the RDMA
17639e39c5baSBill Taylor 		 * (recv) enable/disable flags and set the appropriate flag in
17649e39c5baSBill Taylor 		 * the "opmask" parameter
17659e39c5baSBill Taylor 		 */
17669e39c5baSBill Taylor 		opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
17679e39c5baSBill Taylor 
17689e39c5baSBill Taylor 		/*
17699e39c5baSBill Taylor 		 * If we are attempting to modify the path migration state for
17709e39c5baSBill Taylor 		 * this QP, then check for valid state and fill it in.  Also
17719e39c5baSBill Taylor 		 * set the appropriate flag in the "opmask" parameter.
17729e39c5baSBill Taylor 		 */
17739e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_MIG) {
17749e39c5baSBill Taylor 			if (rc->rc_mig_state == IBT_STATE_MIGRATED) {
17759e39c5baSBill Taylor 				qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
17769e39c5baSBill Taylor 			} else if (rc->rc_mig_state == IBT_STATE_REARMED) {
17779e39c5baSBill Taylor 				qpc->pm_state = HERMON_QP_PMSTATE_REARM;
17789e39c5baSBill Taylor 			} else {
17799e39c5baSBill Taylor 				return (IBT_QP_APM_STATE_INVALID);
17809e39c5baSBill Taylor 			}
17819e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_PM_STATE;
17829e39c5baSBill Taylor 		}
17839e39c5baSBill Taylor 
17849e39c5baSBill Taylor 		/*
17859e39c5baSBill Taylor 		 * If we are attempting to modify the "Minimum RNR NAK" value
17869e39c5baSBill Taylor 		 * for this QP, then fill it in and set the appropriate flag
17879e39c5baSBill Taylor 		 * in the "opmask" parameter.
17889e39c5baSBill Taylor 		 */
17899e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_MIN_RNR_NAK) {
17909e39c5baSBill Taylor 			qpc->min_rnr_nak = rc->rc_min_rnr_nak;
17919e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_MINRNRNAK;
17929e39c5baSBill Taylor 		}
17939e39c5baSBill Taylor 
17949e39c5baSBill Taylor 		/*
17959e39c5baSBill Taylor 		 * Check for optional alternate path and fill in the
17969e39c5baSBill Taylor 		 * appropriate QPC fields if one is specified
17979e39c5baSBill Taylor 		 */
17989e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_ALT_PATH) {
17999e39c5baSBill Taylor 			qpc_path = &qpc->alt_addr_path;
18009e39c5baSBill Taylor 			adds_vect = &rc->rc_alt_path.cep_adds_vect;
18019e39c5baSBill Taylor 
18029e39c5baSBill Taylor 			/* Set the common alternate address path fields */
18039e39c5baSBill Taylor 			status = hermon_set_addr_path(state, adds_vect,
18049e39c5baSBill Taylor 			    qpc_path, HERMON_ADDRPATH_QP);
18059e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
18069e39c5baSBill Taylor 				return (status);
18079e39c5baSBill Taylor 			}
18089e39c5baSBill Taylor 
18099e39c5baSBill Taylor 			qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
18109e39c5baSBill Taylor 
18119e39c5baSBill Taylor 			/*
18129e39c5baSBill Taylor 			 * Check for valid alternate path port number and fill
18139e39c5baSBill Taylor 			 * it in
18149e39c5baSBill Taylor 			 */
18159e39c5baSBill Taylor 			portnum = rc->rc_alt_path.cep_hca_port_num;
18169e39c5baSBill Taylor 			if (hermon_portnum_is_valid(state, portnum)) {
18179e39c5baSBill Taylor 				qp->qp_portnum_alt = portnum - 1;
18189e39c5baSBill Taylor 				qpc->alt_addr_path.sched_q =
18199e39c5baSBill Taylor 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
18209e39c5baSBill Taylor 				    adds_vect->av_srvl, qp->qp_is_special);
18219e39c5baSBill Taylor 			} else {
18229e39c5baSBill Taylor 				return (IBT_HCA_PORT_INVALID);
18239e39c5baSBill Taylor 			}
18249e39c5baSBill Taylor 
18259e39c5baSBill Taylor 			/*
18269e39c5baSBill Taylor 			 * Check for valid alternate path PKey index and fill
18279e39c5baSBill Taylor 			 * it in
18289e39c5baSBill Taylor 			 */
18299e39c5baSBill Taylor 			pkeyindx = rc->rc_alt_path.cep_pkey_ix;
18309e39c5baSBill Taylor 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
18319e39c5baSBill Taylor 				qpc->alt_addr_path.pkey_indx = pkeyindx;
18329e39c5baSBill Taylor 			} else {
18339e39c5baSBill Taylor 				return (IBT_PKEY_IX_ILLEGAL);
18349e39c5baSBill Taylor 			}
18359e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_ALT_PATH;
18369e39c5baSBill Taylor 		}
18379e39c5baSBill Taylor 
18389e39c5baSBill Taylor 	} else if (qp->qp_serv_type == HERMON_QP_UC) {
18399e39c5baSBill Taylor 		uc = &info_p->qp_transport.uc;
18409e39c5baSBill Taylor 
18419e39c5baSBill Taylor 		/* Set the send PSN */
18429e39c5baSBill Taylor 		qpc->next_snd_psn = uc->uc_sq_psn;
18439e39c5baSBill Taylor 
18449e39c5baSBill Taylor 		/*
18459e39c5baSBill Taylor 		 * Configure the QP to allow (sending of) all types of allowable
18469e39c5baSBill Taylor 		 * UC traffic (i.e. RDMA Write).
18479e39c5baSBill Taylor 		 */
18489e39c5baSBill Taylor 
18499e39c5baSBill Taylor 
18509e39c5baSBill Taylor 		/*
18519e39c5baSBill Taylor 		 * Check if any of the flags indicate a change in the RDMA
18529e39c5baSBill Taylor 		 * Write (recv) enable/disable and set the appropriate flag
18539e39c5baSBill Taylor 		 * in the "opmask" parameter. Note: RDMA Read and Atomic are
18549e39c5baSBill Taylor 		 * not valid for UC transport.
18559e39c5baSBill Taylor 		 */
18569e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_RDMA_W) {
18579e39c5baSBill Taylor 			qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
18589e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_RWE;
18599e39c5baSBill Taylor 		}
18609e39c5baSBill Taylor 
18619e39c5baSBill Taylor 		/*
18629e39c5baSBill Taylor 		 * If we are attempting to modify the path migration state for
18639e39c5baSBill Taylor 		 * this QP, then check for valid state and fill it in.  Also
18649e39c5baSBill Taylor 		 * set the appropriate flag in the "opmask" parameter.
18659e39c5baSBill Taylor 		 */
18669e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_MIG) {
18679e39c5baSBill Taylor 			if (uc->uc_mig_state == IBT_STATE_MIGRATED) {
18689e39c5baSBill Taylor 				qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
18699e39c5baSBill Taylor 			} else if (uc->uc_mig_state == IBT_STATE_REARMED) {
18709e39c5baSBill Taylor 				qpc->pm_state = HERMON_QP_PMSTATE_REARM;
18719e39c5baSBill Taylor 			} else {
18729e39c5baSBill Taylor 				return (IBT_QP_APM_STATE_INVALID);
18739e39c5baSBill Taylor 			}
18749e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_PM_STATE;
18759e39c5baSBill Taylor 		}
18769e39c5baSBill Taylor 
18779e39c5baSBill Taylor 		/*
18789e39c5baSBill Taylor 		 * Check for optional alternate path and fill in the
18799e39c5baSBill Taylor 		 * appropriate QPC fields if one is specified
18809e39c5baSBill Taylor 		 */
18819e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_ALT_PATH) {
18829e39c5baSBill Taylor 			qpc_path = &qpc->alt_addr_path;
18839e39c5baSBill Taylor 			adds_vect = &uc->uc_alt_path.cep_adds_vect;
18849e39c5baSBill Taylor 
18859e39c5baSBill Taylor 			/* Set the common alternate address path fields */
18869e39c5baSBill Taylor 			status = hermon_set_addr_path(state, adds_vect,
18879e39c5baSBill Taylor 			    qpc_path, HERMON_ADDRPATH_QP);
18889e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
18899e39c5baSBill Taylor 				return (status);
18909e39c5baSBill Taylor 			}
18919e39c5baSBill Taylor 			qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
18929e39c5baSBill Taylor 
18939e39c5baSBill Taylor 			/*
18949e39c5baSBill Taylor 			 * Check for valid alternate path port number and fill
18959e39c5baSBill Taylor 			 * it in
18969e39c5baSBill Taylor 			 */
18979e39c5baSBill Taylor 			portnum = uc->uc_alt_path.cep_hca_port_num;
18989e39c5baSBill Taylor 			if (hermon_portnum_is_valid(state, portnum)) {
18999e39c5baSBill Taylor 				qpc->alt_addr_path.sched_q =
19009e39c5baSBill Taylor 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
19019e39c5baSBill Taylor 				    adds_vect->av_srvl, qp->qp_is_special);
19029e39c5baSBill Taylor 			} else {
19039e39c5baSBill Taylor 				return (IBT_HCA_PORT_INVALID);
19049e39c5baSBill Taylor 			}
19059e39c5baSBill Taylor 
19069e39c5baSBill Taylor 			/*
19079e39c5baSBill Taylor 			 * Check for valid alternate path PKey index and fill
19089e39c5baSBill Taylor 			 * it in
19099e39c5baSBill Taylor 			 */
19109e39c5baSBill Taylor 			pkeyindx = uc->uc_alt_path.cep_pkey_ix;
19119e39c5baSBill Taylor 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
19129e39c5baSBill Taylor 				qpc->alt_addr_path.pkey_indx = pkeyindx;
19139e39c5baSBill Taylor 			} else {
19149e39c5baSBill Taylor 				return (IBT_PKEY_IX_ILLEGAL);
19159e39c5baSBill Taylor 			}
19169e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_ALT_PATH;
19179e39c5baSBill Taylor 		}
19189e39c5baSBill Taylor 	} else {
19199e39c5baSBill Taylor 		/*
19209e39c5baSBill Taylor 		 * Invalid QP transport type. If we got here then it's a
19219e39c5baSBill Taylor 		 * warning of a probably serious problem.  So print a message
19229e39c5baSBill Taylor 		 * and return failure
19239e39c5baSBill Taylor 		 */
19249e39c5baSBill Taylor 		HERMON_WARNING(state, "unknown QP transport type in rtr2rts");
19259e39c5baSBill Taylor 		return (ibc_get_ci_failure(0));
19269e39c5baSBill Taylor 	}
19279e39c5baSBill Taylor 
19289e39c5baSBill Taylor 	/*
19299e39c5baSBill Taylor 	 * Post the RTR2RTS_QP command to the Hermon firmware
19309e39c5baSBill Taylor 	 *
19319e39c5baSBill Taylor 	 * We do a HERMON_NOSLEEP here because we are still holding the
19329e39c5baSBill Taylor 	 * "qp_lock".  If we got raised to interrupt level by priority
19339e39c5baSBill Taylor 	 * inversion, we do not want to block in this routine waiting for
19349e39c5baSBill Taylor 	 * success.
19359e39c5baSBill Taylor 	 */
19369e39c5baSBill Taylor 	status = hermon_cmn_qp_cmd_post(state, RTR2RTS_QP, qpc, qp->qp_qpnum,
19379e39c5baSBill Taylor 	    opmask, HERMON_CMD_NOSLEEP_SPIN);
19389e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
19399e39c5baSBill Taylor 		if (status != HERMON_CMD_BAD_QP_STATE) {
19409e39c5baSBill Taylor 			cmn_err(CE_NOTE, "hermon%d: RTR2RTS_QP command failed: "
19419e39c5baSBill Taylor 			    "%08x\n", state->hs_instance, status);
19429e39c5baSBill Taylor 			if (status == HERMON_CMD_INVALID_STATUS) {
19439e39c5baSBill Taylor 				hermon_fm_ereport(state, HCA_SYS_ERR,
19449e39c5baSBill Taylor 				    HCA_ERR_SRV_LOST);
19459e39c5baSBill Taylor 			}
19469e39c5baSBill Taylor 			return (ibc_get_ci_failure(0));
19479e39c5baSBill Taylor 		} else {
19489e39c5baSBill Taylor 			return (IBT_QP_STATE_INVALID);
19499e39c5baSBill Taylor 		}
19509e39c5baSBill Taylor 	}
19519e39c5baSBill Taylor 
19529e39c5baSBill Taylor 	return (DDI_SUCCESS);
19539e39c5baSBill Taylor }
19549e39c5baSBill Taylor 
19559e39c5baSBill Taylor 
19569e39c5baSBill Taylor /*
19579e39c5baSBill Taylor  * hermon_qp_rts2rts()
19589e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
19599e39c5baSBill Taylor  */
19609e39c5baSBill Taylor static int
hermon_qp_rts2rts(hermon_state_t * state,hermon_qphdl_t qp,ibt_cep_modify_flags_t flags,ibt_qp_info_t * info_p)19619e39c5baSBill Taylor hermon_qp_rts2rts(hermon_state_t *state, hermon_qphdl_t qp,
19629e39c5baSBill Taylor     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
19639e39c5baSBill Taylor {
19649e39c5baSBill Taylor 	hermon_hw_qpc_t		*qpc;
19659e39c5baSBill Taylor 	ibt_qp_rc_attr_t	*rc;
19669e39c5baSBill Taylor 	ibt_qp_ud_attr_t	*ud;
19679e39c5baSBill Taylor 	ibt_qp_uc_attr_t	*uc;
19689e39c5baSBill Taylor 	hermon_hw_addr_path_t	*qpc_path;
19699e39c5baSBill Taylor 	ibt_adds_vect_t		*adds_vect;
19709e39c5baSBill Taylor 	uint_t			portnum, pkeyindx;
19719e39c5baSBill Taylor 	uint32_t		opmask = 0;
19729e39c5baSBill Taylor 	int			status;
19739e39c5baSBill Taylor 
19749e39c5baSBill Taylor 	ASSERT(MUTEX_HELD(&qp->qp_lock));
19759e39c5baSBill Taylor 
19769e39c5baSBill Taylor 	/*
19779e39c5baSBill Taylor 	 * Grab the temporary QPC entry from QP software state
19789e39c5baSBill Taylor 	 */
19799e39c5baSBill Taylor 
19809e39c5baSBill Taylor 	qpc = &qp->qpc;
19819e39c5baSBill Taylor 
19829e39c5baSBill Taylor 	/*
19839e39c5baSBill Taylor 	 * Since there are no common fields to be filled in for this command,
19849e39c5baSBill Taylor 	 * we begin with the QPC fields which are specific to transport type.
19859e39c5baSBill Taylor 	 */
198617a2b317SBill Taylor 	if (qp->qp_type == IBT_UD_RQP) {
19879e39c5baSBill Taylor 		ud = &info_p->qp_transport.ud;
19889e39c5baSBill Taylor 
19899e39c5baSBill Taylor 		/*
19909e39c5baSBill Taylor 		 * If we are attempting to modify the QKey for this QP, then
19919e39c5baSBill Taylor 		 * fill it in and set the appropriate flag in the "opmask"
19929e39c5baSBill Taylor 		 * parameter.
19939e39c5baSBill Taylor 		 */
19949e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_QKEY) {
19959e39c5baSBill Taylor 			qpc->qkey = ud->ud_qkey;
19969e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_QKEY;
19979e39c5baSBill Taylor 		}
19989e39c5baSBill Taylor 
19999e39c5baSBill Taylor 	} else if (qp->qp_serv_type == HERMON_QP_RC) {
20009e39c5baSBill Taylor 		rc = &info_p->qp_transport.rc;
20019e39c5baSBill Taylor 
20029e39c5baSBill Taylor 		/*
20039e39c5baSBill Taylor 		 * Check if any of the flags indicate a change in the RDMA
20049e39c5baSBill Taylor 		 * (recv) enable/disable flags and set the appropriate flag in
20059e39c5baSBill Taylor 		 * the "opmask" parameter
20069e39c5baSBill Taylor 		 */
20079e39c5baSBill Taylor 		opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
20089e39c5baSBill Taylor 
20099e39c5baSBill Taylor 		/*
20109e39c5baSBill Taylor 		 * If we are attempting to modify the path migration state for
20119e39c5baSBill Taylor 		 * this QP, then check for valid state and fill it in.  Also
20129e39c5baSBill Taylor 		 * set the appropriate flag in the "opmask" parameter.
20139e39c5baSBill Taylor 		 */
20149e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_MIG) {
20159e39c5baSBill Taylor 			if (rc->rc_mig_state == IBT_STATE_MIGRATED) {
20169e39c5baSBill Taylor 				qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
20179e39c5baSBill Taylor 			} else if (rc->rc_mig_state == IBT_STATE_REARMED) {
20189e39c5baSBill Taylor 				qpc->pm_state = HERMON_QP_PMSTATE_REARM;
20199e39c5baSBill Taylor 			} else {
20209e39c5baSBill Taylor 				return (IBT_QP_APM_STATE_INVALID);
20219e39c5baSBill Taylor 			}
20229e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_PM_STATE;
20239e39c5baSBill Taylor 		}
20249e39c5baSBill Taylor 
20259e39c5baSBill Taylor 		/*
20269e39c5baSBill Taylor 		 * If we are attempting to modify the "Minimum RNR NAK" value
20279e39c5baSBill Taylor 		 * for this QP, then fill it in and set the appropriate flag
20289e39c5baSBill Taylor 		 * in the "opmask" parameter.
20299e39c5baSBill Taylor 		 */
20309e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_MIN_RNR_NAK) {
20319e39c5baSBill Taylor 			qpc->min_rnr_nak = rc->rc_min_rnr_nak;
20329e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_MINRNRNAK;
20339e39c5baSBill Taylor 		}
20349e39c5baSBill Taylor 
20359e39c5baSBill Taylor 		/*
20369e39c5baSBill Taylor 		 * Check for optional alternate path and fill in the
20379e39c5baSBill Taylor 		 * appropriate QPC fields if one is specified
20389e39c5baSBill Taylor 		 */
20399e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_ALT_PATH) {
20409e39c5baSBill Taylor 			qpc_path = &qpc->alt_addr_path;
20419e39c5baSBill Taylor 			adds_vect = &rc->rc_alt_path.cep_adds_vect;
20429e39c5baSBill Taylor 
20439e39c5baSBill Taylor 			/* Set the common alternate address path fields */
20449e39c5baSBill Taylor 			status = hermon_set_addr_path(state, adds_vect,
20459e39c5baSBill Taylor 			    qpc_path, HERMON_ADDRPATH_QP);
20469e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
20479e39c5baSBill Taylor 				return (status);
20489e39c5baSBill Taylor 			}
20499e39c5baSBill Taylor 			qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
20509e39c5baSBill Taylor 
20519e39c5baSBill Taylor 			/*
20529e39c5baSBill Taylor 			 * Check for valid alternate path port number and fill
20539e39c5baSBill Taylor 			 * it in
20549e39c5baSBill Taylor 			 */
20559e39c5baSBill Taylor 			portnum = rc->rc_alt_path.cep_hca_port_num;
20569e39c5baSBill Taylor 			if (hermon_portnum_is_valid(state, portnum)) {
20579e39c5baSBill Taylor 				qp->qp_portnum_alt = portnum - 1;
20589e39c5baSBill Taylor 				qpc->alt_addr_path.sched_q =
20599e39c5baSBill Taylor 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
20609e39c5baSBill Taylor 				    adds_vect->av_srvl, qp->qp_is_special);
20619e39c5baSBill Taylor 			} else {
20629e39c5baSBill Taylor 				return (IBT_HCA_PORT_INVALID);
20639e39c5baSBill Taylor 			}
20649e39c5baSBill Taylor 
20659e39c5baSBill Taylor 			/*
20669e39c5baSBill Taylor 			 * Check for valid alternate path PKey index and fill
20679e39c5baSBill Taylor 			 * it in
20689e39c5baSBill Taylor 			 */
20699e39c5baSBill Taylor 			pkeyindx = rc->rc_alt_path.cep_pkey_ix;
20709e39c5baSBill Taylor 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
20719e39c5baSBill Taylor 				qpc->alt_addr_path.pkey_indx = pkeyindx;
20729e39c5baSBill Taylor 			} else {
20739e39c5baSBill Taylor 				return (IBT_PKEY_IX_ILLEGAL);
20749e39c5baSBill Taylor 			}
20759e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_ALT_PATH;
20769e39c5baSBill Taylor 		}
20779e39c5baSBill Taylor 
20789e39c5baSBill Taylor 	} else if (qp->qp_serv_type == HERMON_QP_UC) {
20799e39c5baSBill Taylor 		uc = &info_p->qp_transport.uc;
20809e39c5baSBill Taylor 
20819e39c5baSBill Taylor 		/*
20829e39c5baSBill Taylor 		 * Check if any of the flags indicate a change in the RDMA
20839e39c5baSBill Taylor 		 * Write (recv) enable/disable and set the appropriate flag
20849e39c5baSBill Taylor 		 * in the "opmask" parameter. Note: RDMA Read and Atomic are
20859e39c5baSBill Taylor 		 * not valid for UC transport.
20869e39c5baSBill Taylor 		 */
20879e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_RDMA_W) {
20889e39c5baSBill Taylor 			qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
20899e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_RWE;
20909e39c5baSBill Taylor 		}
20919e39c5baSBill Taylor 
20929e39c5baSBill Taylor 		/*
20939e39c5baSBill Taylor 		 * If we are attempting to modify the path migration state for
20949e39c5baSBill Taylor 		 * this QP, then check for valid state and fill it in.  Also
20959e39c5baSBill Taylor 		 * set the appropriate flag in the "opmask" parameter.
20969e39c5baSBill Taylor 		 */
20979e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_MIG) {
20989e39c5baSBill Taylor 			if (uc->uc_mig_state == IBT_STATE_MIGRATED) {
20999e39c5baSBill Taylor 				qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
21009e39c5baSBill Taylor 			} else if (uc->uc_mig_state == IBT_STATE_REARMED) {
21019e39c5baSBill Taylor 				qpc->pm_state = HERMON_QP_PMSTATE_REARM;
21029e39c5baSBill Taylor 			} else {
21039e39c5baSBill Taylor 				return (IBT_QP_APM_STATE_INVALID);
21049e39c5baSBill Taylor 			}
21059e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_PM_STATE;
21069e39c5baSBill Taylor 		}
21079e39c5baSBill Taylor 
21089e39c5baSBill Taylor 		/*
21099e39c5baSBill Taylor 		 * Check for optional alternate path and fill in the
21109e39c5baSBill Taylor 		 * appropriate QPC fields if one is specified
21119e39c5baSBill Taylor 		 */
21129e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_ALT_PATH) {
21139e39c5baSBill Taylor 			qpc_path = &qpc->alt_addr_path;
21149e39c5baSBill Taylor 			adds_vect = &uc->uc_alt_path.cep_adds_vect;
21159e39c5baSBill Taylor 
21169e39c5baSBill Taylor 			/* Set the common alternate address path fields */
21179e39c5baSBill Taylor 			status = hermon_set_addr_path(state, adds_vect,
21189e39c5baSBill Taylor 			    qpc_path, HERMON_ADDRPATH_QP);
21199e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
21209e39c5baSBill Taylor 				return (status);
21219e39c5baSBill Taylor 			}
21229e39c5baSBill Taylor 
21239e39c5baSBill Taylor 			/*
21249e39c5baSBill Taylor 			 * Check for valid alternate path port number and fill
21259e39c5baSBill Taylor 			 * it in
21269e39c5baSBill Taylor 			 */
21279e39c5baSBill Taylor 			portnum = uc->uc_alt_path.cep_hca_port_num;
21289e39c5baSBill Taylor 			if (hermon_portnum_is_valid(state, portnum)) {
21299e39c5baSBill Taylor 				qp->qp_portnum_alt = portnum - 1;
21309e39c5baSBill Taylor 				qpc->alt_addr_path.sched_q =
21319e39c5baSBill Taylor 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
21329e39c5baSBill Taylor 				    adds_vect->av_srvl, qp->qp_is_special);
21339e39c5baSBill Taylor 			} else {
21349e39c5baSBill Taylor 				return (IBT_HCA_PORT_INVALID);
21359e39c5baSBill Taylor 			}
21369e39c5baSBill Taylor 
21379e39c5baSBill Taylor 			/*
21389e39c5baSBill Taylor 			 * Check for valid alternate path PKey index and fill
21399e39c5baSBill Taylor 			 * it in
21409e39c5baSBill Taylor 			 */
21419e39c5baSBill Taylor 			pkeyindx = uc->uc_alt_path.cep_pkey_ix;
21429e39c5baSBill Taylor 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
21439e39c5baSBill Taylor 				qpc->alt_addr_path.pkey_indx = pkeyindx;
21449e39c5baSBill Taylor 			} else {
21459e39c5baSBill Taylor 				return (IBT_PKEY_IX_ILLEGAL);
21469e39c5baSBill Taylor 			}
21479e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_ALT_PATH;
21489e39c5baSBill Taylor 		}
21499e39c5baSBill Taylor 	} else {
21509e39c5baSBill Taylor 		/*
21519e39c5baSBill Taylor 		 * Invalid QP transport type. If we got here then it's a
21529e39c5baSBill Taylor 		 * warning of a probably serious problem.  So print a message
21539e39c5baSBill Taylor 		 * and return failure
21549e39c5baSBill Taylor 		 */
21559e39c5baSBill Taylor 		HERMON_WARNING(state, "unknown QP transport type in rts2rts");
21569e39c5baSBill Taylor 		return (ibc_get_ci_failure(0));
21579e39c5baSBill Taylor 	}
21589e39c5baSBill Taylor 
21599e39c5baSBill Taylor 	/*
21609e39c5baSBill Taylor 	 * Post the RTS2RTS_QP command to the Hermon firmware
21619e39c5baSBill Taylor 	 *
21629e39c5baSBill Taylor 	 * We do a HERMON_NOSLEEP here because we are still holding the
21639e39c5baSBill Taylor 	 * "qp_lock".  If we got raised to interrupt level by priority
21649e39c5baSBill Taylor 	 * inversion, we do not want to block in this routine waiting for
21659e39c5baSBill Taylor 	 * success.
21669e39c5baSBill Taylor 	 */
21679e39c5baSBill Taylor 	status = hermon_cmn_qp_cmd_post(state, RTS2RTS_QP, qpc, qp->qp_qpnum,
21689e39c5baSBill Taylor 	    opmask, HERMON_CMD_NOSLEEP_SPIN);
21699e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
21709e39c5baSBill Taylor 		if (status != HERMON_CMD_BAD_QP_STATE) {
21719e39c5baSBill Taylor 			cmn_err(CE_NOTE, "hermon%d: RTS2RTS_QP command failed: "
21729e39c5baSBill Taylor 			    "%08x\n", state->hs_instance, status);
21739e39c5baSBill Taylor 			if (status == HERMON_CMD_INVALID_STATUS) {
21749e39c5baSBill Taylor 				hermon_fm_ereport(state, HCA_SYS_ERR,
21759e39c5baSBill Taylor 				    HCA_ERR_SRV_LOST);
21769e39c5baSBill Taylor 			}
21779e39c5baSBill Taylor 			return (ibc_get_ci_failure(0));
21789e39c5baSBill Taylor 		} else {
21799e39c5baSBill Taylor 			return (IBT_QP_STATE_INVALID);
21809e39c5baSBill Taylor 		}
21819e39c5baSBill Taylor 	}
21829e39c5baSBill Taylor 
21839e39c5baSBill Taylor 	return (DDI_SUCCESS);
21849e39c5baSBill Taylor }
21859e39c5baSBill Taylor 
21869e39c5baSBill Taylor 
21879e39c5baSBill Taylor #ifdef HERMON_NOTNOW
21889e39c5baSBill Taylor /*
21899e39c5baSBill Taylor  * hermon_qp_rts2sqd()
21909e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
21919e39c5baSBill Taylor  */
21929e39c5baSBill Taylor static int
hermon_qp_rts2sqd(hermon_state_t * state,hermon_qphdl_t qp,ibt_cep_modify_flags_t flags)21939e39c5baSBill Taylor hermon_qp_rts2sqd(hermon_state_t *state, hermon_qphdl_t qp,
21949e39c5baSBill Taylor     ibt_cep_modify_flags_t flags)
21959e39c5baSBill Taylor {
21969e39c5baSBill Taylor 	int			status;
21979e39c5baSBill Taylor 
21989e39c5baSBill Taylor 	ASSERT(MUTEX_HELD(&qp->qp_lock));
21999e39c5baSBill Taylor 
22009e39c5baSBill Taylor 	/*
22019e39c5baSBill Taylor 	 * Set a flag to indicate whether or not the consumer is interested
22029e39c5baSBill Taylor 	 * in receiving the SQ drained event.  Since we are going to always
22039e39c5baSBill Taylor 	 * request hardware generation of the SQD event, we use the value in
22049e39c5baSBill Taylor 	 * "qp_forward_sqd_event" to determine whether or not to pass the event
22059e39c5baSBill Taylor 	 * to the IBTF or to silently consume it.
22069e39c5baSBill Taylor 	 */
22079e39c5baSBill Taylor 	qp->qp_forward_sqd_event = (flags & IBT_CEP_SET_SQD_EVENT) ? 1 : 0;
22089e39c5baSBill Taylor 
22099e39c5baSBill Taylor 	/*
22109e39c5baSBill Taylor 	 * Post the RTS2SQD_QP command to the Hermon firmware
22119e39c5baSBill Taylor 	 *
22129e39c5baSBill Taylor 	 * We do a HERMON_NOSLEEP here because we are still holding the
22139e39c5baSBill Taylor 	 * "qp_lock".  If we got raised to interrupt level by priority
22149e39c5baSBill Taylor 	 * inversion, we do not want to block in this routine waiting for
22159e39c5baSBill Taylor 	 * success.
22169e39c5baSBill Taylor 	 */
22179e39c5baSBill Taylor 	status = hermon_cmn_qp_cmd_post(state, RTS2SQD_QP, NULL, qp->qp_qpnum,
22189e39c5baSBill Taylor 	    0, HERMON_CMD_NOSLEEP_SPIN);
22199e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
22209e39c5baSBill Taylor 		if (status != HERMON_CMD_BAD_QP_STATE) {
22219e39c5baSBill Taylor 			cmn_err(CE_NOTE, "hermon%d: RTS2SQD_QP command failed: "
22229e39c5baSBill Taylor 			    "%08x\n", state->hs_instance, status);
22239e39c5baSBill Taylor 			if (status == HERMON_CMD_INVALID_STATUS) {
22249e39c5baSBill Taylor 				hermon_fm_ereport(state, HCA_SYS_ERR,
22259e39c5baSBill Taylor 				    HCA_ERR_SRV_LOST);
22269e39c5baSBill Taylor 			}
22279e39c5baSBill Taylor 			return (ibc_get_ci_failure(0));
22289e39c5baSBill Taylor 		} else {
22299e39c5baSBill Taylor 			return (IBT_QP_STATE_INVALID);
22309e39c5baSBill Taylor 		}
22319e39c5baSBill Taylor 	}
22329e39c5baSBill Taylor 
22339e39c5baSBill Taylor 	/*
22349e39c5baSBill Taylor 	 * Mark the current QP state as "SQ Draining".  This allows us to
22359e39c5baSBill Taylor 	 * distinguish between the two underlying states in SQD. (see QueryQP()
22369e39c5baSBill Taylor 	 * code in hermon_qp.c)
22379e39c5baSBill Taylor 	 */
22389e39c5baSBill Taylor 	qp->qp_sqd_still_draining = 1;
22399e39c5baSBill Taylor 
22409e39c5baSBill Taylor 	return (DDI_SUCCESS);
22419e39c5baSBill Taylor }
22429e39c5baSBill Taylor #endif
22439e39c5baSBill Taylor 
22449e39c5baSBill Taylor 
22459e39c5baSBill Taylor /*
22469e39c5baSBill Taylor  * hermon_qp_sqd2rts()
22479e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
22489e39c5baSBill Taylor  */
22499e39c5baSBill Taylor static int
hermon_qp_sqd2rts(hermon_state_t * state,hermon_qphdl_t qp,ibt_cep_modify_flags_t flags,ibt_qp_info_t * info_p)22509e39c5baSBill Taylor hermon_qp_sqd2rts(hermon_state_t *state, hermon_qphdl_t qp,
22519e39c5baSBill Taylor     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
22529e39c5baSBill Taylor {
22539e39c5baSBill Taylor 	hermon_hw_qpc_t		*qpc;
22549e39c5baSBill Taylor 	ibt_qp_rc_attr_t	*rc;
22559e39c5baSBill Taylor 	ibt_qp_ud_attr_t	*ud;
22569e39c5baSBill Taylor 	ibt_qp_uc_attr_t	*uc;
22579e39c5baSBill Taylor 	hermon_hw_addr_path_t	*qpc_path;
22589e39c5baSBill Taylor 	ibt_adds_vect_t		*adds_vect;
22599e39c5baSBill Taylor 	uint_t			portnum, pkeyindx;
22609e39c5baSBill Taylor 	uint_t			rra_max, sra_max;
22619e39c5baSBill Taylor 	uint32_t		opmask = 0;
22629e39c5baSBill Taylor 	int			status;
22639e39c5baSBill Taylor 
22649e39c5baSBill Taylor 	ASSERT(MUTEX_HELD(&qp->qp_lock));
22659e39c5baSBill Taylor 
22669e39c5baSBill Taylor 	/*
22679e39c5baSBill Taylor 	 * Grab the temporary QPC entry from QP software state
22689e39c5baSBill Taylor 	 */
22699e39c5baSBill Taylor 	qpc = &qp->qpc;
22709e39c5baSBill Taylor 
22719e39c5baSBill Taylor 	/*
22729e39c5baSBill Taylor 	 * Fill in the common fields in the QPC
22739e39c5baSBill Taylor 	 */
22749e39c5baSBill Taylor 
22759e39c5baSBill Taylor 	/*
22769e39c5baSBill Taylor 	 * Now fill in the QPC fields which are specific to transport type
22779e39c5baSBill Taylor 	 */
227817a2b317SBill Taylor 	if (qp->qp_type == IBT_UD_RQP) {
22799e39c5baSBill Taylor 		ud = &info_p->qp_transport.ud;
22809e39c5baSBill Taylor 
22819e39c5baSBill Taylor 		/*
22829e39c5baSBill Taylor 		 * If we are attempting to modify the port for this QP, then
22839e39c5baSBill Taylor 		 * check for valid port number and fill it in.  Also set the
22849e39c5baSBill Taylor 		 * appropriate flag in the "opmask" parameter.
22859e39c5baSBill Taylor 		 */
22869e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_PORT) {
22879e39c5baSBill Taylor 			portnum = ud->ud_port;
22889e39c5baSBill Taylor 			if (hermon_portnum_is_valid(state, portnum)) {
22899e39c5baSBill Taylor 				qp->qp_portnum = portnum - 1;
22909e39c5baSBill Taylor 				qpc->pri_addr_path.sched_q =
22919e39c5baSBill Taylor 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
22929e39c5baSBill Taylor 				    0, qp->qp_is_special);
22939e39c5baSBill Taylor 			} else {
22949e39c5baSBill Taylor 				return (IBT_HCA_PORT_INVALID);
22959e39c5baSBill Taylor 			}
22969e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_PRIM_PORT;
22979e39c5baSBill Taylor 		}
22989e39c5baSBill Taylor 
22999e39c5baSBill Taylor 		/*
23009e39c5baSBill Taylor 		 * If we are attempting to modify the PKey index for this QP,
23019e39c5baSBill Taylor 		 * then check for valid PKey index and fill it in.  Also set
23029e39c5baSBill Taylor 		 * the appropriate flag in the "opmask" parameter.
23039e39c5baSBill Taylor 		 */
23049e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_PKEY_IX) {
23059e39c5baSBill Taylor 			pkeyindx = ud->ud_pkey_ix;
23069e39c5baSBill Taylor 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
23079e39c5baSBill Taylor 				qpc->pri_addr_path.pkey_indx = pkeyindx;
23089e39c5baSBill Taylor 				opmask |= HERMON_CMD_OP_PKEYINDX;
23099e39c5baSBill Taylor 				qp->qp_pkeyindx = pkeyindx;
23109e39c5baSBill Taylor 			} else {
23119e39c5baSBill Taylor 				return (IBT_PKEY_IX_ILLEGAL);
23129e39c5baSBill Taylor 			}
23139e39c5baSBill Taylor 		}
23149e39c5baSBill Taylor 
23159e39c5baSBill Taylor 		/*
23169e39c5baSBill Taylor 		 * If we are attempting to modify the QKey for this QP, then
23179e39c5baSBill Taylor 		 * fill it in and set the appropriate flag in the "opmask"
23189e39c5baSBill Taylor 		 * parameter.
23199e39c5baSBill Taylor 		 */
23209e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_QKEY) {
23219e39c5baSBill Taylor 			qpc->qkey = ud->ud_qkey;
23229e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_QKEY;
23239e39c5baSBill Taylor 		}
23249e39c5baSBill Taylor 
23259e39c5baSBill Taylor 	} else if (qp->qp_serv_type == HERMON_QP_RC) {
23269e39c5baSBill Taylor 		rc = &info_p->qp_transport.rc;
23279e39c5baSBill Taylor 
23289e39c5baSBill Taylor 		/*
23299e39c5baSBill Taylor 		 * Check if any of the flags indicate a change in the RDMA
23309e39c5baSBill Taylor 		 * (recv) enable/disable flags and set the appropriate flag in
23319e39c5baSBill Taylor 		 * the "opmask" parameter
23329e39c5baSBill Taylor 		 */
23339e39c5baSBill Taylor 		opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
23349e39c5baSBill Taylor 
23359e39c5baSBill Taylor 		qpc->retry_cnt = rc->rc_retry_cnt;
23369e39c5baSBill Taylor 
23379e39c5baSBill Taylor 		/*
23389e39c5baSBill Taylor 		 * If we are attempting to modify the path migration state for
23399e39c5baSBill Taylor 		 * this QP, then check for valid state and fill it in.  Also
23409e39c5baSBill Taylor 		 * set the appropriate flag in the "opmask" parameter.
23419e39c5baSBill Taylor 		 */
23429e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_MIG) {
23439e39c5baSBill Taylor 			if (rc->rc_mig_state == IBT_STATE_MIGRATED) {
23449e39c5baSBill Taylor 				qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
23459e39c5baSBill Taylor 			} else if (rc->rc_mig_state == IBT_STATE_REARMED) {
23469e39c5baSBill Taylor 				qpc->pm_state = HERMON_QP_PMSTATE_REARM;
23479e39c5baSBill Taylor 			} else {
23489e39c5baSBill Taylor 				return (IBT_QP_APM_STATE_INVALID);
23499e39c5baSBill Taylor 			}
23509e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_PM_STATE;
23519e39c5baSBill Taylor 		}
23529e39c5baSBill Taylor 
23539e39c5baSBill Taylor 		/*
23549e39c5baSBill Taylor 		 * Check for optional alternate path and fill in the
23559e39c5baSBill Taylor 		 * appropriate QPC fields if one is specified
23569e39c5baSBill Taylor 		 */
23579e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_ALT_PATH) {
23589e39c5baSBill Taylor 			qpc_path = &qpc->alt_addr_path;
23599e39c5baSBill Taylor 			adds_vect = &rc->rc_alt_path.cep_adds_vect;
23609e39c5baSBill Taylor 
23619e39c5baSBill Taylor 			/* Set the common alternate address path fields */
23629e39c5baSBill Taylor 			status = hermon_set_addr_path(state, adds_vect,
23639e39c5baSBill Taylor 			    qpc_path, HERMON_ADDRPATH_QP);
23649e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
23659e39c5baSBill Taylor 				return (status);
23669e39c5baSBill Taylor 			}
23679e39c5baSBill Taylor 			qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
23689e39c5baSBill Taylor 			/*
23699e39c5baSBill Taylor 			 * Check for valid alternate path port number and fill
23709e39c5baSBill Taylor 			 * it in
23719e39c5baSBill Taylor 			 */
23729e39c5baSBill Taylor 			portnum = rc->rc_alt_path.cep_hca_port_num;
23739e39c5baSBill Taylor 			if (hermon_portnum_is_valid(state, portnum)) {
23749e39c5baSBill Taylor 				qp->qp_portnum_alt = portnum - 1;
23759e39c5baSBill Taylor 				qpc->alt_addr_path.sched_q =
23769e39c5baSBill Taylor 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
23779e39c5baSBill Taylor 				    adds_vect->av_srvl, qp->qp_is_special);
23789e39c5baSBill Taylor 			} else {
23799e39c5baSBill Taylor 				return (IBT_HCA_PORT_INVALID);
23809e39c5baSBill Taylor 			}
23819e39c5baSBill Taylor 
23829e39c5baSBill Taylor 			/*
23839e39c5baSBill Taylor 			 * Check for valid alternate path PKey index and fill
23849e39c5baSBill Taylor 			 * it in
23859e39c5baSBill Taylor 			 */
23869e39c5baSBill Taylor 			pkeyindx = rc->rc_alt_path.cep_pkey_ix;
23879e39c5baSBill Taylor 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
23889e39c5baSBill Taylor 				qpc->alt_addr_path.pkey_indx = pkeyindx;
23899e39c5baSBill Taylor 			} else {
23909e39c5baSBill Taylor 				return (IBT_PKEY_IX_ILLEGAL);
23919e39c5baSBill Taylor 			}
23929e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_ALT_PATH;
23939e39c5baSBill Taylor 		}
23949e39c5baSBill Taylor 
23959e39c5baSBill Taylor 		/*
23969e39c5baSBill Taylor 		 * If we are attempting to modify the number of "outgoing
23979e39c5baSBill Taylor 		 * RDMA resources" for this QP, then check for valid value and
23989e39c5baSBill Taylor 		 * fill it in.  Also set the appropriate flag in the "opmask"
23999e39c5baSBill Taylor 		 * parameter.
24009e39c5baSBill Taylor 		 */
24019e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_RDMARA_OUT) {
24029e39c5baSBill Taylor 			if (hermon_qp_validate_init_depth(state, rc,
24039e39c5baSBill Taylor 			    &sra_max) != DDI_SUCCESS) {
24049e39c5baSBill Taylor 				return (IBT_INVALID_PARAM);
24059e39c5baSBill Taylor 			}
24069e39c5baSBill Taylor 			qpc->sra_max = sra_max;
24079e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_SRA_SET;
24089e39c5baSBill Taylor 		}
24099e39c5baSBill Taylor 
24109e39c5baSBill Taylor 		/*
24119e39c5baSBill Taylor 		 * If we are attempting to modify the number of "incoming
24129e39c5baSBill Taylor 		 * RDMA resources" for this QP, then check for valid value and
24139e39c5baSBill Taylor 		 * update the "rra_max" and "ra_buf_index" fields in the QPC to
24149e39c5baSBill Taylor 		 * point to the pre-allocated RDB resources (in DDR).  Also set
24159e39c5baSBill Taylor 		 * the appropriate flag in the "opmask" parameter.
24169e39c5baSBill Taylor 		 */
24179e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_RDMARA_IN) {
24189e39c5baSBill Taylor 			if (hermon_qp_validate_resp_rsrc(state, rc,
24199e39c5baSBill Taylor 			    &rra_max) != DDI_SUCCESS) {
24209e39c5baSBill Taylor 				return (IBT_INVALID_PARAM);
24219e39c5baSBill Taylor 			}
24229e39c5baSBill Taylor 			qpc->rra_max = rra_max;
24239e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_RRA_SET;
24249e39c5baSBill Taylor 		}
24259e39c5baSBill Taylor 
24269e39c5baSBill Taylor 
24279e39c5baSBill Taylor 		/*
24289e39c5baSBill Taylor 		 * If we are attempting to modify the "Minimum RNR NAK" value
24299e39c5baSBill Taylor 		 * for this QP, then fill it in and set the appropriate flag
24309e39c5baSBill Taylor 		 * in the "opmask" parameter.
24319e39c5baSBill Taylor 		 */
24329e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_MIN_RNR_NAK) {
24339e39c5baSBill Taylor 			qpc->min_rnr_nak = rc->rc_min_rnr_nak;
24349e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_MINRNRNAK;
24359e39c5baSBill Taylor 		}
24369e39c5baSBill Taylor 
24379e39c5baSBill Taylor 	} else if (qp->qp_serv_type == HERMON_QP_UC) {
24389e39c5baSBill Taylor 		uc = &info_p->qp_transport.uc;
24399e39c5baSBill Taylor 
24409e39c5baSBill Taylor 		/*
24419e39c5baSBill Taylor 		 * Check if any of the flags indicate a change in the RDMA
24429e39c5baSBill Taylor 		 * Write (recv) enable/disable and set the appropriate flag
24439e39c5baSBill Taylor 		 * in the "opmask" parameter. Note: RDMA Read and Atomic are
24449e39c5baSBill Taylor 		 * not valid for UC transport.
24459e39c5baSBill Taylor 		 */
24469e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_RDMA_W) {
24479e39c5baSBill Taylor 			qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
24489e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_RWE;
24499e39c5baSBill Taylor 		}
24509e39c5baSBill Taylor 
24519e39c5baSBill Taylor 		/*
24529e39c5baSBill Taylor 		 * If we are attempting to modify the path migration state for
24539e39c5baSBill Taylor 		 * this QP, then check for valid state and fill it in.  Also
24549e39c5baSBill Taylor 		 * set the appropriate flag in the "opmask" parameter.
24559e39c5baSBill Taylor 		 */
24569e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_MIG) {
24579e39c5baSBill Taylor 			if (uc->uc_mig_state == IBT_STATE_MIGRATED) {
24589e39c5baSBill Taylor 				qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
24599e39c5baSBill Taylor 			} else if (uc->uc_mig_state == IBT_STATE_REARMED) {
24609e39c5baSBill Taylor 				qpc->pm_state = HERMON_QP_PMSTATE_REARM;
24619e39c5baSBill Taylor 			} else {
24629e39c5baSBill Taylor 				return (IBT_QP_APM_STATE_INVALID);
24639e39c5baSBill Taylor 			}
24649e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_PM_STATE;
24659e39c5baSBill Taylor 		}
24669e39c5baSBill Taylor 
24679e39c5baSBill Taylor 		/*
24689e39c5baSBill Taylor 		 * Check for optional alternate path and fill in the
24699e39c5baSBill Taylor 		 * appropriate QPC fields if one is specified
24709e39c5baSBill Taylor 		 */
24719e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_ALT_PATH) {
24729e39c5baSBill Taylor 			qpc_path = &qpc->alt_addr_path;
24739e39c5baSBill Taylor 			adds_vect = &uc->uc_alt_path.cep_adds_vect;
24749e39c5baSBill Taylor 
24759e39c5baSBill Taylor 			/* Set the common alternate address path fields */
24769e39c5baSBill Taylor 			status = hermon_set_addr_path(state, adds_vect,
24779e39c5baSBill Taylor 			    qpc_path, HERMON_ADDRPATH_QP);
24789e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
24799e39c5baSBill Taylor 				return (status);
24809e39c5baSBill Taylor 			}
24819e39c5baSBill Taylor 
24829e39c5baSBill Taylor 			/*
24839e39c5baSBill Taylor 			 * Check for valid alternate path port number and fill
24849e39c5baSBill Taylor 			 * it in
24859e39c5baSBill Taylor 			 */
24869e39c5baSBill Taylor 			portnum = uc->uc_alt_path.cep_hca_port_num;
24879e39c5baSBill Taylor 			if (hermon_portnum_is_valid(state, portnum)) {
24889e39c5baSBill Taylor 				qp->qp_portnum_alt = portnum - 1;
24899e39c5baSBill Taylor 				qpc->alt_addr_path.sched_q =
24909e39c5baSBill Taylor 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
24919e39c5baSBill Taylor 				    adds_vect->av_srvl, qp->qp_is_special);
24929e39c5baSBill Taylor 			} else {
24939e39c5baSBill Taylor 				return (IBT_HCA_PORT_INVALID);
24949e39c5baSBill Taylor 			}
24959e39c5baSBill Taylor 
24969e39c5baSBill Taylor 			/*
24979e39c5baSBill Taylor 			 * Check for valid alternate path PKey index and fill
24989e39c5baSBill Taylor 			 * it in
24999e39c5baSBill Taylor 			 */
25009e39c5baSBill Taylor 			pkeyindx = uc->uc_alt_path.cep_pkey_ix;
25019e39c5baSBill Taylor 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
25029e39c5baSBill Taylor 				qpc->alt_addr_path.pkey_indx = pkeyindx;
25039e39c5baSBill Taylor 			} else {
25049e39c5baSBill Taylor 				return (IBT_PKEY_IX_ILLEGAL);
25059e39c5baSBill Taylor 			}
25069e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_ALT_PATH;
25079e39c5baSBill Taylor 		}
25089e39c5baSBill Taylor 	} else {
25099e39c5baSBill Taylor 		/*
25109e39c5baSBill Taylor 		 * Invalid QP transport type. If we got here then it's a
25119e39c5baSBill Taylor 		 * warning of a probably serious problem.  So print a message
25129e39c5baSBill Taylor 		 * and return failure
25139e39c5baSBill Taylor 		 */
25149e39c5baSBill Taylor 		HERMON_WARNING(state, "unknown QP transport type in sqd2rts");
25159e39c5baSBill Taylor 		return (ibc_get_ci_failure(0));
25169e39c5baSBill Taylor 	}
25179e39c5baSBill Taylor 
25189e39c5baSBill Taylor 	/*
25199e39c5baSBill Taylor 	 * Post the SQD2RTS_QP command to the Hermon firmware
25209e39c5baSBill Taylor 	 *
25219e39c5baSBill Taylor 	 * We do a HERMON_NOSLEEP here because we are still holding the
25229e39c5baSBill Taylor 	 * "qp_lock".  If we got raised to interrupt level by priority
25239e39c5baSBill Taylor 	 * inversion, we do not want to block in this routine waiting for
25249e39c5baSBill Taylor 	 * success.
25259e39c5baSBill Taylor 	 */
25269e39c5baSBill Taylor 	status = hermon_cmn_qp_cmd_post(state, SQD2RTS_QP, qpc, qp->qp_qpnum,
25279e39c5baSBill Taylor 	    opmask, HERMON_CMD_NOSLEEP_SPIN);
25289e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
25299e39c5baSBill Taylor 		if (status != HERMON_CMD_BAD_QP_STATE) {
25309e39c5baSBill Taylor 			cmn_err(CE_NOTE, "hermon%d: SQD2RTS_QP command failed: "
25319e39c5baSBill Taylor 			    "%08x\n", state->hs_instance, status);
25329e39c5baSBill Taylor 			if (status == HERMON_CMD_INVALID_STATUS) {
25339e39c5baSBill Taylor 				hermon_fm_ereport(state, HCA_SYS_ERR,
25349e39c5baSBill Taylor 				    HCA_ERR_SRV_LOST);
25359e39c5baSBill Taylor 			}
25369e39c5baSBill Taylor 			return (ibc_get_ci_failure(0));
25379e39c5baSBill Taylor 		} else {
25389e39c5baSBill Taylor 			return (IBT_QP_STATE_INVALID);
25399e39c5baSBill Taylor 		}
25409e39c5baSBill Taylor 	}
25419e39c5baSBill Taylor 
25429e39c5baSBill Taylor 	return (DDI_SUCCESS);
25439e39c5baSBill Taylor }
25449e39c5baSBill Taylor 
25459e39c5baSBill Taylor 
25469e39c5baSBill Taylor /*
25479e39c5baSBill Taylor  * hermon_qp_sqd2sqd()
25489e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
25499e39c5baSBill Taylor  */
25509e39c5baSBill Taylor static int
hermon_qp_sqd2sqd(hermon_state_t * state,hermon_qphdl_t qp,ibt_cep_modify_flags_t flags,ibt_qp_info_t * info_p)25519e39c5baSBill Taylor hermon_qp_sqd2sqd(hermon_state_t *state, hermon_qphdl_t qp,
25529e39c5baSBill Taylor     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
25539e39c5baSBill Taylor {
25549e39c5baSBill Taylor 	hermon_hw_qpc_t		*qpc;
25559e39c5baSBill Taylor 	ibt_qp_rc_attr_t	*rc;
25569e39c5baSBill Taylor 	ibt_qp_ud_attr_t	*ud;
25579e39c5baSBill Taylor 	ibt_qp_uc_attr_t	*uc;
25589e39c5baSBill Taylor 	hermon_hw_addr_path_t	*qpc_path;
25599e39c5baSBill Taylor 	ibt_adds_vect_t		*adds_vect;
25609e39c5baSBill Taylor 	uint_t			portnum, pkeyindx;
25619e39c5baSBill Taylor 	uint_t			rra_max, sra_max;
25629e39c5baSBill Taylor 	uint32_t		opmask = 0;
25639e39c5baSBill Taylor 	int			status;
25649e39c5baSBill Taylor 
25659e39c5baSBill Taylor 	ASSERT(MUTEX_HELD(&qp->qp_lock));
25669e39c5baSBill Taylor 
25679e39c5baSBill Taylor 	/*
25689e39c5baSBill Taylor 	 * Grab the temporary QPC entry from QP software state
25699e39c5baSBill Taylor 	 */
25709e39c5baSBill Taylor 	qpc = &qp->qpc;
25719e39c5baSBill Taylor 
25729e39c5baSBill Taylor 	/*
25739e39c5baSBill Taylor 	 * Fill in the common fields in the QPC
25749e39c5baSBill Taylor 	 */
25759e39c5baSBill Taylor 
25769e39c5baSBill Taylor 	/*
25779e39c5baSBill Taylor 	 * Now fill in the QPC fields which are specific to transport type
25789e39c5baSBill Taylor 	 */
257917a2b317SBill Taylor 	if (qp->qp_type == IBT_UD_RQP) {
25809e39c5baSBill Taylor 		ud = &info_p->qp_transport.ud;
25819e39c5baSBill Taylor 
25829e39c5baSBill Taylor 		/*
25839e39c5baSBill Taylor 		 * If we are attempting to modify the port for this QP, then
25849e39c5baSBill Taylor 		 * check for valid port number and fill it in.  Also set the
25859e39c5baSBill Taylor 		 * appropriate flag in the "opmask" parameter.
25869e39c5baSBill Taylor 		 */
25879e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_PORT) {
25889e39c5baSBill Taylor 			portnum = ud->ud_port;
25899e39c5baSBill Taylor 			if (hermon_portnum_is_valid(state, portnum)) {
25909e39c5baSBill Taylor 				qp->qp_portnum = portnum - 1;
25919e39c5baSBill Taylor 				qpc->pri_addr_path.sched_q =
25929e39c5baSBill Taylor 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
25939e39c5baSBill Taylor 				    0, qp->qp_is_special);
25949e39c5baSBill Taylor 			} else {
25959e39c5baSBill Taylor 				return (IBT_HCA_PORT_INVALID);
25969e39c5baSBill Taylor 			}
25979e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_SCHEDQUEUE;
25989e39c5baSBill Taylor 		}
25999e39c5baSBill Taylor 
26009e39c5baSBill Taylor 		/*
26019e39c5baSBill Taylor 		 * If we are attempting to modify the PKey index for this QP,
26029e39c5baSBill Taylor 		 * then check for valid PKey index and fill it in.  Also set
26039e39c5baSBill Taylor 		 * the appropriate flag in the "opmask" parameter.
26049e39c5baSBill Taylor 		 */
26059e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_PKEY_IX) {
26069e39c5baSBill Taylor 			pkeyindx = ud->ud_pkey_ix;
26079e39c5baSBill Taylor 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
26089e39c5baSBill Taylor 				qpc->pri_addr_path.pkey_indx = pkeyindx;
26099e39c5baSBill Taylor 				opmask |= HERMON_CMD_OP_PKEYINDX;
26109e39c5baSBill Taylor 				qp->qp_pkeyindx = pkeyindx;
26119e39c5baSBill Taylor 			} else {
26129e39c5baSBill Taylor 				return (IBT_PKEY_IX_ILLEGAL);
26139e39c5baSBill Taylor 			}
26149e39c5baSBill Taylor 		}
26159e39c5baSBill Taylor 
26169e39c5baSBill Taylor 		/*
26179e39c5baSBill Taylor 		 * If we are attempting to modify the QKey for this QP, then
26189e39c5baSBill Taylor 		 * fill it in and set the appropriate flag in the "opmask"
26199e39c5baSBill Taylor 		 * parameter.
26209e39c5baSBill Taylor 		 */
26219e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_QKEY) {
26229e39c5baSBill Taylor 			qpc->qkey = ud->ud_qkey;
26239e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_QKEY;
26249e39c5baSBill Taylor 		}
26259e39c5baSBill Taylor 
26269e39c5baSBill Taylor 	} else if (qp->qp_serv_type == HERMON_QP_RC) {
26279e39c5baSBill Taylor 		rc = &info_p->qp_transport.rc;
26289e39c5baSBill Taylor 
26299e39c5baSBill Taylor 		/*
26309e39c5baSBill Taylor 		 * Check if any of the flags indicate a change in the RDMA
26319e39c5baSBill Taylor 		 * (recv) enable/disable flags and set the appropriate flag in
26329e39c5baSBill Taylor 		 * the "opmask" parameter
26339e39c5baSBill Taylor 		 */
26349e39c5baSBill Taylor 		opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
26359e39c5baSBill Taylor 
26369e39c5baSBill Taylor 		/*
26379e39c5baSBill Taylor 		 * Check for optional primary path and fill in the
26389e39c5baSBill Taylor 		 * appropriate QPC fields if one is specified
26399e39c5baSBill Taylor 		 */
26409e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_ADDS_VECT) {
26419e39c5baSBill Taylor 			qpc_path = &qpc->pri_addr_path;
26429e39c5baSBill Taylor 			adds_vect = &rc->rc_path.cep_adds_vect;
26439e39c5baSBill Taylor 
26449e39c5baSBill Taylor 			/* Set the common primary address path fields */
26459e39c5baSBill Taylor 			status = hermon_set_addr_path(state, adds_vect,
26469e39c5baSBill Taylor 			    qpc_path, HERMON_ADDRPATH_QP);
26479e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
26489e39c5baSBill Taylor 				return (status);
26499e39c5baSBill Taylor 			}
26509e39c5baSBill Taylor 			qpc->rnr_retry = rc->rc_rnr_retry_cnt;
26519e39c5baSBill Taylor 			qpc_path->ack_timeout = rc->rc_path.cep_timeout;
26529e39c5baSBill Taylor 			qpc->retry_cnt = rc->rc_retry_cnt;
26539e39c5baSBill Taylor 
26549e39c5baSBill Taylor 			portnum = qp->qp_portnum + 1;
26559e39c5baSBill Taylor 			if (hermon_portnum_is_valid(state, portnum)) {
26569e39c5baSBill Taylor 				qpc->pri_addr_path.sched_q  =
26579e39c5baSBill Taylor 				    HERMON_QP_SCHEDQ_GET(qp->qp_portnum,
26589e39c5baSBill Taylor 				    adds_vect->av_srvl, qp->qp_is_special);
26599e39c5baSBill Taylor 			} else {
26609e39c5baSBill Taylor 				return (IBT_HCA_PORT_INVALID);
26619e39c5baSBill Taylor 			}
26629e39c5baSBill Taylor 
26639e39c5baSBill Taylor 			/*
26649e39c5baSBill Taylor 			 * MTU changes as part of sqd2sqd are not allowed.
26659e39c5baSBill Taylor 			 * Simply keep the same MTU value here, stored in the
26669e39c5baSBill Taylor 			 * qphdl from init2rtr time.
26679e39c5baSBill Taylor 			 */
26689e39c5baSBill Taylor 			qpc->mtu = qp->qp_save_mtu;
26699e39c5baSBill Taylor 
26709e39c5baSBill Taylor 			opmask |= (HERMON_CMD_OP_PRIM_PATH |
26719e39c5baSBill Taylor 			    HERMON_CMD_OP_RETRYCNT | HERMON_CMD_OP_ACKTIMEOUT |
26729e39c5baSBill Taylor 			    HERMON_CMD_OP_PRIM_RNRRETRY);
26739e39c5baSBill Taylor 		}
26749e39c5baSBill Taylor 
26759e39c5baSBill Taylor 		/*
26769e39c5baSBill Taylor 		 * If we are attempting to modify the path migration state for
26779e39c5baSBill Taylor 		 * this QP, then check for valid state and fill it in.  Also
26789e39c5baSBill Taylor 		 * set the appropriate flag in the "opmask" parameter.
26799e39c5baSBill Taylor 		 */
26809e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_MIG) {
26819e39c5baSBill Taylor 			if (rc->rc_mig_state == IBT_STATE_MIGRATED) {
26829e39c5baSBill Taylor 				qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
26839e39c5baSBill Taylor 			} else if (rc->rc_mig_state == IBT_STATE_REARMED) {
26849e39c5baSBill Taylor 				qpc->pm_state = HERMON_QP_PMSTATE_REARM;
26859e39c5baSBill Taylor 			} else {
26869e39c5baSBill Taylor 				return (IBT_QP_APM_STATE_INVALID);
26879e39c5baSBill Taylor 			}
26889e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_PM_STATE;
26899e39c5baSBill Taylor 		}
26909e39c5baSBill Taylor 
26919e39c5baSBill Taylor 		/*
26929e39c5baSBill Taylor 		 * If we are attempting to modify the PKey index for this QP,
26939e39c5baSBill Taylor 		 * then check for valid PKey index and fill it in.  Also set
26949e39c5baSBill Taylor 		 * the appropriate flag in the "opmask" parameter.
26959e39c5baSBill Taylor 		 */
26969e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_PKEY_IX) {
26979e39c5baSBill Taylor 			pkeyindx = rc->rc_path.cep_pkey_ix;
26989e39c5baSBill Taylor 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
26999e39c5baSBill Taylor 				qpc->pri_addr_path.pkey_indx = pkeyindx;
27009e39c5baSBill Taylor 				opmask |= HERMON_CMD_OP_PKEYINDX;
27019e39c5baSBill Taylor 			} else {
27029e39c5baSBill Taylor 				return (IBT_PKEY_IX_ILLEGAL);
27039e39c5baSBill Taylor 			}
27049e39c5baSBill Taylor 		}
27059e39c5baSBill Taylor 
27069e39c5baSBill Taylor 		/*
27079e39c5baSBill Taylor 		 * If we are attempting to modify the port for this QP, then
27089e39c5baSBill Taylor 		 * check for valid port number and fill it in.  Also set the
27099e39c5baSBill Taylor 		 * appropriate flag in the "opmask" parameter.
27109e39c5baSBill Taylor 		 */
27119e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_PORT) {
27129e39c5baSBill Taylor 			portnum = rc->rc_path.cep_hca_port_num;
27139e39c5baSBill Taylor 			if (hermon_portnum_is_valid(state, portnum)) {
27149e39c5baSBill Taylor 				qp->qp_portnum = portnum - 1;
27159e39c5baSBill Taylor 				qpc->pri_addr_path.sched_q =
27169e39c5baSBill Taylor 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
27179e39c5baSBill Taylor 				    adds_vect->av_srvl, qp->qp_is_special);
27189e39c5baSBill Taylor 			} else {
27199e39c5baSBill Taylor 				return (IBT_HCA_PORT_INVALID);
27209e39c5baSBill Taylor 			}
27219e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_SCHEDQUEUE;
27229e39c5baSBill Taylor 		}
27239e39c5baSBill Taylor 
27249e39c5baSBill Taylor 		/*
27259e39c5baSBill Taylor 		 * Check for optional alternate path and fill in the
27269e39c5baSBill Taylor 		 * appropriate QPC fields if one is specified
27279e39c5baSBill Taylor 		 */
27289e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_ALT_PATH) {
27299e39c5baSBill Taylor 			qpc_path = &qpc->alt_addr_path;
27309e39c5baSBill Taylor 			adds_vect = &rc->rc_alt_path.cep_adds_vect;
27319e39c5baSBill Taylor 
27329e39c5baSBill Taylor 			/* Set the common alternate address path fields */
27339e39c5baSBill Taylor 			status = hermon_set_addr_path(state, adds_vect,
27349e39c5baSBill Taylor 			    qpc_path, HERMON_ADDRPATH_QP);
27359e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
27369e39c5baSBill Taylor 				return (status);
27379e39c5baSBill Taylor 			}
27389e39c5baSBill Taylor 			qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
27399e39c5baSBill Taylor 
27409e39c5baSBill Taylor 			/*
27419e39c5baSBill Taylor 			 * Check for valid alternate path port number and fill
27429e39c5baSBill Taylor 			 * it in
27439e39c5baSBill Taylor 			 */
27449e39c5baSBill Taylor 			portnum = rc->rc_alt_path.cep_hca_port_num;
27459e39c5baSBill Taylor 			if (hermon_portnum_is_valid(state, portnum)) {
27469e39c5baSBill Taylor 				qp->qp_portnum_alt = portnum - 1;
27479e39c5baSBill Taylor 				qpc->alt_addr_path.sched_q =
27489e39c5baSBill Taylor 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
27499e39c5baSBill Taylor 				    adds_vect->av_srvl, qp->qp_is_special);
27509e39c5baSBill Taylor 			} else {
27519e39c5baSBill Taylor 				return (IBT_HCA_PORT_INVALID);
27529e39c5baSBill Taylor 			}
27539e39c5baSBill Taylor 
27549e39c5baSBill Taylor 			/*
27559e39c5baSBill Taylor 			 * Check for valid alternate path PKey index and fill
27569e39c5baSBill Taylor 			 * it in
27579e39c5baSBill Taylor 			 */
27589e39c5baSBill Taylor 			pkeyindx = rc->rc_alt_path.cep_pkey_ix;
27599e39c5baSBill Taylor 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
27609e39c5baSBill Taylor 				qpc->alt_addr_path.pkey_indx = pkeyindx;
27619e39c5baSBill Taylor 			} else {
27629e39c5baSBill Taylor 				return (IBT_PKEY_IX_ILLEGAL);
27639e39c5baSBill Taylor 			}
27649e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_ALT_PATH;
27659e39c5baSBill Taylor 		}
27669e39c5baSBill Taylor 
27679e39c5baSBill Taylor 		/*
27689e39c5baSBill Taylor 		 * If we are attempting to modify the number of "outgoing
27699e39c5baSBill Taylor 		 * RDMA resources" for this QP, then check for valid value and
27709e39c5baSBill Taylor 		 * fill it in.  Also set the appropriate flag in the "opmask"
27719e39c5baSBill Taylor 		 * parameter.
27729e39c5baSBill Taylor 		 */
27739e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_RDMARA_OUT) {
27749e39c5baSBill Taylor 			if (hermon_qp_validate_init_depth(state, rc,
27759e39c5baSBill Taylor 			    &sra_max) != DDI_SUCCESS) {
27769e39c5baSBill Taylor 				return (IBT_INVALID_PARAM);
27779e39c5baSBill Taylor 			}
27789e39c5baSBill Taylor 			qpc->sra_max = sra_max;
27799e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_SRA_SET;
27809e39c5baSBill Taylor 		}
27819e39c5baSBill Taylor 
27829e39c5baSBill Taylor 		/*
27839e39c5baSBill Taylor 		 * If we are attempting to modify the number of "incoming
27849e39c5baSBill Taylor 		 * RDMA resources" for this QP, then check for valid value and
27859e39c5baSBill Taylor 		 * update the "rra_max" and "ra_buf_index" fields in the QPC to
27869e39c5baSBill Taylor 		 * point to the pre-allocated RDB resources (in DDR).  Also set
27879e39c5baSBill Taylor 		 * the appropriate flag in the "opmask" parameter.
27889e39c5baSBill Taylor 		 */
27899e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_RDMARA_IN) {
27909e39c5baSBill Taylor 			if (hermon_qp_validate_resp_rsrc(state, rc,
27919e39c5baSBill Taylor 			    &rra_max) != DDI_SUCCESS) {
27929e39c5baSBill Taylor 				return (IBT_INVALID_PARAM);
27939e39c5baSBill Taylor 			}
27949e39c5baSBill Taylor 			qpc->rra_max = rra_max;
27959e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_RRA_SET;
27969e39c5baSBill Taylor 		}
27979e39c5baSBill Taylor 
27989e39c5baSBill Taylor 		/*
27999e39c5baSBill Taylor 		 * If we are attempting to modify the "Local Ack Timeout" value
28009e39c5baSBill Taylor 		 * for this QP, then fill it in and set the appropriate flag in
28019e39c5baSBill Taylor 		 * the "opmask" parameter.
28029e39c5baSBill Taylor 		 */
28039e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_TIMEOUT) {
28049e39c5baSBill Taylor 			qpc_path = &qpc->pri_addr_path;
28059e39c5baSBill Taylor 			qpc_path->ack_timeout = rc->rc_path.cep_timeout;
28069e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_ACKTIMEOUT;
28079e39c5baSBill Taylor 		}
28089e39c5baSBill Taylor 
28099e39c5baSBill Taylor 		/*
28109e39c5baSBill Taylor 		 * If we are attempting to modify the "Retry Count" for this QP,
28119e39c5baSBill Taylor 		 * then fill it in and set the appropriate flag in the "opmask"
28129e39c5baSBill Taylor 		 * parameter.
28139e39c5baSBill Taylor 		 */
28149e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_RETRY) {
28159e39c5baSBill Taylor 			qpc->retry_cnt = rc->rc_retry_cnt;
28169e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_PRIM_RNRRETRY;
28179e39c5baSBill Taylor 		}
28189e39c5baSBill Taylor 
28199e39c5baSBill Taylor 		/*
28209e39c5baSBill Taylor 		 * If we are attempting to modify the "RNR Retry Count" for this
28219e39c5baSBill Taylor 		 * QP, then fill it in and set the appropriate flag in the
28229e39c5baSBill Taylor 		 * "opmask" parameter.
28239e39c5baSBill Taylor 		 */
28249e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_RNR_NAK_RETRY) {
28259e39c5baSBill Taylor 			qpc_path = &qpc->pri_addr_path;
28269e39c5baSBill Taylor 			qpc->rnr_retry = rc->rc_rnr_retry_cnt;
28279e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_RETRYCNT;
28289e39c5baSBill Taylor 		}
28299e39c5baSBill Taylor 
28309e39c5baSBill Taylor 		/*
28319e39c5baSBill Taylor 		 * If we are attempting to modify the "Minimum RNR NAK" value
28329e39c5baSBill Taylor 		 * for this QP, then fill it in and set the appropriate flag
28339e39c5baSBill Taylor 		 * in the "opmask" parameter.
28349e39c5baSBill Taylor 		 */
28359e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_MIN_RNR_NAK) {
28369e39c5baSBill Taylor 			qpc->min_rnr_nak = rc->rc_min_rnr_nak;
28379e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_MINRNRNAK;
28389e39c5baSBill Taylor 		}
28399e39c5baSBill Taylor 
28409e39c5baSBill Taylor 	} else if (qp->qp_serv_type == HERMON_QP_UC) {
28419e39c5baSBill Taylor 		uc = &info_p->qp_transport.uc;
28429e39c5baSBill Taylor 
28439e39c5baSBill Taylor 		/*
28449e39c5baSBill Taylor 		 * Check if any of the flags indicate a change in the RDMA
28459e39c5baSBill Taylor 		 * Write (recv) enable/disable and set the appropriate flag
28469e39c5baSBill Taylor 		 * in the "opmask" parameter. Note: RDMA Read and Atomic are
28479e39c5baSBill Taylor 		 * not valid for UC transport.
28489e39c5baSBill Taylor 		 */
28499e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_RDMA_W) {
28509e39c5baSBill Taylor 			qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
28519e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_RWE;
28529e39c5baSBill Taylor 		}
28539e39c5baSBill Taylor 
28549e39c5baSBill Taylor 		/*
28559e39c5baSBill Taylor 		 * Check for optional primary path and fill in the
28569e39c5baSBill Taylor 		 * appropriate QPC fields if one is specified
28579e39c5baSBill Taylor 		 */
28589e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_ADDS_VECT) {
28599e39c5baSBill Taylor 			qpc_path = &qpc->pri_addr_path;
28609e39c5baSBill Taylor 			adds_vect = &uc->uc_path.cep_adds_vect;
28619e39c5baSBill Taylor 
28629e39c5baSBill Taylor 			/* Set the common primary address path fields */
28639e39c5baSBill Taylor 			status = hermon_set_addr_path(state, adds_vect,
28649e39c5baSBill Taylor 			    qpc_path, HERMON_ADDRPATH_QP);
28659e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
28669e39c5baSBill Taylor 				return (status);
28679e39c5baSBill Taylor 			}
28689e39c5baSBill Taylor 			portnum = qp->qp_portnum + 1;
28699e39c5baSBill Taylor 			if (hermon_portnum_is_valid(state, portnum)) {
28709e39c5baSBill Taylor 				qpc->pri_addr_path.sched_q =
28719e39c5baSBill Taylor 				    HERMON_QP_SCHEDQ_GET(qp->qp_portnum,
28729e39c5baSBill Taylor 				    adds_vect->av_srvl, qp->qp_is_special);
28739e39c5baSBill Taylor 			} else {
28749e39c5baSBill Taylor 				return (IBT_HCA_PORT_INVALID);
28759e39c5baSBill Taylor 			}
28769e39c5baSBill Taylor 
28779e39c5baSBill Taylor 			/*
28789e39c5baSBill Taylor 			 * MTU changes as part of sqd2sqd are not allowed.
28799e39c5baSBill Taylor 			 * Simply keep the same MTU value here, stored in the
28809e39c5baSBill Taylor 			 * qphdl from init2rtr time.
28819e39c5baSBill Taylor 			 */
28829e39c5baSBill Taylor 			qpc->mtu = qp->qp_save_mtu;
28839e39c5baSBill Taylor 
28849e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_PRIM_PATH;
28859e39c5baSBill Taylor 		}
28869e39c5baSBill Taylor 
28879e39c5baSBill Taylor 		/*
28889e39c5baSBill Taylor 		 * If we are attempting to modify the path migration state for
28899e39c5baSBill Taylor 		 * this QP, then check for valid state and fill it in.  Also
28909e39c5baSBill Taylor 		 * set the appropriate flag in the "opmask" parameter.
28919e39c5baSBill Taylor 		 */
28929e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_MIG) {
28939e39c5baSBill Taylor 			if (uc->uc_mig_state == IBT_STATE_MIGRATED) {
28949e39c5baSBill Taylor 				qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
28959e39c5baSBill Taylor 			} else if (uc->uc_mig_state == IBT_STATE_REARMED) {
28969e39c5baSBill Taylor 				qpc->pm_state = HERMON_QP_PMSTATE_REARM;
28979e39c5baSBill Taylor 			} else {
28989e39c5baSBill Taylor 				return (IBT_QP_APM_STATE_INVALID);
28999e39c5baSBill Taylor 			}
29009e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_PM_STATE;
29019e39c5baSBill Taylor 		}
29029e39c5baSBill Taylor 
29039e39c5baSBill Taylor 		/*
29049e39c5baSBill Taylor 		 * If we are attempting to modify the PKey index for this QP,
29059e39c5baSBill Taylor 		 * then check for valid PKey index and fill it in.  Also set
29069e39c5baSBill Taylor 		 * the appropriate flag in the "opmask" parameter.
29079e39c5baSBill Taylor 		 */
29089e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_PKEY_IX) {
29099e39c5baSBill Taylor 			pkeyindx = uc->uc_path.cep_pkey_ix;
29109e39c5baSBill Taylor 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
29119e39c5baSBill Taylor 				qpc->pri_addr_path.pkey_indx = pkeyindx;
29129e39c5baSBill Taylor 				opmask |= HERMON_CMD_OP_PKEYINDX;
29139e39c5baSBill Taylor 			} else {
29149e39c5baSBill Taylor 				return (IBT_PKEY_IX_ILLEGAL);
29159e39c5baSBill Taylor 			}
29169e39c5baSBill Taylor 		}
29179e39c5baSBill Taylor 
29189e39c5baSBill Taylor 		/*
29199e39c5baSBill Taylor 		 * Check for optional alternate path and fill in the
29209e39c5baSBill Taylor 		 * appropriate QPC fields if one is specified
29219e39c5baSBill Taylor 		 */
29229e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_ALT_PATH) {
29239e39c5baSBill Taylor 			qpc_path = &qpc->alt_addr_path;
29249e39c5baSBill Taylor 			adds_vect = &uc->uc_alt_path.cep_adds_vect;
29259e39c5baSBill Taylor 
29269e39c5baSBill Taylor 			/* Set the common alternate address path fields */
29279e39c5baSBill Taylor 			status = hermon_set_addr_path(state, adds_vect,
29289e39c5baSBill Taylor 			    qpc_path, HERMON_ADDRPATH_QP);
29299e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
29309e39c5baSBill Taylor 				return (status);
29319e39c5baSBill Taylor 			}
29329e39c5baSBill Taylor 
29339e39c5baSBill Taylor 			/*
29349e39c5baSBill Taylor 			 * Check for valid alternate path port number and fill
29359e39c5baSBill Taylor 			 * it in
29369e39c5baSBill Taylor 			 */
29379e39c5baSBill Taylor 			portnum = uc->uc_alt_path.cep_hca_port_num;
29389e39c5baSBill Taylor 			if (hermon_portnum_is_valid(state, portnum)) {
29399e39c5baSBill Taylor 				qp->qp_portnum_alt = portnum - 1;
29409e39c5baSBill Taylor 				qpc->alt_addr_path.sched_q =
29419e39c5baSBill Taylor 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
29429e39c5baSBill Taylor 				    adds_vect->av_srvl, qp->qp_is_special);
29439e39c5baSBill Taylor 			} else {
29449e39c5baSBill Taylor 				return (IBT_HCA_PORT_INVALID);
29459e39c5baSBill Taylor 			}
29469e39c5baSBill Taylor 
29479e39c5baSBill Taylor 			/*
29489e39c5baSBill Taylor 			 * Check for valid alternate path PKey index and fill
29499e39c5baSBill Taylor 			 * it in
29509e39c5baSBill Taylor 			 */
29519e39c5baSBill Taylor 			pkeyindx = uc->uc_alt_path.cep_pkey_ix;
29529e39c5baSBill Taylor 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
29539e39c5baSBill Taylor 				qpc->alt_addr_path.pkey_indx = pkeyindx;
29549e39c5baSBill Taylor 			} else {
29559e39c5baSBill Taylor 				return (IBT_PKEY_IX_ILLEGAL);
29569e39c5baSBill Taylor 			}
29579e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_ALT_PATH;
29589e39c5baSBill Taylor 		}
29599e39c5baSBill Taylor 	} else {
29609e39c5baSBill Taylor 		/*
29619e39c5baSBill Taylor 		 * Invalid QP transport type. If we got here then it's a
29629e39c5baSBill Taylor 		 * warning of a probably serious problem.  So print a message
29639e39c5baSBill Taylor 		 * and return failure
29649e39c5baSBill Taylor 		 */
29659e39c5baSBill Taylor 		HERMON_WARNING(state, "unknown QP transport type in sqd2sqd");
29669e39c5baSBill Taylor 		return (ibc_get_ci_failure(0));
29679e39c5baSBill Taylor 	}
29689e39c5baSBill Taylor 
29699e39c5baSBill Taylor 	/*
29709e39c5baSBill Taylor 	 * Post the SQD2SQD_QP command to the Hermon firmware
29719e39c5baSBill Taylor 	 *
29729e39c5baSBill Taylor 	 * We do a HERMON_NOSLEEP here because we are still holding the
29739e39c5baSBill Taylor 	 * "qp_lock".  If we got raised to interrupt level by priority
29749e39c5baSBill Taylor 	 * inversion, we do not want to block in this routine waiting for
29759e39c5baSBill Taylor 	 * success.
29769e39c5baSBill Taylor 	 */
29779e39c5baSBill Taylor 	status = hermon_cmn_qp_cmd_post(state, SQD2SQD_QP, qpc, qp->qp_qpnum,
29789e39c5baSBill Taylor 	    opmask, HERMON_CMD_NOSLEEP_SPIN);
29799e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
29809e39c5baSBill Taylor 		if (status != HERMON_CMD_BAD_QP_STATE) {
29819e39c5baSBill Taylor 			cmn_err(CE_NOTE, "hermon%d: SQD2SQD_QP command failed: "
29829e39c5baSBill Taylor 			    "%08x\n", state->hs_instance, status);
29839e39c5baSBill Taylor 			if (status == HERMON_CMD_INVALID_STATUS) {
29849e39c5baSBill Taylor 				hermon_fm_ereport(state, HCA_SYS_ERR,
29859e39c5baSBill Taylor 				    HCA_ERR_SRV_LOST);
29869e39c5baSBill Taylor 			}
29879e39c5baSBill Taylor 			return (ibc_get_ci_failure(0));
29889e39c5baSBill Taylor 		} else {
29899e39c5baSBill Taylor 			return (IBT_QP_STATE_INVALID);
29909e39c5baSBill Taylor 		}
29919e39c5baSBill Taylor 	}
29929e39c5baSBill Taylor 
29939e39c5baSBill Taylor 	return (DDI_SUCCESS);
29949e39c5baSBill Taylor }
29959e39c5baSBill Taylor 
29969e39c5baSBill Taylor 
29979e39c5baSBill Taylor /*
29989e39c5baSBill Taylor  * hermon_qp_sqerr2rts()
29999e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
30009e39c5baSBill Taylor  */
30019e39c5baSBill Taylor static int
hermon_qp_sqerr2rts(hermon_state_t * state,hermon_qphdl_t qp,ibt_cep_modify_flags_t flags,ibt_qp_info_t * info_p)30029e39c5baSBill Taylor hermon_qp_sqerr2rts(hermon_state_t *state, hermon_qphdl_t qp,
30039e39c5baSBill Taylor     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
30049e39c5baSBill Taylor {
30059e39c5baSBill Taylor 	hermon_hw_qpc_t		*qpc;
30069e39c5baSBill Taylor 	ibt_qp_ud_attr_t	*ud;
30079e39c5baSBill Taylor 	uint32_t		opmask = 0;
30089e39c5baSBill Taylor 	int			status;
30099e39c5baSBill Taylor 
30109e39c5baSBill Taylor 	ASSERT(MUTEX_HELD(&qp->qp_lock));
30119e39c5baSBill Taylor 
30129e39c5baSBill Taylor 	/*
30139e39c5baSBill Taylor 	 * Grab the temporary QPC entry from QP software state
30149e39c5baSBill Taylor 	 */
30159e39c5baSBill Taylor 	qpc = &qp->qpc;
30169e39c5baSBill Taylor 
30179e39c5baSBill Taylor 	/*
30189e39c5baSBill Taylor 	 * Since there are no common fields to be filled in for this command,
30199e39c5baSBill Taylor 	 * we begin with the QPC fields which are specific to transport type.
30209e39c5baSBill Taylor 	 */
302117a2b317SBill Taylor 	if (qp->qp_type == IBT_UD_RQP) {
30229e39c5baSBill Taylor 		ud = &info_p->qp_transport.ud;
30239e39c5baSBill Taylor 
30249e39c5baSBill Taylor 		/*
30259e39c5baSBill Taylor 		 * If we are attempting to modify the QKey for this QP, then
30269e39c5baSBill Taylor 		 * fill it in and set the appropriate flag in the "opmask"
30279e39c5baSBill Taylor 		 * parameter.
30289e39c5baSBill Taylor 		 */
30299e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_QKEY) {
30309e39c5baSBill Taylor 			qpc->qkey = ud->ud_qkey;
30319e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_QKEY;
30329e39c5baSBill Taylor 		}
30339e39c5baSBill Taylor 
30349e39c5baSBill Taylor 	} else if (qp->qp_serv_type == HERMON_QP_UC) {
30359e39c5baSBill Taylor 
30369e39c5baSBill Taylor 		/*
30379e39c5baSBill Taylor 		 * Check if any of the flags indicate a change in the RDMA
30389e39c5baSBill Taylor 		 * Write (recv) enable/disable and set the appropriate flag
30399e39c5baSBill Taylor 		 * in the "opmask" parameter. Note: RDMA Read and Atomic are
30409e39c5baSBill Taylor 		 * not valid for UC transport.
30419e39c5baSBill Taylor 		 */
30429e39c5baSBill Taylor 		if (flags & IBT_CEP_SET_RDMA_W) {
30439e39c5baSBill Taylor 			qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
30449e39c5baSBill Taylor 			opmask |= HERMON_CMD_OP_RWE;
30459e39c5baSBill Taylor 		}
30469e39c5baSBill Taylor 	} else {
30479e39c5baSBill Taylor 		/*
30489e39c5baSBill Taylor 		 * Invalid QP transport type. If we got here then it's a
30499e39c5baSBill Taylor 		 * warning of a probably serious problem.  So print a message
30509e39c5baSBill Taylor 		 * and return failure
30519e39c5baSBill Taylor 		 */
30529e39c5baSBill Taylor 		HERMON_WARNING(state, "unknown QP transport type in sqerr2rts");
30539e39c5baSBill Taylor 		return (ibc_get_ci_failure(0));
30549e39c5baSBill Taylor 	}
30559e39c5baSBill Taylor 
30569e39c5baSBill Taylor 	/*
30579e39c5baSBill Taylor 	 * Post the SQERR2RTS_QP command to the Hermon firmware
30589e39c5baSBill Taylor 	 *
30599e39c5baSBill Taylor 	 * We do a HERMON_NOSLEEP here because we are still holding the
30609e39c5baSBill Taylor 	 * "qp_lock".  If we got raised to interrupt level by priority
30619e39c5baSBill Taylor 	 * inversion, we do not want to block in this routine waiting for
30629e39c5baSBill Taylor 	 * success.
30639e39c5baSBill Taylor 	 */
30649e39c5baSBill Taylor 	status = hermon_cmn_qp_cmd_post(state, SQERR2RTS_QP, qpc, qp->qp_qpnum,
30659e39c5baSBill Taylor 	    opmask, HERMON_CMD_NOSLEEP_SPIN);
30669e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
30679e39c5baSBill Taylor 		if (status != HERMON_CMD_BAD_QP_STATE) {
30689e39c5baSBill Taylor 			cmn_err(CE_NOTE, "hermon%d: SQERR2RTS_QP command "
30699e39c5baSBill Taylor 			    "failed: %08x\n", state->hs_instance, status);
30709e39c5baSBill Taylor 			if (status == HERMON_CMD_INVALID_STATUS) {
30719e39c5baSBill Taylor 				hermon_fm_ereport(state, HCA_SYS_ERR,
30729e39c5baSBill Taylor 				    HCA_ERR_SRV_LOST);
30739e39c5baSBill Taylor 			}
30749e39c5baSBill Taylor 			return (ibc_get_ci_failure(0));
30759e39c5baSBill Taylor 		} else {
30769e39c5baSBill Taylor 			return (IBT_QP_STATE_INVALID);
30779e39c5baSBill Taylor 		}
30789e39c5baSBill Taylor 	}
30799e39c5baSBill Taylor 
30809e39c5baSBill Taylor 	return (DDI_SUCCESS);
30819e39c5baSBill Taylor }
30829e39c5baSBill Taylor 
30839e39c5baSBill Taylor 
30849e39c5baSBill Taylor /*
30859e39c5baSBill Taylor  * hermon_qp_to_error()
30869e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
30879e39c5baSBill Taylor  */
30889e39c5baSBill Taylor static int
hermon_qp_to_error(hermon_state_t * state,hermon_qphdl_t qp)30899e39c5baSBill Taylor hermon_qp_to_error(hermon_state_t *state, hermon_qphdl_t qp)
30909e39c5baSBill Taylor {
30919e39c5baSBill Taylor 	int	status;
30929e39c5baSBill Taylor 
30939e39c5baSBill Taylor 	ASSERT(MUTEX_HELD(&qp->qp_lock));
30949e39c5baSBill Taylor 
30959e39c5baSBill Taylor 	/*
30969e39c5baSBill Taylor 	 * Post the TOERR_QP command to the Hermon firmware
30979e39c5baSBill Taylor 	 *
30989e39c5baSBill Taylor 	 * We do a HERMON_NOSLEEP here because we are still holding the
30999e39c5baSBill Taylor 	 * "qp_lock".  If we got raised to interrupt level by priority
31009e39c5baSBill Taylor 	 * inversion, we do not want to block in this routine waiting for
31019e39c5baSBill Taylor 	 * success.
31029e39c5baSBill Taylor 	 */
31039e39c5baSBill Taylor 	status = hermon_cmn_qp_cmd_post(state, TOERR_QP, NULL, qp->qp_qpnum,
31049e39c5baSBill Taylor 	    0, HERMON_CMD_NOSLEEP_SPIN);
31059e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
31069e39c5baSBill Taylor 		cmn_err(CE_NOTE, "hermon%d: TOERR_QP command failed: %08x\n",
31079e39c5baSBill Taylor 		    state->hs_instance, status);
31089e39c5baSBill Taylor 		if (status == HERMON_CMD_INVALID_STATUS) {
31099e39c5baSBill Taylor 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
31109e39c5baSBill Taylor 		}
31119e39c5baSBill Taylor 		return (ibc_get_ci_failure(0));
31129e39c5baSBill Taylor 	}
31139e39c5baSBill Taylor 
31149e39c5baSBill Taylor 	return (DDI_SUCCESS);
31159e39c5baSBill Taylor }
31169e39c5baSBill Taylor 
31179e39c5baSBill Taylor 
31189e39c5baSBill Taylor /*
31199e39c5baSBill Taylor  * hermon_qp_to_reset()
31209e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
31219e39c5baSBill Taylor  */
31229e39c5baSBill Taylor int
hermon_qp_to_reset(hermon_state_t * state,hermon_qphdl_t qp)31239e39c5baSBill Taylor hermon_qp_to_reset(hermon_state_t *state, hermon_qphdl_t qp)
31249e39c5baSBill Taylor {
31259e39c5baSBill Taylor 	hermon_hw_qpc_t	*qpc;
31269e39c5baSBill Taylor 	int		status;
31279e39c5baSBill Taylor 
31289e39c5baSBill Taylor 	ASSERT(MUTEX_HELD(&qp->qp_lock));
31299e39c5baSBill Taylor 
31309e39c5baSBill Taylor 	/*
31319e39c5baSBill Taylor 	 * Grab the temporary QPC entry from QP software state
31329e39c5baSBill Taylor 	 */
31339e39c5baSBill Taylor 	qpc = &qp->qpc;
31349e39c5baSBill Taylor 
31359e39c5baSBill Taylor 	/*
31369e39c5baSBill Taylor 	 * Post the TORST_QP command to the Hermon firmware
31379e39c5baSBill Taylor 	 *
31389e39c5baSBill Taylor 	 * We do a HERMON_NOSLEEP here because we are still holding the
31399e39c5baSBill Taylor 	 * "qp_lock".  If we got raised to interrupt level by priority
31409e39c5baSBill Taylor 	 * inversion, we do not want to block in this routine waiting for
31419e39c5baSBill Taylor 	 * success.
31429e39c5baSBill Taylor 	 */
31439e39c5baSBill Taylor 	status = hermon_cmn_qp_cmd_post(state, TORST_QP, qpc, qp->qp_qpnum,
31449e39c5baSBill Taylor 	    0, HERMON_CMD_NOSLEEP_SPIN);
31459e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
31469e39c5baSBill Taylor 		cmn_err(CE_NOTE, "hermon%d: TORST_QP command failed: %08x\n",
31479e39c5baSBill Taylor 		    state->hs_instance, status);
31489e39c5baSBill Taylor 		if (status == HERMON_CMD_INVALID_STATUS) {
31499e39c5baSBill Taylor 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
31509e39c5baSBill Taylor 		}
31519e39c5baSBill Taylor 		return (ibc_get_ci_failure(0));
31529e39c5baSBill Taylor 	}
315317a2b317SBill Taylor 	if (qp->qp_serv_type == HERMON_QP_FEXCH) {
315417a2b317SBill Taylor 		status = hermon_fcoib_fexch_mkey_fini(state, qp->qp_pdhdl,
315517a2b317SBill Taylor 		    qp->qp_qpnum, HERMON_CMD_NOSLEEP_SPIN);
315617a2b317SBill Taylor 		if (status != DDI_SUCCESS)
315717a2b317SBill Taylor 			cmn_err(CE_NOTE, "hermon%d: fexch_mkey_fini failed "
315817a2b317SBill Taylor 			    "%08x\n", state->hs_instance, status);
315917a2b317SBill Taylor 	}
31609e39c5baSBill Taylor 	return (DDI_SUCCESS);
31619e39c5baSBill Taylor }
31629e39c5baSBill Taylor 
31639e39c5baSBill Taylor 
31649e39c5baSBill Taylor /*
31659e39c5baSBill Taylor  * hermon_qp_reset2err()
31669e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
31679e39c5baSBill Taylor  */
31689e39c5baSBill Taylor static int
hermon_qp_reset2err(hermon_state_t * state,hermon_qphdl_t qp)31699e39c5baSBill Taylor hermon_qp_reset2err(hermon_state_t *state, hermon_qphdl_t qp)
31709e39c5baSBill Taylor {
31719e39c5baSBill Taylor 	hermon_hw_qpc_t	*qpc;
31729e39c5baSBill Taylor 	int		status;
31739e39c5baSBill Taylor 	uint32_t	cqnmask;
31749e39c5baSBill Taylor 
31759e39c5baSBill Taylor 	ASSERT(MUTEX_HELD(&qp->qp_lock));
31769e39c5baSBill Taylor 
31779e39c5baSBill Taylor 	/*
31789e39c5baSBill Taylor 	 * In order to implement the transition from "Reset" directly to the
31799e39c5baSBill Taylor 	 * "Error" state, it is necessary to first give ownership of the QP
31809e39c5baSBill Taylor 	 * context to the Hermon hardware.  This is accomplished by
31819e39c5baSBill Taylor 	 * transitioning the QP to "Init" as an intermediate step and then,
31829e39c5baSBill Taylor 	 * immediately transitioning to "Error".
31839e39c5baSBill Taylor 	 *
31849e39c5baSBill Taylor 	 * When this function returns success, the QP context will be owned by
31859e39c5baSBill Taylor 	 * the Hermon hardware and will be in the "Error" state.
31869e39c5baSBill Taylor 	 */
31879e39c5baSBill Taylor 
31889e39c5baSBill Taylor 	/*
31899e39c5baSBill Taylor 	 * Grab the temporary QPC entry from QP software state
31909e39c5baSBill Taylor 	 */
31919e39c5baSBill Taylor 	qpc = &qp->qpc;
31929e39c5baSBill Taylor 
31939e39c5baSBill Taylor 	/*
31949e39c5baSBill Taylor 	 * Fill in the common fields in the QPC
31959e39c5baSBill Taylor 	 */
31969e39c5baSBill Taylor 	if (qp->qp_is_special) {
31979e39c5baSBill Taylor 		qpc->serv_type	= HERMON_QP_MLX;
31989e39c5baSBill Taylor 	} else {
31999e39c5baSBill Taylor 		qpc->serv_type	= qp->qp_serv_type;
32009e39c5baSBill Taylor 	}
32019e39c5baSBill Taylor 	qpc->pm_state		= HERMON_QP_PMSTATE_MIGRATED;
32029e39c5baSBill Taylor 	qpc->usr_page		= qp->qp_uarpg;
32039e39c5baSBill Taylor 	/* dbr is now an address, not an index */
32049e39c5baSBill Taylor 	qpc->dbr_addrh		= ((uint64_t)qp->qp_rq_pdbr >> 32);
32059e39c5baSBill Taylor 	qpc->dbr_addrl		= ((uint64_t)qp->qp_rq_pdbr & 0xFFFFFFFC) >> 2;
32069e39c5baSBill Taylor 	qpc->pd			= qp->qp_pdhdl->pd_pdnum;
32079e39c5baSBill Taylor 	/*
32089e39c5baSBill Taylor 	 * HERMON:
32099e39c5baSBill Taylor 	 * qpc->wqe_baseaddr is replaced by LKey from the cMPT, and
32109e39c5baSBill Taylor 	 * page_offset, mtt_base_addr_h/l, and log2_page_size will
32119e39c5baSBill Taylor 	 * be used to map the WQE buffer
32129e39c5baSBill Taylor 	 * NOTE that the cMPT is created implicitly when the QP is
32139e39c5baSBill Taylor 	 * transitioned from reset to init
32149e39c5baSBill Taylor 	 */
32159e39c5baSBill Taylor 	qpc->log2_pgsz		= qp->qp_mrhdl->mr_log2_pgsz;
32169e39c5baSBill Taylor 	qpc->mtt_base_addrh	= (qp->qp_mrhdl->mr_mttaddr) >> 32 & 0xFF;
32179e39c5baSBill Taylor 	qpc->mtt_base_addrl	= (qp->qp_mrhdl->mr_mttaddr) >> 3 & 0xFFFFFFFF;
32189e39c5baSBill Taylor 	cqnmask = (1 << state->hs_cfg_profile->cp_log_num_cq) - 1;
321917a2b317SBill Taylor 	qpc->cqn_snd		=
322017a2b317SBill Taylor 	    (qp->qp_sq_cqhdl == NULL) ? 0 : qp->qp_sq_cqhdl->cq_cqnum & cqnmask;
32219e39c5baSBill Taylor 	qpc->page_offs		= qp->qp_wqinfo.qa_pgoffs >> 6;
322217a2b317SBill Taylor 	qpc->cqn_rcv		=
322317a2b317SBill Taylor 	    (qp->qp_rq_cqhdl == NULL) ? 0 : qp->qp_rq_cqhdl->cq_cqnum & cqnmask;
32249e39c5baSBill Taylor 
32259e39c5baSBill Taylor 	qpc->sq_wqe_counter	= 0;
32269e39c5baSBill Taylor 	qpc->rq_wqe_counter	= 0;
32279e39c5baSBill Taylor 	qpc->log_sq_stride	= qp->qp_sq_log_wqesz - 4;
32289e39c5baSBill Taylor 	qpc->log_rq_stride	= qp->qp_rq_log_wqesz - 4;
32299e39c5baSBill Taylor 	qpc->log_sq_size	= highbit(qp->qp_sq_bufsz) - 1;
32309e39c5baSBill Taylor 	qpc->log_rq_size	= highbit(qp->qp_rq_bufsz) - 1;
323117a2b317SBill Taylor 	qpc->srq_en		= (qp->qp_alloc_flags & IBT_QP_USES_SRQ) != 0;
32329e39c5baSBill Taylor 	qpc->sq_no_prefetch	= qp->qp_no_prefetch;
32339e39c5baSBill Taylor 
323417a2b317SBill Taylor 	if (qp->qp_alloc_flags & IBT_QP_USES_SRQ) {
32359e39c5baSBill Taylor 		qpc->srq_number	= qp->qp_srqhdl->srq_srqnum;
32369e39c5baSBill Taylor 	} else {
32379e39c5baSBill Taylor 		qpc->srq_number = 0;
32389e39c5baSBill Taylor 	}
32399e39c5baSBill Taylor 
32409e39c5baSBill Taylor 	qpc->fre		= 0; /* default disable fast registration WR */
32419e39c5baSBill Taylor 	qpc->rlky		= 0; /* default disable reserved lkey */
32429e39c5baSBill Taylor 
32439e39c5baSBill Taylor 	/*
32449e39c5baSBill Taylor 	 * Now fill in the QPC fields which are specific to transport type
32459e39c5baSBill Taylor 	 */
324617a2b317SBill Taylor 	if (qp->qp_type == IBT_UD_RQP) {
32479e39c5baSBill Taylor 		/* Set the UD parameters to an invalid default */
32489e39c5baSBill Taylor 		qpc->qkey = 0;
32499e39c5baSBill Taylor 		qpc->pri_addr_path.sched_q =
32509e39c5baSBill Taylor 		    HERMON_QP_SCHEDQ_GET(0, 0, qp->qp_is_special);
32519e39c5baSBill Taylor 		qpc->pri_addr_path.pkey_indx = 0;
32529e39c5baSBill Taylor 
32539e39c5baSBill Taylor 	} else if (qp->qp_serv_type == HERMON_QP_RC) {
32549e39c5baSBill Taylor 		/* Set the RC parameters to invalid default */
32559e39c5baSBill Taylor 		qpc->rre = 0;
32569e39c5baSBill Taylor 		qpc->rwe = 0;
32579e39c5baSBill Taylor 		qpc->rae = 0;
32589e39c5baSBill Taylor 		qpc->alt_addr_path.sched_q =
32599e39c5baSBill Taylor 		    HERMON_QP_SCHEDQ_GET(0, 0, qp->qp_is_special);
32609e39c5baSBill Taylor 		qpc->pri_addr_path.pkey_indx = 0;
32619e39c5baSBill Taylor 
32629e39c5baSBill Taylor 	} else if (qp->qp_serv_type == HERMON_QP_UC) {
32639e39c5baSBill Taylor 		/* Set the UC parameters to invalid default */
32649e39c5baSBill Taylor 		qpc->rwe = 0;
32659e39c5baSBill Taylor 		qpc->alt_addr_path.sched_q =
32669e39c5baSBill Taylor 		    HERMON_QP_SCHEDQ_GET(0, 0, qp->qp_is_special);
32679e39c5baSBill Taylor 		qpc->pri_addr_path.pkey_indx = 0;
32689e39c5baSBill Taylor 
32699e39c5baSBill Taylor 	} else {
32709e39c5baSBill Taylor 		/*
32719e39c5baSBill Taylor 		 * Invalid QP transport type. If we got here then it's a
32729e39c5baSBill Taylor 		 * warning of a probably serious problem.  So print a message
32739e39c5baSBill Taylor 		 * and return failure
32749e39c5baSBill Taylor 		 */
32759e39c5baSBill Taylor 		HERMON_WARNING(state, "unknown QP transport type in rst2err");
32769e39c5baSBill Taylor 		return (ibc_get_ci_failure(0));
32779e39c5baSBill Taylor 	}
32789e39c5baSBill Taylor 
32799e39c5baSBill Taylor 	/*
32809e39c5baSBill Taylor 	 * Post the RST2INIT_QP command to the Hermon firmware
32819e39c5baSBill Taylor 	 *
32829e39c5baSBill Taylor 	 * We do a HERMON_NOSLEEP here because we are still holding the
32839e39c5baSBill Taylor 	 * "qp_lock".  If we got raised to interrupt level by priority
32849e39c5baSBill Taylor 	 * inversion, we do not want to block in this routine waiting for
32859e39c5baSBill Taylor 	 * success.
32869e39c5baSBill Taylor 	 */
32879e39c5baSBill Taylor 	status = hermon_cmn_qp_cmd_post(state, RST2INIT_QP, qpc, qp->qp_qpnum,
32889e39c5baSBill Taylor 	    0, HERMON_CMD_NOSLEEP_SPIN);
32899e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
32909e39c5baSBill Taylor 		cmn_err(CE_NOTE, "hermon%d: RST2INIT_QP command failed: %08x\n",
32919e39c5baSBill Taylor 		    state->hs_instance, status);
32929e39c5baSBill Taylor 		if (status == HERMON_CMD_INVALID_STATUS) {
32939e39c5baSBill Taylor 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
32949e39c5baSBill Taylor 		}
32959e39c5baSBill Taylor 		return (ibc_get_ci_failure(0));
32969e39c5baSBill Taylor 	}
32979e39c5baSBill Taylor 
32989e39c5baSBill Taylor 	/*
32999e39c5baSBill Taylor 	 * Now post the TOERR_QP command to the Hermon firmware
33009e39c5baSBill Taylor 	 *
33019e39c5baSBill Taylor 	 * We still do a HERMON_NOSLEEP here because we are still holding the
33029e39c5baSBill Taylor 	 * "qp_lock".  Note:  If this fails (which it really never should),
33039e39c5baSBill Taylor 	 * it indicates a serious problem in the HW or SW.  We try to move
33049e39c5baSBill Taylor 	 * the QP back to the "Reset" state if possible and print a warning
33059e39c5baSBill Taylor 	 * message if not.  In any case, we return an error here.
33069e39c5baSBill Taylor 	 */
33079e39c5baSBill Taylor 	status = hermon_cmn_qp_cmd_post(state, TOERR_QP, NULL, qp->qp_qpnum,
33089e39c5baSBill Taylor 	    0, HERMON_CMD_NOSLEEP_SPIN);
33099e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
33109e39c5baSBill Taylor 		cmn_err(CE_NOTE, "hermon%d: TOERR_QP command failed: %08x\n",
33119e39c5baSBill Taylor 		    state->hs_instance, status);
33129e39c5baSBill Taylor 		if (status == HERMON_CMD_INVALID_STATUS) {
33139e39c5baSBill Taylor 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
33149e39c5baSBill Taylor 		}
33159e39c5baSBill Taylor 		if (hermon_qp_to_reset(state, qp) != DDI_SUCCESS) {
33169e39c5baSBill Taylor 			HERMON_WARNING(state, "failed to reset QP context");
33179e39c5baSBill Taylor 		}
33189e39c5baSBill Taylor 		return (ibc_get_ci_failure(0));
33199e39c5baSBill Taylor 	}
33209e39c5baSBill Taylor 
33219e39c5baSBill Taylor 	return (DDI_SUCCESS);
33229e39c5baSBill Taylor }
33239e39c5baSBill Taylor 
33249e39c5baSBill Taylor 
33259e39c5baSBill Taylor /*
33269e39c5baSBill Taylor  * hermon_check_rdma_enable_flags()
33279e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
33289e39c5baSBill Taylor  */
33299e39c5baSBill Taylor static uint_t
hermon_check_rdma_enable_flags(ibt_cep_modify_flags_t flags,ibt_qp_info_t * info_p,hermon_hw_qpc_t * qpc)33309e39c5baSBill Taylor hermon_check_rdma_enable_flags(ibt_cep_modify_flags_t flags,
33319e39c5baSBill Taylor     ibt_qp_info_t *info_p, hermon_hw_qpc_t *qpc)
33329e39c5baSBill Taylor {
33339e39c5baSBill Taylor 	uint_t	opmask = 0;
33349e39c5baSBill Taylor 
33359e39c5baSBill Taylor 	if (flags & IBT_CEP_SET_RDMA_R) {
33369e39c5baSBill Taylor 		qpc->rre = (info_p->qp_flags & IBT_CEP_RDMA_RD) ? 1 : 0;
33379e39c5baSBill Taylor 		opmask |= HERMON_CMD_OP_RRE;
33389e39c5baSBill Taylor 	}
33399e39c5baSBill Taylor 
33409e39c5baSBill Taylor 	if (flags & IBT_CEP_SET_RDMA_W) {
33419e39c5baSBill Taylor 		qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
33429e39c5baSBill Taylor 		opmask |= HERMON_CMD_OP_RWE;
33439e39c5baSBill Taylor 	}
33449e39c5baSBill Taylor 
33459e39c5baSBill Taylor 	if (flags & IBT_CEP_SET_ATOMIC) {
33469e39c5baSBill Taylor 		qpc->rae = (info_p->qp_flags & IBT_CEP_ATOMIC) ? 1 : 0;
33479e39c5baSBill Taylor 		opmask |= HERMON_CMD_OP_RAE;
33489e39c5baSBill Taylor 	}
33499e39c5baSBill Taylor 
33509e39c5baSBill Taylor 	return (opmask);
33519e39c5baSBill Taylor }
33529e39c5baSBill Taylor 
33539e39c5baSBill Taylor /*
33549e39c5baSBill Taylor  * hermon_qp_validate_resp_rsrc()
33559e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
33569e39c5baSBill Taylor  */
33579e39c5baSBill Taylor static int
hermon_qp_validate_resp_rsrc(hermon_state_t * state,ibt_qp_rc_attr_t * rc,uint_t * rra_max)33589e39c5baSBill Taylor hermon_qp_validate_resp_rsrc(hermon_state_t *state, ibt_qp_rc_attr_t *rc,
33599e39c5baSBill Taylor     uint_t *rra_max)
33609e39c5baSBill Taylor {
33619e39c5baSBill Taylor 	uint_t	rdma_ra_in;
33629e39c5baSBill Taylor 
33639e39c5baSBill Taylor 	rdma_ra_in = rc->rc_rdma_ra_in;
33649e39c5baSBill Taylor 
33659e39c5baSBill Taylor 	/*
33669e39c5baSBill Taylor 	 * Check if number of responder resources is too large.  Return an
33679e39c5baSBill Taylor 	 * error if it is
33689e39c5baSBill Taylor 	 */
33699e39c5baSBill Taylor 	if (rdma_ra_in > state->hs_cfg_profile->cp_hca_max_rdma_in_qp) {
33709e39c5baSBill Taylor 		return (IBT_INVALID_PARAM);
33719e39c5baSBill Taylor 	}
33729e39c5baSBill Taylor 
33739e39c5baSBill Taylor 	/*
33749e39c5baSBill Taylor 	 * If the number of responder resources is too small, round it up.
33759e39c5baSBill Taylor 	 * Then find the next highest power-of-2
33769e39c5baSBill Taylor 	 */
33779e39c5baSBill Taylor 	if (rdma_ra_in == 0) {
33789e39c5baSBill Taylor 		rdma_ra_in = 1;
33799e39c5baSBill Taylor 	}
3380de710d24SJosef 'Jeff' Sipek 	if (ISP2(rdma_ra_in)) {
33819e39c5baSBill Taylor 		*rra_max = highbit(rdma_ra_in) - 1;
33829e39c5baSBill Taylor 	} else {
33839e39c5baSBill Taylor 		*rra_max = highbit(rdma_ra_in);
33849e39c5baSBill Taylor 	}
33859e39c5baSBill Taylor 	return (DDI_SUCCESS);
33869e39c5baSBill Taylor }
33879e39c5baSBill Taylor 
33889e39c5baSBill Taylor 
33899e39c5baSBill Taylor /*
33909e39c5baSBill Taylor  * hermon_qp_validate_init_depth()
33919e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
33929e39c5baSBill Taylor  */
33939e39c5baSBill Taylor static int
hermon_qp_validate_init_depth(hermon_state_t * state,ibt_qp_rc_attr_t * rc,uint_t * sra_max)33949e39c5baSBill Taylor hermon_qp_validate_init_depth(hermon_state_t *state, ibt_qp_rc_attr_t *rc,
33959e39c5baSBill Taylor     uint_t *sra_max)
33969e39c5baSBill Taylor {
33979e39c5baSBill Taylor 	uint_t	rdma_ra_out;
33989e39c5baSBill Taylor 
33999e39c5baSBill Taylor 	rdma_ra_out = rc->rc_rdma_ra_out;
34009e39c5baSBill Taylor 
34019e39c5baSBill Taylor 	/*
34029e39c5baSBill Taylor 	 * Check if requested initiator depth is too large.  Return an error
34039e39c5baSBill Taylor 	 * if it is
34049e39c5baSBill Taylor 	 */
34059e39c5baSBill Taylor 	if (rdma_ra_out > state->hs_cfg_profile->cp_hca_max_rdma_out_qp) {
34069e39c5baSBill Taylor 		return (IBT_INVALID_PARAM);
34079e39c5baSBill Taylor 	}
34089e39c5baSBill Taylor 
34099e39c5baSBill Taylor 	/*
34109e39c5baSBill Taylor 	 * If the requested initiator depth is too small, round it up.
34119e39c5baSBill Taylor 	 * Then find the next highest power-of-2
34129e39c5baSBill Taylor 	 */
34139e39c5baSBill Taylor 	if (rdma_ra_out == 0) {
34149e39c5baSBill Taylor 		rdma_ra_out = 1;
34159e39c5baSBill Taylor 	}
3416de710d24SJosef 'Jeff' Sipek 	if (ISP2(rdma_ra_out)) {
34179e39c5baSBill Taylor 		*sra_max = highbit(rdma_ra_out) - 1;
34189e39c5baSBill Taylor 	} else {
34199e39c5baSBill Taylor 		*sra_max = highbit(rdma_ra_out);
34209e39c5baSBill Taylor 	}
34219e39c5baSBill Taylor 	return (DDI_SUCCESS);
34229e39c5baSBill Taylor }
34239e39c5baSBill Taylor 
34249e39c5baSBill Taylor 
34259e39c5baSBill Taylor /*
34269e39c5baSBill Taylor  * hermon_qp_validate_mtu()
34279e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
34289e39c5baSBill Taylor  */
34299e39c5baSBill Taylor static int
hermon_qp_validate_mtu(hermon_state_t * state,uint_t mtu)34309e39c5baSBill Taylor hermon_qp_validate_mtu(hermon_state_t *state, uint_t mtu)
34319e39c5baSBill Taylor {
34329e39c5baSBill Taylor 	/*
34339e39c5baSBill Taylor 	 * Check for invalid MTU values (i.e. zero or any value larger than
34349e39c5baSBill Taylor 	 * the HCA's port maximum).
34359e39c5baSBill Taylor 	 */
34369e39c5baSBill Taylor 	if ((mtu == 0) || (mtu > state->hs_cfg_profile->cp_max_mtu)) {
34379e39c5baSBill Taylor 		return (IBT_HCA_PORT_MTU_EXCEEDED);
34389e39c5baSBill Taylor 	}
34399e39c5baSBill Taylor 	return (DDI_SUCCESS);
34409e39c5baSBill Taylor }
3441