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