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