xref: /titanic_50/usr/src/uts/common/io/pckt.c (revision a0f9c00cd82d49a710cee8aeb83ce42b5fb293a9)
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 void	pcktrput(queue_t *, mblk_t *);
101 static void	pcktrsrv(queue_t *);
102 static void	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 	(int (*)())pcktrput,
146 	(int (*)())pcktrsrv,
147 	pcktopen,
148 	pcktclose,
149 	NULL,
150 	&pcktiinfo,
151 	NULL
152 };
153 
154 static struct qinit pcktwinit = {
155 	(int (*)())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 void
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 }
410 
411 /*
412  * pcktrsrv - module read service procedure
413  * This function deals with messages left in the queue due to
414  *	(a) not enough memory to allocate the header M_PROTO message
415  *	(b) flow control reasons
416  * The function will attempt to get the messages off the queue and
417  * process them.
418  */
419 static void
pcktrsrv(queue_t * q)420 pcktrsrv(queue_t *q)
421 {
422 	mblk_t *mp;
423 
424 	while ((mp = getq(q)) != NULL) {
425 		if (!canputnext(q)) {
426 			/*
427 			 * For high priority messages, make sure there is no
428 			 * infinite loop. Disable the queue for this case.
429 			 * High priority messages get here only for buffer
430 			 * allocation failures. Thus the bufcall callout
431 			 * will reenable the q.
432 			 * XXX bug alert - nooenable will *not* prevent
433 			 * putbq of a hipri messages frm enabling the queue.
434 			 */
435 			if (!datamsg(mp->b_datap->db_type))
436 				noenable(q);
437 			(void) putbq(q, mp);
438 			return;
439 		}
440 
441 		/*
442 		 * M_FLUSH msgs may also be here if there was a memory
443 		 * failure.
444 		 */
445 		switch (mp->b_datap->db_type) {
446 		case M_FLUSH:
447 		case M_PROTO:
448 		case M_PCPROTO:
449 		case M_STOP:
450 		case M_START:
451 		case M_IOCTL:
452 		case M_DATA:
453 		case M_READ:
454 		case M_STARTI:
455 		case M_STOPI:
456 			/*
457 			 * Prefix an M_PROTO header to msg and pass upstream.
458 			 */
459 			if ((mp = add_ctl_info(q, mp)) == NULL) {
460 				/*
461 				 * Running into memory or flow ctl problems.
462 				 */
463 				return;
464 			}
465 			/* FALL THROUGH */
466 
467 		default:
468 			putnext(q, mp);
469 			break;
470 		}
471 	}
472 }
473 
474 /*
475  * pcktwput - Module write queue put procedure.
476  *	All messages are send downstream unchanged
477  */
478 
479 static void
pcktwput(queue_t * q,mblk_t * mp)480 pcktwput(
481 	queue_t *q,	/* Pointer to the read queue */
482 	mblk_t *mp)	/* Pointer to current message block */
483 {
484 	putnext(q, mp);
485 }
486 
487 #ifdef _MULTI_DATAMODEL
488 /*
489  * reallocb - copy the data block from the given message block into a new block.
490  * This function is used in case data block had another message block
491  * pointing to it (and hence we just copy this one data block).
492  *
493  * Returns new message block if successful. On failure it returns NULL.
494  * It also tries to do a qbufcall and if that also fails,
495  * it frees the message block.
496  */
497 static mblk_t *
pckt_reallocb(queue_t * q,mblk_t * mp)498 pckt_reallocb(
499 	queue_t *q,	/* Pointer to the read queue */
500 	mblk_t *mp	/* Pointer to the message block to be changed */
501 )
502 {
503 	mblk_t	*nmp;
504 
505 	ASSERT(mp->b_datap->db_ref >= 1);
506 
507 	/*
508 	 * No reallocation is needed if there is only one reference
509 	 * to this data block.
510 	 */
511 	if (mp->b_datap->db_ref == 1)
512 		return (mp);
513 
514 	if ((nmp = copyb(mp)) == NULL) {
515 		struct pckt_info	*pip = (struct pckt_info *)q->q_ptr;
516 
517 		noenable(q);
518 		if (pip->pi_bufcall_id = qbufcall(q, mp->b_wptr - mp->b_rptr,
519 		    BPRI_MED, add_ctl_wkup, q)) {
520 			/*
521 			 * Put the message back onto the q.
522 			 */
523 			(void) putq(q, mp);
524 		} else {
525 			/*
526 			 * Things are pretty bad and serious if bufcall fails!
527 			 * Drop the message in this case.
528 			 */
529 			freemsg(mp);
530 		}
531 		return ((mblk_t *)0);
532 	}
533 
534 	nmp->b_cont = mp->b_cont;
535 	freeb(mp);
536 	return (nmp);
537 }
538 #endif /* _MULTI_DATAMODEL */
539 
540 /*
541  * add_ctl_info: add message control information to in coming
542  * 	message.
543  */
544 static mblk_t *
add_ctl_info(queue_t * q,mblk_t * mp)545 add_ctl_info(
546 	queue_t *q,		/* pointer to the read queue */
547 	mblk_t	*mp)		/* pointer to the raw data input message */
548 {
549 	struct pckt_info	*pip = (struct pckt_info *)q->q_ptr;
550 	mblk_t	*bp;		/* pointer to the unmodified message block */
551 
552 	/*
553 	 * Waiting on space for previous message?
554 	 */
555 	if (pip->pi_bufcall_id) {
556 		/*
557 		 * Chain this message on to q for later processing.
558 		 */
559 		(void) putq(q, mp);
560 		return (NULL);
561 	}
562 
563 	/*
564 	 * Need to add the message block header as
565 	 * an M_PROTO type message.
566 	 */
567 	if ((bp = allocb(sizeof (char), BPRI_MED)) == (mblk_t *)NULL) {
568 
569 		/*
570 		 * There are two reasons to disable the q:
571 		 * (1) Flow control reasons should not wake up the q.
572 		 * (2) High priority messages will wakeup the q
573 		 *	immediately. Disallow this.
574 		 */
575 		noenable(q);
576 		if (pip->pi_bufcall_id = qbufcall(q, sizeof (char), BPRI_MED,
577 		    add_ctl_wkup, q)) {
578 			/*
579 			 * Add the message to the q.
580 			 */
581 			(void) putq(q, mp);
582 		} else {
583 			/*
584 			 * Things are pretty bad and serious if bufcall fails!
585 			 * Drop the message in this case.
586 			 */
587 			freemsg(mp);
588 		}
589 
590 		return (NULL);
591 	}
592 
593 	/*
594 	 * Copy the message type information to this message.
595 	 */
596 	bp->b_datap->db_type = M_PROTO;
597 	*(unsigned char *)bp->b_rptr = mp->b_datap->db_type;
598 	bp->b_wptr++;
599 
600 #ifdef _MULTI_DATAMODEL
601 	/*
602 	 * Check the datamodel and if the calling program is
603 	 * an ILP32 application then we covert the M_IOCTLs and M_READs
604 	 * into the native ILP32 format before passing them upstream
605 	 * to user mode.
606 	 */
607 	switch (pip->model) {
608 	case DDI_MODEL_ILP32:
609 		switch (mp->b_datap->db_type) {
610 			/*
611 			 * This structure must have the same shape as
612 			 * the * ILP32 compilation of `struct iocblk'
613 			 * from <sys/stream.h>.
614 			 */
615 			struct iocblk32 {
616 				int32_t   	ioc_cmd;
617 				caddr32_t	ioc_cr;
618 				uint32_t	ioc_id;
619 				int32_t   	ioc_count;
620 				int32_t   	ioc_error;
621 				int32_t   	ioc_rval;
622 				int32_t   	ioc_fill1;
623 				uint32_t	ioc_flag;
624 				int32_t   	ioc_filler[2];
625 			} niocblk_32;
626 			struct iocblk		*iocblk_64;
627 
628 		case M_IOCTL:
629 			if ((mp = pckt_reallocb(q, mp)) == (mblk_t *)0)
630 				return ((mblk_t *)0);
631 
632 			bzero(&niocblk_32, sizeof (niocblk_32));
633 			iocblk_64 = (struct iocblk *)mp->b_rptr;
634 
635 			/* Leave the pointer to cred_t structure as it is. */
636 			niocblk_32.ioc_cmd = iocblk_64->ioc_cmd;
637 			niocblk_32.ioc_cr = (caddr32_t)(uintptr_t)
638 			    iocblk_64->ioc_cr;
639 			niocblk_32.ioc_id = iocblk_64->ioc_id;
640 			niocblk_32.ioc_count = iocblk_64->ioc_count;
641 			niocblk_32.ioc_error = iocblk_64->ioc_error;
642 			niocblk_32.ioc_rval = iocblk_64->ioc_rval;
643 			niocblk_32.ioc_flag = iocblk_64->ioc_flag;
644 
645 			/* Copy the iocblk structure for ILP32 back */
646 			*(struct iocblk32 *)mp->b_rptr = niocblk_32;
647 			mp->b_wptr = mp->b_rptr + sizeof (struct iocblk32);
648 			break;
649 
650 		case M_READ:
651 			if ((mp = pckt_reallocb(q, mp)) == (mblk_t *)0)
652 				return ((mblk_t *)0);
653 
654 			/* change the size_t to size32_t for ILP32 */
655 			*(size32_t *)mp->b_rptr = *(size_t *)mp->b_rptr;
656 			mp->b_wptr = mp->b_rptr + sizeof (size32_t);
657 			break;
658 		}
659 		break;
660 
661 	case DATAMODEL_NONE:
662 		break;
663 	}
664 #endif /* _MULTI_DATAMODEL */
665 
666 	/*
667 	 * Now change the orginal message type to M_DATA and tie them up.
668 	 */
669 	mp->b_datap->db_type = M_DATA;
670 	bp->b_cont = mp;
671 
672 	return (bp);
673 }
674 
675 static void
add_ctl_wkup(void * arg)676 add_ctl_wkup(void *arg)
677 {
678 	queue_t *q = arg;	/* ptr to the read queue */
679 	struct pckt_info *pip = (struct pckt_info *)q->q_ptr;
680 
681 	pip->pi_bufcall_id = 0;
682 	/*
683 	 * Allow enabling of the q to allow the service
684 	 * function to do its job.
685 	 *
686 	 * Also, qenable() to schedule the q immediately.
687 	 * This is to ensure timely processing of high priority
688 	 * messages if they are on the q.
689 	 */
690 	enableok(q);
691 	qenable(q);
692 }
693