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