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 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Interface for Serengeti IOSRAM mailbox 31 * OS <-> SC communication protocol 32 */ 33 34 #include <sys/types.h> 35 #include <sys/systm.h> 36 #include <sys/ddi.h> 37 #include <sys/sunddi.h> 38 #include <sys/kmem.h> 39 #include <sys/uadmin.h> 40 #include <sys/machsystm.h> 41 #include <sys/disp.h> 42 #include <sys/taskq.h> 43 44 #include <sys/sgevents.h> 45 #include <sys/sgsbbc_priv.h> 46 #include <sys/sgsbbc_iosram_priv.h> 47 #include <sys/sgsbbc_mailbox_priv.h> 48 #include <sys/plat_ecc_unum.h> 49 #include <sys/plat_ecc_dimm.h> 50 #include <sys/serengeti.h> 51 #include <sys/fm/util.h> 52 #include <sys/promif.h> 53 #include <sys/plat_datapath.h> 54 55 sbbc_mailbox_t *master_mbox = NULL; 56 57 /* 58 * Panic Shutdown event support 59 */ 60 static kmutex_t panic_hdlr_lock; 61 62 /* 63 * The ID of the soft interrupt which triggers the bringing down of a Domain 64 * when a PANIC_SHUTDOWN event is received. 65 */ 66 static ddi_softintr_t panic_softintr_id = 0; 67 68 static sg_panic_shutdown_t panic_payload; 69 static sbbc_msg_t panic_payload_msg; 70 71 /* 72 * A queue for making sure outgoing messages are in order as ScApp 73 * does not support interleaving messages. 74 */ 75 static kcondvar_t outbox_queue; 76 static kmutex_t outbox_queue_lock; 77 78 /* 79 * Handle unsolicited capability message. 80 */ 81 static plat_capability_data_t cap_payload; 82 static sbbc_msg_t cap_payload_msg; 83 static kmutex_t cap_msg_hdlr_lock; 84 85 /* 86 * Datapath error and fault messages arrive unsolicited. The message data 87 * is contained in a plat_datapath_info_t structure. 88 */ 89 typedef struct { 90 uint8_t type; /* CDS, DX, CP */ 91 uint8_t pad; /* for alignment */ 92 uint16_t cpuid; /* Safari ID of base CPU */ 93 uint32_t t_value; /* SERD timeout threshold (seconds) */ 94 } plat_datapath_info_t; 95 96 /* 97 * Unsolicited datapath error messages are processed via a soft interrupt, 98 * triggered in unsolicited interrupt processing. 99 */ 100 static ddi_softintr_t dp_softintr_id = 0; 101 static kmutex_t dp_hdlr_lock; 102 103 static plat_datapath_info_t dp_payload; 104 static sbbc_msg_t dp_payload_msg; 105 106 static char *dperrtype[] = { 107 DP_ERROR_CDS, 108 DP_ERROR_DX, 109 DP_ERROR_RP 110 }; 111 112 /* 113 * Variable indicating if we are already processing requests. 114 * Setting this value must be protected by outbox_queue_lock. 115 */ 116 static int outbox_busy = 0; 117 118 /* 119 * local stuff 120 */ 121 static int sbbc_mbox_send_msg(sbbc_msg_t *, int, uint_t, time_t, clock_t); 122 static int sbbc_mbox_recv_msg(); 123 static int mbox_write(struct sbbc_mbox_header *, 124 struct sbbc_fragment *, sbbc_msg_t *); 125 static int mbox_read(struct sbbc_mbox_header *, struct sbbc_fragment *, 126 sbbc_msg_t *); 127 static int mbox_has_free_space(struct sbbc_mbox_header *); 128 static void mbox_skip_next_msg(struct sbbc_mbox_header *); 129 static int mbox_read_header(uint32_t, struct sbbc_mbox_header *); 130 static void mbox_update_header(uint32_t, struct sbbc_mbox_header *); 131 static int mbox_read_frag(struct sbbc_mbox_header *, struct sbbc_fragment *); 132 static struct sbbc_msg_waiter *mbox_find_waiter(uint16_t, uint32_t); 133 static void wakeup_next(void); 134 static uint_t sbbc_panic_shutdown_handler(char *arg); 135 static uint_t sbbc_do_fast_shutdown(char *arg); 136 static void sbbc_mbox_post_reg(sbbc_softstate_t *softsp); 137 static uint_t cap_ecc_msg_handler(char *); 138 static uint_t sbbc_datapath_error_msg_handler(char *arg); 139 static uint_t sbbc_datapath_fault_msg_handler(char *arg); 140 static uint_t sbbc_dp_trans_event(char *arg); 141 142 143 /* 144 * Interrupt handlers 145 */ 146 static int sbbc_mbox_msgin(void); 147 static int sbbc_mbox_msgout(void); 148 static int sbbc_mbox_spacein(void); 149 static int sbbc_mbox_spaceout(void); 150 151 /* 152 * ECC event mailbox message taskq and parameters 153 */ 154 static taskq_t *sbbc_ecc_mbox_taskq = NULL; 155 static int sbbc_ecc_mbox_taskq_errs = 0; 156 static int sbbc_ecc_mbox_send_errs = 0; 157 static int sbbc_ecc_mbox_inval_errs = 0; 158 static int sbbc_ecc_mbox_other_errs = 0; 159 int sbbc_ecc_mbox_err_throttle = ECC_MBOX_TASKQ_ERR_THROTTLE; 160 161 /* 162 * Called when SBBC driver is loaded 163 * Initialise global mailbox stuff, etc 164 */ 165 void 166 sbbc_mbox_init() 167 { 168 int i; 169 170 master_mbox = kmem_zalloc(sizeof (sbbc_mailbox_t), KM_NOSLEEP); 171 if (master_mbox == NULL) { 172 cmn_err(CE_PANIC, "Can't allocate memory for mailbox\n"); 173 } 174 175 /* 176 * mutex'es for the wait-lists 177 */ 178 for (i = 0; i < SBBC_MBOX_MSG_TYPES; i++) { 179 mutex_init(&master_mbox->mbox_wait_lock[i], 180 NULL, MUTEX_DEFAULT, NULL); 181 master_mbox->mbox_wait_list[i] = NULL; 182 } 183 184 for (i = 0; i < SBBC_MBOX_MSG_TYPES; i++) 185 master_mbox->intrs[i] = NULL; 186 187 /* 188 * Two mailbox channels SC -> OS , read-only 189 * OS -> SC, read/write 190 */ 191 master_mbox->mbox_in = kmem_zalloc(sizeof (sbbc_mbox_t), KM_NOSLEEP); 192 if (master_mbox->mbox_in == NULL) { 193 cmn_err(CE_PANIC, 194 "Can't allocate memory for inbound mailbox\n"); 195 } 196 197 master_mbox->mbox_out = kmem_zalloc(sizeof (sbbc_mbox_t), KM_NOSLEEP); 198 if (master_mbox->mbox_out == NULL) { 199 cmn_err(CE_PANIC, 200 "Can't allocate memory for outbound mailbox\n"); 201 } 202 203 mutex_init(&master_mbox->mbox_in->mb_lock, NULL, 204 MUTEX_DEFAULT, NULL); 205 mutex_init(&master_mbox->mbox_out->mb_lock, NULL, 206 MUTEX_DEFAULT, NULL); 207 208 /* 209 * Add PANIC_SHUTDOWN Event mutex 210 */ 211 mutex_init(&panic_hdlr_lock, NULL, MUTEX_DEFAULT, NULL); 212 213 /* Initialize datapath error message handler mutex */ 214 mutex_init(&dp_hdlr_lock, NULL, MUTEX_DEFAULT, NULL); 215 216 /* Initialize capability message handler event mutex */ 217 mutex_init(&cap_msg_hdlr_lock, NULL, MUTEX_DEFAULT, NULL); 218 219 /* 220 * NOT USED YET 221 */ 222 master_mbox->mbox_in->mb_type = 223 master_mbox->mbox_out->mb_type = 0; 224 225 cv_init(&outbox_queue, NULL, CV_DEFAULT, NULL); 226 mutex_init(&outbox_queue_lock, NULL, MUTEX_DEFAULT, NULL); 227 228 } 229 230 /* 231 * called when the SBBC driver is unloaded 232 */ 233 void 234 sbbc_mbox_fini() 235 { 236 int i; 237 int err; 238 239 /* 240 * destroy ECC event mailbox taskq 241 */ 242 if (sbbc_ecc_mbox_taskq != NULL) { 243 taskq_destroy(sbbc_ecc_mbox_taskq); 244 sbbc_ecc_mbox_taskq = NULL; 245 sbbc_ecc_mbox_taskq_errs = 0; 246 } 247 248 /* 249 * unregister interrupts 250 */ 251 (void) iosram_unreg_intr(SBBC_MAILBOX_IN); 252 (void) iosram_unreg_intr(SBBC_MAILBOX_IN); 253 (void) iosram_unreg_intr(SBBC_MAILBOX_SPACE_IN); 254 (void) iosram_unreg_intr(SBBC_MAILBOX_SPACE_OUT); 255 256 /* 257 * Remove Panic Shutdown and Datapath Error event support. 258 * 259 * NOTE: If we have not added the soft interrupt handlers for these 260 * then we know that we have not registered the event handlers either. 261 */ 262 if (panic_softintr_id != 0) { 263 ddi_remove_softintr(panic_softintr_id); 264 265 err = sbbc_mbox_unreg_intr(MBOX_EVENT_PANIC_SHUTDOWN, 266 sbbc_panic_shutdown_handler); 267 if (err != 0) { 268 cmn_err(CE_WARN, "Failed to unreg Panic Shutdown " 269 "handler. Err=%d", err); 270 } 271 } 272 if (dp_softintr_id != 0) { 273 ddi_remove_softintr(dp_softintr_id); 274 275 err = sbbc_mbox_unreg_intr(MBOX_EVENT_DP_ERROR, 276 sbbc_datapath_error_msg_handler); 277 err |= sbbc_mbox_unreg_intr(MBOX_EVENT_DP_FAULT, 278 sbbc_datapath_fault_msg_handler); 279 if (err != 0) { 280 cmn_err(CE_WARN, "Failed to unreg Datapath Error " 281 "handler. Err=%d", err); 282 } 283 } 284 285 /* 286 * destroy all its mutex'es, lists etc 287 */ 288 289 /* 290 * mutex'es for the wait-lists 291 */ 292 for (i = 0; i < SBBC_MBOX_MSG_TYPES; i++) { 293 mutex_destroy(&master_mbox->mbox_wait_lock[i]); 294 } 295 296 mutex_destroy(&master_mbox->mbox_in->mb_lock); 297 mutex_destroy(&master_mbox->mbox_out->mb_lock); 298 299 mutex_destroy(&panic_hdlr_lock); 300 mutex_destroy(&dp_hdlr_lock); 301 302 kmem_free(master_mbox->mbox_in, sizeof (sbbc_mbox_t)); 303 kmem_free(master_mbox->mbox_out, sizeof (sbbc_mbox_t)); 304 kmem_free(master_mbox, sizeof (sbbc_mailbox_t)); 305 306 cv_destroy(&outbox_queue); 307 mutex_destroy(&outbox_queue_lock); 308 309 err = sbbc_mbox_unreg_intr(INFO_MBOX, cap_ecc_msg_handler); 310 if (err != 0) { 311 cmn_err(CE_WARN, "Failed to unregister capability message " 312 "handler. Err=%d", err); 313 } 314 315 mutex_destroy(&cap_msg_hdlr_lock); 316 } 317 318 /* 319 * Update iosram_sbbc to the new softstate after a tunnel switch. 320 * Move software interrupts from the old dip to the new dip. 321 */ 322 int 323 sbbc_mbox_switch(sbbc_softstate_t *softsp) 324 { 325 sbbc_intrs_t *intr; 326 int msg_type; 327 int rc = 0; 328 int err; 329 330 if (master_mbox == NULL) 331 return (ENXIO); 332 333 ASSERT(MUTEX_HELD(&master_iosram->iosram_lock)); 334 335 for (msg_type = 0; msg_type < SBBC_MBOX_MSG_TYPES; msg_type++) { 336 337 for (intr = master_mbox->intrs[msg_type]; intr != NULL; 338 intr = intr->sbbc_intr_next) { 339 340 if (intr->sbbc_intr_id) { 341 ddi_remove_softintr(intr->sbbc_intr_id); 342 343 if (ddi_add_softintr(softsp->dip, 344 DDI_SOFTINT_HIGH, 345 &intr->sbbc_intr_id, NULL, NULL, 346 intr->sbbc_handler, intr->sbbc_arg) 347 != DDI_SUCCESS) { 348 349 cmn_err(CE_WARN, 350 "Can't add SBBC mailbox " 351 "softint for msg_type %x\n", 352 msg_type); 353 rc = ENXIO; 354 } 355 } 356 } 357 } 358 359 /* 360 * Add PANIC_SHUTDOWN Event handler 361 */ 362 if (panic_softintr_id) { 363 ddi_remove_softintr(panic_softintr_id); 364 365 err = ddi_add_softintr(softsp->dip, DDI_SOFTINT_LOW, 366 &panic_softintr_id, NULL, NULL, 367 sbbc_do_fast_shutdown, NULL); 368 369 if (err != DDI_SUCCESS) { 370 cmn_err(CE_WARN, "Failed to register Panic " 371 "Shutdown handler. Err=%d", err); 372 (void) sbbc_mbox_unreg_intr(MBOX_EVENT_PANIC_SHUTDOWN, 373 sbbc_panic_shutdown_handler); 374 rc = ENXIO; 375 } 376 377 } 378 /* 379 * Add Datapath Error Event handler 380 */ 381 if (dp_softintr_id) { 382 ddi_remove_softintr(dp_softintr_id); 383 384 err = ddi_add_softintr(softsp->dip, DDI_SOFTINT_LOW, 385 &dp_softintr_id, NULL, NULL, 386 sbbc_dp_trans_event, NULL); 387 388 if (err != DDI_SUCCESS) { 389 cmn_err(CE_WARN, "Failed to register Datapath " 390 "Error Event handler. Err=%d", err); 391 (void) sbbc_mbox_unreg_intr(MBOX_EVENT_DP_ERROR, 392 sbbc_datapath_error_msg_handler); 393 (void) sbbc_mbox_unreg_intr(MBOX_EVENT_DP_FAULT, 394 sbbc_datapath_fault_msg_handler); 395 rc = ENXIO; 396 } 397 398 } 399 400 return (rc); 401 } 402 403 /* 404 * Called when the IOSRAM tunnel is created for the 'chosen' node. 405 * 406 * Read the mailbox header from the IOSRAM 407 * tunnel[SBBC_MAILBOX_KEY] 408 * Register the mailbox interrupt handlers 409 * for messages in/space etc 410 */ 411 int 412 sbbc_mbox_create(sbbc_softstate_t *softsp) 413 { 414 struct sbbc_mbox_header header; 415 416 int i; 417 int err; 418 int rc = 0; 419 420 /* 421 * This function should only be called once when 422 * the chosen node is initialized. 423 */ 424 ASSERT(MUTEX_HELD(&chosen_lock)); 425 426 if (master_mbox == NULL) 427 return (ENXIO); 428 429 /* 430 * read the header at offset 0 431 * check magic/version etc 432 */ 433 if (rc = iosram_read(SBBC_MAILBOX_KEY, 0, (caddr_t)&header, 434 sizeof (struct sbbc_mbox_header))) { 435 436 return (rc); 437 } 438 439 /* 440 * add the interrupt handlers for the mailbox 441 * interrupts 442 */ 443 for (i = 0; i < MBOX_INTRS; i++) { 444 sbbc_intrfunc_t intr_handler; 445 uint_t *state; 446 kmutex_t *lock; 447 uint32_t intr_num; 448 449 switch (i) { 450 case MBOX_MSGIN_INTR: 451 intr_handler = (sbbc_intrfunc_t)sbbc_mbox_msgin; 452 intr_num = SBBC_MAILBOX_IN; 453 break; 454 case MBOX_MSGOUT_INTR: 455 intr_handler = (sbbc_intrfunc_t)sbbc_mbox_msgout; 456 intr_num = SBBC_MAILBOX_OUT; 457 break; 458 case MBOX_SPACEIN_INTR: 459 intr_handler = (sbbc_intrfunc_t)sbbc_mbox_spacein; 460 intr_num = SBBC_MAILBOX_SPACE_IN; 461 break; 462 case MBOX_SPACEOUT_INTR: 463 intr_handler = (sbbc_intrfunc_t)sbbc_mbox_spaceout; 464 intr_num = SBBC_MAILBOX_SPACE_OUT; 465 break; 466 } 467 state = (uint_t *)&master_mbox->intr_state[i].mbox_intr_state; 468 lock = &master_mbox->intr_state[i].mbox_intr_lock; 469 if (iosram_reg_intr(intr_num, intr_handler, (caddr_t)NULL, 470 state, lock)) { 471 472 cmn_err(CE_WARN, 473 "Can't register Mailbox interrupts \n"); 474 } 475 } 476 477 /* 478 * Add PANIC_SHUTDOWN Event handler 479 */ 480 panic_payload_msg.msg_buf = (caddr_t)&panic_payload; 481 panic_payload_msg.msg_len = sizeof (panic_payload); 482 483 err = ddi_add_softintr(softsp->dip, DDI_SOFTINT_LOW, &panic_softintr_id, 484 NULL, NULL, sbbc_do_fast_shutdown, NULL); 485 486 if (err == DDI_SUCCESS) { 487 err = sbbc_mbox_reg_intr(MBOX_EVENT_PANIC_SHUTDOWN, 488 sbbc_panic_shutdown_handler, &panic_payload_msg, 489 NULL, &panic_hdlr_lock); 490 if (err != 0) { 491 cmn_err(CE_WARN, "Failed to register Panic " 492 "Shutdown handler. Err=%d", err); 493 } 494 495 } else { 496 cmn_err(CE_WARN, "Failed to add Panic Shutdown " 497 "softintr handler"); 498 } 499 500 /* 501 * Add Unsolicited Datapath Error Events handler 502 */ 503 dp_payload_msg.msg_buf = (caddr_t)&dp_payload; 504 dp_payload_msg.msg_len = sizeof (dp_payload); 505 506 err = ddi_add_softintr(softsp->dip, DDI_SOFTINT_LOW, &dp_softintr_id, 507 NULL, NULL, sbbc_dp_trans_event, NULL); 508 509 if (err == DDI_SUCCESS) { 510 err = sbbc_mbox_reg_intr(MBOX_EVENT_DP_ERROR, 511 sbbc_datapath_error_msg_handler, &dp_payload_msg, 512 NULL, &dp_hdlr_lock); 513 err |= sbbc_mbox_reg_intr(MBOX_EVENT_DP_FAULT, 514 sbbc_datapath_fault_msg_handler, &dp_payload_msg, 515 NULL, &dp_hdlr_lock); 516 if (err != 0) { 517 cmn_err(CE_WARN, "Failed to register Datapath " 518 "error handler. Err=%d", err); 519 } 520 521 } else { 522 cmn_err(CE_WARN, "Failed to add Datapath error " 523 "softintr handler"); 524 } 525 526 /* 527 * Register an interrupt handler with the sgbbc driver for the 528 * unsolicited INFO_MBOX response for the capability bitmap. 529 * This message is expected whenever the SC is (re)booted or 530 * failed over. 531 */ 532 cap_payload_msg.msg_buf = (caddr_t)&cap_payload; 533 cap_payload_msg.msg_len = sizeof (cap_payload); 534 535 err = sbbc_mbox_reg_intr(INFO_MBOX, cap_ecc_msg_handler, 536 &cap_payload_msg, NULL, &cap_msg_hdlr_lock); 537 if (err != 0) { 538 cmn_err(CE_WARN, "Failed to register capability message" 539 " handler with Err=%d", err); 540 } 541 542 /* 543 * Now is the opportunity to register 544 * the deferred mbox intrs. 545 */ 546 sbbc_mbox_post_reg(softsp); 547 548 return (rc); 549 } 550 551 /* 552 * Called when chosen IOSRAM is initialized 553 * to register the deferred mbox intrs. 554 */ 555 static void 556 sbbc_mbox_post_reg(sbbc_softstate_t *softsp) 557 { 558 uint32_t msg_type; 559 sbbc_intrs_t *intr; 560 561 ASSERT(master_mbox); 562 for (msg_type = 0; msg_type < SBBC_MBOX_MSG_TYPES; msg_type++) { 563 intr = master_mbox->intrs[msg_type]; 564 while (intr != NULL) { 565 if (!intr->registered) { 566 SGSBBC_DBG_INTR(CE_CONT, "sbbc_mbox_post_reg: " 567 "postreg for msgtype=%x\n", msg_type); 568 if (ddi_add_softintr(softsp->dip, 569 DDI_SOFTINT_HIGH, &intr->sbbc_intr_id, 570 NULL, NULL, intr->sbbc_handler, 571 (caddr_t)intr->sbbc_arg) 572 != DDI_SUCCESS) { 573 cmn_err(CE_WARN, "Can't add SBBC " 574 "deferred mailbox softint \n"); 575 } else 576 intr->registered = 1; 577 } 578 intr = intr->sbbc_intr_next; 579 } 580 } 581 } 582 583 /* 584 * Register a handler for a message type 585 * NB NB NB 586 * arg must be either NULL or the address of a sbbc_fragment 587 * pointer 588 */ 589 int 590 sbbc_mbox_reg_intr(uint32_t msg_type, sbbc_intrfunc_t intr_handler, 591 sbbc_msg_t *arg, uint_t *state, kmutex_t *lock) 592 { 593 sbbc_intrs_t *intr, *previntr; 594 int rc = 0; 595 596 /* 597 * Validate arguments 598 */ 599 if (msg_type >= SBBC_MBOX_MSG_TYPES) 600 return (EINVAL); 601 602 /* 603 * Verify that we have already set up the master sbbc 604 */ 605 if (master_iosram == NULL || master_mbox == NULL) 606 return (ENXIO); 607 608 mutex_enter(&master_iosram->iosram_lock); 609 msg_type &= SBBC_MSG_TYPE_MASK; 610 previntr = intr = master_mbox->intrs[msg_type]; 611 612 /* Find the end of the link list */ 613 while (intr != NULL && intr->sbbc_handler != intr_handler) { 614 615 previntr = intr; 616 intr = intr->sbbc_intr_next; 617 } 618 619 /* Return if the handler has been registered */ 620 if (intr != NULL) { 621 mutex_exit(&master_iosram->iosram_lock); 622 return (EBUSY); 623 } 624 625 /* 626 * The requested handler has not been installed. 627 * Allocate some memory. 628 */ 629 intr = kmem_zalloc(sizeof (sbbc_intrs_t), KM_SLEEP); 630 631 intr->sbbc_handler = intr_handler; 632 intr->sbbc_arg = (caddr_t)arg; 633 intr->sbbc_intr_state = state; 634 intr->sbbc_intr_lock = lock; 635 intr->sbbc_intr_next = NULL; 636 /* not registered yet */ 637 intr->registered = 0; 638 639 if (previntr != NULL) 640 previntr->sbbc_intr_next = intr; 641 else 642 master_mbox->intrs[msg_type] = intr; 643 644 /* 645 * register only if the chosen IOSRAM is 646 * initialized, otherwise defer the registration 647 * until IOSRAM initialization. 648 */ 649 if (master_iosram->iosram_sbbc) { 650 if (ddi_add_softintr(master_iosram->iosram_sbbc->dip, 651 DDI_SOFTINT_HIGH, 652 &intr->sbbc_intr_id, NULL, NULL, 653 intr_handler, (caddr_t)arg) != DDI_SUCCESS) { 654 cmn_err(CE_WARN, "Can't add SBBC mailbox softint \n"); 655 rc = ENXIO; 656 } else 657 intr->registered = 1; 658 } else { 659 SGSBBC_DBG_INTR(CE_CONT, "sbbc_mbox_reg_intr: " 660 "deferring msg=%x registration\n", msg_type); 661 } 662 663 mutex_exit(&master_iosram->iosram_lock); 664 665 return (rc); 666 } 667 668 /* 669 * Unregister a handler for a message type 670 */ 671 int 672 sbbc_mbox_unreg_intr(uint32_t msg_type, sbbc_intrfunc_t intr_handler) 673 { 674 sbbc_intrs_t *intr, *previntr, *nextintr; 675 676 /* 677 * Verify that we have already set up the master sbbc 678 */ 679 if (master_iosram == NULL || master_mbox == NULL) 680 return (ENXIO); 681 682 msg_type &= SBBC_MSG_TYPE_MASK; 683 684 if (msg_type >= SBBC_MBOX_MSG_TYPES || 685 intr_handler == (sbbc_intrfunc_t)NULL) { 686 687 return (EINVAL); 688 } 689 690 mutex_enter(&master_iosram->iosram_lock); 691 692 previntr = intr = master_mbox->intrs[msg_type]; 693 694 /* 695 * No handlers installed 696 */ 697 if (intr == NULL) { 698 mutex_exit(&master_iosram->iosram_lock); 699 return (EINVAL); 700 } 701 702 while (intr != NULL) { 703 704 /* Save the next pointer */ 705 nextintr = intr->sbbc_intr_next; 706 707 /* Found a match. Remove it from the link list */ 708 if (intr->sbbc_handler == intr_handler) { 709 710 if (intr->sbbc_intr_id) 711 ddi_remove_softintr(intr->sbbc_intr_id); 712 713 kmem_free(intr, sizeof (sbbc_intrs_t)); 714 715 if (previntr != master_mbox->intrs[msg_type]) 716 previntr->sbbc_intr_next = nextintr; 717 else 718 master_mbox->intrs[msg_type] = nextintr; 719 720 break; 721 } 722 723 /* update pointers */ 724 previntr = intr; 725 intr = nextintr; 726 } 727 728 mutex_exit(&master_iosram->iosram_lock); 729 730 return (0); 731 } 732 /* 733 * Interrupt handlers - one for each mailbox 734 * interrupt type 735 */ 736 737 /* 738 * mailbox message received 739 */ 740 static int 741 sbbc_mbox_msgin() 742 { 743 mutex_enter(&master_mbox->intr_state[MBOX_MSGIN_INTR].mbox_intr_lock); 744 master_mbox->intr_state[MBOX_MSGIN_INTR].mbox_intr_state = 745 SBBC_INTR_RUNNING; 746 mutex_exit(&master_mbox->intr_state[MBOX_MSGIN_INTR].mbox_intr_lock); 747 748 /* 749 * We are only locking the InBox here, not the whole 750 * mailbox. This is based on the assumption of 751 * complete separation of mailboxes - outbox is 752 * read/write, inbox is read-only. 753 * We only ever update the producer for the 754 * outbox and the consumer for the inbox. 755 */ 756 mutex_enter(&master_mbox->mbox_in->mb_lock); 757 758 for (;;) { 759 /* 760 * Get as many incoming messages as possible 761 */ 762 while (sbbc_mbox_recv_msg() == 0) 763 /* empty */; 764 765 /* 766 * send interrupt to SC to let it know that 767 * space is available over here 768 */ 769 (void) iosram_send_intr(SBBC_MAILBOX_SPACE_IN); 770 771 mutex_enter(&master_mbox->intr_state[MBOX_MSGIN_INTR]. 772 mbox_intr_lock); 773 /* 774 * Read the inbox one more time to see if new messages 775 * has come in after we exit the loop. 776 */ 777 if (sbbc_mbox_recv_msg() == 0) { 778 mutex_exit(&master_mbox->intr_state[MBOX_MSGIN_INTR]. 779 mbox_intr_lock); 780 } else { 781 master_mbox->intr_state[MBOX_MSGIN_INTR]. 782 mbox_intr_state = SBBC_INTR_IDLE; 783 mutex_exit(&master_mbox->intr_state[MBOX_MSGIN_INTR]. 784 mbox_intr_lock); 785 break; 786 } 787 } 788 789 mutex_exit(&master_mbox->mbox_in->mb_lock); 790 791 return (DDI_INTR_CLAIMED); 792 } 793 794 /* 795 * mailbox message sent 796 */ 797 static int 798 sbbc_mbox_msgout() 799 { 800 /* 801 * Should never get this 802 */ 803 804 return (DDI_INTR_CLAIMED); 805 } 806 807 /* 808 * space in the inbox 809 */ 810 static int 811 sbbc_mbox_spacein() 812 { 813 /* 814 * Should never get this 815 */ 816 817 return (DDI_INTR_CLAIMED); 818 } 819 820 /* 821 * space in the outbox 822 */ 823 static int 824 sbbc_mbox_spaceout() 825 { 826 /* 827 * cv_broadcast() the threads waiting on the 828 * outbox's mb_full 829 */ 830 831 mutex_enter(&master_mbox->mbox_out->mb_lock); 832 833 cv_broadcast(&master_mbox->mbox_out->mb_full); 834 835 mutex_exit(&master_mbox->mbox_out->mb_lock); 836 837 return (DDI_INTR_CLAIMED); 838 } 839 840 /* 841 * Client Interface 842 * 843 * The main interface will be 844 * 845 * sbbc_mbox_request_response(sbbc_msg_t *request, 846 * sbbc_msg_t *response, time_t wait_time) 847 * 848 * 1) the client calls request_response 849 * 2) a new unique msg ID is assigned for that msg 850 * 3) if there is space available in the outbox 851 * - the request msg is written to the mbox_out mailbox 852 * and the mailbox info updated. 853 * - allocate a sbbc_msg_waiter struct for this 854 * message, initialise the w_cv condvar. 855 * - get the mailbox mbox_wait_lock mutex for this 856 * message type 857 * - the response msg is put on the mbox_wait_list for 858 * that message type to await the SC's response 859 * - wait on the w_cv condvar protected by the 860 * mbox_wait_lock 861 * - SBBC_MAILBOX_OUT interrupt is sent to the SC 862 * 863 * 4) if no space in the outbox, 864 * - the request message blocks waiting 865 * for a SBBC_MAILBOX_SPACE_OUT interrupt 866 * It will block on the mailbox mb_full condvar. 867 * - go to (3) above 868 * 5) When we get a SBBC_MAILBOX_IN interrupt. 869 * - read the message ID of the next message (FIFO) 870 * - find that ID on the wait list 871 * - no wait list entry => unsolicited message. If theres 872 * a handler, trigger it 873 * - if someone is waiting, read the message in from 874 * SRAM, handling fragmentation, wraparound, etc 875 * - if the whole message has been read, signal 876 * the waiter 877 * - read next message until mailbox empty 878 * - send SBBC_MAILBOX_SPACE_IN interrupt to the SC 879 * 880 * 6) If a response is required and none is received, the client 881 * will timeout after <wait_time> seconds and the message 882 * status will be set to ETIMEDOUT. 883 */ 884 int 885 sbbc_mbox_request_response(sbbc_msg_t *request, 886 sbbc_msg_t *response, time_t wait_time) 887 { 888 889 struct sbbc_msg_waiter *waiter; 890 uint_t msg_id; 891 int rc = 0; 892 int flags; 893 uint16_t msg_type; 894 clock_t stop_time; 895 clock_t clockleft; 896 kmutex_t *mbox_wait_lock; 897 kmutex_t *mb_lock; 898 static fn_t f = "sbbc_mbox_request_response"; 899 900 if ((request == NULL) || 901 (request->msg_type.type >= SBBC_MBOX_MSG_TYPES) || 902 ((response != NULL) && 903 (response->msg_type.type >= SBBC_MBOX_MSG_TYPES))) 904 return (EINVAL); 905 906 msg_type = request->msg_type.type; 907 908 /* 909 * Verify that we have already set up the master sbbc 910 */ 911 if (master_mbox == NULL) 912 return (ENXIO); 913 mbox_wait_lock = &master_mbox->mbox_wait_lock[msg_type]; 914 915 flags = WAIT_FOR_REPLY|WAIT_FOR_SPACE; 916 917 /* 918 * We want to place a lower limit on the shortest amount of time we 919 * will wait before timing out while communicating with the SC via 920 * the mailbox. 921 */ 922 if (wait_time < sbbc_mbox_min_timeout) 923 wait_time = sbbc_mbox_default_timeout; 924 925 stop_time = ddi_get_lbolt() + wait_time * drv_usectohz(MICROSEC); 926 927 /* 928 * If there is a message being processed, sleep until it is our turn. 929 */ 930 mutex_enter(&outbox_queue_lock); 931 932 /* 933 * allocate an ID for this message, let it wrap 934 * around transparently. 935 * msg_id == 0 is unsolicited message 936 */ 937 msg_id = ++(master_mbox->mbox_msg_id); 938 if (msg_id == 0) 939 msg_id = ++(master_mbox->mbox_msg_id); 940 941 SGSBBC_DBG_MBOX("%s: msg_id = 0x%x, msg_len = 0x%x\n", 942 f, msg_id, request->msg_len); 943 944 /* 945 * A new message can actually grab the lock before the thread 946 * that has just been signaled. Therefore, we need to double 947 * check to make sure that outbox_busy is not already set 948 * after we wake up. 949 * 950 * Potentially this could mean starvation for certain unfortunate 951 * threads that keep getting woken up and putting back to sleep. 952 * But the window of such contention is very small to begin with. 953 */ 954 while (outbox_busy) { 955 956 clockleft = cv_timedwait(&outbox_queue, &outbox_queue_lock, 957 stop_time); 958 959 SGSBBC_DBG_MBOX("%s: msg_id = 0x%x is woken up\n", f, msg_id); 960 961 /* 962 * If we have timed out, set status to ETIMEOUT and return. 963 */ 964 if (clockleft < 0) { 965 SGSBBC_DBG_MBOX("%s: msg_id = 0x%x has timed out\n", 966 f, msg_id); 967 cmn_err(CE_NOTE, 968 "Timed out obtaining SBBC outbox lock"); 969 request->msg_status = ETIMEDOUT; 970 if (response != NULL) 971 response->msg_status = ETIMEDOUT; 972 mutex_exit(&outbox_queue_lock); 973 return (ETIMEDOUT); 974 } 975 } 976 977 outbox_busy = 1; 978 mutex_exit(&outbox_queue_lock); 979 980 /* 981 * We are only locking the OutBox from here, not the whole 982 * mailbox. This is based on the assumption of 983 * complete separation of mailboxes - outbox is 984 * read/write, inbox is read-only. 985 * We only ever update the producer for the 986 * outbox and the consumer for the inbox. 987 */ 988 mb_lock = &master_mbox->mbox_out->mb_lock; 989 mutex_enter(mb_lock); 990 991 /* 992 * No response expected ? Just send the message and return 993 */ 994 if (response == NULL) { 995 rc = sbbc_mbox_send_msg(request, flags, msg_id, wait_time, 996 stop_time); 997 SGSBBC_DBG_MBOX("%s: msg_id = 0x%x send rc = %d\n", 998 f, msg_id, rc); 999 1000 wakeup_next(); 1001 1002 mutex_exit(mb_lock); 1003 request->msg_status = rc; 1004 return (rc); 1005 } 1006 1007 /* 1008 * allocate/initialise a waiter 1009 */ 1010 waiter = kmem_zalloc(sizeof (struct sbbc_msg_waiter), KM_NOSLEEP); 1011 1012 if (waiter == (struct sbbc_msg_waiter *)NULL) { 1013 cmn_err(CE_WARN, "SBBC Mailbox can't allocate waiter\n"); 1014 1015 wakeup_next(); 1016 1017 mutex_exit(mb_lock); 1018 return (ENOMEM); 1019 } 1020 1021 waiter->w_id = 0; /* Until we get an ID from the send */ 1022 waiter->w_msg = response; 1023 waiter->w_msg->msg_status = EINPROGRESS; 1024 1025 cv_init(&waiter->w_cv, NULL, CV_DEFAULT, NULL); 1026 1027 rc = sbbc_mbox_send_msg(request, flags, msg_id, wait_time, stop_time); 1028 1029 wakeup_next(); 1030 1031 if (rc != 0) { 1032 1033 request->msg_status = response->msg_status = rc; 1034 mutex_exit(mb_lock); 1035 1036 /* Free the waiter */ 1037 cv_destroy(&waiter->w_cv); 1038 kmem_free(waiter, sizeof (struct sbbc_msg_waiter)); 1039 1040 SGSBBC_DBG_MBOX("%s: msg_id = 0x%x send rc = %d\n", 1041 f, msg_id, rc); 1042 1043 return (rc); 1044 } 1045 1046 waiter->w_id = msg_id; 1047 1048 /* 1049 * Lock this waiter list and add the waiter 1050 */ 1051 mutex_enter(mbox_wait_lock); 1052 1053 if (master_mbox->mbox_wait_list[msg_type] == NULL) { 1054 master_mbox->mbox_wait_list[msg_type] = waiter; 1055 waiter->w_next = NULL; 1056 } else { 1057 struct sbbc_msg_waiter *tmp; 1058 tmp = master_mbox->mbox_wait_list[msg_type]; 1059 master_mbox->mbox_wait_list[msg_type] = waiter; 1060 waiter->w_next = tmp; 1061 } 1062 1063 mutex_exit(mb_lock); 1064 1065 /* 1066 * wait here for a response to our message 1067 * holding the mbox_wait_lock for the list ensures 1068 * that the interrupt handler can't get in before 1069 * we block. 1070 * NOTE: We use the request msg_type for the 1071 * the wait_list. This ensures that the 1072 * msg_type won't change. 1073 */ 1074 clockleft = cv_timedwait(&waiter->w_cv, mbox_wait_lock, stop_time); 1075 1076 SGSBBC_DBG_MBOX("%s: msg_id = 0x%x is woken up for response\n", 1077 f, msg_id); 1078 1079 /* 1080 * If we have timed out, set msg_status to ETIMEDOUT, 1081 * and remove the waiter from the waiter list. 1082 */ 1083 if (clockleft < 0) { 1084 /* 1085 * Remove the waiter from the waiter list. 1086 * If we can't find the waiter in the list, 1087 * 1. msg_status == EINPROGRESS 1088 * It is being processed. We will give it 1089 * a chance to finish. 1090 * 2. msg_status != EINPROGRESS 1091 * It is done processing. We can safely 1092 * remove it. 1093 * If we can find the waiter, it has timed out. 1094 */ 1095 SGSBBC_DBG_MBOX("%s: msg_id = 0x%x has timed out\n", 1096 f, msg_id); 1097 if (mbox_find_waiter(msg_type, msg_id) == NULL) { 1098 if (waiter->w_msg->msg_status == EINPROGRESS) { 1099 SGSBBC_DBG_MBOX("%s: Waiting for msg_id = 0x%x " 1100 "complete.\n", f, msg_id); 1101 cv_wait(&waiter->w_cv, mbox_wait_lock); 1102 } 1103 } else { 1104 SGSBBC_DBG_MBOX("%s: setting msg_id = 0x%x " 1105 "to ETIMEDOUT\n", f, msg_id); 1106 cmn_err(CE_NOTE, "Timed out waiting for SC response"); 1107 rc = waiter->w_msg->msg_status = ETIMEDOUT; 1108 } 1109 } 1110 1111 /* 1112 * lose the waiter 1113 */ 1114 cv_destroy(&waiter->w_cv); 1115 kmem_free(waiter, sizeof (struct sbbc_msg_waiter)); 1116 1117 mutex_exit(mbox_wait_lock); 1118 1119 return (rc); 1120 1121 } 1122 1123 static void 1124 wakeup_next() 1125 { 1126 /* 1127 * Done sending the current message or encounter an error. 1128 * Wake up the one request in the outbox_queue. 1129 */ 1130 mutex_enter(&outbox_queue_lock); 1131 outbox_busy = 0; 1132 cv_signal(&outbox_queue); 1133 mutex_exit(&outbox_queue_lock); 1134 } 1135 1136 1137 /* ARGSUSED */ 1138 int 1139 sbbc_mbox_send_msg(sbbc_msg_t *msg, int flags, uint_t msg_id, 1140 time_t wait_time, clock_t stop_time) 1141 { 1142 struct sbbc_mbox_header header; 1143 struct sbbc_fragment frag; 1144 int rc = 0; 1145 int bytes_written; 1146 uint32_t intr_enabled; 1147 clock_t clockleft; 1148 static fn_t f = "sbbc_mbox_send_msg"; 1149 1150 /* 1151 * First check that the SC has enabled its mailbox 1152 */ 1153 rc = iosram_read(SBBC_INTR_SC_ENABLED_KEY, 0, 1154 (caddr_t)&intr_enabled, sizeof (intr_enabled)); 1155 1156 if (rc) 1157 return (rc); 1158 1159 if (!(intr_enabled & SBBC_MAILBOX_OUT)) 1160 return (ENOTSUP); 1161 1162 /* 1163 * read the mailbox header 1164 */ 1165 if (rc = mbox_read_header(SBBC_OUTBOX, &header)) 1166 return (rc); 1167 1168 /* 1169 * Allocate/initialise a fragment for this message 1170 */ 1171 frag.f_id = msg_id; 1172 frag.f_type = msg->msg_type; 1173 frag.f_status = 0; 1174 frag.f_total_len = msg->msg_len; 1175 frag.f_frag_offset = 0; 1176 /* 1177 * Throw in the message data 1178 */ 1179 bcopy(&msg->msg_data, &frag.f_data, sizeof (msg->msg_data)); 1180 1181 /* 1182 * If not enough space is available 1183 * write what we can and wait for 1184 * an interrupt to tell us that more 1185 * space is available 1186 */ 1187 1188 bytes_written = 0; 1189 do { 1190 rc = mbox_write(&header, &frag, msg); 1191 1192 if (rc != 0 && rc != ENOSPC) { 1193 return (rc); 1194 } 1195 1196 if (rc == 0) { 1197 /* 1198 * Always tell the SC when there is a message. 1199 * Ignore returned value as not being able to 1200 * signal the SC about space available does 1201 * not stop the SC from processing input. 1202 */ 1203 (void) iosram_send_intr(SBBC_MAILBOX_OUT); 1204 } 1205 1206 bytes_written += frag.f_frag_len; 1207 frag.f_frag_offset += frag.f_frag_len; 1208 if ((bytes_written < msg->msg_len) || (rc == ENOSPC)) { 1209 1210 if (mbox_has_free_space(&header) <= 1211 sizeof (struct sbbc_fragment)) { 1212 1213 int tmprc; 1214 1215 clockleft = cv_timedwait( 1216 &master_mbox->mbox_out->mb_full, 1217 &master_mbox->mbox_out->mb_lock, 1218 stop_time); 1219 1220 /* Return ETIMEDOUT if we timed out */ 1221 if (clockleft < 0) { 1222 SGSBBC_DBG_MBOX("%s: msg_id = 0x%x " 1223 "has timed out\n", f, msg_id); 1224 cmn_err(CE_NOTE, 1225 "Timed out sending message " 1226 "to SC"); 1227 return (ETIMEDOUT); 1228 } 1229 1230 /* Read updated header from IOSRAM */ 1231 if (tmprc = mbox_read_header(SBBC_OUTBOX, 1232 &header)) { 1233 1234 return (tmprc); 1235 } 1236 } 1237 } 1238 1239 SGSBBC_DBG_MBOX("%s: msg_id = 0x%x, bytes_written = 0x%x, " 1240 "msg_len = 0x%x\n", f, 1241 msg_id, bytes_written, msg->msg_len); 1242 } while ((bytes_written < msg->msg_len) || (rc == ENOSPC)); 1243 1244 /* 1245 * this could be a spurious interrupt 1246 * as the SC may be merrily readings its 1247 * mail even as send, but what can you do ? No 1248 * synchronization method between SC <-> OS 1249 * SRAM data eaters means that this is inevitable. 1250 * It would take a bigger brain to fix this. 1251 * 1252 */ 1253 (void) iosram_send_intr(SBBC_MAILBOX_OUT); 1254 1255 return (rc); 1256 } 1257 1258 1259 /* 1260 * get next message 1261 * Read the next message from SRAM 1262 * Check if theres an entry on the wait queue 1263 * for this message 1264 * If yes, read the message in and signal 1265 * the waiter (if all the message has been received) 1266 * No, its unsolicited, if theres a handler installed for 1267 * this message type trigger it, otherwise toss 1268 * the message 1269 */ 1270 int 1271 sbbc_mbox_recv_msg() 1272 { 1273 struct sbbc_mbox_header header; 1274 struct sbbc_fragment frag; 1275 sbbc_msg_t tmpmsg; /* Temporary msg storage */ 1276 int rc = 0, i, first_hdlr, last_hdlr; 1277 uint32_t intr_enabled; 1278 sbbc_intrs_t *intr; 1279 struct sbbc_msg_waiter *waiter; 1280 uint16_t type; /* frag.f_type.type */ 1281 uint32_t f_id; /* frag.f_id */ 1282 uint32_t f_frag_offset, f_frag_len; 1283 kmutex_t *mbox_wait_lock; 1284 static fn_t f = "sbbc_mbox_recv_msg"; 1285 1286 /* 1287 * First check that the OS has enabled its mailbox 1288 */ 1289 rc = iosram_read(SBBC_SC_INTR_ENABLED_KEY, 0, 1290 (caddr_t)&intr_enabled, sizeof (intr_enabled)); 1291 1292 if (rc) { 1293 return (rc); 1294 } 1295 1296 if (!(intr_enabled & SBBC_MAILBOX_IN)) 1297 return (ENOTSUP); 1298 1299 /* 1300 * read the mailbox header 1301 */ 1302 if (rc = mbox_read_header(SBBC_INBOX, &header)) 1303 return (rc); 1304 1305 /* 1306 * check if any messages available. If 1307 * consumer == producer then no more 1308 * messages 1309 */ 1310 if ((header.mailboxes[SBBC_INBOX].mbox_consumer == 1311 header.mailboxes[SBBC_INBOX].mbox_producer)) { 1312 1313 return (-1); 1314 } 1315 1316 /* 1317 * read the fragment header for this message 1318 */ 1319 if (rc = mbox_read_frag(&header, &frag)) { 1320 1321 return (rc); 1322 } 1323 1324 /* Save to local variable for easy reading */ 1325 type = frag.f_type.type; 1326 f_id = frag.f_id; 1327 1328 SGSBBC_DBG_MBOX("%s: f_id = 0x%x\n", f, f_id); 1329 1330 /* 1331 * check the message type. If its invalid, we will 1332 * just toss the message 1333 */ 1334 if (type >= SBBC_MBOX_MSG_TYPES) { 1335 goto done; 1336 } 1337 1338 /* 1339 * if theres no waiters for this message type, and theres 1340 * no message handler installed, toss it. 1341 * 1342 * Unsolicited messages (f_id == 0) are tricky because we won't know 1343 * when the handler has finished so that we can 1344 * remove the message, so, given the small brains in operation 1345 * here, what we do is restrict junk mail to zero-length 1346 * messages, then we allocate a fragment using kmem, 1347 * make a copy of the fragment in this memory, 1348 * pass this pointer to the fragment, then skip the message. 1349 * So even if there is data associated with the junkmail, 1350 * the message handler doesn't get to see it 1351 * We expect the mesaage handler to free the memory. 1352 */ 1353 if (type == SBBC_BROADCAST_MSG) { 1354 /* 1355 * Broadcast message, trigger all handlers 1356 */ 1357 first_hdlr = 0; 1358 last_hdlr = SBBC_MBOX_MSG_TYPES - 1; 1359 } else if ((master_mbox->mbox_wait_list[type] == NULL) || (f_id == 0)) { 1360 /* 1361 * Theres no waiters, or its unsolicited anyway 1362 */ 1363 first_hdlr = last_hdlr = type; 1364 } else { 1365 /* 1366 * check the fragment message type, look at the wait list for 1367 * that type to find its associated message 1368 * 1369 * First find the message. If we get it, take it off 1370 * the waiter list and read the data. We will 1371 * put it back on the list if necessary. 1372 * This avoids the problem of a second message-in 1373 * interrupt playing with this waiter. 1374 * This will cut down on mutex spinning on the wait 1375 * list locks, also, expect the next fragment to be 1376 * for this messageso we might as well have it at the 1377 * start of the list. 1378 * 1379 * its possible that a return message has a different type, 1380 * (possible but not recommended!). So, if we don't find 1381 * it on the list pointed to by the request type, 1382 * go look at all the other lists 1383 */ 1384 1385 mbox_wait_lock = &master_mbox->mbox_wait_lock[type]; 1386 1387 mutex_enter(mbox_wait_lock); 1388 if ((waiter = mbox_find_waiter(type, f_id)) == NULL) { 1389 for (i = 0; i < SBBC_MBOX_MSG_TYPES; i++) { 1390 if (i == type) 1391 continue; 1392 if ((waiter = mbox_find_waiter(i, f_id)) 1393 != NULL) 1394 break; 1395 } 1396 } 1397 mutex_exit(mbox_wait_lock); 1398 1399 if (waiter == NULL) { 1400 rc = -1; 1401 /* 1402 * there's no waiter for this message, but that 1403 * could mean that this message is the start of 1404 * a send/receive to us, and every 'first' request 1405 * must by definition be unsolicited, 1406 * so trigger the handler 1407 */ 1408 first_hdlr = last_hdlr = type; 1409 } else { 1410 SGSBBC_DBG_MBOX("%s: f_id = 0x%x, msg_id = 0x%x, " 1411 "msg_len = 0x%x\n", 1412 f, f_id, waiter->w_id, 1413 waiter->w_msg->msg_len); 1414 1415 rc = mbox_read(&header, &frag, waiter->w_msg); 1416 1417 SGSBBC_DBG_MBOX("%s: f_id = 0x%x, offset = 0x%x, " 1418 "len = 0x%x, total_len = 0x%x\n", 1419 f, frag.f_id, frag.f_frag_offset, 1420 frag.f_frag_len, frag.f_total_len); 1421 1422 if (rc || ((frag.f_frag_offset + frag.f_frag_len) == 1423 frag.f_total_len)) { 1424 /* 1425 * failed or all the message has been read in 1426 */ 1427 mutex_enter(mbox_wait_lock); 1428 waiter->w_msg->msg_status = (rc == ENOMEM)? 1429 rc : frag.f_status; 1430 SGSBBC_DBG_MBOX("%s: msg_status = %d\n", 1431 f, waiter->w_msg->msg_status); 1432 cv_signal(&waiter->w_cv); 1433 mutex_exit(mbox_wait_lock); 1434 1435 } else { 1436 /* 1437 * back on the wait list 1438 */ 1439 mutex_enter(mbox_wait_lock); 1440 if (waiter->w_msg->msg_status == ETIMEDOUT) { 1441 cv_signal(&waiter->w_cv); 1442 mutex_exit(mbox_wait_lock); 1443 goto done; 1444 } 1445 1446 if (master_mbox->mbox_wait_list[type] == NULL) { 1447 master_mbox->mbox_wait_list[type] = 1448 waiter; 1449 waiter->w_next = NULL; 1450 } else { 1451 struct sbbc_msg_waiter *tmp; 1452 tmp = master_mbox->mbox_wait_list[type]; 1453 master_mbox->mbox_wait_list[type] = 1454 waiter; 1455 waiter->w_next = tmp; 1456 } 1457 mutex_exit(mbox_wait_lock); 1458 } 1459 goto done; 1460 } 1461 } 1462 1463 /* 1464 * Set msg_len to f_frag_len so msg_buf will be large enough 1465 * to contain what is in the fragment. 1466 */ 1467 f_frag_len = tmpmsg.msg_len = frag.f_frag_len; 1468 /* 1469 * Save the f_frag_offset for copying into client's space. 1470 * Set frag.f_frag_offset to 0 so we don't have to allocate 1471 * too much space for reading in the message. 1472 */ 1473 f_frag_offset = frag.f_frag_offset; 1474 frag.f_frag_offset = 0; 1475 1476 /* Allocate space for msg_buf */ 1477 if (f_frag_len != 0 && (tmpmsg.msg_buf = 1478 kmem_alloc(f_frag_len, KM_NOSLEEP)) == NULL) { 1479 1480 rc = ENOMEM; 1481 cmn_err(CE_WARN, "Can't allocate memory" 1482 " for unsolicited messages\n"); 1483 } else { 1484 /* Save the incoming message in tmpmsg */ 1485 rc = mbox_read(&header, &frag, &tmpmsg); 1486 1487 for (i = first_hdlr; rc == 0 && i <= last_hdlr; i++) { 1488 1489 intr = master_mbox->intrs[i]; 1490 if ((intr == NULL) || (intr->sbbc_intr_id == 0)) { 1491 continue; 1492 } 1493 1494 while (intr != NULL) { 1495 /* 1496 * If the client has allocated enough space 1497 * for incoming message, copy into the 1498 * client buffer. 1499 */ 1500 sbbc_msg_t *arg = (sbbc_msg_t *)intr->sbbc_arg; 1501 if (arg != (void *)NULL) { 1502 if (arg->msg_len >= frag.f_total_len) { 1503 if (f_frag_len > 0) 1504 bcopy(tmpmsg.msg_buf, 1505 arg->msg_buf + 1506 f_frag_offset, 1507 f_frag_len); 1508 } else { 1509 arg->msg_status = ENOMEM; 1510 } 1511 } 1512 1513 /* 1514 * Only trigger the interrupt when we 1515 * have received the whole message. 1516 */ 1517 if (f_frag_offset + f_frag_len == 1518 frag.f_total_len) { 1519 1520 ddi_trigger_softintr( 1521 intr->sbbc_intr_id); 1522 } 1523 intr = intr->sbbc_intr_next; 1524 } 1525 } 1526 1527 if (f_frag_len != 0) { 1528 /* Don't forget to free the buffer */ 1529 kmem_free(tmpmsg.msg_buf, f_frag_len); 1530 } 1531 } 1532 done: 1533 mbox_skip_next_msg(&header); 1534 return (rc); 1535 } 1536 1537 /* 1538 * available free space in the outbox 1539 */ 1540 static int 1541 mbox_has_free_space(struct sbbc_mbox_header *header) 1542 { 1543 uint32_t space = 0; 1544 1545 ASSERT(MUTEX_HELD(&master_mbox->mbox_out->mb_lock)); 1546 1547 if (header->mailboxes[SBBC_OUTBOX].mbox_producer == 1548 header->mailboxes[SBBC_OUTBOX].mbox_consumer) { 1549 /* 1550 * mailbox is empty 1551 */ 1552 space += header->mailboxes[SBBC_OUTBOX].mbox_len - 1553 header->mailboxes[SBBC_OUTBOX].mbox_producer; 1554 space += 1555 header->mailboxes[SBBC_OUTBOX].mbox_producer; 1556 } else if (header->mailboxes[SBBC_OUTBOX].mbox_producer > 1557 header->mailboxes[SBBC_OUTBOX].mbox_consumer) { 1558 space += header->mailboxes[SBBC_OUTBOX].mbox_len - 1559 header->mailboxes[SBBC_OUTBOX].mbox_producer; 1560 space += header->mailboxes[SBBC_OUTBOX].mbox_consumer; 1561 } else { 1562 /* 1563 * mailbox wrapped around 1564 */ 1565 space += header->mailboxes[SBBC_OUTBOX].mbox_consumer - 1566 header->mailboxes[SBBC_OUTBOX].mbox_producer; 1567 } 1568 1569 /* 1570 * Need to make sure that the mailbox never 1571 * gets completely full, as consumer == producer is 1572 * our test for empty, so we drop MBOX_ALIGN_BYTES. 1573 */ 1574 1575 if (space >= MBOX_ALIGN_BYTES) 1576 space -= MBOX_ALIGN_BYTES; 1577 else 1578 space = 0; 1579 1580 return (space); 1581 1582 } 1583 /* 1584 * Write the data to IOSRAM 1585 * Update the SRAM mailbox header 1586 * Update the local mailbox pointers 1587 * Only write a single fragment. If possible, 1588 * put the whole message into a fragment. 1589 * 1590 * Note: We assume that there is no 'max' message 1591 * size. We will just keep fragmenting. 1592 * Note: We always write to SBBC_OUTBOX and 1593 * read from SBBC_INBOX 1594 * 1595 * If we get an error at any time, return immediately 1596 * without updating the mailbox header in SRAM 1597 */ 1598 static int 1599 mbox_write(struct sbbc_mbox_header *header, 1600 struct sbbc_fragment *frag, sbbc_msg_t *msg) 1601 { 1602 int bytes_written, bytes_remaining, free_space; 1603 int rc = 0; 1604 caddr_t src; 1605 uint32_t sram_dst; 1606 int space_at_end, space_at_start; 1607 uint32_t mbox_offset, mbox_len; 1608 uint32_t mbox_producer, mbox_consumer; 1609 uint32_t f_total_len, f_frag_offset; 1610 uint32_t frag_header_size; 1611 static fn_t f = "mbox_write"; 1612 1613 ASSERT(MUTEX_HELD(&master_mbox->mbox_out->mb_lock)); 1614 1615 /* 1616 * Save to local variables to make code more readable 1617 */ 1618 mbox_offset = header->mailboxes[SBBC_OUTBOX].mbox_offset; 1619 mbox_len = header->mailboxes[SBBC_OUTBOX].mbox_len; 1620 mbox_producer = header->mailboxes[SBBC_OUTBOX].mbox_producer; 1621 mbox_consumer = header->mailboxes[SBBC_OUTBOX].mbox_consumer; 1622 f_total_len = frag->f_total_len; 1623 f_frag_offset = frag->f_frag_offset; 1624 frag_header_size = sizeof (struct sbbc_fragment); 1625 1626 SGSBBC_DBG_MBOX("%s: mbox_consumer = 0x%x, " 1627 "mbox_producer = 0x%x\n", f, mbox_consumer, mbox_producer); 1628 1629 /* 1630 * Write pointer in SRAM 1631 */ 1632 sram_dst = mbox_offset + mbox_producer; 1633 1634 /* 1635 * NB We assume that the consumer stays constant 1636 * during the write. It may not necessarily 1637 * be the case but it won't cause us any problems, just means 1638 * we fragment more than is absolutely necessary 1639 * 1640 * possible cases 1641 * 1) consumer == producer, mailbox empty 1642 * space_at_end == mailbox end - producer 1643 * space_at_start == producer - MBOX_ALIGN_BYTES 1644 * 2) producer < consumer 1645 * space_at_end = (consumer - producer - MBOX_ALIGN_BYTES) 1646 * space_at_start == 0 1647 * 3) producer > consumer 1648 * space_at_end = mailbox end - producer 1649 * space_at_start = consumer - MBOX_ALIGN_BYTES 1650 * 1651 * (space - MBOX_ALIGN_BYTES) because we need to avoid the 1652 * scenario where the producer wraps around completely and 1653 * producer == consumer, as this is our test for 'empty'. 1654 * Also we want it to be 8-byte aligned. 1655 * Note: start is assumed = 0 1656 */ 1657 if (mbox_producer < mbox_consumer) { 1658 space_at_end = mbox_consumer - mbox_producer - MBOX_ALIGN_BYTES; 1659 if (space_at_end < 0) 1660 space_at_end = 0; 1661 space_at_start = 0; 1662 } else { 1663 space_at_end = mbox_len - mbox_producer; 1664 if (mbox_consumer == 0) 1665 space_at_end -= MBOX_ALIGN_BYTES; 1666 space_at_start = mbox_consumer - MBOX_ALIGN_BYTES; 1667 if (space_at_start < 0) 1668 space_at_start = 0; 1669 } 1670 1671 SGSBBC_DBG_MBOX("%s: space_at_end = 0x%x, space_at_start = 0x%x\n", 1672 f, space_at_end, space_at_start); 1673 1674 free_space = space_at_end + space_at_start; 1675 1676 if (free_space < frag_header_size) { 1677 /* 1678 * can't even write a fragment header, so just return 1679 * the caller will block waiting for space 1680 */ 1681 frag->f_frag_len = 0; 1682 return (ENOSPC); 1683 } 1684 1685 /* 1686 * How many bytes will be in the fragment ? 1687 */ 1688 bytes_remaining = f_total_len - f_frag_offset; 1689 frag->f_frag_len = min(bytes_remaining, free_space - frag_header_size); 1690 1691 SGSBBC_DBG_MBOX("%s: writing header:sram_dst = 0x%x\n", 1692 f, sram_dst); 1693 1694 /* 1695 * we can write the fragment header and some data 1696 * First, the fragment header 1697 */ 1698 if (space_at_end >= frag_header_size) { 1699 rc = iosram_write(SBBC_MAILBOX_KEY, sram_dst, (caddr_t)frag, 1700 frag_header_size); 1701 if (rc) 1702 return (rc); 1703 1704 sram_dst = (uint32_t)(sram_dst + frag_header_size); 1705 /* 1706 * Wrap around if we reach the end 1707 */ 1708 if (sram_dst >= (mbox_len + mbox_offset)) { 1709 sram_dst = mbox_offset; 1710 } 1711 space_at_end -= frag_header_size; 1712 } else { 1713 /* wraparound */ 1714 if (space_at_end) { 1715 rc = iosram_write(SBBC_MAILBOX_KEY, sram_dst, 1716 (caddr_t)frag, space_at_end); 1717 if (rc) 1718 return (rc); 1719 sram_dst = (uint32_t)mbox_offset; 1720 } 1721 rc = iosram_write(SBBC_MAILBOX_KEY, sram_dst, 1722 (caddr_t)((caddr_t)frag + space_at_end), 1723 (frag_header_size - space_at_end)); 1724 if (rc) 1725 return (rc); 1726 sram_dst += frag_header_size - space_at_end; 1727 space_at_start -= (frag_header_size - space_at_end); 1728 space_at_end = 0; 1729 } 1730 1731 SGSBBC_DBG_MBOX("%s: space_at_end = 0x%x, space_at_start = 0x%x\n", 1732 f, space_at_end, space_at_start); 1733 1734 /* 1735 * Now the fragment data 1736 */ 1737 free_space -= frag_header_size; 1738 src = (caddr_t)(msg->msg_buf + f_frag_offset); 1739 bytes_written = 0; 1740 if (space_at_end) { 1741 SGSBBC_DBG_MBOX("%s: writing data:sram_dst = 0x%x, " 1742 "bytes_remaining = 0x%x\n", 1743 f, sram_dst, bytes_remaining); 1744 1745 if (space_at_end < bytes_remaining) 1746 bytes_written = space_at_end; 1747 else 1748 bytes_written = bytes_remaining; 1749 rc = iosram_write(SBBC_MAILBOX_KEY, sram_dst, src, 1750 bytes_written); 1751 if (rc) 1752 return (rc); 1753 1754 sram_dst = (uint32_t)(sram_dst + bytes_written); 1755 /* 1756 * Wrap around if we reach the end 1757 */ 1758 if (sram_dst >= (mbox_len + mbox_offset)) { 1759 sram_dst = mbox_offset; 1760 } 1761 src = (caddr_t)(src + bytes_written); 1762 bytes_remaining -= bytes_written; 1763 } 1764 1765 if ((bytes_remaining > 0) && space_at_start) { 1766 SGSBBC_DBG_MBOX("%s: writing the rest:sram_dst = 0x%x, " 1767 "bytes_remaining = 0x%x\n", 1768 f, sram_dst, bytes_remaining); 1769 if (space_at_start < bytes_remaining) { 1770 rc = iosram_write(SBBC_MAILBOX_KEY, sram_dst, src, 1771 space_at_start); 1772 bytes_written += space_at_start; 1773 } else { 1774 rc = iosram_write(SBBC_MAILBOX_KEY, sram_dst, src, 1775 bytes_remaining); 1776 bytes_written += bytes_remaining; 1777 } 1778 if (rc) 1779 return (rc); 1780 } 1781 1782 frag->f_frag_len = bytes_written; 1783 1784 /* 1785 * update header->mbox_producer (bytes_written + frag_size) 1786 */ 1787 sram_dst = mbox_producer + bytes_written + frag_header_size; 1788 if (sram_dst >= mbox_len) { 1789 sram_dst = sram_dst % mbox_len; 1790 } 1791 1792 SGSBBC_DBG_MBOX("%s: after writing data:sram_dst = 0x%x, " 1793 "bytes_written = 0x%x\n", f, sram_dst, bytes_written); 1794 1795 header->mailboxes[SBBC_OUTBOX].mbox_producer = sram_dst; 1796 1797 mbox_update_header(SBBC_OUTBOX, header); 1798 1799 1800 return (rc); 1801 } 1802 1803 1804 /* 1805 * Get the next frag from IOSRAM. 1806 * Write it to the corresponding msg buf. 1807 * The caller must update the SRAM pointers etc. 1808 */ 1809 static int 1810 mbox_read(struct sbbc_mbox_header *header, 1811 struct sbbc_fragment *frag, sbbc_msg_t *msg) 1812 { 1813 int rc = 0; 1814 uint32_t sram_src, sram_end; 1815 caddr_t msg_buf; 1816 int bytes_at_start, bytes_at_end; 1817 int bytes_to_read; 1818 uint32_t frag_header_size, frag_total_size; 1819 uint32_t f_frag_offset, f_frag_len; 1820 uint32_t mbox_producer, mbox_consumer; 1821 uint32_t mbox_len, mbox_offset; 1822 static fn_t f = "mbox_read"; 1823 1824 ASSERT(MUTEX_HELD(&master_mbox->mbox_in->mb_lock)); 1825 1826 /* 1827 * Save to local variables to make code more readable 1828 */ 1829 mbox_producer = header->mailboxes[SBBC_INBOX].mbox_producer; 1830 mbox_consumer = header->mailboxes[SBBC_INBOX].mbox_consumer; 1831 mbox_len = header->mailboxes[SBBC_INBOX].mbox_len; 1832 mbox_offset = header->mailboxes[SBBC_INBOX].mbox_offset; 1833 frag_header_size = sizeof (struct sbbc_fragment); 1834 f_frag_offset = frag->f_frag_offset; 1835 f_frag_len = frag->f_frag_len; 1836 frag_total_size = frag_header_size + f_frag_len; 1837 1838 /* 1839 * If the message buffer size is smaller than the fragment 1840 * size, return an error. 1841 */ 1842 if (msg->msg_len < f_frag_len) { 1843 rc = ENOMEM; 1844 goto done; 1845 } 1846 1847 msg_buf = (caddr_t)(msg->msg_buf + f_frag_offset); 1848 1849 /* 1850 * Throw in the message data 1851 */ 1852 bcopy(&frag->f_data, &msg->msg_data, sizeof (msg->msg_data)); 1853 1854 /* 1855 * We have it all, waiter, message, so lets 1856 * go get that puppy! 1857 * Message could be in one or two chunks - 1858 * consumer < producer: 1 chunk, (producer - consumer) 1859 * consumer > producer: 2 chunks, (end - consumer) 1860 * (producer - start) 1861 */ 1862 sram_end = (uint32_t)(mbox_offset + mbox_len); 1863 sram_src = (uint32_t)(mbox_offset + mbox_consumer + frag_header_size); 1864 1865 /* 1866 * wraparound 1867 */ 1868 if (sram_src >= sram_end) 1869 sram_src -= mbox_len; 1870 1871 /* 1872 * find where the data is 1873 * possible cases 1874 * 1) consumer == producer, mailbox empty 1875 * error 1876 * 2) producer < consumer 1877 * bytes_at_end = mailbox end - consumer 1878 * bytes_at_start = producer 1879 * 3) producer > consumer 1880 * bytes_at_end = producer - consumer 1881 * bytes_at_start = 0 1882 */ 1883 1884 SGSBBC_DBG_MBOX("%s: mbox_consumer = 0x%x, mbox_producer = 0x%x, " 1885 "frag_len = 0x%x\n", 1886 f, mbox_consumer, mbox_producer, f_frag_len); 1887 1888 if (mbox_producer == mbox_consumer) { 1889 bytes_at_end = bytes_at_start = 0; 1890 } else if (mbox_producer < mbox_consumer) { 1891 bytes_at_end = mbox_len - mbox_consumer; 1892 bytes_at_start = mbox_producer; 1893 } else { 1894 bytes_at_end = mbox_producer - mbox_consumer; 1895 bytes_at_start = 0; 1896 } 1897 1898 SGSBBC_DBG_MBOX("%s: bytes_at_end = 0x%x, " 1899 "bytes_at_start = 0x%x\n", f, bytes_at_end, bytes_at_start); 1900 1901 if ((bytes_at_end + bytes_at_start) < frag_total_size) { 1902 1903 /* 1904 * mailbox is corrupt 1905 * but what to do ? 1906 */ 1907 cmn_err(CE_PANIC, "Corrupt INBOX!\n" 1908 "producer = %x, consumer = %x, bytes_at_start = %x, " 1909 "bytes_at_end = %x\n", mbox_producer, mbox_consumer, 1910 bytes_at_start, bytes_at_end); 1911 } 1912 1913 /* 1914 * If bytes_at_end is greater than header size, read the 1915 * part at the end of the mailbox, and then update the 1916 * pointers and bytes_to_read. 1917 */ 1918 if (bytes_at_end > frag_header_size) { 1919 /* 1920 * We are only interested in the data segment. 1921 */ 1922 bytes_at_end -= frag_header_size; 1923 bytes_to_read = (bytes_at_end >= f_frag_len)? 1924 f_frag_len : bytes_at_end; 1925 SGSBBC_DBG_MBOX("%s: reading data: sram_src = 0x%x, " 1926 "bytes_to_read = 0x%x\n", f, sram_src, bytes_to_read); 1927 rc = iosram_read(SBBC_MAILBOX_KEY, sram_src, msg_buf, 1928 bytes_to_read); 1929 if (rc) { 1930 goto done; 1931 } 1932 1933 /* 1934 * Update pointers in SRAM and message buffer. 1935 */ 1936 sram_src = (uint32_t)mbox_offset; 1937 msg_buf = (caddr_t)(msg_buf + bytes_to_read); 1938 bytes_to_read = f_frag_len - bytes_to_read; 1939 } else { 1940 bytes_to_read = f_frag_len; 1941 } 1942 1943 /* 1944 * wraparound to start of mailbox 1945 */ 1946 if (bytes_to_read > 0) { 1947 SGSBBC_DBG_MBOX("%s: reading the rest: sram_src = 0x%x, " 1948 "bytes_to_read = 0x%x\n", f, sram_src, bytes_to_read); 1949 rc = iosram_read(SBBC_MAILBOX_KEY, sram_src, msg_buf, 1950 bytes_to_read); 1951 } 1952 1953 done: 1954 msg->msg_bytes += f_frag_len; 1955 1956 return (rc); 1957 } 1958 1959 /* 1960 * move past the next message in the inbox 1961 */ 1962 static void 1963 mbox_skip_next_msg(struct sbbc_mbox_header *header) 1964 { 1965 struct sbbc_fragment frag; 1966 uint32_t next_msg; 1967 1968 ASSERT(MUTEX_HELD(&master_mbox->mbox_in->mb_lock)); 1969 1970 if (mbox_read_frag(header, &frag)) { 1971 cmn_err(CE_PANIC, "INBOX is Corrupt !\n"); 1972 } 1973 1974 /* 1975 * Move on to the next message 1976 */ 1977 next_msg = header->mailboxes[SBBC_INBOX].mbox_consumer; 1978 next_msg += sizeof (struct sbbc_fragment); 1979 next_msg += frag.f_frag_len; 1980 if (next_msg >= header->mailboxes[SBBC_INBOX].mbox_len) { 1981 next_msg = (next_msg + 1982 header->mailboxes[SBBC_INBOX].mbox_len) % 1983 header->mailboxes[SBBC_INBOX].mbox_len; 1984 } 1985 header->mailboxes[SBBC_INBOX].mbox_consumer = 1986 next_msg; 1987 1988 mbox_update_header(SBBC_INBOX, header); 1989 1990 return; 1991 1992 } 1993 1994 static struct sbbc_msg_waiter * 1995 mbox_find_waiter(uint16_t msg_type, uint32_t msg_id) 1996 { 1997 struct sbbc_msg_waiter *waiter, *prev; 1998 1999 prev = NULL; 2000 for (waiter = master_mbox->mbox_wait_list[msg_type]; 2001 waiter != NULL; waiter = waiter->w_next) { 2002 2003 if (waiter->w_id == msg_id) { 2004 if (prev != NULL) { 2005 prev->w_next = waiter->w_next; 2006 } else { 2007 master_mbox->mbox_wait_list[msg_type] = 2008 waiter->w_next; 2009 } 2010 break; 2011 } 2012 prev = waiter; 2013 } 2014 2015 return (waiter); 2016 } 2017 2018 static int 2019 mbox_read_header(uint32_t mailbox, struct sbbc_mbox_header *header) 2020 { 2021 struct sbbc_mbox_header *hd; 2022 uint32_t offset; 2023 int rc; 2024 2025 /* 2026 * Initialize a sbbc_mbox_header pointer to 0 so that we 2027 * can use it to calculate the offsets of fields inside 2028 * the structure. 2029 */ 2030 hd = (struct sbbc_mbox_header *)0; 2031 2032 if (rc = iosram_read(SBBC_MAILBOX_KEY, 0, (caddr_t)header, 2033 sizeof (struct sbbc_mbox_header))) 2034 return (rc); 2035 2036 /* 2037 * Since the header is read in a byte-by-byte fashion 2038 * using ddi_rep_get8, we need to re-read the producer 2039 * or consumer pointer as integer in case it has changed 2040 * after part of the previous value has been read. 2041 */ 2042 switch (mailbox) { 2043 2044 case SBBC_INBOX: 2045 offset = (uint32_t)(uintptr_t) 2046 (&hd->mailboxes[SBBC_INBOX].mbox_producer); 2047 rc = iosram_read(SBBC_MAILBOX_KEY, offset, 2048 (caddr_t)&header->mailboxes[SBBC_INBOX].mbox_producer, 2049 sizeof (uint32_t)); 2050 break; 2051 case SBBC_OUTBOX: 2052 offset = (uint32_t)(uintptr_t) 2053 (&hd->mailboxes[SBBC_OUTBOX].mbox_consumer); 2054 rc = iosram_read(SBBC_MAILBOX_KEY, offset, 2055 (caddr_t)&header->mailboxes[SBBC_OUTBOX].mbox_consumer, 2056 sizeof (uint32_t)); 2057 break; 2058 default: 2059 cmn_err(CE_PANIC, "Invalid Mbox header type\n"); 2060 break; 2061 2062 } 2063 2064 return (rc); 2065 } 2066 2067 /* 2068 * There are only two fields updated by the domain, 2069 * the inbox consumer field and the outbox producer 2070 * field. These fields are protected by the respective 2071 * mbox_{in|out}->mb_lock so that accesses will 2072 * be serialised. The only coherency issue is writing 2073 * back the header, so we do it here after grabbing 2074 * the global mailbox lock. 2075 */ 2076 static void 2077 mbox_update_header(uint32_t mailbox, struct sbbc_mbox_header *header) 2078 { 2079 struct sbbc_mbox_header *hd; 2080 uint32_t value, offset, mbox_len; 2081 2082 /* 2083 * Initialize a sbbc_mbox_header pointer to 0 so that we 2084 * can use it to calculate the offsets of fields inside 2085 * the structure. 2086 */ 2087 hd = (struct sbbc_mbox_header *)0; 2088 2089 switch (mailbox) { 2090 2091 case SBBC_INBOX: 2092 value = header->mailboxes[SBBC_INBOX].mbox_consumer; 2093 offset = (uint32_t)(uintptr_t) 2094 (&hd->mailboxes[SBBC_INBOX].mbox_consumer); 2095 2096 mbox_len = header->mailboxes[SBBC_INBOX].mbox_len; 2097 break; 2098 case SBBC_OUTBOX: 2099 value = header->mailboxes[SBBC_OUTBOX].mbox_producer; 2100 offset = (uint32_t)(uintptr_t) 2101 (&hd->mailboxes[SBBC_OUTBOX].mbox_producer); 2102 mbox_len = header->mailboxes[SBBC_OUTBOX].mbox_len; 2103 break; 2104 default: 2105 cmn_err(CE_PANIC, "Invalid Mbox header type\n"); 2106 break; 2107 2108 } 2109 2110 /* 2111 * If the last read/write would cause the next read/write 2112 * to be unaligned, we skip on modulo MBOX_ALIGN_BYTES. 2113 * This is OK because all the mailbox handlers will 2114 * conform to this. 2115 */ 2116 if (value % MBOX_ALIGN_BYTES) { 2117 value += (MBOX_ALIGN_BYTES - (value % MBOX_ALIGN_BYTES)); 2118 value %= mbox_len; 2119 } 2120 2121 if (iosram_write(SBBC_MAILBOX_KEY, offset, (caddr_t)&value, 2122 sizeof (uint32_t))) { 2123 cmn_err(CE_PANIC, "Mailbox Corrupt ! \n"); 2124 } 2125 2126 /* 2127 * Update internal pointers so they won't be out of sync with 2128 * the values in IOSRAM. 2129 */ 2130 switch (mailbox) { 2131 2132 case SBBC_INBOX: 2133 header->mailboxes[SBBC_INBOX].mbox_consumer = value; 2134 break; 2135 case SBBC_OUTBOX: 2136 header->mailboxes[SBBC_OUTBOX].mbox_producer = value; 2137 break; 2138 } 2139 } 2140 2141 static int 2142 mbox_read_frag(struct sbbc_mbox_header *header, 2143 struct sbbc_fragment *frag) 2144 { 2145 int rc = 0; 2146 uint32_t sram_src, bytes; 2147 caddr_t dst; 2148 2149 ASSERT(MUTEX_HELD(&master_mbox->mbox_in->mb_lock)); 2150 /* 2151 * read the fragment header for this message 2152 */ 2153 sram_src = (uint32_t)(header->mailboxes[SBBC_INBOX].mbox_offset + 2154 header->mailboxes[SBBC_INBOX].mbox_consumer); 2155 2156 /* 2157 * wraparound ? 2158 */ 2159 if ((header->mailboxes[SBBC_INBOX].mbox_consumer + 2160 sizeof (struct sbbc_fragment)) >= 2161 header->mailboxes[SBBC_INBOX].mbox_len) { 2162 2163 dst = (caddr_t)frag; 2164 bytes = header->mailboxes[SBBC_INBOX].mbox_len - 2165 header->mailboxes[SBBC_INBOX].mbox_consumer; 2166 2167 if (rc = iosram_read(SBBC_MAILBOX_KEY, sram_src, dst, bytes)) { 2168 return (rc); 2169 } 2170 2171 dst += bytes; 2172 sram_src = header->mailboxes[SBBC_INBOX].mbox_offset; 2173 bytes = (header->mailboxes[SBBC_INBOX].mbox_consumer + 2174 sizeof (struct sbbc_fragment)) % 2175 header->mailboxes[SBBC_INBOX].mbox_len; 2176 2177 if (rc = iosram_read(SBBC_MAILBOX_KEY, sram_src, 2178 dst, bytes)) { 2179 return (rc); 2180 } 2181 } else { 2182 if (rc = iosram_read(SBBC_MAILBOX_KEY, sram_src, (caddr_t)frag, 2183 sizeof (struct sbbc_fragment))) { 2184 return (rc); 2185 } 2186 } 2187 2188 return (0); 2189 } 2190 2191 2192 /* 2193 * This function is triggered by a soft interrupt and it's purpose is to call 2194 * to kadmin() to shutdown the Domain. 2195 */ 2196 /*ARGSUSED0*/ 2197 static uint_t 2198 sbbc_do_fast_shutdown(char *arg) 2199 { 2200 (void) kadmin(A_SHUTDOWN, AD_POWEROFF, NULL, kcred); 2201 2202 /* 2203 * If kadmin fails for some reason then we bring the system down 2204 * via power_down(), or failing that using halt(). 2205 */ 2206 power_down("kadmin() failed, trying power_down()"); 2207 2208 halt("power_down() failed, trying halt()"); 2209 2210 /* 2211 * We should never make it this far, so something must have gone 2212 * horribly, horribly wrong. 2213 */ 2214 /*NOTREACHED*/ 2215 return (DDI_FAILURE); 2216 } 2217 2218 2219 /* 2220 * This function handles unsolicited PANIC_SHUTDOWN events 2221 */ 2222 static uint_t 2223 sbbc_panic_shutdown_handler(char *arg) 2224 { 2225 static fn_t f = "sbbc_panic_shutdown_handler()"; 2226 2227 sg_panic_shutdown_t *payload = NULL; 2228 sbbc_msg_t *msg = NULL; 2229 2230 if (arg == NULL) { 2231 SGSBBC_DBG_EVENT(CE_NOTE, "%s: arg == NULL", f); 2232 return (DDI_INTR_UNCLAIMED); 2233 } 2234 2235 msg = (sbbc_msg_t *)arg; 2236 2237 if (msg->msg_buf == NULL) { 2238 SGSBBC_DBG_EVENT(CE_NOTE, "%s: msg_buf == NULL", f); 2239 return (DDI_INTR_UNCLAIMED); 2240 } 2241 2242 payload = (sg_panic_shutdown_t *)msg->msg_buf; 2243 2244 switch (*payload) { 2245 case SC_EVENT_PANIC_ENV: 2246 2247 /* 2248 * Let the user know why the domain is going down. 2249 */ 2250 cmn_err(CE_WARN, "%s", PANIC_ENV_EVENT_MSG); 2251 2252 /* 2253 * trigger sbbc_do_fast_shutdown(). 2254 */ 2255 ddi_trigger_softintr(panic_softintr_id); 2256 2257 /*NOTREACHED*/ 2258 break; 2259 2260 case SC_EVENT_PANIC_KEYSWITCH: 2261 /* 2262 * The SC warns a user if they try a destructive keyswitch 2263 * command on a Domain which is currently running Solaris. 2264 * If the user chooses to continue despite our best advise 2265 * then we bring down the Domain immediately without trying 2266 * to shut the system down gracefully. 2267 */ 2268 break; 2269 2270 default: 2271 SGSBBC_DBG_EVENT(CE_NOTE, "%s: Unknown payload:%d", f, 2272 *payload); 2273 return (DDI_INTR_UNCLAIMED); 2274 } 2275 2276 return (DDI_INTR_CLAIMED); 2277 } 2278 2279 /* 2280 * dp_get_cores() 2281 * 2282 * Checks cpu implementation for the input cpuid and returns 2283 * the number of cores. 2284 * If implementation cannot be determined, returns 1 2285 */ 2286 static int 2287 dp_get_cores(uint16_t cpuid) 2288 { 2289 int bd, ii, impl, nc; 2290 2291 bd = cpuid / 4; 2292 nc = SG_MAX_CPUS_PER_BD; 2293 2294 /* find first with valid implementation */ 2295 for (ii = 0; ii < nc; ii++) 2296 if (cpu[MAKE_CPUID(bd, ii)]) { 2297 impl = cpunodes[MAKE_CPUID(bd, ii)].implementation; 2298 break; 2299 } 2300 2301 if (IS_JAGUAR(impl) || IS_PANTHER(impl)) 2302 return (2); 2303 else 2304 return (1); 2305 } 2306 2307 /* 2308 * dp_payload_add_cpus() 2309 * 2310 * From datapath mailbox message, determines the number of and safari IDs 2311 * for affected cpus, then adds this info to the datapath ereport. 2312 * 2313 */ 2314 static int 2315 dp_payload_add_cpus(plat_datapath_info_t *dpmsg, nvlist_t *erp) 2316 { 2317 int jj = 0, numcpus = 0; 2318 int bd, procpos, ii, num, ncores, ret; 2319 uint16_t *dparray, cpuid; 2320 uint64_t *snarray; 2321 2322 /* check for multiple core architectures */ 2323 ncores = dp_get_cores(dpmsg->cpuid); 2324 2325 switch (dpmsg->type) { 2326 case DP_CDS_TYPE: 2327 numcpus = ncores; 2328 break; 2329 2330 case DP_DX_TYPE: 2331 numcpus = 2 * ncores; 2332 break; 2333 2334 case DP_RP_TYPE: 2335 numcpus = SG_MAX_CPUS_PER_BD; 2336 break; 2337 2338 default: 2339 ASSERT(0); 2340 return (-1); 2341 } 2342 2343 num = numcpus; 2344 2345 /* 2346 * populate dparray with impacted cores (only those present) 2347 */ 2348 dparray = kmem_zalloc(num * sizeof (uint16_t *), KM_SLEEP); 2349 bd = SG_PORTID_TO_BOARD_NUM(SG_CPUID_TO_PORTID(dpmsg->cpuid)); 2350 procpos = SG_CPUID_TO_PORTID(dpmsg->cpuid) & 0x3; 2351 2352 mutex_enter(&cpu_lock); 2353 2354 switch (dpmsg->type) { 2355 2356 case DP_CDS_TYPE: 2357 /* 2358 * For a CDS error, it's the reporting cpuid 2359 * and it's other core (if present) 2360 */ 2361 cpuid = dpmsg->cpuid & 0x1FF; /* core 0 */ 2362 if (cpu[cpuid]) 2363 dparray[jj++] = cpuid; 2364 2365 cpuid = dpmsg->cpuid | SG_CORE_ID_MASK; /* core 1 */ 2366 if (cpu[cpuid]) 2367 dparray[jj++] = cpuid; 2368 break; 2369 2370 case DP_DX_TYPE: 2371 /* 2372 * For a DX error, it's the reporting cpuid (all 2373 * cores) and the other CPU sharing the same 2374 * DX<-->DCDS interface (all cores) 2375 */ 2376 2377 /* reporting cpuid */ 2378 cpuid = dpmsg->cpuid & 0x1FF; /* core 0 */ 2379 if (cpu[cpuid]) 2380 dparray[jj++] = cpuid; 2381 2382 cpuid = dpmsg->cpuid | SG_CORE_ID_MASK; /* core 1 */ 2383 if (cpu[cpuid]) 2384 dparray[jj++] = cpuid; 2385 2386 /* find partner cpuid */ 2387 if (procpos == 0 || procpos == 2) 2388 cpuid = dpmsg->cpuid + 1; 2389 else 2390 cpuid = dpmsg->cpuid - 1; 2391 2392 /* add partner cpuid */ 2393 cpuid &= 0x1FF; /* core 0 */ 2394 if (cpu[cpuid]) 2395 dparray[jj++] = cpuid; 2396 2397 cpuid |= SG_CORE_ID_MASK; /* core 1 */ 2398 if (cpu[cpuid]) 2399 dparray[jj++] = cpuid; 2400 break; 2401 2402 case DP_RP_TYPE: 2403 /* 2404 * For a RP error, it's all cpuids (all cores) on 2405 * the reporting board 2406 */ 2407 for (ii = 0; ii < SG_MAX_CMPS_PER_BD; ii++) { 2408 cpuid = MAKE_CPUID(bd, ii); 2409 if (cpu[cpuid]) /* core 0 */ 2410 dparray[jj++] = cpuid; 2411 cpuid |= SG_CORE_ID_MASK; 2412 if (cpu[cpuid]) /* core 1 */ 2413 dparray[jj++] = cpuid; 2414 } 2415 break; 2416 } 2417 2418 mutex_exit(&cpu_lock); 2419 2420 /* 2421 * The datapath message could not be associated with any 2422 * configured CPU. 2423 */ 2424 if (!jj) { 2425 kmem_free(dparray, num * sizeof (uint16_t *)); 2426 ret = nvlist_add_uint32(erp, DP_LIST_SIZE, jj); 2427 ASSERT(ret == 0); 2428 return (-1); 2429 } 2430 2431 snarray = kmem_zalloc(jj * sizeof (uint64_t), KM_SLEEP); 2432 for (ii = 0; ii < jj; ii++) 2433 snarray[ii] = cpunodes[dparray[ii]].device_id; 2434 2435 ret = nvlist_add_uint32(erp, DP_LIST_SIZE, jj); 2436 ret |= nvlist_add_uint16_array(erp, DP_LIST, dparray, jj); 2437 ret |= nvlist_add_uint64_array(erp, SN_LIST, snarray, jj); 2438 ASSERT(ret == 0); 2439 2440 kmem_free(dparray, num * sizeof (uint16_t *)); 2441 kmem_free(snarray, jj * sizeof (uint64_t *)); 2442 2443 return (0); 2444 } 2445 2446 /* 2447 * sbbc_dp_trans_event() - datapath message handler. 2448 * 2449 * Process datapath error and fault messages received from the SC. Checks 2450 * for, and disregards, messages associated with I/O boards. Otherwise, 2451 * extracts message info to produce a datapath ereport. 2452 */ 2453 /*ARGSUSED*/ 2454 static uint_t 2455 sbbc_dp_trans_event(char *arg) 2456 { 2457 const char *f = "sbbc_dp_trans_event()"; 2458 nvlist_t *erp, *detector, *hcelem; 2459 char buf[FM_MAX_CLASS]; 2460 int board; 2461 plat_datapath_info_t *dpmsg; 2462 sbbc_msg_t *msg; 2463 int msgtype; 2464 2465 /* set i/f message and payload pointers */ 2466 msg = &dp_payload_msg; 2467 dpmsg = &dp_payload; 2468 msgtype = msg->msg_type.type; 2469 2470 cmn_err(CE_NOTE, "%s: msgtype=0x%x\n", f, msgtype); 2471 cmn_err(CE_NOTE, "type=0x%x cpuid=0x%x t_value=0x%x\n", dpmsg->type, 2472 dpmsg->cpuid, dpmsg->t_value); 2473 2474 /* check for valid type */ 2475 if (dpmsg->type > DP_RP_TYPE) { 2476 cmn_err(CE_WARN, "%s: dpmsg type 0x%x invalid\n", 2477 f, dpmsg->type); 2478 return (DDI_INTR_CLAIMED); 2479 } 2480 2481 /* check for I/O board message - Schizo AIDs are 25 - 30 */ 2482 if (dpmsg->cpuid > 23) { 2483 cmn_err(CE_NOTE, "%s: ignore I/O board msg\n", f); 2484 return (DDI_INTR_CLAIMED); 2485 } 2486 2487 /* allocate space for ereport */ 2488 erp = fm_nvlist_create(NULL); 2489 2490 /* 2491 * Member Name Data Type Comments 2492 * ----------- --------- ----------- 2493 * version uint8 0 2494 * class string "asic" 2495 * ENA uint64 ENA Format 1 2496 * detector fmri aggregated ID data for SC-DE 2497 * 2498 * Datapath ereport subclasses and data payloads: 2499 * There will be two types of ereports (error and fault) which will be 2500 * identified by the "type" member. 2501 * 2502 * ereport.asic.serengeti.cds.cds-dp 2503 * ereport.asic.serengeti.dx.dx-dp (board) 2504 * ereport.asic.serengeti.rp.rp-dp (centerplane) 2505 * 2506 * Member Name Data Type Comments 2507 * ----------- --------- ----------- 2508 * erptype uint16 derived from message type: error or 2509 * fault 2510 * t-value uint32 SC's datapath SERD timeout threshold 2511 * dp-list-sz uint8 number of dp-list array elements 2512 * dp-list array of uint16 Safari IDs of affected cpus 2513 * sn-list array of uint64 Serial numbers of affected cpus 2514 */ 2515 2516 /* compose common ereport elements */ 2517 detector = fm_nvlist_create(NULL); 2518 2519 /* 2520 * Create legacy FMRI for the detector 2521 */ 2522 board = SG_PORTID_TO_BOARD_NUM(SG_CPUID_TO_PORTID(dpmsg->cpuid)); 2523 switch (dpmsg->type) { 2524 case DP_CDS_TYPE: 2525 case DP_DX_TYPE: 2526 (void) snprintf(buf, FM_MAX_CLASS, "SB%d", board); 2527 break; 2528 case DP_RP_TYPE: 2529 (void) snprintf(buf, FM_MAX_CLASS, "RP"); 2530 break; 2531 default: 2532 (void) snprintf(buf, FM_MAX_CLASS, "UNKNOWN"); 2533 break; 2534 } 2535 2536 hcelem = fm_nvlist_create(NULL); 2537 2538 (void) nvlist_add_string(hcelem, FM_FMRI_HC_NAME, FM_FMRI_LEGACY_HC); 2539 (void) nvlist_add_string(hcelem, FM_FMRI_HC_ID, buf); 2540 2541 (void) nvlist_add_uint8(detector, FM_VERSION, FM_HC_SCHEME_VERSION); 2542 (void) nvlist_add_string(detector, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC); 2543 (void) nvlist_add_string(detector, FM_FMRI_HC_ROOT, ""); 2544 (void) nvlist_add_uint32(detector, FM_FMRI_HC_LIST_SZ, 1); 2545 (void) nvlist_add_nvlist_array(detector, FM_FMRI_HC_LIST, &hcelem, 1); 2546 2547 /* build ereport class name */ 2548 (void) snprintf(buf, FM_MAX_CLASS, "asic.serengeti.%s.%s-%s", 2549 dperrtype[dpmsg->type], dperrtype[dpmsg->type], 2550 FM_ERROR_DATAPATH); 2551 2552 fm_ereport_set(erp, FM_EREPORT_VERSION, buf, 2553 fm_ena_generate(0, FM_ENA_FMT1), detector, NULL); 2554 2555 /* add payload elements */ 2556 if (msgtype == MBOX_EVENT_DP_ERROR) 2557 fm_payload_set(erp, 2558 DP_EREPORT_TYPE, DATA_TYPE_UINT16, DP_ERROR, NULL); 2559 else 2560 fm_payload_set(erp, 2561 DP_EREPORT_TYPE, DATA_TYPE_UINT16, DP_FAULT, NULL); 2562 2563 fm_payload_set(erp, DP_TVALUE, DATA_TYPE_UINT32, dpmsg->t_value, NULL); 2564 2565 dp_payload_add_cpus(dpmsg, erp); 2566 2567 /* post ereport */ 2568 fm_ereport_post(erp, EVCH_SLEEP); 2569 2570 /* free ereport memory */ 2571 fm_nvlist_destroy(erp, FM_NVA_FREE); 2572 fm_nvlist_destroy(detector, FM_NVA_FREE); 2573 2574 return (DDI_INTR_CLAIMED); 2575 } 2576 2577 static uint_t 2578 sbbc_datapath_error_msg_handler(char *arg) 2579 { 2580 static fn_t f = "sbbc_datapath_error_msg_handler()"; 2581 sbbc_msg_t *msg = NULL; 2582 2583 if (arg == NULL) { 2584 SGSBBC_DBG_EVENT(CE_NOTE, "%s: arg == NULL", f); 2585 return (DDI_INTR_UNCLAIMED); 2586 } 2587 2588 msg = (sbbc_msg_t *)arg; 2589 2590 if (msg->msg_buf == NULL) { 2591 SGSBBC_DBG_EVENT(CE_NOTE, "%s: msg_buf == NULL", f); 2592 return (DDI_INTR_UNCLAIMED); 2593 } 2594 2595 msg->msg_type.type = MBOX_EVENT_DP_ERROR; 2596 2597 /* trigger sbbc_dp_trans_event() */ 2598 ddi_trigger_softintr(dp_softintr_id); 2599 2600 return (DDI_INTR_CLAIMED); 2601 } 2602 2603 static uint_t 2604 sbbc_datapath_fault_msg_handler(char *arg) 2605 { 2606 2607 static fn_t f = "sbbc_datapath_fault_msg_handler()"; 2608 2609 sbbc_msg_t *msg = NULL; 2610 2611 if (arg == NULL) { 2612 SGSBBC_DBG_EVENT(CE_NOTE, "%s: arg == NULL", f); 2613 return (DDI_INTR_UNCLAIMED); 2614 } 2615 2616 msg = (sbbc_msg_t *)arg; 2617 2618 if (msg->msg_buf == NULL) { 2619 SGSBBC_DBG_EVENT(CE_NOTE, "%s: msg_buf == NULL", f); 2620 return (DDI_INTR_UNCLAIMED); 2621 } 2622 2623 msg->msg_type.type = MBOX_EVENT_DP_FAULT; 2624 2625 /* trigger sbbc_dp_trans_event() */ 2626 ddi_trigger_softintr(dp_softintr_id); 2627 2628 return (DDI_INTR_CLAIMED); 2629 } 2630 2631 /* 2632 * Log an ECC event message to the SC. This is called from the 2633 * sbbc_ecc_mbox_taskq or directly from plat_send_ecc_mailbox_msg 2634 * for indictment messages. 2635 */ 2636 int 2637 sbbc_mbox_ecc_output(sbbc_ecc_mbox_t *msgp) 2638 { 2639 int rv; 2640 plat_capability_data_t *cap; 2641 plat_dimm_sid_board_data_t *ddata; 2642 plat_ecc_msg_hdr_t *hdr; 2643 2644 rv = sbbc_mbox_request_response(&msgp->ecc_req, &msgp->ecc_resp, 2645 sbbc_mbox_default_timeout); 2646 2647 if (rv != 0) { 2648 /* 2649 * Indictment messages use the return value to indicate a 2650 * problem in the mailbox. For Error mailbox messages, we'll 2651 * have to use a syslog message. 2652 */ 2653 if (msgp->ecc_log_error) { 2654 if (sbbc_ecc_mbox_send_errs == 0) { 2655 cmn_err(CE_NOTE, "!Solaris failed to send a " 2656 "message (0x%x/0x%x) to the System " 2657 "Controller. Error: %d, Message Status: %d", 2658 msgp->ecc_resp.msg_type.type, 2659 msgp->ecc_resp.msg_type.sub_type, 2660 rv, msgp->ecc_resp.msg_status); 2661 } 2662 2663 if (++sbbc_ecc_mbox_send_errs >= 2664 sbbc_ecc_mbox_err_throttle) { 2665 sbbc_ecc_mbox_send_errs = 0; 2666 } 2667 } 2668 2669 } else if (msgp->ecc_resp.msg_status != 0) { 2670 if (msgp->ecc_resp.msg_type.type == INFO_MBOX) { 2671 switch (msgp->ecc_resp.msg_type.sub_type) { 2672 case INFO_MBOX_ECC: 2673 hdr = (plat_ecc_msg_hdr_t *) 2674 msgp->ecc_req.msg_buf; 2675 if (hdr->emh_msg_type == 2676 PLAT_ECC_DIMM_SID_MESSAGE) { 2677 rv = msgp->ecc_resp.msg_status; 2678 break; 2679 } 2680 /*FALLTHROUGH*/ 2681 case INFO_MBOX_ECC_CAP: 2682 /* 2683 * The positive response comes only 2684 * from the AVL FS1 updated SC. 2685 * If the firmware is either downgraded 2686 * or failover to an older version, then 2687 * lets reset the SC capability to 2688 * default. 2689 */ 2690 plat_ecc_capability_sc_set 2691 (PLAT_ECC_CAPABILITY_SC_DEFAULT); 2692 break; 2693 default: 2694 break; 2695 } 2696 } 2697 if (msgp->ecc_log_error) { 2698 if (sbbc_ecc_mbox_inval_errs == 0) { 2699 cmn_err(CE_NOTE, "!An internal error (%d) " 2700 "occurred in the System Controller while " 2701 "processing this message (0x%x/0x%x)", 2702 msgp->ecc_resp.msg_status, 2703 msgp->ecc_resp.msg_type.type, 2704 msgp->ecc_resp.msg_type.sub_type); 2705 } 2706 if (msgp->ecc_resp.msg_status == EINVAL) { 2707 if (++sbbc_ecc_mbox_inval_errs >= 2708 sbbc_ecc_mbox_err_throttle) { 2709 sbbc_ecc_mbox_inval_errs = 0; 2710 } 2711 rv = ENOMSG; 2712 } else { 2713 if (++sbbc_ecc_mbox_other_errs >= 2714 sbbc_ecc_mbox_err_throttle) { 2715 sbbc_ecc_mbox_other_errs = 0; 2716 } 2717 rv = msgp->ecc_resp.msg_status; 2718 } 2719 } 2720 2721 } else { 2722 if (msgp->ecc_resp.msg_type.type == INFO_MBOX) { 2723 switch (msgp->ecc_resp.msg_type.sub_type) { 2724 case INFO_MBOX_ECC_CAP: 2725 /* 2726 * Successfully received the response 2727 * for the capability message, so updating 2728 * the SC ECC messaging capability. 2729 */ 2730 cap = (plat_capability_data_t *) 2731 msgp->ecc_resp.msg_buf; 2732 plat_ecc_capability_sc_set 2733 (cap->capd_capability); 2734 break; 2735 2736 case INFO_MBOX_ECC: 2737 hdr = (plat_ecc_msg_hdr_t *) 2738 msgp->ecc_resp.msg_buf; 2739 if (hdr && (hdr->emh_msg_type == 2740 PLAT_ECC_DIMM_SID_MESSAGE)) { 2741 /* 2742 * Successfully received a response 2743 * to a request for DIMM serial ids. 2744 */ 2745 ddata = (plat_dimm_sid_board_data_t *) 2746 msgp->ecc_resp.msg_buf; 2747 (void) plat_store_mem_sids(ddata); 2748 } 2749 break; 2750 2751 default: 2752 break; 2753 } 2754 } 2755 } 2756 2757 if (msgp->ecc_resp.msg_buf) 2758 kmem_free((void *)msgp->ecc_resp.msg_buf, 2759 (size_t)msgp->ecc_resp.msg_len); 2760 2761 kmem_free((void *)msgp->ecc_req.msg_buf, (size_t)msgp->ecc_req.msg_len); 2762 kmem_free(msgp, sizeof (sbbc_ecc_mbox_t)); 2763 return (rv); 2764 } 2765 2766 /* 2767 * Enqueue ECC event message on taskq to SC. This is invoked from 2768 * plat_send_ecc_mailbox_msg() for each ECC event generating a message. 2769 */ 2770 void 2771 sbbc_mbox_queue_ecc_event(sbbc_ecc_mbox_t *sbbc_ecc_msgp) 2772 { 2773 /* 2774 * Create the ECC event mailbox taskq, if it does not yet exist. 2775 * This must be done here rather than in sbbc_mbox_init(). The 2776 * sgsbbc driver is loaded very early in the boot flow. Calling 2777 * taskq_create() from sbbc_mbox_init could lead to a boot deadlock. 2778 * 2779 * There might be a tiny probability that two ECC handlers on 2780 * different processors could arrive here simultaneously. If 2781 * the taskq has not been created previously, then these two 2782 * simultaneous events could cause the creation of an extra taskq. 2783 * Given the extremely small likelihood (if not outright impossibility) 2784 * of this occurrence, sbbc_ecc_mbox_taskq is not protected by a lock. 2785 */ 2786 2787 if (sbbc_ecc_mbox_taskq == NULL) { 2788 sbbc_ecc_mbox_taskq = taskq_create("ECC_event_mailbox", 1, 2789 minclsyspri, ECC_MBOX_TASKQ_MIN, ECC_MBOX_TASKQ_MAX, 2790 TASKQ_PREPOPULATE); 2791 if (sbbc_ecc_mbox_taskq == NULL) { 2792 if (sbbc_ecc_mbox_taskq_errs == 0) { 2793 cmn_err(CE_NOTE, "Unable to create mailbox " 2794 "task queue for ECC event logging to " 2795 "System Controller"); 2796 } 2797 if (++sbbc_ecc_mbox_taskq_errs >= 2798 sbbc_ecc_mbox_err_throttle) { 2799 sbbc_ecc_mbox_taskq_errs = 0; 2800 } 2801 2802 kmem_free((void *)sbbc_ecc_msgp->ecc_req.msg_buf, 2803 (size_t)sbbc_ecc_msgp->ecc_req.msg_len); 2804 kmem_free((void *)sbbc_ecc_msgp, 2805 sizeof (sbbc_ecc_mbox_t)); 2806 return; 2807 } 2808 2809 /* 2810 * Reset error counter so that first taskq_dispatch 2811 * error will be output 2812 */ 2813 sbbc_ecc_mbox_taskq_errs = 0; 2814 } 2815 2816 /* 2817 * Enqueue the message 2818 */ 2819 2820 if (taskq_dispatch(sbbc_ecc_mbox_taskq, 2821 (task_func_t *)sbbc_mbox_ecc_output, sbbc_ecc_msgp, 2822 TQ_NOSLEEP) == NULL) { 2823 2824 if (sbbc_ecc_mbox_taskq_errs == 0) { 2825 cmn_err(CE_NOTE, "Unable to send ECC event " 2826 "message to System Controller"); 2827 } 2828 if (++sbbc_ecc_mbox_taskq_errs >= sbbc_ecc_mbox_err_throttle) { 2829 sbbc_ecc_mbox_taskq_errs = 0; 2830 } 2831 2832 kmem_free((void *)sbbc_ecc_msgp->ecc_req.msg_buf, 2833 (size_t)sbbc_ecc_msgp->ecc_req.msg_len); 2834 kmem_free((void *)sbbc_ecc_msgp, sizeof (sbbc_ecc_mbox_t)); 2835 } 2836 } 2837 2838 static uint_t 2839 cap_ecc_msg_handler(char *addr) 2840 { 2841 sbbc_msg_t *msg = NULL; 2842 plat_capability_data_t *cap = NULL; 2843 static fn_t f = "cap_ecc_msg_handler"; 2844 2845 msg = (sbbc_msg_t *)addr; 2846 2847 if (msg == NULL) { 2848 SGSBBC_DBG_EVENT(CE_WARN, "cap_ecc_msg_handler() called with " 2849 "null addr"); 2850 return (DDI_INTR_CLAIMED); 2851 } 2852 2853 if (msg->msg_buf == NULL) { 2854 SGSBBC_DBG_EVENT(CE_WARN, "cap_ecc_msg_handler() called with " 2855 "null data buffer"); 2856 return (DDI_INTR_CLAIMED); 2857 } 2858 2859 cap = (plat_capability_data_t *)msg->msg_buf; 2860 switch (cap->capd_msg_type) { 2861 case PLAT_ECC_CAPABILITY_MESSAGE: 2862 SGSBBC_DBG_MBOX("%s: capability 0x%x\n", f, 2863 cap->capd_capability); 2864 plat_ecc_capability_sc_set(cap->capd_capability); 2865 break; 2866 default: 2867 SGSBBC_DBG_MBOX("%s: Unknown message type = 0x%x\n", f, 2868 cap->capd_msg_type); 2869 break; 2870 } 2871 2872 return (DDI_INTR_CLAIMED); 2873 } 2874