xref: /onnv-gate/usr/src/uts/sun4u/starcat/io/mboxsc.c (revision 11311:639e7bc0b42f)
11708Sstevel /*
21708Sstevel  * CDDL HEADER START
31708Sstevel  *
41708Sstevel  * The contents of this file are subject to the terms of the
51708Sstevel  * Common Development and Distribution License (the "License").
61708Sstevel  * You may not use this file except in compliance with the License.
71708Sstevel  *
81708Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel  * or http://www.opensolaris.org/os/licensing.
101708Sstevel  * See the License for the specific language governing permissions
111708Sstevel  * and limitations under the License.
121708Sstevel  *
131708Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel  * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel  *
191708Sstevel  * CDDL HEADER END
201708Sstevel  */
211708Sstevel 
221708Sstevel /*
23*11311SSurya.Prakki@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
241708Sstevel  * Use is subject to license terms.
251708Sstevel  */
261708Sstevel 
271708Sstevel /*
281708Sstevel  * This file contains the implementation of the mboxsc module, a mailbox layer
291708Sstevel  * built upon the Starcat IOSRAM driver.
301708Sstevel  */
311708Sstevel 
321708Sstevel #include <sys/types.h>
331708Sstevel #include <sys/systm.h>
341708Sstevel #include <sys/modctl.h>
351708Sstevel #include <sys/errno.h>
361708Sstevel #include <sys/ksynch.h>
371708Sstevel #include <sys/kmem.h>
381708Sstevel #include <sys/varargs.h>
391708Sstevel #include <sys/ddi.h>
401708Sstevel #include <sys/sunddi.h>
411708Sstevel #include <sys/cmn_err.h>
421708Sstevel #include <sys/debug.h>
431708Sstevel #include <sys/sysmacros.h>
441708Sstevel 
451708Sstevel #include <sys/iosramreg.h>
461708Sstevel #include <sys/iosramio.h>
471708Sstevel #include <sys/mboxsc.h>
481708Sstevel #include <sys/mboxsc_impl.h>
491708Sstevel 
501708Sstevel /*
511708Sstevel  * Debugging facility
521708Sstevel  */
531708Sstevel #define	DBGACT_NONE	(0x00000000)
541708Sstevel #define	DBGACT_BREAK	(0x00000001)
551708Sstevel #define	DBGACT_SHOWPOS	(0x00000002)
561708Sstevel #define	DBGACT_DEFAULT	DBGACT_NONE
571708Sstevel 
581708Sstevel #define	DBG_DEV		(0x00000001)
591708Sstevel #define	DBG_CALLS	(0x00000002)
601708Sstevel #define	DBG_RETS	(0x00000004)
611708Sstevel #define	DBG_ARGS	(0x00000008)
621708Sstevel #define	DBG_KMEM	(0x00000010)
631708Sstevel #define	DBG_ALL		(0xFFFFFFFF)
641708Sstevel 
651708Sstevel #ifdef DEBUG
661708Sstevel static uint32_t	mboxsc_debug_mask = 0x00000000;
671708Sstevel #define	DPRINTF0(class, action, fmt) \
681708Sstevel 	mboxsc_dprintf(__FILE__, __LINE__, (class), (action), (fmt))
691708Sstevel #define	DPRINTF1(class, action, fmt, arg1) \
701708Sstevel 	mboxsc_dprintf(__FILE__, __LINE__, (class), (action), (fmt),\
711708Sstevel 	    (arg1))
721708Sstevel #define	DPRINTF2(class, action, fmt, arg1, arg2) \
731708Sstevel 	mboxsc_dprintf(__FILE__, __LINE__, (class), (action), (fmt),\
741708Sstevel 	    (arg1), (arg2))
751708Sstevel #define	DPRINTF3(class, action, fmt, arg1, arg2, arg3) \
761708Sstevel 	mboxsc_dprintf(__FILE__, __LINE__, (class), (action), (fmt),\
771708Sstevel 	    (arg1), (arg2), (arg3))
781708Sstevel #define	DPRINTF4(class, action, fmt, arg1, arg2, arg3, arg4) \
791708Sstevel 	mboxsc_dprintf(__FILE__, __LINE__, (class), (action), (fmt),\
801708Sstevel 	    (arg1), (arg2), (arg3), (arg4))
811708Sstevel #define	DPRINTF5(class, action, fmt, arg1, arg2, arg3, arg4, arg5) \
821708Sstevel 	mboxsc_dprintf(__FILE__, __LINE__, (class), (action), (fmt),\
831708Sstevel 	    (arg1), (arg2), (arg3), (arg4), (arg5))
841708Sstevel #else	/* DEBUG */
851708Sstevel #define	DPRINTF0(class, action, fmt)
861708Sstevel #define	DPRINTF1(class, action, fmt, arg1)
871708Sstevel #define	DPRINTF2(class, action, fmt, arg1, arg2)
881708Sstevel #define	DPRINTF3(class, action, fmt, arg1, arg2, arg3)
891708Sstevel #define	DPRINTF4(class, action, fmt, arg1, arg2, arg3, arg4)
901708Sstevel #define	DPRINTF5(class, action, fmt, arg1, arg2, arg3, arg4, arg5)
911708Sstevel #endif	/* DEBUG */
921708Sstevel 
931708Sstevel /*
941708Sstevel  * Basic constants
951708Sstevel  */
961708Sstevel #ifndef TRUE
971708Sstevel #define	TRUE	(1)
981708Sstevel #endif	/* TRUE */
991708Sstevel #ifndef FALSE
1001708Sstevel #define	FALSE	(0)
1011708Sstevel #endif	/* FALSE */
1021708Sstevel 
1031708Sstevel 
1041708Sstevel /*
1051708Sstevel  * Whenever mboxsc_init is called to create a new mailbox, an instance of
1061708Sstevel  * mboxsc_mbox_t is created and inserted into a hash table to maintain
1071708Sstevel  * various information about the mailbox.  The mbox_state, mbox_refcount, and
1081708Sstevel  * mbox_wait fields are all protected by the global mboxsc_lock mutex.
1091708Sstevel  * If lock contention between mailboxes becomes an issue, each mailbox will
1101708Sstevel  * need to be given its own mutex to protect the mbox_wait, mbox_state,
1111708Sstevel  * and mbox_update_wait fields.  The mbox_refcount field will probably need to
1121708Sstevel  * remain under global protection, however, since it is used to keep track of
1131708Sstevel  * the number of threads sleeping inside the mailbox's various synchronization
1141708Sstevel  * mechanisms and would consequently be difficult to protect using those same
1151708Sstevel  * mechanisms.
1161708Sstevel  */
1171708Sstevel typedef struct mboxsc_mbox {
1181708Sstevel 	uint32_t		mbox_key;
1191708Sstevel 	int			mbox_direction;
1201708Sstevel 	void			(*mbox_callback)(void);
1211708Sstevel 	uint32_t		mbox_length;
1221708Sstevel 	uint16_t		mbox_refcount;
1231708Sstevel 	uint16_t		mbox_state;
1241708Sstevel 	kcondvar_t		mbox_wait;
1251708Sstevel 	mboxsc_msghdr_t		mbox_header;
1261708Sstevel 	struct mboxsc_mbox	*mbox_hash_next;
1271708Sstevel } mboxsc_mbox_t;
1281708Sstevel 
1291708Sstevel /*
1301708Sstevel  * Various state flags that can be set on a mailbox.  Multiple states may
1311708Sstevel  * be active at the same time.
1321708Sstevel  */
1331708Sstevel #define	STATE_IDLE	(0x0000)
1341708Sstevel #define	STATE_WRITING	(0x0001)
1351708Sstevel #define	STATE_READING	(0x0002)
1361708Sstevel #define	STATE_HDRVALID	(0x0004)
1371708Sstevel 
1381708Sstevel /*
1391708Sstevel  * Timeout periods for mboxsc_putmsg and mboxsc_getmsg, converted to ticks
1401708Sstevel  * from the microsecond values found in mboxsc_impl.h.
1411708Sstevel  */
1421708Sstevel #define	EAGAIN_POLL		(drv_usectohz(MBOXSC_EAGAIN_POLL_USECS))
1431708Sstevel #define	PUTMSG_POLL		(drv_usectohz(MBOXSC_PUTMSG_POLL_USECS))
1441708Sstevel #define	HWLOCK_POLL		(drv_usectohz(MBOXSC_HWLOCK_POLL_USECS))
1451708Sstevel #define	LOOP_WARN_INTERVAL	(drv_usectohz(MBOXSC_USECS_PER_SECOND * 15))
1461708Sstevel 
1471708Sstevel /*
1481708Sstevel  * Various tests that are performed on message header fields.
1491708Sstevel  */
1501708Sstevel #define	IS_UNSOLICITED_TYPE(type)	((type) != MBOXSC_MSG_REPLY)
1511708Sstevel #define	MSG_TYPE_MATCHES(type, msgp)	\
1521708Sstevel 	(((type) == 0) || ((type) & (msgp)->msg_type))
1531708Sstevel #define	MSG_CMD_MATCHES(cmd, msgp)	\
1541708Sstevel 	(((cmd) == 0) || ((cmd) == (msgp)->msg_cmd))
1551708Sstevel #define	MSG_TRANSID_MATCHES(tid, msgp)	\
1561708Sstevel 	(((tid) == 0) || ((tid) == (msgp)->msg_transid))
1571708Sstevel 
1581708Sstevel /*
1591708Sstevel  * These macros can be used to determine the offset or size of any field in the
1601708Sstevel  * message header (or any other struct, for that matter).
1611708Sstevel  */
1621708Sstevel #define	FIELD_OFFSET(type, field)	((uint32_t)&(((type *)0)->field))
1631708Sstevel #define	FIELD_SIZE(type, field)		(sizeof (((type *)0)->field))
1641708Sstevel 
1651708Sstevel /*
1661708Sstevel  * Mask used when generating unique transaction ID values.
1671708Sstevel  * This arbitrarily chosen value will be OR'd together with
1681708Sstevel  * a counter for each successive internally-generated transaction ID.
1691708Sstevel  */
1701708Sstevel #define	TRANSID_GEN_MASK	(0xFFC0000000000000)
1711708Sstevel 
1721708Sstevel /*
1731708Sstevel  * All existing mailboxes are stored in a hash table with HASHTBL_SIZE
1741708Sstevel  * entries so they can be rapidly accessed by their key values.
1751708Sstevel  */
1761708Sstevel #define	HASHTBL_SIZE	(32)
1771708Sstevel #define	HASH_KEY(key)	((((key) >> 24) ^ ((key) >> 16) ^ ((key) >> 9) ^\
1781708Sstevel 			    (key)) & (HASHTBL_SIZE - 1));
1791708Sstevel 
1801708Sstevel /*
1811708Sstevel  * Unfortunately, it is necessary to calculate checksums on data split up
1821708Sstevel  * amongst different buffers in some cases.  Consequently, mboxsc_checksum
1831708Sstevel  * accepts a "seed" value as one of its parameters.  When first starting a
1841708Sstevel  * checksum calculation, the seed should be 0.
1851708Sstevel  */
1861708Sstevel #define	CHKSUM_INIT	(0)
1871708Sstevel 
1881708Sstevel /*
1891708Sstevel  * local variables
1901708Sstevel  */
1911708Sstevel static kmutex_t		mboxsc_lock;
1921708Sstevel static mboxsc_mbox_t	*mboxsc_hash_table[HASHTBL_SIZE];
1931708Sstevel static uint32_t		mboxsc_flaglock_count;
1941708Sstevel static uint32_t		mboxsc_active_version = MBOXSC_PROTOCOL_VERSION;
1951708Sstevel static kcondvar_t	mboxsc_dereference_cv;
1961708Sstevel 
1971708Sstevel /*
1981708Sstevel  * Structures from modctl.h used for loadable module support.
1991708Sstevel  * The mboxsc API is a "miscellaneous" module.
2001708Sstevel  */
2011708Sstevel extern struct mod_ops mod_miscops;
2021708Sstevel 
2031708Sstevel static struct modlmisc modlmisc = {
2041708Sstevel 	&mod_miscops,
2057799SRichard.Bean@Sun.COM 	"IOSRAM Mailbox API 'mboxsc'",
2061708Sstevel };
2071708Sstevel 
2081708Sstevel static struct modlinkage modlinkage = {
2091708Sstevel 	MODREV_1,
2101708Sstevel 	(void *)&modlmisc,
2111708Sstevel 	NULL
2121708Sstevel };
2131708Sstevel 
2141708Sstevel /*
2151708Sstevel  * Prototypes for local functions
2161708Sstevel  */
2171708Sstevel static void		mboxsc_iosram_callback(void *arg);
2181708Sstevel static void		mboxsc_hdrchange_callback(void);
2191708Sstevel static int		mboxsc_add_mailbox(mboxsc_mbox_t *mailboxp);
2201708Sstevel static void		mboxsc_close_mailbox(mboxsc_mbox_t *mailboxp);
2211708Sstevel static void		mboxsc_hashinsert_mailbox(mboxsc_mbox_t *mailboxp);
2221708Sstevel static mboxsc_mbox_t	*mboxsc_hashfind_mailbox_by_key(uint32_t key);
2231708Sstevel static mboxsc_mbox_t	*mboxsc_hashremove_mailbox_by_key(uint32_t key);
2241708Sstevel static mboxsc_chksum_t	mboxsc_checksum(mboxsc_chksum_t seed, uint8_t *buf,
2251708Sstevel 	uint32_t length);
2261708Sstevel static int		mboxsc_lock_flags(uint8_t mandatory, clock_t deadline);
2271708Sstevel static int		mboxsc_unlock_flags(uint8_t mandatory);
2281708Sstevel static int		mboxsc_timed_read(clock_t deadline, uint32_t key,
2291708Sstevel 	uint32_t off, uint32_t len, caddr_t dptr);
2301708Sstevel static int		mboxsc_timed_write(clock_t deadline, uint32_t key,
2311708Sstevel 	uint32_t off, uint32_t len, caddr_t dptr);
2321708Sstevel static int		mboxsc_timed_get_flag(clock_t deadline, uint32_t key,
2331708Sstevel 	uint8_t *data_validp, uint8_t *int_pendingp);
2341708Sstevel static int		mboxsc_timed_set_flag(clock_t deadline, uint32_t key,
2351708Sstevel 	uint8_t data_valid, uint8_t int_pending);
2361708Sstevel static int		mboxsc_timed_send_intr(clock_t deadline);
2371708Sstevel static int		mboxsc_expire_message(uint32_t key, int *resultp);
2381708Sstevel static uint64_t		mboxsc_generate_transid(uint64_t prev_transid);
2391708Sstevel static void		mboxsc_reference_mailbox(mboxsc_mbox_t *mailboxp);
2401708Sstevel static void		mboxsc_dereference_mailbox(mboxsc_mbox_t *mailboxp);
2411708Sstevel #ifdef DEBUG
2421708Sstevel /*PRINTFLIKE5*/
2431708Sstevel static void		mboxsc_dprintf(const char *file, int line,
2441708Sstevel 	uint32_t class, uint32_t action, const char *fmt, ...);
2451708Sstevel int			mboxsc_debug(int cmd, void *arg);
2461708Sstevel #endif /* DEBUG */
2471708Sstevel 
2481708Sstevel 
2491708Sstevel /*
2501708Sstevel  * _init
2511708Sstevel  *
2521708Sstevel  * Loadable module support routine.  Initializes global lock and hash table.
2531708Sstevel  */
2541708Sstevel int
_init(void)2551708Sstevel _init(void)
2561708Sstevel {
2571708Sstevel 	int		i;
2581708Sstevel 	uint32_t	sms_version;
2591708Sstevel 	int		error = 0;
2601708Sstevel 
2611708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "_init called\n");
2621708Sstevel 
2631708Sstevel 	/*
2641708Sstevel 	 * Initialize all module resources.
2651708Sstevel 	 */
2661708Sstevel 	mutex_init(&mboxsc_lock, NULL, MUTEX_DRIVER, NULL);
2671708Sstevel 	cv_init(&mboxsc_dereference_cv, NULL, CV_DRIVER, NULL);
2681708Sstevel 
2691708Sstevel 	for (i = 0; i < HASHTBL_SIZE; i++) {
2701708Sstevel 		mboxsc_hash_table[i] = NULL;
2711708Sstevel 	}
2721708Sstevel 	mboxsc_flaglock_count = 0;
2731708Sstevel 
2741708Sstevel 	if (mod_install(&modlinkage) != 0) {
2751708Sstevel 		goto failed;
2761708Sstevel 	}
2771708Sstevel 
2781708Sstevel 	/*
2791708Sstevel 	 * Set the os_mbox_version field in the IOSRAM header to indicate the
2801708Sstevel 	 * highest Mailbox Protocol version we support
2811708Sstevel 	 */
2821708Sstevel 	error = iosram_hdr_ctrl(IOSRAM_HDRCMD_SET_OS_MBOX_VER,
2831708Sstevel 	    (void *)MBOXSC_PROTOCOL_VERSION);
2841708Sstevel 	if (error != 0) {
2851708Sstevel 		goto failed;
2861708Sstevel 	}
2871708Sstevel 
2881708Sstevel 	/*
2891708Sstevel 	 * Read the sms_mbox_version field in the IOSRAM header to determine
2901708Sstevel 	 * what the greatest commonly supported version is.
2911708Sstevel 	 */
2921708Sstevel 	error = iosram_hdr_ctrl(IOSRAM_HDRCMD_GET_SMS_MBOX_VER,
2931708Sstevel 	    (void *)&sms_version);
2941708Sstevel 	if (error != 0) {
2951708Sstevel 		goto failed;
2961708Sstevel 	}
2971708Sstevel 	mboxsc_active_version = MIN(MBOXSC_PROTOCOL_VERSION, sms_version);
2981708Sstevel 	DPRINTF2(DBG_DEV, DBGACT_DEFAULT,
2991708Sstevel 	    "sms version: %d, active version: %d\n", sms_version,
3001708Sstevel 	    mboxsc_active_version);
3011708Sstevel 
3021708Sstevel 	/*
3031708Sstevel 	 * Register a callback with the IOSRAM driver to receive notification of
3041708Sstevel 	 * changes to the IOSRAM header, in case the sms_mbox_version field
3051708Sstevel 	 * changes.
3061708Sstevel 	 */
3071708Sstevel 	error = iosram_hdr_ctrl(IOSRAM_HDRCMD_REG_CALLBACK,
3081708Sstevel 	    (void *)mboxsc_hdrchange_callback);
3091708Sstevel 	if (error != 0) {
3101708Sstevel 		goto failed;
3111708Sstevel 	}
3121708Sstevel 
3131708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "_init ret: 0x%08x\n", error);
3141708Sstevel 	return (0);
3151708Sstevel 
3161708Sstevel 	/*
3171708Sstevel 	 * If initialization fails, uninitialize resources.
3181708Sstevel 	 */
3191708Sstevel failed:
3201708Sstevel 	mutex_destroy(&mboxsc_lock);
3211708Sstevel 	cv_destroy(&mboxsc_dereference_cv);
3221708Sstevel 
3231708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "_init ret: 0x%08x\n", error);
3241708Sstevel 	return (error);
3251708Sstevel }
3261708Sstevel 
3271708Sstevel /*
3281708Sstevel  * _fini
3291708Sstevel  *
3301708Sstevel  * Loadable module support routine. Closes all mailboxes and releases all
3311708Sstevel  * resources.
3321708Sstevel  */
3331708Sstevel int
_fini(void)3341708Sstevel _fini(void)
3351708Sstevel {
3361708Sstevel 	int		i;
3371708Sstevel 	int		error = 0;
3381708Sstevel 	mboxsc_mbox_t	*mailboxp;
3391708Sstevel 
3401708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "_fini called\n");
3411708Sstevel 
3421708Sstevel 	/*
3431708Sstevel 	 * Attempt to remove the module.  If successful, close all mailboxes
3441708Sstevel 	 * and deallocate the global lock.
3451708Sstevel 	 */
3461708Sstevel 	error = mod_remove(&modlinkage);
3471708Sstevel 	if (error == 0) {
3481708Sstevel 		mutex_enter(&mboxsc_lock);
3491708Sstevel 
350*11311SSurya.Prakki@Sun.COM 		(void) iosram_hdr_ctrl(IOSRAM_HDRCMD_REG_CALLBACK, NULL);
3511708Sstevel 
3521708Sstevel 		for (i = 0; i < HASHTBL_SIZE; i++) {
3531708Sstevel 			while (mboxsc_hash_table[i] != NULL) {
3541708Sstevel 				mailboxp = mboxsc_hash_table[i];
3551708Sstevel 				mboxsc_close_mailbox(mailboxp);
3561708Sstevel 			}
3571708Sstevel 		}
3581708Sstevel 		mutex_exit(&mboxsc_lock);
3591708Sstevel 		mutex_destroy(&mboxsc_lock);
3601708Sstevel 		cv_destroy(&mboxsc_dereference_cv);
3611708Sstevel 	}
3621708Sstevel 
3631708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "_fini ret: 0x%08x\n", error);
3641708Sstevel 	return (error);
3651708Sstevel }
3661708Sstevel 
3671708Sstevel /*
3681708Sstevel  * _info
3691708Sstevel  *
3701708Sstevel  * Loadable module support routine.
3711708Sstevel  */
3721708Sstevel int
_info(struct modinfo * modinfop)3731708Sstevel _info(struct modinfo *modinfop)
3741708Sstevel {
3751708Sstevel 	int		error = 0;
3761708Sstevel 
3771708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "_info called\n");
3781708Sstevel 
3791708Sstevel 	error = mod_info(&modlinkage, modinfop);
3801708Sstevel 
3811708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "_info ret: 0x%08x\n", error);
3821708Sstevel 
3831708Sstevel 	return (error);
3841708Sstevel }
3851708Sstevel 
3861708Sstevel /*
3871708Sstevel  * mboxsc_init
3881708Sstevel  *
3891708Sstevel  * Attempts to create a new mailbox.
3901708Sstevel  */
3911708Sstevel int
mboxsc_init(uint32_t key,int direction,void (* event_handler)(void))3921708Sstevel mboxsc_init(uint32_t key, int direction, void (*event_handler)(void))
3931708Sstevel {
3941708Sstevel 	int		error = 0;
3951708Sstevel 	mboxsc_mbox_t	*mailboxp;
3961708Sstevel 
3971708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_init called\n");
3981708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key);
3991708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "direction = %d\n", direction);
4001708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "event_handlerp = %p\n",
401*11311SSurya.Prakki@Sun.COM 	    (void *)event_handler);
4021708Sstevel 
4031708Sstevel 	/*
4041708Sstevel 	 * Check for valid direction and callback specification.
4051708Sstevel 	 */
4061708Sstevel 	if (((direction != MBOXSC_MBOX_IN) && (direction != MBOXSC_MBOX_OUT)) ||
4071708Sstevel 	    ((event_handler != NULL) && (direction != MBOXSC_MBOX_IN))) {
4081708Sstevel 		DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_init ret: 0x%08x\n",
4091708Sstevel 		    EINVAL);
4101708Sstevel 		return (EINVAL);
4111708Sstevel 	}
4121708Sstevel 
4131708Sstevel 	/*
4141708Sstevel 	 * Allocate memory for the mailbox structure and initialize all
4151708Sstevel 	 * caller-provided fields.
4161708Sstevel 	 */
4171708Sstevel 	mailboxp = (mboxsc_mbox_t *)kmem_zalloc(sizeof (mboxsc_mbox_t),
4181708Sstevel 	    KM_SLEEP);
419*11311SSurya.Prakki@Sun.COM 	DPRINTF2(DBG_KMEM, DBGACT_DEFAULT, "kmem_zalloc(%lu) = %p\n",
420*11311SSurya.Prakki@Sun.COM 	    sizeof (mboxsc_mbox_t), (void *)mailboxp);
4211708Sstevel 	mailboxp->mbox_key = key;
4221708Sstevel 	mailboxp->mbox_direction = direction;
4231708Sstevel 	mailboxp->mbox_callback = event_handler;
4241708Sstevel 
4251708Sstevel 	/*
4261708Sstevel 	 * Attempt to add the mailbox.  If unsuccessful, free the allocated
4271708Sstevel 	 * memory.
4281708Sstevel 	 */
4291708Sstevel 	mutex_enter(&mboxsc_lock);
4301708Sstevel 	error = mboxsc_add_mailbox(mailboxp);
4311708Sstevel 	mutex_exit(&mboxsc_lock);
4321708Sstevel 
4331708Sstevel 	if (error != 0) {
434*11311SSurya.Prakki@Sun.COM 		DPRINTF2(DBG_KMEM, DBGACT_DEFAULT, "kmem_free(%p, %lu)\n",
435*11311SSurya.Prakki@Sun.COM 		    (void *)mailboxp, sizeof (mboxsc_mbox_t));
4361708Sstevel 		kmem_free(mailboxp, sizeof (mboxsc_mbox_t));
4371708Sstevel 	}
4381708Sstevel 
4391708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_init ret: 0x%08x\n", error);
4401708Sstevel 	return (error);
4411708Sstevel }
4421708Sstevel 
4431708Sstevel /*
4441708Sstevel  * mboxsc_fini
4451708Sstevel  *
4461708Sstevel  * Closes the mailbox with the indicated key, if it exists.
4471708Sstevel  */
4481708Sstevel int
mboxsc_fini(uint32_t key)4491708Sstevel mboxsc_fini(uint32_t key)
4501708Sstevel {
4511708Sstevel 	int		error = 0;
4521708Sstevel 	mboxsc_mbox_t	*mailboxp;
4531708Sstevel 
4541708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_fini called\n");
4551708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key);
4561708Sstevel 
4571708Sstevel 	/*
4581708Sstevel 	 * Attempt to close the mailbox.
4591708Sstevel 	 */
4601708Sstevel 	mutex_enter(&mboxsc_lock);
4611708Sstevel 	mailboxp = mboxsc_hashfind_mailbox_by_key(key);
4621708Sstevel 	if (mailboxp == NULL) {
4631708Sstevel 		error = EBADF;
4641708Sstevel 	} else {
4651708Sstevel 		while (mailboxp->mbox_refcount != 0) {
4661708Sstevel 			cv_wait(&mboxsc_dereference_cv, &mboxsc_lock);
4671708Sstevel 		}
4681708Sstevel 		mboxsc_close_mailbox(mailboxp);
4691708Sstevel 	}
4701708Sstevel 	mutex_exit(&mboxsc_lock);
4711708Sstevel 
4721708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_fini ret: 0x%08x\n", error);
4731708Sstevel 	return (error);
4741708Sstevel }
4751708Sstevel 
4761708Sstevel /*
4771708Sstevel  * mboxsc_putmsg
4781708Sstevel  *
4791708Sstevel  * Attempt to place a message into an outbound mailbox and signal the
4801708Sstevel  * recipient.  A successful return (0) indicates that the message was
4811708Sstevel  * successfully delivered.
4821708Sstevel  */
4831708Sstevel int
mboxsc_putmsg(uint32_t key,uint32_t type,uint32_t cmd,uint64_t * transidp,uint32_t length,void * datap,clock_t timeout)4841708Sstevel mboxsc_putmsg(uint32_t key, uint32_t type, uint32_t cmd, uint64_t *transidp,
4851708Sstevel 		uint32_t length, void *datap, clock_t timeout)
4861708Sstevel {
4871708Sstevel 	int		i;
4881708Sstevel 	int		error = 0;
4891708Sstevel 	int		result;
4901708Sstevel 	int		lock_held = 0;
4911708Sstevel 	int		unlock_err;
4921708Sstevel 	uint8_t		data_valid;
4931708Sstevel 	clock_t		deadline;
4941708Sstevel 	clock_t		remainder;
4951708Sstevel 	mboxsc_chksum_t	checksum;
4961708Sstevel 	mboxsc_mbox_t	*mailboxp;
4971708Sstevel 	mboxsc_msghdr_t	header;
4981708Sstevel 
4991708Sstevel #ifdef DEBUG /* because lint whines about if stmts without consequents */
5001708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_putmsg called\n");
5011708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key);
5021708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "type = 0x%x\n", type);
5031708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "cmd = 0x%x\n", cmd);
504*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "transidp = %p\n", (void *)transidp);
5051708Sstevel 	if (transidp != NULL) {
506*11311SSurya.Prakki@Sun.COM 		DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "*transidp = 0x%016lx\n",
5071708Sstevel 		    *transidp);
5081708Sstevel 	}
5091708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "length = 0x%x\n", length);
5101708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "datap = %p\n", datap);
511*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "timeout = %ld\n", timeout);
5121708Sstevel #endif /* DEBUG */
5131708Sstevel 
5141708Sstevel 	/*
5151708Sstevel 	 * Perform some basic sanity checks on the message.
5161708Sstevel 	 */
5171708Sstevel 	for (i = 0; i < MBOXSC_NUM_MSG_TYPES; i++) {
5181708Sstevel 		if (type == (1 << i)) {
5191708Sstevel 			break;
5201708Sstevel 		}
5211708Sstevel 	}
5221708Sstevel 	if ((i == MBOXSC_NUM_MSG_TYPES) || (cmd == 0) ||
5231708Sstevel 	    ((datap == NULL) && (length != 0)) ||
5241708Sstevel 	    (timeout < MBOXSC_PUTMSG_MIN_TIMEOUT_MSECS) ||
5251708Sstevel 	    (timeout > MBOXSC_PUTMSG_MAX_TIMEOUT_MSECS)) {
5261708Sstevel 		DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
5271708Sstevel 		    "mboxsc_putmsg ret: 0x%08x\n", EINVAL);
5281708Sstevel 		return (EINVAL);
5291708Sstevel 	}
5301708Sstevel 
5311708Sstevel 	/*
5321708Sstevel 	 * Initialize the header structure with values provided by the caller.
5331708Sstevel 	 */
5341708Sstevel 	header.msg_version = mboxsc_active_version;
5351708Sstevel 	header.msg_type = type;
5361708Sstevel 	header.msg_cmd = cmd;
5371708Sstevel 	header.msg_length = MBOXSC_MSGHDR_SIZE + length;
5381708Sstevel 	if (transidp != NULL) {
5391708Sstevel 		header.msg_transid = *transidp;
5401708Sstevel 	} else {
5411708Sstevel 		header.msg_transid = 0;
5421708Sstevel 	}
5431708Sstevel 
5441708Sstevel 	/*
5451708Sstevel 	 * Perform additional sanity checks on the mailbox and message.
5461708Sstevel 	 * Make sure that the specified mailbox really exists, that the
5471708Sstevel 	 * given message will fit in it, and that the current message's
5481708Sstevel 	 * transaction ID isn't the same as the last message's transaction
5491708Sstevel 	 * ID unless both messages are replies (it's okay, necessary even,
5501708Sstevel 	 * to reuse a transaction ID when resending a failed reply message,
5511708Sstevel 	 * but that is the only case in which it is permissible).
5521708Sstevel 	 */
5531708Sstevel 	mutex_enter(&mboxsc_lock);
5541708Sstevel 	mailboxp = mboxsc_hashfind_mailbox_by_key(key);
5551708Sstevel 
5561708Sstevel 	if (mailboxp == NULL) {
5571708Sstevel 		error = EBADF;
5581708Sstevel 	} else if ((mailboxp->mbox_direction != MBOXSC_MBOX_OUT) ||
5591708Sstevel 	    (length + MBOXSC_PROTOCOL_SIZE > mailboxp->mbox_length) ||
5601708Sstevel 	    ((header.msg_transid == mailboxp->mbox_header.msg_transid) &&
5611708Sstevel 	    ((type & mailboxp->mbox_header.msg_type) != MBOXSC_MSG_REPLY) &&
5621708Sstevel 	    (header.msg_transid != 0))) {
5631708Sstevel 		error = EINVAL;
5641708Sstevel 	}
5651708Sstevel 
5661708Sstevel 	if (error != 0) {
5671708Sstevel 		mutex_exit(&mboxsc_lock);
5681708Sstevel 		DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
5691708Sstevel 		    "mboxsc_putmsg ret: 0x%08x\n", error);
5701708Sstevel 		return (error);
5711708Sstevel 	}
5721708Sstevel 
5731708Sstevel 	/*
5741708Sstevel 	 * If the message's transaction ID is set to 0, generate a unique
5751708Sstevel 	 * transaction ID and copy it into the message header.  If the message
5761708Sstevel 	 * is successfully delivered and transidp != NULL, we'll copy this new
5771708Sstevel 	 * transid into *transidp later.
5781708Sstevel 	 */
5791708Sstevel 	if (header.msg_transid == 0) {
5801708Sstevel 		header.msg_transid =
5811708Sstevel 		    mboxsc_generate_transid(mailboxp->mbox_header.msg_transid);
5821708Sstevel 	}
5831708Sstevel 
5841708Sstevel 	/*
5851708Sstevel 	 * Don't allow mboxsc_putmsg to attempt to place a message for
5861708Sstevel 	 * longer than the caller's timeout.
5871708Sstevel 	 */
5881708Sstevel 	deadline = ddi_get_lbolt() +
5891708Sstevel 	    drv_usectohz(timeout * MBOXSC_USECS_PER_MSEC);
5901708Sstevel 
5911708Sstevel 	/*
5921708Sstevel 	 * Increment the reference count on the mailbox to keep it from being
5931708Sstevel 	 * closed, and wait for it to become available.
5941708Sstevel 	 */
5951708Sstevel 	mboxsc_reference_mailbox(mailboxp);
5961708Sstevel 	remainder = 1;
5971708Sstevel 	while ((mailboxp->mbox_state & STATE_WRITING) &&
5981708Sstevel 	    (remainder > 0)) {
5991708Sstevel 		remainder = cv_timedwait_sig(&(mailboxp->mbox_wait),
6001708Sstevel 		    &mboxsc_lock, deadline);
6011708Sstevel 	}
6021708Sstevel 
6031708Sstevel 	/*
6041708Sstevel 	 * Check to see whether or not the mailbox became available.  If it
6051708Sstevel 	 * did not, decrement its reference count and return an error to the
6061708Sstevel 	 * caller.
6071708Sstevel 	 */
6081708Sstevel 	if (remainder == -1) {
6091708Sstevel 		error = ENOSPC;
6101708Sstevel 	} else if (remainder == 0) {
6111708Sstevel 		error = EINTR;
6121708Sstevel 	}
6131708Sstevel 
6141708Sstevel 	if (error != 0) {
6151708Sstevel 		mboxsc_dereference_mailbox(mailboxp);
6161708Sstevel 		mutex_exit(&mboxsc_lock);
6171708Sstevel 		DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
6181708Sstevel 		    "mboxsc_putmsg ret: 0x%08x\n", error);
6191708Sstevel 		return (error);
6201708Sstevel 	}
6211708Sstevel 
6221708Sstevel 	/*
6231708Sstevel 	 * Since the message is valid and we're going to try to write it to
6241708Sstevel 	 * IOSRAM, record its header for future reference (e.g. to make sure the
6251708Sstevel 	 * next message doesn't incorrectly use the same transID).
6261708Sstevel 	 */
6271708Sstevel 	bcopy(&header, &(mailboxp->mbox_header), MBOXSC_MSGHDR_SIZE);
6281708Sstevel 
6291708Sstevel 	/*
6301708Sstevel 	 * Flag the mailbox as being in use and release the global lock.
6311708Sstevel 	 */
6321708Sstevel 	mailboxp->mbox_state |= STATE_WRITING;
6331708Sstevel 	mutex_exit(&mboxsc_lock);
6341708Sstevel 
6351708Sstevel 	/*
6361708Sstevel 	 * Calculate the message checksum using the header and the data.
6371708Sstevel 	 */
6381708Sstevel 	checksum = mboxsc_checksum(CHKSUM_INIT, (uint8_t *)&header,
6391708Sstevel 	    MBOXSC_MSGHDR_SIZE);
6401708Sstevel 	checksum = mboxsc_checksum(checksum, (uint8_t *)datap, length);
6411708Sstevel 
6421708Sstevel 	/*
6431708Sstevel 	 * Attempt to write the message and checksum to IOSRAM until successful,
6441708Sstevel 	 * or as long as time remains and no errors other than EAGAIN are
6451708Sstevel 	 * returned from any call to the IOSRAM driver in case there is a tunnel
6461708Sstevel 	 * switch in progress.
6471708Sstevel 	 */
6481708Sstevel 	error = mboxsc_timed_write(deadline, key, MBOXSC_MSGHDR_OFFSET,
6491708Sstevel 	    MBOXSC_MSGHDR_SIZE, (caddr_t)&header);
6501708Sstevel 
6511708Sstevel 	if (error == 0) {
6521708Sstevel 		error = mboxsc_timed_write(deadline, key, MBOXSC_DATA_OFFSET,
6531708Sstevel 		    length, (caddr_t)datap);
6541708Sstevel 	}
6551708Sstevel 
6561708Sstevel 	if (error == 0) {
6571708Sstevel 		error = mboxsc_timed_write(deadline, key, header.msg_length,
6581708Sstevel 		    MBOXSC_CHKSUM_SIZE, (caddr_t)&checksum);
6591708Sstevel 	}
6601708Sstevel 
6611708Sstevel 	/*
6621708Sstevel 	 * Lock the flags before setting data_valid.  This isn't strictly
6631708Sstevel 	 * necessary for correct protocol operation, but it gives us a chance to
6641708Sstevel 	 * verify that the flags lock is functional before we commit to sending
6651708Sstevel 	 * the message.
6661708Sstevel 	 */
6671708Sstevel 	if (error == 0) {
6681708Sstevel 		error = mboxsc_lock_flags(FALSE, deadline);
6691708Sstevel 		if (error == 0) {
6701708Sstevel 			lock_held = 1;
6711708Sstevel 		} else if (error == EBUSY) {
6721708Sstevel 			error = EAGAIN;
6731708Sstevel 		}
6741708Sstevel 	}
6751708Sstevel 
6761708Sstevel 	if (error == 0) {
6771708Sstevel 		error = mboxsc_timed_set_flag(deadline, key, IOSRAM_DATA_VALID,
6781708Sstevel 		    IOSRAM_INT_TO_SSC);
6791708Sstevel 	}
6801708Sstevel 
6811708Sstevel 	/*
6821708Sstevel 	 * Unlock the flags.  If an error is encountered, only return it if
6831708Sstevel 	 * another error hasn't been encountered previously.
6841708Sstevel 	 */
6851708Sstevel 	if (lock_held) {
6861708Sstevel 		unlock_err = mboxsc_unlock_flags(TRUE);
6871708Sstevel 		if ((unlock_err != 0) && ((error == 0) || (error == EAGAIN))) {
6881708Sstevel 			error = unlock_err;
6891708Sstevel 		}
6901708Sstevel 	}
6911708Sstevel 
6921708Sstevel 	/*
6931708Sstevel 	 * If time ran out or an IOSRAM call failed, notify other callers that
6941708Sstevel 	 * the mailbox is available, decrement its reference count, and return
6951708Sstevel 	 * an error.
6961708Sstevel 	 */
6971708Sstevel 	if (error != 0) {
6981708Sstevel 		ASSERT((error != EINVAL) && (error != EMSGSIZE));
6991708Sstevel 		mutex_enter(&mboxsc_lock);
7001708Sstevel 		mailboxp->mbox_state &= ~STATE_WRITING;
7011708Sstevel 		cv_broadcast(&(mailboxp->mbox_wait));
7021708Sstevel 		mboxsc_dereference_mailbox(mailboxp);
7031708Sstevel 		mutex_exit(&mboxsc_lock);
7041708Sstevel 		DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
7051708Sstevel 		    "mboxsc_putmsg ret: 0x%08x\n", error);
7061708Sstevel 		return (error);
7071708Sstevel 	}
7081708Sstevel 
7091708Sstevel 	/*
7101708Sstevel 	 * Send an interrupt to the remote mailbox interface to announce the
7111708Sstevel 	 * presence of a new, valid message.
7121708Sstevel 	 */
7131708Sstevel 	error = mboxsc_timed_send_intr(deadline);
7141708Sstevel 
7151708Sstevel 	/*
7161708Sstevel 	 * Wait until either the data_valid flag is set INVALID by the
7171708Sstevel 	 * remote client or time runs out.  Since we're calling delay as
7181708Sstevel 	 * a part of polling the flag anyway, we don't really need to do
7191708Sstevel 	 * the usual continuous retry if iosram_get_flag returns EAGAIN.
7201708Sstevel 	 */
7211708Sstevel 	data_valid = IOSRAM_DATA_VALID;
7221708Sstevel 	if (error == DDI_SUCCESS) {
7231708Sstevel 		do {
7241708Sstevel 			delay(MIN(PUTMSG_POLL, deadline - ddi_get_lbolt()));
7251708Sstevel 			error = iosram_get_flag(key, &data_valid, NULL);
7261708Sstevel 		} while ((data_valid == IOSRAM_DATA_VALID) &&
7271708Sstevel 		    ((error == EAGAIN) || (error == 0)) &&
7281708Sstevel 		    (deadline - ddi_get_lbolt() >= 0));
7291708Sstevel 	}
7301708Sstevel 
7311708Sstevel 	/*
7321708Sstevel 	 * If the data_valid flag was set to INVALID by the other side, the
7331708Sstevel 	 * message was successfully transmitted.  If it wasn't, but there
7341708Sstevel 	 * weren't any IOSRAM errors, the operation timed out.  If there was a
7351708Sstevel 	 * problem with the IOSRAM, pass that info back to the caller.
7361708Sstevel 	 */
7371708Sstevel 	if (data_valid == IOSRAM_DATA_INVALID) {
7381708Sstevel 		result = 0;
7391708Sstevel 	} else if ((error == 0) || (error == DDI_FAILURE)) {
7401708Sstevel 		result = ETIMEDOUT;
7411708Sstevel 	} else {
7421708Sstevel 		ASSERT(error != EINVAL);
7431708Sstevel 		result = error;
7441708Sstevel 	}
7451708Sstevel 
7461708Sstevel 	/*
7471708Sstevel 	 * If the message has not been picked up, expire it. Note that this may
7481708Sstevel 	 * actually result in detecting successful message delivery if the SC
7491708Sstevel 	 * picks it up at the last moment.  If expiration fails due to an error,
7501708Sstevel 	 * return an error to the user even if the message appears to have
7511708Sstevel 	 * been successfully delivered.
7521708Sstevel 	 */
7531708Sstevel 	if (data_valid == IOSRAM_DATA_VALID) {
7541708Sstevel 		error = mboxsc_expire_message(key, &result);
7551708Sstevel 		if ((error != 0) && ((result == 0) || (result == ETIMEDOUT))) {
7561708Sstevel 			result = error;
7571708Sstevel 		}
7581708Sstevel 	}
7591708Sstevel 
7601708Sstevel 	/*
7611708Sstevel 	 * If the message was successfully delivered, and we generated a
7621708Sstevel 	 * transaction ID for the caller, and the caller wants to know what it
7631708Sstevel 	 * was, give it to them.
7641708Sstevel 	 */
7651708Sstevel 	if ((result == 0) && (transidp != NULL) && (*transidp == 0)) {
7661708Sstevel 		*transidp = header.msg_transid;
7671708Sstevel 	}
7681708Sstevel 
7691708Sstevel 	/*
7701708Sstevel 	 * Regardless of whether the message was successfully transmitted or
7711708Sstevel 	 * not, notify other callers that the mailbox is available and decrement
7721708Sstevel 	 * its reference count.
7731708Sstevel 	 */
7741708Sstevel 	mutex_enter(&mboxsc_lock);
7751708Sstevel 	mailboxp->mbox_state &= ~STATE_WRITING;
7761708Sstevel 	cv_broadcast(&(mailboxp->mbox_wait));
7771708Sstevel 	mboxsc_dereference_mailbox(mailboxp);
7781708Sstevel 	mutex_exit(&mboxsc_lock);
7791708Sstevel 
7801708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_putmsg ret: 0x%08x\n",
7811708Sstevel 	    result);
7821708Sstevel 	return (result);
7831708Sstevel }
7841708Sstevel 
7851708Sstevel /*
7861708Sstevel  * mboxsc_getmsg
7871708Sstevel  *
7881708Sstevel  * Attempt to retrieve a message from the mailbox with the given key that
7891708Sstevel  * matches values provided in msgp.  A successful return (0) indicates that
7901708Sstevel  * a message matching the caller's request was successfully received within
7911708Sstevel  * timeout milliseconds.  If a message matching the caller's request is
7921708Sstevel  * detected, but can't be successfully read, an error will be returned even
7931708Sstevel  * if the caller's timeout hasn't expired.
7941708Sstevel  */
7951708Sstevel int
mboxsc_getmsg(uint32_t key,uint32_t * typep,uint32_t * cmdp,uint64_t * transidp,uint32_t * lengthp,void * datap,clock_t timeout)7961708Sstevel mboxsc_getmsg(uint32_t key, uint32_t *typep, uint32_t *cmdp, uint64_t *transidp,
7971708Sstevel 		uint32_t *lengthp, void *datap, clock_t timeout)
7981708Sstevel {
7991708Sstevel 	int		error = 0;
8001708Sstevel 	uint32_t	datalen;
8011708Sstevel 	uint8_t		data_valid;
8021708Sstevel 	uint8_t		lock_held;
8031708Sstevel 	mboxsc_chksum_t	read_checksum;
8041708Sstevel 	mboxsc_chksum_t	calc_checksum;
8051708Sstevel 	uint64_t	read_transid;
8061708Sstevel 	clock_t		deadline;
8071708Sstevel 	clock_t		remainder;
8081708Sstevel 	mboxsc_mbox_t	*mailboxp;
8091708Sstevel 	mboxsc_msghdr_t	header;
8101708Sstevel 
8111708Sstevel #ifdef DEBUG /* because lint whines about if stmts without consequents */
8121708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_getmsg called\n");
8131708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key);
814*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "typep = %p\n", (void *)typep);
8151708Sstevel 	if (typep != NULL) {
8161708Sstevel 		DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "*typep = 0x%x\n", *typep);
8171708Sstevel 	}
818*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "cmdp = %p\n", (void *)cmdp);
8191708Sstevel 	if (cmdp != NULL) {
8201708Sstevel 		DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "*cmdp = 0x%x\n", *cmdp);
8211708Sstevel 	}
822*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "transidp = %p\n", (void *)transidp);
8231708Sstevel 	if (transidp != NULL) {
824*11311SSurya.Prakki@Sun.COM 		DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "*transidp = 0x%lx\n",
8251708Sstevel 		    *transidp);
8261708Sstevel 	}
827*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "lengthp = %p\n", (void *)lengthp);
8281708Sstevel 	if (lengthp != NULL) {
8291708Sstevel 		DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "*lengthp = 0x%x\n",
8301708Sstevel 		    *lengthp);
8311708Sstevel 	}
8321708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "datap = %p\n", datap);
8331708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "timeout = %ld\n", timeout);
8341708Sstevel #endif /* DEBUG */
8351708Sstevel 
8361708Sstevel 	/*
8371708Sstevel 	 * Perform basic sanity checks on the caller's request.
8381708Sstevel 	 */
8391708Sstevel 	if ((typep == NULL) || (*typep >= (1 << MBOXSC_NUM_MSG_TYPES)) ||
8401708Sstevel 	    (cmdp == NULL) || (transidp == NULL) || (lengthp == NULL) ||
8411708Sstevel 	    ((datap == NULL) && (*lengthp != 0)) ||
8421708Sstevel 	    (timeout < MBOXSC_GETMSG_MIN_TIMEOUT_MSECS) ||
8431708Sstevel 	    (timeout > MBOXSC_GETMSG_MAX_TIMEOUT_MSECS)) {
8441708Sstevel 		DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
8451708Sstevel 		    "mboxsc_getmsg ret: 0x%08x\n", EINVAL);
8461708Sstevel 		return (EINVAL);
8471708Sstevel 	}
8481708Sstevel 
8491708Sstevel 	/*
8501708Sstevel 	 * Don't allow mboxsc_getmsg to attempt to receive a message for
8511708Sstevel 	 * longer than the caller's timeout.
8521708Sstevel 	 */
8531708Sstevel 	deadline = ddi_get_lbolt() +
8541708Sstevel 	    drv_usectohz(timeout * MBOXSC_USECS_PER_MSEC);
8551708Sstevel 
8561708Sstevel 	/*
8571708Sstevel 	 * Perform additional sanity checks on the client's request and the
8581708Sstevel 	 * associated mailbox.
8591708Sstevel 	 */
8601708Sstevel 	mutex_enter(&mboxsc_lock);
8611708Sstevel 	mailboxp = mboxsc_hashfind_mailbox_by_key(key);
8621708Sstevel 	if (mailboxp == NULL) {
8631708Sstevel 		error = EBADF;
8641708Sstevel 	} else if (mailboxp->mbox_direction != MBOXSC_MBOX_IN) {
8651708Sstevel 		error = EINVAL;
8661708Sstevel 	}
8671708Sstevel 
8681708Sstevel 	if (error != 0) {
8691708Sstevel 		mutex_exit(&mboxsc_lock);
8701708Sstevel 		DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
8711708Sstevel 		    "mboxsc_getmsg ret: 0x%08x\n", error);
8721708Sstevel 		return (error);
8731708Sstevel 	}
8741708Sstevel 
8751708Sstevel 	/*
8761708Sstevel 	 * The request is okay, so reference the mailbox (to keep it from being
8771708Sstevel 	 * closed), and proceed with the real work.
8781708Sstevel 	 */
8791708Sstevel 	mboxsc_reference_mailbox(mailboxp);
8801708Sstevel 
8811708Sstevel 	/*
8821708Sstevel 	 * Certain failures that may occur late in the process of getting a
8831708Sstevel 	 * message (e.g. checksum error, cancellation by the sender) are
8841708Sstevel 	 * supposed to leave the recipient waiting for the next message to
8851708Sstevel 	 * arrive rather than returning an error.  To facilitate restarting
8861708Sstevel 	 * the message acquisition process, the following label is provided
8871708Sstevel 	 * as a target for a very few judiciously-placed "goto"s.
8881708Sstevel 	 *
8891708Sstevel 	 * The mboxsc_lock mutex MUST be held when jumping to this point.
8901708Sstevel 	 */
8911708Sstevel mboxsc_getmsg_retry:
8921708Sstevel 	;
8931708Sstevel 
8941708Sstevel 	/*
8951708Sstevel 	 * If there is a valid message in the mailbox right now, check to
8961708Sstevel 	 * see if it matches the caller's request.  If not, or if another
8971708Sstevel 	 * caller is already reading it, wait for either the arrival of the
8981708Sstevel 	 * next message or the expiration of the caller's specified timeout.
8991708Sstevel 	 */
9001708Sstevel 	error = 0;
9011708Sstevel 	while (!(mailboxp->mbox_state & STATE_HDRVALID) ||
9021708Sstevel 	    (mailboxp->mbox_state & STATE_READING) ||
9031708Sstevel 	    !MSG_TYPE_MATCHES(*typep, &(mailboxp->mbox_header)) ||
9041708Sstevel 	    !MSG_CMD_MATCHES(*cmdp, &(mailboxp->mbox_header)) ||
9051708Sstevel 	    !MSG_TRANSID_MATCHES(*transidp, &(mailboxp->mbox_header))) {
9061708Sstevel 		remainder = cv_timedwait_sig(&(mailboxp->mbox_wait),
9071708Sstevel 		    &mboxsc_lock, deadline);
9081708Sstevel 		if (remainder == -1) {
9091708Sstevel 			error = ETIMEDOUT;
9101708Sstevel 		} else if (remainder == 0) {
9111708Sstevel 			error = EINTR;
9121708Sstevel 		}
9131708Sstevel 
9141708Sstevel 		if (error != 0) {
9151708Sstevel 			mboxsc_dereference_mailbox(mailboxp);
9161708Sstevel 			mutex_exit(&mboxsc_lock);
9171708Sstevel 			DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
9181708Sstevel 			    "mboxsc_getmsg ret: 0x%08x\n", error);
9191708Sstevel 			return (error);
9201708Sstevel 		}
9211708Sstevel 	}
9221708Sstevel 
9231708Sstevel 	/*
9241708Sstevel 	 * If somebody sends us a message using a Mailbox Protocol version
9251708Sstevel 	 * greater than the highest one we understand, invalidate the message,
9261708Sstevel 	 * because we can't safely interpret anything beyond the version field.
9271708Sstevel 	 */
9281708Sstevel 	if (mailboxp->mbox_header.msg_version > MBOXSC_PROTOCOL_VERSION) {
9291708Sstevel 		DPRINTF1(DBG_DEV, DBGACT_DEFAULT,
9301708Sstevel 		    "incoming message with unsupported version %d\n",
9311708Sstevel 		    mailboxp->mbox_header.msg_version);
9321708Sstevel 		mailboxp->mbox_state &= ~STATE_HDRVALID;
9331708Sstevel 		goto mboxsc_getmsg_retry;
9341708Sstevel 	}
9351708Sstevel 
9361708Sstevel 	/*
9371708Sstevel 	 * At this point, there is a stored message header that matches the
9381708Sstevel 	 * caller's request, but the actual message may no longer be valid
9391708Sstevel 	 * in IOSRAM.  Check the data_valid flag to see whether or not
9401708Sstevel 	 * this is the case.  If the message has expired, go start over.
9411708Sstevel 	 *
9421708Sstevel 	 * The global mutex is held while reading flag data from IOSRAM to
9431708Sstevel 	 * avoid certain race conditions.  One race condition is still
9441708Sstevel 	 * possible (i.e. SC-side has just set the data_valid flag for a
9451708Sstevel 	 * new message, but the stored message header hasn't been updated
9461708Sstevel 	 * yet), but it won't cause incorrect behavior (just some wasted work).
9471708Sstevel 	 */
9481708Sstevel 	error = iosram_get_flag(key, &data_valid, NULL);
9491708Sstevel 
9501708Sstevel 	ASSERT(error != EINVAL);
9511708Sstevel 	if (error == 0) {
9521708Sstevel 		if (data_valid != IOSRAM_DATA_VALID) {
9531708Sstevel 			mailboxp->mbox_state &= ~STATE_HDRVALID;
9541708Sstevel 			goto mboxsc_getmsg_retry;
9551708Sstevel 		}
9561708Sstevel 	} else if ((error == EAGAIN) && (deadline - ddi_get_lbolt() >= 0)) {
9571708Sstevel 		mutex_exit(&mboxsc_lock);
9581708Sstevel 		delay(MIN(EAGAIN_POLL, deadline - ddi_get_lbolt()));
9591708Sstevel 		mutex_enter(&mboxsc_lock);
9601708Sstevel 		goto mboxsc_getmsg_retry;
9611708Sstevel 	}
9621708Sstevel 
9631708Sstevel 	/*
9641708Sstevel 	 * If the message is larger than the caller's buffer, provide the caller
9651708Sstevel 	 * with the length of the message and return an error.
9661708Sstevel 	 */
9671708Sstevel 	datalen = mailboxp->mbox_header.msg_length - MBOXSC_MSGHDR_SIZE;
9681708Sstevel 	if ((error == 0) && (datalen > *lengthp)) {
9691708Sstevel 		*lengthp = datalen;
9701708Sstevel 		error = EMSGSIZE;
9711708Sstevel 	}
9721708Sstevel 
9731708Sstevel 	/*
9741708Sstevel 	 * Note that there's no need to check STATE_HDRVALID before broadcasting
9751708Sstevel 	 * here because the header is guaranteed to be valid at this point.
9761708Sstevel 	 */
9771708Sstevel 	if (error != 0) {
9781708Sstevel 		cv_broadcast(&(mailboxp->mbox_wait));
9791708Sstevel 		mboxsc_dereference_mailbox(mailboxp);
9801708Sstevel 		mutex_exit(&mboxsc_lock);
9811708Sstevel 		DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
9821708Sstevel 		    "mboxsc_getmsg ret: 0x%08x\n", error);
9831708Sstevel 		return (error);
9841708Sstevel 	}
9851708Sstevel 
9861708Sstevel 	/*
9871708Sstevel 	 * Store a copy of the current message header, flag the mailbox to
9881708Sstevel 	 * indicate that it is being read and attempt to read the message data
9891708Sstevel 	 * and checksum.
9901708Sstevel 	 */
9911708Sstevel 	bcopy(&(mailboxp->mbox_header), &header, MBOXSC_MSGHDR_SIZE);
9921708Sstevel 	mailboxp->mbox_state |= STATE_READING;
9931708Sstevel 	mutex_exit(&mboxsc_lock);
9941708Sstevel 
9951708Sstevel 	if (datalen > 0) {
9961708Sstevel 		error = mboxsc_timed_read(deadline, key, MBOXSC_DATA_OFFSET,
9971708Sstevel 		    datalen, (caddr_t)datap);
9981708Sstevel 	}
9991708Sstevel 
10001708Sstevel 	if (error == 0) {
10011708Sstevel 		error = mboxsc_timed_read(deadline, key, header.msg_length,
10021708Sstevel 		    MBOXSC_CHKSUM_SIZE, (caddr_t)&read_checksum);
10031708Sstevel 	}
10041708Sstevel 
10051708Sstevel 	/*
10061708Sstevel 	 * Check for errors that may have occurred while accessing IOSRAM.
10071708Sstevel 	 */
10081708Sstevel 	if (error != 0) {
10091708Sstevel 		ASSERT((error != EINVAL) && (error != EMSGSIZE));
10101708Sstevel 		mutex_enter(&mboxsc_lock);
10111708Sstevel 		mailboxp->mbox_state &= ~STATE_READING;
10121708Sstevel 		if (mailboxp->mbox_state & STATE_HDRVALID) {
10131708Sstevel 			cv_broadcast(&(mailboxp->mbox_wait));
10141708Sstevel 		}
10151708Sstevel 		mboxsc_dereference_mailbox(mailboxp);
10161708Sstevel 		mutex_exit(&mboxsc_lock);
10171708Sstevel 		DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
10181708Sstevel 		    "mboxsc_getmsg ret: 0x%08x\n", error);
10191708Sstevel 		return (error);
10201708Sstevel 	}
10211708Sstevel 
10221708Sstevel 	/*
10231708Sstevel 	 * Calculate the checksum for the header and data that was read from
10241708Sstevel 	 * IOSRAM.
10251708Sstevel 	 */
10261708Sstevel 	calc_checksum = mboxsc_checksum(CHKSUM_INIT, (uint8_t *)&header,
10271708Sstevel 	    MBOXSC_MSGHDR_SIZE);
10281708Sstevel 	calc_checksum = mboxsc_checksum(calc_checksum, (uint8_t *)datap,
10291708Sstevel 	    datalen);
10301708Sstevel 
10311708Sstevel 	/*
10321708Sstevel 	 * If the message header has been invalidated, note the change.
10331708Sstevel 	 * If a the checksum verification fails, invalidate the message
10341708Sstevel 	 * header.  In either case, go back to the beginning and wait
10351708Sstevel 	 * for a new message.
10361708Sstevel 	 */
10371708Sstevel 	mutex_enter(&mboxsc_lock);
10381708Sstevel 	if (!(mailboxp->mbox_state & STATE_HDRVALID)) {
10391708Sstevel 		error = -1;
10401708Sstevel 		DPRINTF0(DBG_DEV, DBGACT_DEFAULT,
10411708Sstevel 		    "mboxsc_getmsg - message invalidated while reading\n");
10421708Sstevel 	} else if (read_checksum != calc_checksum) {
10431708Sstevel 		error = -1;
10441708Sstevel 		mailboxp->mbox_state &= ~STATE_HDRVALID;
10451708Sstevel 		DPRINTF0(DBG_DEV, DBGACT_DEFAULT,
10461708Sstevel 		    "mboxsc_getmsg - message failed checksum\n");
10471708Sstevel 		cmn_err(CE_NOTE,
10481708Sstevel 		    "mboxsc_getmsg - message failed checksum\n");
10491708Sstevel 	}
10501708Sstevel 
10511708Sstevel 	if (error == -1) {
10521708Sstevel 		mailboxp->mbox_state &= ~STATE_READING;
10531708Sstevel 		goto mboxsc_getmsg_retry;
10541708Sstevel 	}
10551708Sstevel 
10561708Sstevel 	/*
10571708Sstevel 	 * Acquire the hardware lock used for synchronization of data_valid flag
10581708Sstevel 	 * access to avoid race conditions.  If it is acquired, try to check the
10591708Sstevel 	 * current data_valid flag and transaction ID to verify that the message
10601708Sstevel 	 * is still valid.
10611708Sstevel 	 */
10621708Sstevel 	mutex_exit(&mboxsc_lock);
10631708Sstevel 
10641708Sstevel 	if ((error = mboxsc_lock_flags(FALSE, deadline)) != 0) {
10651708Sstevel 		lock_held = FALSE;
10661708Sstevel 		/*
10671708Sstevel 		 * We don't "do" EBUSY here, so treat it as EAGAIN.
10681708Sstevel 		 */
10691708Sstevel 		if (error == EBUSY) {
10701708Sstevel 			error = EAGAIN;
10711708Sstevel 		}
10721708Sstevel 	} else {
10731708Sstevel 		lock_held = TRUE;
10741708Sstevel 	}
10751708Sstevel 
10761708Sstevel 	if (error == 0) {
10771708Sstevel 		error = mboxsc_timed_get_flag(deadline, key, &data_valid, NULL);
10781708Sstevel 	}
10791708Sstevel 
10801708Sstevel 	if ((error == 0) && (data_valid == IOSRAM_DATA_VALID)) {
10811708Sstevel 		error = mboxsc_timed_read(deadline, key,
10821708Sstevel 		    FIELD_OFFSET(mboxsc_msghdr_t, msg_transid),
10831708Sstevel 		    FIELD_SIZE(mboxsc_msghdr_t, msg_transid),
10841708Sstevel 		    (caddr_t)&read_transid);
10851708Sstevel 	}
10861708Sstevel 
10871708Sstevel 	/*
10881708Sstevel 	 * If something failed along the way, either the error is unrecoverable
10891708Sstevel 	 * or we're just plain out of time, so unlock the flags if they were
10901708Sstevel 	 * locked, release the mailbox, wake up other potential readers if
10911708Sstevel 	 * there's still a message around, and return.
10921708Sstevel 	 */
10931708Sstevel 	if (error != 0) {
10941708Sstevel 		ASSERT((error != EINVAL) && (error != EMSGSIZE));
10951708Sstevel 		if (lock_held) {
1096*11311SSurya.Prakki@Sun.COM 			(void) mboxsc_unlock_flags(TRUE);
10971708Sstevel 		}
10981708Sstevel 		mutex_enter(&mboxsc_lock);
10991708Sstevel 		mailboxp->mbox_state &= ~STATE_READING;
11001708Sstevel 		if (mailboxp->mbox_state & STATE_HDRVALID) {
11011708Sstevel 			cv_broadcast(&(mailboxp->mbox_wait));
11021708Sstevel 		}
11031708Sstevel 		mboxsc_dereference_mailbox(mailboxp);
11041708Sstevel 		mutex_exit(&mboxsc_lock);
11051708Sstevel 		DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
11061708Sstevel 		    "mboxsc_getmsg ret: 0x%08x\n", error);
11071708Sstevel 		return (error);
11081708Sstevel 	}
11091708Sstevel 
11101708Sstevel 	/*
11111708Sstevel 	 * If the data_valid flag isn't set to IOSRAM_DATA_VALID, or the
11121708Sstevel 	 * message transaction ID in IOSRAM has changed, the message being
11131708Sstevel 	 * read was timed out by its sender.  Since the data_valid flag can't
11141708Sstevel 	 * change as long as we have the flags locked, we can safely mark the
11151708Sstevel 	 * stored message header invalid if either the data_valid flag isn't set
11161708Sstevel 	 * or the stored transaction ID doesn't match the one we read.  (If
11171708Sstevel 	 * data_valid is set, the transaction ID shouldn't be changing
11181708Sstevel 	 * underneath us.)  On the other hand, if there may still be a valid
11191708Sstevel 	 * message, wake up any pending readers.
11201708Sstevel 	 */
11211708Sstevel 	if ((data_valid != IOSRAM_DATA_VALID) ||
11221708Sstevel 	    (read_transid != header.msg_transid)) {
11231708Sstevel 		mutex_enter(&mboxsc_lock);
11241708Sstevel 		mailboxp->mbox_state &= ~STATE_READING;
11251708Sstevel 		if ((data_valid != IOSRAM_DATA_VALID) ||
11261708Sstevel 		    (mailboxp->mbox_header.msg_transid != read_transid)) {
11271708Sstevel 			mailboxp->mbox_state &= ~STATE_HDRVALID;
11281708Sstevel 		} else if (mailboxp->mbox_state & STATE_HDRVALID) {
11291708Sstevel 			cv_broadcast(&(mailboxp->mbox_wait));
11301708Sstevel 		}
11311708Sstevel 
11321708Sstevel 		/*
11331708Sstevel 		 * Unfortunately, we can't be holding mboxsc_lock when we unlock
11341708Sstevel 		 * the flags.  However, we have to hold the flags until here to
11351708Sstevel 		 * make sure the SC doesn't change the message's state while
11361708Sstevel 		 * we're checking to see if we should invalidate our stored
11371708Sstevel 		 * header.
11381708Sstevel 		 */
11391708Sstevel 		mutex_exit(&mboxsc_lock);
11401708Sstevel 		error = mboxsc_unlock_flags(TRUE);
11411708Sstevel 		mutex_enter(&mboxsc_lock);
11421708Sstevel 
11431708Sstevel 		DPRINTF0(DBG_DEV, DBGACT_DEFAULT,
11441708Sstevel 		    "mboxsc_getmsg() - message invalidated by sender\n");
11451708Sstevel 		goto mboxsc_getmsg_retry;
11461708Sstevel 	}
11471708Sstevel 
11481708Sstevel 	/*
11491708Sstevel 	 * If everything has worked up to this point, all that remains is
11501708Sstevel 	 * to set the data_valid flag to IOSRAM_DATA_INVALID, tidy up, and
11511708Sstevel 	 * return the message.  If the flag can't be set, the message can't
11521708Sstevel 	 * be received, so keep trying as long as there is time.
11531708Sstevel 	 */
11541708Sstevel 	error = mboxsc_timed_set_flag(deadline, key, IOSRAM_DATA_INVALID,
11551708Sstevel 	    IOSRAM_INT_NONE);
11561708Sstevel 
1157*11311SSurya.Prakki@Sun.COM 	(void) mboxsc_unlock_flags(TRUE);
11581708Sstevel 	mutex_enter(&mboxsc_lock);
11591708Sstevel 
11601708Sstevel 	if (error != 0) {
11611708Sstevel 		ASSERT(error != EINVAL);
11621708Sstevel 		mboxsc_dereference_mailbox(mailboxp);
11631708Sstevel 		mailboxp->mbox_state &= ~STATE_READING;
11641708Sstevel 		if (mailboxp->mbox_state & STATE_HDRVALID) {
11651708Sstevel 			cv_broadcast(&(mailboxp->mbox_wait));
11661708Sstevel 		}
11671708Sstevel 		mutex_exit(&mboxsc_lock);
11681708Sstevel 		DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
11691708Sstevel 		    "mboxsc_getmsg ret: 0x%08x\n", error);
11701708Sstevel 		return (error);
11711708Sstevel 	}
11721708Sstevel 
11731708Sstevel 	/*
11741708Sstevel 	 * If the message was read 100% successfully and the stored message
11751708Sstevel 	 * header for the mailbox still matches the message that was read,
11761708Sstevel 	 * invalidate it to prevent other readers from trying to read it.
11771708Sstevel 	 */
11781708Sstevel 	if (bcmp(&(mailboxp->mbox_header), &header, MBOXSC_MSGHDR_SIZE) == 0) {
11791708Sstevel 		mailboxp->mbox_state &= ~STATE_HDRVALID;
11801708Sstevel 	} else if (mailboxp->mbox_state & STATE_HDRVALID) {
11811708Sstevel 		cv_broadcast(&(mailboxp->mbox_wait));
11821708Sstevel 	}
11831708Sstevel 
11841708Sstevel 	mboxsc_dereference_mailbox(mailboxp);
11851708Sstevel 	mailboxp->mbox_state &= ~STATE_READING;
11861708Sstevel 	mutex_exit(&mboxsc_lock);
11871708Sstevel 
11881708Sstevel 	/*
11891708Sstevel 	 * Since we're successfully returning a message, we need to provide the
11901708Sstevel 	 * caller with all of the interesting header information.
11911708Sstevel 	 */
11921708Sstevel 	*typep = header.msg_type;
11931708Sstevel 	*cmdp = header.msg_cmd;
11941708Sstevel 	*transidp = header.msg_transid;
11951708Sstevel 	*lengthp = datalen;
11961708Sstevel 
11971708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_getmsg ret: 0x%08x\n", 0);
11981708Sstevel 	return (0);
11991708Sstevel }
12001708Sstevel 
12011708Sstevel /*
12021708Sstevel  * mboxsc_ctrl
12031708Sstevel  *
12041708Sstevel  * This routine provides access to a variety of services not available through
12051708Sstevel  * the basic API.
12061708Sstevel  */
12071708Sstevel int
mboxsc_ctrl(uint32_t key,uint32_t cmd,void * arg)12081708Sstevel mboxsc_ctrl(uint32_t key, uint32_t cmd, void *arg)
12091708Sstevel {
12101708Sstevel 	int		error = 0;
12111708Sstevel 	mboxsc_mbox_t	*mailboxp;
12121708Sstevel 
12131708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_ctrl called\n");
12141708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key);
12151708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "cmd = 0x%x\n", cmd);
12161708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "arg = %p\n", arg);
12171708Sstevel 
12181708Sstevel 	mutex_enter(&mboxsc_lock);
12191708Sstevel 	mailboxp = mboxsc_hashfind_mailbox_by_key(key);
12201708Sstevel 	if (mailboxp == NULL) {
12211708Sstevel 		mutex_exit(&mboxsc_lock);
12221708Sstevel 		DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_ctrl ret: 0x%08x\n",
12231708Sstevel 		    EBADF);
12241708Sstevel 		return (EBADF);
12251708Sstevel 	}
12261708Sstevel 
12271708Sstevel 	switch (cmd) {
12281708Sstevel 		case MBOXSC_CMD_VERSION:
12291708Sstevel 			/*
12301708Sstevel 			 * Return the Protocol version currently in use.  Since
12311708Sstevel 			 * there is only one version that exists right now, we
12321708Sstevel 			 * can't be using anything else.
12331708Sstevel 			 */
12341708Sstevel 			if (arg == NULL) {
12351708Sstevel 				error = EINVAL;
12361708Sstevel 				break;
12371708Sstevel 			}
12381708Sstevel 
12391708Sstevel 			*(uint32_t *)arg = MBOXSC_PROTOCOL_VERSION;
12401708Sstevel 			break;
12411708Sstevel 
12421708Sstevel 		case MBOXSC_CMD_MAXVERSION:
12431708Sstevel 			/*
12441708Sstevel 			 * Return the highest Protocol version that we support.
12451708Sstevel 			 */
12461708Sstevel 			if (arg == NULL) {
12471708Sstevel 				error = EINVAL;
12481708Sstevel 				break;
12491708Sstevel 			}
12501708Sstevel 
12511708Sstevel 			*(uint32_t *)arg = MBOXSC_PROTOCOL_VERSION;
12521708Sstevel 			break;
12531708Sstevel 
12541708Sstevel 		case MBOXSC_CMD_MAXDATALEN:
12551708Sstevel 			/*
12561708Sstevel 			 * Return the amount of space available for client data
12571708Sstevel 			 * in the indicated mailbox.
12581708Sstevel 			 */
12591708Sstevel 			if (arg == NULL) {
12601708Sstevel 				error = EINVAL;
12611708Sstevel 				break;
12621708Sstevel 			}
12631708Sstevel 
12641708Sstevel 			*(uint32_t *)arg = mailboxp->mbox_length -
12651708Sstevel 			    MBOXSC_PROTOCOL_SIZE;
12661708Sstevel 			break;
12671708Sstevel 
12681708Sstevel 		case MBOXSC_CMD_PUTMSG_TIMEOUT_RANGE:
12691708Sstevel 		{
12701708Sstevel 			mboxsc_timeout_range_t *rangep;
12711708Sstevel 
12721708Sstevel 			/*
12731708Sstevel 			 * Return the range of acceptable timeout values for
12741708Sstevel 			 * mboxsc_putmsg, expressed in milliseconds.
12751708Sstevel 			 */
12761708Sstevel 			if (arg == NULL) {
12771708Sstevel 				error = EINVAL;
12781708Sstevel 				break;
12791708Sstevel 			}
12801708Sstevel 
12811708Sstevel 			rangep = (mboxsc_timeout_range_t *)arg;
12821708Sstevel 			rangep->min_timeout = MBOXSC_PUTMSG_MIN_TIMEOUT_MSECS;
12831708Sstevel 			rangep->max_timeout = MBOXSC_PUTMSG_MAX_TIMEOUT_MSECS;
12841708Sstevel 			break;
12851708Sstevel 		}
12861708Sstevel 
12871708Sstevel 		case MBOXSC_CMD_GETMSG_TIMEOUT_RANGE:
12881708Sstevel 		{
12891708Sstevel 			mboxsc_timeout_range_t *rangep;
12901708Sstevel 
12911708Sstevel 			/*
12921708Sstevel 			 * Return the range of acceptable timeout values for
12931708Sstevel 			 * mboxsc_getmsg, expressed in milliseconds.
12941708Sstevel 			 */
12951708Sstevel 			if (arg == NULL) {
12961708Sstevel 				error = EINVAL;
12971708Sstevel 				break;
12981708Sstevel 			}
12991708Sstevel 
13001708Sstevel 			rangep = (mboxsc_timeout_range_t *)arg;
13011708Sstevel 			rangep->min_timeout = MBOXSC_GETMSG_MIN_TIMEOUT_MSECS;
13021708Sstevel 			rangep->max_timeout = MBOXSC_GETMSG_MAX_TIMEOUT_MSECS;
13031708Sstevel 			break;
13041708Sstevel 		}
13051708Sstevel 
13061708Sstevel 		default:
13071708Sstevel 			error = ENOTSUP;
13081708Sstevel 			break;
13091708Sstevel 	}
13101708Sstevel 
13111708Sstevel 	mutex_exit(&mboxsc_lock);
13121708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_ctrl ret: 0x%08x\n", error);
13131708Sstevel 	return (error);
13141708Sstevel }
13151708Sstevel 
13161708Sstevel /*
13171708Sstevel  * mboxsc_putmsg_def_timeout
13181708Sstevel  *
13191708Sstevel  * This routine returns the default mboxsc_putmsg timeout provided for the
13201708Sstevel  * convenience of clients.
13211708Sstevel  */
13221708Sstevel clock_t
mboxsc_putmsg_def_timeout(void)13231708Sstevel mboxsc_putmsg_def_timeout(void)
13241708Sstevel {
13251708Sstevel 	return (MBOXSC_PUTMSG_DEF_TIMEOUT_MSECS);
13261708Sstevel }
13271708Sstevel 
13281708Sstevel /*
13291708Sstevel  * mboxsc_iosram_callback
13301708Sstevel  *
13311708Sstevel  * This routine is registered with the IOSRAM driver for all inbound mailboxes,
13321708Sstevel  * and performs preliminary processing of all new messages.
13331708Sstevel  */
13341708Sstevel static void
mboxsc_iosram_callback(void * arg)13351708Sstevel mboxsc_iosram_callback(void *arg)
13361708Sstevel {
13371708Sstevel 	int		error = 0;
13381708Sstevel 	uint8_t		data_valid;
13391708Sstevel 	uint32_t	key = (uint32_t)(uintptr_t)arg;
13401708Sstevel 	mboxsc_mbox_t	*mailboxp;
13411708Sstevel 
13421708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_iosram_callback called\n");
13431708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "arg = 0x%x\n", key);
13441708Sstevel 
13451708Sstevel 	mutex_enter(&mboxsc_lock);
13461708Sstevel 	mailboxp = mboxsc_hashfind_mailbox_by_key(key);
13471708Sstevel 
13481708Sstevel 	/*
13491708Sstevel 	 * We shouldn't ever receive a callback for a mailbox that doesn't
13501708Sstevel 	 * exist or for an output mailbox.
13511708Sstevel 	 */
13521708Sstevel 	ASSERT(mailboxp != NULL);
13531708Sstevel 	ASSERT(mailboxp->mbox_direction == MBOXSC_MBOX_IN);
13541708Sstevel 
13551708Sstevel 	/*
13561708Sstevel 	 * Attempt to read the header of the mailbox.  If the IOSRAM returns
13571708Sstevel 	 * EAGAIN, indicating a tunnel switch is in progress, do not retry
13581708Sstevel 	 * the operation.
13591708Sstevel 	 */
13601708Sstevel 	mailboxp->mbox_state &= ~STATE_HDRVALID;
13611708Sstevel 	error = iosram_rd(key, MBOXSC_MSGHDR_OFFSET, MBOXSC_MSGHDR_SIZE,
13621708Sstevel 	    (caddr_t)&(mailboxp->mbox_header));
13631708Sstevel 
13641708Sstevel 	/*
13651708Sstevel 	 * If somebody sends us a message using a Mailbox Protocol version
13661708Sstevel 	 * greater than the highest one we understand, ignore the message,
13671708Sstevel 	 * because we can't safely interpret anything beyond the version field.
13681708Sstevel 	 */
13691708Sstevel 	if (mailboxp->mbox_header.msg_version > MBOXSC_PROTOCOL_VERSION) {
13701708Sstevel 		error = -1;
13711708Sstevel 		DPRINTF1(DBG_DEV, DBGACT_DEFAULT,
13721708Sstevel 		    "incoming message with unsupported version %d\n",
13731708Sstevel 		    mailboxp->mbox_header.msg_version);
13741708Sstevel 	}
13751708Sstevel 
13761708Sstevel 	/*
13771708Sstevel 	 * If this message is a repeat of a previous message (which should
13781708Sstevel 	 * only happen with reply messages), it is conceivable that a client
13791708Sstevel 	 * already executing in mboxsc_getmsg for the previous message could
13801708Sstevel 	 * end up receiving the new message before this callback gets a chance
13811708Sstevel 	 * to execute.  If that happens, the data_valid flag will already have
13821708Sstevel 	 * been cleared.  Call iosram_get_flag to see if that is the case, and
13831708Sstevel 	 * do not process the message if it is.
13841708Sstevel 	 */
13851708Sstevel 	if (error == 0) {
13861708Sstevel 		error = iosram_get_flag(key, &data_valid, NULL);
13871708Sstevel 		if ((error == 0) && (data_valid != IOSRAM_DATA_VALID)) {
13881708Sstevel 			error = -1;
13891708Sstevel 		}
13901708Sstevel 	}
13911708Sstevel 
13921708Sstevel 	/*
13931708Sstevel 	 * If the iosram_rd call failed, return.
13941708Sstevel 	 */
13951708Sstevel 	if (error != 0) {
13961708Sstevel 		mutex_exit(&mboxsc_lock);
13971708Sstevel 		DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
13981708Sstevel 		    "mboxsc_iosram_callback ret (0x%08x)\n", error);
13991708Sstevel 		return;
14001708Sstevel 	}
14011708Sstevel 
14021708Sstevel 	/*
14031708Sstevel 	 * If the message read from IOSRAM was unsolicited, invoke
14041708Sstevel 	 * its callback.  Otherwise, wake all threads that are waiting
14051708Sstevel 	 * in mboxsc_getmsg.
14061708Sstevel 	 */
14071708Sstevel 	mailboxp->mbox_state |= STATE_HDRVALID;
14081708Sstevel 	if (IS_UNSOLICITED_TYPE(mailboxp->mbox_header.msg_type) &&
14091708Sstevel 	    (mailboxp->mbox_callback != NULL)) {
14101708Sstevel 		mboxsc_reference_mailbox(mailboxp);
14111708Sstevel 		mutex_exit(&mboxsc_lock);
14121708Sstevel 		(*(mailboxp->mbox_callback))();
14131708Sstevel 		mutex_enter(&mboxsc_lock);
14141708Sstevel 		mboxsc_dereference_mailbox(mailboxp);
14151708Sstevel 	} else {
14161708Sstevel 		cv_broadcast(&(mailboxp->mbox_wait));
14171708Sstevel 	}
14181708Sstevel 
14191708Sstevel 	mutex_exit(&mboxsc_lock);
14201708Sstevel 
14211708Sstevel 	DPRINTF0(DBG_RETS, DBGACT_DEFAULT, "mboxsc_iosram_callback ret\n");
14221708Sstevel }
14231708Sstevel 
14241708Sstevel /*
14251708Sstevel  * mboxsc_hdrchange_callback
14261708Sstevel  *
14271708Sstevel  * This routine is registered with the IOSRAM driver to react to any changes SMS
14281708Sstevel  * makes to the IOSRAM header.
14291708Sstevel  */
14301708Sstevel static void
mboxsc_hdrchange_callback(void)14311708Sstevel mboxsc_hdrchange_callback(void)
14321708Sstevel {
14331708Sstevel 	int		error;
14341708Sstevel 	uint32_t	sms_version;
14351708Sstevel 
14361708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT,
14371708Sstevel 	    "mboxsc_hdrchange_callback called\n");
14381708Sstevel 
14391708Sstevel 	error = iosram_hdr_ctrl(IOSRAM_HDRCMD_GET_SMS_MBOX_VER,
14401708Sstevel 	    (void *)&sms_version);
14411708Sstevel 	if (error == 0) {
14421708Sstevel 		DPRINTF1(DBG_DEV, DBGACT_DEFAULT,
14431708Sstevel 		    "sms mailbox version = %d\n", sms_version);
14441708Sstevel 		mboxsc_active_version = MIN(MBOXSC_PROTOCOL_VERSION,
14451708Sstevel 		    sms_version);
14461708Sstevel 	}
14471708Sstevel 
14481708Sstevel 	DPRINTF0(DBG_RETS, DBGACT_DEFAULT, "mboxsc_hdrchange_callback ret\n");
14491708Sstevel }
14501708Sstevel 
14511708Sstevel 
14521708Sstevel /*
14531708Sstevel  * mboxsc_add_mailbox
14541708Sstevel  *
14551708Sstevel  * If no other mailbox exists with the same key as this mailbox, attempt to
14561708Sstevel  * retrieve its length from the IOSRAM driver and register the mboxsc callback
14571708Sstevel  * for the associated IOSRAM chunk.  If successful, initialize the
14581708Sstevel  * non-client-supplied mailbox fields and insert it into the hash table.
14591708Sstevel  * NOTE: The caller MUST hold mboxsc_lock to avoid corrupting the hash table.
14601708Sstevel  */
14611708Sstevel static int
mboxsc_add_mailbox(mboxsc_mbox_t * mailboxp)14621708Sstevel mboxsc_add_mailbox(mboxsc_mbox_t *mailboxp)
14631708Sstevel {
14641708Sstevel 	int		error = 0;
14651708Sstevel 	uint32_t	key = mailboxp->mbox_key;
14661708Sstevel 
14671708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_add_mailbox called\n");
1468*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "mailboxp = %p\n", (void *)mailboxp);
14691708Sstevel 
14701708Sstevel 	/*
14711708Sstevel 	 * The global lock must be held by the caller.
14721708Sstevel 	 */
14731708Sstevel 	ASSERT(mutex_owned(&mboxsc_lock));
14741708Sstevel 
14751708Sstevel 	/*
14761708Sstevel 	 * Don't create the mailbox if it already exists.
14771708Sstevel 	 */
14781708Sstevel 	if (mboxsc_hashfind_mailbox_by_key(key) != NULL) {
14791708Sstevel 		DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
14801708Sstevel 		    "mboxsc_add_mailbox ret: 0x%08x\n", EEXIST);
14811708Sstevel 		return (EEXIST);
14821708Sstevel 	}
14831708Sstevel 
14841708Sstevel 	/*
14851708Sstevel 	 * Obtain the mailbox length and register the mboxsc callback with the
14861708Sstevel 	 * IOSRAM driver.  If either call to the IOSRAM driver fails, or the
14871708Sstevel 	 * chunk is too small to be used as a mailbox, return an error to the
14881708Sstevel 	 * caller.
14891708Sstevel 	 */
14901708Sstevel 	error = iosram_ctrl(key, IOSRAM_CMD_CHUNKLEN, &(mailboxp->mbox_length));
14911708Sstevel 
14921708Sstevel 	if ((error == 0) && (mailboxp->mbox_length < MBOXSC_PROTOCOL_SIZE)) {
14931708Sstevel 		error = EFAULT;
14941708Sstevel 	}
14951708Sstevel 
14961708Sstevel 	if ((error == 0) && (mailboxp->mbox_direction == MBOXSC_MBOX_IN)) {
14971708Sstevel 		error = iosram_register(key, mboxsc_iosram_callback,
14981708Sstevel 		    (void *)(uintptr_t)(key));
14991708Sstevel 		if (error == EBUSY) {
15001708Sstevel 			error = EFAULT;
15011708Sstevel 		}
15021708Sstevel 	}
15031708Sstevel 
15041708Sstevel 	if (error != 0) {
15051708Sstevel 		DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
15061708Sstevel 		    "mboxsc_add_mailbox ret: 0x%08x\n", error);
15071708Sstevel 		return (error);
15081708Sstevel 	}
15091708Sstevel 
15101708Sstevel 	/*
15111708Sstevel 	 * Initialize remaining mailbox fields and insert mailbox into
15121708Sstevel 	 * hash table.
15131708Sstevel 	 */
15141708Sstevel 	mailboxp->mbox_state = STATE_IDLE;
15151708Sstevel 	mailboxp->mbox_refcount = 0;
15161708Sstevel 	cv_init(&(mailboxp->mbox_wait), NULL, CV_DRIVER, NULL);
15171708Sstevel 	mboxsc_hashinsert_mailbox(mailboxp);
15181708Sstevel 
15191708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_add_mailbox ret: 0x%08x\n",
15201708Sstevel 	    0);
15211708Sstevel 	return (0);
15221708Sstevel }
15231708Sstevel 
15241708Sstevel /*
15251708Sstevel  * mboxsc_close_mailbox
15261708Sstevel  *
15271708Sstevel  * Remove a mailbox from the hash table, unregister its IOSRAM callback, and
15281708Sstevel  * deallocate its resources.
15291708Sstevel  * NOTE: The caller MUST hold mboxsc_lock to avoid corrupting the hash table.
15301708Sstevel  */
15311708Sstevel static void
mboxsc_close_mailbox(mboxsc_mbox_t * mailboxp)15321708Sstevel mboxsc_close_mailbox(mboxsc_mbox_t *mailboxp)
15331708Sstevel {
15341708Sstevel 	int		error = 0;
15351708Sstevel 	uint32_t	key = mailboxp->mbox_key;
15361708Sstevel 
15371708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_close_mailbox called\n");
1538*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "mailboxp = %p\n", (void *)mailboxp);
15391708Sstevel 
15401708Sstevel 	/*
15411708Sstevel 	 * The global lock must be held by the caller.
15421708Sstevel 	 */
15431708Sstevel 	ASSERT(mutex_owned(&mboxsc_lock));
15441708Sstevel 
15451708Sstevel 	/*
15461708Sstevel 	 * Unregister the mboxsc callback for this particular mailbox.
15471708Sstevel 	 */
15481708Sstevel 	if (mailboxp->mbox_direction == MBOXSC_MBOX_IN) {
15491708Sstevel 		error = iosram_unregister(key);
15501708Sstevel 		if (error == EINVAL) {
15511708Sstevel 			DPRINTF1(DBG_DEV, DBGACT_DEFAULT, "invalid key (0x%08x)"
15521708Sstevel 			    " reported in mboxsc_close_mailbox.\n", key);
15531708Sstevel 			error = 0;
15541708Sstevel 		}
15551708Sstevel 	}
15561708Sstevel 
15571708Sstevel 	/*
15581708Sstevel 	 * Remove the mailbox from the hash table and deallocate its resources.
15591708Sstevel 	 */
1560*11311SSurya.Prakki@Sun.COM 	(void) mboxsc_hashremove_mailbox_by_key(key);
15611708Sstevel 	cv_destroy(&(mailboxp->mbox_wait));
1562*11311SSurya.Prakki@Sun.COM 	DPRINTF2(DBG_KMEM, DBGACT_DEFAULT, "kmem_free(%p, %lu)\n",
1563*11311SSurya.Prakki@Sun.COM 	    (void *)mailboxp, sizeof (mboxsc_mbox_t));
15641708Sstevel 	kmem_free(mailboxp, sizeof (mboxsc_mbox_t));
15651708Sstevel 
15661708Sstevel 	DPRINTF0(DBG_RETS, DBGACT_DEFAULT, "mboxsc_close_mailbox ret\n");
15671708Sstevel }
15681708Sstevel 
15691708Sstevel /*
15701708Sstevel  * mboxsc_hashinsert_mailbox
15711708Sstevel  *
15721708Sstevel  * Insert a fully initialized mailbox into the hash table.  No duplicate
15731708Sstevel  * checking is performed at this point, so the caller is responsible for
15741708Sstevel  * duplicate prevention if it is desired.
15751708Sstevel  * NOTE: The caller MUST hold mboxsc_lock to avoid corrupting the hash table.
15761708Sstevel  */
15771708Sstevel static void
mboxsc_hashinsert_mailbox(mboxsc_mbox_t * mailboxp)15781708Sstevel mboxsc_hashinsert_mailbox(mboxsc_mbox_t *mailboxp)
15791708Sstevel {
15801708Sstevel 	uint32_t	hash;
15811708Sstevel 
15821708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT,
15831708Sstevel 	    "mboxsc_hashinsert_mailbox called\n");
1584*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "mailboxp = %p\n", (void *)mailboxp);
15851708Sstevel 
15861708Sstevel 	/*
15871708Sstevel 	 * The global lock must be held by the caller.
15881708Sstevel 	 */
15891708Sstevel 	ASSERT(mutex_owned(&mboxsc_lock));
15901708Sstevel 
15911708Sstevel 	hash = HASH_KEY(mailboxp->mbox_key);
15921708Sstevel 	mailboxp->mbox_hash_next = mboxsc_hash_table[hash];
15931708Sstevel 	mboxsc_hash_table[hash] = mailboxp;
15941708Sstevel 
15951708Sstevel 	DPRINTF0(DBG_RETS, DBGACT_DEFAULT,
15961708Sstevel 	    "mboxsc_hashinsert_mailbox ret\n");
15971708Sstevel }
15981708Sstevel 
15991708Sstevel /*
16001708Sstevel  * mboxsc_hashfind_mailbox_by_key
16011708Sstevel  *
16021708Sstevel  * Locate a mailbox with the given key in the hash table.  Return a pointer
16031708Sstevel  * to the mailbox if it exists, or NULL if no matching mailbox is found.
16041708Sstevel  * NOTE: The caller MUST hold mboxsc_lock to avoid corrupting the hash table.
16051708Sstevel  */
16061708Sstevel static mboxsc_mbox_t *
mboxsc_hashfind_mailbox_by_key(uint32_t key)16071708Sstevel mboxsc_hashfind_mailbox_by_key(uint32_t key)
16081708Sstevel {
16091708Sstevel 	uint32_t	hash;
16101708Sstevel 	mboxsc_mbox_t	*mailboxp;
16111708Sstevel 
16121708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT,
16131708Sstevel 	    "mboxsc_hashfind_mailbox_by_key called\n");
16141708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key);
16151708Sstevel 
16161708Sstevel 	/*
16171708Sstevel 	 * The global lock must be held by the caller.
16181708Sstevel 	 */
16191708Sstevel 	ASSERT(mutex_owned(&mboxsc_lock));
16201708Sstevel 
16211708Sstevel 	hash = HASH_KEY(key);
16221708Sstevel 	mailboxp = mboxsc_hash_table[hash];
16231708Sstevel 	while (mailboxp != NULL) {
16241708Sstevel 		if (mailboxp->mbox_key == key) {
16251708Sstevel 			break;
16261708Sstevel 		}
16271708Sstevel 		mailboxp = mailboxp->mbox_hash_next;
16281708Sstevel 	}
16291708Sstevel 
16301708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
1631*11311SSurya.Prakki@Sun.COM 	    "mboxsc_hashfind_mailbox_by_key ret: %p\n", (void *)mailboxp);
16321708Sstevel 	return (mailboxp);
16331708Sstevel }
16341708Sstevel 
16351708Sstevel /*
16361708Sstevel  * mboxsc_hashremove_mailbox_by_key
16371708Sstevel  *
16381708Sstevel  * Locate a mailbox with the given key in the hash table.  If it exists,
16391708Sstevel  * remove it from the hash table and return a pointer to it.  Otherwise,
16401708Sstevel  * return NULL.
16411708Sstevel  * NOTE: The caller MUST hold mboxsc_lock to avoid corrupting the hash table.
16421708Sstevel  */
16431708Sstevel static mboxsc_mbox_t *
mboxsc_hashremove_mailbox_by_key(uint32_t key)16441708Sstevel mboxsc_hashremove_mailbox_by_key(uint32_t key)
16451708Sstevel {
16461708Sstevel 	uint32_t	hash;
16471708Sstevel 	mboxsc_mbox_t	*mailboxp;
16481708Sstevel 	mboxsc_mbox_t	*last;
16491708Sstevel 
16501708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT,
16511708Sstevel 	    "mboxsc_hashremove_mailbox_by_key called\n");
16521708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key);
16531708Sstevel 
16541708Sstevel 	/*
16551708Sstevel 	 * The global lock must be held by the caller.
16561708Sstevel 	 */
16571708Sstevel 	ASSERT(mutex_owned(&mboxsc_lock));
16581708Sstevel 
16591708Sstevel 	hash = HASH_KEY(key);
16601708Sstevel 	mailboxp = mboxsc_hash_table[hash];
16611708Sstevel 	last = NULL;
16621708Sstevel 	while (mailboxp != NULL) {
16631708Sstevel 		if (mailboxp->mbox_key == key) {
16641708Sstevel 			break;
16651708Sstevel 		}
16661708Sstevel 		last = mailboxp;
16671708Sstevel 		mailboxp = mailboxp->mbox_hash_next;
16681708Sstevel 	}
16691708Sstevel 
16701708Sstevel 	/*
16711708Sstevel 	 * If a mailbox was found, remove it from the hash table.
16721708Sstevel 	 */
16731708Sstevel 	if (mailboxp != NULL) {
16741708Sstevel 		if (last == NULL) {
16751708Sstevel 			mboxsc_hash_table[hash] = mailboxp->mbox_hash_next;
16761708Sstevel 		} else {
16771708Sstevel 			last->mbox_hash_next = mailboxp->mbox_hash_next;
16781708Sstevel 		}
16791708Sstevel 
16801708Sstevel 		mailboxp->mbox_hash_next = NULL;
16811708Sstevel 	}
16821708Sstevel 
16831708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
1684*11311SSurya.Prakki@Sun.COM 	    "mboxsc_hashremove_mailbox_by_key ret: %p\n", (void *)mailboxp);
16851708Sstevel 	return (mailboxp);
16861708Sstevel }
16871708Sstevel 
16881708Sstevel /*
16891708Sstevel  * mboxsc_checksum
16901708Sstevel  *
16911708Sstevel  * Given a pointer to a data buffer and its length, calculate the checksum of
16921708Sstevel  * the data contained therein.
16931708Sstevel  */
16941708Sstevel static mboxsc_chksum_t
mboxsc_checksum(mboxsc_chksum_t seed,uint8_t * buf,uint32_t length)16951708Sstevel mboxsc_checksum(mboxsc_chksum_t seed, uint8_t *buf, uint32_t length)
16961708Sstevel {
16971708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_checksum called\n");
16981708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "seed = 0x%x\n", seed);
1699*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "buf = %p\n", (void *)buf);
17001708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "length = 0x%x\n", length);
17011708Sstevel 
17021708Sstevel 	while (length-- > 0) {
17031708Sstevel 		seed += *(buf++);
17041708Sstevel 	}
17051708Sstevel 
17061708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_checksum ret: 0x%08x\n",
17071708Sstevel 	    seed);
17081708Sstevel 	return (seed);
17091708Sstevel }
17101708Sstevel 
17111708Sstevel /*
17121708Sstevel  * mboxsc_lock_flags
17131708Sstevel  *
17141708Sstevel  * Acquire the hardware lock used for data_valid flag synchronization.  If the
17151708Sstevel  * lock is currently held by SMS and acquisition is mandatory, just keep on
17161708Sstevel  * trying until it is acquired.  If acquisition is not mandatory, keep trying
17171708Sstevel  * until the given deadline has been reached.  To avoid loading the system
17181708Sstevel  * unreasonably on EBUSY or EAGAIN, sleep for an appropriate amount of time
17191708Sstevel  * before retrying.  If a hardware error is encountered return it to the caller.
17201708Sstevel  *
17211708Sstevel  * If the lock is held, but not by SMS, clear it and acquire it.  Nobody
17221708Sstevel  * else should be grabbing that lock.
17231708Sstevel  */
17241708Sstevel static int
mboxsc_lock_flags(uint8_t mandatory,clock_t deadline)17251708Sstevel mboxsc_lock_flags(uint8_t mandatory, clock_t deadline)
17261708Sstevel {
17271708Sstevel 	int		error;
17281708Sstevel 	int		warned = 0;
17291708Sstevel 	uint32_t	sema;
17301708Sstevel 	clock_t		pause;
17311708Sstevel 	clock_t		warning_time = ddi_get_lbolt() + LOOP_WARN_INTERVAL;
17321708Sstevel 
17331708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_lock_flags called\n");
17341708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "mandatory = 0x%x\n", mandatory);
1735*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "deadline = 0x%lx\n", deadline);
17361708Sstevel 
17371708Sstevel 	/*
17381708Sstevel 	 * Keep trying to acquire the lock until successful or (if acquisition
17391708Sstevel 	 * is not mandatory) time runs out.  If EBUSY (lock is already held) or
17401708Sstevel 	 * EAGAIN (tunnel switch in progress) is encountered, sleep for an
17411708Sstevel 	 * appropriate amount of time before retrying.  Any other error is
17421708Sstevel 	 * unrecoverable.
17431708Sstevel 	 */
17441708Sstevel 	do {
17451708Sstevel 		pause = 0;
17461708Sstevel 
17471708Sstevel 		/*
17481708Sstevel 		 * Since multiple threads could conceivably want the flag lock
17491708Sstevel 		 * at the same time, we place the lock under a mutex and keep a
17501708Sstevel 		 * counter indicating how many threads have the flags locked at
17511708Sstevel 		 * the moment.
17521708Sstevel 		 */
17531708Sstevel 		mutex_enter(&mboxsc_lock);
17541708Sstevel 		if ((mboxsc_flaglock_count > 0) ||
17551708Sstevel 		    ((error = iosram_sema_acquire(&sema)) == 0)) {
17561708Sstevel 			mboxsc_flaglock_count++;
17571708Sstevel 			mutex_exit(&mboxsc_lock);
17581708Sstevel 
17591708Sstevel 			if (warned) {
17601708Sstevel 				cmn_err(CE_WARN, "Flags locked");
17611708Sstevel 			}
17621708Sstevel 			DPRINTF0(DBG_RETS, DBGACT_DEFAULT,
17631708Sstevel 			    "mboxsc_lock_flags ret: 0\n");
17641708Sstevel 			return (0);
17651708Sstevel 		}
17661708Sstevel 
17671708Sstevel 		/*
17681708Sstevel 		 * If iosram_sema_acquire returned EBUSY (lock already held),
17691708Sstevel 		 * make sure the lock is held by SMS, since nobody else should
17701708Sstevel 		 * ever be holding it.  If EBUSY or EAGAIN (tunnel switch in
17711708Sstevel 		 * progress) was returned, determine the appropriate amount of
17721708Sstevel 		 * time to sleep before trying again.
17731708Sstevel 		 */
17741708Sstevel 		if (error == EBUSY) {
17751708Sstevel 			if (IOSRAM_SEMA_GET_IDX(sema) != IOSRAM_SEMA_SMS_IDX) {
1776*11311SSurya.Prakki@Sun.COM 				(void) iosram_sema_release();
17771708Sstevel 				cmn_err(CE_WARN,
17781708Sstevel 				    "Incorrect flag lock value read (0x%08x)",
17791708Sstevel 				    sema);
17801708Sstevel 			} else {
17811708Sstevel 				pause = (mandatory ? HWLOCK_POLL :
17821708Sstevel 				    MIN(HWLOCK_POLL, deadline -
17831708Sstevel 				    ddi_get_lbolt()));
17841708Sstevel 			}
17851708Sstevel 		} else if (error == EAGAIN) {
17861708Sstevel 			pause = (mandatory ? EAGAIN_POLL : MIN(EAGAIN_POLL,
17871708Sstevel 			    deadline - ddi_get_lbolt()));
17881708Sstevel 		}
17891708Sstevel 
17901708Sstevel 		/*
17911708Sstevel 		 * We had to hold the lock until now to protect the potential
17921708Sstevel 		 * iosram_sema_release call above.
17931708Sstevel 		 */
17941708Sstevel 		mutex_exit(&mboxsc_lock);
17951708Sstevel 
17961708Sstevel 		/*
17971708Sstevel 		 * If EAGAIN or EBUSY was encountered, we're looping.
17981708Sstevel 		 */
17991708Sstevel 		if ((error == EAGAIN) || (error == EBUSY)) {
18001708Sstevel 			/*
18011708Sstevel 			 * If we've been looping here for a while, something is
18021708Sstevel 			 * probably wrong, so we should generated a warning.
18031708Sstevel 			 */
18041708Sstevel 			if (warning_time - ddi_get_lbolt() <= 0) {
18051708Sstevel 				if (!warned) {
18061708Sstevel 					warned = 1;
18071708Sstevel 					cmn_err(CE_WARN,
18081708Sstevel 					    "Unable to lock flags (0x%08x)",
18091708Sstevel 					    error);
18101708Sstevel 				} else {
18111708Sstevel 					cmn_err(CE_WARN,
18121708Sstevel 					    "Still unable to lock flags");
18131708Sstevel 				}
18141708Sstevel 				warning_time = ddi_get_lbolt() +
18151708Sstevel 				    LOOP_WARN_INTERVAL;
18161708Sstevel 			}
18171708Sstevel 
18181708Sstevel 			/*
18191708Sstevel 			 * Sleep a while before trying again.
18201708Sstevel 			 */
18211708Sstevel 			delay(pause);
18221708Sstevel 		}
18231708Sstevel 	} while (((error == EAGAIN) || (error == EBUSY)) &&
18241708Sstevel 	    (mandatory || (deadline - ddi_get_lbolt() >= 0)));
18251708Sstevel 
18261708Sstevel 	/*
18271708Sstevel 	 * If something really bad has happened, generate a warning.
18281708Sstevel 	 */
18291708Sstevel 	if ((error != EAGAIN) && (error != EBUSY)) {
18301708Sstevel 		cmn_err(CE_WARN, "Flag locking failed! (%d)", error);
18311708Sstevel 	}
18321708Sstevel 
18331708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_lock_flags ret: 0x%08x\n",
18341708Sstevel 	    error);
18351708Sstevel 	return (error);
18361708Sstevel }
18371708Sstevel 
18381708Sstevel /*
18391708Sstevel  * mboxsc_unlock_flags
18401708Sstevel  *
18411708Sstevel  * Release the hardware lock used for data_valid flag synchronization.
18421708Sstevel  * If a hardware error is encountered, return it to the caller.  If the
18431708Sstevel  * mandatory flag is set, loop and retry if EAGAIN is encountered.
18441708Sstevel  */
18451708Sstevel static int
mboxsc_unlock_flags(uint8_t mandatory)18461708Sstevel mboxsc_unlock_flags(uint8_t mandatory)
18471708Sstevel {
18481708Sstevel 	int	error;
18491708Sstevel 	int	warned = 0;
18501708Sstevel 	clock_t	warning_time = ddi_get_lbolt() + LOOP_WARN_INTERVAL;
18511708Sstevel 
18521708Sstevel 	ASSERT(mboxsc_flaglock_count != 0);
18531708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_unlock_flags called\n");
18541708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "mandatory = 0x%x\n", mandatory);
18551708Sstevel 
18561708Sstevel 	do {
18571708Sstevel 		/*
18581708Sstevel 		 * Since multiple threads could conceivably want the flag lock
18591708Sstevel 		 * at the same time, we place the lock under a mutex and keep a
18601708Sstevel 		 * counter indicating how many threads have the flags locked at
18611708Sstevel 		 * the moment.
18621708Sstevel 		 */
18631708Sstevel 		mutex_enter(&mboxsc_lock);
18641708Sstevel 		if ((mboxsc_flaglock_count > 1) ||
18651708Sstevel 		    ((error = iosram_sema_release()) == 0)) {
18661708Sstevel 			mboxsc_flaglock_count--;
18671708Sstevel 			mutex_exit(&mboxsc_lock);
18681708Sstevel 
18691708Sstevel 			if (warned) {
18701708Sstevel 				cmn_err(CE_WARN, "Flags unlocked");
18711708Sstevel 			}
18721708Sstevel 			DPRINTF0(DBG_RETS, DBGACT_DEFAULT,
18731708Sstevel 			    "mboxsc_unlock_flags ret: 0\n");
18741708Sstevel 			return (0);
18751708Sstevel 		}
18761708Sstevel 		mutex_exit(&mboxsc_lock);
18771708Sstevel 
18781708Sstevel 		/*
18791708Sstevel 		 * If iosram_sema_release returned EAGAIN (tunnel switch in
18801708Sstevel 		 * progress) and unlocking the flags is mandatory, sleep before
18811708Sstevel 		 * trying again.  If we've been trying for a while, display a
18821708Sstevel 		 * warning message too.
18831708Sstevel 		 */
18841708Sstevel 		if ((error == EAGAIN) && mandatory) {
18851708Sstevel 			if (warning_time - ddi_get_lbolt() <= 0) {
18861708Sstevel 				if (!warned) {
18871708Sstevel 					warned = 1;
18881708Sstevel 					cmn_err(CE_WARN, "Unable to unlock "
18891708Sstevel 					    "flags (iosram EAGAIN)");
18901708Sstevel 				} else {
18911708Sstevel 					cmn_err(CE_WARN,
18921708Sstevel 					    "Still unable to unlock flags");
18931708Sstevel 				}
18941708Sstevel 				warning_time = ddi_get_lbolt() +
18951708Sstevel 				    LOOP_WARN_INTERVAL;
18961708Sstevel 			}
18971708Sstevel 
18981708Sstevel 			delay(EAGAIN_POLL);
18991708Sstevel 		}
19001708Sstevel 	} while ((error == EAGAIN) && mandatory);
19011708Sstevel 
19021708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_unlock_flags ret: 0x%08x\n",
19031708Sstevel 	    error);
19041708Sstevel 	return (error);
19051708Sstevel }
19061708Sstevel 
19071708Sstevel /*
19081708Sstevel  * mboxsc_timed_read
19091708Sstevel  *
19101708Sstevel  * This function is just a wrapper around iosram_rd that will keep sleeping
19111708Sstevel  * and retrying, up to a given deadline, if iosram_rd returns EAGAIN
19121708Sstevel  * (presumably due to a tunnel switch).
19131708Sstevel  */
19141708Sstevel static int
mboxsc_timed_read(clock_t deadline,uint32_t key,uint32_t off,uint32_t len,caddr_t dptr)19151708Sstevel mboxsc_timed_read(clock_t deadline, uint32_t key, uint32_t off, uint32_t len,
19161708Sstevel 	caddr_t dptr)
19171708Sstevel {
19181708Sstevel 	int error;
19191708Sstevel 
19201708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_timed_read called\n");
1921*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "deadline = 0x%lx\n", deadline);
19221708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key);
19231708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "off = 0x%x\n", off);
19241708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "len = 0x%x\n", len);
1925*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "dptr = %p\n", (void *)dptr);
19261708Sstevel 
19271708Sstevel 	do {
19281708Sstevel 		error = iosram_rd(key, off, len, dptr);
19291708Sstevel 		if (error == EAGAIN) {
19301708Sstevel 			delay(MIN(EAGAIN_POLL, deadline - ddi_get_lbolt()));
19311708Sstevel 		}
19321708Sstevel 	} while ((error == EAGAIN) && (deadline - ddi_get_lbolt() >= 0));
19331708Sstevel 
19341708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
19351708Sstevel 	    "mboxsc_timed_read ret: 0x%08x\n", error);
19361708Sstevel 	return (error);
19371708Sstevel }
19381708Sstevel 
19391708Sstevel /*
19401708Sstevel  * mboxsc_timed_write
19411708Sstevel  *
19421708Sstevel  * This function is just a wrapper around iosram_wr that will keep sleeping
19431708Sstevel  * and retrying, up to a given deadline, if iosram_wr returns EAGAIN
19441708Sstevel  * (presumably due to a tunnel switch).
19451708Sstevel  */
19461708Sstevel static int
mboxsc_timed_write(clock_t deadline,uint32_t key,uint32_t off,uint32_t len,caddr_t dptr)19471708Sstevel mboxsc_timed_write(clock_t deadline, uint32_t key, uint32_t off, uint32_t len,
19481708Sstevel 	caddr_t dptr)
19491708Sstevel {
19501708Sstevel 	int error;
19511708Sstevel 
19521708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_timed_write called\n");
1953*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "deadline = 0x%lx\n", deadline);
19541708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key);
19551708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "off = 0x%x\n", off);
19561708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "len = 0x%x\n", len);
1957*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "dptr = %p\n", (void *)dptr);
19581708Sstevel 
19591708Sstevel 	do {
19601708Sstevel 		error = iosram_wr(key, off, len, dptr);
19611708Sstevel 		if (error == EAGAIN) {
19621708Sstevel 			delay(MIN(EAGAIN_POLL, deadline - ddi_get_lbolt()));
19631708Sstevel 		}
19641708Sstevel 	} while ((error == EAGAIN) && (deadline - ddi_get_lbolt() >= 0));
19651708Sstevel 
19661708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
19671708Sstevel 	    "mboxsc_timed_write ret: 0x%08x\n", error);
19681708Sstevel 	return (error);
19691708Sstevel }
19701708Sstevel 
19711708Sstevel /*
19721708Sstevel  * mboxsc_timed_get_flag
19731708Sstevel  *
19741708Sstevel  * This function is just a wrapper around iosram_get_flag that will keep
19751708Sstevel  * sleeping and retrying, up to a given deadline, if iosram_get_flag returns
19761708Sstevel  * EAGAIN (presumably due to a tunnel switch).
19771708Sstevel  */
19781708Sstevel static int
mboxsc_timed_get_flag(clock_t deadline,uint32_t key,uint8_t * data_validp,uint8_t * int_pendingp)19791708Sstevel mboxsc_timed_get_flag(clock_t deadline, uint32_t key, uint8_t *data_validp,
19801708Sstevel 	uint8_t *int_pendingp)
19811708Sstevel {
19821708Sstevel 	int error;
19831708Sstevel 
19841708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_timed_get_flag called\n");
1985*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "deadline = 0x%lx\n", deadline);
19861708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key);
1987*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "data_validp = %p\n",
1988*11311SSurya.Prakki@Sun.COM 	    (void *)data_validp);
1989*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "int_pendingp = %p\n",
1990*11311SSurya.Prakki@Sun.COM 	    (void *)int_pendingp);
19911708Sstevel 
19921708Sstevel 	do {
19931708Sstevel 		error = iosram_get_flag(key, data_validp, int_pendingp);
19941708Sstevel 		if (error == EAGAIN) {
19951708Sstevel 			delay(MIN(EAGAIN_POLL, deadline - ddi_get_lbolt()));
19961708Sstevel 		}
19971708Sstevel 	} while ((error == EAGAIN) && (deadline - ddi_get_lbolt() >= 0));
19981708Sstevel 
19991708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
20001708Sstevel 	    "mboxsc_timed_get_flag ret: 0x%08x\n", error);
20011708Sstevel 	return (error);
20021708Sstevel }
20031708Sstevel 
20041708Sstevel /*
20051708Sstevel  * mboxsc_timed_set_flag
20061708Sstevel  *
20071708Sstevel  * This function is just a wrapper around iosram_set_flag that will keep
20081708Sstevel  * sleeping and retrying, up to a given deadline, if iosram_set_flag returns
20091708Sstevel  * EAGAIN (presumably due to a tunnel switch).
20101708Sstevel  */
20111708Sstevel static int
mboxsc_timed_set_flag(clock_t deadline,uint32_t key,uint8_t data_valid,uint8_t int_pending)20121708Sstevel mboxsc_timed_set_flag(clock_t deadline, uint32_t key, uint8_t data_valid,
20131708Sstevel 	uint8_t int_pending)
20141708Sstevel {
20151708Sstevel 	int error;
20161708Sstevel 
20171708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_timed_set_flag called\n");
2018*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "deadline = 0x%lx\n", deadline);
20191708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key);
20201708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "data_valid = %d\n", data_valid);
20211708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "int_pending = %d\n", int_pending);
20221708Sstevel 
20231708Sstevel 	do {
20241708Sstevel 		error = iosram_set_flag(key, data_valid, int_pending);
20251708Sstevel 		if (error == EAGAIN) {
20261708Sstevel 			delay(MIN(EAGAIN_POLL, deadline - ddi_get_lbolt()));
20271708Sstevel 		}
20281708Sstevel 	} while ((error == EAGAIN) && (deadline - ddi_get_lbolt() >= 0));
20291708Sstevel 
20301708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
20311708Sstevel 	    "mboxsc_timed_set_flag ret: 0x%08x\n", error);
20321708Sstevel 	return (error);
20331708Sstevel }
20341708Sstevel 
20351708Sstevel /*
20361708Sstevel  * mboxsc_timed_send_intr
20371708Sstevel  *
20381708Sstevel  * This function is just a wrapper around iosram_send_intr that will keep
20391708Sstevel  * sleeping and retrying, up to a given deadline, if iosram_send_intr returns
20401708Sstevel  * EAGAIN (presumably due to a tunnel switch).
20411708Sstevel  */
20421708Sstevel static int
mboxsc_timed_send_intr(clock_t deadline)20431708Sstevel mboxsc_timed_send_intr(clock_t deadline)
20441708Sstevel {
20451708Sstevel 	int error;
20461708Sstevel 
20471708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_timed_send_intr called\n");
2048*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "deadline = 0x%lx\n", deadline);
20491708Sstevel 
20501708Sstevel 	do {
20511708Sstevel 		error = iosram_send_intr();
20521708Sstevel 		if (error == DDI_FAILURE) {
20531708Sstevel 			delay(MIN(EAGAIN_POLL, deadline - ddi_get_lbolt()));
20541708Sstevel 		}
20551708Sstevel 	} while ((error == DDI_FAILURE) && (deadline - ddi_get_lbolt() >= 0));
20561708Sstevel 
20571708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
20581708Sstevel 	    "mboxsc_timed_send_intr ret: 0x%08x\n", error);
20591708Sstevel 	return (error);
20601708Sstevel }
20611708Sstevel 
20621708Sstevel /*
20631708Sstevel  * mboxsc_expire_message
20641708Sstevel  *
20651708Sstevel  * This function is called by mboxsc_putmsg to handle expiration of messages
20661708Sstevel  * that weren't picked up before they timed out.  It will not return until the
20671708Sstevel  * message has been picked up (which isn't expected), the message has been
20681708Sstevel  * successfully expired, or a serious error has been encountered.  If the
20691708Sstevel  * message is finally picked up, it will set the value pointed to by "resultp"
20701708Sstevel  * to 0.  Unlike other sections of code, this function will never time out on
20711708Sstevel  * EAGAIN from the iosram driver, since it is important that both sides of the
20721708Sstevel  * IOSRAM agree on whether or not a message was delivered successfully.
20731708Sstevel  */
20741708Sstevel static int
mboxsc_expire_message(uint32_t key,int * resultp)20751708Sstevel mboxsc_expire_message(uint32_t key, int *resultp)
20761708Sstevel {
20771708Sstevel 	int	error = 0;
20781708Sstevel 	int	lock_held = 0;
20791708Sstevel 	int	warned = 0;
20801708Sstevel 	uint8_t	data_valid;
20811708Sstevel 	clock_t	warning_time = ddi_get_lbolt() + LOOP_WARN_INTERVAL;
20821708Sstevel 
20831708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_expire_message called\n");
20841708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%x\n", key);
2085*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "resultp = %p\n", (void *)resultp);
20861708Sstevel 
20871708Sstevel 	do {
20881708Sstevel 		error = 0;
20891708Sstevel 
20901708Sstevel 		/*
20911708Sstevel 		 * Lock the flags if they aren't locked already.
20921708Sstevel 		 */
20931708Sstevel 		if (!lock_held) {
20941708Sstevel 			error = mboxsc_lock_flags(TRUE, 0);
20951708Sstevel 			if (error == 0) {
20961708Sstevel 				lock_held = 1;
20971708Sstevel 			}
20981708Sstevel 		}
20991708Sstevel 
21001708Sstevel 		/*
21011708Sstevel 		 * If the flags were locked successfully, reread the data-valid
21021708Sstevel 		 * flag.
21031708Sstevel 		 */
21041708Sstevel 		if (error == 0) {
21051708Sstevel 			error = iosram_get_flag(key, &data_valid, NULL);
21061708Sstevel 		}
21071708Sstevel 
21081708Sstevel 		/*
21091708Sstevel 		 * If the data-valid flag was read successfully, see if it has
21101708Sstevel 		 * been cleared or not, as the other side may have finally read
21111708Sstevel 		 * the message.
21121708Sstevel 		 */
21131708Sstevel 		if (error == 0) {
21141708Sstevel 			if (data_valid == IOSRAM_DATA_INVALID) {
21151708Sstevel 				/*
21161708Sstevel 				 * Surprise!  The SC finally picked up the
21171708Sstevel 				 * message, so delivery succeeded after all.
21181708Sstevel 				 */
21191708Sstevel 				if (*resultp == ETIMEDOUT) {
21201708Sstevel 					*resultp = 0;
21211708Sstevel 				}
21221708Sstevel 			} else {
21231708Sstevel 				/*
21241708Sstevel 				 * The message still hasn't been read, so try to
21251708Sstevel 				 * clear the data-valid flag.
21261708Sstevel 				 */
21271708Sstevel 				error = iosram_set_flag(key,
21281708Sstevel 				    IOSRAM_DATA_INVALID, IOSRAM_INT_NONE);
21291708Sstevel 			}
21301708Sstevel 		}
21311708Sstevel 
21321708Sstevel 		/*
21331708Sstevel 		 * If the flags were locked, unlock them, no matter what else
21341708Sstevel 		 * has or has not succeeded.  Don't overwrite the existing value
21351708Sstevel 		 * of "error" unless no errors other than EAGAIN have been
21361708Sstevel 		 * encountered previously.  If we hit EAGAIN at some point,
21371708Sstevel 		 * unlocking the flags here is optional.  In all other cases, it
21381708Sstevel 		 * is mandatory.
21391708Sstevel 		 */
21401708Sstevel 		if (lock_held) {
21411708Sstevel 			int unlock_err;
21421708Sstevel 
21431708Sstevel 			if (error == EAGAIN) {
21441708Sstevel 				unlock_err = mboxsc_unlock_flags(FALSE);
21451708Sstevel 			} else {
21461708Sstevel 				unlock_err = mboxsc_unlock_flags(TRUE);
21471708Sstevel 			}
21481708Sstevel 
21491708Sstevel 			if (unlock_err == 0) {
21501708Sstevel 				lock_held = 0;
21511708Sstevel 			} else if ((error == 0) || (error == EAGAIN)) {
21521708Sstevel 				error = unlock_err;
21531708Sstevel 			}
21541708Sstevel 		}
21551708Sstevel 
21561708Sstevel 		/*
21571708Sstevel 		 * Did we hit a tunnel switch? (iosram driver returns EAGAIN)
21581708Sstevel 		 * If so, sleep for a while before trying the whole process
21591708Sstevel 		 * again.
21601708Sstevel 		 */
21611708Sstevel 		if (error == EAGAIN) {
21621708Sstevel 			/*
21631708Sstevel 			 * If we've been stuck in this loop for a while,
21641708Sstevel 			 * something is probably wrong, and we should display a
21651708Sstevel 			 * warning.
21661708Sstevel 			 */
21671708Sstevel 			if (warning_time - ddi_get_lbolt() <= 0) {
21681708Sstevel 				if (!warned) {
21691708Sstevel 					warned = 1;
21701708Sstevel 					cmn_err(CE_WARN, "Unable to clear flag "
21711708Sstevel 					    "(iosram EAGAIN)");
21721708Sstevel 				} else {
21731708Sstevel 					cmn_err(CE_WARN,
21741708Sstevel 					    "Still unable to clear flag");
21751708Sstevel 				}
21761708Sstevel 				warning_time = ddi_get_lbolt() +
21771708Sstevel 				    LOOP_WARN_INTERVAL;
21781708Sstevel 			}
21791708Sstevel 
21801708Sstevel 			delay(EAGAIN_POLL);
21811708Sstevel 		}
21821708Sstevel 	} while (error == EAGAIN);
21831708Sstevel 
21841708Sstevel 	/*
21851708Sstevel 	 * If the data-valid flag was not successfully cleared due to some sort
21861708Sstevel 	 * of problem, report it.  Otherwise, if we looped for a while on EAGAIN
21871708Sstevel 	 * and generated a warning about it, indicate that everything is okay
21881708Sstevel 	 * now.
21891708Sstevel 	 */
21901708Sstevel 	if (error != 0) {
21911708Sstevel 		cmn_err(CE_WARN, "Message expiration failure! (%d)", error);
21921708Sstevel 	} else if (warned) {
21931708Sstevel 		cmn_err(CE_WARN, "Flag cleared");
21941708Sstevel 	}
21951708Sstevel 
21961708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
21971708Sstevel 	    "mboxsc_expire_message ret: 0x%08x\n", error);
21981708Sstevel 	return (error);
21991708Sstevel }
22001708Sstevel 
22011708Sstevel 
22021708Sstevel /*
22031708Sstevel  * mboxsc_generate_transid
22041708Sstevel  *
22051708Sstevel  * This function generates unique transaction IDs using an incrementing counter.
22061708Sstevel  * The value generated is guaranteed not to be the same as the prev_transid
22071708Sstevel  * value passed in by the caller.
22081708Sstevel  */
22091708Sstevel static uint64_t
mboxsc_generate_transid(uint64_t prev_transid)22101708Sstevel mboxsc_generate_transid(uint64_t prev_transid)
22111708Sstevel {
22121708Sstevel 	uint64_t	new_transid;
22131708Sstevel 	static uint64_t	transid_counter = 0;
22141708Sstevel 
22151708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_generate_transid called");
2216*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "prev_transid = 0x%016lx\n",
22171708Sstevel 	    prev_transid);
22181708Sstevel 
22191708Sstevel 	do {
22201708Sstevel 		new_transid = TRANSID_GEN_MASK | transid_counter++;
22211708Sstevel 		if (transid_counter & TRANSID_GEN_MASK) {
22221708Sstevel 			transid_counter = 0;
22231708Sstevel 		}
22241708Sstevel 	} while (new_transid == prev_transid);
22251708Sstevel 
22261708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
2227*11311SSurya.Prakki@Sun.COM 	    "mboxsc_generate_transid ret: 0x%016lx", new_transid);
22281708Sstevel 	return (new_transid);
22291708Sstevel }
22301708Sstevel 
22311708Sstevel 
22321708Sstevel /*
22331708Sstevel  * mboxsc_reference_mailbox
22341708Sstevel  *
22351708Sstevel  * Increment the mailbox's reference count to prevent it from being closed.
22361708Sstevel  * This really doesn't deserve to be a function, but since a dereference
22371708Sstevel  * function is needed, having a corresponding reference function makes the code
22381708Sstevel  * clearer.
22391708Sstevel  */
22401708Sstevel static void
mboxsc_reference_mailbox(mboxsc_mbox_t * mailboxp)22411708Sstevel mboxsc_reference_mailbox(mboxsc_mbox_t *mailboxp)
22421708Sstevel {
22431708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_reference_mailbox called");
2244*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "mailboxp = 0x%p\n",
2245*11311SSurya.Prakki@Sun.COM 	    (void *)mailboxp);
22461708Sstevel 
22471708Sstevel 	ASSERT(mutex_owned(&mboxsc_lock));
22481708Sstevel 
22491708Sstevel 	mailboxp->mbox_refcount++;
22501708Sstevel 
22511708Sstevel 	DPRINTF0(DBG_RETS, DBGACT_DEFAULT, "mboxsc_reference_mailbox ret");
22521708Sstevel }
22531708Sstevel 
22541708Sstevel 
22551708Sstevel /*
22561708Sstevel  * mboxsc_dereference_mailbox
22571708Sstevel  *
22581708Sstevel  * Decrement the mailbox's reference count, and if the count has gone to zero,
22591708Sstevel  * signal any threads waiting for mailboxes to be completely dereferenced.
22601708Sstevel  */
22611708Sstevel static void
mboxsc_dereference_mailbox(mboxsc_mbox_t * mailboxp)22621708Sstevel mboxsc_dereference_mailbox(mboxsc_mbox_t *mailboxp)
22631708Sstevel {
22641708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT,
22651708Sstevel 	    "mboxsc_dereference_mailbox called");
2266*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "mailboxp = 0x%p\n",
2267*11311SSurya.Prakki@Sun.COM 	    (void *)mailboxp);
22681708Sstevel 
22691708Sstevel 	ASSERT(mutex_owned(&mboxsc_lock));
22701708Sstevel 
22711708Sstevel 	mailboxp->mbox_refcount--;
22721708Sstevel 	if (mailboxp->mbox_refcount == 0) {
22731708Sstevel 		cv_broadcast(&mboxsc_dereference_cv);
22741708Sstevel 	}
22751708Sstevel 
22761708Sstevel 	DPRINTF0(DBG_RETS, DBGACT_DEFAULT, "mboxsc_dereference_mailbox ret");
22771708Sstevel }
22781708Sstevel 
22791708Sstevel 
22801708Sstevel #ifndef DEBUG
22811708Sstevel /* ARGSUSED */
22821708Sstevel int
mboxsc_debug(int cmd,void * arg)22831708Sstevel mboxsc_debug(int cmd, void *arg)
22841708Sstevel {
22851708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_debug called");
22861708Sstevel 	DPRINTF0(DBG_RETS, DBGACT_DEFAULT, "mboxsc_debug ret");
22871708Sstevel 	return (ENOTSUP);
22881708Sstevel }
22891708Sstevel #else	/* DEBUG */
22901708Sstevel 
22911708Sstevel static void	print_hash_table(void);
22921708Sstevel static int	print_mailbox_by_key(uint32_t key);
22931708Sstevel static void	print_mailbox(mboxsc_mbox_t *mailboxp);
22941708Sstevel 
22951708Sstevel int
mboxsc_debug(int cmd,void * arg)22961708Sstevel mboxsc_debug(int cmd, void *arg)
22971708Sstevel {
22981708Sstevel 	int		error = 0;
22991708Sstevel 
23001708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "mboxsc_debug called\n");
23011708Sstevel 
23021708Sstevel 	switch (cmd) {
23031708Sstevel 		case MBOXSC_PRNMBOX:
23041708Sstevel 			error = print_mailbox_by_key((uint32_t)(uintptr_t)arg);
23051708Sstevel 			break;
23061708Sstevel 
23071708Sstevel 		case MBOXSC_PRNHASHTBL:
23081708Sstevel 			print_hash_table();
23091708Sstevel 			break;
23101708Sstevel 
23111708Sstevel 		case MBOXSC_SETDBGMASK:
23121708Sstevel 			mboxsc_debug_mask = (uint32_t)(uintptr_t)arg;
23131708Sstevel 			break;
23141708Sstevel 
23151708Sstevel 		default:
23161708Sstevel 			DPRINTF1(DBG_DEV, DBGACT_DEFAULT,
23171708Sstevel 			    "Error: unknown mboxsc debug cmd (%d)\n", cmd);
23181708Sstevel 			error = ENOTTY;
23191708Sstevel 			break;
23201708Sstevel 	}
23211708Sstevel 
23221708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT, "mboxsc_debug ret: 0x%08x\n", error);
23231708Sstevel 
23241708Sstevel 	return (error);
23251708Sstevel }
23261708Sstevel 
23271708Sstevel /*PRINTFLIKE5*/
23281708Sstevel static void
mboxsc_dprintf(const char * file,int line,uint32_t class,uint32_t action,const char * fmt,...)23291708Sstevel mboxsc_dprintf(
23301708Sstevel 	const char	*file,
23311708Sstevel 	int		line,
23321708Sstevel 	uint32_t	class,
23331708Sstevel 	uint32_t	action,
23341708Sstevel 	const char	*fmt,
23351708Sstevel 	...)
23361708Sstevel {
23371708Sstevel 	int		i;
23381708Sstevel 	char		indent_buf[64];
23391708Sstevel 	char		msg_buf[256];
23401708Sstevel 	va_list		adx;
23411708Sstevel 	static uint32_t	indent = 0;
23421708Sstevel 
23431708Sstevel 	if (action & DBGACT_SHOWPOS) {
23441708Sstevel 		cmn_err(CE_CONT, "%s at line %d:\n", file, line);
23451708Sstevel 	}
23461708Sstevel 
23471708Sstevel 	if (class & DBG_RETS) {
23481708Sstevel 		indent--;
23491708Sstevel 	}
23501708Sstevel 
23511708Sstevel 	if (class & mboxsc_debug_mask) {
23521708Sstevel 		indent_buf[0] = '\0';
23531708Sstevel 		for (i = 0; i < indent; i++) {
2354*11311SSurya.Prakki@Sun.COM 			(void) strcat(indent_buf, "  ");
23551708Sstevel 		}
23561708Sstevel 
23571708Sstevel 		va_start(adx, fmt);
2358*11311SSurya.Prakki@Sun.COM 		(void) vsprintf(msg_buf, fmt, adx);
23591708Sstevel 		va_end(adx);
23601708Sstevel 
23611708Sstevel 		cmn_err(CE_CONT, "%s%s", indent_buf, msg_buf);
23621708Sstevel 	}
23631708Sstevel 
23641708Sstevel 	if (class & DBG_CALLS) {
23651708Sstevel 		indent++;
23661708Sstevel 	}
23671708Sstevel 
23681708Sstevel 	if (action & DBGACT_BREAK) {
23691708Sstevel 		debug_enter("");
23701708Sstevel 	}
23711708Sstevel }
23721708Sstevel 
23731708Sstevel static void
print_hash_table(void)23741708Sstevel print_hash_table(void)
23751708Sstevel {
23761708Sstevel 	int		i;
23771708Sstevel 	mboxsc_mbox_t	*mailboxp;
23781708Sstevel 
23791708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "print_hash_table called\n");
23801708Sstevel 
23811708Sstevel 	mutex_enter(&mboxsc_lock);
23821708Sstevel 
23831708Sstevel 	for (i = 0; i < HASHTBL_SIZE; i++) {
23841708Sstevel 		DPRINTF1(DBG_DEV, DBGACT_DEFAULT, "hash[%02d]:\n", i);
23851708Sstevel 
23861708Sstevel 		for (mailboxp = mboxsc_hash_table[i]; mailboxp != NULL;
23871708Sstevel 		    mailboxp = mailboxp->mbox_hash_next) {
23881708Sstevel 			DPRINTF2(DBG_DEV, DBGACT_DEFAULT,
23891708Sstevel 			    "    key: 0x%08x, dir: %d\n", mailboxp->mbox_key,
23901708Sstevel 			    mailboxp->mbox_direction);
23911708Sstevel 		}
23921708Sstevel 	}
23931708Sstevel 
23941708Sstevel 	mutex_exit(&mboxsc_lock);
23951708Sstevel 
23961708Sstevel 	DPRINTF0(DBG_RETS, DBGACT_DEFAULT, "print_hash_table ret\n");
23971708Sstevel }
23981708Sstevel 
23991708Sstevel static int
print_mailbox_by_key(uint32_t key)24001708Sstevel print_mailbox_by_key(uint32_t key)
24011708Sstevel {
24021708Sstevel 	int		error = 0;
24031708Sstevel 	mboxsc_mbox_t	*mailboxp;
24041708Sstevel 
24051708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "print_mailbox_by_key called\n");
24061708Sstevel 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "key = 0x%08x\n", key);
24071708Sstevel 
24081708Sstevel 	mutex_enter(&mboxsc_lock);
24091708Sstevel 
24101708Sstevel 	mailboxp = mboxsc_hashfind_mailbox_by_key(key);
24111708Sstevel 	if (mailboxp != NULL) {
24121708Sstevel 		print_mailbox(mailboxp);
24131708Sstevel 		error = 0;
24141708Sstevel 	} else {
24151708Sstevel 		DPRINTF1(DBG_DEV, DBGACT_DEFAULT,
24161708Sstevel 		    "print_mailbox_by_key: no such mbox 0x%08x\n", key);
24171708Sstevel 		error = EBADF;
24181708Sstevel 	}
24191708Sstevel 
24201708Sstevel 	mutex_exit(&mboxsc_lock);
24211708Sstevel 	DPRINTF1(DBG_RETS, DBGACT_DEFAULT,
24221708Sstevel 	    "print_mailbox_by_key ret: 0x%08x\n", error);
24231708Sstevel 
24241708Sstevel 	return (error);
24251708Sstevel }
24261708Sstevel 
24271708Sstevel /* ARGSUSED */
24281708Sstevel static void
print_mailbox(mboxsc_mbox_t * mailboxp)24291708Sstevel print_mailbox(mboxsc_mbox_t *mailboxp)
24301708Sstevel {
24311708Sstevel 	DPRINTF0(DBG_CALLS, DBGACT_DEFAULT, "print_mailbox called\n");
2432*11311SSurya.Prakki@Sun.COM 	DPRINTF1(DBG_ARGS, DBGACT_DEFAULT, "mailboxp = %p\n",
2433*11311SSurya.Prakki@Sun.COM 	    (void *)mailboxp);
24341708Sstevel 	if (mailboxp->mbox_direction == MBOXSC_MBOX_IN) {
24351708Sstevel 		DPRINTF3(DBG_DEV, DBGACT_DEFAULT,
24361708Sstevel 		    "key = 0x%08x, dir = %d, callback = %p\n",
24371708Sstevel 		    mailboxp->mbox_key, mailboxp->mbox_direction,
2438*11311SSurya.Prakki@Sun.COM 		    (void *)mailboxp->mbox_callback);
24391708Sstevel 	} else {
24401708Sstevel 		DPRINTF2(DBG_DEV, DBGACT_DEFAULT, "key = 0x%08x, dir = %d\n",
2441*11311SSurya.Prakki@Sun.COM 		    (int)mailboxp->mbox_key, mailboxp->mbox_direction);
24421708Sstevel 	}
24431708Sstevel 	DPRINTF3(DBG_DEV, DBGACT_DEFAULT,
24441708Sstevel 	    "length = %d, refcount = %d, state = %d\n",
24451708Sstevel 	    mailboxp->mbox_length, mailboxp->mbox_refcount,
24461708Sstevel 	    mailboxp->mbox_state);
2447*11311SSurya.Prakki@Sun.COM 	/* LINTED E_BAD_FORMAT_ARG_TYPE2 */
2448*11311SSurya.Prakki@Sun.COM 	DPRINTF2(DBG_DEV, DBGACT_DEFAULT, "waitcv = %p, hashnext = %p\n",
2449*11311SSurya.Prakki@Sun.COM 	    (void *)&mailboxp->mbox_wait, (void *)mailboxp->mbox_hash_next);
24501708Sstevel 	if (mailboxp->mbox_direction == MBOXSC_MBOX_IN) {
24511708Sstevel 		DPRINTF3(DBG_DEV, DBGACT_DEFAULT,
24521708Sstevel 		    "hdr.type = 0x%x, hdr.cmd = 0x%x, hdr.len = 0x%x\n",
24531708Sstevel 		    mailboxp->mbox_header.msg_type,
24541708Sstevel 		    mailboxp->mbox_header.msg_cmd,
24551708Sstevel 		    mailboxp->mbox_header.msg_length);
2456*11311SSurya.Prakki@Sun.COM 		DPRINTF1(DBG_DEV, DBGACT_DEFAULT, "hdr.tid = 0x%016lx\n",
24571708Sstevel 		    mailboxp->mbox_header.msg_transid);
24581708Sstevel 	}
24591708Sstevel 	DPRINTF0(DBG_RETS, DBGACT_DEFAULT, "print_mailbox ret\n");
24601708Sstevel }
24611708Sstevel #endif	/* DEBUG */
2462