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
_init(void)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
_fini(void)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
_info(struct modinfo * modinfop)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
mboxsc_init(uint32_t key,int direction,void (* event_handler)(void))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
mboxsc_fini(uint32_t key)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
mboxsc_putmsg(uint32_t key,uint32_t type,uint32_t cmd,uint64_t * transidp,uint32_t length,void * datap,clock_t timeout)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
mboxsc_getmsg(uint32_t key,uint32_t * typep,uint32_t * cmdp,uint64_t * transidp,uint32_t * lengthp,void * datap,clock_t timeout)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
mboxsc_ctrl(uint32_t key,uint32_t cmd,void * arg)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
mboxsc_putmsg_def_timeout(void)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
mboxsc_iosram_callback(void * arg)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
mboxsc_hdrchange_callback(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
mboxsc_add_mailbox(mboxsc_mbox_t * mailboxp)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
mboxsc_close_mailbox(mboxsc_mbox_t * mailboxp)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
mboxsc_hashinsert_mailbox(mboxsc_mbox_t * mailboxp)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 *
mboxsc_hashfind_mailbox_by_key(uint32_t key)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 *
mboxsc_hashremove_mailbox_by_key(uint32_t key)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
mboxsc_checksum(mboxsc_chksum_t seed,uint8_t * buf,uint32_t length)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
mboxsc_lock_flags(uint8_t mandatory,clock_t deadline)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
mboxsc_unlock_flags(uint8_t mandatory)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
mboxsc_timed_read(clock_t deadline,uint32_t key,uint32_t off,uint32_t len,caddr_t dptr)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
mboxsc_timed_write(clock_t deadline,uint32_t key,uint32_t off,uint32_t len,caddr_t dptr)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
mboxsc_timed_get_flag(clock_t deadline,uint32_t key,uint8_t * data_validp,uint8_t * int_pendingp)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
mboxsc_timed_set_flag(clock_t deadline,uint32_t key,uint8_t data_valid,uint8_t int_pending)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
mboxsc_timed_send_intr(clock_t deadline)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
mboxsc_expire_message(uint32_t key,int * resultp)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
mboxsc_generate_transid(uint64_t prev_transid)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
mboxsc_reference_mailbox(mboxsc_mbox_t * mailboxp)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
mboxsc_dereference_mailbox(mboxsc_mbox_t * mailboxp)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
mboxsc_debug(int cmd,void * arg)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
mboxsc_debug(int cmd,void * arg)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
mboxsc_dprintf(const char * file,int line,uint32_t class,uint32_t action,const char * fmt,...)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
print_hash_table(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
print_mailbox_by_key(uint32_t key)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
print_mailbox(mboxsc_mbox_t * mailboxp)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