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