1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * This file contains the implementation of the mboxsc module, a mailbox layer 29 * built upon the Starcat IOSRAM driver. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/systm.h> 34 #include <sys/modctl.h> 35 #include <sys/errno.h> 36 #include <sys/ksynch.h> 37 #include <sys/kmem.h> 38 #include <sys/varargs.h> 39 #include <sys/ddi.h> 40 #include <sys/sunddi.h> 41 #include <sys/cmn_err.h> 42 #include <sys/debug.h> 43 #include <sys/sysmacros.h> 44 45 #include <sys/iosramreg.h> 46 #include <sys/iosramio.h> 47 #include <sys/mboxsc.h> 48 #include <sys/mboxsc_impl.h> 49 50 /* 51 * Debugging facility 52 */ 53 #define DBGACT_NONE (0x00000000) 54 #define DBGACT_BREAK (0x00000001) 55 #define DBGACT_SHOWPOS (0x00000002) 56 #define DBGACT_DEFAULT DBGACT_NONE 57 58 #define DBG_DEV (0x00000001) 59 #define DBG_CALLS (0x00000002) 60 #define DBG_RETS (0x00000004) 61 #define DBG_ARGS (0x00000008) 62 #define DBG_KMEM (0x00000010) 63 #define DBG_ALL (0xFFFFFFFF) 64 65 #ifdef DEBUG 66 static uint32_t mboxsc_debug_mask = 0x00000000; 67 #define DPRINTF0(class, action, fmt) \ 68 mboxsc_dprintf(__FILE__, __LINE__, (class), (action), (fmt)) 69 #define DPRINTF1(class, action, fmt, arg1) \ 70 mboxsc_dprintf(__FILE__, __LINE__, (class), (action), (fmt),\ 71 (arg1)) 72 #define DPRINTF2(class, action, fmt, arg1, arg2) \ 73 mboxsc_dprintf(__FILE__, __LINE__, (class), (action), (fmt),\ 74 (arg1), (arg2)) 75 #define DPRINTF3(class, action, fmt, arg1, arg2, arg3) \ 76 mboxsc_dprintf(__FILE__, __LINE__, (class), (action), (fmt),\ 77 (arg1), (arg2), (arg3)) 78 #define DPRINTF4(class, action, fmt, arg1, arg2, arg3, arg4) \ 79 mboxsc_dprintf(__FILE__, __LINE__, (class), (action), (fmt),\ 80 (arg1), (arg2), (arg3), (arg4)) 81 #define DPRINTF5(class, action, fmt, arg1, arg2, arg3, arg4, arg5) \ 82 mboxsc_dprintf(__FILE__, __LINE__, (class), (action), (fmt),\ 83 (arg1), (arg2), (arg3), (arg4), (arg5)) 84 #else /* DEBUG */ 85 #define DPRINTF0(class, action, fmt) 86 #define DPRINTF1(class, action, fmt, arg1) 87 #define DPRINTF2(class, action, fmt, arg1, arg2) 88 #define DPRINTF3(class, action, fmt, arg1, arg2, arg3) 89 #define DPRINTF4(class, action, fmt, arg1, arg2, arg3, arg4) 90 #define DPRINTF5(class, action, fmt, arg1, arg2, arg3, arg4, arg5) 91 #endif /* DEBUG */ 92 93 /* 94 * Basic constants 95 */ 96 #ifndef TRUE 97 #define TRUE (1) 98 #endif /* TRUE */ 99 #ifndef FALSE 100 #define FALSE (0) 101 #endif /* FALSE */ 102 103 104 /* 105 * Whenever mboxsc_init is called to create a new mailbox, an instance of 106 * mboxsc_mbox_t is created and inserted into a hash table to maintain 107 * various information about the mailbox. The mbox_state, mbox_refcount, and 108 * mbox_wait fields are all protected by the global mboxsc_lock mutex. 109 * If lock contention between mailboxes becomes an issue, each mailbox will 110 * need to be given its own mutex to protect the mbox_wait, mbox_state, 111 * and mbox_update_wait fields. The mbox_refcount field will probably need to 112 * remain under global protection, however, since it is used to keep track of 113 * the number of threads sleeping inside the mailbox's various synchronization 114 * mechanisms and would consequently be difficult to protect using those same 115 * mechanisms. 116 */ 117 typedef struct mboxsc_mbox { 118 uint32_t mbox_key; 119 int mbox_direction; 120 void (*mbox_callback)(void); 121 uint32_t mbox_length; 122 uint16_t mbox_refcount; 123 uint16_t mbox_state; 124 kcondvar_t mbox_wait; 125 mboxsc_msghdr_t mbox_header; 126 struct mboxsc_mbox *mbox_hash_next; 127 } mboxsc_mbox_t; 128 129 /* 130 * Various state flags that can be set on a mailbox. Multiple states may 131 * be active at the same time. 132 */ 133 #define STATE_IDLE (0x0000) 134 #define STATE_WRITING (0x0001) 135 #define STATE_READING (0x0002) 136 #define STATE_HDRVALID (0x0004) 137 138 /* 139 * Timeout periods for mboxsc_putmsg and mboxsc_getmsg, converted to ticks 140 * from the microsecond values found in mboxsc_impl.h. 141 */ 142 #define EAGAIN_POLL (drv_usectohz(MBOXSC_EAGAIN_POLL_USECS)) 143 #define PUTMSG_POLL (drv_usectohz(MBOXSC_PUTMSG_POLL_USECS)) 144 #define HWLOCK_POLL (drv_usectohz(MBOXSC_HWLOCK_POLL_USECS)) 145 #define LOOP_WARN_INTERVAL (drv_usectohz(MBOXSC_USECS_PER_SECOND * 15)) 146 147 /* 148 * Various tests that are performed on message header fields. 149 */ 150 #define IS_UNSOLICITED_TYPE(type) ((type) != MBOXSC_MSG_REPLY) 151 #define MSG_TYPE_MATCHES(type, msgp) \ 152 (((type) == 0) || ((type) & (msgp)->msg_type)) 153 #define MSG_CMD_MATCHES(cmd, msgp) \ 154 (((cmd) == 0) || ((cmd) == (msgp)->msg_cmd)) 155 #define MSG_TRANSID_MATCHES(tid, msgp) \ 156 (((tid) == 0) || ((tid) == (msgp)->msg_transid)) 157 158 /* 159 * These macros can be used to determine the offset or size of any field in the 160 * message header (or any other struct, for that matter). 161 */ 162 #define FIELD_OFFSET(type, field) ((uint32_t)&(((type *)0)->field)) 163 #define FIELD_SIZE(type, field) (sizeof (((type *)0)->field)) 164 165 /* 166 * Mask used when generating unique transaction ID values. 167 * This arbitrarily chosen value will be OR'd together with 168 * a counter for each successive internally-generated transaction ID. 169 */ 170 #define TRANSID_GEN_MASK (0xFFC0000000000000) 171 172 /* 173 * All existing mailboxes are stored in a hash table with HASHTBL_SIZE 174 * entries so they can be rapidly accessed by their key values. 175 */ 176 #define HASHTBL_SIZE (32) 177 #define HASH_KEY(key) ((((key) >> 24) ^ ((key) >> 16) ^ ((key) >> 9) ^\ 178 (key)) & (HASHTBL_SIZE - 1)); 179 180 /* 181 * Unfortunately, it is necessary to calculate checksums on data split up 182 * amongst different buffers in some cases. Consequently, mboxsc_checksum 183 * accepts a "seed" value as one of its parameters. When first starting a 184 * checksum calculation, the seed should be 0. 185 */ 186 #define CHKSUM_INIT (0) 187 188 /* 189 * local variables 190 */ 191 static kmutex_t mboxsc_lock; 192 static mboxsc_mbox_t *mboxsc_hash_table[HASHTBL_SIZE]; 193 static uint32_t mboxsc_flaglock_count; 194 static uint32_t mboxsc_active_version = MBOXSC_PROTOCOL_VERSION; 195 static kcondvar_t mboxsc_dereference_cv; 196 197 /* 198 * Structures from modctl.h used for loadable module support. 199 * The mboxsc API is a "miscellaneous" module. 200 */ 201 extern struct mod_ops mod_miscops; 202 203 static struct modlmisc modlmisc = { 204 &mod_miscops, 205 "IOSRAM Mailbox API 'mboxsc'", 206 }; 207 208 static struct modlinkage modlinkage = { 209 MODREV_1, 210 (void *)&modlmisc, 211 NULL 212 }; 213 214 /* 215 * Prototypes for local functions 216 */ 217 static void mboxsc_iosram_callback(void *arg); 218 static void mboxsc_hdrchange_callback(void); 219 static int mboxsc_add_mailbox(mboxsc_mbox_t *mailboxp); 220 static void mboxsc_close_mailbox(mboxsc_mbox_t *mailboxp); 221 static void mboxsc_hashinsert_mailbox(mboxsc_mbox_t *mailboxp); 222 static mboxsc_mbox_t *mboxsc_hashfind_mailbox_by_key(uint32_t key); 223 static mboxsc_mbox_t *mboxsc_hashremove_mailbox_by_key(uint32_t key); 224 static mboxsc_chksum_t mboxsc_checksum(mboxsc_chksum_t seed, uint8_t *buf, 225 uint32_t length); 226 static int mboxsc_lock_flags(uint8_t mandatory, clock_t deadline); 227 static int mboxsc_unlock_flags(uint8_t mandatory); 228 static int mboxsc_timed_read(clock_t deadline, uint32_t key, 229 uint32_t off, uint32_t len, caddr_t dptr); 230 static int mboxsc_timed_write(clock_t deadline, uint32_t key, 231 uint32_t off, uint32_t len, caddr_t dptr); 232 static int mboxsc_timed_get_flag(clock_t deadline, uint32_t key, 233 uint8_t *data_validp, uint8_t *int_pendingp); 234 static int mboxsc_timed_set_flag(clock_t deadline, uint32_t key, 235 uint8_t data_valid, uint8_t int_pending); 236 static int mboxsc_timed_send_intr(clock_t deadline); 237 static int mboxsc_expire_message(uint32_t key, int *resultp); 238 static uint64_t mboxsc_generate_transid(uint64_t prev_transid); 239 static void mboxsc_reference_mailbox(mboxsc_mbox_t *mailboxp); 240 static void mboxsc_dereference_mailbox(mboxsc_mbox_t *mailboxp); 241 #ifdef DEBUG 242 /*PRINTFLIKE5*/ 243 static void mboxsc_dprintf(const char *file, int line, 244 uint32_t class, uint32_t action, const char *fmt, ...); 245 int mboxsc_debug(int cmd, void *arg); 246 #endif /* DEBUG */ 247 248 249 /* 250 * _init 251 * 252 * Loadable module support routine. Initializes global lock and hash table. 253 */ 254 int 255 _init(void) 256 { 257 int i; 258 uint32_t sms_version; 259 int error = 0; 260 261 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "_init called\n"); 262 263 /* 264 * Initialize all module resources. 265 */ 266 mutex_init(&mboxsc_lock, NULL, MUTEX_DRIVER, NULL); 267 cv_init(&mboxsc_dereference_cv, NULL, CV_DRIVER, NULL); 268 269 for (i = 0; i < HASHTBL_SIZE; i++) { 270 mboxsc_hash_table[i] = NULL; 271 } 272 mboxsc_flaglock_count = 0; 273 274 if (mod_install(&modlinkage) != 0) { 275 goto failed; 276 } 277 278 /* 279 * Set the os_mbox_version field in the IOSRAM header to indicate the 280 * highest Mailbox Protocol version we support 281 */ 282 error = iosram_hdr_ctrl(IOSRAM_HDRCMD_SET_OS_MBOX_VER, 283 (void *)MBOXSC_PROTOCOL_VERSION); 284 if (error != 0) { 285 goto failed; 286 } 287 288 /* 289 * Read the sms_mbox_version field in the IOSRAM header to determine 290 * what the greatest commonly supported version is. 291 */ 292 error = iosram_hdr_ctrl(IOSRAM_HDRCMD_GET_SMS_MBOX_VER, 293 (void *)&sms_version); 294 if (error != 0) { 295 goto failed; 296 } 297 mboxsc_active_version = MIN(MBOXSC_PROTOCOL_VERSION, sms_version); 298 DPRINTF2(DBG_DEV, DBGACT_DEFAULT, 299 "sms version: %d, active version: %d\n", sms_version, 300 mboxsc_active_version); 301 302 /* 303 * Register a callback with the IOSRAM driver to receive notification of 304 * changes to the IOSRAM header, in case the sms_mbox_version field 305 * changes. 306 */ 307 error = iosram_hdr_ctrl(IOSRAM_HDRCMD_REG_CALLBACK, 308 (void *)mboxsc_hdrchange_callback); 309 if (error != 0) { 310 goto failed; 311 } 312 313 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "_init ret: 0x%08x\n", error); 314 return (0); 315 316 /* 317 * If initialization fails, uninitialize resources. 318 */ 319 failed: 320 mutex_destroy(&mboxsc_lock); 321 cv_destroy(&mboxsc_dereference_cv); 322 323 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "_init ret: 0x%08x\n", error); 324 return (error); 325 } 326 327 /* 328 * _fini 329 * 330 * Loadable module support routine. Closes all mailboxes and releases all 331 * resources. 332 */ 333 int 334 _fini(void) 335 { 336 int i; 337 int error = 0; 338 mboxsc_mbox_t *mailboxp; 339 340 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "_fini called\n"); 341 342 /* 343 * Attempt to remove the module. If successful, close all mailboxes 344 * and deallocate the global lock. 345 */ 346 error = mod_remove(&modlinkage); 347 if (error == 0) { 348 mutex_enter(&mboxsc_lock); 349 350 (void) iosram_hdr_ctrl(IOSRAM_HDRCMD_REG_CALLBACK, NULL); 351 352 for (i = 0; i < HASHTBL_SIZE; i++) { 353 while (mboxsc_hash_table[i] != NULL) { 354 mailboxp = mboxsc_hash_table[i]; 355 mboxsc_close_mailbox(mailboxp); 356 } 357 } 358 mutex_exit(&mboxsc_lock); 359 mutex_destroy(&mboxsc_lock); 360 cv_destroy(&mboxsc_dereference_cv); 361 } 362 363 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "_fini ret: 0x%08x\n", error); 364 return (error); 365 } 366 367 /* 368 * _info 369 * 370 * Loadable module support routine. 371 */ 372 int 373 _info(struct modinfo *modinfop) 374 { 375 int error = 0; 376 377 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "_info called\n"); 378 379 error = mod_info(&modlinkage, modinfop); 380 381 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "_info ret: 0x%08x\n", error); 382 383 return (error); 384 } 385 386 /* 387 * mboxsc_init 388 * 389 * Attempts to create a new mailbox. 390 */ 391 int 392 mboxsc_init(uint32_t key, int direction, void (*event_handler)(void)) 393 { 394 int error = 0; 395 mboxsc_mbox_t *mailboxp; 396 397 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_init called\n"); 398 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key); 399 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "direction = %d\n", direction); 400 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "event_handlerp = %p\n", 401 (void *)event_handler); 402 403 /* 404 * Check for valid direction and callback specification. 405 */ 406 if (((direction != MBOXSC_MBOX_IN) && (direction != MBOXSC_MBOX_OUT)) || 407 ((event_handler != NULL) && (direction != MBOXSC_MBOX_IN))) { 408 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_init ret: 0x%08x\n", 409 EINVAL); 410 return (EINVAL); 411 } 412 413 /* 414 * Allocate memory for the mailbox structure and initialize all 415 * caller-provided fields. 416 */ 417 mailboxp = (mboxsc_mbox_t *)kmem_zalloc(sizeof (mboxsc_mbox_t), 418 KM_SLEEP); 419 DPRINTF2(DBG_KMEM, DBGACT_DEFAULT, "kmem_zalloc(%lu) = %p\n", 420 sizeof (mboxsc_mbox_t), (void *)mailboxp); 421 mailboxp->mbox_key = key; 422 mailboxp->mbox_direction = direction; 423 mailboxp->mbox_callback = event_handler; 424 425 /* 426 * Attempt to add the mailbox. If unsuccessful, free the allocated 427 * memory. 428 */ 429 mutex_enter(&mboxsc_lock); 430 error = mboxsc_add_mailbox(mailboxp); 431 mutex_exit(&mboxsc_lock); 432 433 if (error != 0) { 434 DPRINTF2(DBG_KMEM, DBGACT_DEFAULT, "kmem_free(%p, %lu)\n", 435 (void *)mailboxp, sizeof (mboxsc_mbox_t)); 436 kmem_free(mailboxp, sizeof (mboxsc_mbox_t)); 437 } 438 439 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_init ret: 0x%08x\n", error); 440 return (error); 441 } 442 443 /* 444 * mboxsc_fini 445 * 446 * Closes the mailbox with the indicated key, if it exists. 447 */ 448 int 449 mboxsc_fini(uint32_t key) 450 { 451 int error = 0; 452 mboxsc_mbox_t *mailboxp; 453 454 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_fini called\n"); 455 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key); 456 457 /* 458 * Attempt to close the mailbox. 459 */ 460 mutex_enter(&mboxsc_lock); 461 mailboxp = mboxsc_hashfind_mailbox_by_key(key); 462 if (mailboxp == NULL) { 463 error = EBADF; 464 } else { 465 while (mailboxp->mbox_refcount != 0) { 466 cv_wait(&mboxsc_dereference_cv, &mboxsc_lock); 467 } 468 mboxsc_close_mailbox(mailboxp); 469 } 470 mutex_exit(&mboxsc_lock); 471 472 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_fini ret: 0x%08x\n", error); 473 return (error); 474 } 475 476 /* 477 * mboxsc_putmsg 478 * 479 * Attempt to place a message into an outbound mailbox and signal the 480 * recipient. A successful return (0) indicates that the message was 481 * successfully delivered. 482 */ 483 int 484 mboxsc_putmsg(uint32_t key, uint32_t type, uint32_t cmd, uint64_t *transidp, 485 uint32_t length, void *datap, clock_t timeout) 486 { 487 int i; 488 int error = 0; 489 int result; 490 int lock_held = 0; 491 int unlock_err; 492 uint8_t data_valid; 493 clock_t deadline; 494 clock_t remainder; 495 mboxsc_chksum_t checksum; 496 mboxsc_mbox_t *mailboxp; 497 mboxsc_msghdr_t header; 498 499 #ifdef DEBUG /* because lint whines about if stmts without consequents */ 500 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_putmsg called\n"); 501 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key); 502 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "type = 0x%x\n", type); 503 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "cmd = 0x%x\n", cmd); 504 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "transidp = %p\n", (void *)transidp); 505 if (transidp != NULL) { 506 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "*transidp = 0x%016lx\n", 507 *transidp); 508 } 509 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "length = 0x%x\n", length); 510 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "datap = %p\n", datap); 511 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "timeout = %ld\n", timeout); 512 #endif /* DEBUG */ 513 514 /* 515 * Perform some basic sanity checks on the message. 516 */ 517 for (i = 0; i < MBOXSC_NUM_MSG_TYPES; i++) { 518 if (type == (1 << i)) { 519 break; 520 } 521 } 522 if ((i == MBOXSC_NUM_MSG_TYPES) || (cmd == 0) || 523 ((datap == NULL) && (length != 0)) || 524 (timeout < MBOXSC_PUTMSG_MIN_TIMEOUT_MSECS) || 525 (timeout > MBOXSC_PUTMSG_MAX_TIMEOUT_MSECS)) { 526 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 527 "mboxsc_putmsg ret: 0x%08x\n", EINVAL); 528 return (EINVAL); 529 } 530 531 /* 532 * Initialize the header structure with values provided by the caller. 533 */ 534 header.msg_version = mboxsc_active_version; 535 header.msg_type = type; 536 header.msg_cmd = cmd; 537 header.msg_length = MBOXSC_MSGHDR_SIZE + length; 538 if (transidp != NULL) { 539 header.msg_transid = *transidp; 540 } else { 541 header.msg_transid = 0; 542 } 543 544 /* 545 * Perform additional sanity checks on the mailbox and message. 546 * Make sure that the specified mailbox really exists, that the 547 * given message will fit in it, and that the current message's 548 * transaction ID isn't the same as the last message's transaction 549 * ID unless both messages are replies (it's okay, necessary even, 550 * to reuse a transaction ID when resending a failed reply message, 551 * but that is the only case in which it is permissible). 552 */ 553 mutex_enter(&mboxsc_lock); 554 mailboxp = mboxsc_hashfind_mailbox_by_key(key); 555 556 if (mailboxp == NULL) { 557 error = EBADF; 558 } else if ((mailboxp->mbox_direction != MBOXSC_MBOX_OUT) || 559 (length + MBOXSC_PROTOCOL_SIZE > mailboxp->mbox_length) || 560 ((header.msg_transid == mailboxp->mbox_header.msg_transid) && 561 ((type & mailboxp->mbox_header.msg_type) != MBOXSC_MSG_REPLY) && 562 (header.msg_transid != 0))) { 563 error = EINVAL; 564 } 565 566 if (error != 0) { 567 mutex_exit(&mboxsc_lock); 568 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 569 "mboxsc_putmsg ret: 0x%08x\n", error); 570 return (error); 571 } 572 573 /* 574 * If the message's transaction ID is set to 0, generate a unique 575 * transaction ID and copy it into the message header. If the message 576 * is successfully delivered and transidp != NULL, we'll copy this new 577 * transid into *transidp later. 578 */ 579 if (header.msg_transid == 0) { 580 header.msg_transid = 581 mboxsc_generate_transid(mailboxp->mbox_header.msg_transid); 582 } 583 584 /* 585 * Don't allow mboxsc_putmsg to attempt to place a message for 586 * longer than the caller's timeout. 587 */ 588 deadline = ddi_get_lbolt() + 589 drv_usectohz(timeout * MBOXSC_USECS_PER_MSEC); 590 591 /* 592 * Increment the reference count on the mailbox to keep it from being 593 * closed, and wait for it to become available. 594 */ 595 mboxsc_reference_mailbox(mailboxp); 596 remainder = 1; 597 while ((mailboxp->mbox_state & STATE_WRITING) && 598 (remainder > 0)) { 599 remainder = cv_timedwait_sig(&(mailboxp->mbox_wait), 600 &mboxsc_lock, deadline); 601 } 602 603 /* 604 * Check to see whether or not the mailbox became available. If it 605 * did not, decrement its reference count and return an error to the 606 * caller. 607 */ 608 if (remainder == -1) { 609 error = ENOSPC; 610 } else if (remainder == 0) { 611 error = EINTR; 612 } 613 614 if (error != 0) { 615 mboxsc_dereference_mailbox(mailboxp); 616 mutex_exit(&mboxsc_lock); 617 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 618 "mboxsc_putmsg ret: 0x%08x\n", error); 619 return (error); 620 } 621 622 /* 623 * Since the message is valid and we're going to try to write it to 624 * IOSRAM, record its header for future reference (e.g. to make sure the 625 * next message doesn't incorrectly use the same transID). 626 */ 627 bcopy(&header, &(mailboxp->mbox_header), MBOXSC_MSGHDR_SIZE); 628 629 /* 630 * Flag the mailbox as being in use and release the global lock. 631 */ 632 mailboxp->mbox_state |= STATE_WRITING; 633 mutex_exit(&mboxsc_lock); 634 635 /* 636 * Calculate the message checksum using the header and the data. 637 */ 638 checksum = mboxsc_checksum(CHKSUM_INIT, (uint8_t *)&header, 639 MBOXSC_MSGHDR_SIZE); 640 checksum = mboxsc_checksum(checksum, (uint8_t *)datap, length); 641 642 /* 643 * Attempt to write the message and checksum to IOSRAM until successful, 644 * or as long as time remains and no errors other than EAGAIN are 645 * returned from any call to the IOSRAM driver in case there is a tunnel 646 * switch in progress. 647 */ 648 error = mboxsc_timed_write(deadline, key, MBOXSC_MSGHDR_OFFSET, 649 MBOXSC_MSGHDR_SIZE, (caddr_t)&header); 650 651 if (error == 0) { 652 error = mboxsc_timed_write(deadline, key, MBOXSC_DATA_OFFSET, 653 length, (caddr_t)datap); 654 } 655 656 if (error == 0) { 657 error = mboxsc_timed_write(deadline, key, header.msg_length, 658 MBOXSC_CHKSUM_SIZE, (caddr_t)&checksum); 659 } 660 661 /* 662 * Lock the flags before setting data_valid. This isn't strictly 663 * necessary for correct protocol operation, but it gives us a chance to 664 * verify that the flags lock is functional before we commit to sending 665 * the message. 666 */ 667 if (error == 0) { 668 error = mboxsc_lock_flags(FALSE, deadline); 669 if (error == 0) { 670 lock_held = 1; 671 } else if (error == EBUSY) { 672 error = EAGAIN; 673 } 674 } 675 676 if (error == 0) { 677 error = mboxsc_timed_set_flag(deadline, key, IOSRAM_DATA_VALID, 678 IOSRAM_INT_TO_SSC); 679 } 680 681 /* 682 * Unlock the flags. If an error is encountered, only return it if 683 * another error hasn't been encountered previously. 684 */ 685 if (lock_held) { 686 unlock_err = mboxsc_unlock_flags(TRUE); 687 if ((unlock_err != 0) && ((error == 0) || (error == EAGAIN))) { 688 error = unlock_err; 689 } 690 } 691 692 /* 693 * If time ran out or an IOSRAM call failed, notify other callers that 694 * the mailbox is available, decrement its reference count, and return 695 * an error. 696 */ 697 if (error != 0) { 698 ASSERT((error != EINVAL) && (error != EMSGSIZE)); 699 mutex_enter(&mboxsc_lock); 700 mailboxp->mbox_state &= ~STATE_WRITING; 701 cv_broadcast(&(mailboxp->mbox_wait)); 702 mboxsc_dereference_mailbox(mailboxp); 703 mutex_exit(&mboxsc_lock); 704 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 705 "mboxsc_putmsg ret: 0x%08x\n", error); 706 return (error); 707 } 708 709 /* 710 * Send an interrupt to the remote mailbox interface to announce the 711 * presence of a new, valid message. 712 */ 713 error = mboxsc_timed_send_intr(deadline); 714 715 /* 716 * Wait until either the data_valid flag is set INVALID by the 717 * remote client or time runs out. Since we're calling delay as 718 * a part of polling the flag anyway, we don't really need to do 719 * the usual continuous retry if iosram_get_flag returns EAGAIN. 720 */ 721 data_valid = IOSRAM_DATA_VALID; 722 if (error == DDI_SUCCESS) { 723 do { 724 delay(MIN(PUTMSG_POLL, deadline - ddi_get_lbolt())); 725 error = iosram_get_flag(key, &data_valid, NULL); 726 } while ((data_valid == IOSRAM_DATA_VALID) && 727 ((error == EAGAIN) || (error == 0)) && 728 (deadline - ddi_get_lbolt() >= 0)); 729 } 730 731 /* 732 * If the data_valid flag was set to INVALID by the other side, the 733 * message was successfully transmitted. If it wasn't, but there 734 * weren't any IOSRAM errors, the operation timed out. If there was a 735 * problem with the IOSRAM, pass that info back to the caller. 736 */ 737 if (data_valid == IOSRAM_DATA_INVALID) { 738 result = 0; 739 } else if ((error == 0) || (error == DDI_FAILURE)) { 740 result = ETIMEDOUT; 741 } else { 742 ASSERT(error != EINVAL); 743 result = error; 744 } 745 746 /* 747 * If the message has not been picked up, expire it. Note that this may 748 * actually result in detecting successful message delivery if the SC 749 * picks it up at the last moment. If expiration fails due to an error, 750 * return an error to the user even if the message appears to have 751 * been successfully delivered. 752 */ 753 if (data_valid == IOSRAM_DATA_VALID) { 754 error = mboxsc_expire_message(key, &result); 755 if ((error != 0) && ((result == 0) || (result == ETIMEDOUT))) { 756 result = error; 757 } 758 } 759 760 /* 761 * If the message was successfully delivered, and we generated a 762 * transaction ID for the caller, and the caller wants to know what it 763 * was, give it to them. 764 */ 765 if ((result == 0) && (transidp != NULL) && (*transidp == 0)) { 766 *transidp = header.msg_transid; 767 } 768 769 /* 770 * Regardless of whether the message was successfully transmitted or 771 * not, notify other callers that the mailbox is available and decrement 772 * its reference count. 773 */ 774 mutex_enter(&mboxsc_lock); 775 mailboxp->mbox_state &= ~STATE_WRITING; 776 cv_broadcast(&(mailboxp->mbox_wait)); 777 mboxsc_dereference_mailbox(mailboxp); 778 mutex_exit(&mboxsc_lock); 779 780 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_putmsg ret: 0x%08x\n", 781 result); 782 return (result); 783 } 784 785 /* 786 * mboxsc_getmsg 787 * 788 * Attempt to retrieve a message from the mailbox with the given key that 789 * matches values provided in msgp. A successful return (0) indicates that 790 * a message matching the caller's request was successfully received within 791 * timeout milliseconds. If a message matching the caller's request is 792 * detected, but can't be successfully read, an error will be returned even 793 * if the caller's timeout hasn't expired. 794 */ 795 int 796 mboxsc_getmsg(uint32_t key, uint32_t *typep, uint32_t *cmdp, uint64_t *transidp, 797 uint32_t *lengthp, void *datap, clock_t timeout) 798 { 799 int error = 0; 800 uint32_t datalen; 801 uint8_t data_valid; 802 uint8_t lock_held; 803 mboxsc_chksum_t read_checksum; 804 mboxsc_chksum_t calc_checksum; 805 uint64_t read_transid; 806 clock_t deadline; 807 clock_t remainder; 808 mboxsc_mbox_t *mailboxp; 809 mboxsc_msghdr_t header; 810 811 #ifdef DEBUG /* because lint whines about if stmts without consequents */ 812 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_getmsg called\n"); 813 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key); 814 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "typep = %p\n", (void *)typep); 815 if (typep != NULL) { 816 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "*typep = 0x%x\n", *typep); 817 } 818 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "cmdp = %p\n", (void *)cmdp); 819 if (cmdp != NULL) { 820 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "*cmdp = 0x%x\n", *cmdp); 821 } 822 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "transidp = %p\n", (void *)transidp); 823 if (transidp != NULL) { 824 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "*transidp = 0x%lx\n", 825 *transidp); 826 } 827 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "lengthp = %p\n", (void *)lengthp); 828 if (lengthp != NULL) { 829 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "*lengthp = 0x%x\n", 830 *lengthp); 831 } 832 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "datap = %p\n", datap); 833 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "timeout = %ld\n", timeout); 834 #endif /* DEBUG */ 835 836 /* 837 * Perform basic sanity checks on the caller's request. 838 */ 839 if ((typep == NULL) || (*typep >= (1 << MBOXSC_NUM_MSG_TYPES)) || 840 (cmdp == NULL) || (transidp == NULL) || (lengthp == NULL) || 841 ((datap == NULL) && (*lengthp != 0)) || 842 (timeout < MBOXSC_GETMSG_MIN_TIMEOUT_MSECS) || 843 (timeout > MBOXSC_GETMSG_MAX_TIMEOUT_MSECS)) { 844 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 845 "mboxsc_getmsg ret: 0x%08x\n", EINVAL); 846 return (EINVAL); 847 } 848 849 /* 850 * Don't allow mboxsc_getmsg to attempt to receive a message for 851 * longer than the caller's timeout. 852 */ 853 deadline = ddi_get_lbolt() + 854 drv_usectohz(timeout * MBOXSC_USECS_PER_MSEC); 855 856 /* 857 * Perform additional sanity checks on the client's request and the 858 * associated mailbox. 859 */ 860 mutex_enter(&mboxsc_lock); 861 mailboxp = mboxsc_hashfind_mailbox_by_key(key); 862 if (mailboxp == NULL) { 863 error = EBADF; 864 } else if (mailboxp->mbox_direction != MBOXSC_MBOX_IN) { 865 error = EINVAL; 866 } 867 868 if (error != 0) { 869 mutex_exit(&mboxsc_lock); 870 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 871 "mboxsc_getmsg ret: 0x%08x\n", error); 872 return (error); 873 } 874 875 /* 876 * The request is okay, so reference the mailbox (to keep it from being 877 * closed), and proceed with the real work. 878 */ 879 mboxsc_reference_mailbox(mailboxp); 880 881 /* 882 * Certain failures that may occur late in the process of getting a 883 * message (e.g. checksum error, cancellation by the sender) are 884 * supposed to leave the recipient waiting for the next message to 885 * arrive rather than returning an error. To facilitate restarting 886 * the message acquisition process, the following label is provided 887 * as a target for a very few judiciously-placed "goto"s. 888 * 889 * The mboxsc_lock mutex MUST be held when jumping to this point. 890 */ 891 mboxsc_getmsg_retry: 892 ; 893 894 /* 895 * If there is a valid message in the mailbox right now, check to 896 * see if it matches the caller's request. If not, or if another 897 * caller is already reading it, wait for either the arrival of the 898 * next message or the expiration of the caller's specified timeout. 899 */ 900 error = 0; 901 while (!(mailboxp->mbox_state & STATE_HDRVALID) || 902 (mailboxp->mbox_state & STATE_READING) || 903 !MSG_TYPE_MATCHES(*typep, &(mailboxp->mbox_header)) || 904 !MSG_CMD_MATCHES(*cmdp, &(mailboxp->mbox_header)) || 905 !MSG_TRANSID_MATCHES(*transidp, &(mailboxp->mbox_header))) { 906 remainder = cv_timedwait_sig(&(mailboxp->mbox_wait), 907 &mboxsc_lock, deadline); 908 if (remainder == -1) { 909 error = ETIMEDOUT; 910 } else if (remainder == 0) { 911 error = EINTR; 912 } 913 914 if (error != 0) { 915 mboxsc_dereference_mailbox(mailboxp); 916 mutex_exit(&mboxsc_lock); 917 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 918 "mboxsc_getmsg ret: 0x%08x\n", error); 919 return (error); 920 } 921 } 922 923 /* 924 * If somebody sends us a message using a Mailbox Protocol version 925 * greater than the highest one we understand, invalidate the message, 926 * because we can't safely interpret anything beyond the version field. 927 */ 928 if (mailboxp->mbox_header.msg_version > MBOXSC_PROTOCOL_VERSION) { 929 DPRINTF1(DBG_DEV, DBGACT_DEFAULT, 930 "incoming message with unsupported version %d\n", 931 mailboxp->mbox_header.msg_version); 932 mailboxp->mbox_state &= ~STATE_HDRVALID; 933 goto mboxsc_getmsg_retry; 934 } 935 936 /* 937 * At this point, there is a stored message header that matches the 938 * caller's request, but the actual message may no longer be valid 939 * in IOSRAM. Check the data_valid flag to see whether or not 940 * this is the case. If the message has expired, go start over. 941 * 942 * The global mutex is held while reading flag data from IOSRAM to 943 * avoid certain race conditions. One race condition is still 944 * possible (i.e. SC-side has just set the data_valid flag for a 945 * new message, but the stored message header hasn't been updated 946 * yet), but it won't cause incorrect behavior (just some wasted work). 947 */ 948 error = iosram_get_flag(key, &data_valid, NULL); 949 950 ASSERT(error != EINVAL); 951 if (error == 0) { 952 if (data_valid != IOSRAM_DATA_VALID) { 953 mailboxp->mbox_state &= ~STATE_HDRVALID; 954 goto mboxsc_getmsg_retry; 955 } 956 } else if ((error == EAGAIN) && (deadline - ddi_get_lbolt() >= 0)) { 957 mutex_exit(&mboxsc_lock); 958 delay(MIN(EAGAIN_POLL, deadline - ddi_get_lbolt())); 959 mutex_enter(&mboxsc_lock); 960 goto mboxsc_getmsg_retry; 961 } 962 963 /* 964 * If the message is larger than the caller's buffer, provide the caller 965 * with the length of the message and return an error. 966 */ 967 datalen = mailboxp->mbox_header.msg_length - MBOXSC_MSGHDR_SIZE; 968 if ((error == 0) && (datalen > *lengthp)) { 969 *lengthp = datalen; 970 error = EMSGSIZE; 971 } 972 973 /* 974 * Note that there's no need to check STATE_HDRVALID before broadcasting 975 * here because the header is guaranteed to be valid at this point. 976 */ 977 if (error != 0) { 978 cv_broadcast(&(mailboxp->mbox_wait)); 979 mboxsc_dereference_mailbox(mailboxp); 980 mutex_exit(&mboxsc_lock); 981 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 982 "mboxsc_getmsg ret: 0x%08x\n", error); 983 return (error); 984 } 985 986 /* 987 * Store a copy of the current message header, flag the mailbox to 988 * indicate that it is being read and attempt to read the message data 989 * and checksum. 990 */ 991 bcopy(&(mailboxp->mbox_header), &header, MBOXSC_MSGHDR_SIZE); 992 mailboxp->mbox_state |= STATE_READING; 993 mutex_exit(&mboxsc_lock); 994 995 if (datalen > 0) { 996 error = mboxsc_timed_read(deadline, key, MBOXSC_DATA_OFFSET, 997 datalen, (caddr_t)datap); 998 } 999 1000 if (error == 0) { 1001 error = mboxsc_timed_read(deadline, key, header.msg_length, 1002 MBOXSC_CHKSUM_SIZE, (caddr_t)&read_checksum); 1003 } 1004 1005 /* 1006 * Check for errors that may have occurred while accessing IOSRAM. 1007 */ 1008 if (error != 0) { 1009 ASSERT((error != EINVAL) && (error != EMSGSIZE)); 1010 mutex_enter(&mboxsc_lock); 1011 mailboxp->mbox_state &= ~STATE_READING; 1012 if (mailboxp->mbox_state & STATE_HDRVALID) { 1013 cv_broadcast(&(mailboxp->mbox_wait)); 1014 } 1015 mboxsc_dereference_mailbox(mailboxp); 1016 mutex_exit(&mboxsc_lock); 1017 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 1018 "mboxsc_getmsg ret: 0x%08x\n", error); 1019 return (error); 1020 } 1021 1022 /* 1023 * Calculate the checksum for the header and data that was read from 1024 * IOSRAM. 1025 */ 1026 calc_checksum = mboxsc_checksum(CHKSUM_INIT, (uint8_t *)&header, 1027 MBOXSC_MSGHDR_SIZE); 1028 calc_checksum = mboxsc_checksum(calc_checksum, (uint8_t *)datap, 1029 datalen); 1030 1031 /* 1032 * If the message header has been invalidated, note the change. 1033 * If a the checksum verification fails, invalidate the message 1034 * header. In either case, go back to the beginning and wait 1035 * for a new message. 1036 */ 1037 mutex_enter(&mboxsc_lock); 1038 if (!(mailboxp->mbox_state & STATE_HDRVALID)) { 1039 error = -1; 1040 DPRINTF0(DBG_DEV, DBGACT_DEFAULT, 1041 "mboxsc_getmsg - message invalidated while reading\n"); 1042 } else if (read_checksum != calc_checksum) { 1043 error = -1; 1044 mailboxp->mbox_state &= ~STATE_HDRVALID; 1045 DPRINTF0(DBG_DEV, DBGACT_DEFAULT, 1046 "mboxsc_getmsg - message failed checksum\n"); 1047 cmn_err(CE_NOTE, 1048 "mboxsc_getmsg - message failed checksum\n"); 1049 } 1050 1051 if (error == -1) { 1052 mailboxp->mbox_state &= ~STATE_READING; 1053 goto mboxsc_getmsg_retry; 1054 } 1055 1056 /* 1057 * Acquire the hardware lock used for synchronization of data_valid flag 1058 * access to avoid race conditions. If it is acquired, try to check the 1059 * current data_valid flag and transaction ID to verify that the message 1060 * is still valid. 1061 */ 1062 mutex_exit(&mboxsc_lock); 1063 1064 if ((error = mboxsc_lock_flags(FALSE, deadline)) != 0) { 1065 lock_held = FALSE; 1066 /* 1067 * We don't "do" EBUSY here, so treat it as EAGAIN. 1068 */ 1069 if (error == EBUSY) { 1070 error = EAGAIN; 1071 } 1072 } else { 1073 lock_held = TRUE; 1074 } 1075 1076 if (error == 0) { 1077 error = mboxsc_timed_get_flag(deadline, key, &data_valid, NULL); 1078 } 1079 1080 if ((error == 0) && (data_valid == IOSRAM_DATA_VALID)) { 1081 error = mboxsc_timed_read(deadline, key, 1082 FIELD_OFFSET(mboxsc_msghdr_t, msg_transid), 1083 FIELD_SIZE(mboxsc_msghdr_t, msg_transid), 1084 (caddr_t)&read_transid); 1085 } 1086 1087 /* 1088 * If something failed along the way, either the error is unrecoverable 1089 * or we're just plain out of time, so unlock the flags if they were 1090 * locked, release the mailbox, wake up other potential readers if 1091 * there's still a message around, and return. 1092 */ 1093 if (error != 0) { 1094 ASSERT((error != EINVAL) && (error != EMSGSIZE)); 1095 if (lock_held) { 1096 (void) mboxsc_unlock_flags(TRUE); 1097 } 1098 mutex_enter(&mboxsc_lock); 1099 mailboxp->mbox_state &= ~STATE_READING; 1100 if (mailboxp->mbox_state & STATE_HDRVALID) { 1101 cv_broadcast(&(mailboxp->mbox_wait)); 1102 } 1103 mboxsc_dereference_mailbox(mailboxp); 1104 mutex_exit(&mboxsc_lock); 1105 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 1106 "mboxsc_getmsg ret: 0x%08x\n", error); 1107 return (error); 1108 } 1109 1110 /* 1111 * If the data_valid flag isn't set to IOSRAM_DATA_VALID, or the 1112 * message transaction ID in IOSRAM has changed, the message being 1113 * read was timed out by its sender. Since the data_valid flag can't 1114 * change as long as we have the flags locked, we can safely mark the 1115 * stored message header invalid if either the data_valid flag isn't set 1116 * or the stored transaction ID doesn't match the one we read. (If 1117 * data_valid is set, the transaction ID shouldn't be changing 1118 * underneath us.) On the other hand, if there may still be a valid 1119 * message, wake up any pending readers. 1120 */ 1121 if ((data_valid != IOSRAM_DATA_VALID) || 1122 (read_transid != header.msg_transid)) { 1123 mutex_enter(&mboxsc_lock); 1124 mailboxp->mbox_state &= ~STATE_READING; 1125 if ((data_valid != IOSRAM_DATA_VALID) || 1126 (mailboxp->mbox_header.msg_transid != read_transid)) { 1127 mailboxp->mbox_state &= ~STATE_HDRVALID; 1128 } else if (mailboxp->mbox_state & STATE_HDRVALID) { 1129 cv_broadcast(&(mailboxp->mbox_wait)); 1130 } 1131 1132 /* 1133 * Unfortunately, we can't be holding mboxsc_lock when we unlock 1134 * the flags. However, we have to hold the flags until here to 1135 * make sure the SC doesn't change the message's state while 1136 * we're checking to see if we should invalidate our stored 1137 * header. 1138 */ 1139 mutex_exit(&mboxsc_lock); 1140 error = mboxsc_unlock_flags(TRUE); 1141 mutex_enter(&mboxsc_lock); 1142 1143 DPRINTF0(DBG_DEV, DBGACT_DEFAULT, 1144 "mboxsc_getmsg() - message invalidated by sender\n"); 1145 goto mboxsc_getmsg_retry; 1146 } 1147 1148 /* 1149 * If everything has worked up to this point, all that remains is 1150 * to set the data_valid flag to IOSRAM_DATA_INVALID, tidy up, and 1151 * return the message. If the flag can't be set, the message can't 1152 * be received, so keep trying as long as there is time. 1153 */ 1154 error = mboxsc_timed_set_flag(deadline, key, IOSRAM_DATA_INVALID, 1155 IOSRAM_INT_NONE); 1156 1157 (void) mboxsc_unlock_flags(TRUE); 1158 mutex_enter(&mboxsc_lock); 1159 1160 if (error != 0) { 1161 ASSERT(error != EINVAL); 1162 mboxsc_dereference_mailbox(mailboxp); 1163 mailboxp->mbox_state &= ~STATE_READING; 1164 if (mailboxp->mbox_state & STATE_HDRVALID) { 1165 cv_broadcast(&(mailboxp->mbox_wait)); 1166 } 1167 mutex_exit(&mboxsc_lock); 1168 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 1169 "mboxsc_getmsg ret: 0x%08x\n", error); 1170 return (error); 1171 } 1172 1173 /* 1174 * If the message was read 100% successfully and the stored message 1175 * header for the mailbox still matches the message that was read, 1176 * invalidate it to prevent other readers from trying to read it. 1177 */ 1178 if (bcmp(&(mailboxp->mbox_header), &header, MBOXSC_MSGHDR_SIZE) == 0) { 1179 mailboxp->mbox_state &= ~STATE_HDRVALID; 1180 } else if (mailboxp->mbox_state & STATE_HDRVALID) { 1181 cv_broadcast(&(mailboxp->mbox_wait)); 1182 } 1183 1184 mboxsc_dereference_mailbox(mailboxp); 1185 mailboxp->mbox_state &= ~STATE_READING; 1186 mutex_exit(&mboxsc_lock); 1187 1188 /* 1189 * Since we're successfully returning a message, we need to provide the 1190 * caller with all of the interesting header information. 1191 */ 1192 *typep = header.msg_type; 1193 *cmdp = header.msg_cmd; 1194 *transidp = header.msg_transid; 1195 *lengthp = datalen; 1196 1197 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_getmsg ret: 0x%08x\n", 0); 1198 return (0); 1199 } 1200 1201 /* 1202 * mboxsc_ctrl 1203 * 1204 * This routine provides access to a variety of services not available through 1205 * the basic API. 1206 */ 1207 int 1208 mboxsc_ctrl(uint32_t key, uint32_t cmd, void *arg) 1209 { 1210 int error = 0; 1211 mboxsc_mbox_t *mailboxp; 1212 1213 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_ctrl called\n"); 1214 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key); 1215 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "cmd = 0x%x\n", cmd); 1216 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "arg = %p\n", arg); 1217 1218 mutex_enter(&mboxsc_lock); 1219 mailboxp = mboxsc_hashfind_mailbox_by_key(key); 1220 if (mailboxp == NULL) { 1221 mutex_exit(&mboxsc_lock); 1222 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_ctrl ret: 0x%08x\n", 1223 EBADF); 1224 return (EBADF); 1225 } 1226 1227 switch (cmd) { 1228 case MBOXSC_CMD_VERSION: 1229 /* 1230 * Return the Protocol version currently in use. Since 1231 * there is only one version that exists right now, we 1232 * can't be using anything else. 1233 */ 1234 if (arg == NULL) { 1235 error = EINVAL; 1236 break; 1237 } 1238 1239 *(uint32_t *)arg = MBOXSC_PROTOCOL_VERSION; 1240 break; 1241 1242 case MBOXSC_CMD_MAXVERSION: 1243 /* 1244 * Return the highest Protocol version that we support. 1245 */ 1246 if (arg == NULL) { 1247 error = EINVAL; 1248 break; 1249 } 1250 1251 *(uint32_t *)arg = MBOXSC_PROTOCOL_VERSION; 1252 break; 1253 1254 case MBOXSC_CMD_MAXDATALEN: 1255 /* 1256 * Return the amount of space available for client data 1257 * in the indicated mailbox. 1258 */ 1259 if (arg == NULL) { 1260 error = EINVAL; 1261 break; 1262 } 1263 1264 *(uint32_t *)arg = mailboxp->mbox_length - 1265 MBOXSC_PROTOCOL_SIZE; 1266 break; 1267 1268 case MBOXSC_CMD_PUTMSG_TIMEOUT_RANGE: 1269 { 1270 mboxsc_timeout_range_t *rangep; 1271 1272 /* 1273 * Return the range of acceptable timeout values for 1274 * mboxsc_putmsg, expressed in milliseconds. 1275 */ 1276 if (arg == NULL) { 1277 error = EINVAL; 1278 break; 1279 } 1280 1281 rangep = (mboxsc_timeout_range_t *)arg; 1282 rangep->min_timeout = MBOXSC_PUTMSG_MIN_TIMEOUT_MSECS; 1283 rangep->max_timeout = MBOXSC_PUTMSG_MAX_TIMEOUT_MSECS; 1284 break; 1285 } 1286 1287 case MBOXSC_CMD_GETMSG_TIMEOUT_RANGE: 1288 { 1289 mboxsc_timeout_range_t *rangep; 1290 1291 /* 1292 * Return the range of acceptable timeout values for 1293 * mboxsc_getmsg, expressed in milliseconds. 1294 */ 1295 if (arg == NULL) { 1296 error = EINVAL; 1297 break; 1298 } 1299 1300 rangep = (mboxsc_timeout_range_t *)arg; 1301 rangep->min_timeout = MBOXSC_GETMSG_MIN_TIMEOUT_MSECS; 1302 rangep->max_timeout = MBOXSC_GETMSG_MAX_TIMEOUT_MSECS; 1303 break; 1304 } 1305 1306 default: 1307 error = ENOTSUP; 1308 break; 1309 } 1310 1311 mutex_exit(&mboxsc_lock); 1312 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_ctrl ret: 0x%08x\n", error); 1313 return (error); 1314 } 1315 1316 /* 1317 * mboxsc_putmsg_def_timeout 1318 * 1319 * This routine returns the default mboxsc_putmsg timeout provided for the 1320 * convenience of clients. 1321 */ 1322 clock_t 1323 mboxsc_putmsg_def_timeout(void) 1324 { 1325 return (MBOXSC_PUTMSG_DEF_TIMEOUT_MSECS); 1326 } 1327 1328 /* 1329 * mboxsc_iosram_callback 1330 * 1331 * This routine is registered with the IOSRAM driver for all inbound mailboxes, 1332 * and performs preliminary processing of all new messages. 1333 */ 1334 static void 1335 mboxsc_iosram_callback(void *arg) 1336 { 1337 int error = 0; 1338 uint8_t data_valid; 1339 uint32_t key = (uint32_t)(uintptr_t)arg; 1340 mboxsc_mbox_t *mailboxp; 1341 1342 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_iosram_callback called\n"); 1343 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "arg = 0x%x\n", key); 1344 1345 mutex_enter(&mboxsc_lock); 1346 mailboxp = mboxsc_hashfind_mailbox_by_key(key); 1347 1348 /* 1349 * We shouldn't ever receive a callback for a mailbox that doesn't 1350 * exist or for an output mailbox. 1351 */ 1352 ASSERT(mailboxp != NULL); 1353 ASSERT(mailboxp->mbox_direction == MBOXSC_MBOX_IN); 1354 1355 /* 1356 * Attempt to read the header of the mailbox. If the IOSRAM returns 1357 * EAGAIN, indicating a tunnel switch is in progress, do not retry 1358 * the operation. 1359 */ 1360 mailboxp->mbox_state &= ~STATE_HDRVALID; 1361 error = iosram_rd(key, MBOXSC_MSGHDR_OFFSET, MBOXSC_MSGHDR_SIZE, 1362 (caddr_t)&(mailboxp->mbox_header)); 1363 1364 /* 1365 * If somebody sends us a message using a Mailbox Protocol version 1366 * greater than the highest one we understand, ignore the message, 1367 * because we can't safely interpret anything beyond the version field. 1368 */ 1369 if (mailboxp->mbox_header.msg_version > MBOXSC_PROTOCOL_VERSION) { 1370 error = -1; 1371 DPRINTF1(DBG_DEV, DBGACT_DEFAULT, 1372 "incoming message with unsupported version %d\n", 1373 mailboxp->mbox_header.msg_version); 1374 } 1375 1376 /* 1377 * If this message is a repeat of a previous message (which should 1378 * only happen with reply messages), it is conceivable that a client 1379 * already executing in mboxsc_getmsg for the previous message could 1380 * end up receiving the new message before this callback gets a chance 1381 * to execute. If that happens, the data_valid flag will already have 1382 * been cleared. Call iosram_get_flag to see if that is the case, and 1383 * do not process the message if it is. 1384 */ 1385 if (error == 0) { 1386 error = iosram_get_flag(key, &data_valid, NULL); 1387 if ((error == 0) && (data_valid != IOSRAM_DATA_VALID)) { 1388 error = -1; 1389 } 1390 } 1391 1392 /* 1393 * If the iosram_rd call failed, return. 1394 */ 1395 if (error != 0) { 1396 mutex_exit(&mboxsc_lock); 1397 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 1398 "mboxsc_iosram_callback ret (0x%08x)\n", error); 1399 return; 1400 } 1401 1402 /* 1403 * If the message read from IOSRAM was unsolicited, invoke 1404 * its callback. Otherwise, wake all threads that are waiting 1405 * in mboxsc_getmsg. 1406 */ 1407 mailboxp->mbox_state |= STATE_HDRVALID; 1408 if (IS_UNSOLICITED_TYPE(mailboxp->mbox_header.msg_type) && 1409 (mailboxp->mbox_callback != NULL)) { 1410 mboxsc_reference_mailbox(mailboxp); 1411 mutex_exit(&mboxsc_lock); 1412 (*(mailboxp->mbox_callback))(); 1413 mutex_enter(&mboxsc_lock); 1414 mboxsc_dereference_mailbox(mailboxp); 1415 } else { 1416 cv_broadcast(&(mailboxp->mbox_wait)); 1417 } 1418 1419 mutex_exit(&mboxsc_lock); 1420 1421 DPRINTF0(DBG_RETS, DBGACT_DEFAULT, "mboxsc_iosram_callback ret\n"); 1422 } 1423 1424 /* 1425 * mboxsc_hdrchange_callback 1426 * 1427 * This routine is registered with the IOSRAM driver to react to any changes SMS 1428 * makes to the IOSRAM header. 1429 */ 1430 static void 1431 mboxsc_hdrchange_callback(void) 1432 { 1433 int error; 1434 uint32_t sms_version; 1435 1436 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, 1437 "mboxsc_hdrchange_callback called\n"); 1438 1439 error = iosram_hdr_ctrl(IOSRAM_HDRCMD_GET_SMS_MBOX_VER, 1440 (void *)&sms_version); 1441 if (error == 0) { 1442 DPRINTF1(DBG_DEV, DBGACT_DEFAULT, 1443 "sms mailbox version = %d\n", sms_version); 1444 mboxsc_active_version = MIN(MBOXSC_PROTOCOL_VERSION, 1445 sms_version); 1446 } 1447 1448 DPRINTF0(DBG_RETS, DBGACT_DEFAULT, "mboxsc_hdrchange_callback ret\n"); 1449 } 1450 1451 1452 /* 1453 * mboxsc_add_mailbox 1454 * 1455 * If no other mailbox exists with the same key as this mailbox, attempt to 1456 * retrieve its length from the IOSRAM driver and register the mboxsc callback 1457 * for the associated IOSRAM chunk. If successful, initialize the 1458 * non-client-supplied mailbox fields and insert it into the hash table. 1459 * NOTE: The caller MUST hold mboxsc_lock to avoid corrupting the hash table. 1460 */ 1461 static int 1462 mboxsc_add_mailbox(mboxsc_mbox_t *mailboxp) 1463 { 1464 int error = 0; 1465 uint32_t key = mailboxp->mbox_key; 1466 1467 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_add_mailbox called\n"); 1468 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "mailboxp = %p\n", (void *)mailboxp); 1469 1470 /* 1471 * The global lock must be held by the caller. 1472 */ 1473 ASSERT(mutex_owned(&mboxsc_lock)); 1474 1475 /* 1476 * Don't create the mailbox if it already exists. 1477 */ 1478 if (mboxsc_hashfind_mailbox_by_key(key) != NULL) { 1479 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 1480 "mboxsc_add_mailbox ret: 0x%08x\n", EEXIST); 1481 return (EEXIST); 1482 } 1483 1484 /* 1485 * Obtain the mailbox length and register the mboxsc callback with the 1486 * IOSRAM driver. If either call to the IOSRAM driver fails, or the 1487 * chunk is too small to be used as a mailbox, return an error to the 1488 * caller. 1489 */ 1490 error = iosram_ctrl(key, IOSRAM_CMD_CHUNKLEN, &(mailboxp->mbox_length)); 1491 1492 if ((error == 0) && (mailboxp->mbox_length < MBOXSC_PROTOCOL_SIZE)) { 1493 error = EFAULT; 1494 } 1495 1496 if ((error == 0) && (mailboxp->mbox_direction == MBOXSC_MBOX_IN)) { 1497 error = iosram_register(key, mboxsc_iosram_callback, 1498 (void *)(uintptr_t)(key)); 1499 if (error == EBUSY) { 1500 error = EFAULT; 1501 } 1502 } 1503 1504 if (error != 0) { 1505 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 1506 "mboxsc_add_mailbox ret: 0x%08x\n", error); 1507 return (error); 1508 } 1509 1510 /* 1511 * Initialize remaining mailbox fields and insert mailbox into 1512 * hash table. 1513 */ 1514 mailboxp->mbox_state = STATE_IDLE; 1515 mailboxp->mbox_refcount = 0; 1516 cv_init(&(mailboxp->mbox_wait), NULL, CV_DRIVER, NULL); 1517 mboxsc_hashinsert_mailbox(mailboxp); 1518 1519 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_add_mailbox ret: 0x%08x\n", 1520 0); 1521 return (0); 1522 } 1523 1524 /* 1525 * mboxsc_close_mailbox 1526 * 1527 * Remove a mailbox from the hash table, unregister its IOSRAM callback, and 1528 * deallocate its resources. 1529 * NOTE: The caller MUST hold mboxsc_lock to avoid corrupting the hash table. 1530 */ 1531 static void 1532 mboxsc_close_mailbox(mboxsc_mbox_t *mailboxp) 1533 { 1534 int error = 0; 1535 uint32_t key = mailboxp->mbox_key; 1536 1537 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_close_mailbox called\n"); 1538 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "mailboxp = %p\n", (void *)mailboxp); 1539 1540 /* 1541 * The global lock must be held by the caller. 1542 */ 1543 ASSERT(mutex_owned(&mboxsc_lock)); 1544 1545 /* 1546 * Unregister the mboxsc callback for this particular mailbox. 1547 */ 1548 if (mailboxp->mbox_direction == MBOXSC_MBOX_IN) { 1549 error = iosram_unregister(key); 1550 if (error == EINVAL) { 1551 DPRINTF1(DBG_DEV, DBGACT_DEFAULT, "invalid key (0x%08x)" 1552 " reported in mboxsc_close_mailbox.\n", key); 1553 error = 0; 1554 } 1555 } 1556 1557 /* 1558 * Remove the mailbox from the hash table and deallocate its resources. 1559 */ 1560 (void) mboxsc_hashremove_mailbox_by_key(key); 1561 cv_destroy(&(mailboxp->mbox_wait)); 1562 DPRINTF2(DBG_KMEM, DBGACT_DEFAULT, "kmem_free(%p, %lu)\n", 1563 (void *)mailboxp, sizeof (mboxsc_mbox_t)); 1564 kmem_free(mailboxp, sizeof (mboxsc_mbox_t)); 1565 1566 DPRINTF0(DBG_RETS, DBGACT_DEFAULT, "mboxsc_close_mailbox ret\n"); 1567 } 1568 1569 /* 1570 * mboxsc_hashinsert_mailbox 1571 * 1572 * Insert a fully initialized mailbox into the hash table. No duplicate 1573 * checking is performed at this point, so the caller is responsible for 1574 * duplicate prevention if it is desired. 1575 * NOTE: The caller MUST hold mboxsc_lock to avoid corrupting the hash table. 1576 */ 1577 static void 1578 mboxsc_hashinsert_mailbox(mboxsc_mbox_t *mailboxp) 1579 { 1580 uint32_t hash; 1581 1582 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, 1583 "mboxsc_hashinsert_mailbox called\n"); 1584 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "mailboxp = %p\n", (void *)mailboxp); 1585 1586 /* 1587 * The global lock must be held by the caller. 1588 */ 1589 ASSERT(mutex_owned(&mboxsc_lock)); 1590 1591 hash = HASH_KEY(mailboxp->mbox_key); 1592 mailboxp->mbox_hash_next = mboxsc_hash_table[hash]; 1593 mboxsc_hash_table[hash] = mailboxp; 1594 1595 DPRINTF0(DBG_RETS, DBGACT_DEFAULT, 1596 "mboxsc_hashinsert_mailbox ret\n"); 1597 } 1598 1599 /* 1600 * mboxsc_hashfind_mailbox_by_key 1601 * 1602 * Locate a mailbox with the given key in the hash table. Return a pointer 1603 * to the mailbox if it exists, or NULL if no matching mailbox is found. 1604 * NOTE: The caller MUST hold mboxsc_lock to avoid corrupting the hash table. 1605 */ 1606 static mboxsc_mbox_t * 1607 mboxsc_hashfind_mailbox_by_key(uint32_t key) 1608 { 1609 uint32_t hash; 1610 mboxsc_mbox_t *mailboxp; 1611 1612 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, 1613 "mboxsc_hashfind_mailbox_by_key called\n"); 1614 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key); 1615 1616 /* 1617 * The global lock must be held by the caller. 1618 */ 1619 ASSERT(mutex_owned(&mboxsc_lock)); 1620 1621 hash = HASH_KEY(key); 1622 mailboxp = mboxsc_hash_table[hash]; 1623 while (mailboxp != NULL) { 1624 if (mailboxp->mbox_key == key) { 1625 break; 1626 } 1627 mailboxp = mailboxp->mbox_hash_next; 1628 } 1629 1630 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 1631 "mboxsc_hashfind_mailbox_by_key ret: %p\n", (void *)mailboxp); 1632 return (mailboxp); 1633 } 1634 1635 /* 1636 * mboxsc_hashremove_mailbox_by_key 1637 * 1638 * Locate a mailbox with the given key in the hash table. If it exists, 1639 * remove it from the hash table and return a pointer to it. Otherwise, 1640 * return NULL. 1641 * NOTE: The caller MUST hold mboxsc_lock to avoid corrupting the hash table. 1642 */ 1643 static mboxsc_mbox_t * 1644 mboxsc_hashremove_mailbox_by_key(uint32_t key) 1645 { 1646 uint32_t hash; 1647 mboxsc_mbox_t *mailboxp; 1648 mboxsc_mbox_t *last; 1649 1650 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, 1651 "mboxsc_hashremove_mailbox_by_key called\n"); 1652 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key); 1653 1654 /* 1655 * The global lock must be held by the caller. 1656 */ 1657 ASSERT(mutex_owned(&mboxsc_lock)); 1658 1659 hash = HASH_KEY(key); 1660 mailboxp = mboxsc_hash_table[hash]; 1661 last = NULL; 1662 while (mailboxp != NULL) { 1663 if (mailboxp->mbox_key == key) { 1664 break; 1665 } 1666 last = mailboxp; 1667 mailboxp = mailboxp->mbox_hash_next; 1668 } 1669 1670 /* 1671 * If a mailbox was found, remove it from the hash table. 1672 */ 1673 if (mailboxp != NULL) { 1674 if (last == NULL) { 1675 mboxsc_hash_table[hash] = mailboxp->mbox_hash_next; 1676 } else { 1677 last->mbox_hash_next = mailboxp->mbox_hash_next; 1678 } 1679 1680 mailboxp->mbox_hash_next = NULL; 1681 } 1682 1683 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 1684 "mboxsc_hashremove_mailbox_by_key ret: %p\n", (void *)mailboxp); 1685 return (mailboxp); 1686 } 1687 1688 /* 1689 * mboxsc_checksum 1690 * 1691 * Given a pointer to a data buffer and its length, calculate the checksum of 1692 * the data contained therein. 1693 */ 1694 static mboxsc_chksum_t 1695 mboxsc_checksum(mboxsc_chksum_t seed, uint8_t *buf, uint32_t length) 1696 { 1697 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_checksum called\n"); 1698 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "seed = 0x%x\n", seed); 1699 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "buf = %p\n", (void *)buf); 1700 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "length = 0x%x\n", length); 1701 1702 while (length-- > 0) { 1703 seed += *(buf++); 1704 } 1705 1706 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_checksum ret: 0x%08x\n", 1707 seed); 1708 return (seed); 1709 } 1710 1711 /* 1712 * mboxsc_lock_flags 1713 * 1714 * Acquire the hardware lock used for data_valid flag synchronization. If the 1715 * lock is currently held by SMS and acquisition is mandatory, just keep on 1716 * trying until it is acquired. If acquisition is not mandatory, keep trying 1717 * until the given deadline has been reached. To avoid loading the system 1718 * unreasonably on EBUSY or EAGAIN, sleep for an appropriate amount of time 1719 * before retrying. If a hardware error is encountered return it to the caller. 1720 * 1721 * If the lock is held, but not by SMS, clear it and acquire it. Nobody 1722 * else should be grabbing that lock. 1723 */ 1724 static int 1725 mboxsc_lock_flags(uint8_t mandatory, clock_t deadline) 1726 { 1727 int error; 1728 int warned = 0; 1729 uint32_t sema; 1730 clock_t pause; 1731 clock_t warning_time = ddi_get_lbolt() + LOOP_WARN_INTERVAL; 1732 1733 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_lock_flags called\n"); 1734 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "mandatory = 0x%x\n", mandatory); 1735 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "deadline = 0x%lx\n", deadline); 1736 1737 /* 1738 * Keep trying to acquire the lock until successful or (if acquisition 1739 * is not mandatory) time runs out. If EBUSY (lock is already held) or 1740 * EAGAIN (tunnel switch in progress) is encountered, sleep for an 1741 * appropriate amount of time before retrying. Any other error is 1742 * unrecoverable. 1743 */ 1744 do { 1745 pause = 0; 1746 1747 /* 1748 * Since multiple threads could conceivably want the flag lock 1749 * at the same time, we place the lock under a mutex and keep a 1750 * counter indicating how many threads have the flags locked at 1751 * the moment. 1752 */ 1753 mutex_enter(&mboxsc_lock); 1754 if ((mboxsc_flaglock_count > 0) || 1755 ((error = iosram_sema_acquire(&sema)) == 0)) { 1756 mboxsc_flaglock_count++; 1757 mutex_exit(&mboxsc_lock); 1758 1759 if (warned) { 1760 cmn_err(CE_WARN, "Flags locked"); 1761 } 1762 DPRINTF0(DBG_RETS, DBGACT_DEFAULT, 1763 "mboxsc_lock_flags ret: 0\n"); 1764 return (0); 1765 } 1766 1767 /* 1768 * If iosram_sema_acquire returned EBUSY (lock already held), 1769 * make sure the lock is held by SMS, since nobody else should 1770 * ever be holding it. If EBUSY or EAGAIN (tunnel switch in 1771 * progress) was returned, determine the appropriate amount of 1772 * time to sleep before trying again. 1773 */ 1774 if (error == EBUSY) { 1775 if (IOSRAM_SEMA_GET_IDX(sema) != IOSRAM_SEMA_SMS_IDX) { 1776 (void) iosram_sema_release(); 1777 cmn_err(CE_WARN, 1778 "Incorrect flag lock value read (0x%08x)", 1779 sema); 1780 } else { 1781 pause = (mandatory ? HWLOCK_POLL : 1782 MIN(HWLOCK_POLL, deadline - 1783 ddi_get_lbolt())); 1784 } 1785 } else if (error == EAGAIN) { 1786 pause = (mandatory ? EAGAIN_POLL : MIN(EAGAIN_POLL, 1787 deadline - ddi_get_lbolt())); 1788 } 1789 1790 /* 1791 * We had to hold the lock until now to protect the potential 1792 * iosram_sema_release call above. 1793 */ 1794 mutex_exit(&mboxsc_lock); 1795 1796 /* 1797 * If EAGAIN or EBUSY was encountered, we're looping. 1798 */ 1799 if ((error == EAGAIN) || (error == EBUSY)) { 1800 /* 1801 * If we've been looping here for a while, something is 1802 * probably wrong, so we should generated a warning. 1803 */ 1804 if (warning_time - ddi_get_lbolt() <= 0) { 1805 if (!warned) { 1806 warned = 1; 1807 cmn_err(CE_WARN, 1808 "Unable to lock flags (0x%08x)", 1809 error); 1810 } else { 1811 cmn_err(CE_WARN, 1812 "Still unable to lock flags"); 1813 } 1814 warning_time = ddi_get_lbolt() + 1815 LOOP_WARN_INTERVAL; 1816 } 1817 1818 /* 1819 * Sleep a while before trying again. 1820 */ 1821 delay(pause); 1822 } 1823 } while (((error == EAGAIN) || (error == EBUSY)) && 1824 (mandatory || (deadline - ddi_get_lbolt() >= 0))); 1825 1826 /* 1827 * If something really bad has happened, generate a warning. 1828 */ 1829 if ((error != EAGAIN) && (error != EBUSY)) { 1830 cmn_err(CE_WARN, "Flag locking failed! (%d)", error); 1831 } 1832 1833 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_lock_flags ret: 0x%08x\n", 1834 error); 1835 return (error); 1836 } 1837 1838 /* 1839 * mboxsc_unlock_flags 1840 * 1841 * Release the hardware lock used for data_valid flag synchronization. 1842 * If a hardware error is encountered, return it to the caller. If the 1843 * mandatory flag is set, loop and retry if EAGAIN is encountered. 1844 */ 1845 static int 1846 mboxsc_unlock_flags(uint8_t mandatory) 1847 { 1848 int error; 1849 int warned = 0; 1850 clock_t warning_time = ddi_get_lbolt() + LOOP_WARN_INTERVAL; 1851 1852 ASSERT(mboxsc_flaglock_count != 0); 1853 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_unlock_flags called\n"); 1854 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "mandatory = 0x%x\n", mandatory); 1855 1856 do { 1857 /* 1858 * Since multiple threads could conceivably want the flag lock 1859 * at the same time, we place the lock under a mutex and keep a 1860 * counter indicating how many threads have the flags locked at 1861 * the moment. 1862 */ 1863 mutex_enter(&mboxsc_lock); 1864 if ((mboxsc_flaglock_count > 1) || 1865 ((error = iosram_sema_release()) == 0)) { 1866 mboxsc_flaglock_count--; 1867 mutex_exit(&mboxsc_lock); 1868 1869 if (warned) { 1870 cmn_err(CE_WARN, "Flags unlocked"); 1871 } 1872 DPRINTF0(DBG_RETS, DBGACT_DEFAULT, 1873 "mboxsc_unlock_flags ret: 0\n"); 1874 return (0); 1875 } 1876 mutex_exit(&mboxsc_lock); 1877 1878 /* 1879 * If iosram_sema_release returned EAGAIN (tunnel switch in 1880 * progress) and unlocking the flags is mandatory, sleep before 1881 * trying again. If we've been trying for a while, display a 1882 * warning message too. 1883 */ 1884 if ((error == EAGAIN) && mandatory) { 1885 if (warning_time - ddi_get_lbolt() <= 0) { 1886 if (!warned) { 1887 warned = 1; 1888 cmn_err(CE_WARN, "Unable to unlock " 1889 "flags (iosram EAGAIN)"); 1890 } else { 1891 cmn_err(CE_WARN, 1892 "Still unable to unlock flags"); 1893 } 1894 warning_time = ddi_get_lbolt() + 1895 LOOP_WARN_INTERVAL; 1896 } 1897 1898 delay(EAGAIN_POLL); 1899 } 1900 } while ((error == EAGAIN) && mandatory); 1901 1902 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_unlock_flags ret: 0x%08x\n", 1903 error); 1904 return (error); 1905 } 1906 1907 /* 1908 * mboxsc_timed_read 1909 * 1910 * This function is just a wrapper around iosram_rd that will keep sleeping 1911 * and retrying, up to a given deadline, if iosram_rd returns EAGAIN 1912 * (presumably due to a tunnel switch). 1913 */ 1914 static int 1915 mboxsc_timed_read(clock_t deadline, uint32_t key, uint32_t off, uint32_t len, 1916 caddr_t dptr) 1917 { 1918 int error; 1919 1920 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_timed_read called\n"); 1921 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "deadline = 0x%lx\n", deadline); 1922 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key); 1923 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "off = 0x%x\n", off); 1924 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "len = 0x%x\n", len); 1925 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "dptr = %p\n", (void *)dptr); 1926 1927 do { 1928 error = iosram_rd(key, off, len, dptr); 1929 if (error == EAGAIN) { 1930 delay(MIN(EAGAIN_POLL, deadline - ddi_get_lbolt())); 1931 } 1932 } while ((error == EAGAIN) && (deadline - ddi_get_lbolt() >= 0)); 1933 1934 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 1935 "mboxsc_timed_read ret: 0x%08x\n", error); 1936 return (error); 1937 } 1938 1939 /* 1940 * mboxsc_timed_write 1941 * 1942 * This function is just a wrapper around iosram_wr that will keep sleeping 1943 * and retrying, up to a given deadline, if iosram_wr returns EAGAIN 1944 * (presumably due to a tunnel switch). 1945 */ 1946 static int 1947 mboxsc_timed_write(clock_t deadline, uint32_t key, uint32_t off, uint32_t len, 1948 caddr_t dptr) 1949 { 1950 int error; 1951 1952 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_timed_write called\n"); 1953 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "deadline = 0x%lx\n", deadline); 1954 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key); 1955 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "off = 0x%x\n", off); 1956 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "len = 0x%x\n", len); 1957 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "dptr = %p\n", (void *)dptr); 1958 1959 do { 1960 error = iosram_wr(key, off, len, dptr); 1961 if (error == EAGAIN) { 1962 delay(MIN(EAGAIN_POLL, deadline - ddi_get_lbolt())); 1963 } 1964 } while ((error == EAGAIN) && (deadline - ddi_get_lbolt() >= 0)); 1965 1966 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 1967 "mboxsc_timed_write ret: 0x%08x\n", error); 1968 return (error); 1969 } 1970 1971 /* 1972 * mboxsc_timed_get_flag 1973 * 1974 * This function is just a wrapper around iosram_get_flag that will keep 1975 * sleeping and retrying, up to a given deadline, if iosram_get_flag returns 1976 * EAGAIN (presumably due to a tunnel switch). 1977 */ 1978 static int 1979 mboxsc_timed_get_flag(clock_t deadline, uint32_t key, uint8_t *data_validp, 1980 uint8_t *int_pendingp) 1981 { 1982 int error; 1983 1984 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_timed_get_flag called\n"); 1985 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "deadline = 0x%lx\n", deadline); 1986 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key); 1987 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "data_validp = %p\n", 1988 (void *)data_validp); 1989 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "int_pendingp = %p\n", 1990 (void *)int_pendingp); 1991 1992 do { 1993 error = iosram_get_flag(key, data_validp, int_pendingp); 1994 if (error == EAGAIN) { 1995 delay(MIN(EAGAIN_POLL, deadline - ddi_get_lbolt())); 1996 } 1997 } while ((error == EAGAIN) && (deadline - ddi_get_lbolt() >= 0)); 1998 1999 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 2000 "mboxsc_timed_get_flag ret: 0x%08x\n", error); 2001 return (error); 2002 } 2003 2004 /* 2005 * mboxsc_timed_set_flag 2006 * 2007 * This function is just a wrapper around iosram_set_flag that will keep 2008 * sleeping and retrying, up to a given deadline, if iosram_set_flag returns 2009 * EAGAIN (presumably due to a tunnel switch). 2010 */ 2011 static int 2012 mboxsc_timed_set_flag(clock_t deadline, uint32_t key, uint8_t data_valid, 2013 uint8_t int_pending) 2014 { 2015 int error; 2016 2017 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_timed_set_flag called\n"); 2018 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "deadline = 0x%lx\n", deadline); 2019 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key); 2020 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "data_valid = %d\n", data_valid); 2021 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "int_pending = %d\n", int_pending); 2022 2023 do { 2024 error = iosram_set_flag(key, data_valid, int_pending); 2025 if (error == EAGAIN) { 2026 delay(MIN(EAGAIN_POLL, deadline - ddi_get_lbolt())); 2027 } 2028 } while ((error == EAGAIN) && (deadline - ddi_get_lbolt() >= 0)); 2029 2030 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 2031 "mboxsc_timed_set_flag ret: 0x%08x\n", error); 2032 return (error); 2033 } 2034 2035 /* 2036 * mboxsc_timed_send_intr 2037 * 2038 * This function is just a wrapper around iosram_send_intr that will keep 2039 * sleeping and retrying, up to a given deadline, if iosram_send_intr returns 2040 * EAGAIN (presumably due to a tunnel switch). 2041 */ 2042 static int 2043 mboxsc_timed_send_intr(clock_t deadline) 2044 { 2045 int error; 2046 2047 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_timed_send_intr called\n"); 2048 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "deadline = 0x%lx\n", deadline); 2049 2050 do { 2051 error = iosram_send_intr(); 2052 if (error == DDI_FAILURE) { 2053 delay(MIN(EAGAIN_POLL, deadline - ddi_get_lbolt())); 2054 } 2055 } while ((error == DDI_FAILURE) && (deadline - ddi_get_lbolt() >= 0)); 2056 2057 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 2058 "mboxsc_timed_send_intr ret: 0x%08x\n", error); 2059 return (error); 2060 } 2061 2062 /* 2063 * mboxsc_expire_message 2064 * 2065 * This function is called by mboxsc_putmsg to handle expiration of messages 2066 * that weren't picked up before they timed out. It will not return until the 2067 * message has been picked up (which isn't expected), the message has been 2068 * successfully expired, or a serious error has been encountered. If the 2069 * message is finally picked up, it will set the value pointed to by "resultp" 2070 * to 0. Unlike other sections of code, this function will never time out on 2071 * EAGAIN from the iosram driver, since it is important that both sides of the 2072 * IOSRAM agree on whether or not a message was delivered successfully. 2073 */ 2074 static int 2075 mboxsc_expire_message(uint32_t key, int *resultp) 2076 { 2077 int error = 0; 2078 int lock_held = 0; 2079 int warned = 0; 2080 uint8_t data_valid; 2081 clock_t warning_time = ddi_get_lbolt() + LOOP_WARN_INTERVAL; 2082 2083 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_expire_message called\n"); 2084 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key); 2085 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "resultp = %p\n", (void *)resultp); 2086 2087 do { 2088 error = 0; 2089 2090 /* 2091 * Lock the flags if they aren't locked already. 2092 */ 2093 if (!lock_held) { 2094 error = mboxsc_lock_flags(TRUE, 0); 2095 if (error == 0) { 2096 lock_held = 1; 2097 } 2098 } 2099 2100 /* 2101 * If the flags were locked successfully, reread the data-valid 2102 * flag. 2103 */ 2104 if (error == 0) { 2105 error = iosram_get_flag(key, &data_valid, NULL); 2106 } 2107 2108 /* 2109 * If the data-valid flag was read successfully, see if it has 2110 * been cleared or not, as the other side may have finally read 2111 * the message. 2112 */ 2113 if (error == 0) { 2114 if (data_valid == IOSRAM_DATA_INVALID) { 2115 /* 2116 * Surprise! The SC finally picked up the 2117 * message, so delivery succeeded after all. 2118 */ 2119 if (*resultp == ETIMEDOUT) { 2120 *resultp = 0; 2121 } 2122 } else { 2123 /* 2124 * The message still hasn't been read, so try to 2125 * clear the data-valid flag. 2126 */ 2127 error = iosram_set_flag(key, 2128 IOSRAM_DATA_INVALID, IOSRAM_INT_NONE); 2129 } 2130 } 2131 2132 /* 2133 * If the flags were locked, unlock them, no matter what else 2134 * has or has not succeeded. Don't overwrite the existing value 2135 * of "error" unless no errors other than EAGAIN have been 2136 * encountered previously. If we hit EAGAIN at some point, 2137 * unlocking the flags here is optional. In all other cases, it 2138 * is mandatory. 2139 */ 2140 if (lock_held) { 2141 int unlock_err; 2142 2143 if (error == EAGAIN) { 2144 unlock_err = mboxsc_unlock_flags(FALSE); 2145 } else { 2146 unlock_err = mboxsc_unlock_flags(TRUE); 2147 } 2148 2149 if (unlock_err == 0) { 2150 lock_held = 0; 2151 } else if ((error == 0) || (error == EAGAIN)) { 2152 error = unlock_err; 2153 } 2154 } 2155 2156 /* 2157 * Did we hit a tunnel switch? (iosram driver returns EAGAIN) 2158 * If so, sleep for a while before trying the whole process 2159 * again. 2160 */ 2161 if (error == EAGAIN) { 2162 /* 2163 * If we've been stuck in this loop for a while, 2164 * something is probably wrong, and we should display a 2165 * warning. 2166 */ 2167 if (warning_time - ddi_get_lbolt() <= 0) { 2168 if (!warned) { 2169 warned = 1; 2170 cmn_err(CE_WARN, "Unable to clear flag " 2171 "(iosram EAGAIN)"); 2172 } else { 2173 cmn_err(CE_WARN, 2174 "Still unable to clear flag"); 2175 } 2176 warning_time = ddi_get_lbolt() + 2177 LOOP_WARN_INTERVAL; 2178 } 2179 2180 delay(EAGAIN_POLL); 2181 } 2182 } while (error == EAGAIN); 2183 2184 /* 2185 * If the data-valid flag was not successfully cleared due to some sort 2186 * of problem, report it. Otherwise, if we looped for a while on EAGAIN 2187 * and generated a warning about it, indicate that everything is okay 2188 * now. 2189 */ 2190 if (error != 0) { 2191 cmn_err(CE_WARN, "Message expiration failure! (%d)", error); 2192 } else if (warned) { 2193 cmn_err(CE_WARN, "Flag cleared"); 2194 } 2195 2196 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 2197 "mboxsc_expire_message ret: 0x%08x\n", error); 2198 return (error); 2199 } 2200 2201 2202 /* 2203 * mboxsc_generate_transid 2204 * 2205 * This function generates unique transaction IDs using an incrementing counter. 2206 * The value generated is guaranteed not to be the same as the prev_transid 2207 * value passed in by the caller. 2208 */ 2209 static uint64_t 2210 mboxsc_generate_transid(uint64_t prev_transid) 2211 { 2212 uint64_t new_transid; 2213 static uint64_t transid_counter = 0; 2214 2215 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_generate_transid called"); 2216 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "prev_transid = 0x%016lx\n", 2217 prev_transid); 2218 2219 do { 2220 new_transid = TRANSID_GEN_MASK | transid_counter++; 2221 if (transid_counter & TRANSID_GEN_MASK) { 2222 transid_counter = 0; 2223 } 2224 } while (new_transid == prev_transid); 2225 2226 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 2227 "mboxsc_generate_transid ret: 0x%016lx", new_transid); 2228 return (new_transid); 2229 } 2230 2231 2232 /* 2233 * mboxsc_reference_mailbox 2234 * 2235 * Increment the mailbox's reference count to prevent it from being closed. 2236 * This really doesn't deserve to be a function, but since a dereference 2237 * function is needed, having a corresponding reference function makes the code 2238 * clearer. 2239 */ 2240 static void 2241 mboxsc_reference_mailbox(mboxsc_mbox_t *mailboxp) 2242 { 2243 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_reference_mailbox called"); 2244 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "mailboxp = 0x%p\n", 2245 (void *)mailboxp); 2246 2247 ASSERT(mutex_owned(&mboxsc_lock)); 2248 2249 mailboxp->mbox_refcount++; 2250 2251 DPRINTF0(DBG_RETS, DBGACT_DEFAULT, "mboxsc_reference_mailbox ret"); 2252 } 2253 2254 2255 /* 2256 * mboxsc_dereference_mailbox 2257 * 2258 * Decrement the mailbox's reference count, and if the count has gone to zero, 2259 * signal any threads waiting for mailboxes to be completely dereferenced. 2260 */ 2261 static void 2262 mboxsc_dereference_mailbox(mboxsc_mbox_t *mailboxp) 2263 { 2264 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, 2265 "mboxsc_dereference_mailbox called"); 2266 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "mailboxp = 0x%p\n", 2267 (void *)mailboxp); 2268 2269 ASSERT(mutex_owned(&mboxsc_lock)); 2270 2271 mailboxp->mbox_refcount--; 2272 if (mailboxp->mbox_refcount == 0) { 2273 cv_broadcast(&mboxsc_dereference_cv); 2274 } 2275 2276 DPRINTF0(DBG_RETS, DBGACT_DEFAULT, "mboxsc_dereference_mailbox ret"); 2277 } 2278 2279 2280 #ifndef DEBUG 2281 /* ARGSUSED */ 2282 int 2283 mboxsc_debug(int cmd, void *arg) 2284 { 2285 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_debug called"); 2286 DPRINTF0(DBG_RETS, DBGACT_DEFAULT, "mboxsc_debug ret"); 2287 return (ENOTSUP); 2288 } 2289 #else /* DEBUG */ 2290 2291 static void print_hash_table(void); 2292 static int print_mailbox_by_key(uint32_t key); 2293 static void print_mailbox(mboxsc_mbox_t *mailboxp); 2294 2295 int 2296 mboxsc_debug(int cmd, void *arg) 2297 { 2298 int error = 0; 2299 2300 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_debug called\n"); 2301 2302 switch (cmd) { 2303 case MBOXSC_PRNMBOX: 2304 error = print_mailbox_by_key((uint32_t)(uintptr_t)arg); 2305 break; 2306 2307 case MBOXSC_PRNHASHTBL: 2308 print_hash_table(); 2309 break; 2310 2311 case MBOXSC_SETDBGMASK: 2312 mboxsc_debug_mask = (uint32_t)(uintptr_t)arg; 2313 break; 2314 2315 default: 2316 DPRINTF1(DBG_DEV, DBGACT_DEFAULT, 2317 "Error: unknown mboxsc debug cmd (%d)\n", cmd); 2318 error = ENOTTY; 2319 break; 2320 } 2321 2322 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_debug ret: 0x%08x\n", error); 2323 2324 return (error); 2325 } 2326 2327 /*PRINTFLIKE5*/ 2328 static void 2329 mboxsc_dprintf( 2330 const char *file, 2331 int line, 2332 uint32_t class, 2333 uint32_t action, 2334 const char *fmt, 2335 ...) 2336 { 2337 int i; 2338 char indent_buf[64]; 2339 char msg_buf[256]; 2340 va_list adx; 2341 static uint32_t indent = 0; 2342 2343 if (action & DBGACT_SHOWPOS) { 2344 cmn_err(CE_CONT, "%s at line %d:\n", file, line); 2345 } 2346 2347 if (class & DBG_RETS) { 2348 indent--; 2349 } 2350 2351 if (class & mboxsc_debug_mask) { 2352 indent_buf[0] = '\0'; 2353 for (i = 0; i < indent; i++) { 2354 (void) strcat(indent_buf, " "); 2355 } 2356 2357 va_start(adx, fmt); 2358 (void) vsprintf(msg_buf, fmt, adx); 2359 va_end(adx); 2360 2361 cmn_err(CE_CONT, "%s%s", indent_buf, msg_buf); 2362 } 2363 2364 if (class & DBG_CALLS) { 2365 indent++; 2366 } 2367 2368 if (action & DBGACT_BREAK) { 2369 debug_enter(""); 2370 } 2371 } 2372 2373 static void 2374 print_hash_table(void) 2375 { 2376 int i; 2377 mboxsc_mbox_t *mailboxp; 2378 2379 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "print_hash_table called\n"); 2380 2381 mutex_enter(&mboxsc_lock); 2382 2383 for (i = 0; i < HASHTBL_SIZE; i++) { 2384 DPRINTF1(DBG_DEV, DBGACT_DEFAULT, "hash[%02d]:\n", i); 2385 2386 for (mailboxp = mboxsc_hash_table[i]; mailboxp != NULL; 2387 mailboxp = mailboxp->mbox_hash_next) { 2388 DPRINTF2(DBG_DEV, DBGACT_DEFAULT, 2389 " key: 0x%08x, dir: %d\n", mailboxp->mbox_key, 2390 mailboxp->mbox_direction); 2391 } 2392 } 2393 2394 mutex_exit(&mboxsc_lock); 2395 2396 DPRINTF0(DBG_RETS, DBGACT_DEFAULT, "print_hash_table ret\n"); 2397 } 2398 2399 static int 2400 print_mailbox_by_key(uint32_t key) 2401 { 2402 int error = 0; 2403 mboxsc_mbox_t *mailboxp; 2404 2405 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "print_mailbox_by_key called\n"); 2406 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%08x\n", key); 2407 2408 mutex_enter(&mboxsc_lock); 2409 2410 mailboxp = mboxsc_hashfind_mailbox_by_key(key); 2411 if (mailboxp != NULL) { 2412 print_mailbox(mailboxp); 2413 error = 0; 2414 } else { 2415 DPRINTF1(DBG_DEV, DBGACT_DEFAULT, 2416 "print_mailbox_by_key: no such mbox 0x%08x\n", key); 2417 error = EBADF; 2418 } 2419 2420 mutex_exit(&mboxsc_lock); 2421 DPRINTF1(DBG_RETS, DBGACT_DEFAULT, 2422 "print_mailbox_by_key ret: 0x%08x\n", error); 2423 2424 return (error); 2425 } 2426 2427 /* ARGSUSED */ 2428 static void 2429 print_mailbox(mboxsc_mbox_t *mailboxp) 2430 { 2431 DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "print_mailbox called\n"); 2432 DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "mailboxp = %p\n", 2433 (void *)mailboxp); 2434 if (mailboxp->mbox_direction == MBOXSC_MBOX_IN) { 2435 DPRINTF3(DBG_DEV, DBGACT_DEFAULT, 2436 "key = 0x%08x, dir = %d, callback = %p\n", 2437 mailboxp->mbox_key, mailboxp->mbox_direction, 2438 (void *)mailboxp->mbox_callback); 2439 } else { 2440 DPRINTF2(DBG_DEV, DBGACT_DEFAULT, "key = 0x%08x, dir = %d\n", 2441 (int)mailboxp->mbox_key, mailboxp->mbox_direction); 2442 } 2443 DPRINTF3(DBG_DEV, DBGACT_DEFAULT, 2444 "length = %d, refcount = %d, state = %d\n", 2445 mailboxp->mbox_length, mailboxp->mbox_refcount, 2446 mailboxp->mbox_state); 2447 /* LINTED E_BAD_FORMAT_ARG_TYPE2 */ 2448 DPRINTF2(DBG_DEV, DBGACT_DEFAULT, "waitcv = %p, hashnext = %p\n", 2449 (void *)&mailboxp->mbox_wait, (void *)mailboxp->mbox_hash_next); 2450 if (mailboxp->mbox_direction == MBOXSC_MBOX_IN) { 2451 DPRINTF3(DBG_DEV, DBGACT_DEFAULT, 2452 "hdr.type = 0x%x, hdr.cmd = 0x%x, hdr.len = 0x%x\n", 2453 mailboxp->mbox_header.msg_type, 2454 mailboxp->mbox_header.msg_cmd, 2455 mailboxp->mbox_header.msg_length); 2456 DPRINTF1(DBG_DEV, DBGACT_DEFAULT, "hdr.tid = 0x%016lx\n", 2457 mailboxp->mbox_header.msg_transid); 2458 } 2459 DPRINTF0(DBG_RETS, DBGACT_DEFAULT, "print_mailbox ret\n"); 2460 } 2461 #endif /* DEBUG */ 2462