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