xref: /onnv-gate/usr/src/uts/common/io/ib/adapters/hermon/hermon_qpmod.c (revision 12965:b65a8427f8fe)
19517SBill.Taylor@Sun.COM /*
29517SBill.Taylor@Sun.COM  * CDDL HEADER START
39517SBill.Taylor@Sun.COM  *
49517SBill.Taylor@Sun.COM  * The contents of this file are subject to the terms of the
59517SBill.Taylor@Sun.COM  * Common Development and Distribution License (the "License").
69517SBill.Taylor@Sun.COM  * You may not use this file except in compliance with the License.
79517SBill.Taylor@Sun.COM  *
89517SBill.Taylor@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99517SBill.Taylor@Sun.COM  * or http://www.opensolaris.org/os/licensing.
109517SBill.Taylor@Sun.COM  * See the License for the specific language governing permissions
119517SBill.Taylor@Sun.COM  * and limitations under the License.
129517SBill.Taylor@Sun.COM  *
139517SBill.Taylor@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
149517SBill.Taylor@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159517SBill.Taylor@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
169517SBill.Taylor@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
179517SBill.Taylor@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
189517SBill.Taylor@Sun.COM  *
199517SBill.Taylor@Sun.COM  * CDDL HEADER END
209517SBill.Taylor@Sun.COM  */
219517SBill.Taylor@Sun.COM 
229517SBill.Taylor@Sun.COM /*
23*12965SWilliam.Taylor@Oracle.COM  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
249517SBill.Taylor@Sun.COM  */
259517SBill.Taylor@Sun.COM 
269517SBill.Taylor@Sun.COM /*
279517SBill.Taylor@Sun.COM  * hermon_qpmod.c
289517SBill.Taylor@Sun.COM  *    Hermon Queue Pair Modify Routines
299517SBill.Taylor@Sun.COM  *
309517SBill.Taylor@Sun.COM  *    This contains all the routines necessary to implement the
319517SBill.Taylor@Sun.COM  *    ModifyQP() verb.  This includes all the code for legal
329517SBill.Taylor@Sun.COM  *    transitions to and from Reset, Init, RTR, RTS, SQD, SQErr,
339517SBill.Taylor@Sun.COM  *    and Error.
349517SBill.Taylor@Sun.COM  */
359517SBill.Taylor@Sun.COM 
369517SBill.Taylor@Sun.COM #include <sys/types.h>
379517SBill.Taylor@Sun.COM #include <sys/conf.h>
389517SBill.Taylor@Sun.COM #include <sys/ddi.h>
399517SBill.Taylor@Sun.COM #include <sys/sunddi.h>
409517SBill.Taylor@Sun.COM #include <sys/modctl.h>
419517SBill.Taylor@Sun.COM #include <sys/bitmap.h>
429517SBill.Taylor@Sun.COM 
439517SBill.Taylor@Sun.COM #include <sys/ib/adapters/hermon/hermon.h>
449517SBill.Taylor@Sun.COM #include <sys/ib/ib_pkt_hdrs.h>
459517SBill.Taylor@Sun.COM 
469517SBill.Taylor@Sun.COM static int hermon_qp_reset2init(hermon_state_t *state, hermon_qphdl_t qp,
479517SBill.Taylor@Sun.COM     ibt_qp_info_t *info_p);
489517SBill.Taylor@Sun.COM static int hermon_qp_init2init(hermon_state_t *state, hermon_qphdl_t qp,
499517SBill.Taylor@Sun.COM     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
509517SBill.Taylor@Sun.COM static int hermon_qp_init2rtr(hermon_state_t *state, hermon_qphdl_t qp,
519517SBill.Taylor@Sun.COM     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
529517SBill.Taylor@Sun.COM static int hermon_qp_rtr2rts(hermon_state_t *state, hermon_qphdl_t qp,
539517SBill.Taylor@Sun.COM     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
549517SBill.Taylor@Sun.COM static int hermon_qp_rts2rts(hermon_state_t *state, hermon_qphdl_t qp,
559517SBill.Taylor@Sun.COM     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
569517SBill.Taylor@Sun.COM #ifdef HERMON_NOTNOW
579517SBill.Taylor@Sun.COM static int hermon_qp_rts2sqd(hermon_state_t *state, hermon_qphdl_t qp,
589517SBill.Taylor@Sun.COM     ibt_cep_modify_flags_t flags);
599517SBill.Taylor@Sun.COM #endif
609517SBill.Taylor@Sun.COM static int hermon_qp_sqd2rts(hermon_state_t *state, hermon_qphdl_t qp,
619517SBill.Taylor@Sun.COM     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
629517SBill.Taylor@Sun.COM static int hermon_qp_sqd2sqd(hermon_state_t *state, hermon_qphdl_t qp,
639517SBill.Taylor@Sun.COM     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
649517SBill.Taylor@Sun.COM static int hermon_qp_sqerr2rts(hermon_state_t *state, hermon_qphdl_t qp,
659517SBill.Taylor@Sun.COM     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
669517SBill.Taylor@Sun.COM static int hermon_qp_to_error(hermon_state_t *state, hermon_qphdl_t qp);
679517SBill.Taylor@Sun.COM static int hermon_qp_reset2err(hermon_state_t *state, hermon_qphdl_t qp);
689517SBill.Taylor@Sun.COM 
699517SBill.Taylor@Sun.COM static uint_t hermon_check_rdma_enable_flags(ibt_cep_modify_flags_t flags,
709517SBill.Taylor@Sun.COM     ibt_qp_info_t *info_p, hermon_hw_qpc_t *qpc);
719517SBill.Taylor@Sun.COM static int hermon_qp_validate_resp_rsrc(hermon_state_t *state,
729517SBill.Taylor@Sun.COM     ibt_qp_rc_attr_t *rc, uint_t *rra_max);
739517SBill.Taylor@Sun.COM static int hermon_qp_validate_init_depth(hermon_state_t *state,
749517SBill.Taylor@Sun.COM     ibt_qp_rc_attr_t *rc, uint_t *sra_max);
759517SBill.Taylor@Sun.COM static int hermon_qp_validate_mtu(hermon_state_t *state, uint_t mtu);
769517SBill.Taylor@Sun.COM 
779517SBill.Taylor@Sun.COM /*
789517SBill.Taylor@Sun.COM  * hermon_qp_modify()
799517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
809517SBill.Taylor@Sun.COM  */
819517SBill.Taylor@Sun.COM /* ARGSUSED */
829517SBill.Taylor@Sun.COM 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)839517SBill.Taylor@Sun.COM hermon_qp_modify(hermon_state_t *state, hermon_qphdl_t qp,
849517SBill.Taylor@Sun.COM     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p,
859517SBill.Taylor@Sun.COM     ibt_queue_sizes_t *actual_sz)
869517SBill.Taylor@Sun.COM {
879517SBill.Taylor@Sun.COM 	ibt_cep_state_t		cur_state, mod_state;
889517SBill.Taylor@Sun.COM 	ibt_cep_modify_flags_t	okflags;
899517SBill.Taylor@Sun.COM 	int			status;
909517SBill.Taylor@Sun.COM 
919517SBill.Taylor@Sun.COM 	/*
929517SBill.Taylor@Sun.COM 	 * TODO add support for SUSPEND and RESUME
939517SBill.Taylor@Sun.COM 	 */
949517SBill.Taylor@Sun.COM 
959517SBill.Taylor@Sun.COM 	/*
969517SBill.Taylor@Sun.COM 	 * Lock the QP so that we can modify it atomically.  After grabbing
979517SBill.Taylor@Sun.COM 	 * the lock, get the current QP state.  We will use this current QP
989517SBill.Taylor@Sun.COM 	 * state to determine the legal transitions (and the checks that need
999517SBill.Taylor@Sun.COM 	 * to be performed.)
1009517SBill.Taylor@Sun.COM 	 * Below is a case for every possible QP state.  In each case, we
1019517SBill.Taylor@Sun.COM 	 * check that no flags are set which are not valid for the possible
1029517SBill.Taylor@Sun.COM 	 * transitions from that state.  If these tests pass and the
1039517SBill.Taylor@Sun.COM 	 * state transition we are attempting is legal, then we call one
1049517SBill.Taylor@Sun.COM 	 * of the helper functions.  Each of these functions does some
1059517SBill.Taylor@Sun.COM 	 * additional setup before posting the firmware command for the
1069517SBill.Taylor@Sun.COM 	 * appropriate state transition.
1079517SBill.Taylor@Sun.COM 	 */
1089517SBill.Taylor@Sun.COM 	mutex_enter(&qp->qp_lock);
1099517SBill.Taylor@Sun.COM 
1109517SBill.Taylor@Sun.COM 	/*
1119517SBill.Taylor@Sun.COM 	 * Verify that the transport type matches between the serv_type and the
1129517SBill.Taylor@Sun.COM 	 * qp_trans.  A caller to IBT must specify the qp_trans field as
1139517SBill.Taylor@Sun.COM 	 * IBT_UD_SRV, IBT_RC_SRV, or IBT_UC_SRV, depending on the QP.  We
1149517SBill.Taylor@Sun.COM 	 * check here that the correct value was specified, based on our
1159517SBill.Taylor@Sun.COM 	 * understanding of the QP serv type.
1169517SBill.Taylor@Sun.COM 	 *
1179517SBill.Taylor@Sun.COM 	 * Because callers specify part of a 'union' based on what QP type they
1189517SBill.Taylor@Sun.COM 	 * think they're working with, this ensures that we do not pickup bogus
1199517SBill.Taylor@Sun.COM 	 * data if the caller thought they were working with a different QP
1209517SBill.Taylor@Sun.COM 	 * type.
1219517SBill.Taylor@Sun.COM 	 */
1229517SBill.Taylor@Sun.COM 	if (!(HERMON_QP_TYPE_VALID(info_p->qp_trans, qp->qp_serv_type))) {
1239517SBill.Taylor@Sun.COM 		mutex_exit(&qp->qp_lock);
1249517SBill.Taylor@Sun.COM 		return (IBT_QP_SRV_TYPE_INVALID);
1259517SBill.Taylor@Sun.COM 	}
1269517SBill.Taylor@Sun.COM 
1279517SBill.Taylor@Sun.COM 	/*
1289517SBill.Taylor@Sun.COM 	 * If this is a transition to RTS (which is valid from RTR, RTS,
1299517SBill.Taylor@Sun.COM 	 * SQError, and SQ Drain) then we should honor the "current QP state"
1309517SBill.Taylor@Sun.COM 	 * specified by the consumer.  This means converting the IBTF QP state
1319517SBill.Taylor@Sun.COM 	 * in "info_p->qp_current_state" to an Hermon QP state.  Otherwise, we
1329517SBill.Taylor@Sun.COM 	 * assume that we already know the current state (i.e. whatever it was
1339517SBill.Taylor@Sun.COM 	 * last modified to or queried as - in "qp->qp_state").
1349517SBill.Taylor@Sun.COM 	 */
1359517SBill.Taylor@Sun.COM 	mod_state = info_p->qp_state;
1369517SBill.Taylor@Sun.COM 
1379517SBill.Taylor@Sun.COM 	if (flags & IBT_CEP_SET_RTR_RTS) {
1389517SBill.Taylor@Sun.COM 		cur_state = HERMON_QP_RTR;		/* Ready to Receive */
1399517SBill.Taylor@Sun.COM 
1409517SBill.Taylor@Sun.COM 	} else if ((flags & IBT_CEP_SET_STATE) &&
1419517SBill.Taylor@Sun.COM 	    (mod_state == IBT_STATE_RTS)) {
1429517SBill.Taylor@Sun.COM 
1439517SBill.Taylor@Sun.COM 		/* Convert the current IBTF QP state to an Hermon QP state */
1449517SBill.Taylor@Sun.COM 		switch (info_p->qp_current_state) {
1459517SBill.Taylor@Sun.COM 		case IBT_STATE_RTR:
1469517SBill.Taylor@Sun.COM 			cur_state = HERMON_QP_RTR;	/* Ready to Receive */
1479517SBill.Taylor@Sun.COM 			break;
1489517SBill.Taylor@Sun.COM 		case IBT_STATE_RTS:
1499517SBill.Taylor@Sun.COM 			cur_state = HERMON_QP_RTS;	/* Ready to Send */
1509517SBill.Taylor@Sun.COM 			break;
1519517SBill.Taylor@Sun.COM 		case IBT_STATE_SQE:
1529517SBill.Taylor@Sun.COM 			cur_state = HERMON_QP_SQERR;	/* Send Queue Error */
1539517SBill.Taylor@Sun.COM 			break;
1549517SBill.Taylor@Sun.COM 		case IBT_STATE_SQD:
1559517SBill.Taylor@Sun.COM 			cur_state = HERMON_QP_SQD;	/* SQ Drained */
1569517SBill.Taylor@Sun.COM 			break;
1579517SBill.Taylor@Sun.COM 		default:
1589517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
1599517SBill.Taylor@Sun.COM 			return (IBT_QP_STATE_INVALID);
1609517SBill.Taylor@Sun.COM 		}
1619517SBill.Taylor@Sun.COM 	} else {
1629517SBill.Taylor@Sun.COM 		cur_state = qp->qp_state;
1639517SBill.Taylor@Sun.COM 	}
1649517SBill.Taylor@Sun.COM 
1659517SBill.Taylor@Sun.COM 	switch (cur_state) {
1669517SBill.Taylor@Sun.COM 	case HERMON_QP_RESET:
1679517SBill.Taylor@Sun.COM 		okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_RESET_INIT |
1689517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_RDMA_R | IBT_CEP_SET_RDMA_W |
1699517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_ATOMIC | IBT_CEP_SET_PKEY_IX |
1709517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_PORT | IBT_CEP_SET_QKEY);
1719517SBill.Taylor@Sun.COM 
1729517SBill.Taylor@Sun.COM 		/*
1739517SBill.Taylor@Sun.COM 		 * Check for attempts to modify invalid attributes from the
1749517SBill.Taylor@Sun.COM 		 * "Reset" state
1759517SBill.Taylor@Sun.COM 		 */
1769517SBill.Taylor@Sun.COM 		if (flags & ~okflags) {
1779517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
1789517SBill.Taylor@Sun.COM 			status = IBT_QP_ATTR_RO;
1799517SBill.Taylor@Sun.COM 			goto qpmod_fail;
1809517SBill.Taylor@Sun.COM 		}
1819517SBill.Taylor@Sun.COM 
1829517SBill.Taylor@Sun.COM 		/*
1839517SBill.Taylor@Sun.COM 		 * Verify state transition is to either "Init", back to
1849517SBill.Taylor@Sun.COM 		 * "Reset", or to "Error".
1859517SBill.Taylor@Sun.COM 		 */
1869517SBill.Taylor@Sun.COM 		if ((flags & IBT_CEP_SET_RESET_INIT) &&
1879517SBill.Taylor@Sun.COM 		    (flags & IBT_CEP_SET_STATE) &&
1889517SBill.Taylor@Sun.COM 		    (mod_state != IBT_STATE_INIT)) {
1899517SBill.Taylor@Sun.COM 			/* Invalid transition - ambiguous flags */
1909517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
1919517SBill.Taylor@Sun.COM 			status = IBT_QP_STATE_INVALID;
1929517SBill.Taylor@Sun.COM 			goto qpmod_fail;
1939517SBill.Taylor@Sun.COM 
1949517SBill.Taylor@Sun.COM 		} else if ((flags & IBT_CEP_SET_RESET_INIT) ||
1959517SBill.Taylor@Sun.COM 		    ((flags & IBT_CEP_SET_STATE) &&
1969517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_INIT))) {
1979517SBill.Taylor@Sun.COM 			/*
1989517SBill.Taylor@Sun.COM 			 * Attempt to transition from "Reset" to "Init"
1999517SBill.Taylor@Sun.COM 			 */
2009517SBill.Taylor@Sun.COM 			status = hermon_qp_reset2init(state, qp, info_p);
2019517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
2029517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
2039517SBill.Taylor@Sun.COM 				goto qpmod_fail;
2049517SBill.Taylor@Sun.COM 			}
2059517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_INIT;
206*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_INIT);
2079517SBill.Taylor@Sun.COM 
2089517SBill.Taylor@Sun.COM 		} else if ((flags & IBT_CEP_SET_STATE) &&
2099517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_RESET)) {
2109517SBill.Taylor@Sun.COM 			/*
2119517SBill.Taylor@Sun.COM 			 * Attempt to transition from "Reset" back to "Reset"
2129517SBill.Taylor@Sun.COM 			 *    Nothing to do here really... just drop the lock
2139517SBill.Taylor@Sun.COM 			 *    and return success.  The qp->qp_state should
2149517SBill.Taylor@Sun.COM 			 *    already be set to HERMON_QP_RESET.
2159517SBill.Taylor@Sun.COM 			 *
2169517SBill.Taylor@Sun.COM 			 * Note: We return here because we do not want to fall
2179517SBill.Taylor@Sun.COM 			 *    through to the hermon_wrid_from_reset_handling()
2189517SBill.Taylor@Sun.COM 			 *    routine below (since we are not really moving
2199517SBill.Taylor@Sun.COM 			 *    _out_ of the "Reset" state.
2209517SBill.Taylor@Sun.COM 			 */
2219517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
2229517SBill.Taylor@Sun.COM 			return (DDI_SUCCESS);
2239517SBill.Taylor@Sun.COM 
2249517SBill.Taylor@Sun.COM 		} else if ((flags & IBT_CEP_SET_STATE) &&
2259517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_ERROR)) {
2269517SBill.Taylor@Sun.COM 			/*
2279517SBill.Taylor@Sun.COM 			 * Attempt to transition from "Reset" to "Error"
2289517SBill.Taylor@Sun.COM 			 */
2299517SBill.Taylor@Sun.COM 			status = hermon_qp_reset2err(state, qp);
2309517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
2319517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
2329517SBill.Taylor@Sun.COM 				goto qpmod_fail;
2339517SBill.Taylor@Sun.COM 			}
2349517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_ERR;
235*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
2369517SBill.Taylor@Sun.COM 
2379517SBill.Taylor@Sun.COM 		} else {
2389517SBill.Taylor@Sun.COM 			/* Invalid transition - return error */
2399517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
2409517SBill.Taylor@Sun.COM 			status = IBT_QP_STATE_INVALID;
2419517SBill.Taylor@Sun.COM 			goto qpmod_fail;
2429517SBill.Taylor@Sun.COM 		}
2439517SBill.Taylor@Sun.COM 
2449517SBill.Taylor@Sun.COM 		/*
2459517SBill.Taylor@Sun.COM 		 * Do any additional handling necessary here for the transition
2469517SBill.Taylor@Sun.COM 		 * from the "Reset" state (e.g. re-initialize the workQ WRID
2479517SBill.Taylor@Sun.COM 		 * lists).  Note: If hermon_wrid_from_reset_handling() fails,
2489517SBill.Taylor@Sun.COM 		 * then we attempt to transition the QP back to the "Reset"
2499517SBill.Taylor@Sun.COM 		 * state.  If that fails, then it is an indication of a serious
2509517SBill.Taylor@Sun.COM 		 * problem (either HW or SW).  So we print out a warning
2519517SBill.Taylor@Sun.COM 		 * message and return failure.
2529517SBill.Taylor@Sun.COM 		 */
2539517SBill.Taylor@Sun.COM 		status = hermon_wrid_from_reset_handling(state, qp);
2549517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
2559517SBill.Taylor@Sun.COM 			if (hermon_qp_to_reset(state, qp) != DDI_SUCCESS) {
2569517SBill.Taylor@Sun.COM 				HERMON_WARNING(state, "failed to reset QP");
2579517SBill.Taylor@Sun.COM 			}
2589517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_RESET;
259*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
2609517SBill.Taylor@Sun.COM 
2619517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
2629517SBill.Taylor@Sun.COM 			goto qpmod_fail;
2639517SBill.Taylor@Sun.COM 		}
2649517SBill.Taylor@Sun.COM 		break;
2659517SBill.Taylor@Sun.COM 
2669517SBill.Taylor@Sun.COM 	case HERMON_QP_INIT:
2679517SBill.Taylor@Sun.COM 		okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_INIT_RTR |
2689517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_ADDS_VECT | IBT_CEP_SET_RDMARA_IN |
2699517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_MIN_RNR_NAK | IBT_CEP_SET_ALT_PATH |
2709517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_RDMA_R | IBT_CEP_SET_RDMA_W |
2719517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_ATOMIC | IBT_CEP_SET_PKEY_IX |
2729517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_QKEY | IBT_CEP_SET_PORT);
2739517SBill.Taylor@Sun.COM 
2749517SBill.Taylor@Sun.COM 		/*
2759517SBill.Taylor@Sun.COM 		 * Check for attempts to modify invalid attributes from the
2769517SBill.Taylor@Sun.COM 		 * "Init" state
2779517SBill.Taylor@Sun.COM 		 */
2789517SBill.Taylor@Sun.COM 		if (flags & ~okflags) {
2799517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
2809517SBill.Taylor@Sun.COM 			status = IBT_QP_ATTR_RO;
2819517SBill.Taylor@Sun.COM 			goto qpmod_fail;
2829517SBill.Taylor@Sun.COM 		}
2839517SBill.Taylor@Sun.COM 
2849517SBill.Taylor@Sun.COM 		/*
2859517SBill.Taylor@Sun.COM 		 * Verify state transition is to either "RTR", back to "Init",
2869517SBill.Taylor@Sun.COM 		 * to "Reset", or to "Error"
2879517SBill.Taylor@Sun.COM 		 */
2889517SBill.Taylor@Sun.COM 		if ((flags & IBT_CEP_SET_INIT_RTR) &&
2899517SBill.Taylor@Sun.COM 		    (flags & IBT_CEP_SET_STATE) &&
2909517SBill.Taylor@Sun.COM 		    (mod_state != IBT_STATE_RTR)) {
2919517SBill.Taylor@Sun.COM 			/* Invalid transition - ambiguous flags */
2929517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
2939517SBill.Taylor@Sun.COM 			status = IBT_QP_STATE_INVALID;
2949517SBill.Taylor@Sun.COM 			goto qpmod_fail;
2959517SBill.Taylor@Sun.COM 
2969517SBill.Taylor@Sun.COM 		} else if ((flags & IBT_CEP_SET_INIT_RTR) ||
2979517SBill.Taylor@Sun.COM 		    ((flags & IBT_CEP_SET_STATE) &&
2989517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_RTR))) {
2999517SBill.Taylor@Sun.COM 			/*
3009517SBill.Taylor@Sun.COM 			 * Attempt to transition from "Init" to "RTR"
3019517SBill.Taylor@Sun.COM 			 */
3029517SBill.Taylor@Sun.COM 			status = hermon_qp_init2rtr(state, qp, flags, info_p);
3039517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
3049517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
3059517SBill.Taylor@Sun.COM 				goto qpmod_fail;
3069517SBill.Taylor@Sun.COM 			}
3079517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_RTR;
308*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTR);
3099517SBill.Taylor@Sun.COM 
3109517SBill.Taylor@Sun.COM 		} else if ((flags & IBT_CEP_SET_STATE) &&
3119517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_INIT)) {
3129517SBill.Taylor@Sun.COM 			/*
3139517SBill.Taylor@Sun.COM 			 * Attempt to transition from "Init" to "Init"
3149517SBill.Taylor@Sun.COM 			 */
3159517SBill.Taylor@Sun.COM 			status = hermon_qp_init2init(state, qp, flags, info_p);
3169517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
3179517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
3189517SBill.Taylor@Sun.COM 				goto qpmod_fail;
3199517SBill.Taylor@Sun.COM 			}
3209517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_INIT;
321*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_INIT);
3229517SBill.Taylor@Sun.COM 
3239517SBill.Taylor@Sun.COM 		} else if ((flags & IBT_CEP_SET_STATE) &&
3249517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_RESET)) {
3259517SBill.Taylor@Sun.COM 			/*
3269517SBill.Taylor@Sun.COM 			 * Attempt to transition from "Init" to "Reset"
3279517SBill.Taylor@Sun.COM 			 */
3289517SBill.Taylor@Sun.COM 			status = hermon_qp_to_reset(state, qp);
3299517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
3309517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
3319517SBill.Taylor@Sun.COM 				goto qpmod_fail;
3329517SBill.Taylor@Sun.COM 			}
3339517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_RESET;
334*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
3359517SBill.Taylor@Sun.COM 
3369517SBill.Taylor@Sun.COM 			/*
3379517SBill.Taylor@Sun.COM 			 * Do any additional handling necessary for the
3389517SBill.Taylor@Sun.COM 			 * transition _to_ the "Reset" state (e.g. update the
3399517SBill.Taylor@Sun.COM 			 * workQ WRID lists)
3409517SBill.Taylor@Sun.COM 			 */
3419517SBill.Taylor@Sun.COM 			status = hermon_wrid_to_reset_handling(state, qp);
3429517SBill.Taylor@Sun.COM 			if (status != IBT_SUCCESS) {
3439517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
3449517SBill.Taylor@Sun.COM 				goto qpmod_fail;
3459517SBill.Taylor@Sun.COM 			}
3469517SBill.Taylor@Sun.COM 
3479517SBill.Taylor@Sun.COM 		} else if ((flags & IBT_CEP_SET_STATE) &&
3489517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_ERROR)) {
3499517SBill.Taylor@Sun.COM 			/*
3509517SBill.Taylor@Sun.COM 			 * Attempt to transition from "Init" to "Error"
3519517SBill.Taylor@Sun.COM 			 */
3529517SBill.Taylor@Sun.COM 			status = hermon_qp_to_error(state, qp);
3539517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
3549517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
3559517SBill.Taylor@Sun.COM 				goto qpmod_fail;
3569517SBill.Taylor@Sun.COM 			}
3579517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_ERR;
358*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
3599517SBill.Taylor@Sun.COM 
3609517SBill.Taylor@Sun.COM 		} else {
3619517SBill.Taylor@Sun.COM 			/* Invalid transition - return error */
3629517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
3639517SBill.Taylor@Sun.COM 			status = IBT_QP_STATE_INVALID;
3649517SBill.Taylor@Sun.COM 			goto qpmod_fail;
3659517SBill.Taylor@Sun.COM 		}
3669517SBill.Taylor@Sun.COM 		break;
3679517SBill.Taylor@Sun.COM 
3689517SBill.Taylor@Sun.COM 	case HERMON_QP_RTR:
3699517SBill.Taylor@Sun.COM 		okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_RTR_RTS |
3709517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_TIMEOUT | IBT_CEP_SET_RETRY |
3719517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_RNR_NAK_RETRY | IBT_CEP_SET_RDMARA_OUT |
3729517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_RDMA_R | IBT_CEP_SET_RDMA_W |
3739517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_ATOMIC | IBT_CEP_SET_QKEY |
3749517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_ALT_PATH | IBT_CEP_SET_MIG |
3759517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_MIN_RNR_NAK);
3769517SBill.Taylor@Sun.COM 
3779517SBill.Taylor@Sun.COM 		/*
3789517SBill.Taylor@Sun.COM 		 * Check for attempts to modify invalid attributes from the
3799517SBill.Taylor@Sun.COM 		 * "RTR" state
3809517SBill.Taylor@Sun.COM 		 */
3819517SBill.Taylor@Sun.COM 		if (flags & ~okflags) {
3829517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
3839517SBill.Taylor@Sun.COM 			status = IBT_QP_ATTR_RO;
3849517SBill.Taylor@Sun.COM 			goto qpmod_fail;
3859517SBill.Taylor@Sun.COM 		}
3869517SBill.Taylor@Sun.COM 
3879517SBill.Taylor@Sun.COM 		/*
3889517SBill.Taylor@Sun.COM 		 * Verify state transition is to either "RTS", "Reset",
3899517SBill.Taylor@Sun.COM 		 * or "Error"
3909517SBill.Taylor@Sun.COM 		 */
3919517SBill.Taylor@Sun.COM 		if ((flags & IBT_CEP_SET_RTR_RTS) &&
3929517SBill.Taylor@Sun.COM 		    (flags & IBT_CEP_SET_STATE) &&
3939517SBill.Taylor@Sun.COM 		    (mod_state != IBT_STATE_RTS)) {
3949517SBill.Taylor@Sun.COM 			/* Invalid transition - ambiguous flags */
3959517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
3969517SBill.Taylor@Sun.COM 			status = IBT_QP_STATE_INVALID;
3979517SBill.Taylor@Sun.COM 			goto qpmod_fail;
3989517SBill.Taylor@Sun.COM 
3999517SBill.Taylor@Sun.COM 		} else if ((flags & IBT_CEP_SET_RTR_RTS) ||
4009517SBill.Taylor@Sun.COM 		    ((flags & IBT_CEP_SET_STATE) &&
4019517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_RTS))) {
4029517SBill.Taylor@Sun.COM 			/*
4039517SBill.Taylor@Sun.COM 			 * Attempt to transition from "RTR" to "RTS"
4049517SBill.Taylor@Sun.COM 			 */
4059517SBill.Taylor@Sun.COM 			status = hermon_qp_rtr2rts(state, qp, flags, info_p);
4069517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
4079517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
4089517SBill.Taylor@Sun.COM 				goto qpmod_fail;
4099517SBill.Taylor@Sun.COM 			}
4109517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_RTS;
411*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTS);
4129517SBill.Taylor@Sun.COM 
4139517SBill.Taylor@Sun.COM 		} else if ((flags & IBT_CEP_SET_STATE) &&
4149517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_RESET)) {
4159517SBill.Taylor@Sun.COM 			/*
4169517SBill.Taylor@Sun.COM 			 * Attempt to transition from "RTR" to "Reset"
4179517SBill.Taylor@Sun.COM 			 */
4189517SBill.Taylor@Sun.COM 			status = hermon_qp_to_reset(state, qp);
4199517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
4209517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
4219517SBill.Taylor@Sun.COM 				goto qpmod_fail;
4229517SBill.Taylor@Sun.COM 			}
4239517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_RESET;
424*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
4259517SBill.Taylor@Sun.COM 
4269517SBill.Taylor@Sun.COM 			/*
4279517SBill.Taylor@Sun.COM 			 * Do any additional handling necessary for the
4289517SBill.Taylor@Sun.COM 			 * transition _to_ the "Reset" state (e.g. update the
4299517SBill.Taylor@Sun.COM 			 * workQ WRID lists)
4309517SBill.Taylor@Sun.COM 			 */
4319517SBill.Taylor@Sun.COM 			status = hermon_wrid_to_reset_handling(state, qp);
4329517SBill.Taylor@Sun.COM 			if (status != IBT_SUCCESS) {
4339517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
4349517SBill.Taylor@Sun.COM 				goto qpmod_fail;
4359517SBill.Taylor@Sun.COM 			}
4369517SBill.Taylor@Sun.COM 
4379517SBill.Taylor@Sun.COM 		} else if ((flags & IBT_CEP_SET_STATE) &&
4389517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_ERROR)) {
4399517SBill.Taylor@Sun.COM 			/*
4409517SBill.Taylor@Sun.COM 			 * Attempt to transition from "RTR" to "Error"
4419517SBill.Taylor@Sun.COM 			 */
4429517SBill.Taylor@Sun.COM 			status = hermon_qp_to_error(state, qp);
4439517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
4449517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
4459517SBill.Taylor@Sun.COM 				goto qpmod_fail;
4469517SBill.Taylor@Sun.COM 			}
4479517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_ERR;
448*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
4499517SBill.Taylor@Sun.COM 
4509517SBill.Taylor@Sun.COM 		} else {
4519517SBill.Taylor@Sun.COM 			/* Invalid transition - return error */
4529517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
4539517SBill.Taylor@Sun.COM 			status = IBT_QP_STATE_INVALID;
4549517SBill.Taylor@Sun.COM 			goto qpmod_fail;
4559517SBill.Taylor@Sun.COM 		}
4569517SBill.Taylor@Sun.COM 		break;
4579517SBill.Taylor@Sun.COM 
4589517SBill.Taylor@Sun.COM 	case HERMON_QP_RTS:
4599517SBill.Taylor@Sun.COM 		okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_RDMA_R |
4609517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_RDMA_W | IBT_CEP_SET_ATOMIC |
4619517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_QKEY | IBT_CEP_SET_ALT_PATH |
4629517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_MIG | IBT_CEP_SET_MIN_RNR_NAK |
4639517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_SQD_EVENT);
4649517SBill.Taylor@Sun.COM 
4659517SBill.Taylor@Sun.COM 		/*
4669517SBill.Taylor@Sun.COM 		 * Check for attempts to modify invalid attributes from the
4679517SBill.Taylor@Sun.COM 		 * "RTS" state
4689517SBill.Taylor@Sun.COM 		 */
4699517SBill.Taylor@Sun.COM 		if (flags & ~okflags) {
4709517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
4719517SBill.Taylor@Sun.COM 			status = IBT_QP_ATTR_RO;
4729517SBill.Taylor@Sun.COM 			goto qpmod_fail;
4739517SBill.Taylor@Sun.COM 		}
4749517SBill.Taylor@Sun.COM 
4759517SBill.Taylor@Sun.COM 		/*
4769517SBill.Taylor@Sun.COM 		 * Verify state transition is to either "RTS", "SQD", "Reset",
4779517SBill.Taylor@Sun.COM 		 * or "Error"
4789517SBill.Taylor@Sun.COM 		 */
4799517SBill.Taylor@Sun.COM 		if ((flags & IBT_CEP_SET_STATE) &&
4809517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_RTS)) {
4819517SBill.Taylor@Sun.COM 			/*
4829517SBill.Taylor@Sun.COM 			 * Attempt to transition from "RTS" to "RTS"
4839517SBill.Taylor@Sun.COM 			 */
4849517SBill.Taylor@Sun.COM 			status = hermon_qp_rts2rts(state, qp, flags, info_p);
4859517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
4869517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
4879517SBill.Taylor@Sun.COM 				goto qpmod_fail;
4889517SBill.Taylor@Sun.COM 			}
4899517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_RTS;
490*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTS);
4919517SBill.Taylor@Sun.COM 
4929517SBill.Taylor@Sun.COM 		} else if ((flags & IBT_CEP_SET_STATE) &&
4939517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_SQD)) {
4949517SBill.Taylor@Sun.COM #ifdef HERMON_NOTNOW
4959517SBill.Taylor@Sun.COM 			/*
4969517SBill.Taylor@Sun.COM 			 * Attempt to transition from "RTS" to "SQD"
4979517SBill.Taylor@Sun.COM 			 */
4989517SBill.Taylor@Sun.COM 			status = hermon_qp_rts2sqd(state, qp, flags);
4999517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
5009517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
5019517SBill.Taylor@Sun.COM 				goto qpmod_fail;
5029517SBill.Taylor@Sun.COM 			}
5039517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_SQD;
504*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_SQD);
5059517SBill.Taylor@Sun.COM #else
5069517SBill.Taylor@Sun.COM 			/* hack because of the lack of fw support for SQD */
5079517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
5089517SBill.Taylor@Sun.COM 			status = IBT_QP_STATE_INVALID;
5099517SBill.Taylor@Sun.COM 			goto qpmod_fail;
5109517SBill.Taylor@Sun.COM #endif
5119517SBill.Taylor@Sun.COM 
5129517SBill.Taylor@Sun.COM 		} else if ((flags & IBT_CEP_SET_STATE) &&
5139517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_RESET)) {
5149517SBill.Taylor@Sun.COM 			/*
5159517SBill.Taylor@Sun.COM 			 * Attempt to transition from "RTS" to "Reset"
5169517SBill.Taylor@Sun.COM 			 */
5179517SBill.Taylor@Sun.COM 			status = hermon_qp_to_reset(state, qp);
5189517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
5199517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
5209517SBill.Taylor@Sun.COM 				goto qpmod_fail;
5219517SBill.Taylor@Sun.COM 			}
5229517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_RESET;
523*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
5249517SBill.Taylor@Sun.COM 
5259517SBill.Taylor@Sun.COM 			/*
5269517SBill.Taylor@Sun.COM 			 * Do any additional handling necessary for the
5279517SBill.Taylor@Sun.COM 			 * transition _to_ the "Reset" state (e.g. update the
5289517SBill.Taylor@Sun.COM 			 * workQ WRID lists)
5299517SBill.Taylor@Sun.COM 			 */
5309517SBill.Taylor@Sun.COM 			status = hermon_wrid_to_reset_handling(state, qp);
5319517SBill.Taylor@Sun.COM 			if (status != IBT_SUCCESS) {
5329517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
5339517SBill.Taylor@Sun.COM 				goto qpmod_fail;
5349517SBill.Taylor@Sun.COM 			}
5359517SBill.Taylor@Sun.COM 
5369517SBill.Taylor@Sun.COM 		} else if ((flags & IBT_CEP_SET_STATE) &&
5379517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_ERROR)) {
5389517SBill.Taylor@Sun.COM 			/*
5399517SBill.Taylor@Sun.COM 			 * Attempt to transition from "RTS" to "Error"
5409517SBill.Taylor@Sun.COM 			 */
5419517SBill.Taylor@Sun.COM 			status = hermon_qp_to_error(state, qp);
5429517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
5439517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
5449517SBill.Taylor@Sun.COM 				goto qpmod_fail;
5459517SBill.Taylor@Sun.COM 			}
5469517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_ERR;
547*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
5489517SBill.Taylor@Sun.COM 
5499517SBill.Taylor@Sun.COM 		} else {
5509517SBill.Taylor@Sun.COM 			/* Invalid transition - return error */
5519517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
5529517SBill.Taylor@Sun.COM 			status = IBT_QP_STATE_INVALID;
5539517SBill.Taylor@Sun.COM 			goto qpmod_fail;
5549517SBill.Taylor@Sun.COM 		}
5559517SBill.Taylor@Sun.COM 		break;
5569517SBill.Taylor@Sun.COM 
5579517SBill.Taylor@Sun.COM 	case HERMON_QP_SQERR:
5589517SBill.Taylor@Sun.COM 		okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_RDMA_R |
5599517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_RDMA_W | IBT_CEP_SET_ATOMIC |
5609517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_QKEY | IBT_CEP_SET_MIN_RNR_NAK);
5619517SBill.Taylor@Sun.COM 
5629517SBill.Taylor@Sun.COM 		/*
5639517SBill.Taylor@Sun.COM 		 * Check for attempts to modify invalid attributes from the
5649517SBill.Taylor@Sun.COM 		 * "SQErr" state
5659517SBill.Taylor@Sun.COM 		 */
5669517SBill.Taylor@Sun.COM 		if (flags & ~okflags) {
5679517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
5689517SBill.Taylor@Sun.COM 			status = IBT_QP_ATTR_RO;
5699517SBill.Taylor@Sun.COM 			goto qpmod_fail;
5709517SBill.Taylor@Sun.COM 		}
5719517SBill.Taylor@Sun.COM 
5729517SBill.Taylor@Sun.COM 		/*
5739517SBill.Taylor@Sun.COM 		 * Verify state transition is to either "RTS", "Reset", or
5749517SBill.Taylor@Sun.COM 		 * "Error"
5759517SBill.Taylor@Sun.COM 		 */
5769517SBill.Taylor@Sun.COM 		if ((flags & IBT_CEP_SET_STATE) &&
5779517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_RTS)) {
5789517SBill.Taylor@Sun.COM 			/*
5799517SBill.Taylor@Sun.COM 			 * Attempt to transition from "SQErr" to "RTS"
5809517SBill.Taylor@Sun.COM 			 */
5819517SBill.Taylor@Sun.COM 			status = hermon_qp_sqerr2rts(state, qp, flags, info_p);
5829517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
5839517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
5849517SBill.Taylor@Sun.COM 				goto qpmod_fail;
5859517SBill.Taylor@Sun.COM 			}
5869517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_RTS;
587*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTS);
5889517SBill.Taylor@Sun.COM 
5899517SBill.Taylor@Sun.COM 		} else if ((flags & IBT_CEP_SET_STATE) &&
5909517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_RESET)) {
5919517SBill.Taylor@Sun.COM 			/*
5929517SBill.Taylor@Sun.COM 			 * Attempt to transition from "SQErr" to "Reset"
5939517SBill.Taylor@Sun.COM 			 */
5949517SBill.Taylor@Sun.COM 			status = hermon_qp_to_reset(state, qp);
5959517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
5969517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
5979517SBill.Taylor@Sun.COM 				goto qpmod_fail;
5989517SBill.Taylor@Sun.COM 			}
5999517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_RESET;
600*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
6019517SBill.Taylor@Sun.COM 
6029517SBill.Taylor@Sun.COM 			/*
6039517SBill.Taylor@Sun.COM 			 * Do any additional handling necessary for the
6049517SBill.Taylor@Sun.COM 			 * transition _to_ the "Reset" state (e.g. update the
6059517SBill.Taylor@Sun.COM 			 * workQ WRID lists)
6069517SBill.Taylor@Sun.COM 			 */
6079517SBill.Taylor@Sun.COM 			status = hermon_wrid_to_reset_handling(state, qp);
6089517SBill.Taylor@Sun.COM 			if (status != IBT_SUCCESS) {
6099517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
6109517SBill.Taylor@Sun.COM 				goto qpmod_fail;
6119517SBill.Taylor@Sun.COM 			}
6129517SBill.Taylor@Sun.COM 
6139517SBill.Taylor@Sun.COM 		} else if ((flags & IBT_CEP_SET_STATE) &&
6149517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_ERROR)) {
6159517SBill.Taylor@Sun.COM 			/*
6169517SBill.Taylor@Sun.COM 			 * Attempt to transition from "SQErr" to "Error"
6179517SBill.Taylor@Sun.COM 			 */
6189517SBill.Taylor@Sun.COM 			status = hermon_qp_to_error(state, qp);
6199517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
6209517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
6219517SBill.Taylor@Sun.COM 				goto qpmod_fail;
6229517SBill.Taylor@Sun.COM 			}
6239517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_ERR;
624*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
6259517SBill.Taylor@Sun.COM 
6269517SBill.Taylor@Sun.COM 		} else {
6279517SBill.Taylor@Sun.COM 			/* Invalid transition - return error */
6289517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
6299517SBill.Taylor@Sun.COM 			status = IBT_QP_STATE_INVALID;
6309517SBill.Taylor@Sun.COM 			goto qpmod_fail;
6319517SBill.Taylor@Sun.COM 		}
6329517SBill.Taylor@Sun.COM 		break;
6339517SBill.Taylor@Sun.COM 
6349517SBill.Taylor@Sun.COM 	case HERMON_QP_SQD:
6359517SBill.Taylor@Sun.COM 		okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_ADDS_VECT |
6369517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_ALT_PATH | IBT_CEP_SET_MIG |
6379517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_RDMARA_OUT | IBT_CEP_SET_RDMARA_IN |
6389517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_QKEY | IBT_CEP_SET_PKEY_IX |
6399517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_TIMEOUT | IBT_CEP_SET_RETRY |
6409517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_RNR_NAK_RETRY | IBT_CEP_SET_PORT |
6419517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_MIN_RNR_NAK | IBT_CEP_SET_RDMA_R |
6429517SBill.Taylor@Sun.COM 		    IBT_CEP_SET_RDMA_W | IBT_CEP_SET_ATOMIC);
6439517SBill.Taylor@Sun.COM 
6449517SBill.Taylor@Sun.COM 		/*
6459517SBill.Taylor@Sun.COM 		 * Check for attempts to modify invalid attributes from the
6469517SBill.Taylor@Sun.COM 		 * "SQD" state
6479517SBill.Taylor@Sun.COM 		 */
6489517SBill.Taylor@Sun.COM 		if (flags & ~okflags) {
6499517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
6509517SBill.Taylor@Sun.COM 			status = IBT_QP_ATTR_RO;
6519517SBill.Taylor@Sun.COM 			goto qpmod_fail;
6529517SBill.Taylor@Sun.COM 		}
6539517SBill.Taylor@Sun.COM 
6549517SBill.Taylor@Sun.COM 		/*
6559517SBill.Taylor@Sun.COM 		 * Verify state transition is to either "SQD", "RTS", "Reset",
6569517SBill.Taylor@Sun.COM 		 * or "Error"
6579517SBill.Taylor@Sun.COM 		 */
6589517SBill.Taylor@Sun.COM 
6599517SBill.Taylor@Sun.COM 		if ((flags & IBT_CEP_SET_STATE) &&
6609517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_SQD)) {
6619517SBill.Taylor@Sun.COM 			/*
6629517SBill.Taylor@Sun.COM 			 * Attempt to transition from "SQD" to "SQD"
6639517SBill.Taylor@Sun.COM 			 */
6649517SBill.Taylor@Sun.COM 			status = hermon_qp_sqd2sqd(state, qp, flags, info_p);
6659517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
6669517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
6679517SBill.Taylor@Sun.COM 				goto qpmod_fail;
6689517SBill.Taylor@Sun.COM 			}
6699517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_SQD;
670*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_SQD);
6719517SBill.Taylor@Sun.COM 
6729517SBill.Taylor@Sun.COM 		} else if ((flags & IBT_CEP_SET_STATE) &&
6739517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_RTS)) {
6749517SBill.Taylor@Sun.COM 			/*
6759517SBill.Taylor@Sun.COM 			 * If still draining SQ, then fail transition attempt
6769517SBill.Taylor@Sun.COM 			 * to RTS, even though this is now done is two steps
6779517SBill.Taylor@Sun.COM 			 * (see below) if the consumer has tried this before
6789517SBill.Taylor@Sun.COM 			 * it's drained, let him fail and wait appropriately
6799517SBill.Taylor@Sun.COM 			 */
6809517SBill.Taylor@Sun.COM 			if (qp->qp_sqd_still_draining) {
6819517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
6829517SBill.Taylor@Sun.COM 				goto qpmod_fail;
6839517SBill.Taylor@Sun.COM 			}
6849517SBill.Taylor@Sun.COM 			/*
6859517SBill.Taylor@Sun.COM 			 * IBA 1.2 has changed - most/all the things that were
6869517SBill.Taylor@Sun.COM 			 * done in SQD2RTS can be done in SQD2SQD.  So make this
6879517SBill.Taylor@Sun.COM 			 * a 2-step process.  First, set any attributes requsted
6889517SBill.Taylor@Sun.COM 			 * w/ SQD2SQD, but no real transition.
6899517SBill.Taylor@Sun.COM 			 *
6909517SBill.Taylor@Sun.COM 			 * First, Attempt to transition from "SQD" to "SQD"
6919517SBill.Taylor@Sun.COM 			 */
6929517SBill.Taylor@Sun.COM 			status = hermon_qp_sqd2sqd(state, qp, flags, info_p);
6939517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
6949517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
6959517SBill.Taylor@Sun.COM 				goto qpmod_fail;
6969517SBill.Taylor@Sun.COM 			}
6979517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_SQD;
698*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_SQD);
6999517SBill.Taylor@Sun.COM 
7009517SBill.Taylor@Sun.COM 			/*
7019517SBill.Taylor@Sun.COM 			 * The, attempt to transition from "SQD" to "RTS", but
7029517SBill.Taylor@Sun.COM 			 * request only the state transition, no attributes
7039517SBill.Taylor@Sun.COM 			 */
7049517SBill.Taylor@Sun.COM 
7059517SBill.Taylor@Sun.COM 			status = hermon_qp_sqd2rts(state, qp,
7069517SBill.Taylor@Sun.COM 			    IBT_CEP_SET_STATE, info_p);
7079517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
7089517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
7099517SBill.Taylor@Sun.COM 				goto qpmod_fail;
7109517SBill.Taylor@Sun.COM 			}
7119517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_RTS;
712*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTS);
7139517SBill.Taylor@Sun.COM 
7149517SBill.Taylor@Sun.COM 		} else if ((flags & IBT_CEP_SET_STATE) &&
7159517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_RESET)) {
7169517SBill.Taylor@Sun.COM 			/*
7179517SBill.Taylor@Sun.COM 			 * Attempt to transition from "SQD" to "Reset"
7189517SBill.Taylor@Sun.COM 			 */
7199517SBill.Taylor@Sun.COM 			status = hermon_qp_to_reset(state, qp);
7209517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
7219517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
7229517SBill.Taylor@Sun.COM 				goto qpmod_fail;
7239517SBill.Taylor@Sun.COM 			}
7249517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_RESET;
725*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
7269517SBill.Taylor@Sun.COM 
7279517SBill.Taylor@Sun.COM 			/*
7289517SBill.Taylor@Sun.COM 			 * Do any additional handling necessary for the
7299517SBill.Taylor@Sun.COM 			 * transition _to_ the "Reset" state (e.g. update the
7309517SBill.Taylor@Sun.COM 			 * workQ WRID lists)
7319517SBill.Taylor@Sun.COM 			 */
7329517SBill.Taylor@Sun.COM 			status = hermon_wrid_to_reset_handling(state, qp);
7339517SBill.Taylor@Sun.COM 			if (status != IBT_SUCCESS) {
7349517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
7359517SBill.Taylor@Sun.COM 				goto qpmod_fail;
7369517SBill.Taylor@Sun.COM 			}
7379517SBill.Taylor@Sun.COM 
7389517SBill.Taylor@Sun.COM 		} else if ((flags & IBT_CEP_SET_STATE) &&
7399517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_ERROR)) {
7409517SBill.Taylor@Sun.COM 			/*
7419517SBill.Taylor@Sun.COM 			 * Attempt to transition from "SQD" to "Error"
7429517SBill.Taylor@Sun.COM 			 */
7439517SBill.Taylor@Sun.COM 			status = hermon_qp_to_error(state, qp);
7449517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
7459517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
7469517SBill.Taylor@Sun.COM 				goto qpmod_fail;
7479517SBill.Taylor@Sun.COM 			}
7489517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_ERR;
749*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
7509517SBill.Taylor@Sun.COM 
7519517SBill.Taylor@Sun.COM 		} else {
7529517SBill.Taylor@Sun.COM 			/* Invalid transition - return error */
7539517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
7549517SBill.Taylor@Sun.COM 			status = IBT_QP_STATE_INVALID;
7559517SBill.Taylor@Sun.COM 			goto qpmod_fail;
7569517SBill.Taylor@Sun.COM 		}
7579517SBill.Taylor@Sun.COM 		break;
7589517SBill.Taylor@Sun.COM 
7599517SBill.Taylor@Sun.COM 	case HERMON_QP_ERR:
7609517SBill.Taylor@Sun.COM 		/*
7619517SBill.Taylor@Sun.COM 		 * Verify state transition is to either "Reset" or back to
7629517SBill.Taylor@Sun.COM 		 * "Error"
7639517SBill.Taylor@Sun.COM 		 */
7649517SBill.Taylor@Sun.COM 		if ((flags & IBT_CEP_SET_STATE) &&
7659517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_RESET)) {
7669517SBill.Taylor@Sun.COM 			/*
7679517SBill.Taylor@Sun.COM 			 * Attempt to transition from "Error" to "Reset"
7689517SBill.Taylor@Sun.COM 			 */
7699517SBill.Taylor@Sun.COM 			status = hermon_qp_to_reset(state, qp);
7709517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
7719517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
7729517SBill.Taylor@Sun.COM 				goto qpmod_fail;
7739517SBill.Taylor@Sun.COM 			}
7749517SBill.Taylor@Sun.COM 			qp->qp_state = HERMON_QP_RESET;
775*12965SWilliam.Taylor@Oracle.COM 			HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
7769517SBill.Taylor@Sun.COM 
7779517SBill.Taylor@Sun.COM 			/*
7789517SBill.Taylor@Sun.COM 			 * Do any additional handling necessary for the
7799517SBill.Taylor@Sun.COM 			 * transition _to_ the "Reset" state (e.g. update the
7809517SBill.Taylor@Sun.COM 			 * workQ WRID lists)
7819517SBill.Taylor@Sun.COM 			 */
7829517SBill.Taylor@Sun.COM 			status = hermon_wrid_to_reset_handling(state, qp);
7839517SBill.Taylor@Sun.COM 			if (status != IBT_SUCCESS) {
7849517SBill.Taylor@Sun.COM 				mutex_exit(&qp->qp_lock);
7859517SBill.Taylor@Sun.COM 				goto qpmod_fail;
7869517SBill.Taylor@Sun.COM 			}
7879517SBill.Taylor@Sun.COM 
7889517SBill.Taylor@Sun.COM 		} else if ((flags & IBT_CEP_SET_STATE) &&
7899517SBill.Taylor@Sun.COM 		    (mod_state == IBT_STATE_ERROR)) {
7909517SBill.Taylor@Sun.COM 			/*
7919517SBill.Taylor@Sun.COM 			 * Attempt to transition from "Error" back to "Error"
7929517SBill.Taylor@Sun.COM 			 *    Nothing to do here really... just drop the lock
7939517SBill.Taylor@Sun.COM 			 *    and return success.  The qp->qp_state should
7949517SBill.Taylor@Sun.COM 			 *    already be set to HERMON_QP_ERR.
7959517SBill.Taylor@Sun.COM 			 *
7969517SBill.Taylor@Sun.COM 			 */
7979517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
7989517SBill.Taylor@Sun.COM 			return (DDI_SUCCESS);
7999517SBill.Taylor@Sun.COM 
8009517SBill.Taylor@Sun.COM 		} else {
8019517SBill.Taylor@Sun.COM 			/* Invalid transition - return error */
8029517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
8039517SBill.Taylor@Sun.COM 			status = IBT_QP_STATE_INVALID;
8049517SBill.Taylor@Sun.COM 			goto qpmod_fail;
8059517SBill.Taylor@Sun.COM 		}
8069517SBill.Taylor@Sun.COM 		break;
8079517SBill.Taylor@Sun.COM 
8089517SBill.Taylor@Sun.COM 	default:
8099517SBill.Taylor@Sun.COM 		/*
8109517SBill.Taylor@Sun.COM 		 * Invalid QP state.  If we got here then it's a warning of
8119517SBill.Taylor@Sun.COM 		 * a probably serious problem.  So print a message and return
8129517SBill.Taylor@Sun.COM 		 * failure
8139517SBill.Taylor@Sun.COM 		 */
8149517SBill.Taylor@Sun.COM 		mutex_exit(&qp->qp_lock);
8159517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "unknown QP state in modify");
8169517SBill.Taylor@Sun.COM 		status = IBT_QP_STATE_INVALID;
8179517SBill.Taylor@Sun.COM 		goto qpmod_fail;
8189517SBill.Taylor@Sun.COM 	}
8199517SBill.Taylor@Sun.COM 
8209517SBill.Taylor@Sun.COM 	mutex_exit(&qp->qp_lock);
8219517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
8229517SBill.Taylor@Sun.COM 
8239517SBill.Taylor@Sun.COM qpmod_fail:
8249517SBill.Taylor@Sun.COM 	return (status);
8259517SBill.Taylor@Sun.COM }
8269517SBill.Taylor@Sun.COM 
8279517SBill.Taylor@Sun.COM 
8289517SBill.Taylor@Sun.COM /*
8299517SBill.Taylor@Sun.COM  * hermon_qp_reset2init()
8309517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
8319517SBill.Taylor@Sun.COM  */
8329517SBill.Taylor@Sun.COM static int
hermon_qp_reset2init(hermon_state_t * state,hermon_qphdl_t qp,ibt_qp_info_t * info_p)8339517SBill.Taylor@Sun.COM hermon_qp_reset2init(hermon_state_t *state, hermon_qphdl_t qp,
8349517SBill.Taylor@Sun.COM     ibt_qp_info_t *info_p)
8359517SBill.Taylor@Sun.COM {
8369517SBill.Taylor@Sun.COM 	hermon_hw_qpc_t		*qpc;
8379517SBill.Taylor@Sun.COM 	ibt_qp_rc_attr_t	*rc;
8389517SBill.Taylor@Sun.COM 	ibt_qp_ud_attr_t	*ud;
8399517SBill.Taylor@Sun.COM 	ibt_qp_uc_attr_t	*uc;
8409517SBill.Taylor@Sun.COM 	uint_t			portnum, pkeyindx;
8419517SBill.Taylor@Sun.COM 	int			status;
8429517SBill.Taylor@Sun.COM 	uint32_t		cqnmask;
843*12965SWilliam.Taylor@Oracle.COM 	int			qp_srq_en;
8449517SBill.Taylor@Sun.COM 
8459517SBill.Taylor@Sun.COM 	ASSERT(MUTEX_HELD(&qp->qp_lock));
8469517SBill.Taylor@Sun.COM 
8479517SBill.Taylor@Sun.COM 	/*
8489517SBill.Taylor@Sun.COM 	 * Grab the temporary QPC entry from QP software state
8499517SBill.Taylor@Sun.COM 	 */
8509517SBill.Taylor@Sun.COM 	qpc = &qp->qpc;
8519517SBill.Taylor@Sun.COM 
8529517SBill.Taylor@Sun.COM 	/*
8539517SBill.Taylor@Sun.COM 	 * Fill in the common fields in the QPC
8549517SBill.Taylor@Sun.COM 	 */
8559517SBill.Taylor@Sun.COM 
8569517SBill.Taylor@Sun.COM 	if (qp->qp_is_special) {
8579517SBill.Taylor@Sun.COM 		qpc->serv_type	= HERMON_QP_MLX;
8589517SBill.Taylor@Sun.COM 	} else {
8599517SBill.Taylor@Sun.COM 		qpc->serv_type	= qp->qp_serv_type;
8609517SBill.Taylor@Sun.COM 	}
8619517SBill.Taylor@Sun.COM 	qpc->pm_state		= HERMON_QP_PMSTATE_MIGRATED;
8629517SBill.Taylor@Sun.COM 
8639517SBill.Taylor@Sun.COM 	qpc->pd			= qp->qp_pdhdl->pd_pdnum;
8649517SBill.Taylor@Sun.COM 
8659517SBill.Taylor@Sun.COM 	qpc->log_sq_stride	= qp->qp_sq_log_wqesz - 4;
8669517SBill.Taylor@Sun.COM 	qpc->log_rq_stride	= qp->qp_rq_log_wqesz - 4;
8679517SBill.Taylor@Sun.COM 	qpc->sq_no_prefetch	= qp->qp_no_prefetch;
8689517SBill.Taylor@Sun.COM 	qpc->log_sq_size	= highbit(qp->qp_sq_bufsz) - 1;
8699517SBill.Taylor@Sun.COM 	qpc->log_rq_size	= highbit(qp->qp_rq_bufsz) - 1;
8709517SBill.Taylor@Sun.COM 
8719517SBill.Taylor@Sun.COM 	qpc->usr_page		= qp->qp_uarpg;
8729517SBill.Taylor@Sun.COM 
8739517SBill.Taylor@Sun.COM 	cqnmask = (1 << state->hs_cfg_profile->cp_log_num_cq) - 1;
874*12965SWilliam.Taylor@Oracle.COM 	qpc->cqn_snd		=
875*12965SWilliam.Taylor@Oracle.COM 	    (qp->qp_sq_cqhdl == NULL) ? 0 : qp->qp_sq_cqhdl->cq_cqnum & cqnmask;
8769517SBill.Taylor@Sun.COM 	qpc->page_offs		= qp->qp_wqinfo.qa_pgoffs >> 6;
877*12965SWilliam.Taylor@Oracle.COM 	qpc->cqn_rcv		=
878*12965SWilliam.Taylor@Oracle.COM 	    (qp->qp_rq_cqhdl == NULL) ? 0 : qp->qp_rq_cqhdl->cq_cqnum & cqnmask;
8799517SBill.Taylor@Sun.COM 
8809517SBill.Taylor@Sun.COM 	/* dbr is now an address, not an index */
8819517SBill.Taylor@Sun.COM 	qpc->dbr_addrh		= ((uint64_t)qp->qp_rq_pdbr >> 32);
8829517SBill.Taylor@Sun.COM 	qpc->dbr_addrl		= ((uint64_t)qp->qp_rq_pdbr & 0xFFFFFFFC) >> 2;
8839517SBill.Taylor@Sun.COM 	qpc->sq_wqe_counter	= 0;
8849517SBill.Taylor@Sun.COM 	qpc->rq_wqe_counter	= 0;
8859517SBill.Taylor@Sun.COM 	/*
8869517SBill.Taylor@Sun.COM 	 * HERMON:
8879517SBill.Taylor@Sun.COM 	 * qpc->wqe_baseaddr is replaced by LKey from the cMPT, and
8889517SBill.Taylor@Sun.COM 	 * page_offset, mtt_base_addr_h/l, and log2_page_size will
8899517SBill.Taylor@Sun.COM 	 * be used to map the WQE buffer
8909517SBill.Taylor@Sun.COM 	 * NOTE that the cMPT is created implicitly when the QP is
8919517SBill.Taylor@Sun.COM 	 * transitioned from reset to init
8929517SBill.Taylor@Sun.COM 	 */
8939517SBill.Taylor@Sun.COM 	qpc->log2_pgsz		= qp->qp_mrhdl->mr_log2_pgsz;
8949517SBill.Taylor@Sun.COM 	qpc->mtt_base_addrl	= (qp->qp_mrhdl->mr_mttaddr) >> 3;
8959517SBill.Taylor@Sun.COM 	qpc->mtt_base_addrh	= (uint32_t)((qp->qp_mrhdl->mr_mttaddr >> 32) &
8969517SBill.Taylor@Sun.COM 	    0xFF);
897*12965SWilliam.Taylor@Oracle.COM 	qp_srq_en		= (qp->qp_alloc_flags & IBT_QP_USES_SRQ) != 0;
898*12965SWilliam.Taylor@Oracle.COM 	qpc->srq_en		= qp_srq_en;
899*12965SWilliam.Taylor@Oracle.COM 
900*12965SWilliam.Taylor@Oracle.COM 	if (qp_srq_en) {
9019517SBill.Taylor@Sun.COM 		qpc->srq_number	= qp->qp_srqhdl->srq_srqnum;
9029517SBill.Taylor@Sun.COM 	} else {
9039517SBill.Taylor@Sun.COM 		qpc->srq_number = 0;
9049517SBill.Taylor@Sun.COM 	}
9059517SBill.Taylor@Sun.COM 
906*12965SWilliam.Taylor@Oracle.COM 	/*
907*12965SWilliam.Taylor@Oracle.COM 	 * Fast Registration Work Requests and Reserved Lkey are enabled
908*12965SWilliam.Taylor@Oracle.COM 	 * with the single IBT bit stored in qp_rlky.
909*12965SWilliam.Taylor@Oracle.COM 	 */
910*12965SWilliam.Taylor@Oracle.COM 	qpc->fre		= qp->qp_rlky;
9119517SBill.Taylor@Sun.COM 	qpc->rlky		= qp->qp_rlky;
912*12965SWilliam.Taylor@Oracle.COM 
913*12965SWilliam.Taylor@Oracle.COM 	/* 1.2 verbs extensions disabled for now */
914*12965SWilliam.Taylor@Oracle.COM 	qpc->header_sep		= 0; /* disable header separation for now */
915*12965SWilliam.Taylor@Oracle.COM 	qpc->rss		= qp->qp_alloc_flags & IBT_QP_USES_RSS ? 1 : 0;
9169517SBill.Taylor@Sun.COM 	qpc->inline_scatter	= 0; /* disable inline scatter for now */
9179517SBill.Taylor@Sun.COM 
9189517SBill.Taylor@Sun.COM 	/*
9199517SBill.Taylor@Sun.COM 	 * Now fill in the QPC fields which are specific to transport type
9209517SBill.Taylor@Sun.COM 	 */
921*12965SWilliam.Taylor@Oracle.COM 	if (qp->qp_type == IBT_UD_RQP) {
922*12965SWilliam.Taylor@Oracle.COM 		int my_fc_id_idx, exch_base;
923*12965SWilliam.Taylor@Oracle.COM 
9249517SBill.Taylor@Sun.COM 		ud = &info_p->qp_transport.ud;
9259517SBill.Taylor@Sun.COM 
9269517SBill.Taylor@Sun.COM 		/* Set the QKey */
9279517SBill.Taylor@Sun.COM 		qpc->qkey = ud->ud_qkey;
9289517SBill.Taylor@Sun.COM 
9299517SBill.Taylor@Sun.COM 		/*
9309517SBill.Taylor@Sun.COM 		 * Set MTU and message max. Hermon checks the QPC
9319517SBill.Taylor@Sun.COM 		 * MTU settings rather than just the port MTU,
9329517SBill.Taylor@Sun.COM 		 * so set it to maximum size.
9339517SBill.Taylor@Sun.COM 		 */
9349517SBill.Taylor@Sun.COM 		qpc->mtu = HERMON_MAX_MTU;
9359517SBill.Taylor@Sun.COM 		if (qp->qp_uses_lso)
9369517SBill.Taylor@Sun.COM 			qpc->msg_max = state->hs_devlim.log_max_gso_sz;
937*12965SWilliam.Taylor@Oracle.COM 		else if (qp->qp_is_special)
938*12965SWilliam.Taylor@Oracle.COM 			qpc->msg_max = HERMON_MAX_MTU + 6;
9399517SBill.Taylor@Sun.COM 		else
9409517SBill.Taylor@Sun.COM 			qpc->msg_max = HERMON_QP_LOG_MAX_MSGSZ;
9419517SBill.Taylor@Sun.COM 
9429517SBill.Taylor@Sun.COM 		/* Check for valid port number and fill it in */
9439517SBill.Taylor@Sun.COM 		portnum = ud->ud_port;
9449517SBill.Taylor@Sun.COM 		if (hermon_portnum_is_valid(state, portnum)) {
9459517SBill.Taylor@Sun.COM 			qp->qp_portnum = portnum - 1;
9469517SBill.Taylor@Sun.COM 			qpc->pri_addr_path.sched_q =
9479517SBill.Taylor@Sun.COM 			    HERMON_QP_SCHEDQ_GET(portnum - 1,
9489517SBill.Taylor@Sun.COM 			    0, qp->qp_is_special);
9499517SBill.Taylor@Sun.COM 		} else {
9509517SBill.Taylor@Sun.COM 			return (IBT_HCA_PORT_INVALID);
9519517SBill.Taylor@Sun.COM 		}
9529517SBill.Taylor@Sun.COM 
9539517SBill.Taylor@Sun.COM 
9549517SBill.Taylor@Sun.COM 		/* Check for valid PKey index and fill it in */
9559517SBill.Taylor@Sun.COM 		pkeyindx = ud->ud_pkey_ix;
9569517SBill.Taylor@Sun.COM 		if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
9579517SBill.Taylor@Sun.COM 			qpc->pri_addr_path.pkey_indx = pkeyindx;
9589517SBill.Taylor@Sun.COM 			qp->qp_pkeyindx = pkeyindx;
9599517SBill.Taylor@Sun.COM 		} else {
9609517SBill.Taylor@Sun.COM 			return (IBT_PKEY_IX_ILLEGAL);
9619517SBill.Taylor@Sun.COM 		}
9629517SBill.Taylor@Sun.COM 
963*12965SWilliam.Taylor@Oracle.COM 		/* fill in the RSS fields */
964*12965SWilliam.Taylor@Oracle.COM 		if (qpc->rss) {
965*12965SWilliam.Taylor@Oracle.COM 			struct hermon_hw_rss_s *rssp;
966*12965SWilliam.Taylor@Oracle.COM 			ibt_rss_flags_t flags = ud->ud_rss.rss_flags;
967*12965SWilliam.Taylor@Oracle.COM 
968*12965SWilliam.Taylor@Oracle.COM 			rssp = (struct hermon_hw_rss_s *)&qpc->pri_addr_path;
969*12965SWilliam.Taylor@Oracle.COM 			rssp->log2_tbl_sz = ud->ud_rss.rss_log2_table;
970*12965SWilliam.Taylor@Oracle.COM 			rssp->base_qpn = ud->ud_rss.rss_base_qpn;
971*12965SWilliam.Taylor@Oracle.COM 			rssp->default_qpn = ud->ud_rss.rss_def_qpn;
972*12965SWilliam.Taylor@Oracle.COM 			if (flags & IBT_RSS_ALG_XOR)
973*12965SWilliam.Taylor@Oracle.COM 				rssp->hash_fn = 0;	/* XOR Hash Function */
974*12965SWilliam.Taylor@Oracle.COM 			else if (flags & IBT_RSS_ALG_TPL)
975*12965SWilliam.Taylor@Oracle.COM 				rssp->hash_fn = 1;	/* Toeplitz Hash Fn */
976*12965SWilliam.Taylor@Oracle.COM 			else
977*12965SWilliam.Taylor@Oracle.COM 				return (IBT_INVALID_PARAM);
978*12965SWilliam.Taylor@Oracle.COM 			rssp->ipv4 = (flags & IBT_RSS_HASH_IPV4) != 0;
979*12965SWilliam.Taylor@Oracle.COM 			rssp->tcp_ipv4 = (flags & IBT_RSS_HASH_TCP_IPV4) != 0;
980*12965SWilliam.Taylor@Oracle.COM 			rssp->ipv6 = (flags & IBT_RSS_HASH_IPV6) != 0;
981*12965SWilliam.Taylor@Oracle.COM 			rssp->tcp_ipv4 = (flags & IBT_RSS_HASH_TCP_IPV6) != 0;
982*12965SWilliam.Taylor@Oracle.COM 			bcopy(ud->ud_rss.rss_toe_key, rssp->rss_key, 40);
983*12965SWilliam.Taylor@Oracle.COM 		} else if (qp->qp_serv_type == HERMON_QP_RFCI) {
984*12965SWilliam.Taylor@Oracle.COM 			status = hermon_fcoib_set_id(state, portnum,
985*12965SWilliam.Taylor@Oracle.COM 			    qp->qp_qpnum, ud->ud_fc.fc_src_id);
986*12965SWilliam.Taylor@Oracle.COM 			if (status != DDI_SUCCESS)
987*12965SWilliam.Taylor@Oracle.COM 				return (status);
988*12965SWilliam.Taylor@Oracle.COM 			qp->qp_fc_attr = ud->ud_fc;
989*12965SWilliam.Taylor@Oracle.COM 		} else if (qp->qp_serv_type == HERMON_QP_FEXCH) {
990*12965SWilliam.Taylor@Oracle.COM 			my_fc_id_idx = hermon_fcoib_get_id_idx(state,
991*12965SWilliam.Taylor@Oracle.COM 			    portnum, &ud->ud_fc);
992*12965SWilliam.Taylor@Oracle.COM 			if (my_fc_id_idx == -1)
993*12965SWilliam.Taylor@Oracle.COM 				return (IBT_INVALID_PARAM);
994*12965SWilliam.Taylor@Oracle.COM 			qpc->my_fc_id_idx = my_fc_id_idx;
995*12965SWilliam.Taylor@Oracle.COM 
996*12965SWilliam.Taylor@Oracle.COM 			status = hermon_fcoib_fexch_mkey_init(state,
997*12965SWilliam.Taylor@Oracle.COM 			    qp->qp_pdhdl, ud->ud_fc.fc_hca_port,
998*12965SWilliam.Taylor@Oracle.COM 			    qp->qp_qpnum, HERMON_CMD_NOSLEEP_SPIN);
999*12965SWilliam.Taylor@Oracle.COM 			if (status != DDI_SUCCESS)
1000*12965SWilliam.Taylor@Oracle.COM 				return (status);
1001*12965SWilliam.Taylor@Oracle.COM 			qp->qp_fc_attr = ud->ud_fc;
1002*12965SWilliam.Taylor@Oracle.COM 		} else if (qp->qp_serv_type == HERMON_QP_FCMND) {
1003*12965SWilliam.Taylor@Oracle.COM 			my_fc_id_idx = hermon_fcoib_get_id_idx(state,
1004*12965SWilliam.Taylor@Oracle.COM 			    portnum, &ud->ud_fc);
1005*12965SWilliam.Taylor@Oracle.COM 			if (my_fc_id_idx == -1)
1006*12965SWilliam.Taylor@Oracle.COM 				return (IBT_INVALID_PARAM);
1007*12965SWilliam.Taylor@Oracle.COM 			qpc->my_fc_id_idx = my_fc_id_idx;
1008*12965SWilliam.Taylor@Oracle.COM 			exch_base = hermon_fcoib_check_exch_base_off(state,
1009*12965SWilliam.Taylor@Oracle.COM 			    portnum, &ud->ud_fc);
1010*12965SWilliam.Taylor@Oracle.COM 			if (exch_base == -1)
1011*12965SWilliam.Taylor@Oracle.COM 				return (IBT_INVALID_PARAM);
1012*12965SWilliam.Taylor@Oracle.COM 			qpc->exch_base = exch_base;
1013*12965SWilliam.Taylor@Oracle.COM 			qpc->exch_size = ud->ud_fc.fc_exch_log2_sz;
1014*12965SWilliam.Taylor@Oracle.COM 			qp->qp_fc_attr = ud->ud_fc;
1015*12965SWilliam.Taylor@Oracle.COM 		}
1016*12965SWilliam.Taylor@Oracle.COM 
10179517SBill.Taylor@Sun.COM 	} else if (qp->qp_serv_type == HERMON_QP_RC) {
10189517SBill.Taylor@Sun.COM 		rc = &info_p->qp_transport.rc;
10199517SBill.Taylor@Sun.COM 
10209517SBill.Taylor@Sun.COM 		/* Set the RDMA (recv) enable/disable flags */
10219517SBill.Taylor@Sun.COM 		qpc->rre = (info_p->qp_flags & IBT_CEP_RDMA_RD) ? 1 : 0;
10229517SBill.Taylor@Sun.COM 		qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
10239517SBill.Taylor@Sun.COM 		qpc->rae = (info_p->qp_flags & IBT_CEP_ATOMIC)  ? 1 : 0;
10249517SBill.Taylor@Sun.COM 
10259517SBill.Taylor@Sun.COM 		/* Check for valid port number and fill it in */
10269517SBill.Taylor@Sun.COM 		portnum = rc->rc_path.cep_hca_port_num;
10279517SBill.Taylor@Sun.COM 		if (hermon_portnum_is_valid(state, portnum)) {
10289517SBill.Taylor@Sun.COM 			qp->qp_portnum = portnum - 1;
10299517SBill.Taylor@Sun.COM 			qpc->pri_addr_path.sched_q =
10309517SBill.Taylor@Sun.COM 			    HERMON_QP_SCHEDQ_GET(portnum - 1,
10319517SBill.Taylor@Sun.COM 			    0, qp->qp_is_special);
10329517SBill.Taylor@Sun.COM 		} else {
10339517SBill.Taylor@Sun.COM 			return (IBT_HCA_PORT_INVALID);
10349517SBill.Taylor@Sun.COM 		}
10359517SBill.Taylor@Sun.COM 
10369517SBill.Taylor@Sun.COM 		/* Check for valid PKey index and fill it in */
10379517SBill.Taylor@Sun.COM 		pkeyindx = rc->rc_path.cep_pkey_ix;
10389517SBill.Taylor@Sun.COM 		if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
10399517SBill.Taylor@Sun.COM 			qpc->pri_addr_path.pkey_indx = pkeyindx;
10409517SBill.Taylor@Sun.COM 		} else {
10419517SBill.Taylor@Sun.COM 			return (IBT_PKEY_IX_ILLEGAL);
10429517SBill.Taylor@Sun.COM 		}
10439517SBill.Taylor@Sun.COM 
10449517SBill.Taylor@Sun.COM 	} else if (qp->qp_serv_type == HERMON_QP_UC) {
10459517SBill.Taylor@Sun.COM 		uc = &info_p->qp_transport.uc;
10469517SBill.Taylor@Sun.COM 
10479517SBill.Taylor@Sun.COM 		/*
10489517SBill.Taylor@Sun.COM 		 * Set the RDMA (recv) enable/disable flags.  Note: RDMA Read
10499517SBill.Taylor@Sun.COM 		 * and Atomic are ignored by default.
10509517SBill.Taylor@Sun.COM 		 */
10519517SBill.Taylor@Sun.COM 		qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
10529517SBill.Taylor@Sun.COM 
10539517SBill.Taylor@Sun.COM 		/* Check for valid port number and fill it in */
10549517SBill.Taylor@Sun.COM 		portnum = uc->uc_path.cep_hca_port_num;
10559517SBill.Taylor@Sun.COM 		if (hermon_portnum_is_valid(state, portnum)) {
10569517SBill.Taylor@Sun.COM 			qp->qp_portnum = portnum - 1;
10579517SBill.Taylor@Sun.COM 			qpc->pri_addr_path.sched_q =
10589517SBill.Taylor@Sun.COM 			    HERMON_QP_SCHEDQ_GET(portnum - 1,
10599517SBill.Taylor@Sun.COM 			    0, qp->qp_is_special);
10609517SBill.Taylor@Sun.COM 		} else {
10619517SBill.Taylor@Sun.COM 			return (IBT_HCA_PORT_INVALID);
10629517SBill.Taylor@Sun.COM 		}
10639517SBill.Taylor@Sun.COM 
10649517SBill.Taylor@Sun.COM 		/* Check for valid PKey index and fill it in */
10659517SBill.Taylor@Sun.COM 		pkeyindx = uc->uc_path.cep_pkey_ix;
10669517SBill.Taylor@Sun.COM 		if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
10679517SBill.Taylor@Sun.COM 			qpc->pri_addr_path.pkey_indx = pkeyindx;
10689517SBill.Taylor@Sun.COM 		} else {
10699517SBill.Taylor@Sun.COM 			return (IBT_PKEY_IX_ILLEGAL);
10709517SBill.Taylor@Sun.COM 		}
10719517SBill.Taylor@Sun.COM 
10729517SBill.Taylor@Sun.COM 	} else {
10739517SBill.Taylor@Sun.COM 		/*
10749517SBill.Taylor@Sun.COM 		 * Invalid QP transport type. If we got here then it's a
10759517SBill.Taylor@Sun.COM 		 * warning of a probably serious problem.  So print a message
10769517SBill.Taylor@Sun.COM 		 * and return failure
10779517SBill.Taylor@Sun.COM 		 */
10789517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "unknown QP transport type in rst2init");
10799517SBill.Taylor@Sun.COM 		return (ibc_get_ci_failure(0));
10809517SBill.Taylor@Sun.COM 	}
10819517SBill.Taylor@Sun.COM 
10829517SBill.Taylor@Sun.COM 	/*
10839517SBill.Taylor@Sun.COM 	 * Post the RST2INIT_QP command to the Hermon firmware
10849517SBill.Taylor@Sun.COM 	 *
10859517SBill.Taylor@Sun.COM 	 * We do a HERMON_NOSLEEP here because we are still holding the
10869517SBill.Taylor@Sun.COM 	 * "qp_lock".  If we got raised to interrupt level by priority
10879517SBill.Taylor@Sun.COM 	 * inversion, we do not want to block in this routine waiting for
10889517SBill.Taylor@Sun.COM 	 * success.
10899517SBill.Taylor@Sun.COM 	 */
10909517SBill.Taylor@Sun.COM 	status = hermon_cmn_qp_cmd_post(state, RST2INIT_QP, qpc, qp->qp_qpnum,
10919517SBill.Taylor@Sun.COM 	    0, HERMON_CMD_NOSLEEP_SPIN);
10929517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
10939517SBill.Taylor@Sun.COM 		cmn_err(CE_NOTE, "hermon%d: RST2INIT_QP command failed: %08x\n",
10949517SBill.Taylor@Sun.COM 		    state->hs_instance, status);
10959517SBill.Taylor@Sun.COM 		if (status == HERMON_CMD_INVALID_STATUS) {
10969517SBill.Taylor@Sun.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
10979517SBill.Taylor@Sun.COM 		}
10989517SBill.Taylor@Sun.COM 		return (ibc_get_ci_failure(0));
10999517SBill.Taylor@Sun.COM 	}
11009517SBill.Taylor@Sun.COM 
11019517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
11029517SBill.Taylor@Sun.COM }
11039517SBill.Taylor@Sun.COM 
11049517SBill.Taylor@Sun.COM 
11059517SBill.Taylor@Sun.COM /*
11069517SBill.Taylor@Sun.COM  * hermon_qp_init2init()
11079517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
11089517SBill.Taylor@Sun.COM  */
11099517SBill.Taylor@Sun.COM 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)11109517SBill.Taylor@Sun.COM hermon_qp_init2init(hermon_state_t *state, hermon_qphdl_t qp,
11119517SBill.Taylor@Sun.COM     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
11129517SBill.Taylor@Sun.COM {
11139517SBill.Taylor@Sun.COM 	hermon_hw_qpc_t		*qpc;
11149517SBill.Taylor@Sun.COM 	ibt_qp_rc_attr_t	*rc;
11159517SBill.Taylor@Sun.COM 	ibt_qp_ud_attr_t	*ud;
11169517SBill.Taylor@Sun.COM 	ibt_qp_uc_attr_t	*uc;
11179517SBill.Taylor@Sun.COM 	uint_t			portnum, pkeyindx;
11189517SBill.Taylor@Sun.COM 	uint32_t		opmask = 0;
11199517SBill.Taylor@Sun.COM 	int			status;
11209517SBill.Taylor@Sun.COM 
11219517SBill.Taylor@Sun.COM 	ASSERT(MUTEX_HELD(&qp->qp_lock));
11229517SBill.Taylor@Sun.COM 
11239517SBill.Taylor@Sun.COM 	/*
11249517SBill.Taylor@Sun.COM 	 * Grab the temporary QPC entry from QP software state
11259517SBill.Taylor@Sun.COM 	 */
11269517SBill.Taylor@Sun.COM 	qpc = &qp->qpc;
11279517SBill.Taylor@Sun.COM 
11289517SBill.Taylor@Sun.COM 	/*
11299517SBill.Taylor@Sun.COM 	 * Since there are no common fields to be filled in for this command,
11309517SBill.Taylor@Sun.COM 	 * we begin with the QPC fields which are specific to transport type.
11319517SBill.Taylor@Sun.COM 	 */
1132*12965SWilliam.Taylor@Oracle.COM 	if (qp->qp_type == IBT_UD_RQP) {
11339517SBill.Taylor@Sun.COM 		ud = &info_p->qp_transport.ud;
11349517SBill.Taylor@Sun.COM 
11359517SBill.Taylor@Sun.COM 		/*
11369517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the port for this QP, then
11379517SBill.Taylor@Sun.COM 		 * check for valid port number and fill it in.  Also set the
11389517SBill.Taylor@Sun.COM 		 * appropriate flag in the "opmask" parameter.
11399517SBill.Taylor@Sun.COM 		 */
11409517SBill.Taylor@Sun.COM 	/*
11419517SBill.Taylor@Sun.COM 	 * set port is not supported in init2init - however, in init2rtr it will
11429517SBill.Taylor@Sun.COM 	 * take the entire qpc, including the embedded sched_q in the path
11439517SBill.Taylor@Sun.COM 	 * structure - so, we can just skip setting the opmask for it explicitly
11449517SBill.Taylor@Sun.COM 	 * and allow it to be set later on
11459517SBill.Taylor@Sun.COM 	 */
11469517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_PORT) {
11479517SBill.Taylor@Sun.COM 			portnum = ud->ud_port;
11489517SBill.Taylor@Sun.COM 			if (hermon_portnum_is_valid(state, portnum)) {
11499517SBill.Taylor@Sun.COM 				qp->qp_portnum = portnum - 1; /* save it away */
11509517SBill.Taylor@Sun.COM 				qpc->pri_addr_path.sched_q =
11519517SBill.Taylor@Sun.COM 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
11529517SBill.Taylor@Sun.COM 				    0, qp->qp_is_special);
11539517SBill.Taylor@Sun.COM 			} else {
11549517SBill.Taylor@Sun.COM 				return (IBT_HCA_PORT_INVALID);
11559517SBill.Taylor@Sun.COM 			}
11569517SBill.Taylor@Sun.COM 		}
11579517SBill.Taylor@Sun.COM 
11589517SBill.Taylor@Sun.COM 		/*
11599517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the PKey index for this QP,
11609517SBill.Taylor@Sun.COM 		 * then check for valid PKey index and fill it in.  Also set
11619517SBill.Taylor@Sun.COM 		 * the appropriate flag in the "opmask" parameter.
11629517SBill.Taylor@Sun.COM 		 */
11639517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_PKEY_IX) {
11649517SBill.Taylor@Sun.COM 			pkeyindx = ud->ud_pkey_ix;
11659517SBill.Taylor@Sun.COM 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
11669517SBill.Taylor@Sun.COM 				qpc->pri_addr_path.pkey_indx = pkeyindx;
11679517SBill.Taylor@Sun.COM 				opmask |= HERMON_CMD_OP_PKEYINDX;
11689517SBill.Taylor@Sun.COM 				qp->qp_pkeyindx = pkeyindx;
11699517SBill.Taylor@Sun.COM 			} else {
11709517SBill.Taylor@Sun.COM 				return (IBT_PKEY_IX_ILLEGAL);
11719517SBill.Taylor@Sun.COM 			}
11729517SBill.Taylor@Sun.COM 		}
11739517SBill.Taylor@Sun.COM 
11749517SBill.Taylor@Sun.COM 		/*
11759517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the QKey for this QP, then
11769517SBill.Taylor@Sun.COM 		 * fill it in and set the appropriate flag in the "opmask"
11779517SBill.Taylor@Sun.COM 		 * parameter.
11789517SBill.Taylor@Sun.COM 		 */
11799517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_QKEY) {
11809517SBill.Taylor@Sun.COM 			qpc->qkey = ud->ud_qkey;
11819517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_QKEY;
11829517SBill.Taylor@Sun.COM 		}
11839517SBill.Taylor@Sun.COM 
11849517SBill.Taylor@Sun.COM 	} else if (qp->qp_serv_type == HERMON_QP_RC) {
11859517SBill.Taylor@Sun.COM 		rc = &info_p->qp_transport.rc;
11869517SBill.Taylor@Sun.COM 
11879517SBill.Taylor@Sun.COM 		/*
11889517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the port for this QP, then
11899517SBill.Taylor@Sun.COM 		 * check for valid port number and fill it in.  Also set the
11909517SBill.Taylor@Sun.COM 		 * appropriate flag in the "opmask" parameter.
11919517SBill.Taylor@Sun.COM 		 */
11929517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_PORT) {
11939517SBill.Taylor@Sun.COM 			portnum = rc->rc_path.cep_hca_port_num;
11949517SBill.Taylor@Sun.COM 			if (hermon_portnum_is_valid(state, portnum)) {
11959517SBill.Taylor@Sun.COM 				qp->qp_portnum = portnum - 1;
11969517SBill.Taylor@Sun.COM 				qpc->pri_addr_path.sched_q =
11979517SBill.Taylor@Sun.COM 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
11989517SBill.Taylor@Sun.COM 				    0, qp->qp_is_special);
11999517SBill.Taylor@Sun.COM 			} else {
12009517SBill.Taylor@Sun.COM 				return (IBT_HCA_PORT_INVALID);
12019517SBill.Taylor@Sun.COM 			}
12029517SBill.Taylor@Sun.COM 
12039517SBill.Taylor@Sun.COM 		}
12049517SBill.Taylor@Sun.COM 
12059517SBill.Taylor@Sun.COM 		/*
12069517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the PKey index for this QP,
12079517SBill.Taylor@Sun.COM 		 * then check for valid PKey index and fill it in.  Also set
12089517SBill.Taylor@Sun.COM 		 * the appropriate flag in the "opmask" parameter.
12099517SBill.Taylor@Sun.COM 		 */
12109517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_PKEY_IX) {
12119517SBill.Taylor@Sun.COM 			pkeyindx = rc->rc_path.cep_pkey_ix;
12129517SBill.Taylor@Sun.COM 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
12139517SBill.Taylor@Sun.COM 				qpc->pri_addr_path.pkey_indx = pkeyindx;
12149517SBill.Taylor@Sun.COM 				opmask |= HERMON_CMD_OP_PKEYINDX;
12159517SBill.Taylor@Sun.COM 			} else {
12169517SBill.Taylor@Sun.COM 				return (IBT_PKEY_IX_ILLEGAL);
12179517SBill.Taylor@Sun.COM 			}
12189517SBill.Taylor@Sun.COM 		}
12199517SBill.Taylor@Sun.COM 
12209517SBill.Taylor@Sun.COM 		/*
12219517SBill.Taylor@Sun.COM 		 * Check if any of the flags indicate a change in the RDMA
12229517SBill.Taylor@Sun.COM 		 * (recv) enable/disable flags and set the appropriate flag in
12239517SBill.Taylor@Sun.COM 		 * the "opmask" parameter
12249517SBill.Taylor@Sun.COM 		 */
12259517SBill.Taylor@Sun.COM 		opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
12269517SBill.Taylor@Sun.COM 
12279517SBill.Taylor@Sun.COM 	} else if (qp->qp_serv_type == HERMON_QP_UC) {
12289517SBill.Taylor@Sun.COM 		uc = &info_p->qp_transport.uc;
12299517SBill.Taylor@Sun.COM 
12309517SBill.Taylor@Sun.COM 		/*
12319517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the port for this QP, then
12329517SBill.Taylor@Sun.COM 		 * check for valid port number and fill it in.  Also set the
12339517SBill.Taylor@Sun.COM 		 * appropriate flag in the "opmask" parameter.
12349517SBill.Taylor@Sun.COM 		 */
12359517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_PORT) {
12369517SBill.Taylor@Sun.COM 			portnum = uc->uc_path.cep_hca_port_num;
12379517SBill.Taylor@Sun.COM 			if (hermon_portnum_is_valid(state, portnum)) {
12389517SBill.Taylor@Sun.COM 				qp->qp_portnum = portnum - 1;
12399517SBill.Taylor@Sun.COM 				qpc->pri_addr_path.sched_q =
12409517SBill.Taylor@Sun.COM 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
12419517SBill.Taylor@Sun.COM 				    0, qp->qp_is_special);
12429517SBill.Taylor@Sun.COM 			} else {
12439517SBill.Taylor@Sun.COM 				return (IBT_HCA_PORT_INVALID);
12449517SBill.Taylor@Sun.COM 			}
12459517SBill.Taylor@Sun.COM 		/* port# cannot be set in this transition - defer to init2rtr */
12469517SBill.Taylor@Sun.COM 		}
12479517SBill.Taylor@Sun.COM 
12489517SBill.Taylor@Sun.COM 		/*
12499517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the PKey index for this QP,
12509517SBill.Taylor@Sun.COM 		 * then check for valid PKey index and fill it in.  Also set
12519517SBill.Taylor@Sun.COM 		 * the appropriate flag in the "opmask" parameter.
12529517SBill.Taylor@Sun.COM 		 */
12539517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_PKEY_IX) {
12549517SBill.Taylor@Sun.COM 			pkeyindx = uc->uc_path.cep_pkey_ix;
12559517SBill.Taylor@Sun.COM 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
12569517SBill.Taylor@Sun.COM 				qpc->pri_addr_path.pkey_indx = pkeyindx;
12579517SBill.Taylor@Sun.COM 				opmask |= HERMON_CMD_OP_PKEYINDX;
12589517SBill.Taylor@Sun.COM 			} else {
12599517SBill.Taylor@Sun.COM 				return (IBT_PKEY_IX_ILLEGAL);
12609517SBill.Taylor@Sun.COM 			}
12619517SBill.Taylor@Sun.COM 		}
12629517SBill.Taylor@Sun.COM 
12639517SBill.Taylor@Sun.COM 		/*
12649517SBill.Taylor@Sun.COM 		 * Check if any of the flags indicate a change in the RDMA
12659517SBill.Taylor@Sun.COM 		 * Write (recv) enable/disable and set the appropriate flag
12669517SBill.Taylor@Sun.COM 		 * in the "opmask" parameter. Note: RDMA Read and Atomic are
12679517SBill.Taylor@Sun.COM 		 * not valid for UC transport.
12689517SBill.Taylor@Sun.COM 		 */
12699517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_RDMA_W) {
12709517SBill.Taylor@Sun.COM 			qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
12719517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_RWE;
12729517SBill.Taylor@Sun.COM 		}
12739517SBill.Taylor@Sun.COM 	} else {
12749517SBill.Taylor@Sun.COM 		/*
12759517SBill.Taylor@Sun.COM 		 * Invalid QP transport type. If we got here then it's a
12769517SBill.Taylor@Sun.COM 		 * warning of a probably serious problem.  So print a message
12779517SBill.Taylor@Sun.COM 		 * and return failure
12789517SBill.Taylor@Sun.COM 		 */
12799517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "unknown QP transport type in init2init");
12809517SBill.Taylor@Sun.COM 		return (ibc_get_ci_failure(0));
12819517SBill.Taylor@Sun.COM 	}
12829517SBill.Taylor@Sun.COM 
12839517SBill.Taylor@Sun.COM 	/*
12849517SBill.Taylor@Sun.COM 	 * Post the INIT2INIT_QP command to the Hermon firmware
12859517SBill.Taylor@Sun.COM 	 *
12869517SBill.Taylor@Sun.COM 	 * We do a HERMON_NOSLEEP here because we are still holding the
12879517SBill.Taylor@Sun.COM 	 * "qp_lock".  If we got raised to interrupt level by priority
12889517SBill.Taylor@Sun.COM 	 * inversion, we do not want to block in this routine waiting for
12899517SBill.Taylor@Sun.COM 	 * success.
12909517SBill.Taylor@Sun.COM 	 */
12919517SBill.Taylor@Sun.COM 	status = hermon_cmn_qp_cmd_post(state, INIT2INIT_QP, qpc, qp->qp_qpnum,
12929517SBill.Taylor@Sun.COM 	    opmask, HERMON_CMD_NOSLEEP_SPIN);
12939517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
12949517SBill.Taylor@Sun.COM 		if (status != HERMON_CMD_BAD_QP_STATE) {
12959517SBill.Taylor@Sun.COM 			cmn_err(CE_NOTE, "hermon%d: INIT2INIT_QP command "
12969517SBill.Taylor@Sun.COM 			    "failed: %08x\n", state->hs_instance, status);
12979517SBill.Taylor@Sun.COM 			if (status == HERMON_CMD_INVALID_STATUS) {
12989517SBill.Taylor@Sun.COM 				hermon_fm_ereport(state, HCA_SYS_ERR,
12999517SBill.Taylor@Sun.COM 				    HCA_ERR_SRV_LOST);
13009517SBill.Taylor@Sun.COM 			}
13019517SBill.Taylor@Sun.COM 			return (ibc_get_ci_failure(0));
13029517SBill.Taylor@Sun.COM 		} else {
13039517SBill.Taylor@Sun.COM 			return (IBT_QP_STATE_INVALID);
13049517SBill.Taylor@Sun.COM 		}
13059517SBill.Taylor@Sun.COM 	}
13069517SBill.Taylor@Sun.COM 
13079517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
13089517SBill.Taylor@Sun.COM }
13099517SBill.Taylor@Sun.COM 
13109517SBill.Taylor@Sun.COM 
13119517SBill.Taylor@Sun.COM /*
13129517SBill.Taylor@Sun.COM  * hermon_qp_init2rtr()
13139517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
13149517SBill.Taylor@Sun.COM  */
13159517SBill.Taylor@Sun.COM 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)13169517SBill.Taylor@Sun.COM hermon_qp_init2rtr(hermon_state_t *state, hermon_qphdl_t qp,
13179517SBill.Taylor@Sun.COM     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
13189517SBill.Taylor@Sun.COM {
13199517SBill.Taylor@Sun.COM 	hermon_hw_qpc_t		*qpc;
13209517SBill.Taylor@Sun.COM 	ibt_qp_rc_attr_t	*rc;
13219517SBill.Taylor@Sun.COM 	ibt_qp_ud_attr_t	*ud;
13229517SBill.Taylor@Sun.COM 	ibt_qp_uc_attr_t	*uc;
13239517SBill.Taylor@Sun.COM 	hermon_hw_addr_path_t	*qpc_path;
13249517SBill.Taylor@Sun.COM 	ibt_adds_vect_t		*adds_vect;
13259517SBill.Taylor@Sun.COM 	uint_t			portnum, pkeyindx, rra_max;
13269517SBill.Taylor@Sun.COM 	uint_t			mtu;
13279517SBill.Taylor@Sun.COM 	uint32_t		opmask = 0;
13289517SBill.Taylor@Sun.COM 	int			status;
13299517SBill.Taylor@Sun.COM 
13309517SBill.Taylor@Sun.COM 	ASSERT(MUTEX_HELD(&qp->qp_lock));
13319517SBill.Taylor@Sun.COM 
13329517SBill.Taylor@Sun.COM 	/*
13339517SBill.Taylor@Sun.COM 	 * Grab the temporary QPC entry from QP software state
13349517SBill.Taylor@Sun.COM 	 */
13359517SBill.Taylor@Sun.COM 	qpc = &qp->qpc;
13369517SBill.Taylor@Sun.COM 
13379517SBill.Taylor@Sun.COM 	/*
13389517SBill.Taylor@Sun.COM 	 * Since there are few common fields to be filled in for this command,
13399517SBill.Taylor@Sun.COM 	 * we just do the QPC fields that are specific to transport type.
13409517SBill.Taylor@Sun.COM 	 */
1341*12965SWilliam.Taylor@Oracle.COM 	if (qp->qp_type == IBT_UD_RQP) {
13429517SBill.Taylor@Sun.COM 		ud = &info_p->qp_transport.ud;
13439517SBill.Taylor@Sun.COM 
13449517SBill.Taylor@Sun.COM 		/*
13459517SBill.Taylor@Sun.COM 		 * If this UD QP is also a "special QP" (QP0 or QP1), then
13469517SBill.Taylor@Sun.COM 		 * the MTU is 256 bytes.  However, Hermon checks the QPC
13479517SBill.Taylor@Sun.COM 		 * MTU settings rather than just the port MTU, so we will
13489517SBill.Taylor@Sun.COM 		 * set it to maximum size for all UD.
13499517SBill.Taylor@Sun.COM 		 */
13509517SBill.Taylor@Sun.COM 		qpc->mtu = HERMON_MAX_MTU;
13519517SBill.Taylor@Sun.COM 		if (qp->qp_uses_lso)
13529517SBill.Taylor@Sun.COM 			qpc->msg_max = state->hs_devlim.log_max_gso_sz;
13539517SBill.Taylor@Sun.COM 		else
13549517SBill.Taylor@Sun.COM 			qpc->msg_max = HERMON_QP_LOG_MAX_MSGSZ;
13559517SBill.Taylor@Sun.COM 
13569517SBill.Taylor@Sun.COM 		/*
13579517SBill.Taylor@Sun.COM 		 * Save away the MTU value.  This is used in future sqd2sqd
13589517SBill.Taylor@Sun.COM 		 * transitions, as the MTU must remain the same in future
13599517SBill.Taylor@Sun.COM 		 * changes.
13609517SBill.Taylor@Sun.COM 		 */
13619517SBill.Taylor@Sun.COM 		qp->qp_save_mtu = qpc->mtu;
13629517SBill.Taylor@Sun.COM 
13639517SBill.Taylor@Sun.COM 		/*
13649517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the PKey index for this QP,
13659517SBill.Taylor@Sun.COM 		 * then check for valid PKey index and fill it in.  Also set
13669517SBill.Taylor@Sun.COM 		 * the appropriate flag in the "opmask" parameter.
13679517SBill.Taylor@Sun.COM 		 */
13689517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_PKEY_IX) {
13699517SBill.Taylor@Sun.COM 			pkeyindx = ud->ud_pkey_ix;
13709517SBill.Taylor@Sun.COM 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
13719517SBill.Taylor@Sun.COM 				qpc->pri_addr_path.pkey_indx = pkeyindx;
13729517SBill.Taylor@Sun.COM 				opmask |= HERMON_CMD_OP_PKEYINDX;
13739517SBill.Taylor@Sun.COM 				qp->qp_pkeyindx = pkeyindx;
13749517SBill.Taylor@Sun.COM 			} else {
13759517SBill.Taylor@Sun.COM 				return (IBT_PKEY_IX_ILLEGAL);
13769517SBill.Taylor@Sun.COM 			}
13779517SBill.Taylor@Sun.COM 		}
13789517SBill.Taylor@Sun.COM 
13799517SBill.Taylor@Sun.COM 		/*
13809517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the QKey for this QP, then
13819517SBill.Taylor@Sun.COM 		 * fill it in and set the appropriate flag in the "opmask"
13829517SBill.Taylor@Sun.COM 		 * parameter.
13839517SBill.Taylor@Sun.COM 		 */
13849517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_QKEY) {
13859517SBill.Taylor@Sun.COM 			qpc->qkey = ud->ud_qkey;
13869517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_QKEY;
13879517SBill.Taylor@Sun.COM 		}
13889517SBill.Taylor@Sun.COM 
13899517SBill.Taylor@Sun.COM 	} else if (qp->qp_serv_type == HERMON_QP_RC) {
13909517SBill.Taylor@Sun.COM 		rc = &info_p->qp_transport.rc;
13919517SBill.Taylor@Sun.COM 		qpc_path = &qpc->pri_addr_path;
13929517SBill.Taylor@Sun.COM 		adds_vect = &rc->rc_path.cep_adds_vect;
13939517SBill.Taylor@Sun.COM 
13949517SBill.Taylor@Sun.COM 		/*
13959517SBill.Taylor@Sun.COM 		 * Set the common primary address path fields
13969517SBill.Taylor@Sun.COM 		 */
13979517SBill.Taylor@Sun.COM 		status = hermon_set_addr_path(state, adds_vect, qpc_path,
13989517SBill.Taylor@Sun.COM 		    HERMON_ADDRPATH_QP);
13999517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
14009517SBill.Taylor@Sun.COM 			return (status);
14019517SBill.Taylor@Sun.COM 		}
14029517SBill.Taylor@Sun.COM 		/* set the primary port number/sched_q */
14039517SBill.Taylor@Sun.COM 		portnum = qp->qp_portnum + 1;
14049517SBill.Taylor@Sun.COM 		if (hermon_portnum_is_valid(state, portnum)) {
14059517SBill.Taylor@Sun.COM 			qpc->pri_addr_path.sched_q  =
14069517SBill.Taylor@Sun.COM 			    HERMON_QP_SCHEDQ_GET(qp->qp_portnum,
14079517SBill.Taylor@Sun.COM 			    adds_vect->av_srvl, qp->qp_is_special);
14089517SBill.Taylor@Sun.COM 		} else {
14099517SBill.Taylor@Sun.COM 			return (IBT_HCA_PORT_INVALID);
14109517SBill.Taylor@Sun.COM 		}
14119517SBill.Taylor@Sun.COM 
14129517SBill.Taylor@Sun.COM 		/*
14139517SBill.Taylor@Sun.COM 		 * The following values are apparently "required" here (as
14149517SBill.Taylor@Sun.COM 		 * they are part of the IBA-defined "Remote Node Address
14159517SBill.Taylor@Sun.COM 		 * Vector").  However, they are also going to be "required"
14169517SBill.Taylor@Sun.COM 		 * later - at RTR2RTS_QP time.  Not sure why.  But we set
14179517SBill.Taylor@Sun.COM 		 * them here anyway.
14189517SBill.Taylor@Sun.COM 		 */
14199517SBill.Taylor@Sun.COM 		qpc->rnr_retry		= rc->rc_rnr_retry_cnt;
14209517SBill.Taylor@Sun.COM 		qpc->retry_cnt		= rc->rc_retry_cnt;
14219517SBill.Taylor@Sun.COM 		qpc_path->ack_timeout	= rc->rc_path.cep_timeout;
14229517SBill.Taylor@Sun.COM 
14239517SBill.Taylor@Sun.COM 		/*
14249517SBill.Taylor@Sun.COM 		 * Setup the destination QP, recv PSN, MTU, max msg size,etc.
14259517SBill.Taylor@Sun.COM 		 * Note max message size is defined to be the maximum IB
14269517SBill.Taylor@Sun.COM 		 * allowed message size (which is 2^31 bytes).  Also max
14279517SBill.Taylor@Sun.COM 		 * MTU is defined by HCA port properties.
14289517SBill.Taylor@Sun.COM 		 */
14299517SBill.Taylor@Sun.COM 		qpc->rem_qpn	  = rc->rc_dst_qpn;
14309517SBill.Taylor@Sun.COM 		qpc->next_rcv_psn = rc->rc_rq_psn;
14319517SBill.Taylor@Sun.COM 		qpc->msg_max	  = HERMON_QP_LOG_MAX_MSGSZ;
14329517SBill.Taylor@Sun.COM 		qpc->ric	  = 0;
14339517SBill.Taylor@Sun.COM 		mtu		  = rc->rc_path_mtu;
14349517SBill.Taylor@Sun.COM 
14359517SBill.Taylor@Sun.COM 		if (hermon_qp_validate_mtu(state, mtu) != DDI_SUCCESS) {
14369517SBill.Taylor@Sun.COM 			return (IBT_HCA_PORT_MTU_EXCEEDED);
14379517SBill.Taylor@Sun.COM 		}
14389517SBill.Taylor@Sun.COM 		qpc->mtu = mtu;
14399517SBill.Taylor@Sun.COM 
14409517SBill.Taylor@Sun.COM 		/*
14419517SBill.Taylor@Sun.COM 		 * Save away the MTU value.  This is used in future sqd2sqd
14429517SBill.Taylor@Sun.COM 		 * transitions, as the MTU must remain the same in future
14439517SBill.Taylor@Sun.COM 		 * changes.
14449517SBill.Taylor@Sun.COM 		 */
14459517SBill.Taylor@Sun.COM 		qp->qp_save_mtu = qpc->mtu;
14469517SBill.Taylor@Sun.COM 
14479517SBill.Taylor@Sun.COM 		/*
14489517SBill.Taylor@Sun.COM 		 * Though it is a "required" parameter, "min_rnr_nak" is
14499517SBill.Taylor@Sun.COM 		 * optionally specifiable in Hermon.  So we force the
14509517SBill.Taylor@Sun.COM 		 * optional flag here.
14519517SBill.Taylor@Sun.COM 		 */
14529517SBill.Taylor@Sun.COM 		qpc->min_rnr_nak = rc->rc_min_rnr_nak;
14539517SBill.Taylor@Sun.COM 		opmask |= HERMON_CMD_OP_MINRNRNAK;
14549517SBill.Taylor@Sun.COM 
14559517SBill.Taylor@Sun.COM 		/*
14569517SBill.Taylor@Sun.COM 		 * Check that the number of specified "incoming RDMA resources"
14579517SBill.Taylor@Sun.COM 		 * is valid.  And if it is, then setup the "rra_max
14589517SBill.Taylor@Sun.COM 		 */
14599517SBill.Taylor@Sun.COM 		if (hermon_qp_validate_resp_rsrc(state, rc, &rra_max) !=
14609517SBill.Taylor@Sun.COM 		    DDI_SUCCESS) {
14619517SBill.Taylor@Sun.COM 			return (IBT_INVALID_PARAM);
14629517SBill.Taylor@Sun.COM 		}
14639517SBill.Taylor@Sun.COM 		qpc->rra_max = rra_max;
14649517SBill.Taylor@Sun.COM 
14659517SBill.Taylor@Sun.COM 		/* don't need to set up ra_buff_indx, implicit for hermon */
14669517SBill.Taylor@Sun.COM 
14679517SBill.Taylor@Sun.COM 		/*
14689517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the PKey index for this QP,
14699517SBill.Taylor@Sun.COM 		 * then check for valid PKey index and fill it in.  Also set
14709517SBill.Taylor@Sun.COM 		 * the appropriate flag in the "opmask" parameter.
14719517SBill.Taylor@Sun.COM 		 */
14729517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_PKEY_IX) {
14739517SBill.Taylor@Sun.COM 			pkeyindx = rc->rc_path.cep_pkey_ix;
14749517SBill.Taylor@Sun.COM 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
14759517SBill.Taylor@Sun.COM 				qpc->pri_addr_path.pkey_indx = pkeyindx;
14769517SBill.Taylor@Sun.COM 				opmask |= HERMON_CMD_OP_PKEYINDX;
14779517SBill.Taylor@Sun.COM 			} else {
14789517SBill.Taylor@Sun.COM 				return (IBT_PKEY_IX_ILLEGAL);
14799517SBill.Taylor@Sun.COM 			}
14809517SBill.Taylor@Sun.COM 		}
14819517SBill.Taylor@Sun.COM 
14829517SBill.Taylor@Sun.COM 		/*
14839517SBill.Taylor@Sun.COM 		 * Check if any of the flags indicate a change in the RDMA
14849517SBill.Taylor@Sun.COM 		 * (recv) enable/disable flags and set the appropriate flag in
14859517SBill.Taylor@Sun.COM 		 * the "opmask" parameter
14869517SBill.Taylor@Sun.COM 		 */
14879517SBill.Taylor@Sun.COM 		opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
14889517SBill.Taylor@Sun.COM 
14899517SBill.Taylor@Sun.COM 		/*
14909517SBill.Taylor@Sun.COM 		 * Check for optional alternate path and fill in the
14919517SBill.Taylor@Sun.COM 		 * appropriate QPC fields if one is specified
14929517SBill.Taylor@Sun.COM 		 */
14939517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_ALT_PATH) {
14949517SBill.Taylor@Sun.COM 			qpc_path = &qpc->alt_addr_path;
14959517SBill.Taylor@Sun.COM 			adds_vect = &rc->rc_alt_path.cep_adds_vect;
14969517SBill.Taylor@Sun.COM 
14979517SBill.Taylor@Sun.COM 			/* Set the common alternate address path fields */
14989517SBill.Taylor@Sun.COM 			status = hermon_set_addr_path(state, adds_vect,
14999517SBill.Taylor@Sun.COM 			    qpc_path, HERMON_ADDRPATH_QP);
15009517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
15019517SBill.Taylor@Sun.COM 				return (status);
15029517SBill.Taylor@Sun.COM 			}
15039517SBill.Taylor@Sun.COM 			qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
15049517SBill.Taylor@Sun.COM 
15059517SBill.Taylor@Sun.COM 
15069517SBill.Taylor@Sun.COM 			/*
15079517SBill.Taylor@Sun.COM 			 * Check for valid alternate path port number and fill
15089517SBill.Taylor@Sun.COM 			 * it in
15099517SBill.Taylor@Sun.COM 			 */
15109517SBill.Taylor@Sun.COM 			portnum = rc->rc_alt_path.cep_hca_port_num;
15119517SBill.Taylor@Sun.COM 			if (hermon_portnum_is_valid(state, portnum)) {
15129517SBill.Taylor@Sun.COM 				qp->qp_portnum_alt = portnum - 1;
15139517SBill.Taylor@Sun.COM 				qpc->alt_addr_path.sched_q =
15149517SBill.Taylor@Sun.COM 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
15159517SBill.Taylor@Sun.COM 				    adds_vect->av_srvl, qp->qp_is_special);
15169517SBill.Taylor@Sun.COM 			} else {
15179517SBill.Taylor@Sun.COM 				return (IBT_HCA_PORT_INVALID);
15189517SBill.Taylor@Sun.COM 			}
15199517SBill.Taylor@Sun.COM 			/*
15209517SBill.Taylor@Sun.COM 			 * Check for valid alternate path PKey index and fill
15219517SBill.Taylor@Sun.COM 			 * it in
15229517SBill.Taylor@Sun.COM 			 */
15239517SBill.Taylor@Sun.COM 			pkeyindx = rc->rc_alt_path.cep_pkey_ix;
15249517SBill.Taylor@Sun.COM 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
15259517SBill.Taylor@Sun.COM 				qpc->alt_addr_path.pkey_indx = pkeyindx;
15269517SBill.Taylor@Sun.COM 			} else {
15279517SBill.Taylor@Sun.COM 				return (IBT_PKEY_IX_ILLEGAL);
15289517SBill.Taylor@Sun.COM 			}
15299517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_ALT_PATH;
15309517SBill.Taylor@Sun.COM 		}
15319517SBill.Taylor@Sun.COM 
15329517SBill.Taylor@Sun.COM 	} else if (qp->qp_serv_type == HERMON_QP_UC) {
15339517SBill.Taylor@Sun.COM 		uc = &info_p->qp_transport.uc;
15349517SBill.Taylor@Sun.COM 		qpc_path = &qpc->pri_addr_path;
15359517SBill.Taylor@Sun.COM 		adds_vect = &uc->uc_path.cep_adds_vect;
15369517SBill.Taylor@Sun.COM 
15379517SBill.Taylor@Sun.COM 		/*
15389517SBill.Taylor@Sun.COM 		 * Set the common primary address path fields
15399517SBill.Taylor@Sun.COM 		 */
15409517SBill.Taylor@Sun.COM 		status = hermon_set_addr_path(state, adds_vect, qpc_path,
15419517SBill.Taylor@Sun.COM 		    HERMON_ADDRPATH_QP);
15429517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
15439517SBill.Taylor@Sun.COM 			return (status);
15449517SBill.Taylor@Sun.COM 		}
15459517SBill.Taylor@Sun.COM 
15469517SBill.Taylor@Sun.COM 		/* set the primary port num/schedq */
15479517SBill.Taylor@Sun.COM 		portnum = qp->qp_portnum + 1;
15489517SBill.Taylor@Sun.COM 		if (hermon_portnum_is_valid(state, portnum)) {
15499517SBill.Taylor@Sun.COM 			qpc->pri_addr_path.sched_q  =
15509517SBill.Taylor@Sun.COM 			    HERMON_QP_SCHEDQ_GET(qp->qp_portnum,
15519517SBill.Taylor@Sun.COM 			    adds_vect->av_srvl, qp->qp_is_special);
15529517SBill.Taylor@Sun.COM 		} else {
15539517SBill.Taylor@Sun.COM 			return (IBT_HCA_PORT_INVALID);
15549517SBill.Taylor@Sun.COM 		}
15559517SBill.Taylor@Sun.COM 
15569517SBill.Taylor@Sun.COM 		/*
15579517SBill.Taylor@Sun.COM 		 * Setup the destination QP, recv PSN, MTU, max msg size,etc.
15589517SBill.Taylor@Sun.COM 		 * Note max message size is defined to be the maximum IB
15599517SBill.Taylor@Sun.COM 		 * allowed message size (which is 2^31 bytes).  Also max
15609517SBill.Taylor@Sun.COM 		 * MTU is defined by HCA port properties.
15619517SBill.Taylor@Sun.COM 		 */
15629517SBill.Taylor@Sun.COM 		qpc->rem_qpn	  = uc->uc_dst_qpn;
15639517SBill.Taylor@Sun.COM 		qpc->next_rcv_psn = uc->uc_rq_psn;
15649517SBill.Taylor@Sun.COM 		qpc->msg_max	  = HERMON_QP_LOG_MAX_MSGSZ;
15659517SBill.Taylor@Sun.COM 		mtu = uc->uc_path_mtu;
15669517SBill.Taylor@Sun.COM 		if (hermon_qp_validate_mtu(state, mtu) != DDI_SUCCESS) {
15679517SBill.Taylor@Sun.COM 			return (IBT_HCA_PORT_MTU_EXCEEDED);
15689517SBill.Taylor@Sun.COM 		}
15699517SBill.Taylor@Sun.COM 		qpc->mtu = mtu;
15709517SBill.Taylor@Sun.COM 
15719517SBill.Taylor@Sun.COM 		/*
15729517SBill.Taylor@Sun.COM 		 * Save away the MTU value.  This is used in future sqd2sqd
15739517SBill.Taylor@Sun.COM 		 * transitions, as the MTU must remain the same in future
15749517SBill.Taylor@Sun.COM 		 * changes.
15759517SBill.Taylor@Sun.COM 		 */
15769517SBill.Taylor@Sun.COM 		qp->qp_save_mtu = qpc->mtu;
15779517SBill.Taylor@Sun.COM 
15789517SBill.Taylor@Sun.COM 		/*
15799517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the PKey index for this QP,
15809517SBill.Taylor@Sun.COM 		 * then check for valid PKey index and fill it in.  Also set
15819517SBill.Taylor@Sun.COM 		 * the appropriate flag in the "opmask" parameter.
15829517SBill.Taylor@Sun.COM 		 */
15839517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_PKEY_IX) {
15849517SBill.Taylor@Sun.COM 			pkeyindx = uc->uc_path.cep_pkey_ix;
15859517SBill.Taylor@Sun.COM 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
15869517SBill.Taylor@Sun.COM 				qpc->pri_addr_path.pkey_indx = pkeyindx;
15879517SBill.Taylor@Sun.COM 				opmask |= HERMON_CMD_OP_PKEYINDX;
15889517SBill.Taylor@Sun.COM 			} else {
15899517SBill.Taylor@Sun.COM 				return (IBT_PKEY_IX_ILLEGAL);
15909517SBill.Taylor@Sun.COM 			}
15919517SBill.Taylor@Sun.COM 		}
15929517SBill.Taylor@Sun.COM 
15939517SBill.Taylor@Sun.COM 		/*
15949517SBill.Taylor@Sun.COM 		 * Check if any of the flags indicate a change in the RDMA
15959517SBill.Taylor@Sun.COM 		 * Write (recv) enable/disable and set the appropriate flag
15969517SBill.Taylor@Sun.COM 		 * in the "opmask" parameter. Note: RDMA Read and Atomic are
15979517SBill.Taylor@Sun.COM 		 * not valid for UC transport.
15989517SBill.Taylor@Sun.COM 		 */
15999517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_RDMA_W) {
16009517SBill.Taylor@Sun.COM 			qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
16019517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_RWE;
16029517SBill.Taylor@Sun.COM 		}
16039517SBill.Taylor@Sun.COM 
16049517SBill.Taylor@Sun.COM 		/*
16059517SBill.Taylor@Sun.COM 		 * Check for optional alternate path and fill in the
16069517SBill.Taylor@Sun.COM 		 * appropriate QPC fields if one is specified
16079517SBill.Taylor@Sun.COM 		 */
16089517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_ALT_PATH) {
16099517SBill.Taylor@Sun.COM 			qpc_path = &qpc->alt_addr_path;
16109517SBill.Taylor@Sun.COM 			adds_vect = &uc->uc_alt_path.cep_adds_vect;
16119517SBill.Taylor@Sun.COM 
16129517SBill.Taylor@Sun.COM 			/* Set the common alternate address path fields */
16139517SBill.Taylor@Sun.COM 			status = hermon_set_addr_path(state, adds_vect,
16149517SBill.Taylor@Sun.COM 			    qpc_path, HERMON_ADDRPATH_QP);
16159517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
16169517SBill.Taylor@Sun.COM 				return (status);
16179517SBill.Taylor@Sun.COM 			}
16189517SBill.Taylor@Sun.COM 
16199517SBill.Taylor@Sun.COM 			qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
16209517SBill.Taylor@Sun.COM 
16219517SBill.Taylor@Sun.COM 			/*
16229517SBill.Taylor@Sun.COM 			 * Check for valid alternate path port number and fill
16239517SBill.Taylor@Sun.COM 			 * it in
16249517SBill.Taylor@Sun.COM 			 */
16259517SBill.Taylor@Sun.COM 			portnum = uc->uc_alt_path.cep_hca_port_num;
16269517SBill.Taylor@Sun.COM 			if (hermon_portnum_is_valid(state, portnum)) {
16279517SBill.Taylor@Sun.COM 				qp->qp_portnum_alt = portnum - 1;
16289517SBill.Taylor@Sun.COM 				qpc->alt_addr_path.sched_q =
16299517SBill.Taylor@Sun.COM 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
16309517SBill.Taylor@Sun.COM 				    adds_vect->av_srvl, qp->qp_is_special);
16319517SBill.Taylor@Sun.COM 			} else {
16329517SBill.Taylor@Sun.COM 				return (IBT_HCA_PORT_INVALID);
16339517SBill.Taylor@Sun.COM 			}
16349517SBill.Taylor@Sun.COM 
16359517SBill.Taylor@Sun.COM 			/*
16369517SBill.Taylor@Sun.COM 			 * Check for valid alternate path PKey index and fill
16379517SBill.Taylor@Sun.COM 			 * it in
16389517SBill.Taylor@Sun.COM 			 */
16399517SBill.Taylor@Sun.COM 			pkeyindx = uc->uc_alt_path.cep_pkey_ix;
16409517SBill.Taylor@Sun.COM 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
16419517SBill.Taylor@Sun.COM 				qpc->alt_addr_path.pkey_indx = pkeyindx;
16429517SBill.Taylor@Sun.COM 			} else {
16439517SBill.Taylor@Sun.COM 				return (IBT_PKEY_IX_ILLEGAL);
16449517SBill.Taylor@Sun.COM 			}
16459517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_ALT_PATH;
16469517SBill.Taylor@Sun.COM 		}
16479517SBill.Taylor@Sun.COM 	} else {
16489517SBill.Taylor@Sun.COM 		/*
16499517SBill.Taylor@Sun.COM 		 * Invalid QP transport type. If we got here then it's a
16509517SBill.Taylor@Sun.COM 		 * warning of a probably serious problem.  So print a message
16519517SBill.Taylor@Sun.COM 		 * and return failure
16529517SBill.Taylor@Sun.COM 		 */
16539517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "unknown QP transport type in init2rtr");
16549517SBill.Taylor@Sun.COM 		return (ibc_get_ci_failure(0));
16559517SBill.Taylor@Sun.COM 	}
16569517SBill.Taylor@Sun.COM 
16579517SBill.Taylor@Sun.COM 	/*
16589517SBill.Taylor@Sun.COM 	 * Post the INIT2RTR_QP command to the Hermon firmware
16599517SBill.Taylor@Sun.COM 	 *
16609517SBill.Taylor@Sun.COM 	 * We do a HERMON_NOSLEEP here because we are still holding the
16619517SBill.Taylor@Sun.COM 	 * "qp_lock".  If we got raised to interrupt level by priority
16629517SBill.Taylor@Sun.COM 	 * inversion, we do not want to block in this routine waiting for
16639517SBill.Taylor@Sun.COM 	 * success.
16649517SBill.Taylor@Sun.COM 	 */
16659517SBill.Taylor@Sun.COM 	status = hermon_cmn_qp_cmd_post(state, INIT2RTR_QP, qpc, qp->qp_qpnum,
16669517SBill.Taylor@Sun.COM 	    opmask, HERMON_CMD_NOSLEEP_SPIN);
16679517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
16689517SBill.Taylor@Sun.COM 		if (status != HERMON_CMD_BAD_QP_STATE) {
16699517SBill.Taylor@Sun.COM 			cmn_err(CE_NOTE, "hermon%d: INIT2RTR_QP command "
16709517SBill.Taylor@Sun.COM 			    "failed: %08x\n", state->hs_instance, status);
16719517SBill.Taylor@Sun.COM 			if (status == HERMON_CMD_INVALID_STATUS) {
16729517SBill.Taylor@Sun.COM 				hermon_fm_ereport(state, HCA_SYS_ERR,
16739517SBill.Taylor@Sun.COM 				    HCA_ERR_SRV_LOST);
16749517SBill.Taylor@Sun.COM 			}
16759517SBill.Taylor@Sun.COM 			return (ibc_get_ci_failure(0));
16769517SBill.Taylor@Sun.COM 		} else {
16779517SBill.Taylor@Sun.COM 			return (IBT_QP_STATE_INVALID);
16789517SBill.Taylor@Sun.COM 		}
16799517SBill.Taylor@Sun.COM 	}
16809517SBill.Taylor@Sun.COM 
16819517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
16829517SBill.Taylor@Sun.COM }
16839517SBill.Taylor@Sun.COM 
16849517SBill.Taylor@Sun.COM 
16859517SBill.Taylor@Sun.COM /*
16869517SBill.Taylor@Sun.COM  * hermon_qp_rtr2rts()
16879517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
16889517SBill.Taylor@Sun.COM  */
16899517SBill.Taylor@Sun.COM 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)16909517SBill.Taylor@Sun.COM hermon_qp_rtr2rts(hermon_state_t *state, hermon_qphdl_t qp,
16919517SBill.Taylor@Sun.COM     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
16929517SBill.Taylor@Sun.COM {
16939517SBill.Taylor@Sun.COM 	hermon_hw_qpc_t		*qpc;
16949517SBill.Taylor@Sun.COM 	ibt_qp_rc_attr_t	*rc;
16959517SBill.Taylor@Sun.COM 	ibt_qp_ud_attr_t	*ud;
16969517SBill.Taylor@Sun.COM 	ibt_qp_uc_attr_t	*uc;
16979517SBill.Taylor@Sun.COM 	hermon_hw_addr_path_t	*qpc_path;
16989517SBill.Taylor@Sun.COM 	ibt_adds_vect_t		*adds_vect;
16999517SBill.Taylor@Sun.COM 	uint_t			portnum, pkeyindx, sra_max;
17009517SBill.Taylor@Sun.COM 	uint32_t		opmask = 0;
17019517SBill.Taylor@Sun.COM 	int			status;
17029517SBill.Taylor@Sun.COM 
17039517SBill.Taylor@Sun.COM 	ASSERT(MUTEX_HELD(&qp->qp_lock));
17049517SBill.Taylor@Sun.COM 
17059517SBill.Taylor@Sun.COM 	/*
17069517SBill.Taylor@Sun.COM 	 * Grab the temporary QPC entry from QP software state
17079517SBill.Taylor@Sun.COM 	 */
17089517SBill.Taylor@Sun.COM 	qpc = &qp->qpc;
17099517SBill.Taylor@Sun.COM 
17109517SBill.Taylor@Sun.COM 	/*
17119517SBill.Taylor@Sun.COM 	 * Now fill in the QPC fields which are specific to transport type
17129517SBill.Taylor@Sun.COM 	 */
1713*12965SWilliam.Taylor@Oracle.COM 	if (qp->qp_type == IBT_UD_RQP) {
17149517SBill.Taylor@Sun.COM 		ud = &info_p->qp_transport.ud;
17159517SBill.Taylor@Sun.COM 
17169517SBill.Taylor@Sun.COM 		/* Set the send PSN */
17179517SBill.Taylor@Sun.COM 		qpc->next_snd_psn = ud->ud_sq_psn;
17189517SBill.Taylor@Sun.COM 
17199517SBill.Taylor@Sun.COM 		/*
17209517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the QKey for this QP, then
17219517SBill.Taylor@Sun.COM 		 * fill it in and set the appropriate flag in the "opmask"
17229517SBill.Taylor@Sun.COM 		 * parameter.
17239517SBill.Taylor@Sun.COM 		 */
17249517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_QKEY) {
17259517SBill.Taylor@Sun.COM 			qpc->qkey = ud->ud_qkey;
17269517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_QKEY;
17279517SBill.Taylor@Sun.COM 		}
17289517SBill.Taylor@Sun.COM 
17299517SBill.Taylor@Sun.COM 	} else if (qp->qp_serv_type == HERMON_QP_RC) {
17309517SBill.Taylor@Sun.COM 		rc = &info_p->qp_transport.rc;
17319517SBill.Taylor@Sun.COM 		qpc_path = &qpc->pri_addr_path;
17329517SBill.Taylor@Sun.COM 
17339517SBill.Taylor@Sun.COM 		/*
17349517SBill.Taylor@Sun.COM 		 * Setup the send PSN, ACK timeout, and retry counts
17359517SBill.Taylor@Sun.COM 		 */
17369517SBill.Taylor@Sun.COM 		qpc->next_snd_psn	= rc->rc_sq_psn;
17379517SBill.Taylor@Sun.COM 		qpc_path->ack_timeout	= rc->rc_path.cep_timeout;
17389517SBill.Taylor@Sun.COM 		qpc->rnr_retry		= rc->rc_rnr_retry_cnt;
17399517SBill.Taylor@Sun.COM 						/* in qpc now, not path */
17409517SBill.Taylor@Sun.COM 		qpc->retry_cnt		= rc->rc_retry_cnt;
17419517SBill.Taylor@Sun.COM 
17429517SBill.Taylor@Sun.COM 		/*
17439517SBill.Taylor@Sun.COM 		 * Set "ack_req_freq" based on the configuration variable
17449517SBill.Taylor@Sun.COM 		 */
17459517SBill.Taylor@Sun.COM 		qpc->ack_req_freq = state->hs_cfg_profile->cp_ackreq_freq;
17469517SBill.Taylor@Sun.COM 
17479517SBill.Taylor@Sun.COM 		/*
17489517SBill.Taylor@Sun.COM 		 * Check that the number of specified "outgoing RDMA resources"
17499517SBill.Taylor@Sun.COM 		 * is valid.  And if it is, then setup the "sra_max"
17509517SBill.Taylor@Sun.COM 		 * appropriately
17519517SBill.Taylor@Sun.COM 		 */
17529517SBill.Taylor@Sun.COM 		if (hermon_qp_validate_init_depth(state, rc, &sra_max) !=
17539517SBill.Taylor@Sun.COM 		    DDI_SUCCESS) {
17549517SBill.Taylor@Sun.COM 			return (IBT_INVALID_PARAM);
17559517SBill.Taylor@Sun.COM 		}
17569517SBill.Taylor@Sun.COM 		qpc->sra_max = sra_max;
17579517SBill.Taylor@Sun.COM 
17589517SBill.Taylor@Sun.COM 
17599517SBill.Taylor@Sun.COM 		/*
17609517SBill.Taylor@Sun.COM 		 * Check if any of the flags indicate a change in the RDMA
17619517SBill.Taylor@Sun.COM 		 * (recv) enable/disable flags and set the appropriate flag in
17629517SBill.Taylor@Sun.COM 		 * the "opmask" parameter
17639517SBill.Taylor@Sun.COM 		 */
17649517SBill.Taylor@Sun.COM 		opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
17659517SBill.Taylor@Sun.COM 
17669517SBill.Taylor@Sun.COM 		/*
17679517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the path migration state for
17689517SBill.Taylor@Sun.COM 		 * this QP, then check for valid state and fill it in.  Also
17699517SBill.Taylor@Sun.COM 		 * set the appropriate flag in the "opmask" parameter.
17709517SBill.Taylor@Sun.COM 		 */
17719517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_MIG) {
17729517SBill.Taylor@Sun.COM 			if (rc->rc_mig_state == IBT_STATE_MIGRATED) {
17739517SBill.Taylor@Sun.COM 				qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
17749517SBill.Taylor@Sun.COM 			} else if (rc->rc_mig_state == IBT_STATE_REARMED) {
17759517SBill.Taylor@Sun.COM 				qpc->pm_state = HERMON_QP_PMSTATE_REARM;
17769517SBill.Taylor@Sun.COM 			} else {
17779517SBill.Taylor@Sun.COM 				return (IBT_QP_APM_STATE_INVALID);
17789517SBill.Taylor@Sun.COM 			}
17799517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_PM_STATE;
17809517SBill.Taylor@Sun.COM 		}
17819517SBill.Taylor@Sun.COM 
17829517SBill.Taylor@Sun.COM 		/*
17839517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the "Minimum RNR NAK" value
17849517SBill.Taylor@Sun.COM 		 * for this QP, then fill it in and set the appropriate flag
17859517SBill.Taylor@Sun.COM 		 * in the "opmask" parameter.
17869517SBill.Taylor@Sun.COM 		 */
17879517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_MIN_RNR_NAK) {
17889517SBill.Taylor@Sun.COM 			qpc->min_rnr_nak = rc->rc_min_rnr_nak;
17899517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_MINRNRNAK;
17909517SBill.Taylor@Sun.COM 		}
17919517SBill.Taylor@Sun.COM 
17929517SBill.Taylor@Sun.COM 		/*
17939517SBill.Taylor@Sun.COM 		 * Check for optional alternate path and fill in the
17949517SBill.Taylor@Sun.COM 		 * appropriate QPC fields if one is specified
17959517SBill.Taylor@Sun.COM 		 */
17969517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_ALT_PATH) {
17979517SBill.Taylor@Sun.COM 			qpc_path = &qpc->alt_addr_path;
17989517SBill.Taylor@Sun.COM 			adds_vect = &rc->rc_alt_path.cep_adds_vect;
17999517SBill.Taylor@Sun.COM 
18009517SBill.Taylor@Sun.COM 			/* Set the common alternate address path fields */
18019517SBill.Taylor@Sun.COM 			status = hermon_set_addr_path(state, adds_vect,
18029517SBill.Taylor@Sun.COM 			    qpc_path, HERMON_ADDRPATH_QP);
18039517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
18049517SBill.Taylor@Sun.COM 				return (status);
18059517SBill.Taylor@Sun.COM 			}
18069517SBill.Taylor@Sun.COM 
18079517SBill.Taylor@Sun.COM 			qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
18089517SBill.Taylor@Sun.COM 
18099517SBill.Taylor@Sun.COM 			/*
18109517SBill.Taylor@Sun.COM 			 * Check for valid alternate path port number and fill
18119517SBill.Taylor@Sun.COM 			 * it in
18129517SBill.Taylor@Sun.COM 			 */
18139517SBill.Taylor@Sun.COM 			portnum = rc->rc_alt_path.cep_hca_port_num;
18149517SBill.Taylor@Sun.COM 			if (hermon_portnum_is_valid(state, portnum)) {
18159517SBill.Taylor@Sun.COM 				qp->qp_portnum_alt = portnum - 1;
18169517SBill.Taylor@Sun.COM 				qpc->alt_addr_path.sched_q =
18179517SBill.Taylor@Sun.COM 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
18189517SBill.Taylor@Sun.COM 				    adds_vect->av_srvl, qp->qp_is_special);
18199517SBill.Taylor@Sun.COM 			} else {
18209517SBill.Taylor@Sun.COM 				return (IBT_HCA_PORT_INVALID);
18219517SBill.Taylor@Sun.COM 			}
18229517SBill.Taylor@Sun.COM 
18239517SBill.Taylor@Sun.COM 			/*
18249517SBill.Taylor@Sun.COM 			 * Check for valid alternate path PKey index and fill
18259517SBill.Taylor@Sun.COM 			 * it in
18269517SBill.Taylor@Sun.COM 			 */
18279517SBill.Taylor@Sun.COM 			pkeyindx = rc->rc_alt_path.cep_pkey_ix;
18289517SBill.Taylor@Sun.COM 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
18299517SBill.Taylor@Sun.COM 				qpc->alt_addr_path.pkey_indx = pkeyindx;
18309517SBill.Taylor@Sun.COM 			} else {
18319517SBill.Taylor@Sun.COM 				return (IBT_PKEY_IX_ILLEGAL);
18329517SBill.Taylor@Sun.COM 			}
18339517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_ALT_PATH;
18349517SBill.Taylor@Sun.COM 		}
18359517SBill.Taylor@Sun.COM 
18369517SBill.Taylor@Sun.COM 	} else if (qp->qp_serv_type == HERMON_QP_UC) {
18379517SBill.Taylor@Sun.COM 		uc = &info_p->qp_transport.uc;
18389517SBill.Taylor@Sun.COM 
18399517SBill.Taylor@Sun.COM 		/* Set the send PSN */
18409517SBill.Taylor@Sun.COM 		qpc->next_snd_psn = uc->uc_sq_psn;
18419517SBill.Taylor@Sun.COM 
18429517SBill.Taylor@Sun.COM 		/*
18439517SBill.Taylor@Sun.COM 		 * Configure the QP to allow (sending of) all types of allowable
18449517SBill.Taylor@Sun.COM 		 * UC traffic (i.e. RDMA Write).
18459517SBill.Taylor@Sun.COM 		 */
18469517SBill.Taylor@Sun.COM 
18479517SBill.Taylor@Sun.COM 
18489517SBill.Taylor@Sun.COM 		/*
18499517SBill.Taylor@Sun.COM 		 * Check if any of the flags indicate a change in the RDMA
18509517SBill.Taylor@Sun.COM 		 * Write (recv) enable/disable and set the appropriate flag
18519517SBill.Taylor@Sun.COM 		 * in the "opmask" parameter. Note: RDMA Read and Atomic are
18529517SBill.Taylor@Sun.COM 		 * not valid for UC transport.
18539517SBill.Taylor@Sun.COM 		 */
18549517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_RDMA_W) {
18559517SBill.Taylor@Sun.COM 			qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
18569517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_RWE;
18579517SBill.Taylor@Sun.COM 		}
18589517SBill.Taylor@Sun.COM 
18599517SBill.Taylor@Sun.COM 		/*
18609517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the path migration state for
18619517SBill.Taylor@Sun.COM 		 * this QP, then check for valid state and fill it in.  Also
18629517SBill.Taylor@Sun.COM 		 * set the appropriate flag in the "opmask" parameter.
18639517SBill.Taylor@Sun.COM 		 */
18649517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_MIG) {
18659517SBill.Taylor@Sun.COM 			if (uc->uc_mig_state == IBT_STATE_MIGRATED) {
18669517SBill.Taylor@Sun.COM 				qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
18679517SBill.Taylor@Sun.COM 			} else if (uc->uc_mig_state == IBT_STATE_REARMED) {
18689517SBill.Taylor@Sun.COM 				qpc->pm_state = HERMON_QP_PMSTATE_REARM;
18699517SBill.Taylor@Sun.COM 			} else {
18709517SBill.Taylor@Sun.COM 				return (IBT_QP_APM_STATE_INVALID);
18719517SBill.Taylor@Sun.COM 			}
18729517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_PM_STATE;
18739517SBill.Taylor@Sun.COM 		}
18749517SBill.Taylor@Sun.COM 
18759517SBill.Taylor@Sun.COM 		/*
18769517SBill.Taylor@Sun.COM 		 * Check for optional alternate path and fill in the
18779517SBill.Taylor@Sun.COM 		 * appropriate QPC fields if one is specified
18789517SBill.Taylor@Sun.COM 		 */
18799517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_ALT_PATH) {
18809517SBill.Taylor@Sun.COM 			qpc_path = &qpc->alt_addr_path;
18819517SBill.Taylor@Sun.COM 			adds_vect = &uc->uc_alt_path.cep_adds_vect;
18829517SBill.Taylor@Sun.COM 
18839517SBill.Taylor@Sun.COM 			/* Set the common alternate address path fields */
18849517SBill.Taylor@Sun.COM 			status = hermon_set_addr_path(state, adds_vect,
18859517SBill.Taylor@Sun.COM 			    qpc_path, HERMON_ADDRPATH_QP);
18869517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
18879517SBill.Taylor@Sun.COM 				return (status);
18889517SBill.Taylor@Sun.COM 			}
18899517SBill.Taylor@Sun.COM 			qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
18909517SBill.Taylor@Sun.COM 
18919517SBill.Taylor@Sun.COM 			/*
18929517SBill.Taylor@Sun.COM 			 * Check for valid alternate path port number and fill
18939517SBill.Taylor@Sun.COM 			 * it in
18949517SBill.Taylor@Sun.COM 			 */
18959517SBill.Taylor@Sun.COM 			portnum = uc->uc_alt_path.cep_hca_port_num;
18969517SBill.Taylor@Sun.COM 			if (hermon_portnum_is_valid(state, portnum)) {
18979517SBill.Taylor@Sun.COM 				qpc->alt_addr_path.sched_q =
18989517SBill.Taylor@Sun.COM 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
18999517SBill.Taylor@Sun.COM 				    adds_vect->av_srvl, qp->qp_is_special);
19009517SBill.Taylor@Sun.COM 			} else {
19019517SBill.Taylor@Sun.COM 				return (IBT_HCA_PORT_INVALID);
19029517SBill.Taylor@Sun.COM 			}
19039517SBill.Taylor@Sun.COM 
19049517SBill.Taylor@Sun.COM 			/*
19059517SBill.Taylor@Sun.COM 			 * Check for valid alternate path PKey index and fill
19069517SBill.Taylor@Sun.COM 			 * it in
19079517SBill.Taylor@Sun.COM 			 */
19089517SBill.Taylor@Sun.COM 			pkeyindx = uc->uc_alt_path.cep_pkey_ix;
19099517SBill.Taylor@Sun.COM 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
19109517SBill.Taylor@Sun.COM 				qpc->alt_addr_path.pkey_indx = pkeyindx;
19119517SBill.Taylor@Sun.COM 			} else {
19129517SBill.Taylor@Sun.COM 				return (IBT_PKEY_IX_ILLEGAL);
19139517SBill.Taylor@Sun.COM 			}
19149517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_ALT_PATH;
19159517SBill.Taylor@Sun.COM 		}
19169517SBill.Taylor@Sun.COM 	} else {
19179517SBill.Taylor@Sun.COM 		/*
19189517SBill.Taylor@Sun.COM 		 * Invalid QP transport type. If we got here then it's a
19199517SBill.Taylor@Sun.COM 		 * warning of a probably serious problem.  So print a message
19209517SBill.Taylor@Sun.COM 		 * and return failure
19219517SBill.Taylor@Sun.COM 		 */
19229517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "unknown QP transport type in rtr2rts");
19239517SBill.Taylor@Sun.COM 		return (ibc_get_ci_failure(0));
19249517SBill.Taylor@Sun.COM 	}
19259517SBill.Taylor@Sun.COM 
19269517SBill.Taylor@Sun.COM 	/*
19279517SBill.Taylor@Sun.COM 	 * Post the RTR2RTS_QP command to the Hermon firmware
19289517SBill.Taylor@Sun.COM 	 *
19299517SBill.Taylor@Sun.COM 	 * We do a HERMON_NOSLEEP here because we are still holding the
19309517SBill.Taylor@Sun.COM 	 * "qp_lock".  If we got raised to interrupt level by priority
19319517SBill.Taylor@Sun.COM 	 * inversion, we do not want to block in this routine waiting for
19329517SBill.Taylor@Sun.COM 	 * success.
19339517SBill.Taylor@Sun.COM 	 */
19349517SBill.Taylor@Sun.COM 	status = hermon_cmn_qp_cmd_post(state, RTR2RTS_QP, qpc, qp->qp_qpnum,
19359517SBill.Taylor@Sun.COM 	    opmask, HERMON_CMD_NOSLEEP_SPIN);
19369517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
19379517SBill.Taylor@Sun.COM 		if (status != HERMON_CMD_BAD_QP_STATE) {
19389517SBill.Taylor@Sun.COM 			cmn_err(CE_NOTE, "hermon%d: RTR2RTS_QP command failed: "
19399517SBill.Taylor@Sun.COM 			    "%08x\n", state->hs_instance, status);
19409517SBill.Taylor@Sun.COM 			if (status == HERMON_CMD_INVALID_STATUS) {
19419517SBill.Taylor@Sun.COM 				hermon_fm_ereport(state, HCA_SYS_ERR,
19429517SBill.Taylor@Sun.COM 				    HCA_ERR_SRV_LOST);
19439517SBill.Taylor@Sun.COM 			}
19449517SBill.Taylor@Sun.COM 			return (ibc_get_ci_failure(0));
19459517SBill.Taylor@Sun.COM 		} else {
19469517SBill.Taylor@Sun.COM 			return (IBT_QP_STATE_INVALID);
19479517SBill.Taylor@Sun.COM 		}
19489517SBill.Taylor@Sun.COM 	}
19499517SBill.Taylor@Sun.COM 
19509517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
19519517SBill.Taylor@Sun.COM }
19529517SBill.Taylor@Sun.COM 
19539517SBill.Taylor@Sun.COM 
19549517SBill.Taylor@Sun.COM /*
19559517SBill.Taylor@Sun.COM  * hermon_qp_rts2rts()
19569517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
19579517SBill.Taylor@Sun.COM  */
19589517SBill.Taylor@Sun.COM 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)19599517SBill.Taylor@Sun.COM hermon_qp_rts2rts(hermon_state_t *state, hermon_qphdl_t qp,
19609517SBill.Taylor@Sun.COM     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
19619517SBill.Taylor@Sun.COM {
19629517SBill.Taylor@Sun.COM 	hermon_hw_qpc_t		*qpc;
19639517SBill.Taylor@Sun.COM 	ibt_qp_rc_attr_t	*rc;
19649517SBill.Taylor@Sun.COM 	ibt_qp_ud_attr_t	*ud;
19659517SBill.Taylor@Sun.COM 	ibt_qp_uc_attr_t	*uc;
19669517SBill.Taylor@Sun.COM 	hermon_hw_addr_path_t	*qpc_path;
19679517SBill.Taylor@Sun.COM 	ibt_adds_vect_t		*adds_vect;
19689517SBill.Taylor@Sun.COM 	uint_t			portnum, pkeyindx;
19699517SBill.Taylor@Sun.COM 	uint32_t		opmask = 0;
19709517SBill.Taylor@Sun.COM 	int			status;
19719517SBill.Taylor@Sun.COM 
19729517SBill.Taylor@Sun.COM 	ASSERT(MUTEX_HELD(&qp->qp_lock));
19739517SBill.Taylor@Sun.COM 
19749517SBill.Taylor@Sun.COM 	/*
19759517SBill.Taylor@Sun.COM 	 * Grab the temporary QPC entry from QP software state
19769517SBill.Taylor@Sun.COM 	 */
19779517SBill.Taylor@Sun.COM 
19789517SBill.Taylor@Sun.COM 	qpc = &qp->qpc;
19799517SBill.Taylor@Sun.COM 
19809517SBill.Taylor@Sun.COM 	/*
19819517SBill.Taylor@Sun.COM 	 * Since there are no common fields to be filled in for this command,
19829517SBill.Taylor@Sun.COM 	 * we begin with the QPC fields which are specific to transport type.
19839517SBill.Taylor@Sun.COM 	 */
1984*12965SWilliam.Taylor@Oracle.COM 	if (qp->qp_type == IBT_UD_RQP) {
19859517SBill.Taylor@Sun.COM 		ud = &info_p->qp_transport.ud;
19869517SBill.Taylor@Sun.COM 
19879517SBill.Taylor@Sun.COM 		/*
19889517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the QKey for this QP, then
19899517SBill.Taylor@Sun.COM 		 * fill it in and set the appropriate flag in the "opmask"
19909517SBill.Taylor@Sun.COM 		 * parameter.
19919517SBill.Taylor@Sun.COM 		 */
19929517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_QKEY) {
19939517SBill.Taylor@Sun.COM 			qpc->qkey = ud->ud_qkey;
19949517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_QKEY;
19959517SBill.Taylor@Sun.COM 		}
19969517SBill.Taylor@Sun.COM 
19979517SBill.Taylor@Sun.COM 	} else if (qp->qp_serv_type == HERMON_QP_RC) {
19989517SBill.Taylor@Sun.COM 		rc = &info_p->qp_transport.rc;
19999517SBill.Taylor@Sun.COM 
20009517SBill.Taylor@Sun.COM 		/*
20019517SBill.Taylor@Sun.COM 		 * Check if any of the flags indicate a change in the RDMA
20029517SBill.Taylor@Sun.COM 		 * (recv) enable/disable flags and set the appropriate flag in
20039517SBill.Taylor@Sun.COM 		 * the "opmask" parameter
20049517SBill.Taylor@Sun.COM 		 */
20059517SBill.Taylor@Sun.COM 		opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
20069517SBill.Taylor@Sun.COM 
20079517SBill.Taylor@Sun.COM 		/*
20089517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the path migration state for
20099517SBill.Taylor@Sun.COM 		 * this QP, then check for valid state and fill it in.  Also
20109517SBill.Taylor@Sun.COM 		 * set the appropriate flag in the "opmask" parameter.
20119517SBill.Taylor@Sun.COM 		 */
20129517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_MIG) {
20139517SBill.Taylor@Sun.COM 			if (rc->rc_mig_state == IBT_STATE_MIGRATED) {
20149517SBill.Taylor@Sun.COM 				qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
20159517SBill.Taylor@Sun.COM 			} else if (rc->rc_mig_state == IBT_STATE_REARMED) {
20169517SBill.Taylor@Sun.COM 				qpc->pm_state = HERMON_QP_PMSTATE_REARM;
20179517SBill.Taylor@Sun.COM 			} else {
20189517SBill.Taylor@Sun.COM 				return (IBT_QP_APM_STATE_INVALID);
20199517SBill.Taylor@Sun.COM 			}
20209517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_PM_STATE;
20219517SBill.Taylor@Sun.COM 		}
20229517SBill.Taylor@Sun.COM 
20239517SBill.Taylor@Sun.COM 		/*
20249517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the "Minimum RNR NAK" value
20259517SBill.Taylor@Sun.COM 		 * for this QP, then fill it in and set the appropriate flag
20269517SBill.Taylor@Sun.COM 		 * in the "opmask" parameter.
20279517SBill.Taylor@Sun.COM 		 */
20289517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_MIN_RNR_NAK) {
20299517SBill.Taylor@Sun.COM 			qpc->min_rnr_nak = rc->rc_min_rnr_nak;
20309517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_MINRNRNAK;
20319517SBill.Taylor@Sun.COM 		}
20329517SBill.Taylor@Sun.COM 
20339517SBill.Taylor@Sun.COM 		/*
20349517SBill.Taylor@Sun.COM 		 * Check for optional alternate path and fill in the
20359517SBill.Taylor@Sun.COM 		 * appropriate QPC fields if one is specified
20369517SBill.Taylor@Sun.COM 		 */
20379517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_ALT_PATH) {
20389517SBill.Taylor@Sun.COM 			qpc_path = &qpc->alt_addr_path;
20399517SBill.Taylor@Sun.COM 			adds_vect = &rc->rc_alt_path.cep_adds_vect;
20409517SBill.Taylor@Sun.COM 
20419517SBill.Taylor@Sun.COM 			/* Set the common alternate address path fields */
20429517SBill.Taylor@Sun.COM 			status = hermon_set_addr_path(state, adds_vect,
20439517SBill.Taylor@Sun.COM 			    qpc_path, HERMON_ADDRPATH_QP);
20449517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
20459517SBill.Taylor@Sun.COM 				return (status);
20469517SBill.Taylor@Sun.COM 			}
20479517SBill.Taylor@Sun.COM 			qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
20489517SBill.Taylor@Sun.COM 
20499517SBill.Taylor@Sun.COM 			/*
20509517SBill.Taylor@Sun.COM 			 * Check for valid alternate path port number and fill
20519517SBill.Taylor@Sun.COM 			 * it in
20529517SBill.Taylor@Sun.COM 			 */
20539517SBill.Taylor@Sun.COM 			portnum = rc->rc_alt_path.cep_hca_port_num;
20549517SBill.Taylor@Sun.COM 			if (hermon_portnum_is_valid(state, portnum)) {
20559517SBill.Taylor@Sun.COM 				qp->qp_portnum_alt = portnum - 1;
20569517SBill.Taylor@Sun.COM 				qpc->alt_addr_path.sched_q =
20579517SBill.Taylor@Sun.COM 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
20589517SBill.Taylor@Sun.COM 				    adds_vect->av_srvl, qp->qp_is_special);
20599517SBill.Taylor@Sun.COM 			} else {
20609517SBill.Taylor@Sun.COM 				return (IBT_HCA_PORT_INVALID);
20619517SBill.Taylor@Sun.COM 			}
20629517SBill.Taylor@Sun.COM 
20639517SBill.Taylor@Sun.COM 			/*
20649517SBill.Taylor@Sun.COM 			 * Check for valid alternate path PKey index and fill
20659517SBill.Taylor@Sun.COM 			 * it in
20669517SBill.Taylor@Sun.COM 			 */
20679517SBill.Taylor@Sun.COM 			pkeyindx = rc->rc_alt_path.cep_pkey_ix;
20689517SBill.Taylor@Sun.COM 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
20699517SBill.Taylor@Sun.COM 				qpc->alt_addr_path.pkey_indx = pkeyindx;
20709517SBill.Taylor@Sun.COM 			} else {
20719517SBill.Taylor@Sun.COM 				return (IBT_PKEY_IX_ILLEGAL);
20729517SBill.Taylor@Sun.COM 			}
20739517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_ALT_PATH;
20749517SBill.Taylor@Sun.COM 		}
20759517SBill.Taylor@Sun.COM 
20769517SBill.Taylor@Sun.COM 	} else if (qp->qp_serv_type == HERMON_QP_UC) {
20779517SBill.Taylor@Sun.COM 		uc = &info_p->qp_transport.uc;
20789517SBill.Taylor@Sun.COM 
20799517SBill.Taylor@Sun.COM 		/*
20809517SBill.Taylor@Sun.COM 		 * Check if any of the flags indicate a change in the RDMA
20819517SBill.Taylor@Sun.COM 		 * Write (recv) enable/disable and set the appropriate flag
20829517SBill.Taylor@Sun.COM 		 * in the "opmask" parameter. Note: RDMA Read and Atomic are
20839517SBill.Taylor@Sun.COM 		 * not valid for UC transport.
20849517SBill.Taylor@Sun.COM 		 */
20859517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_RDMA_W) {
20869517SBill.Taylor@Sun.COM 			qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
20879517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_RWE;
20889517SBill.Taylor@Sun.COM 		}
20899517SBill.Taylor@Sun.COM 
20909517SBill.Taylor@Sun.COM 		/*
20919517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the path migration state for
20929517SBill.Taylor@Sun.COM 		 * this QP, then check for valid state and fill it in.  Also
20939517SBill.Taylor@Sun.COM 		 * set the appropriate flag in the "opmask" parameter.
20949517SBill.Taylor@Sun.COM 		 */
20959517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_MIG) {
20969517SBill.Taylor@Sun.COM 			if (uc->uc_mig_state == IBT_STATE_MIGRATED) {
20979517SBill.Taylor@Sun.COM 				qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
20989517SBill.Taylor@Sun.COM 			} else if (uc->uc_mig_state == IBT_STATE_REARMED) {
20999517SBill.Taylor@Sun.COM 				qpc->pm_state = HERMON_QP_PMSTATE_REARM;
21009517SBill.Taylor@Sun.COM 			} else {
21019517SBill.Taylor@Sun.COM 				return (IBT_QP_APM_STATE_INVALID);
21029517SBill.Taylor@Sun.COM 			}
21039517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_PM_STATE;
21049517SBill.Taylor@Sun.COM 		}
21059517SBill.Taylor@Sun.COM 
21069517SBill.Taylor@Sun.COM 		/*
21079517SBill.Taylor@Sun.COM 		 * Check for optional alternate path and fill in the
21089517SBill.Taylor@Sun.COM 		 * appropriate QPC fields if one is specified
21099517SBill.Taylor@Sun.COM 		 */
21109517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_ALT_PATH) {
21119517SBill.Taylor@Sun.COM 			qpc_path = &qpc->alt_addr_path;
21129517SBill.Taylor@Sun.COM 			adds_vect = &uc->uc_alt_path.cep_adds_vect;
21139517SBill.Taylor@Sun.COM 
21149517SBill.Taylor@Sun.COM 			/* Set the common alternate address path fields */
21159517SBill.Taylor@Sun.COM 			status = hermon_set_addr_path(state, adds_vect,
21169517SBill.Taylor@Sun.COM 			    qpc_path, HERMON_ADDRPATH_QP);
21179517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
21189517SBill.Taylor@Sun.COM 				return (status);
21199517SBill.Taylor@Sun.COM 			}
21209517SBill.Taylor@Sun.COM 
21219517SBill.Taylor@Sun.COM 			/*
21229517SBill.Taylor@Sun.COM 			 * Check for valid alternate path port number and fill
21239517SBill.Taylor@Sun.COM 			 * it in
21249517SBill.Taylor@Sun.COM 			 */
21259517SBill.Taylor@Sun.COM 			portnum = uc->uc_alt_path.cep_hca_port_num;
21269517SBill.Taylor@Sun.COM 			if (hermon_portnum_is_valid(state, portnum)) {
21279517SBill.Taylor@Sun.COM 				qp->qp_portnum_alt = portnum - 1;
21289517SBill.Taylor@Sun.COM 				qpc->alt_addr_path.sched_q =
21299517SBill.Taylor@Sun.COM 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
21309517SBill.Taylor@Sun.COM 				    adds_vect->av_srvl, qp->qp_is_special);
21319517SBill.Taylor@Sun.COM 			} else {
21329517SBill.Taylor@Sun.COM 				return (IBT_HCA_PORT_INVALID);
21339517SBill.Taylor@Sun.COM 			}
21349517SBill.Taylor@Sun.COM 
21359517SBill.Taylor@Sun.COM 			/*
21369517SBill.Taylor@Sun.COM 			 * Check for valid alternate path PKey index and fill
21379517SBill.Taylor@Sun.COM 			 * it in
21389517SBill.Taylor@Sun.COM 			 */
21399517SBill.Taylor@Sun.COM 			pkeyindx = uc->uc_alt_path.cep_pkey_ix;
21409517SBill.Taylor@Sun.COM 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
21419517SBill.Taylor@Sun.COM 				qpc->alt_addr_path.pkey_indx = pkeyindx;
21429517SBill.Taylor@Sun.COM 			} else {
21439517SBill.Taylor@Sun.COM 				return (IBT_PKEY_IX_ILLEGAL);
21449517SBill.Taylor@Sun.COM 			}
21459517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_ALT_PATH;
21469517SBill.Taylor@Sun.COM 		}
21479517SBill.Taylor@Sun.COM 	} else {
21489517SBill.Taylor@Sun.COM 		/*
21499517SBill.Taylor@Sun.COM 		 * Invalid QP transport type. If we got here then it's a
21509517SBill.Taylor@Sun.COM 		 * warning of a probably serious problem.  So print a message
21519517SBill.Taylor@Sun.COM 		 * and return failure
21529517SBill.Taylor@Sun.COM 		 */
21539517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "unknown QP transport type in rts2rts");
21549517SBill.Taylor@Sun.COM 		return (ibc_get_ci_failure(0));
21559517SBill.Taylor@Sun.COM 	}
21569517SBill.Taylor@Sun.COM 
21579517SBill.Taylor@Sun.COM 	/*
21589517SBill.Taylor@Sun.COM 	 * Post the RTS2RTS_QP command to the Hermon firmware
21599517SBill.Taylor@Sun.COM 	 *
21609517SBill.Taylor@Sun.COM 	 * We do a HERMON_NOSLEEP here because we are still holding the
21619517SBill.Taylor@Sun.COM 	 * "qp_lock".  If we got raised to interrupt level by priority
21629517SBill.Taylor@Sun.COM 	 * inversion, we do not want to block in this routine waiting for
21639517SBill.Taylor@Sun.COM 	 * success.
21649517SBill.Taylor@Sun.COM 	 */
21659517SBill.Taylor@Sun.COM 	status = hermon_cmn_qp_cmd_post(state, RTS2RTS_QP, qpc, qp->qp_qpnum,
21669517SBill.Taylor@Sun.COM 	    opmask, HERMON_CMD_NOSLEEP_SPIN);
21679517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
21689517SBill.Taylor@Sun.COM 		if (status != HERMON_CMD_BAD_QP_STATE) {
21699517SBill.Taylor@Sun.COM 			cmn_err(CE_NOTE, "hermon%d: RTS2RTS_QP command failed: "
21709517SBill.Taylor@Sun.COM 			    "%08x\n", state->hs_instance, status);
21719517SBill.Taylor@Sun.COM 			if (status == HERMON_CMD_INVALID_STATUS) {
21729517SBill.Taylor@Sun.COM 				hermon_fm_ereport(state, HCA_SYS_ERR,
21739517SBill.Taylor@Sun.COM 				    HCA_ERR_SRV_LOST);
21749517SBill.Taylor@Sun.COM 			}
21759517SBill.Taylor@Sun.COM 			return (ibc_get_ci_failure(0));
21769517SBill.Taylor@Sun.COM 		} else {
21779517SBill.Taylor@Sun.COM 			return (IBT_QP_STATE_INVALID);
21789517SBill.Taylor@Sun.COM 		}
21799517SBill.Taylor@Sun.COM 	}
21809517SBill.Taylor@Sun.COM 
21819517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
21829517SBill.Taylor@Sun.COM }
21839517SBill.Taylor@Sun.COM 
21849517SBill.Taylor@Sun.COM 
21859517SBill.Taylor@Sun.COM #ifdef HERMON_NOTNOW
21869517SBill.Taylor@Sun.COM /*
21879517SBill.Taylor@Sun.COM  * hermon_qp_rts2sqd()
21889517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
21899517SBill.Taylor@Sun.COM  */
21909517SBill.Taylor@Sun.COM static int
hermon_qp_rts2sqd(hermon_state_t * state,hermon_qphdl_t qp,ibt_cep_modify_flags_t flags)21919517SBill.Taylor@Sun.COM hermon_qp_rts2sqd(hermon_state_t *state, hermon_qphdl_t qp,
21929517SBill.Taylor@Sun.COM     ibt_cep_modify_flags_t flags)
21939517SBill.Taylor@Sun.COM {
21949517SBill.Taylor@Sun.COM 	int			status;
21959517SBill.Taylor@Sun.COM 
21969517SBill.Taylor@Sun.COM 	ASSERT(MUTEX_HELD(&qp->qp_lock));
21979517SBill.Taylor@Sun.COM 
21989517SBill.Taylor@Sun.COM 	/*
21999517SBill.Taylor@Sun.COM 	 * Set a flag to indicate whether or not the consumer is interested
22009517SBill.Taylor@Sun.COM 	 * in receiving the SQ drained event.  Since we are going to always
22019517SBill.Taylor@Sun.COM 	 * request hardware generation of the SQD event, we use the value in
22029517SBill.Taylor@Sun.COM 	 * "qp_forward_sqd_event" to determine whether or not to pass the event
22039517SBill.Taylor@Sun.COM 	 * to the IBTF or to silently consume it.
22049517SBill.Taylor@Sun.COM 	 */
22059517SBill.Taylor@Sun.COM 	qp->qp_forward_sqd_event = (flags & IBT_CEP_SET_SQD_EVENT) ? 1 : 0;
22069517SBill.Taylor@Sun.COM 
22079517SBill.Taylor@Sun.COM 	/*
22089517SBill.Taylor@Sun.COM 	 * Post the RTS2SQD_QP command to the Hermon firmware
22099517SBill.Taylor@Sun.COM 	 *
22109517SBill.Taylor@Sun.COM 	 * We do a HERMON_NOSLEEP here because we are still holding the
22119517SBill.Taylor@Sun.COM 	 * "qp_lock".  If we got raised to interrupt level by priority
22129517SBill.Taylor@Sun.COM 	 * inversion, we do not want to block in this routine waiting for
22139517SBill.Taylor@Sun.COM 	 * success.
22149517SBill.Taylor@Sun.COM 	 */
22159517SBill.Taylor@Sun.COM 	status = hermon_cmn_qp_cmd_post(state, RTS2SQD_QP, NULL, qp->qp_qpnum,
22169517SBill.Taylor@Sun.COM 	    0, HERMON_CMD_NOSLEEP_SPIN);
22179517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
22189517SBill.Taylor@Sun.COM 		if (status != HERMON_CMD_BAD_QP_STATE) {
22199517SBill.Taylor@Sun.COM 			cmn_err(CE_NOTE, "hermon%d: RTS2SQD_QP command failed: "
22209517SBill.Taylor@Sun.COM 			    "%08x\n", state->hs_instance, status);
22219517SBill.Taylor@Sun.COM 			if (status == HERMON_CMD_INVALID_STATUS) {
22229517SBill.Taylor@Sun.COM 				hermon_fm_ereport(state, HCA_SYS_ERR,
22239517SBill.Taylor@Sun.COM 				    HCA_ERR_SRV_LOST);
22249517SBill.Taylor@Sun.COM 			}
22259517SBill.Taylor@Sun.COM 			return (ibc_get_ci_failure(0));
22269517SBill.Taylor@Sun.COM 		} else {
22279517SBill.Taylor@Sun.COM 			return (IBT_QP_STATE_INVALID);
22289517SBill.Taylor@Sun.COM 		}
22299517SBill.Taylor@Sun.COM 	}
22309517SBill.Taylor@Sun.COM 
22319517SBill.Taylor@Sun.COM 	/*
22329517SBill.Taylor@Sun.COM 	 * Mark the current QP state as "SQ Draining".  This allows us to
22339517SBill.Taylor@Sun.COM 	 * distinguish between the two underlying states in SQD. (see QueryQP()
22349517SBill.Taylor@Sun.COM 	 * code in hermon_qp.c)
22359517SBill.Taylor@Sun.COM 	 */
22369517SBill.Taylor@Sun.COM 	qp->qp_sqd_still_draining = 1;
22379517SBill.Taylor@Sun.COM 
22389517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
22399517SBill.Taylor@Sun.COM }
22409517SBill.Taylor@Sun.COM #endif
22419517SBill.Taylor@Sun.COM 
22429517SBill.Taylor@Sun.COM 
22439517SBill.Taylor@Sun.COM /*
22449517SBill.Taylor@Sun.COM  * hermon_qp_sqd2rts()
22459517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
22469517SBill.Taylor@Sun.COM  */
22479517SBill.Taylor@Sun.COM 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)22489517SBill.Taylor@Sun.COM hermon_qp_sqd2rts(hermon_state_t *state, hermon_qphdl_t qp,
22499517SBill.Taylor@Sun.COM     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
22509517SBill.Taylor@Sun.COM {
22519517SBill.Taylor@Sun.COM 	hermon_hw_qpc_t		*qpc;
22529517SBill.Taylor@Sun.COM 	ibt_qp_rc_attr_t	*rc;
22539517SBill.Taylor@Sun.COM 	ibt_qp_ud_attr_t	*ud;
22549517SBill.Taylor@Sun.COM 	ibt_qp_uc_attr_t	*uc;
22559517SBill.Taylor@Sun.COM 	hermon_hw_addr_path_t	*qpc_path;
22569517SBill.Taylor@Sun.COM 	ibt_adds_vect_t		*adds_vect;
22579517SBill.Taylor@Sun.COM 	uint_t			portnum, pkeyindx;
22589517SBill.Taylor@Sun.COM 	uint_t			rra_max, sra_max;
22599517SBill.Taylor@Sun.COM 	uint32_t		opmask = 0;
22609517SBill.Taylor@Sun.COM 	int			status;
22619517SBill.Taylor@Sun.COM 
22629517SBill.Taylor@Sun.COM 	ASSERT(MUTEX_HELD(&qp->qp_lock));
22639517SBill.Taylor@Sun.COM 
22649517SBill.Taylor@Sun.COM 	/*
22659517SBill.Taylor@Sun.COM 	 * Grab the temporary QPC entry from QP software state
22669517SBill.Taylor@Sun.COM 	 */
22679517SBill.Taylor@Sun.COM 	qpc = &qp->qpc;
22689517SBill.Taylor@Sun.COM 
22699517SBill.Taylor@Sun.COM 	/*
22709517SBill.Taylor@Sun.COM 	 * Fill in the common fields in the QPC
22719517SBill.Taylor@Sun.COM 	 */
22729517SBill.Taylor@Sun.COM 
22739517SBill.Taylor@Sun.COM 	/*
22749517SBill.Taylor@Sun.COM 	 * Now fill in the QPC fields which are specific to transport type
22759517SBill.Taylor@Sun.COM 	 */
2276*12965SWilliam.Taylor@Oracle.COM 	if (qp->qp_type == IBT_UD_RQP) {
22779517SBill.Taylor@Sun.COM 		ud = &info_p->qp_transport.ud;
22789517SBill.Taylor@Sun.COM 
22799517SBill.Taylor@Sun.COM 		/*
22809517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the port for this QP, then
22819517SBill.Taylor@Sun.COM 		 * check for valid port number and fill it in.  Also set the
22829517SBill.Taylor@Sun.COM 		 * appropriate flag in the "opmask" parameter.
22839517SBill.Taylor@Sun.COM 		 */
22849517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_PORT) {
22859517SBill.Taylor@Sun.COM 			portnum = ud->ud_port;
22869517SBill.Taylor@Sun.COM 			if (hermon_portnum_is_valid(state, portnum)) {
22879517SBill.Taylor@Sun.COM 				qp->qp_portnum = portnum - 1;
22889517SBill.Taylor@Sun.COM 				qpc->pri_addr_path.sched_q =
22899517SBill.Taylor@Sun.COM 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
22909517SBill.Taylor@Sun.COM 				    0, qp->qp_is_special);
22919517SBill.Taylor@Sun.COM 			} else {
22929517SBill.Taylor@Sun.COM 				return (IBT_HCA_PORT_INVALID);
22939517SBill.Taylor@Sun.COM 			}
22949517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_PRIM_PORT;
22959517SBill.Taylor@Sun.COM 		}
22969517SBill.Taylor@Sun.COM 
22979517SBill.Taylor@Sun.COM 		/*
22989517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the PKey index for this QP,
22999517SBill.Taylor@Sun.COM 		 * then check for valid PKey index and fill it in.  Also set
23009517SBill.Taylor@Sun.COM 		 * the appropriate flag in the "opmask" parameter.
23019517SBill.Taylor@Sun.COM 		 */
23029517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_PKEY_IX) {
23039517SBill.Taylor@Sun.COM 			pkeyindx = ud->ud_pkey_ix;
23049517SBill.Taylor@Sun.COM 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
23059517SBill.Taylor@Sun.COM 				qpc->pri_addr_path.pkey_indx = pkeyindx;
23069517SBill.Taylor@Sun.COM 				opmask |= HERMON_CMD_OP_PKEYINDX;
23079517SBill.Taylor@Sun.COM 				qp->qp_pkeyindx = pkeyindx;
23089517SBill.Taylor@Sun.COM 			} else {
23099517SBill.Taylor@Sun.COM 				return (IBT_PKEY_IX_ILLEGAL);
23109517SBill.Taylor@Sun.COM 			}
23119517SBill.Taylor@Sun.COM 		}
23129517SBill.Taylor@Sun.COM 
23139517SBill.Taylor@Sun.COM 		/*
23149517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the QKey for this QP, then
23159517SBill.Taylor@Sun.COM 		 * fill it in and set the appropriate flag in the "opmask"
23169517SBill.Taylor@Sun.COM 		 * parameter.
23179517SBill.Taylor@Sun.COM 		 */
23189517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_QKEY) {
23199517SBill.Taylor@Sun.COM 			qpc->qkey = ud->ud_qkey;
23209517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_QKEY;
23219517SBill.Taylor@Sun.COM 		}
23229517SBill.Taylor@Sun.COM 
23239517SBill.Taylor@Sun.COM 	} else if (qp->qp_serv_type == HERMON_QP_RC) {
23249517SBill.Taylor@Sun.COM 		rc = &info_p->qp_transport.rc;
23259517SBill.Taylor@Sun.COM 
23269517SBill.Taylor@Sun.COM 		/*
23279517SBill.Taylor@Sun.COM 		 * Check if any of the flags indicate a change in the RDMA
23289517SBill.Taylor@Sun.COM 		 * (recv) enable/disable flags and set the appropriate flag in
23299517SBill.Taylor@Sun.COM 		 * the "opmask" parameter
23309517SBill.Taylor@Sun.COM 		 */
23319517SBill.Taylor@Sun.COM 		opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
23329517SBill.Taylor@Sun.COM 
23339517SBill.Taylor@Sun.COM 		qpc->retry_cnt = rc->rc_retry_cnt;
23349517SBill.Taylor@Sun.COM 
23359517SBill.Taylor@Sun.COM 		/*
23369517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the path migration state for
23379517SBill.Taylor@Sun.COM 		 * this QP, then check for valid state and fill it in.  Also
23389517SBill.Taylor@Sun.COM 		 * set the appropriate flag in the "opmask" parameter.
23399517SBill.Taylor@Sun.COM 		 */
23409517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_MIG) {
23419517SBill.Taylor@Sun.COM 			if (rc->rc_mig_state == IBT_STATE_MIGRATED) {
23429517SBill.Taylor@Sun.COM 				qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
23439517SBill.Taylor@Sun.COM 			} else if (rc->rc_mig_state == IBT_STATE_REARMED) {
23449517SBill.Taylor@Sun.COM 				qpc->pm_state = HERMON_QP_PMSTATE_REARM;
23459517SBill.Taylor@Sun.COM 			} else {
23469517SBill.Taylor@Sun.COM 				return (IBT_QP_APM_STATE_INVALID);
23479517SBill.Taylor@Sun.COM 			}
23489517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_PM_STATE;
23499517SBill.Taylor@Sun.COM 		}
23509517SBill.Taylor@Sun.COM 
23519517SBill.Taylor@Sun.COM 		/*
23529517SBill.Taylor@Sun.COM 		 * Check for optional alternate path and fill in the
23539517SBill.Taylor@Sun.COM 		 * appropriate QPC fields if one is specified
23549517SBill.Taylor@Sun.COM 		 */
23559517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_ALT_PATH) {
23569517SBill.Taylor@Sun.COM 			qpc_path = &qpc->alt_addr_path;
23579517SBill.Taylor@Sun.COM 			adds_vect = &rc->rc_alt_path.cep_adds_vect;
23589517SBill.Taylor@Sun.COM 
23599517SBill.Taylor@Sun.COM 			/* Set the common alternate address path fields */
23609517SBill.Taylor@Sun.COM 			status = hermon_set_addr_path(state, adds_vect,
23619517SBill.Taylor@Sun.COM 			    qpc_path, HERMON_ADDRPATH_QP);
23629517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
23639517SBill.Taylor@Sun.COM 				return (status);
23649517SBill.Taylor@Sun.COM 			}
23659517SBill.Taylor@Sun.COM 			qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
23669517SBill.Taylor@Sun.COM 			/*
23679517SBill.Taylor@Sun.COM 			 * Check for valid alternate path port number and fill
23689517SBill.Taylor@Sun.COM 			 * it in
23699517SBill.Taylor@Sun.COM 			 */
23709517SBill.Taylor@Sun.COM 			portnum = rc->rc_alt_path.cep_hca_port_num;
23719517SBill.Taylor@Sun.COM 			if (hermon_portnum_is_valid(state, portnum)) {
23729517SBill.Taylor@Sun.COM 				qp->qp_portnum_alt = portnum - 1;
23739517SBill.Taylor@Sun.COM 				qpc->alt_addr_path.sched_q =
23749517SBill.Taylor@Sun.COM 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
23759517SBill.Taylor@Sun.COM 				    adds_vect->av_srvl, qp->qp_is_special);
23769517SBill.Taylor@Sun.COM 			} else {
23779517SBill.Taylor@Sun.COM 				return (IBT_HCA_PORT_INVALID);
23789517SBill.Taylor@Sun.COM 			}
23799517SBill.Taylor@Sun.COM 
23809517SBill.Taylor@Sun.COM 			/*
23819517SBill.Taylor@Sun.COM 			 * Check for valid alternate path PKey index and fill
23829517SBill.Taylor@Sun.COM 			 * it in
23839517SBill.Taylor@Sun.COM 			 */
23849517SBill.Taylor@Sun.COM 			pkeyindx = rc->rc_alt_path.cep_pkey_ix;
23859517SBill.Taylor@Sun.COM 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
23869517SBill.Taylor@Sun.COM 				qpc->alt_addr_path.pkey_indx = pkeyindx;
23879517SBill.Taylor@Sun.COM 			} else {
23889517SBill.Taylor@Sun.COM 				return (IBT_PKEY_IX_ILLEGAL);
23899517SBill.Taylor@Sun.COM 			}
23909517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_ALT_PATH;
23919517SBill.Taylor@Sun.COM 		}
23929517SBill.Taylor@Sun.COM 
23939517SBill.Taylor@Sun.COM 		/*
23949517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the number of "outgoing
23959517SBill.Taylor@Sun.COM 		 * RDMA resources" for this QP, then check for valid value and
23969517SBill.Taylor@Sun.COM 		 * fill it in.  Also set the appropriate flag in the "opmask"
23979517SBill.Taylor@Sun.COM 		 * parameter.
23989517SBill.Taylor@Sun.COM 		 */
23999517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_RDMARA_OUT) {
24009517SBill.Taylor@Sun.COM 			if (hermon_qp_validate_init_depth(state, rc,
24019517SBill.Taylor@Sun.COM 			    &sra_max) != DDI_SUCCESS) {
24029517SBill.Taylor@Sun.COM 				return (IBT_INVALID_PARAM);
24039517SBill.Taylor@Sun.COM 			}
24049517SBill.Taylor@Sun.COM 			qpc->sra_max = sra_max;
24059517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_SRA_SET;
24069517SBill.Taylor@Sun.COM 		}
24079517SBill.Taylor@Sun.COM 
24089517SBill.Taylor@Sun.COM 		/*
24099517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the number of "incoming
24109517SBill.Taylor@Sun.COM 		 * RDMA resources" for this QP, then check for valid value and
24119517SBill.Taylor@Sun.COM 		 * update the "rra_max" and "ra_buf_index" fields in the QPC to
24129517SBill.Taylor@Sun.COM 		 * point to the pre-allocated RDB resources (in DDR).  Also set
24139517SBill.Taylor@Sun.COM 		 * the appropriate flag in the "opmask" parameter.
24149517SBill.Taylor@Sun.COM 		 */
24159517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_RDMARA_IN) {
24169517SBill.Taylor@Sun.COM 			if (hermon_qp_validate_resp_rsrc(state, rc,
24179517SBill.Taylor@Sun.COM 			    &rra_max) != DDI_SUCCESS) {
24189517SBill.Taylor@Sun.COM 				return (IBT_INVALID_PARAM);
24199517SBill.Taylor@Sun.COM 			}
24209517SBill.Taylor@Sun.COM 			qpc->rra_max = rra_max;
24219517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_RRA_SET;
24229517SBill.Taylor@Sun.COM 		}
24239517SBill.Taylor@Sun.COM 
24249517SBill.Taylor@Sun.COM 
24259517SBill.Taylor@Sun.COM 		/*
24269517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the "Minimum RNR NAK" value
24279517SBill.Taylor@Sun.COM 		 * for this QP, then fill it in and set the appropriate flag
24289517SBill.Taylor@Sun.COM 		 * in the "opmask" parameter.
24299517SBill.Taylor@Sun.COM 		 */
24309517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_MIN_RNR_NAK) {
24319517SBill.Taylor@Sun.COM 			qpc->min_rnr_nak = rc->rc_min_rnr_nak;
24329517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_MINRNRNAK;
24339517SBill.Taylor@Sun.COM 		}
24349517SBill.Taylor@Sun.COM 
24359517SBill.Taylor@Sun.COM 	} else if (qp->qp_serv_type == HERMON_QP_UC) {
24369517SBill.Taylor@Sun.COM 		uc = &info_p->qp_transport.uc;
24379517SBill.Taylor@Sun.COM 
24389517SBill.Taylor@Sun.COM 		/*
24399517SBill.Taylor@Sun.COM 		 * Check if any of the flags indicate a change in the RDMA
24409517SBill.Taylor@Sun.COM 		 * Write (recv) enable/disable and set the appropriate flag
24419517SBill.Taylor@Sun.COM 		 * in the "opmask" parameter. Note: RDMA Read and Atomic are
24429517SBill.Taylor@Sun.COM 		 * not valid for UC transport.
24439517SBill.Taylor@Sun.COM 		 */
24449517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_RDMA_W) {
24459517SBill.Taylor@Sun.COM 			qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
24469517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_RWE;
24479517SBill.Taylor@Sun.COM 		}
24489517SBill.Taylor@Sun.COM 
24499517SBill.Taylor@Sun.COM 		/*
24509517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the path migration state for
24519517SBill.Taylor@Sun.COM 		 * this QP, then check for valid state and fill it in.  Also
24529517SBill.Taylor@Sun.COM 		 * set the appropriate flag in the "opmask" parameter.
24539517SBill.Taylor@Sun.COM 		 */
24549517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_MIG) {
24559517SBill.Taylor@Sun.COM 			if (uc->uc_mig_state == IBT_STATE_MIGRATED) {
24569517SBill.Taylor@Sun.COM 				qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
24579517SBill.Taylor@Sun.COM 			} else if (uc->uc_mig_state == IBT_STATE_REARMED) {
24589517SBill.Taylor@Sun.COM 				qpc->pm_state = HERMON_QP_PMSTATE_REARM;
24599517SBill.Taylor@Sun.COM 			} else {
24609517SBill.Taylor@Sun.COM 				return (IBT_QP_APM_STATE_INVALID);
24619517SBill.Taylor@Sun.COM 			}
24629517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_PM_STATE;
24639517SBill.Taylor@Sun.COM 		}
24649517SBill.Taylor@Sun.COM 
24659517SBill.Taylor@Sun.COM 		/*
24669517SBill.Taylor@Sun.COM 		 * Check for optional alternate path and fill in the
24679517SBill.Taylor@Sun.COM 		 * appropriate QPC fields if one is specified
24689517SBill.Taylor@Sun.COM 		 */
24699517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_ALT_PATH) {
24709517SBill.Taylor@Sun.COM 			qpc_path = &qpc->alt_addr_path;
24719517SBill.Taylor@Sun.COM 			adds_vect = &uc->uc_alt_path.cep_adds_vect;
24729517SBill.Taylor@Sun.COM 
24739517SBill.Taylor@Sun.COM 			/* Set the common alternate address path fields */
24749517SBill.Taylor@Sun.COM 			status = hermon_set_addr_path(state, adds_vect,
24759517SBill.Taylor@Sun.COM 			    qpc_path, HERMON_ADDRPATH_QP);
24769517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
24779517SBill.Taylor@Sun.COM 				return (status);
24789517SBill.Taylor@Sun.COM 			}
24799517SBill.Taylor@Sun.COM 
24809517SBill.Taylor@Sun.COM 			/*
24819517SBill.Taylor@Sun.COM 			 * Check for valid alternate path port number and fill
24829517SBill.Taylor@Sun.COM 			 * it in
24839517SBill.Taylor@Sun.COM 			 */
24849517SBill.Taylor@Sun.COM 			portnum = uc->uc_alt_path.cep_hca_port_num;
24859517SBill.Taylor@Sun.COM 			if (hermon_portnum_is_valid(state, portnum)) {
24869517SBill.Taylor@Sun.COM 				qp->qp_portnum_alt = portnum - 1;
24879517SBill.Taylor@Sun.COM 				qpc->alt_addr_path.sched_q =
24889517SBill.Taylor@Sun.COM 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
24899517SBill.Taylor@Sun.COM 				    adds_vect->av_srvl, qp->qp_is_special);
24909517SBill.Taylor@Sun.COM 			} else {
24919517SBill.Taylor@Sun.COM 				return (IBT_HCA_PORT_INVALID);
24929517SBill.Taylor@Sun.COM 			}
24939517SBill.Taylor@Sun.COM 
24949517SBill.Taylor@Sun.COM 			/*
24959517SBill.Taylor@Sun.COM 			 * Check for valid alternate path PKey index and fill
24969517SBill.Taylor@Sun.COM 			 * it in
24979517SBill.Taylor@Sun.COM 			 */
24989517SBill.Taylor@Sun.COM 			pkeyindx = uc->uc_alt_path.cep_pkey_ix;
24999517SBill.Taylor@Sun.COM 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
25009517SBill.Taylor@Sun.COM 				qpc->alt_addr_path.pkey_indx = pkeyindx;
25019517SBill.Taylor@Sun.COM 			} else {
25029517SBill.Taylor@Sun.COM 				return (IBT_PKEY_IX_ILLEGAL);
25039517SBill.Taylor@Sun.COM 			}
25049517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_ALT_PATH;
25059517SBill.Taylor@Sun.COM 		}
25069517SBill.Taylor@Sun.COM 	} else {
25079517SBill.Taylor@Sun.COM 		/*
25089517SBill.Taylor@Sun.COM 		 * Invalid QP transport type. If we got here then it's a
25099517SBill.Taylor@Sun.COM 		 * warning of a probably serious problem.  So print a message
25109517SBill.Taylor@Sun.COM 		 * and return failure
25119517SBill.Taylor@Sun.COM 		 */
25129517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "unknown QP transport type in sqd2rts");
25139517SBill.Taylor@Sun.COM 		return (ibc_get_ci_failure(0));
25149517SBill.Taylor@Sun.COM 	}
25159517SBill.Taylor@Sun.COM 
25169517SBill.Taylor@Sun.COM 	/*
25179517SBill.Taylor@Sun.COM 	 * Post the SQD2RTS_QP command to the Hermon firmware
25189517SBill.Taylor@Sun.COM 	 *
25199517SBill.Taylor@Sun.COM 	 * We do a HERMON_NOSLEEP here because we are still holding the
25209517SBill.Taylor@Sun.COM 	 * "qp_lock".  If we got raised to interrupt level by priority
25219517SBill.Taylor@Sun.COM 	 * inversion, we do not want to block in this routine waiting for
25229517SBill.Taylor@Sun.COM 	 * success.
25239517SBill.Taylor@Sun.COM 	 */
25249517SBill.Taylor@Sun.COM 	status = hermon_cmn_qp_cmd_post(state, SQD2RTS_QP, qpc, qp->qp_qpnum,
25259517SBill.Taylor@Sun.COM 	    opmask, HERMON_CMD_NOSLEEP_SPIN);
25269517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
25279517SBill.Taylor@Sun.COM 		if (status != HERMON_CMD_BAD_QP_STATE) {
25289517SBill.Taylor@Sun.COM 			cmn_err(CE_NOTE, "hermon%d: SQD2RTS_QP command failed: "
25299517SBill.Taylor@Sun.COM 			    "%08x\n", state->hs_instance, status);
25309517SBill.Taylor@Sun.COM 			if (status == HERMON_CMD_INVALID_STATUS) {
25319517SBill.Taylor@Sun.COM 				hermon_fm_ereport(state, HCA_SYS_ERR,
25329517SBill.Taylor@Sun.COM 				    HCA_ERR_SRV_LOST);
25339517SBill.Taylor@Sun.COM 			}
25349517SBill.Taylor@Sun.COM 			return (ibc_get_ci_failure(0));
25359517SBill.Taylor@Sun.COM 		} else {
25369517SBill.Taylor@Sun.COM 			return (IBT_QP_STATE_INVALID);
25379517SBill.Taylor@Sun.COM 		}
25389517SBill.Taylor@Sun.COM 	}
25399517SBill.Taylor@Sun.COM 
25409517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
25419517SBill.Taylor@Sun.COM }
25429517SBill.Taylor@Sun.COM 
25439517SBill.Taylor@Sun.COM 
25449517SBill.Taylor@Sun.COM /*
25459517SBill.Taylor@Sun.COM  * hermon_qp_sqd2sqd()
25469517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
25479517SBill.Taylor@Sun.COM  */
25489517SBill.Taylor@Sun.COM 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)25499517SBill.Taylor@Sun.COM hermon_qp_sqd2sqd(hermon_state_t *state, hermon_qphdl_t qp,
25509517SBill.Taylor@Sun.COM     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
25519517SBill.Taylor@Sun.COM {
25529517SBill.Taylor@Sun.COM 	hermon_hw_qpc_t		*qpc;
25539517SBill.Taylor@Sun.COM 	ibt_qp_rc_attr_t	*rc;
25549517SBill.Taylor@Sun.COM 	ibt_qp_ud_attr_t	*ud;
25559517SBill.Taylor@Sun.COM 	ibt_qp_uc_attr_t	*uc;
25569517SBill.Taylor@Sun.COM 	hermon_hw_addr_path_t	*qpc_path;
25579517SBill.Taylor@Sun.COM 	ibt_adds_vect_t		*adds_vect;
25589517SBill.Taylor@Sun.COM 	uint_t			portnum, pkeyindx;
25599517SBill.Taylor@Sun.COM 	uint_t			rra_max, sra_max;
25609517SBill.Taylor@Sun.COM 	uint32_t		opmask = 0;
25619517SBill.Taylor@Sun.COM 	int			status;
25629517SBill.Taylor@Sun.COM 
25639517SBill.Taylor@Sun.COM 	ASSERT(MUTEX_HELD(&qp->qp_lock));
25649517SBill.Taylor@Sun.COM 
25659517SBill.Taylor@Sun.COM 	/*
25669517SBill.Taylor@Sun.COM 	 * Grab the temporary QPC entry from QP software state
25679517SBill.Taylor@Sun.COM 	 */
25689517SBill.Taylor@Sun.COM 	qpc = &qp->qpc;
25699517SBill.Taylor@Sun.COM 
25709517SBill.Taylor@Sun.COM 	/*
25719517SBill.Taylor@Sun.COM 	 * Fill in the common fields in the QPC
25729517SBill.Taylor@Sun.COM 	 */
25739517SBill.Taylor@Sun.COM 
25749517SBill.Taylor@Sun.COM 	/*
25759517SBill.Taylor@Sun.COM 	 * Now fill in the QPC fields which are specific to transport type
25769517SBill.Taylor@Sun.COM 	 */
2577*12965SWilliam.Taylor@Oracle.COM 	if (qp->qp_type == IBT_UD_RQP) {
25789517SBill.Taylor@Sun.COM 		ud = &info_p->qp_transport.ud;
25799517SBill.Taylor@Sun.COM 
25809517SBill.Taylor@Sun.COM 		/*
25819517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the port for this QP, then
25829517SBill.Taylor@Sun.COM 		 * check for valid port number and fill it in.  Also set the
25839517SBill.Taylor@Sun.COM 		 * appropriate flag in the "opmask" parameter.
25849517SBill.Taylor@Sun.COM 		 */
25859517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_PORT) {
25869517SBill.Taylor@Sun.COM 			portnum = ud->ud_port;
25879517SBill.Taylor@Sun.COM 			if (hermon_portnum_is_valid(state, portnum)) {
25889517SBill.Taylor@Sun.COM 				qp->qp_portnum = portnum - 1;
25899517SBill.Taylor@Sun.COM 				qpc->pri_addr_path.sched_q =
25909517SBill.Taylor@Sun.COM 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
25919517SBill.Taylor@Sun.COM 				    0, qp->qp_is_special);
25929517SBill.Taylor@Sun.COM 			} else {
25939517SBill.Taylor@Sun.COM 				return (IBT_HCA_PORT_INVALID);
25949517SBill.Taylor@Sun.COM 			}
25959517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_SCHEDQUEUE;
25969517SBill.Taylor@Sun.COM 		}
25979517SBill.Taylor@Sun.COM 
25989517SBill.Taylor@Sun.COM 		/*
25999517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the PKey index for this QP,
26009517SBill.Taylor@Sun.COM 		 * then check for valid PKey index and fill it in.  Also set
26019517SBill.Taylor@Sun.COM 		 * the appropriate flag in the "opmask" parameter.
26029517SBill.Taylor@Sun.COM 		 */
26039517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_PKEY_IX) {
26049517SBill.Taylor@Sun.COM 			pkeyindx = ud->ud_pkey_ix;
26059517SBill.Taylor@Sun.COM 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
26069517SBill.Taylor@Sun.COM 				qpc->pri_addr_path.pkey_indx = pkeyindx;
26079517SBill.Taylor@Sun.COM 				opmask |= HERMON_CMD_OP_PKEYINDX;
26089517SBill.Taylor@Sun.COM 				qp->qp_pkeyindx = pkeyindx;
26099517SBill.Taylor@Sun.COM 			} else {
26109517SBill.Taylor@Sun.COM 				return (IBT_PKEY_IX_ILLEGAL);
26119517SBill.Taylor@Sun.COM 			}
26129517SBill.Taylor@Sun.COM 		}
26139517SBill.Taylor@Sun.COM 
26149517SBill.Taylor@Sun.COM 		/*
26159517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the QKey for this QP, then
26169517SBill.Taylor@Sun.COM 		 * fill it in and set the appropriate flag in the "opmask"
26179517SBill.Taylor@Sun.COM 		 * parameter.
26189517SBill.Taylor@Sun.COM 		 */
26199517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_QKEY) {
26209517SBill.Taylor@Sun.COM 			qpc->qkey = ud->ud_qkey;
26219517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_QKEY;
26229517SBill.Taylor@Sun.COM 		}
26239517SBill.Taylor@Sun.COM 
26249517SBill.Taylor@Sun.COM 	} else if (qp->qp_serv_type == HERMON_QP_RC) {
26259517SBill.Taylor@Sun.COM 		rc = &info_p->qp_transport.rc;
26269517SBill.Taylor@Sun.COM 
26279517SBill.Taylor@Sun.COM 		/*
26289517SBill.Taylor@Sun.COM 		 * Check if any of the flags indicate a change in the RDMA
26299517SBill.Taylor@Sun.COM 		 * (recv) enable/disable flags and set the appropriate flag in
26309517SBill.Taylor@Sun.COM 		 * the "opmask" parameter
26319517SBill.Taylor@Sun.COM 		 */
26329517SBill.Taylor@Sun.COM 		opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
26339517SBill.Taylor@Sun.COM 
26349517SBill.Taylor@Sun.COM 		/*
26359517SBill.Taylor@Sun.COM 		 * Check for optional primary path and fill in the
26369517SBill.Taylor@Sun.COM 		 * appropriate QPC fields if one is specified
26379517SBill.Taylor@Sun.COM 		 */
26389517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_ADDS_VECT) {
26399517SBill.Taylor@Sun.COM 			qpc_path = &qpc->pri_addr_path;
26409517SBill.Taylor@Sun.COM 			adds_vect = &rc->rc_path.cep_adds_vect;
26419517SBill.Taylor@Sun.COM 
26429517SBill.Taylor@Sun.COM 			/* Set the common primary address path fields */
26439517SBill.Taylor@Sun.COM 			status = hermon_set_addr_path(state, adds_vect,
26449517SBill.Taylor@Sun.COM 			    qpc_path, HERMON_ADDRPATH_QP);
26459517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
26469517SBill.Taylor@Sun.COM 				return (status);
26479517SBill.Taylor@Sun.COM 			}
26489517SBill.Taylor@Sun.COM 			qpc->rnr_retry = rc->rc_rnr_retry_cnt;
26499517SBill.Taylor@Sun.COM 			qpc_path->ack_timeout = rc->rc_path.cep_timeout;
26509517SBill.Taylor@Sun.COM 			qpc->retry_cnt = rc->rc_retry_cnt;
26519517SBill.Taylor@Sun.COM 
26529517SBill.Taylor@Sun.COM 			portnum = qp->qp_portnum + 1;
26539517SBill.Taylor@Sun.COM 			if (hermon_portnum_is_valid(state, portnum)) {
26549517SBill.Taylor@Sun.COM 				qpc->pri_addr_path.sched_q  =
26559517SBill.Taylor@Sun.COM 				    HERMON_QP_SCHEDQ_GET(qp->qp_portnum,
26569517SBill.Taylor@Sun.COM 				    adds_vect->av_srvl, qp->qp_is_special);
26579517SBill.Taylor@Sun.COM 			} else {
26589517SBill.Taylor@Sun.COM 				return (IBT_HCA_PORT_INVALID);
26599517SBill.Taylor@Sun.COM 			}
26609517SBill.Taylor@Sun.COM 
26619517SBill.Taylor@Sun.COM 			/*
26629517SBill.Taylor@Sun.COM 			 * MTU changes as part of sqd2sqd are not allowed.
26639517SBill.Taylor@Sun.COM 			 * Simply keep the same MTU value here, stored in the
26649517SBill.Taylor@Sun.COM 			 * qphdl from init2rtr time.
26659517SBill.Taylor@Sun.COM 			 */
26669517SBill.Taylor@Sun.COM 			qpc->mtu = qp->qp_save_mtu;
26679517SBill.Taylor@Sun.COM 
26689517SBill.Taylor@Sun.COM 			opmask |= (HERMON_CMD_OP_PRIM_PATH |
26699517SBill.Taylor@Sun.COM 			    HERMON_CMD_OP_RETRYCNT | HERMON_CMD_OP_ACKTIMEOUT |
26709517SBill.Taylor@Sun.COM 			    HERMON_CMD_OP_PRIM_RNRRETRY);
26719517SBill.Taylor@Sun.COM 		}
26729517SBill.Taylor@Sun.COM 
26739517SBill.Taylor@Sun.COM 		/*
26749517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the path migration state for
26759517SBill.Taylor@Sun.COM 		 * this QP, then check for valid state and fill it in.  Also
26769517SBill.Taylor@Sun.COM 		 * set the appropriate flag in the "opmask" parameter.
26779517SBill.Taylor@Sun.COM 		 */
26789517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_MIG) {
26799517SBill.Taylor@Sun.COM 			if (rc->rc_mig_state == IBT_STATE_MIGRATED) {
26809517SBill.Taylor@Sun.COM 				qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
26819517SBill.Taylor@Sun.COM 			} else if (rc->rc_mig_state == IBT_STATE_REARMED) {
26829517SBill.Taylor@Sun.COM 				qpc->pm_state = HERMON_QP_PMSTATE_REARM;
26839517SBill.Taylor@Sun.COM 			} else {
26849517SBill.Taylor@Sun.COM 				return (IBT_QP_APM_STATE_INVALID);
26859517SBill.Taylor@Sun.COM 			}
26869517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_PM_STATE;
26879517SBill.Taylor@Sun.COM 		}
26889517SBill.Taylor@Sun.COM 
26899517SBill.Taylor@Sun.COM 		/*
26909517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the PKey index for this QP,
26919517SBill.Taylor@Sun.COM 		 * then check for valid PKey index and fill it in.  Also set
26929517SBill.Taylor@Sun.COM 		 * the appropriate flag in the "opmask" parameter.
26939517SBill.Taylor@Sun.COM 		 */
26949517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_PKEY_IX) {
26959517SBill.Taylor@Sun.COM 			pkeyindx = rc->rc_path.cep_pkey_ix;
26969517SBill.Taylor@Sun.COM 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
26979517SBill.Taylor@Sun.COM 				qpc->pri_addr_path.pkey_indx = pkeyindx;
26989517SBill.Taylor@Sun.COM 				opmask |= HERMON_CMD_OP_PKEYINDX;
26999517SBill.Taylor@Sun.COM 			} else {
27009517SBill.Taylor@Sun.COM 				return (IBT_PKEY_IX_ILLEGAL);
27019517SBill.Taylor@Sun.COM 			}
27029517SBill.Taylor@Sun.COM 		}
27039517SBill.Taylor@Sun.COM 
27049517SBill.Taylor@Sun.COM 		/*
27059517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the port for this QP, then
27069517SBill.Taylor@Sun.COM 		 * check for valid port number and fill it in.  Also set the
27079517SBill.Taylor@Sun.COM 		 * appropriate flag in the "opmask" parameter.
27089517SBill.Taylor@Sun.COM 		 */
27099517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_PORT) {
27109517SBill.Taylor@Sun.COM 			portnum = rc->rc_path.cep_hca_port_num;
27119517SBill.Taylor@Sun.COM 			if (hermon_portnum_is_valid(state, portnum)) {
27129517SBill.Taylor@Sun.COM 				qp->qp_portnum = portnum - 1;
27139517SBill.Taylor@Sun.COM 				qpc->pri_addr_path.sched_q =
27149517SBill.Taylor@Sun.COM 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
27159517SBill.Taylor@Sun.COM 				    adds_vect->av_srvl, qp->qp_is_special);
27169517SBill.Taylor@Sun.COM 			} else {
27179517SBill.Taylor@Sun.COM 				return (IBT_HCA_PORT_INVALID);
27189517SBill.Taylor@Sun.COM 			}
27199517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_SCHEDQUEUE;
27209517SBill.Taylor@Sun.COM 		}
27219517SBill.Taylor@Sun.COM 
27229517SBill.Taylor@Sun.COM 		/*
27239517SBill.Taylor@Sun.COM 		 * Check for optional alternate path and fill in the
27249517SBill.Taylor@Sun.COM 		 * appropriate QPC fields if one is specified
27259517SBill.Taylor@Sun.COM 		 */
27269517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_ALT_PATH) {
27279517SBill.Taylor@Sun.COM 			qpc_path = &qpc->alt_addr_path;
27289517SBill.Taylor@Sun.COM 			adds_vect = &rc->rc_alt_path.cep_adds_vect;
27299517SBill.Taylor@Sun.COM 
27309517SBill.Taylor@Sun.COM 			/* Set the common alternate address path fields */
27319517SBill.Taylor@Sun.COM 			status = hermon_set_addr_path(state, adds_vect,
27329517SBill.Taylor@Sun.COM 			    qpc_path, HERMON_ADDRPATH_QP);
27339517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
27349517SBill.Taylor@Sun.COM 				return (status);
27359517SBill.Taylor@Sun.COM 			}
27369517SBill.Taylor@Sun.COM 			qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
27379517SBill.Taylor@Sun.COM 
27389517SBill.Taylor@Sun.COM 			/*
27399517SBill.Taylor@Sun.COM 			 * Check for valid alternate path port number and fill
27409517SBill.Taylor@Sun.COM 			 * it in
27419517SBill.Taylor@Sun.COM 			 */
27429517SBill.Taylor@Sun.COM 			portnum = rc->rc_alt_path.cep_hca_port_num;
27439517SBill.Taylor@Sun.COM 			if (hermon_portnum_is_valid(state, portnum)) {
27449517SBill.Taylor@Sun.COM 				qp->qp_portnum_alt = portnum - 1;
27459517SBill.Taylor@Sun.COM 				qpc->alt_addr_path.sched_q =
27469517SBill.Taylor@Sun.COM 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
27479517SBill.Taylor@Sun.COM 				    adds_vect->av_srvl, qp->qp_is_special);
27489517SBill.Taylor@Sun.COM 			} else {
27499517SBill.Taylor@Sun.COM 				return (IBT_HCA_PORT_INVALID);
27509517SBill.Taylor@Sun.COM 			}
27519517SBill.Taylor@Sun.COM 
27529517SBill.Taylor@Sun.COM 			/*
27539517SBill.Taylor@Sun.COM 			 * Check for valid alternate path PKey index and fill
27549517SBill.Taylor@Sun.COM 			 * it in
27559517SBill.Taylor@Sun.COM 			 */
27569517SBill.Taylor@Sun.COM 			pkeyindx = rc->rc_alt_path.cep_pkey_ix;
27579517SBill.Taylor@Sun.COM 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
27589517SBill.Taylor@Sun.COM 				qpc->alt_addr_path.pkey_indx = pkeyindx;
27599517SBill.Taylor@Sun.COM 			} else {
27609517SBill.Taylor@Sun.COM 				return (IBT_PKEY_IX_ILLEGAL);
27619517SBill.Taylor@Sun.COM 			}
27629517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_ALT_PATH;
27639517SBill.Taylor@Sun.COM 		}
27649517SBill.Taylor@Sun.COM 
27659517SBill.Taylor@Sun.COM 		/*
27669517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the number of "outgoing
27679517SBill.Taylor@Sun.COM 		 * RDMA resources" for this QP, then check for valid value and
27689517SBill.Taylor@Sun.COM 		 * fill it in.  Also set the appropriate flag in the "opmask"
27699517SBill.Taylor@Sun.COM 		 * parameter.
27709517SBill.Taylor@Sun.COM 		 */
27719517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_RDMARA_OUT) {
27729517SBill.Taylor@Sun.COM 			if (hermon_qp_validate_init_depth(state, rc,
27739517SBill.Taylor@Sun.COM 			    &sra_max) != DDI_SUCCESS) {
27749517SBill.Taylor@Sun.COM 				return (IBT_INVALID_PARAM);
27759517SBill.Taylor@Sun.COM 			}
27769517SBill.Taylor@Sun.COM 			qpc->sra_max = sra_max;
27779517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_SRA_SET;
27789517SBill.Taylor@Sun.COM 		}
27799517SBill.Taylor@Sun.COM 
27809517SBill.Taylor@Sun.COM 		/*
27819517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the number of "incoming
27829517SBill.Taylor@Sun.COM 		 * RDMA resources" for this QP, then check for valid value and
27839517SBill.Taylor@Sun.COM 		 * update the "rra_max" and "ra_buf_index" fields in the QPC to
27849517SBill.Taylor@Sun.COM 		 * point to the pre-allocated RDB resources (in DDR).  Also set
27859517SBill.Taylor@Sun.COM 		 * the appropriate flag in the "opmask" parameter.
27869517SBill.Taylor@Sun.COM 		 */
27879517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_RDMARA_IN) {
27889517SBill.Taylor@Sun.COM 			if (hermon_qp_validate_resp_rsrc(state, rc,
27899517SBill.Taylor@Sun.COM 			    &rra_max) != DDI_SUCCESS) {
27909517SBill.Taylor@Sun.COM 				return (IBT_INVALID_PARAM);
27919517SBill.Taylor@Sun.COM 			}
27929517SBill.Taylor@Sun.COM 			qpc->rra_max = rra_max;
27939517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_RRA_SET;
27949517SBill.Taylor@Sun.COM 		}
27959517SBill.Taylor@Sun.COM 
27969517SBill.Taylor@Sun.COM 		/*
27979517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the "Local Ack Timeout" value
27989517SBill.Taylor@Sun.COM 		 * for this QP, then fill it in and set the appropriate flag in
27999517SBill.Taylor@Sun.COM 		 * the "opmask" parameter.
28009517SBill.Taylor@Sun.COM 		 */
28019517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_TIMEOUT) {
28029517SBill.Taylor@Sun.COM 			qpc_path = &qpc->pri_addr_path;
28039517SBill.Taylor@Sun.COM 			qpc_path->ack_timeout = rc->rc_path.cep_timeout;
28049517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_ACKTIMEOUT;
28059517SBill.Taylor@Sun.COM 		}
28069517SBill.Taylor@Sun.COM 
28079517SBill.Taylor@Sun.COM 		/*
28089517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the "Retry Count" for this QP,
28099517SBill.Taylor@Sun.COM 		 * then fill it in and set the appropriate flag in the "opmask"
28109517SBill.Taylor@Sun.COM 		 * parameter.
28119517SBill.Taylor@Sun.COM 		 */
28129517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_RETRY) {
28139517SBill.Taylor@Sun.COM 			qpc->retry_cnt = rc->rc_retry_cnt;
28149517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_PRIM_RNRRETRY;
28159517SBill.Taylor@Sun.COM 		}
28169517SBill.Taylor@Sun.COM 
28179517SBill.Taylor@Sun.COM 		/*
28189517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the "RNR Retry Count" for this
28199517SBill.Taylor@Sun.COM 		 * QP, then fill it in and set the appropriate flag in the
28209517SBill.Taylor@Sun.COM 		 * "opmask" parameter.
28219517SBill.Taylor@Sun.COM 		 */
28229517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_RNR_NAK_RETRY) {
28239517SBill.Taylor@Sun.COM 			qpc_path = &qpc->pri_addr_path;
28249517SBill.Taylor@Sun.COM 			qpc->rnr_retry = rc->rc_rnr_retry_cnt;
28259517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_RETRYCNT;
28269517SBill.Taylor@Sun.COM 		}
28279517SBill.Taylor@Sun.COM 
28289517SBill.Taylor@Sun.COM 		/*
28299517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the "Minimum RNR NAK" value
28309517SBill.Taylor@Sun.COM 		 * for this QP, then fill it in and set the appropriate flag
28319517SBill.Taylor@Sun.COM 		 * in the "opmask" parameter.
28329517SBill.Taylor@Sun.COM 		 */
28339517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_MIN_RNR_NAK) {
28349517SBill.Taylor@Sun.COM 			qpc->min_rnr_nak = rc->rc_min_rnr_nak;
28359517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_MINRNRNAK;
28369517SBill.Taylor@Sun.COM 		}
28379517SBill.Taylor@Sun.COM 
28389517SBill.Taylor@Sun.COM 	} else if (qp->qp_serv_type == HERMON_QP_UC) {
28399517SBill.Taylor@Sun.COM 		uc = &info_p->qp_transport.uc;
28409517SBill.Taylor@Sun.COM 
28419517SBill.Taylor@Sun.COM 		/*
28429517SBill.Taylor@Sun.COM 		 * Check if any of the flags indicate a change in the RDMA
28439517SBill.Taylor@Sun.COM 		 * Write (recv) enable/disable and set the appropriate flag
28449517SBill.Taylor@Sun.COM 		 * in the "opmask" parameter. Note: RDMA Read and Atomic are
28459517SBill.Taylor@Sun.COM 		 * not valid for UC transport.
28469517SBill.Taylor@Sun.COM 		 */
28479517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_RDMA_W) {
28489517SBill.Taylor@Sun.COM 			qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
28499517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_RWE;
28509517SBill.Taylor@Sun.COM 		}
28519517SBill.Taylor@Sun.COM 
28529517SBill.Taylor@Sun.COM 		/*
28539517SBill.Taylor@Sun.COM 		 * Check for optional primary path and fill in the
28549517SBill.Taylor@Sun.COM 		 * appropriate QPC fields if one is specified
28559517SBill.Taylor@Sun.COM 		 */
28569517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_ADDS_VECT) {
28579517SBill.Taylor@Sun.COM 			qpc_path = &qpc->pri_addr_path;
28589517SBill.Taylor@Sun.COM 			adds_vect = &uc->uc_path.cep_adds_vect;
28599517SBill.Taylor@Sun.COM 
28609517SBill.Taylor@Sun.COM 			/* Set the common primary address path fields */
28619517SBill.Taylor@Sun.COM 			status = hermon_set_addr_path(state, adds_vect,
28629517SBill.Taylor@Sun.COM 			    qpc_path, HERMON_ADDRPATH_QP);
28639517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
28649517SBill.Taylor@Sun.COM 				return (status);
28659517SBill.Taylor@Sun.COM 			}
28669517SBill.Taylor@Sun.COM 			portnum = qp->qp_portnum + 1;
28679517SBill.Taylor@Sun.COM 			if (hermon_portnum_is_valid(state, portnum)) {
28689517SBill.Taylor@Sun.COM 				qpc->pri_addr_path.sched_q =
28699517SBill.Taylor@Sun.COM 				    HERMON_QP_SCHEDQ_GET(qp->qp_portnum,
28709517SBill.Taylor@Sun.COM 				    adds_vect->av_srvl, qp->qp_is_special);
28719517SBill.Taylor@Sun.COM 			} else {
28729517SBill.Taylor@Sun.COM 				return (IBT_HCA_PORT_INVALID);
28739517SBill.Taylor@Sun.COM 			}
28749517SBill.Taylor@Sun.COM 
28759517SBill.Taylor@Sun.COM 			/*
28769517SBill.Taylor@Sun.COM 			 * MTU changes as part of sqd2sqd are not allowed.
28779517SBill.Taylor@Sun.COM 			 * Simply keep the same MTU value here, stored in the
28789517SBill.Taylor@Sun.COM 			 * qphdl from init2rtr time.
28799517SBill.Taylor@Sun.COM 			 */
28809517SBill.Taylor@Sun.COM 			qpc->mtu = qp->qp_save_mtu;
28819517SBill.Taylor@Sun.COM 
28829517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_PRIM_PATH;
28839517SBill.Taylor@Sun.COM 		}
28849517SBill.Taylor@Sun.COM 
28859517SBill.Taylor@Sun.COM 		/*
28869517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the path migration state for
28879517SBill.Taylor@Sun.COM 		 * this QP, then check for valid state and fill it in.  Also
28889517SBill.Taylor@Sun.COM 		 * set the appropriate flag in the "opmask" parameter.
28899517SBill.Taylor@Sun.COM 		 */
28909517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_MIG) {
28919517SBill.Taylor@Sun.COM 			if (uc->uc_mig_state == IBT_STATE_MIGRATED) {
28929517SBill.Taylor@Sun.COM 				qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
28939517SBill.Taylor@Sun.COM 			} else if (uc->uc_mig_state == IBT_STATE_REARMED) {
28949517SBill.Taylor@Sun.COM 				qpc->pm_state = HERMON_QP_PMSTATE_REARM;
28959517SBill.Taylor@Sun.COM 			} else {
28969517SBill.Taylor@Sun.COM 				return (IBT_QP_APM_STATE_INVALID);
28979517SBill.Taylor@Sun.COM 			}
28989517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_PM_STATE;
28999517SBill.Taylor@Sun.COM 		}
29009517SBill.Taylor@Sun.COM 
29019517SBill.Taylor@Sun.COM 		/*
29029517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the PKey index for this QP,
29039517SBill.Taylor@Sun.COM 		 * then check for valid PKey index and fill it in.  Also set
29049517SBill.Taylor@Sun.COM 		 * the appropriate flag in the "opmask" parameter.
29059517SBill.Taylor@Sun.COM 		 */
29069517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_PKEY_IX) {
29079517SBill.Taylor@Sun.COM 			pkeyindx = uc->uc_path.cep_pkey_ix;
29089517SBill.Taylor@Sun.COM 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
29099517SBill.Taylor@Sun.COM 				qpc->pri_addr_path.pkey_indx = pkeyindx;
29109517SBill.Taylor@Sun.COM 				opmask |= HERMON_CMD_OP_PKEYINDX;
29119517SBill.Taylor@Sun.COM 			} else {
29129517SBill.Taylor@Sun.COM 				return (IBT_PKEY_IX_ILLEGAL);
29139517SBill.Taylor@Sun.COM 			}
29149517SBill.Taylor@Sun.COM 		}
29159517SBill.Taylor@Sun.COM 
29169517SBill.Taylor@Sun.COM 		/*
29179517SBill.Taylor@Sun.COM 		 * Check for optional alternate path and fill in the
29189517SBill.Taylor@Sun.COM 		 * appropriate QPC fields if one is specified
29199517SBill.Taylor@Sun.COM 		 */
29209517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_ALT_PATH) {
29219517SBill.Taylor@Sun.COM 			qpc_path = &qpc->alt_addr_path;
29229517SBill.Taylor@Sun.COM 			adds_vect = &uc->uc_alt_path.cep_adds_vect;
29239517SBill.Taylor@Sun.COM 
29249517SBill.Taylor@Sun.COM 			/* Set the common alternate address path fields */
29259517SBill.Taylor@Sun.COM 			status = hermon_set_addr_path(state, adds_vect,
29269517SBill.Taylor@Sun.COM 			    qpc_path, HERMON_ADDRPATH_QP);
29279517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
29289517SBill.Taylor@Sun.COM 				return (status);
29299517SBill.Taylor@Sun.COM 			}
29309517SBill.Taylor@Sun.COM 
29319517SBill.Taylor@Sun.COM 			/*
29329517SBill.Taylor@Sun.COM 			 * Check for valid alternate path port number and fill
29339517SBill.Taylor@Sun.COM 			 * it in
29349517SBill.Taylor@Sun.COM 			 */
29359517SBill.Taylor@Sun.COM 			portnum = uc->uc_alt_path.cep_hca_port_num;
29369517SBill.Taylor@Sun.COM 			if (hermon_portnum_is_valid(state, portnum)) {
29379517SBill.Taylor@Sun.COM 				qp->qp_portnum_alt = portnum - 1;
29389517SBill.Taylor@Sun.COM 				qpc->alt_addr_path.sched_q =
29399517SBill.Taylor@Sun.COM 				    HERMON_QP_SCHEDQ_GET(portnum - 1,
29409517SBill.Taylor@Sun.COM 				    adds_vect->av_srvl, qp->qp_is_special);
29419517SBill.Taylor@Sun.COM 			} else {
29429517SBill.Taylor@Sun.COM 				return (IBT_HCA_PORT_INVALID);
29439517SBill.Taylor@Sun.COM 			}
29449517SBill.Taylor@Sun.COM 
29459517SBill.Taylor@Sun.COM 			/*
29469517SBill.Taylor@Sun.COM 			 * Check for valid alternate path PKey index and fill
29479517SBill.Taylor@Sun.COM 			 * it in
29489517SBill.Taylor@Sun.COM 			 */
29499517SBill.Taylor@Sun.COM 			pkeyindx = uc->uc_alt_path.cep_pkey_ix;
29509517SBill.Taylor@Sun.COM 			if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
29519517SBill.Taylor@Sun.COM 				qpc->alt_addr_path.pkey_indx = pkeyindx;
29529517SBill.Taylor@Sun.COM 			} else {
29539517SBill.Taylor@Sun.COM 				return (IBT_PKEY_IX_ILLEGAL);
29549517SBill.Taylor@Sun.COM 			}
29559517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_ALT_PATH;
29569517SBill.Taylor@Sun.COM 		}
29579517SBill.Taylor@Sun.COM 	} else {
29589517SBill.Taylor@Sun.COM 		/*
29599517SBill.Taylor@Sun.COM 		 * Invalid QP transport type. If we got here then it's a
29609517SBill.Taylor@Sun.COM 		 * warning of a probably serious problem.  So print a message
29619517SBill.Taylor@Sun.COM 		 * and return failure
29629517SBill.Taylor@Sun.COM 		 */
29639517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "unknown QP transport type in sqd2sqd");
29649517SBill.Taylor@Sun.COM 		return (ibc_get_ci_failure(0));
29659517SBill.Taylor@Sun.COM 	}
29669517SBill.Taylor@Sun.COM 
29679517SBill.Taylor@Sun.COM 	/*
29689517SBill.Taylor@Sun.COM 	 * Post the SQD2SQD_QP command to the Hermon firmware
29699517SBill.Taylor@Sun.COM 	 *
29709517SBill.Taylor@Sun.COM 	 * We do a HERMON_NOSLEEP here because we are still holding the
29719517SBill.Taylor@Sun.COM 	 * "qp_lock".  If we got raised to interrupt level by priority
29729517SBill.Taylor@Sun.COM 	 * inversion, we do not want to block in this routine waiting for
29739517SBill.Taylor@Sun.COM 	 * success.
29749517SBill.Taylor@Sun.COM 	 */
29759517SBill.Taylor@Sun.COM 	status = hermon_cmn_qp_cmd_post(state, SQD2SQD_QP, qpc, qp->qp_qpnum,
29769517SBill.Taylor@Sun.COM 	    opmask, HERMON_CMD_NOSLEEP_SPIN);
29779517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
29789517SBill.Taylor@Sun.COM 		if (status != HERMON_CMD_BAD_QP_STATE) {
29799517SBill.Taylor@Sun.COM 			cmn_err(CE_NOTE, "hermon%d: SQD2SQD_QP command failed: "
29809517SBill.Taylor@Sun.COM 			    "%08x\n", state->hs_instance, status);
29819517SBill.Taylor@Sun.COM 			if (status == HERMON_CMD_INVALID_STATUS) {
29829517SBill.Taylor@Sun.COM 				hermon_fm_ereport(state, HCA_SYS_ERR,
29839517SBill.Taylor@Sun.COM 				    HCA_ERR_SRV_LOST);
29849517SBill.Taylor@Sun.COM 			}
29859517SBill.Taylor@Sun.COM 			return (ibc_get_ci_failure(0));
29869517SBill.Taylor@Sun.COM 		} else {
29879517SBill.Taylor@Sun.COM 			return (IBT_QP_STATE_INVALID);
29889517SBill.Taylor@Sun.COM 		}
29899517SBill.Taylor@Sun.COM 	}
29909517SBill.Taylor@Sun.COM 
29919517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
29929517SBill.Taylor@Sun.COM }
29939517SBill.Taylor@Sun.COM 
29949517SBill.Taylor@Sun.COM 
29959517SBill.Taylor@Sun.COM /*
29969517SBill.Taylor@Sun.COM  * hermon_qp_sqerr2rts()
29979517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
29989517SBill.Taylor@Sun.COM  */
29999517SBill.Taylor@Sun.COM 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)30009517SBill.Taylor@Sun.COM hermon_qp_sqerr2rts(hermon_state_t *state, hermon_qphdl_t qp,
30019517SBill.Taylor@Sun.COM     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
30029517SBill.Taylor@Sun.COM {
30039517SBill.Taylor@Sun.COM 	hermon_hw_qpc_t		*qpc;
30049517SBill.Taylor@Sun.COM 	ibt_qp_ud_attr_t	*ud;
30059517SBill.Taylor@Sun.COM 	uint32_t		opmask = 0;
30069517SBill.Taylor@Sun.COM 	int			status;
30079517SBill.Taylor@Sun.COM 
30089517SBill.Taylor@Sun.COM 	ASSERT(MUTEX_HELD(&qp->qp_lock));
30099517SBill.Taylor@Sun.COM 
30109517SBill.Taylor@Sun.COM 	/*
30119517SBill.Taylor@Sun.COM 	 * Grab the temporary QPC entry from QP software state
30129517SBill.Taylor@Sun.COM 	 */
30139517SBill.Taylor@Sun.COM 	qpc = &qp->qpc;
30149517SBill.Taylor@Sun.COM 
30159517SBill.Taylor@Sun.COM 	/*
30169517SBill.Taylor@Sun.COM 	 * Since there are no common fields to be filled in for this command,
30179517SBill.Taylor@Sun.COM 	 * we begin with the QPC fields which are specific to transport type.
30189517SBill.Taylor@Sun.COM 	 */
3019*12965SWilliam.Taylor@Oracle.COM 	if (qp->qp_type == IBT_UD_RQP) {
30209517SBill.Taylor@Sun.COM 		ud = &info_p->qp_transport.ud;
30219517SBill.Taylor@Sun.COM 
30229517SBill.Taylor@Sun.COM 		/*
30239517SBill.Taylor@Sun.COM 		 * If we are attempting to modify the QKey for this QP, then
30249517SBill.Taylor@Sun.COM 		 * fill it in and set the appropriate flag in the "opmask"
30259517SBill.Taylor@Sun.COM 		 * parameter.
30269517SBill.Taylor@Sun.COM 		 */
30279517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_QKEY) {
30289517SBill.Taylor@Sun.COM 			qpc->qkey = ud->ud_qkey;
30299517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_QKEY;
30309517SBill.Taylor@Sun.COM 		}
30319517SBill.Taylor@Sun.COM 
30329517SBill.Taylor@Sun.COM 	} else if (qp->qp_serv_type == HERMON_QP_UC) {
30339517SBill.Taylor@Sun.COM 
30349517SBill.Taylor@Sun.COM 		/*
30359517SBill.Taylor@Sun.COM 		 * Check if any of the flags indicate a change in the RDMA
30369517SBill.Taylor@Sun.COM 		 * Write (recv) enable/disable and set the appropriate flag
30379517SBill.Taylor@Sun.COM 		 * in the "opmask" parameter. Note: RDMA Read and Atomic are
30389517SBill.Taylor@Sun.COM 		 * not valid for UC transport.
30399517SBill.Taylor@Sun.COM 		 */
30409517SBill.Taylor@Sun.COM 		if (flags & IBT_CEP_SET_RDMA_W) {
30419517SBill.Taylor@Sun.COM 			qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
30429517SBill.Taylor@Sun.COM 			opmask |= HERMON_CMD_OP_RWE;
30439517SBill.Taylor@Sun.COM 		}
30449517SBill.Taylor@Sun.COM 	} else {
30459517SBill.Taylor@Sun.COM 		/*
30469517SBill.Taylor@Sun.COM 		 * Invalid QP transport type. If we got here then it's a
30479517SBill.Taylor@Sun.COM 		 * warning of a probably serious problem.  So print a message
30489517SBill.Taylor@Sun.COM 		 * and return failure
30499517SBill.Taylor@Sun.COM 		 */
30509517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "unknown QP transport type in sqerr2rts");
30519517SBill.Taylor@Sun.COM 		return (ibc_get_ci_failure(0));
30529517SBill.Taylor@Sun.COM 	}
30539517SBill.Taylor@Sun.COM 
30549517SBill.Taylor@Sun.COM 	/*
30559517SBill.Taylor@Sun.COM 	 * Post the SQERR2RTS_QP command to the Hermon firmware
30569517SBill.Taylor@Sun.COM 	 *
30579517SBill.Taylor@Sun.COM 	 * We do a HERMON_NOSLEEP here because we are still holding the
30589517SBill.Taylor@Sun.COM 	 * "qp_lock".  If we got raised to interrupt level by priority
30599517SBill.Taylor@Sun.COM 	 * inversion, we do not want to block in this routine waiting for
30609517SBill.Taylor@Sun.COM 	 * success.
30619517SBill.Taylor@Sun.COM 	 */
30629517SBill.Taylor@Sun.COM 	status = hermon_cmn_qp_cmd_post(state, SQERR2RTS_QP, qpc, qp->qp_qpnum,
30639517SBill.Taylor@Sun.COM 	    opmask, HERMON_CMD_NOSLEEP_SPIN);
30649517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
30659517SBill.Taylor@Sun.COM 		if (status != HERMON_CMD_BAD_QP_STATE) {
30669517SBill.Taylor@Sun.COM 			cmn_err(CE_NOTE, "hermon%d: SQERR2RTS_QP command "
30679517SBill.Taylor@Sun.COM 			    "failed: %08x\n", state->hs_instance, status);
30689517SBill.Taylor@Sun.COM 			if (status == HERMON_CMD_INVALID_STATUS) {
30699517SBill.Taylor@Sun.COM 				hermon_fm_ereport(state, HCA_SYS_ERR,
30709517SBill.Taylor@Sun.COM 				    HCA_ERR_SRV_LOST);
30719517SBill.Taylor@Sun.COM 			}
30729517SBill.Taylor@Sun.COM 			return (ibc_get_ci_failure(0));
30739517SBill.Taylor@Sun.COM 		} else {
30749517SBill.Taylor@Sun.COM 			return (IBT_QP_STATE_INVALID);
30759517SBill.Taylor@Sun.COM 		}
30769517SBill.Taylor@Sun.COM 	}
30779517SBill.Taylor@Sun.COM 
30789517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
30799517SBill.Taylor@Sun.COM }
30809517SBill.Taylor@Sun.COM 
30819517SBill.Taylor@Sun.COM 
30829517SBill.Taylor@Sun.COM /*
30839517SBill.Taylor@Sun.COM  * hermon_qp_to_error()
30849517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
30859517SBill.Taylor@Sun.COM  */
30869517SBill.Taylor@Sun.COM static int
hermon_qp_to_error(hermon_state_t * state,hermon_qphdl_t qp)30879517SBill.Taylor@Sun.COM hermon_qp_to_error(hermon_state_t *state, hermon_qphdl_t qp)
30889517SBill.Taylor@Sun.COM {
30899517SBill.Taylor@Sun.COM 	int	status;
30909517SBill.Taylor@Sun.COM 
30919517SBill.Taylor@Sun.COM 	ASSERT(MUTEX_HELD(&qp->qp_lock));
30929517SBill.Taylor@Sun.COM 
30939517SBill.Taylor@Sun.COM 	/*
30949517SBill.Taylor@Sun.COM 	 * Post the TOERR_QP command to the Hermon firmware
30959517SBill.Taylor@Sun.COM 	 *
30969517SBill.Taylor@Sun.COM 	 * We do a HERMON_NOSLEEP here because we are still holding the
30979517SBill.Taylor@Sun.COM 	 * "qp_lock".  If we got raised to interrupt level by priority
30989517SBill.Taylor@Sun.COM 	 * inversion, we do not want to block in this routine waiting for
30999517SBill.Taylor@Sun.COM 	 * success.
31009517SBill.Taylor@Sun.COM 	 */
31019517SBill.Taylor@Sun.COM 	status = hermon_cmn_qp_cmd_post(state, TOERR_QP, NULL, qp->qp_qpnum,
31029517SBill.Taylor@Sun.COM 	    0, HERMON_CMD_NOSLEEP_SPIN);
31039517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
31049517SBill.Taylor@Sun.COM 		cmn_err(CE_NOTE, "hermon%d: TOERR_QP command failed: %08x\n",
31059517SBill.Taylor@Sun.COM 		    state->hs_instance, status);
31069517SBill.Taylor@Sun.COM 		if (status == HERMON_CMD_INVALID_STATUS) {
31079517SBill.Taylor@Sun.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
31089517SBill.Taylor@Sun.COM 		}
31099517SBill.Taylor@Sun.COM 		return (ibc_get_ci_failure(0));
31109517SBill.Taylor@Sun.COM 	}
31119517SBill.Taylor@Sun.COM 
31129517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
31139517SBill.Taylor@Sun.COM }
31149517SBill.Taylor@Sun.COM 
31159517SBill.Taylor@Sun.COM 
31169517SBill.Taylor@Sun.COM /*
31179517SBill.Taylor@Sun.COM  * hermon_qp_to_reset()
31189517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
31199517SBill.Taylor@Sun.COM  */
31209517SBill.Taylor@Sun.COM int
hermon_qp_to_reset(hermon_state_t * state,hermon_qphdl_t qp)31219517SBill.Taylor@Sun.COM hermon_qp_to_reset(hermon_state_t *state, hermon_qphdl_t qp)
31229517SBill.Taylor@Sun.COM {
31239517SBill.Taylor@Sun.COM 	hermon_hw_qpc_t	*qpc;
31249517SBill.Taylor@Sun.COM 	int		status;
31259517SBill.Taylor@Sun.COM 
31269517SBill.Taylor@Sun.COM 	ASSERT(MUTEX_HELD(&qp->qp_lock));
31279517SBill.Taylor@Sun.COM 
31289517SBill.Taylor@Sun.COM 	/*
31299517SBill.Taylor@Sun.COM 	 * Grab the temporary QPC entry from QP software state
31309517SBill.Taylor@Sun.COM 	 */
31319517SBill.Taylor@Sun.COM 	qpc = &qp->qpc;
31329517SBill.Taylor@Sun.COM 
31339517SBill.Taylor@Sun.COM 	/*
31349517SBill.Taylor@Sun.COM 	 * Post the TORST_QP command to the Hermon firmware
31359517SBill.Taylor@Sun.COM 	 *
31369517SBill.Taylor@Sun.COM 	 * We do a HERMON_NOSLEEP here because we are still holding the
31379517SBill.Taylor@Sun.COM 	 * "qp_lock".  If we got raised to interrupt level by priority
31389517SBill.Taylor@Sun.COM 	 * inversion, we do not want to block in this routine waiting for
31399517SBill.Taylor@Sun.COM 	 * success.
31409517SBill.Taylor@Sun.COM 	 */
31419517SBill.Taylor@Sun.COM 	status = hermon_cmn_qp_cmd_post(state, TORST_QP, qpc, qp->qp_qpnum,
31429517SBill.Taylor@Sun.COM 	    0, HERMON_CMD_NOSLEEP_SPIN);
31439517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
31449517SBill.Taylor@Sun.COM 		cmn_err(CE_NOTE, "hermon%d: TORST_QP command failed: %08x\n",
31459517SBill.Taylor@Sun.COM 		    state->hs_instance, status);
31469517SBill.Taylor@Sun.COM 		if (status == HERMON_CMD_INVALID_STATUS) {
31479517SBill.Taylor@Sun.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
31489517SBill.Taylor@Sun.COM 		}
31499517SBill.Taylor@Sun.COM 		return (ibc_get_ci_failure(0));
31509517SBill.Taylor@Sun.COM 	}
3151*12965SWilliam.Taylor@Oracle.COM 	if (qp->qp_serv_type == HERMON_QP_FEXCH) {
3152*12965SWilliam.Taylor@Oracle.COM 		status = hermon_fcoib_fexch_mkey_fini(state, qp->qp_pdhdl,
3153*12965SWilliam.Taylor@Oracle.COM 		    qp->qp_qpnum, HERMON_CMD_NOSLEEP_SPIN);
3154*12965SWilliam.Taylor@Oracle.COM 		if (status != DDI_SUCCESS)
3155*12965SWilliam.Taylor@Oracle.COM 			cmn_err(CE_NOTE, "hermon%d: fexch_mkey_fini failed "
3156*12965SWilliam.Taylor@Oracle.COM 			    "%08x\n", state->hs_instance, status);
3157*12965SWilliam.Taylor@Oracle.COM 	}
31589517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
31599517SBill.Taylor@Sun.COM }
31609517SBill.Taylor@Sun.COM 
31619517SBill.Taylor@Sun.COM 
31629517SBill.Taylor@Sun.COM /*
31639517SBill.Taylor@Sun.COM  * hermon_qp_reset2err()
31649517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
31659517SBill.Taylor@Sun.COM  */
31669517SBill.Taylor@Sun.COM static int
hermon_qp_reset2err(hermon_state_t * state,hermon_qphdl_t qp)31679517SBill.Taylor@Sun.COM hermon_qp_reset2err(hermon_state_t *state, hermon_qphdl_t qp)
31689517SBill.Taylor@Sun.COM {
31699517SBill.Taylor@Sun.COM 	hermon_hw_qpc_t	*qpc;
31709517SBill.Taylor@Sun.COM 	int		status;
31719517SBill.Taylor@Sun.COM 	uint32_t	cqnmask;
31729517SBill.Taylor@Sun.COM 
31739517SBill.Taylor@Sun.COM 	ASSERT(MUTEX_HELD(&qp->qp_lock));
31749517SBill.Taylor@Sun.COM 
31759517SBill.Taylor@Sun.COM 	/*
31769517SBill.Taylor@Sun.COM 	 * In order to implement the transition from "Reset" directly to the
31779517SBill.Taylor@Sun.COM 	 * "Error" state, it is necessary to first give ownership of the QP
31789517SBill.Taylor@Sun.COM 	 * context to the Hermon hardware.  This is accomplished by
31799517SBill.Taylor@Sun.COM 	 * transitioning the QP to "Init" as an intermediate step and then,
31809517SBill.Taylor@Sun.COM 	 * immediately transitioning to "Error".
31819517SBill.Taylor@Sun.COM 	 *
31829517SBill.Taylor@Sun.COM 	 * When this function returns success, the QP context will be owned by
31839517SBill.Taylor@Sun.COM 	 * the Hermon hardware and will be in the "Error" state.
31849517SBill.Taylor@Sun.COM 	 */
31859517SBill.Taylor@Sun.COM 
31869517SBill.Taylor@Sun.COM 	/*
31879517SBill.Taylor@Sun.COM 	 * Grab the temporary QPC entry from QP software state
31889517SBill.Taylor@Sun.COM 	 */
31899517SBill.Taylor@Sun.COM 	qpc = &qp->qpc;
31909517SBill.Taylor@Sun.COM 
31919517SBill.Taylor@Sun.COM 	/*
31929517SBill.Taylor@Sun.COM 	 * Fill in the common fields in the QPC
31939517SBill.Taylor@Sun.COM 	 */
31949517SBill.Taylor@Sun.COM 	if (qp->qp_is_special) {
31959517SBill.Taylor@Sun.COM 		qpc->serv_type	= HERMON_QP_MLX;
31969517SBill.Taylor@Sun.COM 	} else {
31979517SBill.Taylor@Sun.COM 		qpc->serv_type	= qp->qp_serv_type;
31989517SBill.Taylor@Sun.COM 	}
31999517SBill.Taylor@Sun.COM 	qpc->pm_state		= HERMON_QP_PMSTATE_MIGRATED;
32009517SBill.Taylor@Sun.COM 	qpc->usr_page		= qp->qp_uarpg;
32019517SBill.Taylor@Sun.COM 	/* dbr is now an address, not an index */
32029517SBill.Taylor@Sun.COM 	qpc->dbr_addrh		= ((uint64_t)qp->qp_rq_pdbr >> 32);
32039517SBill.Taylor@Sun.COM 	qpc->dbr_addrl		= ((uint64_t)qp->qp_rq_pdbr & 0xFFFFFFFC) >> 2;
32049517SBill.Taylor@Sun.COM 	qpc->pd			= qp->qp_pdhdl->pd_pdnum;
32059517SBill.Taylor@Sun.COM 	/*
32069517SBill.Taylor@Sun.COM 	 * HERMON:
32079517SBill.Taylor@Sun.COM 	 * qpc->wqe_baseaddr is replaced by LKey from the cMPT, and
32089517SBill.Taylor@Sun.COM 	 * page_offset, mtt_base_addr_h/l, and log2_page_size will
32099517SBill.Taylor@Sun.COM 	 * be used to map the WQE buffer
32109517SBill.Taylor@Sun.COM 	 * NOTE that the cMPT is created implicitly when the QP is
32119517SBill.Taylor@Sun.COM 	 * transitioned from reset to init
32129517SBill.Taylor@Sun.COM 	 */
32139517SBill.Taylor@Sun.COM 	qpc->log2_pgsz		= qp->qp_mrhdl->mr_log2_pgsz;
32149517SBill.Taylor@Sun.COM 	qpc->mtt_base_addrh	= (qp->qp_mrhdl->mr_mttaddr) >> 32 & 0xFF;
32159517SBill.Taylor@Sun.COM 	qpc->mtt_base_addrl	= (qp->qp_mrhdl->mr_mttaddr) >> 3 & 0xFFFFFFFF;
32169517SBill.Taylor@Sun.COM 	cqnmask = (1 << state->hs_cfg_profile->cp_log_num_cq) - 1;
3217*12965SWilliam.Taylor@Oracle.COM 	qpc->cqn_snd		=
3218*12965SWilliam.Taylor@Oracle.COM 	    (qp->qp_sq_cqhdl == NULL) ? 0 : qp->qp_sq_cqhdl->cq_cqnum & cqnmask;
32199517SBill.Taylor@Sun.COM 	qpc->page_offs		= qp->qp_wqinfo.qa_pgoffs >> 6;
3220*12965SWilliam.Taylor@Oracle.COM 	qpc->cqn_rcv		=
3221*12965SWilliam.Taylor@Oracle.COM 	    (qp->qp_rq_cqhdl == NULL) ? 0 : qp->qp_rq_cqhdl->cq_cqnum & cqnmask;
32229517SBill.Taylor@Sun.COM 
32239517SBill.Taylor@Sun.COM 	qpc->sq_wqe_counter	= 0;
32249517SBill.Taylor@Sun.COM 	qpc->rq_wqe_counter	= 0;
32259517SBill.Taylor@Sun.COM 	qpc->log_sq_stride	= qp->qp_sq_log_wqesz - 4;
32269517SBill.Taylor@Sun.COM 	qpc->log_rq_stride	= qp->qp_rq_log_wqesz - 4;
32279517SBill.Taylor@Sun.COM 	qpc->log_sq_size	= highbit(qp->qp_sq_bufsz) - 1;
32289517SBill.Taylor@Sun.COM 	qpc->log_rq_size	= highbit(qp->qp_rq_bufsz) - 1;
3229*12965SWilliam.Taylor@Oracle.COM 	qpc->srq_en		= (qp->qp_alloc_flags & IBT_QP_USES_SRQ) != 0;
32309517SBill.Taylor@Sun.COM 	qpc->sq_no_prefetch	= qp->qp_no_prefetch;
32319517SBill.Taylor@Sun.COM 
3232*12965SWilliam.Taylor@Oracle.COM 	if (qp->qp_alloc_flags & IBT_QP_USES_SRQ) {
32339517SBill.Taylor@Sun.COM 		qpc->srq_number	= qp->qp_srqhdl->srq_srqnum;
32349517SBill.Taylor@Sun.COM 	} else {
32359517SBill.Taylor@Sun.COM 		qpc->srq_number = 0;
32369517SBill.Taylor@Sun.COM 	}
32379517SBill.Taylor@Sun.COM 
32389517SBill.Taylor@Sun.COM 	qpc->fre		= 0; /* default disable fast registration WR */
32399517SBill.Taylor@Sun.COM 	qpc->rlky		= 0; /* default disable reserved lkey */
32409517SBill.Taylor@Sun.COM 
32419517SBill.Taylor@Sun.COM 	/*
32429517SBill.Taylor@Sun.COM 	 * Now fill in the QPC fields which are specific to transport type
32439517SBill.Taylor@Sun.COM 	 */
3244*12965SWilliam.Taylor@Oracle.COM 	if (qp->qp_type == IBT_UD_RQP) {
32459517SBill.Taylor@Sun.COM 		/* Set the UD parameters to an invalid default */
32469517SBill.Taylor@Sun.COM 		qpc->qkey = 0;
32479517SBill.Taylor@Sun.COM 		qpc->pri_addr_path.sched_q =
32489517SBill.Taylor@Sun.COM 		    HERMON_QP_SCHEDQ_GET(0, 0, qp->qp_is_special);
32499517SBill.Taylor@Sun.COM 		qpc->pri_addr_path.pkey_indx = 0;
32509517SBill.Taylor@Sun.COM 
32519517SBill.Taylor@Sun.COM 	} else if (qp->qp_serv_type == HERMON_QP_RC) {
32529517SBill.Taylor@Sun.COM 		/* Set the RC parameters to invalid default */
32539517SBill.Taylor@Sun.COM 		qpc->rre = 0;
32549517SBill.Taylor@Sun.COM 		qpc->rwe = 0;
32559517SBill.Taylor@Sun.COM 		qpc->rae = 0;
32569517SBill.Taylor@Sun.COM 		qpc->alt_addr_path.sched_q =
32579517SBill.Taylor@Sun.COM 		    HERMON_QP_SCHEDQ_GET(0, 0, qp->qp_is_special);
32589517SBill.Taylor@Sun.COM 		qpc->pri_addr_path.pkey_indx = 0;
32599517SBill.Taylor@Sun.COM 
32609517SBill.Taylor@Sun.COM 	} else if (qp->qp_serv_type == HERMON_QP_UC) {
32619517SBill.Taylor@Sun.COM 		/* Set the UC parameters to invalid default */
32629517SBill.Taylor@Sun.COM 		qpc->rwe = 0;
32639517SBill.Taylor@Sun.COM 		qpc->alt_addr_path.sched_q =
32649517SBill.Taylor@Sun.COM 		    HERMON_QP_SCHEDQ_GET(0, 0, qp->qp_is_special);
32659517SBill.Taylor@Sun.COM 		qpc->pri_addr_path.pkey_indx = 0;
32669517SBill.Taylor@Sun.COM 
32679517SBill.Taylor@Sun.COM 	} else {
32689517SBill.Taylor@Sun.COM 		/*
32699517SBill.Taylor@Sun.COM 		 * Invalid QP transport type. If we got here then it's a
32709517SBill.Taylor@Sun.COM 		 * warning of a probably serious problem.  So print a message
32719517SBill.Taylor@Sun.COM 		 * and return failure
32729517SBill.Taylor@Sun.COM 		 */
32739517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "unknown QP transport type in rst2err");
32749517SBill.Taylor@Sun.COM 		return (ibc_get_ci_failure(0));
32759517SBill.Taylor@Sun.COM 	}
32769517SBill.Taylor@Sun.COM 
32779517SBill.Taylor@Sun.COM 	/*
32789517SBill.Taylor@Sun.COM 	 * Post the RST2INIT_QP command to the Hermon firmware
32799517SBill.Taylor@Sun.COM 	 *
32809517SBill.Taylor@Sun.COM 	 * We do a HERMON_NOSLEEP here because we are still holding the
32819517SBill.Taylor@Sun.COM 	 * "qp_lock".  If we got raised to interrupt level by priority
32829517SBill.Taylor@Sun.COM 	 * inversion, we do not want to block in this routine waiting for
32839517SBill.Taylor@Sun.COM 	 * success.
32849517SBill.Taylor@Sun.COM 	 */
32859517SBill.Taylor@Sun.COM 	status = hermon_cmn_qp_cmd_post(state, RST2INIT_QP, qpc, qp->qp_qpnum,
32869517SBill.Taylor@Sun.COM 	    0, HERMON_CMD_NOSLEEP_SPIN);
32879517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
32889517SBill.Taylor@Sun.COM 		cmn_err(CE_NOTE, "hermon%d: RST2INIT_QP command failed: %08x\n",
32899517SBill.Taylor@Sun.COM 		    state->hs_instance, status);
32909517SBill.Taylor@Sun.COM 		if (status == HERMON_CMD_INVALID_STATUS) {
32919517SBill.Taylor@Sun.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
32929517SBill.Taylor@Sun.COM 		}
32939517SBill.Taylor@Sun.COM 		return (ibc_get_ci_failure(0));
32949517SBill.Taylor@Sun.COM 	}
32959517SBill.Taylor@Sun.COM 
32969517SBill.Taylor@Sun.COM 	/*
32979517SBill.Taylor@Sun.COM 	 * Now post the TOERR_QP command to the Hermon firmware
32989517SBill.Taylor@Sun.COM 	 *
32999517SBill.Taylor@Sun.COM 	 * We still do a HERMON_NOSLEEP here because we are still holding the
33009517SBill.Taylor@Sun.COM 	 * "qp_lock".  Note:  If this fails (which it really never should),
33019517SBill.Taylor@Sun.COM 	 * it indicates a serious problem in the HW or SW.  We try to move
33029517SBill.Taylor@Sun.COM 	 * the QP back to the "Reset" state if possible and print a warning
33039517SBill.Taylor@Sun.COM 	 * message if not.  In any case, we return an error here.
33049517SBill.Taylor@Sun.COM 	 */
33059517SBill.Taylor@Sun.COM 	status = hermon_cmn_qp_cmd_post(state, TOERR_QP, NULL, qp->qp_qpnum,
33069517SBill.Taylor@Sun.COM 	    0, HERMON_CMD_NOSLEEP_SPIN);
33079517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
33089517SBill.Taylor@Sun.COM 		cmn_err(CE_NOTE, "hermon%d: TOERR_QP command failed: %08x\n",
33099517SBill.Taylor@Sun.COM 		    state->hs_instance, status);
33109517SBill.Taylor@Sun.COM 		if (status == HERMON_CMD_INVALID_STATUS) {
33119517SBill.Taylor@Sun.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
33129517SBill.Taylor@Sun.COM 		}
33139517SBill.Taylor@Sun.COM 		if (hermon_qp_to_reset(state, qp) != DDI_SUCCESS) {
33149517SBill.Taylor@Sun.COM 			HERMON_WARNING(state, "failed to reset QP context");
33159517SBill.Taylor@Sun.COM 		}
33169517SBill.Taylor@Sun.COM 		return (ibc_get_ci_failure(0));
33179517SBill.Taylor@Sun.COM 	}
33189517SBill.Taylor@Sun.COM 
33199517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
33209517SBill.Taylor@Sun.COM }
33219517SBill.Taylor@Sun.COM 
33229517SBill.Taylor@Sun.COM 
33239517SBill.Taylor@Sun.COM /*
33249517SBill.Taylor@Sun.COM  * hermon_check_rdma_enable_flags()
33259517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
33269517SBill.Taylor@Sun.COM  */
33279517SBill.Taylor@Sun.COM 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)33289517SBill.Taylor@Sun.COM hermon_check_rdma_enable_flags(ibt_cep_modify_flags_t flags,
33299517SBill.Taylor@Sun.COM     ibt_qp_info_t *info_p, hermon_hw_qpc_t *qpc)
33309517SBill.Taylor@Sun.COM {
33319517SBill.Taylor@Sun.COM 	uint_t	opmask = 0;
33329517SBill.Taylor@Sun.COM 
33339517SBill.Taylor@Sun.COM 	if (flags & IBT_CEP_SET_RDMA_R) {
33349517SBill.Taylor@Sun.COM 		qpc->rre = (info_p->qp_flags & IBT_CEP_RDMA_RD) ? 1 : 0;
33359517SBill.Taylor@Sun.COM 		opmask |= HERMON_CMD_OP_RRE;
33369517SBill.Taylor@Sun.COM 	}
33379517SBill.Taylor@Sun.COM 
33389517SBill.Taylor@Sun.COM 	if (flags & IBT_CEP_SET_RDMA_W) {
33399517SBill.Taylor@Sun.COM 		qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
33409517SBill.Taylor@Sun.COM 		opmask |= HERMON_CMD_OP_RWE;
33419517SBill.Taylor@Sun.COM 	}
33429517SBill.Taylor@Sun.COM 
33439517SBill.Taylor@Sun.COM 	if (flags & IBT_CEP_SET_ATOMIC) {
33449517SBill.Taylor@Sun.COM 		qpc->rae = (info_p->qp_flags & IBT_CEP_ATOMIC) ? 1 : 0;
33459517SBill.Taylor@Sun.COM 		opmask |= HERMON_CMD_OP_RAE;
33469517SBill.Taylor@Sun.COM 	}
33479517SBill.Taylor@Sun.COM 
33489517SBill.Taylor@Sun.COM 	return (opmask);
33499517SBill.Taylor@Sun.COM }
33509517SBill.Taylor@Sun.COM 
33519517SBill.Taylor@Sun.COM /*
33529517SBill.Taylor@Sun.COM  * hermon_qp_validate_resp_rsrc()
33539517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
33549517SBill.Taylor@Sun.COM  */
33559517SBill.Taylor@Sun.COM static int
hermon_qp_validate_resp_rsrc(hermon_state_t * state,ibt_qp_rc_attr_t * rc,uint_t * rra_max)33569517SBill.Taylor@Sun.COM hermon_qp_validate_resp_rsrc(hermon_state_t *state, ibt_qp_rc_attr_t *rc,
33579517SBill.Taylor@Sun.COM     uint_t *rra_max)
33589517SBill.Taylor@Sun.COM {
33599517SBill.Taylor@Sun.COM 	uint_t	rdma_ra_in;
33609517SBill.Taylor@Sun.COM 
33619517SBill.Taylor@Sun.COM 	rdma_ra_in = rc->rc_rdma_ra_in;
33629517SBill.Taylor@Sun.COM 
33639517SBill.Taylor@Sun.COM 	/*
33649517SBill.Taylor@Sun.COM 	 * Check if number of responder resources is too large.  Return an
33659517SBill.Taylor@Sun.COM 	 * error if it is
33669517SBill.Taylor@Sun.COM 	 */
33679517SBill.Taylor@Sun.COM 	if (rdma_ra_in > state->hs_cfg_profile->cp_hca_max_rdma_in_qp) {
33689517SBill.Taylor@Sun.COM 		return (IBT_INVALID_PARAM);
33699517SBill.Taylor@Sun.COM 	}
33709517SBill.Taylor@Sun.COM 
33719517SBill.Taylor@Sun.COM 	/*
33729517SBill.Taylor@Sun.COM 	 * If the number of responder resources is too small, round it up.
33739517SBill.Taylor@Sun.COM 	 * Then find the next highest power-of-2
33749517SBill.Taylor@Sun.COM 	 */
33759517SBill.Taylor@Sun.COM 	if (rdma_ra_in == 0) {
33769517SBill.Taylor@Sun.COM 		rdma_ra_in = 1;
33779517SBill.Taylor@Sun.COM 	}
33789517SBill.Taylor@Sun.COM 	if ((rdma_ra_in & (rdma_ra_in - 1)) == 0) {
33799517SBill.Taylor@Sun.COM 		*rra_max = highbit(rdma_ra_in) - 1;
33809517SBill.Taylor@Sun.COM 	} else {
33819517SBill.Taylor@Sun.COM 		*rra_max = highbit(rdma_ra_in);
33829517SBill.Taylor@Sun.COM 	}
33839517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
33849517SBill.Taylor@Sun.COM }
33859517SBill.Taylor@Sun.COM 
33869517SBill.Taylor@Sun.COM 
33879517SBill.Taylor@Sun.COM /*
33889517SBill.Taylor@Sun.COM  * hermon_qp_validate_init_depth()
33899517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
33909517SBill.Taylor@Sun.COM  */
33919517SBill.Taylor@Sun.COM static int
hermon_qp_validate_init_depth(hermon_state_t * state,ibt_qp_rc_attr_t * rc,uint_t * sra_max)33929517SBill.Taylor@Sun.COM hermon_qp_validate_init_depth(hermon_state_t *state, ibt_qp_rc_attr_t *rc,
33939517SBill.Taylor@Sun.COM     uint_t *sra_max)
33949517SBill.Taylor@Sun.COM {
33959517SBill.Taylor@Sun.COM 	uint_t	rdma_ra_out;
33969517SBill.Taylor@Sun.COM 
33979517SBill.Taylor@Sun.COM 	rdma_ra_out = rc->rc_rdma_ra_out;
33989517SBill.Taylor@Sun.COM 
33999517SBill.Taylor@Sun.COM 	/*
34009517SBill.Taylor@Sun.COM 	 * Check if requested initiator depth is too large.  Return an error
34019517SBill.Taylor@Sun.COM 	 * if it is
34029517SBill.Taylor@Sun.COM 	 */
34039517SBill.Taylor@Sun.COM 	if (rdma_ra_out > state->hs_cfg_profile->cp_hca_max_rdma_out_qp) {
34049517SBill.Taylor@Sun.COM 		return (IBT_INVALID_PARAM);
34059517SBill.Taylor@Sun.COM 	}
34069517SBill.Taylor@Sun.COM 
34079517SBill.Taylor@Sun.COM 	/*
34089517SBill.Taylor@Sun.COM 	 * If the requested initiator depth is too small, round it up.
34099517SBill.Taylor@Sun.COM 	 * Then find the next highest power-of-2
34109517SBill.Taylor@Sun.COM 	 */
34119517SBill.Taylor@Sun.COM 	if (rdma_ra_out == 0) {
34129517SBill.Taylor@Sun.COM 		rdma_ra_out = 1;
34139517SBill.Taylor@Sun.COM 	}
34149517SBill.Taylor@Sun.COM 	if ((rdma_ra_out & (rdma_ra_out - 1)) == 0) {
34159517SBill.Taylor@Sun.COM 		*sra_max = highbit(rdma_ra_out) - 1;
34169517SBill.Taylor@Sun.COM 	} else {
34179517SBill.Taylor@Sun.COM 		*sra_max = highbit(rdma_ra_out);
34189517SBill.Taylor@Sun.COM 	}
34199517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
34209517SBill.Taylor@Sun.COM }
34219517SBill.Taylor@Sun.COM 
34229517SBill.Taylor@Sun.COM 
34239517SBill.Taylor@Sun.COM /*
34249517SBill.Taylor@Sun.COM  * hermon_qp_validate_mtu()
34259517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
34269517SBill.Taylor@Sun.COM  */
34279517SBill.Taylor@Sun.COM static int
hermon_qp_validate_mtu(hermon_state_t * state,uint_t mtu)34289517SBill.Taylor@Sun.COM hermon_qp_validate_mtu(hermon_state_t *state, uint_t mtu)
34299517SBill.Taylor@Sun.COM {
34309517SBill.Taylor@Sun.COM 	/*
34319517SBill.Taylor@Sun.COM 	 * Check for invalid MTU values (i.e. zero or any value larger than
34329517SBill.Taylor@Sun.COM 	 * the HCA's port maximum).
34339517SBill.Taylor@Sun.COM 	 */
34349517SBill.Taylor@Sun.COM 	if ((mtu == 0) || (mtu > state->hs_cfg_profile->cp_max_mtu)) {
34359517SBill.Taylor@Sun.COM 		return (IBT_HCA_PORT_MTU_EXCEEDED);
34369517SBill.Taylor@Sun.COM 	}
34379517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
34389517SBill.Taylor@Sun.COM }
3439