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