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