dm2s.c revision 7656:2621e50fdf4a
1271947Sdes/*
2271947Sdes * CDDL HEADER START
3271947Sdes *
4271947Sdes * The contents of this file are subject to the terms of the
5271947Sdes * Common Development and Distribution License (the "License").
6271947Sdes * You may not use this file except in compliance with the License.
7271947Sdes *
8271947Sdes * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9271947Sdes * or http://www.opensolaris.org/os/licensing.
10271947Sdes * See the License for the specific language governing permissions
11271947Sdes * and limitations under the License.
12271947Sdes *
13271947Sdes * When distributing Covered Code, include this CDDL HEADER in each
14271947Sdes * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15271947Sdes * If applicable, add the following below this CDDL HEADER, with the
16271947Sdes * fields enclosed by brackets "[]" replaced with your own identifying
17271947Sdes * information: Portions Copyright [yyyy] [name of copyright owner]
18271947Sdes *
19271947Sdes * CDDL HEADER END
20271947Sdes */
21271947Sdes/*
22255376Sdes * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23255376Sdes * Use is subject to license terms.
24255376Sdes */
25255376Sdes
26255376Sdes
27255376Sdes/*
28255376Sdes * DM2S - Domain side Mailbox to synchronous serial device driver.
29255376Sdes *
30255376Sdes * Description:
31255376Sdes * -----------
32255376Sdes * It is a streams driver which simulates a sync serial device on
33255376Sdes * top of a mailbox type of communication. That is, it sends/receives
34255376Sdes * frames as mailbox messages. The mailbox communication is provided
35255376Sdes * by another driver, which exports the mailbox interfaces.
36255376Sdes *
37255376Sdes * Synchronization:
38255376Sdes * ---------------
39255376Sdes * This driver uses streams perimeters to simplify the synchronization.
40255376Sdes * An inner perimeter D_MTPERMOD which protects the entire module,
41255376Sdes * that is only one thread exists inside the perimeter, is used. As
42255376Sdes * this driver supports only one instance and is not a high-performance
43255376Sdes * driver, D_MTPERMOD is highly suitable.
44255376Sdes *
45255376Sdes * All transmission and reception of frames is done inside the service
46255376Sdes * procedures so that all streams related operations are protected
47255376Sdes * by the perimeters.
48255376Sdes *
49236109Sdes * The mailbox event handler is the only asynchronous callback which
50236109Sdes * needs to be protected outside of the streams perimeters. This is
51236109Sdes * done using the module private lock('ms_lock');
52236109Sdes *
53236109Sdes */
54236109Sdes
55236109Sdes#include <sys/types.h>
56236109Sdes#include <sys/param.h>
57236109Sdes#include <sys/stream.h>
58236109Sdes#include <sys/cred.h>
59236109Sdes#include <sys/systm.h>
60236109Sdes#include <sys/sunddi.h>
61236109Sdes#include <sys/ddi.h>
62236109Sdes#include <sys/conf.h>
63236109Sdes#include <sys/modctl.h>
64236109Sdes#include <sys/mkdev.h>
65236109Sdes#include <sys/errno.h>
66236109Sdes#include <sys/debug.h>
67236109Sdes#include <sys/kbio.h>
68236109Sdes#include <sys/kmem.h>
69236109Sdes#include <sys/consdev.h>
70236109Sdes#include <sys/file.h>
71236109Sdes#include <sys/stropts.h>
72236109Sdes#include <sys/strsun.h>
73236109Sdes#include <sys/dlpi.h>
74236109Sdes#include <sys/stat.h>
75236109Sdes#include <sys/ser_sync.h>
76236109Sdes#include <sys/sysmacros.h>
77236109Sdes#include <sys/note.h>
78236109Sdes#include <sys/sdt.h>
79236109Sdes
80236109Sdes#include <sys/scfd/scfdscpif.h>
81236109Sdes#include <sys/dm2s.h>
82236109Sdes
83236109Sdes
84236109Sdes#define	DM2S_MODNAME	"dm2s"			/* Module name */
85236109Sdes#define	DM2S_TARGET_ID	0			/* Target ID of the peer */
86236109Sdes#define	DM2S_ID_NUM	0x4D53			/* 'M''S' */
87236109Sdes#define	DM2S_DEF_MTU	1504			/* Def. MTU size + PPP bytes */
88236109Sdes#define	DM2S_MAXPSZ	DM2S_DEF_MTU		/* Set it to the default MTU */
89236109Sdes#define	DM2S_LOWAT	(4 * 1024)		/* Low water mark */
90236109Sdes#define	DM2S_HIWAT	(12 * 1024)		/* High water mark */
91236109Sdes#define	DM2S_SM_TOUT	5000			/* Small timeout (5msec) */
92236109Sdes#define	DM2S_LG_TOUT	50000			/* Large timeout (50msec) */
93236109Sdes#define	DM2S_MB_TOUT	10000000		/* Mailbox timeout (10sec) */
94236109Sdes
95236109Sdes/*
96236109Sdes * Global variables
97228692Sdes */
98228692Sdesvoid		*dm2s_softstate = NULL;			/* Softstate pointer */
99228692Sdes
100228692Sdes
101228692Sdes/*
102228692Sdes * Prototypes for the module related functions.
103228692Sdes */
104228692Sdesint dm2s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
105228692Sdesint dm2s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
106228692Sdesint dm2s_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
107228692Sdes    void *arg, void **result);
108228692Sdes
109228692Sdes/*
110228692Sdes * Prototypes for the streams related functions.
111228692Sdes */
112228692Sdesint dm2s_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr);
113228692Sdesint dm2s_close(queue_t *rq, int flag, cred_t *cred);
114228692Sdesint dm2s_wput(queue_t *wq, mblk_t *mp);
115228692Sdesint dm2s_rsrv(queue_t *rq);
116228692Sdesint dm2s_wsrv(queue_t *wq);
117228692Sdes
118228692Sdes/*
119228692Sdes * Prototypes for the internal functions.
120228692Sdes */
121271947Sdesvoid dm2s_start(queue_t *wq, dm2s_t *dm2sp);
122228692Sdesvoid dm2s_event_handler(scf_event_t event, void *arg);
123174832Sdesint dm2s_transmit(queue_t *wq, mblk_t *mp, target_id_t target, mkey_t key);
124147455Sdesvoid dm2s_receive(dm2s_t *dm2sp);
125174832Sdesvoid dm2s_wq_timeout(void *arg);
126174832Sdesvoid dm2s_rq_timeout(void *arg);
127174832Sdesvoid dm2s_bufcall_rcv(void *arg);
128174832Sdesstatic clock_t dm2s_timeout_val(int error);
129174832Sdesstatic void dm2s_cleanup(dm2s_t *dm2sp);
130174832Sdesstatic int dm2s_mbox_init(dm2s_t *dm2sp);
131174832Sdesstatic void dm2s_mbox_fini(dm2s_t *dm2sp);
132174832Sdesstatic int dm2s_prep_scatgath(mblk_t *mp, uint32_t *numsg,
133174832Sdes    mscat_gath_t *sgp, int maxsg);
134174832Sdes
135174832Sdes#ifdef DEBUG
136174832Sdesuint32_t dm2s_debug = DBG_WARN;
137174832Sdes#endif /* DEBUG */
138174832Sdes
139174832Sdes
140174832Sdes/*
141174832Sdes * Streams and module related structures.
142174832Sdes */
143174832Sdesstruct module_info dm2s_module_info = {
144174832Sdes	DM2S_ID_NUM,		/* module ID number */
145174832Sdes	DM2S_MODNAME,		/* module name. */
146228692Sdes	0,			/* Minimum packet size (none) */
147174832Sdes	DM2S_MAXPSZ,		/* Maximum packet size (none) */
148147455Sdes	DM2S_HIWAT,		/* queue high water mark */
149147455Sdes	DM2S_LOWAT		/* queue low water mark */
150147455Sdes};
151147455Sdes
152147455Sdesstruct qinit dm2s_rinit = {
153147455Sdes	putq,			/* qi_putp */
154147455Sdes	dm2s_rsrv,		/* qi_srvp */
155147455Sdes	dm2s_open,		/* qi_qopen */
156147455Sdes	dm2s_close,		/* qi_qlcose */
157147455Sdes	NULL,			/* qi_qadmin */
158147455Sdes	&dm2s_module_info,	/* qi_minfo */
159141098Sdes	NULL			/* qi_mstat */
160141098Sdes};
161141098Sdes
162141098Sdesstruct qinit dm2s_winit = {
163141098Sdes	dm2s_wput,		/* qi_putp */
164141098Sdes	dm2s_wsrv,		/* qi_srvp */
165141098Sdes	NULL,			/* qi_qopen */
166141098Sdes	NULL,			/* qi_qlcose */
167141098Sdes	NULL,			/* qi_qadmin */
168141098Sdes	&dm2s_module_info,	/* qi_minfo */
169141098Sdes	NULL			/* qi_mstat */
170141098Sdes};
171141098Sdes
172141098Sdes
173141098Sdesstruct streamtab dm2s_streamtab = {
174141098Sdes	&dm2s_rinit,
175141098Sdes	&dm2s_winit,
176141098Sdes	NULL,
177141098Sdes	NULL
178125647Sdes};
179125647Sdes
180125647SdesDDI_DEFINE_STREAM_OPS(dm2s_ops, nulldev, nulldev, dm2s_attach,		\
181125647Sdes	dm2s_detach, nodev, dm2s_info, D_NEW | D_MP | D_MTPERMOD,	\
182125647Sdes	&dm2s_streamtab, ddi_quiesce_not_supported);
183125647Sdes
184125647Sdes
185125647Sdesstruct modldrv modldrv = {
186125647Sdes	&mod_driverops,
187117610Sdes	"OPL Mbox to Serial Driver",
188117610Sdes	&dm2s_ops
189117610Sdes};
190117610Sdes
191117610Sdesstruct modlinkage modlinkage = {
192117610Sdes	MODREV_1,
193117610Sdes	&modldrv,
194117610Sdes	NULL
195117610Sdes};
196117610Sdes
197117610Sdes
198117610Sdes/*
199117610Sdes * _init - Module's init routine.
200117610Sdes */
201117610Sdesint
202117610Sdes_init(void)
203117610Sdes{
204117610Sdes	int ret;
205117610Sdes
206117610Sdes	if (ddi_soft_state_init(&dm2s_softstate, sizeof (dm2s_t), 1) != 0) {
207117610Sdes		cmn_err(CE_WARN, "softstate initialization failed\n");
208115619Sdes		return (DDI_FAILURE);
209115619Sdes	}
210115619Sdes	if ((ret = mod_install(&modlinkage)) != 0) {
211115619Sdes		cmn_err(CE_WARN, "mod_install failed, error = %d", ret);
212115619Sdes		ddi_soft_state_fini(&dm2s_softstate);
213115619Sdes	}
214115619Sdes	return (ret);
215115619Sdes}
216115619Sdes
217115619Sdes/*
218115619Sdes * _fini - Module's fini routine.
219115619Sdes */
220115619Sdesint
221115619Sdes_fini(void)
222115619Sdes{
223115619Sdes	int ret;
224115619Sdes
225115619Sdes	if ((ret = mod_remove(&modlinkage)) != 0) {
226115619Sdes		return (ret);
227114536Sdes	}
228114536Sdes	ddi_soft_state_fini(&dm2s_softstate);
229114536Sdes	return (ret);
230114536Sdes}
231114536Sdes
232114536Sdes/*
233114536Sdes * _info - Module's info routine.
234114536Sdes */
235114536Sdesint
236114536Sdes_info(struct modinfo *modinfop)
237114536Sdes{
238114536Sdes	return (mod_info(&modlinkage, modinfop));
239114536Sdes}
240114536Sdes
241114536Sdes/*
242114536Sdes * dm2s_attach - Module's attach routine.
243114536Sdes */
244108794Sdesint
245108794Sdesdm2s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
246108794Sdes{
247108794Sdes	int instance;
248108794Sdes	dm2s_t *dm2sp;
249108794Sdes	char name[20];
250108794Sdes
251108794Sdes
252107937Sdes	instance = ddi_get_instance(dip);
253107937Sdes
254107937Sdes	/* Only one instance is supported. */
255107937Sdes	if (instance != 0) {
256107937Sdes		cmn_err(CE_WARN, "only one instance is supported");
257107937Sdes		return (DDI_FAILURE);
258107937Sdes	}
259107937Sdes
260107937Sdes	if (cmd != DDI_ATTACH) {
261107937Sdes		return (DDI_FAILURE);
262107937Sdes	}
263107937Sdes	if (ddi_soft_state_zalloc(dm2s_softstate, instance) != DDI_SUCCESS) {
264107937Sdes		cmn_err(CE_WARN, "softstate allocation failure");
265107937Sdes		return (DDI_FAILURE);
266107937Sdes	}
26791094Sdes	dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, instance);
26899158Sdes	if (dm2sp == NULL) {
26999158Sdes		ddi_soft_state_free(dm2s_softstate, instance);
27099158Sdes		cmn_err(CE_WARN, "softstate allocation failure.");
27199158Sdes		return (DDI_FAILURE);
27299158Sdes	}
27399158Sdes	dm2sp->ms_dip = dip;
27499158Sdes	dm2sp->ms_major = ddi_name_to_major(ddi_get_name(dip));
275107937Sdes	dm2sp->ms_ppa = instance;
27699158Sdes
27799158Sdes	/*
27899158Sdes	 * Get an interrupt block cookie corresponding to the
27999158Sdes	 * interrupt priority of the event handler.
28099158Sdes	 * Assert that the event priority is not re-defined to
28199158Sdes	 * some higher priority.
28299158Sdes	 */
28399158Sdes	/* LINTED */
28499158Sdes	ASSERT(SCF_EVENT_PRI == DDI_SOFTINT_LOW);
28599158Sdes	if (ddi_get_soft_iblock_cookie(dip, SCF_EVENT_PRI,
28699158Sdes	    &dm2sp->ms_ibcookie) != DDI_SUCCESS) {
28799158Sdes		cmn_err(CE_WARN, "ddi_get_soft_iblock_cookie failed.");
28899158Sdes		goto error;
28997241Sdes	}
29097241Sdes	mutex_init(&dm2sp->ms_lock, NULL, MUTEX_DRIVER,
29197241Sdes	    (void *)dm2sp->ms_ibcookie);
29297241Sdes
29397241Sdes	dm2sp->ms_clean |= DM2S_CLEAN_LOCK;
29497241Sdes	cv_init(&dm2sp->ms_wait, NULL, CV_DRIVER, NULL);
29597241Sdes	dm2sp->ms_clean |= DM2S_CLEAN_CV;
29697241Sdes
29797241Sdes	(void) sprintf(name, "%s%d", DM2S_MODNAME, instance);
29897241Sdes	if (ddi_create_minor_node(dip, name, S_IFCHR, instance,
29995908Sdes	    DDI_PSEUDO, NULL) == DDI_FAILURE) {
30095908Sdes		ddi_remove_minor_node(dip, NULL);
30195908Sdes		cmn_err(CE_WARN, "Device node creation failed.");
30295908Sdes		goto error;
30395908Sdes	}
30495908Sdes
30595908Sdes	dm2sp->ms_clean |= DM2S_CLEAN_NODE;
30695908Sdes	ddi_set_driver_private(dip, (caddr_t)dm2sp);
30795908Sdes	ddi_report_dev(dip);
30895908Sdes	return (DDI_SUCCESS);
30995908Sdeserror:
31095908Sdes	dm2s_cleanup(dm2sp);
31195908Sdes	return (DDI_FAILURE);
31295908Sdes}
31395908Sdes
31495908Sdes/*
31595908Sdes * dm2s_info - Module's info routine.
31695908Sdes */
31795908Sdes/*ARGSUSED*/
31895908Sdesint
31995908Sdesdm2s_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
32094670Sdes{
32194670Sdes	dm2s_t	*dm2sp;
32295908Sdes	minor_t	minor;
32395908Sdes	int	ret = DDI_FAILURE;
32495908Sdes
32594670Sdes	switch (infocmd) {
32694670Sdes	case DDI_INFO_DEVT2DEVINFO:
32794670Sdes		minor = getminor((dev_t)arg);
32894670Sdes		dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, minor);
32994670Sdes		if (dm2sp == NULL) {
33094670Sdes			*result = NULL;
33195908Sdes		} else {
33294670Sdes			*result = dm2sp->ms_dip;
33394670Sdes			ret = DDI_SUCCESS;
33494670Sdes		}
33594670Sdes		break;
33694670Sdes
33794209Sdes	case DDI_INFO_DEVT2INSTANCE:
33894209Sdes		minor = getminor((dev_t)arg);
33994209Sdes		*result = (void *)(uintptr_t)minor;
34094209Sdes		ret = DDI_SUCCESS;
34194209Sdes		break;
34294209Sdes
34394209Sdes	default:
34494209Sdes		break;
34594209Sdes	}
34694209Sdes	return (ret);
34794209Sdes}
34894209Sdes
34994209Sdes/*
35094209Sdes * dm2s_detach - Module's detach routine.
35194209Sdes */
35294209Sdesint
35394209Sdesdm2s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
35494209Sdes{
35594209Sdes	int instance;
35694209Sdes	dm2s_t *dm2sp;
35794209Sdes
35894209Sdes	if (cmd != DDI_DETACH) {
35994209Sdes		return (DDI_FAILURE);
36094209Sdes	}
36194209Sdes
36294209Sdes	instance = ddi_get_instance(dip);
36394209Sdes	dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, instance);
36494209Sdes	if (dm2sp == NULL) {
36594209Sdes		return (DDI_FAILURE);
36694209Sdes	}
36794209Sdes
368236109Sdes	mutex_enter(&dm2sp->ms_lock);
36991684Sdes
37092289Sdes	/* Check if the mailbox is still in use. */
37192289Sdes	if (dm2sp->ms_state & DM2S_MB_INITED) {
37292289Sdes		mutex_exit(&dm2sp->ms_lock);
37392289Sdes		cmn_err(CE_WARN, "Mailbox in use: Detach failed");
37492289Sdes		return (DDI_FAILURE);
37592289Sdes	}
37692289Sdes	mutex_exit(&dm2sp->ms_lock);
37792289Sdes	dm2s_cleanup(dm2sp);
37892289Sdes	return (DDI_SUCCESS);
37992289Sdes}
38092289Sdes
38192289Sdes/*
38292289Sdes * dm2s_open - Device open routine.
38392289Sdes *
38492289Sdes * Only one open supported. Clone open is not supported.
38594209Sdes */
38692289Sdes/* ARGSUSED */
38791684Sdesint
38891684Sdesdm2s_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr)
38991684Sdes{
39091684Sdes	dm2s_t *dm2sp;
39191684Sdes	int instance = getminor(*dev);
39291684Sdes	int ret = 0;
39391684Sdes
39491684Sdes	DPRINTF(DBG_DRV, ("dm2s_open: called\n"));
39591684Sdes	if (sflag == CLONEOPEN)	{
39691684Sdes		/* Clone open not supported */
39791684Sdes		DPRINTF(DBG_WARN, ("dm2s_open: clone open not supported\n"));
39891684Sdes		return (ENOTSUP);
39991684Sdes	}
40091684Sdes
40191684Sdes	if (rq->q_ptr != NULL) {
40291684Sdes		DPRINTF(DBG_WARN, ("dm2s_open: already opened\n"));
40391684Sdes		return (EBUSY);
40491684Sdes	}
40591684Sdes
40691684Sdes	if ((dm2sp = ddi_get_soft_state(dm2s_softstate, instance)) == NULL) {
407236109Sdes		DPRINTF(DBG_WARN, ("dm2s_open: instance not found\n"));
40891100Sdes		return (ENODEV);
40991100Sdes	}
41091100Sdes
41191100Sdes	mutex_enter(&dm2sp->ms_lock);
41291100Sdes	if (dm2sp->ms_state & DM2S_OPENED) {
41391100Sdes		/* Only one open supported */
41491100Sdes		mutex_exit(&dm2sp->ms_lock);
41591100Sdes		DPRINTF(DBG_WARN, ("dm2s_open: already opened\n"));
41691100Sdes		return (EBUSY);
41791100Sdes	}
41891100Sdes
41991100Sdes	dm2sp->ms_state |= DM2S_OPENED;
42091100Sdes	/* Initialize the mailbox. */
42191100Sdes	if ((ret = dm2s_mbox_init(dm2sp)) != 0) {
42291100Sdes		dm2sp->ms_state = 0;
42391100Sdes		mutex_exit(&dm2sp->ms_lock);
42491100Sdes		return (ret);
42591100Sdes	}
42691100Sdes	rq->q_ptr = WR(rq)->q_ptr = (void *)dm2sp;
42791100Sdes	dm2sp->ms_rq = rq;
42891100Sdes	dm2sp->ms_wq = WR(rq);
42991100Sdes	mutex_exit(&dm2sp->ms_lock);
43091100Sdes
43191100Sdes	if (ret == 0) {
43291100Sdes		qprocson(rq);		/* now schedule our queue */
43391100Sdes	}
43491100Sdes	DPRINTF(DBG_DRV, ("dm2s_open: ret=%d\n", ret));
43591100Sdes	return (ret);
43691100Sdes}
437236109Sdes
43891097Sdes/*
43991097Sdes * dm2s_close - Device close routine.
44091097Sdes */
44191097Sdes/* ARGSUSED */
44291097Sdesint
44391097Sdesdm2s_close(queue_t *rq, int flag, cred_t *cred)
44491097Sdes{
44591097Sdes	dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr;
44691097Sdes
44791097Sdes	DPRINTF(DBG_DRV, ("dm2s_close: called\n"));
448236109Sdes	if (dm2sp == NULL) {
44991094Sdes		/* Already closed once */
45091094Sdes		return (ENODEV);
451	}
452
453	/* Close the lower layer first */
454	mutex_enter(&dm2sp->ms_lock);
455	(void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, MB_FLUSH_ALL);
456	dm2s_mbox_fini(dm2sp);
457	mutex_exit(&dm2sp->ms_lock);
458
459	/*
460	 * Now we can assume that no asynchronous callbacks exist.
461	 * Poison the stream head so that we can't be pushed again.
462	 */
463	(void) putnextctl(rq, M_HANGUP);
464	qprocsoff(rq);
465	if (dm2sp->ms_rbufcid != 0) {
466		qunbufcall(rq, dm2sp->ms_rbufcid);
467		dm2sp->ms_rbufcid = 0;
468	}
469	if (dm2sp->ms_rq_timeoutid != 0) {
470		DTRACE_PROBE1(dm2s_rqtimeout__cancel, dm2s_t, dm2sp);
471		(void) quntimeout(dm2sp->ms_rq, dm2sp->ms_rq_timeoutid);
472		dm2sp->ms_rq_timeoutid = 0;
473	}
474	if (dm2sp->ms_wq_timeoutid != 0) {
475		DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp);
476		(void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid);
477		dm2sp->ms_wq_timeoutid = 0;
478	}
479	/*
480	 * Now we can really mark it closed.
481	 */
482	mutex_enter(&dm2sp->ms_lock);
483	dm2sp->ms_rq = dm2sp->ms_wq = NULL;
484	dm2sp->ms_state &= ~DM2S_OPENED;
485	mutex_exit(&dm2sp->ms_lock);
486
487	rq->q_ptr = WR(rq)->q_ptr = NULL;
488	(void) qassociate(rq, -1);
489	DPRINTF(DBG_DRV, ("dm2s_close: successfully closed\n"));
490	return (0);
491}
492
493/*
494 * dm2s_rsrv - Streams read side service procedure.
495 *
496 * All messages are received in the service procedure
497 * only. This is done to simplify the streams synchronization.
498 */
499int
500dm2s_rsrv(queue_t *rq)
501{
502	mblk_t *mp;
503	dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr;
504
505	DPRINTF(DBG_DRV, ("dm2s_rsrv: called\n"));
506	ASSERT(dm2sp != NULL);
507	mutex_enter(&dm2sp->ms_lock);
508
509	/* Receive if there are any messages waiting in the mailbox. */
510	dm2s_receive(dm2sp);
511	mutex_exit(&dm2sp->ms_lock);
512
513	/* Send the received messages up the stream. */
514	while ((mp = getq(rq)) != NULL) {
515		if (canputnext(rq)) {
516			putnext(rq, mp);
517		} else {
518			putbq(rq, mp);
519			break;
520		}
521	}
522	DPRINTF(DBG_DRV, ("dm2s_rsrv: return\n"));
523	return (0);
524}
525
526/*
527 * dm2s_wsrv - Streams write side service procedure.
528 *
529 * All messages are transmitted in the service procedure
530 * only. This is done to simplify the streams synchronization.
531 */
532int
533dm2s_wsrv(queue_t *wq)
534{
535	dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr;
536
537	DPRINTF(DBG_DRV, ("dm2s_wsrv: called\n"));
538	ASSERT(dm2sp != NULL);
539	/* Lets cancel any timeouts waiting to be scheduled. */
540	if (dm2sp->ms_wq_timeoutid != 0) {
541		DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp);
542		(void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid);
543		dm2sp->ms_wq_timeoutid = 0;
544	}
545	mutex_enter(&dm2sp->ms_lock);
546	dm2s_start(wq, dm2sp);
547	mutex_exit(&dm2sp->ms_lock);
548	DPRINTF(DBG_DRV, ("dm2s_wsrv: return\n"));
549	return (0);
550}
551
552/*
553 * dm2s_wput - Streams write side put routine.
554 *
555 * All M_DATA messages are queued so that they are transmitted in
556 * the service procedure. This is done to simplify the streams
557 * synchronization. Other messages are handled appropriately.
558 */
559int
560dm2s_wput(queue_t *wq, mblk_t *mp)
561{
562	dm2s_t	*dm2sp = (dm2s_t *)wq->q_ptr;
563
564	DPRINTF(DBG_DRV, ("dm2s_wput: called\n"));
565	if (dm2sp == NULL) {
566		return (ENODEV);   /* Can't happen. */
567	}
568
569	switch (mp->b_datap->db_type) {
570	case (M_DATA):
571		DPRINTF(DBG_DRV, ("dm2s_wput: M_DATA message\n"));
572		while (mp->b_wptr == mp->b_rptr) {
573			mblk_t *mp1;
574
575			mp1 = unlinkb(mp);
576			freemsg(mp);
577			mp = mp1;
578			if (mp == NULL) {
579				return (0);
580			}
581		}
582
583		/*
584		 * Simply queue the message and handle it in the service
585		 * procedure.
586		 */
587		(void) putq(wq, mp);
588		qenable(wq);
589		return (0);
590
591	case (M_PROTO):
592		DPRINTF(DBG_DRV, ("dm2s_wput: M_PROTO message\n"));
593		/* We don't expect this */
594		mp->b_datap->db_type = M_ERROR;
595		mp->b_rptr = mp->b_wptr = mp->b_datap->db_base;
596		*mp->b_wptr++ = EPROTO;
597		qreply(wq, mp);
598		return (EINVAL);
599
600	case (M_IOCTL):
601		DPRINTF(DBG_DRV, ("dm2s_wput: M_IOCTL message\n"));
602		if (MBLKL(mp) < sizeof (struct iocblk)) {
603			freemsg(mp);
604			return (0);
605		}
606		/*
607		 * No ioctls required to be supported by this driver, so
608		 * return EINVAL for all ioctls.
609		 */
610		miocnak(wq, mp, 0, EINVAL);
611		break;
612
613	case (M_CTL):
614		DPRINTF(DBG_DRV, ("dm2s_wput: M_CTL message\n"));
615		/*
616		 * No M_CTL messages need to supported by this driver,
617		 * so simply ignore them.
618		 */
619		freemsg(mp);
620		break;
621
622	case (M_FLUSH):
623		DPRINTF(DBG_DRV, (
624		    "dm2s_wput: M_FLUSH message 0x%X\n", *mp->b_rptr));
625		if (*mp->b_rptr & FLUSHW) {	/* Flush write-side */
626			(void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key,
627			    MB_FLUSH_SEND);
628			flushq(wq, FLUSHDATA);
629			*mp->b_rptr &= ~FLUSHW;
630		}
631		if (*mp->b_rptr & FLUSHR) {
632			(void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key,
633			    MB_FLUSH_RECEIVE);
634			flushq(RD(wq), FLUSHDATA);
635			qreply(wq, mp);
636		} else {
637			freemsg(mp);
638		}
639		break;
640
641	default:
642		DPRINTF(DBG_DRV, ("dm2s_wput: UNKNOWN message\n"));
643		freemsg(mp);
644
645	}
646	return (0);
647}
648
649/*
650 * dm2s_cleanup - Cleanup routine.
651 */
652static void
653dm2s_cleanup(dm2s_t *dm2sp)
654{
655	char name[20];
656
657	DPRINTF(DBG_DRV, ("dm2s_cleanup: called\n"));
658	ASSERT(dm2sp != NULL);
659	if (dm2sp->ms_clean & DM2S_CLEAN_NODE) {
660		(void) sprintf(name, "%s%d", DM2S_MODNAME, dm2sp->ms_ppa);
661		ddi_remove_minor_node(dm2sp->ms_dip, name);
662	}
663	if (dm2sp->ms_clean & DM2S_CLEAN_LOCK)
664		mutex_destroy(&dm2sp->ms_lock);
665	if (dm2sp->ms_clean & DM2S_CLEAN_CV)
666		cv_destroy(&dm2sp->ms_wait);
667	ddi_set_driver_private(dm2sp->ms_dip, NULL);
668	ddi_soft_state_free(dm2s_softstate, dm2sp->ms_ppa);
669}
670
671/*
672 * dm2s_mbox_init - Mailbox specific initialization.
673 */
674static int
675dm2s_mbox_init(dm2s_t *dm2sp)
676{
677	int ret;
678	clock_t tout;
679
680	ASSERT(MUTEX_HELD(&dm2sp->ms_lock));
681	dm2sp->ms_target = DM2S_TARGET_ID;
682	dm2sp->ms_key = DSCP_KEY;
683	dm2sp->ms_state &= ~DM2S_MB_INITED;
684
685	/* Iterate until mailbox gets connected */
686	while (!(dm2sp->ms_state & DM2S_MB_CONN)) {
687		DPRINTF(DBG_MBOX, ("dm2s_mbox_init: calling mb_init\n"));
688		ret = scf_mb_init(dm2sp->ms_target, dm2sp->ms_key,
689		    dm2s_event_handler, (void *)dm2sp);
690		DPRINTF(DBG_MBOX, ("dm2s_mbox_init: mb_init ret=%d\n", ret));
691
692		if (ret != 0) {
693			DPRINTF(DBG_MBOX,
694			    ("dm2s_mbox_init: failed ret =%d\n", ret));
695			DTRACE_PROBE1(dm2s_mbox_fail, int, ret);
696		} else {
697			dm2sp->ms_state |= DM2S_MB_INITED;
698
699			/* Block until the mailbox is ready to communicate. */
700			while (!(dm2sp->ms_state &
701			    (DM2S_MB_CONN | DM2S_MB_DISC))) {
702
703				if (cv_wait_sig(&dm2sp->ms_wait,
704				    &dm2sp->ms_lock) <= 0) {
705					/* interrupted */
706					ret = EINTR;
707					break;
708				}
709			}
710		}
711
712		if ((ret != 0) || (dm2sp->ms_state & DM2S_MB_DISC)) {
713
714			if (dm2sp->ms_state & DM2S_MB_INITED) {
715				(void) scf_mb_fini(dm2sp->ms_target,
716				    dm2sp->ms_key);
717			}
718			if (dm2sp->ms_state & DM2S_MB_DISC) {
719				DPRINTF(DBG_WARN,
720				    ("dm2s_mbox_init: mbox DISC_ERROR\n"));
721				DTRACE_PROBE1(dm2s_mbox_fail,
722				    int, DM2S_MB_DISC);
723			}
724
725			dm2sp->ms_state &= ~(DM2S_MB_INITED | DM2S_MB_DISC |
726			    DM2S_MB_CONN);
727
728			if (ret == EINTR) {
729				return (ret);
730			}
731
732			/*
733			 * If there was failure, then wait for
734			 * DM2S_MB_TOUT secs and retry again.
735			 */
736
737			DPRINTF(DBG_MBOX, ("dm2s_mbox_init: waiting...\n"));
738			tout = ddi_get_lbolt() + drv_usectohz(DM2S_MB_TOUT);
739			ret = cv_timedwait_sig(&dm2sp->ms_wait,
740			    &dm2sp->ms_lock, tout);
741			if (ret == 0) {
742				/* if interrupted, return immediately. */
743				DPRINTF(DBG_MBOX,
744				    ("dm2s_mbox_init: interrupted\n"));
745				return (EINTR);
746			}
747		}
748	}
749
750	/*
751	 * Obtain the max size of a single message.
752	 * NOTE: There is no mechanism to update the
753	 * upperlayers dynamically, so we expect this
754	 * size to be atleast the default MTU size.
755	 */
756	ret = scf_mb_ctrl(dm2sp->ms_target, dm2sp->ms_key,
757	    SCF_MBOP_MAXMSGSIZE, &dm2sp->ms_mtu);
758
759	if ((ret == 0) && (dm2sp->ms_mtu < DM2S_DEF_MTU)) {
760		cmn_err(CE_WARN, "Max message size expected >= %d "
761		    "but found %d\n", DM2S_DEF_MTU, dm2sp->ms_mtu);
762		ret = EIO;
763	}
764
765	if (ret != 0) {
766		dm2sp->ms_state &= ~DM2S_MB_INITED;
767		(void) scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key);
768	}
769	DPRINTF(DBG_MBOX, ("dm2s_mbox_init: mb_init ret=%d\n", ret));
770	return (ret);
771}
772
773/*
774 * dm2s_mbox_fini - Mailbox de-initialization.
775 */
776static void
777dm2s_mbox_fini(dm2s_t *dm2sp)
778{
779	int ret;
780
781	ASSERT(dm2sp != NULL);
782	if (dm2sp->ms_state & DM2S_MB_INITED) {
783		DPRINTF(DBG_MBOX, ("dm2s_mbox_fini: calling mb_fini\n"));
784		ret =  scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key);
785		if (ret != 0) {
786			cmn_err(CE_WARN,
787			    "Failed to close the Mailbox error =%d", ret);
788		}
789		DPRINTF(DBG_MBOX, ("dm2s_mbox_fini: mb_fini ret=%d\n", ret));
790		dm2sp->ms_state &= ~(DM2S_MB_INITED |DM2S_MB_CONN |
791		    DM2S_MB_DISC);
792	}
793}
794
795/*
796 * dm2s_event_handler - Mailbox event handler.
797 */
798void
799dm2s_event_handler(scf_event_t event, void *arg)
800{
801	dm2s_t *dm2sp = (dm2s_t *)arg;
802	queue_t	*rq;
803
804	ASSERT(dm2sp != NULL);
805	mutex_enter(&dm2sp->ms_lock);
806	if (!(dm2sp->ms_state & DM2S_MB_INITED)) {
807		/*
808		 * Ignore all events if the state flag indicates that the
809		 * mailbox not initialized, this may happen during the close.
810		 */
811		mutex_exit(&dm2sp->ms_lock);
812		DPRINTF(DBG_MBOX,
813		    ("Event(0x%X) received - Mailbox not inited\n", event));
814		return;
815	}
816	switch (event) {
817	case SCF_MB_CONN_OK:
818		/*
819		 * Now the mailbox is ready to use, lets wake up
820		 * any one waiting for this event.
821		 */
822		dm2sp->ms_state |= DM2S_MB_CONN;
823		cv_broadcast(&dm2sp->ms_wait);
824		DPRINTF(DBG_MBOX, ("Event received = CONN_OK\n"));
825		break;
826
827	case SCF_MB_MSG_DATA:
828		if (!DM2S_MBOX_READY(dm2sp)) {
829			DPRINTF(DBG_MBOX,
830			    ("Event(MSG_DATA) received - Mailbox not READY\n"));
831			break;
832		}
833		/*
834		 * A message is available in the mailbox.
835		 * Lets enable the read service procedure
836		 * to receive this message.
837		 */
838		if (dm2sp->ms_rq != NULL) {
839			qenable(dm2sp->ms_rq);
840		}
841		DPRINTF(DBG_MBOX, ("Event received = MSG_DATA\n"));
842		break;
843
844	case SCF_MB_SPACE:
845		if (!DM2S_MBOX_READY(dm2sp)) {
846			DPRINTF(DBG_MBOX,
847			    ("Event(MB_SPACE) received - Mailbox not READY\n"));
848			break;
849		}
850
851		/*
852		 * Now the mailbox is ready to transmit, lets
853		 * schedule the write service procedure.
854		 */
855		if (dm2sp->ms_wq != NULL) {
856			qenable(dm2sp->ms_wq);
857		}
858		DPRINTF(DBG_MBOX, ("Event received = MB_SPACE\n"));
859		break;
860	case SCF_MB_DISC_ERROR:
861		dm2sp->ms_state |= DM2S_MB_DISC;
862		if (dm2sp->ms_state & DM2S_MB_CONN) {
863			/*
864			 * If it was previously connected,
865			 * then send a hangup message.
866			 */
867			rq = dm2sp->ms_rq;
868			if (rq != NULL) {
869				mutex_exit(&dm2sp->ms_lock);
870				/*
871				 * Send a hangup message to indicate
872				 * disconnect event.
873				 */
874				(void) putctl(rq, M_HANGUP);
875				DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp);
876				mutex_enter(&dm2sp->ms_lock);
877			}
878		} else {
879			/*
880			 * Signal if the open is waiting for a
881			 * connection.
882			 */
883			cv_broadcast(&dm2sp->ms_wait);
884		}
885		DPRINTF(DBG_MBOX, ("Event received = DISC_ERROR\n"));
886		break;
887	default:
888		cmn_err(CE_WARN, "Unexpected event received\n");
889		break;
890	}
891	mutex_exit(&dm2sp->ms_lock);
892}
893
894/*
895 * dm2s_start - Start transmission function.
896 *
897 * Send all queued messages. If the mailbox is busy, then
898 * start a timeout as a polling mechanism. The timeout is useful
899 * to not rely entirely on the SCF_MB_SPACE event.
900 */
901void
902dm2s_start(queue_t *wq, dm2s_t *dm2sp)
903{
904	mblk_t *mp;
905	int ret;
906
907	DPRINTF(DBG_DRV, ("dm2s_start: called\n"));
908	ASSERT(dm2sp != NULL);
909	ASSERT(MUTEX_HELD(&dm2sp->ms_lock));
910
911	while ((mp = getq(wq)) != NULL) {
912		switch (mp->b_datap->db_type) {
913
914		case M_DATA:
915			ret = dm2s_transmit(wq, mp, dm2sp->ms_target,
916			    dm2sp->ms_key);
917			if (ret == EBUSY || ret == ENOSPC || ret == EAGAIN) {
918				DPRINTF(DBG_MBOX,
919				    ("dm2s_start: recoverable err=%d\n", ret));
920				/*
921				 * Start a timeout to retry again.
922				 */
923				if (dm2sp->ms_wq_timeoutid == 0) {
924					DTRACE_PROBE1(dm2s_wqtimeout__start,
925					    dm2s_t, dm2sp);
926					dm2sp->ms_wq_timeoutid = qtimeout(wq,
927					    dm2s_wq_timeout, (void *)dm2sp,
928					    dm2s_timeout_val(ret));
929				}
930				return;
931			} else if (ret != 0) {
932				mutex_exit(&dm2sp->ms_lock);
933				/*
934				 * An error occurred with the transmission,
935				 * flush pending messages and initiate a
936				 * hangup.
937				 */
938				flushq(wq, FLUSHDATA);
939				(void) putnextctl(RD(wq), M_HANGUP);
940				DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp);
941				DPRINTF(DBG_WARN,
942				    ("dm2s_start: hangup transmit err=%d\n",
943				    ret));
944				mutex_enter(&dm2sp->ms_lock);
945			}
946			break;
947		default:
948			/*
949			 * At this point, we don't expect any other messages.
950			 */
951			freemsg(mp);
952			break;
953		}
954	}
955}
956
957/*
958 * dm2s_receive - Read all messages from the mailbox.
959 *
960 * This function is called from the read service procedure, to
961 * receive the messages awaiting in the mailbox.
962 */
963void
964dm2s_receive(dm2s_t *dm2sp)
965{
966	queue_t	*rq = dm2sp->ms_rq;
967	mblk_t	*mp;
968	int	ret;
969	uint32_t len;
970
971	DPRINTF(DBG_DRV, ("dm2s_receive: called\n"));
972	ASSERT(dm2sp != NULL);
973	ASSERT(MUTEX_HELD(&dm2sp->ms_lock));
974	if (rq == NULL) {
975		return;
976	}
977	/*
978	 * As the number of messages in the mailbox are pretty limited,
979	 * it is safe to process all messages in one loop.
980	 */
981	while (DM2S_MBOX_READY(dm2sp) && ((ret = scf_mb_canget(dm2sp->ms_target,
982	    dm2sp->ms_key, &len)) == 0)) {
983		DPRINTF(DBG_MBOX, ("dm2s_receive: mb_canget len=%d\n", len));
984		if (len == 0) {
985			break;
986		}
987		mp = allocb(len, BPRI_MED);
988		if (mp == NULL) {
989			DPRINTF(DBG_WARN, ("dm2s_receive: allocb failed\n"));
990			/*
991			 * Start a bufcall so that we can retry again
992			 * when memory becomes available.
993			 */
994			dm2sp->ms_rbufcid = qbufcall(rq, len, BPRI_MED,
995			    dm2s_bufcall_rcv, dm2sp);
996			if (dm2sp->ms_rbufcid == 0) {
997				DPRINTF(DBG_WARN,
998				    ("dm2s_receive: qbufcall failed\n"));
999				/*
1000				 * if bufcall fails, start a timeout to
1001				 * initiate a re-try after some time.
1002				 */
1003				DTRACE_PROBE1(dm2s_rqtimeout__start,
1004				    dm2s_t, dm2sp);
1005				dm2sp->ms_rq_timeoutid = qtimeout(rq,
1006				    dm2s_rq_timeout, (void *)dm2sp,
1007				    drv_usectohz(DM2S_SM_TOUT));
1008			}
1009			break;
1010		}
1011
1012		/*
1013		 * Only a single scatter/gather element is enough here.
1014		 */
1015		dm2sp->ms_sg_rcv.msc_dptr = (caddr_t)mp->b_wptr;
1016		dm2sp->ms_sg_rcv.msc_len = len;
1017		DPRINTF(DBG_MBOX, ("dm2s_receive: calling getmsg\n"));
1018		ret = scf_mb_getmsg(dm2sp->ms_target, dm2sp->ms_key, len, 1,
1019		    &dm2sp->ms_sg_rcv, 0);
1020		DPRINTF(DBG_MBOX, ("dm2s_receive: getmsg ret=%d\n", ret));
1021		if (ret != 0) {
1022			freemsg(mp);
1023			break;
1024		}
1025		DMPBYTES("dm2s: Getmsg: ", len, 1, &dm2sp->ms_sg_rcv);
1026		mp->b_wptr += len;
1027		/*
1028		 * Queue the messages in the rq, so that the service
1029		 * procedure handles sending the messages up the stream.
1030		 */
1031		putq(rq, mp);
1032	}
1033
1034	if ((!DM2S_MBOX_READY(dm2sp)) || (ret != ENOMSG && ret != EMSGSIZE)) {
1035		/*
1036		 * Some thing went wrong, flush pending messages
1037		 * and initiate a hangup.
1038		 * Note: flushing the wq initiates a faster close.
1039		 */
1040		mutex_exit(&dm2sp->ms_lock);
1041		flushq(WR(rq), FLUSHDATA);
1042		(void) putnextctl(rq, M_HANGUP);
1043		DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp);
1044		mutex_enter(&dm2sp->ms_lock);
1045		DPRINTF(DBG_WARN, ("dm2s_receive: encountered unknown "
1046		    "condition - hangup ret=%d\n", ret));
1047	}
1048}
1049
1050/*
1051 * dm2s_transmit - Transmit a message.
1052 */
1053int
1054dm2s_transmit(queue_t *wq, mblk_t *mp, target_id_t target, mkey_t key)
1055{
1056	dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr;
1057	int ret;
1058	uint32_t len;
1059	uint32_t numsg;
1060
1061	DPRINTF(DBG_DRV, ("dm2s_transmit: called\n"));
1062	ASSERT(dm2sp != NULL);
1063	ASSERT(MUTEX_HELD(&dm2sp->ms_lock));
1064	/*
1065	 * Free the message if the mailbox is not in the connected state.
1066	 */
1067	if (!DM2S_MBOX_READY(dm2sp)) {
1068		DPRINTF(DBG_MBOX, ("dm2s_transmit: mailbox not ready yet\n"));
1069		freemsg(mp);
1070		return (EIO);
1071	}
1072
1073	len = msgdsize(mp);
1074	if (len > dm2sp->ms_mtu) {
1075		/*
1076		 * Size is too big to send, free the message.
1077		 */
1078		DPRINTF(DBG_MBOX, ("dm2s_transmit: message too large\n"));
1079		DTRACE_PROBE2(dm2s_msg_too_big, dm2s_t, dm2sp, uint32_t, len);
1080		freemsg(mp);
1081		return (0);
1082	}
1083
1084	if ((ret = dm2s_prep_scatgath(mp, &numsg, dm2sp->ms_sg_tx,
1085	    DM2S_MAX_SG)) != 0) {
1086		DPRINTF(DBG_MBOX, ("dm2s_transmit: prep_scatgath failed\n"));
1087		putbq(wq, mp);
1088		return (EAGAIN);
1089	}
1090	DPRINTF(DBG_MBOX, ("dm2s_transmit: calling mb_putmsg numsg=%d len=%d\n",
1091	    numsg, len));
1092	ret = scf_mb_putmsg(target, key, len, numsg, dm2sp->ms_sg_tx, 0);
1093	if (ret == EBUSY || ret == ENOSPC) {
1094		DPRINTF(DBG_MBOX,
1095		    ("dm2s_transmit: mailbox busy ret=%d\n", ret));
1096		if (++dm2sp->ms_retries >= DM2S_MAX_RETRIES) {
1097			/*
1098			 * If maximum retries are reached, then free the
1099			 * message.
1100			 */
1101			DPRINTF(DBG_MBOX,
1102			    ("dm2s_transmit: freeing msg after max retries\n"));
1103			DTRACE_PROBE2(dm2s_retry_fail, dm2s_t, dm2sp, int, ret);
1104			freemsg(mp);
1105			dm2sp->ms_retries = 0;
1106			return (0);
1107		}
1108		DTRACE_PROBE2(dm2s_mb_busy, dm2s_t, dm2sp, int, ret);
1109		/*
1110		 * Queue it back, so that we can retry again.
1111		 */
1112		putbq(wq, mp);
1113		return (ret);
1114	}
1115	DMPBYTES("dm2s: Putmsg: ", len, numsg, dm2sp->ms_sg_tx);
1116	dm2sp->ms_retries = 0;
1117	freemsg(mp);
1118	DPRINTF(DBG_DRV, ("dm2s_transmit: ret=%d\n", ret));
1119	return (ret);
1120}
1121
1122/*
1123 * dm2s_bufcall_rcv - Bufcall callaback routine.
1124 *
1125 * It simply enables read side queue so that the service procedure
1126 * can retry receive operation.
1127 */
1128void
1129dm2s_bufcall_rcv(void *arg)
1130{
1131	dm2s_t *dm2sp = (dm2s_t *)arg;
1132
1133	DPRINTF(DBG_DRV, ("dm2s_bufcall_rcv: called\n"));
1134	mutex_enter(&dm2sp->ms_lock);
1135	dm2sp->ms_rbufcid = 0;
1136	if (dm2sp->ms_rq != NULL) {
1137		qenable(dm2sp->ms_rq);
1138	}
1139	mutex_exit(&dm2sp->ms_lock);
1140}
1141
1142/*
1143 * dm2s_rq_timeout - Timeout callback for the read side.
1144 *
1145 * It simply enables read side queue so that the service procedure
1146 * can retry the receive operation.
1147 */
1148void
1149dm2s_rq_timeout(void *arg)
1150{
1151	dm2s_t *dm2sp = (dm2s_t *)arg;
1152
1153	DPRINTF(DBG_DRV, ("dm2s_rq_timeout: called\n"));
1154	mutex_enter(&dm2sp->ms_lock);
1155	dm2sp->ms_rq_timeoutid = 0;
1156	if (dm2sp->ms_rq != NULL) {
1157		qenable(dm2sp->ms_rq);
1158	}
1159	mutex_exit(&dm2sp->ms_lock);
1160}
1161
1162/*
1163 * dm2s_wq_timeout - Timeout callback for the write.
1164 *
1165 * It simply enables write side queue so that the service procedure
1166 * can retry the transmission operation.
1167 */
1168void
1169dm2s_wq_timeout(void *arg)
1170{
1171	dm2s_t *dm2sp = (dm2s_t *)arg;
1172
1173	DPRINTF(DBG_DRV, ("dm2s_wq_timeout: called\n"));
1174	mutex_enter(&dm2sp->ms_lock);
1175	dm2sp->ms_wq_timeoutid = 0;
1176	if (dm2sp->ms_wq != NULL) {
1177		qenable(dm2sp->ms_wq);
1178	}
1179	mutex_exit(&dm2sp->ms_lock);
1180}
1181
1182/*
1183 * dm2s_prep_scatgath - Prepare scatter/gather elements for transmission
1184 * of a streams message.
1185 */
1186static int
1187dm2s_prep_scatgath(mblk_t *mp, uint32_t *numsg, mscat_gath_t *sgp, int maxsg)
1188{
1189	uint32_t num = 0;
1190	mblk_t *tmp = mp;
1191
1192	while ((tmp != NULL) && (num < maxsg)) {
1193		sgp[num].msc_dptr = (caddr_t)tmp->b_rptr;
1194		sgp[num].msc_len = MBLKL(tmp);
1195		tmp = tmp->b_cont;
1196		num++;
1197	}
1198
1199	if (tmp != NULL) {
1200		/*
1201		 * Number of scatter/gather elements available are not
1202		 * enough, so lets pullup the msg.
1203		 */
1204		if (pullupmsg(mp, -1) != 1) {
1205			return (EAGAIN);
1206		}
1207		sgp[0].msc_dptr = (caddr_t)mp->b_rptr;
1208		sgp[0].msc_len = MBLKL(mp);
1209		num = 1;
1210	}
1211	*numsg = num;
1212	return (0);
1213}
1214
1215/*
1216 * dm2s_timeout_val -- Return appropriate timeout value.
1217 *
1218 * A small timeout value is returned for EBUSY and EAGAIN cases. This is
1219 * because the condition is expected to be recovered sooner.
1220 *
1221 * A larger timeout value is returned for ENOSPC case, as the condition
1222 * depends on the peer to release buffer space.
1223 * NOTE: there will also be an event(SCF_MB_SPACE) but a timeout is
1224 * used for reliability purposes.
1225 */
1226static clock_t
1227dm2s_timeout_val(int error)
1228{
1229	clock_t tval;
1230
1231	ASSERT(error == EBUSY || error == ENOSPC || error == EAGAIN);
1232
1233	if (error == EBUSY || error == EAGAIN) {
1234		tval = DM2S_SM_TOUT;
1235	} else {
1236		tval = DM2S_LG_TOUT;
1237	}
1238	return (drv_usectohz(tval));
1239}
1240
1241#ifdef DEBUG
1242
1243static void
1244dm2s_dump_bytes(char *str, uint32_t total_len,
1245    uint32_t num_sg, mscat_gath_t *sgp)
1246{
1247	int i, j;
1248	int nsg;
1249	int len, tlen = 0;
1250	mscat_gath_t *tp;
1251	uint8_t *datap;
1252#define	BYTES_PER_LINE	20
1253	char bytestr[BYTES_PER_LINE * 3 + 1];
1254	uint32_t digest = 0;
1255
1256	if (!(dm2s_debug & DBG_MESG))
1257		return;
1258	ASSERT(num_sg != 0);
1259
1260	for (nsg = 0; (nsg < num_sg) && (tlen < total_len); nsg++) {
1261		tp = &sgp[nsg];
1262		datap = (uint8_t *)tp->msc_dptr;
1263		len = tp->msc_len;
1264		for (i = 0; i < len; i++) {
1265			digest += datap[i];
1266		}
1267		tlen += len;
1268	}
1269	sprintf(bytestr, "%s Packet: Size=%d  Digest=%d\n",
1270	    str, total_len, digest);
1271	DTRACE_PROBE1(dm2s_dump_digest, unsigned char *, bytestr);
1272
1273	tlen = 0;
1274	for (nsg = 0; (nsg < num_sg) && (tlen < total_len); nsg++) {
1275		tp = &sgp[nsg];
1276		datap = (uint8_t *)tp->msc_dptr;
1277		len = tp->msc_len;
1278		for (i = 0; i < len; ) {
1279			for (j = 0; (j < BYTES_PER_LINE) &&
1280			    (i < len); j++, i++) {
1281				sprintf(&bytestr[j * 3], "%02X ", datap[i]);
1282				digest += datap[i];
1283			}
1284			if (j != 0) {
1285				DTRACE_PROBE1(dm2s_dump, unsigned char *,
1286				    bytestr);
1287			}
1288		}
1289		tlen += i;
1290	}
1291}
1292
1293#endif	/* DEBUG */
1294