xref: /illumos-gate/usr/src/uts/sun4u/opl/io/oplmsu/oplmsu_ioctl_lrp.c (revision c2c6897e1a5682452b38f92bc27270708f1e033c)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
2625cf1a30Sjl 
2725cf1a30Sjl #include <sys/errno.h>
2825cf1a30Sjl #include <sys/modctl.h>
2925cf1a30Sjl #include <sys/stat.h>
3025cf1a30Sjl #include <sys/kmem.h>
3125cf1a30Sjl #include <sys/ksynch.h>
3225cf1a30Sjl #include <sys/stream.h>
3325cf1a30Sjl #include <sys/stropts.h>
3425cf1a30Sjl #include <sys/termio.h>
3525cf1a30Sjl #include <sys/ddi.h>
3625cf1a30Sjl #include <sys/file.h>
3725cf1a30Sjl #include <sys/disp.h>
3825cf1a30Sjl #include <sys/sunddi.h>
3925cf1a30Sjl #include <sys/sunldi.h>
4025cf1a30Sjl #include <sys/sunndi.h>
4125cf1a30Sjl #include <sys/prom_plat.h>
4225cf1a30Sjl #include <sys/oplmsu/oplmsu.h>
4325cf1a30Sjl #include <sys/oplmsu/oplmsu_proto.h>
4425cf1a30Sjl 
4525cf1a30Sjl /*
4625cf1a30Sjl  *	LOWER READ SERVICE PROCEDURE
4725cf1a30Sjl  */
4825cf1a30Sjl 
4925cf1a30Sjl /* termios ioctl response received */
5025cf1a30Sjl int
5125cf1a30Sjl oplmsu_lrioctl_termios(queue_t *lrq, mblk_t *mp)
5225cf1a30Sjl {
5325cf1a30Sjl 	upath_t		*upath, *altn_upath = NULL, *stp_upath = NULL;
5425cf1a30Sjl 	lpath_t		*lpath, *altn_lpath = NULL, *stp_lpath = NULL;
5525cf1a30Sjl 	struct iocblk	*iocp, *temp_iocp = NULL;
5625cf1a30Sjl 	mblk_t		*hndl_mp, *nmp = NULL, *fmp = NULL;
5725cf1a30Sjl 	queue_t		*dst_queue;
5825cf1a30Sjl 	int		term_ioctl, term_stat, sts;
5925cf1a30Sjl 	int		ack_flag, termio_flag, chkflag;
6025cf1a30Sjl 	ulong_t		trad_sts;
6125cf1a30Sjl 
6225cf1a30Sjl 	rw_enter(&oplmsu_uinst->lock, RW_READER);
6325cf1a30Sjl 	iocp = (struct iocblk *)mp->b_rptr;
6425cf1a30Sjl 
6525cf1a30Sjl 	mutex_enter(&oplmsu_uinst->u_lock);
6625cf1a30Sjl 	mutex_enter(&oplmsu_uinst->l_lock);
6725cf1a30Sjl 	lpath = (lpath_t *)lrq->q_ptr;
6825cf1a30Sjl 	hndl_mp = lpath->hndl_mp;
6925cf1a30Sjl 
7025cf1a30Sjl 	upath = oplmsu_search_upath_info(lpath->path_no);
7125cf1a30Sjl 	trad_sts = upath->traditional_status;
7225cf1a30Sjl 	mutex_exit(&oplmsu_uinst->l_lock);
7325cf1a30Sjl 	mutex_exit(&oplmsu_uinst->u_lock);
7425cf1a30Sjl 
7525cf1a30Sjl 	if (((iocp->ioc_cmd == TCSETS) && (trad_sts == MSU_WTCS_ACK)) ||
7625cf1a30Sjl 	    ((iocp->ioc_cmd == TCSETSW) && (trad_sts == MSU_WTCS_ACK)) ||
7725cf1a30Sjl 	    ((iocp->ioc_cmd == TCSETSF) && (trad_sts == MSU_WTCS_ACK)) ||
7825cf1a30Sjl 	    ((iocp->ioc_cmd == TIOCMSET) && (trad_sts == MSU_WTMS_ACK)) ||
7925cf1a30Sjl 	    ((iocp->ioc_cmd == TIOCSPPS) && (trad_sts == MSU_WPPS_ACK)) ||
8025cf1a30Sjl 	    ((iocp->ioc_cmd == TIOCSWINSZ) && (trad_sts == MSU_WWSZ_ACK)) ||
8125cf1a30Sjl 	    ((iocp->ioc_cmd == TIOCSSOFTCAR) && (trad_sts == MSU_WCAR_ACK))) {
8225cf1a30Sjl 		if (mp->b_datap->db_type == M_IOCACK) {
8325cf1a30Sjl 			ack_flag = ACK_RES;
8425cf1a30Sjl 		} else {
8525cf1a30Sjl 			ack_flag = NAK_RES;
8625cf1a30Sjl 		}
8725cf1a30Sjl 	} else {
8825cf1a30Sjl 		rw_exit(&oplmsu_uinst->lock);
8925cf1a30Sjl 		freemsg(mp);
9025cf1a30Sjl 		cmn_err(CE_WARN, "oplmsu: lr-termios: "
9125cf1a30Sjl 		    "Status of path is improper");
9225cf1a30Sjl 		return (SUCCESS);
9325cf1a30Sjl 	}
9425cf1a30Sjl 
9525cf1a30Sjl 	switch (trad_sts) {
9625cf1a30Sjl 	case MSU_WTCS_ACK :
9725cf1a30Sjl 		termio_flag = MSU_TIOS_TCSETS;
9825cf1a30Sjl 		break;
9925cf1a30Sjl 
10025cf1a30Sjl 	case MSU_WTMS_ACK :
10125cf1a30Sjl 		termio_flag = MSU_TIOS_MSET;
10225cf1a30Sjl 		break;
10325cf1a30Sjl 
10425cf1a30Sjl 	case MSU_WPPS_ACK :
10525cf1a30Sjl 		termio_flag = MSU_TIOS_PPS;
10625cf1a30Sjl 		break;
10725cf1a30Sjl 
10825cf1a30Sjl 	case MSU_WWSZ_ACK :
10925cf1a30Sjl 		termio_flag = MSU_TIOS_WINSZP;
11025cf1a30Sjl 		break;
11125cf1a30Sjl 
11225cf1a30Sjl 	case MSU_WCAR_ACK :
11325cf1a30Sjl 		termio_flag = MSU_TIOS_SOFTCAR;
11425cf1a30Sjl 		break;
11525cf1a30Sjl 
11625cf1a30Sjl 	default :
11725cf1a30Sjl 		termio_flag = MSU_TIOS_END;
11825cf1a30Sjl 		break;
11925cf1a30Sjl 	}
12025cf1a30Sjl 
12125cf1a30Sjl 	if (hndl_mp == NULL) {
12225cf1a30Sjl 		switch (trad_sts) {
12325cf1a30Sjl 		case MSU_WTCS_ACK :	/* FALLTHRU */
12425cf1a30Sjl 		case MSU_WTMS_ACK :	/* FALLTHRU */
12525cf1a30Sjl 		case MSU_WPPS_ACK :	/* FALLTHRU */
12625cf1a30Sjl 		case MSU_WWSZ_ACK :	/* FALLTHRU */
12725cf1a30Sjl 		case MSU_WCAR_ACK :
12825cf1a30Sjl 			chkflag = MSU_CMD_STOP;
12925cf1a30Sjl 			break;
13025cf1a30Sjl 
13125cf1a30Sjl 		default :
13225cf1a30Sjl 			chkflag = FAILURE;
13325cf1a30Sjl 			break;
13425cf1a30Sjl 		}
13525cf1a30Sjl 	} else {
13625cf1a30Sjl 		/* xoff/xon received */
13725cf1a30Sjl 		if (hndl_mp->b_datap->db_type == M_DATA) {
13825cf1a30Sjl 			chkflag = MSU_CMD_ACTIVE;
13925cf1a30Sjl 		} else { /* Normal termios */
14025cf1a30Sjl 			temp_iocp = (struct iocblk *)hndl_mp->b_rptr;
14125cf1a30Sjl 			chkflag = temp_iocp->ioc_cmd;
14225cf1a30Sjl 		}
14325cf1a30Sjl 	}
14425cf1a30Sjl 
14525cf1a30Sjl 	if ((chkflag == MSU_CMD_ACTIVE) || (chkflag == MSU_CMD_STOP)) {
14625cf1a30Sjl 		if (ack_flag == ACK_RES) { /* M_IOCACK received */
14725cf1a30Sjl 			ctrl_t	*ctrl;
14825cf1a30Sjl 
14925cf1a30Sjl 			if (oplmsu_cmn_prechg_termio(lrq, mp, MSU_READ_SIDE,
15025cf1a30Sjl 			    termio_flag, &nmp, &term_stat) == FAILURE) {
15125cf1a30Sjl 				rw_exit(&oplmsu_uinst->lock);
15225cf1a30Sjl 				return (FAILURE);
15325cf1a30Sjl 			}
15425cf1a30Sjl 
15525cf1a30Sjl 			OPLMSU_RWLOCK_UPGRADE();
15625cf1a30Sjl 			mutex_enter(&oplmsu_uinst->u_lock);
15725cf1a30Sjl 			if (term_stat != MSU_WPTH_CHG) {
15825cf1a30Sjl 				upath->traditional_status = term_stat;
15925cf1a30Sjl 				mutex_exit(&oplmsu_uinst->u_lock);
16025cf1a30Sjl 				rw_exit(&oplmsu_uinst->lock);
16125cf1a30Sjl 				freemsg(mp);
16225cf1a30Sjl 
16325cf1a30Sjl 				OPLMSU_TRACE(RD(lrq), nmp, MSU_TRC_LO);
16425cf1a30Sjl 
16525cf1a30Sjl 				/* Continue sending termios ioctls */
16625cf1a30Sjl 				qreply(RD(lrq), nmp);
16725cf1a30Sjl 				return (SUCCESS);
16825cf1a30Sjl 			}
16925cf1a30Sjl 			freemsg(mp);
17025cf1a30Sjl 
17125cf1a30Sjl 			/* Change status of new active path */
17225cf1a30Sjl 			oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_ACTIVE,
17325cf1a30Sjl 			    upath->status, MSU_ACTIVE);
17425cf1a30Sjl 
17525cf1a30Sjl 			mutex_enter(&oplmsu_uinst->l_lock);
17625cf1a30Sjl 			lpath->uinst = oplmsu_uinst;
17725cf1a30Sjl 			dst_queue = lpath->hndl_uqueue;
17825cf1a30Sjl 
17925cf1a30Sjl 			ctrl = oplmsu_uinst->user_ctrl;
18025cf1a30Sjl 			if ((chkflag == MSU_CMD_ACTIVE) && (hndl_mp != NULL)) {
18125cf1a30Sjl 				/* Put a message(M_DATA) on a queue */
18225cf1a30Sjl 				if (ctrl != NULL) {
18325cf1a30Sjl 					mutex_enter(&oplmsu_uinst->c_lock);
18425cf1a30Sjl 					putq(RD(ctrl->queue), hndl_mp);
18525cf1a30Sjl 					mutex_exit(&oplmsu_uinst->c_lock);
18625cf1a30Sjl 				}
18725cf1a30Sjl 			}
18825cf1a30Sjl 
18925cf1a30Sjl 			oplmsu_clear_ioctl_path(lpath);
19025cf1a30Sjl 			stp_upath = lpath->src_upath;
19125cf1a30Sjl 			lpath->src_upath = NULL;
19225cf1a30Sjl 			lpath->status = MSU_EXT_NOTUSED;
19325cf1a30Sjl 
19425cf1a30Sjl 			/* Notify of the active path changing */
19525cf1a30Sjl 			prom_opl_switch_console(upath->ser_devcb.lsb);
19625cf1a30Sjl 
19725cf1a30Sjl 			/* Send XON to notify active path */
19825cf1a30Sjl 			(void) oplmsu_cmn_put_xoffxon(WR(lrq), MSU_XON_4);
19925cf1a30Sjl 
20025cf1a30Sjl 			stp_lpath = stp_upath->lpath;
20125cf1a30Sjl 			stp_lpath->uinst = NULL;
20225cf1a30Sjl 			oplmsu_clear_ioctl_path(stp_lpath);
20325cf1a30Sjl 			stp_lpath->src_upath = NULL;
20425cf1a30Sjl 			stp_lpath->status = MSU_EXT_NOTUSED;
20525cf1a30Sjl 
20625cf1a30Sjl 			/* Change status of stopped or old-active path */
20725cf1a30Sjl 			if (chkflag == MSU_CMD_STOP) {
20825cf1a30Sjl 				sts = MSU_PSTAT_STOP;
20925cf1a30Sjl 				trad_sts = MSU_STOP;
21025cf1a30Sjl 			} else { /* == MSU_CMD_ACTIVE */
21125cf1a30Sjl 				sts = MSU_PSTAT_STANDBY;
21225cf1a30Sjl 				trad_sts = MSU_STANDBY;
21325cf1a30Sjl 			}
21425cf1a30Sjl 			oplmsu_cmn_set_upath_sts(stp_upath, sts,
21525cf1a30Sjl 			    stp_upath->status, trad_sts);
21625cf1a30Sjl 
21725cf1a30Sjl 			/* Send XOFF to notify all standby paths */
21825cf1a30Sjl 			oplmsu_cmn_putxoff_standby();
21925cf1a30Sjl 			oplmsu_uinst->lower_queue = lrq;
22025cf1a30Sjl 			oplmsu_uinst->inst_status = oplmsu_get_inst_status();
22125cf1a30Sjl 			mutex_exit(&oplmsu_uinst->l_lock);
22225cf1a30Sjl 			mutex_exit(&oplmsu_uinst->u_lock);
22325cf1a30Sjl 
22425cf1a30Sjl 			/* Change active path of user node */
22525cf1a30Sjl 			if (ctrl != NULL) {
22625cf1a30Sjl 				queue_t	*temp_queue;
22725cf1a30Sjl 
22825cf1a30Sjl 				mutex_enter(&oplmsu_uinst->c_lock);
22925cf1a30Sjl 				temp_queue = WR(ctrl->queue);
23025cf1a30Sjl 				mutex_exit(&oplmsu_uinst->c_lock);
23125cf1a30Sjl 
23225cf1a30Sjl 				/* Reschedule a queue for service */
23325cf1a30Sjl 				enableok(temp_queue);
23425cf1a30Sjl 
23525cf1a30Sjl 				oplmsu_queue_flag = 0;
23625cf1a30Sjl 				oplmsu_wcmn_high_qenable(temp_queue, RW_WRITER);
23725cf1a30Sjl 			}
23825cf1a30Sjl 			rw_exit(&oplmsu_uinst->lock);
23925cf1a30Sjl 
24025cf1a30Sjl 			if (nmp != NULL) {
24125cf1a30Sjl 				freemsg(nmp);
24225cf1a30Sjl 			}
24325cf1a30Sjl 
24425cf1a30Sjl 			/* Wake up oplmsu_config_stop */
24525cf1a30Sjl 			mutex_enter(&oplmsu_uinst->l_lock);
24625cf1a30Sjl 			if (stp_lpath->sw_flag) {
24725cf1a30Sjl 				stp_lpath->sw_flag = 0;
24825cf1a30Sjl 				cv_signal(&stp_lpath->sw_cv);
24925cf1a30Sjl 			}
25025cf1a30Sjl 			mutex_exit(&oplmsu_uinst->l_lock);
25125cf1a30Sjl 			return (SUCCESS);
25225cf1a30Sjl 		} else { /* M_IOCNAK received */
25325cf1a30Sjl 			mutex_enter(&oplmsu_uinst->u_lock);
25425cf1a30Sjl 			mutex_enter(&oplmsu_uinst->l_lock);
25525cf1a30Sjl 			if ((chkflag == MSU_CMD_ACTIVE) &&
25625cf1a30Sjl 			    (lpath->hndl_uqueue == NULL)) {
25725cf1a30Sjl 				oplmsu_clear_ioctl_path(lpath);
25825cf1a30Sjl 				stp_upath = lpath->src_upath;
25925cf1a30Sjl 				lpath->src_upath = NULL;
26025cf1a30Sjl 				lpath->status = MSU_EXT_NOTUSED;
26125cf1a30Sjl 				mutex_exit(&oplmsu_uinst->l_lock);
26225cf1a30Sjl 
26325cf1a30Sjl 				oplmsu_cmn_set_upath_sts(upath,
26425cf1a30Sjl 				    MSU_PSTAT_STANDBY, upath->status,
26525cf1a30Sjl 				    MSU_STANDBY);
26625cf1a30Sjl 				mutex_exit(&oplmsu_uinst->u_lock);
26725cf1a30Sjl 
26825cf1a30Sjl 				if (hndl_mp != NULL) {
26925cf1a30Sjl 					freemsg(hndl_mp);
27025cf1a30Sjl 				}
27125cf1a30Sjl 
27225cf1a30Sjl 				OPLMSU_RWLOCK_UPGRADE();
27325cf1a30Sjl 				mutex_enter(&oplmsu_uinst->u_lock);
27425cf1a30Sjl 				oplmsu_uinst->inst_status =
27525cf1a30Sjl 				    oplmsu_get_inst_status();
27625cf1a30Sjl 				mutex_exit(&oplmsu_uinst->u_lock);
27725cf1a30Sjl 				rw_exit(&oplmsu_uinst->lock);
27825cf1a30Sjl 				return (SUCCESS);
27925cf1a30Sjl 			} else if ((chkflag == MSU_CMD_STOP) &&
28025cf1a30Sjl 			    (lpath->src_upath != NULL) &&
28125cf1a30Sjl 			    (lpath->src_upath->lpath->sw_flag)) {
28225cf1a30Sjl 			/* MSU_CMD_STOP for active path */
28325cf1a30Sjl 
28425cf1a30Sjl 				dst_queue = RD(lpath->hndl_uqueue);
28525cf1a30Sjl 				stp_upath = lpath->src_upath;
28625cf1a30Sjl 
28725cf1a30Sjl 				/* Search alternate path from standby paths */
28825cf1a30Sjl 				altn_upath = oplmsu_search_standby();
28925cf1a30Sjl 				if (altn_upath == NULL) {
29025cf1a30Sjl 					altn_upath = upath;
29125cf1a30Sjl 				}
29225cf1a30Sjl 
29325cf1a30Sjl 				mutex_exit(&oplmsu_uinst->l_lock);
29425cf1a30Sjl 				if (oplmsu_cmn_allocmb(lrq, mp, &fmp,
29525cf1a30Sjl 				    sizeof (char), MSU_READ_SIDE) == FAILURE) {
29625cf1a30Sjl 					mutex_exit(&oplmsu_uinst->u_lock);
29725cf1a30Sjl 					rw_exit(&oplmsu_uinst->lock);
29825cf1a30Sjl 					return (FAILURE);
29925cf1a30Sjl 				}
30025cf1a30Sjl 
30125cf1a30Sjl 				if (oplmsu_cmn_prechg(lrq, mp, MSU_READ_SIDE,
30225cf1a30Sjl 				    &nmp, &term_ioctl, &term_stat) == FAILURE) {
30325cf1a30Sjl 					mutex_exit(&oplmsu_uinst->u_lock);
30425cf1a30Sjl 					rw_exit(&oplmsu_uinst->lock);
30525cf1a30Sjl 					freeb(fmp);
30625cf1a30Sjl 					return (FAILURE);
30725cf1a30Sjl 				}
30825cf1a30Sjl 
30925cf1a30Sjl 				altn_upath->traditional_status = term_stat;
31025cf1a30Sjl 				altn_lpath = altn_upath->lpath;
31125cf1a30Sjl 
31225cf1a30Sjl 				mutex_enter(&oplmsu_uinst->l_lock);
31325cf1a30Sjl 				altn_lpath->hndl_mp = hndl_mp;
31425cf1a30Sjl 				altn_lpath->hndl_uqueue = dst_queue;
31525cf1a30Sjl 				altn_lpath->src_upath = stp_upath;
31625cf1a30Sjl 				altn_lpath->status = MSU_EXT_VOID;
31725cf1a30Sjl 				dst_queue = RD(altn_lpath->lower_queue);
31825cf1a30Sjl 
31925cf1a30Sjl 				oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_FAIL,
32025cf1a30Sjl 				    upath->status, MSU_FAIL);
32125cf1a30Sjl 
32225cf1a30Sjl 				oplmsu_clear_ioctl_path(lpath);
32325cf1a30Sjl 				lpath->src_upath = NULL;
32425cf1a30Sjl 				lpath->status = MSU_EXT_NOTUSED;
32525cf1a30Sjl 				mutex_exit(&oplmsu_uinst->l_lock);
32625cf1a30Sjl 				mutex_exit(&oplmsu_uinst->u_lock);
32725cf1a30Sjl 
32825cf1a30Sjl 				OPLMSU_RWLOCK_UPGRADE();
32925cf1a30Sjl 				mutex_enter(&oplmsu_uinst->u_lock);
33025cf1a30Sjl 				oplmsu_uinst->inst_status =
33125cf1a30Sjl 				    oplmsu_get_inst_status();
33225cf1a30Sjl 				mutex_exit(&oplmsu_uinst->u_lock);
33325cf1a30Sjl 				rw_exit(&oplmsu_uinst->lock);
33425cf1a30Sjl 				freemsg(mp);
33525cf1a30Sjl 				oplmsu_cmn_set_mflush(fmp);
33625cf1a30Sjl 
33725cf1a30Sjl 				OPLMSU_TRACE(dst_queue, fmp, MSU_TRC_LO);
33825cf1a30Sjl 				qreply(dst_queue, fmp);
33925cf1a30Sjl 
34025cf1a30Sjl 				OPLMSU_TRACE(dst_queue, nmp, MSU_TRC_LO);
34125cf1a30Sjl 				qreply(dst_queue, nmp);
34225cf1a30Sjl 				return (SUCCESS);
34325cf1a30Sjl 			}
34425cf1a30Sjl 		}
34525cf1a30Sjl 	} else if ((chkflag == TCSETS) || (chkflag == TCSETSW) ||
34625cf1a30Sjl 	    (chkflag == TCSETSF) || (chkflag == TIOCMSET) ||
34725cf1a30Sjl 	    (chkflag == TIOCSPPS) || (chkflag == TIOCSWINSZ) ||
34825cf1a30Sjl 	    (chkflag == TIOCSSOFTCAR)) {
34925cf1a30Sjl 		mutex_enter(&oplmsu_uinst->u_lock);
35025cf1a30Sjl 		mutex_enter(&oplmsu_uinst->l_lock);
35125cf1a30Sjl 
35225cf1a30Sjl 		if ((ack_flag == ACK_RES) &&
35325cf1a30Sjl 		    (lpath->hndl_uqueue != NULL)) { /* M_IOCACK received */
35425cf1a30Sjl 			mutex_exit(&oplmsu_uinst->l_lock);
35525cf1a30Sjl 			mutex_exit(&oplmsu_uinst->u_lock);
35625cf1a30Sjl 			if (oplmsu_cmn_copymb(lrq, mp, &nmp, hndl_mp,
35725cf1a30Sjl 			    MSU_READ_SIDE) == FAILURE) {
35825cf1a30Sjl 				rw_exit(&oplmsu_uinst->lock);
35925cf1a30Sjl 				return (FAILURE);
36025cf1a30Sjl 			}
36125cf1a30Sjl 
36225cf1a30Sjl 			OPLMSU_RWLOCK_UPGRADE();
36325cf1a30Sjl 			switch (chkflag) {
36425cf1a30Sjl 			case TCSETS :	/* FALLTHRU */
36525cf1a30Sjl 			case TCSETSW :	/* FALLTHRU */
36625cf1a30Sjl 			case TCSETSF :
36725cf1a30Sjl 				if (oplmsu_uinst->tcsets_p != NULL) {
36825cf1a30Sjl 					freemsg(oplmsu_uinst->tcsets_p);
36925cf1a30Sjl 				}
37025cf1a30Sjl 				oplmsu_uinst->tcsets_p = nmp;
37125cf1a30Sjl 				break;
37225cf1a30Sjl 
37325cf1a30Sjl 			case TIOCMSET :
37425cf1a30Sjl 				if (oplmsu_uinst->tiocmset_p != NULL) {
37525cf1a30Sjl 					freemsg(oplmsu_uinst->tiocmset_p);
37625cf1a30Sjl 				}
37725cf1a30Sjl 				oplmsu_uinst->tiocmset_p = nmp;
37825cf1a30Sjl 				break;
37925cf1a30Sjl 
38025cf1a30Sjl 			case TIOCSPPS :
38125cf1a30Sjl 				if (oplmsu_uinst->tiocspps_p != NULL) {
38225cf1a30Sjl 					freemsg(oplmsu_uinst->tiocspps_p);
38325cf1a30Sjl 				}
38425cf1a30Sjl 				oplmsu_uinst->tiocspps_p = nmp;
38525cf1a30Sjl 				break;
38625cf1a30Sjl 
38725cf1a30Sjl 			case TIOCSWINSZ :
38825cf1a30Sjl 				if (oplmsu_uinst->tiocswinsz_p != NULL) {
38925cf1a30Sjl 					freemsg(oplmsu_uinst->tiocswinsz_p);
39025cf1a30Sjl 				}
39125cf1a30Sjl 				oplmsu_uinst->tiocswinsz_p = nmp;
39225cf1a30Sjl 				break;
39325cf1a30Sjl 
39425cf1a30Sjl 			case TIOCSSOFTCAR :
39525cf1a30Sjl 				if (oplmsu_uinst->tiocssoftcar_p != NULL) {
39625cf1a30Sjl 					freemsg(oplmsu_uinst->tiocssoftcar_p);
39725cf1a30Sjl 				}
39825cf1a30Sjl 				oplmsu_uinst->tiocssoftcar_p = nmp;
39925cf1a30Sjl 				break;
40025cf1a30Sjl 			}
40125cf1a30Sjl 
40225cf1a30Sjl 			mutex_enter(&oplmsu_uinst->u_lock);
40325cf1a30Sjl 			mutex_enter(&oplmsu_uinst->l_lock);
40425cf1a30Sjl 			upath->traditional_status = lpath->status;
40525cf1a30Sjl 			nmp = lpath->hndl_mp;
40625cf1a30Sjl 			nmp->b_datap->db_type = M_IOCACK;
40725cf1a30Sjl 			dst_queue = RD(lpath->hndl_uqueue);
40825cf1a30Sjl 			bcopy(mp->b_rptr, nmp->b_rptr, sizeof (struct iocblk));
40925cf1a30Sjl 
41025cf1a30Sjl 			oplmsu_clear_ioctl_path(lpath);
41125cf1a30Sjl 			lpath->src_upath = NULL;
41225cf1a30Sjl 			lpath->status = MSU_EXT_NOTUSED;
41325cf1a30Sjl 			mutex_exit(&oplmsu_uinst->l_lock);
41425cf1a30Sjl 			mutex_exit(&oplmsu_uinst->u_lock);
41525cf1a30Sjl 			freemsg(mp);
41625cf1a30Sjl 			putq(dst_queue, nmp);
41725cf1a30Sjl 
41825cf1a30Sjl 			/* Check sleep flag and wake up thread */
41925cf1a30Sjl 			oplmsu_cmn_wakeup(dst_queue);
42025cf1a30Sjl 			rw_exit(&oplmsu_uinst->lock);
42125cf1a30Sjl 			return (SUCCESS);
42225cf1a30Sjl 		} else if ((ack_flag == NAK_RES) &&
42325cf1a30Sjl 		    (lpath->hndl_uqueue != NULL)) { /* M_IOCNAK received */
42425cf1a30Sjl 			upath->traditional_status = lpath->status;
42525cf1a30Sjl 
42625cf1a30Sjl 			nmp = lpath->hndl_mp;
42725cf1a30Sjl 			nmp->b_datap->db_type = M_IOCNAK;
42825cf1a30Sjl 			dst_queue = RD(lpath->hndl_uqueue);
42925cf1a30Sjl 
43025cf1a30Sjl 			oplmsu_clear_ioctl_path(lpath);
43125cf1a30Sjl 			lpath->src_upath = NULL;
43225cf1a30Sjl 			lpath->status = MSU_EXT_NOTUSED;
43325cf1a30Sjl 			mutex_exit(&oplmsu_uinst->l_lock);
43425cf1a30Sjl 			mutex_exit(&oplmsu_uinst->u_lock);
43525cf1a30Sjl 			freemsg(mp);
43625cf1a30Sjl 			putq(dst_queue, nmp);
43725cf1a30Sjl 
43825cf1a30Sjl 			/* Check sleep flag and wake up thread */
43925cf1a30Sjl 			oplmsu_cmn_wakeup(dst_queue);
44025cf1a30Sjl 			rw_exit(&oplmsu_uinst->lock);
44125cf1a30Sjl 			return (SUCCESS);
44225cf1a30Sjl 		}
44325cf1a30Sjl 	}
44425cf1a30Sjl 
44525cf1a30Sjl 	mutex_enter(&oplmsu_uinst->u_lock);
44625cf1a30Sjl 	switch (upath->status) {
44725cf1a30Sjl 	case MSU_PSTAT_FAIL :
44825cf1a30Sjl 		upath->traditional_status = MSU_FAIL;
44925cf1a30Sjl 		break;
45025cf1a30Sjl 
45125cf1a30Sjl 	case MSU_PSTAT_STOP :
45225cf1a30Sjl 		upath->traditional_status = MSU_STOP;
45325cf1a30Sjl 		break;
45425cf1a30Sjl 
45525cf1a30Sjl 	case MSU_PSTAT_STANDBY :
45625cf1a30Sjl 		upath->traditional_status = MSU_STANDBY;
45725cf1a30Sjl 		break;
45825cf1a30Sjl 
45925cf1a30Sjl 	case MSU_PSTAT_ACTIVE :
46025cf1a30Sjl 		upath->traditional_status = MSU_ACTIVE;
46125cf1a30Sjl 		break;
46225cf1a30Sjl 	}
46325cf1a30Sjl 
46425cf1a30Sjl 	mutex_enter(&oplmsu_uinst->l_lock);
46525cf1a30Sjl 	oplmsu_clear_ioctl_path(lpath);
46625cf1a30Sjl 	mutex_exit(&oplmsu_uinst->l_lock);
46725cf1a30Sjl 	mutex_exit(&oplmsu_uinst->u_lock);
46825cf1a30Sjl 	rw_exit(&oplmsu_uinst->lock);
46925cf1a30Sjl 	freemsg(mp);
47025cf1a30Sjl 	return (SUCCESS);
47125cf1a30Sjl }
47225cf1a30Sjl 
47325cf1a30Sjl /* M_ERROR or M_HANGUP response received */
47425cf1a30Sjl int
47525cf1a30Sjl oplmsu_lrmsg_error(queue_t *lrq, mblk_t *mp)
47625cf1a30Sjl {
47725cf1a30Sjl 	upath_t	*upath, *altn_upath = NULL;
47825cf1a30Sjl 	lpath_t	*lpath, *altn_lpath = NULL;
47925cf1a30Sjl 	mblk_t	*nmp = NULL, *fmp = NULL;
48025cf1a30Sjl 	queue_t	*dst_queue = NULL;
48125cf1a30Sjl 	ctrl_t	*ctrl;
48225cf1a30Sjl 	int	term_stat, term_ioctl;
48325cf1a30Sjl 
48425cf1a30Sjl 	rw_enter(&oplmsu_uinst->lock, RW_READER);
48525cf1a30Sjl 	mutex_enter(&oplmsu_uinst->c_lock);
48625cf1a30Sjl 	ctrl = oplmsu_uinst->user_ctrl;
48725cf1a30Sjl 	if (ctrl != NULL) {
48825cf1a30Sjl 		dst_queue = RD(ctrl->queue);
48925cf1a30Sjl 	}
49025cf1a30Sjl 	mutex_exit(&oplmsu_uinst->c_lock);
49125cf1a30Sjl 
49225cf1a30Sjl 	mutex_enter(&oplmsu_uinst->u_lock);
49325cf1a30Sjl 	mutex_enter(&oplmsu_uinst->l_lock);
49425cf1a30Sjl 	lpath = (lpath_t *)lrq->q_ptr;
49525cf1a30Sjl 	upath = oplmsu_search_upath_info(lpath->path_no);
49625cf1a30Sjl 
497*c2c6897eSraghuram 	if (upath == NULL) {
498*c2c6897eSraghuram 		mutex_exit(&oplmsu_uinst->l_lock);
499*c2c6897eSraghuram 		mutex_exit(&oplmsu_uinst->u_lock);
500*c2c6897eSraghuram 		rw_exit(&oplmsu_uinst->lock);
501*c2c6897eSraghuram 		freemsg(mp);
502*c2c6897eSraghuram 		return (SUCCESS);
503*c2c6897eSraghuram 	}
504*c2c6897eSraghuram 
50525cf1a30Sjl 	if ((lpath->status == MSU_LINK_NU) ||
50625cf1a30Sjl 	    (lpath->status == MSU_SETID_NU) ||
50725cf1a30Sjl 	    (upath->traditional_status == MSU_WSTR_ACK) ||
50825cf1a30Sjl 	    (upath->traditional_status == MSU_WTCS_ACK) ||
50925cf1a30Sjl 	    (upath->traditional_status == MSU_WTMS_ACK) ||
51025cf1a30Sjl 	    (upath->traditional_status == MSU_WPPS_ACK) ||
51125cf1a30Sjl 	    (upath->traditional_status == MSU_WWSZ_ACK) ||
51225cf1a30Sjl 	    (upath->traditional_status == MSU_WCAR_ACK) ||
51325cf1a30Sjl 	    (upath->traditional_status == MSU_WSTP_ACK) ||
51425cf1a30Sjl 	    (upath->traditional_status == MSU_WPTH_CHG)) {
51525cf1a30Sjl 		mutex_exit(&oplmsu_uinst->l_lock);
51625cf1a30Sjl 		mutex_exit(&oplmsu_uinst->u_lock);
51725cf1a30Sjl 		rw_exit(&oplmsu_uinst->lock);
51825cf1a30Sjl 		freemsg(mp);
51925cf1a30Sjl 	} else if ((upath->traditional_status == MSU_MAKE_INST) ||
52025cf1a30Sjl 	    (upath->traditional_status == MSU_STOP) ||
52125cf1a30Sjl 	    (upath->traditional_status == MSU_STANDBY) ||
52225cf1a30Sjl 	    (upath->traditional_status == MSU_SETID) ||
52325cf1a30Sjl 	    (upath->traditional_status == MSU_LINK)) {
52425cf1a30Sjl 		oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_FAIL, upath->status,
52525cf1a30Sjl 		    MSU_FAIL);
52625cf1a30Sjl 		mutex_exit(&oplmsu_uinst->l_lock);
52725cf1a30Sjl 		mutex_exit(&oplmsu_uinst->u_lock);
52825cf1a30Sjl 		rw_exit(&oplmsu_uinst->lock);
52925cf1a30Sjl 		freemsg(mp);
53025cf1a30Sjl 	} else if (upath->traditional_status == MSU_FAIL) {
53125cf1a30Sjl 		mutex_exit(&oplmsu_uinst->l_lock);
53225cf1a30Sjl 		mutex_exit(&oplmsu_uinst->u_lock);
53325cf1a30Sjl 		rw_exit(&oplmsu_uinst->lock);
53425cf1a30Sjl 		freemsg(mp);
53525cf1a30Sjl 	} else if (upath->traditional_status == MSU_ACTIVE) {
53625cf1a30Sjl 		altn_upath = oplmsu_search_standby();
53725cf1a30Sjl 		if (altn_upath == NULL) {
53825cf1a30Sjl 			oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_FAIL,
53925cf1a30Sjl 			    upath->status, MSU_FAIL);
54025cf1a30Sjl 
54125cf1a30Sjl 			oplmsu_clear_ioctl_path(lpath);
54225cf1a30Sjl 			lpath->src_upath = NULL;
54325cf1a30Sjl 			lpath->status = MSU_EXT_NOTUSED;
54425cf1a30Sjl 			lpath->uinst = NULL;
54525cf1a30Sjl 			mutex_exit(&oplmsu_uinst->l_lock);
54625cf1a30Sjl 			mutex_exit(&oplmsu_uinst->u_lock);
54725cf1a30Sjl 
54825cf1a30Sjl 			OPLMSU_RWLOCK_UPGRADE();
54925cf1a30Sjl 			oplmsu_uinst->lower_queue = NULL;
55025cf1a30Sjl 			rw_exit(&oplmsu_uinst->lock);
55125cf1a30Sjl 			freemsg(mp);
55225cf1a30Sjl 			return (SUCCESS);
55325cf1a30Sjl 		}
55425cf1a30Sjl 
55525cf1a30Sjl 		mutex_exit(&oplmsu_uinst->l_lock);
55625cf1a30Sjl 		if (oplmsu_cmn_allocmb(lrq, mp, &fmp, sizeof (char),
55725cf1a30Sjl 		    MSU_READ_SIDE) == FAILURE) {
55825cf1a30Sjl 			mutex_exit(&oplmsu_uinst->u_lock);
55925cf1a30Sjl 			rw_exit(&oplmsu_uinst->lock);
56025cf1a30Sjl 			return (FAILURE);
56125cf1a30Sjl 		}
56225cf1a30Sjl 
56325cf1a30Sjl 		if (oplmsu_cmn_prechg(lrq, mp, MSU_READ_SIDE, &nmp, &term_ioctl,
56425cf1a30Sjl 		    &term_stat) == FAILURE) {
56525cf1a30Sjl 			mutex_exit(&oplmsu_uinst->u_lock);
56625cf1a30Sjl 			rw_exit(&oplmsu_uinst->lock);
56725cf1a30Sjl 			freeb(fmp);
56825cf1a30Sjl 			return (FAILURE);
56925cf1a30Sjl 		}
57025cf1a30Sjl 
57125cf1a30Sjl 		oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_FAIL,
57225cf1a30Sjl 		    upath->status, MSU_FAIL);
57325cf1a30Sjl 
57425cf1a30Sjl 		mutex_enter(&oplmsu_uinst->l_lock);
57525cf1a30Sjl 		lpath->uinst = NULL;
57625cf1a30Sjl 
57725cf1a30Sjl 		altn_upath->traditional_status = term_stat;
57825cf1a30Sjl 		altn_lpath = altn_upath->lpath;
57925cf1a30Sjl 
58025cf1a30Sjl 		altn_lpath->hndl_mp = NULL;
58125cf1a30Sjl 		altn_lpath->hndl_uqueue = NULL;
58225cf1a30Sjl 		altn_lpath->src_upath = upath;
58325cf1a30Sjl 		altn_lpath->status = MSU_EXT_VOID;
58425cf1a30Sjl 		dst_queue = RD(altn_lpath->lower_queue);
58525cf1a30Sjl 		mutex_exit(&oplmsu_uinst->l_lock);
58625cf1a30Sjl 		mutex_exit(&oplmsu_uinst->u_lock);
58725cf1a30Sjl 
58825cf1a30Sjl 		OPLMSU_RWLOCK_UPGRADE();
58925cf1a30Sjl 		oplmsu_uinst->lower_queue = NULL;
59025cf1a30Sjl 		oplmsu_cmn_set_mflush(fmp);
59125cf1a30Sjl 
59225cf1a30Sjl 		if (ctrl != NULL) {
59325cf1a30Sjl 			mutex_enter(&oplmsu_uinst->c_lock);
59425cf1a30Sjl 			noenable(WR(ctrl->queue));
59525cf1a30Sjl 			mutex_exit(&oplmsu_uinst->c_lock);
59625cf1a30Sjl 
59725cf1a30Sjl 			oplmsu_queue_flag = 1;
59825cf1a30Sjl 		}
59925cf1a30Sjl 
60025cf1a30Sjl 		rw_exit(&oplmsu_uinst->lock);
60125cf1a30Sjl 		freemsg(mp);
60225cf1a30Sjl 
60325cf1a30Sjl 		OPLMSU_TRACE(dst_queue, fmp, MSU_TRC_LO);
60425cf1a30Sjl 		qreply(dst_queue, fmp);
60525cf1a30Sjl 		OPLMSU_TRACE(dst_queue, nmp, MSU_TRC_LO);
60625cf1a30Sjl 		qreply(dst_queue, nmp);
60725cf1a30Sjl 	}
60825cf1a30Sjl 	return (SUCCESS);
60925cf1a30Sjl }
61025cf1a30Sjl 
61125cf1a30Sjl /* M_DATA[xoff/xon] was received from serial port */
61225cf1a30Sjl int
61325cf1a30Sjl oplmsu_lrdata_xoffxon(queue_t *lrq, mblk_t *mp)
61425cf1a30Sjl {
61525cf1a30Sjl 	upath_t	*upath, *stp_upath = NULL;
61625cf1a30Sjl 	lpath_t	*lpath, *stp_lpath = NULL;
61725cf1a30Sjl 	mblk_t	*nmp = NULL, *fmp = NULL;
61825cf1a30Sjl 	ctrl_t	*ctrl;
61925cf1a30Sjl 	int	term_stat, term_ioctl;
62025cf1a30Sjl 
62125cf1a30Sjl 	rw_enter(&oplmsu_uinst->lock, RW_READER);
62225cf1a30Sjl 	mutex_enter(&oplmsu_uinst->u_lock);
62325cf1a30Sjl 	mutex_enter(&oplmsu_uinst->l_lock);
62425cf1a30Sjl 
62525cf1a30Sjl 	if (oplmsu_uinst->lower_queue != NULL) {
62625cf1a30Sjl 		/* Get lower path of active status */
62725cf1a30Sjl 		stp_lpath = (lpath_t *)oplmsu_uinst->lower_queue->q_ptr;
62825cf1a30Sjl 		if (stp_lpath != NULL) {
62925cf1a30Sjl 			stp_upath =
63025cf1a30Sjl 			    oplmsu_search_upath_info(stp_lpath->path_no);
63125cf1a30Sjl 		}
63225cf1a30Sjl 	}
63325cf1a30Sjl 
63425cf1a30Sjl 	lpath = (lpath_t *)lrq->q_ptr;
63525cf1a30Sjl 	upath = oplmsu_search_upath_info(lpath->path_no);
63625cf1a30Sjl 
637*c2c6897eSraghuram 	if (upath == NULL) {
638*c2c6897eSraghuram 		mutex_exit(&oplmsu_uinst->l_lock);
639*c2c6897eSraghuram 		mutex_exit(&oplmsu_uinst->u_lock);
640*c2c6897eSraghuram 		rw_exit(&oplmsu_uinst->lock);
641*c2c6897eSraghuram 		freemsg(mp);
642*c2c6897eSraghuram 		return (SUCCESS);
643*c2c6897eSraghuram 	}
644*c2c6897eSraghuram 
64525cf1a30Sjl 	if ((stp_upath != NULL) && (stp_upath != upath)) {
64625cf1a30Sjl 		if ((stp_upath->status != MSU_PSTAT_ACTIVE) ||
64725cf1a30Sjl 		    (stp_upath->traditional_status != MSU_ACTIVE)) {
64825cf1a30Sjl 			mutex_exit(&oplmsu_uinst->l_lock);
64925cf1a30Sjl 			mutex_exit(&oplmsu_uinst->u_lock);
65025cf1a30Sjl 			rw_exit(&oplmsu_uinst->lock);
65125cf1a30Sjl 			putbq(lrq, mp);
65225cf1a30Sjl 			return (FAILURE);
65325cf1a30Sjl 		}
65425cf1a30Sjl 	}
65525cf1a30Sjl 
65625cf1a30Sjl 	if ((upath->status == MSU_PSTAT_ACTIVE) &&
65725cf1a30Sjl 	    ((upath->traditional_status == MSU_ACTIVE) ||
65825cf1a30Sjl 	    (upath->traditional_status == MSU_WTCS_ACK) ||
65925cf1a30Sjl 	    (upath->traditional_status == MSU_WTMS_ACK) ||
66025cf1a30Sjl 	    (upath->traditional_status == MSU_WPPS_ACK) ||
66125cf1a30Sjl 	    (upath->traditional_status == MSU_WWSZ_ACK) ||
66225cf1a30Sjl 	    (upath->traditional_status == MSU_WCAR_ACK))) {
66325cf1a30Sjl 		mutex_exit(&oplmsu_uinst->l_lock);
66425cf1a30Sjl 		mutex_exit(&oplmsu_uinst->u_lock);
66525cf1a30Sjl 		oplmsu_rcmn_through_hndl(lrq, mp, MSU_NORM);
66625cf1a30Sjl 		rw_exit(&oplmsu_uinst->lock);
66725cf1a30Sjl 		return (SUCCESS);
66825cf1a30Sjl 	} else if ((upath->status != MSU_PSTAT_STANDBY) ||
66925cf1a30Sjl 	    (upath->traditional_status != MSU_STANDBY)) {
67025cf1a30Sjl 		mutex_exit(&oplmsu_uinst->l_lock);
67125cf1a30Sjl 		mutex_exit(&oplmsu_uinst->u_lock);
67225cf1a30Sjl 		rw_exit(&oplmsu_uinst->lock);
67325cf1a30Sjl 		freemsg(mp);
67425cf1a30Sjl 		cmn_err(CE_WARN, "oplmsu: lr-xoffxon: "
67525cf1a30Sjl 		    "Can't change to specified path");
67625cf1a30Sjl 		return (SUCCESS);
67725cf1a30Sjl 	}
67825cf1a30Sjl 	mutex_exit(&oplmsu_uinst->l_lock);
67925cf1a30Sjl 
68025cf1a30Sjl 	if (oplmsu_cmn_allocmb(lrq, mp, &fmp, sizeof (char), MSU_READ_SIDE) ==
68125cf1a30Sjl 	    FAILURE) {
68225cf1a30Sjl 		mutex_exit(&oplmsu_uinst->u_lock);
68325cf1a30Sjl 		rw_exit(&oplmsu_uinst->lock);
68425cf1a30Sjl 		return (FAILURE);
68525cf1a30Sjl 	}
68625cf1a30Sjl 
68725cf1a30Sjl 	if (oplmsu_cmn_prechg(lrq, mp, MSU_READ_SIDE, &nmp, &term_ioctl,
68825cf1a30Sjl 	    &term_stat) == FAILURE) {
68925cf1a30Sjl 		mutex_exit(&oplmsu_uinst->u_lock);
69025cf1a30Sjl 		rw_exit(&oplmsu_uinst->lock);
69125cf1a30Sjl 		freeb(fmp);
69225cf1a30Sjl 		return (FAILURE);
69325cf1a30Sjl 	}
69425cf1a30Sjl 
69525cf1a30Sjl 	oplmsu_cmn_set_mflush(fmp);
69625cf1a30Sjl 	upath->traditional_status = term_stat;
69725cf1a30Sjl 
69825cf1a30Sjl 	mutex_enter(&oplmsu_uinst->l_lock);
69925cf1a30Sjl 	lpath->hndl_mp = mp;
70025cf1a30Sjl 	lpath->hndl_uqueue = NULL;
70125cf1a30Sjl 	lpath->src_upath = stp_upath;
70225cf1a30Sjl 	lpath->status = MSU_EXT_VOID;
70325cf1a30Sjl 
70425cf1a30Sjl 	mutex_enter(&oplmsu_uinst->c_lock);
70525cf1a30Sjl 	ctrl = oplmsu_uinst->user_ctrl;
70625cf1a30Sjl 	if (term_stat != MSU_WPTH_CHG) {
70725cf1a30Sjl 		/*
70825cf1a30Sjl 		 * Send termios to new active path and wait response
70925cf1a30Sjl 		 */
71025cf1a30Sjl 		if (ctrl != NULL) {
71125cf1a30Sjl 			noenable(WR(ctrl->queue));
71225cf1a30Sjl 		}
71325cf1a30Sjl 		mutex_exit(&oplmsu_uinst->c_lock);
71425cf1a30Sjl 		mutex_exit(&oplmsu_uinst->l_lock);
71525cf1a30Sjl 		mutex_exit(&oplmsu_uinst->u_lock);
71625cf1a30Sjl 		rw_exit(&oplmsu_uinst->lock);
71725cf1a30Sjl 
71825cf1a30Sjl 		OPLMSU_TRACE(RD(lrq), fmp, MSU_TRC_LO);
71925cf1a30Sjl 		qreply(RD(lrq), fmp);
72025cf1a30Sjl 		OPLMSU_TRACE(RD(lrq), nmp, MSU_TRC_LO);
72125cf1a30Sjl 		qreply(RD(lrq), nmp);
72225cf1a30Sjl 	} else {
72325cf1a30Sjl 		/*
72425cf1a30Sjl 		 * No termios messages are received. Change active path.
72525cf1a30Sjl 		 */
72625cf1a30Sjl 
72725cf1a30Sjl 		oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_ACTIVE, upath->status,
72825cf1a30Sjl 		    MSU_ACTIVE);
72925cf1a30Sjl 
73025cf1a30Sjl 		lpath->uinst = oplmsu_uinst;
73125cf1a30Sjl 		lpath->src_upath = NULL;
73225cf1a30Sjl 		lpath->status = MSU_EXT_NOTUSED;
73325cf1a30Sjl 
73425cf1a30Sjl 		/* Notify of the active path changing */
73525cf1a30Sjl 		prom_opl_switch_console(upath->ser_devcb.lsb);
73625cf1a30Sjl 
73725cf1a30Sjl 		putq(WR(lrq), fmp);
73825cf1a30Sjl 
73925cf1a30Sjl 		/* Send XON to notify active path */
74025cf1a30Sjl 		(void) oplmsu_cmn_put_xoffxon(WR(lrq), MSU_XON_4);
74125cf1a30Sjl 
74225cf1a30Sjl 		if (lpath->hndl_mp != NULL) {
74325cf1a30Sjl 			/* Put a message(M_DATA) on a queue */
74425cf1a30Sjl 			if (ctrl != NULL) {
74525cf1a30Sjl 				putq(RD(ctrl->queue), lpath->hndl_mp);
74625cf1a30Sjl 			}
74725cf1a30Sjl 		}
74825cf1a30Sjl 
74925cf1a30Sjl 		oplmsu_clear_ioctl_path(lpath);
75025cf1a30Sjl 
75125cf1a30Sjl 		if (ctrl != NULL) {
75225cf1a30Sjl 			noenable(WR(ctrl->queue));
75325cf1a30Sjl 		}
75425cf1a30Sjl 
75525cf1a30Sjl 		if ((stp_upath != NULL) && (stp_lpath != NULL)) {
75625cf1a30Sjl 			/* Change the status of stop path */
75725cf1a30Sjl 			oplmsu_cmn_set_upath_sts(stp_upath, MSU_PSTAT_STANDBY,
75825cf1a30Sjl 			    stp_upath->status, MSU_STANDBY);
75925cf1a30Sjl 
76025cf1a30Sjl 			oplmsu_clear_ioctl_path(stp_lpath);
76125cf1a30Sjl 			stp_lpath->uinst = NULL;
76225cf1a30Sjl 			stp_lpath->src_upath = NULL;
76325cf1a30Sjl 			stp_lpath->status = MSU_EXT_NOTUSED;
76425cf1a30Sjl 		}
76525cf1a30Sjl #ifdef DEBUG
76625cf1a30Sjl 		oplmsu_cmn_prt_pathname(upath->ser_devcb.dip);
76725cf1a30Sjl #endif
76825cf1a30Sjl 		/* Send XOFF to notify all standby paths */
76925cf1a30Sjl 		oplmsu_cmn_putxoff_standby();
77025cf1a30Sjl 		mutex_exit(&oplmsu_uinst->c_lock);
77125cf1a30Sjl 		mutex_exit(&oplmsu_uinst->l_lock);
77225cf1a30Sjl 		mutex_exit(&oplmsu_uinst->u_lock);
77325cf1a30Sjl 
77425cf1a30Sjl 		OPLMSU_RWLOCK_UPGRADE();
77525cf1a30Sjl 		mutex_enter(&oplmsu_uinst->u_lock);
77625cf1a30Sjl 		oplmsu_uinst->lower_queue = lrq;
77725cf1a30Sjl 		oplmsu_uinst->inst_status = oplmsu_get_inst_status();
77825cf1a30Sjl 		mutex_exit(&oplmsu_uinst->u_lock);
77925cf1a30Sjl 
78025cf1a30Sjl 		if (ctrl != NULL) {
78125cf1a30Sjl 			queue_t *temp_queue;
78225cf1a30Sjl 
78325cf1a30Sjl 			mutex_enter(&oplmsu_uinst->c_lock);
78425cf1a30Sjl 			temp_queue = WR(ctrl->queue);
78525cf1a30Sjl 			mutex_exit(&oplmsu_uinst->c_lock);
78625cf1a30Sjl 
78725cf1a30Sjl 			/* Reschedule a queue for service */
78825cf1a30Sjl 			enableok(temp_queue);
78925cf1a30Sjl 
79025cf1a30Sjl 			oplmsu_queue_flag = 0;
79125cf1a30Sjl 			oplmsu_wcmn_high_qenable(temp_queue, RW_WRITER);
79225cf1a30Sjl 		}
79325cf1a30Sjl 		rw_exit(&oplmsu_uinst->lock);
79425cf1a30Sjl 	}
79525cf1a30Sjl 	return (SUCCESS);
79625cf1a30Sjl }
797