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;
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;
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;
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;
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;
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;
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;
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;
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;
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,