1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  27  * hermon_qpmod.c
  28  *    Hermon Queue Pair Modify Routines
  29  *
  30  *    This contains all the routines necessary to implement the
  31  *    ModifyQP() verb.  This includes all the code for legal
  32  *    transitions to and from Reset, Init, RTR, RTS, SQD, SQErr,
  33  *    and Error.
  34  */
  35 
  36 #include <sys/sysmacros.h>
  37 #include <sys/types.h>
  38 #include <sys/conf.h>
  39 #include <sys/ddi.h>
  40 #include <sys/sunddi.h>
  41 #include <sys/modctl.h>
  42 #include <sys/bitmap.h>
  43 
  44 #include <sys/ib/adapters/hermon/hermon.h>
  45 #include <sys/ib/ib_pkt_hdrs.h>
  46 
  47 static int hermon_qp_reset2init(hermon_state_t *state, hermon_qphdl_t qp,
  48     ibt_qp_info_t *info_p);
  49 static int hermon_qp_init2init(hermon_state_t *state, hermon_qphdl_t qp,
  50     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
  51 static int hermon_qp_init2rtr(hermon_state_t *state, hermon_qphdl_t qp,
  52     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
  53 static int hermon_qp_rtr2rts(hermon_state_t *state, hermon_qphdl_t qp,
  54     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
  55 static int hermon_qp_rts2rts(hermon_state_t *state, hermon_qphdl_t qp,
  56     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
  57 #ifdef HERMON_NOTNOW
  58 static int hermon_qp_rts2sqd(hermon_state_t *state, hermon_qphdl_t qp,
  59     ibt_cep_modify_flags_t flags);
  60 #endif
  61 static int hermon_qp_sqd2rts(hermon_state_t *state, hermon_qphdl_t qp,
  62     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
  63 static int hermon_qp_sqd2sqd(hermon_state_t *state, hermon_qphdl_t qp,
  64     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
  65 static int hermon_qp_sqerr2rts(hermon_state_t *state, hermon_qphdl_t qp,
  66     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
  67 static int hermon_qp_to_error(hermon_state_t *state, hermon_qphdl_t qp);
  68 static int hermon_qp_reset2err(hermon_state_t *state, hermon_qphdl_t qp);
  69 
  70 static uint_t hermon_check_rdma_enable_flags(ibt_cep_modify_flags_t flags,
  71     ibt_qp_info_t *info_p, hermon_hw_qpc_t *qpc);
  72 static int hermon_qp_validate_resp_rsrc(hermon_state_t *state,
  73     ibt_qp_rc_attr_t *rc, uint_t *rra_max);
  74 static int hermon_qp_validate_init_depth(hermon_state_t *state,
  75     ibt_qp_rc_attr_t *rc, uint_t *sra_max);
  76 static int hermon_qp_validate_mtu(hermon_state_t *state, uint_t mtu);
  77 
  78 /*
  79  * hermon_qp_modify()
  80  *    Context: Can be called from interrupt or base context.
  81  */
  82 /* ARGSUSED */
  83 int
  84 hermon_qp_modify(hermon_state_t *state, hermon_qphdl_t qp,
  85     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p,
  86     ibt_queue_sizes_t *actual_sz)
  87 {
  88         ibt_cep_state_t         cur_state, mod_state;
  89         ibt_cep_modify_flags_t  okflags;
  90         int                     status;
  91 
  92         /*
  93          * TODO add support for SUSPEND and RESUME
  94          */
  95 
  96         /*
  97          * Lock the QP so that we can modify it atomically.  After grabbing
  98          * the lock, get the current QP state.  We will use this current QP
  99          * state to determine the legal transitions (and the checks that need
 100          * to be performed.)
 101          * Below is a case for every possible QP state.  In each case, we
 102          * check that no flags are set which are not valid for the possible
 103          * transitions from that state.  If these tests pass and the
 104          * state transition we are attempting is legal, then we call one
 105          * of the helper functions.  Each of these functions does some
 106          * additional setup before posting the firmware command for the
 107          * appropriate state transition.
 108          */
 109         mutex_enter(&qp->qp_lock);
 110 
 111         /*
 112          * Verify that the transport type matches between the serv_type and the
 113          * qp_trans.  A caller to IBT must specify the qp_trans field as
 114          * IBT_UD_SRV, IBT_RC_SRV, or IBT_UC_SRV, depending on the QP.  We
 115          * check here that the correct value was specified, based on our
 116          * understanding of the QP serv type.
 117          *
 118          * Because callers specify part of a 'union' based on what QP type they
 119          * think they're working with, this ensures that we do not pickup bogus
 120          * data if the caller thought they were working with a different QP
 121          * type.
 122          */
 123         if (!(HERMON_QP_TYPE_VALID(info_p->qp_trans, qp->qp_serv_type))) {
 124                 mutex_exit(&qp->qp_lock);
 125                 return (IBT_QP_SRV_TYPE_INVALID);
 126         }
 127 
 128         /*
 129          * If this is a transition to RTS (which is valid from RTR, RTS,
 130          * SQError, and SQ Drain) then we should honor the "current QP state"
 131          * specified by the consumer.  This means converting the IBTF QP state
 132          * in "info_p->qp_current_state" to an Hermon QP state.  Otherwise, we
 133          * assume that we already know the current state (i.e. whatever it was
 134          * last modified to or queried as - in "qp->qp_state").
 135          */
 136         mod_state = info_p->qp_state;
 137 
 138         if (flags & IBT_CEP_SET_RTR_RTS) {
 139                 cur_state = HERMON_QP_RTR;              /* Ready to Receive */
 140 
 141         } else if ((flags & IBT_CEP_SET_STATE) &&
 142             (mod_state == IBT_STATE_RTS)) {
 143 
 144                 /* Convert the current IBTF QP state to an Hermon QP state */
 145                 switch (info_p->qp_current_state) {
 146                 case IBT_STATE_RTR:
 147                         cur_state = HERMON_QP_RTR;      /* Ready to Receive */
 148                         break;
 149                 case IBT_STATE_RTS:
 150                         cur_state = HERMON_QP_RTS;      /* Ready to Send */
 151                         break;
 152                 case IBT_STATE_SQE:
 153                         cur_state = HERMON_QP_SQERR;    /* Send Queue Error */
 154                         break;
 155                 case IBT_STATE_SQD:
 156                         cur_state = HERMON_QP_SQD;      /* SQ Drained */
 157                         break;
 158                 default:
 159                         mutex_exit(&qp->qp_lock);
 160                         return (IBT_QP_STATE_INVALID);
 161                 }
 162         } else {
 163                 cur_state = qp->qp_state;
 164         }
 165 
 166         switch (cur_state) {
 167         case HERMON_QP_RESET:
 168                 okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_RESET_INIT |
 169                     IBT_CEP_SET_RDMA_R | IBT_CEP_SET_RDMA_W |
 170                     IBT_CEP_SET_ATOMIC | IBT_CEP_SET_PKEY_IX |
 171                     IBT_CEP_SET_PORT | IBT_CEP_SET_QKEY);
 172 
 173                 /*
 174                  * Check for attempts to modify invalid attributes from the
 175                  * "Reset" state
 176                  */
 177                 if (flags & ~okflags) {
 178                         mutex_exit(&qp->qp_lock);
 179                         status = IBT_QP_ATTR_RO;
 180                         goto qpmod_fail;
 181                 }
 182 
 183                 /*
 184                  * Verify state transition is to either "Init", back to
 185                  * "Reset", or to "Error".
 186                  */
 187                 if ((flags & IBT_CEP_SET_RESET_INIT) &&
 188                     (flags & IBT_CEP_SET_STATE) &&
 189                     (mod_state != IBT_STATE_INIT)) {
 190                         /* Invalid transition - ambiguous flags */
 191                         mutex_exit(&qp->qp_lock);
 192                         status = IBT_QP_STATE_INVALID;
 193                         goto qpmod_fail;
 194 
 195                 } else if ((flags & IBT_CEP_SET_RESET_INIT) ||
 196                     ((flags & IBT_CEP_SET_STATE) &&
 197                     (mod_state == IBT_STATE_INIT))) {
 198                         /*
 199                          * Attempt to transition from "Reset" to "Init"
 200                          */
 201                         status = hermon_qp_reset2init(state, qp, info_p);
 202                         if (status != DDI_SUCCESS) {
 203                                 mutex_exit(&qp->qp_lock);
 204                                 goto qpmod_fail;
 205                         }
 206                         qp->qp_state = HERMON_QP_INIT;
 207                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_INIT);
 208 
 209                 } else if ((flags & IBT_CEP_SET_STATE) &&
 210                     (mod_state == IBT_STATE_RESET)) {
 211                         /*
 212                          * Attempt to transition from "Reset" back to "Reset"
 213                          *    Nothing to do here really... just drop the lock
 214                          *    and return success.  The qp->qp_state should
 215                          *    already be set to HERMON_QP_RESET.
 216                          *
 217                          * Note: We return here because we do not want to fall
 218                          *    through to the hermon_wrid_from_reset_handling()
 219                          *    routine below (since we are not really moving
 220                          *    _out_ of the "Reset" state.
 221                          */
 222                         mutex_exit(&qp->qp_lock);
 223                         return (DDI_SUCCESS);
 224 
 225                 } else if ((flags & IBT_CEP_SET_STATE) &&
 226                     (mod_state == IBT_STATE_ERROR)) {
 227                         /*
 228                          * Attempt to transition from "Reset" to "Error"
 229                          */
 230                         status = hermon_qp_reset2err(state, qp);
 231                         if (status != DDI_SUCCESS) {
 232                                 mutex_exit(&qp->qp_lock);
 233                                 goto qpmod_fail;
 234                         }
 235                         qp->qp_state = HERMON_QP_ERR;
 236                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
 237 
 238                 } else {
 239                         /* Invalid transition - return error */
 240                         mutex_exit(&qp->qp_lock);
 241                         status = IBT_QP_STATE_INVALID;
 242                         goto qpmod_fail;
 243                 }
 244 
 245                 /*
 246                  * Do any additional handling necessary here for the transition
 247                  * from the "Reset" state (e.g. re-initialize the workQ WRID
 248                  * lists).  Note: If hermon_wrid_from_reset_handling() fails,
 249                  * then we attempt to transition the QP back to the "Reset"
 250                  * state.  If that fails, then it is an indication of a serious
 251                  * problem (either HW or SW).  So we print out a warning
 252                  * message and return failure.
 253                  */
 254                 status = hermon_wrid_from_reset_handling(state, qp);
 255                 if (status != DDI_SUCCESS) {
 256                         if (hermon_qp_to_reset(state, qp) != DDI_SUCCESS) {
 257                                 HERMON_WARNING(state, "failed to reset QP");
 258                         }
 259                         qp->qp_state = HERMON_QP_RESET;
 260                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
 261 
 262                         mutex_exit(&qp->qp_lock);
 263                         goto qpmod_fail;
 264                 }
 265                 break;
 266 
 267         case HERMON_QP_INIT:
 268                 okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_INIT_RTR |
 269                     IBT_CEP_SET_ADDS_VECT | IBT_CEP_SET_RDMARA_IN |
 270                     IBT_CEP_SET_MIN_RNR_NAK | IBT_CEP_SET_ALT_PATH |
 271                     IBT_CEP_SET_RDMA_R | IBT_CEP_SET_RDMA_W |
 272                     IBT_CEP_SET_ATOMIC | IBT_CEP_SET_PKEY_IX |
 273                     IBT_CEP_SET_QKEY | IBT_CEP_SET_PORT);
 274 
 275                 /*
 276                  * Check for attempts to modify invalid attributes from the
 277                  * "Init" state
 278                  */
 279                 if (flags & ~okflags) {
 280                         mutex_exit(&qp->qp_lock);
 281                         status = IBT_QP_ATTR_RO;
 282                         goto qpmod_fail;
 283                 }
 284 
 285                 /*
 286                  * Verify state transition is to either "RTR", back to "Init",
 287                  * to "Reset", or to "Error"
 288                  */
 289                 if ((flags & IBT_CEP_SET_INIT_RTR) &&
 290                     (flags & IBT_CEP_SET_STATE) &&
 291                     (mod_state != IBT_STATE_RTR)) {
 292                         /* Invalid transition - ambiguous flags */
 293                         mutex_exit(&qp->qp_lock);
 294                         status = IBT_QP_STATE_INVALID;
 295                         goto qpmod_fail;
 296 
 297                 } else if ((flags & IBT_CEP_SET_INIT_RTR) ||
 298                     ((flags & IBT_CEP_SET_STATE) &&
 299                     (mod_state == IBT_STATE_RTR))) {
 300                         /*
 301                          * Attempt to transition from "Init" to "RTR"
 302                          */
 303                         status = hermon_qp_init2rtr(state, qp, flags, info_p);
 304                         if (status != DDI_SUCCESS) {
 305                                 mutex_exit(&qp->qp_lock);
 306                                 goto qpmod_fail;
 307                         }
 308                         qp->qp_state = HERMON_QP_RTR;
 309                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTR);
 310 
 311                 } else if ((flags & IBT_CEP_SET_STATE) &&
 312                     (mod_state == IBT_STATE_INIT)) {
 313                         /*
 314                          * Attempt to transition from "Init" to "Init"
 315                          */
 316                         status = hermon_qp_init2init(state, qp, flags, info_p);
 317                         if (status != DDI_SUCCESS) {
 318                                 mutex_exit(&qp->qp_lock);
 319                                 goto qpmod_fail;
 320                         }
 321                         qp->qp_state = HERMON_QP_INIT;
 322                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_INIT);
 323 
 324                 } else if ((flags & IBT_CEP_SET_STATE) &&
 325                     (mod_state == IBT_STATE_RESET)) {
 326                         /*
 327                          * Attempt to transition from "Init" to "Reset"
 328                          */
 329                         status = hermon_qp_to_reset(state, qp);
 330                         if (status != DDI_SUCCESS) {
 331                                 mutex_exit(&qp->qp_lock);
 332                                 goto qpmod_fail;
 333                         }
 334                         qp->qp_state = HERMON_QP_RESET;
 335                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
 336 
 337                         /*
 338                          * Do any additional handling necessary for the
 339                          * transition _to_ the "Reset" state (e.g. update the
 340                          * workQ WRID lists)
 341                          */
 342                         status = hermon_wrid_to_reset_handling(state, qp);
 343                         if (status != IBT_SUCCESS) {
 344                                 mutex_exit(&qp->qp_lock);
 345                                 goto qpmod_fail;
 346                         }
 347 
 348                 } else if ((flags & IBT_CEP_SET_STATE) &&
 349                     (mod_state == IBT_STATE_ERROR)) {
 350                         /*
 351                          * Attempt to transition from "Init" to "Error"
 352                          */
 353                         status = hermon_qp_to_error(state, qp);
 354                         if (status != DDI_SUCCESS) {
 355                                 mutex_exit(&qp->qp_lock);
 356                                 goto qpmod_fail;
 357                         }
 358                         qp->qp_state = HERMON_QP_ERR;
 359                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
 360 
 361                 } else {
 362                         /* Invalid transition - return error */
 363                         mutex_exit(&qp->qp_lock);
 364                         status = IBT_QP_STATE_INVALID;
 365                         goto qpmod_fail;
 366                 }
 367                 break;
 368 
 369         case HERMON_QP_RTR:
 370                 okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_RTR_RTS |
 371                     IBT_CEP_SET_TIMEOUT | IBT_CEP_SET_RETRY |
 372                     IBT_CEP_SET_RNR_NAK_RETRY | IBT_CEP_SET_RDMARA_OUT |
 373                     IBT_CEP_SET_RDMA_R | IBT_CEP_SET_RDMA_W |
 374                     IBT_CEP_SET_ATOMIC | IBT_CEP_SET_QKEY |
 375                     IBT_CEP_SET_ALT_PATH | IBT_CEP_SET_MIG |
 376                     IBT_CEP_SET_MIN_RNR_NAK);
 377 
 378                 /*
 379                  * Check for attempts to modify invalid attributes from the
 380                  * "RTR" state
 381                  */
 382                 if (flags & ~okflags) {
 383                         mutex_exit(&qp->qp_lock);
 384                         status = IBT_QP_ATTR_RO;
 385                         goto qpmod_fail;
 386                 }
 387 
 388                 /*
 389                  * Verify state transition is to either "RTS", "Reset",
 390                  * or "Error"
 391                  */
 392                 if ((flags & IBT_CEP_SET_RTR_RTS) &&
 393                     (flags & IBT_CEP_SET_STATE) &&
 394                     (mod_state != IBT_STATE_RTS)) {
 395                         /* Invalid transition - ambiguous flags */
 396                         mutex_exit(&qp->qp_lock);
 397                         status = IBT_QP_STATE_INVALID;
 398                         goto qpmod_fail;
 399 
 400                 } else if ((flags & IBT_CEP_SET_RTR_RTS) ||
 401                     ((flags & IBT_CEP_SET_STATE) &&
 402                     (mod_state == IBT_STATE_RTS))) {
 403                         /*
 404                          * Attempt to transition from "RTR" to "RTS"
 405                          */
 406                         status = hermon_qp_rtr2rts(state, qp, flags, info_p);
 407                         if (status != DDI_SUCCESS) {
 408                                 mutex_exit(&qp->qp_lock);
 409                                 goto qpmod_fail;
 410                         }
 411                         qp->qp_state = HERMON_QP_RTS;
 412                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTS);
 413 
 414                 } else if ((flags & IBT_CEP_SET_STATE) &&
 415                     (mod_state == IBT_STATE_RESET)) {
 416                         /*
 417                          * Attempt to transition from "RTR" to "Reset"
 418                          */
 419                         status = hermon_qp_to_reset(state, qp);
 420                         if (status != DDI_SUCCESS) {
 421                                 mutex_exit(&qp->qp_lock);
 422                                 goto qpmod_fail;
 423                         }
 424                         qp->qp_state = HERMON_QP_RESET;
 425                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
 426 
 427                         /*
 428                          * Do any additional handling necessary for the
 429                          * transition _to_ the "Reset" state (e.g. update the
 430                          * workQ WRID lists)
 431                          */
 432                         status = hermon_wrid_to_reset_handling(state, qp);
 433                         if (status != IBT_SUCCESS) {
 434                                 mutex_exit(&qp->qp_lock);
 435                                 goto qpmod_fail;
 436                         }
 437 
 438                 } else if ((flags & IBT_CEP_SET_STATE) &&
 439                     (mod_state == IBT_STATE_ERROR)) {
 440                         /*
 441                          * Attempt to transition from "RTR" to "Error"
 442                          */
 443                         status = hermon_qp_to_error(state, qp);
 444                         if (status != DDI_SUCCESS) {
 445                                 mutex_exit(&qp->qp_lock);
 446                                 goto qpmod_fail;
 447                         }
 448                         qp->qp_state = HERMON_QP_ERR;
 449                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
 450 
 451                 } else {
 452                         /* Invalid transition - return error */
 453                         mutex_exit(&qp->qp_lock);
 454                         status = IBT_QP_STATE_INVALID;
 455                         goto qpmod_fail;
 456                 }
 457                 break;
 458 
 459         case HERMON_QP_RTS:
 460                 okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_RDMA_R |
 461                     IBT_CEP_SET_RDMA_W | IBT_CEP_SET_ATOMIC |
 462                     IBT_CEP_SET_QKEY | IBT_CEP_SET_ALT_PATH |
 463                     IBT_CEP_SET_MIG | IBT_CEP_SET_MIN_RNR_NAK |
 464                     IBT_CEP_SET_SQD_EVENT);
 465 
 466                 /*
 467                  * Check for attempts to modify invalid attributes from the
 468                  * "RTS" state
 469                  */
 470                 if (flags & ~okflags) {
 471                         mutex_exit(&qp->qp_lock);
 472                         status = IBT_QP_ATTR_RO;
 473                         goto qpmod_fail;
 474                 }
 475 
 476                 /*
 477                  * Verify state transition is to either "RTS", "SQD", "Reset",
 478                  * or "Error"
 479                  */
 480                 if ((flags & IBT_CEP_SET_STATE) &&
 481                     (mod_state == IBT_STATE_RTS)) {
 482                         /*
 483                          * Attempt to transition from "RTS" to "RTS"
 484                          */
 485                         status = hermon_qp_rts2rts(state, qp, flags, info_p);
 486                         if (status != DDI_SUCCESS) {
 487                                 mutex_exit(&qp->qp_lock);
 488                                 goto qpmod_fail;
 489                         }
 490                         qp->qp_state = HERMON_QP_RTS;
 491                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTS);
 492 
 493                 } else if ((flags & IBT_CEP_SET_STATE) &&
 494                     (mod_state == IBT_STATE_SQD)) {
 495 #ifdef HERMON_NOTNOW
 496                         /*
 497                          * Attempt to transition from "RTS" to "SQD"
 498                          */
 499                         status = hermon_qp_rts2sqd(state, qp, flags);
 500                         if (status != DDI_SUCCESS) {
 501                                 mutex_exit(&qp->qp_lock);
 502                                 goto qpmod_fail;
 503                         }
 504                         qp->qp_state = HERMON_QP_SQD;
 505                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_SQD);
 506 #else
 507                         /* hack because of the lack of fw support for SQD */
 508                         mutex_exit(&qp->qp_lock);
 509                         status = IBT_QP_STATE_INVALID;
 510                         goto qpmod_fail;
 511 #endif
 512 
 513                 } else if ((flags & IBT_CEP_SET_STATE) &&
 514                     (mod_state == IBT_STATE_RESET)) {
 515                         /*
 516                          * Attempt to transition from "RTS" to "Reset"
 517                          */
 518                         status = hermon_qp_to_reset(state, qp);
 519                         if (status != DDI_SUCCESS) {
 520                                 mutex_exit(&qp->qp_lock);
 521                                 goto qpmod_fail;
 522                         }
 523                         qp->qp_state = HERMON_QP_RESET;
 524                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
 525 
 526                         /*
 527                          * Do any additional handling necessary for the
 528                          * transition _to_ the "Reset" state (e.g. update the
 529                          * workQ WRID lists)
 530                          */
 531                         status = hermon_wrid_to_reset_handling(state, qp);
 532                         if (status != IBT_SUCCESS) {
 533                                 mutex_exit(&qp->qp_lock);
 534                                 goto qpmod_fail;
 535                         }
 536 
 537                 } else if ((flags & IBT_CEP_SET_STATE) &&
 538                     (mod_state == IBT_STATE_ERROR)) {
 539                         /*
 540                          * Attempt to transition from "RTS" to "Error"
 541                          */
 542                         status = hermon_qp_to_error(state, qp);
 543                         if (status != DDI_SUCCESS) {
 544                                 mutex_exit(&qp->qp_lock);
 545                                 goto qpmod_fail;
 546                         }
 547                         qp->qp_state = HERMON_QP_ERR;
 548                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
 549 
 550                 } else {
 551                         /* Invalid transition - return error */
 552                         mutex_exit(&qp->qp_lock);
 553                         status = IBT_QP_STATE_INVALID;
 554                         goto qpmod_fail;
 555                 }
 556                 break;
 557 
 558         case HERMON_QP_SQERR:
 559                 okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_RDMA_R |
 560                     IBT_CEP_SET_RDMA_W | IBT_CEP_SET_ATOMIC |
 561                     IBT_CEP_SET_QKEY | IBT_CEP_SET_MIN_RNR_NAK);
 562 
 563                 /*
 564                  * Check for attempts to modify invalid attributes from the
 565                  * "SQErr" state
 566                  */
 567                 if (flags & ~okflags) {
 568                         mutex_exit(&qp->qp_lock);
 569                         status = IBT_QP_ATTR_RO;
 570                         goto qpmod_fail;
 571                 }
 572 
 573                 /*
 574                  * Verify state transition is to either "RTS", "Reset", or
 575                  * "Error"
 576                  */
 577                 if ((flags & IBT_CEP_SET_STATE) &&
 578                     (mod_state == IBT_STATE_RTS)) {
 579                         /*
 580                          * Attempt to transition from "SQErr" to "RTS"
 581                          */
 582                         status = hermon_qp_sqerr2rts(state, qp, flags, info_p);
 583                         if (status != DDI_SUCCESS) {
 584                                 mutex_exit(&qp->qp_lock);
 585                                 goto qpmod_fail;
 586                         }
 587                         qp->qp_state = HERMON_QP_RTS;
 588                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTS);
 589 
 590                 } else if ((flags & IBT_CEP_SET_STATE) &&
 591                     (mod_state == IBT_STATE_RESET)) {
 592                         /*
 593                          * Attempt to transition from "SQErr" to "Reset"
 594                          */
 595                         status = hermon_qp_to_reset(state, qp);
 596                         if (status != DDI_SUCCESS) {
 597                                 mutex_exit(&qp->qp_lock);
 598                                 goto qpmod_fail;
 599                         }
 600                         qp->qp_state = HERMON_QP_RESET;
 601                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
 602 
 603                         /*
 604                          * Do any additional handling necessary for the
 605                          * transition _to_ the "Reset" state (e.g. update the
 606                          * workQ WRID lists)
 607                          */
 608                         status = hermon_wrid_to_reset_handling(state, qp);
 609                         if (status != IBT_SUCCESS) {
 610                                 mutex_exit(&qp->qp_lock);
 611                                 goto qpmod_fail;
 612                         }
 613 
 614                 } else if ((flags & IBT_CEP_SET_STATE) &&
 615                     (mod_state == IBT_STATE_ERROR)) {
 616                         /*
 617                          * Attempt to transition from "SQErr" to "Error"
 618                          */
 619                         status = hermon_qp_to_error(state, qp);
 620                         if (status != DDI_SUCCESS) {
 621                                 mutex_exit(&qp->qp_lock);
 622                                 goto qpmod_fail;
 623                         }
 624                         qp->qp_state = HERMON_QP_ERR;
 625                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
 626 
 627                 } else {
 628                         /* Invalid transition - return error */
 629                         mutex_exit(&qp->qp_lock);
 630                         status = IBT_QP_STATE_INVALID;
 631                         goto qpmod_fail;
 632                 }
 633                 break;
 634 
 635         case HERMON_QP_SQD:
 636                 okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_ADDS_VECT |
 637                     IBT_CEP_SET_ALT_PATH | IBT_CEP_SET_MIG |
 638                     IBT_CEP_SET_RDMARA_OUT | IBT_CEP_SET_RDMARA_IN |
 639                     IBT_CEP_SET_QKEY | IBT_CEP_SET_PKEY_IX |
 640                     IBT_CEP_SET_TIMEOUT | IBT_CEP_SET_RETRY |
 641                     IBT_CEP_SET_RNR_NAK_RETRY | IBT_CEP_SET_PORT |
 642                     IBT_CEP_SET_MIN_RNR_NAK | IBT_CEP_SET_RDMA_R |
 643                     IBT_CEP_SET_RDMA_W | IBT_CEP_SET_ATOMIC);
 644 
 645                 /*
 646                  * Check for attempts to modify invalid attributes from the
 647                  * "SQD" state
 648                  */
 649                 if (flags & ~okflags) {
 650                         mutex_exit(&qp->qp_lock);
 651                         status = IBT_QP_ATTR_RO;
 652                         goto qpmod_fail;
 653                 }
 654 
 655                 /*
 656                  * Verify state transition is to either "SQD", "RTS", "Reset",
 657                  * or "Error"
 658                  */
 659 
 660                 if ((flags & IBT_CEP_SET_STATE) &&
 661                     (mod_state == IBT_STATE_SQD)) {
 662                         /*
 663                          * Attempt to transition from "SQD" to "SQD"
 664                          */
 665                         status = hermon_qp_sqd2sqd(state, qp, flags, info_p);
 666                         if (status != DDI_SUCCESS) {
 667                                 mutex_exit(&qp->qp_lock);
 668                                 goto qpmod_fail;
 669                         }
 670                         qp->qp_state = HERMON_QP_SQD;
 671                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_SQD);
 672 
 673                 } else if ((flags & IBT_CEP_SET_STATE) &&
 674                     (mod_state == IBT_STATE_RTS)) {
 675                         /*
 676                          * If still draining SQ, then fail transition attempt
 677                          * to RTS, even though this is now done is two steps
 678                          * (see below) if the consumer has tried this before
 679                          * it's drained, let him fail and wait appropriately
 680                          */
 681                         if (qp->qp_sqd_still_draining) {
 682                                 mutex_exit(&qp->qp_lock);
 683                                 goto qpmod_fail;
 684                         }
 685                         /*
 686                          * IBA 1.2 has changed - most/all the things that were
 687                          * done in SQD2RTS can be done in SQD2SQD.  So make this
 688                          * a 2-step process.  First, set any attributes requsted
 689                          * w/ SQD2SQD, but no real transition.
 690                          *
 691                          * First, Attempt to transition from "SQD" to "SQD"
 692                          */
 693                         status = hermon_qp_sqd2sqd(state, qp, flags, info_p);
 694                         if (status != DDI_SUCCESS) {
 695                                 mutex_exit(&qp->qp_lock);
 696                                 goto qpmod_fail;
 697                         }
 698                         qp->qp_state = HERMON_QP_SQD;
 699                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_SQD);
 700 
 701                         /*
 702                          * The, attempt to transition from "SQD" to "RTS", but
 703                          * request only the state transition, no attributes
 704                          */
 705 
 706                         status = hermon_qp_sqd2rts(state, qp,
 707                             IBT_CEP_SET_STATE, info_p);
 708                         if (status != DDI_SUCCESS) {
 709                                 mutex_exit(&qp->qp_lock);
 710                                 goto qpmod_fail;
 711                         }
 712                         qp->qp_state = HERMON_QP_RTS;
 713                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTS);
 714 
 715                 } else if ((flags & IBT_CEP_SET_STATE) &&
 716                     (mod_state == IBT_STATE_RESET)) {
 717                         /*
 718                          * Attempt to transition from "SQD" to "Reset"
 719                          */
 720                         status = hermon_qp_to_reset(state, qp);
 721                         if (status != DDI_SUCCESS) {
 722                                 mutex_exit(&qp->qp_lock);
 723                                 goto qpmod_fail;
 724                         }
 725                         qp->qp_state = HERMON_QP_RESET;
 726                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
 727 
 728                         /*
 729                          * Do any additional handling necessary for the
 730                          * transition _to_ the "Reset" state (e.g. update the
 731                          * workQ WRID lists)
 732                          */
 733                         status = hermon_wrid_to_reset_handling(state, qp);
 734                         if (status != IBT_SUCCESS) {
 735                                 mutex_exit(&qp->qp_lock);
 736                                 goto qpmod_fail;
 737                         }
 738 
 739                 } else if ((flags & IBT_CEP_SET_STATE) &&
 740                     (mod_state == IBT_STATE_ERROR)) {
 741                         /*
 742                          * Attempt to transition from "SQD" to "Error"
 743                          */
 744                         status = hermon_qp_to_error(state, qp);
 745                         if (status != DDI_SUCCESS) {
 746                                 mutex_exit(&qp->qp_lock);
 747                                 goto qpmod_fail;
 748                         }
 749                         qp->qp_state = HERMON_QP_ERR;
 750                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
 751 
 752                 } else {
 753                         /* Invalid transition - return error */
 754                         mutex_exit(&qp->qp_lock);
 755                         status = IBT_QP_STATE_INVALID;
 756                         goto qpmod_fail;
 757                 }
 758                 break;
 759 
 760         case HERMON_QP_ERR:
 761                 /*
 762                  * Verify state transition is to either "Reset" or back to
 763                  * "Error"
 764                  */
 765                 if ((flags & IBT_CEP_SET_STATE) &&
 766                     (mod_state == IBT_STATE_RESET)) {
 767                         /*
 768                          * Attempt to transition from "Error" to "Reset"
 769                          */
 770                         status = hermon_qp_to_reset(state, qp);
 771                         if (status != DDI_SUCCESS) {
 772                                 mutex_exit(&qp->qp_lock);
 773                                 goto qpmod_fail;
 774                         }
 775                         qp->qp_state = HERMON_QP_RESET;
 776                         HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
 777 
 778                         /*
 779                          * Do any additional handling necessary for the
 780                          * transition _to_ the "Reset" state (e.g. update the
 781                          * workQ WRID lists)
 782                          */
 783                         status = hermon_wrid_to_reset_handling(state, qp);
 784                         if (status != IBT_SUCCESS) {
 785                                 mutex_exit(&qp->qp_lock);
 786                                 goto qpmod_fail;
 787                         }
 788 
 789                 } else if ((flags & IBT_CEP_SET_STATE) &&
 790                     (mod_state == IBT_STATE_ERROR)) {
 791                         /*
 792                          * Attempt to transition from "Error" back to "Error"
 793                          *    Nothing to do here really... just drop the lock
 794                          *    and return success.  The qp->qp_state should
 795                          *    already be set to HERMON_QP_ERR.
 796                          *
 797                          */
 798                         mutex_exit(&qp->qp_lock);
 799                         return (DDI_SUCCESS);
 800 
 801                 } else {
 802                         /* Invalid transition - return error */
 803                         mutex_exit(&qp->qp_lock);
 804                         status = IBT_QP_STATE_INVALID;
 805                         goto qpmod_fail;
 806                 }
 807                 break;
 808 
 809         default:
 810                 /*
 811                  * Invalid QP state.  If we got here then it's a warning of
 812                  * a probably serious problem.  So print a message and return
 813                  * failure
 814                  */
 815                 mutex_exit(&qp->qp_lock);
 816                 HERMON_WARNING(state, "unknown QP state in modify");
 817                 status = IBT_QP_STATE_INVALID;
 818                 goto qpmod_fail;
 819         }
 820 
 821         mutex_exit(&qp->qp_lock);
 822         return (DDI_SUCCESS);
 823 
 824 qpmod_fail:
 825         return (status);
 826 }
 827 
 828 
 829 /*
 830  * hermon_qp_reset2init()
 831  *    Context: Can be called from interrupt or base context.
 832  */
 833 static int
 834 hermon_qp_reset2init(hermon_state_t *state, hermon_qphdl_t qp,
 835     ibt_qp_info_t *info_p)
 836 {
 837         hermon_hw_qpc_t         *qpc;
 838         ibt_qp_rc_attr_t        *rc;
 839         ibt_qp_ud_attr_t        *ud;
 840         ibt_qp_uc_attr_t        *uc;
 841         uint_t                  portnum, pkeyindx;
 842         int                     status;
 843         uint32_t                cqnmask;
 844         int                     qp_srq_en;
 845 
 846         ASSERT(MUTEX_HELD(&qp->qp_lock));
 847 
 848         /*
 849          * Grab the temporary QPC entry from QP software state
 850          */
 851         qpc = &qp->qpc;
 852 
 853         /*
 854          * Fill in the common fields in the QPC
 855          */
 856 
 857         if (qp->qp_is_special) {
 858                 qpc->serv_type       = HERMON_QP_MLX;
 859         } else {
 860                 qpc->serv_type       = qp->qp_serv_type;
 861         }
 862         qpc->pm_state                = HERMON_QP_PMSTATE_MIGRATED;
 863 
 864         qpc->pd                      = qp->qp_pdhdl->pd_pdnum;
 865 
 866         qpc->log_sq_stride   = qp->qp_sq_log_wqesz - 4;
 867         qpc->log_rq_stride   = qp->qp_rq_log_wqesz - 4;
 868         qpc->sq_no_prefetch  = qp->qp_no_prefetch;
 869         qpc->log_sq_size     = highbit(qp->qp_sq_bufsz) - 1;
 870         qpc->log_rq_size     = highbit(qp->qp_rq_bufsz) - 1;
 871 
 872         qpc->usr_page                = qp->qp_uarpg;
 873 
 874         cqnmask = (1 << state->hs_cfg_profile->cp_log_num_cq) - 1;
 875         qpc->cqn_snd         =
 876             (qp->qp_sq_cqhdl == NULL) ? 0 : qp->qp_sq_cqhdl->cq_cqnum & cqnmask;
 877         qpc->page_offs               = qp->qp_wqinfo.qa_pgoffs >> 6;
 878         qpc->cqn_rcv         =
 879             (qp->qp_rq_cqhdl == NULL) ? 0 : qp->qp_rq_cqhdl->cq_cqnum & cqnmask;
 880 
 881         /* dbr is now an address, not an index */
 882         qpc->dbr_addrh               = ((uint64_t)qp->qp_rq_pdbr >> 32);
 883         qpc->dbr_addrl               = ((uint64_t)qp->qp_rq_pdbr & 0xFFFFFFFC) >> 2;
 884         qpc->sq_wqe_counter  = 0;
 885         qpc->rq_wqe_counter  = 0;
 886         /*
 887          * HERMON:
 888          * qpc->wqe_baseaddr is replaced by LKey from the cMPT, and
 889          * page_offset, mtt_base_addr_h/l, and log2_page_size will
 890          * be used to map the WQE buffer
 891          * NOTE that the cMPT is created implicitly when the QP is
 892          * transitioned from reset to init
 893          */
 894         qpc->log2_pgsz               = qp->qp_mrhdl->mr_log2_pgsz;
 895         qpc->mtt_base_addrl  = (qp->qp_mrhdl->mr_mttaddr) >> 3;
 896         qpc->mtt_base_addrh  = (uint32_t)((qp->qp_mrhdl->mr_mttaddr >> 32) &
 897             0xFF);
 898         qp_srq_en               = (qp->qp_alloc_flags & IBT_QP_USES_SRQ) != 0;
 899         qpc->srq_en          = qp_srq_en;
 900 
 901         if (qp_srq_en) {
 902                 qpc->srq_number      = qp->qp_srqhdl->srq_srqnum;
 903         } else {
 904                 qpc->srq_number = 0;
 905         }
 906 
 907         /*
 908          * Fast Registration Work Requests and Reserved Lkey are enabled
 909          * with the single IBT bit stored in qp_rlky.
 910          */
 911         qpc->fre             = qp->qp_rlky;
 912         qpc->rlky            = qp->qp_rlky;
 913 
 914         /* 1.2 verbs extensions disabled for now */
 915         qpc->header_sep              = 0; /* disable header separation for now */
 916         qpc->rss             = qp->qp_alloc_flags & IBT_QP_USES_RSS ? 1 : 0;
 917         qpc->inline_scatter  = 0; /* disable inline scatter for now */
 918 
 919         /*
 920          * Now fill in the QPC fields which are specific to transport type
 921          */
 922         if (qp->qp_type == IBT_UD_RQP) {
 923                 int my_fc_id_idx, exch_base;
 924 
 925                 ud = &info_p->qp_transport.ud;
 926 
 927                 /* Set the QKey */
 928                 qpc->qkey = ud->ud_qkey;
 929 
 930                 /*
 931                  * Set MTU and message max. Hermon checks the QPC
 932                  * MTU settings rather than just the port MTU,
 933                  * so set it to maximum size.
 934                  */
 935                 qpc->mtu = HERMON_MAX_MTU;
 936                 if (qp->qp_uses_lso)
 937                         qpc->msg_max = state->hs_devlim.log_max_gso_sz;
 938                 else if (qp->qp_is_special)
 939                         qpc->msg_max = HERMON_MAX_MTU + 6;
 940                 else
 941                         qpc->msg_max = HERMON_QP_LOG_MAX_MSGSZ;
 942 
 943                 /* Check for valid port number and fill it in */
 944                 portnum = ud->ud_port;
 945                 if (hermon_portnum_is_valid(state, portnum)) {
 946                         qp->qp_portnum = portnum - 1;
 947                         qpc->pri_addr_path.sched_q =
 948                             HERMON_QP_SCHEDQ_GET(portnum - 1,
 949                             0, qp->qp_is_special);
 950                 } else {
 951                         return (IBT_HCA_PORT_INVALID);
 952                 }
 953 
 954 
 955                 /* Check for valid PKey index and fill it in */
 956                 pkeyindx = ud->ud_pkey_ix;
 957                 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
 958                         qpc->pri_addr_path.pkey_indx = pkeyindx;
 959                         qp->qp_pkeyindx = pkeyindx;
 960                 } else {
 961                         return (IBT_PKEY_IX_ILLEGAL);
 962                 }
 963 
 964                 /* fill in the RSS fields */
 965                 if (qpc->rss) {
 966                         struct hermon_hw_rss_s *rssp;
 967                         ibt_rss_flags_t flags = ud->ud_rss.rss_flags;
 968 
 969                         rssp = (struct hermon_hw_rss_s *)&qpc->pri_addr_path;
 970                         rssp->log2_tbl_sz = ud->ud_rss.rss_log2_table;
 971                         rssp->base_qpn = ud->ud_rss.rss_base_qpn;
 972                         rssp->default_qpn = ud->ud_rss.rss_def_qpn;
 973                         if (flags & IBT_RSS_ALG_XOR)
 974                                 rssp->hash_fn = 0;   /* XOR Hash Function */
 975                         else if (flags & IBT_RSS_ALG_TPL)
 976                                 rssp->hash_fn = 1;   /* Toeplitz Hash Fn */
 977                         else
 978                                 return (IBT_INVALID_PARAM);
 979                         rssp->ipv4 = (flags & IBT_RSS_HASH_IPV4) != 0;
 980                         rssp->tcp_ipv4 = (flags & IBT_RSS_HASH_TCP_IPV4) != 0;
 981                         rssp->ipv6 = (flags & IBT_RSS_HASH_IPV6) != 0;
 982                         rssp->tcp_ipv4 = (flags & IBT_RSS_HASH_TCP_IPV6) != 0;
 983                         bcopy(ud->ud_rss.rss_toe_key, rssp->rss_key, 40);
 984                 } else if (qp->qp_serv_type == HERMON_QP_RFCI) {
 985                         status = hermon_fcoib_set_id(state, portnum,
 986                             qp->qp_qpnum, ud->ud_fc.fc_src_id);
 987                         if (status != DDI_SUCCESS)
 988                                 return (status);
 989                         qp->qp_fc_attr = ud->ud_fc;
 990                 } else if (qp->qp_serv_type == HERMON_QP_FEXCH) {
 991                         my_fc_id_idx = hermon_fcoib_get_id_idx(state,
 992                             portnum, &ud->ud_fc);
 993                         if (my_fc_id_idx == -1)
 994                                 return (IBT_INVALID_PARAM);
 995                         qpc->my_fc_id_idx = my_fc_id_idx;
 996 
 997                         status = hermon_fcoib_fexch_mkey_init(state,
 998                             qp->qp_pdhdl, ud->ud_fc.fc_hca_port,
 999                             qp->qp_qpnum, HERMON_CMD_NOSLEEP_SPIN);
1000                         if (status != DDI_SUCCESS)
1001                                 return (status);
1002                         qp->qp_fc_attr = ud->ud_fc;
1003                 } else if (qp->qp_serv_type == HERMON_QP_FCMND) {
1004                         my_fc_id_idx = hermon_fcoib_get_id_idx(state,
1005                             portnum, &ud->ud_fc);
1006                         if (my_fc_id_idx == -1)
1007                                 return (IBT_INVALID_PARAM);
1008                         qpc->my_fc_id_idx = my_fc_id_idx;
1009                         exch_base = hermon_fcoib_check_exch_base_off(state,
1010                             portnum, &ud->ud_fc);
1011                         if (exch_base == -1)
1012                                 return (IBT_INVALID_PARAM);
1013                         qpc->exch_base = exch_base;
1014                         qpc->exch_size = ud->ud_fc.fc_exch_log2_sz;
1015                         qp->qp_fc_attr = ud->ud_fc;
1016                 }
1017 
1018         } else if (qp->qp_serv_type == HERMON_QP_RC) {
1019                 rc = &info_p->qp_transport.rc;
1020 
1021                 /* Set the RDMA (recv) enable/disable flags */
1022                 qpc->rre = (info_p->qp_flags & IBT_CEP_RDMA_RD) ? 1 : 0;
1023                 qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
1024                 qpc->rae = (info_p->qp_flags & IBT_CEP_ATOMIC)  ? 1 : 0;
1025 
1026                 /* Check for valid port number and fill it in */
1027                 portnum = rc->rc_path.cep_hca_port_num;
1028                 if (hermon_portnum_is_valid(state, portnum)) {
1029                         qp->qp_portnum = portnum - 1;
1030                         qpc->pri_addr_path.sched_q =
1031                             HERMON_QP_SCHEDQ_GET(portnum - 1,
1032                             0, qp->qp_is_special);
1033                 } else {
1034                         return (IBT_HCA_PORT_INVALID);
1035                 }
1036 
1037                 /* Check for valid PKey index and fill it in */
1038                 pkeyindx = rc->rc_path.cep_pkey_ix;
1039                 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1040                         qpc->pri_addr_path.pkey_indx = pkeyindx;
1041                 } else {
1042                         return (IBT_PKEY_IX_ILLEGAL);
1043                 }
1044 
1045         } else if (qp->qp_serv_type == HERMON_QP_UC) {
1046                 uc = &info_p->qp_transport.uc;
1047 
1048                 /*
1049                  * Set the RDMA (recv) enable/disable flags.  Note: RDMA Read
1050                  * and Atomic are ignored by default.
1051                  */
1052                 qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
1053 
1054                 /* Check for valid port number and fill it in */
1055                 portnum = uc->uc_path.cep_hca_port_num;
1056                 if (hermon_portnum_is_valid(state, portnum)) {
1057                         qp->qp_portnum = portnum - 1;
1058                         qpc->pri_addr_path.sched_q =
1059                             HERMON_QP_SCHEDQ_GET(portnum - 1,
1060                             0, qp->qp_is_special);
1061                 } else {
1062                         return (IBT_HCA_PORT_INVALID);
1063                 }
1064 
1065                 /* Check for valid PKey index and fill it in */
1066                 pkeyindx = uc->uc_path.cep_pkey_ix;
1067                 if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1068                         qpc->pri_addr_path.pkey_indx = pkeyindx;
1069                 } else {
1070                         return (IBT_PKEY_IX_ILLEGAL);
1071                 }
1072 
1073         } else {
1074                 /*
1075                  * Invalid QP transport type. If we got here then it's a
1076                  * warning of a probably serious problem.  So print a message
1077                  * and return failure
1078                  */
1079                 HERMON_WARNING(state, "unknown QP transport type in rst2init");
1080                 return (ibc_get_ci_failure(0));
1081         }
1082 
1083         /*
1084          * Post the RST2INIT_QP command to the Hermon firmware
1085          *
1086          * We do a HERMON_NOSLEEP here because we are still holding the
1087          * "qp_lock".  If we got raised to interrupt level by priority
1088          * inversion, we do not want to block in this routine waiting for
1089          * success.
1090          */
1091         status = hermon_cmn_qp_cmd_post(state, RST2INIT_QP, qpc, qp->qp_qpnum,
1092             0, HERMON_CMD_NOSLEEP_SPIN);
1093         if (status != HERMON_CMD_SUCCESS) {
1094                 cmn_err(CE_NOTE, "hermon%d: RST2INIT_QP command failed: %08x\n",
1095                     state->hs_instance, status);
1096                 if (status == HERMON_CMD_INVALID_STATUS) {
1097                         hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
1098                 }
1099                 return (ibc_get_ci_failure(0));
1100         }
1101 
1102         return (DDI_SUCCESS);
1103 }
1104 
1105 
1106 /*
1107  * hermon_qp_init2init()
1108  *    Context: Can be called from interrupt or base context.
1109  */
1110 static int
1111 hermon_qp_init2init(hermon_state_t *state, hermon_qphdl_t qp,
1112     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
1113 {
1114         hermon_hw_qpc_t         *qpc;
1115         ibt_qp_rc_attr_t        *rc;
1116         ibt_qp_ud_attr_t        *ud;
1117         ibt_qp_uc_attr_t        *uc;
1118         uint_t                  portnum, pkeyindx;
1119         uint32_t                opmask = 0;
1120         int                     status;
1121 
1122         ASSERT(MUTEX_HELD(&qp->qp_lock));
1123 
1124         /*
1125          * Grab the temporary QPC entry from QP software state
1126          */
1127         qpc = &qp->qpc;
1128 
1129         /*
1130          * Since there are no common fields to be filled in for this command,
1131          * we begin with the QPC fields which are specific to transport type.
1132          */
1133         if (qp->qp_type == IBT_UD_RQP) {
1134                 ud = &info_p->qp_transport.ud;
1135 
1136                 /*
1137                  * If we are attempting to modify the port for this QP, then
1138                  * check for valid port number and fill it in.  Also set the
1139                  * appropriate flag in the "opmask" parameter.
1140                  */
1141         /*
1142          * set port is not supported in init2init - however, in init2rtr it will
1143          * take the entire qpc, including the embedded sched_q in the path
1144          * structure - so, we can just skip setting the opmask for it explicitly
1145          * and allow it to be set later on
1146          */
1147                 if (flags & IBT_CEP_SET_PORT) {
1148                         portnum = ud->ud_port;
1149                         if (hermon_portnum_is_valid(state, portnum)) {
1150                                 qp->qp_portnum = portnum - 1; /* save it away */
1151                                 qpc->pri_addr_path.sched_q =
1152                                     HERMON_QP_SCHEDQ_GET(portnum - 1,
1153                                     0, qp->qp_is_special);
1154                         } else {
1155                                 return (IBT_HCA_PORT_INVALID);
1156                         }
1157                 }
1158 
1159                 /*
1160                  * If we are attempting to modify the PKey index for this QP,
1161                  * then check for valid PKey index and fill it in.  Also set
1162                  * the appropriate flag in the "opmask" parameter.
1163                  */
1164                 if (flags & IBT_CEP_SET_PKEY_IX) {
1165                         pkeyindx = ud->ud_pkey_ix;
1166                         if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1167                                 qpc->pri_addr_path.pkey_indx = pkeyindx;
1168                                 opmask |= HERMON_CMD_OP_PKEYINDX;
1169                                 qp->qp_pkeyindx = pkeyindx;
1170                         } else {
1171                                 return (IBT_PKEY_IX_ILLEGAL);
1172                         }
1173                 }
1174 
1175                 /*
1176                  * If we are attempting to modify the QKey for this QP, then
1177                  * fill it in and set the appropriate flag in the "opmask"
1178                  * parameter.
1179                  */
1180                 if (flags & IBT_CEP_SET_QKEY) {
1181                         qpc->qkey = ud->ud_qkey;
1182                         opmask |= HERMON_CMD_OP_QKEY;
1183                 }
1184 
1185         } else if (qp->qp_serv_type == HERMON_QP_RC) {
1186                 rc = &info_p->qp_transport.rc;
1187 
1188                 /*
1189                  * If we are attempting to modify the port for this QP, then
1190                  * check for valid port number and fill it in.  Also set the
1191                  * appropriate flag in the "opmask" parameter.
1192                  */
1193                 if (flags & IBT_CEP_SET_PORT) {
1194                         portnum = rc->rc_path.cep_hca_port_num;
1195                         if (hermon_portnum_is_valid(state, portnum)) {
1196                                 qp->qp_portnum = portnum - 1;
1197                                 qpc->pri_addr_path.sched_q =
1198                                     HERMON_QP_SCHEDQ_GET(portnum - 1,
1199                                     0, qp->qp_is_special);
1200                         } else {
1201                                 return (IBT_HCA_PORT_INVALID);
1202                         }
1203 
1204                 }
1205 
1206                 /*
1207                  * If we are attempting to modify the PKey index for this QP,
1208                  * then check for valid PKey index and fill it in.  Also set
1209                  * the appropriate flag in the "opmask" parameter.
1210                  */
1211                 if (flags & IBT_CEP_SET_PKEY_IX) {
1212                         pkeyindx = rc->rc_path.cep_pkey_ix;
1213                         if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1214                                 qpc->pri_addr_path.pkey_indx = pkeyindx;
1215                                 opmask |= HERMON_CMD_OP_PKEYINDX;
1216                         } else {
1217                                 return (IBT_PKEY_IX_ILLEGAL);
1218                         }
1219                 }
1220 
1221                 /*
1222                  * Check if any of the flags indicate a change in the RDMA
1223                  * (recv) enable/disable flags and set the appropriate flag in
1224                  * the "opmask" parameter
1225                  */
1226                 opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
1227 
1228         } else if (qp->qp_serv_type == HERMON_QP_UC) {
1229                 uc = &info_p->qp_transport.uc;
1230 
1231                 /*
1232                  * If we are attempting to modify the port for this QP, then
1233                  * check for valid port number and fill it in.  Also set the
1234                  * appropriate flag in the "opmask" parameter.
1235                  */
1236                 if (flags & IBT_CEP_SET_PORT) {
1237                         portnum = uc->uc_path.cep_hca_port_num;
1238                         if (hermon_portnum_is_valid(state, portnum)) {
1239                                 qp->qp_portnum = portnum - 1;
1240                                 qpc->pri_addr_path.sched_q =
1241                                     HERMON_QP_SCHEDQ_GET(portnum - 1,
1242                                     0, qp->qp_is_special);
1243                         } else {
1244                                 return (IBT_HCA_PORT_INVALID);
1245                         }
1246                 /* port# cannot be set in this transition - defer to init2rtr */
1247                 }
1248 
1249                 /*
1250                  * If we are attempting to modify the PKey index for this QP,
1251                  * then check for valid PKey index and fill it in.  Also set
1252                  * the appropriate flag in the "opmask" parameter.
1253                  */
1254                 if (flags & IBT_CEP_SET_PKEY_IX) {
1255                         pkeyindx = uc->uc_path.cep_pkey_ix;
1256                         if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1257                                 qpc->pri_addr_path.pkey_indx = pkeyindx;
1258                                 opmask |= HERMON_CMD_OP_PKEYINDX;
1259                         } else {
1260                                 return (IBT_PKEY_IX_ILLEGAL);
1261                         }
1262                 }
1263 
1264                 /*
1265                  * Check if any of the flags indicate a change in the RDMA
1266                  * Write (recv) enable/disable and set the appropriate flag
1267                  * in the "opmask" parameter. Note: RDMA Read and Atomic are
1268                  * not valid for UC transport.
1269                  */
1270                 if (flags & IBT_CEP_SET_RDMA_W) {
1271                         qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
1272                         opmask |= HERMON_CMD_OP_RWE;
1273                 }
1274         } else {
1275                 /*
1276                  * Invalid QP transport type. If we got here then it's a
1277                  * warning of a probably serious problem.  So print a message
1278                  * and return failure
1279                  */
1280                 HERMON_WARNING(state, "unknown QP transport type in init2init");
1281                 return (ibc_get_ci_failure(0));
1282         }
1283 
1284         /*
1285          * Post the INIT2INIT_QP command to the Hermon firmware
1286          *
1287          * We do a HERMON_NOSLEEP here because we are still holding the
1288          * "qp_lock".  If we got raised to interrupt level by priority
1289          * inversion, we do not want to block in this routine waiting for
1290          * success.
1291          */
1292         status = hermon_cmn_qp_cmd_post(state, INIT2INIT_QP, qpc, qp->qp_qpnum,
1293             opmask, HERMON_CMD_NOSLEEP_SPIN);
1294         if (status != HERMON_CMD_SUCCESS) {
1295                 if (status != HERMON_CMD_BAD_QP_STATE) {
1296                         cmn_err(CE_NOTE, "hermon%d: INIT2INIT_QP command "
1297                             "failed: %08x\n", state->hs_instance, status);
1298                         if (status == HERMON_CMD_INVALID_STATUS) {
1299                                 hermon_fm_ereport(state, HCA_SYS_ERR,
1300                                     HCA_ERR_SRV_LOST);
1301                         }
1302                         return (ibc_get_ci_failure(0));
1303                 } else {
1304                         return (IBT_QP_STATE_INVALID);
1305                 }
1306         }
1307 
1308         return (DDI_SUCCESS);
1309 }
1310 
1311 
1312 /*
1313  * hermon_qp_init2rtr()
1314  *    Context: Can be called from interrupt or base context.
1315  */
1316 static int
1317 hermon_qp_init2rtr(hermon_state_t *state, hermon_qphdl_t qp,
1318     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
1319 {
1320         hermon_hw_qpc_t         *qpc;
1321         ibt_qp_rc_attr_t        *rc;
1322         ibt_qp_ud_attr_t        *ud;
1323         ibt_qp_uc_attr_t        *uc;
1324         hermon_hw_addr_path_t   *qpc_path;
1325         ibt_adds_vect_t         *adds_vect;
1326         uint_t                  portnum, pkeyindx, rra_max;
1327         uint_t                  mtu;
1328         uint32_t                opmask = 0;
1329         int                     status;
1330 
1331         ASSERT(MUTEX_HELD(&qp->qp_lock));
1332 
1333         /*
1334          * Grab the temporary QPC entry from QP software state
1335          */
1336         qpc = &qp->qpc;
1337 
1338         /*
1339          * Since there are few common fields to be filled in for this command,
1340          * we just do the QPC fields that are specific to transport type.
1341          */
1342         if (qp->qp_type == IBT_UD_RQP) {
1343                 ud = &info_p->qp_transport.ud;
1344 
1345                 /*
1346                  * If this UD QP is also a "special QP" (QP0 or QP1), then
1347                  * the MTU is 256 bytes.  However, Hermon checks the QPC
1348                  * MTU settings rather than just the port MTU, so we will
1349                  * set it to maximum size for all UD.
1350                  */
1351                 qpc->mtu = HERMON_MAX_MTU;
1352                 if (qp->qp_uses_lso)
1353                         qpc->msg_max = state->hs_devlim.log_max_gso_sz;
1354                 else
1355                         qpc->msg_max = HERMON_QP_LOG_MAX_MSGSZ;
1356 
1357                 /*
1358                  * Save away the MTU value.  This is used in future sqd2sqd
1359                  * transitions, as the MTU must remain the same in future
1360                  * changes.
1361                  */
1362                 qp->qp_save_mtu = qpc->mtu;
1363 
1364                 /*
1365                  * If we are attempting to modify the PKey index for this QP,
1366                  * then check for valid PKey index and fill it in.  Also set
1367                  * the appropriate flag in the "opmask" parameter.
1368                  */
1369                 if (flags & IBT_CEP_SET_PKEY_IX) {
1370                         pkeyindx = ud->ud_pkey_ix;
1371                         if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1372                                 qpc->pri_addr_path.pkey_indx = pkeyindx;
1373                                 opmask |= HERMON_CMD_OP_PKEYINDX;
1374                                 qp->qp_pkeyindx = pkeyindx;
1375                         } else {
1376                                 return (IBT_PKEY_IX_ILLEGAL);
1377                         }
1378                 }
1379 
1380                 /*
1381                  * If we are attempting to modify the QKey for this QP, then
1382                  * fill it in and set the appropriate flag in the "opmask"
1383                  * parameter.
1384                  */
1385                 if (flags & IBT_CEP_SET_QKEY) {
1386                         qpc->qkey = ud->ud_qkey;
1387                         opmask |= HERMON_CMD_OP_QKEY;
1388                 }
1389 
1390         } else if (qp->qp_serv_type == HERMON_QP_RC) {
1391                 rc = &info_p->qp_transport.rc;
1392                 qpc_path = &qpc->pri_addr_path;
1393                 adds_vect = &rc->rc_path.cep_adds_vect;
1394 
1395                 /*
1396                  * Set the common primary address path fields
1397                  */
1398                 status = hermon_set_addr_path(state, adds_vect, qpc_path,
1399                     HERMON_ADDRPATH_QP);
1400                 if (status != DDI_SUCCESS) {
1401                         return (status);
1402                 }
1403                 /* set the primary port number/sched_q */
1404                 portnum = qp->qp_portnum + 1;
1405                 if (hermon_portnum_is_valid(state, portnum)) {
1406                         qpc->pri_addr_path.sched_q  =
1407                             HERMON_QP_SCHEDQ_GET(qp->qp_portnum,
1408                             adds_vect->av_srvl, qp->qp_is_special);
1409                 } else {
1410                         return (IBT_HCA_PORT_INVALID);
1411                 }
1412 
1413                 /*
1414                  * The following values are apparently "required" here (as
1415                  * they are part of the IBA-defined "Remote Node Address
1416                  * Vector").  However, they are also going to be "required"
1417                  * later - at RTR2RTS_QP time.  Not sure why.  But we set
1418                  * them here anyway.
1419                  */
1420                 qpc->rnr_retry               = rc->rc_rnr_retry_cnt;
1421                 qpc->retry_cnt               = rc->rc_retry_cnt;
1422                 qpc_path->ack_timeout        = rc->rc_path.cep_timeout;
1423 
1424                 /*
1425                  * Setup the destination QP, recv PSN, MTU, max msg size,etc.
1426                  * Note max message size is defined to be the maximum IB
1427                  * allowed message size (which is 2^31 bytes).  Also max
1428                  * MTU is defined by HCA port properties.
1429                  */
1430                 qpc->rem_qpn   = rc->rc_dst_qpn;
1431                 qpc->next_rcv_psn = rc->rc_rq_psn;
1432                 qpc->msg_max   = HERMON_QP_LOG_MAX_MSGSZ;
1433                 qpc->ric       = 0;
1434                 mtu               = rc->rc_path_mtu;
1435 
1436                 if (hermon_qp_validate_mtu(state, mtu) != DDI_SUCCESS) {
1437                         return (IBT_HCA_PORT_MTU_EXCEEDED);
1438                 }
1439                 qpc->mtu = mtu;
1440 
1441                 /*
1442                  * Save away the MTU value.  This is used in future sqd2sqd
1443                  * transitions, as the MTU must remain the same in future
1444                  * changes.
1445                  */
1446                 qp->qp_save_mtu = qpc->mtu;
1447 
1448                 /*
1449                  * Though it is a "required" parameter, "min_rnr_nak" is
1450                  * optionally specifiable in Hermon.  So we force the
1451                  * optional flag here.
1452                  */
1453                 qpc->min_rnr_nak = rc->rc_min_rnr_nak;
1454                 opmask |= HERMON_CMD_OP_MINRNRNAK;
1455 
1456                 /*
1457                  * Check that the number of specified "incoming RDMA resources"
1458                  * is valid.  And if it is, then setup the "rra_max
1459                  */
1460                 if (hermon_qp_validate_resp_rsrc(state, rc, &rra_max) !=
1461                     DDI_SUCCESS) {
1462                         return (IBT_INVALID_PARAM);
1463                 }
1464                 qpc->rra_max = rra_max;
1465 
1466                 /* don't need to set up ra_buff_indx, implicit for hermon */
1467 
1468                 /*
1469                  * If we are attempting to modify the PKey index for this QP,
1470                  * then check for valid PKey index and fill it in.  Also set
1471                  * the appropriate flag in the "opmask" parameter.
1472                  */
1473                 if (flags & IBT_CEP_SET_PKEY_IX) {
1474                         pkeyindx = rc->rc_path.cep_pkey_ix;
1475                         if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1476                                 qpc->pri_addr_path.pkey_indx = pkeyindx;
1477                                 opmask |= HERMON_CMD_OP_PKEYINDX;
1478                         } else {
1479                                 return (IBT_PKEY_IX_ILLEGAL);
1480                         }
1481                 }
1482 
1483                 /*
1484                  * Check if any of the flags indicate a change in the RDMA
1485                  * (recv) enable/disable flags and set the appropriate flag in
1486                  * the "opmask" parameter
1487                  */
1488                 opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
1489 
1490                 /*
1491                  * Check for optional alternate path and fill in the
1492                  * appropriate QPC fields if one is specified
1493                  */
1494                 if (flags & IBT_CEP_SET_ALT_PATH) {
1495                         qpc_path = &qpc->alt_addr_path;
1496                         adds_vect = &rc->rc_alt_path.cep_adds_vect;
1497 
1498                         /* Set the common alternate address path fields */
1499                         status = hermon_set_addr_path(state, adds_vect,
1500                             qpc_path, HERMON_ADDRPATH_QP);
1501                         if (status != DDI_SUCCESS) {
1502                                 return (status);
1503                         }
1504                         qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
1505 
1506 
1507                         /*
1508                          * Check for valid alternate path port number and fill
1509                          * it in
1510                          */
1511                         portnum = rc->rc_alt_path.cep_hca_port_num;
1512                         if (hermon_portnum_is_valid(state, portnum)) {
1513                                 qp->qp_portnum_alt = portnum - 1;
1514                                 qpc->alt_addr_path.sched_q =
1515                                     HERMON_QP_SCHEDQ_GET(portnum - 1,
1516                                     adds_vect->av_srvl, qp->qp_is_special);
1517                         } else {
1518                                 return (IBT_HCA_PORT_INVALID);
1519                         }
1520                         /*
1521                          * Check for valid alternate path PKey index and fill
1522                          * it in
1523                          */
1524                         pkeyindx = rc->rc_alt_path.cep_pkey_ix;
1525                         if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1526                                 qpc->alt_addr_path.pkey_indx = pkeyindx;
1527                         } else {
1528                                 return (IBT_PKEY_IX_ILLEGAL);
1529                         }
1530                         opmask |= HERMON_CMD_OP_ALT_PATH;
1531                 }
1532 
1533         } else if (qp->qp_serv_type == HERMON_QP_UC) {
1534                 uc = &info_p->qp_transport.uc;
1535                 qpc_path = &qpc->pri_addr_path;
1536                 adds_vect = &uc->uc_path.cep_adds_vect;
1537 
1538                 /*
1539                  * Set the common primary address path fields
1540                  */
1541                 status = hermon_set_addr_path(state, adds_vect, qpc_path,
1542                     HERMON_ADDRPATH_QP);
1543                 if (status != DDI_SUCCESS) {
1544                         return (status);
1545                 }
1546 
1547                 /* set the primary port num/schedq */
1548                 portnum = qp->qp_portnum + 1;
1549                 if (hermon_portnum_is_valid(state, portnum)) {
1550                         qpc->pri_addr_path.sched_q  =
1551                             HERMON_QP_SCHEDQ_GET(qp->qp_portnum,
1552                             adds_vect->av_srvl, qp->qp_is_special);
1553                 } else {
1554                         return (IBT_HCA_PORT_INVALID);
1555                 }
1556 
1557                 /*
1558                  * Setup the destination QP, recv PSN, MTU, max msg size,etc.
1559                  * Note max message size is defined to be the maximum IB
1560                  * allowed message size (which is 2^31 bytes).  Also max
1561                  * MTU is defined by HCA port properties.
1562                  */
1563                 qpc->rem_qpn   = uc->uc_dst_qpn;
1564                 qpc->next_rcv_psn = uc->uc_rq_psn;
1565                 qpc->msg_max   = HERMON_QP_LOG_MAX_MSGSZ;
1566                 mtu = uc->uc_path_mtu;
1567                 if (hermon_qp_validate_mtu(state, mtu) != DDI_SUCCESS) {
1568                         return (IBT_HCA_PORT_MTU_EXCEEDED);
1569                 }
1570                 qpc->mtu = mtu;
1571 
1572                 /*
1573                  * Save away the MTU value.  This is used in future sqd2sqd
1574                  * transitions, as the MTU must remain the same in future
1575                  * changes.
1576                  */
1577                 qp->qp_save_mtu = qpc->mtu;
1578 
1579                 /*
1580                  * If we are attempting to modify the PKey index for this QP,
1581                  * then check for valid PKey index and fill it in.  Also set
1582                  * the appropriate flag in the "opmask" parameter.
1583                  */
1584                 if (flags & IBT_CEP_SET_PKEY_IX) {
1585                         pkeyindx = uc->uc_path.cep_pkey_ix;
1586                         if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1587                                 qpc->pri_addr_path.pkey_indx = pkeyindx;
1588                                 opmask |= HERMON_CMD_OP_PKEYINDX;
1589                         } else {
1590                                 return (IBT_PKEY_IX_ILLEGAL);
1591                         }
1592                 }
1593 
1594                 /*
1595                  * Check if any of the flags indicate a change in the RDMA
1596                  * Write (recv) enable/disable and set the appropriate flag
1597                  * in the "opmask" parameter. Note: RDMA Read and Atomic are
1598                  * not valid for UC transport.
1599                  */
1600                 if (flags & IBT_CEP_SET_RDMA_W) {
1601                         qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
1602                         opmask |= HERMON_CMD_OP_RWE;
1603                 }
1604 
1605                 /*
1606                  * Check for optional alternate path and fill in the
1607                  * appropriate QPC fields if one is specified
1608                  */
1609                 if (flags & IBT_CEP_SET_ALT_PATH) {
1610                         qpc_path = &qpc->alt_addr_path;
1611                         adds_vect = &uc->uc_alt_path.cep_adds_vect;
1612 
1613                         /* Set the common alternate address path fields */
1614                         status = hermon_set_addr_path(state, adds_vect,
1615                             qpc_path, HERMON_ADDRPATH_QP);
1616                         if (status != DDI_SUCCESS) {
1617                                 return (status);
1618                         }
1619 
1620                         qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
1621 
1622                         /*
1623                          * Check for valid alternate path port number and fill
1624                          * it in
1625                          */
1626                         portnum = uc->uc_alt_path.cep_hca_port_num;
1627                         if (hermon_portnum_is_valid(state, portnum)) {
1628                                 qp->qp_portnum_alt = portnum - 1;
1629                                 qpc->alt_addr_path.sched_q =
1630                                     HERMON_QP_SCHEDQ_GET(portnum - 1,
1631                                     adds_vect->av_srvl, qp->qp_is_special);
1632                         } else {
1633                                 return (IBT_HCA_PORT_INVALID);
1634                         }
1635 
1636                         /*
1637                          * Check for valid alternate path PKey index and fill
1638                          * it in
1639                          */
1640                         pkeyindx = uc->uc_alt_path.cep_pkey_ix;
1641                         if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1642                                 qpc->alt_addr_path.pkey_indx = pkeyindx;
1643                         } else {
1644                                 return (IBT_PKEY_IX_ILLEGAL);
1645                         }
1646                         opmask |= HERMON_CMD_OP_ALT_PATH;
1647                 }
1648         } else {
1649                 /*
1650                  * Invalid QP transport type. If we got here then it's a
1651                  * warning of a probably serious problem.  So print a message
1652                  * and return failure
1653                  */
1654                 HERMON_WARNING(state, "unknown QP transport type in init2rtr");
1655                 return (ibc_get_ci_failure(0));
1656         }
1657 
1658         /*
1659          * Post the INIT2RTR_QP command to the Hermon firmware
1660          *
1661          * We do a HERMON_NOSLEEP here because we are still holding the
1662          * "qp_lock".  If we got raised to interrupt level by priority
1663          * inversion, we do not want to block in this routine waiting for
1664          * success.
1665          */
1666         status = hermon_cmn_qp_cmd_post(state, INIT2RTR_QP, qpc, qp->qp_qpnum,
1667             opmask, HERMON_CMD_NOSLEEP_SPIN);
1668         if (status != HERMON_CMD_SUCCESS) {
1669                 if (status != HERMON_CMD_BAD_QP_STATE) {
1670                         cmn_err(CE_NOTE, "hermon%d: INIT2RTR_QP command "
1671                             "failed: %08x\n", state->hs_instance, status);
1672                         if (status == HERMON_CMD_INVALID_STATUS) {
1673                                 hermon_fm_ereport(state, HCA_SYS_ERR,
1674                                     HCA_ERR_SRV_LOST);
1675                         }
1676                         return (ibc_get_ci_failure(0));
1677                 } else {
1678                         return (IBT_QP_STATE_INVALID);
1679                 }
1680         }
1681 
1682         return (DDI_SUCCESS);
1683 }
1684 
1685 
1686 /*
1687  * hermon_qp_rtr2rts()
1688  *    Context: Can be called from interrupt or base context.
1689  */
1690 static int
1691 hermon_qp_rtr2rts(hermon_state_t *state, hermon_qphdl_t qp,
1692     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
1693 {
1694         hermon_hw_qpc_t         *qpc;
1695         ibt_qp_rc_attr_t        *rc;
1696         ibt_qp_ud_attr_t        *ud;
1697         ibt_qp_uc_attr_t        *uc;
1698         hermon_hw_addr_path_t   *qpc_path;
1699         ibt_adds_vect_t         *adds_vect;
1700         uint_t                  portnum, pkeyindx, sra_max;
1701         uint32_t                opmask = 0;
1702         int                     status;
1703 
1704         ASSERT(MUTEX_HELD(&qp->qp_lock));
1705 
1706         /*
1707          * Grab the temporary QPC entry from QP software state
1708          */
1709         qpc = &qp->qpc;
1710 
1711         /*
1712          * Now fill in the QPC fields which are specific to transport type
1713          */
1714         if (qp->qp_type == IBT_UD_RQP) {
1715                 ud = &info_p->qp_transport.ud;
1716 
1717                 /* Set the send PSN */
1718                 qpc->next_snd_psn = ud->ud_sq_psn;
1719 
1720                 /*
1721                  * If we are attempting to modify the QKey for this QP, then
1722                  * fill it in and set the appropriate flag in the "opmask"
1723                  * parameter.
1724                  */
1725                 if (flags & IBT_CEP_SET_QKEY) {
1726                         qpc->qkey = ud->ud_qkey;
1727                         opmask |= HERMON_CMD_OP_QKEY;
1728                 }
1729 
1730         } else if (qp->qp_serv_type == HERMON_QP_RC) {
1731                 rc = &info_p->qp_transport.rc;
1732                 qpc_path = &qpc->pri_addr_path;
1733 
1734                 /*
1735                  * Setup the send PSN, ACK timeout, and retry counts
1736                  */
1737                 qpc->next_snd_psn    = rc->rc_sq_psn;
1738                 qpc_path->ack_timeout        = rc->rc_path.cep_timeout;
1739                 qpc->rnr_retry               = rc->rc_rnr_retry_cnt;
1740                                                 /* in qpc now, not path */
1741                 qpc->retry_cnt               = rc->rc_retry_cnt;
1742 
1743                 /*
1744                  * Set "ack_req_freq" based on the configuration variable
1745                  */
1746                 qpc->ack_req_freq = state->hs_cfg_profile->cp_ackreq_freq;
1747 
1748                 /*
1749                  * Check that the number of specified "outgoing RDMA resources"
1750                  * is valid.  And if it is, then setup the "sra_max"
1751                  * appropriately
1752                  */
1753                 if (hermon_qp_validate_init_depth(state, rc, &sra_max) !=
1754                     DDI_SUCCESS) {
1755                         return (IBT_INVALID_PARAM);
1756                 }
1757                 qpc->sra_max = sra_max;
1758 
1759 
1760                 /*
1761                  * Check if any of the flags indicate a change in the RDMA
1762                  * (recv) enable/disable flags and set the appropriate flag in
1763                  * the "opmask" parameter
1764                  */
1765                 opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
1766 
1767                 /*
1768                  * If we are attempting to modify the path migration state for
1769                  * this QP, then check for valid state and fill it in.  Also
1770                  * set the appropriate flag in the "opmask" parameter.
1771                  */
1772                 if (flags & IBT_CEP_SET_MIG) {
1773                         if (rc->rc_mig_state == IBT_STATE_MIGRATED) {
1774                                 qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
1775                         } else if (rc->rc_mig_state == IBT_STATE_REARMED) {
1776                                 qpc->pm_state = HERMON_QP_PMSTATE_REARM;
1777                         } else {
1778                                 return (IBT_QP_APM_STATE_INVALID);
1779                         }
1780                         opmask |= HERMON_CMD_OP_PM_STATE;
1781                 }
1782 
1783                 /*
1784                  * If we are attempting to modify the "Minimum RNR NAK" value
1785                  * for this QP, then fill it in and set the appropriate flag
1786                  * in the "opmask" parameter.
1787                  */
1788                 if (flags & IBT_CEP_SET_MIN_RNR_NAK) {
1789                         qpc->min_rnr_nak = rc->rc_min_rnr_nak;
1790                         opmask |= HERMON_CMD_OP_MINRNRNAK;
1791                 }
1792 
1793                 /*
1794                  * Check for optional alternate path and fill in the
1795                  * appropriate QPC fields if one is specified
1796                  */
1797                 if (flags & IBT_CEP_SET_ALT_PATH) {
1798                         qpc_path = &qpc->alt_addr_path;
1799                         adds_vect = &rc->rc_alt_path.cep_adds_vect;
1800 
1801                         /* Set the common alternate address path fields */
1802                         status = hermon_set_addr_path(state, adds_vect,
1803                             qpc_path, HERMON_ADDRPATH_QP);
1804                         if (status != DDI_SUCCESS) {
1805                                 return (status);
1806                         }
1807 
1808                         qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
1809 
1810                         /*
1811                          * Check for valid alternate path port number and fill
1812                          * it in
1813                          */
1814                         portnum = rc->rc_alt_path.cep_hca_port_num;
1815                         if (hermon_portnum_is_valid(state, portnum)) {
1816                                 qp->qp_portnum_alt = portnum - 1;
1817                                 qpc->alt_addr_path.sched_q =
1818                                     HERMON_QP_SCHEDQ_GET(portnum - 1,
1819                                     adds_vect->av_srvl, qp->qp_is_special);
1820                         } else {
1821                                 return (IBT_HCA_PORT_INVALID);
1822                         }
1823 
1824                         /*
1825                          * Check for valid alternate path PKey index and fill
1826                          * it in
1827                          */
1828                         pkeyindx = rc->rc_alt_path.cep_pkey_ix;
1829                         if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1830                                 qpc->alt_addr_path.pkey_indx = pkeyindx;
1831                         } else {
1832                                 return (IBT_PKEY_IX_ILLEGAL);
1833                         }
1834                         opmask |= HERMON_CMD_OP_ALT_PATH;
1835                 }
1836 
1837         } else if (qp->qp_serv_type == HERMON_QP_UC) {
1838                 uc = &info_p->qp_transport.uc;
1839 
1840                 /* Set the send PSN */
1841                 qpc->next_snd_psn = uc->uc_sq_psn;
1842 
1843                 /*
1844                  * Configure the QP to allow (sending of) all types of allowable
1845                  * UC traffic (i.e. RDMA Write).
1846                  */
1847 
1848 
1849                 /*
1850                  * Check if any of the flags indicate a change in the RDMA
1851                  * Write (recv) enable/disable and set the appropriate flag
1852                  * in the "opmask" parameter. Note: RDMA Read and Atomic are
1853                  * not valid for UC transport.
1854                  */
1855                 if (flags & IBT_CEP_SET_RDMA_W) {
1856                         qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
1857                         opmask |= HERMON_CMD_OP_RWE;
1858                 }
1859 
1860                 /*
1861                  * If we are attempting to modify the path migration state for
1862                  * this QP, then check for valid state and fill it in.  Also
1863                  * set the appropriate flag in the "opmask" parameter.
1864                  */
1865                 if (flags & IBT_CEP_SET_MIG) {
1866                         if (uc->uc_mig_state == IBT_STATE_MIGRATED) {
1867                                 qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
1868                         } else if (uc->uc_mig_state == IBT_STATE_REARMED) {
1869                                 qpc->pm_state = HERMON_QP_PMSTATE_REARM;
1870                         } else {
1871                                 return (IBT_QP_APM_STATE_INVALID);
1872                         }
1873                         opmask |= HERMON_CMD_OP_PM_STATE;
1874                 }
1875 
1876                 /*
1877                  * Check for optional alternate path and fill in the
1878                  * appropriate QPC fields if one is specified
1879                  */
1880                 if (flags & IBT_CEP_SET_ALT_PATH) {
1881                         qpc_path = &qpc->alt_addr_path;
1882                         adds_vect = &uc->uc_alt_path.cep_adds_vect;
1883 
1884                         /* Set the common alternate address path fields */
1885                         status = hermon_set_addr_path(state, adds_vect,
1886                             qpc_path, HERMON_ADDRPATH_QP);
1887                         if (status != DDI_SUCCESS) {
1888                                 return (status);
1889                         }
1890                         qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
1891 
1892                         /*
1893                          * Check for valid alternate path port number and fill
1894                          * it in
1895                          */
1896                         portnum = uc->uc_alt_path.cep_hca_port_num;
1897                         if (hermon_portnum_is_valid(state, portnum)) {
1898                                 qpc->alt_addr_path.sched_q =
1899                                     HERMON_QP_SCHEDQ_GET(portnum - 1,
1900                                     adds_vect->av_srvl, qp->qp_is_special);
1901                         } else {
1902                                 return (IBT_HCA_PORT_INVALID);
1903                         }
1904 
1905                         /*
1906                          * Check for valid alternate path PKey index and fill
1907                          * it in
1908                          */
1909                         pkeyindx = uc->uc_alt_path.cep_pkey_ix;
1910                         if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
1911                                 qpc->alt_addr_path.pkey_indx = pkeyindx;
1912                         } else {
1913                                 return (IBT_PKEY_IX_ILLEGAL);
1914                         }
1915                         opmask |= HERMON_CMD_OP_ALT_PATH;
1916                 }
1917         } else {
1918                 /*
1919                  * Invalid QP transport type. If we got here then it's a
1920                  * warning of a probably serious problem.  So print a message
1921                  * and return failure
1922                  */
1923                 HERMON_WARNING(state, "unknown QP transport type in rtr2rts");
1924                 return (ibc_get_ci_failure(0));
1925         }
1926 
1927         /*
1928          * Post the RTR2RTS_QP command to the Hermon firmware
1929          *
1930          * We do a HERMON_NOSLEEP here because we are still holding the
1931          * "qp_lock".  If we got raised to interrupt level by priority
1932          * inversion, we do not want to block in this routine waiting for
1933          * success.
1934          */
1935         status = hermon_cmn_qp_cmd_post(state, RTR2RTS_QP, qpc, qp->qp_qpnum,
1936             opmask, HERMON_CMD_NOSLEEP_SPIN);
1937         if (status != HERMON_CMD_SUCCESS) {
1938                 if (status != HERMON_CMD_BAD_QP_STATE) {
1939                         cmn_err(CE_NOTE, "hermon%d: RTR2RTS_QP command failed: "
1940                             "%08x\n", state->hs_instance, status);
1941                         if (status == HERMON_CMD_INVALID_STATUS) {
1942                                 hermon_fm_ereport(state, HCA_SYS_ERR,
1943                                     HCA_ERR_SRV_LOST);
1944                         }
1945                         return (ibc_get_ci_failure(0));
1946                 } else {
1947                         return (IBT_QP_STATE_INVALID);
1948                 }
1949         }
1950 
1951         return (DDI_SUCCESS);
1952 }
1953 
1954 
1955 /*
1956  * hermon_qp_rts2rts()
1957  *    Context: Can be called from interrupt or base context.
1958  */
1959 static int
1960 hermon_qp_rts2rts(hermon_state_t *state, hermon_qphdl_t qp,
1961     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
1962 {
1963         hermon_hw_qpc_t         *qpc;
1964         ibt_qp_rc_attr_t        *rc;
1965         ibt_qp_ud_attr_t        *ud;
1966         ibt_qp_uc_attr_t        *uc;
1967         hermon_hw_addr_path_t   *qpc_path;
1968         ibt_adds_vect_t         *adds_vect;
1969         uint_t                  portnum, pkeyindx;
1970         uint32_t                opmask = 0;
1971         int                     status;
1972 
1973         ASSERT(MUTEX_HELD(&qp->qp_lock));
1974 
1975         /*
1976          * Grab the temporary QPC entry from QP software state
1977          */
1978 
1979         qpc = &qp->qpc;
1980 
1981         /*
1982          * Since there are no common fields to be filled in for this command,
1983          * we begin with the QPC fields which are specific to transport type.
1984          */
1985         if (qp->qp_type == IBT_UD_RQP) {
1986                 ud = &info_p->qp_transport.ud;
1987 
1988                 /*
1989                  * If we are attempting to modify the QKey for this QP, then
1990                  * fill it in and set the appropriate flag in the "opmask"
1991                  * parameter.
1992                  */
1993                 if (flags & IBT_CEP_SET_QKEY) {
1994                         qpc->qkey = ud->ud_qkey;
1995                         opmask |= HERMON_CMD_OP_QKEY;
1996                 }
1997 
1998         } else if (qp->qp_serv_type == HERMON_QP_RC) {
1999                 rc = &info_p->qp_transport.rc;
2000 
2001                 /*
2002                  * Check if any of the flags indicate a change in the RDMA
2003                  * (recv) enable/disable flags and set the appropriate flag in
2004                  * the "opmask" parameter
2005                  */
2006                 opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
2007 
2008                 /*
2009                  * If we are attempting to modify the path migration state for
2010                  * this QP, then check for valid state and fill it in.  Also
2011                  * set the appropriate flag in the "opmask" parameter.
2012                  */
2013                 if (flags & IBT_CEP_SET_MIG) {
2014                         if (rc->rc_mig_state == IBT_STATE_MIGRATED) {
2015                                 qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
2016                         } else if (rc->rc_mig_state == IBT_STATE_REARMED) {
2017                                 qpc->pm_state = HERMON_QP_PMSTATE_REARM;
2018                         } else {
2019                                 return (IBT_QP_APM_STATE_INVALID);
2020                         }
2021                         opmask |= HERMON_CMD_OP_PM_STATE;
2022                 }
2023 
2024                 /*
2025                  * If we are attempting to modify the "Minimum RNR NAK" value
2026                  * for this QP, then fill it in and set the appropriate flag
2027                  * in the "opmask" parameter.
2028                  */
2029                 if (flags & IBT_CEP_SET_MIN_RNR_NAK) {
2030                         qpc->min_rnr_nak = rc->rc_min_rnr_nak;
2031                         opmask |= HERMON_CMD_OP_MINRNRNAK;
2032                 }
2033 
2034                 /*
2035                  * Check for optional alternate path and fill in the
2036                  * appropriate QPC fields if one is specified
2037                  */
2038                 if (flags & IBT_CEP_SET_ALT_PATH) {
2039                         qpc_path = &qpc->alt_addr_path;
2040                         adds_vect = &rc->rc_alt_path.cep_adds_vect;
2041 
2042                         /* Set the common alternate address path fields */
2043                         status = hermon_set_addr_path(state, adds_vect,
2044                             qpc_path, HERMON_ADDRPATH_QP);
2045                         if (status != DDI_SUCCESS) {
2046                                 return (status);
2047                         }
2048                         qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
2049 
2050                         /*
2051                          * Check for valid alternate path port number and fill
2052                          * it in
2053                          */
2054                         portnum = rc->rc_alt_path.cep_hca_port_num;
2055                         if (hermon_portnum_is_valid(state, portnum)) {
2056                                 qp->qp_portnum_alt = portnum - 1;
2057                                 qpc->alt_addr_path.sched_q =
2058                                     HERMON_QP_SCHEDQ_GET(portnum - 1,
2059                                     adds_vect->av_srvl, qp->qp_is_special);
2060                         } else {
2061                                 return (IBT_HCA_PORT_INVALID);
2062                         }
2063 
2064                         /*
2065                          * Check for valid alternate path PKey index and fill
2066                          * it in
2067                          */
2068                         pkeyindx = rc->rc_alt_path.cep_pkey_ix;
2069                         if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
2070                                 qpc->alt_addr_path.pkey_indx = pkeyindx;
2071                         } else {
2072                                 return (IBT_PKEY_IX_ILLEGAL);
2073                         }
2074                         opmask |= HERMON_CMD_OP_ALT_PATH;
2075                 }
2076 
2077         } else if (qp->qp_serv_type == HERMON_QP_UC) {
2078                 uc = &info_p->qp_transport.uc;
2079 
2080                 /*
2081                  * Check if any of the flags indicate a change in the RDMA
2082                  * Write (recv) enable/disable and set the appropriate flag
2083                  * in the "opmask" parameter. Note: RDMA Read and Atomic are
2084                  * not valid for UC transport.
2085                  */
2086                 if (flags & IBT_CEP_SET_RDMA_W) {
2087                         qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
2088                         opmask |= HERMON_CMD_OP_RWE;
2089                 }
2090 
2091                 /*
2092                  * If we are attempting to modify the path migration state for
2093                  * this QP, then check for valid state and fill it in.  Also
2094                  * set the appropriate flag in the "opmask" parameter.
2095                  */
2096                 if (flags & IBT_CEP_SET_MIG) {
2097                         if (uc->uc_mig_state == IBT_STATE_MIGRATED) {
2098                                 qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
2099                         } else if (uc->uc_mig_state == IBT_STATE_REARMED) {
2100                                 qpc->pm_state = HERMON_QP_PMSTATE_REARM;
2101                         } else {
2102                                 return (IBT_QP_APM_STATE_INVALID);
2103                         }
2104                         opmask |= HERMON_CMD_OP_PM_STATE;
2105                 }
2106 
2107                 /*
2108                  * Check for optional alternate path and fill in the
2109                  * appropriate QPC fields if one is specified
2110                  */
2111                 if (flags & IBT_CEP_SET_ALT_PATH) {
2112                         qpc_path = &qpc->alt_addr_path;
2113                         adds_vect = &uc->uc_alt_path.cep_adds_vect;
2114 
2115                         /* Set the common alternate address path fields */
2116                         status = hermon_set_addr_path(state, adds_vect,
2117                             qpc_path, HERMON_ADDRPATH_QP);
2118                         if (status != DDI_SUCCESS) {
2119                                 return (status);
2120                         }
2121 
2122                         /*
2123                          * Check for valid alternate path port number and fill
2124                          * it in
2125                          */
2126                         portnum = uc->uc_alt_path.cep_hca_port_num;
2127                         if (hermon_portnum_is_valid(state, portnum)) {
2128                                 qp->qp_portnum_alt = portnum - 1;
2129                                 qpc->alt_addr_path.sched_q =
2130                                     HERMON_QP_SCHEDQ_GET(portnum - 1,
2131                                     adds_vect->av_srvl, qp->qp_is_special);
2132                         } else {
2133                                 return (IBT_HCA_PORT_INVALID);
2134                         }
2135 
2136                         /*
2137                          * Check for valid alternate path PKey index and fill
2138                          * it in
2139                          */
2140                         pkeyindx = uc->uc_alt_path.cep_pkey_ix;
2141                         if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
2142                                 qpc->alt_addr_path.pkey_indx = pkeyindx;
2143                         } else {
2144                                 return (IBT_PKEY_IX_ILLEGAL);
2145                         }
2146                         opmask |= HERMON_CMD_OP_ALT_PATH;
2147                 }
2148         } else {
2149                 /*
2150                  * Invalid QP transport type. If we got here then it's a
2151                  * warning of a probably serious problem.  So print a message
2152                  * and return failure
2153                  */
2154                 HERMON_WARNING(state, "unknown QP transport type in rts2rts");
2155                 return (ibc_get_ci_failure(0));
2156         }
2157 
2158         /*
2159          * Post the RTS2RTS_QP command to the Hermon firmware
2160          *
2161          * We do a HERMON_NOSLEEP here because we are still holding the
2162          * "qp_lock".  If we got raised to interrupt level by priority
2163          * inversion, we do not want to block in this routine waiting for
2164          * success.
2165          */
2166         status = hermon_cmn_qp_cmd_post(state, RTS2RTS_QP, qpc, qp->qp_qpnum,
2167             opmask, HERMON_CMD_NOSLEEP_SPIN);
2168         if (status != HERMON_CMD_SUCCESS) {
2169                 if (status != HERMON_CMD_BAD_QP_STATE) {
2170                         cmn_err(CE_NOTE, "hermon%d: RTS2RTS_QP command failed: "
2171                             "%08x\n", state->hs_instance, status);
2172                         if (status == HERMON_CMD_INVALID_STATUS) {
2173                                 hermon_fm_ereport(state, HCA_SYS_ERR,
2174                                     HCA_ERR_SRV_LOST);
2175                         }
2176                         return (ibc_get_ci_failure(0));
2177                 } else {
2178                         return (IBT_QP_STATE_INVALID);
2179                 }
2180         }
2181 
2182         return (DDI_SUCCESS);
2183 }
2184 
2185 
2186 #ifdef HERMON_NOTNOW
2187 /*
2188  * hermon_qp_rts2sqd()
2189  *    Context: Can be called from interrupt or base context.
2190  */
2191 static int
2192 hermon_qp_rts2sqd(hermon_state_t *state, hermon_qphdl_t qp,
2193     ibt_cep_modify_flags_t flags)
2194 {
2195         int                     status;
2196 
2197         ASSERT(MUTEX_HELD(&qp->qp_lock));
2198 
2199         /*
2200          * Set a flag to indicate whether or not the consumer is interested
2201          * in receiving the SQ drained event.  Since we are going to always
2202          * request hardware generation of the SQD event, we use the value in
2203          * "qp_forward_sqd_event" to determine whether or not to pass the event
2204          * to the IBTF or to silently consume it.
2205          */
2206         qp->qp_forward_sqd_event = (flags & IBT_CEP_SET_SQD_EVENT) ? 1 : 0;
2207 
2208         /*
2209          * Post the RTS2SQD_QP command to the Hermon firmware
2210          *
2211          * We do a HERMON_NOSLEEP here because we are still holding the
2212          * "qp_lock".  If we got raised to interrupt level by priority
2213          * inversion, we do not want to block in this routine waiting for
2214          * success.
2215          */
2216         status = hermon_cmn_qp_cmd_post(state, RTS2SQD_QP, NULL, qp->qp_qpnum,
2217             0, HERMON_CMD_NOSLEEP_SPIN);
2218         if (status != HERMON_CMD_SUCCESS) {
2219                 if (status != HERMON_CMD_BAD_QP_STATE) {
2220                         cmn_err(CE_NOTE, "hermon%d: RTS2SQD_QP command failed: "
2221                             "%08x\n", state->hs_instance, status);
2222                         if (status == HERMON_CMD_INVALID_STATUS) {
2223                                 hermon_fm_ereport(state, HCA_SYS_ERR,
2224                                     HCA_ERR_SRV_LOST);
2225                         }
2226                         return (ibc_get_ci_failure(0));
2227                 } else {
2228                         return (IBT_QP_STATE_INVALID);
2229                 }
2230         }
2231 
2232         /*
2233          * Mark the current QP state as "SQ Draining".  This allows us to
2234          * distinguish between the two underlying states in SQD. (see QueryQP()
2235          * code in hermon_qp.c)
2236          */
2237         qp->qp_sqd_still_draining = 1;
2238 
2239         return (DDI_SUCCESS);
2240 }
2241 #endif
2242 
2243 
2244 /*
2245  * hermon_qp_sqd2rts()
2246  *    Context: Can be called from interrupt or base context.
2247  */
2248 static int
2249 hermon_qp_sqd2rts(hermon_state_t *state, hermon_qphdl_t qp,
2250     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
2251 {
2252         hermon_hw_qpc_t         *qpc;
2253         ibt_qp_rc_attr_t        *rc;
2254         ibt_qp_ud_attr_t        *ud;
2255         ibt_qp_uc_attr_t        *uc;
2256         hermon_hw_addr_path_t   *qpc_path;
2257         ibt_adds_vect_t         *adds_vect;
2258         uint_t                  portnum, pkeyindx;
2259         uint_t                  rra_max, sra_max;
2260         uint32_t                opmask = 0;
2261         int                     status;
2262 
2263         ASSERT(MUTEX_HELD(&qp->qp_lock));
2264 
2265         /*
2266          * Grab the temporary QPC entry from QP software state
2267          */
2268         qpc = &qp->qpc;
2269 
2270         /*
2271          * Fill in the common fields in the QPC
2272          */
2273 
2274         /*
2275          * Now fill in the QPC fields which are specific to transport type
2276          */
2277         if (qp->qp_type == IBT_UD_RQP) {
2278                 ud = &info_p->qp_transport.ud;
2279 
2280                 /*
2281                  * If we are attempting to modify the port for this QP, then
2282                  * check for valid port number and fill it in.  Also set the
2283                  * appropriate flag in the "opmask" parameter.
2284                  */
2285                 if (flags & IBT_CEP_SET_PORT) {
2286                         portnum = ud->ud_port;
2287                         if (hermon_portnum_is_valid(state, portnum)) {
2288                                 qp->qp_portnum = portnum - 1;
2289                                 qpc->pri_addr_path.sched_q =
2290                                     HERMON_QP_SCHEDQ_GET(portnum - 1,
2291                                     0, qp->qp_is_special);
2292                         } else {
2293                                 return (IBT_HCA_PORT_INVALID);
2294                         }
2295                         opmask |= HERMON_CMD_OP_PRIM_PORT;
2296                 }
2297 
2298                 /*
2299                  * If we are attempting to modify the PKey index for this QP,
2300                  * then check for valid PKey index and fill it in.  Also set
2301                  * the appropriate flag in the "opmask" parameter.
2302                  */
2303                 if (flags & IBT_CEP_SET_PKEY_IX) {
2304                         pkeyindx = ud->ud_pkey_ix;
2305                         if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
2306                                 qpc->pri_addr_path.pkey_indx = pkeyindx;
2307                                 opmask |= HERMON_CMD_OP_PKEYINDX;
2308                                 qp->qp_pkeyindx = pkeyindx;
2309                         } else {
2310                                 return (IBT_PKEY_IX_ILLEGAL);
2311                         }
2312                 }
2313 
2314                 /*
2315                  * If we are attempting to modify the QKey for this QP, then
2316                  * fill it in and set the appropriate flag in the "opmask"
2317                  * parameter.
2318                  */
2319                 if (flags & IBT_CEP_SET_QKEY) {
2320                         qpc->qkey = ud->ud_qkey;
2321                         opmask |= HERMON_CMD_OP_QKEY;
2322                 }
2323 
2324         } else if (qp->qp_serv_type == HERMON_QP_RC) {
2325                 rc = &info_p->qp_transport.rc;
2326 
2327                 /*
2328                  * Check if any of the flags indicate a change in the RDMA
2329                  * (recv) enable/disable flags and set the appropriate flag in
2330                  * the "opmask" parameter
2331                  */
2332                 opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
2333 
2334                 qpc->retry_cnt = rc->rc_retry_cnt;
2335 
2336                 /*
2337                  * If we are attempting to modify the path migration state for
2338                  * this QP, then check for valid state and fill it in.  Also
2339                  * set the appropriate flag in the "opmask" parameter.
2340                  */
2341                 if (flags & IBT_CEP_SET_MIG) {
2342                         if (rc->rc_mig_state == IBT_STATE_MIGRATED) {
2343                                 qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
2344                         } else if (rc->rc_mig_state == IBT_STATE_REARMED) {
2345                                 qpc->pm_state = HERMON_QP_PMSTATE_REARM;
2346                         } else {
2347                                 return (IBT_QP_APM_STATE_INVALID);
2348                         }
2349                         opmask |= HERMON_CMD_OP_PM_STATE;
2350                 }
2351 
2352                 /*
2353                  * Check for optional alternate path and fill in the
2354                  * appropriate QPC fields if one is specified
2355                  */
2356                 if (flags & IBT_CEP_SET_ALT_PATH) {
2357                         qpc_path = &qpc->alt_addr_path;
2358                         adds_vect = &rc->rc_alt_path.cep_adds_vect;
2359 
2360                         /* Set the common alternate address path fields */
2361                         status = hermon_set_addr_path(state, adds_vect,
2362                             qpc_path, HERMON_ADDRPATH_QP);
2363                         if (status != DDI_SUCCESS) {
2364                                 return (status);
2365                         }
2366                         qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
2367                         /*
2368                          * Check for valid alternate path port number and fill
2369                          * it in
2370                          */
2371                         portnum = rc->rc_alt_path.cep_hca_port_num;
2372                         if (hermon_portnum_is_valid(state, portnum)) {
2373                                 qp->qp_portnum_alt = portnum - 1;
2374                                 qpc->alt_addr_path.sched_q =
2375                                     HERMON_QP_SCHEDQ_GET(portnum - 1,
2376                                     adds_vect->av_srvl, qp->qp_is_special);
2377                         } else {
2378                                 return (IBT_HCA_PORT_INVALID);
2379                         }
2380 
2381                         /*
2382                          * Check for valid alternate path PKey index and fill
2383                          * it in
2384                          */
2385                         pkeyindx = rc->rc_alt_path.cep_pkey_ix;
2386                         if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
2387                                 qpc->alt_addr_path.pkey_indx = pkeyindx;
2388                         } else {
2389                                 return (IBT_PKEY_IX_ILLEGAL);
2390                         }
2391                         opmask |= HERMON_CMD_OP_ALT_PATH;
2392                 }
2393 
2394                 /*
2395                  * If we are attempting to modify the number of "outgoing
2396                  * RDMA resources" for this QP, then check for valid value and
2397                  * fill it in.  Also set the appropriate flag in the "opmask"
2398                  * parameter.
2399                  */
2400                 if (flags & IBT_CEP_SET_RDMARA_OUT) {
2401                         if (hermon_qp_validate_init_depth(state, rc,
2402                             &sra_max) != DDI_SUCCESS) {
2403                                 return (IBT_INVALID_PARAM);
2404                         }
2405                         qpc->sra_max = sra_max;
2406                         opmask |= HERMON_CMD_OP_SRA_SET;
2407                 }
2408 
2409                 /*
2410                  * If we are attempting to modify the number of "incoming
2411                  * RDMA resources" for this QP, then check for valid value and
2412                  * update the "rra_max" and "ra_buf_index" fields in the QPC to
2413                  * point to the pre-allocated RDB resources (in DDR).  Also set
2414                  * the appropriate flag in the "opmask" parameter.
2415                  */
2416                 if (flags & IBT_CEP_SET_RDMARA_IN) {
2417                         if (hermon_qp_validate_resp_rsrc(state, rc,
2418                             &rra_max) != DDI_SUCCESS) {
2419                                 return (IBT_INVALID_PARAM);
2420                         }
2421                         qpc->rra_max = rra_max;
2422                         opmask |= HERMON_CMD_OP_RRA_SET;
2423                 }
2424 
2425 
2426                 /*
2427                  * If we are attempting to modify the "Minimum RNR NAK" value
2428                  * for this QP, then fill it in and set the appropriate flag
2429                  * in the "opmask" parameter.
2430                  */
2431                 if (flags & IBT_CEP_SET_MIN_RNR_NAK) {
2432                         qpc->min_rnr_nak = rc->rc_min_rnr_nak;
2433                         opmask |= HERMON_CMD_OP_MINRNRNAK;
2434                 }
2435 
2436         } else if (qp->qp_serv_type == HERMON_QP_UC) {
2437                 uc = &info_p->qp_transport.uc;
2438 
2439                 /*
2440                  * Check if any of the flags indicate a change in the RDMA
2441                  * Write (recv) enable/disable and set the appropriate flag
2442                  * in the "opmask" parameter. Note: RDMA Read and Atomic are
2443                  * not valid for UC transport.
2444                  */
2445                 if (flags & IBT_CEP_SET_RDMA_W) {
2446                         qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
2447                         opmask |= HERMON_CMD_OP_RWE;
2448                 }
2449 
2450                 /*
2451                  * If we are attempting to modify the path migration state for
2452                  * this QP, then check for valid state and fill it in.  Also
2453                  * set the appropriate flag in the "opmask" parameter.
2454                  */
2455                 if (flags & IBT_CEP_SET_MIG) {
2456                         if (uc->uc_mig_state == IBT_STATE_MIGRATED) {
2457                                 qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
2458                         } else if (uc->uc_mig_state == IBT_STATE_REARMED) {
2459                                 qpc->pm_state = HERMON_QP_PMSTATE_REARM;
2460                         } else {
2461                                 return (IBT_QP_APM_STATE_INVALID);
2462                         }
2463                         opmask |= HERMON_CMD_OP_PM_STATE;
2464                 }
2465 
2466                 /*
2467                  * Check for optional alternate path and fill in the
2468                  * appropriate QPC fields if one is specified
2469                  */
2470                 if (flags & IBT_CEP_SET_ALT_PATH) {
2471                         qpc_path = &qpc->alt_addr_path;
2472                         adds_vect = &uc->uc_alt_path.cep_adds_vect;
2473 
2474                         /* Set the common alternate address path fields */
2475                         status = hermon_set_addr_path(state, adds_vect,
2476                             qpc_path, HERMON_ADDRPATH_QP);
2477                         if (status != DDI_SUCCESS) {
2478                                 return (status);
2479                         }
2480 
2481                         /*
2482                          * Check for valid alternate path port number and fill
2483                          * it in
2484                          */
2485                         portnum = uc->uc_alt_path.cep_hca_port_num;
2486                         if (hermon_portnum_is_valid(state, portnum)) {
2487                                 qp->qp_portnum_alt = portnum - 1;
2488                                 qpc->alt_addr_path.sched_q =
2489                                     HERMON_QP_SCHEDQ_GET(portnum - 1,
2490                                     adds_vect->av_srvl, qp->qp_is_special);
2491                         } else {
2492                                 return (IBT_HCA_PORT_INVALID);
2493                         }
2494 
2495                         /*
2496                          * Check for valid alternate path PKey index and fill
2497                          * it in
2498                          */
2499                         pkeyindx = uc->uc_alt_path.cep_pkey_ix;
2500                         if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
2501                                 qpc->alt_addr_path.pkey_indx = pkeyindx;
2502                         } else {
2503                                 return (IBT_PKEY_IX_ILLEGAL);
2504                         }
2505                         opmask |= HERMON_CMD_OP_ALT_PATH;
2506                 }
2507         } else {
2508                 /*
2509                  * Invalid QP transport type. If we got here then it's a
2510                  * warning of a probably serious problem.  So print a message
2511                  * and return failure
2512                  */
2513                 HERMON_WARNING(state, "unknown QP transport type in sqd2rts");
2514                 return (ibc_get_ci_failure(0));
2515         }
2516 
2517         /*
2518          * Post the SQD2RTS_QP command to the Hermon firmware
2519          *
2520          * We do a HERMON_NOSLEEP here because we are still holding the
2521          * "qp_lock".  If we got raised to interrupt level by priority
2522          * inversion, we do not want to block in this routine waiting for
2523          * success.
2524          */
2525         status = hermon_cmn_qp_cmd_post(state, SQD2RTS_QP, qpc, qp->qp_qpnum,
2526             opmask, HERMON_CMD_NOSLEEP_SPIN);
2527         if (status != HERMON_CMD_SUCCESS) {
2528                 if (status != HERMON_CMD_BAD_QP_STATE) {
2529                         cmn_err(CE_NOTE, "hermon%d: SQD2RTS_QP command failed: "
2530                             "%08x\n", state->hs_instance, status);
2531                         if (status == HERMON_CMD_INVALID_STATUS) {
2532                                 hermon_fm_ereport(state, HCA_SYS_ERR,
2533                                     HCA_ERR_SRV_LOST);
2534                         }
2535                         return (ibc_get_ci_failure(0));
2536                 } else {
2537                         return (IBT_QP_STATE_INVALID);
2538                 }
2539         }
2540 
2541         return (DDI_SUCCESS);
2542 }
2543 
2544 
2545 /*
2546  * hermon_qp_sqd2sqd()
2547  *    Context: Can be called from interrupt or base context.
2548  */
2549 static int
2550 hermon_qp_sqd2sqd(hermon_state_t *state, hermon_qphdl_t qp,
2551     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
2552 {
2553         hermon_hw_qpc_t         *qpc;
2554         ibt_qp_rc_attr_t        *rc;
2555         ibt_qp_ud_attr_t        *ud;
2556         ibt_qp_uc_attr_t        *uc;
2557         hermon_hw_addr_path_t   *qpc_path;
2558         ibt_adds_vect_t         *adds_vect;
2559         uint_t                  portnum, pkeyindx;
2560         uint_t                  rra_max, sra_max;
2561         uint32_t                opmask = 0;
2562         int                     status;
2563 
2564         ASSERT(MUTEX_HELD(&qp->qp_lock));
2565 
2566         /*
2567          * Grab the temporary QPC entry from QP software state
2568          */
2569         qpc = &qp->qpc;
2570 
2571         /*
2572          * Fill in the common fields in the QPC
2573          */
2574 
2575         /*
2576          * Now fill in the QPC fields which are specific to transport type
2577          */
2578         if (qp->qp_type == IBT_UD_RQP) {
2579                 ud = &info_p->qp_transport.ud;
2580 
2581                 /*
2582                  * If we are attempting to modify the port for this QP, then
2583                  * check for valid port number and fill it in.  Also set the
2584                  * appropriate flag in the "opmask" parameter.
2585                  */
2586                 if (flags & IBT_CEP_SET_PORT) {
2587                         portnum = ud->ud_port;
2588                         if (hermon_portnum_is_valid(state, portnum)) {
2589                                 qp->qp_portnum = portnum - 1;
2590                                 qpc->pri_addr_path.sched_q =
2591                                     HERMON_QP_SCHEDQ_GET(portnum - 1,
2592                                     0, qp->qp_is_special);
2593                         } else {
2594                                 return (IBT_HCA_PORT_INVALID);
2595                         }
2596                         opmask |= HERMON_CMD_OP_SCHEDQUEUE;
2597                 }
2598 
2599                 /*
2600                  * If we are attempting to modify the PKey index for this QP,
2601                  * then check for valid PKey index and fill it in.  Also set
2602                  * the appropriate flag in the "opmask" parameter.
2603                  */
2604                 if (flags & IBT_CEP_SET_PKEY_IX) {
2605                         pkeyindx = ud->ud_pkey_ix;
2606                         if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
2607                                 qpc->pri_addr_path.pkey_indx = pkeyindx;
2608                                 opmask |= HERMON_CMD_OP_PKEYINDX;
2609                                 qp->qp_pkeyindx = pkeyindx;
2610                         } else {
2611                                 return (IBT_PKEY_IX_ILLEGAL);
2612                         }
2613                 }
2614 
2615                 /*
2616                  * If we are attempting to modify the QKey for this QP, then
2617                  * fill it in and set the appropriate flag in the "opmask"
2618                  * parameter.
2619                  */
2620                 if (flags & IBT_CEP_SET_QKEY) {
2621                         qpc->qkey = ud->ud_qkey;
2622                         opmask |= HERMON_CMD_OP_QKEY;
2623                 }
2624 
2625         } else if (qp->qp_serv_type == HERMON_QP_RC) {
2626                 rc = &info_p->qp_transport.rc;
2627 
2628                 /*
2629                  * Check if any of the flags indicate a change in the RDMA
2630                  * (recv) enable/disable flags and set the appropriate flag in
2631                  * the "opmask" parameter
2632                  */
2633                 opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
2634 
2635                 /*
2636                  * Check for optional primary path and fill in the
2637                  * appropriate QPC fields if one is specified
2638                  */
2639                 if (flags & IBT_CEP_SET_ADDS_VECT) {
2640                         qpc_path = &qpc->pri_addr_path;
2641                         adds_vect = &rc->rc_path.cep_adds_vect;
2642 
2643                         /* Set the common primary address path fields */
2644                         status = hermon_set_addr_path(state, adds_vect,
2645                             qpc_path, HERMON_ADDRPATH_QP);
2646                         if (status != DDI_SUCCESS) {
2647                                 return (status);
2648                         }
2649                         qpc->rnr_retry = rc->rc_rnr_retry_cnt;
2650                         qpc_path->ack_timeout = rc->rc_path.cep_timeout;
2651                         qpc->retry_cnt = rc->rc_retry_cnt;
2652 
2653                         portnum = qp->qp_portnum + 1;
2654                         if (hermon_portnum_is_valid(state, portnum)) {
2655                                 qpc->pri_addr_path.sched_q  =
2656                                     HERMON_QP_SCHEDQ_GET(qp->qp_portnum,
2657                                     adds_vect->av_srvl, qp->qp_is_special);
2658                         } else {
2659                                 return (IBT_HCA_PORT_INVALID);
2660                         }
2661 
2662                         /*
2663                          * MTU changes as part of sqd2sqd are not allowed.
2664                          * Simply keep the same MTU value here, stored in the
2665                          * qphdl from init2rtr time.
2666                          */
2667                         qpc->mtu = qp->qp_save_mtu;
2668 
2669                         opmask |= (HERMON_CMD_OP_PRIM_PATH |
2670                             HERMON_CMD_OP_RETRYCNT | HERMON_CMD_OP_ACKTIMEOUT |
2671                             HERMON_CMD_OP_PRIM_RNRRETRY);
2672                 }
2673 
2674                 /*
2675                  * If we are attempting to modify the path migration state for
2676                  * this QP, then check for valid state and fill it in.  Also
2677                  * set the appropriate flag in the "opmask" parameter.
2678                  */
2679                 if (flags & IBT_CEP_SET_MIG) {
2680                         if (rc->rc_mig_state == IBT_STATE_MIGRATED) {
2681                                 qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
2682                         } else if (rc->rc_mig_state == IBT_STATE_REARMED) {
2683                                 qpc->pm_state = HERMON_QP_PMSTATE_REARM;
2684                         } else {
2685                                 return (IBT_QP_APM_STATE_INVALID);
2686                         }
2687                         opmask |= HERMON_CMD_OP_PM_STATE;
2688                 }
2689 
2690                 /*
2691                  * If we are attempting to modify the PKey index for this QP,
2692                  * then check for valid PKey index and fill it in.  Also set
2693                  * the appropriate flag in the "opmask" parameter.
2694                  */
2695                 if (flags & IBT_CEP_SET_PKEY_IX) {
2696                         pkeyindx = rc->rc_path.cep_pkey_ix;
2697                         if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
2698                                 qpc->pri_addr_path.pkey_indx = pkeyindx;
2699                                 opmask |= HERMON_CMD_OP_PKEYINDX;
2700                         } else {
2701                                 return (IBT_PKEY_IX_ILLEGAL);
2702                         }
2703                 }
2704 
2705                 /*
2706                  * If we are attempting to modify the port for this QP, then
2707                  * check for valid port number and fill it in.  Also set the
2708                  * appropriate flag in the "opmask" parameter.
2709                  */
2710                 if (flags & IBT_CEP_SET_PORT) {
2711                         portnum = rc->rc_path.cep_hca_port_num;
2712                         if (hermon_portnum_is_valid(state, portnum)) {
2713                                 qp->qp_portnum = portnum - 1;
2714                                 qpc->pri_addr_path.sched_q =
2715                                     HERMON_QP_SCHEDQ_GET(portnum - 1,
2716                                     adds_vect->av_srvl, qp->qp_is_special);
2717                         } else {
2718                                 return (IBT_HCA_PORT_INVALID);
2719                         }
2720                         opmask |= HERMON_CMD_OP_SCHEDQUEUE;
2721                 }
2722 
2723                 /*
2724                  * Check for optional alternate path and fill in the
2725                  * appropriate QPC fields if one is specified
2726                  */
2727                 if (flags & IBT_CEP_SET_ALT_PATH) {
2728                         qpc_path = &qpc->alt_addr_path;
2729                         adds_vect = &rc->rc_alt_path.cep_adds_vect;
2730 
2731                         /* Set the common alternate address path fields */
2732                         status = hermon_set_addr_path(state, adds_vect,
2733                             qpc_path, HERMON_ADDRPATH_QP);
2734                         if (status != DDI_SUCCESS) {
2735                                 return (status);
2736                         }
2737                         qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
2738 
2739                         /*
2740                          * Check for valid alternate path port number and fill
2741                          * it in
2742                          */
2743                         portnum = rc->rc_alt_path.cep_hca_port_num;
2744                         if (hermon_portnum_is_valid(state, portnum)) {
2745                                 qp->qp_portnum_alt = portnum - 1;
2746                                 qpc->alt_addr_path.sched_q =
2747                                     HERMON_QP_SCHEDQ_GET(portnum - 1,
2748                                     adds_vect->av_srvl, qp->qp_is_special);
2749                         } else {
2750                                 return (IBT_HCA_PORT_INVALID);
2751                         }
2752 
2753                         /*
2754                          * Check for valid alternate path PKey index and fill
2755                          * it in
2756                          */
2757                         pkeyindx = rc->rc_alt_path.cep_pkey_ix;
2758                         if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
2759                                 qpc->alt_addr_path.pkey_indx = pkeyindx;
2760                         } else {
2761                                 return (IBT_PKEY_IX_ILLEGAL);
2762                         }
2763                         opmask |= HERMON_CMD_OP_ALT_PATH;
2764                 }
2765 
2766                 /*
2767                  * If we are attempting to modify the number of "outgoing
2768                  * RDMA resources" for this QP, then check for valid value and
2769                  * fill it in.  Also set the appropriate flag in the "opmask"
2770                  * parameter.
2771                  */
2772                 if (flags & IBT_CEP_SET_RDMARA_OUT) {
2773                         if (hermon_qp_validate_init_depth(state, rc,
2774                             &sra_max) != DDI_SUCCESS) {
2775                                 return (IBT_INVALID_PARAM);
2776                         }
2777                         qpc->sra_max = sra_max;
2778                         opmask |= HERMON_CMD_OP_SRA_SET;
2779                 }
2780 
2781                 /*
2782                  * If we are attempting to modify the number of "incoming
2783                  * RDMA resources" for this QP, then check for valid value and
2784                  * update the "rra_max" and "ra_buf_index" fields in the QPC to
2785                  * point to the pre-allocated RDB resources (in DDR).  Also set
2786                  * the appropriate flag in the "opmask" parameter.
2787                  */
2788                 if (flags & IBT_CEP_SET_RDMARA_IN) {
2789                         if (hermon_qp_validate_resp_rsrc(state, rc,
2790                             &rra_max) != DDI_SUCCESS) {
2791                                 return (IBT_INVALID_PARAM);
2792                         }
2793                         qpc->rra_max = rra_max;
2794                         opmask |= HERMON_CMD_OP_RRA_SET;
2795                 }
2796 
2797                 /*
2798                  * If we are attempting to modify the "Local Ack Timeout" value
2799                  * for this QP, then fill it in and set the appropriate flag in
2800                  * the "opmask" parameter.
2801                  */
2802                 if (flags & IBT_CEP_SET_TIMEOUT) {
2803                         qpc_path = &qpc->pri_addr_path;
2804                         qpc_path->ack_timeout = rc->rc_path.cep_timeout;
2805                         opmask |= HERMON_CMD_OP_ACKTIMEOUT;
2806                 }
2807 
2808                 /*
2809                  * If we are attempting to modify the "Retry Count" for this QP,
2810                  * then fill it in and set the appropriate flag in the "opmask"
2811                  * parameter.
2812                  */
2813                 if (flags & IBT_CEP_SET_RETRY) {
2814                         qpc->retry_cnt = rc->rc_retry_cnt;
2815                         opmask |= HERMON_CMD_OP_PRIM_RNRRETRY;
2816                 }
2817 
2818                 /*
2819                  * If we are attempting to modify the "RNR Retry Count" for this
2820                  * QP, then fill it in and set the appropriate flag in the
2821                  * "opmask" parameter.
2822                  */
2823                 if (flags & IBT_CEP_SET_RNR_NAK_RETRY) {
2824                         qpc_path = &qpc->pri_addr_path;
2825                         qpc->rnr_retry = rc->rc_rnr_retry_cnt;
2826                         opmask |= HERMON_CMD_OP_RETRYCNT;
2827                 }
2828 
2829                 /*
2830                  * If we are attempting to modify the "Minimum RNR NAK" value
2831                  * for this QP, then fill it in and set the appropriate flag
2832                  * in the "opmask" parameter.
2833                  */
2834                 if (flags & IBT_CEP_SET_MIN_RNR_NAK) {
2835                         qpc->min_rnr_nak = rc->rc_min_rnr_nak;
2836                         opmask |= HERMON_CMD_OP_MINRNRNAK;
2837                 }
2838 
2839         } else if (qp->qp_serv_type == HERMON_QP_UC) {
2840                 uc = &info_p->qp_transport.uc;
2841 
2842                 /*
2843                  * Check if any of the flags indicate a change in the RDMA
2844                  * Write (recv) enable/disable and set the appropriate flag
2845                  * in the "opmask" parameter. Note: RDMA Read and Atomic are
2846                  * not valid for UC transport.
2847                  */
2848                 if (flags & IBT_CEP_SET_RDMA_W) {
2849                         qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
2850                         opmask |= HERMON_CMD_OP_RWE;
2851                 }
2852 
2853                 /*
2854                  * Check for optional primary path and fill in the
2855                  * appropriate QPC fields if one is specified
2856                  */
2857                 if (flags & IBT_CEP_SET_ADDS_VECT) {
2858                         qpc_path = &qpc->pri_addr_path;
2859                         adds_vect = &uc->uc_path.cep_adds_vect;
2860 
2861                         /* Set the common primary address path fields */
2862                         status = hermon_set_addr_path(state, adds_vect,
2863                             qpc_path, HERMON_ADDRPATH_QP);
2864                         if (status != DDI_SUCCESS) {
2865                                 return (status);
2866                         }
2867                         portnum = qp->qp_portnum + 1;
2868                         if (hermon_portnum_is_valid(state, portnum)) {
2869                                 qpc->pri_addr_path.sched_q =
2870                                     HERMON_QP_SCHEDQ_GET(qp->qp_portnum,
2871                                     adds_vect->av_srvl, qp->qp_is_special);
2872                         } else {
2873                                 return (IBT_HCA_PORT_INVALID);
2874                         }
2875 
2876                         /*
2877                          * MTU changes as part of sqd2sqd are not allowed.
2878                          * Simply keep the same MTU value here, stored in the
2879                          * qphdl from init2rtr time.
2880                          */
2881                         qpc->mtu = qp->qp_save_mtu;
2882 
2883                         opmask |= HERMON_CMD_OP_PRIM_PATH;
2884                 }
2885 
2886                 /*
2887                  * If we are attempting to modify the path migration state for
2888                  * this QP, then check for valid state and fill it in.  Also
2889                  * set the appropriate flag in the "opmask" parameter.
2890                  */
2891                 if (flags & IBT_CEP_SET_MIG) {
2892                         if (uc->uc_mig_state == IBT_STATE_MIGRATED) {
2893                                 qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
2894                         } else if (uc->uc_mig_state == IBT_STATE_REARMED) {
2895                                 qpc->pm_state = HERMON_QP_PMSTATE_REARM;
2896                         } else {
2897                                 return (IBT_QP_APM_STATE_INVALID);
2898                         }
2899                         opmask |= HERMON_CMD_OP_PM_STATE;
2900                 }
2901 
2902                 /*
2903                  * If we are attempting to modify the PKey index for this QP,
2904                  * then check for valid PKey index and fill it in.  Also set
2905                  * the appropriate flag in the "opmask" parameter.
2906                  */
2907                 if (flags & IBT_CEP_SET_PKEY_IX) {
2908                         pkeyindx = uc->uc_path.cep_pkey_ix;
2909                         if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
2910                                 qpc->pri_addr_path.pkey_indx = pkeyindx;
2911                                 opmask |= HERMON_CMD_OP_PKEYINDX;
2912                         } else {
2913                                 return (IBT_PKEY_IX_ILLEGAL);
2914                         }
2915                 }
2916 
2917                 /*
2918                  * Check for optional alternate path and fill in the
2919                  * appropriate QPC fields if one is specified
2920                  */
2921                 if (flags & IBT_CEP_SET_ALT_PATH) {
2922                         qpc_path = &qpc->alt_addr_path;
2923                         adds_vect = &uc->uc_alt_path.cep_adds_vect;
2924 
2925                         /* Set the common alternate address path fields */
2926                         status = hermon_set_addr_path(state, adds_vect,
2927                             qpc_path, HERMON_ADDRPATH_QP);
2928                         if (status != DDI_SUCCESS) {
2929                                 return (status);
2930                         }
2931 
2932                         /*
2933                          * Check for valid alternate path port number and fill
2934                          * it in
2935                          */
2936                         portnum = uc->uc_alt_path.cep_hca_port_num;
2937                         if (hermon_portnum_is_valid(state, portnum)) {
2938                                 qp->qp_portnum_alt = portnum - 1;
2939                                 qpc->alt_addr_path.sched_q =
2940                                     HERMON_QP_SCHEDQ_GET(portnum - 1,
2941                                     adds_vect->av_srvl, qp->qp_is_special);
2942                         } else {
2943                                 return (IBT_HCA_PORT_INVALID);
2944                         }
2945 
2946                         /*
2947                          * Check for valid alternate path PKey index and fill
2948                          * it in
2949                          */
2950                         pkeyindx = uc->uc_alt_path.cep_pkey_ix;
2951                         if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
2952                                 qpc->alt_addr_path.pkey_indx = pkeyindx;
2953                         } else {
2954                                 return (IBT_PKEY_IX_ILLEGAL);
2955                         }
2956                         opmask |= HERMON_CMD_OP_ALT_PATH;
2957                 }
2958         } else {
2959                 /*
2960                  * Invalid QP transport type. If we got here then it's a
2961                  * warning of a probably serious problem.  So print a message
2962                  * and return failure
2963                  */
2964                 HERMON_WARNING(state, "unknown QP transport type in sqd2sqd");
2965                 return (ibc_get_ci_failure(0));
2966         }
2967 
2968         /*
2969          * Post the SQD2SQD_QP command to the Hermon firmware
2970          *
2971          * We do a HERMON_NOSLEEP here because we are still holding the
2972          * "qp_lock".  If we got raised to interrupt level by priority
2973          * inversion, we do not want to block in this routine waiting for
2974          * success.
2975          */
2976         status = hermon_cmn_qp_cmd_post(state, SQD2SQD_QP, qpc, qp->qp_qpnum,
2977             opmask, HERMON_CMD_NOSLEEP_SPIN);
2978         if (status != HERMON_CMD_SUCCESS) {
2979                 if (status != HERMON_CMD_BAD_QP_STATE) {
2980                         cmn_err(CE_NOTE, "hermon%d: SQD2SQD_QP command failed: "
2981                             "%08x\n", state->hs_instance, status);
2982                         if (status == HERMON_CMD_INVALID_STATUS) {
2983                                 hermon_fm_ereport(state, HCA_SYS_ERR,
2984                                     HCA_ERR_SRV_LOST);
2985                         }
2986                         return (ibc_get_ci_failure(0));
2987                 } else {
2988                         return (IBT_QP_STATE_INVALID);
2989                 }
2990         }
2991 
2992         return (DDI_SUCCESS);
2993 }
2994 
2995 
2996 /*
2997  * hermon_qp_sqerr2rts()
2998  *    Context: Can be called from interrupt or base context.
2999  */
3000 static int
3001 hermon_qp_sqerr2rts(hermon_state_t *state, hermon_qphdl_t qp,
3002     ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
3003 {
3004         hermon_hw_qpc_t         *qpc;
3005         ibt_qp_ud_attr_t        *ud;
3006         uint32_t                opmask = 0;
3007         int                     status;
3008 
3009         ASSERT(MUTEX_HELD(&qp->qp_lock));
3010 
3011         /*
3012          * Grab the temporary QPC entry from QP software state
3013          */
3014         qpc = &qp->qpc;
3015 
3016         /*
3017          * Since there are no common fields to be filled in for this command,
3018          * we begin with the QPC fields which are specific to transport type.
3019          */
3020         if (qp->qp_type == IBT_UD_RQP) {
3021                 ud = &info_p->qp_transport.ud;
3022 
3023                 /*
3024                  * If we are attempting to modify the QKey for this QP, then
3025                  * fill it in and set the appropriate flag in the "opmask"
3026                  * parameter.
3027                  */
3028                 if (flags & IBT_CEP_SET_QKEY) {
3029                         qpc->qkey = ud->ud_qkey;
3030                         opmask |= HERMON_CMD_OP_QKEY;
3031                 }
3032 
3033         } else if (qp->qp_serv_type == HERMON_QP_UC) {
3034 
3035                 /*
3036                  * Check if any of the flags indicate a change in the RDMA
3037                  * Write (recv) enable/disable and set the appropriate flag
3038                  * in the "opmask" parameter. Note: RDMA Read and Atomic are
3039                  * not valid for UC transport.
3040                  */
3041                 if (flags & IBT_CEP_SET_RDMA_W) {
3042                         qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
3043                         opmask |= HERMON_CMD_OP_RWE;
3044                 }
3045         } else {
3046                 /*
3047                  * Invalid QP transport type. If we got here then it's a
3048                  * warning of a probably serious problem.  So print a message
3049                  * and return failure
3050                  */
3051                 HERMON_WARNING(state, "unknown QP transport type in sqerr2rts");
3052                 return (ibc_get_ci_failure(0));
3053         }
3054 
3055         /*
3056          * Post the SQERR2RTS_QP command to the Hermon firmware
3057          *
3058          * We do a HERMON_NOSLEEP here because we are still holding the
3059          * "qp_lock".  If we got raised to interrupt level by priority
3060          * inversion, we do not want to block in this routine waiting for
3061          * success.
3062          */
3063         status = hermon_cmn_qp_cmd_post(state, SQERR2RTS_QP, qpc, qp->qp_qpnum,
3064             opmask, HERMON_CMD_NOSLEEP_SPIN);
3065         if (status != HERMON_CMD_SUCCESS) {
3066                 if (status != HERMON_CMD_BAD_QP_STATE) {
3067                         cmn_err(CE_NOTE, "hermon%d: SQERR2RTS_QP command "
3068                             "failed: %08x\n", state->hs_instance, status);
3069                         if (status == HERMON_CMD_INVALID_STATUS) {
3070                                 hermon_fm_ereport(state, HCA_SYS_ERR,
3071                                     HCA_ERR_SRV_LOST);
3072                         }
3073                         return (ibc_get_ci_failure(0));
3074                 } else {
3075                         return (IBT_QP_STATE_INVALID);
3076                 }
3077         }
3078 
3079         return (DDI_SUCCESS);
3080 }
3081 
3082 
3083 /*
3084  * hermon_qp_to_error()
3085  *    Context: Can be called from interrupt or base context.
3086  */
3087 static int
3088 hermon_qp_to_error(hermon_state_t *state, hermon_qphdl_t qp)
3089 {
3090         int     status;
3091 
3092         ASSERT(MUTEX_HELD(&qp->qp_lock));
3093 
3094         /*
3095          * Post the TOERR_QP command to the Hermon firmware
3096          *
3097          * We do a HERMON_NOSLEEP here because we are still holding the
3098          * "qp_lock".  If we got raised to interrupt level by priority
3099          * inversion, we do not want to block in this routine waiting for
3100          * success.
3101          */
3102         status = hermon_cmn_qp_cmd_post(state, TOERR_QP, NULL, qp->qp_qpnum,
3103             0, HERMON_CMD_NOSLEEP_SPIN);
3104         if (status != HERMON_CMD_SUCCESS) {
3105                 cmn_err(CE_NOTE, "hermon%d: TOERR_QP command failed: %08x\n",
3106                     state->hs_instance, status);
3107                 if (status == HERMON_CMD_INVALID_STATUS) {
3108                         hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
3109                 }
3110                 return (ibc_get_ci_failure(0));
3111         }
3112 
3113         return (DDI_SUCCESS);
3114 }
3115 
3116 
3117 /*
3118  * hermon_qp_to_reset()
3119  *    Context: Can be called from interrupt or base context.
3120  */
3121 int
3122 hermon_qp_to_reset(hermon_state_t *state, hermon_qphdl_t qp)
3123 {
3124         hermon_hw_qpc_t *qpc;
3125         int             status;
3126 
3127         ASSERT(MUTEX_HELD(&qp->qp_lock));
3128 
3129         /*
3130          * Grab the temporary QPC entry from QP software state
3131          */
3132         qpc = &qp->qpc;
3133 
3134         /*
3135          * Post the TORST_QP command to the Hermon firmware
3136          *
3137          * We do a HERMON_NOSLEEP here because we are still holding the
3138          * "qp_lock".  If we got raised to interrupt level by priority
3139          * inversion, we do not want to block in this routine waiting for
3140          * success.
3141          */
3142         status = hermon_cmn_qp_cmd_post(state, TORST_QP, qpc, qp->qp_qpnum,
3143             0, HERMON_CMD_NOSLEEP_SPIN);
3144         if (status != HERMON_CMD_SUCCESS) {
3145                 cmn_err(CE_NOTE, "hermon%d: TORST_QP command failed: %08x\n",
3146                     state->hs_instance, status);
3147                 if (status == HERMON_CMD_INVALID_STATUS) {
3148                         hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
3149                 }
3150                 return (ibc_get_ci_failure(0));
3151         }
3152         if (qp->qp_serv_type == HERMON_QP_FEXCH) {
3153                 status = hermon_fcoib_fexch_mkey_fini(state, qp->qp_pdhdl,
3154                     qp->qp_qpnum, HERMON_CMD_NOSLEEP_SPIN);
3155                 if (status != DDI_SUCCESS)
3156                         cmn_err(CE_NOTE, "hermon%d: fexch_mkey_fini failed "
3157                             "%08x\n", state->hs_instance, status);
3158         }
3159         return (DDI_SUCCESS);
3160 }
3161 
3162 
3163 /*
3164  * hermon_qp_reset2err()
3165  *    Context: Can be called from interrupt or base context.
3166  */
3167 static int
3168 hermon_qp_reset2err(hermon_state_t *state, hermon_qphdl_t qp)
3169 {
3170         hermon_hw_qpc_t *qpc;
3171         int             status;
3172         uint32_t        cqnmask;
3173 
3174         ASSERT(MUTEX_HELD(&qp->qp_lock));
3175 
3176         /*
3177          * In order to implement the transition from "Reset" directly to the
3178          * "Error" state, it is necessary to first give ownership of the QP
3179          * context to the Hermon hardware.  This is accomplished by
3180          * transitioning the QP to "Init" as an intermediate step and then,
3181          * immediately transitioning to "Error".
3182          *
3183          * When this function returns success, the QP context will be owned by
3184          * the Hermon hardware and will be in the "Error" state.
3185          */
3186 
3187         /*
3188          * Grab the temporary QPC entry from QP software state
3189          */
3190         qpc = &qp->qpc;
3191 
3192         /*
3193          * Fill in the common fields in the QPC
3194          */
3195         if (qp->qp_is_special) {
3196                 qpc->serv_type       = HERMON_QP_MLX;
3197         } else {
3198                 qpc->serv_type       = qp->qp_serv_type;
3199         }
3200         qpc->pm_state                = HERMON_QP_PMSTATE_MIGRATED;
3201         qpc->usr_page                = qp->qp_uarpg;
3202         /* dbr is now an address, not an index */
3203         qpc->dbr_addrh               = ((uint64_t)qp->qp_rq_pdbr >> 32);
3204         qpc->dbr_addrl               = ((uint64_t)qp->qp_rq_pdbr & 0xFFFFFFFC) >> 2;
3205         qpc->pd                      = qp->qp_pdhdl->pd_pdnum;
3206         /*
3207          * HERMON:
3208          * qpc->wqe_baseaddr is replaced by LKey from the cMPT, and
3209          * page_offset, mtt_base_addr_h/l, and log2_page_size will
3210          * be used to map the WQE buffer
3211          * NOTE that the cMPT is created implicitly when the QP is
3212          * transitioned from reset to init
3213          */
3214         qpc->log2_pgsz               = qp->qp_mrhdl->mr_log2_pgsz;
3215         qpc->mtt_base_addrh  = (qp->qp_mrhdl->mr_mttaddr) >> 32 & 0xFF;
3216         qpc->mtt_base_addrl  = (qp->qp_mrhdl->mr_mttaddr) >> 3 & 0xFFFFFFFF;
3217         cqnmask = (1 << state->hs_cfg_profile->cp_log_num_cq) - 1;
3218         qpc->cqn_snd         =
3219             (qp->qp_sq_cqhdl == NULL) ? 0 : qp->qp_sq_cqhdl->cq_cqnum & cqnmask;
3220         qpc->page_offs               = qp->qp_wqinfo.qa_pgoffs >> 6;
3221         qpc->cqn_rcv         =
3222             (qp->qp_rq_cqhdl == NULL) ? 0 : qp->qp_rq_cqhdl->cq_cqnum & cqnmask;
3223 
3224         qpc->sq_wqe_counter  = 0;
3225         qpc->rq_wqe_counter  = 0;
3226         qpc->log_sq_stride   = qp->qp_sq_log_wqesz - 4;
3227         qpc->log_rq_stride   = qp->qp_rq_log_wqesz - 4;
3228         qpc->log_sq_size     = highbit(qp->qp_sq_bufsz) - 1;
3229         qpc->log_rq_size     = highbit(qp->qp_rq_bufsz) - 1;
3230         qpc->srq_en          = (qp->qp_alloc_flags & IBT_QP_USES_SRQ) != 0;
3231         qpc->sq_no_prefetch  = qp->qp_no_prefetch;
3232 
3233         if (qp->qp_alloc_flags & IBT_QP_USES_SRQ) {
3234                 qpc->srq_number      = qp->qp_srqhdl->srq_srqnum;
3235         } else {
3236                 qpc->srq_number = 0;
3237         }
3238 
3239         qpc->fre             = 0; /* default disable fast registration WR */
3240         qpc->rlky            = 0; /* default disable reserved lkey */
3241 
3242         /*
3243          * Now fill in the QPC fields which are specific to transport type
3244          */
3245         if (qp->qp_type == IBT_UD_RQP) {
3246                 /* Set the UD parameters to an invalid default */
3247                 qpc->qkey = 0;
3248                 qpc->pri_addr_path.sched_q =
3249                     HERMON_QP_SCHEDQ_GET(0, 0, qp->qp_is_special);
3250                 qpc->pri_addr_path.pkey_indx = 0;
3251 
3252         } else if (qp->qp_serv_type == HERMON_QP_RC) {
3253                 /* Set the RC parameters to invalid default */
3254                 qpc->rre = 0;
3255                 qpc->rwe = 0;
3256                 qpc->rae = 0;
3257                 qpc->alt_addr_path.sched_q =
3258                     HERMON_QP_SCHEDQ_GET(0, 0, qp->qp_is_special);
3259                 qpc->pri_addr_path.pkey_indx = 0;
3260 
3261         } else if (qp->qp_serv_type == HERMON_QP_UC) {
3262                 /* Set the UC parameters to invalid default */
3263                 qpc->rwe = 0;
3264                 qpc->alt_addr_path.sched_q =
3265                     HERMON_QP_SCHEDQ_GET(0, 0, qp->qp_is_special);
3266                 qpc->pri_addr_path.pkey_indx = 0;
3267 
3268         } else {
3269                 /*
3270                  * Invalid QP transport type. If we got here then it's a
3271                  * warning of a probably serious problem.  So print a message
3272                  * and return failure
3273                  */
3274                 HERMON_WARNING(state, "unknown QP transport type in rst2err");
3275                 return (ibc_get_ci_failure(0));
3276         }
3277 
3278         /*
3279          * Post the RST2INIT_QP command to the Hermon firmware
3280          *
3281          * We do a HERMON_NOSLEEP here because we are still holding the
3282          * "qp_lock".  If we got raised to interrupt level by priority
3283          * inversion, we do not want to block in this routine waiting for
3284          * success.
3285          */
3286         status = hermon_cmn_qp_cmd_post(state, RST2INIT_QP, qpc, qp->qp_qpnum,
3287             0, HERMON_CMD_NOSLEEP_SPIN);
3288         if (status != HERMON_CMD_SUCCESS) {
3289                 cmn_err(CE_NOTE, "hermon%d: RST2INIT_QP command failed: %08x\n",
3290                     state->hs_instance, status);
3291                 if (status == HERMON_CMD_INVALID_STATUS) {
3292                         hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
3293                 }
3294                 return (ibc_get_ci_failure(0));
3295         }
3296 
3297         /*
3298          * Now post the TOERR_QP command to the Hermon firmware
3299          *
3300          * We still do a HERMON_NOSLEEP here because we are still holding the
3301          * "qp_lock".  Note:  If this fails (which it really never should),
3302          * it indicates a serious problem in the HW or SW.  We try to move
3303          * the QP back to the "Reset" state if possible and print a warning
3304          * message if not.  In any case, we return an error here.
3305          */
3306         status = hermon_cmn_qp_cmd_post(state, TOERR_QP, NULL, qp->qp_qpnum,
3307             0, HERMON_CMD_NOSLEEP_SPIN);
3308         if (status != HERMON_CMD_SUCCESS) {
3309                 cmn_err(CE_NOTE, "hermon%d: TOERR_QP command failed: %08x\n",
3310                     state->hs_instance, status);
3311                 if (status == HERMON_CMD_INVALID_STATUS) {
3312                         hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
3313                 }
3314                 if (hermon_qp_to_reset(state, qp) != DDI_SUCCESS) {
3315                         HERMON_WARNING(state, "failed to reset QP context");
3316                 }
3317                 return (ibc_get_ci_failure(0));
3318         }
3319 
3320         return (DDI_SUCCESS);
3321 }
3322 
3323 
3324 /*
3325  * hermon_check_rdma_enable_flags()
3326  *    Context: Can be called from interrupt or base context.
3327  */
3328 static uint_t
3329 hermon_check_rdma_enable_flags(ibt_cep_modify_flags_t flags,
3330     ibt_qp_info_t *info_p, hermon_hw_qpc_t *qpc)
3331 {
3332         uint_t  opmask = 0;
3333 
3334         if (flags & IBT_CEP_SET_RDMA_R) {
3335                 qpc->rre = (info_p->qp_flags & IBT_CEP_RDMA_RD) ? 1 : 0;
3336                 opmask |= HERMON_CMD_OP_RRE;
3337         }
3338 
3339         if (flags & IBT_CEP_SET_RDMA_W) {
3340                 qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
3341                 opmask |= HERMON_CMD_OP_RWE;
3342         }
3343 
3344         if (flags & IBT_CEP_SET_ATOMIC) {
3345                 qpc->rae = (info_p->qp_flags & IBT_CEP_ATOMIC) ? 1 : 0;
3346                 opmask |= HERMON_CMD_OP_RAE;
3347         }
3348 
3349         return (opmask);
3350 }
3351 
3352 /*
3353  * hermon_qp_validate_resp_rsrc()
3354  *    Context: Can be called from interrupt or base context.
3355  */
3356 static int
3357 hermon_qp_validate_resp_rsrc(hermon_state_t *state, ibt_qp_rc_attr_t *rc,
3358     uint_t *rra_max)
3359 {
3360         uint_t  rdma_ra_in;
3361 
3362         rdma_ra_in = rc->rc_rdma_ra_in;
3363 
3364         /*
3365          * Check if number of responder resources is too large.  Return an
3366          * error if it is
3367          */
3368         if (rdma_ra_in > state->hs_cfg_profile->cp_hca_max_rdma_in_qp) {
3369                 return (IBT_INVALID_PARAM);
3370         }
3371 
3372         /*
3373          * If the number of responder resources is too small, round it up.
3374          * Then find the next highest power-of-2
3375          */
3376         if (rdma_ra_in == 0) {
3377                 rdma_ra_in = 1;
3378         }
3379         if (ISP2(rdma_ra_in)) {
3380                 *rra_max = highbit(rdma_ra_in) - 1;
3381         } else {
3382                 *rra_max = highbit(rdma_ra_in);
3383         }
3384         return (DDI_SUCCESS);
3385 }
3386 
3387 
3388 /*
3389  * hermon_qp_validate_init_depth()
3390  *    Context: Can be called from interrupt or base context.
3391  */
3392 static int
3393 hermon_qp_validate_init_depth(hermon_state_t *state, ibt_qp_rc_attr_t *rc,
3394     uint_t *sra_max)
3395 {
3396         uint_t  rdma_ra_out;
3397 
3398         rdma_ra_out = rc->rc_rdma_ra_out;
3399 
3400         /*
3401          * Check if requested initiator depth is too large.  Return an error
3402          * if it is
3403          */
3404         if (rdma_ra_out > state->hs_cfg_profile->cp_hca_max_rdma_out_qp) {
3405                 return (IBT_INVALID_PARAM);
3406         }
3407 
3408         /*
3409          * If the requested initiator depth is too small, round it up.
3410          * Then find the next highest power-of-2
3411          */
3412         if (rdma_ra_out == 0) {
3413                 rdma_ra_out = 1;
3414         }
3415         if (ISP2(rdma_ra_out)) {
3416                 *sra_max = highbit(rdma_ra_out) - 1;
3417         } else {
3418                 *sra_max = highbit(rdma_ra_out);
3419         }
3420         return (DDI_SUCCESS);
3421 }
3422 
3423 
3424 /*
3425  * hermon_qp_validate_mtu()
3426  *    Context: Can be called from interrupt or base context.
3427  */
3428 static int
3429 hermon_qp_validate_mtu(hermon_state_t *state, uint_t mtu)
3430 {
3431         /*
3432          * Check for invalid MTU values (i.e. zero or any value larger than
3433          * the HCA's port maximum).
3434          */
3435         if ((mtu == 0) || (mtu > state->hs_cfg_profile->cp_max_mtu)) {
3436                 return (IBT_HCA_PORT_MTU_EXCEEDED);
3437         }
3438         return (DDI_SUCCESS);
3439 }