xref: /illumos-gate/usr/src/uts/sun4u/opl/io/dm2s.c (revision 030f3a8f)
125cf1a30Sjl /*
225cf1a30Sjl  * CDDL HEADER START
325cf1a30Sjl  *
425cf1a30Sjl  * The contents of this file are subject to the terms of the
525cf1a30Sjl  * Common Development and Distribution License (the "License").
625cf1a30Sjl  * You may not use this file except in compliance with the License.
725cf1a30Sjl  *
825cf1a30Sjl  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
925cf1a30Sjl  * or http://www.opensolaris.org/os/licensing.
1025cf1a30Sjl  * See the License for the specific language governing permissions
1125cf1a30Sjl  * and limitations under the License.
1225cf1a30Sjl  *
1325cf1a30Sjl  * When distributing Covered Code, include this CDDL HEADER in each
1425cf1a30Sjl  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1525cf1a30Sjl  * If applicable, add the following below this CDDL HEADER, with the
1625cf1a30Sjl  * fields enclosed by brackets "[]" replaced with your own identifying
1725cf1a30Sjl  * information: Portions Copyright [yyyy] [name of copyright owner]
1825cf1a30Sjl  *
1925cf1a30Sjl  * CDDL HEADER END
2025cf1a30Sjl  */
2125cf1a30Sjl /*
2225cf1a30Sjl  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
2325cf1a30Sjl  * Use is subject to license terms.
2425cf1a30Sjl  */
2525cf1a30Sjl 
2625cf1a30Sjl #pragma ident	"%Z%%M%	%I%	%E% SMI"
2725cf1a30Sjl 
2825cf1a30Sjl /*
2925cf1a30Sjl  * DM2S - Domain side Mailbox to synchronous serial device driver.
3025cf1a30Sjl  *
3125cf1a30Sjl  * Description:
3225cf1a30Sjl  * -----------
3325cf1a30Sjl  * It is a streams driver which simulates a sync serial device on
3425cf1a30Sjl  * top of a mailbox type of communication. That is, it sends/receives
3525cf1a30Sjl  * frames as mailbox messages. The mailbox communication is provided
3625cf1a30Sjl  * by another driver, which exports the mailbox interfaces.
3725cf1a30Sjl  *
3825cf1a30Sjl  * Synchronization:
3925cf1a30Sjl  * ---------------
4025cf1a30Sjl  * This driver uses streams perimeters to simplify the synchronization.
4125cf1a30Sjl  * An inner perimeter D_MTPERMOD which protects the entire module,
4225cf1a30Sjl  * that is only one thread exists inside the perimeter, is used. As
4325cf1a30Sjl  * this driver supports only one instance and is not a high-performance
4425cf1a30Sjl  * driver, D_MTPERMOD is highly suitable.
4525cf1a30Sjl  *
4625cf1a30Sjl  * All transmission and reception of frames is done inside the service
4725cf1a30Sjl  * procedures so that all streams related operations are protected
4825cf1a30Sjl  * by the perimeters.
4925cf1a30Sjl  *
5025cf1a30Sjl  * The mailbox event handler is the only asynchronous callback which
5125cf1a30Sjl  * needs to be protected outside of the streams perimeters. This is
5225cf1a30Sjl  * done using the module private lock('ms_lock');
5325cf1a30Sjl  *
5425cf1a30Sjl  */
5525cf1a30Sjl 
5625cf1a30Sjl #include <sys/types.h>
5725cf1a30Sjl #include <sys/param.h>
5825cf1a30Sjl #include <sys/stream.h>
5925cf1a30Sjl #include <sys/cred.h>
6025cf1a30Sjl #include <sys/systm.h>
6125cf1a30Sjl #include <sys/sunddi.h>
6225cf1a30Sjl #include <sys/ddi.h>
6325cf1a30Sjl #include <sys/conf.h>
6425cf1a30Sjl #include <sys/modctl.h>
6525cf1a30Sjl #include <sys/mkdev.h>
6625cf1a30Sjl #include <sys/errno.h>
6725cf1a30Sjl #include <sys/debug.h>
6825cf1a30Sjl #include <sys/kbio.h>
6925cf1a30Sjl #include <sys/kmem.h>
7025cf1a30Sjl #include <sys/consdev.h>
7125cf1a30Sjl #include <sys/file.h>
7225cf1a30Sjl #include <sys/stropts.h>
7325cf1a30Sjl #include <sys/strsun.h>
7425cf1a30Sjl #include <sys/dlpi.h>
7525cf1a30Sjl #include <sys/stat.h>
7625cf1a30Sjl #include <sys/ser_sync.h>
7725cf1a30Sjl #include <sys/sysmacros.h>
7825cf1a30Sjl #include <sys/note.h>
7925cf1a30Sjl #include <sys/sdt.h>
8025cf1a30Sjl 
8125cf1a30Sjl #include <sys/scfd/scfdscpif.h>
8225cf1a30Sjl #include <sys/dm2s.h>
8325cf1a30Sjl 
8425cf1a30Sjl 
8525cf1a30Sjl #define	DM2S_MODNAME	"dm2s"			/* Module name */
8625cf1a30Sjl #define	DM2S_TARGET_ID	0			/* Target ID of the peer */
8725cf1a30Sjl #define	DM2S_ID_NUM	0x4D53			/* 'M''S' */
8825cf1a30Sjl #define	DM2S_DEF_MTU	1504			/* Def. MTU size + PPP bytes */
8925cf1a30Sjl #define	DM2S_MAXPSZ	DM2S_DEF_MTU		/* Set it to the default MTU */
9025cf1a30Sjl #define	DM2S_LOWAT	(4 * 1024)		/* Low water mark */
9125cf1a30Sjl #define	DM2S_HIWAT	(12 * 1024)		/* High water mark */
9225cf1a30Sjl #define	DM2S_SM_TOUT	5000			/* Small timeout (5msec) */
9325cf1a30Sjl #define	DM2S_LG_TOUT	50000			/* Large timeout (50msec) */
9425cf1a30Sjl #define	DM2S_MB_TOUT	10000000		/* Mailbox timeout (10sec) */
9525cf1a30Sjl 
9625cf1a30Sjl /*
9725cf1a30Sjl  * Global variables
9825cf1a30Sjl  */
9925cf1a30Sjl void		*dm2s_softstate = NULL;			/* Softstate pointer */
10025cf1a30Sjl 
10125cf1a30Sjl 
10225cf1a30Sjl /*
10325cf1a30Sjl  * Prototypes for the module related functions.
10425cf1a30Sjl  */
10525cf1a30Sjl int dm2s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
10625cf1a30Sjl int dm2s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
10725cf1a30Sjl int dm2s_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
10825cf1a30Sjl     void *arg, void **result);
10925cf1a30Sjl 
11025cf1a30Sjl /*
11125cf1a30Sjl  * Prototypes for the streams related functions.
11225cf1a30Sjl  */
11325cf1a30Sjl int dm2s_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr);
11425cf1a30Sjl int dm2s_close(queue_t *rq, int flag, cred_t *cred);
11525cf1a30Sjl int dm2s_wput(queue_t *wq, mblk_t *mp);
11625cf1a30Sjl int dm2s_rsrv(queue_t *rq);
11725cf1a30Sjl int dm2s_wsrv(queue_t *wq);
11825cf1a30Sjl 
11925cf1a30Sjl /*
12025cf1a30Sjl  * Prototypes for the internal functions.
12125cf1a30Sjl  */
12225cf1a30Sjl void dm2s_start(queue_t *wq, dm2s_t *dm2sp);
12325cf1a30Sjl void dm2s_event_handler(scf_event_t event, void *arg);
12425cf1a30Sjl int dm2s_transmit(queue_t *wq, mblk_t *mp, target_id_t target, mkey_t key);
12525cf1a30Sjl void dm2s_receive(dm2s_t *dm2sp);
12625cf1a30Sjl void dm2s_wq_timeout(void *arg);
12725cf1a30Sjl void dm2s_rq_timeout(void *arg);
12825cf1a30Sjl void dm2s_bufcall_rcv(void *arg);
12925cf1a30Sjl static clock_t dm2s_timeout_val(int error);
13025cf1a30Sjl static void dm2s_cleanup(dm2s_t *dm2sp);
13125cf1a30Sjl static int dm2s_mbox_init(dm2s_t *dm2sp);
13225cf1a30Sjl static void dm2s_mbox_fini(dm2s_t *dm2sp);
13325cf1a30Sjl static int dm2s_prep_scatgath(mblk_t *mp, uint32_t *numsg,
13425cf1a30Sjl     mscat_gath_t *sgp, int maxsg);
13525cf1a30Sjl 
13625cf1a30Sjl #ifdef DEBUG
13725cf1a30Sjl uint32_t dm2s_debug = DBG_WARN;
13825cf1a30Sjl #endif /* DEBUG */
13925cf1a30Sjl 
14025cf1a30Sjl 
14125cf1a30Sjl /*
14225cf1a30Sjl  * Streams and module related structures.
14325cf1a30Sjl  */
14425cf1a30Sjl struct module_info dm2s_module_info = {
14525cf1a30Sjl 	DM2S_ID_NUM,		/* module ID number */
14625cf1a30Sjl 	DM2S_MODNAME,		/* module name. */
14725cf1a30Sjl 	0,			/* Minimum packet size (none) */
14825cf1a30Sjl 	DM2S_MAXPSZ,		/* Maximum packet size (none) */
14925cf1a30Sjl 	DM2S_HIWAT,		/* queue high water mark */
15025cf1a30Sjl 	DM2S_LOWAT		/* queue low water mark */
15125cf1a30Sjl };
15225cf1a30Sjl 
15325cf1a30Sjl struct qinit dm2s_rinit = {
15425cf1a30Sjl 	putq,			/* qi_putp */
15525cf1a30Sjl 	dm2s_rsrv,		/* qi_srvp */
15625cf1a30Sjl 	dm2s_open,		/* qi_qopen */
15725cf1a30Sjl 	dm2s_close,		/* qi_qlcose */
15825cf1a30Sjl 	NULL,			/* qi_qadmin */
15925cf1a30Sjl 	&dm2s_module_info,	/* qi_minfo */
16025cf1a30Sjl 	NULL			/* qi_mstat */
16125cf1a30Sjl };
16225cf1a30Sjl 
16325cf1a30Sjl struct qinit dm2s_winit = {
16425cf1a30Sjl 	dm2s_wput,		/* qi_putp */
16525cf1a30Sjl 	dm2s_wsrv,		/* qi_srvp */
16625cf1a30Sjl 	NULL,			/* qi_qopen */
16725cf1a30Sjl 	NULL,			/* qi_qlcose */
16825cf1a30Sjl 	NULL,			/* qi_qadmin */
16925cf1a30Sjl 	&dm2s_module_info,	/* qi_minfo */
17025cf1a30Sjl 	NULL			/* qi_mstat */
17125cf1a30Sjl };
17225cf1a30Sjl 
17325cf1a30Sjl 
17425cf1a30Sjl struct streamtab dm2s_streamtab = {
17525cf1a30Sjl 	&dm2s_rinit,
17625cf1a30Sjl 	&dm2s_winit,
17725cf1a30Sjl 	NULL,
17825cf1a30Sjl 	NULL
17925cf1a30Sjl };
18025cf1a30Sjl 
18125cf1a30Sjl DDI_DEFINE_STREAM_OPS(dm2s_ops, nulldev, nulldev, dm2s_attach,		\
18225cf1a30Sjl 	dm2s_detach, nodev, dm2s_info, D_NEW | D_MP | D_MTPERMOD,	\
18325cf1a30Sjl 	&dm2s_streamtab);
18425cf1a30Sjl 
18525cf1a30Sjl 
18625cf1a30Sjl struct modldrv modldrv = {
18725cf1a30Sjl 	&mod_driverops,
18825cf1a30Sjl 	"OPL Mbox to Serial Driver %I%",
18925cf1a30Sjl 	&dm2s_ops
19025cf1a30Sjl };
19125cf1a30Sjl 
19225cf1a30Sjl struct modlinkage modlinkage = {
19325cf1a30Sjl 	MODREV_1,
19425cf1a30Sjl 	&modldrv,
19525cf1a30Sjl 	NULL
19625cf1a30Sjl };
19725cf1a30Sjl 
19825cf1a30Sjl 
19925cf1a30Sjl /*
20025cf1a30Sjl  * _init - Module's init routine.
20125cf1a30Sjl  */
20225cf1a30Sjl int
20325cf1a30Sjl _init(void)
20425cf1a30Sjl {
20525cf1a30Sjl 	int ret;
20625cf1a30Sjl 
20725cf1a30Sjl 	if (ddi_soft_state_init(&dm2s_softstate, sizeof (dm2s_t), 1) != 0) {
20825cf1a30Sjl 		cmn_err(CE_WARN, "softstate initialization failed\n");
20925cf1a30Sjl 		return (DDI_FAILURE);
21025cf1a30Sjl 	}
21125cf1a30Sjl 	if ((ret = mod_install(&modlinkage)) != 0) {
21225cf1a30Sjl 		cmn_err(CE_WARN, "mod_install failed, error = %d", ret);
21325cf1a30Sjl 		ddi_soft_state_fini(&dm2s_softstate);
21425cf1a30Sjl 	}
21525cf1a30Sjl 	return (ret);
21625cf1a30Sjl }
21725cf1a30Sjl 
21825cf1a30Sjl /*
21925cf1a30Sjl  * _fini - Module's fini routine.
22025cf1a30Sjl  */
22125cf1a30Sjl int
22225cf1a30Sjl _fini(void)
22325cf1a30Sjl {
22425cf1a30Sjl 	int ret;
22525cf1a30Sjl 
22625cf1a30Sjl 	if ((ret = mod_remove(&modlinkage)) != 0) {
22725cf1a30Sjl 		return (ret);
22825cf1a30Sjl 	}
22925cf1a30Sjl 	ddi_soft_state_fini(&dm2s_softstate);
23025cf1a30Sjl 	return (ret);
23125cf1a30Sjl }
23225cf1a30Sjl 
23325cf1a30Sjl /*
23425cf1a30Sjl  * _info - Module's info routine.
23525cf1a30Sjl  */
23625cf1a30Sjl int
23725cf1a30Sjl _info(struct modinfo *modinfop)
23825cf1a30Sjl {
23925cf1a30Sjl 	return (mod_info(&modlinkage, modinfop));
24025cf1a30Sjl }
24125cf1a30Sjl 
24225cf1a30Sjl /*
24325cf1a30Sjl  * dm2s_attach - Module's attach routine.
24425cf1a30Sjl  */
24525cf1a30Sjl int
24625cf1a30Sjl dm2s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
24725cf1a30Sjl {
24825cf1a30Sjl 	int instance;
24925cf1a30Sjl 	dm2s_t *dm2sp;
25025cf1a30Sjl 	char name[20];
25125cf1a30Sjl 
25225cf1a30Sjl 
25325cf1a30Sjl 	instance = ddi_get_instance(dip);
25425cf1a30Sjl 
25525cf1a30Sjl 	/* Only one instance is supported. */
25625cf1a30Sjl 	if (instance != 0) {
25725cf1a30Sjl 		cmn_err(CE_WARN, "only one instance is supported");
25825cf1a30Sjl 		return (DDI_FAILURE);
25925cf1a30Sjl 	}
26025cf1a30Sjl 
26125cf1a30Sjl 	if (cmd != DDI_ATTACH) {
26225cf1a30Sjl 		return (DDI_FAILURE);
26325cf1a30Sjl 	}
26425cf1a30Sjl 	if (ddi_soft_state_zalloc(dm2s_softstate, instance) != DDI_SUCCESS) {
26525cf1a30Sjl 		cmn_err(CE_WARN, "softstate allocation failure");
26625cf1a30Sjl 		return (DDI_FAILURE);
26725cf1a30Sjl 	}
26825cf1a30Sjl 	dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, instance);
26925cf1a30Sjl 	if (dm2sp == NULL) {
27025cf1a30Sjl 		ddi_soft_state_free(dm2s_softstate, instance);
27125cf1a30Sjl 		cmn_err(CE_WARN, "softstate allocation failure.");
27225cf1a30Sjl 		return (DDI_FAILURE);
27325cf1a30Sjl 	}
27425cf1a30Sjl 	dm2sp->ms_dip = dip;
27525cf1a30Sjl 	dm2sp->ms_major = ddi_name_to_major(ddi_get_name(dip));
27625cf1a30Sjl 	dm2sp->ms_ppa = instance;
27725cf1a30Sjl 
27825cf1a30Sjl 	/*
27925cf1a30Sjl 	 * Get an interrupt block cookie corresponding to the
28025cf1a30Sjl 	 * interrupt priority of the event handler.
28125cf1a30Sjl 	 * Assert that the event priority is not re-defined to
28225cf1a30Sjl 	 * some higher priority.
28325cf1a30Sjl 	 */
28425cf1a30Sjl 	/* LINTED */
28525cf1a30Sjl 	ASSERT(SCF_EVENT_PRI == DDI_SOFTINT_LOW);
28625cf1a30Sjl 	if (ddi_get_soft_iblock_cookie(dip, SCF_EVENT_PRI,
28725cf1a30Sjl 	    &dm2sp->ms_ibcookie) != DDI_SUCCESS) {
28825cf1a30Sjl 		cmn_err(CE_WARN, "ddi_get_soft_iblock_cookie failed.");
28925cf1a30Sjl 		goto error;
29025cf1a30Sjl 	}
29125cf1a30Sjl 	mutex_init(&dm2sp->ms_lock, NULL, MUTEX_DRIVER,
29225cf1a30Sjl 	    (void *)dm2sp->ms_ibcookie);
29325cf1a30Sjl 
29425cf1a30Sjl 	dm2sp->ms_clean |= DM2S_CLEAN_LOCK;
29525cf1a30Sjl 	cv_init(&dm2sp->ms_wait, NULL, CV_DRIVER, NULL);
29625cf1a30Sjl 	dm2sp->ms_clean |= DM2S_CLEAN_CV;
29725cf1a30Sjl 
29825cf1a30Sjl 	(void) sprintf(name, "%s%d", DM2S_MODNAME, instance);
29925cf1a30Sjl 	if (ddi_create_minor_node(dip, name, S_IFCHR, instance,
30025cf1a30Sjl 	    DDI_PSEUDO, NULL) == DDI_FAILURE) {
30125cf1a30Sjl 		ddi_remove_minor_node(dip, NULL);
30225cf1a30Sjl 		cmn_err(CE_WARN, "Device node creation failed.");
30325cf1a30Sjl 		goto error;
30425cf1a30Sjl 	}
30525cf1a30Sjl 
30625cf1a30Sjl 	dm2sp->ms_clean |= DM2S_CLEAN_NODE;
30725cf1a30Sjl 	ddi_set_driver_private(dip, (caddr_t)dm2sp);
30825cf1a30Sjl 	ddi_report_dev(dip);
30925cf1a30Sjl 	return (DDI_SUCCESS);
31025cf1a30Sjl error:
31125cf1a30Sjl 	dm2s_cleanup(dm2sp);
31225cf1a30Sjl 	return (DDI_FAILURE);
31325cf1a30Sjl }
31425cf1a30Sjl 
31525cf1a30Sjl /*
31625cf1a30Sjl  * dm2s_info - Module's info routine.
31725cf1a30Sjl  */
31825cf1a30Sjl /*ARGSUSED*/
31925cf1a30Sjl int
32025cf1a30Sjl dm2s_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
32125cf1a30Sjl {
32225cf1a30Sjl 	dm2s_t	*dm2sp;
32325cf1a30Sjl 	minor_t	minor;
32425cf1a30Sjl 	int	ret = DDI_FAILURE;
32525cf1a30Sjl 
32625cf1a30Sjl 	switch (infocmd) {
32725cf1a30Sjl 	case DDI_INFO_DEVT2DEVINFO:
32825cf1a30Sjl 		minor = getminor((dev_t)arg);
32925cf1a30Sjl 		dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, minor);
33025cf1a30Sjl 		if (dm2sp == NULL) {
33125cf1a30Sjl 			*result = NULL;
33225cf1a30Sjl 		} else {
33325cf1a30Sjl 			*result = dm2sp->ms_dip;
33425cf1a30Sjl 			ret = DDI_SUCCESS;
33525cf1a30Sjl 		}
33625cf1a30Sjl 		break;
33725cf1a30Sjl 
33825cf1a30Sjl 	case DDI_INFO_DEVT2INSTANCE:
33925cf1a30Sjl 		minor = getminor((dev_t)arg);
34025cf1a30Sjl 		*result = (void *)(uintptr_t)minor;
34125cf1a30Sjl 		ret = DDI_SUCCESS;
34225cf1a30Sjl 		break;
34325cf1a30Sjl 
34425cf1a30Sjl 	default:
34525cf1a30Sjl 		break;
34625cf1a30Sjl 	}
34725cf1a30Sjl 	return (ret);
34825cf1a30Sjl }
34925cf1a30Sjl 
35025cf1a30Sjl /*
35125cf1a30Sjl  * dm2s_detach - Module's detach routine.
35225cf1a30Sjl  */
35325cf1a30Sjl int
35425cf1a30Sjl dm2s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
35525cf1a30Sjl {
35625cf1a30Sjl 	int instance;
35725cf1a30Sjl 	dm2s_t *dm2sp;
35825cf1a30Sjl 
35925cf1a30Sjl 	if (cmd != DDI_DETACH) {
36025cf1a30Sjl 		return (DDI_FAILURE);
36125cf1a30Sjl 	}
36225cf1a30Sjl 
36325cf1a30Sjl 	instance = ddi_get_instance(dip);
36425cf1a30Sjl 	dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, instance);
36525cf1a30Sjl 	if (dm2sp == NULL) {
36625cf1a30Sjl 		return (DDI_FAILURE);
36725cf1a30Sjl 	}
36825cf1a30Sjl 
36925cf1a30Sjl 	mutex_enter(&dm2sp->ms_lock);
37025cf1a30Sjl 
37125cf1a30Sjl 	/* Check if the mailbox is still in use. */
37225cf1a30Sjl 	if (dm2sp->ms_state & DM2S_MB_INITED) {
37325cf1a30Sjl 		mutex_exit(&dm2sp->ms_lock);
37425cf1a30Sjl 		cmn_err(CE_WARN, "Mailbox in use: Detach failed");
37525cf1a30Sjl 		return (DDI_FAILURE);
37625cf1a30Sjl 	}
37725cf1a30Sjl 	mutex_exit(&dm2sp->ms_lock);
37825cf1a30Sjl 	dm2s_cleanup(dm2sp);
37925cf1a30Sjl 	return (DDI_SUCCESS);
38025cf1a30Sjl }
38125cf1a30Sjl 
38225cf1a30Sjl /*
38325cf1a30Sjl  * dm2s_open - Device open routine.
38425cf1a30Sjl  *
38525cf1a30Sjl  * Only one open supported. Clone open is not supported.
38625cf1a30Sjl  */
38725cf1a30Sjl /* ARGSUSED */
38825cf1a30Sjl int
38925cf1a30Sjl dm2s_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr)
39025cf1a30Sjl {
39125cf1a30Sjl 	dm2s_t *dm2sp;
39225cf1a30Sjl 	int instance = getminor(*dev);
39325cf1a30Sjl 	int ret = 0;
39425cf1a30Sjl 
39525cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_open: called\n"));
39625cf1a30Sjl 	if (sflag == CLONEOPEN)	{
39725cf1a30Sjl 		/* Clone open not supported */
39825cf1a30Sjl 		DPRINTF(DBG_WARN, ("dm2s_open: clone open not supported\n"));
39925cf1a30Sjl 		return (ENOTSUP);
40025cf1a30Sjl 	}
40125cf1a30Sjl 
40225cf1a30Sjl 	if (rq->q_ptr != NULL) {
40325cf1a30Sjl 		DPRINTF(DBG_WARN, ("dm2s_open: already opened\n"));
40425cf1a30Sjl 		return (EBUSY);
40525cf1a30Sjl 	}
40625cf1a30Sjl 
40725cf1a30Sjl 	if ((dm2sp = ddi_get_soft_state(dm2s_softstate, instance)) == NULL) {
40825cf1a30Sjl 		DPRINTF(DBG_WARN, ("dm2s_open: instance not found\n"));
40925cf1a30Sjl 		return (ENODEV);
41025cf1a30Sjl 	}
41125cf1a30Sjl 
41225cf1a30Sjl 	mutex_enter(&dm2sp->ms_lock);
41325cf1a30Sjl 	if (dm2sp->ms_state & DM2S_OPENED) {
41425cf1a30Sjl 		/* Only one open supported */
41525cf1a30Sjl 		mutex_exit(&dm2sp->ms_lock);
41625cf1a30Sjl 		DPRINTF(DBG_WARN, ("dm2s_open: already opened\n"));
41725cf1a30Sjl 		return (EBUSY);
41825cf1a30Sjl 	}
41925cf1a30Sjl 
42025cf1a30Sjl 	dm2sp->ms_state |= DM2S_OPENED;
42125cf1a30Sjl 	/* Initialize the mailbox. */
42225cf1a30Sjl 	if ((ret = dm2s_mbox_init(dm2sp)) != 0) {
42325cf1a30Sjl 		dm2sp->ms_state = 0;
42425cf1a30Sjl 		mutex_exit(&dm2sp->ms_lock);
42525cf1a30Sjl 		return (ret);
42625cf1a30Sjl 	}
42725cf1a30Sjl 	rq->q_ptr = WR(rq)->q_ptr = (void *)dm2sp;
42825cf1a30Sjl 	dm2sp->ms_rq = rq;
42925cf1a30Sjl 	dm2sp->ms_wq = WR(rq);
43025cf1a30Sjl 	mutex_exit(&dm2sp->ms_lock);
43125cf1a30Sjl 
43225cf1a30Sjl 	if (ret == 0) {
43325cf1a30Sjl 		qprocson(rq);		/* now schedule our queue */
43425cf1a30Sjl 	}
43525cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_open: ret=%d\n", ret));
43625cf1a30Sjl 	return (ret);
43725cf1a30Sjl }
43825cf1a30Sjl 
43925cf1a30Sjl /*
44025cf1a30Sjl  * dm2s_close - Device close routine.
44125cf1a30Sjl  */
44225cf1a30Sjl /* ARGSUSED */
44325cf1a30Sjl int
44425cf1a30Sjl dm2s_close(queue_t *rq, int flag, cred_t *cred)
44525cf1a30Sjl {
44625cf1a30Sjl 	dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr;
44725cf1a30Sjl 
44825cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_close: called\n"));
44925cf1a30Sjl 	if (dm2sp == NULL) {
45025cf1a30Sjl 		/* Already closed once */
45125cf1a30Sjl 		return (ENODEV);
45225cf1a30Sjl 	}
45325cf1a30Sjl 
45425cf1a30Sjl 	/* Close the lower layer first */
45525cf1a30Sjl 	mutex_enter(&dm2sp->ms_lock);
45625cf1a30Sjl 	(void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, MB_FLUSH_ALL);
45725cf1a30Sjl 	dm2s_mbox_fini(dm2sp);
45825cf1a30Sjl 	mutex_exit(&dm2sp->ms_lock);
45925cf1a30Sjl 
46025cf1a30Sjl 	/*
46125cf1a30Sjl 	 * Now we can assume that no asynchronous callbacks exist.
46225cf1a30Sjl 	 * Poison the stream head so that we can't be pushed again.
46325cf1a30Sjl 	 */
46425cf1a30Sjl 	(void) putnextctl(rq, M_HANGUP);
46525cf1a30Sjl 	qprocsoff(rq);
46625cf1a30Sjl 	if (dm2sp->ms_rbufcid != 0) {
46725cf1a30Sjl 		qunbufcall(rq, dm2sp->ms_rbufcid);
46825cf1a30Sjl 		dm2sp->ms_rbufcid = 0;
46925cf1a30Sjl 	}
47025cf1a30Sjl 	if (dm2sp->ms_rq_timeoutid != 0) {
47125cf1a30Sjl 		DTRACE_PROBE1(dm2s_rqtimeout__cancel, dm2s_t, dm2sp);
47225cf1a30Sjl 		(void) quntimeout(dm2sp->ms_rq, dm2sp->ms_rq_timeoutid);
47325cf1a30Sjl 		dm2sp->ms_rq_timeoutid = 0;
47425cf1a30Sjl 	}
47525cf1a30Sjl 	if (dm2sp->ms_wq_timeoutid != 0) {
47625cf1a30Sjl 		DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp);
47725cf1a30Sjl 		(void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid);
47825cf1a30Sjl 		dm2sp->ms_wq_timeoutid = 0;
47925cf1a30Sjl 	}
48025cf1a30Sjl 	/*
48125cf1a30Sjl 	 * Now we can really mark it closed.
48225cf1a30Sjl 	 */
48325cf1a30Sjl 	mutex_enter(&dm2sp->ms_lock);
48425cf1a30Sjl 	dm2sp->ms_rq = dm2sp->ms_wq = NULL;
48525cf1a30Sjl 	dm2sp->ms_state &= ~DM2S_OPENED;
48625cf1a30Sjl 	mutex_exit(&dm2sp->ms_lock);
48725cf1a30Sjl 
48825cf1a30Sjl 	rq->q_ptr = WR(rq)->q_ptr = NULL;
48925cf1a30Sjl 	(void) qassociate(rq, -1);
49025cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_close: successfully closed\n"));
49125cf1a30Sjl 	return (0);
49225cf1a30Sjl }
49325cf1a30Sjl 
49425cf1a30Sjl /*
49525cf1a30Sjl  * dm2s_rsrv - Streams read side service procedure.
49625cf1a30Sjl  *
49725cf1a30Sjl  * All messages are received in the service procedure
49825cf1a30Sjl  * only. This is done to simplify the streams synchronization.
49925cf1a30Sjl  */
50025cf1a30Sjl int
50125cf1a30Sjl dm2s_rsrv(queue_t *rq)
50225cf1a30Sjl {
50325cf1a30Sjl 	mblk_t *mp;
50425cf1a30Sjl 	dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr;
50525cf1a30Sjl 
50625cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_rsrv: called\n"));
50725cf1a30Sjl 	ASSERT(dm2sp != NULL);
50825cf1a30Sjl 	mutex_enter(&dm2sp->ms_lock);
50925cf1a30Sjl 
51025cf1a30Sjl 	/* Receive if there are any messages waiting in the mailbox. */
51125cf1a30Sjl 	dm2s_receive(dm2sp);
51225cf1a30Sjl 	mutex_exit(&dm2sp->ms_lock);
51325cf1a30Sjl 
51425cf1a30Sjl 	/* Send the received messages up the stream. */
51525cf1a30Sjl 	while ((mp = getq(rq)) != NULL) {
51625cf1a30Sjl 		if (canputnext(rq)) {
51725cf1a30Sjl 			putnext(rq, mp);
51825cf1a30Sjl 		} else {
51925cf1a30Sjl 			putbq(rq, mp);
52025cf1a30Sjl 			break;
52125cf1a30Sjl 		}
52225cf1a30Sjl 	}
52325cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_rsrv: return\n"));
52425cf1a30Sjl 	return (0);
52525cf1a30Sjl }
52625cf1a30Sjl 
52725cf1a30Sjl /*
52825cf1a30Sjl  * dm2s_wsrv - Streams write side service procedure.
52925cf1a30Sjl  *
53025cf1a30Sjl  * All messages are transmitted in the service procedure
53125cf1a30Sjl  * only. This is done to simplify the streams synchronization.
53225cf1a30Sjl  */
53325cf1a30Sjl int
53425cf1a30Sjl dm2s_wsrv(queue_t *wq)
53525cf1a30Sjl {
53625cf1a30Sjl 	dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr;
53725cf1a30Sjl 
53825cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_wsrv: called\n"));
53925cf1a30Sjl 	ASSERT(dm2sp != NULL);
54025cf1a30Sjl 	/* Lets cancel any timeouts waiting to be scheduled. */
54125cf1a30Sjl 	if (dm2sp->ms_wq_timeoutid != 0) {
54225cf1a30Sjl 		DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp);
54325cf1a30Sjl 		(void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid);
54425cf1a30Sjl 		dm2sp->ms_wq_timeoutid = 0;
54525cf1a30Sjl 	}
54625cf1a30Sjl 	mutex_enter(&dm2sp->ms_lock);
54725cf1a30Sjl 	dm2s_start(wq, dm2sp);
54825cf1a30Sjl 	mutex_exit(&dm2sp->ms_lock);
54925cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_wsrv: return\n"));
55025cf1a30Sjl 	return (0);
55125cf1a30Sjl }
55225cf1a30Sjl 
55325cf1a30Sjl /*
55425cf1a30Sjl  * dm2s_wput - Streams write side put routine.
55525cf1a30Sjl  *
55625cf1a30Sjl  * All M_DATA messages are queued so that they are transmitted in
55725cf1a30Sjl  * the service procedure. This is done to simplify the streams
55825cf1a30Sjl  * synchronization. Other messages are handled appropriately.
55925cf1a30Sjl  */
56025cf1a30Sjl int
56125cf1a30Sjl dm2s_wput(queue_t *wq, mblk_t *mp)
56225cf1a30Sjl {
56325cf1a30Sjl 	dm2s_t	*dm2sp = (dm2s_t *)wq->q_ptr;
56425cf1a30Sjl 
56525cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_wput: called\n"));
56625cf1a30Sjl 	if (dm2sp == NULL) {
56725cf1a30Sjl 		return (ENODEV);   /* Can't happen. */
56825cf1a30Sjl 	}
56925cf1a30Sjl 
57025cf1a30Sjl 	switch (mp->b_datap->db_type) {
57125cf1a30Sjl 	case (M_DATA):
57225cf1a30Sjl 		DPRINTF(DBG_DRV, ("dm2s_wput: M_DATA message\n"));
57325cf1a30Sjl 		while (mp->b_wptr == mp->b_rptr) {
57425cf1a30Sjl 			mblk_t *mp1;
57525cf1a30Sjl 
57625cf1a30Sjl 			mp1 = unlinkb(mp);
57725cf1a30Sjl 			freemsg(mp);
57825cf1a30Sjl 			mp = mp1;
57925cf1a30Sjl 			if (mp == NULL) {
58025cf1a30Sjl 				return (0);
58125cf1a30Sjl 			}
58225cf1a30Sjl 		}
58325cf1a30Sjl 
58425cf1a30Sjl 		/*
58525cf1a30Sjl 		 * Simply queue the message and handle it in the service
58625cf1a30Sjl 		 * procedure.
58725cf1a30Sjl 		 */
58825cf1a30Sjl 		(void) putq(wq, mp);
58925cf1a30Sjl 		qenable(wq);
59025cf1a30Sjl 		return (0);
59125cf1a30Sjl 
59225cf1a30Sjl 	case (M_PROTO):
59325cf1a30Sjl 		DPRINTF(DBG_DRV, ("dm2s_wput: M_PROTO message\n"));
59425cf1a30Sjl 		/* We don't expect this */
59525cf1a30Sjl 		mp->b_datap->db_type = M_ERROR;
59625cf1a30Sjl 		mp->b_rptr = mp->b_wptr = mp->b_datap->db_base;
59725cf1a30Sjl 		*mp->b_wptr++ = EPROTO;
59825cf1a30Sjl 		qreply(wq, mp);
59925cf1a30Sjl 		return (EINVAL);
60025cf1a30Sjl 
60125cf1a30Sjl 	case (M_IOCTL):
60225cf1a30Sjl 		DPRINTF(DBG_DRV, ("dm2s_wput: M_IOCTL message\n"));
60325cf1a30Sjl 		if (MBLKL(mp) < sizeof (struct iocblk)) {
60425cf1a30Sjl 			freemsg(mp);
60525cf1a30Sjl 			return (0);
60625cf1a30Sjl 		}
60725cf1a30Sjl 		/*
60825cf1a30Sjl 		 * No ioctls required to be supported by this driver, so
60925cf1a30Sjl 		 * return EINVAL for all ioctls.
61025cf1a30Sjl 		 */
61125cf1a30Sjl 		miocnak(wq, mp, 0, EINVAL);
61225cf1a30Sjl 		break;
61325cf1a30Sjl 
61425cf1a30Sjl 	case (M_CTL):
61525cf1a30Sjl 		DPRINTF(DBG_DRV, ("dm2s_wput: M_CTL message\n"));
61625cf1a30Sjl 		/*
61725cf1a30Sjl 		 * No M_CTL messages need to supported by this driver,
61825cf1a30Sjl 		 * so simply ignore them.
61925cf1a30Sjl 		 */
62025cf1a30Sjl 		freemsg(mp);
62125cf1a30Sjl 		break;
62225cf1a30Sjl 
62325cf1a30Sjl 	case (M_FLUSH):
62425cf1a30Sjl 		DPRINTF(DBG_DRV, (
62525cf1a30Sjl 		    "dm2s_wput: M_FLUSH message 0x%X\n", *mp->b_rptr));
62625cf1a30Sjl 		if (*mp->b_rptr & FLUSHW) {	/* Flush write-side */
62725cf1a30Sjl 			(void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key,
62825cf1a30Sjl 			    MB_FLUSH_SEND);
62925cf1a30Sjl 			flushq(wq, FLUSHDATA);
63025cf1a30Sjl 			*mp->b_rptr &= ~FLUSHW;
63125cf1a30Sjl 		}
63225cf1a30Sjl 		if (*mp->b_rptr & FLUSHR) {
63325cf1a30Sjl 			(void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key,
63425cf1a30Sjl 			    MB_FLUSH_RECEIVE);
63525cf1a30Sjl 			flushq(RD(wq), FLUSHDATA);
63625cf1a30Sjl 			qreply(wq, mp);
63725cf1a30Sjl 		} else {
63825cf1a30Sjl 			freemsg(mp);
63925cf1a30Sjl 		}
64025cf1a30Sjl 		break;
64125cf1a30Sjl 
64225cf1a30Sjl 	default:
64325cf1a30Sjl 		DPRINTF(DBG_DRV, ("dm2s_wput: UNKNOWN message\n"));
64425cf1a30Sjl 		freemsg(mp);
64525cf1a30Sjl 
64625cf1a30Sjl 	}
64725cf1a30Sjl 	return (0);
64825cf1a30Sjl }
64925cf1a30Sjl 
65025cf1a30Sjl /*
65125cf1a30Sjl  * dm2s_cleanup - Cleanup routine.
65225cf1a30Sjl  */
65325cf1a30Sjl static void
65425cf1a30Sjl dm2s_cleanup(dm2s_t *dm2sp)
65525cf1a30Sjl {
65625cf1a30Sjl 	char name[20];
65725cf1a30Sjl 
65825cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_cleanup: called\n"));
65925cf1a30Sjl 	ASSERT(dm2sp != NULL);
66025cf1a30Sjl 	if (dm2sp->ms_clean & DM2S_CLEAN_NODE) {
66125cf1a30Sjl 		(void) sprintf(name, "%s%d", DM2S_MODNAME, dm2sp->ms_ppa);
66225cf1a30Sjl 		ddi_remove_minor_node(dm2sp->ms_dip, name);
66325cf1a30Sjl 	}
66425cf1a30Sjl 	if (dm2sp->ms_clean & DM2S_CLEAN_LOCK)
66525cf1a30Sjl 		mutex_destroy(&dm2sp->ms_lock);
66625cf1a30Sjl 	if (dm2sp->ms_clean & DM2S_CLEAN_CV)
66725cf1a30Sjl 		cv_destroy(&dm2sp->ms_wait);
66825cf1a30Sjl 	ddi_set_driver_private(dm2sp->ms_dip, NULL);
66925cf1a30Sjl 	ddi_soft_state_free(dm2s_softstate, dm2sp->ms_ppa);
67025cf1a30Sjl }
67125cf1a30Sjl 
67225cf1a30Sjl /*
67325cf1a30Sjl  * dm2s_mbox_init - Mailbox specific initialization.
67425cf1a30Sjl  */
67525cf1a30Sjl static int
67625cf1a30Sjl dm2s_mbox_init(dm2s_t *dm2sp)
67725cf1a30Sjl {
67825cf1a30Sjl 	int ret;
67925cf1a30Sjl 	clock_t tout;
68025cf1a30Sjl 
68125cf1a30Sjl 	ASSERT(MUTEX_HELD(&dm2sp->ms_lock));
68225cf1a30Sjl 	dm2sp->ms_target = DM2S_TARGET_ID;
68325cf1a30Sjl 	dm2sp->ms_key = DSCP_KEY;
68425cf1a30Sjl 	dm2sp->ms_state &= ~DM2S_MB_INITED;
68525cf1a30Sjl 
68625cf1a30Sjl 	/* Iterate until mailbox gets connected */
68725cf1a30Sjl 	while (!(dm2sp->ms_state & DM2S_MB_CONN)) {
68825cf1a30Sjl 		DPRINTF(DBG_MBOX, ("dm2s_mbox_init: calling mb_init\n"));
68925cf1a30Sjl 		ret = scf_mb_init(dm2sp->ms_target, dm2sp->ms_key,
69025cf1a30Sjl 		    dm2s_event_handler, (void *)dm2sp);
69125cf1a30Sjl 		DPRINTF(DBG_MBOX, ("dm2s_mbox_init: mb_init ret=%d\n", ret));
69225cf1a30Sjl 
693*030f3a8fSraghuram 		if (ret != 0) {
694*030f3a8fSraghuram 			DPRINTF(DBG_MBOX,
695*030f3a8fSraghuram 			    ("dm2s_mbox_init: failed ret =%d\n", ret));
696*030f3a8fSraghuram 			DTRACE_PROBE1(dm2s_mbox_fail, int, ret);
697*030f3a8fSraghuram 		} else {
69825cf1a30Sjl 			dm2sp->ms_state |= DM2S_MB_INITED;
69925cf1a30Sjl 
70025cf1a30Sjl 			/* Block until the mailbox is ready to communicate. */
70125cf1a30Sjl 			while (!(dm2sp->ms_state &
70225cf1a30Sjl 			    (DM2S_MB_CONN | DM2S_MB_DISC))) {
70325cf1a30Sjl 
70425cf1a30Sjl 				if (cv_wait_sig(&dm2sp->ms_wait,
70525cf1a30Sjl 				    &dm2sp->ms_lock) <= 0) {
70625cf1a30Sjl 					/* interrupted */
70725cf1a30Sjl 					ret = EINTR;
70825cf1a30Sjl 					break;
70925cf1a30Sjl 				}
71025cf1a30Sjl 			}
71125cf1a30Sjl 		}
71225cf1a30Sjl 
713*030f3a8fSraghuram 		if ((ret != 0) || (dm2sp->ms_state & DM2S_MB_DISC)) {
71425cf1a30Sjl 
715*030f3a8fSraghuram 			if (dm2sp->ms_state & DM2S_MB_INITED) {
716*030f3a8fSraghuram 				(void) scf_mb_fini(dm2sp->ms_target,
717*030f3a8fSraghuram 				    dm2sp->ms_key);
718*030f3a8fSraghuram 			}
719*030f3a8fSraghuram 			if (dm2sp->ms_state & DM2S_MB_DISC) {
720*030f3a8fSraghuram 				DPRINTF(DBG_WARN,
721*030f3a8fSraghuram 				    ("dm2s_mbox_init: mbox DISC_ERROR\n"));
722*030f3a8fSraghuram 				DTRACE_PROBE1(dm2s_mbox_fail,
723*030f3a8fSraghuram 				    int, DM2S_MB_DISC);
724*030f3a8fSraghuram 			}
72525cf1a30Sjl 
726*030f3a8fSraghuram 			dm2sp->ms_state &= ~(DM2S_MB_INITED | DM2S_MB_DISC |
727*030f3a8fSraghuram 			    DM2S_MB_CONN);
72825cf1a30Sjl 
729*030f3a8fSraghuram 			if (ret == EINTR) {
730*030f3a8fSraghuram 				return (ret);
731*030f3a8fSraghuram 			}
73225cf1a30Sjl 
73325cf1a30Sjl 			/*
73425cf1a30Sjl 			 * If there was failure, then wait for
73525cf1a30Sjl 			 * DM2S_MB_TOUT secs and retry again.
73625cf1a30Sjl 			 */
73725cf1a30Sjl 
73825cf1a30Sjl 			DPRINTF(DBG_MBOX, ("dm2s_mbox_init: waiting...\n"));
73925cf1a30Sjl 			tout = ddi_get_lbolt() + drv_usectohz(DM2S_MB_TOUT);
74025cf1a30Sjl 			ret = cv_timedwait_sig(&dm2sp->ms_wait,
74125cf1a30Sjl 			    &dm2sp->ms_lock, tout);
74225cf1a30Sjl 			if (ret == 0) {
74325cf1a30Sjl 				/* if interrupted, return immediately. */
74425cf1a30Sjl 				DPRINTF(DBG_MBOX,
74525cf1a30Sjl 				    ("dm2s_mbox_init: interrupted\n"));
74625cf1a30Sjl 				return (EINTR);
74725cf1a30Sjl 			}
74825cf1a30Sjl 		}
74925cf1a30Sjl 	}
75025cf1a30Sjl 
75125cf1a30Sjl 	/*
75225cf1a30Sjl 	 * Obtain the max size of a single message.
75325cf1a30Sjl 	 * NOTE: There is no mechanism to update the
75425cf1a30Sjl 	 * upperlayers dynamically, so we expect this
75525cf1a30Sjl 	 * size to be atleast the default MTU size.
75625cf1a30Sjl 	 */
75725cf1a30Sjl 	ret = scf_mb_ctrl(dm2sp->ms_target, dm2sp->ms_key,
75825cf1a30Sjl 	    SCF_MBOP_MAXMSGSIZE, &dm2sp->ms_mtu);
75925cf1a30Sjl 
76025cf1a30Sjl 	if ((ret == 0) && (dm2sp->ms_mtu < DM2S_DEF_MTU)) {
76125cf1a30Sjl 		cmn_err(CE_WARN, "Max message size expected >= %d "
76225cf1a30Sjl 		    "but found %d\n", DM2S_DEF_MTU, dm2sp->ms_mtu);
76325cf1a30Sjl 		ret = EIO;
76425cf1a30Sjl 	}
76525cf1a30Sjl 
76625cf1a30Sjl 	if (ret != 0) {
76725cf1a30Sjl 		dm2sp->ms_state &= ~DM2S_MB_INITED;
76825cf1a30Sjl 		(void) scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key);
76925cf1a30Sjl 	}
77025cf1a30Sjl 	DPRINTF(DBG_MBOX, ("dm2s_mbox_init: mb_init ret=%d\n", ret));
77125cf1a30Sjl 	return (ret);
77225cf1a30Sjl }
77325cf1a30Sjl 
77425cf1a30Sjl /*
77525cf1a30Sjl  * dm2s_mbox_fini - Mailbox de-initialization.
77625cf1a30Sjl  */
77725cf1a30Sjl static void
77825cf1a30Sjl dm2s_mbox_fini(dm2s_t *dm2sp)
77925cf1a30Sjl {
78025cf1a30Sjl 	int ret;
78125cf1a30Sjl 
78225cf1a30Sjl 	ASSERT(dm2sp != NULL);
78325cf1a30Sjl 	if (dm2sp->ms_state & DM2S_MB_INITED) {
78425cf1a30Sjl 		DPRINTF(DBG_MBOX, ("dm2s_mbox_fini: calling mb_fini\n"));
78525cf1a30Sjl 		ret =  scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key);
78625cf1a30Sjl 		if (ret != 0) {
78725cf1a30Sjl 			cmn_err(CE_WARN,
78825cf1a30Sjl 			    "Failed to close the Mailbox error =%d", ret);
78925cf1a30Sjl 		}
79025cf1a30Sjl 		DPRINTF(DBG_MBOX, ("dm2s_mbox_fini: mb_fini ret=%d\n", ret));
79125cf1a30Sjl 		dm2sp->ms_state &= ~(DM2S_MB_INITED |DM2S_MB_CONN |
79225cf1a30Sjl 		    DM2S_MB_DISC);
79325cf1a30Sjl 	}
79425cf1a30Sjl }
79525cf1a30Sjl 
79625cf1a30Sjl /*
79725cf1a30Sjl  * dm2s_event_handler - Mailbox event handler.
79825cf1a30Sjl  */
79925cf1a30Sjl void
80025cf1a30Sjl dm2s_event_handler(scf_event_t event, void *arg)
80125cf1a30Sjl {
80225cf1a30Sjl 	dm2s_t *dm2sp = (dm2s_t *)arg;
80325cf1a30Sjl 	queue_t	*rq;
80425cf1a30Sjl 
80525cf1a30Sjl 	ASSERT(dm2sp != NULL);
80625cf1a30Sjl 	mutex_enter(&dm2sp->ms_lock);
80725cf1a30Sjl 	if (!(dm2sp->ms_state & DM2S_MB_INITED)) {
80825cf1a30Sjl 		/*
80925cf1a30Sjl 		 * Ignore all events if the state flag indicates that the
81025cf1a30Sjl 		 * mailbox not initialized, this may happen during the close.
81125cf1a30Sjl 		 */
81225cf1a30Sjl 		mutex_exit(&dm2sp->ms_lock);
81325cf1a30Sjl 		DPRINTF(DBG_MBOX,
81425cf1a30Sjl 		    ("Event(0x%X) received - Mailbox not inited\n", event));
81525cf1a30Sjl 		return;
81625cf1a30Sjl 	}
81725cf1a30Sjl 	switch (event) {
81825cf1a30Sjl 	case SCF_MB_CONN_OK:
81925cf1a30Sjl 		/*
82025cf1a30Sjl 		 * Now the mailbox is ready to use, lets wake up
82125cf1a30Sjl 		 * any one waiting for this event.
82225cf1a30Sjl 		 */
82325cf1a30Sjl 		dm2sp->ms_state |= DM2S_MB_CONN;
82425cf1a30Sjl 		cv_broadcast(&dm2sp->ms_wait);
82525cf1a30Sjl 		DPRINTF(DBG_MBOX, ("Event received = CONN_OK\n"));
82625cf1a30Sjl 		break;
82725cf1a30Sjl 
82825cf1a30Sjl 	case SCF_MB_MSG_DATA:
82925cf1a30Sjl 		if (!DM2S_MBOX_READY(dm2sp)) {
83025cf1a30Sjl 			DPRINTF(DBG_MBOX,
83125cf1a30Sjl 			    ("Event(MSG_DATA) received - Mailbox not READY\n"));
83225cf1a30Sjl 			break;
83325cf1a30Sjl 		}
83425cf1a30Sjl 		/*
83525cf1a30Sjl 		 * A message is available in the mailbox.
83625cf1a30Sjl 		 * Lets enable the read service procedure
83725cf1a30Sjl 		 * to receive this message.
83825cf1a30Sjl 		 */
83925cf1a30Sjl 		if (dm2sp->ms_rq != NULL) {
84025cf1a30Sjl 			qenable(dm2sp->ms_rq);
84125cf1a30Sjl 		}
84225cf1a30Sjl 		DPRINTF(DBG_MBOX, ("Event received = MSG_DATA\n"));
84325cf1a30Sjl 		break;
84425cf1a30Sjl 
84525cf1a30Sjl 	case SCF_MB_SPACE:
84625cf1a30Sjl 		if (!DM2S_MBOX_READY(dm2sp)) {
84725cf1a30Sjl 			DPRINTF(DBG_MBOX,
84825cf1a30Sjl 			    ("Event(MB_SPACE) received - Mailbox not READY\n"));
84925cf1a30Sjl 			break;
85025cf1a30Sjl 		}
85125cf1a30Sjl 
85225cf1a30Sjl 		/*
85325cf1a30Sjl 		 * Now the mailbox is ready to transmit, lets
85425cf1a30Sjl 		 * schedule the write service procedure.
85525cf1a30Sjl 		 */
85625cf1a30Sjl 		if (dm2sp->ms_wq != NULL) {
85725cf1a30Sjl 			qenable(dm2sp->ms_wq);
85825cf1a30Sjl 		}
85925cf1a30Sjl 		DPRINTF(DBG_MBOX, ("Event received = MB_SPACE\n"));
86025cf1a30Sjl 		break;
86125cf1a30Sjl 	case SCF_MB_DISC_ERROR:
86225cf1a30Sjl 		dm2sp->ms_state |= DM2S_MB_DISC;
86325cf1a30Sjl 		if (dm2sp->ms_state & DM2S_MB_CONN) {
86425cf1a30Sjl 			/*
86525cf1a30Sjl 			 * If it was previously connected,
86625cf1a30Sjl 			 * then send a hangup message.
86725cf1a30Sjl 			 */
86825cf1a30Sjl 			rq = dm2sp->ms_rq;
86925cf1a30Sjl 			if (rq != NULL) {
87025cf1a30Sjl 				mutex_exit(&dm2sp->ms_lock);
87125cf1a30Sjl 				/*
87225cf1a30Sjl 				 * Send a hangup message to indicate
87325cf1a30Sjl 				 * disconnect event.
87425cf1a30Sjl 				 */
87525cf1a30Sjl 				(void) putctl(rq, M_HANGUP);
87625cf1a30Sjl 				DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp);
87725cf1a30Sjl 				mutex_enter(&dm2sp->ms_lock);
87825cf1a30Sjl 			}
87925cf1a30Sjl 		} else {
88025cf1a30Sjl 			/*
88125cf1a30Sjl 			 * Signal if the open is waiting for a
88225cf1a30Sjl 			 * connection.
88325cf1a30Sjl 			 */
88425cf1a30Sjl 			cv_broadcast(&dm2sp->ms_wait);
88525cf1a30Sjl 		}
88625cf1a30Sjl 		DPRINTF(DBG_MBOX, ("Event received = DISC_ERROR\n"));
88725cf1a30Sjl 		break;
88825cf1a30Sjl 	default:
88925cf1a30Sjl 		cmn_err(CE_WARN, "Unexpected event received\n");
89025cf1a30Sjl 		break;
89125cf1a30Sjl 	}
89225cf1a30Sjl 	mutex_exit(&dm2sp->ms_lock);
89325cf1a30Sjl }
89425cf1a30Sjl 
89525cf1a30Sjl /*
89625cf1a30Sjl  * dm2s_start - Start transmission function.
89725cf1a30Sjl  *
89825cf1a30Sjl  * Send all queued messages. If the mailbox is busy, then
89925cf1a30Sjl  * start a timeout as a polling mechanism. The timeout is useful
90025cf1a30Sjl  * to not rely entirely on the SCF_MB_SPACE event.
90125cf1a30Sjl  */
90225cf1a30Sjl void
90325cf1a30Sjl dm2s_start(queue_t *wq, dm2s_t *dm2sp)
90425cf1a30Sjl {
90525cf1a30Sjl 	mblk_t *mp;
90625cf1a30Sjl 	int ret;
90725cf1a30Sjl 
90825cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_start: called\n"));
90925cf1a30Sjl 	ASSERT(dm2sp != NULL);
91025cf1a30Sjl 	ASSERT(MUTEX_HELD(&dm2sp->ms_lock));
91125cf1a30Sjl 
91225cf1a30Sjl 	while ((mp = getq(wq)) != NULL) {
91325cf1a30Sjl 		switch (mp->b_datap->db_type) {
91425cf1a30Sjl 
91525cf1a30Sjl 		case M_DATA:
91625cf1a30Sjl 			ret = dm2s_transmit(wq, mp, dm2sp->ms_target,
91725cf1a30Sjl 			    dm2sp->ms_key);
91825cf1a30Sjl 			if (ret == EBUSY || ret == ENOSPC || ret == EAGAIN) {
91925cf1a30Sjl 				DPRINTF(DBG_MBOX,
92025cf1a30Sjl 				    ("dm2s_start: recoverable err=%d\n", ret));
92125cf1a30Sjl 				/*
92225cf1a30Sjl 				 * Start a timeout to retry again.
92325cf1a30Sjl 				 */
92425cf1a30Sjl 				if (dm2sp->ms_wq_timeoutid == 0) {
92525cf1a30Sjl 					DTRACE_PROBE1(dm2s_wqtimeout__start,
92625cf1a30Sjl 					    dm2s_t, dm2sp);
92725cf1a30Sjl 					dm2sp->ms_wq_timeoutid = qtimeout(wq,
92825cf1a30Sjl 					    dm2s_wq_timeout, (void *)dm2sp,
92925cf1a30Sjl 					    dm2s_timeout_val(ret));
93025cf1a30Sjl 				}
93125cf1a30Sjl 				return;
93225cf1a30Sjl 			} else if (ret != 0) {
93325cf1a30Sjl 				mutex_exit(&dm2sp->ms_lock);
93425cf1a30Sjl 				/*
93525cf1a30Sjl 				 * An error occurred with the transmission,
93625cf1a30Sjl 				 * flush pending messages and initiate a
93725cf1a30Sjl 				 * hangup.
93825cf1a30Sjl 				 */
93925cf1a30Sjl 				flushq(wq, FLUSHDATA);
94025cf1a30Sjl 				(void) putnextctl(RD(wq), M_HANGUP);
94125cf1a30Sjl 				DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp);
94225cf1a30Sjl 				DPRINTF(DBG_WARN,
94325cf1a30Sjl 				    ("dm2s_start: hangup transmit err=%d\n",
94425cf1a30Sjl 				    ret));
94525cf1a30Sjl 				mutex_enter(&dm2sp->ms_lock);
94625cf1a30Sjl 			}
94725cf1a30Sjl 			break;
94825cf1a30Sjl 		default:
94925cf1a30Sjl 			/*
95025cf1a30Sjl 			 * At this point, we don't expect any other messages.
95125cf1a30Sjl 			 */
95225cf1a30Sjl 			freemsg(mp);
95325cf1a30Sjl 			break;
95425cf1a30Sjl 		}
95525cf1a30Sjl 	}
95625cf1a30Sjl }
95725cf1a30Sjl 
95825cf1a30Sjl /*
95925cf1a30Sjl  * dm2s_receive - Read all messages from the mailbox.
96025cf1a30Sjl  *
96125cf1a30Sjl  * This function is called from the read service procedure, to
96225cf1a30Sjl  * receive the messages awaiting in the mailbox.
96325cf1a30Sjl  */
96425cf1a30Sjl void
96525cf1a30Sjl dm2s_receive(dm2s_t *dm2sp)
96625cf1a30Sjl {
96725cf1a30Sjl 	queue_t	*rq = dm2sp->ms_rq;
96825cf1a30Sjl 	mblk_t	*mp;
96925cf1a30Sjl 	int	ret;
97025cf1a30Sjl 	uint32_t len;
97125cf1a30Sjl 
97225cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_receive: called\n"));
97325cf1a30Sjl 	ASSERT(dm2sp != NULL);
97425cf1a30Sjl 	ASSERT(MUTEX_HELD(&dm2sp->ms_lock));
97525cf1a30Sjl 	if (rq == NULL) {
97625cf1a30Sjl 		return;
97725cf1a30Sjl 	}
97825cf1a30Sjl 	/*
97925cf1a30Sjl 	 * As the number of messages in the mailbox are pretty limited,
98025cf1a30Sjl 	 * it is safe to process all messages in one loop.
98125cf1a30Sjl 	 */
98225cf1a30Sjl 	while (DM2S_MBOX_READY(dm2sp) && ((ret = scf_mb_canget(dm2sp->ms_target,
98325cf1a30Sjl 	    dm2sp->ms_key, &len)) == 0)) {
98425cf1a30Sjl 		DPRINTF(DBG_MBOX, ("dm2s_receive: mb_canget len=%d\n", len));
98525cf1a30Sjl 		if (len == 0) {
98625cf1a30Sjl 			break;
98725cf1a30Sjl 		}
98825cf1a30Sjl 		mp = allocb(len, BPRI_MED);
98925cf1a30Sjl 		if (mp == NULL) {
99025cf1a30Sjl 			DPRINTF(DBG_WARN, ("dm2s_receive: allocb failed\n"));
99125cf1a30Sjl 			/*
99225cf1a30Sjl 			 * Start a bufcall so that we can retry again
99325cf1a30Sjl 			 * when memory becomes available.
99425cf1a30Sjl 			 */
99525cf1a30Sjl 			dm2sp->ms_rbufcid = qbufcall(rq, len, BPRI_MED,
99625cf1a30Sjl 			    dm2s_bufcall_rcv, dm2sp);
99725cf1a30Sjl 			if (dm2sp->ms_rbufcid == 0) {
99825cf1a30Sjl 				DPRINTF(DBG_WARN,
99925cf1a30Sjl 				    ("dm2s_receive: qbufcall failed\n"));
100025cf1a30Sjl 				/*
100125cf1a30Sjl 				 * if bufcall fails, start a timeout to
100225cf1a30Sjl 				 * initiate a re-try after some time.
100325cf1a30Sjl 				 */
100425cf1a30Sjl 				DTRACE_PROBE1(dm2s_rqtimeout__start,
100525cf1a30Sjl 				    dm2s_t, dm2sp);
100625cf1a30Sjl 				dm2sp->ms_rq_timeoutid = qtimeout(rq,
100725cf1a30Sjl 				    dm2s_rq_timeout, (void *)dm2sp,
100825cf1a30Sjl 				    drv_usectohz(DM2S_SM_TOUT));
100925cf1a30Sjl 			}
101025cf1a30Sjl 			break;
101125cf1a30Sjl 		}
101225cf1a30Sjl 
101325cf1a30Sjl 		/*
101425cf1a30Sjl 		 * Only a single scatter/gather element is enough here.
101525cf1a30Sjl 		 */
101625cf1a30Sjl 		dm2sp->ms_sg_rcv.msc_dptr = (caddr_t)mp->b_wptr;
101725cf1a30Sjl 		dm2sp->ms_sg_rcv.msc_len = len;
101825cf1a30Sjl 		DPRINTF(DBG_MBOX, ("dm2s_receive: calling getmsg\n"));
101925cf1a30Sjl 		ret = scf_mb_getmsg(dm2sp->ms_target, dm2sp->ms_key, len, 1,
102025cf1a30Sjl 		    &dm2sp->ms_sg_rcv, 0);
102125cf1a30Sjl 		DPRINTF(DBG_MBOX, ("dm2s_receive: getmsg ret=%d\n", ret));
102225cf1a30Sjl 		if (ret != 0) {
102325cf1a30Sjl 			freemsg(mp);
102425cf1a30Sjl 			break;
102525cf1a30Sjl 		}
102625cf1a30Sjl 		DMPBYTES("dm2s: Getmsg: ", len, 1, &dm2sp->ms_sg_rcv);
102725cf1a30Sjl 		mp->b_wptr += len;
102825cf1a30Sjl 		/*
102925cf1a30Sjl 		 * Queue the messages in the rq, so that the service
103025cf1a30Sjl 		 * procedure handles sending the messages up the stream.
103125cf1a30Sjl 		 */
103225cf1a30Sjl 		putq(rq, mp);
103325cf1a30Sjl 	}
103425cf1a30Sjl 
103525cf1a30Sjl 	if ((!DM2S_MBOX_READY(dm2sp)) || (ret != ENOMSG && ret != EMSGSIZE)) {
103625cf1a30Sjl 		/*
103725cf1a30Sjl 		 * Some thing went wrong, flush pending messages
103825cf1a30Sjl 		 * and initiate a hangup.
103925cf1a30Sjl 		 * Note: flushing the wq initiates a faster close.
104025cf1a30Sjl 		 */
104125cf1a30Sjl 		mutex_exit(&dm2sp->ms_lock);
104225cf1a30Sjl 		flushq(WR(rq), FLUSHDATA);
104325cf1a30Sjl 		(void) putnextctl(rq, M_HANGUP);
104425cf1a30Sjl 		DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp);
104525cf1a30Sjl 		mutex_enter(&dm2sp->ms_lock);
104625cf1a30Sjl 		DPRINTF(DBG_WARN, ("dm2s_receive: encountered unknown "
104725cf1a30Sjl 		    "condition - hangup ret=%d\n", ret));
104825cf1a30Sjl 	}
104925cf1a30Sjl }
105025cf1a30Sjl 
105125cf1a30Sjl /*
105225cf1a30Sjl  * dm2s_transmit - Transmit a message.
105325cf1a30Sjl  */
105425cf1a30Sjl int
105525cf1a30Sjl dm2s_transmit(queue_t *wq, mblk_t *mp, target_id_t target, mkey_t key)
105625cf1a30Sjl {
105725cf1a30Sjl 	dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr;
105825cf1a30Sjl 	int ret;
105925cf1a30Sjl 	uint32_t len;
106025cf1a30Sjl 	uint32_t numsg;
106125cf1a30Sjl 
106225cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_transmit: called\n"));
106325cf1a30Sjl 	ASSERT(dm2sp != NULL);
106425cf1a30Sjl 	ASSERT(MUTEX_HELD(&dm2sp->ms_lock));
106525cf1a30Sjl 	/*
106625cf1a30Sjl 	 * Free the message if the mailbox is not in the connected state.
106725cf1a30Sjl 	 */
106825cf1a30Sjl 	if (!DM2S_MBOX_READY(dm2sp)) {
106925cf1a30Sjl 		DPRINTF(DBG_MBOX, ("dm2s_transmit: mailbox not ready yet\n"));
107025cf1a30Sjl 		freemsg(mp);
107125cf1a30Sjl 		return (EIO);
107225cf1a30Sjl 	}
107325cf1a30Sjl 
107425cf1a30Sjl 	len = msgdsize(mp);
107525cf1a30Sjl 	if (len > dm2sp->ms_mtu) {
107625cf1a30Sjl 		/*
107725cf1a30Sjl 		 * Size is too big to send, free the message.
107825cf1a30Sjl 		 */
107925cf1a30Sjl 		DPRINTF(DBG_MBOX, ("dm2s_transmit: message too large\n"));
108025cf1a30Sjl 		DTRACE_PROBE2(dm2s_msg_too_big, dm2s_t, dm2sp, uint32_t, len);
108125cf1a30Sjl 		freemsg(mp);
108225cf1a30Sjl 		return (0);
108325cf1a30Sjl 	}
108425cf1a30Sjl 
108525cf1a30Sjl 	if ((ret = dm2s_prep_scatgath(mp, &numsg, dm2sp->ms_sg_tx,
108625cf1a30Sjl 	    DM2S_MAX_SG)) != 0) {
108725cf1a30Sjl 		DPRINTF(DBG_MBOX, ("dm2s_transmit: prep_scatgath failed\n"));
108825cf1a30Sjl 		putbq(wq, mp);
108925cf1a30Sjl 		return (EAGAIN);
109025cf1a30Sjl 	}
109125cf1a30Sjl 	DPRINTF(DBG_MBOX, ("dm2s_transmit: calling mb_putmsg numsg=%d len=%d\n",
109225cf1a30Sjl 	    numsg, len));
109325cf1a30Sjl 	ret = scf_mb_putmsg(target, key, len, numsg, dm2sp->ms_sg_tx, 0);
109425cf1a30Sjl 	if (ret == EBUSY || ret == ENOSPC) {
109525cf1a30Sjl 		DPRINTF(DBG_MBOX,
109625cf1a30Sjl 		    ("dm2s_transmit: mailbox busy ret=%d\n", ret));
109725cf1a30Sjl 		if (++dm2sp->ms_retries >= DM2S_MAX_RETRIES) {
109825cf1a30Sjl 			/*
109925cf1a30Sjl 			 * If maximum retries are reached, then free the
110025cf1a30Sjl 			 * message.
110125cf1a30Sjl 			 */
110225cf1a30Sjl 			DPRINTF(DBG_MBOX,
110325cf1a30Sjl 			    ("dm2s_transmit: freeing msg after max retries\n"));
110425cf1a30Sjl 			DTRACE_PROBE2(dm2s_retry_fail, dm2s_t, dm2sp, int, ret);
110525cf1a30Sjl 			freemsg(mp);
110625cf1a30Sjl 			dm2sp->ms_retries = 0;
110725cf1a30Sjl 			return (0);
110825cf1a30Sjl 		}
110925cf1a30Sjl 		DTRACE_PROBE2(dm2s_mb_busy, dm2s_t, dm2sp, int, ret);
111025cf1a30Sjl 		/*
111125cf1a30Sjl 		 * Queue it back, so that we can retry again.
111225cf1a30Sjl 		 */
111325cf1a30Sjl 		putbq(wq, mp);
111425cf1a30Sjl 		return (ret);
111525cf1a30Sjl 	}
111625cf1a30Sjl 	DMPBYTES("dm2s: Putmsg: ", len, numsg, dm2sp->ms_sg_tx);
111725cf1a30Sjl 	dm2sp->ms_retries = 0;
111825cf1a30Sjl 	freemsg(mp);
111925cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_transmit: ret=%d\n", ret));
112025cf1a30Sjl 	return (ret);
112125cf1a30Sjl }
112225cf1a30Sjl 
112325cf1a30Sjl /*
112425cf1a30Sjl  * dm2s_bufcall_rcv - Bufcall callaback routine.
112525cf1a30Sjl  *
112625cf1a30Sjl  * It simply enables read side queue so that the service procedure
112725cf1a30Sjl  * can retry receive operation.
112825cf1a30Sjl  */
112925cf1a30Sjl void
113025cf1a30Sjl dm2s_bufcall_rcv(void *arg)
113125cf1a30Sjl {
113225cf1a30Sjl 	dm2s_t *dm2sp = (dm2s_t *)arg;
113325cf1a30Sjl 
113425cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_bufcall_rcv: called\n"));
113525cf1a30Sjl 	mutex_enter(&dm2sp->ms_lock);
113625cf1a30Sjl 	dm2sp->ms_rbufcid = 0;
113725cf1a30Sjl 	if (dm2sp->ms_rq != NULL) {
113825cf1a30Sjl 		qenable(dm2sp->ms_rq);
113925cf1a30Sjl 	}
114025cf1a30Sjl 	mutex_exit(&dm2sp->ms_lock);
114125cf1a30Sjl }
114225cf1a30Sjl 
114325cf1a30Sjl /*
114425cf1a30Sjl  * dm2s_rq_timeout - Timeout callback for the read side.
114525cf1a30Sjl  *
114625cf1a30Sjl  * It simply enables read side queue so that the service procedure
114725cf1a30Sjl  * can retry the receive operation.
114825cf1a30Sjl  */
114925cf1a30Sjl void
115025cf1a30Sjl dm2s_rq_timeout(void *arg)
115125cf1a30Sjl {
115225cf1a30Sjl 	dm2s_t *dm2sp = (dm2s_t *)arg;
115325cf1a30Sjl 
115425cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_rq_timeout: called\n"));
115525cf1a30Sjl 	mutex_enter(&dm2sp->ms_lock);
115625cf1a30Sjl 	dm2sp->ms_rq_timeoutid = 0;
115725cf1a30Sjl 	if (dm2sp->ms_rq != NULL) {
115825cf1a30Sjl 		qenable(dm2sp->ms_rq);
115925cf1a30Sjl 	}
116025cf1a30Sjl 	mutex_exit(&dm2sp->ms_lock);
116125cf1a30Sjl }
116225cf1a30Sjl 
116325cf1a30Sjl /*
116425cf1a30Sjl  * dm2s_wq_timeout - Timeout callback for the write.
116525cf1a30Sjl  *
116625cf1a30Sjl  * It simply enables write side queue so that the service procedure
116725cf1a30Sjl  * can retry the transmission operation.
116825cf1a30Sjl  */
116925cf1a30Sjl void
117025cf1a30Sjl dm2s_wq_timeout(void *arg)
117125cf1a30Sjl {
117225cf1a30Sjl 	dm2s_t *dm2sp = (dm2s_t *)arg;
117325cf1a30Sjl 
117425cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_wq_timeout: called\n"));
117525cf1a30Sjl 	mutex_enter(&dm2sp->ms_lock);
117625cf1a30Sjl 	dm2sp->ms_wq_timeoutid = 0;
117725cf1a30Sjl 	if (dm2sp->ms_wq != NULL) {
117825cf1a30Sjl 		qenable(dm2sp->ms_wq);
117925cf1a30Sjl 	}
118025cf1a30Sjl 	mutex_exit(&dm2sp->ms_lock);
118125cf1a30Sjl }
118225cf1a30Sjl 
118325cf1a30Sjl /*
118425cf1a30Sjl  * dm2s_prep_scatgath - Prepare scatter/gather elements for transmission
118525cf1a30Sjl  * of a streams message.
118625cf1a30Sjl  */
118725cf1a30Sjl static int
118825cf1a30Sjl dm2s_prep_scatgath(mblk_t *mp, uint32_t *numsg, mscat_gath_t *sgp, int maxsg)
118925cf1a30Sjl {
119025cf1a30Sjl 	uint32_t num = 0;
119125cf1a30Sjl 	mblk_t *tmp = mp;
119225cf1a30Sjl 
119325cf1a30Sjl 	while ((tmp != NULL) && (num < maxsg)) {
119425cf1a30Sjl 		sgp[num].msc_dptr = (caddr_t)tmp->b_rptr;
119525cf1a30Sjl 		sgp[num].msc_len = MBLKL(tmp);
119625cf1a30Sjl 		tmp = tmp->b_cont;
119725cf1a30Sjl 		num++;
119825cf1a30Sjl 	}
119925cf1a30Sjl 
120025cf1a30Sjl 	if (tmp != NULL) {
120125cf1a30Sjl 		/*
120225cf1a30Sjl 		 * Number of scatter/gather elements available are not
120325cf1a30Sjl 		 * enough, so lets pullup the msg.
120425cf1a30Sjl 		 */
120525cf1a30Sjl 		if (pullupmsg(mp, -1) != 1) {
120625cf1a30Sjl 			return (EAGAIN);
120725cf1a30Sjl 		}
120825cf1a30Sjl 		sgp[0].msc_dptr = (caddr_t)mp->b_rptr;
120925cf1a30Sjl 		sgp[0].msc_len = MBLKL(mp);
121025cf1a30Sjl 		num = 1;
121125cf1a30Sjl 	}
121225cf1a30Sjl 	*numsg = num;
121325cf1a30Sjl 	return (0);
121425cf1a30Sjl }
121525cf1a30Sjl 
121625cf1a30Sjl /*
121725cf1a30Sjl  * dm2s_timeout_val -- Return appropriate timeout value.
121825cf1a30Sjl  *
121925cf1a30Sjl  * A small timeout value is returned for EBUSY and EAGAIN cases. This is
122025cf1a30Sjl  * because the condition is expected to be recovered sooner.
122125cf1a30Sjl  *
122225cf1a30Sjl  * A larger timeout value is returned for ENOSPC case, as the condition
122325cf1a30Sjl  * depends on the peer to release buffer space.
122425cf1a30Sjl  * NOTE: there will also be an event(SCF_MB_SPACE) but a timeout is
122525cf1a30Sjl  * used for reliability purposes.
122625cf1a30Sjl  */
122725cf1a30Sjl static clock_t
122825cf1a30Sjl dm2s_timeout_val(int error)
122925cf1a30Sjl {
123025cf1a30Sjl 	clock_t tval;
123125cf1a30Sjl 
123225cf1a30Sjl 	ASSERT(error == EBUSY || error == ENOSPC || error == EAGAIN);
123325cf1a30Sjl 
123425cf1a30Sjl 	if (error == EBUSY || error == EAGAIN) {
123525cf1a30Sjl 		tval = DM2S_SM_TOUT;
123625cf1a30Sjl 	} else {
123725cf1a30Sjl 		tval = DM2S_LG_TOUT;
123825cf1a30Sjl 	}
123925cf1a30Sjl 	return (drv_usectohz(tval));
124025cf1a30Sjl }
124125cf1a30Sjl 
124225cf1a30Sjl #ifdef DEBUG
124325cf1a30Sjl 
124425cf1a30Sjl static void
124525cf1a30Sjl dm2s_dump_bytes(char *str, uint32_t total_len,
124625cf1a30Sjl     uint32_t num_sg, mscat_gath_t *sgp)
124725cf1a30Sjl {
124825cf1a30Sjl 	int i, j;
124925cf1a30Sjl 	int nsg;
125025cf1a30Sjl 	int len, tlen = 0;
125125cf1a30Sjl 	mscat_gath_t *tp;
125225cf1a30Sjl 	uint8_t *datap;
125325cf1a30Sjl #define	BYTES_PER_LINE	20
125425cf1a30Sjl 	char bytestr[BYTES_PER_LINE * 3 + 1];
125525cf1a30Sjl 	uint32_t digest = 0;
125625cf1a30Sjl 
125725cf1a30Sjl 	if (!(dm2s_debug & DBG_MESG))
125825cf1a30Sjl 		return;
125925cf1a30Sjl 	ASSERT(num_sg != 0);
126025cf1a30Sjl 
126125cf1a30Sjl 	for (nsg = 0; (nsg < num_sg) && (tlen < total_len); nsg++) {
126225cf1a30Sjl 		tp = &sgp[nsg];
126325cf1a30Sjl 		datap = (uint8_t *)tp->msc_dptr;
126425cf1a30Sjl 		len = tp->msc_len;
126525cf1a30Sjl 		for (i = 0; i < len; i++) {
126625cf1a30Sjl 			digest += datap[i];
126725cf1a30Sjl 		}
126825cf1a30Sjl 		tlen += len;
126925cf1a30Sjl 	}
127025cf1a30Sjl 	sprintf(bytestr, "%s Packet: Size=%d  Digest=%d\n",
127125cf1a30Sjl 		str, total_len, digest);
127225cf1a30Sjl 	DTRACE_PROBE1(dm2s_dump_digest, unsigned char *, bytestr);
127325cf1a30Sjl 
1274*030f3a8fSraghuram 	tlen = 0;
127525cf1a30Sjl 	for (nsg = 0; (nsg < num_sg) && (tlen < total_len); nsg++) {
127625cf1a30Sjl 		tp = &sgp[nsg];
127725cf1a30Sjl 		datap = (uint8_t *)tp->msc_dptr;
127825cf1a30Sjl 		len = tp->msc_len;
127925cf1a30Sjl 		for (i = 0; i < len; ) {
128025cf1a30Sjl 			for (j = 0; (j < BYTES_PER_LINE) &&
128125cf1a30Sjl 			    (i < len); j++, i++) {
128225cf1a30Sjl 				sprintf(&bytestr[j * 3], "%02X ", datap[i]);
128325cf1a30Sjl 				digest += datap[i];
128425cf1a30Sjl 			}
128525cf1a30Sjl 			if (j != 0) {
128625cf1a30Sjl 				DTRACE_PROBE1(dm2s_dump, unsigned char *,
128725cf1a30Sjl 				    bytestr);
128825cf1a30Sjl 			}
128925cf1a30Sjl 		}
129025cf1a30Sjl 		tlen += i;
129125cf1a30Sjl 	}
129225cf1a30Sjl }
129325cf1a30Sjl 
129425cf1a30Sjl #endif	/* DEBUG */
1295