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