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