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