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  * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006
23  */
24 
25 #pragma ident	"%Z%%M%	%I%	%E% SMI"
26 
27 #include <sys/errno.h>
28 #include <sys/modctl.h>
29 #include <sys/stat.h>
30 #include <sys/kmem.h>
31 #include <sys/ksynch.h>
32 #include <sys/stream.h>
33 #include <sys/stropts.h>
34 #include <sys/termio.h>
35 #include <sys/ddi.h>
36 #include <sys/file.h>
37 #include <sys/disp.h>
38 #include <sys/sunddi.h>
39 #include <sys/sunldi.h>
40 #include <sys/sunndi.h>
41 #include <sys/strsun.h>
42 #include <sys/oplmsu/oplmsu.h>
43 #include <sys/oplmsu/oplmsu_proto.h>
44 
45 /*
46  * Link upper_path_table structure
47  *
48  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
49  *  -. uinst_t->lock   : M [RW_WRITER]
50  *  -. uinst_t->u_lock : M
51  *  -. uinst_t->l_lock : A
52  *  -. uinst_t->c_lock : A
53  */
54 void
55 oplmsu_link_upath(upath_t *add_upath)
56 {
57 
58 	ASSERT(add_upath != NULL);
59 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
60 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
61 
62 	if (oplmsu_uinst->first_upath == NULL) {
63 		oplmsu_uinst->first_upath = add_upath;
64 		add_upath->u_prev = NULL;
65 	} else {
66 		upath_t	*last_upath;
67 
68 		last_upath = oplmsu_uinst->last_upath;
69 		last_upath->u_next = add_upath;
70 		add_upath->u_prev = last_upath;
71 	}
72 
73 	oplmsu_uinst->last_upath = add_upath;
74 	add_upath->u_next = NULL;
75 }
76 
77 /*
78  * Unlink upper_path_table structure
79  *
80  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
81  *  -. uinst_t->lock   : M [RW_WRITER]
82  *  -. uinst_t->u_lock : P
83  *  -. uinst_t->l_lock : P
84  *  -. uinst_t->c_lock : P
85  */
86 void
87 oplmsu_unlink_upath(upath_t *del_upath)
88 {
89 	upath_t **first, **last;
90 
91 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
92 
93 	first = &oplmsu_uinst->first_upath;
94 	last = &oplmsu_uinst->last_upath;
95 
96 	if ((*first != del_upath) && (*last != del_upath)) {
97 		del_upath->u_prev->u_next = del_upath->u_next;
98 		del_upath->u_next->u_prev = del_upath->u_prev;
99 	} else {
100 		if (*first == del_upath) {
101 			*first = (*first)->u_next;
102 			if (*first) {
103 				(*first)->u_prev = NULL;
104 			}
105 		}
106 
107 		if (*last == del_upath) {
108 			*last = (*last)->u_prev;
109 			if (*last) {
110 				(*last)->u_next = NULL;
111 			}
112 		}
113 	}
114 
115 	del_upath->u_next = NULL;
116 	del_upath->u_prev = NULL;
117 }
118 
119 /*
120  * Link lower_path_table structure
121  *
122  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
123  *  -. uinst_t->lock   : M [RW_WRITER]
124  *  -. uinst_t->u_lock : A
125  *  -. uinst_t->l_lock : M
126  *  -. uinst_t->c_lock : A
127  */
128 void
129 oplmsu_link_lpath(lpath_t *add_lpath)
130 {
131 
132 	ASSERT(add_lpath != NULL);
133 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
134 
135 	if (oplmsu_uinst->first_lpath == NULL) {
136 		oplmsu_uinst->first_lpath = add_lpath;
137 		add_lpath->l_prev = NULL;
138 	} else {
139 		lpath_t	*last_lpath;
140 
141 		last_lpath = oplmsu_uinst->last_lpath;
142 		last_lpath->l_next = add_lpath;
143 		add_lpath->l_prev = last_lpath;
144 	}
145 
146 	oplmsu_uinst->last_lpath = add_lpath;
147 	add_lpath->l_next = NULL;
148 }
149 
150 /*
151  * Unlink lower_path_table structure
152  *
153  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
154  *  -. uinst_t->lock   : M [RW_WRITER]
155  *  -. uinst_t->u_lock : P
156  *  -. uinst_t->l_lock : P
157  *  -. uinst_t->c_lock : P
158  */
159 void
160 oplmsu_unlink_lpath(lpath_t *del_lpath)
161 {
162 	lpath_t **first, **last;
163 
164 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
165 
166 	first = &oplmsu_uinst->first_lpath;
167 	last = &oplmsu_uinst->last_lpath;
168 
169 	if ((*first != del_lpath) && (*last != del_lpath)) {
170 		del_lpath->l_prev->l_next = del_lpath->l_next;
171 		del_lpath->l_next->l_prev = del_lpath->l_prev;
172 	} else {
173 		if (*first == del_lpath) {
174 			*first = (*first)->l_next;
175 			if (*first) {
176 				(*first)->l_prev = NULL;
177 			}
178 		}
179 
180 		if (*last == del_lpath) {
181 			*last = (*last)->l_prev;
182 			if (*last) {
183 				(*last)->l_next = NULL;
184 			}
185 		}
186 	}
187 
188 	del_lpath->l_next = NULL;
189 	del_lpath->l_prev = NULL;
190 }
191 
192 /*
193  * Link msgb structure of high priority
194  *
195  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
196  *  -. uinst_t->lock   : M [RW_READER]
197  *  -. uinst_t->u_lock : A
198  *  -. uinst_t->l_lock : A [It depends on caller]
199  *  -. uinst_t->c_lock : A [It depends on caller]
200  */
201 void
202 oplmsu_link_high_primsg(mblk_t **first, mblk_t **last, mblk_t *add_msg)
203 {
204 
205 	ASSERT(add_msg != NULL);
206 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
207 
208 	if (*first == NULL) {
209 		*first = add_msg;
210 		add_msg->b_prev = NULL;
211 	} else {
212 		(*last)->b_next = add_msg;
213 		add_msg->b_prev = *last;
214 	}
215 
216 	*last = add_msg;
217 	add_msg->b_next = NULL;
218 }
219 
220 /*
221  * Check whether lower path is usable by lower path info table address
222  *
223  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
224  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
225  *  -. uinst_t->u_lock : A
226  *  -. uinst_t->l_lock : M
227  *  -. uinst_t->c_lock : P
228  */
229 int
230 oplmsu_check_lpath_usable(void)
231 {
232 	lpath_t	*lpath;
233 	int	rval = SUCCESS;
234 
235 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
236 	ASSERT(MUTEX_HELD(&oplmsu_uinst->l_lock));
237 
238 	lpath = oplmsu_uinst->first_lpath;
239 	while (lpath) {
240 		if ((lpath->hndl_uqueue != NULL) || (lpath->hndl_mp != NULL)) {
241 			rval = BUSY;
242 			break;
243 		}
244 		lpath = lpath->l_next;
245 	}
246 	return (rval);
247 }
248 
249 /*
250  * Search upath_t by path number
251  *
252  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
253  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
254  *  -. uinst_t->u_lock : M
255  *  -. uinst_t->l_lock : A
256  *  -. uinst_t->c_lock : P
257  */
258 upath_t	*
259 oplmsu_search_upath_info(int path_no)
260 {
261 	upath_t	*upath;
262 
263 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
264 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
265 
266 	upath = oplmsu_uinst->first_upath;
267 	while (upath) {
268 		if (upath->path_no == path_no) {
269 			break;
270 		}
271 		upath = upath->u_next;
272 	}
273 	return (upath);
274 }
275 
276 /*
277  * Send M_IOCACK(or M_IOCNAK) message to stream
278  *
279  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
280  *  -. uinst_t->lock   : P
281  *  -. uinst_t->u_lock : P
282  *  -. uinst_t->l_lock : P
283  *  -. uinst_t->c_lock : P
284  */
285 void
286 oplmsu_iocack(queue_t *q, mblk_t *mp, int errno)
287 {
288 	struct iocblk	*iocp = NULL;
289 
290 	ASSERT(mp != NULL);
291 
292 	iocp = (struct iocblk *)mp->b_rptr;
293 	iocp->ioc_error = errno;
294 
295 	if (errno) {	/* Error */
296 		mp->b_datap->db_type = M_IOCNAK;
297 		iocp->ioc_rval = FAILURE;
298 
299 		OPLMSU_TRACE(q, mp, MSU_TRC_UO);
300 		qreply(q, mp);
301 	} else {	/* Good */
302 		mp->b_datap->db_type = M_IOCACK;
303 		iocp->ioc_rval = SUCCESS;
304 
305 		OPLMSU_TRACE(q, mp, MSU_TRC_UO);
306 		qreply(q, mp);
307 	}
308 }
309 
310 /*
311  * Delete all upath_t
312  *
313  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
314  *  -. uinst_t->lock   : M [RW_WRITER]
315  *  -. uinst_t->u_lock : M
316  *  -. uinst_t->l_lock : A
317  *  -. uinst_t->c_lock : A
318  */
319 void
320 oplmsu_delete_upath_info(void)
321 {
322 	upath_t	*upath, *next_upath;
323 
324 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
325 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
326 
327 	upath = oplmsu_uinst->first_upath;
328 	oplmsu_uinst->first_upath = NULL;
329 	oplmsu_uinst->last_upath = NULL;
330 
331 	while (upath) {
332 		next_upath = upath->u_next;
333 		kmem_free(upath, sizeof (upath_t));
334 		upath = next_upath;
335 	}
336 }
337 
338 /*
339  * Set queue and ioctl to lpath_t
340  *
341  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
342  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
343  *  -. uinst_t->u_lock : A
344  *  -. uinst_t->l_lock : M
345  *  -. uinst_t->c_lock : P
346  */
347 int
348 oplmsu_set_ioctl_path(lpath_t *lpath, queue_t *hndl_queue, mblk_t *mp)
349 {
350 	int	rval = SUCCESS;
351 
352 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
353 	ASSERT(MUTEX_HELD(&oplmsu_uinst->l_lock));
354 
355 	if ((lpath->hndl_uqueue == NULL) && (lpath->hndl_mp == NULL) &&
356 	    (lpath->sw_flag == 0)) {
357 		if ((lpath->status == MSU_EXT_NOTUSED) ||
358 		    (lpath->status == MSU_EXT_ACTIVE_CANDIDATE) ||
359 		    (lpath->status == MSU_SETID_NU)) {
360 			if (hndl_queue == NULL) {
361 				lpath->hndl_uqueue = hndl_queue;
362 			} else {
363 				lpath->hndl_uqueue = WR(hndl_queue);
364 			}
365 			lpath->hndl_mp = mp;
366 		} else {
367 			rval = BUSY;
368 		}
369 	} else {
370 		rval = BUSY;
371 	}
372 	return (rval);
373 }
374 
375 /*
376  * Clear queue and ioctl to lpath_t
377  *
378  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
379  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
380  *  -. uinst_t->u_lock : A
381  *  -. uinst_t->l_lock : M
382  *  -. uinst_t->c_lock : P
383  */
384 void
385 oplmsu_clear_ioctl_path(lpath_t *lpath)
386 {
387 
388 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
389 	ASSERT(MUTEX_HELD(&oplmsu_uinst->l_lock));
390 
391 	lpath->hndl_uqueue = NULL;
392 	lpath->hndl_mp = NULL;
393 }
394 
395 /*
396  * Get instanse status from status of upath_t
397  *
398  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
399  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
400  *  -. uinst_t->u_lock : M
401  *  -. uinst_t->l_lock : A
402  *  -. uinst_t->c_lock : P
403  */
404 int
405 oplmsu_get_inst_status(void)
406 {
407 	upath_t	*upath;
408 	int	sts, pre_sts = INST_STAT_UNCONFIGURED;
409 
410 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
411 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
412 
413 	upath = oplmsu_uinst->first_upath;
414 	while (upath) {
415 		if (((upath->status == MSU_PSTAT_ACTIVE) &&
416 		    (upath->traditional_status == MSU_ACTIVE)) ||
417 		    ((upath->status == MSU_PSTAT_STANDBY) &&
418 		    (upath->traditional_status == MSU_STANDBY))) {
419 			sts = INST_STAT_ONLINE;
420 		} else if (((upath->status == MSU_PSTAT_STOP) &&
421 		    (upath->traditional_status == MSU_STOP)) ||
422 		    ((upath->status == MSU_PSTAT_FAIL) &&
423 		    (upath->traditional_status == MSU_FAIL))) {
424 			sts = INST_STAT_OFFLINE;
425 		} else if (((upath->status == MSU_PSTAT_DISCON) &&
426 		    (upath->traditional_status == MSU_DISCON)) ||
427 		    ((upath->status == MSU_PSTAT_EMPTY) &&
428 		    (upath->traditional_status == MSU_EMPTY))) {
429 			sts = INST_STAT_UNCONFIGURED;
430 		} else {
431 			sts = INST_STAT_BUSY;
432 		}
433 
434 		if (pre_sts > sts) {
435 			pre_sts = sts;
436 		}
437 		upath = upath->u_next;
438 	}
439 	return (pre_sts);
440 }
441 
442 /*
443  * Search path of "online:standby" status
444  *
445  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
446  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
447  *  -. uinst_t->u_lock : M
448  *  -. uinst_t->l_lock : A
449  *  -. uinst_t->c_lock : P
450  */
451 upath_t	*
452 oplmsu_search_standby(void)
453 {
454 	upath_t	*upath, *altn_upath = NULL;
455 	int	max_pathnum = UNDEFINED;
456 
457 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
458 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
459 
460 	upath = oplmsu_uinst->first_upath;
461 	while (upath) {
462 		if ((upath->status == MSU_PSTAT_STANDBY) &&
463 		    (upath->traditional_status == MSU_STANDBY) &&
464 		    (upath->lpath != NULL)) {
465 			if ((max_pathnum == UNDEFINED) ||
466 			    (max_pathnum > upath->path_no)) {
467 				max_pathnum = upath->path_no;
468 				altn_upath = upath;
469 			}
470 		}
471 		upath = upath->u_next;
472 	}
473 	return (altn_upath);
474 }
475 
476 /*
477  * Search path of "offline:stop" status, and minimum path number
478  *
479  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
480  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
481  *  -. uinst_t->u_lock : M
482  *  -. uinst_t->l_lock : P
483  *  -. uinst_t->c_lock : P
484  */
485 void
486 oplmsu_search_min_stop_path(void)
487 {
488 	upath_t	*upath, *min_upath;
489 	lpath_t	*lpath;
490 	int	min_no = UNDEFINED;
491 	int	active_flag = 0;
492 
493 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
494 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
495 
496 	upath = oplmsu_uinst->first_upath;
497 	while (upath) {
498 		if ((upath->status == MSU_PSTAT_ACTIVE) &&
499 		    (upath->traditional_status == MSU_ACTIVE)) {
500 			active_flag = 1;
501 			break;
502 		} else if ((upath->status == MSU_PSTAT_STOP) &&
503 		    (upath->traditional_status == MSU_STOP)) {
504 			if (upath->lpath != NULL) {
505 				if ((min_no == UNDEFINED) ||
506 				    (upath->path_no < min_no)) {
507 					lpath = upath->lpath;
508 					mutex_enter(&oplmsu_uinst->l_lock);
509 					if (lpath->status == MSU_EXT_NOTUSED) {
510 						min_upath = upath;
511 						min_no = upath->path_no;
512 					}
513 					mutex_exit(&oplmsu_uinst->l_lock);
514 				}
515 			}
516 		}
517 		upath = upath->u_next;
518 	}
519 
520 	if (active_flag == 0) {
521 		lpath = min_upath->lpath;
522 		mutex_enter(&oplmsu_uinst->l_lock);
523 		lpath->src_upath = NULL;
524 		lpath->status = MSU_EXT_ACTIVE_CANDIDATE;
525 		mutex_exit(&oplmsu_uinst->l_lock);
526 	}
527 }
528 
529 /*
530  * Get the total number of serial paths
531  *
532  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
533  *  -. uinst_t->lock   : M [RW_WRITER]
534  *  -. uinst_t->u_lock : M
535  *  -. uinst_t->l_lock : A
536  *  -. uinst_t->c_lock : A
537  */
538 int
539 oplmsu_get_pathnum(void)
540 {
541 	upath_t	*upath;
542 	int	total_num = 0;
543 
544 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
545 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
546 
547 	if (oplmsu_uinst->first_upath != NULL) {
548 		upath = oplmsu_uinst->first_upath;
549 		while (upath) {
550 			total_num++;
551 			upath = upath->u_next;
552 		}
553 	}
554 	return (total_num);
555 }
556 
557 /*
558  * Put XOFF/ XON message on write queue
559  *
560  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
561  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
562  *  -. uinst_t->u_lock : A
563  *  -. uinst_t->l_lock : A
564  *  -. uinst_t->c_lock : A
565  */
566 int
567 oplmsu_cmn_put_xoffxon(queue_t *queue, int data)
568 {
569 	mblk_t	*mp;
570 	int	rval = SUCCESS;
571 
572 	/* Send M_START */
573 	if ((mp = allocb(0, BPRI_LO)) != NULL) {
574 		mp->b_datap->db_type = M_START;
575 		putq(queue, mp);
576 
577 		/* Send M_DATA(XOFF, XON) */
578 		if ((mp = allocb(sizeof (int), BPRI_LO)) != NULL) {
579 			*(uint_t *)mp->b_rptr = data;
580 			mp->b_wptr = mp->b_rptr + sizeof (int);
581 			putq(queue, mp);
582 		} else {
583 			rval = FAILURE;
584 		}
585 	} else {
586 		rval = FAILURE;
587 	}
588 	return (rval);
589 }
590 
591 /*
592  * Put XOFF message on write queue for all standby paths
593  *
594  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
595  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
596  *  -. uinst_t->u_lock : M
597  *  -. uinst_t->l_lock : M
598  *  -. uinst_t->c_lock : P
599  */
600 void
601 oplmsu_cmn_putxoff_standby(void)
602 {
603 	upath_t	*upath;
604 	lpath_t	*lpath;
605 
606 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
607 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
608 	ASSERT(MUTEX_HELD(&oplmsu_uinst->l_lock));
609 
610 	upath = oplmsu_uinst->first_upath;
611 	while (upath) {
612 		lpath = upath->lpath;
613 		if ((upath->status != MSU_PSTAT_STANDBY) ||
614 		    (lpath == NULL)) {
615 			upath = upath->u_next;
616 			continue;
617 		}
618 
619 		(void) oplmsu_cmn_put_xoffxon(
620 		    WR(lpath->lower_queue), MSU_XOFF_4);
621 		upath = upath->u_next;
622 	}
623 }
624 
625 /*
626  * Set M_FLUSH message
627  *
628  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
629  *  -. uinst_t->lock   : A [RW_READER or RW_WRITER]
630  *  -. uinst_t->u_lock : A
631  *  -. uinst_t->l_lock : A
632  *  -. uinst_t->c_lock : A
633  */
634 void
635 oplmsu_cmn_set_mflush(mblk_t *mp)
636 {
637 
638 	mp->b_datap->db_type = M_FLUSH;
639 	*mp->b_rptr = FLUSHW;
640 	mp->b_wptr = mp->b_rptr + sizeof (char);
641 }
642 
643 /*
644  * Set status informations of upath_t
645  *
646  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
647  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
648  *  -. uinst_t->u_lock : M
649  *  -. uinst_t->l_lock : A
650  *  -. uinst_t->c_lock : A
651  */
652 void
653 oplmsu_cmn_set_upath_sts(upath_t *upath, int sts, int prev_sts,
654     ulong_t trad_sts)
655 {
656 
657 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
658 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
659 
660 	upath->status = sts;
661 	upath->prev_status = prev_sts;
662 	upath->traditional_status = trad_sts;
663 }
664 
665 /*
666  * Allocate a message block
667  *
668  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
669  *  -. uinst_t->lock   : M [RW_READER]
670  *  -. uinst_t->u_lock : A
671  *  -. uinst_t->l_lock : P
672  *  -. uinst_t->c_lock : P
673  */
674 int
675 oplmsu_cmn_allocmb(queue_t *q, mblk_t *mp, mblk_t **nmp, size_t size,
676     int rw_flag)
677 {
678 	int	rval = SUCCESS;
679 
680 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
681 
682 	if ((*nmp = (mblk_t *)allocb(size, BPRI_LO)) == NULL) {
683 		oplmsu_cmn_bufcall(q, mp, size, rw_flag);
684 		rval = FAILURE;
685 	} else {
686 		(*nmp)->b_wptr = (*nmp)->b_rptr + size;
687 	}
688 	return (rval);
689 }
690 
691 /*
692  * Copy a message
693  *
694  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
695  *  -. uinst_t->lock   : M [RW_READER]
696  *  -. uinst_t->u_lock : A
697  *  -. uinst_t->l_lock : P
698  *  -. uinst_t->c_lock : P
699  */
700 int
701 oplmsu_cmn_copymb(queue_t *q, mblk_t *mp, mblk_t **nmp, mblk_t *cmp,
702     int rw_flag)
703 {
704 	int	rval = SUCCESS;
705 
706 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
707 
708 	if ((*nmp = copymsg(cmp)) == NULL) {
709 		oplmsu_cmn_bufcall(q, mp, msgsize(cmp), rw_flag);
710 		rval = FAILURE;
711 	}
712 	return (rval);
713 }
714 
715 /*
716  * bufcall request
717  *
718  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
719  *  -. uinst_t->lock   : M [RW_READER]
720  *  -. uinst_t->u_lock : A
721  *  -. uinst_t->l_lock : P
722  *  -. uinst_t->c_lock : P
723  */
724 void
725 oplmsu_cmn_bufcall(queue_t *q, mblk_t *mp, size_t size, int rw_flag)
726 {
727 
728 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
729 
730 	if (rw_flag == MSU_WRITE_SIDE) {
731 		ctrl_t	*ctrl;
732 
733 		putbq(q, mp);
734 
735 		mutex_enter(&oplmsu_uinst->c_lock);
736 		ctrl = (ctrl_t *)q->q_ptr;
737 		if (ctrl->wbuf_id != 0) {
738 			mutex_exit(&oplmsu_uinst->c_lock);
739 			return;
740 		}
741 
742 		ctrl->wbuftbl->q = q;
743 		ctrl->wbuftbl->rw_flag = rw_flag;
744 		ctrl->wbuf_id = bufcall(size, BPRI_LO, oplmsu_cmn_bufcb,
745 		    (void *)ctrl->wbuftbl);
746 
747 		if (ctrl->wbuf_id == 0) {
748 			if (ctrl->wtout_id != 0) {
749 				mutex_exit(&oplmsu_uinst->c_lock);
750 				return;
751 			}
752 
753 			ctrl->wtout_id = timeout(oplmsu_cmn_bufcb,
754 			    (void *)ctrl->wbuftbl, drv_usectohz(MSU_TM_500MS));
755 		}
756 		mutex_exit(&oplmsu_uinst->c_lock);
757 	} else if (rw_flag == MSU_READ_SIDE) {
758 		lpath_t	*lpath;
759 		mblk_t	*wrk_msg;
760 
761 		mutex_enter(&oplmsu_uinst->l_lock);
762 		lpath = (lpath_t *)q->q_ptr;
763 		if (mp->b_datap->db_type >= QPCTL) {
764 			if (lpath->first_lpri_hi == NULL) {
765 				lpath->last_lpri_hi = mp;
766 				mp->b_next = NULL;
767 			} else {
768 				wrk_msg = lpath->first_lpri_hi;
769 				wrk_msg->b_prev = mp;
770 				mp->b_next = wrk_msg;
771 			}
772 			mp->b_prev = NULL;
773 			lpath->first_lpri_hi = mp;
774 		} else {
775 			putbq(q, mp);
776 		}
777 
778 		if (lpath->rbuf_id != 0) {
779 			mutex_exit(&oplmsu_uinst->l_lock);
780 			return;
781 		}
782 
783 		lpath->rbuftbl->q = q;
784 		lpath->rbuftbl->rw_flag = rw_flag;
785 		lpath->rbuf_id = bufcall(size, BPRI_LO, oplmsu_cmn_bufcb,
786 		    (void *)lpath->rbuftbl);
787 
788 		if (lpath->rbuf_id == 0) {
789 			if (lpath->rtout_id != 0) {
790 				mutex_exit(&oplmsu_uinst->l_lock);
791 				return;
792 			}
793 
794 			lpath->rtout_id = timeout(oplmsu_cmn_bufcb,
795 			    (void *)lpath->rbuftbl, drv_usectohz(MSU_TM_500MS));
796 		}
797 		mutex_exit(&oplmsu_uinst->l_lock);
798 	}
799 }
800 
801 /*
802  * Previous sequence for active path change
803  *
804  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
805  *  -. uinst_t->lock   : M [RW_READER]
806  *  -. uinst_t->u_lock : A
807  *  -. uinst_t->l_lock : P
808  *  -. uinst_t->c_lock : P
809  */
810 int
811 oplmsu_cmn_prechg(queue_t *q, mblk_t *mp, int rw_flag, mblk_t **term_mp,
812     int *term_ioctl, int *term_stat)
813 {
814 
815 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
816 
817 	if (oplmsu_uinst->tcsets_p != NULL) {
818 		struct iocblk	*iocp;
819 
820 		if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tcsets_p,
821 		    rw_flag) == -1) {
822 			return (FAILURE);
823 		}
824 
825 		iocp = (struct iocblk *)(*term_mp)->b_rptr;
826 		*term_ioctl = iocp->ioc_cmd;
827 		*term_stat = MSU_WTCS_ACK;
828 	} else if (oplmsu_uinst->tiocmset_p != NULL) {
829 		if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocmset_p,
830 		    rw_flag) == -1) {
831 			return (FAILURE);
832 		}
833 
834 		*term_ioctl = TIOCMSET;
835 		*term_stat = MSU_WTMS_ACK;
836 	} else if (oplmsu_uinst->tiocspps_p != NULL) {
837 		if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocspps_p,
838 		    rw_flag) == -1) {
839 			return (FAILURE);
840 		}
841 
842 		*term_ioctl = TIOCSPPS;
843 		*term_stat = MSU_WPPS_ACK;
844 	} else if (oplmsu_uinst->tiocswinsz_p != NULL) {
845 		if (oplmsu_cmn_copymb(q, mp, term_mp,
846 		    oplmsu_uinst->tiocswinsz_p, rw_flag) == -1) {
847 			return (FAILURE);
848 		}
849 
850 		*term_ioctl = TIOCSWINSZ;
851 		*term_stat = MSU_WWSZ_ACK;
852 	} else if (oplmsu_uinst->tiocssoftcar_p != NULL) {
853 		if (oplmsu_cmn_copymb(q, mp, term_mp,
854 		    oplmsu_uinst->tiocssoftcar_p, rw_flag) == -1) {
855 			return (FAILURE);
856 		}
857 
858 		*term_ioctl = TIOCSSOFTCAR;
859 		*term_stat = MSU_WCAR_ACK;
860 	} else {
861 		*term_stat = MSU_WPTH_CHG;
862 		*term_mp = NULL;
863 	}
864 	return (SUCCESS);
865 }
866 
867 /*
868  * Pick up termios to re-set
869  *
870  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
871  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
872  *  -. uinst_t->u_lock : A
873  *  -. uinst_t->l_lock : A
874  *  -. uinst_t->c_lock : A
875  */
876 int
877 oplmsu_stop_prechg(mblk_t **term_mp, int *term_ioctl, int *term_stat)
878 {
879 
880 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
881 
882 	if (oplmsu_uinst->tcsets_p != NULL) {
883 		struct iocblk	*iocp;
884 
885 		if ((*term_mp = copymsg(oplmsu_uinst->tcsets_p)) == NULL) {
886 			return (FAILURE);
887 		}
888 
889 		iocp = (struct iocblk *)(*term_mp)->b_rptr;
890 		*term_ioctl = iocp->ioc_cmd;
891 		*term_stat = MSU_WTCS_ACK;
892 	} else if (oplmsu_uinst->tiocmset_p != NULL) {
893 		if ((*term_mp = copymsg(oplmsu_uinst->tiocmset_p)) == NULL) {
894 			return (FAILURE);
895 		}
896 
897 		*term_ioctl = TIOCMSET;
898 		*term_stat = MSU_WTMS_ACK;
899 	} else if (oplmsu_uinst->tiocspps_p != NULL) {
900 		if ((*term_mp = copymsg(oplmsu_uinst->tiocspps_p)) == NULL) {
901 			return (FAILURE);
902 		}
903 
904 		*term_ioctl = TIOCSPPS;
905 		*term_stat = MSU_WPPS_ACK;
906 	} else if (oplmsu_uinst->tiocswinsz_p != NULL) {
907 		if ((*term_mp = copymsg(oplmsu_uinst->tiocswinsz_p)) == NULL) {
908 			return (FAILURE);
909 		}
910 
911 		*term_ioctl = TIOCSWINSZ;
912 		*term_stat = MSU_WWSZ_ACK;
913 	} else if (oplmsu_uinst->tiocssoftcar_p != NULL) {
914 		if ((*term_mp = copymsg(oplmsu_uinst->tiocssoftcar_p))
915 		    == NULL) {
916 			return (FAILURE);
917 		}
918 
919 		*term_ioctl = TIOCSSOFTCAR;
920 		*term_stat = MSU_WCAR_ACK;
921 	} else {
922 		*term_stat = MSU_WPTH_CHG;
923 		*term_mp = NULL;
924 	}
925 	return (SUCCESS);
926 }
927 
928 /*
929  * Previous sequence for active path change termio
930  *
931  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
932  *  -. uinst_t->lock   : M [RW_READER]
933  *  -. uinst_t->u_lock : A
934  *  -. uinst_t->l_lock : P
935  *  -. uinst_t->c_lock : P
936  */
937 int
938 oplmsu_cmn_prechg_termio(queue_t *q, mblk_t *mp, int rw_flag, int prev_flag,
939     mblk_t **term_mp, int *term_stat)
940 {
941 
942 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
943 
944 	if ((prev_flag == MSU_TIOS_TCSETS) &&
945 	    (oplmsu_uinst->tiocmset_p != NULL)) {
946 		if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocmset_p,
947 		    rw_flag) == FAILURE) {
948 			return (FAILURE);
949 		}
950 
951 		*term_stat = MSU_WTMS_ACK;
952 	} else if ((prev_flag <= MSU_TIOS_MSET) &&
953 	    (oplmsu_uinst->tiocspps_p != NULL)) {
954 		if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocspps_p,
955 		    rw_flag) == FAILURE) {
956 			return (FAILURE);
957 		}
958 
959 		*term_stat = MSU_WPPS_ACK;
960 	} else if ((prev_flag <= MSU_TIOS_PPS) &&
961 	    (oplmsu_uinst->tiocswinsz_p != NULL)) {
962 		if (oplmsu_cmn_copymb(q, mp, term_mp,
963 		    oplmsu_uinst->tiocswinsz_p, rw_flag) == FAILURE) {
964 			return (FAILURE);
965 		}
966 
967 		*term_stat = MSU_WWSZ_ACK;
968 	} else if ((prev_flag <= MSU_TIOS_WINSZP) &&
969 	    (oplmsu_uinst->tiocssoftcar_p != NULL)) {
970 		if (oplmsu_cmn_copymb(q, mp, term_mp,
971 		    oplmsu_uinst->tiocssoftcar_p, rw_flag) == FAILURE) {
972 			return (FAILURE);
973 		}
974 
975 		*term_stat = MSU_WCAR_ACK;
976 	} else if (prev_flag <= MSU_TIOS_SOFTCAR) {
977 		*term_mp = NULL;
978 		*term_stat = MSU_WPTH_CHG;
979 	}
980 	return (SUCCESS);
981 }
982 
983 /*
984  * Pull up messages
985  *
986  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
987  *  -. uinst_t->lock   : P
988  *  -. uinst_t->u_lock : P
989  *  -. uinst_t->l_lock : P
990  *  -. uinst_t->c_lock : P
991  */
992 int
993 oplmsu_cmn_pullup_msg(queue_t *q, mblk_t *mp)
994 {
995 	mblk_t	*nmp = NULL;
996 
997 	if ((mp != NULL) && (mp->b_cont != NULL) &&
998 	    (mp->b_cont->b_cont != NULL)) {
999 		if ((nmp = msgpullup(mp->b_cont, -1)) == NULL) {
1000 			oplmsu_iocack(q, mp, ENOSR);
1001 			return (FAILURE);
1002 		} else {
1003 			freemsg(mp->b_cont);
1004 			mp->b_cont = nmp;
1005 		}
1006 	}
1007 	return (SUCCESS);
1008 }
1009 
1010 /*
1011  * Wake up flow control
1012  *
1013  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1014  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
1015  *  -. uinst_t->u_lock : P
1016  *  -. uinst_t->l_lock : P
1017  *  -. uinst_t->c_lock : P
1018  */
1019 void
1020 oplmsu_cmn_wakeup(queue_t *q)
1021 {
1022 	ctrl_t	*ctrl;
1023 
1024 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
1025 
1026 	mutex_enter(&oplmsu_uinst->c_lock);
1027 	ctrl = (ctrl_t *)q->q_ptr;
1028 	if (ctrl->sleep_flag == CV_SLEEP) {
1029 		ctrl->sleep_flag = CV_WAKEUP;
1030 		cv_signal(&ctrl->cvp);
1031 	}
1032 	mutex_exit(&oplmsu_uinst->c_lock);
1033 }
1034 
1035 /*
1036  * bufcall() and timeout() callback entry for read/write stream
1037  *
1038  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1039  *  -. uinst_t->lock   : P
1040  *  -. uinst_t->u_lock : P
1041  *  -. uinst_t->l_lock : P
1042  *  -. uinst_t->c_lock : P
1043  */
1044 void
1045 oplmsu_cmn_bufcb(void *arg)
1046 {
1047 	struct buf_tbl	*buftbl = arg;
1048 	lpath_t		*lpath;
1049 	ctrl_t		*ctrl;
1050 	queue_t		*q;
1051 	int		lq_flag = 0;
1052 
1053 	rw_enter(&oplmsu_uinst->lock, RW_WRITER);
1054 	mutex_enter(&oplmsu_uinst->l_lock);
1055 
1056 	lpath = oplmsu_uinst->first_lpath;
1057 	while (lpath) {
1058 		if ((buftbl == lpath->rbuftbl) &&
1059 		    (buftbl->rw_flag == MSU_READ_SIDE)) {
1060 			if ((lpath->rbuf_id == 0) && (lpath->rtout_id == 0)) {
1061 				mutex_exit(&oplmsu_uinst->l_lock);
1062 				rw_exit(&oplmsu_uinst->lock);
1063 			} else {
1064 				q = lpath->rbuftbl->q;
1065 				lpath->rbuftbl->q = NULL;
1066 				lpath->rbuftbl->rw_flag = UNDEFINED;
1067 
1068 				if (lpath->rbuf_id) {
1069 					lpath->rbuf_id = 0;
1070 				} else {
1071 					lpath->rtout_id = 0;
1072 				}
1073 				mutex_exit(&oplmsu_uinst->l_lock);
1074 
1075 				if (oplmsu_queue_flag == 1) {
1076 					lq_flag = 1;
1077 					oplmsu_queue_flag = 0;
1078 				}
1079 
1080 				rw_exit(&oplmsu_uinst->lock);
1081 				oplmsu_rcmn_high_qenable(q);
1082 
1083 				if (lq_flag == 1) {
1084 					rw_enter(&oplmsu_uinst->lock,
1085 					    RW_WRITER);
1086 					oplmsu_queue_flag = 1;
1087 					rw_exit(&oplmsu_uinst->lock);
1088 				}
1089 			}
1090 			return;
1091 		}
1092 		lpath = lpath->l_next;
1093 	}
1094 	mutex_exit(&oplmsu_uinst->l_lock);
1095 
1096 	mutex_enter(&oplmsu_uinst->c_lock);
1097 	if ((ctrl = oplmsu_uinst->user_ctrl) != NULL) {
1098 		if ((buftbl == ctrl->wbuftbl) &&
1099 		    (buftbl->rw_flag == MSU_WRITE_SIDE)) {
1100 			oplmsu_wbufcb_posthndl(ctrl);
1101 			mutex_exit(&oplmsu_uinst->c_lock);
1102 			rw_exit(&oplmsu_uinst->lock);
1103 			return;
1104 		}
1105 	}
1106 
1107 	if ((ctrl = oplmsu_uinst->meta_ctrl) != NULL) {
1108 		if ((buftbl == ctrl->wbuftbl) &&
1109 		    (buftbl->rw_flag == MSU_WRITE_SIDE)) {
1110 			oplmsu_wbufcb_posthndl(ctrl);
1111 			mutex_exit(&oplmsu_uinst->c_lock);
1112 			rw_exit(&oplmsu_uinst->lock);
1113 			return;
1114 		}
1115 	}
1116 	mutex_exit(&oplmsu_uinst->c_lock);
1117 	rw_exit(&oplmsu_uinst->lock);
1118 }
1119 
1120 /*
1121  * bufcall() or timeout() callback post handling for write stream
1122  *
1123  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1124  *  -. uinst_t->lock   : M [RW_WRITER]
1125  *  -. uinst_t->u_lock : P
1126  *  -. uinst_t->l_lock : P
1127  *  -. uinst_t->c_lock : M
1128  */
1129 void
1130 oplmsu_wbufcb_posthndl(ctrl_t *ctrl)
1131 {
1132 	queue_t	*q;
1133 	int	lq_flag = 0;
1134 
1135 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
1136 	ASSERT(MUTEX_HELD(&oplmsu_uinst->c_lock));
1137 
1138 	if ((ctrl->wbuf_id == 0) && (ctrl->wtout_id == 0)) {
1139 		return;
1140 	}
1141 
1142 	q = ctrl->wbuftbl->q;
1143 	ctrl->wbuftbl->q = NULL;
1144 	ctrl->wbuftbl->rw_flag = UNDEFINED;
1145 	if (ctrl->wbuf_id) {
1146 		ctrl->wbuf_id = 0;
1147 	} else {
1148 		ctrl->wtout_id = 0;
1149 	}
1150 
1151 	if (oplmsu_queue_flag == 1) {
1152 		lq_flag = 1;
1153 		oplmsu_queue_flag = 0;
1154 	}
1155 
1156 	mutex_exit(&oplmsu_uinst->c_lock);
1157 	oplmsu_wcmn_high_qenable(q, RW_WRITER);
1158 	mutex_enter(&oplmsu_uinst->c_lock);
1159 
1160 	if (lq_flag == 1) {
1161 		oplmsu_queue_flag = 1;
1162 	}
1163 }
1164 
1165 /*
1166  *	COMMON FUNCTIONS FOR WRITE STREAM
1167  */
1168 
1169 /*
1170  * Check control node and driver privilege
1171  *
1172  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1173  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
1174  *  -. uinst_t->u_lock : A
1175  *  -. uinst_t->l_lock : A
1176  *  -. uinst_t->c_lock : P
1177  */
1178 int
1179 oplmsu_wcmn_chknode(queue_t *q, int node, mblk_t *mp)
1180 {
1181 	struct iocblk	*iocp;
1182 
1183 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
1184 
1185 	mutex_enter(&oplmsu_uinst->c_lock);
1186 	if (((ctrl_t *)q->q_ptr)->node_type != node) {
1187 		mutex_exit(&oplmsu_uinst->c_lock);
1188 		cmn_err(CE_WARN, "oplmsu: chk-node: ctrl node type = %d", node);
1189 		return (EINVAL);
1190 	}
1191 	mutex_exit(&oplmsu_uinst->c_lock);
1192 
1193 	/* Check super-user by oplmsu.conf */
1194 	if (oplmsu_check_su != 0) {
1195 		iocp = (struct iocblk *)mp->b_rptr;
1196 		if (drv_priv(iocp->ioc_cr) != 0) {
1197 			cmn_err(CE_WARN, "oplmsu: chk-node: Permission denied");
1198 			return (EPERM);
1199 		}
1200 	}
1201 	return (SUCCESS);
1202 }
1203 
1204 /*
1205  * Flush handle for write side stream
1206  *
1207  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1208  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
1209  *  -. uinst_t->u_lock : P
1210  *  -. uinst_t->l_lock : P
1211  *  -. uinst_t->c_lock : P
1212  */
1213 void
1214 oplmsu_wcmn_flush_hndl(queue_t *q, mblk_t *mp, krw_t rw)
1215 {
1216 	queue_t	*dst_queue = NULL;
1217 
1218 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
1219 
1220 	if (*mp->b_rptr & FLUSHW) {	/* Write side */
1221 		flushq(q, FLUSHDATA);
1222 	}
1223 
1224 	dst_queue = oplmsu_uinst->lower_queue;
1225 	if (dst_queue == NULL) {
1226 		if (*mp->b_rptr & FLUSHR) {
1227 			flushq(RD(q), FLUSHDATA);
1228 			*mp->b_rptr &= ~FLUSHW;
1229 
1230 			rw_exit(&oplmsu_uinst->lock);
1231 			OPLMSU_TRACE(q, mp, MSU_TRC_UO);
1232 			qreply(q, mp);
1233 			rw_enter(&oplmsu_uinst->lock, rw);
1234 		} else {
1235 			freemsg(mp);
1236 		}
1237 	} else {
1238 		putq(WR(dst_queue), mp);
1239 	}
1240 }
1241 
1242 /*
1243  * Through message handle for write side stream
1244  *
1245  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1246  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
1247  *  -. uinst_t->u_lock : P
1248  *  -. uinst_t->l_lock : P
1249  *  -. uinst_t->c_lock : P
1250  */
1251 int
1252 oplmsu_wcmn_through_hndl(queue_t *q, mblk_t *mp, int pri_flag, krw_t rw)
1253 {
1254 	queue_t	*usr_queue = NULL, *dst_queue = NULL;
1255 	ctrl_t	*ctrl;
1256 
1257 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
1258 
1259 	mutex_enter(&oplmsu_uinst->c_lock);
1260 	if ((ctrl = oplmsu_uinst->user_ctrl) != NULL) {
1261 		usr_queue = ctrl->queue;
1262 		mutex_exit(&oplmsu_uinst->c_lock);
1263 	} else {
1264 		mutex_exit(&oplmsu_uinst->c_lock);
1265 		if (mp->b_datap->db_type == M_IOCTL) {
1266 			rw_exit(&oplmsu_uinst->lock);
1267 			oplmsu_iocack(q, mp, ENODEV);
1268 			rw_enter(&oplmsu_uinst->lock, rw);
1269 		} else {
1270 			freemsg(mp);
1271 		}
1272 		return (SUCCESS);
1273 	}
1274 
1275 	if (oplmsu_uinst->lower_queue != NULL) {
1276 		dst_queue = WR(oplmsu_uinst->lower_queue);
1277 	} else {
1278 		cmn_err(CE_WARN, "!oplmsu: through-lwq: "
1279 		    "Active path doesn't exist");
1280 
1281 		if (mp->b_datap->db_type == M_IOCTL) {
1282 			rw_exit(&oplmsu_uinst->lock);
1283 			oplmsu_iocack(q, mp, ENODEV);
1284 			rw_enter(&oplmsu_uinst->lock, rw);
1285 		} else {
1286 			freemsg(mp);
1287 		}
1288 		return (SUCCESS);
1289 	}
1290 
1291 	if ((usr_queue == WR(q)) || (usr_queue == RD(q))) {
1292 		if (pri_flag == MSU_HIGH) {
1293 			putq(dst_queue, mp);
1294 		} else {
1295 			if (canput(dst_queue)) {
1296 				putq(dst_queue, mp);
1297 			} else {
1298 				oplmsu_wcmn_norm_putbq(WR(q), mp, dst_queue);
1299 				return (FAILURE);
1300 			}
1301 		}
1302 	} else {
1303 		cmn_err(CE_WARN, "oplmsu: through-lwq: "
1304 		    "Inappropriate message for this node");
1305 
1306 		if (mp->b_datap->db_type == M_IOCTL) {
1307 			rw_exit(&oplmsu_uinst->lock);
1308 			oplmsu_iocack(q, mp, ENODEV);
1309 			rw_enter(&oplmsu_uinst->lock, rw);
1310 		} else {
1311 			freemsg(mp);
1312 		}
1313 	}
1314 	return (SUCCESS);
1315 }
1316 
1317 /*
1318  * Get high priority message from buffer for upper write stream
1319  *
1320  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1321  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
1322  *  -. uinst_t->u_lock : A
1323  *  -. uinst_t->l_lock : A
1324  *  -. uinst_t->c_lock : P
1325  */
1326 mblk_t *
1327 oplmsu_wcmn_high_getq(queue_t *uwq)
1328 {
1329 	mblk_t	*mp;
1330 	ctrl_t	*ctrl;
1331 
1332 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
1333 
1334 	mutex_enter(&oplmsu_uinst->c_lock);
1335 	ctrl = (ctrl_t *)uwq->q_ptr;
1336 	mp = ctrl->first_upri_hi;
1337 	if (mp != NULL) {
1338 		if (mp->b_next == NULL) {
1339 			ctrl->first_upri_hi = NULL;
1340 			ctrl->last_upri_hi = NULL;
1341 		} else {
1342 			ctrl->first_upri_hi = mp->b_next;
1343 			mp->b_next->b_prev = NULL;
1344 			mp->b_next = NULL;
1345 		}
1346 		mp->b_prev = NULL;
1347 	}
1348 	mutex_exit(&oplmsu_uinst->c_lock);
1349 	return (mp);
1350 }
1351 
1352 /*
1353  * putbq() function for normal priority message of write stream
1354  *
1355  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1356  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
1357  *  -. uinst_t->u_lock : A
1358  *  -. uinst_t->l_lock : P
1359  *  -. uinst_t->c_lock : P
1360  */
1361 void
1362 oplmsu_wcmn_norm_putbq(queue_t *uwq, mblk_t *mp, queue_t *dq)
1363 {
1364 	lpath_t	*lpath;
1365 
1366 	ASSERT(mp != NULL);
1367 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
1368 
1369 	mutex_enter(&oplmsu_uinst->l_lock);
1370 	lpath = (lpath_t *)dq->q_ptr;
1371 	lpath->uwq_flag = 1;
1372 	lpath->uwq_queue = uwq;
1373 	mutex_exit(&oplmsu_uinst->l_lock);
1374 	putbq(uwq, mp);
1375 }
1376 
1377 /*
1378  * Restart queuing for high priority message of write stream when flow control
1379  * failed
1380  *
1381  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1382  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
1383  *  -. uinst_t->u_lock : P
1384  *  -. uinst_t->l_lock : P
1385  *  -. uinst_t->c_lock : P
1386  */
1387 void
1388 oplmsu_wcmn_high_qenable(queue_t *q, krw_t rw)
1389 {
1390 	mblk_t	*mp;
1391 
1392 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
1393 
1394 	if (oplmsu_queue_flag == 1) {
1395 		return;
1396 	}
1397 
1398 	/* Handle high priority message */
1399 	while (mp = oplmsu_wcmn_high_getq(WR(q))) {
1400 		if (mp->b_datap->db_type & M_FLUSH) {
1401 			oplmsu_wcmn_flush_hndl(q, mp, rw);
1402 			continue;
1403 		}
1404 
1405 		if (oplmsu_wcmn_through_hndl(q, mp, MSU_HIGH, rw) == FAILURE) {
1406 			return;
1407 		}
1408 	}
1409 	qenable(WR(q));	/* enable upper write queue */
1410 }
1411 
1412 /*
1413  *	COMMON FUNCTIONS FOR READ STREAM
1414  */
1415 
1416 /*
1417  * Flush handle for read side stream
1418  *
1419  * Requires lock ( M: mandatory  P: prohibited  A: allowed
1420  *  -. uinst_t->lock   : M [RW_READER]
1421  *  -. uinst_t->u_lock : P
1422  *  -. uinst_t->l_lock : P
1423  *  -. uinst_t->c_lock : P
1424  */
1425 void
1426 oplmsu_rcmn_flush_hndl(queue_t *q, mblk_t *mp)
1427 {
1428 	queue_t	*dst_queue = NULL;
1429 	ctrl_t	*ctrl;
1430 
1431 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
1432 
1433 	if (*mp->b_rptr & FLUSHR) {
1434 		/* Remove only data messages from read queue */
1435 		flushq(q, FLUSHDATA);
1436 	}
1437 
1438 	mutex_enter(&oplmsu_uinst->c_lock);
1439 	if ((ctrl = oplmsu_uinst->user_ctrl) != NULL) {
1440 		dst_queue = RD(ctrl->queue);
1441 		mutex_exit(&oplmsu_uinst->c_lock);
1442 
1443 		if (dst_queue != NULL) {
1444 			putq(dst_queue, mp);
1445 		} else {
1446 			if (*mp->b_rptr & FLUSHW) {
1447 				flushq(WR(q), FLUSHDATA);
1448 				*mp->b_rptr &= ~FLUSHR;
1449 
1450 				rw_exit(&oplmsu_uinst->lock);
1451 				OPLMSU_TRACE(q, mp, MSU_TRC_LO);
1452 				qreply(q, mp);
1453 				rw_enter(&oplmsu_uinst->lock, RW_READER);
1454 			} else {
1455 				freemsg(mp);
1456 			}
1457 		}
1458 	} else {
1459 		mutex_exit(&oplmsu_uinst->c_lock);
1460 		if (*mp->b_rptr & FLUSHW) {
1461 			flushq(WR(q), FLUSHDATA);
1462 			*mp->b_rptr &= ~FLUSHR;
1463 
1464 			rw_exit(&oplmsu_uinst->lock);
1465 			OPLMSU_TRACE(q, mp, MSU_TRC_LO);
1466 			qreply(q, mp);
1467 			rw_enter(&oplmsu_uinst->lock, RW_READER);
1468 		} else {
1469 			freemsg(mp);
1470 		}
1471 	}
1472 }
1473 
1474 /*
1475  * Through message handle for read side stream
1476  *
1477  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1478  *  -. uinst_t->lock   : M [RW_READER]
1479  *  -. uinst_t->u_lock : A
1480  *  -. uinst_t->l_lock : P
1481  *  -. uinst_t->c_lock : P
1482  */
1483 int
1484 oplmsu_rcmn_through_hndl(queue_t *q, mblk_t *mp, int pri_flag)
1485 {
1486 	lpath_t	*lpath;
1487 	ctrl_t	*ctrl;
1488 	queue_t	*dst_queue = NULL;
1489 	int	act_flag;
1490 
1491 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
1492 
1493 	mutex_enter(&oplmsu_uinst->l_lock);
1494 	lpath = (lpath_t *)q->q_ptr;
1495 	if (lpath->uinst != NULL) {
1496 		act_flag = ACTIVE_RES;
1497 	} else {
1498 		act_flag = NOT_ACTIVE_RES;
1499 	}
1500 	mutex_exit(&oplmsu_uinst->l_lock);
1501 
1502 	mutex_enter(&oplmsu_uinst->c_lock);
1503 	if (((ctrl = oplmsu_uinst->user_ctrl) != NULL) &&
1504 	    (((mp->b_datap->db_type == M_IOCACK) ||
1505 	    (mp->b_datap->db_type == M_IOCNAK)) || (act_flag == ACTIVE_RES))) {
1506 		dst_queue = RD(ctrl->queue);
1507 	} else {
1508 		mutex_exit(&oplmsu_uinst->c_lock);
1509 		freemsg(mp);
1510 		return (SUCCESS);
1511 	}
1512 
1513 	if (pri_flag == MSU_HIGH) {
1514 		putq(dst_queue, mp);
1515 	} else {
1516 		if (canput(dst_queue)) {
1517 			putq(dst_queue, mp);
1518 		} else {
1519 			/*
1520 			 * Place a normal priority message at the head of
1521 			 * read queue
1522 			 */
1523 
1524 			ctrl = (ctrl_t *)dst_queue->q_ptr;
1525 			ctrl->lrq_flag = 1;
1526 			ctrl->lrq_queue = q;
1527 			mutex_exit(&oplmsu_uinst->c_lock);
1528 			putbq(q, mp);
1529 			return (FAILURE);
1530 		}
1531 	}
1532 	mutex_exit(&oplmsu_uinst->c_lock);
1533 	return (SUCCESS);
1534 }
1535 
1536 /*
1537  * Restart queuing for high priority message of read stream
1538  * when flow control failed
1539  *
1540  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1541  *  -. uinst_t->lock   : P
1542  *  -. uinst_t->u_lock : P
1543  *  -. uinst_t->l_lock : P
1544  *  -. uinst_t->c_lock : P
1545  */
1546 void
1547 oplmsu_rcmn_high_qenable(queue_t *q)
1548 {
1549 	mblk_t		*mp;
1550 	struct iocblk	*iocp = NULL;
1551 	lpath_t		*lpath;
1552 	int		rval;
1553 
1554 	rw_enter(&oplmsu_uinst->lock, RW_READER);
1555 
1556 	for (;;) {	/* Handle high priority message */
1557 		mutex_enter(&oplmsu_uinst->l_lock);
1558 		lpath = (lpath_t *)q->q_ptr;
1559 		if ((mp = lpath->first_lpri_hi) == NULL) {
1560 			mutex_exit(&oplmsu_uinst->l_lock);
1561 			break;
1562 		}
1563 
1564 		if (mp->b_next == NULL) {
1565 			lpath->first_lpri_hi = NULL;
1566 			lpath->last_lpri_hi = NULL;
1567 		} else {
1568 			lpath->first_lpri_hi = mp->b_next;
1569 			mp->b_next->b_prev = NULL;
1570 			mp->b_next = NULL;
1571 		}
1572 		mp->b_prev = NULL;
1573 		mutex_exit(&oplmsu_uinst->l_lock);
1574 
1575 		rval = SUCCESS;
1576 		switch (mp->b_datap->db_type) {
1577 		case M_IOCACK :		/* FALLTHRU */
1578 		case M_IOCNAK :
1579 			iocp = (struct iocblk *)mp->b_rptr;
1580 			switch (iocp->ioc_cmd) {
1581 			case TCSETS :		/* FALLTHRU */
1582 			case TCSETSW :		/* FALLTHRU */
1583 			case TCSETSF :		/* FALLTHRU */
1584 			case TIOCMSET :		/* FALLTHRU */
1585 			case TIOCSPPS :		/* FALLTHRU */
1586 			case TIOCSWINSZ :	/* FALLTHRU */
1587 			case TIOCSSOFTCAR :
1588 				rw_exit(&oplmsu_uinst->lock);
1589 				rval = oplmsu_lrioctl_termios(q, mp);
1590 				rw_enter(&oplmsu_uinst->lock, RW_WRITER);
1591 				break;
1592 
1593 			default :
1594 				rval = oplmsu_rcmn_through_hndl(
1595 				    q, mp, MSU_HIGH);
1596 				if (rval == FAILURE) {
1597 					rw_exit(&oplmsu_uinst->lock);
1598 					return;
1599 				}
1600 			}
1601 			break;
1602 
1603 		case M_ERROR :
1604 			rw_exit(&oplmsu_uinst->lock);
1605 			rval = oplmsu_lrmsg_error(q, mp);
1606 			rw_enter(&oplmsu_uinst->lock, RW_WRITER);
1607 			break;
1608 
1609 		case M_FLUSH :
1610 			oplmsu_rcmn_flush_hndl(q, mp);
1611 			break;
1612 
1613 		default :
1614 			rval = oplmsu_rcmn_through_hndl(q, mp, MSU_HIGH);
1615 			if (rval == FAILURE) {
1616 				rw_exit(&oplmsu_uinst->lock);
1617 				return;
1618 			}
1619 		}
1620 
1621 		if (rval == FAILURE) {
1622 			break;
1623 		}
1624 	}
1625 
1626 	rw_exit(&oplmsu_uinst->lock);
1627 	qenable(q);	/* Enable lower read queue */
1628 }
1629 
1630 #ifdef DEBUG
1631 /*
1632  * Online trace
1633  *
1634  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1635  *  -. uinst_t->lock   : P
1636  *  -. uinst_t->u_lock : P
1637  *  -. uinst_t->l_lock : P
1638  *  -. uinst_t->c_lock : P
1639  */
1640 void
1641 oplmsu_cmn_trace(queue_t *q, mblk_t *mp, int op)
1642 {
1643 	struct iocblk	*iocp;
1644 
1645 	if ((op < MSU_TRC_UI) || (op > MSU_TRC_CLS)) {
1646 		return;
1647 	}
1648 
1649 	mutex_enter(&oplmsu_ltrc_lock);
1650 
1651 	if (oplmsu_debug_mode & MSU_DPRINT_ON) {
1652 		oplmsu_cmn_msglog(mp, op);
1653 	}
1654 
1655 	/* Trace current counter */
1656 	drv_getparm(LBOLT, (void *)&oplmsu_ltrc_ccnt);
1657 
1658 	if (oplmsu_ltrc_cur == oplmsu_ltrc_tail) {
1659 		oplmsu_ltrc_cur = oplmsu_ltrc_top;
1660 	} else {
1661 		oplmsu_ltrc_cur++;
1662 	}
1663 	oplmsu_ltrc_cur->q = q;
1664 	oplmsu_ltrc_cur->mp = mp;
1665 
1666 	switch (op) {
1667 	case MSU_TRC_UI :
1668 		oplmsu_ltrc_cur->op[0] = 'u';
1669 		oplmsu_ltrc_cur->op[1] = 'i';
1670 		break;
1671 
1672 	case MSU_TRC_UO :
1673 		oplmsu_ltrc_cur->op[0] = 'u';
1674 		oplmsu_ltrc_cur->op[1] = 'o';
1675 		break;
1676 
1677 	case MSU_TRC_LI :
1678 		oplmsu_ltrc_cur->op[0] = 'l';
1679 		oplmsu_ltrc_cur->op[1] = 'i';
1680 		break;
1681 
1682 	case MSU_TRC_LO :
1683 		oplmsu_ltrc_cur->op[0] = 'l';
1684 		oplmsu_ltrc_cur->op[1] = 'o';
1685 		break;
1686 
1687 	case MSU_TRC_OPN :
1688 		oplmsu_ltrc_cur->op[0] = 'o';
1689 		oplmsu_ltrc_cur->op[1] = 'p';
1690 		break;
1691 
1692 	case MSU_TRC_CLS :
1693 		oplmsu_ltrc_cur->op[0] = 'c';
1694 		oplmsu_ltrc_cur->op[1] = 'l';
1695 		break;
1696 	}
1697 
1698 	if ((op == MSU_TRC_LI) || (op == MSU_TRC_LO)) {
1699 		mutex_enter(&oplmsu_uinst->l_lock);
1700 		oplmsu_ltrc_cur->pathno = ((lpath_t *)q->q_ptr)->path_no;
1701 		mutex_exit(&oplmsu_uinst->l_lock);
1702 	} else {
1703 		oplmsu_ltrc_cur->pathno = 0;
1704 	}
1705 
1706 	if ((op == MSU_TRC_OPN) || (op == MSU_TRC_CLS)) {
1707 		oplmsu_ltrc_cur->msg_type = 0;
1708 		oplmsu_ltrc_cur->msg_cmd = 0;
1709 		oplmsu_ltrc_cur->data = 0;
1710 
1711 		switch ((ulong_t)mp) {
1712 		case MSU_NODE_USER :
1713 			oplmsu_ltrc_cur->data = MSU_TRC_USER;
1714 			break;
1715 
1716 		case MSU_NODE_META :
1717 			oplmsu_ltrc_cur->data = MSU_TRC_META;
1718 			break;
1719 		}
1720 		oplmsu_ltrc_cur->mp = NULL;
1721 	} else {
1722 		oplmsu_ltrc_cur->msg_type = mp->b_datap->db_type;
1723 		iocp = (struct iocblk *)mp->b_rptr;
1724 		oplmsu_ltrc_cur->msg_cmd = iocp->ioc_cmd;
1725 
1726 		if ((mp->b_datap->db_type == M_IOCTL) ||
1727 		    (mp->b_datap->db_type == M_IOCACK) ||
1728 		    (mp->b_datap->db_type == M_IOCNAK)) {
1729 			oplmsu_ltrc_cur->msg_cmd = iocp->ioc_cmd;
1730 
1731 			if (mp->b_cont != NULL) {
1732 				oplmsu_ltrc_cur->data =
1733 				    (ulong_t)mp->b_cont->b_rptr;
1734 			} else {
1735 				oplmsu_ltrc_cur->data = 0;
1736 			}
1737 		} else {
1738 			oplmsu_ltrc_cur->msg_cmd = 0;
1739 
1740 			if (mp->b_rptr == NULL) {
1741 				oplmsu_ltrc_cur->data = 0;
1742 			} else {
1743 				oplmsu_ltrc_cur->data = *(ulong_t *)mp->b_rptr;
1744 			}
1745 		}
1746 	}
1747 	mutex_exit(&oplmsu_ltrc_lock);
1748 }
1749 
1750 /*
1751  * Display message log to console
1752  *
1753  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1754  *  -. uinst_t->lock   : P
1755  *  -. uinst_t->u_lock : P
1756  *  -. uinst_t->l_lock : P
1757  *  -. uinst_t->c_lock : P
1758  */
1759 void
1760 oplmsu_cmn_msglog(mblk_t *mp, int direction)
1761 {
1762 	uchar_t	*cur = NULL;
1763 	mblk_t	*tmp_mp = NULL;
1764 	ulong_t	len;
1765 	ulong_t	line;
1766 	ulong_t	col;
1767 	ulong_t	row;
1768 	ulong_t	count;
1769 	char	buffer[70];
1770 	char	*bufp;
1771 
1772 	if (mp == NULL) {
1773 		return;
1774 	}
1775 
1776 	switch (direction) {
1777 	case 0:
1778 		cmn_err(CE_NOTE, "!---------- Upper in --------");
1779 		break;
1780 
1781 	case 1:
1782 		cmn_err(CE_NOTE, "!---------- Upper out -------");
1783 		break;
1784 
1785 	case 2:
1786 		cmn_err(CE_NOTE, "!---------- Lower in --------");
1787 		break;
1788 
1789 	case 3:
1790 		cmn_err(CE_NOTE, "!---------- Lower out -------");
1791 		break;
1792 
1793 	default:
1794 		return;
1795 	}
1796 
1797 	for (tmp_mp = mp; tmp_mp; tmp_mp = tmp_mp->b_cont) {
1798 		cmn_err(CE_NOTE, "!db_type = 0x%02x", tmp_mp->b_datap->db_type);
1799 
1800 		len = tmp_mp->b_wptr - tmp_mp->b_rptr;
1801 		line = (len + 31) / 32;
1802 		cur = (uchar_t *)tmp_mp->b_rptr;
1803 		count = 0;
1804 
1805 		for (col = 0; col < line; col++) {
1806 			bufp = buffer;
1807 
1808 			for (row = 0; row < 32; row++) {
1809 				if (row != 0 && (row % 8) == 0) {
1810 					*bufp = ' ';
1811 					bufp++;
1812 				}
1813 				sprintf(bufp, "%02x", *cur);
1814 				bufp += 2;
1815 				cur++;
1816 				count++;
1817 
1818 				if (count >= len) {
1819 					break;
1820 				}
1821 			}
1822 			*bufp = '\0';
1823 			cmn_err(CE_NOTE, "!%s", buffer);
1824 
1825 			if (count >= len) {
1826 				break;
1827 			}
1828 		}
1829 	}
1830 }
1831 
1832 void
1833 oplmsu_cmn_prt_pathname(dev_info_t *dip)
1834 {
1835 	char	pathname[128];
1836 	char	wrkbuf[128];
1837 
1838 	ddi_pathname(dip, wrkbuf);
1839 	*(wrkbuf + strlen(wrkbuf)) = '\0';
1840 	sprintf(pathname, "/devices%s:%c", wrkbuf, 'a'+ ddi_get_instance(dip));
1841 
1842 	DBG_PRINT((CE_NOTE, "oplmsu: debug-info: "
1843 	    "Active path change to path => %s", pathname));
1844 }
1845 #endif
1846