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