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_getpefcntr_cmd_post() 2056 * Context: Can be called from interrupt or base context. 2057 * 2058 * If reset is zero, read the performance counters of the specified port and 2059 * copy them into perfinfo. 2060 * If reset is non-zero reset the performance counters of the specified port. 2061 */ 2062 int 2063 hermon_getperfcntr_cmd_post(hermon_state_t *state, uint_t port, 2064 uint_t sleepflag, hermon_hw_sm_perfcntr_t *perfinfo, int reset) 2065 { 2066 hermon_mbox_info_t mbox_info; 2067 hermon_cmd_post_t cmd; 2068 uint64_t data; 2069 uint32_t *mbox; 2070 uint_t size; 2071 int status, i; 2072 2073 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 2074 2075 /* Get "In" and "Out" mailboxes for the command */ 2076 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX; 2077 status = hermon_mbox_alloc(state, &mbox_info, sleepflag); 2078 if (status != HERMON_CMD_SUCCESS) { 2079 return (status); 2080 } 2081 2082 /* Build the GetPortInfo request MAD in the "In" mailbox */ 2083 size = HERMON_CMD_MAD_IFC_SIZE; 2084 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr; 2085 2086 if (reset) { 2087 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], 2088 HERMON_CMD_PERF_SET); 2089 } else { 2090 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], 2091 HERMON_CMD_PERF_GET); 2092 } 2093 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1); 2094 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2); 2095 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3); 2096 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_PERFCNTRS); 2097 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], HERMON_CMD_PERFATTR); 2098 2099 if (reset) { 2100 /* reset counters for XmitData, RcvData, XmitPkts, RcvPkts */ 2101 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16], 2102 ((port << 16) | 0xf000)); 2103 2104 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[22], 0); 2105 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[23], 0); 2106 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[24], 0); 2107 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[25], 0); 2108 } else 2109 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16], (port << 16)); 2110 2111 /* Sync the mailbox for the device to read */ 2112 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 2113 2114 /* Setup the Hermon "MAD_IFC" command */ 2115 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 2116 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr; 2117 cmd.cp_inmod = port; 2118 cmd.cp_opcode = MAD_IFC; 2119 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK; /* No MKey checking */ 2120 cmd.cp_opmod = 0x03; /* temp, no bkey either */ 2121 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN; /* NO SLEEP */ 2122 status = hermon_cmd_post(state, &cmd); 2123 if (status != HERMON_CMD_SUCCESS) { 2124 goto getperfinfo_fail; 2125 } 2126 2127 /* Sync the mailbox to read the results */ 2128 size = HERMON_CMD_MAD_IFC_SIZE; 2129 hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU); 2130 2131 if (reset == 0) { 2132 size = sizeof (hermon_hw_sm_perfcntr_t); /* for the copy */ 2133 /* 2134 * Copy Perfcounters into "perfinfo". We can discard the MAD 2135 * header and the 8 Quadword reserved area of the PERM mgmt 2136 * class MAD 2137 */ 2138 2139 for (i = 0; i < size >> 3; i++) { 2140 data = ddi_get64(mbox_info.mbi_out->mb_acchdl, 2141 ((uint64_t *)mbox_info.mbi_out->mb_addr + i + 8)); 2142 ((uint64_t *)(void *)perfinfo)[i] = data; 2143 } 2144 } 2145 2146 getperfinfo_fail: 2147 /* Free the mailbox */ 2148 hermon_mbox_free(state, &mbox_info); 2149 return (status); 2150 } 2151 2152 2153 2154 /* 2155 * hermon_getnodeinfo_cmd_post() 2156 * Context: Can be called from interrupt or base context. 2157 * (Currently called only from attach() and detach() path contexts) 2158 */ 2159 int 2160 hermon_getnodeinfo_cmd_post(hermon_state_t *state, uint_t sleepflag, 2161 sm_nodeinfo_t *nodeinfo) 2162 { 2163 hermon_mbox_info_t mbox_info; 2164 hermon_cmd_post_t cmd; 2165 uint32_t *mbox; 2166 uint_t size; 2167 int status, i; 2168 2169 /* Make sure we are called with the correct flag */ 2170 ASSERT(sleepflag == HERMON_CMD_NOSLEEP_SPIN); 2171 2172 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 2173 2174 /* Get "In" and "Out" mailboxes for the command */ 2175 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX; 2176 status = hermon_mbox_alloc(state, &mbox_info, sleepflag); 2177 if (status != HERMON_CMD_SUCCESS) { 2178 return (status); 2179 } 2180 2181 /* Build the GetNodeInfo request MAD into the "In" mailbox */ 2182 size = HERMON_CMD_MAD_IFC_SIZE; 2183 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr; 2184 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0); 2185 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1); 2186 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2); 2187 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3); 2188 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_NODEINFO); 2189 for (i = 5; i < (size >> 2); i++) { 2190 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0); 2191 } 2192 2193 /* Sync the mailbox for the device to read */ 2194 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 2195 2196 /* Setup the Hermon "MAD_IFC" command */ 2197 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 2198 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr; 2199 cmd.cp_inmod = 1; /* Get NodeInfo from port #1 */ 2200 cmd.cp_opcode = MAD_IFC; 2201 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK; /* No MKey checking */ 2202 cmd.cp_flags = sleepflag; 2203 status = hermon_cmd_post(state, &cmd); 2204 if (status != HERMON_CMD_SUCCESS) { 2205 goto getnodeinfo_fail; 2206 } 2207 2208 /* Sync the mailbox to read the results */ 2209 size = sizeof (sm_nodeinfo_t); 2210 hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET, 2211 size, DDI_DMA_SYNC_FORCPU); 2212 2213 /* 2214 * Copy GetNodeInfo response MAD into "nodeinfo". Do any endian 2215 * swapping that may be necessary to flip any of the "nodeinfo" 2216 * fields 2217 */ 2218 bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr + 2219 HERMON_CMD_MADDATA_OFFSET), nodeinfo, size); 2220 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*nodeinfo)) 2221 HERMON_GETNODEINFO_SWAP(nodeinfo); 2222 2223 getnodeinfo_fail: 2224 /* Free the mailbox */ 2225 hermon_mbox_free(state, &mbox_info); 2226 return (status); 2227 } 2228 2229 2230 /* 2231 * hermon_getnodedesc_cmd_post() 2232 * Context: Can be called from interrupt or base context. 2233 * (Currently called only from attach() and detach() path contexts) 2234 */ 2235 int 2236 hermon_getnodedesc_cmd_post(hermon_state_t *state, uint_t sleepflag, 2237 sm_nodedesc_t *nodedesc) 2238 { 2239 hermon_mbox_info_t mbox_info; 2240 hermon_cmd_post_t cmd; 2241 uint32_t *mbox; 2242 uint_t size; 2243 int status, i; 2244 2245 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 2246 2247 /* Get "In" and "Out" mailboxes for the command */ 2248 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX; 2249 status = hermon_mbox_alloc(state, &mbox_info, sleepflag); 2250 if (status != HERMON_CMD_SUCCESS) { 2251 return (status); 2252 } 2253 2254 /* Build the GetNodeDesc request MAD into the "In" mailbox */ 2255 size = HERMON_CMD_MAD_IFC_SIZE; 2256 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr; 2257 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0); 2258 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1); 2259 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2); 2260 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3); 2261 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_NODEDESC); 2262 for (i = 5; i < (size >> 2); i++) { 2263 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0); 2264 } 2265 2266 /* Sync the mailbox for the device to read */ 2267 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 2268 2269 /* Setup the Hermon "MAD_IFC" command */ 2270 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 2271 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr; 2272 cmd.cp_inmod = 1; /* Get NodeDesc from port #1 */ 2273 cmd.cp_opcode = MAD_IFC; 2274 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK; /* No MKey checking */ 2275 cmd.cp_flags = sleepflag; 2276 status = hermon_cmd_post(state, &cmd); 2277 if (status != HERMON_CMD_SUCCESS) { 2278 goto getnodedesc_fail; 2279 } 2280 2281 /* Sync the mailbox to read the results */ 2282 size = sizeof (sm_nodedesc_t); 2283 hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET, 2284 size, DDI_DMA_SYNC_FORCPU); 2285 2286 /* Copy GetNodeDesc response MAD into "nodedesc" */ 2287 bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr + 2288 HERMON_CMD_MADDATA_OFFSET), nodedesc, size); 2289 2290 getnodedesc_fail: 2291 /* Free the mailbox */ 2292 hermon_mbox_free(state, &mbox_info); 2293 return (status); 2294 } 2295 2296 2297 /* 2298 * hermon_getguidinfo_cmd_post() 2299 * Context: Can be called from interrupt or base context. 2300 */ 2301 int 2302 hermon_getguidinfo_cmd_post(hermon_state_t *state, uint_t port, 2303 uint_t guidblock, uint_t sleepflag, sm_guidinfo_t *guidinfo) 2304 { 2305 hermon_mbox_info_t mbox_info; 2306 hermon_cmd_post_t cmd; 2307 uint32_t *mbox; 2308 uint_t size; 2309 int status, i; 2310 2311 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 2312 2313 /* Get "In" and "Out" mailboxes for the command */ 2314 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX; 2315 status = hermon_mbox_alloc(state, &mbox_info, sleepflag); 2316 if (status != HERMON_CMD_SUCCESS) { 2317 return (status); 2318 } 2319 2320 /* Build the GetGUIDInfo request MAD into the "In" mailbox */ 2321 size = HERMON_CMD_MAD_IFC_SIZE; 2322 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr; 2323 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0); 2324 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1); 2325 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2); 2326 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3); 2327 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_GUIDINFO); 2328 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], guidblock); 2329 for (i = 6; i < (size >> 2); i++) { 2330 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0); 2331 } 2332 2333 /* Sync the mailbox for the device to read */ 2334 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 2335 2336 /* Setup the Hermon "MAD_IFC" command */ 2337 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 2338 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr; 2339 cmd.cp_inmod = port; 2340 cmd.cp_opcode = MAD_IFC; 2341 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK; /* No MKey checking */ 2342 cmd.cp_flags = sleepflag; 2343 status = hermon_cmd_post(state, &cmd); 2344 if (status != HERMON_CMD_SUCCESS) { 2345 goto getguidinfo_fail; 2346 } 2347 2348 /* Sync the mailbox to read the results */ 2349 size = sizeof (sm_guidinfo_t); 2350 hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET, 2351 size, DDI_DMA_SYNC_FORCPU); 2352 2353 /* 2354 * Copy GetGUIDInfo response MAD into "guidinfo". Do any endian 2355 * swapping that may be necessary to flip the "guidinfo" fields 2356 */ 2357 bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr + 2358 HERMON_CMD_MADDATA_OFFSET), guidinfo, size); 2359 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*guidinfo)) 2360 HERMON_GETGUIDINFO_SWAP(guidinfo); 2361 2362 getguidinfo_fail: 2363 /* Free the mailbox */ 2364 hermon_mbox_free(state, &mbox_info); 2365 return (status); 2366 } 2367 2368 2369 /* 2370 * hermon_getpkeytable_cmd_post() 2371 * Context: Can be called from interrupt or base context. 2372 */ 2373 int 2374 hermon_getpkeytable_cmd_post(hermon_state_t *state, uint_t port, 2375 uint_t pkeyblock, uint_t sleepflag, sm_pkey_table_t *pkeytable) 2376 { 2377 hermon_mbox_info_t mbox_info; 2378 hermon_cmd_post_t cmd; 2379 uint32_t *mbox; 2380 uint_t size; 2381 int status, i; 2382 2383 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 2384 2385 /* Get "In" and "Out" mailboxes for the command */ 2386 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX | HERMON_ALLOC_OUTMBOX; 2387 status = hermon_mbox_alloc(state, &mbox_info, sleepflag); 2388 if (status != HERMON_CMD_SUCCESS) { 2389 return (status); 2390 } 2391 2392 /* Build the GetPkeyTable request MAD into the "In" mailbox */ 2393 size = HERMON_CMD_MAD_IFC_SIZE; 2394 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr; 2395 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], HERMON_CMD_MADHDR0); 2396 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], HERMON_CMD_MADHDR1); 2397 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], HERMON_CMD_MADHDR2); 2398 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], HERMON_CMD_MADHDR3); 2399 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], HERMON_CMD_PKEYTBLE); 2400 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], pkeyblock); 2401 for (i = 6; i < (size >> 2); i++) { 2402 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0); 2403 } 2404 2405 /* Sync the mailbox for the device to read */ 2406 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 2407 2408 /* Setup the Hermon "MAD_IFC" command */ 2409 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 2410 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr; 2411 cmd.cp_inmod = port; 2412 cmd.cp_opcode = MAD_IFC; 2413 cmd.cp_opmod = HERMON_CMD_MKEY_DONTCHECK; /* No MKey checking */ 2414 cmd.cp_flags = sleepflag; 2415 status = hermon_cmd_post(state, &cmd); 2416 if (status != HERMON_CMD_SUCCESS) { 2417 goto getpkeytable_fail; 2418 } 2419 2420 /* Sync the mailbox to read the results */ 2421 size = sizeof (sm_pkey_table_t); 2422 hermon_mbox_sync(mbox_info.mbi_out, HERMON_CMD_MADDATA_OFFSET, 2423 size, DDI_DMA_SYNC_FORCPU); 2424 2425 /* 2426 * Copy GetPKeyTable response MAD into "pkeytable". Do any endian 2427 * swapping that may be necessary to flip the "pkeytable" fields 2428 */ 2429 bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr + 2430 HERMON_CMD_MADDATA_OFFSET), pkeytable, size); 2431 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*pkeytable)) 2432 HERMON_GETPKEYTABLE_SWAP(pkeytable); 2433 2434 getpkeytable_fail: 2435 /* Free the mailbox */ 2436 hermon_mbox_free(state, &mbox_info); 2437 return (status); 2438 } 2439 2440 2441 /* 2442 * hermon_write_mtt_cmd_post() 2443 * Context: Can be called from interrupt or base context. 2444 */ 2445 int 2446 hermon_write_mtt_cmd_post(hermon_state_t *state, hermon_rsrc_t *mtt, 2447 uint64_t start_addr, uint_t nummtt, uint_t sleepflag) 2448 { 2449 hermon_mbox_info_t mbox_info; 2450 hermon_cmd_post_t cmd; 2451 uint64_t data; 2452 uint_t size; 2453 int status; 2454 int i; 2455 2456 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 2457 2458 /* Get an "In" mailbox for the command */ 2459 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX; 2460 status = hermon_mbox_alloc(state, &mbox_info, sleepflag); 2461 if (status != HERMON_CMD_SUCCESS) { 2462 return (status); 2463 } 2464 2465 /* 2466 * The WRITE_MTT command input parameter contains the 64-bit addr of 2467 * the first target MTT, followed by 64 bits reserved, followed by an 2468 * array of MTT entries. 2469 * 2470 */ 2471 ddi_put64(mbox_info.mbi_in->mb_acchdl, 2472 ((uint64_t *)mbox_info.mbi_in->mb_addr), 2473 start_addr); 2474 2475 ddi_put64(mbox_info.mbi_in->mb_acchdl, 2476 ((uint64_t *)mbox_info.mbi_in->mb_addr + 1), 0x0); 2477 2478 for (i = 0; i < nummtt; i++) { 2479 data = ((uint64_t *)mtt->hr_addr)[i]; 2480 ddi_put64(mbox_info.mbi_in->mb_acchdl, 2481 ((uint64_t *)mbox_info.mbi_in->mb_addr + i + 2), data); 2482 } 2483 2484 /* Sync the mailbox for the device to read */ 2485 size = (nummtt << HERMON_MTT_SIZE_SHIFT) + HERMON_CMD_WRITEMTT_RSVD_SZ; 2486 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 2487 2488 /* Setup and post Hermon "WRITE_MTT" command */ 2489 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 2490 cmd.cp_outparm = 0; 2491 cmd.cp_inmod = nummtt; 2492 cmd.cp_opcode = WRITE_MTT; 2493 cmd.cp_opmod = 0; 2494 cmd.cp_flags = sleepflag; 2495 status = hermon_cmd_post(state, &cmd); 2496 if (status != HERMON_CMD_SUCCESS) { 2497 cmn_err(CE_CONT, "WRITE_MTT failed (0x%x)\n", status); 2498 } 2499 2500 /* Free the mailbox */ 2501 hermon_mbox_free(state, &mbox_info); 2502 return (status); 2503 } 2504 2505 2506 /* 2507 * hermon_sync_tpt_cmd_post() 2508 * Context: Can be called from interrupt or base context. 2509 */ 2510 int 2511 hermon_sync_tpt_cmd_post(hermon_state_t *state, uint_t sleepflag) 2512 { 2513 hermon_cmd_post_t cmd; 2514 int status; 2515 2516 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 2517 2518 /* Setup and post the Hermon "SYNC_TPT" command */ 2519 cmd.cp_inparm = 0; 2520 cmd.cp_outparm = 0; 2521 cmd.cp_inmod = 0; 2522 cmd.cp_opcode = SYNC_TPT; 2523 cmd.cp_opmod = 0; 2524 cmd.cp_flags = sleepflag; 2525 status = hermon_cmd_post(state, &cmd); 2526 2527 return (status); 2528 } 2529 2530 /* 2531 * hermon_map_eq_cmd_post() 2532 * Context: Can be called from interrupt or base context. 2533 * (Currently called only from attach() and/or detach() path contexts) 2534 */ 2535 int 2536 hermon_map_eq_cmd_post(hermon_state_t *state, uint_t map, uint_t eqcindx, 2537 uint64_t eqmapmask, uint_t sleepflag) 2538 { 2539 hermon_cmd_post_t cmd; 2540 int status; 2541 2542 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 2543 2544 /* Setup and post Hermon "MAP_EQ" command */ 2545 cmd.cp_inparm = eqmapmask; 2546 cmd.cp_outparm = 0; 2547 cmd.cp_inmod = eqcindx; 2548 if (map != HERMON_CMD_MAP_EQ_EVT_MAP) { 2549 cmd.cp_inmod |= HERMON_CMD_UNMAP_EQ_MASK; 2550 } 2551 cmd.cp_opcode = MAP_EQ; 2552 cmd.cp_opmod = 0; 2553 cmd.cp_flags = sleepflag; 2554 status = hermon_cmd_post(state, &cmd); 2555 return (status); 2556 } 2557 2558 2559 /* 2560 * hermon_resize_cq_cmd_post() 2561 * Context: Can be called from interrupt or base context. 2562 */ 2563 int 2564 hermon_resize_cq_cmd_post(hermon_state_t *state, hermon_hw_cqc_t *cqc, 2565 uint_t cqcindx, uint32_t *prod_indx, uint_t sleepflag) 2566 { 2567 hermon_mbox_info_t mbox_info; 2568 hermon_cmd_post_t cmd; 2569 uint64_t data; 2570 uint_t size; 2571 int status, i; 2572 2573 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 2574 2575 /* Get an "In" mailbox for the command */ 2576 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX; 2577 status = hermon_mbox_alloc(state, &mbox_info, sleepflag); 2578 if (status != HERMON_CMD_SUCCESS) { 2579 return (status); 2580 } 2581 2582 /* Copy the Hermon "MODIFY_CQ" command into mailbox */ 2583 size = sizeof (hermon_hw_cqc_t); 2584 for (i = 0; i < (size >> 3); i++) { 2585 data = ((uint64_t *)(void *)cqc)[i]; 2586 ddi_put64(mbox_info.mbi_in->mb_acchdl, 2587 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data); 2588 } 2589 2590 /* Sync the mailbox for the device to read */ 2591 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 2592 2593 /* Setup and post Hermon "MODIFY_CQ" command */ 2594 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 2595 cmd.cp_outparm = 0; /* resize cq */ 2596 cmd.cp_inmod = cqcindx; 2597 cmd.cp_opcode = MODIFY_CQ; 2598 cmd.cp_opmod = RESIZE_CQ; 2599 cmd.cp_flags = sleepflag; 2600 status = hermon_cmd_post(state, &cmd); 2601 2602 /* 2603 * New "producer index" is returned in the upper 32 bits of 2604 * command "outparam" 2605 */ 2606 *prod_indx = (cmd.cp_outparm >> 32); 2607 2608 /* Free the mailbox */ 2609 hermon_mbox_free(state, &mbox_info); 2610 return (status); 2611 } 2612 2613 2614 /* 2615 * hermon_modify_cq_cmd_post() 2616 * Context: Can be called from interrupt or base context. 2617 */ 2618 int 2619 hermon_modify_cq_cmd_post(hermon_state_t *state, hermon_hw_cqc_t *cqc, 2620 uint_t cqcindx, uint_t opmod, uint_t sleepflag) 2621 { 2622 hermon_mbox_info_t mbox_info; 2623 hermon_cmd_post_t cmd; 2624 uint64_t data; 2625 uint_t size; 2626 int status, i; 2627 2628 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 2629 2630 /* Get an "In" mailbox for the command */ 2631 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX; 2632 status = hermon_mbox_alloc(state, &mbox_info, sleepflag); 2633 if (status != HERMON_CMD_SUCCESS) { 2634 return (status); 2635 } 2636 2637 /* Copy the Hermon "MODIFY_CQ" command into mailbox */ 2638 size = sizeof (hermon_hw_cqc_t); 2639 for (i = 0; i < (size >> 3); i++) { 2640 data = ((uint64_t *)(void *)cqc)[i]; 2641 ddi_put64(mbox_info.mbi_in->mb_acchdl, 2642 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data); 2643 } 2644 2645 /* Sync the mailbox for the device to read */ 2646 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 2647 2648 /* Setup and post Hermon "MODIFY_CQ" command */ 2649 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 2650 cmd.cp_outparm = 0; 2651 cmd.cp_inmod = cqcindx; 2652 cmd.cp_opcode = MODIFY_CQ; 2653 cmd.cp_opmod = (uint16_t)opmod; 2654 cmd.cp_flags = sleepflag; 2655 status = hermon_cmd_post(state, &cmd); 2656 2657 /* Free the mailbox */ 2658 hermon_mbox_free(state, &mbox_info); 2659 return (status); 2660 } 2661 2662 2663 /* 2664 * hermon_cmn_qp_cmd_post() 2665 * Context: Can be called from interrupt or base context. 2666 * 2667 * This is the common function for posting all the various types of 2668 * QP state transition related Hermon commands. Since some of the 2669 * commands differ from the others in the number (and type) of arguments 2670 * that each require, this routine does checks based on opcode type 2671 * (explained in more detail below). 2672 * 2673 * Note: This common function should be used only with the following 2674 * opcodes: RTS2SQD_QP, TOERR_QP, TORST_QP, RST2INIT_QP, INIT2INIT_QP, 2675 * INIT2RTR_QP, RTR2RTS_QP, RTS2RTS_QP, SQD2RTS_QP, and SQERR2RTS_QP. 2676 */ 2677 int 2678 hermon_cmn_qp_cmd_post(hermon_state_t *state, uint_t opcode, 2679 hermon_hw_qpc_t *qp, uint_t qpindx, uint32_t opmask, 2680 uint_t sleepflag) 2681 { 2682 hermon_mbox_info_t mbox_info; 2683 hermon_cmd_post_t cmd; 2684 uint64_t data, in_mapaddr, out_mapaddr; 2685 uint_t size, flags, opmod; 2686 int status, i; 2687 2688 /* 2689 * Use the specified opcode type to set the appropriate parameters. 2690 * Specifically, we need to set in_mapaddr, out_mapaddr, flags, and 2691 * opmod (as necessary). Setting these parameters may also require 2692 * us to allocate an "In" or "Out" mailbox depending on the command 2693 * type. 2694 */ 2695 2696 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 2697 2698 if (opcode == RTS2SQD_QP) { 2699 /* 2700 * Note: For RTS-to-SendQueueDrain state transitions we 2701 * always want to request the event generation from the 2702 * hardware. Though we may not notify the consumer of the 2703 * drained event, the decision to forward (or not) is made 2704 * later in the SQD event handler. 2705 */ 2706 flags = HERMON_CMD_REQ_SQD_EVENT; 2707 2708 /* 2709 * The RTS2SQD_QP command uses no "In" or "Out" mailboxes (and 2710 * has no special opcode modifiers). 2711 */ 2712 in_mapaddr = 0; 2713 out_mapaddr = 0; 2714 opmod = 0; 2715 2716 } else if (opcode == TOERR_QP) { 2717 /* 2718 * The TOERR_QP command uses no "In" or "Out" mailboxes, has no 2719 * special opcode modifiers, and takes no special flags. 2720 */ 2721 in_mapaddr = 0; 2722 out_mapaddr = 0; 2723 opmod = 0; 2724 flags = 0; 2725 2726 } else if (opcode == TORST_QP) { 2727 /* 2728 * The TORST_QP command could take an "Out" mailbox, but we do 2729 * not require it here. It also does not takes any special 2730 * flags. It does however, take a HERMON_CMD_DIRECT_TO_RESET 2731 * opcode modifier, which indicates that the transition to 2732 * reset should happen without first moving the QP through the 2733 * Error state (and, hence, without generating any unnecessary 2734 * "flushed-in-error" completions). 2735 */ 2736 in_mapaddr = 0; 2737 out_mapaddr = 0; 2738 opmod = HERMON_CMD_DIRECT_TO_RESET | HERMON_CMD_NO_OUTMBOX; 2739 flags = 0; 2740 2741 } else { 2742 /* 2743 * All the other QP state transition commands (RST2INIT_QP, 2744 * INIT2INIT_QP, INIT2RTR_QP, RTR2RTS_QP, RTS2RTS_QP, 2745 * SQD2RTS_QP, and SQERR2RTS_QP) require an "In" mailbox. 2746 * None of these require any special flags or opcode modifiers. 2747 */ 2748 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX; 2749 status = hermon_mbox_alloc(state, &mbox_info, sleepflag); 2750 if (status != HERMON_CMD_SUCCESS) { 2751 return (status); 2752 } 2753 in_mapaddr = mbox_info.mbi_in->mb_mapaddr; 2754 out_mapaddr = 0; 2755 flags = 0; 2756 opmod = 0; 2757 2758 /* Copy the Hermon command into the "In" mailbox */ 2759 size = sizeof (hermon_hw_qpc_t); 2760 for (i = 0; i < (size >> 3); i++) { 2761 data = ((uint64_t *)(void *)qp)[i]; 2762 ddi_put64(mbox_info.mbi_in->mb_acchdl, 2763 ((uint64_t *)mbox_info.mbi_in->mb_addr + i + 1), 2764 data); 2765 } 2766 ddi_put32(mbox_info.mbi_in->mb_acchdl, 2767 ((uint32_t *)mbox_info.mbi_in->mb_addr), opmask); 2768 2769 /* 2770 * Sync the mailbox for the device to read. We have to add 2771 * eight bytes here to account for "opt_param_mask" and 2772 * proper alignment. 2773 */ 2774 hermon_mbox_sync(mbox_info.mbi_in, 0, size + 8, 2775 DDI_DMA_SYNC_FORDEV); 2776 } 2777 2778 /* Setup and post Hermon QP state transition command */ 2779 cmd.cp_inparm = in_mapaddr; 2780 cmd.cp_outparm = out_mapaddr; 2781 cmd.cp_inmod = qpindx | flags; 2782 cmd.cp_opcode = (uint16_t)opcode; 2783 cmd.cp_opmod = (uint16_t)opmod; 2784 cmd.cp_flags = sleepflag; 2785 status = hermon_cmd_post(state, &cmd); 2786 2787 /* 2788 * If we allocated a mailbox (either an "In" or an "Out") above, 2789 * then free it now before returning. 2790 */ 2791 if ((opcode != RTS2SQD_QP) && (opcode != TOERR_QP) && 2792 (opcode != TORST_QP)) { 2793 /* Free the mailbox */ 2794 hermon_mbox_free(state, &mbox_info); 2795 } 2796 return (status); 2797 } 2798 2799 2800 /* 2801 * hermon_cmn_query_cmd_post() 2802 * Context: Can be called from interrupt or base context. 2803 * 2804 * This is the common function for posting all the various types of 2805 * Hermon query commands. All Hermon query commands require an "Out" 2806 * mailbox to be allocated for the resulting queried data. 2807 * 2808 * Note: This common function should be used only with the following 2809 * opcodes: QUERY_DEV_LIM, QUERY_FW, QUERY_DDR, QUERY_ADAPTER, QUERY_PORT 2810 * QUERY_HCA, QUERY_MPT, QUERY_EQ, QUERY_CQ, and QUERY_QP. 2811 */ 2812 int 2813 hermon_cmn_query_cmd_post(hermon_state_t *state, uint_t opcode, uint_t opmod, 2814 uint_t queryindx, void *query, uint_t size, uint_t sleepflag) 2815 { 2816 hermon_mbox_info_t mbox_info; 2817 hermon_cmd_post_t cmd; 2818 uint64_t data; 2819 uint_t offset; 2820 int status, i; 2821 2822 bzero(&cmd, sizeof (hermon_cmd_post_t)); 2823 2824 /* Get an "Out" mailbox for the command */ 2825 mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX; 2826 status = hermon_mbox_alloc(state, &mbox_info, sleepflag); 2827 if (status != HERMON_CMD_SUCCESS) { 2828 return (status); 2829 } 2830 2831 /* Setup and post the Hermon query command */ 2832 cmd.cp_inparm = 0; 2833 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr; 2834 cmd.cp_inmod = queryindx; 2835 cmd.cp_opcode = (uint16_t)opcode; 2836 cmd.cp_opmod = (uint16_t)opmod; 2837 cmd.cp_flags = sleepflag; 2838 status = hermon_cmd_post(state, &cmd); 2839 if (status != HERMON_CMD_SUCCESS) { 2840 goto cmn_query_fail; 2841 } 2842 2843 /* Sync the mailbox to read the results */ 2844 hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU); 2845 2846 /* 2847 * QUERY_QP is handled somewhat differently than the other query 2848 * commands. For QUERY_QP, the actual queried data is offset into 2849 * the mailbox (by one 64-bit word). 2850 */ 2851 offset = (opcode == QUERY_QP) ? 1 : 0; 2852 2853 /* Copy query command results into "query" */ 2854 for (i = 0; i < (size >> 3); i++) { 2855 data = ddi_get64(mbox_info.mbi_out->mb_acchdl, 2856 ((uint64_t *)mbox_info.mbi_out->mb_addr + i + offset)); 2857 ((uint64_t *)query)[i] = data; 2858 } 2859 2860 cmn_query_fail: 2861 /* Free the mailbox */ 2862 hermon_mbox_free(state, &mbox_info); 2863 return (status); 2864 } 2865 2866 2867 /* 2868 * hermon_cmn_ownership_cmd_post() 2869 * Context: Can be called from interrupt or base context. 2870 * 2871 * This is the common function for posting all the various types of 2872 * Hermon HW/SW resource ownership commands. Since some of the commands 2873 * differ from the others in the direction of ownership change (i.e. 2874 * from HW ownership to SW, or vice versa), they differ in the type of 2875 * mailbox and specific handling that each requires. This routine does 2876 * certain checks based on opcode type to determine the direction of 2877 * the transition and to correctly handle the request. 2878 * 2879 * Note: This common function should be used only with the following 2880 * opcodes: HW2SW_MPT, HW2SW_EQ, HW2SW_CQ, SW2HW_MPT, SW2HW_EQ, and 2881 * SW2HW_CQ 2882 */ 2883 int 2884 hermon_cmn_ownership_cmd_post(hermon_state_t *state, uint_t opcode, 2885 void *hwrsrc, uint_t size, uint_t hwrsrcindx, uint_t sleepflag) 2886 { 2887 hermon_mbox_info_t mbox_info; 2888 hermon_cmd_post_t cmd; 2889 uint64_t data, in_mapaddr, out_mapaddr; 2890 uint_t direction, opmod; 2891 int status, i; 2892 2893 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 2894 2895 /* 2896 * Determine the direction of the ownership transfer based on the 2897 * provided opcode 2898 */ 2899 if ((opcode == HW2SW_MPT) || (opcode == HW2SW_EQ) || 2900 (opcode == HW2SW_CQ) || (opcode == HW2SW_SRQ)) { 2901 direction = HERMON_CMD_RSRC_HW2SW; 2902 2903 } else if ((opcode == SW2HW_MPT) || (opcode == SW2HW_EQ) || 2904 (opcode == SW2HW_CQ) || (opcode == SW2HW_SRQ)) { 2905 direction = HERMON_CMD_RSRC_SW2HW; 2906 2907 } else { 2908 return (HERMON_CMD_INVALID_STATUS); 2909 } 2910 2911 /* 2912 * If hwrsrc is NULL then we do not allocate a mailbox. This is used 2913 * in the case of memory deregister where the out mailbox is not 2914 * needed. In the case of re-register, we do use the hwrsrc. 2915 * 2916 * Otherwise, If ownership transfer is going from hardware to software, 2917 * then allocate an "Out" mailbox. This will be filled in later as a 2918 * result of the Hermon command. 2919 * 2920 * And if the ownership transfer is going from software to hardware, 2921 * then we need an "In" mailbox, and we need to fill it in and sync it 2922 * (if necessary). Then the mailbox can be passed to the Hermon 2923 * firmware. 2924 * 2925 * For the HW2SW (dereg) case, we only use an out mbox if hwrsrc is != 2926 * NULL. This implies a re-reg, and the out mbox must be used. If 2927 * hwrsrc is == NULL, then we can save some time and resources by not 2928 * using an out mbox at all. We must set opmod to HERMON_CMD_DO_OUTMBOX 2929 * and HERMON_CMD_NO_OUTMBOX appropriately in this case. 2930 * 2931 * For the SW2HW (reg) case, no out mbox is possible. We set opmod to 2932 * 0 anyway, but this field is not used in this case. 2933 */ 2934 if (direction == HERMON_CMD_RSRC_HW2SW) { 2935 if (hwrsrc != NULL) { 2936 mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX; 2937 status = hermon_mbox_alloc(state, &mbox_info, 2938 sleepflag); 2939 if (status != HERMON_CMD_SUCCESS) { 2940 return (status); 2941 } 2942 in_mapaddr = 0; 2943 out_mapaddr = mbox_info.mbi_out->mb_mapaddr; 2944 opmod = HERMON_CMD_DO_OUTMBOX; 2945 } else { 2946 in_mapaddr = 0; 2947 out_mapaddr = 0; 2948 opmod = HERMON_CMD_NO_OUTMBOX; 2949 } 2950 } else { /* HERMON_CMD_RSRC_SW2HW */ 2951 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX; 2952 status = hermon_mbox_alloc(state, &mbox_info, sleepflag); 2953 if (status != HERMON_CMD_SUCCESS) { 2954 return (status); 2955 } 2956 2957 /* Copy the SW2HW ownership command into mailbox */ 2958 for (i = 0; i < (size >> 3); i++) { 2959 data = ((uint64_t *)hwrsrc)[i]; 2960 ddi_put64(mbox_info.mbi_in->mb_acchdl, 2961 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), 2962 data); 2963 } 2964 2965 /* Sync the mailbox for the device to read */ 2966 hermon_mbox_sync(mbox_info.mbi_in, 0, size, 2967 DDI_DMA_SYNC_FORDEV); 2968 2969 in_mapaddr = mbox_info.mbi_in->mb_mapaddr; 2970 out_mapaddr = 0; 2971 opmod = 0; 2972 } 2973 2974 /* Setup and post the Hermon ownership command */ 2975 cmd.cp_inparm = in_mapaddr; 2976 cmd.cp_outparm = out_mapaddr; 2977 cmd.cp_inmod = hwrsrcindx; 2978 cmd.cp_opcode = (uint16_t)opcode; 2979 cmd.cp_opmod = (uint16_t)opmod; 2980 cmd.cp_flags = sleepflag; 2981 status = hermon_cmd_post(state, &cmd); 2982 if (status != HERMON_CMD_SUCCESS) { 2983 goto cmn_ownership_fail; 2984 } 2985 2986 /* 2987 * As mentioned above, for HW2SW ownership transfers we need to 2988 * sync (if necessary) and copy out the resulting data from the 2989 * "Out" mailbox" (assuming the above command was successful). 2990 */ 2991 if (direction == HERMON_CMD_RSRC_HW2SW && hwrsrc != NULL) { 2992 2993 /* Sync the mailbox to read the results */ 2994 hermon_mbox_sync(mbox_info.mbi_out, 0, size, 2995 DDI_DMA_SYNC_FORCPU); 2996 2997 /* Copy HW2SW ownership command results into "hwrsrc" */ 2998 for (i = 0; i < (size >> 3); i++) { 2999 data = ddi_get64(mbox_info.mbi_out->mb_acchdl, 3000 ((uint64_t *)mbox_info.mbi_out->mb_addr + i)); 3001 ((uint64_t *)hwrsrc)[i] = data; 3002 } 3003 } 3004 3005 cmn_ownership_fail: 3006 if (hwrsrc != NULL) { 3007 /* Free the mailbox */ 3008 hermon_mbox_free(state, &mbox_info); 3009 } 3010 return (status); 3011 } 3012 3013 3014 /* 3015 * hermon_conf_special_qp_cmd_post() 3016 * Context: Can be called from interrupt or base context. 3017 */ 3018 /*ARGSUSED*/ 3019 int 3020 hermon_conf_special_qp_cmd_post(hermon_state_t *state, uint_t qpindx, 3021 uint_t qptype, uint_t sleepflag, uint_t opmod) 3022 { 3023 hermon_cmd_post_t cmd; 3024 int status; 3025 3026 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 3027 3028 /* Setup and post Hermon "CONF_SPECIAL_QP" command */ 3029 cmd.cp_inparm = 0; 3030 cmd.cp_outparm = 0; 3031 cmd.cp_inmod = qpindx & 0x00FFFFF8; /* mask off low 3 bits */ 3032 cmd.cp_opcode = CONF_SPECIAL_QP; 3033 cmd.cp_opmod = (uint16_t)opmod; 3034 cmd.cp_flags = sleepflag; 3035 status = hermon_cmd_post(state, &cmd); 3036 3037 return (status); 3038 } 3039 3040 3041 /* 3042 * hermon_mgid_hash_cmd_post() 3043 * Context: Can be called from interrupt or base context. 3044 */ 3045 int 3046 hermon_mgid_hash_cmd_post(hermon_state_t *state, uint64_t mgid_h, 3047 uint64_t mgid_l, uint64_t *mgid_hash, uint_t sleepflag) 3048 { 3049 hermon_mbox_info_t mbox_info; 3050 hermon_cmd_post_t cmd; 3051 int status; 3052 3053 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 3054 3055 /* Get an "In" mailbox for the command */ 3056 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX; 3057 status = hermon_mbox_alloc(state, &mbox_info, sleepflag); 3058 if (status != HERMON_CMD_SUCCESS) { 3059 return (status); 3060 } 3061 3062 /* Copy the Hermon "MGID_HASH" command into mailbox */ 3063 ddi_put64(mbox_info.mbi_in->mb_acchdl, 3064 ((uint64_t *)mbox_info.mbi_in->mb_addr + 0), mgid_h); 3065 ddi_put64(mbox_info.mbi_in->mb_acchdl, 3066 ((uint64_t *)mbox_info.mbi_in->mb_addr + 1), mgid_l); 3067 3068 /* Sync the mailbox for the device to read */ 3069 hermon_mbox_sync(mbox_info.mbi_in, 0, HERMON_CMD_MGIDHASH_SZ, 3070 DDI_DMA_SYNC_FORDEV); 3071 3072 /* Setup and post the Hermon "MGID_HASH" command */ 3073 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 3074 cmd.cp_outparm = 0; 3075 cmd.cp_inmod = 0; 3076 cmd.cp_opcode = MGID_HASH; 3077 cmd.cp_opmod = 0; 3078 cmd.cp_flags = sleepflag; 3079 status = hermon_cmd_post(state, &cmd); 3080 3081 /* MGID hash value is returned in command "outparam" */ 3082 *mgid_hash = cmd.cp_outparm; 3083 3084 /* Free the mailbox */ 3085 hermon_mbox_free(state, &mbox_info); 3086 return (status); 3087 } 3088 3089 3090 /* 3091 * hermon_read_mgm_cmd_post() 3092 * Context: Can be called from interrupt or base context. 3093 * 3094 * Note: It is assumed that the "mcg" parameter is actually a pointer to a 3095 * "hermon_hw_mcg_t" struct and some number of "hermon_hw_mcg_qp_list_t" 3096 * structs. Combined size should be equal to result of HERMON_MCGMEM_SZ() 3097 * macro. 3098 */ 3099 int 3100 hermon_read_mgm_cmd_post(hermon_state_t *state, hermon_hw_mcg_t *mcg, 3101 uint_t mcgindx, uint_t sleepflag) 3102 { 3103 hermon_mbox_info_t mbox_info; 3104 hermon_cmd_post_t cmd; 3105 uint64_t data; 3106 uint32_t data32; 3107 uint_t size, hdrsz, qplistsz; 3108 int status, i; 3109 3110 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 3111 3112 /* Get an "Out" mailbox for the results */ 3113 mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX; 3114 status = hermon_mbox_alloc(state, &mbox_info, sleepflag); 3115 if (status != HERMON_CMD_SUCCESS) { 3116 return (status); 3117 } 3118 3119 /* Setup and post Hermon "READ_MGM" command */ 3120 cmd.cp_inparm = 0; 3121 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr; 3122 cmd.cp_inmod = mcgindx; 3123 cmd.cp_opcode = READ_MGM; 3124 cmd.cp_opmod = 0; 3125 cmd.cp_flags = sleepflag; 3126 status = hermon_cmd_post(state, &cmd); 3127 if (status != HERMON_CMD_SUCCESS) { 3128 goto read_mgm_fail; 3129 } 3130 3131 /* Sync the mailbox to read the results */ 3132 size = HERMON_MCGMEM_SZ(state); 3133 hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU); 3134 3135 /* Copy the READ_MGM command results into "mcg" */ 3136 hdrsz = sizeof (hermon_hw_mcg_t); 3137 for (i = 0; i < (hdrsz >> 3); i++) { 3138 data = ddi_get64(mbox_info.mbi_out->mb_acchdl, 3139 ((uint64_t *)mbox_info.mbi_out->mb_addr + i)); 3140 ((uint64_t *)mcg)[i] = data; 3141 } 3142 qplistsz = size - hdrsz; 3143 for (i = 0; i < (qplistsz >> 2); i++) { 3144 data32 = ddi_get32(mbox_info.mbi_out->mb_acchdl, 3145 ((uint32_t *)mbox_info.mbi_out->mb_addr + i + 8)); 3146 ((uint32_t *)mcg)[i + 8] = data32; 3147 } 3148 3149 read_mgm_fail: 3150 /* Free the mailbox */ 3151 hermon_mbox_free(state, &mbox_info); 3152 return (status); 3153 } 3154 3155 3156 /* 3157 * hermon_write_mgm_cmd_post() 3158 * Context: Can be called from interrupt or base context. 3159 * 3160 * Note: It is assumed that the "mcg" parameter is actually a pointer to a 3161 * "hermon_hw_mcg_t" struct and some number of "hermon_hw_mcg_qp_list_t" 3162 * structs. Combined size should be equal to result of HERMON_MCGMEM_SZ() 3163 * macro. 3164 */ 3165 int 3166 hermon_write_mgm_cmd_post(hermon_state_t *state, hermon_hw_mcg_t *mcg, 3167 uint_t mcgindx, uint_t sleepflag) 3168 { 3169 hermon_mbox_info_t mbox_info; 3170 hermon_cmd_post_t cmd; 3171 uint64_t data; 3172 uint_t size, hdrsz, qplistsz; 3173 int status, i; 3174 3175 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 3176 3177 /* Get an "In" mailbox for the command */ 3178 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX; 3179 status = hermon_mbox_alloc(state, &mbox_info, sleepflag); 3180 if (status != HERMON_CMD_SUCCESS) { 3181 return (status); 3182 } 3183 3184 /* Copy the Hermon "WRITE_MGM" command into mailbox */ 3185 size = HERMON_MCGMEM_SZ(state); 3186 hdrsz = sizeof (hermon_hw_mcg_t); 3187 for (i = 0; i < (hdrsz >> 3); i++) { 3188 data = ((uint64_t *)mcg)[i]; 3189 ddi_put64(mbox_info.mbi_in->mb_acchdl, 3190 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data); 3191 } 3192 qplistsz = size - hdrsz; 3193 for (i = 0; i < (qplistsz >> 2); i++) { 3194 data = ((uint32_t *)mcg)[i + 8]; 3195 ddi_put32(mbox_info.mbi_in->mb_acchdl, 3196 ((uint32_t *)mbox_info.mbi_in->mb_addr + i + 8), data); 3197 } 3198 3199 /* Sync the mailbox for the device to read */ 3200 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 3201 3202 /* Setup and post Hermon "WRITE_MGM" command */ 3203 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 3204 cmd.cp_outparm = 0; 3205 cmd.cp_inmod = mcgindx; 3206 cmd.cp_opcode = WRITE_MGM; 3207 cmd.cp_opmod = 0; 3208 cmd.cp_flags = sleepflag; 3209 status = hermon_cmd_post(state, &cmd); 3210 3211 /* Free the mailbox */ 3212 hermon_mbox_free(state, &mbox_info); 3213 return (status); 3214 } 3215 3216 /* 3217 * hermon_resize_srq_cmd_post() 3218 * Context: Can be called from interrupt or base context. 3219 */ 3220 3221 int hermon_resize_srq_cmd_post(hermon_state_t *state, hermon_hw_srqc_t *srq, 3222 uint_t srqnum, uint_t sleepflag) 3223 { 3224 hermon_mbox_info_t mbox_info; 3225 hermon_cmd_post_t cmd; 3226 uint64_t data; 3227 uint_t size; 3228 int status, i; 3229 3230 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 3231 3232 /* Get an "In" mailbox for the command */ 3233 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX; 3234 status = hermon_mbox_alloc(state, &mbox_info, sleepflag); 3235 if (status != HERMON_CMD_SUCCESS) { 3236 return (status); 3237 } 3238 3239 /* Copy the Hermon "RESIZE_SRQ" command into mailbox */ 3240 size = sizeof (hermon_hw_srqc_t); 3241 for (i = 0; i < (size >> 3); i++) { 3242 data = ((uint64_t *)(void *)srq)[i]; 3243 ddi_put64(mbox_info.mbi_in->mb_acchdl, 3244 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data); 3245 } 3246 3247 /* Sync the mailbox for the device to read */ 3248 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 3249 3250 /* Setup and post Hermon "RESIZE_SRQ" command */ 3251 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 3252 cmd.cp_outparm = 0; 3253 cmd.cp_inmod = srqnum; 3254 cmd.cp_opcode = RESIZE_SRQ; 3255 cmd.cp_opmod = 0; 3256 cmd.cp_flags = sleepflag; 3257 status = hermon_cmd_post(state, &cmd); 3258 3259 /* Free the mailbox */ 3260 hermon_mbox_free(state, &mbox_info); 3261 return (status); 3262 } 3263 /* 3264 * hermon_modify_mpt_cmd_post() 3265 * Context: Can be called from interrupt or base context. 3266 */ 3267 int 3268 hermon_modify_mpt_cmd_post(hermon_state_t *state, hermon_hw_dmpt_t *mpt, 3269 uint_t mptindx, uint_t flags, uint_t sleepflag) 3270 { 3271 hermon_mbox_info_t mbox_info; 3272 hermon_cmd_post_t cmd; 3273 uint64_t data; 3274 uint_t size; 3275 int status, i; 3276 3277 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 3278 3279 /* Get an "In" mailbox for the command */ 3280 mbox_info.mbi_alloc_flags = HERMON_ALLOC_INMBOX; 3281 status = hermon_mbox_alloc(state, &mbox_info, sleepflag); 3282 if (status != HERMON_CMD_SUCCESS) { 3283 return (status); 3284 } 3285 3286 /* Copy the Hermon "MODIFY_MPT" command into mailbox */ 3287 size = sizeof (hermon_hw_dmpt_t); 3288 for (i = 0; i < (size >> 3); i++) { 3289 data = ((uint64_t *)mpt)[i]; 3290 ddi_put64(mbox_info.mbi_in->mb_acchdl, 3291 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data); 3292 } 3293 3294 /* Sync the mailbox for the device to read */ 3295 hermon_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 3296 3297 /* Setup and post Hermon "MODIFY_MPT" command */ 3298 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 3299 cmd.cp_outparm = 0; 3300 cmd.cp_inmod = mptindx; 3301 cmd.cp_opcode = MODIFY_MPT; 3302 cmd.cp_opmod = (uint16_t)flags; 3303 cmd.cp_flags = sleepflag; 3304 status = hermon_cmd_post(state, &cmd); 3305 3306 /* Free the mailbox */ 3307 hermon_mbox_free(state, &mbox_info); 3308 return (status); 3309 } 3310 3311 3312 int 3313 hermon_nop_post(hermon_state_t *state, uint_t interval, uint_t sleep) 3314 { 3315 hermon_cmd_post_t cmd; 3316 int status; 3317 3318 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 3319 3320 /* Setup and post Hermon "CMD_NOP" command */ 3321 cmd.cp_inparm = 0; 3322 cmd.cp_outparm = 0; 3323 cmd.cp_inmod = interval; 3324 cmd.cp_opcode = CMD_NOP; 3325 cmd.cp_opmod = 0; 3326 cmd.cp_flags = HERMON_CMD_SLEEP_NOSPIN; 3327 if (sleep) cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN; 3328 status = hermon_cmd_post(state, &cmd); 3329 return (status); 3330 } 3331 3332 int 3333 hermon_setdebug_post(hermon_state_t *state) 3334 { 3335 hermon_cmd_post_t cmd; 3336 int status; 3337 3338 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 3339 3340 /* Setup and post Hermon "CMD_NOP" command */ 3341 cmd.cp_inparm = 0xFFFFFFFFFFFFFFFF; 3342 cmd.cp_outparm = 0; 3343 cmd.cp_inmod = 0; 3344 cmd.cp_opcode = SET_DEBUG_MSG; 3345 cmd.cp_opmod = 0; 3346 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN; 3347 status = hermon_cmd_post(state, &cmd); 3348 return (status); 3349 } 3350 3351 3352 int 3353 hermon_read_mtt_cmd_post(hermon_state_t *state, uint64_t mtt_addr, 3354 hermon_hw_mtt_t *mtt) 3355 { 3356 3357 hermon_cmd_post_t cmd; 3358 hermon_mbox_info_t mbox_info; 3359 int i, status; 3360 uint_t size; 3361 uint64_t data; 3362 3363 bzero((void *)&cmd, sizeof (hermon_cmd_post_t)); 3364 3365 /* Get an "Out" mailbox for the command */ 3366 mbox_info.mbi_alloc_flags = HERMON_ALLOC_OUTMBOX; 3367 status = hermon_mbox_alloc(state, &mbox_info, HERMON_CMD_SLEEP_NOSPIN); 3368 if (status != HERMON_CMD_SUCCESS) { 3369 return (status); 3370 } 3371 3372 /* Setup and post the "READ_MTT" command */ 3373 cmd.cp_inparm = mtt_addr; 3374 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr; 3375 cmd.cp_inmod = 1; 3376 cmd.cp_opcode = READ_MTT; 3377 cmd.cp_opmod = 0; 3378 cmd.cp_flags = HERMON_CMD_NOSLEEP_SPIN; 3379 status = hermon_cmd_post(state, &cmd); 3380 if (status != HERMON_CMD_SUCCESS) { 3381 return (status); 3382 } 3383 3384 /* Sync the mailbox to read the results */ 3385 size = sizeof (hermon_hw_mtt_t); 3386 hermon_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU); 3387 3388 /* Copy mtt read out */ 3389 for (i = 0; i < (size >> 3); i++) { 3390 data = ddi_get64(mbox_info.mbi_out->mb_acchdl, 3391 ((uint64_t *)mbox_info.mbi_out->mb_addr + i)); 3392 ((uint64_t *)(void *)mtt)[i] = data; 3393 } 3394 3395 /* Free the mailbox */ 3396 hermon_mbox_free(state, &mbox_info); 3397 return (status); 3398 } 3399