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_cmd.c
  28  *    Hermon Firmware Command Routines
  29  *
  30  *    Implements all the routines necessary for allocating, posting, and
  31  *    freeing commands for the Hermon firmware.  These routines manage a
  32  *    preallocated list of command mailboxes and provide interfaces to post
  33  *    each of the several dozen commands to the Hermon firmware.
  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 
  45 static int hermon_impl_mbox_alloc(hermon_state_t *state,
  46     hermon_mboxlist_t *mblist, hermon_mbox_t **mb, uint_t mbox_wait);
  47 static void hermon_impl_mbox_free(hermon_mboxlist_t *mblist,
  48     hermon_mbox_t **mb);
  49 static int hermon_impl_mboxlist_init(hermon_state_t *state,
  50     hermon_mboxlist_t *mblist, uint_t num_mbox, hermon_rsrc_type_t type);
  51 static void hermon_impl_mboxlist_fini(hermon_state_t *state,
  52     hermon_mboxlist_t *mblist);
  53 static int hermon_outstanding_cmd_alloc(hermon_state_t *state,
  54     hermon_cmd_t **cmd_ptr, uint_t cmd_wait);
  55 static void hermon_outstanding_cmd_free(hermon_state_t *state,
  56     hermon_cmd_t **cmd_ptr);
  57 static int hermon_write_hcr(hermon_state_t *state, hermon_cmd_post_t *cmdpost,
  58     uint16_t token, int *hwerr);
  59 static void hermon_mbox_sync(hermon_mbox_t *mbox, uint_t offset,
  60     uint_t length, uint_t flag);
  61 static void hermon_cmd_check_status(hermon_state_t *state, int status);
  62 
  63 /*
  64  * hermon_cmd_post()
  65  *    Context: Can be called from interrupt or base context.
  66  *
  67  *    The "cp_flags" field in cmdpost
  68  *    is used to determine whether to wait for an available
  69  *    outstanding command (if necessary) or to return error.
  70  */
  71 int
  72 hermon_cmd_post(hermon_state_t *state, hermon_cmd_post_t *cmdpost)
  73 {
  74         hermon_cmd_t    *cmdptr;
  75         int             status, retry_cnt, retry_cnt2, hw_err;
  76         uint16_t        token;
  77 
  78         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdpost))
  79 
  80         /* Determine if we are going to spin until completion */
  81         if (cmdpost->cp_flags == HERMON_CMD_NOSLEEP_SPIN) {
  82 
  83                 /* Write the command to the HCR */
  84                 retry_cnt = HCA_PIO_RETRY_CNT;
  85                 do {
  86                         status = hermon_write_hcr(state, cmdpost, 0, &hw_err);
  87                 } while (status == HERMON_CMD_INTERNAL_ERR && retry_cnt-- > 0);
  88 
  89                 /* Check if there is an error status in hermon_write_hcr() */
  90                 if (status != HERMON_CMD_SUCCESS) {
  91                         /*
  92                          * If there is a HW error, call hermon_cmd_retry_ok()
  93                          * to check the side-effect of the operation retry.
  94                          */
  95                         if ((retry_cnt == HCA_PIO_RETRY_CNT &&
  96                             hw_err == HCA_PIO_OK) ||
  97                             !hermon_cmd_retry_ok(cmdpost, status)) {
  98                                 hermon_cmd_check_status(state, status);
  99                                 return (status);
 100                         }
 101                 /* Check if there is a transient internal error */
 102                 } else if (retry_cnt != HCA_PIO_RETRY_CNT) {
 103                         hermon_fm_ereport(state, HCA_IBA_ERR,
 104                             HCA_ERR_TRANSIENT);
 105                 }
 106 
 107         } else {  /* "HERMON_CMD_SLEEP_NOSPIN" */
 108                 ASSERT(HERMON_SLEEPFLAG_FOR_CONTEXT() != HERMON_NOSLEEP);
 109 
 110                 /* NOTE: Expect threads to be waiting in here */
 111                 status = hermon_outstanding_cmd_alloc(state, &cmdptr,
 112                     cmdpost->cp_flags);
 113                 if (status != HERMON_CMD_SUCCESS) {
 114                         return (status);
 115                 }
 116                 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdptr))
 117 
 118                 retry_cnt = HCA_PIO_RETRY_CNT;
 119 retry:
 120                 /*
 121                  * Set status to "HERMON_CMD_INVALID_STATUS".  It is
 122                  * appropriate to do this here without the "cmd_comp_lock"
 123                  * because this register is overloaded.  Later it will be
 124                  * used to indicate - through a change from this invalid
 125                  * value to some other value - that the condition variable
 126                  * has been signaled.  Once it has, status will then contain
 127                  * the _real_ completion status
 128                  */
 129                 cmdptr->cmd_status = HERMON_CMD_INVALID_STATUS;
 130 
 131                 /* Write the command to the HCR */
 132                 token = (uint16_t)cmdptr->cmd_indx;
 133                 retry_cnt2 = HCA_PIO_RETRY_CNT;
 134                 do {
 135                         status = hermon_write_hcr(state, cmdpost, token,
 136                             &hw_err);
 137                 } while (status == HERMON_CMD_INTERNAL_ERR && retry_cnt2-- > 0);
 138 
 139                 /* Check if there is an error status in hermon_write_hcr() */
 140                 if (status != HERMON_CMD_SUCCESS) {
 141                         /*
 142                          * If there is a HW error, call hermon_cmd_retry_ok()
 143                          * to check the side-effect of the operation retry.
 144                          */
 145                         if ((retry_cnt == HCA_PIO_RETRY_CNT &&
 146                             hw_err == HCA_PIO_OK) ||
 147                             !hermon_cmd_retry_ok(cmdpost, status)) {
 148                                 hermon_cmd_check_status(state, status);
 149                                 hermon_outstanding_cmd_free(state, &cmdptr);
 150                                 return (status);
 151                         }
 152                 /* Check if there is a transient internal error */
 153                 } else if (retry_cnt2 != HCA_PIO_RETRY_CNT) {
 154                         hermon_fm_ereport(state, HCA_IBA_ERR,
 155                             HCA_ERR_TRANSIENT);
 156                 }
 157 
 158                 /*
 159                  * cv_wait() on the "command_complete" condition variable.
 160                  * Note: We have the "__lock_lint" here to workaround warlock.
 161                  * Since warlock doesn't know that other parts of the Hermon
 162                  * may occasionally call this routine while holding their own
 163                  * locks, it complains about this cv_wait.  In reality,
 164                  * however, the rest of the driver never calls this routine
 165                  * with a lock held unless they pass HERMON_CMD_NOSLEEP.
 166                  */
 167                 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*cmdptr))
 168                 mutex_enter(&cmdptr->cmd_comp_lock);
 169                 while (cmdptr->cmd_status == HERMON_CMD_INVALID_STATUS) {
 170 #ifndef __lock_lint
 171                         cv_wait(&cmdptr->cmd_comp_cv, &cmdptr->cmd_comp_lock);
 172                         /* NOTE: EXPECT SEVERAL THREADS TO BE WAITING HERE */
 173 #endif
 174                 }
 175                 mutex_exit(&cmdptr->cmd_comp_lock);
 176                 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdptr))
 177 
 178                 /*
 179                  * Wake up after command completes (cv_signal).  Read status
 180                  * from the command (success, fail, etc.).  It is appropriate
 181                  * here (as above) to read the status field without the
 182                  * "cmd_comp_lock" because it is no longer being used to
 183                  * indicate whether the condition variable has been signaled
 184                  * (i.e. at this point we are certain that it already has).
 185                  */
 186                 status = cmdptr->cmd_status;
 187 
 188                 /* retry the operation if an internal error occurs */
 189                 if (status == HERMON_CMD_INTERNAL_ERR && retry_cnt-- > 0)
 190                         goto retry;
 191 
 192                 /* Save the "outparam" values into the cmdpost struct */
 193                 cmdpost->cp_outparm = cmdptr->cmd_outparm;
 194 
 195                 /*
 196                  * Add the command back to the "outstanding commands list".
 197                  * Signal the "cmd_list" condition variable, if necessary.
 198                  */
 199                 hermon_outstanding_cmd_free(state, &cmdptr);
 200 
 201                 /* Check if there is an error status in hermon_write_hcr() */
 202                 if (status != HERMON_CMD_SUCCESS) {
 203                         /*
 204                          * If there is a HW error, call hermon_cmd_retry_ok()
 205                          * to check the side-effect of the operation retry.
 206                          */
 207                         if ((retry_cnt == HCA_PIO_RETRY_CNT &&
 208                             hw_err == HCA_PIO_OK) ||
 209                             !hermon_cmd_retry_ok(cmdpost, status)) {
 210                                 hermon_cmd_check_status(state, status);
 211                                 cmn_err(CE_NOTE, "hermon%d: post cmd failed "
 212                                     "opcode (0x%x) status (0x%x)\n",
 213                                     state->hs_instance, cmdpost->cp_opcode,
 214                                     status);
 215                                 return (status);
 216                         }
 217                 /* Check if there is a transient internal error */
 218                 } else if (retry_cnt != HCA_PIO_RETRY_CNT) {
 219                         hermon_fm_ereport(state, HCA_IBA_ERR,
 220                             HCA_ERR_TRANSIENT);
 221                 }
 222         }
 223 
 224         return (HERMON_CMD_SUCCESS);
 225 }
 226 
 227 /*
 228  * hermon_cmd_check_status()
 229  *      Context:  Can be called from interrupt or base
 230  *
 231  * checks the status returned from write_hcr and does the right
 232  * notice to the console, if any
 233  */
 234 static void
 235 hermon_cmd_check_status(hermon_state_t *state, int status)
 236 {
 237         switch (status) {
 238                 case HERMON_CMD_TIMEOUT_TOGGLE:
 239                         HERMON_FMANOTE(state, HERMON_FMA_TOTOG);
 240                         hermon_fm_ereport(state, HCA_IBA_ERR,
 241                             HCA_ERR_NON_FATAL);
 242                         break;
 243 
 244                 case HERMON_CMD_TIMEOUT_GOBIT:
 245                         HERMON_FMANOTE(state, HERMON_FMA_GOBIT);
 246                         hermon_fm_ereport(state, HCA_IBA_ERR,
 247                             HCA_ERR_NON_FATAL);
 248                         break;
 249 
 250                 case HERMON_CMD_INSUFF_RSRC:
 251                         HERMON_FMANOTE(state, HERMON_FMA_RSRC);
 252                         break;
 253 
 254                 case HERMON_CMD_INVALID_STATUS:
 255                         HERMON_FMANOTE(state, HERMON_FMA_CMDINV);
 256                         hermon_fm_ereport(state, HCA_IBA_ERR,
 257                             HCA_ERR_NON_FATAL);
 258                         break;
 259 
 260                 case HERMON_CMD_INTERNAL_ERR:
 261                         HERMON_FMANOTE(state, HERMON_FMA_HCRINT);
 262                         hermon_fm_ereport(state, HCA_IBA_ERR,
 263                             HCA_ERR_NON_FATAL);
 264                         break;
 265 
 266                 case HERMON_CMD_BAD_NVMEM:
 267                         /*
 268                          * No need of an ereport here since this case
 269                          * is treated as a degradation later.
 270                          */
 271                         HERMON_FMANOTE(state, HERMON_FMA_NVMEM);
 272                         break;
 273 
 274                 default:
 275                         break;
 276         }
 277 }
 278 
 279 /*
 280  * hermon_mbox_alloc()
 281  *    Context: Can be called from interrupt or base context.
 282  *
 283  *    The "mbox_wait" parameter is used to determine whether to
 284  *    wait for a mailbox to become available or not.
 285  */
 286 int
 287 hermon_mbox_alloc(hermon_state_t *state, hermon_mbox_info_t *mbox_info,
 288     uint_t mbox_wait)
 289 {
 290         int             status;
 291         uint_t          sleep_context;
 292 
 293         sleep_context = HERMON_SLEEPFLAG_FOR_CONTEXT();
 294 
 295         /* Allocate an "In" mailbox */
 296         if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_INMBOX) {
 297                 /* Determine correct mboxlist based on calling context */
 298                 if (sleep_context == HERMON_NOSLEEP) {
 299                         status = hermon_impl_mbox_alloc(state,
 300                             &state->hs_in_intr_mblist,
 301                             &mbox_info->mbi_in, mbox_wait);
 302 
 303                         ASSERT(status == HERMON_CMD_SUCCESS);
 304                 } else {
 305                         /* NOTE: Expect threads to be waiting in here */
 306                         status = hermon_impl_mbox_alloc(state,
 307                             &state->hs_in_mblist, &mbox_info->mbi_in,
 308                             mbox_wait);
 309                         if (status != HERMON_CMD_SUCCESS) {
 310                                 return (status);
 311                         }
 312                 }
 313 
 314         }
 315 
 316         /* Allocate an "Out" mailbox */
 317         if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_OUTMBOX) {
 318                 /* Determine correct mboxlist based on calling context */
 319                 if (sleep_context == HERMON_NOSLEEP) {
 320                         status = hermon_impl_mbox_alloc(state,
 321                             &state->hs_out_intr_mblist,
 322                             &mbox_info->mbi_out, mbox_wait);
 323 
 324                         ASSERT(status == HERMON_CMD_SUCCESS);
 325                 } else {
 326                         /* NOTE: Expect threads to be waiting in here */
 327                         status = hermon_impl_mbox_alloc(state,
 328                             &state->hs_out_mblist, &mbox_info->mbi_out,
 329                             mbox_wait);
 330                         if (status != HERMON_CMD_SUCCESS) {
 331                                 /* If we allocated an "In" mailbox, free it */
 332                                 if (mbox_info->mbi_alloc_flags &
 333                                     HERMON_ALLOC_INMBOX) {
 334                                         hermon_impl_mbox_free(
 335                                             &state->hs_in_mblist,
 336                                             &mbox_info->mbi_in);
 337                                 }
 338                                 return (status);
 339                         }
 340                 }
 341         }
 342 
 343         /* Store appropriate context in mbox_info */
 344         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(mbox_info->mbi_sleep_context))
 345         mbox_info->mbi_sleep_context = sleep_context;
 346 
 347         return (HERMON_CMD_SUCCESS);
 348 }
 349 
 350 
 351 /*
 352  * hermon_mbox_free()
 353  *    Context: Can be called from interrupt or base context.
 354  */
 355 void
 356 hermon_mbox_free(hermon_state_t *state, hermon_mbox_info_t *mbox_info)
 357 {
 358         /*
 359          * The mailbox has to be freed in the same context from which it was
 360          * allocated.  The context is stored in the mbox_info at
 361          * hermon_mbox_alloc() time.  We check the stored context against the
 362          * current context here.
 363          */
 364         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(mbox_info->mbi_sleep_context))
 365         ASSERT(mbox_info->mbi_sleep_context == HERMON_SLEEPFLAG_FOR_CONTEXT());
 366 
 367         /* Determine correct mboxlist based on calling context */
 368         if (mbox_info->mbi_sleep_context == HERMON_NOSLEEP) {
 369                 /* Free the intr "In" mailbox */
 370                 if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_INMBOX) {
 371                         hermon_impl_mbox_free(&state->hs_in_intr_mblist,
 372                             &mbox_info->mbi_in);
 373                 }
 374 
 375                 /* Free the intr "Out" mailbox */
 376                 if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_OUTMBOX) {
 377                         hermon_impl_mbox_free(&state->hs_out_intr_mblist,
 378                             &mbox_info->mbi_out);
 379                 }
 380         } else {
 381                 /* Free the "In" mailbox */
 382                 if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_INMBOX) {
 383                         hermon_impl_mbox_free(&state->hs_in_mblist,
 384                             &mbox_info->mbi_in);
 385                 }
 386 
 387                 /* Free the "Out" mailbox */
 388                 if (mbox_info->mbi_alloc_flags & HERMON_ALLOC_OUTMBOX) {
 389                         hermon_impl_mbox_free(&state->hs_out_mblist,
 390                             &mbox_info->mbi_out);
 391                 }
 392         }
 393 }
 394 
 395 
 396 
 397 /*
 398  * hermon_cmd_complete_handler()
 399  *    Context: Called only from interrupt context.
 400  */
 401 /* ARGSUSED */
 402 int
 403 hermon_cmd_complete_handler(hermon_state_t *state, hermon_eqhdl_t eq,
 404     hermon_hw_eqe_t *eqe)
 405 {
 406         hermon_cmd_t            *cmdp;
 407 
 408         /*
 409          * Find the outstanding command pointer based on value returned
 410          * in "token"
 411          */
 412         cmdp = &state->hs_cmd_list.cml_cmd[HERMON_EQE_CMDTOKEN_GET(eq, eqe)];
 413 
 414         /* Signal the waiting thread */
 415         mutex_enter(&cmdp->cmd_comp_lock);
 416         cmdp->cmd_outparm = ((uint64_t)HERMON_EQE_CMDOUTP0_GET(eq, eqe) << 32) |
 417             HERMON_EQE_CMDOUTP1_GET(eq, eqe);
 418         cmdp->cmd_status = HERMON_EQE_CMDSTATUS_GET(eq, eqe);
 419 
 420         cv_signal(&cmdp->cmd_comp_cv);
 421         mutex_exit(&cmdp->cmd_comp_lock);
 422 
 423         return (DDI_SUCCESS);
 424 }
 425 
 426 
 427 /*
 428  * hermon_inmbox_list_init()
 429  *    Context: Only called from attach() path context
 430  */
 431 int
 432 hermon_inmbox_list_init(hermon_state_t *state)
 433 {
 434         int             status;
 435         uint_t          num_inmbox;
 436 
 437         /* Initialize the "In" mailbox list */
 438         num_inmbox  =  (1 << state->hs_cfg_profile->cp_log_num_inmbox);
 439         status = hermon_impl_mboxlist_init(state, &state->hs_in_mblist,
 440             num_inmbox, HERMON_IN_MBOX);
 441         if (status != DDI_SUCCESS) {
 442                 return (DDI_FAILURE);
 443         }
 444 
 445         return (DDI_SUCCESS);
 446 }
 447 
 448 
 449 /*
 450  * hermon_intr_inmbox_list_init()
 451  *    Context: Only called from attach() path context
 452  */
 453 int
 454 hermon_intr_inmbox_list_init(hermon_state_t *state)
 455 {
 456         int             status;
 457         uint_t          num_inmbox;
 458 
 459         /* Initialize the interrupt "In" mailbox list */
 460         num_inmbox  =  (1 << state->hs_cfg_profile->cp_log_num_intr_inmbox);
 461         status = hermon_impl_mboxlist_init(state, &state->hs_in_intr_mblist,
 462             num_inmbox, HERMON_INTR_IN_MBOX);
 463         if (status != DDI_SUCCESS) {
 464                 return (DDI_FAILURE);
 465         }
 466 
 467         return (DDI_SUCCESS);
 468 }
 469 
 470 
 471 /*
 472  * hermon_outmbox_list_init()
 473  *    Context: Only called from attach() path context
 474  */
 475 int
 476 hermon_outmbox_list_init(hermon_state_t *state)
 477 {
 478         int             status;
 479         uint_t          num_outmbox;
 480 
 481         /* Initialize the "Out" mailbox list */
 482         num_outmbox  =  (1 << state->hs_cfg_profile->cp_log_num_outmbox);
 483         status = hermon_impl_mboxlist_init(state, &state->hs_out_mblist,
 484             num_outmbox, HERMON_OUT_MBOX);
 485         if (status != DDI_SUCCESS) {
 486                 return (DDI_FAILURE);
 487         }
 488 
 489         return (DDI_SUCCESS);
 490 }
 491 
 492 
 493 /*
 494  * hermon_intr_outmbox_list_init()
 495  *    Context: Only called from attach() path context
 496  */
 497 int
 498 hermon_intr_outmbox_list_init(hermon_state_t *state)
 499 {
 500         int             status;
 501         uint_t          num_outmbox;
 502 
 503         /* Initialize the interrupts "Out" mailbox list */
 504         num_outmbox  =  (1 << state->hs_cfg_profile->cp_log_num_intr_outmbox);
 505         status = hermon_impl_mboxlist_init(state, &state->hs_out_intr_mblist,
 506             num_outmbox, HERMON_INTR_OUT_MBOX);
 507         if (status != DDI_SUCCESS) {
 508                 return (DDI_FAILURE);
 509         }
 510 
 511         return (DDI_SUCCESS);
 512 }
 513 
 514 
 515 /*
 516  * hermon_inmbox_list_fini()
 517  *    Context: Only called from attach() and/or detach() path contexts
 518  */
 519 void
 520 hermon_inmbox_list_fini(hermon_state_t *state)
 521 {
 522         /* Free up the "In" mailbox list */
 523         hermon_impl_mboxlist_fini(state, &state->hs_in_mblist);
 524 }
 525 
 526 
 527 /*
 528  * hermon_intr_inmbox_list_fini()
 529  *    Context: Only called from attach() and/or detach() path contexts
 530  */
 531 void
 532 hermon_intr_inmbox_list_fini(hermon_state_t *state)
 533 {
 534         /* Free up the interupts "In" mailbox list */
 535         hermon_impl_mboxlist_fini(state, &state->hs_in_intr_mblist);
 536 }
 537 
 538 
 539 /*
 540  * hermon_outmbox_list_fini()
 541  *    Context: Only called from attach() and/or detach() path contexts
 542  */
 543 void
 544 hermon_outmbox_list_fini(hermon_state_t *state)
 545 {
 546         /* Free up the "Out" mailbox list */
 547         hermon_impl_mboxlist_fini(state, &state->hs_out_mblist);
 548 }
 549 
 550 
 551 /*
 552  * hermon_intr_outmbox_list_fini()
 553  *    Context: Only called from attach() and/or detach() path contexts
 554  */
 555 void
 556 hermon_intr_outmbox_list_fini(hermon_state_t *state)
 557 {
 558         /* Free up the interrupt "Out" mailbox list */
 559         hermon_impl_mboxlist_fini(state, &state->hs_out_intr_mblist);
 560 }
 561 
 562 
 563 /*
 564  * hermon_impl_mbox_alloc()
 565  *    Context: Can be called from interrupt or base context.
 566  */
 567 static int
 568 hermon_impl_mbox_alloc(hermon_state_t *state, hermon_mboxlist_t *mblist,
 569     hermon_mbox_t **mb, uint_t mbox_wait)
 570 {
 571         hermon_mbox_t   *mbox_ptr;
 572         uint_t          index, next, prev;
 573         uint_t          count, countmax;
 574 
 575         /*
 576          * If the mailbox list is empty, then wait (if appropriate in the
 577          * current context).  Otherwise, grab the next available mailbox.
 578          */
 579         if (mbox_wait == HERMON_NOSLEEP) {
 580                 count    = 0;
 581                 countmax = state->hs_cfg_profile->cp_cmd_poll_max;
 582 
 583                 mutex_enter(&mblist->mbl_lock);
 584                 mblist->mbl_pollers++;
 585                 while (mblist->mbl_entries_free == 0) {
 586                         mutex_exit(&mblist->mbl_lock);
 587                         /* Delay loop polling for an available mbox */
 588                         if (++count > countmax) {
 589                                 return (HERMON_CMD_INSUFF_RSRC);
 590                         }
 591 
 592                         /* Delay before polling for mailbox again */
 593                         drv_usecwait(state->hs_cfg_profile->cp_cmd_poll_delay);
 594                         mutex_enter(&mblist->mbl_lock);
 595                 }
 596                 mblist->mbl_pollers--;
 597 
 598         /* HERMON_SLEEP */
 599         } else {
 600                 /*
 601                  * Grab lock here as we prepare to cv_wait if needed.
 602                  */
 603                 mutex_enter(&mblist->mbl_lock);
 604                 while (mblist->mbl_entries_free == 0) {
 605                         /*
 606                          * Wait (on cv) for a mailbox to become free.  Note:
 607                          * Just as we do above in hermon_cmd_post(), we also
 608                          * have the "__lock_lint" here to workaround warlock.
 609                          * Warlock doesn't know that other parts of the Hermon
 610                          * may occasionally call this routine while holding
 611                          * their own locks, so it complains about this cv_wait.
 612                          * In reality, however, the rest of the driver never
 613                          * calls this routine with a lock held unless they pass
 614                          * HERMON_CMD_NOSLEEP.
 615                          */
 616                         mblist->mbl_waiters++;
 617 #ifndef __lock_lint
 618                         cv_wait(&mblist->mbl_cv, &mblist->mbl_lock);
 619 #endif
 620                 }
 621         }
 622 
 623         /* Grab the next available mailbox from list */
 624         mbox_ptr = mblist->mbl_mbox;
 625         index    = mblist->mbl_head_indx;
 626         next     = mbox_ptr[index].mb_next;
 627         prev     = mbox_ptr[index].mb_prev;
 628 
 629         /* Remove it from the mailbox list */
 630         mblist->mbl_mbox[next].mb_prev       = prev;
 631         mblist->mbl_mbox[prev].mb_next       = next;
 632         mblist->mbl_head_indx                = next;
 633 
 634         /* Update the "free" count and return the mailbox pointer */
 635         mblist->mbl_entries_free--;
 636         *mb = &mbox_ptr[index];
 637 
 638         mutex_exit(&mblist->mbl_lock);
 639 
 640         return (HERMON_CMD_SUCCESS);
 641 }
 642 
 643 
 644 /*
 645  * hermon_impl_mbox_free()
 646  *    Context: Can be called from interrupt or base context.
 647  */
 648 static void
 649 hermon_impl_mbox_free(hermon_mboxlist_t *mblist, hermon_mbox_t **mb)
 650 {
 651         uint_t          mbox_indx;
 652 
 653         mutex_enter(&mblist->mbl_lock);
 654 
 655         /* Pull the "index" from mailbox entry */
 656         mbox_indx = (*mb)->mb_indx;
 657 
 658         /*
 659          * If mailbox list is not empty, then insert the entry.  Otherwise,
 660          * this is the only entry.  So update the pointers appropriately.
 661          */
 662         if (mblist->mbl_entries_free++ != 0) {
 663                 /* Update the current mailbox */
 664                 (*mb)->mb_next = mblist->mbl_head_indx;
 665                 (*mb)->mb_prev = mblist->mbl_tail_indx;
 666 
 667                 /* Update head and tail mailboxes */
 668                 mblist->mbl_mbox[mblist->mbl_head_indx].mb_prev = mbox_indx;
 669                 mblist->mbl_mbox[mblist->mbl_tail_indx].mb_next = mbox_indx;
 670 
 671                 /* Update tail index */
 672                 mblist->mbl_tail_indx = mbox_indx;
 673 
 674         } else {
 675                 /* Update the current mailbox */
 676                 (*mb)->mb_next = mbox_indx;
 677                 (*mb)->mb_prev = mbox_indx;
 678 
 679                 /* Update head and tail indexes */
 680                 mblist->mbl_tail_indx = mbox_indx;
 681                 mblist->mbl_head_indx = mbox_indx;
 682         }
 683 
 684         /*
 685          * Because we can have both waiters (SLEEP treads waiting for a
 686          * cv_signal to continue processing) and pollers (NOSLEEP treads
 687          * polling for a mailbox to become available), we try to share CPU time
 688          * between them.  We do this by signalling the waiters only every other
 689          * call to mbox_free.  This gives the pollers a chance to get some CPU
 690          * time to do their command.  If we signalled every time, the pollers
 691          * would have a much harder time getting CPU time.
 692          *
 693          * If there are waiters and no pollers, then we signal always.
 694          *
 695          * Otherwise, if there are either no waiters, there may in fact be
 696          * pollers, so we do not signal in that case.
 697          */
 698         if (mblist->mbl_pollers > 0 && mblist->mbl_waiters > 0) {
 699                 /* flip the signal value */
 700                 mblist->mbl_signal = (++mblist->mbl_signal) % 2;
 701         } else if (mblist->mbl_waiters > 0) {
 702                 mblist->mbl_signal = 1;
 703         } else {
 704                 mblist->mbl_signal = 0;
 705         }
 706 
 707         /*
 708          * Depending on the conditions in the previous check, we signal only if
 709          * we are supposed to.
 710          */
 711         if (mblist->mbl_signal) {
 712                 mblist->mbl_waiters--;
 713                 cv_signal(&mblist->mbl_cv);
 714         }
 715 
 716         /* Clear out the mailbox entry pointer */
 717         *mb = NULL;
 718 
 719         mutex_exit(&mblist->mbl_lock);
 720 }
 721 
 722 
 723 /*
 724  * hermon_impl_mboxlist_init()
 725  *    Context: Only called from attach() path context
 726  */
 727 static int
 728 hermon_impl_mboxlist_init(hermon_state_t *state, hermon_mboxlist_t *mblist,
 729     uint_t num_mbox, hermon_rsrc_type_t type)
 730 {
 731         hermon_rsrc_t           *rsrc;
 732         ddi_dma_cookie_t        dma_cookie;
 733         uint_t                  dma_cookiecnt;
 734         int                     status, i;
 735 
 736         /* Allocate the memory for the mailbox entries list */
 737         mblist->mbl_list_sz = num_mbox;
 738         mblist->mbl_mbox = kmem_zalloc(mblist->mbl_list_sz *
 739             sizeof (hermon_mbox_t), KM_SLEEP);
 740 
 741         /* Initialize the mailbox entries list */
 742         mblist->mbl_head_indx         = 0;
 743         mblist->mbl_tail_indx         = mblist->mbl_list_sz - 1;
 744         mblist->mbl_entries_free = mblist->mbl_list_sz;
 745         mblist->mbl_waiters   = 0;
 746         mblist->mbl_num_alloc         = 0;
 747 
 748         /* Set up the mailbox list's cv and mutex */
 749         mutex_init(&mblist->mbl_lock, NULL, MUTEX_DRIVER,
 750             DDI_INTR_PRI(state->hs_intrmsi_pri));
 751         cv_init(&mblist->mbl_cv, NULL, CV_DRIVER, NULL);
 752 
 753         /* Initialize the mailbox list entries */
 754         for (i = 0; i < mblist->mbl_list_sz; i++) {
 755                 /* Allocate resources for the mailbox */
 756                 status = hermon_rsrc_alloc(state, type, 1, HERMON_SLEEP,
 757                     &rsrc);
 758                 if (status != DDI_SUCCESS) {
 759                         /* Jump to cleanup and return error */
 760                         goto mboxlist_init_fail;
 761                 }
 762 
 763                 /* Save away the mailbox resource info */
 764                 mblist->mbl_mbox[i].mb_rsrcptr       = rsrc;
 765                 mblist->mbl_mbox[i].mb_addr  = rsrc->hr_addr;
 766                 mblist->mbl_mbox[i].mb_acchdl        = rsrc->hr_acchdl;
 767 
 768                 /*
 769                  * Get a PCI mapped address for each mailbox.  Note: this
 770                  * uses the ddi_dma_handle return from the resource
 771                  * allocation routine
 772                  */
 773                 status = ddi_dma_addr_bind_handle(rsrc->hr_dmahdl, NULL,
 774                     rsrc->hr_addr, rsrc->hr_len,
 775                     (DDI_DMA_RDWR | DDI_DMA_CONSISTENT),
 776                     DDI_DMA_SLEEP, NULL, &dma_cookie, &dma_cookiecnt);
 777                 if (status != DDI_SUCCESS) {
 778                         /* Jump to cleanup and return error */
 779                         hermon_rsrc_free(state, &rsrc);
 780                         goto mboxlist_init_fail;
 781                 }
 782 
 783                 /* Save away the mapped address for the mailbox */
 784                 mblist->mbl_mbox[i].mb_mapaddr       = dma_cookie.dmac_laddress;
 785 
 786                 /* Make each entry point to the "next" and "prev" entries */
 787                 mblist->mbl_mbox[i].mb_next  = i+1;
 788                 mblist->mbl_mbox[i].mb_prev  = i-1;
 789                 mblist->mbl_mbox[i].mb_indx  = i;
 790                 mblist->mbl_num_alloc                = i + 1;
 791         }
 792 
 793         /* Make the "head" and "tail" entries point to each other */
 794         mblist->mbl_mbox[mblist->mbl_head_indx].mb_prev =
 795             mblist->mbl_tail_indx;
 796         mblist->mbl_mbox[mblist->mbl_tail_indx].mb_next =
 797             mblist->mbl_head_indx;
 798 
 799         return (DDI_SUCCESS);
 800 
 801 mboxlist_init_fail:
 802         hermon_impl_mboxlist_fini(state, mblist);
 803 
 804         return (DDI_FAILURE);
 805 }
 806 
 807 
 808 /*
 809  * hermon_impl_mboxlist_fini()
 810  *    Context: Only called from attach() and/or detach() path contexts
 811  */
 812 static void
 813 hermon_impl_mboxlist_fini(hermon_state_t *state, hermon_mboxlist_t *mblist)
 814 {
 815         hermon_rsrc_t   *rsrc;
 816         int             i, status;
 817 
 818         /* Release the resources for each of the mailbox list entries */
 819         for (i = 0; i < mblist->mbl_num_alloc; i++) {
 820                 rsrc = mblist->mbl_mbox[i].mb_rsrcptr;
 821 
 822                 /*
 823                  * First, unbind the DMA memory for the mailbox
 824                  *
 825                  * Note: The only way ddi_dma_unbind_handle() currently
 826                  * can return an error is if the handle passed in is invalid.
 827                  * Since this should never happen, we choose to return void
 828                  * from this function!  If this does return an error,
 829                  * however, then we print a warning message to the console.
 830                  */
 831                 status = ddi_dma_unbind_handle(rsrc->hr_dmahdl);
 832                 if (status != DDI_SUCCESS) {
 833                         HERMON_WARNING(state, "failed to unbind DMA mapping");
 834                         return;
 835                 }
 836 
 837                 /* Next, free the mailbox resource */
 838                 hermon_rsrc_free(state, &rsrc);
 839         }
 840 
 841         /* Destroy the mailbox list mutex and cv */
 842         mutex_destroy(&mblist->mbl_lock);
 843         cv_destroy(&mblist->mbl_cv);
 844 
 845         /* Free up the memory for tracking the mailbox list */
 846         kmem_free(mblist->mbl_mbox, mblist->mbl_list_sz *
 847             sizeof (hermon_mbox_t));
 848 }
 849 
 850 
 851 /*
 852  * hermon_outstanding_cmd_alloc()
 853  *    Context: Can be called only from base context.
 854  */
 855 static int
 856 hermon_outstanding_cmd_alloc(hermon_state_t *state, hermon_cmd_t **cmd_ptr,
 857     uint_t cmd_wait)
 858 {
 859         hermon_cmdlist_t        *cmd_list;
 860         uint_t          next, prev, head;
 861 
 862         cmd_list = &state->hs_cmd_list;
 863         mutex_enter(&cmd_list->cml_lock);
 864 
 865         /* Ensure that outstanding commands are supported */
 866         ASSERT(cmd_list->cml_num_alloc != 0);
 867 
 868         /*
 869          * If the outstanding command list is empty, then wait (if
 870          * appropriate in the current context).  Otherwise, grab the
 871          * next available command.
 872          */
 873         while (cmd_list->cml_entries_free == 0) {
 874                 /* No free commands */
 875                 if (cmd_wait == HERMON_NOSLEEP) {
 876                         mutex_exit(&cmd_list->cml_lock);
 877                         return (HERMON_CMD_INSUFF_RSRC);
 878                 }
 879 
 880                 /*
 881                  * Wait (on cv) for a command to become free.  Note: Just
 882                  * as we do above in hermon_cmd_post(), we also have the
 883                  * "__lock_lint" here to workaround warlock.  Warlock doesn't
 884                  * know that other parts of the Hermon may occasionally call
 885                  * this routine while holding their own locks, so it complains
 886                  * about this cv_wait.  In reality, however, the rest of the
 887                  * driver never calls this routine with a lock held unless
 888                  * they pass HERMON_CMD_NOSLEEP.
 889                  */
 890                 cmd_list->cml_waiters++;
 891 #ifndef __lock_lint
 892                 cv_wait(&cmd_list->cml_cv, &cmd_list->cml_lock);
 893 #endif
 894         }
 895 
 896         /* Grab the next available command from the list */
 897         head = cmd_list->cml_head_indx;
 898         *cmd_ptr = &cmd_list->cml_cmd[head];
 899         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(**cmd_ptr))
 900         next = (*cmd_ptr)->cmd_next;
 901         prev = (*cmd_ptr)->cmd_prev;
 902         (*cmd_ptr)->cmd_status = HERMON_CMD_INVALID_STATUS;
 903 
 904         /* Remove it from the command list */
 905         cmd_list->cml_cmd[next].cmd_prev = prev;
 906         cmd_list->cml_cmd[prev].cmd_next = next;
 907         cmd_list->cml_head_indx               = next;
 908 
 909         /* Update the "free" count and return */
 910         cmd_list->cml_entries_free--;
 911 
 912         mutex_exit(&cmd_list->cml_lock);
 913 
 914         return (HERMON_CMD_SUCCESS);
 915 }
 916 
 917 
 918 /*
 919  * hermon_outstanding_cmd_free()
 920  *    Context: Can be called only from base context.
 921  */
 922 static void
 923 hermon_outstanding_cmd_free(hermon_state_t *state, hermon_cmd_t **cmd_ptr)
 924 {
 925         hermon_cmdlist_t        *cmd_list;
 926         uint_t          cmd_indx;
 927 
 928         cmd_list = &state->hs_cmd_list;
 929         mutex_enter(&cmd_list->cml_lock);
 930 
 931         /* Pull the "index" from command entry */
 932         cmd_indx = (*cmd_ptr)->cmd_indx;
 933 
 934         /*
 935          * If outstanding command list is not empty, then insert the entry.
 936          * Otherwise, this is the only entry.  So update the pointers
 937          * appropriately.
 938          */
 939         if (cmd_list->cml_entries_free++ != 0) {
 940                 /* Update the current command */
 941                 (*cmd_ptr)->cmd_next = cmd_list->cml_head_indx;
 942                 (*cmd_ptr)->cmd_prev = cmd_list->cml_tail_indx;
 943 
 944                 /* Update head and tail commands */
 945                 cmd_list->cml_cmd[cmd_list->cml_head_indx].cmd_prev = cmd_indx;
 946                 cmd_list->cml_cmd[cmd_list->cml_tail_indx].cmd_next = cmd_indx;
 947 
 948                 /* Update tail index */
 949                 cmd_list->cml_tail_indx = cmd_indx;
 950 
 951         } else {
 952                 /* Update the current command */
 953                 (*cmd_ptr)->cmd_next = cmd_indx;
 954                 (*cmd_ptr)->cmd_prev = cmd_indx;
 955 
 956                 /* Update head and tail indexes */
 957                 cmd_list->cml_head_indx = cmd_indx;
 958                 cmd_list->cml_tail_indx = cmd_indx;
 959         }
 960 
 961         /* If there are threads waiting, signal one of them */
 962         if (cmd_list->cml_waiters > 0) {
 963                 cmd_list->cml_waiters--;
 964                 cv_signal(&cmd_list->cml_cv);
 965         }
 966 
 967         /* Clear out the command entry pointer */
 968         *cmd_ptr = NULL;
 969 
 970         mutex_exit(&cmd_list->cml_lock);
 971 }
 972 
 973 
 974 /*
 975  * hermon_write_hcr()
 976  *    Context: Can be called from interrupt or base context.
 977  */
 978 static int
 979 hermon_write_hcr(hermon_state_t *state, hermon_cmd_post_t *cmdpost,
 980     uint16_t token, int *hw_err)
 981 {
 982         hermon_hw_hcr_t *hcr;
 983         uint_t          status, count, countmax;
 984         uint64_t        hcrreg;
 985         uint64_t        togmask;
 986         ddi_acc_handle_t cmdhdl = hermon_get_cmdhdl(state);
 987         boolean_t       hw_error = B_FALSE;
 988 
 989         /* initialize the FMA retry loop */
 990         hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
 991 
 992         /*
 993          * Grab the "HCR access" lock if the driver is not in
 994          * fastreboot. In fastreboot, this function is called
 995          * with the single thread but in high interrupt context
 996          * (so that this mutex lock cannot be used).
 997          */
 998 #ifdef __lock_lint
 999         mutex_enter(&state->hs_cmd_regs.hcr_lock);
1000 #else
1001         if (!HERMON_IN_FASTREBOOT(state)) {
1002                 mutex_enter(&state->hs_cmd_regs.hcr_lock);
1003         }
1004 #endif
1005         hcr = state->hs_cmd_regs.hcr;
1006 
1007         /*
1008          * First, check the "go" bit to see if any previous hcr usage is
1009          * complete.  As long as it is set then we must continue to poll.
1010          */
1011 
1012         countmax = state->hs_cfg_profile->cp_cmd_poll_max;
1013         togmask = (state->hs_cmd_toggle & 0x01) << HERMON_HCR_CMD_T_SHFT;
1014 
1015         /* the FMA retry loop starts. */
1016         hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
1017             fm_test);
1018 
1019         count    = 0;
1020         for (;;) {
1021                 hcrreg = ddi_get32(cmdhdl, &hcr->cmd);
1022 
1023                 /* If "go" bit is clear and toggle reset, then done */
1024                 if (((hcrreg & HERMON_HCR_CMD_GO_MASK) == 0) &&
1025                     ((hcrreg & HERMON_HCR_CMD_T_MASK)  == togmask)) {
1026                         break;
1027                 }
1028                 /* Delay before polling the "go" bit again */
1029                 drv_usecwait(state->hs_cfg_profile->cp_cmd_poll_delay);
1030 
1031                 /*
1032                  * If we poll more than the maximum number of times, then
1033                  * return a "timeout" error.
1034                  */
1035                 if (++count > countmax) {
1036 #ifdef __lock_lint
1037                         mutex_exit(&state->hs_cmd_regs.hcr_lock);
1038 #else
1039                         if (!HERMON_IN_FASTREBOOT(state)) {
1040                                 mutex_exit(&state->hs_cmd_regs.hcr_lock);
1041                         }
1042 #endif
1043                         cmn_err(CE_NOTE, "write_hcr: cannot start cmd");
1044                         return (HERMON_CMD_TIMEOUT_GOBIT);
1045                 }
1046         }
1047 
1048         /* the FMA retry loop ends. */
1049         hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
1050             fm_test);
1051 
1052         /* check if there is a transient error */
1053         if (fm_loop_cnt != HCA_PIO_RETRY_CNT) {
1054                 hw_error = B_TRUE;
1055         }
1056 
1057         /* succeeded, so update the cmd counter for this cmd's completion */
1058         state->hs_cmd_toggle++;
1059         togmask = (state->hs_cmd_toggle & 0x01) << HERMON_HCR_CMD_T_SHFT;
1060 
1061         /* the FMA retry loop starts. */
1062         hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
1063             fm_test);
1064 
1065         /* Write "inparam" as a 64-bit quantity */
1066         ddi_put64(cmdhdl, (uint64_t *)(void *)&hcr->in_param0,
1067             cmdpost->cp_inparm);
1068 
1069         /* Write "inmod" and 32-bits of "outparam" as 64-bit */
1070         hcrreg = ((uint64_t)cmdpost->cp_inmod << 32);
1071         hcrreg = hcrreg | (cmdpost->cp_outparm >> 32);
1072 
1073         ddi_put64(cmdhdl, (uint64_t *)(void *)&hcr->input_modifier, hcrreg);
1074 
1075         /* Write the other 32-bits of "outparam" and "token" as 64-bit */
1076         hcrreg = (cmdpost->cp_outparm << 32);
1077         hcrreg = hcrreg | ((uint32_t)token << HERMON_HCR_TOKEN_SHIFT);
1078 
1079         ddi_put64(cmdhdl, (uint64_t *)(void *)&hcr->out_param1, hcrreg);
1080 
1081         /* Then setup the final hcrreg to hit doorbell (i.e. "go" bit) */
1082         hcrreg = HERMON_HCR_CMD_GO_MASK;
1083         /* Then set the toggle bit for this command */
1084         hcrreg |= (state->hs_cmd_toggle & 0x01) << HERMON_HCR_CMD_T_SHFT;
1085         if (cmdpost->cp_flags == HERMON_CMD_SLEEP_NOSPIN) {
1086                 hcrreg = hcrreg | HERMON_HCR_CMD_E_MASK;
1087         }
1088         hcrreg = hcrreg | (cmdpost->cp_opmod << HERMON_HCR_CMD_OPMOD_SHFT);
1089         hcrreg = hcrreg | (cmdpost->cp_opcode);
1090 
1091         /* Write the doorbell to the HCR */
1092         ddi_put32(cmdhdl, &hcr->cmd, hcrreg);
1093 
1094         /* the FMA retry loop ends. */
1095         hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
1096             fm_test);
1097 
1098         /* check if there is a transient error */
1099         if (fm_loop_cnt != HCA_PIO_RETRY_CNT) {
1100                 hw_error = B_TRUE;
1101         }
1102 
1103         /*
1104          * In the SPIN case we read the HCR and check the "go" bit.  For the
1105          * NOSPIN case we do not have to poll, we simply release the HCR lock
1106          * and return.
1107          */
1108         if (cmdpost->cp_flags == HERMON_CMD_NOSLEEP_SPIN) {
1109 
1110                 countmax = (state->hs_cfg_profile->cp_cmd_poll_max << 4);
1111 
1112                 /* the FMA retry loop starts. */
1113                 hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt,
1114                     fm_status, fm_test);
1115 
1116                 count    = 0;
1117                 for (;;) {
1118                         hcrreg = ddi_get32(cmdhdl, &hcr->cmd);
1119 
1120                         /* If "go" bit is clear and toggle reset, then done */
1121                         if (((hcrreg & HERMON_HCR_CMD_GO_MASK) == 0) &&
1122                             ((hcrreg & HERMON_HCR_CMD_T_MASK)  == togmask)) {
1123                                 break;
1124                         }
1125                         /* Delay before polling the "go" bit again */
1126                         drv_usecwait(state->hs_cfg_profile->cp_cmd_poll_delay);
1127 
1128                         /*
1129                          * If we poll more than the maximum number of times,
1130                          * then return a "timeout" error.
1131                          */
1132                         if (++count > countmax) {
1133 #ifdef __lock_lint
1134                                 mutex_exit(&state-> hs_cmd_regs.hcr_lock);
1135 #else
1136                                 if (!HERMON_IN_FASTREBOOT(state)) {
1137                                         mutex_exit(&state->
1138                                             hs_cmd_regs.hcr_lock);
1139                                 }
1140 #endif
1141                                 cmn_err(CE_NOTE,
1142                                     "write_hcr: cannot complete cmd");
1143                                 return (HERMON_CMD_TIMEOUT_GOBIT);
1144                         }
1145                 }
1146 
1147                 /* Pull out the "status" bits from the HCR */
1148                 status = (hcrreg >> HERMON_HCR_CMD_STATUS_SHFT);
1149 
1150                 /*
1151                  * Read the "outparam" value.  Note: we have to read "outparam"
1152                  * as two separate 32-bit reads because the field in the HCR is
1153                  * not 64-bit aligned.
1154                  */
1155                 hcrreg = ddi_get32(cmdhdl, &hcr->out_param0);
1156                 cmdpost->cp_outparm = hcrreg << 32;
1157                 hcrreg = ddi_get32(cmdhdl, &hcr->out_param1);
1158                 cmdpost->cp_outparm |= hcrreg;
1159 
1160                 /* the FMA retry loop ends. */
1161                 hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
1162                     fm_test);
1163 
1164                 /* check if there is a transient error */
1165                 if (fm_loop_cnt != HCA_PIO_RETRY_CNT) {
1166                         hw_error = B_TRUE;
1167                 }
1168 
1169         /* END SPIN */
1170         } else {                /* NOSPIN */
1171                 status = HERMON_CMD_SUCCESS;
1172         }
1173 
1174         /* Drop the "HCR access" lock */
1175 #ifdef __lock_lint
1176         mutex_exit(&state->hs_cmd_regs.hcr_lock);
1177 #else
1178         if (!HERMON_IN_FASTREBOOT(state)) {
1179                 mutex_exit(&state->hs_cmd_regs.hcr_lock);
1180         }
1181 #endif
1182         if (hw_error == B_TRUE) {
1183                 *hw_err = HCA_PIO_TRANSIENT;
1184         } else {
1185                 *hw_err = HCA_PIO_OK;
1186         }
1187 #ifdef FMA_TEST
1188         if (hermon_test_num == -3) {
1189                 status = HERMON_CMD_INTERNAL_ERR;
1190         }
1191 #endif
1192         return (status);
1193 
1194 pio_error:
1195 #ifdef __lock_lint
1196         mutex_exit(&state->hs_cmd_regs.hcr_lock);
1197 #else
1198         if (!HERMON_IN_FASTREBOOT(state)) {
1199                 mutex_exit(&state->hs_cmd_regs.hcr_lock);
1200         }
1201 #endif
1202         hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_NON_FATAL);
1203         *hw_err = HCA_PIO_PERSISTENT;
1204         return (HERMON_CMD_INVALID_STATUS);
1205 }
1206 
1207 
1208 /*
1209  * hermon_outstanding_cmdlist_init()
1210  *    Context: Only called from attach() path context
1211  */
1212 int
1213 hermon_outstanding_cmdlist_init(hermon_state_t *state)
1214 {
1215         uint_t          num_outstanding_cmds, head, tail;
1216         int             i;
1217 
1218         /*
1219          * Determine the number of the outstanding commands supported
1220          * by the Hermon device (obtained from the QUERY_FW command).  Note:
1221          * Because we handle both SLEEP and NOSLEEP cases around the hermon HCR,
1222          * we know that when an interrupt comes in it will be next on the
1223          * command register, and will at most have to wait one commands time.
1224          * We do not have to reserve an outstanding command here for
1225          * interrupts.
1226          */
1227         num_outstanding_cmds = (1 << state->hs_fw.log_max_cmd);
1228 
1229         /* Initialize the outstanding command list */
1230         state->hs_cmd_list.cml_list_sz        = num_outstanding_cmds;
1231         state->hs_cmd_list.cml_head_indx = 0;
1232         state->hs_cmd_list.cml_tail_indx = state->hs_cmd_list.cml_list_sz - 1;
1233         state->hs_cmd_list.cml_entries_free = state->hs_cmd_list.cml_list_sz;
1234         state->hs_cmd_list.cml_waiters        = 0;
1235         state->hs_cmd_list.cml_num_alloc = 0;
1236 
1237         /* Allocate the memory for the outstanding command list */
1238         if (num_outstanding_cmds) {
1239                 state->hs_cmd_list.cml_cmd =
1240                     kmem_zalloc(state->hs_cmd_list.cml_list_sz *
1241                     sizeof (hermon_cmd_t), KM_SLEEP);
1242         }
1243         mutex_init(&state->hs_cmd_list.cml_lock, NULL, MUTEX_DRIVER,
1244             DDI_INTR_PRI(state->hs_intrmsi_pri));
1245         cv_init(&state->hs_cmd_list.cml_cv, NULL, CV_DRIVER, NULL);
1246 
1247         /* Initialize the individual outstanding command list entries */
1248         for (i = 0; i < state->hs_cmd_list.cml_list_sz; i++) {
1249                 mutex_init(&state->hs_cmd_list.cml_cmd[i].cmd_comp_lock,
1250                     NULL, MUTEX_DRIVER, DDI_INTR_PRI(state->hs_intrmsi_pri));
1251                 cv_init(&state->hs_cmd_list.cml_cmd[i].cmd_comp_cv, NULL,
1252                     CV_DRIVER, NULL);
1253 
1254                 state->hs_cmd_list.cml_cmd[i].cmd_next       = i+1;
1255                 state->hs_cmd_list.cml_cmd[i].cmd_prev       = i-1;
1256                 state->hs_cmd_list.cml_cmd[i].cmd_indx       = i;
1257                 state->hs_cmd_list.cml_num_alloc     = i + 1;
1258         }
1259         if (num_outstanding_cmds) {
1260                 head = state->hs_cmd_list.cml_head_indx;
1261                 tail = state->hs_cmd_list.cml_tail_indx;
1262                 state->hs_cmd_list.cml_cmd[head].cmd_prev =
1263                     state->hs_cmd_list.cml_tail_indx;
1264                 state->hs_cmd_list.cml_cmd[tail].cmd_next =
1265                     state->hs_cmd_list.cml_head_indx;
1266         }
1267 
1268         return (DDI_SUCCESS);
1269 }
1270 
1271 
1272 /*
1273  * hermon_outstanding_cmdlist_fini()
1274  *    Context: Only called from attach() and/or detach() path contexts
1275  */
1276 void
1277 hermon_outstanding_cmdlist_fini(hermon_state_t *state)
1278 {
1279         int             i;
1280 
1281         /* Destroy the outstanding command list entries */
1282         for (i = 0; i < state->hs_cmd_list.cml_num_alloc; i++) {
1283                 mutex_destroy(&state->hs_cmd_list.cml_cmd[i].cmd_comp_lock);
1284                 cv_destroy(&state->hs_cmd_list.cml_cmd[i].cmd_comp_cv);
1285         }
1286 
1287         /* Destroy the lock (and cv) and free up memory for list */
1288         mutex_destroy(&state->hs_cmd_list.cml_lock);
1289         cv_destroy(&state->hs_cmd_list.cml_cv);
1290         if (state->hs_cmd_list.cml_num_alloc) {
1291                 kmem_free(state->hs_cmd_list.cml_cmd,
1292                     state->hs_cmd_list.cml_list_sz * sizeof (hermon_cmd_t));
1293         }
1294 }
1295 
1296 
1297 /*
1298  * hermon_mbox_sync()
1299  */
1300 static void
1301 hermon_mbox_sync(hermon_mbox_t *mbox, uint_t offset, uint_t length,
1302     uint_t flag)
1303 {
1304         ddi_dma_handle_t        dmahdl;
1305         int                     status;
1306 
1307         /* Get the DMA handle from mailbox */
1308         dmahdl = mbox->mb_rsrcptr->hr_dmahdl;
1309 
1310         /* Calculate offset into mailbox */
1311         status = ddi_dma_sync(dmahdl, (off_t)offset, (size_t)length, flag);
1312         if (status != DDI_SUCCESS) {
1313                 return;
1314         }
1315 }
1316 
1317 
1318 /*
1319  * hermon_init_hca_cmd_post()
1320  *    Context: Can be called from interrupt or base context.
1321  *    (Currently called only from attach() path context)
1322  */
1323 int
1324 hermon_init_hca_cmd_post(hermon_state_t *state,
1325     hermon_hw_initqueryhca_t *inithca, uint_t sleepflag)
1326 {
1327         hermon_mbox_info_t      mbox_info;
1328         hermon_cmd_post_t       cmd;
1329         uint64_t                data;
1330         uint_t                  size;
1331         int                     status, i;
1332 
1333         /* Make sure we are called with the correct flag */
1334         ASSERT(sleepflag == HERMON_CMD_NOSLEEP_SPIN);
1335 
1336         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1337 
1338         /* Get an "In" mailbox for the command */
1339         mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
1340         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
1341         if (status != HERMON_CMD_SUCCESS) {
1342                 return (status);
1343         }
1344 
1345         /* Copy the Hermon "INIT_HCA" command into the mailbox */
1346         size = sizeof (hermon_hw_initqueryhca_t);
1347         for (i = 0; i < (size >> 3); i++) {
1348                 data = ((uint64_t *)inithca)[i];
1349                 ddi_put64(mbox_info.mbi_in->mb_acchdl,
1350                     ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
1351         }
1352 
1353         /* Sync the mailbox for the device to read */
1354         hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
1355 
1356         /* Setup and post the Hermon "INIT_HCA" command */
1357         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
1358         cmd.cp_outparm  = 0;
1359         cmd.cp_inmod    = 0;
1360         cmd.cp_opcode   = INIT_HCA;
1361         cmd.cp_opmod    = 0;
1362         cmd.cp_flags    = sleepflag;
1363         status = hermon_cmd_post(state, &cmd);
1364 
1365         /* Free the mailbox */
1366         hermon_mbox_free(state, &mbox_info);
1367         return (status);
1368 }
1369 
1370 
1371 /*
1372  * hermon_close_hca_cmd_post()
1373  *    Context: Can be called from interrupt or base context.
1374  *    (Currently called only from attach() and/or detach() path contexts)
1375  */
1376 int
1377 hermon_close_hca_cmd_post(hermon_state_t *state, uint_t sleepflag)
1378 {
1379         hermon_cmd_post_t       cmd;
1380         int                     status;
1381 
1382         /* Make sure we are called with the correct flag */
1383         ASSERT(sleepflag == HERMON_CMD_NOSLEEP_SPIN);
1384 
1385         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1386 
1387 
1388         /* Setup and post the Hermon "CLOSE_HCA" command */
1389         cmd.cp_inparm   = 0;
1390         cmd.cp_outparm  = 0;
1391         cmd.cp_inmod    = 0;
1392         cmd.cp_opcode   = CLOSE_HCA;
1393         cmd.cp_opmod    = 0;
1394         cmd.cp_flags    = sleepflag;
1395         status = hermon_cmd_post(state, &cmd);
1396         return (status);
1397 }
1398 
1399 
1400 /*
1401  * hermon_set_port_cmd_post()
1402  *    Context: Can be called from interrupt or base context.
1403  *    (Currently called only from attach() path context)
1404  */
1405 int
1406 hermon_set_port_cmd_post(hermon_state_t *state, hermon_hw_set_port_t *initport,
1407     uint_t port, uint_t sleepflag)
1408 {
1409         hermon_mbox_info_t      mbox_info;
1410         hermon_cmd_post_t       cmd;
1411         uint64_t                data;
1412         uint_t                  size;
1413         int                     status, i;
1414 
1415         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1416 
1417         /* Get an "In" mailbox for the command */
1418         mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
1419         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
1420         if (status != HERMON_CMD_SUCCESS) {
1421                 return (status);
1422         }
1423 
1424         /* Copy the Hermon "INIT_PORT" command into the mailbox */
1425         size = sizeof (hermon_hw_set_port_t);
1426         for (i = 0; i < (size >> 3); i++) {
1427                 data = ((uint64_t *)initport)[i];
1428                 ddi_put64(mbox_info.mbi_in->mb_acchdl,
1429                     ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
1430         }
1431 
1432         /* Sync the mailbox for the device to read */
1433         hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
1434 
1435         /* Setup and post the Hermon "SET_PORT" command */
1436         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
1437         cmd.cp_outparm  = 0;
1438         cmd.cp_inmod    = port;
1439         cmd.cp_opcode   = SET_PORT;
1440         cmd.cp_opmod    = 0;
1441         cmd.cp_flags    = sleepflag;
1442         status = hermon_cmd_post(state, &cmd);
1443 
1444         /* Free the mailbox */
1445         hermon_mbox_free(state, &mbox_info);
1446         return (status);
1447 }
1448 
1449 
1450 /*
1451  * hermon_init_port_cmd_post()
1452  *    Context: Can be called from interrupt or base context.
1453  *    (Currently called only from attach() and/or detach() path contexts)
1454  */
1455 int
1456 hermon_init_port_cmd_post(hermon_state_t *state, uint_t port, uint_t sleepflag)
1457 {
1458         hermon_cmd_post_t       cmd;
1459         int                     status;
1460 
1461         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1462 
1463         /* Setup and post the Hermon "INIT_PORT" command */
1464         cmd.cp_inparm   = 0;
1465         cmd.cp_outparm  = 0;
1466         cmd.cp_inmod    = port;
1467         cmd.cp_opcode   = INIT_PORT;
1468         cmd.cp_opmod    = 0;
1469         cmd.cp_flags    = sleepflag;
1470         status = hermon_cmd_post(state, &cmd);
1471 
1472         return (status);
1473 }
1474 
1475 
1476 /*
1477  * hermon_close_port_cmd_post()
1478  *    Context: Can be called from interrupt or base context.
1479  *    (Currently called only from attach() and/or detach() path contexts)
1480  */
1481 int
1482 hermon_close_port_cmd_post(hermon_state_t *state, uint_t port, uint_t sleepflag)
1483 {
1484         hermon_cmd_post_t       cmd;
1485         int                     status;
1486 
1487         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1488 
1489         /* Setup and post the Hermon "CLOSE_PORT" command */
1490         cmd.cp_inparm   = 0;
1491         cmd.cp_outparm  = 0;
1492         cmd.cp_inmod    = port;
1493         cmd.cp_opcode   = CLOSE_PORT;
1494         cmd.cp_opmod    = 0;
1495         cmd.cp_flags    = sleepflag;
1496         status = hermon_cmd_post(state, &cmd);
1497         return (status);
1498 }
1499 
1500 
1501 /*
1502  * hermon_mod_stat_cfg_cmd_post()
1503  *    Context: Can be called only from attach() path
1504  *
1505  * This routine was initially implemented to enable SRQ. That's no longer needed
1506  * in hermon, and the code is conditionally compiled OUT, but left here because
1507  * there are other static configuration parameters we might one day want to set
1508  */
1509 #ifdef HERMON_NO_MOD_STAT_CFG
1510 int
1511 hermon_mod_stat_cfg_cmd_post(hermon_state_t *state)
1512 {
1513         hermon_mbox_info_t      mbox_info;
1514         hermon_cmd_post_t       cmd;
1515         hermon_hw_mod_stat_cfg_t        *mod;
1516         hermon_hw_msg_in_mod_t  inmod;
1517         uint64_t                data;
1518         uint_t                  size;
1519         int                     status, i;
1520 
1521         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1522 
1523         /*
1524          * "MOD_STAT_CFG" needs an INMBOX parameter, to specify what operations
1525          * to do.  However, at the point in time that we call this command, the
1526          * DDR has not yet been initialized, and all INMBOX'es are located in
1527          * DDR.  Because we want to call MOD_STAT_CFG before QUERY_DEVLIM is
1528          * called, and thus call it before DDR is setup, we simply use an
1529          * OUTMBOX memory location here as our INMBOX parameter.
1530          */
1531         mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
1532         status = hermon_mbox_alloc(state, &mbox_info, HERMON_NOSLEEP);
1533         if (status != HERMON_CMD_SUCCESS) {
1534                 return (status);
1535         }
1536 
1537         /*
1538          * Allocate on the heap our 'mod_stat_cfg' structure.  We want to
1539          * ideally move all of this on to the stack in the future, but this
1540          * works well for now.
1541          */
1542         mod = (hermon_hw_mod_stat_cfg_t *)kmem_zalloc(
1543             sizeof (hermon_hw_mod_stat_cfg_t), KM_SLEEP);
1544 
1545         /* Setup "MOD_STAT_CFG" settings */
1546         mod->srq_m   = 1;
1547         mod->srq     = state->hs_cfg_profile->cp_srq_enable;
1548 
1549         if (mod->srq) {
1550                 /*  use DEV_LIMS num srq */
1551                 mod->log_max_srq = state->hs_cfg_profile->cp_log_num_srq;
1552         } else {
1553                 mod->log_max_srq = 0;
1554         }
1555 
1556         /* Copy the "MOD_STAT_CFG" command into the "In" mailbox */
1557         size = sizeof (hermon_hw_mod_stat_cfg_t);
1558         for (i = 0; i < (size >> 3); i++) {
1559                 data = ((uint64_t *)mod)[i];
1560                 ddi_put64(mbox_info.mbi_in->mb_acchdl,
1561                     ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
1562         }
1563 
1564         /* Sync the mailbox for the device to read */
1565         hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
1566 
1567         /* Setup and post the Hermon "MOD_STAT_CFG" command */
1568         cmd.cp_inparm   = mbox_info.mbi_out->mb_mapaddr;
1569         cmd.cp_outparm  = 0;
1570         cmd.cp_inmod    = 0;
1571         cmd.cp_opcode   = MOD_STAT_CFG;
1572         cmd.cp_opmod    = HERMON_MOD_STAT_CFG_PTR;
1573         cmd.cp_flags    = HERMON_CMD_NOSLEEP_SPIN;
1574         status = hermon_cmd_post(state, &cmd);
1575 
1576         /* Free "MOD_STAT_CFG" struct */
1577         kmem_free(mod, sizeof (hermon_hw_mod_stat_cfg_t));
1578 
1579         /* Free the mailbox */
1580         hermon_mbox_free(state, &mbox_info);
1581         return (status);
1582 }
1583 #endif
1584 
1585 
1586 /*
1587  * hermon_map_cmd_post()
1588  *    Context: Can be called only from user or kernel context
1589  *
1590  * Generic routine to map FW, ICMA, and ICM.
1591  */
1592 int
1593 hermon_map_cmd_post(hermon_state_t *state, hermon_dma_info_t *dma,
1594     uint16_t opcode, ddi_dma_cookie_t cookie, uint_t ccount)
1595 {
1596         hermon_mbox_info_t      mbox_info;
1597         hermon_cmd_post_t       cmd;
1598         hermon_hw_vpm_t         vpm;
1599         uint64_t                data;
1600         uint64_t                paddr, vaddr;
1601         uint_t                  size;
1602         int                     status, i, j, k = 0;
1603         int                     max_mailbox_size;
1604         int                     cookie_num_icm_pages;
1605         int                     num_vpm_entries;
1606         int                     log2_npages;
1607         int                     npages;
1608 
1609         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1610 
1611         /* Allocate an IN mailbox */
1612         mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
1613         status = hermon_mbox_alloc(state, &mbox_info, HERMON_SLEEP);
1614         if (status != HERMON_CMD_SUCCESS) {
1615                 return (status);
1616         }
1617 
1618         /* Initialize cmd parameters */
1619         cmd.cp_outparm  = 0;
1620         cmd.cp_opcode   = opcode;
1621         cmd.cp_opmod    = 0;
1622         cmd.cp_flags    = HERMON_CMD_NOSLEEP_SPIN;
1623 
1624         /*
1625          * Allocate a list of VPM (Virtual Physical Mapping) structures.
1626          * A VPM encodes a power-of-2 number of DMA pages that have been
1627          * allocated and are passed in the dma_info. We need to break up
1628          * the DMA cookies that are in the dma_info into power-of-2 page
1629          * mappings. We also need to keep track of the number of VPMs we
1630          * have total, as it is used as the inmod for this command.
1631          */
1632 
1633         /* Start with the ICM address passed and the first cookie */
1634         vaddr  = dma->icmaddr;
1635 
1636         /* Initialize the VPM count and the VPM struct */
1637         num_vpm_entries = 0;
1638         size = sizeof (hermon_hw_vpm_t);
1639         bzero(&vpm, size);
1640 
1641         /*
1642          * Establish a max mailbox size (in VPM entries). If we reach this,
1643          * we must post a MAP command, reinitialzie num_vpm_entries, and
1644          * continue.
1645          */
1646         max_mailbox_size = HERMON_MBOX_SIZE / size;
1647 
1648         /*
1649          * First, walk through the DMA cookies and build VPMs from them.
1650          */
1651         while (ccount-- > 0) {
1652 
1653                 /* Determine the number of ICM pages in this cookie. */
1654                 cookie_num_icm_pages = cookie.dmac_size / HERMON_PAGESIZE;
1655 
1656                 /* Initialize this set of VPM's starting physical address. */
1657                 paddr = cookie.dmac_laddress;
1658 
1659                 /*
1660                  * Now build a set of VPMs for this cookie's memory, breaking
1661                  * up the cookies into multiple VPMs if necessary to achieve
1662                  * the required power-of-2 number of pages per VPM. Once each
1663                  * VPM is constructed, write it out to the mailbox memory.
1664                  */
1665                 for (i = cookie_num_icm_pages; i > 0; i -= npages) {
1666                         log2_npages = highbit(i) - 1;
1667                         npages      = (1 << log2_npages);
1668                         /* Ensure this chunk is aligned on it's own size */
1669                         while (((npages * HERMON_PAGESIZE - 1) & paddr) != 0) {
1670                                 log2_npages--;
1671                                 npages = (1 << log2_npages);
1672                         }
1673                         vpm.log2sz    = log2_npages;
1674 
1675                         vpm.paddr_l = (uint32_t)(paddr >> 12);
1676                         vpm.paddr_h = (uint32_t)(paddr >> 32);
1677                         /* Increment the paddr for the next VPM */
1678                         paddr += npages * HERMON_PAGESIZE;
1679 
1680                         if (opcode == MAP_ICM) {
1681                                 vpm.vaddr_l = (uint32_t)(vaddr >> 12);
1682                                 vpm.vaddr_h = (uint32_t)(vaddr >> 32);
1683                                 /* Increment the ICM address for the next VPM */
1684                                 vaddr += npages * HERMON_PAGESIZE;
1685                         }
1686 
1687                         /*
1688                          * Copy this VPM into the "In" mailbox. Note we're
1689                          * using 'k' as the offset from mb_addr for this cmd.
1690                          */
1691                         for (j = 0; j < (size >> 3); j++, k++) {
1692                                 data = ((uint64_t *)(void *)&vpm)[j];
1693                                 ddi_put64(mbox_info.mbi_in->mb_acchdl,
1694                                     ((uint64_t *)mbox_info.mbi_in->mb_addr + k),
1695                                     data);
1696                         }
1697 
1698                         /*
1699                          * Increment the number of VPM entries and check
1700                          * against max mailbox size. If we have reached
1701                          * the maximum mailbox size, post the map cmd.
1702                          */
1703                         if (++num_vpm_entries == max_mailbox_size) {
1704 
1705                                 /* Sync the mailbox for the device to read */
1706                                 hermon_mbox_sync(mbox_info.mbi_in, 0, (size *
1707                                     num_vpm_entries), DDI_DMA_SYNC_FORDEV);
1708 
1709                                 /* Setup and post the command */
1710                                 cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
1711                                 cmd.cp_inmod    = num_vpm_entries;
1712                                 status = hermon_cmd_post(state, &cmd);
1713                                 if (status != HERMON_CMD_SUCCESS) {
1714                                         cmn_err(CE_NOTE, "hermon%d: %s cmd "
1715                                             "failed (0x%x)", state->hs_instance,
1716                                             opcode == MAP_FA ? "MAP_FA" :
1717                                             opcode == MAP_ICM ? "MAP_ICM" :
1718                                             opcode == MAP_ICM_AUX ? "MAP_ICMA" :
1719                                             "UNKNOWN", status);
1720                                         goto map_fail;
1721                                 }
1722 
1723                                 /*
1724                                  * Reinitialize num_vpm_entries, and the
1725                                  * mb_addr offset
1726                                  */
1727                                 num_vpm_entries = k = 0;
1728                         }
1729                 }
1730 
1731                 /* If count remains, move onto the next cookie */
1732                 if (ccount != 0) {
1733                         ddi_dma_nextcookie(dma->dma_hdl, &cookie);
1734                 }
1735         }
1736 
1737         if (num_vpm_entries) {
1738 
1739                 /* Sync the mailbox for the device to read */
1740                 hermon_mbox_sync(mbox_info.mbi_in, 0, (size * num_vpm_entries),
1741                     DDI_DMA_SYNC_FORDEV);
1742 
1743                 /* Setup and post the command */
1744                 cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
1745                 cmd.cp_inmod    = num_vpm_entries;
1746                 status = hermon_cmd_post(state, &cmd);
1747                 if (status != HERMON_CMD_SUCCESS) {
1748                         cmn_err(CE_NOTE, "hermon%d: %s cmd "
1749                             "failed (0x%x)", state->hs_instance,
1750                             opcode == MAP_FA ? "MAP_FA" :
1751                             opcode == MAP_ICM ? "MAP_ICM" :
1752                             opcode == MAP_ICM_AUX ? "MAP_ICMA" :
1753                             "UNKNOWN", status);
1754                         goto map_fail;
1755                 }
1756         }
1757 
1758 map_fail:
1759         /* Free the mailbox */
1760         hermon_mbox_free(state, &mbox_info);
1761         return (status);
1762 }
1763 
1764 
1765 /*
1766  * hermon_unmap_fa_cmd_post()
1767  *    Context: Can be called only from attach() path
1768  */
1769 int
1770 hermon_unmap_fa_cmd_post(hermon_state_t *state)
1771 {
1772         hermon_cmd_post_t       cmd;
1773         int                     status;
1774 
1775         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1776 
1777         /* Setup and post the Hermon "UNMAP_FA" command */
1778         cmd.cp_inparm   = 0;
1779         cmd.cp_outparm  = 0;
1780         cmd.cp_inmod    = 0;
1781         cmd.cp_opcode   = UNMAP_FA;
1782         cmd.cp_opmod    = 0;
1783         cmd.cp_flags    = HERMON_CMD_NOSLEEP_SPIN;
1784         status = hermon_cmd_post(state, &cmd);
1785 
1786         return (status);
1787 }
1788 
1789 
1790 /*
1791  * hermon_run_fw_cmd_post()
1792  *    Context: Can be called only from attach() path
1793  */
1794 int
1795 hermon_run_fw_cmd_post(hermon_state_t *state)
1796 {
1797         hermon_cmd_post_t       cmd;
1798         int                     status;
1799 
1800         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1801 
1802         /* Setup and post the Hermon "RUN_FW" command */
1803         cmd.cp_inparm   = 0;
1804         cmd.cp_outparm  = 0;
1805         cmd.cp_inmod    = 0;
1806         cmd.cp_opcode   = RUN_FW;
1807         cmd.cp_opmod    = 0;
1808         cmd.cp_flags    = HERMON_CMD_NOSLEEP_SPIN;
1809 
1810         status = hermon_cmd_post(state, &cmd);
1811 #ifdef FMA_TEST
1812         if (hermon_test_num == -2) {
1813                 status = HERMON_CMD_BAD_NVMEM;
1814                 /*
1815                  * No need of an ereport here since this case
1816                  * is treated as a degradation later.
1817                  */
1818                 HERMON_FMANOTE(state, HERMON_FMA_BADNVMEM);
1819         }
1820 #endif
1821         return (status);
1822 }
1823 
1824 
1825 /*
1826  * hermon_set_icm_size_cmd_post()
1827  *    Context: Can be called only from attach() path
1828  */
1829 int
1830 hermon_set_icm_size_cmd_post(hermon_state_t *state)
1831 {
1832         hermon_cmd_post_t       cmd;
1833         int                     status;
1834 
1835         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1836 
1837         /* Setup and post the Hermon "SET_ICM_SIZE" command */
1838         cmd.cp_inparm   = (uint64_t)state->hs_icm_sz;
1839         cmd.cp_outparm  = 0;
1840         cmd.cp_inmod    = 0;
1841         cmd.cp_opcode   = SET_ICM_SIZE;
1842         cmd.cp_opmod    = 0;
1843         cmd.cp_flags    = HERMON_CMD_NOSLEEP_SPIN;
1844         status = hermon_cmd_post(state, &cmd);
1845 
1846         /*
1847          * Aux ICM size in 4K pages returned in output param
1848          * convert it to bytes
1849          */
1850         state->hs_icma_sz = (uint64_t)(cmd.cp_outparm << HERMON_PAGESHIFT);
1851         return (status);
1852 }
1853 
1854 
1855 /*
1856  * hermon_unmap_icm_aux_cmd_post()
1857  *    Context: Can be called only from attach() path
1858  */
1859 int
1860 hermon_unmap_icm_aux_cmd_post(hermon_state_t *state)
1861 {
1862         hermon_cmd_post_t       cmd;
1863         int                     status;
1864 
1865         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1866 
1867         /* Setup and post the Hermon "UNMAP_ICM_AUX" command */
1868         cmd.cp_inparm   = 0;
1869         cmd.cp_outparm  = 0;
1870         cmd.cp_inmod    = 0;
1871         cmd.cp_opcode   = UNMAP_ICM_AUX;
1872         cmd.cp_opmod    = 0;
1873         cmd.cp_flags    = HERMON_CMD_NOSLEEP_SPIN;
1874         status = hermon_cmd_post(state, &cmd);
1875         return (status);
1876 }
1877 
1878 
1879 /*
1880  * hermon_unmap_icm_cmd_post()
1881  *    Context: Can be called from base or attach context
1882  */
1883 int
1884 hermon_unmap_icm_cmd_post(hermon_state_t *state, hermon_dma_info_t *dma_info)
1885 {
1886         hermon_cmd_post_t       cmd;
1887         uint64_t                addr;
1888         uint32_t                npages;
1889         int                     status;
1890 
1891         /*
1892          * Setup and post the Hermon "UNMAP_ICM" command. If a
1893          * hermon_dma_info_t was passed, we want to unmap a set
1894          * of pages. Otherwise, unmap all of ICM.
1895          */
1896         if (dma_info != NULL) {
1897                 addr   = dma_info->icmaddr;
1898                 npages = dma_info->length / HERMON_PAGESIZE;
1899         } else {
1900                 addr   = 0;
1901                 npages = state->hs_icm_sz / HERMON_PAGESIZE;
1902         }
1903 
1904         /* Setup and post the Hermon "UNMAP_ICM" command */
1905         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1906         cmd.cp_inparm   = addr;
1907         cmd.cp_outparm  = 0;
1908         cmd.cp_inmod    = npages;
1909         cmd.cp_opcode   = UNMAP_ICM;
1910         cmd.cp_opmod    = 0;
1911         cmd.cp_flags    = HERMON_CMD_NOSLEEP_SPIN;
1912         status = hermon_cmd_post(state, &cmd);
1913         return (status);
1914 }
1915 
1916 
1917 /*
1918  * hermon_mad_ifc_cmd_post()
1919  *    Context: Can be called from interrupt or base context.
1920  */
1921 int
1922 hermon_mad_ifc_cmd_post(hermon_state_t *state, uint_t port,
1923     uint_t sleepflag, uint32_t *mad, uint32_t *resp)
1924 {
1925         hermon_mbox_info_t      mbox_info;
1926         hermon_cmd_post_t       cmd;
1927         uint_t                  size;
1928         int                     status;
1929 
1930         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1931 
1932         /* Get "In" and "Out" mailboxes for the command */
1933         mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
1934         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
1935         if (status != HERMON_CMD_SUCCESS) {
1936                 return (status);
1937         }
1938 
1939         /* Copy the request MAD into the "In" mailbox */
1940         size = HERMON_CMD_MAD_IFC_SIZE;
1941         bcopy(mad, mbox_info.mbi_in->mb_addr, size);
1942 
1943         /* Sync the mailbox for the device to read */
1944         hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
1945 
1946         /* Setup the Hermon "MAD_IFC" command */
1947         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
1948         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
1949         cmd.cp_inmod    = port;
1950         cmd.cp_opcode   = MAD_IFC;
1951         cmd.cp_opmod    = HERMON_CMD_MKEY_CHECK;  /* Enable MKey checking */
1952         cmd.cp_flags    = sleepflag;
1953         status = hermon_cmd_post(state, &cmd);
1954         if (status != HERMON_CMD_SUCCESS) {
1955                 goto mad_ifc_fail;
1956         }
1957 
1958         /* Sync the mailbox to read the results */
1959         hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
1960 
1961         /* Copy the response MAD into "resp" */
1962         bcopy(mbox_info.mbi_out->mb_addr, resp, size);
1963 
1964 mad_ifc_fail:
1965         /* Free the mailbox */
1966         hermon_mbox_free(state, &mbox_info);
1967         return (status);
1968 }
1969 
1970 
1971 /*
1972  * hermon_getportinfo_cmd_post()
1973  *    Context: Can be called from interrupt or base context.
1974  */
1975 int
1976 hermon_getportinfo_cmd_post(hermon_state_t *state, uint_t port,
1977     uint_t sleepflag, sm_portinfo_t *portinfo)
1978 {
1979         hermon_mbox_info_t      mbox_info;
1980         hermon_cmd_post_t       cmd;
1981         uint32_t                *mbox;
1982         uint_t                  size;
1983         int                     status, i;
1984 
1985         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
1986 
1987         /* Get "In" and "Out" mailboxes for the command */
1988         mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
1989         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
1990         if (status != HERMON_CMD_SUCCESS) {
1991                 return (status);
1992         }
1993 
1994         /* Build the GetPortInfo request MAD in the "In" mailbox */
1995         size = HERMON_CMD_MAD_IFC_SIZE;
1996         mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
1997         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
1998         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
1999         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2000         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2001         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_PORTINFO);
2002         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], port);
2003         for (i = 6; i < (size >> 2); i++) {
2004                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
2005         }
2006 
2007         /* Sync the mailbox for the device to read */
2008         hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2009 
2010         /* Setup the Hermon "MAD_IFC" command */
2011         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
2012         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
2013         cmd.cp_inmod    = port;
2014         cmd.cp_opcode   = MAD_IFC;
2015         cmd.cp_opmod    = HERMON_CMD_MKEY_DONTCHECK;  /* No MKey checking */
2016         cmd.cp_flags    = HERMON_CMD_NOSLEEP_SPIN; /* NO SLEEP */
2017         status = hermon_cmd_post(state, &cmd);
2018         if (status != HERMON_CMD_SUCCESS) {
2019                 goto getportinfo_fail;
2020         }
2021 
2022         /* Sync the mailbox to read the results */
2023         size = sizeof (sm_portinfo_t);
2024         hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
2025             size, DDI_DMA_SYNC_FORCPU);
2026 
2027         /*
2028          * Copy GetPortInfo response MAD into "portinfo".  Do any endian
2029          * swapping that may be necessary to flip any of the "portinfo"
2030          * fields
2031          */
2032         bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
2033             HERMON_CMD_MADDATA_OFFSET), portinfo, size);
2034         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*portinfo))
2035         HERMON_GETPORTINFO_SWAP(portinfo);
2036 
2037 getportinfo_fail:
2038         /* Free the mailbox */
2039         hermon_mbox_free(state, &mbox_info);
2040         return (status);
2041 }
2042 
2043 /*
2044  * hermon_is_ext_port_counters_supported()
2045  *
2046  * Determine weather extended port counters are supported or not by sending
2047  * ClassPortInfo perf mgmt class MAD.
2048  */
2049 int
2050 hermon_is_ext_port_counters_supported(hermon_state_t *state, uint_t port,
2051     uint_t sleepflag, int *ext_width_supported)
2052 {
2053         hermon_mbox_info_t      mbox_info;
2054         hermon_cmd_post_t       cmd;
2055         uint64_t                data;
2056         uint32_t                *mbox;
2057         int                     status;
2058 
2059         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2060 
2061         /* Get "In" and "Out" mailboxes for the command */
2062         mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2063         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2064         if (status != HERMON_CMD_SUCCESS) {
2065                 return (status);
2066         }
2067 
2068         /* Build the ClassPortInfo request MAD in the "In" mailbox */
2069         mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2070 
2071         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_PERF_GET);
2072         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2073         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2074         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2075         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4],
2076             HERMON_CMD_CLASSPORTINFO);
2077         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], HERMON_CMD_PERFATTR);
2078 
2079         /* Sync the mailbox for the device to read */
2080         hermon_mbox_sync(mbox_info.mbi_in, 0, HERMON_CMD_MAD_IFC_SIZE,
2081             DDI_DMA_SYNC_FORDEV);
2082 
2083         /* Setup the Hermon "MAD_IFC" command */
2084         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
2085         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
2086         cmd.cp_inmod    = port;
2087         cmd.cp_opcode   = MAD_IFC;
2088         /* No MKey and BKey checking */
2089         cmd.cp_opmod    = HERMON_CMD_MKEY_DONTCHECK | HERMON_CMD_BKEY_DONTCHECK;
2090         cmd.cp_flags    = HERMON_CMD_NOSLEEP_SPIN; /* NO SLEEP */
2091         status = hermon_cmd_post(state, &cmd);
2092         if (status != HERMON_CMD_SUCCESS) {
2093                 goto fail;
2094         }
2095 
2096         /* Sync the mailbox to read the results */
2097         hermon_mbox_sync(mbox_info.mbi_out, 0, HERMON_CMD_MAD_IFC_SIZE,
2098             DDI_DMA_SYNC_FORCPU);
2099 
2100         /*
2101          * We can discard the MAD header and the reserved area of the
2102          * perf mgmt class MAD
2103          */
2104         data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2105             ((uint64_t *)mbox_info.mbi_out->mb_addr + 8));
2106         *ext_width_supported = (data & (HERMON_IS_EXT_WIDTH_SUPPORTED |
2107             HERMON_IS_EXT_WIDTH_SUPPORTED_NOIETF)) ? 1 : 0;
2108 
2109 fail:
2110         /* Free the mailbox */
2111         hermon_mbox_free(state, &mbox_info);
2112         return (status);
2113 }
2114 
2115 /*
2116  * hermon_getextpefcntr_cmd_post()
2117  *
2118  * Read the extended performance counters of the specified port and
2119  * copy them into perfinfo.
2120  */
2121 int
2122 hermon_getextperfcntr_cmd_post(hermon_state_t *state, uint_t port,
2123     uint_t sleepflag, hermon_hw_sm_extperfcntr_t *perfinfo)
2124 {
2125         hermon_mbox_info_t      mbox_info;
2126         hermon_cmd_post_t       cmd;
2127         uint64_t                data;
2128         uint32_t                *mbox;
2129         int                     status, i;
2130 
2131         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2132 
2133         /* Get "In" and "Out" mailboxes for the command */
2134         mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2135         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2136         if (status != HERMON_CMD_SUCCESS) {
2137                 return (status);
2138         }
2139 
2140         /* Build PortCountersExtended request MAD in the "In" mailbox */
2141         mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2142 
2143         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_PERF_GET);
2144         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2145         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2146         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2147         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4],
2148             HERMON_CMD_EXTPERFCNTRS);
2149         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], HERMON_CMD_PERFATTR);
2150         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16], (port << 16));
2151 
2152         /* Sync the mailbox for the device to read */
2153         hermon_mbox_sync(mbox_info.mbi_in, 0, HERMON_CMD_MAD_IFC_SIZE,
2154             DDI_DMA_SYNC_FORDEV);
2155 
2156         /* Setup the Hermon "MAD_IFC" command */
2157         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
2158         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
2159         cmd.cp_inmod    = port;
2160         cmd.cp_opcode   = MAD_IFC;
2161         /* No MKey and BKey checking */
2162         cmd.cp_opmod    = HERMON_CMD_MKEY_DONTCHECK | HERMON_CMD_BKEY_DONTCHECK;
2163         cmd.cp_flags    = HERMON_CMD_NOSLEEP_SPIN; /* NO SLEEP */
2164         status = hermon_cmd_post(state, &cmd);
2165         if (status != HERMON_CMD_SUCCESS) {
2166                 goto fail;
2167         }
2168 
2169         /* Sync the mailbox to read the results */
2170         hermon_mbox_sync(mbox_info.mbi_out, 0, HERMON_CMD_MAD_IFC_SIZE,
2171             DDI_DMA_SYNC_FORCPU);
2172 
2173         /*
2174          * Copy Perfcounters into "perfinfo". We can discard the MAD
2175          * header and the reserved area of the perf mgmt class MAD.
2176          */
2177         for (i = 0; i < (sizeof (hermon_hw_sm_extperfcntr_t) >> 3); i++) {
2178                 data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2179                     ((uint64_t *)mbox_info.mbi_out->mb_addr + i + 8));
2180                 ((uint64_t *)(void *)perfinfo)[i] = data;
2181         }
2182 
2183 fail:
2184         /* Free the mailbox */
2185         hermon_mbox_free(state, &mbox_info);
2186         return (status);
2187 }
2188 
2189 /*
2190  * hermon_getpefcntr_cmd_post()
2191  *    Context: Can be called from interrupt or base context.
2192  *
2193  * If reset is zero, read the performance counters of the specified port and
2194  * copy them into perfinfo.
2195  * If reset is non-zero reset the performance counters of the specified port.
2196  */
2197 int
2198 hermon_getperfcntr_cmd_post(hermon_state_t *state, uint_t port,
2199     uint_t sleepflag, hermon_hw_sm_perfcntr_t *perfinfo, int reset)
2200 {
2201         hermon_mbox_info_t      mbox_info;
2202         hermon_cmd_post_t       cmd;
2203         uint64_t                data;
2204         uint32_t                *mbox;
2205         uint_t                  size;
2206         int                     status, i;
2207 
2208         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2209 
2210         /* Get "In" and "Out" mailboxes for the command */
2211         mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2212         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2213         if (status != HERMON_CMD_SUCCESS) {
2214                 return (status);
2215         }
2216 
2217         /* Build the GetPortInfo request MAD in the "In" mailbox */
2218         size = HERMON_CMD_MAD_IFC_SIZE;
2219         mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2220 
2221         if (reset) {
2222                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0],
2223                     HERMON_CMD_PERF_SET);
2224         } else {
2225                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0],
2226                     HERMON_CMD_PERF_GET);
2227         }
2228         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2229         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2230         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2231         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_PERFCNTRS);
2232         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], HERMON_CMD_PERFATTR);
2233 
2234         if (reset) {
2235                 /* reset counters for XmitData, RcvData, XmitPkts, RcvPkts */
2236                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16],
2237                     ((port << 16) | 0xf000));
2238 
2239                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[22], 0);
2240                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[23], 0);
2241                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[24], 0);
2242                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[25], 0);
2243         } else
2244                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16], (port << 16));
2245 
2246         /* Sync the mailbox for the device to read */
2247         hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2248 
2249         /* Setup the Hermon "MAD_IFC" command */
2250         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
2251         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
2252         cmd.cp_inmod    = port;
2253         cmd.cp_opcode   = MAD_IFC;
2254         /* No MKey and BKey checking */
2255         cmd.cp_opmod    = HERMON_CMD_MKEY_DONTCHECK | HERMON_CMD_BKEY_DONTCHECK;
2256         cmd.cp_flags    = HERMON_CMD_NOSLEEP_SPIN; /* NO SLEEP */
2257         status = hermon_cmd_post(state, &cmd);
2258         if (status != HERMON_CMD_SUCCESS) {
2259                 goto getperfinfo_fail;
2260         }
2261 
2262         /* Sync the mailbox to read the results */
2263         size = HERMON_CMD_MAD_IFC_SIZE;
2264         hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
2265 
2266         if (reset == 0) {
2267                 size = sizeof (hermon_hw_sm_perfcntr_t); /* for the copy */
2268                 /*
2269                  * Copy Perfcounters into "perfinfo".  We can discard the MAD
2270                  * header and the 8 Quadword reserved area of the PERM mgmt
2271                  * class MAD
2272                  */
2273 
2274                 for (i = 0; i < size >> 3; i++) {
2275                         data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2276                             ((uint64_t *)mbox_info.mbi_out->mb_addr + i + 8));
2277                         ((uint64_t *)(void *)perfinfo)[i] = data;
2278                 }
2279         }
2280 
2281 getperfinfo_fail:
2282         /* Free the mailbox */
2283         hermon_mbox_free(state, &mbox_info);
2284         return (status);
2285 }
2286 
2287 
2288 
2289 /*
2290  * hermon_getnodeinfo_cmd_post()
2291  *    Context: Can be called from interrupt or base context.
2292  *    (Currently called only from attach() and detach() path contexts)
2293  */
2294 int
2295 hermon_getnodeinfo_cmd_post(hermon_state_t *state, uint_t sleepflag,
2296     sm_nodeinfo_t *nodeinfo)
2297 {
2298         hermon_mbox_info_t      mbox_info;
2299         hermon_cmd_post_t       cmd;
2300         uint32_t                *mbox;
2301         uint_t                  size;
2302         int                     status, i;
2303 
2304         /* Make sure we are called with the correct flag */
2305         ASSERT(sleepflag == HERMON_CMD_NOSLEEP_SPIN);
2306 
2307         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2308 
2309         /* Get "In" and "Out" mailboxes for the command */
2310         mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2311         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2312         if (status != HERMON_CMD_SUCCESS) {
2313                 return (status);
2314         }
2315 
2316         /* Build the GetNodeInfo request MAD into the "In" mailbox */
2317         size = HERMON_CMD_MAD_IFC_SIZE;
2318         mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2319         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
2320         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2321         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2322         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2323         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_NODEINFO);
2324         for (i = 5; i < (size >> 2); i++) {
2325                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
2326         }
2327 
2328         /* Sync the mailbox for the device to read */
2329         hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2330 
2331         /* Setup the Hermon "MAD_IFC" command */
2332         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
2333         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
2334         cmd.cp_inmod    = 1;  /* Get NodeInfo from port #1 */
2335         cmd.cp_opcode   = MAD_IFC;
2336         cmd.cp_opmod    = HERMON_CMD_MKEY_DONTCHECK;  /* No MKey checking */
2337         cmd.cp_flags    = sleepflag;
2338         status = hermon_cmd_post(state, &cmd);
2339         if (status != HERMON_CMD_SUCCESS) {
2340                 goto getnodeinfo_fail;
2341         }
2342 
2343         /* Sync the mailbox to read the results */
2344         size = sizeof (sm_nodeinfo_t);
2345         hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
2346             size, DDI_DMA_SYNC_FORCPU);
2347 
2348         /*
2349          * Copy GetNodeInfo response MAD into "nodeinfo".  Do any endian
2350          * swapping that may be necessary to flip any of the "nodeinfo"
2351          * fields
2352          */
2353         bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
2354             HERMON_CMD_MADDATA_OFFSET), nodeinfo, size);
2355         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*nodeinfo))
2356         HERMON_GETNODEINFO_SWAP(nodeinfo);
2357 
2358 getnodeinfo_fail:
2359         /* Free the mailbox */
2360         hermon_mbox_free(state, &mbox_info);
2361         return (status);
2362 }
2363 
2364 
2365 /*
2366  * hermon_getnodedesc_cmd_post()
2367  *    Context: Can be called from interrupt or base context.
2368  *    (Currently called only from attach() and detach() path contexts)
2369  */
2370 int
2371 hermon_getnodedesc_cmd_post(hermon_state_t *state, uint_t sleepflag,
2372     sm_nodedesc_t *nodedesc)
2373 {
2374         hermon_mbox_info_t      mbox_info;
2375         hermon_cmd_post_t       cmd;
2376         uint32_t                *mbox;
2377         uint_t                  size;
2378         int                     status, i;
2379 
2380         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2381 
2382         /* Get "In" and "Out" mailboxes for the command */
2383         mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2384         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2385         if (status != HERMON_CMD_SUCCESS) {
2386                 return (status);
2387         }
2388 
2389         /* Build the GetNodeDesc request MAD into the "In" mailbox */
2390         size = HERMON_CMD_MAD_IFC_SIZE;
2391         mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2392         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
2393         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2394         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2395         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2396         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_NODEDESC);
2397         for (i = 5; i < (size >> 2); i++) {
2398                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
2399         }
2400 
2401         /* Sync the mailbox for the device to read */
2402         hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2403 
2404         /* Setup the Hermon "MAD_IFC" command */
2405         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
2406         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
2407         cmd.cp_inmod    = 1;  /* Get NodeDesc from port #1 */
2408         cmd.cp_opcode   = MAD_IFC;
2409         cmd.cp_opmod    = HERMON_CMD_MKEY_DONTCHECK;  /* No MKey checking */
2410         cmd.cp_flags    = sleepflag;
2411         status = hermon_cmd_post(state, &cmd);
2412         if (status != HERMON_CMD_SUCCESS) {
2413                 goto getnodedesc_fail;
2414         }
2415 
2416         /* Sync the mailbox to read the results */
2417         size = sizeof (sm_nodedesc_t);
2418         hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
2419             size, DDI_DMA_SYNC_FORCPU);
2420 
2421         /* Copy GetNodeDesc response MAD into "nodedesc" */
2422         bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
2423             HERMON_CMD_MADDATA_OFFSET), nodedesc, size);
2424 
2425 getnodedesc_fail:
2426         /* Free the mailbox */
2427         hermon_mbox_free(state, &mbox_info);
2428         return (status);
2429 }
2430 
2431 
2432 /*
2433  * hermon_getguidinfo_cmd_post()
2434  *    Context: Can be called from interrupt or base context.
2435  */
2436 int
2437 hermon_getguidinfo_cmd_post(hermon_state_t *state, uint_t port,
2438     uint_t guidblock, uint_t sleepflag, sm_guidinfo_t *guidinfo)
2439 {
2440         hermon_mbox_info_t      mbox_info;
2441         hermon_cmd_post_t       cmd;
2442         uint32_t                *mbox;
2443         uint_t                  size;
2444         int                     status, i;
2445 
2446         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2447 
2448         /* Get "In" and "Out" mailboxes for the command */
2449         mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2450         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2451         if (status != HERMON_CMD_SUCCESS) {
2452                 return (status);
2453         }
2454 
2455         /* Build the GetGUIDInfo request MAD into the "In" mailbox */
2456         size = HERMON_CMD_MAD_IFC_SIZE;
2457         mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2458         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
2459         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2460         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2461         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2462         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_GUIDINFO);
2463         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], guidblock);
2464         for (i = 6; i < (size >> 2); i++) {
2465                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
2466         }
2467 
2468         /* Sync the mailbox for the device to read */
2469         hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2470 
2471         /* Setup the Hermon "MAD_IFC" command */
2472         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
2473         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
2474         cmd.cp_inmod    = port;
2475         cmd.cp_opcode   = MAD_IFC;
2476         cmd.cp_opmod    = HERMON_CMD_MKEY_DONTCHECK;  /* No MKey checking */
2477         cmd.cp_flags    = sleepflag;
2478         status = hermon_cmd_post(state, &cmd);
2479         if (status != HERMON_CMD_SUCCESS) {
2480                 goto getguidinfo_fail;
2481         }
2482 
2483         /* Sync the mailbox to read the results */
2484         size = sizeof (sm_guidinfo_t);
2485         hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
2486             size, DDI_DMA_SYNC_FORCPU);
2487 
2488         /*
2489          * Copy GetGUIDInfo response MAD into "guidinfo".  Do any endian
2490          * swapping that may be necessary to flip the "guidinfo" fields
2491          */
2492         bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
2493             HERMON_CMD_MADDATA_OFFSET), guidinfo, size);
2494         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*guidinfo))
2495         HERMON_GETGUIDINFO_SWAP(guidinfo);
2496 
2497 getguidinfo_fail:
2498         /* Free the mailbox */
2499         hermon_mbox_free(state, &mbox_info);
2500         return (status);
2501 }
2502 
2503 
2504 /*
2505  * hermon_getpkeytable_cmd_post()
2506  *    Context: Can be called from interrupt or base context.
2507  */
2508 int
2509 hermon_getpkeytable_cmd_post(hermon_state_t *state, uint_t port,
2510     uint_t pkeyblock, uint_t sleepflag, sm_pkey_table_t *pkeytable)
2511 {
2512         hermon_mbox_info_t      mbox_info;
2513         hermon_cmd_post_t       cmd;
2514         uint32_t                *mbox;
2515         uint_t                  size;
2516         int                     status, i;
2517 
2518         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2519 
2520         /* Get "In" and "Out" mailboxes for the command */
2521         mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX;
2522         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2523         if (status != HERMON_CMD_SUCCESS) {
2524                 return (status);
2525         }
2526 
2527         /* Build the GetPkeyTable request MAD into the "In" mailbox */
2528         size = HERMON_CMD_MAD_IFC_SIZE;
2529         mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2530         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0);
2531         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1);
2532         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2);
2533         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3);
2534         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_PKEYTBLE);
2535         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], pkeyblock);
2536         for (i = 6; i < (size >> 2); i++) {
2537                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
2538         }
2539 
2540         /* Sync the mailbox for the device to read */
2541         hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2542 
2543         /* Setup the Hermon "MAD_IFC" command */
2544         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
2545         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
2546         cmd.cp_inmod    = port;
2547         cmd.cp_opcode   = MAD_IFC;
2548         cmd.cp_opmod    = HERMON_CMD_MKEY_DONTCHECK;  /* No MKey checking */
2549         cmd.cp_flags    = sleepflag;
2550         status = hermon_cmd_post(state, &cmd);
2551         if (status != HERMON_CMD_SUCCESS) {
2552                 goto getpkeytable_fail;
2553         }
2554 
2555         /* Sync the mailbox to read the results */
2556         size = sizeof (sm_pkey_table_t);
2557         hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET,
2558             size, DDI_DMA_SYNC_FORCPU);
2559 
2560         /*
2561          * Copy GetPKeyTable response MAD into "pkeytable".  Do any endian
2562          * swapping that may be necessary to flip the "pkeytable" fields
2563          */
2564         bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
2565             HERMON_CMD_MADDATA_OFFSET), pkeytable, size);
2566         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*pkeytable))
2567         HERMON_GETPKEYTABLE_SWAP(pkeytable);
2568 
2569 getpkeytable_fail:
2570         /* Free the mailbox */
2571         hermon_mbox_free(state, &mbox_info);
2572         return (status);
2573 }
2574 
2575 
2576 /*
2577  * hermon_write_mtt_cmd_post()
2578  *    Context: Can be called from interrupt or base context.
2579  */
2580 int
2581 hermon_write_mtt_cmd_post(hermon_state_t *state, hermon_rsrc_t *mtt,
2582     uint64_t start_addr, uint_t nummtt, uint_t sleepflag)
2583 {
2584         hermon_mbox_info_t      mbox_info;
2585         hermon_cmd_post_t       cmd;
2586         uint64_t                data;
2587         uint_t                  size;
2588         int                     status;
2589         int                     i;
2590 
2591         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2592 
2593         /* Get an "In" mailbox for the command */
2594         mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
2595         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2596         if (status != HERMON_CMD_SUCCESS) {
2597                 return (status);
2598         }
2599 
2600         /*
2601          * The WRITE_MTT command input parameter contains the 64-bit addr of
2602          * the first target MTT, followed by 64 bits reserved, followed by an
2603          * array of MTT entries.
2604          *
2605          */
2606         ddi_put64(mbox_info.mbi_in->mb_acchdl,
2607             ((uint64_t *)mbox_info.mbi_in->mb_addr),
2608             start_addr);
2609 
2610         ddi_put64(mbox_info.mbi_in->mb_acchdl,
2611             ((uint64_t *)mbox_info.mbi_in->mb_addr + 1), 0x0);
2612 
2613         for (i = 0; i < nummtt; i++) {
2614                 data = ((uint64_t *)mtt->hr_addr)[i];
2615                 ddi_put64(mbox_info.mbi_in->mb_acchdl,
2616                     ((uint64_t *)mbox_info.mbi_in->mb_addr + i + 2), data);
2617         }
2618 
2619         /* Sync the mailbox for the device to read */
2620         size = (nummtt << HERMON_MTT_SIZE_SHIFT) + HERMON_CMD_WRITEMTT_RSVD_SZ;
2621         hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2622 
2623         /* Setup and post Hermon "WRITE_MTT" command */
2624         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
2625         cmd.cp_outparm  = 0;
2626         cmd.cp_inmod    = nummtt;
2627         cmd.cp_opcode   = WRITE_MTT;
2628         cmd.cp_opmod    = 0;
2629         cmd.cp_flags    = sleepflag;
2630         status = hermon_cmd_post(state, &cmd);
2631         if (status != HERMON_CMD_SUCCESS) {
2632                 cmn_err(CE_CONT, "WRITE_MTT failed (0x%x)\n", status);
2633         }
2634 
2635         /* Free the mailbox */
2636         hermon_mbox_free(state, &mbox_info);
2637         return (status);
2638 }
2639 
2640 
2641 /*
2642  * hermon_sync_tpt_cmd_post()
2643  *    Context: Can be called from interrupt or base context.
2644  */
2645 int
2646 hermon_sync_tpt_cmd_post(hermon_state_t *state, uint_t sleepflag)
2647 {
2648         hermon_cmd_post_t       cmd;
2649         int                     status;
2650 
2651         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2652 
2653         /* Setup and post the Hermon "SYNC_TPT" command */
2654         cmd.cp_inparm   = 0;
2655         cmd.cp_outparm  = 0;
2656         cmd.cp_inmod    = 0;
2657         cmd.cp_opcode   = SYNC_TPT;
2658         cmd.cp_opmod    = 0;
2659         cmd.cp_flags    = sleepflag;
2660         status = hermon_cmd_post(state, &cmd);
2661 
2662         return (status);
2663 }
2664 
2665 /*
2666  * hermon_map_eq_cmd_post()
2667  *    Context: Can be called from interrupt or base context.
2668  *    (Currently called only from attach() and/or detach() path contexts)
2669  */
2670 int
2671 hermon_map_eq_cmd_post(hermon_state_t *state, uint_t map, uint_t eqcindx,
2672     uint64_t eqmapmask, uint_t sleepflag)
2673 {
2674         hermon_cmd_post_t       cmd;
2675         int                     status;
2676 
2677         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2678 
2679         /* Setup and post Hermon "MAP_EQ" command */
2680         cmd.cp_inparm   = eqmapmask;
2681         cmd.cp_outparm  = 0;
2682         cmd.cp_inmod    = eqcindx;
2683         if (map != HERMON_CMD_MAP_EQ_EVT_MAP) {
2684                 cmd.cp_inmod |= HERMON_CMD_UNMAP_EQ_MASK;
2685         }
2686         cmd.cp_opcode   = MAP_EQ;
2687         cmd.cp_opmod    = 0;
2688         cmd.cp_flags    = sleepflag;
2689         status = hermon_cmd_post(state, &cmd);
2690         return (status);
2691 }
2692 
2693 
2694 /*
2695  * hermon_resize_cq_cmd_post()
2696  *    Context: Can be called from interrupt or base context.
2697  */
2698 int
2699 hermon_resize_cq_cmd_post(hermon_state_t *state, hermon_hw_cqc_t *cqc,
2700     uint_t cqcindx, uint32_t *prod_indx, uint_t sleepflag)
2701 {
2702         hermon_mbox_info_t      mbox_info;
2703         hermon_cmd_post_t       cmd;
2704         uint64_t                data;
2705         uint_t                  size;
2706         int                     status, i;
2707 
2708         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2709 
2710         /* Get an "In" mailbox for the command */
2711         mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
2712         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2713         if (status != HERMON_CMD_SUCCESS) {
2714                 return (status);
2715         }
2716 
2717         /* Copy the Hermon "MODIFY_CQ" command into mailbox */
2718         size = sizeof (hermon_hw_cqc_t);
2719         for (i = 0; i < (size >> 3); i++) {
2720                 data = ((uint64_t *)(void *)cqc)[i];
2721                 ddi_put64(mbox_info.mbi_in->mb_acchdl,
2722                     ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
2723         }
2724 
2725         /* Sync the mailbox for the device to read */
2726         hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2727 
2728         /* Setup and post Hermon "MODIFY_CQ" command */
2729         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
2730         cmd.cp_outparm  = 0;    /* resize cq */
2731         cmd.cp_inmod    = cqcindx;
2732         cmd.cp_opcode   = MODIFY_CQ;
2733         cmd.cp_opmod    = RESIZE_CQ;
2734         cmd.cp_flags    = sleepflag;
2735         status = hermon_cmd_post(state, &cmd);
2736 
2737         /*
2738          * New "producer index" is returned in the upper 32 bits of
2739          * command "outparam"
2740          */
2741         *prod_indx = (cmd.cp_outparm >> 32);
2742 
2743         /* Free the mailbox */
2744         hermon_mbox_free(state, &mbox_info);
2745         return (status);
2746 }
2747 
2748 
2749 /*
2750  * hermon_modify_cq_cmd_post()
2751  *    Context: Can be called from interrupt or base context.
2752  */
2753 int
2754 hermon_modify_cq_cmd_post(hermon_state_t *state, hermon_hw_cqc_t *cqc,
2755     uint_t cqcindx, uint_t opmod, uint_t sleepflag)
2756 {
2757         hermon_mbox_info_t      mbox_info;
2758         hermon_cmd_post_t       cmd;
2759         uint64_t                data;
2760         uint_t                  size;
2761         int                     status, i;
2762 
2763         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2764 
2765         /* Get an "In" mailbox for the command */
2766         mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
2767         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2768         if (status != HERMON_CMD_SUCCESS) {
2769                 return (status);
2770         }
2771 
2772         /* Copy the Hermon "MODIFY_CQ" command into mailbox */
2773         size = sizeof (hermon_hw_cqc_t);
2774         for (i = 0; i < (size >> 3); i++) {
2775                 data = ((uint64_t *)(void *)cqc)[i];
2776                 ddi_put64(mbox_info.mbi_in->mb_acchdl,
2777                     ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
2778         }
2779 
2780         /* Sync the mailbox for the device to read */
2781         hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2782 
2783         /* Setup and post Hermon "MODIFY_CQ" command */
2784         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
2785         cmd.cp_outparm  = 0;
2786         cmd.cp_inmod    = cqcindx;
2787         cmd.cp_opcode   = MODIFY_CQ;
2788         cmd.cp_opmod    = (uint16_t)opmod;
2789         cmd.cp_flags    = sleepflag;
2790         status = hermon_cmd_post(state, &cmd);
2791 
2792         /* Free the mailbox */
2793         hermon_mbox_free(state, &mbox_info);
2794         return (status);
2795 }
2796 
2797 
2798 /*
2799  * hermon_cmn_qp_cmd_post()
2800  *    Context: Can be called from interrupt or base context.
2801  *
2802  *    This is the common function for posting all the various types of
2803  *    QP state transition related Hermon commands.  Since some of the
2804  *    commands differ from the others in the number (and type) of arguments
2805  *    that each require, this routine does checks based on opcode type
2806  *    (explained in more detail below).
2807  *
2808  * Note: This common function should be used only with the following
2809  *    opcodes: RTS2SQD_QP, TOERR_QP, TORST_QP, RST2INIT_QP, INIT2INIT_QP,
2810  *    INIT2RTR_QP, RTR2RTS_QP, RTS2RTS_QP, SQD2RTS_QP, and SQERR2RTS_QP.
2811  */
2812 int
2813 hermon_cmn_qp_cmd_post(hermon_state_t *state, uint_t opcode,
2814     hermon_hw_qpc_t *qp, uint_t qpindx, uint32_t opmask,
2815     uint_t sleepflag)
2816 {
2817         hermon_mbox_info_t      mbox_info;
2818         hermon_cmd_post_t       cmd;
2819         uint64_t                data, in_mapaddr, out_mapaddr;
2820         uint_t                  size, flags, opmod;
2821         int                     status, i;
2822 
2823         /*
2824          * Use the specified opcode type to set the appropriate parameters.
2825          * Specifically, we need to set in_mapaddr, out_mapaddr, flags, and
2826          * opmod (as necessary).  Setting these parameters may also require
2827          * us to allocate an "In" or "Out" mailbox depending on the command
2828          * type.
2829          */
2830 
2831         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
2832 
2833         if (opcode == RTS2SQD_QP) {
2834                 /*
2835                  * Note: For RTS-to-SendQueueDrain state transitions we
2836                  * always want to request the event generation from the
2837                  * hardware.  Though we may not notify the consumer of the
2838                  * drained event, the decision to forward (or not) is made
2839                  * later in the SQD event handler.
2840                  */
2841                 flags = HERMON_CMD_REQ_SQD_EVENT;
2842 
2843                 /*
2844                  * The RTS2SQD_QP command uses no "In" or "Out" mailboxes (and
2845                  * has no special opcode modifiers).
2846                  */
2847                 in_mapaddr  = 0;
2848                 out_mapaddr = 0;
2849                 opmod = 0;
2850 
2851         } else if (opcode == TOERR_QP) {
2852                 /*
2853                  * The TOERR_QP command uses no "In" or "Out" mailboxes, has no
2854                  * special opcode modifiers, and takes no special flags.
2855                  */
2856                 in_mapaddr  = 0;
2857                 out_mapaddr = 0;
2858                 opmod = 0;
2859                 flags = 0;
2860 
2861         } else if (opcode == TORST_QP) {
2862                 /*
2863                  * The TORST_QP command could take an "Out" mailbox, but we do
2864                  * not require it here.  It also does not takes any special
2865                  * flags.  It does however, take a HERMON_CMD_DIRECT_TO_RESET
2866                  * opcode modifier, which indicates that the transition to
2867                  * reset should happen without first moving the QP through the
2868                  * Error state (and, hence, without generating any unnecessary
2869                  * "flushed-in-error" completions).
2870                  */
2871                 in_mapaddr  = 0;
2872                 out_mapaddr = 0;
2873                 opmod = HERMON_CMD_DIRECT_TO_RESET | HERMON_CMD_NO_OUTMBOX;
2874                 flags = 0;
2875 
2876         } else {
2877                 /*
2878                  * All the other QP state transition commands (RST2INIT_QP,
2879                  * INIT2INIT_QP, INIT2RTR_QP, RTR2RTS_QP, RTS2RTS_QP,
2880                  * SQD2RTS_QP, and SQERR2RTS_QP) require an "In" mailbox.
2881                  * None of these require any special flags or opcode modifiers.
2882                  */
2883                 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
2884                 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2885                 if (status != HERMON_CMD_SUCCESS) {
2886                         return (status);
2887                 }
2888                 in_mapaddr  = mbox_info.mbi_in->mb_mapaddr;
2889                 out_mapaddr = 0;
2890                 flags = 0;
2891                 opmod = 0;
2892 
2893                 /* Copy the Hermon command into the "In" mailbox */
2894                 size = sizeof (hermon_hw_qpc_t);
2895                 for (i = 0; i < (size >> 3); i++) {
2896                         data = ((uint64_t *)(void *)qp)[i];
2897                         ddi_put64(mbox_info.mbi_in->mb_acchdl,
2898                             ((uint64_t *)mbox_info.mbi_in->mb_addr + i + 1),
2899                             data);
2900                 }
2901                 ddi_put32(mbox_info.mbi_in->mb_acchdl,
2902                     ((uint32_t *)mbox_info.mbi_in->mb_addr), opmask);
2903 
2904                 /*
2905                  * Sync the mailbox for the device to read.  We have to add
2906                  * eight bytes here to account for "opt_param_mask" and
2907                  * proper alignment.
2908                  */
2909                 hermon_mbox_sync(mbox_info.mbi_in, 0, size + 8,
2910                     DDI_DMA_SYNC_FORDEV);
2911         }
2912 
2913         /* Setup and post Hermon QP state transition command */
2914         cmd.cp_inparm   = in_mapaddr;
2915         cmd.cp_outparm  = out_mapaddr;
2916         cmd.cp_inmod    = qpindx | flags;
2917         cmd.cp_opcode   = (uint16_t)opcode;
2918         cmd.cp_opmod    = (uint16_t)opmod;
2919         cmd.cp_flags    = sleepflag;
2920         status = hermon_cmd_post(state, &cmd);
2921 
2922         /*
2923          * If we allocated a mailbox (either an "In" or an "Out") above,
2924          * then free it now before returning.
2925          */
2926         if ((opcode != RTS2SQD_QP) && (opcode != TOERR_QP) &&
2927             (opcode != TORST_QP)) {
2928                 /* Free the mailbox */
2929                 hermon_mbox_free(state, &mbox_info);
2930         }
2931         return (status);
2932 }
2933 
2934 
2935 /*
2936  * hermon_cmn_query_cmd_post()
2937  *    Context: Can be called from interrupt or base context.
2938  *
2939  *    This is the common function for posting all the various types of
2940  *    Hermon query commands.  All Hermon query commands require an "Out"
2941  *    mailbox to be allocated for the resulting queried data.
2942  *
2943  * Note: This common function should be used only with the following
2944  *    opcodes: QUERY_DEV_LIM, QUERY_FW, QUERY_DDR, QUERY_ADAPTER, QUERY_PORT
2945  *     QUERY_HCA, QUERY_MPT, QUERY_EQ, QUERY_CQ, and QUERY_QP.
2946  *      With support of FCoIB, this also supports QUERY_FC.
2947  */
2948 int
2949 hermon_cmn_query_cmd_post(hermon_state_t *state, uint_t opcode, uint_t opmod,
2950     uint_t queryindx, void *query, uint_t size, uint_t sleepflag)
2951 {
2952         hermon_mbox_info_t      mbox_info;
2953         hermon_cmd_post_t       cmd;
2954         uint64_t                data;
2955         uint_t                  offset;
2956         int                     status, i;
2957 
2958         bzero(&cmd, sizeof (hermon_cmd_post_t));
2959 
2960         /* Get an "Out" mailbox for the command */
2961         mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
2962         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
2963         if (status != HERMON_CMD_SUCCESS) {
2964                 return (status);
2965         }
2966 
2967         /* Setup and post the Hermon query command */
2968         cmd.cp_inparm   = 0;
2969         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
2970         cmd.cp_inmod    = queryindx;
2971         cmd.cp_opcode   = (uint16_t)opcode;
2972         cmd.cp_opmod    = (uint16_t)opmod;
2973         cmd.cp_flags    = sleepflag;
2974         status = hermon_cmd_post(state, &cmd);
2975         if (status != HERMON_CMD_SUCCESS) {
2976                 goto cmn_query_fail;
2977         }
2978 
2979         /* Sync the mailbox to read the results */
2980         hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
2981 
2982         /*
2983          * QUERY_QP is handled somewhat differently than the other query
2984          * commands.  For QUERY_QP, the actual queried data is offset into
2985          * the mailbox (by one 64-bit word).
2986          */
2987         offset = (opcode == QUERY_QP) ? 1 : 0;
2988 
2989         /* Copy query command results into "query" */
2990         for (i = 0; i < (size >> 3); i++) {
2991                 data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2992                     ((uint64_t *)mbox_info.mbi_out->mb_addr + i + offset));
2993                 ((uint64_t *)query)[i] = data;
2994         }
2995 
2996 cmn_query_fail:
2997         /* Free the mailbox */
2998         hermon_mbox_free(state, &mbox_info);
2999         return (status);
3000 }
3001 
3002 
3003 /*
3004  * hermon_cmn_ownership_cmd_post()
3005  *    Context: Can be called from interrupt or base context.
3006  *
3007  *    This is the common function for posting all the various types of
3008  *    Hermon HW/SW resource ownership commands.  Since some of the commands
3009  *    differ from the others in the direction of ownership change (i.e.
3010  *    from HW ownership to SW, or vice versa), they differ in the type of
3011  *    mailbox and specific handling that each requires.  This routine does
3012  *    certain checks based on opcode type to determine the direction of
3013  *    the transition and to correctly handle the request.
3014  *
3015  * Note: This common function should be used only with the following
3016  *    opcodes: HW2SW_MPT, HW2SW_EQ, HW2SW_CQ, SW2HW_MPT, SW2HW_EQ, and
3017  *    SW2HW_CQ
3018  */
3019 int
3020 hermon_cmn_ownership_cmd_post(hermon_state_t *state, uint_t opcode,
3021     void *hwrsrc, uint_t size, uint_t hwrsrcindx, uint_t sleepflag)
3022 {
3023         hermon_mbox_info_t      mbox_info;
3024         hermon_cmd_post_t       cmd;
3025         uint64_t                data, in_mapaddr, out_mapaddr;
3026         uint_t                  direction, opmod;
3027         int                     status, i;
3028 
3029         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3030 
3031         /*
3032          * Determine the direction of the ownership transfer based on the
3033          * provided opcode
3034          */
3035         if ((opcode == HW2SW_MPT) || (opcode == HW2SW_EQ) ||
3036             (opcode == HW2SW_CQ) || (opcode == HW2SW_SRQ)) {
3037                 direction = HERMON_CMD_RSRC_HW2SW;
3038 
3039         } else if ((opcode == SW2HW_MPT) || (opcode == SW2HW_EQ) ||
3040             (opcode == SW2HW_CQ) || (opcode == SW2HW_SRQ)) {
3041                 direction = HERMON_CMD_RSRC_SW2HW;
3042 
3043         } else {
3044                 return (HERMON_CMD_INVALID_STATUS);
3045         }
3046 
3047         /*
3048          * If hwrsrc is NULL then we do not allocate a mailbox.  This is used
3049          * in the case of memory deregister where the out mailbox is not
3050          * needed.  In the case of re-register, we do use the hwrsrc.
3051          *
3052          * Otherwise, If ownership transfer is going from hardware to software,
3053          * then allocate an "Out" mailbox.  This will be filled in later as a
3054          * result of the Hermon command.
3055          *
3056          * And if the ownership transfer is going from software to hardware,
3057          * then we need an "In" mailbox, and we need to fill it in and sync it
3058          * (if necessary).  Then the mailbox can be passed to the Hermon
3059          * firmware.
3060          *
3061          * For the HW2SW (dereg) case, we only use an out mbox if hwrsrc is !=
3062          * NULL.  This implies a re-reg, and the out mbox must be used.  If
3063          * hwrsrc is == NULL, then we can save some time and resources by not
3064          * using an out mbox at all.  We must set opmod to HERMON_CMD_DO_OUTMBOX
3065          * and HERMON_CMD_NO_OUTMBOX appropriately in this case.
3066          *
3067          * For the SW2HW (reg) case, no out mbox is possible.  We set opmod to
3068          * 0 anyway, but this field is not used in this case.
3069          */
3070         if (direction == HERMON_CMD_RSRC_HW2SW) {
3071                 if (hwrsrc != NULL) {
3072                         mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
3073                         status = hermon_mbox_alloc(state, &mbox_info,
3074                             sleepflag);
3075                         if (status != HERMON_CMD_SUCCESS) {
3076                                 return (status);
3077                         }
3078                         in_mapaddr  = 0;
3079                         out_mapaddr = mbox_info.mbi_out->mb_mapaddr;
3080                         opmod = HERMON_CMD_DO_OUTMBOX;
3081                 } else {
3082                         in_mapaddr = 0;
3083                         out_mapaddr = 0;
3084                         opmod = HERMON_CMD_NO_OUTMBOX;
3085                 }
3086         } else {  /* HERMON_CMD_RSRC_SW2HW */
3087                 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3088                 status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3089                 if (status != HERMON_CMD_SUCCESS) {
3090                         return (status);
3091                 }
3092 
3093                 /* Copy the SW2HW ownership command into mailbox */
3094                 for (i = 0; i < (size >> 3); i++) {
3095                         data = ((uint64_t *)hwrsrc)[i];
3096                         ddi_put64(mbox_info.mbi_in->mb_acchdl,
3097                             ((uint64_t *)mbox_info.mbi_in->mb_addr + i),
3098                             data);
3099                 }
3100 
3101                 /* Sync the mailbox for the device to read */
3102                 hermon_mbox_sync(mbox_info.mbi_in, 0, size,
3103                     DDI_DMA_SYNC_FORDEV);
3104 
3105                 in_mapaddr  = mbox_info.mbi_in->mb_mapaddr;
3106                 out_mapaddr = 0;
3107                 opmod = 0;
3108         }
3109 
3110         /* Setup and post the Hermon ownership command */
3111         cmd.cp_inparm   = in_mapaddr;
3112         cmd.cp_outparm  = out_mapaddr;
3113         cmd.cp_inmod    = hwrsrcindx;
3114         cmd.cp_opcode   = (uint16_t)opcode;
3115         cmd.cp_opmod    = (uint16_t)opmod;
3116         cmd.cp_flags    = sleepflag;
3117         status = hermon_cmd_post(state, &cmd);
3118         if (status != HERMON_CMD_SUCCESS) {
3119                 goto cmn_ownership_fail;
3120         }
3121 
3122         /*
3123          * As mentioned above, for HW2SW ownership transfers we need to
3124          * sync (if necessary) and copy out the resulting data from the
3125          * "Out" mailbox" (assuming the above command was successful).
3126          */
3127         if (direction == HERMON_CMD_RSRC_HW2SW && hwrsrc != NULL) {
3128 
3129                 /* Sync the mailbox to read the results */
3130                 hermon_mbox_sync(mbox_info.mbi_out, 0, size,
3131                     DDI_DMA_SYNC_FORCPU);
3132 
3133                 /* Copy HW2SW ownership command results into "hwrsrc" */
3134                 for (i = 0; i < (size >> 3); i++) {
3135                         data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
3136                             ((uint64_t *)mbox_info.mbi_out->mb_addr + i));
3137                         ((uint64_t *)hwrsrc)[i] = data;
3138                 }
3139         }
3140 
3141 cmn_ownership_fail:
3142         if (hwrsrc != NULL) {
3143                 /* Free the mailbox */
3144                 hermon_mbox_free(state, &mbox_info);
3145         }
3146         return (status);
3147 }
3148 
3149 
3150 /*
3151  * hermon_conf_special_qp_cmd_post()
3152  *    Context: Can be called from interrupt or base context.
3153  */
3154 /*ARGSUSED*/
3155 int
3156 hermon_conf_special_qp_cmd_post(hermon_state_t *state, uint_t qpindx,
3157     uint_t qptype, uint_t sleepflag, uint_t opmod)
3158 {
3159         hermon_cmd_post_t       cmd;
3160         int                     status;
3161 
3162         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3163 
3164         /* Setup and post Hermon "CONF_SPECIAL_QP" command */
3165         cmd.cp_inparm   = 0;
3166         cmd.cp_outparm  = 0;
3167         cmd.cp_inmod    = qpindx & 0x00FFFFF8;      /* mask off low 3 bits */
3168         cmd.cp_opcode   = CONF_SPECIAL_QP;
3169         cmd.cp_opmod    = (uint16_t)opmod;
3170         cmd.cp_flags    = sleepflag;
3171         status = hermon_cmd_post(state, &cmd);
3172 
3173         return (status);
3174 }
3175 
3176 
3177 /*
3178  * hermon_get_heart_beat_rq_cmd_post()
3179  *    Context: Can be called only from kernel or interrupt context
3180  */
3181 int
3182 hermon_get_heart_beat_rq_cmd_post(hermon_state_t *state, uint_t qpindx,
3183     uint64_t *outparm)
3184 {
3185         hermon_cmd_post_t       cmd;
3186         int                     status;
3187 
3188         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3189 
3190         /* Setup and post the Hermon "HEART_BEAT_RQ" command */
3191         cmd.cp_inparm   = 0;
3192         cmd.cp_outparm  = 0;
3193         cmd.cp_inmod    = qpindx;
3194         cmd.cp_opcode   = HEART_BEAT_RQ;
3195         cmd.cp_opmod    = 0;
3196         cmd.cp_flags    = HERMON_CMD_NOSLEEP_SPIN;
3197         status = hermon_cmd_post(state, &cmd);
3198 
3199         /*
3200          * Return immediate out param through argument pointer.
3201          */
3202         *outparm = cmd.cp_outparm;
3203         return (status);
3204 }
3205 
3206 
3207 /*
3208  * hermon_mgid_hash_cmd_post()
3209  *    Context: Can be called from interrupt or base context.
3210  */
3211 int
3212 hermon_mgid_hash_cmd_post(hermon_state_t *state, uint64_t mgid_h,
3213     uint64_t mgid_l, uint64_t *mgid_hash, uint_t sleepflag)
3214 {
3215         hermon_mbox_info_t      mbox_info;
3216         hermon_cmd_post_t       cmd;
3217         int                     status;
3218 
3219         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3220 
3221         /* Get an "In" mailbox for the command */
3222         mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3223         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3224         if (status != HERMON_CMD_SUCCESS) {
3225                 return (status);
3226         }
3227 
3228         /* Copy the Hermon "MGID_HASH" command into mailbox */
3229         ddi_put64(mbox_info.mbi_in->mb_acchdl,
3230             ((uint64_t *)mbox_info.mbi_in->mb_addr + 0), mgid_h);
3231         ddi_put64(mbox_info.mbi_in->mb_acchdl,
3232             ((uint64_t *)mbox_info.mbi_in->mb_addr + 1), mgid_l);
3233 
3234         /* Sync the mailbox for the device to read */
3235         hermon_mbox_sync(mbox_info.mbi_in, 0, HERMON_CMD_MGIDHASH_SZ,
3236             DDI_DMA_SYNC_FORDEV);
3237 
3238         /* Setup and post the Hermon "MGID_HASH" command */
3239         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
3240         cmd.cp_outparm  = 0;
3241         cmd.cp_inmod    = 0;
3242         cmd.cp_opcode   = MGID_HASH;
3243         cmd.cp_opmod    = 0;
3244         cmd.cp_flags    = sleepflag;
3245         status = hermon_cmd_post(state, &cmd);
3246 
3247         /* MGID hash value is returned in command "outparam" */
3248         *mgid_hash = cmd.cp_outparm;
3249 
3250         /* Free the mailbox */
3251         hermon_mbox_free(state, &mbox_info);
3252         return (status);
3253 }
3254 
3255 
3256 /*
3257  * hermon_read_mgm_cmd_post()
3258  *    Context: Can be called from interrupt or base context.
3259  *
3260  * Note: It is assumed that the "mcg" parameter is actually a pointer to a
3261  *    "hermon_hw_mcg_t" struct and some number of "hermon_hw_mcg_qp_list_t"
3262  *    structs.  Combined size should be equal to result of HERMON_MCGMEM_SZ()
3263  *    macro.
3264  */
3265 int
3266 hermon_read_mgm_cmd_post(hermon_state_t *state, hermon_hw_mcg_t *mcg,
3267     uint_t mcgindx, uint_t sleepflag)
3268 {
3269         hermon_mbox_info_t      mbox_info;
3270         hermon_cmd_post_t       cmd;
3271         uint64_t                data;
3272         uint32_t                data32;
3273         uint_t                  size, hdrsz, qplistsz;
3274         int                     status, i;
3275 
3276         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3277 
3278         /* Get an "Out" mailbox for the results */
3279         mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
3280         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3281         if (status != HERMON_CMD_SUCCESS) {
3282                 return (status);
3283         }
3284 
3285         /* Setup and post Hermon "READ_MGM" command */
3286         cmd.cp_inparm   = 0;
3287         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
3288         cmd.cp_inmod    = mcgindx;
3289         cmd.cp_opcode   = READ_MGM;
3290         cmd.cp_opmod    = 0;
3291         cmd.cp_flags    = sleepflag;
3292         status = hermon_cmd_post(state, &cmd);
3293         if (status != HERMON_CMD_SUCCESS) {
3294                 goto read_mgm_fail;
3295         }
3296 
3297         /* Sync the mailbox to read the results */
3298         size = HERMON_MCGMEM_SZ(state);
3299         hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
3300 
3301         /* Copy the READ_MGM command results into "mcg" */
3302         hdrsz = sizeof (hermon_hw_mcg_t);
3303         for (i = 0; i < (hdrsz >> 3); i++) {
3304                 data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
3305                     ((uint64_t *)mbox_info.mbi_out->mb_addr + i));
3306                 ((uint64_t *)mcg)[i] = data;
3307         }
3308         qplistsz = size - hdrsz;
3309         for (i = 0; i < (qplistsz >> 2); i++) {
3310                 data32 = ddi_get32(mbox_info.mbi_out->mb_acchdl,
3311                     ((uint32_t *)mbox_info.mbi_out->mb_addr + i + 8));
3312                 ((uint32_t *)mcg)[i + 8] = data32;
3313         }
3314 
3315 read_mgm_fail:
3316         /* Free the mailbox */
3317         hermon_mbox_free(state, &mbox_info);
3318         return (status);
3319 }
3320 
3321 
3322 /*
3323  * hermon_write_mgm_cmd_post()
3324  *    Context: Can be called from interrupt or base context.
3325  *
3326  * Note: It is assumed that the "mcg" parameter is actually a pointer to a
3327  *    "hermon_hw_mcg_t" struct and some number of "hermon_hw_mcg_qp_list_t"
3328  *    structs.  Combined size should be equal to result of HERMON_MCGMEM_SZ()
3329  *    macro.
3330  */
3331 int
3332 hermon_write_mgm_cmd_post(hermon_state_t *state, hermon_hw_mcg_t *mcg,
3333     uint_t mcgindx, uint_t sleepflag)
3334 {
3335         hermon_mbox_info_t      mbox_info;
3336         hermon_cmd_post_t       cmd;
3337         uint64_t                data;
3338         uint_t                  size, hdrsz, qplistsz;
3339         int                     status, i;
3340 
3341         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3342 
3343         /* Get an "In" mailbox for the command */
3344         mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3345         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3346         if (status != HERMON_CMD_SUCCESS) {
3347                 return (status);
3348         }
3349 
3350         /* Copy the Hermon "WRITE_MGM" command into mailbox */
3351         size  = HERMON_MCGMEM_SZ(state);
3352         hdrsz = sizeof (hermon_hw_mcg_t);
3353         for (i = 0; i < (hdrsz >> 3); i++) {
3354                 data = ((uint64_t *)mcg)[i];
3355                 ddi_put64(mbox_info.mbi_in->mb_acchdl,
3356                     ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
3357         }
3358         qplistsz = size - hdrsz;
3359         for (i = 0; i < (qplistsz >> 2); i++) {
3360                 data = ((uint32_t *)mcg)[i + 8];
3361                 ddi_put32(mbox_info.mbi_in->mb_acchdl,
3362                     ((uint32_t *)mbox_info.mbi_in->mb_addr + i + 8), data);
3363         }
3364 
3365         /* Sync the mailbox for the device to read */
3366         hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
3367 
3368         /* Setup and post Hermon "WRITE_MGM" command */
3369         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
3370         cmd.cp_outparm  = 0;
3371         cmd.cp_inmod    = mcgindx;
3372         cmd.cp_opcode   = WRITE_MGM;
3373         cmd.cp_opmod    = 0;
3374         cmd.cp_flags    = sleepflag;
3375         status = hermon_cmd_post(state, &cmd);
3376 
3377         /* Free the mailbox */
3378         hermon_mbox_free(state, &mbox_info);
3379         return (status);
3380 }
3381 
3382 /*
3383  * hermon_resize_srq_cmd_post()
3384  *    Context: Can be called from interrupt or base context.
3385  */
3386 
3387 int hermon_resize_srq_cmd_post(hermon_state_t *state, hermon_hw_srqc_t *srq,
3388     uint_t srqnum, uint_t sleepflag)
3389 {
3390         hermon_mbox_info_t      mbox_info;
3391         hermon_cmd_post_t       cmd;
3392         uint64_t                data;
3393         uint_t                  size;
3394         int                     status, i;
3395 
3396         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3397 
3398         /* Get an "In" mailbox for the command */
3399         mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3400         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3401         if (status != HERMON_CMD_SUCCESS) {
3402                 return (status);
3403         }
3404 
3405         /* Copy the Hermon "RESIZE_SRQ" command into mailbox */
3406         size = sizeof (hermon_hw_srqc_t);
3407         for (i = 0; i < (size >> 3); i++) {
3408                 data = ((uint64_t *)(void *)srq)[i];
3409                 ddi_put64(mbox_info.mbi_in->mb_acchdl,
3410                     ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
3411         }
3412 
3413         /* Sync the mailbox for the device to read */
3414         hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
3415 
3416         /* Setup and post Hermon "RESIZE_SRQ" command */
3417         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
3418         cmd.cp_outparm  = 0;
3419         cmd.cp_inmod    = srqnum;
3420         cmd.cp_opcode   = RESIZE_SRQ;
3421         cmd.cp_opmod    = 0;
3422         cmd.cp_flags    = sleepflag;
3423         status = hermon_cmd_post(state, &cmd);
3424 
3425         /* Free the mailbox */
3426         hermon_mbox_free(state, &mbox_info);
3427         return (status);
3428 }
3429 /*
3430  * hermon_modify_mpt_cmd_post()
3431  *    Context: Can be called from interrupt or base context.
3432  */
3433 int
3434 hermon_modify_mpt_cmd_post(hermon_state_t *state, hermon_hw_dmpt_t *mpt,
3435     uint_t mptindx, uint_t flags, uint_t sleepflag)
3436 {
3437         hermon_mbox_info_t      mbox_info;
3438         hermon_cmd_post_t       cmd;
3439         uint64_t                data;
3440         uint_t                  size;
3441         int                     status, i;
3442 
3443         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3444 
3445         /* Get an "In" mailbox for the command */
3446         mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3447         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3448         if (status != HERMON_CMD_SUCCESS) {
3449                 return (status);
3450         }
3451 
3452         /* Copy the Hermon "MODIFY_MPT" command into mailbox */
3453         size = sizeof (hermon_hw_dmpt_t);
3454         for (i = 0; i < (size >> 3); i++) {
3455                 data = ((uint64_t *)mpt)[i];
3456                 ddi_put64(mbox_info.mbi_in->mb_acchdl,
3457                     ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
3458         }
3459 
3460         /* Sync the mailbox for the device to read */
3461         hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
3462 
3463         /* Setup and post Hermon "MODIFY_MPT" command */
3464         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
3465         cmd.cp_outparm  = 0;
3466         cmd.cp_inmod    = mptindx;
3467         cmd.cp_opcode   = MODIFY_MPT;
3468         cmd.cp_opmod    = (uint16_t)flags;
3469         cmd.cp_flags    = sleepflag;
3470         status = hermon_cmd_post(state, &cmd);
3471 
3472         /* Free the mailbox */
3473         hermon_mbox_free(state, &mbox_info);
3474         return (status);
3475 }
3476 
3477 
3478 /*
3479  * hermon_config_fc_cmd_post()
3480  *      Context: Can be called from user or kernel context.
3481  *      This can do either a basic config passing in
3482  *      *hermon_hw_config_fc_basic_s, or config the N_Port table.
3483  *      passing in pointer to an array of 32-bit id's
3484  *      Note that either one needs to be cast to void *
3485  */
3486 int
3487 hermon_config_fc_cmd_post(hermon_state_t *state, void *cfginfo, int enable,
3488     int selector, int n_ports, int portnum, uint_t sleepflag)
3489 {
3490         hermon_mbox_info_t      mbox_info;
3491         hermon_cmd_post_t       cmd;
3492         uint64_t                data;
3493         uint32_t                portid;
3494         uint_t                  size;
3495         int                     status, i;
3496 
3497         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3498 
3499         /* Get an "In" mailbox for the command */
3500         mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX;
3501         status = hermon_mbox_alloc(state, &mbox_info, sleepflag);
3502         if (status != HERMON_CMD_SUCCESS) {
3503                 return (status);
3504         }
3505 
3506         /* Copy the appropriate info into mailbox */
3507         if (selector == HERMON_HW_FC_CONF_BASIC) {      /* basic info */
3508                 size = sizeof (hermon_hw_config_fc_basic_t);
3509                 for (i = 0; i < (size >> 3); i++) {
3510                         data = ((uint64_t *)cfginfo)[i];
3511                         ddi_put64(mbox_info.mbi_in->mb_acchdl,
3512                             ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
3513                 }
3514         } else {                                        /* NPort config */
3515                 ASSERT(selector == HERMON_HW_FC_CONF_NPORT);
3516                 size = n_ports * sizeof (uint32_t);
3517                 /*
3518                  * n_ports must == number queried from card
3519                  *
3520                  * passed in is an array but for little endian needs to
3521                  * be rearranged in the mbox
3522                  */
3523                 for (i = 0; i < (size >> 3); i++) {
3524                         portid = ((uint32_t *)cfginfo)[i * 2];
3525                         data = (uint64_t)portid << 32;
3526                         if (i * 2 < n_ports) {
3527                                 portid = ((uint32_t *)cfginfo)[i * 2 + 1];
3528                                 data |= portid;
3529                         }
3530                         ddi_put64(mbox_info.mbi_in->mb_acchdl,
3531                             ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
3532                 }
3533         }
3534 
3535         /* Sync the mailbox for the device to read */
3536         hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
3537 
3538         /* Setup and post Hermon "CONFIG_FC" command */
3539         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
3540         cmd.cp_outparm  = 0;
3541         cmd.cp_inmod    = (uint32_t)(selector | portnum);
3542         cmd.cp_opcode   = CONFIG_FC;
3543         cmd.cp_opmod    = (uint16_t)enable;
3544         cmd.cp_flags    = sleepflag;
3545         status = hermon_cmd_post(state, &cmd);
3546 
3547         /* Free the mailbox */
3548         hermon_mbox_free(state, &mbox_info);
3549         return (status);
3550 }
3551 
3552 /*
3553  * hermon_sense_port_post() - used to send protocol running on a port
3554  *      Context: Can be called from interrupt or base context
3555  */
3556 
3557 int
3558 hermon_sense_port_post(hermon_state_t *state, uint_t portnum,
3559     uint32_t *protocol)
3560 {
3561         hermon_cmd_post_t       cmd;
3562         int                     status;
3563 
3564         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3565 
3566         /* Setup and post Hermon "CMD_NOP" command */
3567         cmd.cp_inparm   = 0;
3568         cmd.cp_outparm  = 0;
3569         cmd.cp_inmod    = (uint32_t)portnum;
3570         cmd.cp_opcode   = SENSE_PORT;
3571         cmd.cp_opmod    = 0;
3572         cmd.cp_flags    = HERMON_CMD_NOSLEEP_SPIN;
3573         status = hermon_cmd_post(state, &cmd);
3574         if (status == HERMON_CMD_SUCCESS) *protocol = (uint32_t)cmd.cp_outparm;
3575         return (status);
3576 }
3577 
3578 
3579 /*
3580  * CONFIG_INT_MOD - used to configure INTERRUPT moderation
3581  *      if command fails, *health is invalid/undefined
3582  */
3583 int
3584 hermon_config_int_mod(hermon_state_t *state, uint_t min_delay, uint_t vector)
3585 {
3586         hermon_cmd_post_t       cmd;
3587         int                     status;
3588         uint64_t                inparm = 0;
3589 
3590         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3591 
3592         /* Setup and post Hermon "CONFIG_INT_MOD" command */
3593         inparm = (((uint64_t)min_delay & 0xFFFF) << 48) ||
3594             (((uint64_t)vector & 0xFFFF) << 32);
3595 
3596         cmd.cp_inparm   = inparm;
3597         cmd.cp_outparm  = 0;
3598         cmd.cp_inmod    = 0;
3599         cmd.cp_opcode   = CONFIG_INT_MOD;
3600         cmd.cp_opmod    = 0;
3601         cmd.cp_flags    = HERMON_CMD_NOSLEEP_SPIN;
3602         status = hermon_cmd_post(state, &cmd);
3603         return (status);
3604 }
3605 
3606 
3607 int
3608 hermon_nop_post(hermon_state_t *state, uint_t interval, uint_t sleep)
3609 {
3610         hermon_cmd_post_t       cmd;
3611         int                     status;
3612 
3613         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3614 
3615         /* Setup and post Hermon "CMD_NOP" command */
3616         cmd.cp_inparm   = 0;
3617         cmd.cp_outparm  = 0;
3618         cmd.cp_inmod    = interval;
3619         cmd.cp_opcode   = CMD_NOP;
3620         cmd.cp_opmod    = 0;
3621         cmd.cp_flags    = HERMON_CMD_SLEEP_NOSPIN;
3622         if (sleep) cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN;
3623         status = hermon_cmd_post(state, &cmd);
3624         return (status);
3625 }
3626 
3627 int
3628 hermon_hw_health_check(hermon_state_t *state, int *health)
3629 {
3630         hermon_cmd_post_t       cmd;
3631         int                     status;
3632 
3633         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3634 
3635         /* Setup and post Hermon "CMD_NOP" command */
3636         cmd.cp_inparm   = 0;
3637         cmd.cp_outparm  = 0;
3638         cmd.cp_inmod    = 0;
3639         cmd.cp_opcode   = HW_HEALTH_CHECK;
3640         cmd.cp_opmod    = 0;
3641         cmd.cp_flags    = HERMON_CMD_NOSLEEP_SPIN;
3642         status = hermon_cmd_post(state, &cmd);
3643         *health = (int)cmd.cp_outparm;
3644         return (status);
3645 }
3646 
3647 int
3648 hermon_setdebug_post(hermon_state_t *state)
3649 {
3650         hermon_cmd_post_t       cmd;
3651         int                     status;
3652 
3653         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3654 
3655         /* Setup and post Hermon "CMD_NOP" command */
3656         cmd.cp_inparm   = 0xFFFFFFFFFFFFFFFF;
3657         cmd.cp_outparm  = 0;
3658         cmd.cp_inmod    = 0;
3659         cmd.cp_opcode   = SET_DEBUG_MSG;
3660         cmd.cp_opmod    = 0;
3661         cmd.cp_flags    = HERMON_CMD_NOSLEEP_SPIN;
3662         status = hermon_cmd_post(state, &cmd);
3663         return (status);
3664 }
3665 
3666 
3667 int
3668 hermon_read_mtt_cmd_post(hermon_state_t *state, uint64_t mtt_addr,
3669         hermon_hw_mtt_t *mtt)
3670 {
3671 
3672         hermon_cmd_post_t       cmd;
3673         hermon_mbox_info_t      mbox_info;
3674         int                     i, status;
3675         uint_t                  size;
3676         uint64_t                data;
3677 
3678         bzero((void *)&cmd, sizeof (hermon_cmd_post_t));
3679 
3680         /* Get an "Out" mailbox for the command */
3681         mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX;
3682         status = hermon_mbox_alloc(state, &mbox_info, HERMON_CMD_SLEEP_NOSPIN);
3683         if (status != HERMON_CMD_SUCCESS) {
3684                 return (status);
3685         }
3686 
3687         /* Setup and post the "READ_MTT" command */
3688         cmd.cp_inparm   = mtt_addr;
3689         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
3690         cmd.cp_inmod    = 1;
3691         cmd.cp_opcode   = READ_MTT;
3692         cmd.cp_opmod    = 0;
3693         cmd.cp_flags    = HERMON_CMD_NOSLEEP_SPIN;
3694         status = hermon_cmd_post(state, &cmd);
3695         if (status != HERMON_CMD_SUCCESS) {
3696                 return (status);
3697         }
3698 
3699         /* Sync the mailbox to read the results */
3700         size = sizeof (hermon_hw_mtt_t);
3701         hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
3702 
3703         /* Copy mtt read out */
3704         for (i = 0; i < (size >> 3); i++) {
3705                 data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
3706                     ((uint64_t *)mbox_info.mbi_out->mb_addr + i));
3707                 ((uint64_t *)(void *)mtt)[i] = data;
3708         }
3709 
3710         /* Free the mailbox */
3711         hermon_mbox_free(state, &mbox_info);
3712         return (status);
3713 }