xref: /titanic_41/usr/src/uts/common/io/pckt.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* from S5R4 1.10 */
32 
33 /*
34  * Description: The pckt module packetizes messages on
35  *		its read queue by pre-fixing an M_PROTO
36  *		message type to certain incoming messages.
37  */
38 
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/stream.h>
42 #include <sys/stropts.h>
43 #include <sys/kmem.h>
44 #include <sys/errno.h>
45 #include <sys/ddi.h>
46 #include <sys/sunddi.h>
47 #include <sys/debug.h>
48 
49 /*
50  * This is the loadable module wrapper.
51  */
52 #include <sys/conf.h>
53 #include <sys/modctl.h>
54 
55 static struct streamtab pcktinfo;
56 
57 /*
58  * Per queue instances are single-threaded since the q_ptr
59  * field of queues need to be shared among threads.
60  */
61 static struct fmodsw fsw = {
62 	"pckt",
63 	&pcktinfo,
64 	D_NEW | D_MTPERQ | D_MP
65 };
66 
67 /*
68  * Module linkage information for the kernel.
69  */
70 
71 static struct modlstrmod modlstrmod = {
72 	&mod_strmodops,
73 	"pckt module",
74 	&fsw
75 };
76 
77 static struct modlinkage modlinkage = {
78 	MODREV_1, &modlstrmod, NULL
79 };
80 
81 
82 int
_init(void)83 _init(void)
84 {
85 	return (mod_install(&modlinkage));
86 }
87 
88 int
_fini(void)89 _fini(void)
90 {
91 	return (mod_remove(&modlinkage));
92 }
93 
94 int
_info(struct modinfo * modinfop)95 _info(struct modinfo *modinfop)
96 {
97 	return (mod_info(&modlinkage, modinfop));
98 }
99 
100 static int	pcktopen(queue_t *, dev_t *, int, int, cred_t *);
101 static int	pcktclose(queue_t *, int, cred_t *);
102 static void	pcktrput(queue_t *, mblk_t *);
103 static void	pcktrsrv(queue_t *);
104 static void	pcktwput(queue_t *, mblk_t *);
105 static mblk_t	*add_ctl_info(queue_t *, mblk_t *);
106 static void	add_ctl_wkup(void *);
107 
108 
109 /*
110  * Stream module data structure definitions.
111  * Sits over the ptm module generally.
112  *
113  * Read side flow control strategy: Since we may be putting messages on
114  * the read q due to allocb failures, these failures must get
115  * reflected fairly quickly to the module below us.
116  * No sense in piling on messages in times of memory shortage.
117  * Further, for the case of upper level flow control, there is no
118  * compelling reason to have more buffering in this module.
119  * Thus use a hi-water mark of one.
120  * This module imposes no max packet size, there is no inherent reason
121  * in the code to do so.
122  */
123 static struct module_info pcktiinfo = {
124 	0x9898,					/* module id number */
125 	"pckt",					/* module name */
126 	0,					/* minimum packet size */
127 	INFPSZ,					/* maximum packet size */
128 	1,					/* hi-water mark */
129 	0					/* lo-water mark */
130 };
131 
132 /*
133  * Write side flow control strategy: There is no write service procedure.
134  * The write put function is pass thru, thus there is no reason to have any
135  * limits on the maximum packet size.
136  */
137 static struct module_info pcktoinfo = {
138 	0x9898,					/* module id number */
139 	"pckt",					/* module name */
140 	0,					/* minimum packet size */
141 	INFPSZ,					/* maximum packet size */
142 	0,					/* hi-water mark */
143 	0					/* lo-water mark */
144 };
145 
146 static struct qinit pcktrinit = {
147 	(int (*)())pcktrput,
148 	(int (*)())pcktrsrv,
149 	pcktopen,
150 	pcktclose,
151 	NULL,
152 	&pcktiinfo,
153 	NULL
154 };
155 
156 static struct qinit pcktwinit = {
157 	(int (*)())pcktwput,
158 	NULL,
159 	NULL,
160 	NULL,
161 	NULL,
162 	&pcktoinfo,
163 	NULL
164 };
165 
166 static struct streamtab pcktinfo = {
167 	&pcktrinit,
168 	&pcktwinit,
169 	NULL,
170 	NULL
171 };
172 
173 
174 /*
175  * Per-instance state struct for the pckt module.
176  */
177 struct pckt_info {
178 	queue_t		*pi_qptr;		/* back pointer to q */
179 	bufcall_id_t	pi_bufcall_id;
180 #ifdef _MULTI_DATAMODEL
181 	model_t		model;
182 #endif /* _MULTI_DATAMODEL */
183 };
184 
185 /*
186  * Dummy qbufcall callback routine used by open and close.
187  * The framework will wake up qwait_sig when we return from
188  * this routine (as part of leaving the perimeters.)
189  * (The framework enters the perimeters before calling the qbufcall() callback
190  * and leaves the perimeters after the callback routine has executed. The
191  * framework performs an implicit wakeup of any thread in qwait/qwait_sig
192  * when it leaves the perimeter. See qwait(9E).)
193  */
194 /* ARGSUSED */
195 static void
dummy_callback(void * arg)196 dummy_callback(void *arg)
197 {}
198 
199 /*
200  * pcktopen - open routine gets called when the
201  *	    module gets pushed onto the stream.
202  */
203 /*ARGSUSED*/
204 static int
pcktopen(queue_t * q,dev_t * devp,int oflag,int sflag,cred_t * credp)205 pcktopen(
206 	queue_t *q,		/* pointer to the read side queue */
207 	dev_t   *devp,		/* pointer to stream tail's dev */
208 	int	oflag,		/* the user open(2) supplied flags */
209 	int	sflag,		/* open state flag */
210 	cred_t  *credp)		/* credentials */
211 {
212 	struct pckt_info	*pip;
213 	mblk_t			*mop; /* ptr to a setopts msg block */
214 	struct stroptions	*sop;
215 
216 	if (sflag != MODOPEN)
217 		return (EINVAL);
218 
219 	if (q->q_ptr != NULL) {
220 		/* It's already attached. */
221 		return (0);
222 	}
223 
224 	/*
225 	 * Allocate state structure.
226 	 */
227 	pip = kmem_alloc(sizeof (*pip), KM_SLEEP);
228 	bzero(pip, sizeof (*pip));
229 
230 #ifdef _MULTI_DATAMODEL
231 	pip->model = ddi_model_convert_from(get_udatamodel());
232 #endif /* _MULTI_DATAMODEL */
233 
234 	/*
235 	 * Cross-link.
236 	 */
237 	pip->pi_qptr = q;
238 	q->q_ptr = pip;
239 	WR(q)->q_ptr = pip;
240 
241 	qprocson(q);
242 
243 	/*
244 	 * Initialize an M_SETOPTS message to set up hi/lo water marks on
245 	 * stream head read queue.
246 	 */
247 
248 	while ((mop = allocb(sizeof (struct stroptions), BPRI_MED)) == NULL) {
249 		bufcall_id_t id = qbufcall(q, sizeof (struct stroptions),
250 		    BPRI_MED, dummy_callback, NULL);
251 		if (!qwait_sig(q)) {
252 			qunbufcall(q, id);
253 			kmem_free(pip, sizeof (*pip));
254 			qprocsoff(q);
255 			return (EINTR);
256 		}
257 		qunbufcall(q, id);
258 	}
259 
260 
261 	/*
262 	 * XXX: Should this module really control the hi/low water marks?
263 	 * Is there any reason in this code to do so?
264 	 */
265 	mop->b_datap->db_type = M_SETOPTS;
266 	mop->b_wptr += sizeof (struct stroptions);
267 	sop = (struct stroptions *)mop->b_rptr;
268 	sop->so_flags = SO_HIWAT | SO_LOWAT;
269 	sop->so_hiwat = 512;
270 	sop->so_lowat = 256;
271 
272 	/*
273 	 * Commit to the open and send the M_SETOPTS off to the stream head.
274 	 */
275 	putnext(q, mop);
276 
277 	return (0);
278 }
279 
280 
281 /*
282  * pcktclose - This routine gets called when the module
283  *	gets popped off of the stream.
284  */
285 
286 /*ARGSUSED*/
287 static int
pcktclose(queue_t * q,int flag,cred_t * credp)288 pcktclose(
289 	queue_t *q,	/* Pointer to the read queue */
290 	int	flag,
291 	cred_t  *credp)
292 {
293 	struct pckt_info	*pip = (struct pckt_info *)q->q_ptr;
294 
295 	qprocsoff(q);
296 	/*
297 	 * Cancel outstanding qbufcall
298 	 */
299 	if (pip->pi_bufcall_id) {
300 		qunbufcall(q, pip->pi_bufcall_id);
301 		pip->pi_bufcall_id = 0;
302 	}
303 	/*
304 	 * Do not worry about msgs queued on the q, the framework
305 	 * will free them up.
306 	 */
307 	kmem_free(q->q_ptr, sizeof (struct pckt_info));
308 	q->q_ptr = WR(q)->q_ptr = NULL;
309 	return (0);
310 }
311 
312 /*
313  * pcktrput - Module read queue put procedure.
314  *	This is called from the module or
315  *	driver downstream.
316  */
317 static void
pcktrput(queue_t * q,mblk_t * mp)318 pcktrput(
319 	queue_t *q,	/* Pointer to the read queue */
320 	mblk_t *mp)	/* Pointer to the current message block */
321 {
322 	mblk_t		*pckt_msgp;
323 
324 
325 	switch (mp->b_datap->db_type) {
326 	case M_FLUSH:
327 		/*
328 		 * The PTS driver swaps the FLUSHR and FLUSHW flags
329 		 * we need to swap them back to reflect the actual
330 		 * slave side FLUSH mode.
331 		 */
332 		if ((*mp->b_rptr & FLUSHRW) != FLUSHRW)
333 			if ((*mp->b_rptr & FLUSHRW) == FLUSHR)
334 				*mp->b_rptr = FLUSHW;
335 			else if ((*mp->b_rptr & FLUSHRW) == FLUSHW)
336 				*mp->b_rptr = FLUSHR;
337 
338 		pckt_msgp = copymsg(mp);
339 		if (*mp->b_rptr & FLUSHW) {
340 			/*
341 			 * In the packet model we are not allowing
342 			 * flushes of the master's stream head read
343 			 * side queue. This is because all packet
344 			 * state information is stored there and
345 			 * a flush could destroy this data before
346 			 * it is read.
347 			 */
348 			*mp->b_rptr = FLUSHW;
349 			putnext(q, mp);
350 		} else {
351 			/*
352 			 * Free messages that only flush the
353 			 * master's read queue.
354 			 */
355 			freemsg(mp);
356 		}
357 
358 		if (pckt_msgp == NULL)
359 			break;
360 
361 		mp = pckt_msgp;
362 		/*
363 		 * Prefix M_PROTO and putnext.
364 		 */
365 		goto prefix_head;
366 
367 	case M_DATA:
368 	case M_IOCTL:
369 	case M_PROTO:
370 		/*
371 		 * For non-priority messages, follow flow-control rules.
372 		 * Also, if there are messages on the q already, keep
373 		 * queueing them since they need to be processed in order.
374 		 */
375 		if (!canputnext(q) || (qsize(q) > 0)) {
376 			(void) putq(q, mp);
377 			break;
378 		}
379 		/* FALLTHROUGH */
380 
381 	/*
382 	 * For high priority messages, skip flow control checks.
383 	 */
384 	case M_PCPROTO:
385 	case M_READ:
386 	case M_STOP:
387 	case M_START:
388 	case M_STARTI:
389 	case M_STOPI:
390 prefix_head:
391 		/*
392 		 * Prefix an M_PROTO header to message and pass upstream.
393 		 */
394 		if ((mp = add_ctl_info(q, mp)) != NULL)
395 			putnext(q, mp);
396 		break;
397 
398 	default:
399 		/*
400 		 * For data messages, queue them back on the queue if
401 		 * there are messages on the queue already. This is
402 		 * done to preserve the order of messages.
403 		 * For high priority messages or for no messages on the
404 		 * q, simply putnext() and pass it on.
405 		 */
406 		if ((datamsg(mp->b_datap->db_type)) && (qsize(q) > 0))
407 			(void) putq(q, mp);
408 		else
409 			putnext(q, mp);
410 		break;
411 	}
412 }
413 
414 /*
415  * pcktrsrv - module read service procedure
416  * This function deals with messages left in the queue due to
417  *	(a) not enough memory to allocate the header M_PROTO message
418  *	(b) flow control reasons
419  * The function will attempt to get the messages off the queue and
420  * process them.
421  */
422 static void
pcktrsrv(queue_t * q)423 pcktrsrv(queue_t *q)
424 {
425 	mblk_t *mp;
426 
427 	while ((mp = getq(q)) != NULL) {
428 		if (!canputnext(q)) {
429 			/*
430 			 * For high priority messages, make sure there is no
431 			 * infinite loop. Disable the queue for this case.
432 			 * High priority messages get here only for buffer
433 			 * allocation failures. Thus the bufcall callout
434 			 * will reenable the q.
435 			 * XXX bug alert - nooenable will *not* prevent
436 			 * putbq of a hipri messages frm enabling the queue.
437 			 */
438 			if (!datamsg(mp->b_datap->db_type))
439 				noenable(q);
440 			(void) putbq(q, mp);
441 			return;
442 		}
443 
444 		/*
445 		 * M_FLUSH msgs may also be here if there was a memory
446 		 * failure.
447 		 */
448 		switch (mp->b_datap->db_type) {
449 		case M_FLUSH:
450 		case M_PROTO:
451 		case M_PCPROTO:
452 		case M_STOP:
453 		case M_START:
454 		case M_IOCTL:
455 		case M_DATA:
456 		case M_READ:
457 		case M_STARTI:
458 		case M_STOPI:
459 			/*
460 			 * Prefix an M_PROTO header to msg and pass upstream.
461 			 */
462 			if ((mp = add_ctl_info(q, mp)) == NULL) {
463 				/*
464 				 * Running into memory or flow ctl problems.
465 				 */
466 				return;
467 			}
468 			/* FALL THROUGH */
469 
470 		default:
471 			putnext(q, mp);
472 			break;
473 		}
474 	}
475 }
476 
477 /*
478  * pcktwput - Module write queue put procedure.
479  *	All messages are send downstream unchanged
480  */
481 
482 static void
pcktwput(queue_t * q,mblk_t * mp)483 pcktwput(
484 	queue_t *q,	/* Pointer to the read queue */
485 	mblk_t *mp)	/* Pointer to current message block */
486 {
487 	putnext(q, mp);
488 }
489 
490 #ifdef _MULTI_DATAMODEL
491 /*
492  * reallocb - copy the data block from the given message block into a new block.
493  * This function is used in case data block had another message block
494  * pointing to it (and hence we just copy this one data block).
495  *
496  * Returns new message block if successful. On failure it returns NULL.
497  * It also tries to do a qbufcall and if that also fails,
498  * it frees the message block.
499  */
500 static mblk_t *
pckt_reallocb(queue_t * q,mblk_t * mp)501 pckt_reallocb(
502 	queue_t *q,	/* Pointer to the read queue */
503 	mblk_t *mp	/* Pointer to the message block to be changed */
504 )
505 {
506 	mblk_t	*nmp;
507 
508 	ASSERT(mp->b_datap->db_ref >= 1);
509 
510 	/*
511 	 * No reallocation is needed if there is only one reference
512 	 * to this data block.
513 	 */
514 	if (mp->b_datap->db_ref == 1)
515 		return (mp);
516 
517 	if ((nmp = copyb(mp)) == NULL) {
518 		struct pckt_info	*pip = (struct pckt_info *)q->q_ptr;
519 
520 		noenable(q);
521 		if (pip->pi_bufcall_id = qbufcall(q, mp->b_wptr - mp->b_rptr,
522 		    BPRI_MED, add_ctl_wkup, q)) {
523 			/*
524 			 * Put the message back onto the q.
525 			 */
526 			(void) putq(q, mp);
527 		} else {
528 			/*
529 			 * Things are pretty bad and serious if bufcall fails!
530 			 * Drop the message in this case.
531 			 */
532 			freemsg(mp);
533 		}
534 		return ((mblk_t *)0);
535 	}
536 
537 	nmp->b_cont = mp->b_cont;
538 	freeb(mp);
539 	return (nmp);
540 }
541 #endif /* _MULTI_DATAMODEL */
542 
543 /*
544  * add_ctl_info: add message control information to in coming
545  * 	message.
546  */
547 static mblk_t *
add_ctl_info(queue_t * q,mblk_t * mp)548 add_ctl_info(
549 	queue_t *q,		/* pointer to the read queue */
550 	mblk_t	*mp)		/* pointer to the raw data input message */
551 {
552 	struct pckt_info	*pip = (struct pckt_info *)q->q_ptr;
553 	mblk_t	*bp;		/* pointer to the unmodified message block */
554 
555 	/*
556 	 * Waiting on space for previous message?
557 	 */
558 	if (pip->pi_bufcall_id) {
559 		/*
560 		 * Chain this message on to q for later processing.
561 		 */
562 		(void) putq(q, mp);
563 		return (NULL);
564 	}
565 
566 	/*
567 	 * Need to add the message block header as
568 	 * an M_PROTO type message.
569 	 */
570 	if ((bp = allocb(sizeof (char), BPRI_MED)) == (mblk_t *)NULL) {
571 
572 		/*
573 		 * There are two reasons to disable the q:
574 		 * (1) Flow control reasons should not wake up the q.
575 		 * (2) High priority messages will wakeup the q
576 		 *	immediately. Disallow this.
577 		 */
578 		noenable(q);
579 		if (pip->pi_bufcall_id = qbufcall(q, sizeof (char), BPRI_MED,
580 		    add_ctl_wkup, q)) {
581 			/*
582 			 * Add the message to the q.
583 			 */
584 			(void) putq(q, mp);
585 		} else {
586 			/*
587 			 * Things are pretty bad and serious if bufcall fails!
588 			 * Drop the message in this case.
589 			 */
590 			freemsg(mp);
591 		}
592 
593 		return (NULL);
594 	}
595 
596 	/*
597 	 * Copy the message type information to this message.
598 	 */
599 	bp->b_datap->db_type = M_PROTO;
600 	*(unsigned char *)bp->b_rptr = mp->b_datap->db_type;
601 	bp->b_wptr++;
602 
603 #ifdef _MULTI_DATAMODEL
604 	/*
605 	 * Check the datamodel and if the calling program is
606 	 * an ILP32 application then we covert the M_IOCTLs and M_READs
607 	 * into the native ILP32 format before passing them upstream
608 	 * to user mode.
609 	 */
610 	switch (pip->model) {
611 	case DDI_MODEL_ILP32:
612 		switch (mp->b_datap->db_type) {
613 			/*
614 			 * This structure must have the same shape as
615 			 * the * ILP32 compilation of `struct iocblk'
616 			 * from <sys/stream.h>.
617 			 */
618 			struct iocblk32 {
619 				int32_t   	ioc_cmd;
620 				caddr32_t	ioc_cr;
621 				uint32_t	ioc_id;
622 				int32_t   	ioc_count;
623 				int32_t   	ioc_error;
624 				int32_t   	ioc_rval;
625 				int32_t   	ioc_fill1;
626 				uint32_t	ioc_flag;
627 				int32_t   	ioc_filler[2];
628 			} niocblk_32;
629 			struct iocblk		*iocblk_64;
630 
631 		case M_IOCTL:
632 			if ((mp = pckt_reallocb(q, mp)) == (mblk_t *)0)
633 				return ((mblk_t *)0);
634 
635 			bzero(&niocblk_32, sizeof (niocblk_32));
636 			iocblk_64 = (struct iocblk *)mp->b_rptr;
637 
638 			/* Leave the pointer to cred_t structure as it is. */
639 			niocblk_32.ioc_cmd = iocblk_64->ioc_cmd;
640 			niocblk_32.ioc_cr = (caddr32_t)(uintptr_t)
641 			    iocblk_64->ioc_cr;
642 			niocblk_32.ioc_id = iocblk_64->ioc_id;
643 			niocblk_32.ioc_count = iocblk_64->ioc_count;
644 			niocblk_32.ioc_error = iocblk_64->ioc_error;
645 			niocblk_32.ioc_rval = iocblk_64->ioc_rval;
646 			niocblk_32.ioc_flag = iocblk_64->ioc_flag;
647 
648 			/* Copy the iocblk structure for ILP32 back */
649 			*(struct iocblk32 *)mp->b_rptr = niocblk_32;
650 			mp->b_wptr = mp->b_rptr + sizeof (struct iocblk32);
651 			break;
652 
653 		case M_READ:
654 			if ((mp = pckt_reallocb(q, mp)) == (mblk_t *)0)
655 				return ((mblk_t *)0);
656 
657 			/* change the size_t to size32_t for ILP32 */
658 			*(size32_t *)mp->b_rptr = *(size_t *)mp->b_rptr;
659 			mp->b_wptr = mp->b_rptr + sizeof (size32_t);
660 			break;
661 		}
662 		break;
663 
664 	case DATAMODEL_NONE:
665 		break;
666 	}
667 #endif /* _MULTI_DATAMODEL */
668 
669 	/*
670 	 * Now change the orginal message type to M_DATA and tie them up.
671 	 */
672 	mp->b_datap->db_type = M_DATA;
673 	bp->b_cont = mp;
674 
675 	return (bp);
676 }
677 
678 static void
add_ctl_wkup(void * arg)679 add_ctl_wkup(void *arg)
680 {
681 	queue_t *q = arg;	/* ptr to the read queue */
682 	struct pckt_info *pip = (struct pckt_info *)q->q_ptr;
683 
684 	pip->pi_bufcall_id = 0;
685 	/*
686 	 * Allow enabling of the q to allow the service
687 	 * function to do its job.
688 	 *
689 	 * Also, qenable() to schedule the q immediately.
690 	 * This is to ensure timely processing of high priority
691 	 * messages if they are on the q.
692 	 */
693 	enableok(q);
694 	qenable(q);
695 }
696