xref: /illumos-gate/usr/src/uts/sun4u/opl/io/dm2s.c (revision 25cf1a30)
1*25cf1a30Sjl /*
2*25cf1a30Sjl  * CDDL HEADER START
3*25cf1a30Sjl  *
4*25cf1a30Sjl  * The contents of this file are subject to the terms of the
5*25cf1a30Sjl  * Common Development and Distribution License (the "License").
6*25cf1a30Sjl  * You may not use this file except in compliance with the License.
7*25cf1a30Sjl  *
8*25cf1a30Sjl  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*25cf1a30Sjl  * or http://www.opensolaris.org/os/licensing.
10*25cf1a30Sjl  * See the License for the specific language governing permissions
11*25cf1a30Sjl  * and limitations under the License.
12*25cf1a30Sjl  *
13*25cf1a30Sjl  * When distributing Covered Code, include this CDDL HEADER in each
14*25cf1a30Sjl  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*25cf1a30Sjl  * If applicable, add the following below this CDDL HEADER, with the
16*25cf1a30Sjl  * fields enclosed by brackets "[]" replaced with your own identifying
17*25cf1a30Sjl  * information: Portions Copyright [yyyy] [name of copyright owner]
18*25cf1a30Sjl  *
19*25cf1a30Sjl  * CDDL HEADER END
20*25cf1a30Sjl  */
21*25cf1a30Sjl /*
22*25cf1a30Sjl  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*25cf1a30Sjl  * Use is subject to license terms.
24*25cf1a30Sjl  */
25*25cf1a30Sjl 
26*25cf1a30Sjl #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*25cf1a30Sjl 
28*25cf1a30Sjl /*
29*25cf1a30Sjl  * DM2S - Domain side Mailbox to synchronous serial device driver.
30*25cf1a30Sjl  *
31*25cf1a30Sjl  * Description:
32*25cf1a30Sjl  * -----------
33*25cf1a30Sjl  * It is a streams driver which simulates a sync serial device on
34*25cf1a30Sjl  * top of a mailbox type of communication. That is, it sends/receives
35*25cf1a30Sjl  * frames as mailbox messages. The mailbox communication is provided
36*25cf1a30Sjl  * by another driver, which exports the mailbox interfaces.
37*25cf1a30Sjl  *
38*25cf1a30Sjl  * Synchronization:
39*25cf1a30Sjl  * ---------------
40*25cf1a30Sjl  * This driver uses streams perimeters to simplify the synchronization.
41*25cf1a30Sjl  * An inner perimeter D_MTPERMOD which protects the entire module,
42*25cf1a30Sjl  * that is only one thread exists inside the perimeter, is used. As
43*25cf1a30Sjl  * this driver supports only one instance and is not a high-performance
44*25cf1a30Sjl  * driver, D_MTPERMOD is highly suitable.
45*25cf1a30Sjl  *
46*25cf1a30Sjl  * All transmission and reception of frames is done inside the service
47*25cf1a30Sjl  * procedures so that all streams related operations are protected
48*25cf1a30Sjl  * by the perimeters.
49*25cf1a30Sjl  *
50*25cf1a30Sjl  * The mailbox event handler is the only asynchronous callback which
51*25cf1a30Sjl  * needs to be protected outside of the streams perimeters. This is
52*25cf1a30Sjl  * done using the module private lock('ms_lock');
53*25cf1a30Sjl  *
54*25cf1a30Sjl  */
55*25cf1a30Sjl 
56*25cf1a30Sjl #include <sys/types.h>
57*25cf1a30Sjl #include <sys/param.h>
58*25cf1a30Sjl #include <sys/stream.h>
59*25cf1a30Sjl #include <sys/cred.h>
60*25cf1a30Sjl #include <sys/systm.h>
61*25cf1a30Sjl #include <sys/sunddi.h>
62*25cf1a30Sjl #include <sys/ddi.h>
63*25cf1a30Sjl #include <sys/conf.h>
64*25cf1a30Sjl #include <sys/modctl.h>
65*25cf1a30Sjl #include <sys/mkdev.h>
66*25cf1a30Sjl #include <sys/errno.h>
67*25cf1a30Sjl #include <sys/debug.h>
68*25cf1a30Sjl #include <sys/kbio.h>
69*25cf1a30Sjl #include <sys/kmem.h>
70*25cf1a30Sjl #include <sys/consdev.h>
71*25cf1a30Sjl #include <sys/file.h>
72*25cf1a30Sjl #include <sys/stropts.h>
73*25cf1a30Sjl #include <sys/strsun.h>
74*25cf1a30Sjl #include <sys/dlpi.h>
75*25cf1a30Sjl #include <sys/stat.h>
76*25cf1a30Sjl #include <sys/ser_sync.h>
77*25cf1a30Sjl #include <sys/sysmacros.h>
78*25cf1a30Sjl #include <sys/note.h>
79*25cf1a30Sjl #include <sys/sdt.h>
80*25cf1a30Sjl 
81*25cf1a30Sjl #include <sys/scfd/scfdscpif.h>
82*25cf1a30Sjl #include <sys/dm2s.h>
83*25cf1a30Sjl 
84*25cf1a30Sjl 
85*25cf1a30Sjl #define	DM2S_MODNAME	"dm2s"			/* Module name */
86*25cf1a30Sjl #define	DM2S_TARGET_ID	0			/* Target ID of the peer */
87*25cf1a30Sjl #define	DM2S_ID_NUM	0x4D53			/* 'M''S' */
88*25cf1a30Sjl #define	DM2S_DEF_MTU	1504			/* Def. MTU size + PPP bytes */
89*25cf1a30Sjl #define	DM2S_MAXPSZ	DM2S_DEF_MTU		/* Set it to the default MTU */
90*25cf1a30Sjl #define	DM2S_LOWAT	(4 * 1024)		/* Low water mark */
91*25cf1a30Sjl #define	DM2S_HIWAT	(12 * 1024)		/* High water mark */
92*25cf1a30Sjl #define	DM2S_SM_TOUT	5000			/* Small timeout (5msec) */
93*25cf1a30Sjl #define	DM2S_LG_TOUT	50000			/* Large timeout (50msec) */
94*25cf1a30Sjl #define	DM2S_MB_TOUT	10000000		/* Mailbox timeout (10sec) */
95*25cf1a30Sjl 
96*25cf1a30Sjl /*
97*25cf1a30Sjl  * Global variables
98*25cf1a30Sjl  */
99*25cf1a30Sjl void		*dm2s_softstate = NULL;			/* Softstate pointer */
100*25cf1a30Sjl 
101*25cf1a30Sjl 
102*25cf1a30Sjl /*
103*25cf1a30Sjl  * Prototypes for the module related functions.
104*25cf1a30Sjl  */
105*25cf1a30Sjl int dm2s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
106*25cf1a30Sjl int dm2s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
107*25cf1a30Sjl int dm2s_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
108*25cf1a30Sjl     void *arg, void **result);
109*25cf1a30Sjl 
110*25cf1a30Sjl /*
111*25cf1a30Sjl  * Prototypes for the streams related functions.
112*25cf1a30Sjl  */
113*25cf1a30Sjl int dm2s_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr);
114*25cf1a30Sjl int dm2s_close(queue_t *rq, int flag, cred_t *cred);
115*25cf1a30Sjl int dm2s_wput(queue_t *wq, mblk_t *mp);
116*25cf1a30Sjl int dm2s_rsrv(queue_t *rq);
117*25cf1a30Sjl int dm2s_wsrv(queue_t *wq);
118*25cf1a30Sjl 
119*25cf1a30Sjl /*
120*25cf1a30Sjl  * Prototypes for the internal functions.
121*25cf1a30Sjl  */
122*25cf1a30Sjl void dm2s_start(queue_t *wq, dm2s_t *dm2sp);
123*25cf1a30Sjl void dm2s_event_handler(scf_event_t event, void *arg);
124*25cf1a30Sjl int dm2s_transmit(queue_t *wq, mblk_t *mp, target_id_t target, mkey_t key);
125*25cf1a30Sjl void dm2s_receive(dm2s_t *dm2sp);
126*25cf1a30Sjl void dm2s_wq_timeout(void *arg);
127*25cf1a30Sjl void dm2s_rq_timeout(void *arg);
128*25cf1a30Sjl void dm2s_bufcall_rcv(void *arg);
129*25cf1a30Sjl static clock_t dm2s_timeout_val(int error);
130*25cf1a30Sjl static void dm2s_cleanup(dm2s_t *dm2sp);
131*25cf1a30Sjl static int dm2s_mbox_init(dm2s_t *dm2sp);
132*25cf1a30Sjl static void dm2s_mbox_fini(dm2s_t *dm2sp);
133*25cf1a30Sjl static int dm2s_prep_scatgath(mblk_t *mp, uint32_t *numsg,
134*25cf1a30Sjl     mscat_gath_t *sgp, int maxsg);
135*25cf1a30Sjl 
136*25cf1a30Sjl #ifdef DEBUG
137*25cf1a30Sjl uint32_t dm2s_debug = DBG_WARN;
138*25cf1a30Sjl #endif /* DEBUG */
139*25cf1a30Sjl 
140*25cf1a30Sjl 
141*25cf1a30Sjl /*
142*25cf1a30Sjl  * Streams and module related structures.
143*25cf1a30Sjl  */
144*25cf1a30Sjl struct module_info dm2s_module_info = {
145*25cf1a30Sjl 	DM2S_ID_NUM,		/* module ID number */
146*25cf1a30Sjl 	DM2S_MODNAME,		/* module name. */
147*25cf1a30Sjl 	0,			/* Minimum packet size (none) */
148*25cf1a30Sjl 	DM2S_MAXPSZ,		/* Maximum packet size (none) */
149*25cf1a30Sjl 	DM2S_HIWAT,		/* queue high water mark */
150*25cf1a30Sjl 	DM2S_LOWAT		/* queue low water mark */
151*25cf1a30Sjl };
152*25cf1a30Sjl 
153*25cf1a30Sjl struct qinit dm2s_rinit = {
154*25cf1a30Sjl 	putq,			/* qi_putp */
155*25cf1a30Sjl 	dm2s_rsrv,		/* qi_srvp */
156*25cf1a30Sjl 	dm2s_open,		/* qi_qopen */
157*25cf1a30Sjl 	dm2s_close,		/* qi_qlcose */
158*25cf1a30Sjl 	NULL,			/* qi_qadmin */
159*25cf1a30Sjl 	&dm2s_module_info,	/* qi_minfo */
160*25cf1a30Sjl 	NULL			/* qi_mstat */
161*25cf1a30Sjl };
162*25cf1a30Sjl 
163*25cf1a30Sjl struct qinit dm2s_winit = {
164*25cf1a30Sjl 	dm2s_wput,		/* qi_putp */
165*25cf1a30Sjl 	dm2s_wsrv,		/* qi_srvp */
166*25cf1a30Sjl 	NULL,			/* qi_qopen */
167*25cf1a30Sjl 	NULL,			/* qi_qlcose */
168*25cf1a30Sjl 	NULL,			/* qi_qadmin */
169*25cf1a30Sjl 	&dm2s_module_info,	/* qi_minfo */
170*25cf1a30Sjl 	NULL			/* qi_mstat */
171*25cf1a30Sjl };
172*25cf1a30Sjl 
173*25cf1a30Sjl 
174*25cf1a30Sjl struct streamtab dm2s_streamtab = {
175*25cf1a30Sjl 	&dm2s_rinit,
176*25cf1a30Sjl 	&dm2s_winit,
177*25cf1a30Sjl 	NULL,
178*25cf1a30Sjl 	NULL
179*25cf1a30Sjl };
180*25cf1a30Sjl 
181*25cf1a30Sjl DDI_DEFINE_STREAM_OPS(dm2s_ops, nulldev, nulldev, dm2s_attach,		\
182*25cf1a30Sjl 	dm2s_detach, nodev, dm2s_info, D_NEW | D_MP | D_MTPERMOD,	\
183*25cf1a30Sjl 	&dm2s_streamtab);
184*25cf1a30Sjl 
185*25cf1a30Sjl 
186*25cf1a30Sjl struct modldrv modldrv = {
187*25cf1a30Sjl 	&mod_driverops,
188*25cf1a30Sjl 	"OPL Mbox to Serial Driver %I%",
189*25cf1a30Sjl 	&dm2s_ops
190*25cf1a30Sjl };
191*25cf1a30Sjl 
192*25cf1a30Sjl struct modlinkage modlinkage = {
193*25cf1a30Sjl 	MODREV_1,
194*25cf1a30Sjl 	&modldrv,
195*25cf1a30Sjl 	NULL
196*25cf1a30Sjl };
197*25cf1a30Sjl 
198*25cf1a30Sjl 
199*25cf1a30Sjl /*
200*25cf1a30Sjl  * _init - Module's init routine.
201*25cf1a30Sjl  */
202*25cf1a30Sjl int
203*25cf1a30Sjl _init(void)
204*25cf1a30Sjl {
205*25cf1a30Sjl 	int ret;
206*25cf1a30Sjl 
207*25cf1a30Sjl 	if (ddi_soft_state_init(&dm2s_softstate, sizeof (dm2s_t), 1) != 0) {
208*25cf1a30Sjl 		cmn_err(CE_WARN, "softstate initialization failed\n");
209*25cf1a30Sjl 		return (DDI_FAILURE);
210*25cf1a30Sjl 	}
211*25cf1a30Sjl 	if ((ret = mod_install(&modlinkage)) != 0) {
212*25cf1a30Sjl 		cmn_err(CE_WARN, "mod_install failed, error = %d", ret);
213*25cf1a30Sjl 		ddi_soft_state_fini(&dm2s_softstate);
214*25cf1a30Sjl 	}
215*25cf1a30Sjl 	return (ret);
216*25cf1a30Sjl }
217*25cf1a30Sjl 
218*25cf1a30Sjl /*
219*25cf1a30Sjl  * _fini - Module's fini routine.
220*25cf1a30Sjl  */
221*25cf1a30Sjl int
222*25cf1a30Sjl _fini(void)
223*25cf1a30Sjl {
224*25cf1a30Sjl 	int ret;
225*25cf1a30Sjl 
226*25cf1a30Sjl 	if ((ret = mod_remove(&modlinkage)) != 0) {
227*25cf1a30Sjl 		return (ret);
228*25cf1a30Sjl 	}
229*25cf1a30Sjl 	ddi_soft_state_fini(&dm2s_softstate);
230*25cf1a30Sjl 	return (ret);
231*25cf1a30Sjl }
232*25cf1a30Sjl 
233*25cf1a30Sjl /*
234*25cf1a30Sjl  * _info - Module's info routine.
235*25cf1a30Sjl  */
236*25cf1a30Sjl int
237*25cf1a30Sjl _info(struct modinfo *modinfop)
238*25cf1a30Sjl {
239*25cf1a30Sjl 	return (mod_info(&modlinkage, modinfop));
240*25cf1a30Sjl }
241*25cf1a30Sjl 
242*25cf1a30Sjl /*
243*25cf1a30Sjl  * dm2s_attach - Module's attach routine.
244*25cf1a30Sjl  */
245*25cf1a30Sjl int
246*25cf1a30Sjl dm2s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
247*25cf1a30Sjl {
248*25cf1a30Sjl 	int instance;
249*25cf1a30Sjl 	dm2s_t *dm2sp;
250*25cf1a30Sjl 	char name[20];
251*25cf1a30Sjl 
252*25cf1a30Sjl 
253*25cf1a30Sjl 	instance = ddi_get_instance(dip);
254*25cf1a30Sjl 
255*25cf1a30Sjl 	/* Only one instance is supported. */
256*25cf1a30Sjl 	if (instance != 0) {
257*25cf1a30Sjl 		cmn_err(CE_WARN, "only one instance is supported");
258*25cf1a30Sjl 		return (DDI_FAILURE);
259*25cf1a30Sjl 	}
260*25cf1a30Sjl 
261*25cf1a30Sjl 	if (cmd != DDI_ATTACH) {
262*25cf1a30Sjl 		return (DDI_FAILURE);
263*25cf1a30Sjl 	}
264*25cf1a30Sjl 	if (ddi_soft_state_zalloc(dm2s_softstate, instance) != DDI_SUCCESS) {
265*25cf1a30Sjl 		cmn_err(CE_WARN, "softstate allocation failure");
266*25cf1a30Sjl 		return (DDI_FAILURE);
267*25cf1a30Sjl 	}
268*25cf1a30Sjl 	dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, instance);
269*25cf1a30Sjl 	if (dm2sp == NULL) {
270*25cf1a30Sjl 		ddi_soft_state_free(dm2s_softstate, instance);
271*25cf1a30Sjl 		cmn_err(CE_WARN, "softstate allocation failure.");
272*25cf1a30Sjl 		return (DDI_FAILURE);
273*25cf1a30Sjl 	}
274*25cf1a30Sjl 	dm2sp->ms_dip = dip;
275*25cf1a30Sjl 	dm2sp->ms_major = ddi_name_to_major(ddi_get_name(dip));
276*25cf1a30Sjl 	dm2sp->ms_ppa = instance;
277*25cf1a30Sjl 
278*25cf1a30Sjl 	/*
279*25cf1a30Sjl 	 * Get an interrupt block cookie corresponding to the
280*25cf1a30Sjl 	 * interrupt priority of the event handler.
281*25cf1a30Sjl 	 * Assert that the event priority is not re-defined to
282*25cf1a30Sjl 	 * some higher priority.
283*25cf1a30Sjl 	 */
284*25cf1a30Sjl 	/* LINTED */
285*25cf1a30Sjl 	ASSERT(SCF_EVENT_PRI == DDI_SOFTINT_LOW);
286*25cf1a30Sjl 	if (ddi_get_soft_iblock_cookie(dip, SCF_EVENT_PRI,
287*25cf1a30Sjl 	    &dm2sp->ms_ibcookie) != DDI_SUCCESS) {
288*25cf1a30Sjl 		cmn_err(CE_WARN, "ddi_get_soft_iblock_cookie failed.");
289*25cf1a30Sjl 		goto error;
290*25cf1a30Sjl 	}
291*25cf1a30Sjl 	mutex_init(&dm2sp->ms_lock, NULL, MUTEX_DRIVER,
292*25cf1a30Sjl 	    (void *)dm2sp->ms_ibcookie);
293*25cf1a30Sjl 
294*25cf1a30Sjl 	dm2sp->ms_clean |= DM2S_CLEAN_LOCK;
295*25cf1a30Sjl 	cv_init(&dm2sp->ms_wait, NULL, CV_DRIVER, NULL);
296*25cf1a30Sjl 	dm2sp->ms_clean |= DM2S_CLEAN_CV;
297*25cf1a30Sjl 
298*25cf1a30Sjl 	(void) sprintf(name, "%s%d", DM2S_MODNAME, instance);
299*25cf1a30Sjl 	if (ddi_create_minor_node(dip, name, S_IFCHR, instance,
300*25cf1a30Sjl 	    DDI_PSEUDO, NULL) == DDI_FAILURE) {
301*25cf1a30Sjl 		ddi_remove_minor_node(dip, NULL);
302*25cf1a30Sjl 		cmn_err(CE_WARN, "Device node creation failed.");
303*25cf1a30Sjl 		goto error;
304*25cf1a30Sjl 	}
305*25cf1a30Sjl 
306*25cf1a30Sjl 	dm2sp->ms_clean |= DM2S_CLEAN_NODE;
307*25cf1a30Sjl 	ddi_set_driver_private(dip, (caddr_t)dm2sp);
308*25cf1a30Sjl 	ddi_report_dev(dip);
309*25cf1a30Sjl 	return (DDI_SUCCESS);
310*25cf1a30Sjl error:
311*25cf1a30Sjl 	dm2s_cleanup(dm2sp);
312*25cf1a30Sjl 	return (DDI_FAILURE);
313*25cf1a30Sjl }
314*25cf1a30Sjl 
315*25cf1a30Sjl /*
316*25cf1a30Sjl  * dm2s_info - Module's info routine.
317*25cf1a30Sjl  */
318*25cf1a30Sjl /*ARGSUSED*/
319*25cf1a30Sjl int
320*25cf1a30Sjl dm2s_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
321*25cf1a30Sjl {
322*25cf1a30Sjl 	dm2s_t	*dm2sp;
323*25cf1a30Sjl 	minor_t	minor;
324*25cf1a30Sjl 	int	ret = DDI_FAILURE;
325*25cf1a30Sjl 
326*25cf1a30Sjl 	switch (infocmd) {
327*25cf1a30Sjl 	case DDI_INFO_DEVT2DEVINFO:
328*25cf1a30Sjl 		minor = getminor((dev_t)arg);
329*25cf1a30Sjl 		dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, minor);
330*25cf1a30Sjl 		if (dm2sp == NULL) {
331*25cf1a30Sjl 			*result = NULL;
332*25cf1a30Sjl 		} else {
333*25cf1a30Sjl 			*result = dm2sp->ms_dip;
334*25cf1a30Sjl 			ret = DDI_SUCCESS;
335*25cf1a30Sjl 		}
336*25cf1a30Sjl 		break;
337*25cf1a30Sjl 
338*25cf1a30Sjl 	case DDI_INFO_DEVT2INSTANCE:
339*25cf1a30Sjl 		minor = getminor((dev_t)arg);
340*25cf1a30Sjl 		*result = (void *)(uintptr_t)minor;
341*25cf1a30Sjl 		ret = DDI_SUCCESS;
342*25cf1a30Sjl 		break;
343*25cf1a30Sjl 
344*25cf1a30Sjl 	default:
345*25cf1a30Sjl 		break;
346*25cf1a30Sjl 	}
347*25cf1a30Sjl 	return (ret);
348*25cf1a30Sjl }
349*25cf1a30Sjl 
350*25cf1a30Sjl /*
351*25cf1a30Sjl  * dm2s_detach - Module's detach routine.
352*25cf1a30Sjl  */
353*25cf1a30Sjl int
354*25cf1a30Sjl dm2s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
355*25cf1a30Sjl {
356*25cf1a30Sjl 	int instance;
357*25cf1a30Sjl 	dm2s_t *dm2sp;
358*25cf1a30Sjl 
359*25cf1a30Sjl 	if (cmd != DDI_DETACH) {
360*25cf1a30Sjl 		return (DDI_FAILURE);
361*25cf1a30Sjl 	}
362*25cf1a30Sjl 
363*25cf1a30Sjl 	instance = ddi_get_instance(dip);
364*25cf1a30Sjl 	dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, instance);
365*25cf1a30Sjl 	if (dm2sp == NULL) {
366*25cf1a30Sjl 		return (DDI_FAILURE);
367*25cf1a30Sjl 	}
368*25cf1a30Sjl 
369*25cf1a30Sjl 	mutex_enter(&dm2sp->ms_lock);
370*25cf1a30Sjl 
371*25cf1a30Sjl 	/* Check if the mailbox is still in use. */
372*25cf1a30Sjl 	if (dm2sp->ms_state & DM2S_MB_INITED) {
373*25cf1a30Sjl 		mutex_exit(&dm2sp->ms_lock);
374*25cf1a30Sjl 		cmn_err(CE_WARN, "Mailbox in use: Detach failed");
375*25cf1a30Sjl 		return (DDI_FAILURE);
376*25cf1a30Sjl 	}
377*25cf1a30Sjl 	mutex_exit(&dm2sp->ms_lock);
378*25cf1a30Sjl 	dm2s_cleanup(dm2sp);
379*25cf1a30Sjl 	return (DDI_SUCCESS);
380*25cf1a30Sjl }
381*25cf1a30Sjl 
382*25cf1a30Sjl /*
383*25cf1a30Sjl  * dm2s_open - Device open routine.
384*25cf1a30Sjl  *
385*25cf1a30Sjl  * Only one open supported. Clone open is not supported.
386*25cf1a30Sjl  */
387*25cf1a30Sjl /* ARGSUSED */
388*25cf1a30Sjl int
389*25cf1a30Sjl dm2s_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr)
390*25cf1a30Sjl {
391*25cf1a30Sjl 	dm2s_t *dm2sp;
392*25cf1a30Sjl 	int instance = getminor(*dev);
393*25cf1a30Sjl 	int ret = 0;
394*25cf1a30Sjl 
395*25cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_open: called\n"));
396*25cf1a30Sjl 	if (sflag == CLONEOPEN)	{
397*25cf1a30Sjl 		/* Clone open not supported */
398*25cf1a30Sjl 		DPRINTF(DBG_WARN, ("dm2s_open: clone open not supported\n"));
399*25cf1a30Sjl 		return (ENOTSUP);
400*25cf1a30Sjl 	}
401*25cf1a30Sjl 
402*25cf1a30Sjl 	if (rq->q_ptr != NULL) {
403*25cf1a30Sjl 		DPRINTF(DBG_WARN, ("dm2s_open: already opened\n"));
404*25cf1a30Sjl 		return (EBUSY);
405*25cf1a30Sjl 	}
406*25cf1a30Sjl 
407*25cf1a30Sjl 	if ((dm2sp = ddi_get_soft_state(dm2s_softstate, instance)) == NULL) {
408*25cf1a30Sjl 		DPRINTF(DBG_WARN, ("dm2s_open: instance not found\n"));
409*25cf1a30Sjl 		return (ENODEV);
410*25cf1a30Sjl 	}
411*25cf1a30Sjl 
412*25cf1a30Sjl 	mutex_enter(&dm2sp->ms_lock);
413*25cf1a30Sjl 	if (dm2sp->ms_state & DM2S_OPENED) {
414*25cf1a30Sjl 		/* Only one open supported */
415*25cf1a30Sjl 		mutex_exit(&dm2sp->ms_lock);
416*25cf1a30Sjl 		DPRINTF(DBG_WARN, ("dm2s_open: already opened\n"));
417*25cf1a30Sjl 		return (EBUSY);
418*25cf1a30Sjl 	}
419*25cf1a30Sjl 
420*25cf1a30Sjl 	dm2sp->ms_state |= DM2S_OPENED;
421*25cf1a30Sjl 	/* Initialize the mailbox. */
422*25cf1a30Sjl 	if ((ret = dm2s_mbox_init(dm2sp)) != 0) {
423*25cf1a30Sjl 		dm2sp->ms_state = 0;
424*25cf1a30Sjl 		mutex_exit(&dm2sp->ms_lock);
425*25cf1a30Sjl 		return (ret);
426*25cf1a30Sjl 	}
427*25cf1a30Sjl 	rq->q_ptr = WR(rq)->q_ptr = (void *)dm2sp;
428*25cf1a30Sjl 	dm2sp->ms_rq = rq;
429*25cf1a30Sjl 	dm2sp->ms_wq = WR(rq);
430*25cf1a30Sjl 	mutex_exit(&dm2sp->ms_lock);
431*25cf1a30Sjl 
432*25cf1a30Sjl 	if (ret == 0) {
433*25cf1a30Sjl 		qprocson(rq);		/* now schedule our queue */
434*25cf1a30Sjl 	}
435*25cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_open: ret=%d\n", ret));
436*25cf1a30Sjl 	return (ret);
437*25cf1a30Sjl }
438*25cf1a30Sjl 
439*25cf1a30Sjl /*
440*25cf1a30Sjl  * dm2s_close - Device close routine.
441*25cf1a30Sjl  */
442*25cf1a30Sjl /* ARGSUSED */
443*25cf1a30Sjl int
444*25cf1a30Sjl dm2s_close(queue_t *rq, int flag, cred_t *cred)
445*25cf1a30Sjl {
446*25cf1a30Sjl 	dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr;
447*25cf1a30Sjl 
448*25cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_close: called\n"));
449*25cf1a30Sjl 	if (dm2sp == NULL) {
450*25cf1a30Sjl 		/* Already closed once */
451*25cf1a30Sjl 		return (ENODEV);
452*25cf1a30Sjl 	}
453*25cf1a30Sjl 
454*25cf1a30Sjl 	/* Close the lower layer first */
455*25cf1a30Sjl 	mutex_enter(&dm2sp->ms_lock);
456*25cf1a30Sjl 	(void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, MB_FLUSH_ALL);
457*25cf1a30Sjl 	dm2s_mbox_fini(dm2sp);
458*25cf1a30Sjl 	mutex_exit(&dm2sp->ms_lock);
459*25cf1a30Sjl 
460*25cf1a30Sjl 	/*
461*25cf1a30Sjl 	 * Now we can assume that no asynchronous callbacks exist.
462*25cf1a30Sjl 	 * Poison the stream head so that we can't be pushed again.
463*25cf1a30Sjl 	 */
464*25cf1a30Sjl 	(void) putnextctl(rq, M_HANGUP);
465*25cf1a30Sjl 	qprocsoff(rq);
466*25cf1a30Sjl 	if (dm2sp->ms_rbufcid != 0) {
467*25cf1a30Sjl 		qunbufcall(rq, dm2sp->ms_rbufcid);
468*25cf1a30Sjl 		dm2sp->ms_rbufcid = 0;
469*25cf1a30Sjl 	}
470*25cf1a30Sjl 	if (dm2sp->ms_rq_timeoutid != 0) {
471*25cf1a30Sjl 		DTRACE_PROBE1(dm2s_rqtimeout__cancel, dm2s_t, dm2sp);
472*25cf1a30Sjl 		(void) quntimeout(dm2sp->ms_rq, dm2sp->ms_rq_timeoutid);
473*25cf1a30Sjl 		dm2sp->ms_rq_timeoutid = 0;
474*25cf1a30Sjl 	}
475*25cf1a30Sjl 	if (dm2sp->ms_wq_timeoutid != 0) {
476*25cf1a30Sjl 		DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp);
477*25cf1a30Sjl 		(void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid);
478*25cf1a30Sjl 		dm2sp->ms_wq_timeoutid = 0;
479*25cf1a30Sjl 	}
480*25cf1a30Sjl 	/*
481*25cf1a30Sjl 	 * Now we can really mark it closed.
482*25cf1a30Sjl 	 */
483*25cf1a30Sjl 	mutex_enter(&dm2sp->ms_lock);
484*25cf1a30Sjl 	dm2sp->ms_rq = dm2sp->ms_wq = NULL;
485*25cf1a30Sjl 	dm2sp->ms_state &= ~DM2S_OPENED;
486*25cf1a30Sjl 	mutex_exit(&dm2sp->ms_lock);
487*25cf1a30Sjl 
488*25cf1a30Sjl 	rq->q_ptr = WR(rq)->q_ptr = NULL;
489*25cf1a30Sjl 	(void) qassociate(rq, -1);
490*25cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_close: successfully closed\n"));
491*25cf1a30Sjl 	return (0);
492*25cf1a30Sjl }
493*25cf1a30Sjl 
494*25cf1a30Sjl /*
495*25cf1a30Sjl  * dm2s_rsrv - Streams read side service procedure.
496*25cf1a30Sjl  *
497*25cf1a30Sjl  * All messages are received in the service procedure
498*25cf1a30Sjl  * only. This is done to simplify the streams synchronization.
499*25cf1a30Sjl  */
500*25cf1a30Sjl int
501*25cf1a30Sjl dm2s_rsrv(queue_t *rq)
502*25cf1a30Sjl {
503*25cf1a30Sjl 	mblk_t *mp;
504*25cf1a30Sjl 	dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr;
505*25cf1a30Sjl 
506*25cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_rsrv: called\n"));
507*25cf1a30Sjl 	ASSERT(dm2sp != NULL);
508*25cf1a30Sjl 	mutex_enter(&dm2sp->ms_lock);
509*25cf1a30Sjl 
510*25cf1a30Sjl 	/* Receive if there are any messages waiting in the mailbox. */
511*25cf1a30Sjl 	dm2s_receive(dm2sp);
512*25cf1a30Sjl 	mutex_exit(&dm2sp->ms_lock);
513*25cf1a30Sjl 
514*25cf1a30Sjl 	/* Send the received messages up the stream. */
515*25cf1a30Sjl 	while ((mp = getq(rq)) != NULL) {
516*25cf1a30Sjl 		if (canputnext(rq)) {
517*25cf1a30Sjl 			putnext(rq, mp);
518*25cf1a30Sjl 		} else {
519*25cf1a30Sjl 			putbq(rq, mp);
520*25cf1a30Sjl 			break;
521*25cf1a30Sjl 		}
522*25cf1a30Sjl 	}
523*25cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_rsrv: return\n"));
524*25cf1a30Sjl 	return (0);
525*25cf1a30Sjl }
526*25cf1a30Sjl 
527*25cf1a30Sjl /*
528*25cf1a30Sjl  * dm2s_wsrv - Streams write side service procedure.
529*25cf1a30Sjl  *
530*25cf1a30Sjl  * All messages are transmitted in the service procedure
531*25cf1a30Sjl  * only. This is done to simplify the streams synchronization.
532*25cf1a30Sjl  */
533*25cf1a30Sjl int
534*25cf1a30Sjl dm2s_wsrv(queue_t *wq)
535*25cf1a30Sjl {
536*25cf1a30Sjl 	dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr;
537*25cf1a30Sjl 
538*25cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_wsrv: called\n"));
539*25cf1a30Sjl 	ASSERT(dm2sp != NULL);
540*25cf1a30Sjl 	/* Lets cancel any timeouts waiting to be scheduled. */
541*25cf1a30Sjl 	if (dm2sp->ms_wq_timeoutid != 0) {
542*25cf1a30Sjl 		DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp);
543*25cf1a30Sjl 		(void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid);
544*25cf1a30Sjl 		dm2sp->ms_wq_timeoutid = 0;
545*25cf1a30Sjl 	}
546*25cf1a30Sjl 	mutex_enter(&dm2sp->ms_lock);
547*25cf1a30Sjl 	dm2s_start(wq, dm2sp);
548*25cf1a30Sjl 	mutex_exit(&dm2sp->ms_lock);
549*25cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_wsrv: return\n"));
550*25cf1a30Sjl 	return (0);
551*25cf1a30Sjl }
552*25cf1a30Sjl 
553*25cf1a30Sjl /*
554*25cf1a30Sjl  * dm2s_wput - Streams write side put routine.
555*25cf1a30Sjl  *
556*25cf1a30Sjl  * All M_DATA messages are queued so that they are transmitted in
557*25cf1a30Sjl  * the service procedure. This is done to simplify the streams
558*25cf1a30Sjl  * synchronization. Other messages are handled appropriately.
559*25cf1a30Sjl  */
560*25cf1a30Sjl int
561*25cf1a30Sjl dm2s_wput(queue_t *wq, mblk_t *mp)
562*25cf1a30Sjl {
563*25cf1a30Sjl 	dm2s_t	*dm2sp = (dm2s_t *)wq->q_ptr;
564*25cf1a30Sjl 
565*25cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_wput: called\n"));
566*25cf1a30Sjl 	if (dm2sp == NULL) {
567*25cf1a30Sjl 		return (ENODEV);   /* Can't happen. */
568*25cf1a30Sjl 	}
569*25cf1a30Sjl 
570*25cf1a30Sjl 	switch (mp->b_datap->db_type) {
571*25cf1a30Sjl 	case (M_DATA):
572*25cf1a30Sjl 		DPRINTF(DBG_DRV, ("dm2s_wput: M_DATA message\n"));
573*25cf1a30Sjl 		while (mp->b_wptr == mp->b_rptr) {
574*25cf1a30Sjl 			mblk_t *mp1;
575*25cf1a30Sjl 
576*25cf1a30Sjl 			mp1 = unlinkb(mp);
577*25cf1a30Sjl 			freemsg(mp);
578*25cf1a30Sjl 			mp = mp1;
579*25cf1a30Sjl 			if (mp == NULL) {
580*25cf1a30Sjl 				return (0);
581*25cf1a30Sjl 			}
582*25cf1a30Sjl 		}
583*25cf1a30Sjl 
584*25cf1a30Sjl 		/*
585*25cf1a30Sjl 		 * Simply queue the message and handle it in the service
586*25cf1a30Sjl 		 * procedure.
587*25cf1a30Sjl 		 */
588*25cf1a30Sjl 		(void) putq(wq, mp);
589*25cf1a30Sjl 		qenable(wq);
590*25cf1a30Sjl 		return (0);
591*25cf1a30Sjl 
592*25cf1a30Sjl 	case (M_PROTO):
593*25cf1a30Sjl 		DPRINTF(DBG_DRV, ("dm2s_wput: M_PROTO message\n"));
594*25cf1a30Sjl 		/* We don't expect this */
595*25cf1a30Sjl 		mp->b_datap->db_type = M_ERROR;
596*25cf1a30Sjl 		mp->b_rptr = mp->b_wptr = mp->b_datap->db_base;
597*25cf1a30Sjl 		*mp->b_wptr++ = EPROTO;
598*25cf1a30Sjl 		qreply(wq, mp);
599*25cf1a30Sjl 		return (EINVAL);
600*25cf1a30Sjl 
601*25cf1a30Sjl 	case (M_IOCTL):
602*25cf1a30Sjl 		DPRINTF(DBG_DRV, ("dm2s_wput: M_IOCTL message\n"));
603*25cf1a30Sjl 		if (MBLKL(mp) < sizeof (struct iocblk)) {
604*25cf1a30Sjl 			freemsg(mp);
605*25cf1a30Sjl 			return (0);
606*25cf1a30Sjl 		}
607*25cf1a30Sjl 		/*
608*25cf1a30Sjl 		 * No ioctls required to be supported by this driver, so
609*25cf1a30Sjl 		 * return EINVAL for all ioctls.
610*25cf1a30Sjl 		 */
611*25cf1a30Sjl 		miocnak(wq, mp, 0, EINVAL);
612*25cf1a30Sjl 		break;
613*25cf1a30Sjl 
614*25cf1a30Sjl 	case (M_CTL):
615*25cf1a30Sjl 		DPRINTF(DBG_DRV, ("dm2s_wput: M_CTL message\n"));
616*25cf1a30Sjl 		/*
617*25cf1a30Sjl 		 * No M_CTL messages need to supported by this driver,
618*25cf1a30Sjl 		 * so simply ignore them.
619*25cf1a30Sjl 		 */
620*25cf1a30Sjl 		freemsg(mp);
621*25cf1a30Sjl 		break;
622*25cf1a30Sjl 
623*25cf1a30Sjl 	case (M_FLUSH):
624*25cf1a30Sjl 		DPRINTF(DBG_DRV, (
625*25cf1a30Sjl 		    "dm2s_wput: M_FLUSH message 0x%X\n", *mp->b_rptr));
626*25cf1a30Sjl 		if (*mp->b_rptr & FLUSHW) {	/* Flush write-side */
627*25cf1a30Sjl 			(void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key,
628*25cf1a30Sjl 			    MB_FLUSH_SEND);
629*25cf1a30Sjl 			flushq(wq, FLUSHDATA);
630*25cf1a30Sjl 			*mp->b_rptr &= ~FLUSHW;
631*25cf1a30Sjl 		}
632*25cf1a30Sjl 		if (*mp->b_rptr & FLUSHR) {
633*25cf1a30Sjl 			(void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key,
634*25cf1a30Sjl 			    MB_FLUSH_RECEIVE);
635*25cf1a30Sjl 			flushq(RD(wq), FLUSHDATA);
636*25cf1a30Sjl 			qreply(wq, mp);
637*25cf1a30Sjl 		} else {
638*25cf1a30Sjl 			freemsg(mp);
639*25cf1a30Sjl 		}
640*25cf1a30Sjl 		break;
641*25cf1a30Sjl 
642*25cf1a30Sjl 	default:
643*25cf1a30Sjl 		DPRINTF(DBG_DRV, ("dm2s_wput: UNKNOWN message\n"));
644*25cf1a30Sjl 		freemsg(mp);
645*25cf1a30Sjl 
646*25cf1a30Sjl 	}
647*25cf1a30Sjl 	return (0);
648*25cf1a30Sjl }
649*25cf1a30Sjl 
650*25cf1a30Sjl /*
651*25cf1a30Sjl  * dm2s_cleanup - Cleanup routine.
652*25cf1a30Sjl  */
653*25cf1a30Sjl static void
654*25cf1a30Sjl dm2s_cleanup(dm2s_t *dm2sp)
655*25cf1a30Sjl {
656*25cf1a30Sjl 	char name[20];
657*25cf1a30Sjl 
658*25cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_cleanup: called\n"));
659*25cf1a30Sjl 	ASSERT(dm2sp != NULL);
660*25cf1a30Sjl 	if (dm2sp->ms_clean & DM2S_CLEAN_NODE) {
661*25cf1a30Sjl 		(void) sprintf(name, "%s%d", DM2S_MODNAME, dm2sp->ms_ppa);
662*25cf1a30Sjl 		ddi_remove_minor_node(dm2sp->ms_dip, name);
663*25cf1a30Sjl 	}
664*25cf1a30Sjl 	if (dm2sp->ms_clean & DM2S_CLEAN_LOCK)
665*25cf1a30Sjl 		mutex_destroy(&dm2sp->ms_lock);
666*25cf1a30Sjl 	if (dm2sp->ms_clean & DM2S_CLEAN_CV)
667*25cf1a30Sjl 		cv_destroy(&dm2sp->ms_wait);
668*25cf1a30Sjl 	ddi_set_driver_private(dm2sp->ms_dip, NULL);
669*25cf1a30Sjl 	ddi_soft_state_free(dm2s_softstate, dm2sp->ms_ppa);
670*25cf1a30Sjl }
671*25cf1a30Sjl 
672*25cf1a30Sjl /*
673*25cf1a30Sjl  * dm2s_mbox_init - Mailbox specific initialization.
674*25cf1a30Sjl  */
675*25cf1a30Sjl static int
676*25cf1a30Sjl dm2s_mbox_init(dm2s_t *dm2sp)
677*25cf1a30Sjl {
678*25cf1a30Sjl 	int ret;
679*25cf1a30Sjl 	clock_t tout;
680*25cf1a30Sjl 
681*25cf1a30Sjl 	ASSERT(MUTEX_HELD(&dm2sp->ms_lock));
682*25cf1a30Sjl 	dm2sp->ms_target = DM2S_TARGET_ID;
683*25cf1a30Sjl 	dm2sp->ms_key = DSCP_KEY;
684*25cf1a30Sjl 	dm2sp->ms_state &= ~DM2S_MB_INITED;
685*25cf1a30Sjl 
686*25cf1a30Sjl 	/* Iterate until mailbox gets connected */
687*25cf1a30Sjl 	while (!(dm2sp->ms_state & DM2S_MB_CONN)) {
688*25cf1a30Sjl 		DPRINTF(DBG_MBOX, ("dm2s_mbox_init: calling mb_init\n"));
689*25cf1a30Sjl 		ret = scf_mb_init(dm2sp->ms_target, dm2sp->ms_key,
690*25cf1a30Sjl 		    dm2s_event_handler, (void *)dm2sp);
691*25cf1a30Sjl 		DPRINTF(DBG_MBOX, ("dm2s_mbox_init: mb_init ret=%d\n", ret));
692*25cf1a30Sjl 
693*25cf1a30Sjl 		if (ret == 0) {
694*25cf1a30Sjl 			dm2sp->ms_state |= DM2S_MB_INITED;
695*25cf1a30Sjl 
696*25cf1a30Sjl 			/* Block until the mailbox is ready to communicate. */
697*25cf1a30Sjl 			while (!(dm2sp->ms_state &
698*25cf1a30Sjl 			    (DM2S_MB_CONN | DM2S_MB_DISC))) {
699*25cf1a30Sjl 
700*25cf1a30Sjl 				if (cv_wait_sig(&dm2sp->ms_wait,
701*25cf1a30Sjl 				    &dm2sp->ms_lock) <= 0) {
702*25cf1a30Sjl 					/* interrupted */
703*25cf1a30Sjl 					ret = EINTR;
704*25cf1a30Sjl 					break;
705*25cf1a30Sjl 				}
706*25cf1a30Sjl 			}
707*25cf1a30Sjl 		}
708*25cf1a30Sjl 
709*25cf1a30Sjl 		if (ret != 0) {
710*25cf1a30Sjl 
711*25cf1a30Sjl 			DPRINTF(DBG_MBOX,
712*25cf1a30Sjl 			    ("dm2s_mbox_init: failed/interrupted\n"));
713*25cf1a30Sjl 			DTRACE_PROBE1(dm2s_mbox_fail, int, ret);
714*25cf1a30Sjl 			dm2sp->ms_state &= ~DM2S_MB_INITED;
715*25cf1a30Sjl 			(void) scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key);
716*25cf1a30Sjl 
717*25cf1a30Sjl 			/* if interrupted, return immediately. */
718*25cf1a30Sjl 			if (ret == EINTR)
719*25cf1a30Sjl 				return (ret);
720*25cf1a30Sjl 
721*25cf1a30Sjl 		}
722*25cf1a30Sjl 
723*25cf1a30Sjl 		if ((ret != 0) || (dm2sp->ms_state & DM2S_MB_DISC)) {
724*25cf1a30Sjl 
725*25cf1a30Sjl 			DPRINTF(DBG_WARN,
726*25cf1a30Sjl 			    ("dm2s_mbox_init: mbox DISC_ERROR\n"));
727*25cf1a30Sjl 			DTRACE_PROBE1(dm2s_mbox_fail, int, DM2S_MB_DISC);
728*25cf1a30Sjl 			dm2sp->ms_state &= ~DM2S_MB_INITED;
729*25cf1a30Sjl 			(void) scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key);
730*25cf1a30Sjl 
731*25cf1a30Sjl 			/*
732*25cf1a30Sjl 			 * If there was failure, then wait for
733*25cf1a30Sjl 			 * DM2S_MB_TOUT secs and retry again.
734*25cf1a30Sjl 			 */
735*25cf1a30Sjl 
736*25cf1a30Sjl 			DPRINTF(DBG_MBOX, ("dm2s_mbox_init: waiting...\n"));
737*25cf1a30Sjl 			tout = ddi_get_lbolt() + drv_usectohz(DM2S_MB_TOUT);
738*25cf1a30Sjl 			ret = cv_timedwait_sig(&dm2sp->ms_wait,
739*25cf1a30Sjl 			    &dm2sp->ms_lock, tout);
740*25cf1a30Sjl 			if (ret == 0) {
741*25cf1a30Sjl 				/* if interrupted, return immediately. */
742*25cf1a30Sjl 				DPRINTF(DBG_MBOX,
743*25cf1a30Sjl 				    ("dm2s_mbox_init: interrupted\n"));
744*25cf1a30Sjl 				return (EINTR);
745*25cf1a30Sjl 			}
746*25cf1a30Sjl 		}
747*25cf1a30Sjl 	}
748*25cf1a30Sjl 
749*25cf1a30Sjl 	/*
750*25cf1a30Sjl 	 * Obtain the max size of a single message.
751*25cf1a30Sjl 	 * NOTE: There is no mechanism to update the
752*25cf1a30Sjl 	 * upperlayers dynamically, so we expect this
753*25cf1a30Sjl 	 * size to be atleast the default MTU size.
754*25cf1a30Sjl 	 */
755*25cf1a30Sjl 	ret = scf_mb_ctrl(dm2sp->ms_target, dm2sp->ms_key,
756*25cf1a30Sjl 	    SCF_MBOP_MAXMSGSIZE, &dm2sp->ms_mtu);
757*25cf1a30Sjl 
758*25cf1a30Sjl 	if ((ret == 0) && (dm2sp->ms_mtu < DM2S_DEF_MTU)) {
759*25cf1a30Sjl 		cmn_err(CE_WARN, "Max message size expected >= %d "
760*25cf1a30Sjl 		    "but found %d\n", DM2S_DEF_MTU, dm2sp->ms_mtu);
761*25cf1a30Sjl 		ret = EIO;
762*25cf1a30Sjl 	}
763*25cf1a30Sjl 
764*25cf1a30Sjl 	if (ret != 0) {
765*25cf1a30Sjl 		dm2sp->ms_state &= ~DM2S_MB_INITED;
766*25cf1a30Sjl 		(void) scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key);
767*25cf1a30Sjl 	}
768*25cf1a30Sjl 	DPRINTF(DBG_MBOX, ("dm2s_mbox_init: mb_init ret=%d\n", ret));
769*25cf1a30Sjl 	return (ret);
770*25cf1a30Sjl }
771*25cf1a30Sjl 
772*25cf1a30Sjl /*
773*25cf1a30Sjl  * dm2s_mbox_fini - Mailbox de-initialization.
774*25cf1a30Sjl  */
775*25cf1a30Sjl static void
776*25cf1a30Sjl dm2s_mbox_fini(dm2s_t *dm2sp)
777*25cf1a30Sjl {
778*25cf1a30Sjl 	int ret;
779*25cf1a30Sjl 
780*25cf1a30Sjl 	ASSERT(dm2sp != NULL);
781*25cf1a30Sjl 	if (dm2sp->ms_state & DM2S_MB_INITED) {
782*25cf1a30Sjl 		DPRINTF(DBG_MBOX, ("dm2s_mbox_fini: calling mb_fini\n"));
783*25cf1a30Sjl 		ret =  scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key);
784*25cf1a30Sjl 		if (ret != 0) {
785*25cf1a30Sjl 			cmn_err(CE_WARN,
786*25cf1a30Sjl 			    "Failed to close the Mailbox error =%d", ret);
787*25cf1a30Sjl 		}
788*25cf1a30Sjl 		DPRINTF(DBG_MBOX, ("dm2s_mbox_fini: mb_fini ret=%d\n", ret));
789*25cf1a30Sjl 		dm2sp->ms_state &= ~(DM2S_MB_INITED |DM2S_MB_CONN |
790*25cf1a30Sjl 		    DM2S_MB_DISC);
791*25cf1a30Sjl 	}
792*25cf1a30Sjl }
793*25cf1a30Sjl 
794*25cf1a30Sjl /*
795*25cf1a30Sjl  * dm2s_event_handler - Mailbox event handler.
796*25cf1a30Sjl  */
797*25cf1a30Sjl void
798*25cf1a30Sjl dm2s_event_handler(scf_event_t event, void *arg)
799*25cf1a30Sjl {
800*25cf1a30Sjl 	dm2s_t *dm2sp = (dm2s_t *)arg;
801*25cf1a30Sjl 	queue_t	*rq;
802*25cf1a30Sjl 
803*25cf1a30Sjl 	ASSERT(dm2sp != NULL);
804*25cf1a30Sjl 	mutex_enter(&dm2sp->ms_lock);
805*25cf1a30Sjl 	if (!(dm2sp->ms_state & DM2S_MB_INITED)) {
806*25cf1a30Sjl 		/*
807*25cf1a30Sjl 		 * Ignore all events if the state flag indicates that the
808*25cf1a30Sjl 		 * mailbox not initialized, this may happen during the close.
809*25cf1a30Sjl 		 */
810*25cf1a30Sjl 		mutex_exit(&dm2sp->ms_lock);
811*25cf1a30Sjl 		DPRINTF(DBG_MBOX,
812*25cf1a30Sjl 		    ("Event(0x%X) received - Mailbox not inited\n", event));
813*25cf1a30Sjl 		return;
814*25cf1a30Sjl 	}
815*25cf1a30Sjl 	switch (event) {
816*25cf1a30Sjl 	case SCF_MB_CONN_OK:
817*25cf1a30Sjl 		/*
818*25cf1a30Sjl 		 * Now the mailbox is ready to use, lets wake up
819*25cf1a30Sjl 		 * any one waiting for this event.
820*25cf1a30Sjl 		 */
821*25cf1a30Sjl 		dm2sp->ms_state |= DM2S_MB_CONN;
822*25cf1a30Sjl 		cv_broadcast(&dm2sp->ms_wait);
823*25cf1a30Sjl 		DPRINTF(DBG_MBOX, ("Event received = CONN_OK\n"));
824*25cf1a30Sjl 		break;
825*25cf1a30Sjl 
826*25cf1a30Sjl 	case SCF_MB_MSG_DATA:
827*25cf1a30Sjl 		if (!DM2S_MBOX_READY(dm2sp)) {
828*25cf1a30Sjl 			DPRINTF(DBG_MBOX,
829*25cf1a30Sjl 			    ("Event(MSG_DATA) received - Mailbox not READY\n"));
830*25cf1a30Sjl 			break;
831*25cf1a30Sjl 		}
832*25cf1a30Sjl 		/*
833*25cf1a30Sjl 		 * A message is available in the mailbox.
834*25cf1a30Sjl 		 * Lets enable the read service procedure
835*25cf1a30Sjl 		 * to receive this message.
836*25cf1a30Sjl 		 */
837*25cf1a30Sjl 		if (dm2sp->ms_rq != NULL) {
838*25cf1a30Sjl 			qenable(dm2sp->ms_rq);
839*25cf1a30Sjl 		}
840*25cf1a30Sjl 		DPRINTF(DBG_MBOX, ("Event received = MSG_DATA\n"));
841*25cf1a30Sjl 		break;
842*25cf1a30Sjl 
843*25cf1a30Sjl 	case SCF_MB_SPACE:
844*25cf1a30Sjl 		if (!DM2S_MBOX_READY(dm2sp)) {
845*25cf1a30Sjl 			DPRINTF(DBG_MBOX,
846*25cf1a30Sjl 			    ("Event(MB_SPACE) received - Mailbox not READY\n"));
847*25cf1a30Sjl 			break;
848*25cf1a30Sjl 		}
849*25cf1a30Sjl 
850*25cf1a30Sjl 		/*
851*25cf1a30Sjl 		 * Now the mailbox is ready to transmit, lets
852*25cf1a30Sjl 		 * schedule the write service procedure.
853*25cf1a30Sjl 		 */
854*25cf1a30Sjl 		if (dm2sp->ms_wq != NULL) {
855*25cf1a30Sjl 			qenable(dm2sp->ms_wq);
856*25cf1a30Sjl 		}
857*25cf1a30Sjl 		DPRINTF(DBG_MBOX, ("Event received = MB_SPACE\n"));
858*25cf1a30Sjl 		break;
859*25cf1a30Sjl 	case SCF_MB_DISC_ERROR:
860*25cf1a30Sjl 		dm2sp->ms_state |= DM2S_MB_DISC;
861*25cf1a30Sjl 		if (dm2sp->ms_state & DM2S_MB_CONN) {
862*25cf1a30Sjl 			/*
863*25cf1a30Sjl 			 * If it was previously connected,
864*25cf1a30Sjl 			 * then send a hangup message.
865*25cf1a30Sjl 			 */
866*25cf1a30Sjl 			rq = dm2sp->ms_rq;
867*25cf1a30Sjl 			if (rq != NULL) {
868*25cf1a30Sjl 				mutex_exit(&dm2sp->ms_lock);
869*25cf1a30Sjl 				/*
870*25cf1a30Sjl 				 * Send a hangup message to indicate
871*25cf1a30Sjl 				 * disconnect event.
872*25cf1a30Sjl 				 */
873*25cf1a30Sjl 				(void) putctl(rq, M_HANGUP);
874*25cf1a30Sjl 				DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp);
875*25cf1a30Sjl 				mutex_enter(&dm2sp->ms_lock);
876*25cf1a30Sjl 			}
877*25cf1a30Sjl 		} else {
878*25cf1a30Sjl 			/*
879*25cf1a30Sjl 			 * Signal if the open is waiting for a
880*25cf1a30Sjl 			 * connection.
881*25cf1a30Sjl 			 */
882*25cf1a30Sjl 			cv_broadcast(&dm2sp->ms_wait);
883*25cf1a30Sjl 		}
884*25cf1a30Sjl 		DPRINTF(DBG_MBOX, ("Event received = DISC_ERROR\n"));
885*25cf1a30Sjl 		break;
886*25cf1a30Sjl 	default:
887*25cf1a30Sjl 		cmn_err(CE_WARN, "Unexpected event received\n");
888*25cf1a30Sjl 		break;
889*25cf1a30Sjl 	}
890*25cf1a30Sjl 	mutex_exit(&dm2sp->ms_lock);
891*25cf1a30Sjl }
892*25cf1a30Sjl 
893*25cf1a30Sjl /*
894*25cf1a30Sjl  * dm2s_start - Start transmission function.
895*25cf1a30Sjl  *
896*25cf1a30Sjl  * Send all queued messages. If the mailbox is busy, then
897*25cf1a30Sjl  * start a timeout as a polling mechanism. The timeout is useful
898*25cf1a30Sjl  * to not rely entirely on the SCF_MB_SPACE event.
899*25cf1a30Sjl  */
900*25cf1a30Sjl void
901*25cf1a30Sjl dm2s_start(queue_t *wq, dm2s_t *dm2sp)
902*25cf1a30Sjl {
903*25cf1a30Sjl 	mblk_t *mp;
904*25cf1a30Sjl 	int ret;
905*25cf1a30Sjl 
906*25cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_start: called\n"));
907*25cf1a30Sjl 	ASSERT(dm2sp != NULL);
908*25cf1a30Sjl 	ASSERT(MUTEX_HELD(&dm2sp->ms_lock));
909*25cf1a30Sjl 
910*25cf1a30Sjl 	while ((mp = getq(wq)) != NULL) {
911*25cf1a30Sjl 		switch (mp->b_datap->db_type) {
912*25cf1a30Sjl 
913*25cf1a30Sjl 		case M_DATA:
914*25cf1a30Sjl 			ret = dm2s_transmit(wq, mp, dm2sp->ms_target,
915*25cf1a30Sjl 			    dm2sp->ms_key);
916*25cf1a30Sjl 			if (ret == EBUSY || ret == ENOSPC || ret == EAGAIN) {
917*25cf1a30Sjl 				DPRINTF(DBG_MBOX,
918*25cf1a30Sjl 				    ("dm2s_start: recoverable err=%d\n", ret));
919*25cf1a30Sjl 				/*
920*25cf1a30Sjl 				 * Start a timeout to retry again.
921*25cf1a30Sjl 				 */
922*25cf1a30Sjl 				if (dm2sp->ms_wq_timeoutid == 0) {
923*25cf1a30Sjl 					DTRACE_PROBE1(dm2s_wqtimeout__start,
924*25cf1a30Sjl 					    dm2s_t, dm2sp);
925*25cf1a30Sjl 					dm2sp->ms_wq_timeoutid = qtimeout(wq,
926*25cf1a30Sjl 					    dm2s_wq_timeout, (void *)dm2sp,
927*25cf1a30Sjl 					    dm2s_timeout_val(ret));
928*25cf1a30Sjl 				}
929*25cf1a30Sjl 				return;
930*25cf1a30Sjl 			} else if (ret != 0) {
931*25cf1a30Sjl 				mutex_exit(&dm2sp->ms_lock);
932*25cf1a30Sjl 				/*
933*25cf1a30Sjl 				 * An error occurred with the transmission,
934*25cf1a30Sjl 				 * flush pending messages and initiate a
935*25cf1a30Sjl 				 * hangup.
936*25cf1a30Sjl 				 */
937*25cf1a30Sjl 				flushq(wq, FLUSHDATA);
938*25cf1a30Sjl 				(void) putnextctl(RD(wq), M_HANGUP);
939*25cf1a30Sjl 				DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp);
940*25cf1a30Sjl 				DPRINTF(DBG_WARN,
941*25cf1a30Sjl 				    ("dm2s_start: hangup transmit err=%d\n",
942*25cf1a30Sjl 				    ret));
943*25cf1a30Sjl 				mutex_enter(&dm2sp->ms_lock);
944*25cf1a30Sjl 			}
945*25cf1a30Sjl 			break;
946*25cf1a30Sjl 		default:
947*25cf1a30Sjl 			/*
948*25cf1a30Sjl 			 * At this point, we don't expect any other messages.
949*25cf1a30Sjl 			 */
950*25cf1a30Sjl 			freemsg(mp);
951*25cf1a30Sjl 			break;
952*25cf1a30Sjl 		}
953*25cf1a30Sjl 	}
954*25cf1a30Sjl }
955*25cf1a30Sjl 
956*25cf1a30Sjl /*
957*25cf1a30Sjl  * dm2s_receive - Read all messages from the mailbox.
958*25cf1a30Sjl  *
959*25cf1a30Sjl  * This function is called from the read service procedure, to
960*25cf1a30Sjl  * receive the messages awaiting in the mailbox.
961*25cf1a30Sjl  */
962*25cf1a30Sjl void
963*25cf1a30Sjl dm2s_receive(dm2s_t *dm2sp)
964*25cf1a30Sjl {
965*25cf1a30Sjl 	queue_t	*rq = dm2sp->ms_rq;
966*25cf1a30Sjl 	mblk_t	*mp;
967*25cf1a30Sjl 	int	ret;
968*25cf1a30Sjl 	uint32_t len;
969*25cf1a30Sjl 
970*25cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_receive: called\n"));
971*25cf1a30Sjl 	ASSERT(dm2sp != NULL);
972*25cf1a30Sjl 	ASSERT(MUTEX_HELD(&dm2sp->ms_lock));
973*25cf1a30Sjl 	if (rq == NULL) {
974*25cf1a30Sjl 		return;
975*25cf1a30Sjl 	}
976*25cf1a30Sjl 	/*
977*25cf1a30Sjl 	 * As the number of messages in the mailbox are pretty limited,
978*25cf1a30Sjl 	 * it is safe to process all messages in one loop.
979*25cf1a30Sjl 	 */
980*25cf1a30Sjl 	while (DM2S_MBOX_READY(dm2sp) && ((ret = scf_mb_canget(dm2sp->ms_target,
981*25cf1a30Sjl 	    dm2sp->ms_key, &len)) == 0)) {
982*25cf1a30Sjl 		DPRINTF(DBG_MBOX, ("dm2s_receive: mb_canget len=%d\n", len));
983*25cf1a30Sjl 		if (len == 0) {
984*25cf1a30Sjl 			break;
985*25cf1a30Sjl 		}
986*25cf1a30Sjl 		mp = allocb(len, BPRI_MED);
987*25cf1a30Sjl 		if (mp == NULL) {
988*25cf1a30Sjl 			DPRINTF(DBG_WARN, ("dm2s_receive: allocb failed\n"));
989*25cf1a30Sjl 			/*
990*25cf1a30Sjl 			 * Start a bufcall so that we can retry again
991*25cf1a30Sjl 			 * when memory becomes available.
992*25cf1a30Sjl 			 */
993*25cf1a30Sjl 			dm2sp->ms_rbufcid = qbufcall(rq, len, BPRI_MED,
994*25cf1a30Sjl 			    dm2s_bufcall_rcv, dm2sp);
995*25cf1a30Sjl 			if (dm2sp->ms_rbufcid == 0) {
996*25cf1a30Sjl 				DPRINTF(DBG_WARN,
997*25cf1a30Sjl 				    ("dm2s_receive: qbufcall failed\n"));
998*25cf1a30Sjl 				/*
999*25cf1a30Sjl 				 * if bufcall fails, start a timeout to
1000*25cf1a30Sjl 				 * initiate a re-try after some time.
1001*25cf1a30Sjl 				 */
1002*25cf1a30Sjl 				DTRACE_PROBE1(dm2s_rqtimeout__start,
1003*25cf1a30Sjl 				    dm2s_t, dm2sp);
1004*25cf1a30Sjl 				dm2sp->ms_rq_timeoutid = qtimeout(rq,
1005*25cf1a30Sjl 				    dm2s_rq_timeout, (void *)dm2sp,
1006*25cf1a30Sjl 				    drv_usectohz(DM2S_SM_TOUT));
1007*25cf1a30Sjl 			}
1008*25cf1a30Sjl 			break;
1009*25cf1a30Sjl 		}
1010*25cf1a30Sjl 
1011*25cf1a30Sjl 		/*
1012*25cf1a30Sjl 		 * Only a single scatter/gather element is enough here.
1013*25cf1a30Sjl 		 */
1014*25cf1a30Sjl 		dm2sp->ms_sg_rcv.msc_dptr = (caddr_t)mp->b_wptr;
1015*25cf1a30Sjl 		dm2sp->ms_sg_rcv.msc_len = len;
1016*25cf1a30Sjl 		DPRINTF(DBG_MBOX, ("dm2s_receive: calling getmsg\n"));
1017*25cf1a30Sjl 		ret = scf_mb_getmsg(dm2sp->ms_target, dm2sp->ms_key, len, 1,
1018*25cf1a30Sjl 		    &dm2sp->ms_sg_rcv, 0);
1019*25cf1a30Sjl 		DPRINTF(DBG_MBOX, ("dm2s_receive: getmsg ret=%d\n", ret));
1020*25cf1a30Sjl 		if (ret != 0) {
1021*25cf1a30Sjl 			freemsg(mp);
1022*25cf1a30Sjl 			break;
1023*25cf1a30Sjl 		}
1024*25cf1a30Sjl 		DMPBYTES("dm2s: Getmsg: ", len, 1, &dm2sp->ms_sg_rcv);
1025*25cf1a30Sjl 		mp->b_wptr += len;
1026*25cf1a30Sjl 		/*
1027*25cf1a30Sjl 		 * Queue the messages in the rq, so that the service
1028*25cf1a30Sjl 		 * procedure handles sending the messages up the stream.
1029*25cf1a30Sjl 		 */
1030*25cf1a30Sjl 		putq(rq, mp);
1031*25cf1a30Sjl 	}
1032*25cf1a30Sjl 
1033*25cf1a30Sjl 	if ((!DM2S_MBOX_READY(dm2sp)) || (ret != ENOMSG && ret != EMSGSIZE)) {
1034*25cf1a30Sjl 		/*
1035*25cf1a30Sjl 		 * Some thing went wrong, flush pending messages
1036*25cf1a30Sjl 		 * and initiate a hangup.
1037*25cf1a30Sjl 		 * Note: flushing the wq initiates a faster close.
1038*25cf1a30Sjl 		 */
1039*25cf1a30Sjl 		mutex_exit(&dm2sp->ms_lock);
1040*25cf1a30Sjl 		flushq(WR(rq), FLUSHDATA);
1041*25cf1a30Sjl 		(void) putnextctl(rq, M_HANGUP);
1042*25cf1a30Sjl 		DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp);
1043*25cf1a30Sjl 		mutex_enter(&dm2sp->ms_lock);
1044*25cf1a30Sjl 		DPRINTF(DBG_WARN, ("dm2s_receive: encountered unknown "
1045*25cf1a30Sjl 		    "condition - hangup ret=%d\n", ret));
1046*25cf1a30Sjl 	}
1047*25cf1a30Sjl }
1048*25cf1a30Sjl 
1049*25cf1a30Sjl /*
1050*25cf1a30Sjl  * dm2s_transmit - Transmit a message.
1051*25cf1a30Sjl  */
1052*25cf1a30Sjl int
1053*25cf1a30Sjl dm2s_transmit(queue_t *wq, mblk_t *mp, target_id_t target, mkey_t key)
1054*25cf1a30Sjl {
1055*25cf1a30Sjl 	dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr;
1056*25cf1a30Sjl 	int ret;
1057*25cf1a30Sjl 	uint32_t len;
1058*25cf1a30Sjl 	uint32_t numsg;
1059*25cf1a30Sjl 
1060*25cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_transmit: called\n"));
1061*25cf1a30Sjl 	ASSERT(dm2sp != NULL);
1062*25cf1a30Sjl 	ASSERT(MUTEX_HELD(&dm2sp->ms_lock));
1063*25cf1a30Sjl 	/*
1064*25cf1a30Sjl 	 * Free the message if the mailbox is not in the connected state.
1065*25cf1a30Sjl 	 */
1066*25cf1a30Sjl 	if (!DM2S_MBOX_READY(dm2sp)) {
1067*25cf1a30Sjl 		DPRINTF(DBG_MBOX, ("dm2s_transmit: mailbox not ready yet\n"));
1068*25cf1a30Sjl 		freemsg(mp);
1069*25cf1a30Sjl 		return (EIO);
1070*25cf1a30Sjl 	}
1071*25cf1a30Sjl 
1072*25cf1a30Sjl 	len = msgdsize(mp);
1073*25cf1a30Sjl 	if (len > dm2sp->ms_mtu) {
1074*25cf1a30Sjl 		/*
1075*25cf1a30Sjl 		 * Size is too big to send, free the message.
1076*25cf1a30Sjl 		 */
1077*25cf1a30Sjl 		DPRINTF(DBG_MBOX, ("dm2s_transmit: message too large\n"));
1078*25cf1a30Sjl 		DTRACE_PROBE2(dm2s_msg_too_big, dm2s_t, dm2sp, uint32_t, len);
1079*25cf1a30Sjl 		freemsg(mp);
1080*25cf1a30Sjl 		return (0);
1081*25cf1a30Sjl 	}
1082*25cf1a30Sjl 
1083*25cf1a30Sjl 	if ((ret = dm2s_prep_scatgath(mp, &numsg, dm2sp->ms_sg_tx,
1084*25cf1a30Sjl 	    DM2S_MAX_SG)) != 0) {
1085*25cf1a30Sjl 		DPRINTF(DBG_MBOX, ("dm2s_transmit: prep_scatgath failed\n"));
1086*25cf1a30Sjl 		putbq(wq, mp);
1087*25cf1a30Sjl 		return (EAGAIN);
1088*25cf1a30Sjl 	}
1089*25cf1a30Sjl 	DPRINTF(DBG_MBOX, ("dm2s_transmit: calling mb_putmsg numsg=%d len=%d\n",
1090*25cf1a30Sjl 	    numsg, len));
1091*25cf1a30Sjl 	ret = scf_mb_putmsg(target, key, len, numsg, dm2sp->ms_sg_tx, 0);
1092*25cf1a30Sjl 	if (ret == EBUSY || ret == ENOSPC) {
1093*25cf1a30Sjl 		DPRINTF(DBG_MBOX,
1094*25cf1a30Sjl 		    ("dm2s_transmit: mailbox busy ret=%d\n", ret));
1095*25cf1a30Sjl 		if (++dm2sp->ms_retries >= DM2S_MAX_RETRIES) {
1096*25cf1a30Sjl 			/*
1097*25cf1a30Sjl 			 * If maximum retries are reached, then free the
1098*25cf1a30Sjl 			 * message.
1099*25cf1a30Sjl 			 */
1100*25cf1a30Sjl 			DPRINTF(DBG_MBOX,
1101*25cf1a30Sjl 			    ("dm2s_transmit: freeing msg after max retries\n"));
1102*25cf1a30Sjl 			DTRACE_PROBE2(dm2s_retry_fail, dm2s_t, dm2sp, int, ret);
1103*25cf1a30Sjl 			freemsg(mp);
1104*25cf1a30Sjl 			dm2sp->ms_retries = 0;
1105*25cf1a30Sjl 			return (0);
1106*25cf1a30Sjl 		}
1107*25cf1a30Sjl 		DTRACE_PROBE2(dm2s_mb_busy, dm2s_t, dm2sp, int, ret);
1108*25cf1a30Sjl 		/*
1109*25cf1a30Sjl 		 * Queue it back, so that we can retry again.
1110*25cf1a30Sjl 		 */
1111*25cf1a30Sjl 		putbq(wq, mp);
1112*25cf1a30Sjl 		return (ret);
1113*25cf1a30Sjl 	}
1114*25cf1a30Sjl 	DMPBYTES("dm2s: Putmsg: ", len, numsg, dm2sp->ms_sg_tx);
1115*25cf1a30Sjl 	dm2sp->ms_retries = 0;
1116*25cf1a30Sjl 	freemsg(mp);
1117*25cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_transmit: ret=%d\n", ret));
1118*25cf1a30Sjl 	return (ret);
1119*25cf1a30Sjl }
1120*25cf1a30Sjl 
1121*25cf1a30Sjl /*
1122*25cf1a30Sjl  * dm2s_bufcall_rcv - Bufcall callaback routine.
1123*25cf1a30Sjl  *
1124*25cf1a30Sjl  * It simply enables read side queue so that the service procedure
1125*25cf1a30Sjl  * can retry receive operation.
1126*25cf1a30Sjl  */
1127*25cf1a30Sjl void
1128*25cf1a30Sjl dm2s_bufcall_rcv(void *arg)
1129*25cf1a30Sjl {
1130*25cf1a30Sjl 	dm2s_t *dm2sp = (dm2s_t *)arg;
1131*25cf1a30Sjl 
1132*25cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_bufcall_rcv: called\n"));
1133*25cf1a30Sjl 	mutex_enter(&dm2sp->ms_lock);
1134*25cf1a30Sjl 	dm2sp->ms_rbufcid = 0;
1135*25cf1a30Sjl 	if (dm2sp->ms_rq != NULL) {
1136*25cf1a30Sjl 		qenable(dm2sp->ms_rq);
1137*25cf1a30Sjl 	}
1138*25cf1a30Sjl 	mutex_exit(&dm2sp->ms_lock);
1139*25cf1a30Sjl }
1140*25cf1a30Sjl 
1141*25cf1a30Sjl /*
1142*25cf1a30Sjl  * dm2s_rq_timeout - Timeout callback for the read side.
1143*25cf1a30Sjl  *
1144*25cf1a30Sjl  * It simply enables read side queue so that the service procedure
1145*25cf1a30Sjl  * can retry the receive operation.
1146*25cf1a30Sjl  */
1147*25cf1a30Sjl void
1148*25cf1a30Sjl dm2s_rq_timeout(void *arg)
1149*25cf1a30Sjl {
1150*25cf1a30Sjl 	dm2s_t *dm2sp = (dm2s_t *)arg;
1151*25cf1a30Sjl 
1152*25cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_rq_timeout: called\n"));
1153*25cf1a30Sjl 	mutex_enter(&dm2sp->ms_lock);
1154*25cf1a30Sjl 	dm2sp->ms_rq_timeoutid = 0;
1155*25cf1a30Sjl 	if (dm2sp->ms_rq != NULL) {
1156*25cf1a30Sjl 		qenable(dm2sp->ms_rq);
1157*25cf1a30Sjl 	}
1158*25cf1a30Sjl 	mutex_exit(&dm2sp->ms_lock);
1159*25cf1a30Sjl }
1160*25cf1a30Sjl 
1161*25cf1a30Sjl /*
1162*25cf1a30Sjl  * dm2s_wq_timeout - Timeout callback for the write.
1163*25cf1a30Sjl  *
1164*25cf1a30Sjl  * It simply enables write side queue so that the service procedure
1165*25cf1a30Sjl  * can retry the transmission operation.
1166*25cf1a30Sjl  */
1167*25cf1a30Sjl void
1168*25cf1a30Sjl dm2s_wq_timeout(void *arg)
1169*25cf1a30Sjl {
1170*25cf1a30Sjl 	dm2s_t *dm2sp = (dm2s_t *)arg;
1171*25cf1a30Sjl 
1172*25cf1a30Sjl 	DPRINTF(DBG_DRV, ("dm2s_wq_timeout: called\n"));
1173*25cf1a30Sjl 	mutex_enter(&dm2sp->ms_lock);
1174*25cf1a30Sjl 	dm2sp->ms_wq_timeoutid = 0;
1175*25cf1a30Sjl 	if (dm2sp->ms_wq != NULL) {
1176*25cf1a30Sjl 		qenable(dm2sp->ms_wq);
1177*25cf1a30Sjl 	}
1178*25cf1a30Sjl 	mutex_exit(&dm2sp->ms_lock);
1179*25cf1a30Sjl }
1180*25cf1a30Sjl 
1181*25cf1a30Sjl /*
1182*25cf1a30Sjl  * dm2s_prep_scatgath - Prepare scatter/gather elements for transmission
1183*25cf1a30Sjl  * of a streams message.
1184*25cf1a30Sjl  */
1185*25cf1a30Sjl static int
1186*25cf1a30Sjl dm2s_prep_scatgath(mblk_t *mp, uint32_t *numsg, mscat_gath_t *sgp, int maxsg)
1187*25cf1a30Sjl {
1188*25cf1a30Sjl 	uint32_t num = 0;
1189*25cf1a30Sjl 	mblk_t *tmp = mp;
1190*25cf1a30Sjl 
1191*25cf1a30Sjl 	while ((tmp != NULL) && (num < maxsg)) {
1192*25cf1a30Sjl 		sgp[num].msc_dptr = (caddr_t)tmp->b_rptr;
1193*25cf1a30Sjl 		sgp[num].msc_len = MBLKL(tmp);
1194*25cf1a30Sjl 		tmp = tmp->b_cont;
1195*25cf1a30Sjl 		num++;
1196*25cf1a30Sjl 	}
1197*25cf1a30Sjl 
1198*25cf1a30Sjl 	if (tmp != NULL) {
1199*25cf1a30Sjl 		/*
1200*25cf1a30Sjl 		 * Number of scatter/gather elements available are not
1201*25cf1a30Sjl 		 * enough, so lets pullup the msg.
1202*25cf1a30Sjl 		 */
1203*25cf1a30Sjl 		if (pullupmsg(mp, -1) != 1) {
1204*25cf1a30Sjl 			return (EAGAIN);
1205*25cf1a30Sjl 		}
1206*25cf1a30Sjl 		sgp[0].msc_dptr = (caddr_t)mp->b_rptr;
1207*25cf1a30Sjl 		sgp[0].msc_len = MBLKL(mp);
1208*25cf1a30Sjl 		num = 1;
1209*25cf1a30Sjl 	}
1210*25cf1a30Sjl 	*numsg = num;
1211*25cf1a30Sjl 	return (0);
1212*25cf1a30Sjl }
1213*25cf1a30Sjl 
1214*25cf1a30Sjl /*
1215*25cf1a30Sjl  * dm2s_timeout_val -- Return appropriate timeout value.
1216*25cf1a30Sjl  *
1217*25cf1a30Sjl  * A small timeout value is returned for EBUSY and EAGAIN cases. This is
1218*25cf1a30Sjl  * because the condition is expected to be recovered sooner.
1219*25cf1a30Sjl  *
1220*25cf1a30Sjl  * A larger timeout value is returned for ENOSPC case, as the condition
1221*25cf1a30Sjl  * depends on the peer to release buffer space.
1222*25cf1a30Sjl  * NOTE: there will also be an event(SCF_MB_SPACE) but a timeout is
1223*25cf1a30Sjl  * used for reliability purposes.
1224*25cf1a30Sjl  */
1225*25cf1a30Sjl static clock_t
1226*25cf1a30Sjl dm2s_timeout_val(int error)
1227*25cf1a30Sjl {
1228*25cf1a30Sjl 	clock_t tval;
1229*25cf1a30Sjl 
1230*25cf1a30Sjl 	ASSERT(error == EBUSY || error == ENOSPC || error == EAGAIN);
1231*25cf1a30Sjl 
1232*25cf1a30Sjl 	if (error == EBUSY || error == EAGAIN) {
1233*25cf1a30Sjl 		tval = DM2S_SM_TOUT;
1234*25cf1a30Sjl 	} else {
1235*25cf1a30Sjl 		tval = DM2S_LG_TOUT;
1236*25cf1a30Sjl 	}
1237*25cf1a30Sjl 	return (drv_usectohz(tval));
1238*25cf1a30Sjl }
1239*25cf1a30Sjl 
1240*25cf1a30Sjl #ifdef DEBUG
1241*25cf1a30Sjl 
1242*25cf1a30Sjl static void
1243*25cf1a30Sjl dm2s_dump_bytes(char *str, uint32_t total_len,
1244*25cf1a30Sjl     uint32_t num_sg, mscat_gath_t *sgp)
1245*25cf1a30Sjl {
1246*25cf1a30Sjl 	int i, j;
1247*25cf1a30Sjl 	int nsg;
1248*25cf1a30Sjl 	int len, tlen = 0;
1249*25cf1a30Sjl 	mscat_gath_t *tp;
1250*25cf1a30Sjl 	uint8_t *datap;
1251*25cf1a30Sjl #define	BYTES_PER_LINE	20
1252*25cf1a30Sjl 	char bytestr[BYTES_PER_LINE * 3 + 1];
1253*25cf1a30Sjl 	uint32_t digest = 0;
1254*25cf1a30Sjl 
1255*25cf1a30Sjl 	if (!(dm2s_debug & DBG_MESG))
1256*25cf1a30Sjl 		return;
1257*25cf1a30Sjl 	ASSERT(num_sg != 0);
1258*25cf1a30Sjl 
1259*25cf1a30Sjl 	for (nsg = 0; (nsg < num_sg) && (tlen < total_len); nsg++) {
1260*25cf1a30Sjl 		tp = &sgp[nsg];
1261*25cf1a30Sjl 		datap = (uint8_t *)tp->msc_dptr;
1262*25cf1a30Sjl 		len = tp->msc_len;
1263*25cf1a30Sjl 		for (i = 0; i < len; i++) {
1264*25cf1a30Sjl 			digest += datap[i];
1265*25cf1a30Sjl 		}
1266*25cf1a30Sjl 		tlen += len;
1267*25cf1a30Sjl 	}
1268*25cf1a30Sjl 	sprintf(bytestr, "%s Packet: Size=%d  Digest=%d\n",
1269*25cf1a30Sjl 		str, total_len, digest);
1270*25cf1a30Sjl 	DTRACE_PROBE1(dm2s_dump_digest, unsigned char *, bytestr);
1271*25cf1a30Sjl 
1272*25cf1a30Sjl 	for (nsg = 0; (nsg < num_sg) && (tlen < total_len); nsg++) {
1273*25cf1a30Sjl 		tp = &sgp[nsg];
1274*25cf1a30Sjl 		datap = (uint8_t *)tp->msc_dptr;
1275*25cf1a30Sjl 		len = tp->msc_len;
1276*25cf1a30Sjl 		for (i = 0; i < len; ) {
1277*25cf1a30Sjl 			for (j = 0; (j < BYTES_PER_LINE) &&
1278*25cf1a30Sjl 			    (i < len); j++, i++) {
1279*25cf1a30Sjl 				sprintf(&bytestr[j * 3], "%02X ", datap[i]);
1280*25cf1a30Sjl 				digest += datap[i];
1281*25cf1a30Sjl 			}
1282*25cf1a30Sjl 			if (j != 0) {
1283*25cf1a30Sjl 				DTRACE_PROBE1(dm2s_dump, unsigned char *,
1284*25cf1a30Sjl 				    bytestr);
1285*25cf1a30Sjl 			}
1286*25cf1a30Sjl 		}
1287*25cf1a30Sjl 		tlen += i;
1288*25cf1a30Sjl 	}
1289*25cf1a30Sjl }
1290*25cf1a30Sjl 
1291*25cf1a30Sjl #endif	/* DEBUG */
1292