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