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