xref: /illumos-gate/usr/src/uts/sun4u/opl/io/oplmsu/oplmsu_cmn_func.c (revision 07d06da50d310a325b457d6330165aebab1e0064)
125cf1a30Sjl /*
225cf1a30Sjl  * CDDL HEADER START
325cf1a30Sjl  *
425cf1a30Sjl  * The contents of this file are subject to the terms of the
525cf1a30Sjl  * Common Development and Distribution License (the "License").
625cf1a30Sjl  * You may not use this file except in compliance with the License.
725cf1a30Sjl  *
825cf1a30Sjl  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
925cf1a30Sjl  * or http://www.opensolaris.org/os/licensing.
1025cf1a30Sjl  * See the License for the specific language governing permissions
1125cf1a30Sjl  * and limitations under the License.
1225cf1a30Sjl  *
1325cf1a30Sjl  * When distributing Covered Code, include this CDDL HEADER in each
1425cf1a30Sjl  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1525cf1a30Sjl  * If applicable, add the following below this CDDL HEADER, with the
1625cf1a30Sjl  * fields enclosed by brackets "[]" replaced with your own identifying
1725cf1a30Sjl  * information: Portions Copyright [yyyy] [name of copyright owner]
1825cf1a30Sjl  *
1925cf1a30Sjl  * CDDL HEADER END
2025cf1a30Sjl  */
2125cf1a30Sjl /*
2225cf1a30Sjl  * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006
2325cf1a30Sjl  */
2425cf1a30Sjl 
2525cf1a30Sjl #include <sys/errno.h>
2625cf1a30Sjl #include <sys/modctl.h>
2725cf1a30Sjl #include <sys/stat.h>
2825cf1a30Sjl #include <sys/kmem.h>
2925cf1a30Sjl #include <sys/ksynch.h>
3025cf1a30Sjl #include <sys/stream.h>
3125cf1a30Sjl #include <sys/stropts.h>
3225cf1a30Sjl #include <sys/termio.h>
3325cf1a30Sjl #include <sys/ddi.h>
3425cf1a30Sjl #include <sys/file.h>
3525cf1a30Sjl #include <sys/disp.h>
3625cf1a30Sjl #include <sys/sunddi.h>
3725cf1a30Sjl #include <sys/sunldi.h>
3825cf1a30Sjl #include <sys/sunndi.h>
3925cf1a30Sjl #include <sys/strsun.h>
4025cf1a30Sjl #include <sys/oplmsu/oplmsu.h>
4125cf1a30Sjl #include <sys/oplmsu/oplmsu_proto.h>
4225cf1a30Sjl 
4325cf1a30Sjl /*
4425cf1a30Sjl  * Link upper_path_table structure
4525cf1a30Sjl  *
4625cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
4725cf1a30Sjl  *  -. uinst_t->lock   : M [RW_WRITER]
4825cf1a30Sjl  *  -. uinst_t->u_lock : M
4925cf1a30Sjl  *  -. uinst_t->l_lock : A
5025cf1a30Sjl  *  -. uinst_t->c_lock : A
5125cf1a30Sjl  */
5225cf1a30Sjl void
5325cf1a30Sjl oplmsu_link_upath(upath_t *add_upath)
5425cf1a30Sjl {
5525cf1a30Sjl 
5625cf1a30Sjl 	ASSERT(add_upath != NULL);
5725cf1a30Sjl 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
5825cf1a30Sjl 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
5925cf1a30Sjl 
6025cf1a30Sjl 	if (oplmsu_uinst->first_upath == NULL) {
6125cf1a30Sjl 		oplmsu_uinst->first_upath = add_upath;
6225cf1a30Sjl 		add_upath->u_prev = NULL;
6325cf1a30Sjl 	} else {
6425cf1a30Sjl 		upath_t	*last_upath;
6525cf1a30Sjl 
6625cf1a30Sjl 		last_upath = oplmsu_uinst->last_upath;
6725cf1a30Sjl 		last_upath->u_next = add_upath;
6825cf1a30Sjl 		add_upath->u_prev = last_upath;
6925cf1a30Sjl 	}
7025cf1a30Sjl 
7125cf1a30Sjl 	oplmsu_uinst->last_upath = add_upath;
7225cf1a30Sjl 	add_upath->u_next = NULL;
7325cf1a30Sjl }
7425cf1a30Sjl 
7525cf1a30Sjl /*
7625cf1a30Sjl  * Unlink upper_path_table structure
7725cf1a30Sjl  *
7825cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
7925cf1a30Sjl  *  -. uinst_t->lock   : M [RW_WRITER]
8025cf1a30Sjl  *  -. uinst_t->u_lock : P
8125cf1a30Sjl  *  -. uinst_t->l_lock : P
8225cf1a30Sjl  *  -. uinst_t->c_lock : P
8325cf1a30Sjl  */
8425cf1a30Sjl void
8525cf1a30Sjl oplmsu_unlink_upath(upath_t *del_upath)
8625cf1a30Sjl {
8725cf1a30Sjl 	upath_t **first, **last;
8825cf1a30Sjl 
8925cf1a30Sjl 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
9025cf1a30Sjl 
9125cf1a30Sjl 	first = &oplmsu_uinst->first_upath;
9225cf1a30Sjl 	last = &oplmsu_uinst->last_upath;
9325cf1a30Sjl 
9425cf1a30Sjl 	if ((*first != del_upath) && (*last != del_upath)) {
9525cf1a30Sjl 		del_upath->u_prev->u_next = del_upath->u_next;
9625cf1a30Sjl 		del_upath->u_next->u_prev = del_upath->u_prev;
9725cf1a30Sjl 	} else {
9825cf1a30Sjl 		if (*first == del_upath) {
9925cf1a30Sjl 			*first = (*first)->u_next;
10025cf1a30Sjl 			if (*first) {
10125cf1a30Sjl 				(*first)->u_prev = NULL;
10225cf1a30Sjl 			}
10325cf1a30Sjl 		}
10425cf1a30Sjl 
10525cf1a30Sjl 		if (*last == del_upath) {
10625cf1a30Sjl 			*last = (*last)->u_prev;
10725cf1a30Sjl 			if (*last) {
10825cf1a30Sjl 				(*last)->u_next = NULL;
10925cf1a30Sjl 			}
11025cf1a30Sjl 		}
11125cf1a30Sjl 	}
11225cf1a30Sjl 
11325cf1a30Sjl 	del_upath->u_next = NULL;
11425cf1a30Sjl 	del_upath->u_prev = NULL;
11525cf1a30Sjl }
11625cf1a30Sjl 
11725cf1a30Sjl /*
11825cf1a30Sjl  * Link lower_path_table structure
11925cf1a30Sjl  *
12025cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
12125cf1a30Sjl  *  -. uinst_t->lock   : M [RW_WRITER]
12225cf1a30Sjl  *  -. uinst_t->u_lock : A
12325cf1a30Sjl  *  -. uinst_t->l_lock : M
12425cf1a30Sjl  *  -. uinst_t->c_lock : A
12525cf1a30Sjl  */
12625cf1a30Sjl void
12725cf1a30Sjl oplmsu_link_lpath(lpath_t *add_lpath)
12825cf1a30Sjl {
12925cf1a30Sjl 
13025cf1a30Sjl 	ASSERT(add_lpath != NULL);
13125cf1a30Sjl 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
13225cf1a30Sjl 
13325cf1a30Sjl 	if (oplmsu_uinst->first_lpath == NULL) {
13425cf1a30Sjl 		oplmsu_uinst->first_lpath = add_lpath;
13525cf1a30Sjl 		add_lpath->l_prev = NULL;
13625cf1a30Sjl 	} else {
13725cf1a30Sjl 		lpath_t	*last_lpath;
13825cf1a30Sjl 
13925cf1a30Sjl 		last_lpath = oplmsu_uinst->last_lpath;
14025cf1a30Sjl 		last_lpath->l_next = add_lpath;
14125cf1a30Sjl 		add_lpath->l_prev = last_lpath;
14225cf1a30Sjl 	}
14325cf1a30Sjl 
14425cf1a30Sjl 	oplmsu_uinst->last_lpath = add_lpath;
14525cf1a30Sjl 	add_lpath->l_next = NULL;
14625cf1a30Sjl }
14725cf1a30Sjl 
14825cf1a30Sjl /*
14925cf1a30Sjl  * Unlink lower_path_table structure
15025cf1a30Sjl  *
15125cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
15225cf1a30Sjl  *  -. uinst_t->lock   : M [RW_WRITER]
15325cf1a30Sjl  *  -. uinst_t->u_lock : P
15425cf1a30Sjl  *  -. uinst_t->l_lock : P
15525cf1a30Sjl  *  -. uinst_t->c_lock : P
15625cf1a30Sjl  */
15725cf1a30Sjl void
15825cf1a30Sjl oplmsu_unlink_lpath(lpath_t *del_lpath)
15925cf1a30Sjl {
16025cf1a30Sjl 	lpath_t **first, **last;
16125cf1a30Sjl 
16225cf1a30Sjl 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
16325cf1a30Sjl 
16425cf1a30Sjl 	first = &oplmsu_uinst->first_lpath;
16525cf1a30Sjl 	last = &oplmsu_uinst->last_lpath;
16625cf1a30Sjl 
16725cf1a30Sjl 	if ((*first != del_lpath) && (*last != del_lpath)) {
16825cf1a30Sjl 		del_lpath->l_prev->l_next = del_lpath->l_next;
16925cf1a30Sjl 		del_lpath->l_next->l_prev = del_lpath->l_prev;
17025cf1a30Sjl 	} else {
17125cf1a30Sjl 		if (*first == del_lpath) {
17225cf1a30Sjl 			*first = (*first)->l_next;
17325cf1a30Sjl 			if (*first) {
17425cf1a30Sjl 				(*first)->l_prev = NULL;
17525cf1a30Sjl 			}
17625cf1a30Sjl 		}
17725cf1a30Sjl 
17825cf1a30Sjl 		if (*last == del_lpath) {
17925cf1a30Sjl 			*last = (*last)->l_prev;
18025cf1a30Sjl 			if (*last) {
18125cf1a30Sjl 				(*last)->l_next = NULL;
18225cf1a30Sjl 			}
18325cf1a30Sjl 		}
18425cf1a30Sjl 	}
18525cf1a30Sjl 
18625cf1a30Sjl 	del_lpath->l_next = NULL;
18725cf1a30Sjl 	del_lpath->l_prev = NULL;
18825cf1a30Sjl }
18925cf1a30Sjl 
19025cf1a30Sjl /*
19125cf1a30Sjl  * Link msgb structure of high priority
19225cf1a30Sjl  *
19325cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
19425cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER]
19525cf1a30Sjl  *  -. uinst_t->u_lock : A
19625cf1a30Sjl  *  -. uinst_t->l_lock : A [It depends on caller]
19725cf1a30Sjl  *  -. uinst_t->c_lock : A [It depends on caller]
19825cf1a30Sjl  */
19925cf1a30Sjl void
20025cf1a30Sjl oplmsu_link_high_primsg(mblk_t **first, mblk_t **last, mblk_t *add_msg)
20125cf1a30Sjl {
20225cf1a30Sjl 
20325cf1a30Sjl 	ASSERT(add_msg != NULL);
20425cf1a30Sjl 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
20525cf1a30Sjl 
20625cf1a30Sjl 	if (*first == NULL) {
20725cf1a30Sjl 		*first = add_msg;
20825cf1a30Sjl 		add_msg->b_prev = NULL;
20925cf1a30Sjl 	} else {
21025cf1a30Sjl 		(*last)->b_next = add_msg;
21125cf1a30Sjl 		add_msg->b_prev = *last;
21225cf1a30Sjl 	}
21325cf1a30Sjl 
21425cf1a30Sjl 	*last = add_msg;
21525cf1a30Sjl 	add_msg->b_next = NULL;
21625cf1a30Sjl }
21725cf1a30Sjl 
21825cf1a30Sjl /*
21925cf1a30Sjl  * Check whether lower path is usable by lower path info table address
22025cf1a30Sjl  *
22125cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
22225cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
22325cf1a30Sjl  *  -. uinst_t->u_lock : A
22425cf1a30Sjl  *  -. uinst_t->l_lock : M
22525cf1a30Sjl  *  -. uinst_t->c_lock : P
22625cf1a30Sjl  */
22725cf1a30Sjl int
22825cf1a30Sjl oplmsu_check_lpath_usable(void)
22925cf1a30Sjl {
23025cf1a30Sjl 	lpath_t	*lpath;
23125cf1a30Sjl 	int	rval = SUCCESS;
23225cf1a30Sjl 
23325cf1a30Sjl 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
23425cf1a30Sjl 	ASSERT(MUTEX_HELD(&oplmsu_uinst->l_lock));
23525cf1a30Sjl 
23625cf1a30Sjl 	lpath = oplmsu_uinst->first_lpath;
23725cf1a30Sjl 	while (lpath) {
23825cf1a30Sjl 		if ((lpath->hndl_uqueue != NULL) || (lpath->hndl_mp != NULL)) {
23925cf1a30Sjl 			rval = BUSY;
24025cf1a30Sjl 			break;
24125cf1a30Sjl 		}
24225cf1a30Sjl 		lpath = lpath->l_next;
24325cf1a30Sjl 	}
24425cf1a30Sjl 	return (rval);
24525cf1a30Sjl }
24625cf1a30Sjl 
24725cf1a30Sjl /*
24825cf1a30Sjl  * Search upath_t by path number
24925cf1a30Sjl  *
25025cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
25125cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
25225cf1a30Sjl  *  -. uinst_t->u_lock : M
25325cf1a30Sjl  *  -. uinst_t->l_lock : A
25425cf1a30Sjl  *  -. uinst_t->c_lock : P
25525cf1a30Sjl  */
25625cf1a30Sjl upath_t	*
25725cf1a30Sjl oplmsu_search_upath_info(int path_no)
25825cf1a30Sjl {
25925cf1a30Sjl 	upath_t	*upath;
26025cf1a30Sjl 
26125cf1a30Sjl 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
26225cf1a30Sjl 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
26325cf1a30Sjl 
26425cf1a30Sjl 	upath = oplmsu_uinst->first_upath;
26525cf1a30Sjl 	while (upath) {
26625cf1a30Sjl 		if (upath->path_no == path_no) {
26725cf1a30Sjl 			break;
26825cf1a30Sjl 		}
26925cf1a30Sjl 		upath = upath->u_next;
27025cf1a30Sjl 	}
27125cf1a30Sjl 	return (upath);
27225cf1a30Sjl }
27325cf1a30Sjl 
27425cf1a30Sjl /*
27525cf1a30Sjl  * Send M_IOCACK(or M_IOCNAK) message to stream
27625cf1a30Sjl  *
27725cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
27825cf1a30Sjl  *  -. uinst_t->lock   : P
27925cf1a30Sjl  *  -. uinst_t->u_lock : P
28025cf1a30Sjl  *  -. uinst_t->l_lock : P
28125cf1a30Sjl  *  -. uinst_t->c_lock : P
28225cf1a30Sjl  */
28325cf1a30Sjl void
28425cf1a30Sjl oplmsu_iocack(queue_t *q, mblk_t *mp, int errno)
28525cf1a30Sjl {
28625cf1a30Sjl 	struct iocblk	*iocp = NULL;
28725cf1a30Sjl 
28825cf1a30Sjl 	ASSERT(mp != NULL);
28925cf1a30Sjl 
29025cf1a30Sjl 	iocp = (struct iocblk *)mp->b_rptr;
29125cf1a30Sjl 	iocp->ioc_error = errno;
29225cf1a30Sjl 
29325cf1a30Sjl 	if (errno) {	/* Error */
29425cf1a30Sjl 		mp->b_datap->db_type = M_IOCNAK;
29525cf1a30Sjl 		iocp->ioc_rval = FAILURE;
29625cf1a30Sjl 
29725cf1a30Sjl 		OPLMSU_TRACE(q, mp, MSU_TRC_UO);
29825cf1a30Sjl 		qreply(q, mp);
29925cf1a30Sjl 	} else {	/* Good */
30025cf1a30Sjl 		mp->b_datap->db_type = M_IOCACK;
30125cf1a30Sjl 		iocp->ioc_rval = SUCCESS;
30225cf1a30Sjl 
30325cf1a30Sjl 		OPLMSU_TRACE(q, mp, MSU_TRC_UO);
30425cf1a30Sjl 		qreply(q, mp);
30525cf1a30Sjl 	}
30625cf1a30Sjl }
30725cf1a30Sjl 
30825cf1a30Sjl /*
30925cf1a30Sjl  * Delete all upath_t
31025cf1a30Sjl  *
31125cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
31225cf1a30Sjl  *  -. uinst_t->lock   : M [RW_WRITER]
31325cf1a30Sjl  *  -. uinst_t->u_lock : M
31425cf1a30Sjl  *  -. uinst_t->l_lock : A
31525cf1a30Sjl  *  -. uinst_t->c_lock : A
31625cf1a30Sjl  */
31725cf1a30Sjl void
31825cf1a30Sjl oplmsu_delete_upath_info(void)
31925cf1a30Sjl {
32025cf1a30Sjl 	upath_t	*upath, *next_upath;
32125cf1a30Sjl 
32225cf1a30Sjl 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
32325cf1a30Sjl 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
32425cf1a30Sjl 
32525cf1a30Sjl 	upath = oplmsu_uinst->first_upath;
32625cf1a30Sjl 	oplmsu_uinst->first_upath = NULL;
32725cf1a30Sjl 	oplmsu_uinst->last_upath = NULL;
32825cf1a30Sjl 
32925cf1a30Sjl 	while (upath) {
33025cf1a30Sjl 		next_upath = upath->u_next;
33125cf1a30Sjl 		kmem_free(upath, sizeof (upath_t));
33225cf1a30Sjl 		upath = next_upath;
33325cf1a30Sjl 	}
33425cf1a30Sjl }
33525cf1a30Sjl 
33625cf1a30Sjl /*
33725cf1a30Sjl  * Set queue and ioctl to lpath_t
33825cf1a30Sjl  *
33925cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
34025cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
34125cf1a30Sjl  *  -. uinst_t->u_lock : A
34225cf1a30Sjl  *  -. uinst_t->l_lock : M
34325cf1a30Sjl  *  -. uinst_t->c_lock : P
34425cf1a30Sjl  */
34525cf1a30Sjl int
34625cf1a30Sjl oplmsu_set_ioctl_path(lpath_t *lpath, queue_t *hndl_queue, mblk_t *mp)
34725cf1a30Sjl {
34825cf1a30Sjl 	int	rval = SUCCESS;
34925cf1a30Sjl 
35025cf1a30Sjl 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
35125cf1a30Sjl 	ASSERT(MUTEX_HELD(&oplmsu_uinst->l_lock));
35225cf1a30Sjl 
35325cf1a30Sjl 	if ((lpath->hndl_uqueue == NULL) && (lpath->hndl_mp == NULL) &&
35425cf1a30Sjl 	    (lpath->sw_flag == 0)) {
35525cf1a30Sjl 		if ((lpath->status == MSU_EXT_NOTUSED) ||
35625cf1a30Sjl 		    (lpath->status == MSU_EXT_ACTIVE_CANDIDATE) ||
35725cf1a30Sjl 		    (lpath->status == MSU_SETID_NU)) {
35825cf1a30Sjl 			if (hndl_queue == NULL) {
35925cf1a30Sjl 				lpath->hndl_uqueue = hndl_queue;
36025cf1a30Sjl 			} else {
36125cf1a30Sjl 				lpath->hndl_uqueue = WR(hndl_queue);
36225cf1a30Sjl 			}
36325cf1a30Sjl 			lpath->hndl_mp = mp;
36425cf1a30Sjl 		} else {
36525cf1a30Sjl 			rval = BUSY;
36625cf1a30Sjl 		}
36725cf1a30Sjl 	} else {
36825cf1a30Sjl 		rval = BUSY;
36925cf1a30Sjl 	}
37025cf1a30Sjl 	return (rval);
37125cf1a30Sjl }
37225cf1a30Sjl 
37325cf1a30Sjl /*
37425cf1a30Sjl  * Clear queue and ioctl to lpath_t
37525cf1a30Sjl  *
37625cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
37725cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
37825cf1a30Sjl  *  -. uinst_t->u_lock : A
37925cf1a30Sjl  *  -. uinst_t->l_lock : M
38025cf1a30Sjl  *  -. uinst_t->c_lock : P
38125cf1a30Sjl  */
38225cf1a30Sjl void
38325cf1a30Sjl oplmsu_clear_ioctl_path(lpath_t *lpath)
38425cf1a30Sjl {
38525cf1a30Sjl 
38625cf1a30Sjl 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
38725cf1a30Sjl 	ASSERT(MUTEX_HELD(&oplmsu_uinst->l_lock));
38825cf1a30Sjl 
38925cf1a30Sjl 	lpath->hndl_uqueue = NULL;
39025cf1a30Sjl 	lpath->hndl_mp = NULL;
39125cf1a30Sjl }
39225cf1a30Sjl 
39325cf1a30Sjl /*
39425cf1a30Sjl  * Get instanse status from status of upath_t
39525cf1a30Sjl  *
39625cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
39725cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
39825cf1a30Sjl  *  -. uinst_t->u_lock : M
39925cf1a30Sjl  *  -. uinst_t->l_lock : A
40025cf1a30Sjl  *  -. uinst_t->c_lock : P
40125cf1a30Sjl  */
40225cf1a30Sjl int
40325cf1a30Sjl oplmsu_get_inst_status(void)
40425cf1a30Sjl {
40525cf1a30Sjl 	upath_t	*upath;
40625cf1a30Sjl 	int	sts, pre_sts = INST_STAT_UNCONFIGURED;
40725cf1a30Sjl 
40825cf1a30Sjl 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
40925cf1a30Sjl 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
41025cf1a30Sjl 
41125cf1a30Sjl 	upath = oplmsu_uinst->first_upath;
41225cf1a30Sjl 	while (upath) {
41325cf1a30Sjl 		if (((upath->status == MSU_PSTAT_ACTIVE) &&
41425cf1a30Sjl 		    (upath->traditional_status == MSU_ACTIVE)) ||
41525cf1a30Sjl 		    ((upath->status == MSU_PSTAT_STANDBY) &&
41625cf1a30Sjl 		    (upath->traditional_status == MSU_STANDBY))) {
41725cf1a30Sjl 			sts = INST_STAT_ONLINE;
41825cf1a30Sjl 		} else if (((upath->status == MSU_PSTAT_STOP) &&
41925cf1a30Sjl 		    (upath->traditional_status == MSU_STOP)) ||
42025cf1a30Sjl 		    ((upath->status == MSU_PSTAT_FAIL) &&
42125cf1a30Sjl 		    (upath->traditional_status == MSU_FAIL))) {
42225cf1a30Sjl 			sts = INST_STAT_OFFLINE;
42325cf1a30Sjl 		} else if (((upath->status == MSU_PSTAT_DISCON) &&
42425cf1a30Sjl 		    (upath->traditional_status == MSU_DISCON)) ||
42525cf1a30Sjl 		    ((upath->status == MSU_PSTAT_EMPTY) &&
42625cf1a30Sjl 		    (upath->traditional_status == MSU_EMPTY))) {
42725cf1a30Sjl 			sts = INST_STAT_UNCONFIGURED;
42825cf1a30Sjl 		} else {
42925cf1a30Sjl 			sts = INST_STAT_BUSY;
43025cf1a30Sjl 		}
43125cf1a30Sjl 
43225cf1a30Sjl 		if (pre_sts > sts) {
43325cf1a30Sjl 			pre_sts = sts;
43425cf1a30Sjl 		}
43525cf1a30Sjl 		upath = upath->u_next;
43625cf1a30Sjl 	}
43725cf1a30Sjl 	return (pre_sts);
43825cf1a30Sjl }
43925cf1a30Sjl 
44025cf1a30Sjl /*
44125cf1a30Sjl  * Search path of "online:standby" status
44225cf1a30Sjl  *
44325cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
44425cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
44525cf1a30Sjl  *  -. uinst_t->u_lock : M
44625cf1a30Sjl  *  -. uinst_t->l_lock : A
44725cf1a30Sjl  *  -. uinst_t->c_lock : P
44825cf1a30Sjl  */
44925cf1a30Sjl upath_t	*
45025cf1a30Sjl oplmsu_search_standby(void)
45125cf1a30Sjl {
45225cf1a30Sjl 	upath_t	*upath, *altn_upath = NULL;
45325cf1a30Sjl 	int	max_pathnum = UNDEFINED;
45425cf1a30Sjl 
45525cf1a30Sjl 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
45625cf1a30Sjl 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
45725cf1a30Sjl 
45825cf1a30Sjl 	upath = oplmsu_uinst->first_upath;
45925cf1a30Sjl 	while (upath) {
46025cf1a30Sjl 		if ((upath->status == MSU_PSTAT_STANDBY) &&
46125cf1a30Sjl 		    (upath->traditional_status == MSU_STANDBY) &&
46225cf1a30Sjl 		    (upath->lpath != NULL)) {
46325cf1a30Sjl 			if ((max_pathnum == UNDEFINED) ||
46425cf1a30Sjl 			    (max_pathnum > upath->path_no)) {
46525cf1a30Sjl 				max_pathnum = upath->path_no;
46625cf1a30Sjl 				altn_upath = upath;
46725cf1a30Sjl 			}
46825cf1a30Sjl 		}
46925cf1a30Sjl 		upath = upath->u_next;
47025cf1a30Sjl 	}
47125cf1a30Sjl 	return (altn_upath);
47225cf1a30Sjl }
47325cf1a30Sjl 
47425cf1a30Sjl /*
47525cf1a30Sjl  * Search path of "offline:stop" status, and minimum path number
47625cf1a30Sjl  *
47725cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
47825cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
47925cf1a30Sjl  *  -. uinst_t->u_lock : M
48025cf1a30Sjl  *  -. uinst_t->l_lock : P
48125cf1a30Sjl  *  -. uinst_t->c_lock : P
48225cf1a30Sjl  */
48325cf1a30Sjl void
48425cf1a30Sjl oplmsu_search_min_stop_path(void)
48525cf1a30Sjl {
48625cf1a30Sjl 	upath_t	*upath, *min_upath;
48725cf1a30Sjl 	lpath_t	*lpath;
48825cf1a30Sjl 	int	min_no = UNDEFINED;
48925cf1a30Sjl 	int	active_flag = 0;
49025cf1a30Sjl 
49125cf1a30Sjl 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
49225cf1a30Sjl 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
49325cf1a30Sjl 
49425cf1a30Sjl 	upath = oplmsu_uinst->first_upath;
49525cf1a30Sjl 	while (upath) {
49625cf1a30Sjl 		if ((upath->status == MSU_PSTAT_ACTIVE) &&
49725cf1a30Sjl 		    (upath->traditional_status == MSU_ACTIVE)) {
49825cf1a30Sjl 			active_flag = 1;
49925cf1a30Sjl 			break;
50025cf1a30Sjl 		} else if ((upath->status == MSU_PSTAT_STOP) &&
50125cf1a30Sjl 		    (upath->traditional_status == MSU_STOP)) {
50225cf1a30Sjl 			if (upath->lpath != NULL) {
50325cf1a30Sjl 				if ((min_no == UNDEFINED) ||
50425cf1a30Sjl 				    (upath->path_no < min_no)) {
50525cf1a30Sjl 					lpath = upath->lpath;
50625cf1a30Sjl 					mutex_enter(&oplmsu_uinst->l_lock);
50725cf1a30Sjl 					if (lpath->status == MSU_EXT_NOTUSED) {
50825cf1a30Sjl 						min_upath = upath;
50925cf1a30Sjl 						min_no = upath->path_no;
51025cf1a30Sjl 					}
51125cf1a30Sjl 					mutex_exit(&oplmsu_uinst->l_lock);
51225cf1a30Sjl 				}
51325cf1a30Sjl 			}
51425cf1a30Sjl 		}
51525cf1a30Sjl 		upath = upath->u_next;
51625cf1a30Sjl 	}
51725cf1a30Sjl 
51825cf1a30Sjl 	if (active_flag == 0) {
51925cf1a30Sjl 		lpath = min_upath->lpath;
52025cf1a30Sjl 		mutex_enter(&oplmsu_uinst->l_lock);
52125cf1a30Sjl 		lpath->src_upath = NULL;
52225cf1a30Sjl 		lpath->status = MSU_EXT_ACTIVE_CANDIDATE;
52325cf1a30Sjl 		mutex_exit(&oplmsu_uinst->l_lock);
52425cf1a30Sjl 	}
52525cf1a30Sjl }
52625cf1a30Sjl 
52725cf1a30Sjl /*
52825cf1a30Sjl  * Get the total number of serial paths
52925cf1a30Sjl  *
53025cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
53125cf1a30Sjl  *  -. uinst_t->lock   : M [RW_WRITER]
53225cf1a30Sjl  *  -. uinst_t->u_lock : M
53325cf1a30Sjl  *  -. uinst_t->l_lock : A
53425cf1a30Sjl  *  -. uinst_t->c_lock : A
53525cf1a30Sjl  */
53625cf1a30Sjl int
53725cf1a30Sjl oplmsu_get_pathnum(void)
53825cf1a30Sjl {
53925cf1a30Sjl 	upath_t	*upath;
54025cf1a30Sjl 	int	total_num = 0;
54125cf1a30Sjl 
54225cf1a30Sjl 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
54325cf1a30Sjl 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
54425cf1a30Sjl 
54525cf1a30Sjl 	if (oplmsu_uinst->first_upath != NULL) {
54625cf1a30Sjl 		upath = oplmsu_uinst->first_upath;
54725cf1a30Sjl 		while (upath) {
54825cf1a30Sjl 			total_num++;
54925cf1a30Sjl 			upath = upath->u_next;
55025cf1a30Sjl 		}
55125cf1a30Sjl 	}
55225cf1a30Sjl 	return (total_num);
55325cf1a30Sjl }
55425cf1a30Sjl 
55525cf1a30Sjl /*
55625cf1a30Sjl  * Put XOFF/ XON message on write queue
55725cf1a30Sjl  *
55825cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
55925cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
56025cf1a30Sjl  *  -. uinst_t->u_lock : A
56125cf1a30Sjl  *  -. uinst_t->l_lock : A
56225cf1a30Sjl  *  -. uinst_t->c_lock : A
56325cf1a30Sjl  */
56425cf1a30Sjl int
56525cf1a30Sjl oplmsu_cmn_put_xoffxon(queue_t *queue, int data)
56625cf1a30Sjl {
56725cf1a30Sjl 	mblk_t	*mp;
56825cf1a30Sjl 	int	rval = SUCCESS;
56925cf1a30Sjl 
57025cf1a30Sjl 	/* Send M_START */
57125cf1a30Sjl 	if ((mp = allocb(0, BPRI_LO)) != NULL) {
57225cf1a30Sjl 		mp->b_datap->db_type = M_START;
573*07d06da5SSurya Prakki 		(void) putq(queue, mp);
57425cf1a30Sjl 
57525cf1a30Sjl 		/* Send M_DATA(XOFF, XON) */
57625cf1a30Sjl 		if ((mp = allocb(sizeof (int), BPRI_LO)) != NULL) {
57725cf1a30Sjl 			*(uint_t *)mp->b_rptr = data;
57825cf1a30Sjl 			mp->b_wptr = mp->b_rptr + sizeof (int);
579*07d06da5SSurya Prakki 			(void) putq(queue, mp);
58025cf1a30Sjl 		} else {
58125cf1a30Sjl 			rval = FAILURE;
58225cf1a30Sjl 		}
58325cf1a30Sjl 	} else {
58425cf1a30Sjl 		rval = FAILURE;
58525cf1a30Sjl 	}
58625cf1a30Sjl 	return (rval);
58725cf1a30Sjl }
58825cf1a30Sjl 
58925cf1a30Sjl /*
59025cf1a30Sjl  * Put XOFF message on write queue for all standby paths
59125cf1a30Sjl  *
59225cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
59325cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
59425cf1a30Sjl  *  -. uinst_t->u_lock : M
59525cf1a30Sjl  *  -. uinst_t->l_lock : M
59625cf1a30Sjl  *  -. uinst_t->c_lock : P
59725cf1a30Sjl  */
59825cf1a30Sjl void
59925cf1a30Sjl oplmsu_cmn_putxoff_standby(void)
60025cf1a30Sjl {
60125cf1a30Sjl 	upath_t	*upath;
60225cf1a30Sjl 	lpath_t	*lpath;
60325cf1a30Sjl 
60425cf1a30Sjl 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
60525cf1a30Sjl 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
60625cf1a30Sjl 	ASSERT(MUTEX_HELD(&oplmsu_uinst->l_lock));
60725cf1a30Sjl 
60825cf1a30Sjl 	upath = oplmsu_uinst->first_upath;
60925cf1a30Sjl 	while (upath) {
61025cf1a30Sjl 		lpath = upath->lpath;
61125cf1a30Sjl 		if ((upath->status != MSU_PSTAT_STANDBY) ||
61225cf1a30Sjl 		    (lpath == NULL)) {
61325cf1a30Sjl 			upath = upath->u_next;
61425cf1a30Sjl 			continue;
61525cf1a30Sjl 		}
61625cf1a30Sjl 
61725cf1a30Sjl 		(void) oplmsu_cmn_put_xoffxon(
61825cf1a30Sjl 		    WR(lpath->lower_queue), MSU_XOFF_4);
61925cf1a30Sjl 		upath = upath->u_next;
62025cf1a30Sjl 	}
62125cf1a30Sjl }
62225cf1a30Sjl 
62325cf1a30Sjl /*
62425cf1a30Sjl  * Set M_FLUSH message
62525cf1a30Sjl  *
62625cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
62725cf1a30Sjl  *  -. uinst_t->lock   : A [RW_READER or RW_WRITER]
62825cf1a30Sjl  *  -. uinst_t->u_lock : A
62925cf1a30Sjl  *  -. uinst_t->l_lock : A
63025cf1a30Sjl  *  -. uinst_t->c_lock : A
63125cf1a30Sjl  */
63225cf1a30Sjl void
63325cf1a30Sjl oplmsu_cmn_set_mflush(mblk_t *mp)
63425cf1a30Sjl {
63525cf1a30Sjl 
63625cf1a30Sjl 	mp->b_datap->db_type = M_FLUSH;
63725cf1a30Sjl 	*mp->b_rptr = FLUSHW;
63825cf1a30Sjl 	mp->b_wptr = mp->b_rptr + sizeof (char);
63925cf1a30Sjl }
64025cf1a30Sjl 
64125cf1a30Sjl /*
64225cf1a30Sjl  * Set status informations of upath_t
64325cf1a30Sjl  *
64425cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
64525cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
64625cf1a30Sjl  *  -. uinst_t->u_lock : M
64725cf1a30Sjl  *  -. uinst_t->l_lock : A
64825cf1a30Sjl  *  -. uinst_t->c_lock : A
64925cf1a30Sjl  */
65025cf1a30Sjl void
65125cf1a30Sjl oplmsu_cmn_set_upath_sts(upath_t *upath, int sts, int prev_sts,
65225cf1a30Sjl     ulong_t trad_sts)
65325cf1a30Sjl {
65425cf1a30Sjl 
65525cf1a30Sjl 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
65625cf1a30Sjl 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
65725cf1a30Sjl 
65825cf1a30Sjl 	upath->status = sts;
65925cf1a30Sjl 	upath->prev_status = prev_sts;
66025cf1a30Sjl 	upath->traditional_status = trad_sts;
66125cf1a30Sjl }
66225cf1a30Sjl 
66325cf1a30Sjl /*
66425cf1a30Sjl  * Allocate a message block
66525cf1a30Sjl  *
66625cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
66725cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER]
66825cf1a30Sjl  *  -. uinst_t->u_lock : A
66925cf1a30Sjl  *  -. uinst_t->l_lock : P
67025cf1a30Sjl  *  -. uinst_t->c_lock : P
67125cf1a30Sjl  */
67225cf1a30Sjl int
67325cf1a30Sjl oplmsu_cmn_allocmb(queue_t *q, mblk_t *mp, mblk_t **nmp, size_t size,
67425cf1a30Sjl     int rw_flag)
67525cf1a30Sjl {
67625cf1a30Sjl 	int	rval = SUCCESS;
67725cf1a30Sjl 
67825cf1a30Sjl 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
67925cf1a30Sjl 
68025cf1a30Sjl 	if ((*nmp = (mblk_t *)allocb(size, BPRI_LO)) == NULL) {
68125cf1a30Sjl 		oplmsu_cmn_bufcall(q, mp, size, rw_flag);
68225cf1a30Sjl 		rval = FAILURE;
68325cf1a30Sjl 	} else {
68425cf1a30Sjl 		(*nmp)->b_wptr = (*nmp)->b_rptr + size;
68525cf1a30Sjl 	}
68625cf1a30Sjl 	return (rval);
68725cf1a30Sjl }
68825cf1a30Sjl 
68925cf1a30Sjl /*
69025cf1a30Sjl  * Copy a message
69125cf1a30Sjl  *
69225cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
69325cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER]
69425cf1a30Sjl  *  -. uinst_t->u_lock : A
69525cf1a30Sjl  *  -. uinst_t->l_lock : P
69625cf1a30Sjl  *  -. uinst_t->c_lock : P
69725cf1a30Sjl  */
69825cf1a30Sjl int
69925cf1a30Sjl oplmsu_cmn_copymb(queue_t *q, mblk_t *mp, mblk_t **nmp, mblk_t *cmp,
70025cf1a30Sjl     int rw_flag)
70125cf1a30Sjl {
70225cf1a30Sjl 	int	rval = SUCCESS;
70325cf1a30Sjl 
70425cf1a30Sjl 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
70525cf1a30Sjl 
70625cf1a30Sjl 	if ((*nmp = copymsg(cmp)) == NULL) {
70725cf1a30Sjl 		oplmsu_cmn_bufcall(q, mp, msgsize(cmp), rw_flag);
70825cf1a30Sjl 		rval = FAILURE;
70925cf1a30Sjl 	}
71025cf1a30Sjl 	return (rval);
71125cf1a30Sjl }
71225cf1a30Sjl 
71325cf1a30Sjl /*
71425cf1a30Sjl  * bufcall request
71525cf1a30Sjl  *
71625cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
71725cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER]
71825cf1a30Sjl  *  -. uinst_t->u_lock : A
71925cf1a30Sjl  *  -. uinst_t->l_lock : P
72025cf1a30Sjl  *  -. uinst_t->c_lock : P
72125cf1a30Sjl  */
72225cf1a30Sjl void
72325cf1a30Sjl oplmsu_cmn_bufcall(queue_t *q, mblk_t *mp, size_t size, int rw_flag)
72425cf1a30Sjl {
72525cf1a30Sjl 
72625cf1a30Sjl 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
72725cf1a30Sjl 
72825cf1a30Sjl 	if (rw_flag == MSU_WRITE_SIDE) {
72925cf1a30Sjl 		ctrl_t	*ctrl;
73025cf1a30Sjl 
731*07d06da5SSurya Prakki 		(void) putbq(q, mp);
73225cf1a30Sjl 
73325cf1a30Sjl 		mutex_enter(&oplmsu_uinst->c_lock);
73425cf1a30Sjl 		ctrl = (ctrl_t *)q->q_ptr;
73525cf1a30Sjl 		if (ctrl->wbuf_id != 0) {
73625cf1a30Sjl 			mutex_exit(&oplmsu_uinst->c_lock);
73725cf1a30Sjl 			return;
73825cf1a30Sjl 		}
73925cf1a30Sjl 
74025cf1a30Sjl 		ctrl->wbuftbl->q = q;
74125cf1a30Sjl 		ctrl->wbuftbl->rw_flag = rw_flag;
74225cf1a30Sjl 		ctrl->wbuf_id = bufcall(size, BPRI_LO, oplmsu_cmn_bufcb,
74325cf1a30Sjl 		    (void *)ctrl->wbuftbl);
74425cf1a30Sjl 
74525cf1a30Sjl 		if (ctrl->wbuf_id == 0) {
74625cf1a30Sjl 			if (ctrl->wtout_id != 0) {
74725cf1a30Sjl 				mutex_exit(&oplmsu_uinst->c_lock);
74825cf1a30Sjl 				return;
74925cf1a30Sjl 			}
75025cf1a30Sjl 
75125cf1a30Sjl 			ctrl->wtout_id = timeout(oplmsu_cmn_bufcb,
75225cf1a30Sjl 			    (void *)ctrl->wbuftbl, drv_usectohz(MSU_TM_500MS));
75325cf1a30Sjl 		}
75425cf1a30Sjl 		mutex_exit(&oplmsu_uinst->c_lock);
75525cf1a30Sjl 	} else if (rw_flag == MSU_READ_SIDE) {
75625cf1a30Sjl 		lpath_t	*lpath;
75725cf1a30Sjl 		mblk_t	*wrk_msg;
75825cf1a30Sjl 
75925cf1a30Sjl 		mutex_enter(&oplmsu_uinst->l_lock);
76025cf1a30Sjl 		lpath = (lpath_t *)q->q_ptr;
76125cf1a30Sjl 		if (mp->b_datap->db_type >= QPCTL) {
76225cf1a30Sjl 			if (lpath->first_lpri_hi == NULL) {
76325cf1a30Sjl 				lpath->last_lpri_hi = mp;
76425cf1a30Sjl 				mp->b_next = NULL;
76525cf1a30Sjl 			} else {
76625cf1a30Sjl 				wrk_msg = lpath->first_lpri_hi;
76725cf1a30Sjl 				wrk_msg->b_prev = mp;
76825cf1a30Sjl 				mp->b_next = wrk_msg;
76925cf1a30Sjl 			}
77025cf1a30Sjl 			mp->b_prev = NULL;
77125cf1a30Sjl 			lpath->first_lpri_hi = mp;
77225cf1a30Sjl 		} else {
773*07d06da5SSurya Prakki 			(void) putbq(q, mp);
77425cf1a30Sjl 		}
77525cf1a30Sjl 
77625cf1a30Sjl 		if (lpath->rbuf_id != 0) {
77725cf1a30Sjl 			mutex_exit(&oplmsu_uinst->l_lock);
77825cf1a30Sjl 			return;
77925cf1a30Sjl 		}
78025cf1a30Sjl 
78125cf1a30Sjl 		lpath->rbuftbl->q = q;
78225cf1a30Sjl 		lpath->rbuftbl->rw_flag = rw_flag;
78325cf1a30Sjl 		lpath->rbuf_id = bufcall(size, BPRI_LO, oplmsu_cmn_bufcb,
78425cf1a30Sjl 		    (void *)lpath->rbuftbl);
78525cf1a30Sjl 
78625cf1a30Sjl 		if (lpath->rbuf_id == 0) {
78725cf1a30Sjl 			if (lpath->rtout_id != 0) {
78825cf1a30Sjl 				mutex_exit(&oplmsu_uinst->l_lock);
78925cf1a30Sjl 				return;
79025cf1a30Sjl 			}
79125cf1a30Sjl 
79225cf1a30Sjl 			lpath->rtout_id = timeout(oplmsu_cmn_bufcb,
79325cf1a30Sjl 			    (void *)lpath->rbuftbl, drv_usectohz(MSU_TM_500MS));
79425cf1a30Sjl 		}
79525cf1a30Sjl 		mutex_exit(&oplmsu_uinst->l_lock);
79625cf1a30Sjl 	}
79725cf1a30Sjl }
79825cf1a30Sjl 
79925cf1a30Sjl /*
80025cf1a30Sjl  * Previous sequence for active path change
80125cf1a30Sjl  *
80225cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
80325cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER]
80425cf1a30Sjl  *  -. uinst_t->u_lock : A
80525cf1a30Sjl  *  -. uinst_t->l_lock : P
80625cf1a30Sjl  *  -. uinst_t->c_lock : P
80725cf1a30Sjl  */
80825cf1a30Sjl int
80925cf1a30Sjl oplmsu_cmn_prechg(queue_t *q, mblk_t *mp, int rw_flag, mblk_t **term_mp,
81025cf1a30Sjl     int *term_ioctl, int *term_stat)
81125cf1a30Sjl {
81225cf1a30Sjl 
81325cf1a30Sjl 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
81425cf1a30Sjl 
81525cf1a30Sjl 	if (oplmsu_uinst->tcsets_p != NULL) {
81625cf1a30Sjl 		struct iocblk	*iocp;
81725cf1a30Sjl 
81825cf1a30Sjl 		if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tcsets_p,
81925cf1a30Sjl 		    rw_flag) == -1) {
82025cf1a30Sjl 			return (FAILURE);
82125cf1a30Sjl 		}
82225cf1a30Sjl 
82325cf1a30Sjl 		iocp = (struct iocblk *)(*term_mp)->b_rptr;
82425cf1a30Sjl 		*term_ioctl = iocp->ioc_cmd;
82525cf1a30Sjl 		*term_stat = MSU_WTCS_ACK;
82625cf1a30Sjl 	} else if (oplmsu_uinst->tiocmset_p != NULL) {
82725cf1a30Sjl 		if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocmset_p,
82825cf1a30Sjl 		    rw_flag) == -1) {
82925cf1a30Sjl 			return (FAILURE);
83025cf1a30Sjl 		}
83125cf1a30Sjl 
83225cf1a30Sjl 		*term_ioctl = TIOCMSET;
83325cf1a30Sjl 		*term_stat = MSU_WTMS_ACK;
83425cf1a30Sjl 	} else if (oplmsu_uinst->tiocspps_p != NULL) {
83525cf1a30Sjl 		if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocspps_p,
83625cf1a30Sjl 		    rw_flag) == -1) {
83725cf1a30Sjl 			return (FAILURE);
83825cf1a30Sjl 		}
83925cf1a30Sjl 
84025cf1a30Sjl 		*term_ioctl = TIOCSPPS;
84125cf1a30Sjl 		*term_stat = MSU_WPPS_ACK;
84225cf1a30Sjl 	} else if (oplmsu_uinst->tiocswinsz_p != NULL) {
84325cf1a30Sjl 		if (oplmsu_cmn_copymb(q, mp, term_mp,
84425cf1a30Sjl 		    oplmsu_uinst->tiocswinsz_p, rw_flag) == -1) {
84525cf1a30Sjl 			return (FAILURE);
84625cf1a30Sjl 		}
84725cf1a30Sjl 
84825cf1a30Sjl 		*term_ioctl = TIOCSWINSZ;
84925cf1a30Sjl 		*term_stat = MSU_WWSZ_ACK;
85025cf1a30Sjl 	} else if (oplmsu_uinst->tiocssoftcar_p != NULL) {
85125cf1a30Sjl 		if (oplmsu_cmn_copymb(q, mp, term_mp,
85225cf1a30Sjl 		    oplmsu_uinst->tiocssoftcar_p, rw_flag) == -1) {
85325cf1a30Sjl 			return (FAILURE);
85425cf1a30Sjl 		}
85525cf1a30Sjl 
85625cf1a30Sjl 		*term_ioctl = TIOCSSOFTCAR;
85725cf1a30Sjl 		*term_stat = MSU_WCAR_ACK;
85825cf1a30Sjl 	} else {
85925cf1a30Sjl 		*term_stat = MSU_WPTH_CHG;
86025cf1a30Sjl 		*term_mp = NULL;
86125cf1a30Sjl 	}
86225cf1a30Sjl 	return (SUCCESS);
86325cf1a30Sjl }
86425cf1a30Sjl 
86525cf1a30Sjl /*
86625cf1a30Sjl  * Pick up termios to re-set
86725cf1a30Sjl  *
86825cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
86925cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
87025cf1a30Sjl  *  -. uinst_t->u_lock : A
87125cf1a30Sjl  *  -. uinst_t->l_lock : A
87225cf1a30Sjl  *  -. uinst_t->c_lock : A
87325cf1a30Sjl  */
87425cf1a30Sjl int
87525cf1a30Sjl oplmsu_stop_prechg(mblk_t **term_mp, int *term_ioctl, int *term_stat)
87625cf1a30Sjl {
87725cf1a30Sjl 
87825cf1a30Sjl 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
87925cf1a30Sjl 
88025cf1a30Sjl 	if (oplmsu_uinst->tcsets_p != NULL) {
88125cf1a30Sjl 		struct iocblk	*iocp;
88225cf1a30Sjl 
88325cf1a30Sjl 		if ((*term_mp = copymsg(oplmsu_uinst->tcsets_p)) == NULL) {
88425cf1a30Sjl 			return (FAILURE);
88525cf1a30Sjl 		}
88625cf1a30Sjl 
88725cf1a30Sjl 		iocp = (struct iocblk *)(*term_mp)->b_rptr;
88825cf1a30Sjl 		*term_ioctl = iocp->ioc_cmd;
88925cf1a30Sjl 		*term_stat = MSU_WTCS_ACK;
89025cf1a30Sjl 	} else if (oplmsu_uinst->tiocmset_p != NULL) {
89125cf1a30Sjl 		if ((*term_mp = copymsg(oplmsu_uinst->tiocmset_p)) == NULL) {
89225cf1a30Sjl 			return (FAILURE);
89325cf1a30Sjl 		}
89425cf1a30Sjl 
89525cf1a30Sjl 		*term_ioctl = TIOCMSET;
89625cf1a30Sjl 		*term_stat = MSU_WTMS_ACK;
89725cf1a30Sjl 	} else if (oplmsu_uinst->tiocspps_p != NULL) {
89825cf1a30Sjl 		if ((*term_mp = copymsg(oplmsu_uinst->tiocspps_p)) == NULL) {
89925cf1a30Sjl 			return (FAILURE);
90025cf1a30Sjl 		}
90125cf1a30Sjl 
90225cf1a30Sjl 		*term_ioctl = TIOCSPPS;
90325cf1a30Sjl 		*term_stat = MSU_WPPS_ACK;
90425cf1a30Sjl 	} else if (oplmsu_uinst->tiocswinsz_p != NULL) {
90525cf1a30Sjl 		if ((*term_mp = copymsg(oplmsu_uinst->tiocswinsz_p)) == NULL) {
90625cf1a30Sjl 			return (FAILURE);
90725cf1a30Sjl 		}
90825cf1a30Sjl 
90925cf1a30Sjl 		*term_ioctl = TIOCSWINSZ;
91025cf1a30Sjl 		*term_stat = MSU_WWSZ_ACK;
91125cf1a30Sjl 	} else if (oplmsu_uinst->tiocssoftcar_p != NULL) {
91225cf1a30Sjl 		if ((*term_mp = copymsg(oplmsu_uinst->tiocssoftcar_p))
91325cf1a30Sjl 		    == NULL) {
91425cf1a30Sjl 			return (FAILURE);
91525cf1a30Sjl 		}
91625cf1a30Sjl 
91725cf1a30Sjl 		*term_ioctl = TIOCSSOFTCAR;
91825cf1a30Sjl 		*term_stat = MSU_WCAR_ACK;
91925cf1a30Sjl 	} else {
92025cf1a30Sjl 		*term_stat = MSU_WPTH_CHG;
92125cf1a30Sjl 		*term_mp = NULL;
92225cf1a30Sjl 	}
92325cf1a30Sjl 	return (SUCCESS);
92425cf1a30Sjl }
92525cf1a30Sjl 
92625cf1a30Sjl /*
92725cf1a30Sjl  * Previous sequence for active path change termio
92825cf1a30Sjl  *
92925cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
93025cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER]
93125cf1a30Sjl  *  -. uinst_t->u_lock : A
93225cf1a30Sjl  *  -. uinst_t->l_lock : P
93325cf1a30Sjl  *  -. uinst_t->c_lock : P
93425cf1a30Sjl  */
93525cf1a30Sjl int
93625cf1a30Sjl oplmsu_cmn_prechg_termio(queue_t *q, mblk_t *mp, int rw_flag, int prev_flag,
93725cf1a30Sjl     mblk_t **term_mp, int *term_stat)
93825cf1a30Sjl {
93925cf1a30Sjl 
94025cf1a30Sjl 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
94125cf1a30Sjl 
94225cf1a30Sjl 	if ((prev_flag == MSU_TIOS_TCSETS) &&
94325cf1a30Sjl 	    (oplmsu_uinst->tiocmset_p != NULL)) {
94425cf1a30Sjl 		if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocmset_p,
94525cf1a30Sjl 		    rw_flag) == FAILURE) {
94625cf1a30Sjl 			return (FAILURE);
94725cf1a30Sjl 		}
94825cf1a30Sjl 
94925cf1a30Sjl 		*term_stat = MSU_WTMS_ACK;
95025cf1a30Sjl 	} else if ((prev_flag <= MSU_TIOS_MSET) &&
95125cf1a30Sjl 	    (oplmsu_uinst->tiocspps_p != NULL)) {
95225cf1a30Sjl 		if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocspps_p,
95325cf1a30Sjl 		    rw_flag) == FAILURE) {
95425cf1a30Sjl 			return (FAILURE);
95525cf1a30Sjl 		}
95625cf1a30Sjl 
95725cf1a30Sjl 		*term_stat = MSU_WPPS_ACK;
95825cf1a30Sjl 	} else if ((prev_flag <= MSU_TIOS_PPS) &&
95925cf1a30Sjl 	    (oplmsu_uinst->tiocswinsz_p != NULL)) {
96025cf1a30Sjl 		if (oplmsu_cmn_copymb(q, mp, term_mp,
96125cf1a30Sjl 		    oplmsu_uinst->tiocswinsz_p, rw_flag) == FAILURE) {
96225cf1a30Sjl 			return (FAILURE);
96325cf1a30Sjl 		}
96425cf1a30Sjl 
96525cf1a30Sjl 		*term_stat = MSU_WWSZ_ACK;
96625cf1a30Sjl 	} else if ((prev_flag <= MSU_TIOS_WINSZP) &&
96725cf1a30Sjl 	    (oplmsu_uinst->tiocssoftcar_p != NULL)) {
96825cf1a30Sjl 		if (oplmsu_cmn_copymb(q, mp, term_mp,
96925cf1a30Sjl 		    oplmsu_uinst->tiocssoftcar_p, rw_flag) == FAILURE) {
97025cf1a30Sjl 			return (FAILURE);
97125cf1a30Sjl 		}
97225cf1a30Sjl 
97325cf1a30Sjl 		*term_stat = MSU_WCAR_ACK;
97425cf1a30Sjl 	} else if (prev_flag <= MSU_TIOS_SOFTCAR) {
97525cf1a30Sjl 		*term_mp = NULL;
97625cf1a30Sjl 		*term_stat = MSU_WPTH_CHG;
97725cf1a30Sjl 	}
97825cf1a30Sjl 	return (SUCCESS);
97925cf1a30Sjl }
98025cf1a30Sjl 
98125cf1a30Sjl /*
98225cf1a30Sjl  * Pull up messages
98325cf1a30Sjl  *
98425cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
98525cf1a30Sjl  *  -. uinst_t->lock   : P
98625cf1a30Sjl  *  -. uinst_t->u_lock : P
98725cf1a30Sjl  *  -. uinst_t->l_lock : P
98825cf1a30Sjl  *  -. uinst_t->c_lock : P
98925cf1a30Sjl  */
99025cf1a30Sjl int
99125cf1a30Sjl oplmsu_cmn_pullup_msg(queue_t *q, mblk_t *mp)
99225cf1a30Sjl {
99325cf1a30Sjl 	mblk_t	*nmp = NULL;
99425cf1a30Sjl 
99525cf1a30Sjl 	if ((mp != NULL) && (mp->b_cont != NULL) &&
99625cf1a30Sjl 	    (mp->b_cont->b_cont != NULL)) {
99725cf1a30Sjl 		if ((nmp = msgpullup(mp->b_cont, -1)) == NULL) {
99825cf1a30Sjl 			oplmsu_iocack(q, mp, ENOSR);
99925cf1a30Sjl 			return (FAILURE);
100025cf1a30Sjl 		} else {
100125cf1a30Sjl 			freemsg(mp->b_cont);
100225cf1a30Sjl 			mp->b_cont = nmp;
100325cf1a30Sjl 		}
100425cf1a30Sjl 	}
100525cf1a30Sjl 	return (SUCCESS);
100625cf1a30Sjl }
100725cf1a30Sjl 
100825cf1a30Sjl /*
100925cf1a30Sjl  * Wake up flow control
101025cf1a30Sjl  *
101125cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
101225cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
101325cf1a30Sjl  *  -. uinst_t->u_lock : P
101425cf1a30Sjl  *  -. uinst_t->l_lock : P
101525cf1a30Sjl  *  -. uinst_t->c_lock : P
101625cf1a30Sjl  */
101725cf1a30Sjl void
101825cf1a30Sjl oplmsu_cmn_wakeup(queue_t *q)
101925cf1a30Sjl {
102025cf1a30Sjl 	ctrl_t	*ctrl;
102125cf1a30Sjl 
102225cf1a30Sjl 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
102325cf1a30Sjl 
102425cf1a30Sjl 	mutex_enter(&oplmsu_uinst->c_lock);
102525cf1a30Sjl 	ctrl = (ctrl_t *)q->q_ptr;
102625cf1a30Sjl 	if (ctrl->sleep_flag == CV_SLEEP) {
102725cf1a30Sjl 		ctrl->sleep_flag = CV_WAKEUP;
102825cf1a30Sjl 		cv_signal(&ctrl->cvp);
102925cf1a30Sjl 	}
103025cf1a30Sjl 	mutex_exit(&oplmsu_uinst->c_lock);
103125cf1a30Sjl }
103225cf1a30Sjl 
103325cf1a30Sjl /*
103425cf1a30Sjl  * bufcall() and timeout() callback entry for read/write stream
103525cf1a30Sjl  *
103625cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
103725cf1a30Sjl  *  -. uinst_t->lock   : P
103825cf1a30Sjl  *  -. uinst_t->u_lock : P
103925cf1a30Sjl  *  -. uinst_t->l_lock : P
104025cf1a30Sjl  *  -. uinst_t->c_lock : P
104125cf1a30Sjl  */
104225cf1a30Sjl void
104325cf1a30Sjl oplmsu_cmn_bufcb(void *arg)
104425cf1a30Sjl {
104525cf1a30Sjl 	struct buf_tbl	*buftbl = arg;
104625cf1a30Sjl 	lpath_t		*lpath;
104725cf1a30Sjl 	ctrl_t		*ctrl;
104825cf1a30Sjl 	queue_t		*q;
104925cf1a30Sjl 	int		lq_flag = 0;
105025cf1a30Sjl 
105125cf1a30Sjl 	rw_enter(&oplmsu_uinst->lock, RW_WRITER);
105225cf1a30Sjl 	mutex_enter(&oplmsu_uinst->l_lock);
105325cf1a30Sjl 
105425cf1a30Sjl 	lpath = oplmsu_uinst->first_lpath;
105525cf1a30Sjl 	while (lpath) {
105625cf1a30Sjl 		if ((buftbl == lpath->rbuftbl) &&
105725cf1a30Sjl 		    (buftbl->rw_flag == MSU_READ_SIDE)) {
105825cf1a30Sjl 			if ((lpath->rbuf_id == 0) && (lpath->rtout_id == 0)) {
105925cf1a30Sjl 				mutex_exit(&oplmsu_uinst->l_lock);
106025cf1a30Sjl 				rw_exit(&oplmsu_uinst->lock);
106125cf1a30Sjl 			} else {
106225cf1a30Sjl 				q = lpath->rbuftbl->q;
106325cf1a30Sjl 				lpath->rbuftbl->q = NULL;
106425cf1a30Sjl 				lpath->rbuftbl->rw_flag = UNDEFINED;
106525cf1a30Sjl 
106625cf1a30Sjl 				if (lpath->rbuf_id) {
106725cf1a30Sjl 					lpath->rbuf_id = 0;
106825cf1a30Sjl 				} else {
106925cf1a30Sjl 					lpath->rtout_id = 0;
107025cf1a30Sjl 				}
107125cf1a30Sjl 				mutex_exit(&oplmsu_uinst->l_lock);
107225cf1a30Sjl 
107325cf1a30Sjl 				if (oplmsu_queue_flag == 1) {
107425cf1a30Sjl 					lq_flag = 1;
107525cf1a30Sjl 					oplmsu_queue_flag = 0;
107625cf1a30Sjl 				}
107725cf1a30Sjl 
107825cf1a30Sjl 				rw_exit(&oplmsu_uinst->lock);
107925cf1a30Sjl 				oplmsu_rcmn_high_qenable(q);
108025cf1a30Sjl 
108125cf1a30Sjl 				if (lq_flag == 1) {
108225cf1a30Sjl 					rw_enter(&oplmsu_uinst->lock,
108325cf1a30Sjl 					    RW_WRITER);
108425cf1a30Sjl 					oplmsu_queue_flag = 1;
108525cf1a30Sjl 					rw_exit(&oplmsu_uinst->lock);
108625cf1a30Sjl 				}
108725cf1a30Sjl 			}
108825cf1a30Sjl 			return;
108925cf1a30Sjl 		}
109025cf1a30Sjl 		lpath = lpath->l_next;
109125cf1a30Sjl 	}
109225cf1a30Sjl 	mutex_exit(&oplmsu_uinst->l_lock);
109325cf1a30Sjl 
109425cf1a30Sjl 	mutex_enter(&oplmsu_uinst->c_lock);
109525cf1a30Sjl 	if ((ctrl = oplmsu_uinst->user_ctrl) != NULL) {
109625cf1a30Sjl 		if ((buftbl == ctrl->wbuftbl) &&
109725cf1a30Sjl 		    (buftbl->rw_flag == MSU_WRITE_SIDE)) {
109825cf1a30Sjl 			oplmsu_wbufcb_posthndl(ctrl);
109925cf1a30Sjl 			mutex_exit(&oplmsu_uinst->c_lock);
110025cf1a30Sjl 			rw_exit(&oplmsu_uinst->lock);
110125cf1a30Sjl 			return;
110225cf1a30Sjl 		}
110325cf1a30Sjl 	}
110425cf1a30Sjl 
110525cf1a30Sjl 	if ((ctrl = oplmsu_uinst->meta_ctrl) != NULL) {
110625cf1a30Sjl 		if ((buftbl == ctrl->wbuftbl) &&
110725cf1a30Sjl 		    (buftbl->rw_flag == MSU_WRITE_SIDE)) {
110825cf1a30Sjl 			oplmsu_wbufcb_posthndl(ctrl);
110925cf1a30Sjl 			mutex_exit(&oplmsu_uinst->c_lock);
111025cf1a30Sjl 			rw_exit(&oplmsu_uinst->lock);
111125cf1a30Sjl 			return;
111225cf1a30Sjl 		}
111325cf1a30Sjl 	}
111425cf1a30Sjl 	mutex_exit(&oplmsu_uinst->c_lock);
111525cf1a30Sjl 	rw_exit(&oplmsu_uinst->lock);
111625cf1a30Sjl }
111725cf1a30Sjl 
111825cf1a30Sjl /*
111925cf1a30Sjl  * bufcall() or timeout() callback post handling for write stream
112025cf1a30Sjl  *
112125cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
112225cf1a30Sjl  *  -. uinst_t->lock   : M [RW_WRITER]
112325cf1a30Sjl  *  -. uinst_t->u_lock : P
112425cf1a30Sjl  *  -. uinst_t->l_lock : P
112525cf1a30Sjl  *  -. uinst_t->c_lock : M
112625cf1a30Sjl  */
112725cf1a30Sjl void
112825cf1a30Sjl oplmsu_wbufcb_posthndl(ctrl_t *ctrl)
112925cf1a30Sjl {
113025cf1a30Sjl 	queue_t	*q;
113125cf1a30Sjl 	int	lq_flag = 0;
113225cf1a30Sjl 
113325cf1a30Sjl 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
113425cf1a30Sjl 	ASSERT(MUTEX_HELD(&oplmsu_uinst->c_lock));
113525cf1a30Sjl 
113625cf1a30Sjl 	if ((ctrl->wbuf_id == 0) && (ctrl->wtout_id == 0)) {
113725cf1a30Sjl 		return;
113825cf1a30Sjl 	}
113925cf1a30Sjl 
114025cf1a30Sjl 	q = ctrl->wbuftbl->q;
114125cf1a30Sjl 	ctrl->wbuftbl->q = NULL;
114225cf1a30Sjl 	ctrl->wbuftbl->rw_flag = UNDEFINED;
114325cf1a30Sjl 	if (ctrl->wbuf_id) {
114425cf1a30Sjl 		ctrl->wbuf_id = 0;
114525cf1a30Sjl 	} else {
114625cf1a30Sjl 		ctrl->wtout_id = 0;
114725cf1a30Sjl 	}
114825cf1a30Sjl 
114925cf1a30Sjl 	if (oplmsu_queue_flag == 1) {
115025cf1a30Sjl 		lq_flag = 1;
115125cf1a30Sjl 		oplmsu_queue_flag = 0;
115225cf1a30Sjl 	}
115325cf1a30Sjl 
115425cf1a30Sjl 	mutex_exit(&oplmsu_uinst->c_lock);
115525cf1a30Sjl 	oplmsu_wcmn_high_qenable(q, RW_WRITER);
115625cf1a30Sjl 	mutex_enter(&oplmsu_uinst->c_lock);
115725cf1a30Sjl 
115825cf1a30Sjl 	if (lq_flag == 1) {
115925cf1a30Sjl 		oplmsu_queue_flag = 1;
116025cf1a30Sjl 	}
116125cf1a30Sjl }
116225cf1a30Sjl 
116325cf1a30Sjl /*
116425cf1a30Sjl  *	COMMON FUNCTIONS FOR WRITE STREAM
116525cf1a30Sjl  */
116625cf1a30Sjl 
116725cf1a30Sjl /*
116825cf1a30Sjl  * Check control node and driver privilege
116925cf1a30Sjl  *
117025cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
117125cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
117225cf1a30Sjl  *  -. uinst_t->u_lock : A
117325cf1a30Sjl  *  -. uinst_t->l_lock : A
117425cf1a30Sjl  *  -. uinst_t->c_lock : P
117525cf1a30Sjl  */
117625cf1a30Sjl int
117725cf1a30Sjl oplmsu_wcmn_chknode(queue_t *q, int node, mblk_t *mp)
117825cf1a30Sjl {
117925cf1a30Sjl 	struct iocblk	*iocp;
118025cf1a30Sjl 
118125cf1a30Sjl 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
118225cf1a30Sjl 
118325cf1a30Sjl 	mutex_enter(&oplmsu_uinst->c_lock);
118425cf1a30Sjl 	if (((ctrl_t *)q->q_ptr)->node_type != node) {
118525cf1a30Sjl 		mutex_exit(&oplmsu_uinst->c_lock);
118625cf1a30Sjl 		cmn_err(CE_WARN, "oplmsu: chk-node: ctrl node type = %d", node);
118725cf1a30Sjl 		return (EINVAL);
118825cf1a30Sjl 	}
118925cf1a30Sjl 	mutex_exit(&oplmsu_uinst->c_lock);
119025cf1a30Sjl 
119125cf1a30Sjl 	/* Check super-user by oplmsu.conf */
119225cf1a30Sjl 	if (oplmsu_check_su != 0) {
119325cf1a30Sjl 		iocp = (struct iocblk *)mp->b_rptr;
119425cf1a30Sjl 		if (drv_priv(iocp->ioc_cr) != 0) {
119525cf1a30Sjl 			cmn_err(CE_WARN, "oplmsu: chk-node: Permission denied");
119625cf1a30Sjl 			return (EPERM);
119725cf1a30Sjl 		}
119825cf1a30Sjl 	}
119925cf1a30Sjl 	return (SUCCESS);
120025cf1a30Sjl }
120125cf1a30Sjl 
120225cf1a30Sjl /*
120325cf1a30Sjl  * Flush handle for write side stream
120425cf1a30Sjl  *
120525cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
120625cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
120725cf1a30Sjl  *  -. uinst_t->u_lock : P
120825cf1a30Sjl  *  -. uinst_t->l_lock : P
120925cf1a30Sjl  *  -. uinst_t->c_lock : P
121025cf1a30Sjl  */
121125cf1a30Sjl void
121225cf1a30Sjl oplmsu_wcmn_flush_hndl(queue_t *q, mblk_t *mp, krw_t rw)
121325cf1a30Sjl {
121425cf1a30Sjl 	queue_t	*dst_queue = NULL;
121525cf1a30Sjl 
121625cf1a30Sjl 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
121725cf1a30Sjl 
121825cf1a30Sjl 	if (*mp->b_rptr & FLUSHW) {	/* Write side */
121925cf1a30Sjl 		flushq(q, FLUSHDATA);
122025cf1a30Sjl 	}
122125cf1a30Sjl 
122225cf1a30Sjl 	dst_queue = oplmsu_uinst->lower_queue;
122325cf1a30Sjl 	if (dst_queue == NULL) {
122425cf1a30Sjl 		if (*mp->b_rptr & FLUSHR) {
122525cf1a30Sjl 			flushq(RD(q), FLUSHDATA);
122625cf1a30Sjl 			*mp->b_rptr &= ~FLUSHW;
122725cf1a30Sjl 
122825cf1a30Sjl 			rw_exit(&oplmsu_uinst->lock);
122925cf1a30Sjl 			OPLMSU_TRACE(q, mp, MSU_TRC_UO);
123025cf1a30Sjl 			qreply(q, mp);
123125cf1a30Sjl 			rw_enter(&oplmsu_uinst->lock, rw);
123225cf1a30Sjl 		} else {
123325cf1a30Sjl 			freemsg(mp);
123425cf1a30Sjl 		}
123525cf1a30Sjl 	} else {
1236*07d06da5SSurya Prakki 		(void) putq(WR(dst_queue), mp);
123725cf1a30Sjl 	}
123825cf1a30Sjl }
123925cf1a30Sjl 
124025cf1a30Sjl /*
124125cf1a30Sjl  * Through message handle for write side stream
124225cf1a30Sjl  *
124325cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
124425cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
124525cf1a30Sjl  *  -. uinst_t->u_lock : P
124625cf1a30Sjl  *  -. uinst_t->l_lock : P
124725cf1a30Sjl  *  -. uinst_t->c_lock : P
124825cf1a30Sjl  */
124925cf1a30Sjl int
125025cf1a30Sjl oplmsu_wcmn_through_hndl(queue_t *q, mblk_t *mp, int pri_flag, krw_t rw)
125125cf1a30Sjl {
125225cf1a30Sjl 	queue_t	*usr_queue = NULL, *dst_queue = NULL;
125325cf1a30Sjl 	ctrl_t	*ctrl;
125425cf1a30Sjl 
125525cf1a30Sjl 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
125625cf1a30Sjl 
125725cf1a30Sjl 	mutex_enter(&oplmsu_uinst->c_lock);
125825cf1a30Sjl 	if ((ctrl = oplmsu_uinst->user_ctrl) != NULL) {
125925cf1a30Sjl 		usr_queue = ctrl->queue;
126025cf1a30Sjl 		mutex_exit(&oplmsu_uinst->c_lock);
126125cf1a30Sjl 	} else {
126225cf1a30Sjl 		mutex_exit(&oplmsu_uinst->c_lock);
126325cf1a30Sjl 		if (mp->b_datap->db_type == M_IOCTL) {
126425cf1a30Sjl 			rw_exit(&oplmsu_uinst->lock);
126525cf1a30Sjl 			oplmsu_iocack(q, mp, ENODEV);
126625cf1a30Sjl 			rw_enter(&oplmsu_uinst->lock, rw);
126725cf1a30Sjl 		} else {
126825cf1a30Sjl 			freemsg(mp);
126925cf1a30Sjl 		}
127025cf1a30Sjl 		return (SUCCESS);
127125cf1a30Sjl 	}
127225cf1a30Sjl 
127325cf1a30Sjl 	if (oplmsu_uinst->lower_queue != NULL) {
127425cf1a30Sjl 		dst_queue = WR(oplmsu_uinst->lower_queue);
127525cf1a30Sjl 	} else {
127625cf1a30Sjl 		cmn_err(CE_WARN, "!oplmsu: through-lwq: "
127725cf1a30Sjl 		    "Active path doesn't exist");
127825cf1a30Sjl 
127925cf1a30Sjl 		if (mp->b_datap->db_type == M_IOCTL) {
128025cf1a30Sjl 			rw_exit(&oplmsu_uinst->lock);
128125cf1a30Sjl 			oplmsu_iocack(q, mp, ENODEV);
128225cf1a30Sjl 			rw_enter(&oplmsu_uinst->lock, rw);
128325cf1a30Sjl 		} else {
128425cf1a30Sjl 			freemsg(mp);
128525cf1a30Sjl 		}
128625cf1a30Sjl 		return (SUCCESS);
128725cf1a30Sjl 	}
128825cf1a30Sjl 
128925cf1a30Sjl 	if ((usr_queue == WR(q)) || (usr_queue == RD(q))) {
129025cf1a30Sjl 		if (pri_flag == MSU_HIGH) {
1291*07d06da5SSurya Prakki 			(void) putq(dst_queue, mp);
129225cf1a30Sjl 		} else {
129325cf1a30Sjl 			if (canput(dst_queue)) {
1294*07d06da5SSurya Prakki 				(void) putq(dst_queue, mp);
129525cf1a30Sjl 			} else {
129625cf1a30Sjl 				oplmsu_wcmn_norm_putbq(WR(q), mp, dst_queue);
129725cf1a30Sjl 				return (FAILURE);
129825cf1a30Sjl 			}
129925cf1a30Sjl 		}
130025cf1a30Sjl 	} else {
130125cf1a30Sjl 		cmn_err(CE_WARN, "oplmsu: through-lwq: "
130225cf1a30Sjl 		    "Inappropriate message for this node");
130325cf1a30Sjl 
130425cf1a30Sjl 		if (mp->b_datap->db_type == M_IOCTL) {
130525cf1a30Sjl 			rw_exit(&oplmsu_uinst->lock);
130625cf1a30Sjl 			oplmsu_iocack(q, mp, ENODEV);
130725cf1a30Sjl 			rw_enter(&oplmsu_uinst->lock, rw);
130825cf1a30Sjl 		} else {
130925cf1a30Sjl 			freemsg(mp);
131025cf1a30Sjl 		}
131125cf1a30Sjl 	}
131225cf1a30Sjl 	return (SUCCESS);
131325cf1a30Sjl }
131425cf1a30Sjl 
131525cf1a30Sjl /*
131625cf1a30Sjl  * Get high priority message from buffer for upper write stream
131725cf1a30Sjl  *
131825cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
131925cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
132025cf1a30Sjl  *  -. uinst_t->u_lock : A
132125cf1a30Sjl  *  -. uinst_t->l_lock : A
132225cf1a30Sjl  *  -. uinst_t->c_lock : P
132325cf1a30Sjl  */
132425cf1a30Sjl mblk_t *
132525cf1a30Sjl oplmsu_wcmn_high_getq(queue_t *uwq)
132625cf1a30Sjl {
132725cf1a30Sjl 	mblk_t	*mp;
132825cf1a30Sjl 	ctrl_t	*ctrl;
132925cf1a30Sjl 
133025cf1a30Sjl 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
133125cf1a30Sjl 
133225cf1a30Sjl 	mutex_enter(&oplmsu_uinst->c_lock);
133325cf1a30Sjl 	ctrl = (ctrl_t *)uwq->q_ptr;
133425cf1a30Sjl 	mp = ctrl->first_upri_hi;
133525cf1a30Sjl 	if (mp != NULL) {
133625cf1a30Sjl 		if (mp->b_next == NULL) {
133725cf1a30Sjl 			ctrl->first_upri_hi = NULL;
133825cf1a30Sjl 			ctrl->last_upri_hi = NULL;
133925cf1a30Sjl 		} else {
134025cf1a30Sjl 			ctrl->first_upri_hi = mp->b_next;
134125cf1a30Sjl 			mp->b_next->b_prev = NULL;
134225cf1a30Sjl 			mp->b_next = NULL;
134325cf1a30Sjl 		}
134425cf1a30Sjl 		mp->b_prev = NULL;
134525cf1a30Sjl 	}
134625cf1a30Sjl 	mutex_exit(&oplmsu_uinst->c_lock);
134725cf1a30Sjl 	return (mp);
134825cf1a30Sjl }
134925cf1a30Sjl 
135025cf1a30Sjl /*
135125cf1a30Sjl  * putbq() function for normal priority message of write stream
135225cf1a30Sjl  *
135325cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
135425cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
135525cf1a30Sjl  *  -. uinst_t->u_lock : A
135625cf1a30Sjl  *  -. uinst_t->l_lock : P
135725cf1a30Sjl  *  -. uinst_t->c_lock : P
135825cf1a30Sjl  */
135925cf1a30Sjl void
136025cf1a30Sjl oplmsu_wcmn_norm_putbq(queue_t *uwq, mblk_t *mp, queue_t *dq)
136125cf1a30Sjl {
136225cf1a30Sjl 	lpath_t	*lpath;
136325cf1a30Sjl 
136425cf1a30Sjl 	ASSERT(mp != NULL);
136525cf1a30Sjl 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
136625cf1a30Sjl 
136725cf1a30Sjl 	mutex_enter(&oplmsu_uinst->l_lock);
136825cf1a30Sjl 	lpath = (lpath_t *)dq->q_ptr;
136925cf1a30Sjl 	lpath->uwq_flag = 1;
137025cf1a30Sjl 	lpath->uwq_queue = uwq;
137125cf1a30Sjl 	mutex_exit(&oplmsu_uinst->l_lock);
1372*07d06da5SSurya Prakki 	(void) putbq(uwq, mp);
137325cf1a30Sjl }
137425cf1a30Sjl 
137525cf1a30Sjl /*
137625cf1a30Sjl  * Restart queuing for high priority message of write stream when flow control
137725cf1a30Sjl  * failed
137825cf1a30Sjl  *
137925cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
138025cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
138125cf1a30Sjl  *  -. uinst_t->u_lock : P
138225cf1a30Sjl  *  -. uinst_t->l_lock : P
138325cf1a30Sjl  *  -. uinst_t->c_lock : P
138425cf1a30Sjl  */
138525cf1a30Sjl void
138625cf1a30Sjl oplmsu_wcmn_high_qenable(queue_t *q, krw_t rw)
138725cf1a30Sjl {
138825cf1a30Sjl 	mblk_t	*mp;
138925cf1a30Sjl 
139025cf1a30Sjl 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
139125cf1a30Sjl 
139225cf1a30Sjl 	if (oplmsu_queue_flag == 1) {
139325cf1a30Sjl 		return;
139425cf1a30Sjl 	}
139525cf1a30Sjl 
139625cf1a30Sjl 	/* Handle high priority message */
139725cf1a30Sjl 	while (mp = oplmsu_wcmn_high_getq(WR(q))) {
139825cf1a30Sjl 		if (mp->b_datap->db_type & M_FLUSH) {
139925cf1a30Sjl 			oplmsu_wcmn_flush_hndl(q, mp, rw);
140025cf1a30Sjl 			continue;
140125cf1a30Sjl 		}
140225cf1a30Sjl 
140325cf1a30Sjl 		if (oplmsu_wcmn_through_hndl(q, mp, MSU_HIGH, rw) == FAILURE) {
140425cf1a30Sjl 			return;
140525cf1a30Sjl 		}
140625cf1a30Sjl 	}
140725cf1a30Sjl 	qenable(WR(q));	/* enable upper write queue */
140825cf1a30Sjl }
140925cf1a30Sjl 
141025cf1a30Sjl /*
141125cf1a30Sjl  *	COMMON FUNCTIONS FOR READ STREAM
141225cf1a30Sjl  */
141325cf1a30Sjl 
141425cf1a30Sjl /*
141525cf1a30Sjl  * Flush handle for read side stream
141625cf1a30Sjl  *
141725cf1a30Sjl  * Requires lock ( M: mandatory  P: prohibited  A: allowed
141825cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER]
141925cf1a30Sjl  *  -. uinst_t->u_lock : P
142025cf1a30Sjl  *  -. uinst_t->l_lock : P
142125cf1a30Sjl  *  -. uinst_t->c_lock : P
142225cf1a30Sjl  */
142325cf1a30Sjl void
142425cf1a30Sjl oplmsu_rcmn_flush_hndl(queue_t *q, mblk_t *mp)
142525cf1a30Sjl {
142625cf1a30Sjl 	queue_t	*dst_queue = NULL;
142725cf1a30Sjl 	ctrl_t	*ctrl;
142825cf1a30Sjl 
142925cf1a30Sjl 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
143025cf1a30Sjl 
143125cf1a30Sjl 	if (*mp->b_rptr & FLUSHR) {
143225cf1a30Sjl 		/* Remove only data messages from read queue */
143325cf1a30Sjl 		flushq(q, FLUSHDATA);
143425cf1a30Sjl 	}
143525cf1a30Sjl 
143625cf1a30Sjl 	mutex_enter(&oplmsu_uinst->c_lock);
143725cf1a30Sjl 	if ((ctrl = oplmsu_uinst->user_ctrl) != NULL) {
143825cf1a30Sjl 		dst_queue = RD(ctrl->queue);
143925cf1a30Sjl 		mutex_exit(&oplmsu_uinst->c_lock);
144025cf1a30Sjl 
144125cf1a30Sjl 		if (dst_queue != NULL) {
1442*07d06da5SSurya Prakki 			(void) putq(dst_queue, mp);
144325cf1a30Sjl 		} else {
144425cf1a30Sjl 			if (*mp->b_rptr & FLUSHW) {
144525cf1a30Sjl 				flushq(WR(q), FLUSHDATA);
144625cf1a30Sjl 				*mp->b_rptr &= ~FLUSHR;
144725cf1a30Sjl 
144825cf1a30Sjl 				rw_exit(&oplmsu_uinst->lock);
144925cf1a30Sjl 				OPLMSU_TRACE(q, mp, MSU_TRC_LO);
145025cf1a30Sjl 				qreply(q, mp);
145125cf1a30Sjl 				rw_enter(&oplmsu_uinst->lock, RW_READER);
145225cf1a30Sjl 			} else {
145325cf1a30Sjl 				freemsg(mp);
145425cf1a30Sjl 			}
145525cf1a30Sjl 		}
145625cf1a30Sjl 	} else {
145725cf1a30Sjl 		mutex_exit(&oplmsu_uinst->c_lock);
145825cf1a30Sjl 		if (*mp->b_rptr & FLUSHW) {
145925cf1a30Sjl 			flushq(WR(q), FLUSHDATA);
146025cf1a30Sjl 			*mp->b_rptr &= ~FLUSHR;
146125cf1a30Sjl 
146225cf1a30Sjl 			rw_exit(&oplmsu_uinst->lock);
146325cf1a30Sjl 			OPLMSU_TRACE(q, mp, MSU_TRC_LO);
146425cf1a30Sjl 			qreply(q, mp);
146525cf1a30Sjl 			rw_enter(&oplmsu_uinst->lock, RW_READER);
146625cf1a30Sjl 		} else {
146725cf1a30Sjl 			freemsg(mp);
146825cf1a30Sjl 		}
146925cf1a30Sjl 	}
147025cf1a30Sjl }
147125cf1a30Sjl 
147225cf1a30Sjl /*
147325cf1a30Sjl  * Through message handle for read side stream
147425cf1a30Sjl  *
147525cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
147625cf1a30Sjl  *  -. uinst_t->lock   : M [RW_READER]
147725cf1a30Sjl  *  -. uinst_t->u_lock : A
147825cf1a30Sjl  *  -. uinst_t->l_lock : P
147925cf1a30Sjl  *  -. uinst_t->c_lock : P
148025cf1a30Sjl  */
148125cf1a30Sjl int
148225cf1a30Sjl oplmsu_rcmn_through_hndl(queue_t *q, mblk_t *mp, int pri_flag)
148325cf1a30Sjl {
148425cf1a30Sjl 	lpath_t	*lpath;
148525cf1a30Sjl 	ctrl_t	*ctrl;
148625cf1a30Sjl 	queue_t	*dst_queue = NULL;
148725cf1a30Sjl 	int	act_flag;
148825cf1a30Sjl 
148925cf1a30Sjl 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
149025cf1a30Sjl 
149125cf1a30Sjl 	mutex_enter(&oplmsu_uinst->l_lock);
149225cf1a30Sjl 	lpath = (lpath_t *)q->q_ptr;
149325cf1a30Sjl 	if (lpath->uinst != NULL) {
149425cf1a30Sjl 		act_flag = ACTIVE_RES;
149525cf1a30Sjl 	} else {
149625cf1a30Sjl 		act_flag = NOT_ACTIVE_RES;
149725cf1a30Sjl 	}
149825cf1a30Sjl 	mutex_exit(&oplmsu_uinst->l_lock);
149925cf1a30Sjl 
150025cf1a30Sjl 	mutex_enter(&oplmsu_uinst->c_lock);
150125cf1a30Sjl 	if (((ctrl = oplmsu_uinst->user_ctrl) != NULL) &&
150225cf1a30Sjl 	    (((mp->b_datap->db_type == M_IOCACK) ||
150325cf1a30Sjl 	    (mp->b_datap->db_type == M_IOCNAK)) || (act_flag == ACTIVE_RES))) {
150425cf1a30Sjl 		dst_queue = RD(ctrl->queue);
150525cf1a30Sjl 	} else {
150625cf1a30Sjl 		mutex_exit(&oplmsu_uinst->c_lock);
150725cf1a30Sjl 		freemsg(mp);
150825cf1a30Sjl 		return (SUCCESS);
150925cf1a30Sjl 	}
151025cf1a30Sjl 
151125cf1a30Sjl 	if (pri_flag == MSU_HIGH) {
1512*07d06da5SSurya Prakki 		(void) putq(dst_queue, mp);
151325cf1a30Sjl 	} else {
151425cf1a30Sjl 		if (canput(dst_queue)) {
1515*07d06da5SSurya Prakki 			(void) putq(dst_queue, mp);
151625cf1a30Sjl 		} else {
151725cf1a30Sjl 			/*
151825cf1a30Sjl 			 * Place a normal priority message at the head of
151925cf1a30Sjl 			 * read queue
152025cf1a30Sjl 			 */
152125cf1a30Sjl 
152225cf1a30Sjl 			ctrl = (ctrl_t *)dst_queue->q_ptr;
152325cf1a30Sjl 			ctrl->lrq_flag = 1;
152425cf1a30Sjl 			ctrl->lrq_queue = q;
152525cf1a30Sjl 			mutex_exit(&oplmsu_uinst->c_lock);
1526*07d06da5SSurya Prakki 			(void) putbq(q, mp);
152725cf1a30Sjl 			return (FAILURE);
152825cf1a30Sjl 		}
152925cf1a30Sjl 	}
153025cf1a30Sjl 	mutex_exit(&oplmsu_uinst->c_lock);
153125cf1a30Sjl 	return (SUCCESS);
153225cf1a30Sjl }
153325cf1a30Sjl 
153425cf1a30Sjl /*
153525cf1a30Sjl  * Restart queuing for high priority message of read stream
153625cf1a30Sjl  * when flow control failed
153725cf1a30Sjl  *
153825cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
153925cf1a30Sjl  *  -. uinst_t->lock   : P
154025cf1a30Sjl  *  -. uinst_t->u_lock : P
154125cf1a30Sjl  *  -. uinst_t->l_lock : P
154225cf1a30Sjl  *  -. uinst_t->c_lock : P
154325cf1a30Sjl  */
154425cf1a30Sjl void
154525cf1a30Sjl oplmsu_rcmn_high_qenable(queue_t *q)
154625cf1a30Sjl {
154725cf1a30Sjl 	mblk_t		*mp;
154825cf1a30Sjl 	struct iocblk	*iocp = NULL;
154925cf1a30Sjl 	lpath_t		*lpath;
155025cf1a30Sjl 	int		rval;
155125cf1a30Sjl 
155225cf1a30Sjl 	rw_enter(&oplmsu_uinst->lock, RW_READER);
155325cf1a30Sjl 
155425cf1a30Sjl 	for (;;) {	/* Handle high priority message */
155525cf1a30Sjl 		mutex_enter(&oplmsu_uinst->l_lock);
155625cf1a30Sjl 		lpath = (lpath_t *)q->q_ptr;
155725cf1a30Sjl 		if ((mp = lpath->first_lpri_hi) == NULL) {
155825cf1a30Sjl 			mutex_exit(&oplmsu_uinst->l_lock);
155925cf1a30Sjl 			break;
156025cf1a30Sjl 		}
156125cf1a30Sjl 
156225cf1a30Sjl 		if (mp->b_next == NULL) {
156325cf1a30Sjl 			lpath->first_lpri_hi = NULL;
156425cf1a30Sjl 			lpath->last_lpri_hi = NULL;
156525cf1a30Sjl 		} else {
156625cf1a30Sjl 			lpath->first_lpri_hi = mp->b_next;
156725cf1a30Sjl 			mp->b_next->b_prev = NULL;
156825cf1a30Sjl 			mp->b_next = NULL;
156925cf1a30Sjl 		}
157025cf1a30Sjl 		mp->b_prev = NULL;
157125cf1a30Sjl 		mutex_exit(&oplmsu_uinst->l_lock);
157225cf1a30Sjl 
157325cf1a30Sjl 		rval = SUCCESS;
157425cf1a30Sjl 		switch (mp->b_datap->db_type) {
157525cf1a30Sjl 		case M_IOCACK :		/* FALLTHRU */
157625cf1a30Sjl 		case M_IOCNAK :
157725cf1a30Sjl 			iocp = (struct iocblk *)mp->b_rptr;
157825cf1a30Sjl 			switch (iocp->ioc_cmd) {
157925cf1a30Sjl 			case TCSETS :		/* FALLTHRU */
158025cf1a30Sjl 			case TCSETSW :		/* FALLTHRU */
158125cf1a30Sjl 			case TCSETSF :		/* FALLTHRU */
158225cf1a30Sjl 			case TIOCMSET :		/* FALLTHRU */
158325cf1a30Sjl 			case TIOCSPPS :		/* FALLTHRU */
158425cf1a30Sjl 			case TIOCSWINSZ :	/* FALLTHRU */
158525cf1a30Sjl 			case TIOCSSOFTCAR :
158625cf1a30Sjl 				rw_exit(&oplmsu_uinst->lock);
158725cf1a30Sjl 				rval = oplmsu_lrioctl_termios(q, mp);
158825cf1a30Sjl 				rw_enter(&oplmsu_uinst->lock, RW_WRITER);
158925cf1a30Sjl 				break;
159025cf1a30Sjl 
159125cf1a30Sjl 			default :
159225cf1a30Sjl 				rval = oplmsu_rcmn_through_hndl(
159325cf1a30Sjl 				    q, mp, MSU_HIGH);
159425cf1a30Sjl 				if (rval == FAILURE) {
159525cf1a30Sjl 					rw_exit(&oplmsu_uinst->lock);
159625cf1a30Sjl 					return;
159725cf1a30Sjl 				}
159825cf1a30Sjl 			}
159925cf1a30Sjl 			break;
160025cf1a30Sjl 
160125cf1a30Sjl 		case M_ERROR :
160225cf1a30Sjl 			rw_exit(&oplmsu_uinst->lock);
160325cf1a30Sjl 			rval = oplmsu_lrmsg_error(q, mp);
160425cf1a30Sjl 			rw_enter(&oplmsu_uinst->lock, RW_WRITER);
160525cf1a30Sjl 			break;
160625cf1a30Sjl 
160725cf1a30Sjl 		case M_FLUSH :
160825cf1a30Sjl 			oplmsu_rcmn_flush_hndl(q, mp);
160925cf1a30Sjl 			break;
161025cf1a30Sjl 
161125cf1a30Sjl 		default :
161225cf1a30Sjl 			rval = oplmsu_rcmn_through_hndl(q, mp, MSU_HIGH);
161325cf1a30Sjl 			if (rval == FAILURE) {
161425cf1a30Sjl 				rw_exit(&oplmsu_uinst->lock);
161525cf1a30Sjl 				return;
161625cf1a30Sjl 			}
161725cf1a30Sjl 		}
161825cf1a30Sjl 
161925cf1a30Sjl 		if (rval == FAILURE) {
162025cf1a30Sjl 			break;
162125cf1a30Sjl 		}
162225cf1a30Sjl 	}
162325cf1a30Sjl 
162425cf1a30Sjl 	rw_exit(&oplmsu_uinst->lock);
162525cf1a30Sjl 	qenable(q);	/* Enable lower read queue */
162625cf1a30Sjl }
162725cf1a30Sjl 
162825cf1a30Sjl #ifdef DEBUG
162925cf1a30Sjl /*
163025cf1a30Sjl  * Online trace
163125cf1a30Sjl  *
163225cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
163325cf1a30Sjl  *  -. uinst_t->lock   : P
163425cf1a30Sjl  *  -. uinst_t->u_lock : P
163525cf1a30Sjl  *  -. uinst_t->l_lock : P
163625cf1a30Sjl  *  -. uinst_t->c_lock : P
163725cf1a30Sjl  */
163825cf1a30Sjl void
163925cf1a30Sjl oplmsu_cmn_trace(queue_t *q, mblk_t *mp, int op)
164025cf1a30Sjl {
164125cf1a30Sjl 	struct iocblk	*iocp;
164225cf1a30Sjl 
164325cf1a30Sjl 	if ((op < MSU_TRC_UI) || (op > MSU_TRC_CLS)) {
164425cf1a30Sjl 		return;
164525cf1a30Sjl 	}
164625cf1a30Sjl 
164725cf1a30Sjl 	mutex_enter(&oplmsu_ltrc_lock);
164825cf1a30Sjl 
164925cf1a30Sjl 	if (oplmsu_debug_mode & MSU_DPRINT_ON) {
165025cf1a30Sjl 		oplmsu_cmn_msglog(mp, op);
165125cf1a30Sjl 	}
165225cf1a30Sjl 
165325cf1a30Sjl 	/* Trace current counter */
1654*07d06da5SSurya Prakki 	(void) drv_getparm(LBOLT, (void *)&oplmsu_ltrc_ccnt);
165525cf1a30Sjl 
165625cf1a30Sjl 	if (oplmsu_ltrc_cur == oplmsu_ltrc_tail) {
165725cf1a30Sjl 		oplmsu_ltrc_cur = oplmsu_ltrc_top;
165825cf1a30Sjl 	} else {
165925cf1a30Sjl 		oplmsu_ltrc_cur++;
166025cf1a30Sjl 	}
166125cf1a30Sjl 	oplmsu_ltrc_cur->q = q;
166225cf1a30Sjl 	oplmsu_ltrc_cur->mp = mp;
166325cf1a30Sjl 
166425cf1a30Sjl 	switch (op) {
166525cf1a30Sjl 	case MSU_TRC_UI :
166625cf1a30Sjl 		oplmsu_ltrc_cur->op[0] = 'u';
166725cf1a30Sjl 		oplmsu_ltrc_cur->op[1] = 'i';
166825cf1a30Sjl 		break;
166925cf1a30Sjl 
167025cf1a30Sjl 	case MSU_TRC_UO :
167125cf1a30Sjl 		oplmsu_ltrc_cur->op[0] = 'u';
167225cf1a30Sjl 		oplmsu_ltrc_cur->op[1] = 'o';
167325cf1a30Sjl 		break;
167425cf1a30Sjl 
167525cf1a30Sjl 	case MSU_TRC_LI :
167625cf1a30Sjl 		oplmsu_ltrc_cur->op[0] = 'l';
167725cf1a30Sjl 		oplmsu_ltrc_cur->op[1] = 'i';
167825cf1a30Sjl 		break;
167925cf1a30Sjl 
168025cf1a30Sjl 	case MSU_TRC_LO :
168125cf1a30Sjl 		oplmsu_ltrc_cur->op[0] = 'l';
168225cf1a30Sjl 		oplmsu_ltrc_cur->op[1] = 'o';
168325cf1a30Sjl 		break;
168425cf1a30Sjl 
168525cf1a30Sjl 	case MSU_TRC_OPN :
168625cf1a30Sjl 		oplmsu_ltrc_cur->op[0] = 'o';
168725cf1a30Sjl 		oplmsu_ltrc_cur->op[1] = 'p';
168825cf1a30Sjl 		break;
168925cf1a30Sjl 
169025cf1a30Sjl 	case MSU_TRC_CLS :
169125cf1a30Sjl 		oplmsu_ltrc_cur->op[0] = 'c';
169225cf1a30Sjl 		oplmsu_ltrc_cur->op[1] = 'l';
169325cf1a30Sjl 		break;
169425cf1a30Sjl 	}
169525cf1a30Sjl 
169625cf1a30Sjl 	if ((op == MSU_TRC_LI) || (op == MSU_TRC_LO)) {
169725cf1a30Sjl 		mutex_enter(&oplmsu_uinst->l_lock);
169825cf1a30Sjl 		oplmsu_ltrc_cur->pathno = ((lpath_t *)q->q_ptr)->path_no;
169925cf1a30Sjl 		mutex_exit(&oplmsu_uinst->l_lock);
170025cf1a30Sjl 	} else {
170125cf1a30Sjl 		oplmsu_ltrc_cur->pathno = 0;
170225cf1a30Sjl 	}
170325cf1a30Sjl 
170425cf1a30Sjl 	if ((op == MSU_TRC_OPN) || (op == MSU_TRC_CLS)) {
170525cf1a30Sjl 		oplmsu_ltrc_cur->msg_type = 0;
170625cf1a30Sjl 		oplmsu_ltrc_cur->msg_cmd = 0;
170725cf1a30Sjl 		oplmsu_ltrc_cur->data = 0;
170825cf1a30Sjl 
170925cf1a30Sjl 		switch ((ulong_t)mp) {
171025cf1a30Sjl 		case MSU_NODE_USER :
171125cf1a30Sjl 			oplmsu_ltrc_cur->data = MSU_TRC_USER;
171225cf1a30Sjl 			break;
171325cf1a30Sjl 
171425cf1a30Sjl 		case MSU_NODE_META :
171525cf1a30Sjl 			oplmsu_ltrc_cur->data = MSU_TRC_META;
171625cf1a30Sjl 			break;
171725cf1a30Sjl 		}
171825cf1a30Sjl 		oplmsu_ltrc_cur->mp = NULL;
171925cf1a30Sjl 	} else {
172025cf1a30Sjl 		oplmsu_ltrc_cur->msg_type = mp->b_datap->db_type;
172125cf1a30Sjl 		iocp = (struct iocblk *)mp->b_rptr;
172225cf1a30Sjl 		oplmsu_ltrc_cur->msg_cmd = iocp->ioc_cmd;
172325cf1a30Sjl 
172425cf1a30Sjl 		if ((mp->b_datap->db_type == M_IOCTL) ||
172525cf1a30Sjl 		    (mp->b_datap->db_type == M_IOCACK) ||
172625cf1a30Sjl 		    (mp->b_datap->db_type == M_IOCNAK)) {
172725cf1a30Sjl 			oplmsu_ltrc_cur->msg_cmd = iocp->ioc_cmd;
172825cf1a30Sjl 
172925cf1a30Sjl 			if (mp->b_cont != NULL) {
173025cf1a30Sjl 				oplmsu_ltrc_cur->data =
173125cf1a30Sjl 				    (ulong_t)mp->b_cont->b_rptr;
173225cf1a30Sjl 			} else {
173325cf1a30Sjl 				oplmsu_ltrc_cur->data = 0;
173425cf1a30Sjl 			}
173525cf1a30Sjl 		} else {
173625cf1a30Sjl 			oplmsu_ltrc_cur->msg_cmd = 0;
173725cf1a30Sjl 
173825cf1a30Sjl 			if (mp->b_rptr == NULL) {
173925cf1a30Sjl 				oplmsu_ltrc_cur->data = 0;
174025cf1a30Sjl 			} else {
174125cf1a30Sjl 				oplmsu_ltrc_cur->data = *(ulong_t *)mp->b_rptr;
174225cf1a30Sjl 			}
174325cf1a30Sjl 		}
174425cf1a30Sjl 	}
174525cf1a30Sjl 	mutex_exit(&oplmsu_ltrc_lock);
174625cf1a30Sjl }
174725cf1a30Sjl 
174825cf1a30Sjl /*
174925cf1a30Sjl  * Display message log to console
175025cf1a30Sjl  *
175125cf1a30Sjl  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
175225cf1a30Sjl  *  -. uinst_t->lock   : P
175325cf1a30Sjl  *  -. uinst_t->u_lock : P
175425cf1a30Sjl  *  -. uinst_t->l_lock : P
175525cf1a30Sjl  *  -. uinst_t->c_lock : P
175625cf1a30Sjl  */
175725cf1a30Sjl void
175825cf1a30Sjl oplmsu_cmn_msglog(mblk_t *mp, int direction)
175925cf1a30Sjl {
176025cf1a30Sjl 	uchar_t	*cur = NULL;
176125cf1a30Sjl 	mblk_t	*tmp_mp = NULL;
176225cf1a30Sjl 	ulong_t	len;
176325cf1a30Sjl 	ulong_t	line;
176425cf1a30Sjl 	ulong_t	col;
176525cf1a30Sjl 	ulong_t	row;
176625cf1a30Sjl 	ulong_t	count;
176725cf1a30Sjl 	char	buffer[70];
176825cf1a30Sjl 	char	*bufp;
176925cf1a30Sjl 
177025cf1a30Sjl 	if (mp == NULL) {
177125cf1a30Sjl 		return;
177225cf1a30Sjl 	}
177325cf1a30Sjl 
177425cf1a30Sjl 	switch (direction) {
177525cf1a30Sjl 	case 0:
177625cf1a30Sjl 		cmn_err(CE_NOTE, "!---------- Upper in --------");
177725cf1a30Sjl 		break;
177825cf1a30Sjl 
177925cf1a30Sjl 	case 1:
178025cf1a30Sjl 		cmn_err(CE_NOTE, "!---------- Upper out -------");
178125cf1a30Sjl 		break;
178225cf1a30Sjl 
178325cf1a30Sjl 	case 2:
178425cf1a30Sjl 		cmn_err(CE_NOTE, "!---------- Lower in --------");
178525cf1a30Sjl 		break;
178625cf1a30Sjl 
178725cf1a30Sjl 	case 3:
178825cf1a30Sjl 		cmn_err(CE_NOTE, "!---------- Lower out -------");
178925cf1a30Sjl 		break;
179025cf1a30Sjl 
179125cf1a30Sjl 	default:
179225cf1a30Sjl 		return;
179325cf1a30Sjl 	}
179425cf1a30Sjl 
179525cf1a30Sjl 	for (tmp_mp = mp; tmp_mp; tmp_mp = tmp_mp->b_cont) {
179625cf1a30Sjl 		cmn_err(CE_NOTE, "!db_type = 0x%02x", tmp_mp->b_datap->db_type);
179725cf1a30Sjl 
179825cf1a30Sjl 		len = tmp_mp->b_wptr - tmp_mp->b_rptr;
179925cf1a30Sjl 		line = (len + 31) / 32;
180025cf1a30Sjl 		cur = (uchar_t *)tmp_mp->b_rptr;
180125cf1a30Sjl 		count = 0;
180225cf1a30Sjl 
180325cf1a30Sjl 		for (col = 0; col < line; col++) {
180425cf1a30Sjl 			bufp = buffer;
180525cf1a30Sjl 
180625cf1a30Sjl 			for (row = 0; row < 32; row++) {
180725cf1a30Sjl 				if (row != 0 && (row % 8) == 0) {
180825cf1a30Sjl 					*bufp = ' ';
180925cf1a30Sjl 					bufp++;
181025cf1a30Sjl 				}
1811*07d06da5SSurya Prakki 				(void) sprintf(bufp, "%02x", *cur);
181225cf1a30Sjl 				bufp += 2;
181325cf1a30Sjl 				cur++;
181425cf1a30Sjl 				count++;
181525cf1a30Sjl 
181625cf1a30Sjl 				if (count >= len) {
181725cf1a30Sjl 					break;
181825cf1a30Sjl 				}
181925cf1a30Sjl 			}
182025cf1a30Sjl 			*bufp = '\0';
182125cf1a30Sjl 			cmn_err(CE_NOTE, "!%s", buffer);
182225cf1a30Sjl 
182325cf1a30Sjl 			if (count >= len) {
182425cf1a30Sjl 				break;
182525cf1a30Sjl 			}
182625cf1a30Sjl 		}
182725cf1a30Sjl 	}
182825cf1a30Sjl }
182925cf1a30Sjl 
183025cf1a30Sjl void
183125cf1a30Sjl oplmsu_cmn_prt_pathname(dev_info_t *dip)
183225cf1a30Sjl {
183325cf1a30Sjl 	char	pathname[128];
183425cf1a30Sjl 	char	wrkbuf[128];
183525cf1a30Sjl 
1836*07d06da5SSurya Prakki 	(void) ddi_pathname(dip, wrkbuf);
183725cf1a30Sjl 	*(wrkbuf + strlen(wrkbuf)) = '\0';
1838*07d06da5SSurya Prakki 	(void) sprintf(pathname, "/devices%s:%c", wrkbuf,
1839*07d06da5SSurya Prakki 	    'a'+ ddi_get_instance(dip));
184025cf1a30Sjl 
184125cf1a30Sjl 	DBG_PRINT((CE_NOTE, "oplmsu: debug-info: "
184225cf1a30Sjl 	    "Active path change to path => %s", pathname));
184325cf1a30Sjl }
184425cf1a30Sjl #endif
1845