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 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * tavor_cmd.c
  29  *    Tavor Firmware Command Routines
  30  *
  31  *    Implements all the routines necessary for allocating, posting, and
  32  *    freeing commands for the Tavor firmware.  These routines manage a
  33  *    preallocated list of command mailboxes and provide interfaces to post
  34  *    each of the several dozen commands to the Tavor firmware.
  35  */
  36 
  37 #include <sys/types.h>
  38 #include <sys/conf.h>
  39 #include <sys/ddi.h>
  40 #include <sys/sunddi.h>
  41 #include <sys/modctl.h>
  42 
  43 #include <sys/ib/adapters/tavor/tavor.h>
  44 
  45 static int tavor_impl_mbox_alloc(tavor_state_t *state, tavor_mboxlist_t *mblist,
  46     tavor_mbox_t **mb, uint_t mbox_wait);
  47 static void tavor_impl_mbox_free(tavor_mboxlist_t *mblist, tavor_mbox_t **mb);
  48 static int tavor_impl_mboxlist_init(tavor_state_t *state,
  49     tavor_mboxlist_t *mblist, uint_t num_mbox, tavor_rsrc_type_t type);
  50 static void tavor_impl_mboxlist_fini(tavor_state_t *state,
  51     tavor_mboxlist_t *mblist);
  52 static int tavor_outstanding_cmd_alloc(tavor_state_t *state,
  53     tavor_cmd_t **cmd_ptr, uint_t cmd_wait);
  54 static void tavor_outstanding_cmd_free(tavor_state_t *state,
  55     tavor_cmd_t **cmd_ptr);
  56 static int tavor_write_hcr(tavor_state_t *state, tavor_cmd_post_t *cmdpost,
  57     uint16_t token);
  58 static void tavor_mbox_sync(tavor_mbox_t *mbox, uint_t offset,
  59     uint_t length, uint_t flag);
  60 
  61 /*
  62  * tavor_cmd_post()
  63  *    Context: Can be called from interrupt or base context.
  64  *
  65  *    The "cp_flags" field in cmdpost
  66  *    is used to determine whether to wait for an available
  67  *    outstanding command (if necessary) or to return error.
  68  */
  69 int
  70 tavor_cmd_post(tavor_state_t *state, tavor_cmd_post_t *cmdpost)
  71 {
  72         tavor_cmd_t     *cmdptr;
  73         int             status;
  74         uint16_t        token;
  75 
  76         TAVOR_TNF_ENTER(tavor_cmd_post);
  77 
  78         /* Determine if we are going to spin until completion */
  79         if (cmdpost->cp_flags == TAVOR_CMD_NOSLEEP_SPIN) {
  80 
  81                 TNF_PROBE_0_DEBUG(tavor_cmd_post_spin, TAVOR_TNF_TRACE, "");
  82 
  83                 /* Write the command to the HCR */
  84                 status = tavor_write_hcr(state, cmdpost, 0);
  85                 if (status != TAVOR_CMD_SUCCESS) {
  86                         TNF_PROBE_0(tavor_cmd_post_fail,
  87                             TAVOR_TNF_ERROR, "");
  88                         TAVOR_TNF_EXIT(tavor_cmd_post);
  89                         return (status);
  90                 }
  91 
  92                 TAVOR_TNF_EXIT(tavor_cmd_post);
  93                 return (TAVOR_CMD_SUCCESS);
  94 
  95         } else {  /* "TAVOR_CMD_SLEEP_NOSPIN" */
  96 
  97                 TNF_PROBE_0_DEBUG(tavor_cmd_post_nospin, TAVOR_TNF_TRACE, "");
  98 
  99                 ASSERT(TAVOR_SLEEPFLAG_FOR_CONTEXT() != TAVOR_NOSLEEP);
 100 
 101                 /* NOTE: Expect threads to be waiting in here */
 102                 status = tavor_outstanding_cmd_alloc(state, &cmdptr,
 103                     cmdpost->cp_flags);
 104                 if (status != TAVOR_CMD_SUCCESS) {
 105                         TNF_PROBE_0(tavor_cmd_alloc_fail, TAVOR_TNF_ERROR, "");
 106                         TAVOR_TNF_EXIT(tavor_cmd_post);
 107                         return (status);
 108                 }
 109 
 110                 /*
 111                  * Set status to "TAVOR_CMD_INVALID_STATUS".  It is
 112                  * appropriate to do this here without the "cmd_comp_lock"
 113                  * because this register is overloaded.  Later it will be
 114                  * used to indicate - through a change from this invalid
 115                  * value to some other value - that the condition variable
 116                  * has been signaled.  Once it has, status will then contain
 117                  * the _real_ completion status
 118                  */
 119                 cmdptr->cmd_status = TAVOR_CMD_INVALID_STATUS;
 120 
 121                 /* Write the command to the HCR */
 122                 token = (uint16_t)cmdptr->cmd_indx;
 123                 status = tavor_write_hcr(state, cmdpost, token);
 124                 if (status != TAVOR_CMD_SUCCESS) {
 125                         tavor_outstanding_cmd_free(state, &cmdptr);
 126                         TNF_PROBE_0(tavor_cmd_post_fail, TAVOR_TNF_ERROR, "");
 127                         TAVOR_TNF_EXIT(tavor_cmd_post);
 128                         return (status);
 129                 }
 130 
 131                 /*
 132                  * cv_wait() on the "command_complete" condition variable.
 133                  */
 134                 mutex_enter(&cmdptr->cmd_comp_lock);
 135                 while (cmdptr->cmd_status == TAVOR_CMD_INVALID_STATUS) {
 136                         /* NOTE: EXPECT SEVERAL THREADS TO BE WAITING HERE */
 137                         cv_wait(&cmdptr->cmd_comp_cv, &cmdptr->cmd_comp_lock);
 138                 }
 139                 mutex_exit(&cmdptr->cmd_comp_lock);
 140 
 141                 /*
 142                  * Wake up after command completes (cv_signal).  Read status
 143                  * from the command (success, fail, etc.).  It is appropriate
 144                  * here (as above) to read the status field without the
 145                  * "cmd_comp_lock" because it is no longer being used to
 146                  * indicate whether the condition variable has been signaled
 147                  * (i.e. at this point we are certain that it already has).
 148                  */
 149                 status = cmdptr->cmd_status;
 150 
 151                 /* Save the "outparam" values into the cmdpost struct */
 152                 cmdpost->cp_outparm = cmdptr->cmd_outparm;
 153 
 154                 /*
 155                  * Add the command back to the "outstanding commands list".
 156                  * Signal the "cmd_list" condition variable, if necessary.
 157                  */
 158                 tavor_outstanding_cmd_free(state, &cmdptr);
 159 
 160                 if (status != TAVOR_CMD_SUCCESS) {
 161                         TNF_PROBE_0(tavor_cmd_post_fail, TAVOR_TNF_ERROR, "");
 162                         TAVOR_TNF_EXIT(tavor_cmd_post);
 163                         return (status);
 164                 }
 165 
 166                 TAVOR_TNF_EXIT(tavor_cmd_post);
 167                 return (TAVOR_CMD_SUCCESS);
 168         }
 169 }
 170 
 171 
 172 /*
 173  * tavor_mbox_alloc()
 174  *    Context: Can be called from interrupt or base context.
 175  *
 176  *    The "mbox_wait" parameter is used to determine whether to
 177  *    wait for a mailbox to become available or not.
 178  */
 179 int
 180 tavor_mbox_alloc(tavor_state_t *state, tavor_mbox_info_t *mbox_info,
 181     uint_t mbox_wait)
 182 {
 183         int                     status;
 184         uint_t                  sleep_context;
 185 
 186         TAVOR_TNF_ENTER(tavor_mbox_alloc);
 187 
 188         sleep_context = TAVOR_SLEEPFLAG_FOR_CONTEXT();
 189 
 190         /* Allocate an "In" mailbox */
 191         if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_INMBOX) {
 192                 /* Determine correct mboxlist based on calling context */
 193                 if (sleep_context == TAVOR_NOSLEEP) {
 194                         status = tavor_impl_mbox_alloc(state,
 195                             &state->ts_in_intr_mblist,
 196                             &mbox_info->mbi_in, mbox_wait);
 197 
 198                         ASSERT(status == TAVOR_CMD_SUCCESS);
 199                 } else {
 200                         /* NOTE: Expect threads to be waiting in here */
 201                         status = tavor_impl_mbox_alloc(state,
 202                             &state->ts_in_mblist, &mbox_info->mbi_in,
 203                             mbox_wait);
 204                         if (status != TAVOR_CMD_SUCCESS) {
 205                                 TAVOR_TNF_EXIT(tavor_mbox_alloc);
 206                                 return (status);
 207                         }
 208                 }
 209 
 210         }
 211 
 212         /* Allocate an "Out" mailbox */
 213         if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_OUTMBOX) {
 214                 /* Determine correct mboxlist based on calling context */
 215                 if (sleep_context == TAVOR_NOSLEEP) {
 216                         status = tavor_impl_mbox_alloc(state,
 217                             &state->ts_out_intr_mblist,
 218                             &mbox_info->mbi_out, mbox_wait);
 219 
 220                         ASSERT(status == TAVOR_CMD_SUCCESS);
 221                 } else {
 222                         /* NOTE: Expect threads to be waiting in here */
 223                         status = tavor_impl_mbox_alloc(state,
 224                             &state->ts_out_mblist, &mbox_info->mbi_out,
 225                             mbox_wait);
 226                         if (status != TAVOR_CMD_SUCCESS) {
 227                                 /* If we allocated an "In" mailbox, free it */
 228                                 if (mbox_info->mbi_alloc_flags &
 229                                     TAVOR_ALLOC_INMBOX) {
 230                                         tavor_impl_mbox_free(
 231                                             &state->ts_in_mblist,
 232                                             &mbox_info->mbi_in);
 233                                 }
 234                                 TAVOR_TNF_EXIT(tavor_mbox_alloc);
 235                                 return (status);
 236                         }
 237                 }
 238         }
 239 
 240         /* Store appropriate context in mbox_info */
 241         mbox_info->mbi_sleep_context = sleep_context;
 242 
 243         TAVOR_TNF_EXIT(tavor_mbox_alloc);
 244         return (TAVOR_CMD_SUCCESS);
 245 }
 246 
 247 
 248 /*
 249  * tavor_mbox_free()
 250  *    Context: Can be called from interrupt or base context.
 251  */
 252 void
 253 tavor_mbox_free(tavor_state_t *state, tavor_mbox_info_t *mbox_info)
 254 {
 255         TAVOR_TNF_ENTER(tavor_mbox_free);
 256 
 257         /*
 258          * The mailbox has to be freed in the same context from which it was
 259          * allocated.  The context is stored in the mbox_info at
 260          * tavor_mbox_alloc() time.  We check the stored context against the
 261          * current context here.
 262          */
 263         ASSERT(mbox_info->mbi_sleep_context == TAVOR_SLEEPFLAG_FOR_CONTEXT());
 264 
 265         /* Determine correct mboxlist based on calling context */
 266         if (mbox_info->mbi_sleep_context == TAVOR_NOSLEEP) {
 267                 /* Free the intr "In" mailbox */
 268                 if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_INMBOX) {
 269                         tavor_impl_mbox_free(&state->ts_in_intr_mblist,
 270                             &mbox_info->mbi_in);
 271                 }
 272 
 273                 /* Free the intr "Out" mailbox */
 274                 if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_OUTMBOX) {
 275                         tavor_impl_mbox_free(&state->ts_out_intr_mblist,
 276                             &mbox_info->mbi_out);
 277                 }
 278         } else {
 279                 /* Free the "In" mailbox */
 280                 if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_INMBOX) {
 281                         tavor_impl_mbox_free(&state->ts_in_mblist,
 282                             &mbox_info->mbi_in);
 283                 }
 284 
 285                 /* Free the "Out" mailbox */
 286                 if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_OUTMBOX) {
 287                         tavor_impl_mbox_free(&state->ts_out_mblist,
 288                             &mbox_info->mbi_out);
 289                 }
 290         }
 291 
 292         TAVOR_TNF_EXIT(tavor_mbox_free);
 293 }
 294 
 295 
 296 /*
 297  * tavor_cmd_complete_handler()
 298  *    Context: Called only from interrupt context.
 299  */
 300 int
 301 tavor_cmd_complete_handler(tavor_state_t *state, tavor_eqhdl_t eq,
 302     tavor_hw_eqe_t *eqe)
 303 {
 304         tavor_cmd_t             *cmdp;
 305         uint_t                  eqe_evttype;
 306 
 307         TAVOR_TNF_ENTER(tavor_cmd_complete_handler);
 308 
 309         eqe_evttype = TAVOR_EQE_EVTTYPE_GET(eq, eqe);
 310 
 311         ASSERT(eqe_evttype == TAVOR_EVT_COMMAND_INTF_COMP ||
 312             eqe_evttype == TAVOR_EVT_EQ_OVERFLOW);
 313 
 314         if (eqe_evttype == TAVOR_EVT_EQ_OVERFLOW) {
 315                 TNF_PROBE_0(tavor_cmd_complete_overflow_condition,
 316                     TAVOR_TNF_ERROR, "");
 317                 tavor_eq_overflow_handler(state, eq, eqe);
 318 
 319                 TAVOR_TNF_EXIT(tavor_cmd_complete_handler);
 320                 return (DDI_FAILURE);
 321         }
 322 
 323         /*
 324          * Find the outstanding command pointer based on value returned
 325          * in "token"
 326          */
 327         cmdp = &state->ts_cmd_list.cml_cmd[TAVOR_EQE_CMDTOKEN_GET(eq, eqe)];
 328 
 329         /* Signal the waiting thread */
 330         mutex_enter(&cmdp->cmd_comp_lock);
 331         cmdp->cmd_outparm = ((uint64_t)TAVOR_EQE_CMDOUTP0_GET(eq, eqe) << 32) |
 332             TAVOR_EQE_CMDOUTP1_GET(eq, eqe);
 333         cmdp->cmd_status = TAVOR_EQE_CMDSTATUS_GET(eq, eqe);
 334 
 335         cv_signal(&cmdp->cmd_comp_cv);
 336         mutex_exit(&cmdp->cmd_comp_lock);
 337 
 338         TAVOR_TNF_EXIT(tavor_cmd_complete_handler);
 339         return (DDI_SUCCESS);
 340 }
 341 
 342 
 343 /*
 344  * tavor_inmbox_list_init()
 345  *    Context: Only called from attach() path context
 346  */
 347 int
 348 tavor_inmbox_list_init(tavor_state_t *state)
 349 {
 350         int             status;
 351         uint_t          num_inmbox;
 352 
 353         TAVOR_TNF_ENTER(tavor_inmbox_list_init);
 354 
 355         /* Initialize the "In" mailbox list */
 356         num_inmbox  =  (1 << state->ts_cfg_profile->cp_log_num_inmbox);
 357         status = tavor_impl_mboxlist_init(state, &state->ts_in_mblist,
 358             num_inmbox, TAVOR_IN_MBOX);
 359         if (status != DDI_SUCCESS) {
 360                 TNF_PROBE_0(tavor_impl_mboxlist_init_fail,
 361                     TAVOR_TNF_ERROR, "");
 362                 TAVOR_TNF_EXIT(tavor_inmbox_list_init);
 363                 return (DDI_FAILURE);
 364         }
 365 
 366         TAVOR_TNF_EXIT(tavor_inmbox_list_init);
 367         return (DDI_SUCCESS);
 368 }
 369 
 370 
 371 /*
 372  * tavor_intr_inmbox_list_init()
 373  *    Context: Only called from attach() path context
 374  */
 375 int
 376 tavor_intr_inmbox_list_init(tavor_state_t *state)
 377 {
 378         int             status;
 379         uint_t          num_inmbox;
 380 
 381         TAVOR_TNF_ENTER(tavor_intr_inmbox_list_init);
 382 
 383         /* Initialize the interrupt "In" mailbox list */
 384         num_inmbox  =  (1 << state->ts_cfg_profile->cp_log_num_intr_inmbox);
 385         status = tavor_impl_mboxlist_init(state, &state->ts_in_intr_mblist,
 386             num_inmbox, TAVOR_INTR_IN_MBOX);
 387         if (status != DDI_SUCCESS) {
 388                 TNF_PROBE_0(tavor_impl_mboxlist_init_fail,
 389                     TAVOR_TNF_ERROR, "");
 390                 TAVOR_TNF_EXIT(tavor_intr_inmbox_list_init);
 391                 return (DDI_FAILURE);
 392         }
 393 
 394         TAVOR_TNF_EXIT(tavor_intr_inmbox_list_init);
 395         return (DDI_SUCCESS);
 396 }
 397 
 398 
 399 /*
 400  * tavor_outmbox_list_init()
 401  *    Context: Only called from attach() path context
 402  */
 403 int
 404 tavor_outmbox_list_init(tavor_state_t *state)
 405 {
 406         int             status;
 407         uint_t          num_outmbox;
 408 
 409         TAVOR_TNF_ENTER(tavor_outmbox_list_init);
 410 
 411         /* Initialize the "Out" mailbox list */
 412         num_outmbox  =  (1 << state->ts_cfg_profile->cp_log_num_outmbox);
 413         status = tavor_impl_mboxlist_init(state, &state->ts_out_mblist,
 414             num_outmbox, TAVOR_OUT_MBOX);
 415         if (status != DDI_SUCCESS) {
 416                 TNF_PROBE_0(tavor_impl_mboxlist_init_fail,
 417                     TAVOR_TNF_ERROR, "");
 418                 TAVOR_TNF_EXIT(tavor_outmbox_list_init);
 419                 return (DDI_FAILURE);
 420         }
 421 
 422         TAVOR_TNF_EXIT(tavor_outmbox_list_init);
 423         return (DDI_SUCCESS);
 424 }
 425 
 426 
 427 /*
 428  * tavor_intr_outmbox_list_init()
 429  *    Context: Only called from attach() path context
 430  */
 431 int
 432 tavor_intr_outmbox_list_init(tavor_state_t *state)
 433 {
 434         int             status;
 435         uint_t          num_outmbox;
 436 
 437         TAVOR_TNF_ENTER(tavor_intr_outmbox_list_init);
 438 
 439         /* Initialize the interrupts "Out" mailbox list */
 440         num_outmbox  =  (1 << state->ts_cfg_profile->cp_log_num_intr_outmbox);
 441         status = tavor_impl_mboxlist_init(state, &state->ts_out_intr_mblist,
 442             num_outmbox, TAVOR_INTR_OUT_MBOX);
 443         if (status != DDI_SUCCESS) {
 444                 TNF_PROBE_0(tavor_impl_mboxlist_init_fail,
 445                     TAVOR_TNF_ERROR, "");
 446                 TAVOR_TNF_EXIT(tavor_intr_outmbox_list_init);
 447                 return (DDI_FAILURE);
 448         }
 449 
 450         TAVOR_TNF_EXIT(tavor_intr_outmbox_list_init);
 451         return (DDI_SUCCESS);
 452 }
 453 
 454 
 455 /*
 456  * tavor_inmbox_list_fini()
 457  *    Context: Only called from attach() and/or detach() path contexts
 458  */
 459 void
 460 tavor_inmbox_list_fini(tavor_state_t *state)
 461 {
 462         TAVOR_TNF_ENTER(tavor_inmbox_list_fini);
 463 
 464         /* Free up the "In" mailbox list */
 465         tavor_impl_mboxlist_fini(state, &state->ts_in_mblist);
 466 
 467         TAVOR_TNF_EXIT(tavor_inmbox_list_fini);
 468 }
 469 
 470 
 471 /*
 472  * tavor_intr_inmbox_list_fini()
 473  *    Context: Only called from attach() and/or detach() path contexts
 474  */
 475 void
 476 tavor_intr_inmbox_list_fini(tavor_state_t *state)
 477 {
 478         TAVOR_TNF_ENTER(tavor_intr_inmbox_list_fini);
 479 
 480         /* Free up the interupts "In" mailbox list */
 481         tavor_impl_mboxlist_fini(state, &state->ts_in_intr_mblist);
 482 
 483         TAVOR_TNF_EXIT(tavor_intr_inmbox_list_fini);
 484 }
 485 
 486 
 487 /*
 488  * tavor_outmbox_list_fini()
 489  *    Context: Only called from attach() and/or detach() path contexts
 490  */
 491 void
 492 tavor_outmbox_list_fini(tavor_state_t *state)
 493 {
 494         TAVOR_TNF_ENTER(tavor_outmbox_list_fini);
 495 
 496         /* Free up the "Out" mailbox list */
 497         tavor_impl_mboxlist_fini(state, &state->ts_out_mblist);
 498 
 499         TAVOR_TNF_EXIT(tavor_outmbox_list_fini);
 500 }
 501 
 502 
 503 /*
 504  * tavor_intr_outmbox_list_fini()
 505  *    Context: Only called from attach() and/or detach() path contexts
 506  */
 507 void
 508 tavor_intr_outmbox_list_fini(tavor_state_t *state)
 509 {
 510         TAVOR_TNF_ENTER(tavor_intr_outmbox_list_fini);
 511 
 512         /* Free up the interrupt "Out" mailbox list */
 513         tavor_impl_mboxlist_fini(state, &state->ts_out_intr_mblist);
 514 
 515         TAVOR_TNF_EXIT(tavor_intr_outmbox_list_fini);
 516 }
 517 
 518 
 519 /*
 520  * tavor_impl_mbox_alloc()
 521  *    Context: Can be called from interrupt or base context.
 522  */
 523 static int
 524 tavor_impl_mbox_alloc(tavor_state_t *state, tavor_mboxlist_t *mblist,
 525     tavor_mbox_t **mb, uint_t mbox_wait)
 526 {
 527         tavor_mbox_t    *mbox_ptr;
 528         uint_t          index, next, prev;
 529         uint_t          count, countmax;
 530 
 531         TAVOR_TNF_ENTER(tavor_impl_mbox_alloc);
 532 
 533         /*
 534          * If the mailbox list is empty, then wait (if appropriate in the
 535          * current context).  Otherwise, grab the next available mailbox.
 536          */
 537         if (mbox_wait == TAVOR_NOSLEEP) {
 538                 count    = 0;
 539                 countmax = state->ts_cfg_profile->cp_cmd_poll_max;
 540 
 541                 mutex_enter(&mblist->mbl_lock);
 542                 mblist->mbl_pollers++;
 543                 while (mblist->mbl_entries_free == 0) {
 544                         mutex_exit(&mblist->mbl_lock);
 545                         /* Delay loop polling for an available mbox */
 546                         if (++count > countmax) {
 547                                 TNF_PROBE_0(tavor_impl_mbox_alloc_fail,
 548                                     TAVOR_TNF_ERROR, "");
 549                                 TAVOR_TNF_EXIT(tavor_impl_mbox_alloc);
 550                                 return (TAVOR_CMD_INSUFF_RSRC);
 551                         }
 552 
 553                         /* Delay before polling for mailbox again */
 554                         drv_usecwait(state->ts_cfg_profile->cp_cmd_poll_delay);
 555                         mutex_enter(&mblist->mbl_lock);
 556                 }
 557                 mblist->mbl_pollers--;
 558 
 559         /* TAVOR_SLEEP */
 560         } else {
 561                 /*
 562                  * Grab lock here as we prepare to cv_wait if needed.
 563                  */
 564                 mutex_enter(&mblist->mbl_lock);
 565                 while (mblist->mbl_entries_free == 0) {
 566                         /*
 567                          * Wait (on cv) for a mailbox to become free.
 568                          */
 569                         mblist->mbl_waiters++;
 570                         cv_wait(&mblist->mbl_cv, &mblist->mbl_lock);
 571                 }
 572         }
 573 
 574         /* Grab the next available mailbox from list */
 575         mbox_ptr = mblist->mbl_mbox;
 576         index    = mblist->mbl_head_indx;
 577         next     = mbox_ptr[index].mb_next;
 578         prev     = mbox_ptr[index].mb_prev;
 579 
 580         /* Remove it from the mailbox list */
 581         mblist->mbl_mbox[next].mb_prev       = prev;
 582         mblist->mbl_mbox[prev].mb_next       = next;
 583         mblist->mbl_head_indx                = next;
 584 
 585         /* Update the "free" count and return the mailbox pointer */
 586         mblist->mbl_entries_free--;
 587         *mb = &mbox_ptr[index];
 588 
 589         mutex_exit(&mblist->mbl_lock);
 590 
 591         TAVOR_TNF_EXIT(tavor_impl_mbox_alloc);
 592         return (TAVOR_CMD_SUCCESS);
 593 }
 594 
 595 
 596 /*
 597  * tavor_impl_mbox_free()
 598  *    Context: Can be called from interrupt or base context.
 599  */
 600 static void
 601 tavor_impl_mbox_free(tavor_mboxlist_t *mblist, tavor_mbox_t **mb)
 602 {
 603         uint_t          mbox_indx;
 604 
 605         TAVOR_TNF_ENTER(tavor_impl_mbox_free);
 606 
 607         mutex_enter(&mblist->mbl_lock);
 608 
 609         /* Pull the "index" from mailbox entry */
 610         mbox_indx = (*mb)->mb_indx;
 611 
 612         /*
 613          * If mailbox list is not empty, then insert the entry.  Otherwise,
 614          * this is the only entry.  So update the pointers appropriately.
 615          */
 616         if (mblist->mbl_entries_free++ != 0) {
 617                 /* Update the current mailbox */
 618                 (*mb)->mb_next = mblist->mbl_head_indx;
 619                 (*mb)->mb_prev = mblist->mbl_tail_indx;
 620 
 621                 /* Update head and tail mailboxes */
 622                 mblist->mbl_mbox[mblist->mbl_head_indx].mb_prev = mbox_indx;
 623                 mblist->mbl_mbox[mblist->mbl_tail_indx].mb_next = mbox_indx;
 624 
 625                 /* Update tail index */
 626                 mblist->mbl_tail_indx = mbox_indx;
 627 
 628         } else {
 629                 /* Update the current mailbox */
 630                 (*mb)->mb_next = mbox_indx;
 631                 (*mb)->mb_prev = mbox_indx;
 632 
 633                 /* Update head and tail indexes */
 634                 mblist->mbl_tail_indx = mbox_indx;
 635                 mblist->mbl_head_indx = mbox_indx;
 636         }
 637 
 638         /*
 639          * Because we can have both waiters (SLEEP treads waiting for a
 640          * cv_signal to continue processing) and pollers (NOSLEEP treads
 641          * polling for a mailbox to become available), we try to share CPU time
 642          * between them.  We do this by signalling the waiters only every other
 643          * call to mbox_free.  This gives the pollers a chance to get some CPU
 644          * time to do their command.  If we signalled every time, the pollers
 645          * would have a much harder time getting CPU time.
 646          *
 647          * If there are waiters and no pollers, then we signal always.
 648          *
 649          * Otherwise, if there are either no waiters, there may in fact be
 650          * pollers, so we do not signal in that case.
 651          */
 652         if (mblist->mbl_pollers > 0 && mblist->mbl_waiters > 0) {
 653                 /* flip the signal value */
 654                 mblist->mbl_signal = (mblist->mbl_signal + 1) % 2;
 655         } else if (mblist->mbl_waiters > 0) {
 656                 mblist->mbl_signal = 1;
 657         } else {
 658                 mblist->mbl_signal = 0;
 659         }
 660 
 661         /*
 662          * Depending on the conditions in the previous check, we signal only if
 663          * we are supposed to.
 664          */
 665         if (mblist->mbl_signal) {
 666                 mblist->mbl_waiters--;
 667                 cv_signal(&mblist->mbl_cv);
 668         }
 669 
 670         /* Clear out the mailbox entry pointer */
 671         *mb = NULL;
 672 
 673         mutex_exit(&mblist->mbl_lock);
 674 
 675         TAVOR_TNF_EXIT(tavor_impl_mbox_free);
 676 }
 677 
 678 
 679 /*
 680  * tavor_impl_mboxlist_init()
 681  *    Context: Only called from attach() path context
 682  */
 683 static int
 684 tavor_impl_mboxlist_init(tavor_state_t *state, tavor_mboxlist_t *mblist,
 685     uint_t num_mbox, tavor_rsrc_type_t type)
 686 {
 687         tavor_rsrc_t            *rsrc;
 688         ddi_dma_cookie_t        dma_cookie;
 689         uint_t                  dma_cookiecnt, flag, sync;
 690         int                     status, i;
 691 
 692         TAVOR_TNF_ENTER(tavor_impl_mboxlist_init);
 693 
 694         /* Allocate the memory for the mailbox entries list */
 695         mblist->mbl_list_sz = num_mbox;
 696         mblist->mbl_mbox = kmem_zalloc(mblist->mbl_list_sz *
 697             sizeof (tavor_mbox_t), KM_SLEEP);
 698 
 699         /* Initialize the mailbox entries list */
 700         mblist->mbl_head_indx         = 0;
 701         mblist->mbl_tail_indx         = mblist->mbl_list_sz - 1;
 702         mblist->mbl_entries_free = mblist->mbl_list_sz;
 703         mblist->mbl_waiters   = 0;
 704         mblist->mbl_num_alloc         = 0;
 705 
 706         /* Set up the mailbox list's cv and mutex */
 707         mutex_init(&mblist->mbl_lock, NULL, MUTEX_DRIVER,
 708             DDI_INTR_PRI(state->ts_intrmsi_pri));
 709         cv_init(&mblist->mbl_cv, NULL, CV_DRIVER, NULL);
 710 
 711         /* Determine if syncs will be necessary */
 712         sync = TAVOR_MBOX_IS_SYNC_REQ(state, type);
 713 
 714         /* Determine whether to map DDI_DMA_STREAMING or DDI_DMA_CONSISTENT */
 715         flag = state->ts_cfg_profile->cp_streaming_consistent;
 716 
 717         /* Initialize the mailbox list entries */
 718         for (i = 0; i < mblist->mbl_list_sz; i++) {
 719                 /* Allocate resources for the mailbox */
 720                 status = tavor_rsrc_alloc(state, type, 1, TAVOR_SLEEP,
 721                     &rsrc);
 722                 if (status != DDI_SUCCESS) {
 723                         /* Jump to cleanup and return error */
 724                         TNF_PROBE_0(tavor_impl_mbox_init_rsrcalloc_fail,
 725                             TAVOR_TNF_ERROR, "");
 726                         goto mboxlist_init_fail;
 727                 }
 728 
 729                 /* Save away the mailbox resource info */
 730                 mblist->mbl_mbox[i].mb_rsrcptr       = rsrc;
 731                 mblist->mbl_mbox[i].mb_addr  = rsrc->tr_addr;
 732                 mblist->mbl_mbox[i].mb_acchdl        = rsrc->tr_acchdl;
 733 
 734                 /*
 735                  * Get a PCI mapped address for each mailbox.  Note: this
 736                  * uses the ddi_dma_handle return from the resource
 737                  * allocation routine
 738                  */
 739                 status = ddi_dma_addr_bind_handle(rsrc->tr_dmahdl, NULL,
 740                     rsrc->tr_addr, rsrc->tr_len, (DDI_DMA_RDWR | flag),
 741                     DDI_DMA_SLEEP, NULL, &dma_cookie, &dma_cookiecnt);
 742                 if (status != DDI_SUCCESS) {
 743                         /* Jump to cleanup and return error */
 744                         tavor_rsrc_free(state, &rsrc);
 745                         TNF_PROBE_0(tavor_impl_mbox_init_dmabind_fail,
 746                             TAVOR_TNF_ERROR, "");
 747                         goto mboxlist_init_fail;
 748                 }
 749 
 750                 /* Save away the mapped address for the mailbox */
 751                 mblist->mbl_mbox[i].mb_mapaddr       = dma_cookie.dmac_laddress;
 752 
 753                 /* Set sync flag appropriately */
 754                 mblist->mbl_mbox[i].mb_sync  = sync;
 755 
 756                 /* Make each entry point to the "next" and "prev" entries */
 757                 mblist->mbl_mbox[i].mb_next  = i+1;
 758                 mblist->mbl_mbox[i].mb_prev  = i-1;
 759                 mblist->mbl_mbox[i].mb_indx  = i;
 760                 mblist->mbl_num_alloc                = i + 1;
 761         }
 762 
 763         /* Make the "head" and "tail" entries point to each other */
 764         mblist->mbl_mbox[mblist->mbl_head_indx].mb_prev =
 765             mblist->mbl_tail_indx;
 766         mblist->mbl_mbox[mblist->mbl_tail_indx].mb_next =
 767             mblist->mbl_head_indx;
 768 
 769         TAVOR_TNF_EXIT(tavor_impl_mboxlist_init);
 770         return (DDI_SUCCESS);
 771 
 772 mboxlist_init_fail:
 773         tavor_impl_mboxlist_fini(state, mblist);
 774 
 775         TAVOR_TNF_EXIT(tavor_impl_mboxlist_init);
 776         return (DDI_FAILURE);
 777 }
 778 
 779 
 780 /*
 781  * tavor_impl_mboxlist_fini()
 782  *    Context: Only called from attach() and/or detach() path contexts
 783  */
 784 static void
 785 tavor_impl_mboxlist_fini(tavor_state_t *state, tavor_mboxlist_t *mblist)
 786 {
 787         tavor_rsrc_t    *rsrc;
 788         int             i, status;
 789 
 790         TAVOR_TNF_ENTER(tavor_impl_mboxlist_fini);
 791 
 792         /* Release the resources for each of the mailbox list entries */
 793         for (i = 0; i < mblist->mbl_num_alloc; i++) {
 794                 rsrc = mblist->mbl_mbox[i].mb_rsrcptr;
 795 
 796                 /*
 797                  * First, unbind the DMA memory for the mailbox
 798                  *
 799                  * Note: The only way ddi_dma_unbind_handle() currently
 800                  * can return an error is if the handle passed in is invalid.
 801                  * Since this should never happen, we choose to return void
 802                  * from this function!  If this does return an error,
 803                  * however, then we print a warning message to the console.
 804                  */
 805                 status = ddi_dma_unbind_handle(rsrc->tr_dmahdl);
 806                 if (status != DDI_SUCCESS) {
 807                         TAVOR_WARNING(state, "failed to unbind DMA mapping");
 808                         TNF_PROBE_0(tavor_impl_mboxlist_fini_dmaunbind_fail,
 809                             TAVOR_TNF_ERROR, "");
 810                         TAVOR_TNF_EXIT(tavor_impl_mboxlist_fini);
 811                         return;
 812                 }
 813 
 814                 /* Next, free the mailbox resource */
 815                 tavor_rsrc_free(state, &rsrc);
 816         }
 817 
 818         /* Destroy the mailbox list mutex and cv */
 819         mutex_destroy(&mblist->mbl_lock);
 820         cv_destroy(&mblist->mbl_cv);
 821 
 822         /* Free up the memory for tracking the mailbox list */
 823         kmem_free(mblist->mbl_mbox, mblist->mbl_list_sz *
 824             sizeof (tavor_mbox_t));
 825 
 826         TAVOR_TNF_EXIT(tavor_impl_mboxlist_fini);
 827 }
 828 
 829 
 830 /*
 831  * tavor_outstanding_cmd_alloc()
 832  *    Context: Can be called only from base context.
 833  */
 834 static int
 835 tavor_outstanding_cmd_alloc(tavor_state_t *state, tavor_cmd_t **cmd_ptr,
 836     uint_t cmd_wait)
 837 {
 838         tavor_cmdlist_t *cmd_list;
 839         uint_t          next, prev, head;
 840 
 841         TAVOR_TNF_ENTER(tavor_outstanding_cmd_alloc);
 842 
 843         cmd_list = &state->ts_cmd_list;
 844         mutex_enter(&cmd_list->cml_lock);
 845 
 846         /* Ensure that outstanding commands are supported */
 847         ASSERT(cmd_list->cml_num_alloc != 0);
 848 
 849         /*
 850          * If the outstanding command list is empty, then wait (if
 851          * appropriate in the current context).  Otherwise, grab the
 852          * next available command.
 853          */
 854         while (cmd_list->cml_entries_free == 0) {
 855                 /* No free commands */
 856                 if (cmd_wait == TAVOR_NOSLEEP) {
 857                         mutex_exit(&cmd_list->cml_lock);
 858                         TNF_PROBE_0(tavor_outstanding_cmd_alloc_fail,
 859                             TAVOR_TNF_ERROR, "");
 860                         TAVOR_TNF_EXIT(tavor_outstanding_cmd_alloc);
 861                         return (TAVOR_CMD_INSUFF_RSRC);
 862                 }
 863 
 864                 /*
 865                  * Wait (on cv) for a command to become free.
 866                  */
 867                 cmd_list->cml_waiters++;
 868                 cv_wait(&cmd_list->cml_cv, &cmd_list->cml_lock);
 869         }
 870 
 871         /* Grab the next available command from the list */
 872         head = cmd_list->cml_head_indx;
 873         *cmd_ptr = &cmd_list->cml_cmd[head];
 874         next = (*cmd_ptr)->cmd_next;
 875         prev = (*cmd_ptr)->cmd_prev;
 876         (*cmd_ptr)->cmd_status = TAVOR_CMD_INVALID_STATUS;
 877 
 878         /* Remove it from the command list */
 879         cmd_list->cml_cmd[next].cmd_prev = prev;
 880         cmd_list->cml_cmd[prev].cmd_next = next;
 881         cmd_list->cml_head_indx               = next;
 882 
 883         /* Update the "free" count and return */
 884         cmd_list->cml_entries_free--;
 885 
 886         mutex_exit(&cmd_list->cml_lock);
 887 
 888         TAVOR_TNF_EXIT(tavor_outstanding_cmd_alloc);
 889         return (TAVOR_CMD_SUCCESS);
 890 }
 891 
 892 
 893 /*
 894  * tavor_outstanding_cmd_free()
 895  *    Context: Can be called only from base context.
 896  */
 897 static void
 898 tavor_outstanding_cmd_free(tavor_state_t *state, tavor_cmd_t **cmd_ptr)
 899 {
 900         tavor_cmdlist_t *cmd_list;
 901         uint_t          cmd_indx;
 902 
 903         TAVOR_TNF_ENTER(tavor_outstanding_cmd_free);
 904 
 905         cmd_list = &state->ts_cmd_list;
 906         mutex_enter(&cmd_list->cml_lock);
 907 
 908         /* Pull the "index" from command entry */
 909         cmd_indx = (*cmd_ptr)->cmd_indx;
 910 
 911         /*
 912          * If outstanding command list is not empty, then insert the entry.
 913          * Otherwise, this is the only entry.  So update the pointers
 914          * appropriately.
 915          */
 916         if (cmd_list->cml_entries_free++ != 0) {
 917                 /* Update the current command */
 918                 (*cmd_ptr)->cmd_next = cmd_list->cml_head_indx;
 919                 (*cmd_ptr)->cmd_prev = cmd_list->cml_tail_indx;
 920 
 921                 /* Update head and tail commands */
 922                 cmd_list->cml_cmd[cmd_list->cml_head_indx].cmd_prev = cmd_indx;
 923                 cmd_list->cml_cmd[cmd_list->cml_tail_indx].cmd_next = cmd_indx;
 924 
 925                 /* Update tail index */
 926                 cmd_list->cml_tail_indx = cmd_indx;
 927 
 928         } else {
 929                 /* Update the current command */
 930                 (*cmd_ptr)->cmd_next = cmd_indx;
 931                 (*cmd_ptr)->cmd_prev = cmd_indx;
 932 
 933                 /* Update head and tail indexes */
 934                 cmd_list->cml_head_indx = cmd_indx;
 935                 cmd_list->cml_tail_indx = cmd_indx;
 936         }
 937 
 938         /* If there are threads waiting, signal one of them */
 939         if (cmd_list->cml_waiters > 0) {
 940                 cmd_list->cml_waiters--;
 941                 cv_signal(&cmd_list->cml_cv);
 942         }
 943 
 944         /* Clear out the command entry pointer */
 945         *cmd_ptr = NULL;
 946 
 947         mutex_exit(&cmd_list->cml_lock);
 948 
 949         TAVOR_TNF_EXIT(tavor_outstanding_cmd_free);
 950 }
 951 
 952 
 953 /*
 954  * tavor_write_hcr()
 955  *    Context: Can be called from interrupt or base context.
 956  */
 957 static int
 958 tavor_write_hcr(tavor_state_t *state, tavor_cmd_post_t *cmdpost,
 959     uint16_t token)
 960 {
 961         tavor_hw_hcr_t  *hcr;
 962         uint_t          status, count, countmax;
 963         uint64_t        hcrreg;
 964 
 965         TAVOR_TNF_ENTER(tavor_write_hcr);
 966 
 967         /*
 968          * Grab the "HCR access" lock if the driver is not in
 969          * fastreboot. In fastreboot, this function is called
 970          * with the single thread but in high interrupt context
 971          * (so that this mutex lock cannot be used).
 972          */
 973         if (!TAVOR_IN_FASTREBOOT(state)) {
 974                 mutex_enter(&state->ts_cmd_regs.hcr_lock);
 975         }
 976 
 977         hcr = state->ts_cmd_regs.hcr;
 978 
 979         /*
 980          * First, check the "go" bit to see if the previous hcr usage is
 981          * complete.  As long as it is set then we must continue to poll.
 982          */
 983         count    = 0;
 984         countmax = state->ts_cfg_profile->cp_cmd_poll_max;
 985         for (;;) {
 986                 hcrreg = ddi_get32(state->ts_reg_cmdhdl, &hcr->cmd);
 987 
 988                 /* If "go" bit is clear, then done */
 989                 if ((hcrreg & TAVOR_HCR_CMD_GO_MASK) == 0) {
 990                         TNF_PROBE_1_DEBUG(tavor_write_hcr_loop_count,
 991                             TAVOR_TNF_ERROR, "", tnf_uint, nospinloopcount,
 992                             count);
 993                         break;
 994                 }
 995                 /* Delay before polling the "go" bit again */
 996                 drv_usecwait(state->ts_cfg_profile->cp_cmd_poll_delay);
 997 
 998                 /*
 999                  * If we poll more than the maximum number of times, then
1000                  * return a "timeout" error.
1001                  */
1002                 if (++count > countmax) {
1003                         if (!TAVOR_IN_FASTREBOOT(state)) {
1004                                 mutex_exit(&state->ts_cmd_regs.hcr_lock);
1005                         }
1006                         TNF_PROBE_0(tavor_write_hcr_timeout1, TAVOR_TNF_ERROR,
1007                             "");
1008                         TAVOR_TNF_EXIT(tavor_write_hcr);
1009                         return (TAVOR_CMD_TIMEOUT);
1010                 }
1011         }
1012 
1013         /* Write "inparam" as a 64-bit quantity */
1014         ddi_put64(state->ts_reg_cmdhdl, (uint64_t *)&hcr->in_param0,
1015             cmdpost->cp_inparm);
1016 
1017         /* Write "inmod" and 32-bits of "outparam" as 64-bit */
1018         hcrreg = ((uint64_t)cmdpost->cp_inmod << 32);
1019         hcrreg = hcrreg | (cmdpost->cp_outparm >> 32);
1020         ddi_put64(state->ts_reg_cmdhdl, (uint64_t *)&hcr->input_modifier,
1021             hcrreg);
1022 
1023         /* Write the other 32-bits of "outparam" and "token" as 64-bit */
1024         hcrreg = (cmdpost->cp_outparm << 32);
1025         hcrreg = hcrreg | ((uint32_t)token << TAVOR_HCR_TOKEN_SHIFT);
1026         ddi_put64(state->ts_reg_cmdhdl, (uint64_t *)&hcr->out_param1,
1027             hcrreg);
1028 
1029         /* Then setup the final hcrreg to hit doorbell (i.e. "go" bit) */
1030         hcrreg = TAVOR_HCR_CMD_GO_MASK;
1031         if (cmdpost->cp_flags == TAVOR_CMD_SLEEP_NOSPIN)
1032                 hcrreg = hcrreg | TAVOR_HCR_CMD_E_MASK;
1033         hcrreg = hcrreg | (cmdpost->cp_opmod << TAVOR_HCR_CMD_OPMOD_SHFT);
1034         hcrreg = hcrreg | (cmdpost->cp_opcode);
1035 
1036         /* Write the doorbell to the HCR */
1037         ddi_put32(state->ts_reg_cmdhdl, &hcr->cmd, hcrreg);
1038 
1039         /*
1040          * In the SPIN case we read the HCR and check the "go" bit.  For the
1041          * NOSPIN case we do not have to poll, we simply release the HCR lock
1042          * and return.
1043          */
1044         if (cmdpost->cp_flags == TAVOR_CMD_NOSLEEP_SPIN) {
1045                 count    = 0;
1046                 countmax = state->ts_cfg_profile->cp_cmd_poll_max;
1047 
1048                 for (;;) {
1049                         hcrreg = ddi_get32(state->ts_reg_cmdhdl, &hcr->cmd);
1050 
1051                         /* If "go" bit is clear, then done */
1052                         if ((hcrreg & TAVOR_HCR_CMD_GO_MASK) == 0) {
1053                                 TNF_PROBE_1_DEBUG(tavor_write_hcr_loop_count,
1054                                     TAVOR_TNF_ERROR, "", tnf_uint,
1055                                     spinloopcount, count);
1056                                 break;
1057                         }
1058                         /* Delay before polling the "go" bit again */
1059                         drv_usecwait(state->ts_cfg_profile->cp_cmd_poll_delay);
1060 
1061                         /*
1062                          * If we poll more than the maximum number of times,
1063                          * then return a "timeout" error.
1064                          */
1065                         if (++count > countmax) {
1066                                 if (!TAVOR_IN_FASTREBOOT(state)) {
1067                                         mutex_exit(&state->
1068                                             ts_cmd_regs.hcr_lock);
1069                                 }
1070                                 TNF_PROBE_0(tavor_write_hcr_timeout2,
1071                                     TAVOR_TNF_ERROR, "");
1072                                 TAVOR_TNF_EXIT(tavor_write_hcr);
1073                                 return (TAVOR_CMD_TIMEOUT);
1074                         }
1075                 }
1076 
1077                 /* Pull out the "status" bits from the HCR */
1078                 status = (hcrreg >> TAVOR_HCR_CMD_STATUS_SHFT);
1079 
1080                 /*
1081                  * Read the "outparam" value.  Note: we have to read "outparam"
1082                  * as two separate 32-bit reads because the field in the HCR is
1083                  * not 64-bit aligned.
1084                  */
1085                 hcrreg = ddi_get32(state->ts_reg_cmdhdl, &hcr->out_param0);
1086                 cmdpost->cp_outparm = hcrreg << 32;
1087                 hcrreg = ddi_get32(state->ts_reg_cmdhdl, &hcr->out_param1);
1088                 cmdpost->cp_outparm |= hcrreg;
1089 
1090         /* NOSPIN */
1091         } else {
1092                 status = TAVOR_CMD_SUCCESS;
1093         }
1094 
1095         /* Drop the "HCR access" lock */
1096         if (!TAVOR_IN_FASTREBOOT(state)) {
1097                 mutex_exit(&state->ts_cmd_regs.hcr_lock);
1098         }
1099 
1100         TAVOR_TNF_EXIT(tavor_write_hcr);
1101         return (status);
1102 }
1103 
1104 
1105 /*
1106  * tavor_outstanding_cmdlist_init()
1107  *    Context: Only called from attach() path context
1108  */
1109 int
1110 tavor_outstanding_cmdlist_init(tavor_state_t *state)
1111 {
1112         uint_t          num_outstanding_cmds, head, tail;
1113         int             i;
1114 
1115         TAVOR_TNF_ENTER(tavor_outstanding_cmdlist_init);
1116 
1117         /*
1118          * Determine the number of the outstanding commands supported
1119          * by the Tavor device (obtained from the QUERY_FW command).  Note:
1120          * Because we handle both SLEEP and NOSLEEP cases around the tavor HCR,
1121          * we know that when an interrupt comes in it will be next on the
1122          * command register, and will at most have to wait one commands time.
1123          * We do not have to reserve an outstanding command here for
1124          * interrupts.
1125          */
1126         num_outstanding_cmds = (1 << state->ts_fw.log_max_cmd);
1127 
1128         /* Initialize the outstanding command list */
1129         state->ts_cmd_list.cml_list_sz        = num_outstanding_cmds;
1130         state->ts_cmd_list.cml_head_indx = 0;
1131         state->ts_cmd_list.cml_tail_indx = state->ts_cmd_list.cml_list_sz - 1;
1132         state->ts_cmd_list.cml_entries_free = state->ts_cmd_list.cml_list_sz;
1133         state->ts_cmd_list.cml_waiters        = 0;
1134         state->ts_cmd_list.cml_num_alloc = 0;
1135 
1136         /* Allocate the memory for the outstanding command list */
1137         if (num_outstanding_cmds) {
1138                 state->ts_cmd_list.cml_cmd =
1139                     kmem_zalloc(state->ts_cmd_list.cml_list_sz *
1140                     sizeof (tavor_cmd_t), KM_SLEEP);
1141         }
1142         mutex_init(&state->ts_cmd_list.cml_lock, NULL, MUTEX_DRIVER,
1143             DDI_INTR_PRI(state->ts_intrmsi_pri));
1144         cv_init(&state->ts_cmd_list.cml_cv, NULL, CV_DRIVER, NULL);
1145 
1146         /* Initialize the individual outstanding command list entries */
1147         for (i = 0; i < state->ts_cmd_list.cml_list_sz; i++) {
1148                 mutex_init(&state->ts_cmd_list.cml_cmd[i].cmd_comp_lock,
1149                     NULL, MUTEX_DRIVER, DDI_INTR_PRI(state->ts_intrmsi_pri));
1150                 cv_init(&state->ts_cmd_list.cml_cmd[i].cmd_comp_cv, NULL,
1151                     CV_DRIVER, NULL);
1152 
1153                 state->ts_cmd_list.cml_cmd[i].cmd_next       = i+1;
1154                 state->ts_cmd_list.cml_cmd[i].cmd_prev       = i-1;
1155                 state->ts_cmd_list.cml_cmd[i].cmd_indx       = i;
1156                 state->ts_cmd_list.cml_num_alloc     = i + 1;
1157         }
1158         if (num_outstanding_cmds) {
1159                 head = state->ts_cmd_list.cml_head_indx;
1160                 tail = state->ts_cmd_list.cml_tail_indx;
1161                 state->ts_cmd_list.cml_cmd[head].cmd_prev =
1162                     state->ts_cmd_list.cml_tail_indx;
1163                 state->ts_cmd_list.cml_cmd[tail].cmd_next =
1164                     state->ts_cmd_list.cml_head_indx;
1165         }
1166 
1167         TAVOR_TNF_EXIT(tavor_outstanding_cmdlist_init);
1168         return (DDI_SUCCESS);
1169 }
1170 
1171 
1172 /*
1173  * tavor_outstanding_cmdlist_fini()
1174  *    Context: Only called from attach() and/or detach() path contexts
1175  */
1176 void
1177 tavor_outstanding_cmdlist_fini(tavor_state_t *state)
1178 {
1179         int             i;
1180 
1181         TAVOR_TNF_ENTER(tavor_outstanding_cmdlist_fini);
1182 
1183         /* Destroy the outstanding command list entries */
1184         for (i = 0; i < state->ts_cmd_list.cml_num_alloc; i++) {
1185                 mutex_destroy(&state->ts_cmd_list.cml_cmd[i].cmd_comp_lock);
1186                 cv_destroy(&state->ts_cmd_list.cml_cmd[i].cmd_comp_cv);
1187         }
1188 
1189         /* Destroy the lock (and cv) and free up memory for list */
1190         mutex_destroy(&state->ts_cmd_list.cml_lock);
1191         cv_destroy(&state->ts_cmd_list.cml_cv);
1192         if (state->ts_cmd_list.cml_num_alloc) {
1193                 kmem_free(state->ts_cmd_list.cml_cmd,
1194                     state->ts_cmd_list.cml_list_sz * sizeof (tavor_cmd_t));
1195         }
1196 
1197         TAVOR_TNF_EXIT(tavor_outstanding_cmdlist_fini);
1198 }
1199 
1200 
1201 /*
1202  * tavor_mbox_sync()
1203  */
1204 static void
1205 tavor_mbox_sync(tavor_mbox_t *mbox, uint_t offset, uint_t length,
1206     uint_t flag)
1207 {
1208         ddi_dma_handle_t        dmahdl;
1209         int                     status;
1210 
1211         TAVOR_TNF_ENTER(tavor_mbox_sync);
1212 
1213         /* Determine if mailbox needs to be synced or not */
1214         if (mbox->mb_sync == 0) {
1215                 TAVOR_TNF_EXIT(tavor_mbox_sync);
1216                 return;
1217         }
1218 
1219         /* Get the DMA handle from mailbox */
1220         dmahdl = mbox->mb_rsrcptr->tr_dmahdl;
1221 
1222         /* Calculate offset into mailbox */
1223         status = ddi_dma_sync(dmahdl, (off_t)offset, (size_t)length, flag);
1224         if (status != DDI_SUCCESS) {
1225                 TNF_PROBE_0(tavor_mbox_sync_fail, TAVOR_TNF_ERROR, "");
1226                 TAVOR_TNF_EXIT(tavor_mbox_sync);
1227                 return;
1228         }
1229 
1230         TAVOR_TNF_EXIT(tavor_mbox_sync);
1231 }
1232 
1233 
1234 /*
1235  * tavor_sys_en_cmd_post()
1236  *    Context: Can be called from interrupt or base context.
1237  *    (Currently called only from attach() path context)
1238  */
1239 int
1240 tavor_sys_en_cmd_post(tavor_state_t *state, uint_t flags,
1241     uint64_t *errorcode, uint_t sleepflag)
1242 {
1243         tavor_cmd_post_t        cmd;
1244         int                     status;
1245 
1246         TAVOR_TNF_ENTER(tavor_sys_en_cmd_post);
1247 
1248         /* Make sure we are called with the correct flag */
1249         ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN);
1250 
1251         /* Setup and post the Tavor "SYS_EN" command */
1252         cmd.cp_inparm   = 0;
1253         cmd.cp_outparm  = 0;
1254         cmd.cp_inmod    = 0;
1255         cmd.cp_opcode   = SYS_EN;
1256         cmd.cp_opmod    = flags;
1257         cmd.cp_flags    = sleepflag;
1258         status = tavor_cmd_post(state, &cmd);
1259         if (status != TAVOR_CMD_SUCCESS) {
1260                 TNF_PROBE_0(tavor_sys_en_cmd_post_fail, TAVOR_TNF_ERROR, "");
1261                 /*
1262                  * When the SYS_EN command fails, the "outparam" field may
1263                  * contain more detailed information about what caused the
1264                  * failure.
1265                  */
1266                 *errorcode = cmd.cp_outparm;
1267         }
1268 
1269         TAVOR_TNF_EXIT(tavor_sys_en_cmd_post);
1270         return (status);
1271 }
1272 
1273 
1274 /*
1275  * tavor_sys_dis_cmd_post()
1276  *    Context: Can be called from interrupt or base context.
1277  *    (Currently called only from attach() and/or detach() path contexts)
1278  */
1279 int
1280 tavor_sys_dis_cmd_post(tavor_state_t *state, uint_t sleepflag)
1281 {
1282         tavor_cmd_post_t        cmd;
1283         int                     status;
1284 
1285         TAVOR_TNF_ENTER(tavor_sys_dis_cmd_post);
1286 
1287         /* Make sure we are called with the correct flag */
1288         ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN);
1289 
1290         /* Setup and post the Tavor "SYS_DIS" command */
1291         cmd.cp_inparm   = 0;
1292         cmd.cp_outparm  = 0;
1293         cmd.cp_inmod    = 0;
1294         cmd.cp_opcode   = SYS_DIS;
1295         cmd.cp_opmod    = 0;
1296         cmd.cp_flags    = sleepflag;
1297         status = tavor_cmd_post(state, &cmd);
1298         if (status != TAVOR_CMD_SUCCESS) {
1299                 TNF_PROBE_0(tavor_sys_dis_cmd_post_fail,
1300                     TAVOR_TNF_ERROR, "");
1301         }
1302 
1303         TAVOR_TNF_EXIT(tavor_sys_dis_cmd_post);
1304         return (status);
1305 }
1306 
1307 
1308 /*
1309  * tavor_init_hca_cmd_post()
1310  *    Context: Can be called from interrupt or base context.
1311  *    (Currently called only from attach() path context)
1312  */
1313 int
1314 tavor_init_hca_cmd_post(tavor_state_t *state,
1315     tavor_hw_initqueryhca_t *inithca, uint_t sleepflag)
1316 {
1317         tavor_mbox_info_t       mbox_info;
1318         tavor_cmd_post_t        cmd;
1319         uint64_t                data;
1320         uint_t                  size;
1321         int                     status, i;
1322 
1323         TAVOR_TNF_ENTER(tavor_init_hca_cmd_post);
1324 
1325         /* Make sure we are called with the correct flag */
1326         ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN);
1327 
1328         /* Get an "In" mailbox for the command */
1329         mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
1330         status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
1331         if (status != TAVOR_CMD_SUCCESS) {
1332                 TNF_PROBE_0(tavor_init_hca_mbox_fail, TAVOR_TNF_ERROR, "");
1333                 TAVOR_TNF_EXIT(tavor_init_hca_cmd_post);
1334                 return (status);
1335         }
1336 
1337         /* Copy the Tavor "INIT_HCA" command into the mailbox */
1338         size = sizeof (tavor_hw_initqueryhca_t);
1339         for (i = 0; i < (size >> 3); i++) {
1340                 data = ((uint64_t *)inithca)[i];
1341                 ddi_put64(mbox_info.mbi_in->mb_acchdl,
1342                     ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
1343         }
1344 
1345         /* Sync the mailbox for the device to read */
1346         tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
1347 
1348         /* Setup and post the Tavor "INIT_HCA" command */
1349         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
1350         cmd.cp_outparm  = 0;
1351         cmd.cp_inmod    = 0;
1352         cmd.cp_opcode   = INIT_HCA;
1353         cmd.cp_opmod    = 0;
1354         cmd.cp_flags    = sleepflag;
1355         status = tavor_cmd_post(state, &cmd);
1356         if (status != TAVOR_CMD_SUCCESS) {
1357                 TNF_PROBE_0(tavor_init_hca_cmd_post_fail,
1358                     TAVOR_TNF_ERROR, "");
1359         }
1360 
1361         /* Free the mailbox */
1362         tavor_mbox_free(state, &mbox_info);
1363 
1364         TAVOR_TNF_EXIT(tavor_init_hca_cmd_post);
1365         return (status);
1366 }
1367 
1368 
1369 /*
1370  * tavor_close_hca_cmd_post()
1371  *    Context: Can be called from interrupt or base context.
1372  *    (Currently called only from attach() and/or detach() path contexts)
1373  */
1374 int
1375 tavor_close_hca_cmd_post(tavor_state_t *state, uint_t sleepflag)
1376 {
1377         tavor_cmd_post_t        cmd;
1378         int                     status;
1379 
1380         TAVOR_TNF_ENTER(tavor_close_hca_cmd_post);
1381 
1382         /* Make sure we are called with the correct flag */
1383         ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN);
1384 
1385         /* Setup and post the Tavor "CLOSE_HCA" command */
1386         cmd.cp_inparm   = 0;
1387         cmd.cp_outparm  = 0;
1388         cmd.cp_inmod    = 0;
1389         cmd.cp_opcode   = CLOSE_HCA;
1390         cmd.cp_opmod    = 0;
1391         cmd.cp_flags    = sleepflag;
1392         status = tavor_cmd_post(state, &cmd);
1393         if (status != TAVOR_CMD_SUCCESS) {
1394                 TNF_PROBE_0(tavor_close_hca_cmd_post_fail,
1395                     TAVOR_TNF_ERROR, "");
1396         }
1397 
1398         TAVOR_TNF_EXIT(tavor_close_hca_cmd_post);
1399         return (status);
1400 }
1401 
1402 
1403 /*
1404  * tavor_init_ib_cmd_post()
1405  *    Context: Can be called from interrupt or base context.
1406  *    (Currently called only from attach() path context)
1407  */
1408 int
1409 tavor_init_ib_cmd_post(tavor_state_t *state, tavor_hw_initib_t *initib,
1410     uint_t port, uint_t sleepflag)
1411 {
1412         tavor_mbox_info_t       mbox_info;
1413         tavor_cmd_post_t        cmd;
1414         uint64_t                data;
1415         uint_t                  size;
1416         int                     status, i;
1417 
1418         TAVOR_TNF_ENTER(tavor_init_ib_cmd_post);
1419 
1420         /* Make sure we are called with the correct flag */
1421         ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN);
1422 
1423         /* Get an "In" mailbox for the command */
1424         mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
1425         status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
1426         if (status != TAVOR_CMD_SUCCESS) {
1427                 TNF_PROBE_0(tavor_init_ib_mbox_fail, TAVOR_TNF_ERROR, "");
1428                 TAVOR_TNF_EXIT(tavor_init_ib_cmd_post);
1429                 return (status);
1430         }
1431 
1432         /* Copy the Tavor "INIT_IB" command into the mailbox */
1433         size = sizeof (tavor_hw_initib_t);
1434         for (i = 0; i < (size >> 3); i++) {
1435                 data = ((uint64_t *)initib)[i];
1436                 ddi_put64(mbox_info.mbi_in->mb_acchdl,
1437                     ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
1438         }
1439 
1440         /* Sync the mailbox for the device to read */
1441         tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
1442 
1443         /* Setup and post the Tavor "INIT_IB" command */
1444         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
1445         cmd.cp_outparm  = 0;
1446         cmd.cp_inmod    = port;
1447         cmd.cp_opcode   = INIT_IB;
1448         cmd.cp_opmod    = 0;
1449         cmd.cp_flags    = sleepflag;
1450         status = tavor_cmd_post(state, &cmd);
1451         if (status != TAVOR_CMD_SUCCESS) {
1452                 TNF_PROBE_0(tavor_init_ib_cmd_post_fail,
1453                     TAVOR_TNF_ERROR, "");
1454         }
1455 
1456         /* Free the mailbox */
1457         tavor_mbox_free(state, &mbox_info);
1458 
1459         TAVOR_TNF_EXIT(tavor_init_ib_cmd_post);
1460         return (status);
1461 }
1462 
1463 
1464 /*
1465  * tavor_close_ib_cmd_post()
1466  *    Context: Can be called from interrupt or base context.
1467  *    (Currently called only from attach() and/or detach() path contexts)
1468  */
1469 int
1470 tavor_close_ib_cmd_post(tavor_state_t *state, uint_t port, uint_t sleepflag)
1471 {
1472         tavor_cmd_post_t        cmd;
1473         int                     status;
1474 
1475         TAVOR_TNF_ENTER(tavor_close_ib_cmd_post);
1476 
1477         /* Setup and post the Tavor "CLOSE_IB" command */
1478         cmd.cp_inparm   = 0;
1479         cmd.cp_outparm  = 0;
1480         cmd.cp_inmod    = port;
1481         cmd.cp_opcode   = CLOSE_IB;
1482         cmd.cp_opmod    = 0;
1483         cmd.cp_flags    = sleepflag;
1484         status = tavor_cmd_post(state, &cmd);
1485         if (status != TAVOR_CMD_SUCCESS) {
1486                 TNF_PROBE_0(tavor_close_ib_cmd_post_fail, TAVOR_TNF_ERROR, "");
1487         }
1488 
1489         TAVOR_TNF_EXIT(tavor_close_ib_cmd_post);
1490         return (status);
1491 }
1492 
1493 
1494 /*
1495  * tavor_set_ib_cmd_post()
1496  *    Context: Can be called from interrupt or base context.
1497  */
1498 int
1499 tavor_set_ib_cmd_post(tavor_state_t *state, uint32_t capmask, uint_t port,
1500     uint_t reset_qkey, uint_t sleepflag)
1501 {
1502         tavor_mbox_info_t       mbox_info;
1503         tavor_cmd_post_t        cmd;
1504         int                     status;
1505 
1506         TAVOR_TNF_ENTER(tavor_set_ib_cmd_post);
1507 
1508         /* Get an "In" mailbox for the command */
1509         mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
1510         status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
1511         if (status != TAVOR_CMD_SUCCESS) {
1512                 TNF_PROBE_0(tavor_set_ib_mbox_fail, TAVOR_TNF_ERROR, "");
1513                 TAVOR_TNF_EXIT(tavor_set_ib_cmd_post);
1514                 return (status);
1515         }
1516 
1517         /* Copy the Tavor "SET_IB" command into mailbox */
1518         ddi_put32(mbox_info.mbi_in->mb_acchdl,
1519             ((uint32_t *)mbox_info.mbi_in->mb_addr + 0), reset_qkey);
1520         ddi_put32(mbox_info.mbi_in->mb_acchdl,
1521             ((uint32_t *)mbox_info.mbi_in->mb_addr + 1), capmask);
1522 
1523         /* Sync the mailbox for the device to read */
1524         tavor_mbox_sync(mbox_info.mbi_in, 0, TAVOR_CMD_SETIB_SZ,
1525             DDI_DMA_SYNC_FORDEV);
1526 
1527         /* Setup and post the Tavor "SET_IB" command */
1528         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
1529         cmd.cp_outparm  = 0;
1530         cmd.cp_inmod    = port;
1531         cmd.cp_opcode   = SET_IB;
1532         cmd.cp_opmod    = 0;
1533         cmd.cp_flags    = sleepflag;
1534         status = tavor_cmd_post(state, &cmd);
1535         if (status != TAVOR_CMD_SUCCESS) {
1536                 TNF_PROBE_0(tavor_set_ib_cmd_post_fail, TAVOR_TNF_ERROR, "");
1537         }
1538 
1539         /* Free the mailbox */
1540         tavor_mbox_free(state, &mbox_info);
1541 
1542         TAVOR_TNF_EXIT(tavor_set_ib_cmd_post);
1543         return (status);
1544 }
1545 
1546 
1547 /*
1548  * tavor_mod_stat_cfg_cmd_post()
1549  *    Context: Can be called only from attach() path
1550  */
1551 int
1552 tavor_mod_stat_cfg_cmd_post(tavor_state_t *state)
1553 {
1554         tavor_mbox_info_t       mbox_info;
1555         tavor_cmd_post_t        cmd;
1556         tavor_hw_mod_stat_cfg_t *mod;
1557         uint64_t                data;
1558         uint_t                  size;
1559         int                     status, i;
1560 
1561         TAVOR_TNF_ENTER(tavor_mod_stat_cfg_cmd_post);
1562 
1563         /*
1564          * "MOD_STAT_CFG" needs an INMBOX parameter, to specify what operations
1565          * to do.  However, at the point in time that we call this command, the
1566          * DDR has not yet been initialized, and all INMBOX'es are located in
1567          * DDR.  Because we want to call MOD_STAT_CFG before QUERY_DEVLIM is
1568          * called, and thus call it before DDR is setup, we simply use an
1569          * OUTMBOX memory location here as our INMBOX parameter.
1570          */
1571         mbox_info.mbi_alloc_flags = TAVOR_ALLOC_OUTMBOX;
1572         status = tavor_mbox_alloc(state, &mbox_info, TAVOR_NOSLEEP);
1573         if (status != TAVOR_CMD_SUCCESS) {
1574                 TNF_PROBE_0(tavor_mod_stat_cfg_mbox_fail, TAVOR_TNF_ERROR, "");
1575                 TAVOR_TNF_EXIT(tavor_mod_stat_cfg_cmd_post);
1576                 return (status);
1577         }
1578 
1579         /*
1580          * Allocate on the heap our 'mod_stat_cfg' structure.  We want to
1581          * ideally move all of this on to the stack in the future, but this
1582          * works well for now.
1583          */
1584         mod = (tavor_hw_mod_stat_cfg_t *)kmem_zalloc(
1585             sizeof (tavor_hw_mod_stat_cfg_t), KM_SLEEP);
1586 
1587         /* Setup "MOD_STAT_CFG" settings */
1588         mod->srq_m   = 1;
1589         mod->srq     = state->ts_cfg_profile->cp_srq_enable;
1590 
1591         if (mod->srq) {
1592                 mod->log_max_srq = state->ts_cfg_profile->cp_log_num_srq;
1593         } else {
1594                 mod->log_max_srq = 0;
1595         }
1596 
1597         /* Copy the "MOD_STAT_CFG" command into the "In" mailbox */
1598         size = sizeof (tavor_hw_mod_stat_cfg_t);
1599         for (i = 0; i < (size >> 3); i++) {
1600                 data = ((uint64_t *)mod)[i];
1601                 ddi_put64(mbox_info.mbi_out->mb_acchdl,
1602                     ((uint64_t *)mbox_info.mbi_out->mb_addr + i), data);
1603         }
1604 
1605         /* Sync the mailbox for the device to read */
1606         tavor_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORDEV);
1607 
1608         /* Setup and post the Tavor "MOD_STAT_CFG" command */
1609         cmd.cp_inparm   = mbox_info.mbi_out->mb_mapaddr;
1610         cmd.cp_outparm  = 0;
1611         cmd.cp_inmod    = 0;
1612         cmd.cp_opcode   = MOD_STAT_CFG;
1613         cmd.cp_opmod    = 0;
1614         cmd.cp_flags    = TAVOR_CMD_NOSLEEP_SPIN;
1615         status = tavor_cmd_post(state, &cmd);
1616         if (status != TAVOR_CMD_SUCCESS) {
1617                 TNF_PROBE_0(tavor_mod_stat_cfg_cmd_post_fail, TAVOR_TNF_ERROR,
1618                     "");
1619         }
1620 
1621         /* Free "MOD_STAT_CFG" struct */
1622         kmem_free(mod, sizeof (tavor_hw_mod_stat_cfg_t));
1623 
1624         /* Free the mailbox */
1625         tavor_mbox_free(state, &mbox_info);
1626 
1627         TAVOR_TNF_EXIT(tavor_mod_stat_cfg_cmd_post);
1628         return (status);
1629 }
1630 
1631 
1632 /*
1633  * tavor_mad_ifc_cmd_post()
1634  *    Context: Can be called from interrupt or base context.
1635  */
1636 int
1637 tavor_mad_ifc_cmd_post(tavor_state_t *state, uint_t port,
1638     uint_t sleepflag, uint32_t *mad, uint32_t *resp)
1639 {
1640         tavor_mbox_info_t       mbox_info;
1641         tavor_cmd_post_t        cmd;
1642         uint_t                  size;
1643         int                     status;
1644 
1645         TAVOR_TNF_ENTER(tavor_mad_ifc_cmd_post);
1646 
1647         /* Get "In" and "Out" mailboxes for the command */
1648         mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
1649         status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
1650         if (status != TAVOR_CMD_SUCCESS) {
1651                 TNF_PROBE_0(tavor_mad_ifc_mbox_fail, TAVOR_TNF_ERROR, "");
1652                 TAVOR_TNF_EXIT(tavor_mad_ifc_cmd_post);
1653                 return (status);
1654         }
1655 
1656         /* Copy the request MAD into the "In" mailbox */
1657         size = TAVOR_CMD_MAD_IFC_SIZE;
1658         bcopy(mad, mbox_info.mbi_in->mb_addr, size);
1659 
1660         /* Sync the mailbox for the device to read */
1661         tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
1662 
1663         /* Setup the Tavor "MAD_IFC" command */
1664         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
1665         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
1666         cmd.cp_inmod    = port;
1667         cmd.cp_opcode   = MAD_IFC;
1668         cmd.cp_opmod    = TAVOR_CMD_MKEY_CHECK;  /* Enable MKey checking */
1669         cmd.cp_flags    = sleepflag;
1670         status = tavor_cmd_post(state, &cmd);
1671         if (status != TAVOR_CMD_SUCCESS) {
1672                 TNF_PROBE_0(tavor_mad_ifc_cmd_post_fail,
1673                     TAVOR_TNF_ERROR, "");
1674                 goto mad_ifc_fail;
1675         }
1676 
1677         /* Sync the mailbox to read the results */
1678         tavor_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
1679 
1680         /* Copy the response MAD into "resp" */
1681         bcopy(mbox_info.mbi_out->mb_addr, resp, size);
1682 
1683 mad_ifc_fail:
1684         /* Free the mailbox */
1685         tavor_mbox_free(state, &mbox_info);
1686 
1687         TAVOR_TNF_EXIT(tavor_mad_ifc_cmd_post);
1688         return (status);
1689 }
1690 
1691 
1692 /*
1693  * tavor_getportinfo_cmd_post()
1694  *    Context: Can be called from interrupt or base context.
1695  */
1696 int
1697 tavor_getportinfo_cmd_post(tavor_state_t *state, uint_t port,
1698     uint_t sleepflag, sm_portinfo_t *portinfo)
1699 {
1700         tavor_mbox_info_t       mbox_info;
1701         tavor_cmd_post_t        cmd;
1702         uint32_t                *mbox;
1703         uint_t                  size;
1704         int                     status, i;
1705 
1706         TAVOR_TNF_ENTER(tavor_getportinfo_cmd_post);
1707 
1708         /* Get "In" and "Out" mailboxes for the command */
1709         mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
1710         status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
1711         if (status != TAVOR_CMD_SUCCESS) {
1712                 TNF_PROBE_0(tavor_getportinfo_mbox_fail,
1713                     TAVOR_TNF_ERROR, "");
1714                 TAVOR_TNF_EXIT(tavor_getportinfo_cmd_post);
1715                 return (status);
1716         }
1717 
1718         /* Build the GetPortInfo request MAD in the "In" mailbox */
1719         size = TAVOR_CMD_MAD_IFC_SIZE;
1720         mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
1721         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], TAVOR_CMD_MADHDR0);
1722         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1);
1723         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2);
1724         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3);
1725         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_PORTINFO);
1726         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], port);
1727         for (i = 6; i < (size >> 2); i++) {
1728                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
1729         }
1730 
1731         /* Sync the mailbox for the device to read */
1732         tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
1733 
1734         /* Setup the Tavor "MAD_IFC" command */
1735         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
1736         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
1737         cmd.cp_inmod    = port;
1738         cmd.cp_opcode   = MAD_IFC;
1739         cmd.cp_opmod    = TAVOR_CMD_MKEY_DONTCHECK;  /* No MKey checking */
1740         cmd.cp_flags    = sleepflag;
1741         status = tavor_cmd_post(state, &cmd);
1742         if (status != TAVOR_CMD_SUCCESS) {
1743                 TNF_PROBE_0(tavor_getportinfo_cmd_post_fail,
1744                     TAVOR_TNF_ERROR, "");
1745                 goto getportinfo_fail;
1746         }
1747 
1748         /* Sync the mailbox to read the results */
1749         size = sizeof (sm_portinfo_t);
1750         tavor_mbox_sync(mbox_info.mbi_out, TAVOR_CMD_MADDATA_OFFSET,
1751             size, DDI_DMA_SYNC_FORCPU);
1752 
1753         /*
1754          * Copy GetPortInfo response MAD into "portinfo".  Do any endian
1755          * swapping that may be necessary to flip any of the "portinfo"
1756          * fields
1757          */
1758         bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
1759             TAVOR_CMD_MADDATA_OFFSET), portinfo, size);
1760         TAVOR_GETPORTINFO_SWAP(portinfo);
1761 
1762 getportinfo_fail:
1763         /* Free the mailbox */
1764         tavor_mbox_free(state, &mbox_info);
1765 
1766         TAVOR_TNF_EXIT(tavor_getportinfo_cmd_post);
1767         return (status);
1768 }
1769 
1770 
1771 /*
1772  * tavor_getnodeinfo_cmd_post()
1773  *    Context: Can be called from interrupt or base context.
1774  *    (Currently called only from attach() and detach() path contexts)
1775  */
1776 int
1777 tavor_getnodeinfo_cmd_post(tavor_state_t *state, uint_t sleepflag,
1778     sm_nodeinfo_t *nodeinfo)
1779 {
1780         tavor_mbox_info_t       mbox_info;
1781         tavor_cmd_post_t        cmd;
1782         uint32_t                *mbox;
1783         uint_t                  size;
1784         int                     status, i;
1785 
1786         TAVOR_TNF_ENTER(tavor_getnodeinfo_cmd_post);
1787 
1788         /* Make sure we are called with the correct flag */
1789         ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN);
1790 
1791         /* Get "In" and "Out" mailboxes for the command */
1792         mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
1793         status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
1794         if (status != TAVOR_CMD_SUCCESS) {
1795                 TNF_PROBE_0(tavor_getnodeinfo_mbox_fail,
1796                     TAVOR_TNF_ERROR, "");
1797                 TAVOR_TNF_EXIT(tavor_getnodeinfo_cmd_post);
1798                 return (status);
1799         }
1800 
1801         /* Build the GetNodeInfo request MAD into the "In" mailbox */
1802         size = TAVOR_CMD_MAD_IFC_SIZE;
1803         mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
1804         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], TAVOR_CMD_MADHDR0);
1805         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1);
1806         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2);
1807         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3);
1808         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_NODEINFO);
1809         for (i = 5; i < (size >> 2); i++) {
1810                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
1811         }
1812 
1813         /* Sync the mailbox for the device to read */
1814         tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
1815 
1816         /* Setup the Tavor "MAD_IFC" command */
1817         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
1818         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
1819         cmd.cp_inmod    = 1;  /* Get NodeInfo from port #1 */
1820         cmd.cp_opcode   = MAD_IFC;
1821         cmd.cp_opmod    = TAVOR_CMD_MKEY_DONTCHECK;  /* No MKey checking */
1822         cmd.cp_flags    = sleepflag;
1823         status = tavor_cmd_post(state, &cmd);
1824         if (status != TAVOR_CMD_SUCCESS) {
1825                 TNF_PROBE_0(tavor_getnodeinfo_cmd_post_fail,
1826                     TAVOR_TNF_ERROR, "");
1827                 goto getnodeinfo_fail;
1828         }
1829 
1830         /* Sync the mailbox to read the results */
1831         size = sizeof (sm_nodeinfo_t);
1832         tavor_mbox_sync(mbox_info.mbi_out, TAVOR_CMD_MADDATA_OFFSET,
1833             size, DDI_DMA_SYNC_FORCPU);
1834 
1835         /*
1836          * Copy GetNodeInfo response MAD into "nodeinfo".  Do any endian
1837          * swapping that may be necessary to flip any of the "nodeinfo"
1838          * fields
1839          */
1840         bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
1841             TAVOR_CMD_MADDATA_OFFSET), nodeinfo, size);
1842         TAVOR_GETNODEINFO_SWAP(nodeinfo);
1843 
1844 getnodeinfo_fail:
1845         /* Free the mailbox */
1846         tavor_mbox_free(state, &mbox_info);
1847 
1848         TAVOR_TNF_EXIT(tavor_getnodeinfo_cmd_post);
1849         return (status);
1850 }
1851 
1852 
1853 /*
1854  * tavor_getnodedesc_cmd_post()
1855  *    Context: Can be called from interrupt or base context.
1856  *    (Currently called only from attach() and detach() path contexts)
1857  */
1858 int
1859 tavor_getnodedesc_cmd_post(tavor_state_t *state, uint_t sleepflag,
1860     sm_nodedesc_t *nodedesc)
1861 {
1862         tavor_mbox_info_t       mbox_info;
1863         tavor_cmd_post_t        cmd;
1864         uint32_t                *mbox;
1865         uint_t                  size;
1866         int                     status, i;
1867 
1868         TAVOR_TNF_ENTER(tavor_getnodedesc_cmd_post);
1869 
1870         /* Get "In" and "Out" mailboxes for the command */
1871         mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
1872         status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
1873         if (status != TAVOR_CMD_SUCCESS) {
1874                 TNF_PROBE_0(tavor_getnodedesc_mbox_fail, TAVOR_TNF_ERROR, "");
1875                 TAVOR_TNF_EXIT(tavor_getnodedesc_cmd_post);
1876                 return (status);
1877         }
1878 
1879         /* Build the GetNodeDesc request MAD into the "In" mailbox */
1880         size = TAVOR_CMD_MAD_IFC_SIZE;
1881         mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
1882         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], TAVOR_CMD_MADHDR0);
1883         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1);
1884         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2);
1885         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3);
1886         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_NODEDESC);
1887         for (i = 5; i < (size >> 2); i++) {
1888                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
1889         }
1890 
1891         /* Sync the mailbox for the device to read */
1892         tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
1893 
1894         /* Setup the Tavor "MAD_IFC" command */
1895         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
1896         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
1897         cmd.cp_inmod    = 1;  /* Get NodeDesc from port #1 */
1898         cmd.cp_opcode   = MAD_IFC;
1899         cmd.cp_opmod    = TAVOR_CMD_MKEY_DONTCHECK;  /* No MKey checking */
1900         cmd.cp_flags    = sleepflag;
1901         status = tavor_cmd_post(state, &cmd);
1902         if (status != TAVOR_CMD_SUCCESS) {
1903                 TNF_PROBE_0(tavor_getnodedesc_cmd_post_fail,
1904                     TAVOR_TNF_ERROR, "");
1905                 goto getnodedesc_fail;
1906         }
1907 
1908         /* Sync the mailbox to read the results */
1909         size = sizeof (sm_nodedesc_t);
1910         tavor_mbox_sync(mbox_info.mbi_out, TAVOR_CMD_MADDATA_OFFSET,
1911             size, DDI_DMA_SYNC_FORCPU);
1912 
1913         /* Copy GetNodeDesc response MAD into "nodedesc" */
1914         bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
1915             TAVOR_CMD_MADDATA_OFFSET), nodedesc, size);
1916 
1917 getnodedesc_fail:
1918         /* Free the mailbox */
1919         tavor_mbox_free(state, &mbox_info);
1920 
1921         TAVOR_TNF_EXIT(tavor_getnodedesc_cmd_post);
1922         return (status);
1923 }
1924 
1925 
1926 /*
1927  * tavor_getguidinfo_cmd_post()
1928  *    Context: Can be called from interrupt or base context.
1929  */
1930 int
1931 tavor_getguidinfo_cmd_post(tavor_state_t *state, uint_t port,
1932     uint_t guidblock, uint_t sleepflag, sm_guidinfo_t *guidinfo)
1933 {
1934         tavor_mbox_info_t       mbox_info;
1935         tavor_cmd_post_t        cmd;
1936         uint32_t                *mbox;
1937         uint_t                  size;
1938         int                     status, i;
1939 
1940         TAVOR_TNF_ENTER(tavor_getguidinfo_cmd_post);
1941 
1942         /* Get "In" and "Out" mailboxes for the command */
1943         mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
1944         status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
1945         if (status != TAVOR_CMD_SUCCESS) {
1946                 TNF_PROBE_0(tavor_getguidinfo_mbox_fail, TAVOR_TNF_ERROR, "");
1947                 TAVOR_TNF_EXIT(tavor_getguidinfo_cmd_post);
1948                 return (status);
1949         }
1950 
1951         /* Build the GetGUIDInfo request MAD into the "In" mailbox */
1952         size = TAVOR_CMD_MAD_IFC_SIZE;
1953         mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
1954         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], TAVOR_CMD_MADHDR0);
1955         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1);
1956         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2);
1957         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3);
1958         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_GUIDINFO);
1959         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], guidblock);
1960         for (i = 6; i < (size >> 2); i++) {
1961                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
1962         }
1963 
1964         /* Sync the mailbox for the device to read */
1965         tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
1966 
1967         /* Setup the Tavor "MAD_IFC" command */
1968         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
1969         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
1970         cmd.cp_inmod    = port;
1971         cmd.cp_opcode   = MAD_IFC;
1972         cmd.cp_opmod    = TAVOR_CMD_MKEY_DONTCHECK;  /* No MKey checking */
1973         cmd.cp_flags    = sleepflag;
1974         status = tavor_cmd_post(state, &cmd);
1975         if (status != TAVOR_CMD_SUCCESS) {
1976                 TNF_PROBE_0(tavor_getguidinfo_cmd_post_fail,
1977                     TAVOR_TNF_ERROR, "");
1978                 goto getguidinfo_fail;
1979         }
1980 
1981         /* Sync the mailbox to read the results */
1982         size = sizeof (sm_guidinfo_t);
1983         tavor_mbox_sync(mbox_info.mbi_out, TAVOR_CMD_MADDATA_OFFSET,
1984             size, DDI_DMA_SYNC_FORCPU);
1985 
1986         /*
1987          * Copy GetGUIDInfo response MAD into "guidinfo".  Do any endian
1988          * swapping that may be necessary to flip the "guidinfo" fields
1989          */
1990         bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
1991             TAVOR_CMD_MADDATA_OFFSET), guidinfo, size);
1992         TAVOR_GETGUIDINFO_SWAP(guidinfo);
1993 
1994 getguidinfo_fail:
1995         /* Free the mailbox */
1996         tavor_mbox_free(state, &mbox_info);
1997 
1998         TAVOR_TNF_EXIT(tavor_getguidinfo_cmd_post);
1999         return (status);
2000 }
2001 
2002 
2003 /*
2004  * tavor_getpkeytable_cmd_post()
2005  *    Context: Can be called from interrupt or base context.
2006  */
2007 int
2008 tavor_getpkeytable_cmd_post(tavor_state_t *state, uint_t port,
2009     uint_t pkeyblock, uint_t sleepflag, sm_pkey_table_t *pkeytable)
2010 {
2011         tavor_mbox_info_t       mbox_info;
2012         tavor_cmd_post_t        cmd;
2013         uint32_t                *mbox;
2014         uint_t                  size;
2015         int                     status, i;
2016 
2017         TAVOR_TNF_ENTER(tavor_getpkeytable_cmd_post);
2018 
2019         /* Get "In" and "Out" mailboxes for the command */
2020         mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
2021         status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
2022         if (status != TAVOR_CMD_SUCCESS) {
2023                 TNF_PROBE_0(tavor_getpkeytable_mbox_fail, TAVOR_TNF_ERROR, "");
2024                 TAVOR_TNF_EXIT(tavor_getpkeytable_cmd_post);
2025                 return (status);
2026         }
2027 
2028         /* Build the GetPkeyTable request MAD into the "In" mailbox */
2029         size = TAVOR_CMD_MAD_IFC_SIZE;
2030         mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2031         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], TAVOR_CMD_MADHDR0);
2032         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1);
2033         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2);
2034         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3);
2035         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_PKEYTBLE);
2036         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], pkeyblock);
2037         for (i = 6; i < (size >> 2); i++) {
2038                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
2039         }
2040 
2041         /* Sync the mailbox for the device to read */
2042         tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2043 
2044         /* Setup the Tavor "MAD_IFC" command */
2045         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
2046         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
2047         cmd.cp_inmod    = port;
2048         cmd.cp_opcode   = MAD_IFC;
2049         cmd.cp_opmod    = TAVOR_CMD_MKEY_DONTCHECK;  /* No MKey checking */
2050         cmd.cp_flags    = sleepflag;
2051         status = tavor_cmd_post(state, &cmd);
2052         if (status != TAVOR_CMD_SUCCESS) {
2053                 TNF_PROBE_0(tavor_getpkeytable_cmd_post_fail,
2054                     TAVOR_TNF_ERROR, "");
2055                 goto getpkeytable_fail;
2056         }
2057 
2058         /* Sync the mailbox to read the results */
2059         size = sizeof (sm_pkey_table_t);
2060         tavor_mbox_sync(mbox_info.mbi_out, TAVOR_CMD_MADDATA_OFFSET,
2061             size, DDI_DMA_SYNC_FORCPU);
2062 
2063         /*
2064          * Copy GetPKeyTable response MAD into "pkeytable".  Do any endian
2065          * swapping that may be necessary to flip the "pkeytable" fields
2066          */
2067         bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
2068             TAVOR_CMD_MADDATA_OFFSET), pkeytable, size);
2069         TAVOR_GETPKEYTABLE_SWAP(pkeytable);
2070 
2071 getpkeytable_fail:
2072         /* Free the mailbox */
2073         tavor_mbox_free(state, &mbox_info);
2074 
2075         TAVOR_TNF_EXIT(tavor_getpkeytable_cmd_post);
2076         return (status);
2077 }
2078 
2079 
2080 /*
2081  * tavor_write_mtt_cmd_post()
2082  *    Context: Can be called from interrupt or base context.
2083  */
2084 int
2085 tavor_write_mtt_cmd_post(tavor_state_t *state, tavor_mbox_info_t *mbox_info,
2086     uint_t num_mtt, uint_t sleepflag)
2087 {
2088         tavor_cmd_post_t        cmd;
2089         uint_t                  size;
2090         int                     status;
2091 
2092         TAVOR_TNF_ENTER(tavor_write_mtt_cmd_post);
2093 
2094         /*
2095          * The WRITE_MTT command is unlike the other commands we use, in that
2096          * we have intentionally separated the mailbox allocation step from
2097          * the rest of the command posting steps.  At this point (when this
2098          * function is called) the "In" mailbox already contains all the MTT
2099          * entries to be copied into the Tavor tables (starting at offset
2100          * 0x10) _and_ the 64-bit address of the destination for the first
2101          * MTT entry in the MTT table.
2102          */
2103 
2104         /* Sync the mailbox for the device to read */
2105         size = (num_mtt << TAVOR_MTT_SIZE_SHIFT) + TAVOR_CMD_WRITEMTT_RSVD_SZ;
2106         tavor_mbox_sync(mbox_info->mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2107 
2108         /* Setup and post Tavor "WRITE_MTT" command */
2109         cmd.cp_inparm   = mbox_info->mbi_in->mb_mapaddr;
2110         cmd.cp_outparm  = 0;
2111         cmd.cp_inmod    = num_mtt;
2112         cmd.cp_opcode   = WRITE_MTT;
2113         cmd.cp_opmod    = 0;
2114         cmd.cp_flags    = sleepflag;
2115         status = tavor_cmd_post(state, &cmd);
2116         if (status != TAVOR_CMD_SUCCESS) {
2117                 TNF_PROBE_0(tavor_write_mtt_cmd_fail, TAVOR_TNF_ERROR, "");
2118         }
2119 
2120         TAVOR_TNF_EXIT(tavor_write_mtt_cmd_post);
2121         return (status);
2122 }
2123 
2124 
2125 /*
2126  * tavor_sync_tpt_cmd_post()
2127  *    Context: Can be called from interrupt or base context.
2128  */
2129 int
2130 tavor_sync_tpt_cmd_post(tavor_state_t *state, uint_t sleepflag)
2131 {
2132         tavor_cmd_post_t        cmd;
2133         int                     status;
2134 
2135         TAVOR_TNF_ENTER(tavor_sync_tpt_cmd_post);
2136 
2137         /* Setup and post the Tavor "SYNC_TPT" command */
2138         cmd.cp_inparm   = 0;
2139         cmd.cp_outparm  = 0;
2140         cmd.cp_inmod    = 0;
2141         cmd.cp_opcode   = SYNC_TPT;
2142         cmd.cp_opmod    = 0;
2143         cmd.cp_flags    = sleepflag;
2144         status = tavor_cmd_post(state, &cmd);
2145         if (status != TAVOR_CMD_SUCCESS) {
2146                 TNF_PROBE_0(tavor_sync_tpt_cmd_post_fail, TAVOR_TNF_ERROR, "");
2147         }
2148 
2149         TAVOR_TNF_EXIT(tavor_sync_tpt_cmd_post);
2150         return (status);
2151 }
2152 
2153 /*
2154  * tavor_map_eq_cmd_post()
2155  *    Context: Can be called from interrupt or base context.
2156  *    (Currently called only from attach() and/or detach() path contexts)
2157  */
2158 int
2159 tavor_map_eq_cmd_post(tavor_state_t *state, uint_t map, uint_t eqcindx,
2160     uint64_t eqmapmask, uint_t sleepflag)
2161 {
2162         tavor_cmd_post_t        cmd;
2163         int                     status;
2164 
2165         TAVOR_TNF_ENTER(tavor_map_eq_cmd_post);
2166 
2167         /* Setup and post Tavor "MAP_EQ" command */
2168         cmd.cp_inparm   = eqmapmask;
2169         cmd.cp_outparm  = 0;
2170         cmd.cp_inmod    = eqcindx;
2171         if (map != TAVOR_CMD_MAP_EQ_EVT_MAP) {
2172                 cmd.cp_inmod |= TAVOR_CMD_UNMAP_EQ_MASK;
2173         }
2174         cmd.cp_opcode   = MAP_EQ;
2175         cmd.cp_opmod    = 0;
2176         cmd.cp_flags    = sleepflag;
2177         status = tavor_cmd_post(state, &cmd);
2178         if (status != TAVOR_CMD_SUCCESS) {
2179                 TNF_PROBE_0(tavor_map_eq_cmd_post_fail, TAVOR_TNF_ERROR, "");
2180         }
2181 
2182         TAVOR_TNF_EXIT(tavor_map_eq_cmd_post);
2183         return (status);
2184 }
2185 
2186 
2187 /*
2188  * tavor_resize_cq_cmd_post()
2189  *    Context: Can be called from interrupt or base context.
2190  */
2191 int
2192 tavor_resize_cq_cmd_post(tavor_state_t *state, tavor_hw_cqc_t *cqc,
2193     uint_t cqcindx, uint32_t *prod_indx, uint_t sleepflag)
2194 {
2195         tavor_mbox_info_t       mbox_info;
2196         tavor_cmd_post_t        cmd;
2197         uint64_t                data;
2198         uint_t                  size;
2199         int                     status, i;
2200 
2201         TAVOR_TNF_ENTER(tavor_resize_cq_cmd_post);
2202 
2203         /* Get an "In" mailbox for the command */
2204         mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
2205         status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
2206         if (status != TAVOR_CMD_SUCCESS) {
2207                 TNF_PROBE_0(tavor_resize_cq_mbox_fail, TAVOR_TNF_ERROR, "");
2208                 TAVOR_TNF_EXIT(tavor_resize_cq_cmd_post);
2209                 return (status);
2210         }
2211 
2212         /* Copy the Tavor "RESIZE_CQ" command into mailbox */
2213         size = sizeof (tavor_hw_cqc_t);
2214         for (i = 0; i < (size >> 3); i++) {
2215                 data = ((uint64_t *)cqc)[i];
2216                 ddi_put64(mbox_info.mbi_in->mb_acchdl,
2217                     ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
2218         }
2219 
2220         /* Sync the mailbox for the device to read */
2221         tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2222 
2223         /* Setup and post Tavor "RESIZE_CQ" command */
2224         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
2225         cmd.cp_outparm  = 0;
2226         cmd.cp_inmod    = cqcindx;
2227         cmd.cp_opcode   = RESIZE_CQ;
2228         cmd.cp_opmod    = 0;
2229         cmd.cp_flags    = sleepflag;
2230         status = tavor_cmd_post(state, &cmd);
2231         if (status != TAVOR_CMD_SUCCESS) {
2232                 TNF_PROBE_0(tavor_resize_cq_cmd_post_fail, TAVOR_TNF_ERROR, "");
2233         }
2234 
2235         /*
2236          * New "producer index" is returned in the upper 32 bits of
2237          * command "outparam"
2238          */
2239         *prod_indx = (cmd.cp_outparm >> 32);
2240 
2241         /* Free the mailbox */
2242         tavor_mbox_free(state, &mbox_info);
2243 
2244         TAVOR_TNF_EXIT(tavor_resize_cq_cmd_post);
2245         return (status);
2246 }
2247 
2248 
2249 /*
2250  * tavor_cmn_qp_cmd_post()
2251  *    Context: Can be called from interrupt or base context.
2252  *
2253  *    This is the common function for posting all the various types of
2254  *    QP state transition related Tavor commands.  Since some of the
2255  *    commands differ from the others in the number (and type) of arguments
2256  *    that each require, this routine does checks based on opcode type
2257  *    (explained in more detail below).
2258  *
2259  * Note: This common function should be used only with the following
2260  *    opcodes: RTS2SQD_QP, TOERR_QP, TORST_QP, RST2INIT_QP, INIT2INIT_QP,
2261  *    INIT2RTR_QP, RTR2RTS_QP, RTS2RTS_QP, SQD2RTS_QP, and SQERR2RTS_QP.
2262  */
2263 int
2264 tavor_cmn_qp_cmd_post(tavor_state_t *state, uint_t opcode,
2265     tavor_hw_qpc_t *qp, uint_t qpindx, uint32_t opmask,
2266     uint_t sleepflag)
2267 {
2268         tavor_mbox_info_t       mbox_info;
2269         tavor_cmd_post_t        cmd;
2270         uint64_t                data, in_mapaddr, out_mapaddr;
2271         uint_t                  size, flags, opmod;
2272         int                     status, i;
2273 
2274         TAVOR_TNF_ENTER(tavor_cmn_qp_cmd_post);
2275 
2276         /*
2277          * Use the specified opcode type to set the appropriate parameters.
2278          * Specifically, we need to set in_mapaddr, out_mapaddr, flags, and
2279          * opmod (as necessary).  Setting these parameters may also require
2280          * us to allocate an "In" or "Out" mailbox depending on the command
2281          * type.
2282          */
2283         if (opcode == RTS2SQD_QP) {
2284                 /*
2285                  * Note: For RTS-to-SendQueueDrain state transitions we
2286                  * always want to request the event generation from the
2287                  * hardware.  Though we may not notify the consumer of the
2288                  * drained event, the decision to forward (or not) is made
2289                  * later in the SQD event handler.
2290                  */
2291                 flags = TAVOR_CMD_REQ_SQD_EVENT;
2292 
2293                 /*
2294                  * The RTS2SQD_QP command uses no "In" or "Out" mailboxes (and
2295                  * has no special opcode modifiers).
2296                  */
2297                 in_mapaddr  = 0;
2298                 out_mapaddr = 0;
2299                 opmod = 0;
2300 
2301         } else if (opcode == TOERR_QP) {
2302                 /*
2303                  * The TOERR_QP command uses no "In" or "Out" mailboxes, has no
2304                  * special opcode modifiers, and takes no special flags.
2305                  */
2306                 in_mapaddr  = 0;
2307                 out_mapaddr = 0;
2308                 opmod = 0;
2309                 flags = 0;
2310 
2311         } else if (opcode == TORST_QP) {
2312                 /*
2313                  * The TORST_QP command could take an "Out" mailbox, but we do
2314                  * not require it here.  It also does not takes any special
2315                  * flags.  It does however, take a TAVOR_CMD_DIRECT_TO_RESET
2316                  * opcode modifier, which indicates that the transition to
2317                  * reset should happen without first moving the QP through the
2318                  * Error state (and, hence, without generating any unnecessary
2319                  * "flushed-in-error" completions).
2320                  */
2321                 in_mapaddr  = 0;
2322                 out_mapaddr = 0;
2323                 opmod = TAVOR_CMD_DIRECT_TO_RESET | TAVOR_CMD_NO_OUTMBOX;
2324                 flags = 0;
2325 
2326         } else {
2327                 /*
2328                  * All the other QP state transition commands (RST2INIT_QP,
2329                  * INIT2INIT_QP, INIT2RTR_QP, RTR2RTS_QP, RTS2RTS_QP,
2330                  * SQD2RTS_QP, and SQERR2RTS_QP) require an "In" mailbox.
2331                  * None of these require any special flags or opcode modifiers.
2332                  */
2333                 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
2334                 status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
2335                 if (status != TAVOR_CMD_SUCCESS) {
2336                         TNF_PROBE_0(tavor_cmn_qp_mbox_fail,
2337                             TAVOR_TNF_ERROR, "");
2338                         TAVOR_TNF_EXIT(tavor_cmn_qp_cmd_post);
2339                         return (status);
2340                 }
2341                 in_mapaddr  = mbox_info.mbi_in->mb_mapaddr;
2342                 out_mapaddr = 0;
2343                 flags = 0;
2344                 opmod = 0;
2345 
2346                 /* Copy the Tavor command into the "In" mailbox */
2347                 size = sizeof (tavor_hw_qpc_t);
2348                 for (i = 0; i < (size >> 3); i++) {
2349                         data = ((uint64_t *)qp)[i];
2350                         ddi_put64(mbox_info.mbi_in->mb_acchdl,
2351                             ((uint64_t *)mbox_info.mbi_in->mb_addr + i + 1),
2352                             data);
2353                 }
2354                 ddi_put32(mbox_info.mbi_in->mb_acchdl,
2355                     ((uint32_t *)mbox_info.mbi_in->mb_addr), opmask);
2356 
2357                 /*
2358                  * Sync the mailbox for the device to read.  We have to add
2359                  * eight bytes here to account for "opt_param_mask" and
2360                  * proper alignment.
2361                  */
2362                 tavor_mbox_sync(mbox_info.mbi_in, 0, size + 8,
2363                     DDI_DMA_SYNC_FORDEV);
2364         }
2365 
2366         /* Setup and post Tavor QP state transition command */
2367         cmd.cp_inparm   = in_mapaddr;
2368         cmd.cp_outparm  = out_mapaddr;
2369         cmd.cp_inmod    = qpindx | flags;
2370         cmd.cp_opcode   = opcode;
2371         cmd.cp_opmod    = opmod;
2372         cmd.cp_flags    = sleepflag;
2373         status = tavor_cmd_post(state, &cmd);
2374         if (status != TAVOR_CMD_SUCCESS) {
2375                 TNF_PROBE_0(tavor_cmn_qp_cmd_post_fail, TAVOR_TNF_ERROR, "");
2376         }
2377 
2378         /*
2379          * If we allocated a mailbox (either an "In" or an "Out") above,
2380          * then free it now before returning.
2381          */
2382         if ((opcode != RTS2SQD_QP) && (opcode != TOERR_QP) &&
2383             (opcode != TORST_QP)) {
2384                 /* Free the mailbox */
2385                 tavor_mbox_free(state, &mbox_info);
2386         }
2387 
2388         TAVOR_TNF_EXIT(tavor_cmn_qp_cmd_post);
2389         return (status);
2390 }
2391 
2392 
2393 /*
2394  * tavor_cmn_query_cmd_post()
2395  *    Context: Can be called from interrupt or base context.
2396  *
2397  *    This is the common function for posting all the various types of
2398  *    Tavor query commands.  All Tavor query commands require an "Out"
2399  *    mailbox to be allocated for the resulting queried data.
2400  *
2401  * Note: This common function should be used only with the following
2402  *    opcodes: QUERY_DEV_LIM, QUERY_FW, QUERY_DDR, QUERY_ADAPTER,
2403  *     QUERY_HCA, QUERY_MPT, QUERY_EQ, QUERY_CQ, and QUERY_QP.
2404  */
2405 int
2406 tavor_cmn_query_cmd_post(tavor_state_t *state, uint_t opcode,
2407     uint_t queryindx, void *query, uint_t size, uint_t sleepflag)
2408 {
2409         tavor_mbox_info_t       mbox_info;
2410         tavor_cmd_post_t        cmd;
2411         uint64_t                data;
2412         uint_t                  offset;
2413         int                     status, i;
2414 
2415         TAVOR_TNF_ENTER(tavor_cmn_query_cmd_post);
2416 
2417         /* Get an "Out" mailbox for the command */
2418         mbox_info.mbi_alloc_flags = TAVOR_ALLOC_OUTMBOX;
2419         status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
2420         if (status != TAVOR_CMD_SUCCESS) {
2421                 TNF_PROBE_0(tavor_cmn_query_mbox_fail, TAVOR_TNF_ERROR, "");
2422                 TAVOR_TNF_EXIT(tavor_cmn_query_cmd_post);
2423                 return (status);
2424         }
2425 
2426         /* Setup and post the Tavor query command */
2427         cmd.cp_inparm   = 0;
2428         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
2429         cmd.cp_inmod    = queryindx;
2430         cmd.cp_opcode   = opcode;
2431         cmd.cp_opmod    = 0;
2432         cmd.cp_flags    = sleepflag;
2433         status = tavor_cmd_post(state, &cmd);
2434         if (status != TAVOR_CMD_SUCCESS) {
2435                 TNF_PROBE_0(tavor_cmn_query_cmd_post_fail, TAVOR_TNF_ERROR, "");
2436                 goto cmn_query_fail;
2437         }
2438 
2439         /* Sync the mailbox to read the results */
2440         tavor_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
2441 
2442         /*
2443          * QUERY_QP is handled somewhat differently than the other query
2444          * commands.  For QUERY_QP, the actual queried data is offset into
2445          * the mailbox (by one 64-bit word).
2446          */
2447         offset = (opcode == QUERY_QP) ? 1 : 0;
2448 
2449         /* Copy query command results into "query" */
2450         for (i = 0; i < (size >> 3); i++) {
2451                 data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2452                     ((uint64_t *)mbox_info.mbi_out->mb_addr + i + offset));
2453                 ((uint64_t *)query)[i] = data;
2454         }
2455 
2456 cmn_query_fail:
2457         /* Free the mailbox */
2458         tavor_mbox_free(state, &mbox_info);
2459 
2460         TAVOR_TNF_EXIT(tavor_cmn_query_cmd_post);
2461         return (status);
2462 }
2463 
2464 
2465 /*
2466  * tavor_cmn_ownership_cmd_post()
2467  *    Context: Can be called from interrupt or base context.
2468  *
2469  *    This is the common function for posting all the various types of
2470  *    Tavor HW/SW resource ownership commands.  Since some of the commands
2471  *    differ from the others in the direction of ownership change (i.e.
2472  *    from HW ownership to SW, or vice versa), they differ in the type of
2473  *    mailbox and specific handling that each requires.  This routine does
2474  *    certain checks based on opcode type to determine the direction of
2475  *    the transition and to correctly handle the request.
2476  *
2477  * Note: This common function should be used only with the following
2478  *    opcodes: HW2SW_MPT, HW2SW_EQ, HW2SW_CQ, SW2HW_MPT, SW2HW_EQ, and
2479  *    SW2HW_CQ
2480  */
2481 int
2482 tavor_cmn_ownership_cmd_post(tavor_state_t *state, uint_t opcode,
2483     void *hwrsrc, uint_t size, uint_t hwrsrcindx, uint_t sleepflag)
2484 {
2485         tavor_mbox_info_t       mbox_info;
2486         tavor_cmd_post_t        cmd;
2487         uint64_t                data, in_mapaddr, out_mapaddr;
2488         uint_t                  direction, opmod;
2489         int                     status, i;
2490 
2491         TAVOR_TNF_ENTER(tavor_cmn_ownership_cmd_post);
2492 
2493         /*
2494          * Determine the direction of the ownership transfer based on the
2495          * provided opcode
2496          */
2497         if ((opcode == HW2SW_MPT) || (opcode == HW2SW_EQ) ||
2498             (opcode == HW2SW_CQ) || (opcode == HW2SW_SRQ)) {
2499                 direction = TAVOR_CMD_RSRC_HW2SW;
2500 
2501         } else if ((opcode == SW2HW_MPT) || (opcode == SW2HW_EQ) ||
2502             (opcode == SW2HW_CQ) || (opcode == SW2HW_SRQ)) {
2503                 direction = TAVOR_CMD_RSRC_SW2HW;
2504 
2505         } else {
2506                 TNF_PROBE_0(tavor_cmn_ownership_dir_fail,
2507                     TAVOR_TNF_ERROR, "");
2508                 TAVOR_TNF_EXIT(tavor_cmn_ownership_cmd_post);
2509                 return (TAVOR_CMD_INVALID_STATUS);
2510         }
2511 
2512         /*
2513          * If hwrsrc is NULL then we do not allocate a mailbox.  This is used
2514          * in the case of memory deregister where the out mailbox is not
2515          * needed.  In the case of re-register, we do use the hwrsrc.
2516          *
2517          * Otherwise, If ownership transfer is going from hardware to software,
2518          * then allocate an "Out" mailbox.  This will be filled in later as a
2519          * result of the Tavor command.
2520          *
2521          * And if the ownership transfer is going from software to hardware,
2522          * then we need an "In" mailbox, and we need to fill it in and sync it
2523          * (if necessary).  Then the mailbox can be passed to the Tavor
2524          * firmware.
2525          *
2526          * For the HW2SW (dereg) case, we only use an out mbox if hwrsrc is !=
2527          * NULL.  This implies a re-reg, and the out mbox must be used.  If
2528          * hwrsrc is == NULL, then we can save some time and resources by not
2529          * using an out mbox at all.  We must set opmod to TAVOR_CMD_DO_OUTMBOX
2530          * and TAVOR_CMD_NO_OUTMBOX appropriately in this case.
2531          *
2532          * For the SW2HW (reg) case, no out mbox is possible.  We set opmod to
2533          * 0 anyway, but this field is not used in this case.
2534          */
2535         if (direction == TAVOR_CMD_RSRC_HW2SW) {
2536                 if (hwrsrc != NULL) {
2537                         mbox_info.mbi_alloc_flags = TAVOR_ALLOC_OUTMBOX;
2538                         status = tavor_mbox_alloc(state, &mbox_info,
2539                             sleepflag);
2540                         if (status != TAVOR_CMD_SUCCESS) {
2541                                 TNF_PROBE_0(tavor_cmn_ownership_mbox_fail,
2542                                     TAVOR_TNF_ERROR, "");
2543                                 TAVOR_TNF_EXIT(tavor_cmn_ownership_cmd_post);
2544                                 return (status);
2545                         }
2546                         in_mapaddr  = 0;
2547                         out_mapaddr = mbox_info.mbi_out->mb_mapaddr;
2548                         opmod = TAVOR_CMD_DO_OUTMBOX;
2549                 } else {
2550                         in_mapaddr = 0;
2551                         out_mapaddr = 0;
2552                         opmod = TAVOR_CMD_NO_OUTMBOX;
2553                 }
2554         } else {  /* TAVOR_CMD_RSRC_SW2HW */
2555                 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
2556                 status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
2557                 if (status != TAVOR_CMD_SUCCESS) {
2558                         TNF_PROBE_0(tavor_cmn_ownership_mbox_fail,
2559                             TAVOR_TNF_ERROR, "");
2560                         TAVOR_TNF_EXIT(tavor_sw2hw_mpt_cmd_post);
2561                         return (status);
2562                 }
2563 
2564                 /* Copy the SW2HW ownership command into mailbox */
2565                 for (i = 0; i < (size >> 3); i++) {
2566                         data = ((uint64_t *)hwrsrc)[i];
2567                         ddi_put64(mbox_info.mbi_in->mb_acchdl,
2568                             ((uint64_t *)mbox_info.mbi_in->mb_addr + i),
2569                             data);
2570                 }
2571 
2572                 /* Sync the mailbox for the device to read */
2573                 tavor_mbox_sync(mbox_info.mbi_in, 0, size,
2574                     DDI_DMA_SYNC_FORDEV);
2575 
2576                 in_mapaddr  = mbox_info.mbi_in->mb_mapaddr;
2577                 out_mapaddr = 0;
2578                 opmod = 0;
2579         }
2580 
2581 
2582         /* Setup and post the Tavor ownership command */
2583         cmd.cp_inparm   = in_mapaddr;
2584         cmd.cp_outparm  = out_mapaddr;
2585         cmd.cp_inmod    = hwrsrcindx;
2586         cmd.cp_opcode   = opcode;
2587         cmd.cp_opmod    = opmod;
2588         cmd.cp_flags    = sleepflag;
2589         status = tavor_cmd_post(state, &cmd);
2590         if (status != TAVOR_CMD_SUCCESS) {
2591                 TNF_PROBE_0(tavor_cmn_ownership_cmd_post_fail,
2592                     TAVOR_TNF_ERROR, "");
2593                 goto cmn_ownership_fail;
2594         }
2595 
2596         /*
2597          * As mentioned above, for HW2SW ownership transfers we need to
2598          * sync (if necessary) and copy out the resulting data from the
2599          * "Out" mailbox" (assuming the above command was successful).
2600          */
2601         if (direction == TAVOR_CMD_RSRC_HW2SW && hwrsrc != NULL) {
2602                 /* Sync the mailbox to read the results */
2603                 tavor_mbox_sync(mbox_info.mbi_out, 0, size,
2604                     DDI_DMA_SYNC_FORCPU);
2605 
2606                 /* Copy HW2SW ownership command results into "hwrsrc" */
2607                 for (i = 0; i < (size >> 3); i++) {
2608                         data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2609                             ((uint64_t *)mbox_info.mbi_out->mb_addr + i));
2610                         ((uint64_t *)hwrsrc)[i] = data;
2611                 }
2612         }
2613 
2614 cmn_ownership_fail:
2615         if (hwrsrc != NULL) {
2616                 /* Free the mailbox */
2617                 tavor_mbox_free(state, &mbox_info);
2618         }
2619 
2620         TAVOR_TNF_EXIT(tavor_cmn_ownership_cmd_post);
2621         return (status);
2622 }
2623 
2624 
2625 /*
2626  * tavor_conf_special_qp_cmd_post()
2627  *    Context: Can be called from interrupt or base context.
2628  */
2629 int
2630 tavor_conf_special_qp_cmd_post(tavor_state_t *state, uint_t qpindx,
2631     uint_t qptype, uint_t sleepflag)
2632 {
2633         tavor_cmd_post_t        cmd;
2634         int                     status;
2635 
2636         TAVOR_TNF_ENTER(tavor_conf_special_qp_cmd_post);
2637 
2638         /* Setup and post Tavor "CONF_SPECIAL_QP" command */
2639         cmd.cp_inparm   = 0;
2640         cmd.cp_outparm  = 0;
2641         cmd.cp_inmod    = qpindx;
2642         cmd.cp_opcode   = CONF_SPECIAL_QP;
2643         cmd.cp_opmod    = qptype;
2644         cmd.cp_flags    = sleepflag;
2645         status = tavor_cmd_post(state, &cmd);
2646         if (status != TAVOR_CMD_SUCCESS) {
2647                 TNF_PROBE_0(tavor_conf_special_qp_cmd_post_fail,
2648                     TAVOR_TNF_ERROR, "");
2649         }
2650 
2651         TAVOR_TNF_EXIT(tavor_conf_special_qp_cmd_post);
2652         return (status);
2653 }
2654 
2655 
2656 /*
2657  * tavor_mgid_hash_cmd_post()
2658  *    Context: Can be called from interrupt or base context.
2659  */
2660 int
2661 tavor_mgid_hash_cmd_post(tavor_state_t *state, uint64_t mgid_h,
2662     uint64_t mgid_l, uint64_t *mgid_hash, uint_t sleepflag)
2663 {
2664         tavor_mbox_info_t       mbox_info;
2665         tavor_cmd_post_t        cmd;
2666         int                     status;
2667 
2668         TAVOR_TNF_ENTER(tavor_mgid_hash_cmd_post);
2669 
2670         /* Get an "In" mailbox for the command */
2671         mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
2672         status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
2673         if (status != TAVOR_CMD_SUCCESS) {
2674                 TNF_PROBE_0(tavor_mgid_hash_mbox_fail, TAVOR_TNF_ERROR, "");
2675                 TAVOR_TNF_EXIT(tavor_mgid_hash_cmd_post);
2676                 return (status);
2677         }
2678 
2679         /* Copy the Tavor "MGID_HASH" command into mailbox */
2680         ddi_put64(mbox_info.mbi_in->mb_acchdl,
2681             ((uint64_t *)mbox_info.mbi_in->mb_addr + 0), mgid_h);
2682         ddi_put64(mbox_info.mbi_in->mb_acchdl,
2683             ((uint64_t *)mbox_info.mbi_in->mb_addr + 1), mgid_l);
2684 
2685         /* Sync the mailbox for the device to read */
2686         tavor_mbox_sync(mbox_info.mbi_in, 0, TAVOR_CMD_MGIDHASH_SZ,
2687             DDI_DMA_SYNC_FORDEV);
2688 
2689         /* Setup and post the Tavor "MGID_HASH" command */
2690         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
2691         cmd.cp_outparm  = 0;
2692         cmd.cp_inmod    = 0;
2693         cmd.cp_opcode   = MGID_HASH;
2694         cmd.cp_opmod    = 0;
2695         cmd.cp_flags    = sleepflag;
2696         status = tavor_cmd_post(state, &cmd);
2697         if (status != TAVOR_CMD_SUCCESS) {
2698                 TNF_PROBE_0(tavor_mgid_hash_cmd_post_fail, TAVOR_TNF_ERROR, "");
2699         }
2700 
2701         /* MGID hash value is returned in command "outparam" */
2702         *mgid_hash = cmd.cp_outparm;
2703 
2704         /* Free the mailbox */
2705         tavor_mbox_free(state, &mbox_info);
2706 
2707         TAVOR_TNF_EXIT(tavor_mgid_hash_cmd_post);
2708         return (status);
2709 }
2710 
2711 
2712 /*
2713  * tavor_read_mgm_cmd_post()
2714  *    Context: Can be called from interrupt or base context.
2715  *
2716  * Note: It is assumed that the "mcg" parameter is actually a pointer to a
2717  *    "tavor_hw_mcg_t" struct and some number of "tavor_hw_mcg_qp_list_t"
2718  *    structs.  Combined size should be equal to result of TAVOR_MCGMEM_SZ()
2719  *    macro.
2720  */
2721 int
2722 tavor_read_mgm_cmd_post(tavor_state_t *state, tavor_hw_mcg_t *mcg,
2723     uint_t mcgindx, uint_t sleepflag)
2724 {
2725         tavor_mbox_info_t       mbox_info;
2726         tavor_cmd_post_t        cmd;
2727         uint64_t                data;
2728         uint_t                  size, hdrsz, qplistsz;
2729         int                     status, i;
2730 
2731         TAVOR_TNF_ENTER(tavor_read_mgm_cmd_post);
2732 
2733         /* Get an "Out" mailbox for the results */
2734         mbox_info.mbi_alloc_flags = TAVOR_ALLOC_OUTMBOX;
2735         status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
2736         if (status != TAVOR_CMD_SUCCESS) {
2737                 TNF_PROBE_0(tavor_read_mgm_mbox_fail, TAVOR_TNF_ERROR, "");
2738                 TAVOR_TNF_EXIT(tavor_read_mgm_cmd_post);
2739                 return (status);
2740         }
2741 
2742         /* Setup and post Tavor "READ_MGM" command */
2743         cmd.cp_inparm   = 0;
2744         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
2745         cmd.cp_inmod    = mcgindx;
2746         cmd.cp_opcode   = READ_MGM;
2747         cmd.cp_opmod    = 0;
2748         cmd.cp_flags    = sleepflag;
2749         status = tavor_cmd_post(state, &cmd);
2750         if (status != TAVOR_CMD_SUCCESS) {
2751                 TNF_PROBE_0(tavor_read_mgm_cmd_post_fail, TAVOR_TNF_ERROR, "");
2752                 goto read_mgm_fail;
2753         }
2754 
2755         /* Sync the mailbox to read the results */
2756         size = TAVOR_MCGMEM_SZ(state);
2757         tavor_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
2758 
2759         /* Copy the READ_MGM command results into "mcg" */
2760         hdrsz = sizeof (tavor_hw_mcg_t);
2761         for (i = 0; i < (hdrsz >> 3); i++) {
2762                 data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2763                     ((uint64_t *)mbox_info.mbi_out->mb_addr + i));
2764                 ((uint64_t *)mcg)[i] = data;
2765         }
2766         qplistsz = size - hdrsz;
2767         for (i = 0; i < (qplistsz >> 2); i++) {
2768                 data = ddi_get32(mbox_info.mbi_out->mb_acchdl,
2769                     ((uint32_t *)mbox_info.mbi_out->mb_addr + i + 8));
2770                 ((uint32_t *)mcg)[i + 8] = data;
2771         }
2772 
2773 read_mgm_fail:
2774         /* Free the mailbox */
2775         tavor_mbox_free(state, &mbox_info);
2776 
2777         TAVOR_TNF_EXIT(tavor_read_mgm_cmd_post);
2778         return (status);
2779 }
2780 
2781 
2782 /*
2783  * tavor_write_mgm_cmd_post()
2784  *    Context: Can be called from interrupt or base context.
2785  *
2786  * Note: It is assumed that the "mcg" parameter is actually a pointer to a
2787  *    "tavor_hw_mcg_t" struct and some number of "tavor_hw_mcg_qp_list_t"
2788  *    structs.  Combined size should be equal to result of TAVOR_MCGMEM_SZ()
2789  *    macro.
2790  */
2791 int
2792 tavor_write_mgm_cmd_post(tavor_state_t *state, tavor_hw_mcg_t *mcg,
2793     uint_t mcgindx, uint_t sleepflag)
2794 {
2795         tavor_mbox_info_t       mbox_info;
2796         tavor_cmd_post_t        cmd;
2797         uint64_t                data;
2798         uint_t                  size, hdrsz, qplistsz;
2799         int                     status, i;
2800 
2801         TAVOR_TNF_ENTER(tavor_write_mgm_cmd_post);
2802 
2803         /* Get an "In" mailbox for the command */
2804         mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
2805         status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
2806         if (status != TAVOR_CMD_SUCCESS) {
2807                 TNF_PROBE_0(tavor_write_mcg_mbox_fail, TAVOR_TNF_ERROR, "");
2808                 TAVOR_TNF_EXIT(tavor_write_mgm_cmd_post);
2809                 return (status);
2810         }
2811 
2812         /* Copy the Tavor "WRITE_MGM" command into mailbox */
2813         size  = TAVOR_MCGMEM_SZ(state);
2814         hdrsz = sizeof (tavor_hw_mcg_t);
2815         for (i = 0; i < (hdrsz >> 3); i++) {
2816                 data = ((uint64_t *)mcg)[i];
2817                 ddi_put64(mbox_info.mbi_in->mb_acchdl,
2818                     ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
2819         }
2820         qplistsz = size - hdrsz;
2821         for (i = 0; i < (qplistsz >> 2); i++) {
2822                 data = ((uint32_t *)mcg)[i + 8];
2823                 ddi_put32(mbox_info.mbi_in->mb_acchdl,
2824                     ((uint32_t *)mbox_info.mbi_in->mb_addr + i + 8), data);
2825         }
2826 
2827         /* Sync the mailbox for the device to read */
2828         tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2829 
2830         /* Setup and post Tavor "WRITE_MGM" command */
2831         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
2832         cmd.cp_outparm  = 0;
2833         cmd.cp_inmod    = mcgindx;
2834         cmd.cp_opcode   = WRITE_MGM;
2835         cmd.cp_opmod    = 0;
2836         cmd.cp_flags    = sleepflag;
2837         status = tavor_cmd_post(state, &cmd);
2838         if (status != TAVOR_CMD_SUCCESS) {
2839                 TNF_PROBE_0(tavor_write_mgm_cmd_post_fail, TAVOR_TNF_ERROR, "");
2840         }
2841 
2842         /* Free the mailbox */
2843         tavor_mbox_free(state, &mbox_info);
2844 
2845         TAVOR_TNF_EXIT(tavor_write_mgm_cmd_post);
2846         return (status);
2847 
2848 }
2849 
2850 
2851 /*
2852  * tavor_modify_mpt_cmd_post()
2853  *    Context: Can be called from interrupt or base context.
2854  */
2855 int
2856 tavor_modify_mpt_cmd_post(tavor_state_t *state, tavor_hw_mpt_t *mpt,
2857     uint_t mptindx, uint_t flags, uint_t sleepflag)
2858 {
2859         tavor_mbox_info_t       mbox_info;
2860         tavor_cmd_post_t        cmd;
2861         uint64_t                data;
2862         uint_t                  size;
2863         int                     status, i;
2864 
2865         TAVOR_TNF_ENTER(tavor_modify_mpt_cmd_post);
2866 
2867         /* Get an "In" mailbox for the command */
2868         mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
2869         status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
2870         if (status != TAVOR_CMD_SUCCESS) {
2871                 TNF_PROBE_0(tavor_modify_mpt_mbox_fail, TAVOR_TNF_ERROR, "");
2872                 TAVOR_TNF_EXIT(tavor_modify_mpt_cmd_post);
2873                 return (status);
2874         }
2875 
2876         /* Copy the Tavor "MODIFY_MPT" command into mailbox */
2877         size = sizeof (tavor_hw_mpt_t);
2878         for (i = 0; i < (size >> 3); i++) {
2879                 data = ((uint64_t *)mpt)[i];
2880                 ddi_put64(mbox_info.mbi_in->mb_acchdl,
2881                     ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
2882         }
2883 
2884         /* Sync the mailbox for the device to read */
2885         tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2886 
2887         /* Setup and post Tavor "MODIFY_MPT" command */
2888         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
2889         cmd.cp_outparm  = 0;
2890         cmd.cp_inmod    = mptindx;
2891         cmd.cp_opcode   = MODIFY_MPT;
2892         cmd.cp_opmod    = flags;
2893         cmd.cp_flags    = sleepflag;
2894         status = tavor_cmd_post(state, &cmd);
2895         if (status != TAVOR_CMD_SUCCESS) {
2896                 TNF_PROBE_0(tavor_modify_mpt_cmd_post_fail,
2897                     TAVOR_TNF_ERROR, "");
2898         }
2899 
2900         /* Free the mailbox */
2901         tavor_mbox_free(state, &mbox_info);
2902 
2903         TAVOR_TNF_EXIT(tavor_modify_mpt_cmd_post);
2904         return (status);
2905 }
2906 
2907 /*
2908  * tavor_getpefcntr_cmd_post()
2909  *    Context: Can be called from interrupt or base context.
2910  *
2911  * If reset is zero, read the performance counters of the specified port and
2912  * copy them into perfinfo.
2913  * If reset is non-zero reset the performance counters of the specified port.
2914  */
2915 int
2916 tavor_getperfcntr_cmd_post(tavor_state_t *state, uint_t port,
2917     uint_t sleepflag, tavor_hw_sm_perfcntr_t *perfinfo, int reset)
2918 {
2919         tavor_mbox_info_t       mbox_info;
2920         tavor_cmd_post_t        cmd;
2921         uint64_t                data;
2922         uint32_t                *mbox;
2923         uint_t                  size;
2924         int                     status, i;
2925 
2926         bzero((void *)&cmd, sizeof (tavor_cmd_post_t));
2927 
2928         /* Get "In" and "Out" mailboxes for the command */
2929         mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
2930         status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
2931         if (status != TAVOR_CMD_SUCCESS) {
2932                 return (status);
2933         }
2934 
2935         /* Build request MAD in the "In" mailbox */
2936         size = TAVOR_CMD_MAD_IFC_SIZE;
2937         mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
2938 
2939         if (reset) {
2940                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0],
2941                     TAVOR_CMD_PERF_SET);
2942         } else {
2943                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0],
2944                     TAVOR_CMD_PERF_GET);
2945         }
2946         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1);
2947         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2);
2948         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3);
2949         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_PERFCNTRS);
2950         ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], TAVOR_CMD_PERFATTR);
2951 
2952         if (reset) {
2953                 /* reset counters for XmitData, RcvData, XmitPkts, RcvPkts */
2954                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16],
2955                     ((port << 16) | 0xf000));
2956 
2957                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[22], 0);
2958                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[23], 0);
2959                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[24], 0);
2960                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[25], 0);
2961         } else
2962                 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16], (port << 16));
2963 
2964         /* Sync the mailbox for the device to read */
2965         tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
2966 
2967         /* Setup the Hermon "MAD_IFC" command */
2968         cmd.cp_inparm   = mbox_info.mbi_in->mb_mapaddr;
2969         cmd.cp_outparm  = mbox_info.mbi_out->mb_mapaddr;
2970         cmd.cp_inmod    = port;
2971         cmd.cp_opcode   = MAD_IFC;
2972         /* No MKey and BKey checking */
2973         cmd.cp_opmod    = TAVOR_CMD_MKEY_DONTCHECK | TAVOR_CMD_BKEY_DONTCHECK;
2974         cmd.cp_flags    = TAVOR_CMD_NOSLEEP_SPIN; /* NO SLEEP */
2975         status = tavor_cmd_post(state, &cmd);
2976         if (status != TAVOR_CMD_SUCCESS) {
2977                 goto getperfinfo_fail;
2978         }
2979 
2980         /* Sync the mailbox to read the results */
2981         size = TAVOR_CMD_MAD_IFC_SIZE;
2982         tavor_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
2983 
2984         if (reset == 0) {
2985                 size = sizeof (tavor_hw_sm_perfcntr_t); /* for the copy */
2986                 /*
2987                  * Copy Perfcounters into "perfinfo".  We can discard the MAD
2988                  * header and the 8 Quadword reserved area of the PERM mgmt
2989                  * class MAD
2990                  */
2991 
2992                 for (i = 0; i < size >> 3; i++) {
2993                         data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
2994                             ((uint64_t *)mbox_info.mbi_out->mb_addr + i + 8));
2995                         ((uint64_t *)(void *)perfinfo)[i] = data;
2996                 }
2997         }
2998 
2999 getperfinfo_fail:
3000         /* Free the mailbox */
3001         tavor_mbox_free(state, &mbox_info);
3002         return (status);
3003 }