Example #1
0
/*
 * dm2s_start - Start transmission function.
 *
 * Send all queued messages. If the mailbox is busy, then
 * start a timeout as a polling mechanism. The timeout is useful
 * to not rely entirely on the SCF_MB_SPACE event.
 */
void
dm2s_start(queue_t *wq, dm2s_t *dm2sp)
{
	mblk_t *mp;
	int ret;

	DPRINTF(DBG_DRV, ("dm2s_start: called\n"));
	ASSERT(dm2sp != NULL);
	ASSERT(MUTEX_HELD(&dm2sp->ms_lock));

	while ((mp = getq(wq)) != NULL) {
		switch (mp->b_datap->db_type) {

		case M_DATA:
			ret = dm2s_transmit(wq, mp, dm2sp->ms_target,
			    dm2sp->ms_key);
			if (ret == EBUSY || ret == ENOSPC || ret == EAGAIN) {
				DPRINTF(DBG_MBOX,
				    ("dm2s_start: recoverable err=%d\n", ret));
				/*
				 * Start a timeout to retry again.
				 */
				if (dm2sp->ms_wq_timeoutid == 0) {
					DTRACE_PROBE1(dm2s_wqtimeout__start,
					    dm2s_t, dm2sp);
					dm2sp->ms_wq_timeoutid = qtimeout(wq,
					    dm2s_wq_timeout, (void *)dm2sp,
					    dm2s_timeout_val(ret));
				}
				return;
			} else if (ret != 0) {
				mutex_exit(&dm2sp->ms_lock);
				/*
				 * An error occurred with the transmission,
				 * flush pending messages and initiate a
				 * hangup.
				 */
				flushq(wq, FLUSHDATA);
				(void) putnextctl(RD(wq), M_HANGUP);
				DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp);
				DPRINTF(DBG_WARN,
				    ("dm2s_start: hangup transmit err=%d\n",
				    ret));
				mutex_enter(&dm2sp->ms_lock);
			}
			break;
		default:
			/*
			 * At this point, we don't expect any other messages.
			 */
			freemsg(mp);
			break;
		}
	}
}
Example #2
0
/*
 * cvc_redir()
 *	called from cvcredir:cvcr_wput() to handle console input
 *	data. This routine puts the cvcredir write (downstream) data
 *	onto the cvc read (upstream) queues.
 */
int
cvc_redir(mblk_t *mp)
{
	register struct iocblk	*iocp;
	int			rv = 1;

	/*
	 * This function shouldn't be called if cvcredir hasn't registered yet.
	 */
	if (cvcinput_q == NULL) {
		/*
		 * Need to let caller know that it may be necessary for them to
		 * free the message buffer, so return 0.
		 */
		CVC_DBG0(CVC_DBG_REDIR, "redirection not enabled");
		cmn_err(CE_WARN, "cvc_redir: cvcinput_q NULL!");
		return (0);
	}

	CVC_DBG1(CVC_DBG_REDIR, "type 0x%x", mp->b_datap->db_type);
	if (mp->b_datap->db_type == M_DATA) {
		/*
		 * XXX - should canputnext be called here?  Starfire's cvc
		 * doesn't do that, and it appears to work anyway.
		 */
		CVC_DBG1(CVC_DBG_NETWORK_RD, "Sending mp 0x%x", mp);
		(void) putnext(cvcinput_q, mp);
	} else if (mp->b_datap->db_type == M_IOCTL) {
		/*
		 * The cvcredir driver filters out ioctl mblks we wouldn't
		 * understand, so we don't have to check for every conceivable
		 * ioc_cmd.  However, additional ioctls may be supported (again)
		 * some day, so the code is structured to check the value even
		 * though there's only one that is currently supported.
		 */
		iocp = (struct iocblk *)mp->b_rptr;
		if (iocp->ioc_cmd == CVC_DISCONNECT) {
			(void) putnextctl(cvcinput_q, M_HANGUP);
		}
	} else {
		/*
		 * Since we don't know what this mblk is, we're not going to
		 * process it.
		 */
		CVC_DBG1(CVC_DBG_REDIR, "unrecognized mblk type: %d",
		    mp->b_datap->db_type);
		rv = 0;
	}

	return (rv);
}
Example #3
0
/* ARGSUSED */
int
dm2s_close(queue_t *rq, int flag, cred_t *cred)
{
	dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr;

	DPRINTF(DBG_DRV, ("dm2s_close: called\n"));
	if (dm2sp == NULL) {
		/* Already closed once */
		return (ENODEV);
	}

	/* Close the lower layer first */
	mutex_enter(&dm2sp->ms_lock);
	(void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, MB_FLUSH_ALL);
	dm2s_mbox_fini(dm2sp);
	mutex_exit(&dm2sp->ms_lock);

	/*
	 * Now we can assume that no asynchronous callbacks exist.
	 * Poison the stream head so that we can't be pushed again.
	 */
	(void) putnextctl(rq, M_HANGUP);
	qprocsoff(rq);
	if (dm2sp->ms_rbufcid != 0) {
		qunbufcall(rq, dm2sp->ms_rbufcid);
		dm2sp->ms_rbufcid = 0;
	}
	if (dm2sp->ms_rq_timeoutid != 0) {
		DTRACE_PROBE1(dm2s_rqtimeout__cancel, dm2s_t, dm2sp);
		(void) quntimeout(dm2sp->ms_rq, dm2sp->ms_rq_timeoutid);
		dm2sp->ms_rq_timeoutid = 0;
	}
	if (dm2sp->ms_wq_timeoutid != 0) {
		DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp);
		(void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid);
		dm2sp->ms_wq_timeoutid = 0;
	}
	/*
	 * Now we can really mark it closed.
	 */
	mutex_enter(&dm2sp->ms_lock);
	dm2sp->ms_rq = dm2sp->ms_wq = NULL;
	dm2sp->ms_state &= ~DM2S_OPENED;
	mutex_exit(&dm2sp->ms_lock);

	rq->q_ptr = WR(rq)->q_ptr = NULL;
	(void) qassociate(rq, -1);
	DPRINTF(DBG_DRV, ("dm2s_close: successfully closed\n"));
	return (0);
}
Example #4
0
/*ARGSUSED*/
static int
telmodclose(queue_t *q, int flag, cred_t *credp)
{
	struct telmod_info   *tmip = (struct telmod_info *)q->q_ptr;
	mblk_t	*mp;

	/*
	 * Flush any write-side data downstream.  Ignoring flow
	 * control at this point is known to be safe because the
	 * M_HANGUP below poisons the stream such that no modules can
	 * be pushed again.
	 */
	while (mp = getq(WR(q)))
		putnext(WR(q), mp);

	/* Poison the stream head so that we can't be pushed again. */
	(void) putnextctl(q, M_HANGUP);

	qprocsoff(q);
	if (tmip->wbufcid) {
		qunbufcall(q, tmip->wbufcid);
		tmip->wbufcid = 0;
	}
	if (tmip->rbufcid) {
		qunbufcall(q, tmip->rbufcid);
		tmip->rbufcid = 0;
	}
	if (tmip->wtimoutid) {
		(void) quntimeout(q, tmip->wtimoutid);
		tmip->wtimoutid = 0;
	}
	if (tmip->rtimoutid) {
		(void) quntimeout(q, tmip->rtimoutid);
		tmip->rtimoutid = 0;
	}
	if (tmip->unbind_mp != NULL) {
		freemsg(tmip->unbind_mp);
	}

	kmem_free(q->q_ptr, sizeof (struct telmod_info));
	q->q_ptr = WR(q)->q_ptr = NULL;
	return (0);
}
Example #5
0
/*
 * This routine is called from both ptemwput and ptemwsrv to do the
 * actual work of dealing with mp.  ptmewput will have already
 * dealt with high priority messages.
 *
 * Return 1 if the message was processed completely and 0 if not.
 */
static int
ptemwmsg(queue_t *q, mblk_t *mp)
{
	struct ptem *ntp = (struct ptem *)q->q_ptr;
	struct iocblk *iocp;	/* outgoing ioctl structure */
	struct termio *termiop;
	struct termios *termiosp;
	mblk_t *dack_ptr;		/* disconnect message ACK block */
	mblk_t *pckt_msgp;		/* message sent to the PCKT module */
	mblk_t *dp;			/* ioctl reply data */
	tcflag_t cflags;
	int error;

	switch (mp->b_datap->db_type) {

	case M_IOCTL:
		/*
		 * Note:  for each "set" type operation a copy
		 * of the M_IOCTL message is made and passed
		 * downstream.  Eventually the PCKT module, if
		 * it has been pushed, should pick up this message.
		 * If the PCKT module has not been pushed the master
		 * side stream head will free it.
		 */
		iocp = (struct iocblk *)mp->b_rptr;
		switch (iocp->ioc_cmd) {

		case TCSETAF:
		case TCSETSF:
			/*
			 * Flush the read queue.
			 */
			if (putnextctl1(q, M_FLUSH, FLUSHR) == 0) {
				miocnak(q, mp, 0, EAGAIN);
				break;
			}
			/* FALLTHROUGH */

		case TCSETA:
		case TCSETAW:
		case TCSETS:
		case TCSETSW:

			switch (iocp->ioc_cmd) {
			case TCSETAF:
			case TCSETA:
			case TCSETAW:
				error = miocpullup(mp, sizeof (struct termio));
				if (error != 0) {
					miocnak(q, mp, 0, error);
					goto out;
				}
				cflags = ((struct termio *)
				    mp->b_cont->b_rptr)->c_cflag;
				ntp->cflags =
				    (ntp->cflags & 0xffff0000 | cflags);
				break;

			case TCSETSF:
			case TCSETS:
			case TCSETSW:
				error = miocpullup(mp, sizeof (struct termios));
				if (error != 0) {
					miocnak(q, mp, 0, error);
					goto out;
				}
				cflags = ((struct termios *)
				    mp->b_cont->b_rptr)->c_cflag;
				ntp->cflags = cflags;
				break;
			}

			if ((cflags & CBAUD) == B0) {
				/*
				 * Hang-up: Send a zero length message.
				 */
				dack_ptr = ntp->dack_ptr;

				if (dack_ptr) {
					ntp->dack_ptr = NULL;
					/*
					 * Send a zero length message
					 * downstream.
					 */
					putnext(q, dack_ptr);
				}
			} else {
				/*
				 * Make a copy of this message and pass it on
				 * to the PCKT module.
				 */
				if ((pckt_msgp = copymsg(mp)) == NULL) {
					miocnak(q, mp, 0, EAGAIN);
					break;
				}
				putnext(q, pckt_msgp);
			}
			/*
			 * Send ACK upstream.
			 */
			mioc2ack(mp, NULL, 0, 0);
			qreply(q, mp);
out:
			break;

		case TCGETA:
			dp = allocb(sizeof (struct termio), BPRI_MED);
			if (dp == NULL) {
				miocnak(q, mp, 0, EAGAIN);
				break;
			}
			termiop = (struct termio *)dp->b_rptr;
			termiop->c_cflag = (ushort_t)ntp->cflags;
			mioc2ack(mp, dp, sizeof (struct termio), 0);
			qreply(q, mp);
			break;

		case TCGETS:
			dp = allocb(sizeof (struct termios), BPRI_MED);
			if (dp == NULL) {
				miocnak(q, mp, 0, EAGAIN);
				break;
			}
			termiosp = (struct termios *)dp->b_rptr;
			termiosp->c_cflag = ntp->cflags;
			mioc2ack(mp, dp, sizeof (struct termios), 0);
			qreply(q, mp);
			break;

		case TCSBRK:
			error = miocpullup(mp, sizeof (int));
			if (error != 0) {
				miocnak(q, mp, 0, error);
				break;
			}

			/*
			 * Need a copy of this message to pass it on to
			 * the PCKT module.
			 */
			if ((pckt_msgp = copymsg(mp)) == NULL) {
				miocnak(q, mp, 0, EAGAIN);
				break;
			}
			/*
			 * Send a copy of the M_IOCTL to the PCKT module.
			 */
			putnext(q, pckt_msgp);

			/*
			 * TCSBRK meaningful if data part of message is 0
			 * cf. termio(7).
			 */
			if (!(*(int *)mp->b_cont->b_rptr))
				(void) putnextctl(q, M_BREAK);
			/*
			 * ACK the ioctl.
			 */
			mioc2ack(mp, NULL, 0, 0);
			qreply(q, mp);
			break;

		case JWINSIZE:
		case TIOCGWINSZ:
		case TIOCSWINSZ:
			ptioc(q, mp, WRSIDE);
			break;

		case TIOCSTI:
			/*
			 * Simulate typing of a character at the terminal.  In
			 * all cases, we acknowledge the ioctl and pass a copy
			 * of it along for the PCKT module to encapsulate.  If
			 * not in remote mode, we also process the ioctl
			 * itself, looping the character given as its argument
			 * back around to the read side.
			 */

			/*
			 * Need a copy of this message to pass on to the PCKT
			 * module.
			 */
			if ((pckt_msgp = copymsg(mp)) == NULL) {
				miocnak(q, mp, 0, EAGAIN);
				break;
			}
			if ((ntp->state & REMOTEMODE) == 0) {
				mblk_t *bp;

				error = miocpullup(mp, sizeof (char));
				if (error != 0) {
					freemsg(pckt_msgp);
					miocnak(q, mp, 0, error);
					break;
				}

				/*
				 * The permission checking has already been
				 * done at the stream head, since it has to be
				 * done in the context of the process doing
				 * the call.
				 */
				if ((bp = allocb(1, BPRI_MED)) == NULL) {
					freemsg(pckt_msgp);
					miocnak(q, mp, 0, EAGAIN);
					break;
				}
				/*
				 * XXX:	Is EAGAIN really the right response to
				 *	flow control blockage?
				 */
				if (!bcanputnext(RD(q), mp->b_band)) {
					freemsg(bp);
					freemsg(pckt_msgp);
					miocnak(q, mp, 0, EAGAIN);
					break;
				}
				*bp->b_wptr++ = *mp->b_cont->b_rptr;
				qreply(q, bp);
			}

			putnext(q, pckt_msgp);
			mioc2ack(mp, NULL, 0, 0);
			qreply(q, mp);
			break;

		case PTSSTTY:
			if (ntp->state & IS_PTSTTY) {
				miocnak(q, mp, 0, EEXIST);
			} else {
				ntp->state |= IS_PTSTTY;
				mioc2ack(mp, NULL, 0, 0);
				qreply(q, mp);
			}
			break;

		default:
			/*
			 * End of the line.  The slave driver doesn't see any
			 * ioctls that we don't explicitly pass along to it.
			 */
			miocnak(q, mp, 0, EINVAL);
			break;
		}
		break;

	case M_DELAY: /* tty delays not supported */
		freemsg(mp);
		break;

	case M_DATA:
		if ((mp->b_wptr - mp->b_rptr) < 0) {
			/*
			 * Free all bad length messages.
			 */
			freemsg(mp);
			break;
		} else if ((mp->b_wptr - mp->b_rptr) == 0) {
			if (!(ntp->state & IS_PTSTTY)) {
				freemsg(mp);
				break;
			}
		}
		if (ntp->state & OFLOW_CTL)
			return (0);

	default:
		putnext(q, mp);
		break;

	}

	return (1);
}
Example #6
0
/*
 * ptemrput - Module read queue put procedure.
 *
 * This is called from the module or driver downstream.
 */
static void
ptemrput(queue_t *q, mblk_t *mp)
{
	struct iocblk *iocp;	/* M_IOCTL data */
	struct copyresp *resp;	/* transparent ioctl response struct */
	int error;

	switch (mp->b_datap->db_type) {
	case M_DELAY:
	case M_READ:
		freemsg(mp);
		break;

	case M_IOCTL:
		iocp = (struct iocblk *)mp->b_rptr;

		switch (iocp->ioc_cmd) {
		case TCSBRK:
			/*
			 * Send a break message upstream.
			 *
			 * XXX:	Shouldn't the argument come into play in
			 *	determining whether or not so send an M_BREAK?
			 *	It certainly does in the write-side direction.
			 */
			error = miocpullup(mp, sizeof (int));
			if (error != 0) {
				miocnak(q, mp, 0, error);
				break;
			}
			if (!(*(int *)mp->b_cont->b_rptr)) {
				if (!putnextctl(q, M_BREAK)) {
					/*
					 * Send an NAK reply back
					 */
					miocnak(q, mp, 0, EAGAIN);
					break;
				}
			}
			/*
			 * ACK it.
			 */
			mioc2ack(mp, NULL, 0, 0);
			qreply(q, mp);
			break;

		case JWINSIZE:
		case TIOCGWINSZ:
		case TIOCSWINSZ:
			ptioc(q, mp, RDSIDE);
			break;

		case TIOCSIGNAL:
			/*
			 * The following subtle logic is due to the fact that
			 * `mp' may be in any one of three distinct formats:
			 *
			 *	1. A transparent M_IOCTL with an intptr_t-sized
			 *	   payload containing the signal number.
			 *
			 *	2. An I_STR M_IOCTL with an int-sized payload
			 *	   containing the signal number.
			 *
			 *	3. An M_IOCDATA with an int-sized payload
			 *	   containing the signal number.
			 */
			if (iocp->ioc_count == TRANSPARENT) {
				intptr_t sig = *(intptr_t *)mp->b_cont->b_rptr;

				if (sig < 1 || sig >= NSIG) {
					/*
					 * it's transparent with pointer
					 * to the arg
					 */
					mcopyin(mp, NULL, sizeof (int), NULL);
					qreply(q, mp);
					break;
				}
			}
			ptioc(q, mp, RDSIDE);
			break;

		case TIOCREMOTE:
			if (iocp->ioc_count != TRANSPARENT)
				ptioc(q, mp, RDSIDE);
			else {
				mcopyin(mp, NULL, sizeof (int), NULL);
				qreply(q, mp);
			}
			break;

		default:
			putnext(q, mp);
			break;
		}
		break;

	case M_IOCDATA:
		resp = (struct copyresp *)mp->b_rptr;
		if (resp->cp_rval) {
			/*
			 * Just free message on failure.
			 */
			freemsg(mp);
			break;
		}

		/*
		 * Only need to copy data for the SET case.
		 */
		switch (resp->cp_cmd) {

		case TIOCSWINSZ:
		case TIOCSIGNAL:
		case TIOCREMOTE:
			ptioc(q, mp, RDSIDE);
			break;

		case JWINSIZE:
		case TIOCGWINSZ:
			mp->b_datap->db_type = M_IOCACK;
			mioc2ack(mp, NULL, 0, 0);
			qreply(q, mp);
			break;

		default:
			freemsg(mp);
			break;
	}
	break;

	case M_IOCACK:
	case M_IOCNAK:
		/*
		 * We only pass write-side ioctls through to the master that
		 * we've already ACKed or NAKed to the stream head.  Thus, we
		 * discard ones arriving from below, since they're redundant
		 * from the point of view of modules above us.
		 */
		freemsg(mp);
		break;

	case M_HANGUP:
		/*
		 * clear blocked state.
		 */
		{
			struct ptem *ntp = (struct ptem *)q->q_ptr;
			if (ntp->state & OFLOW_CTL) {
				ntp->state &= ~OFLOW_CTL;
				qenable(WR(q));
			}
		}
	default:
		putnext(q, mp);
		break;
	}
}
Example #7
0
/*
 * dm2s_receive - Read all messages from the mailbox.
 *
 * This function is called from the read service procedure, to
 * receive the messages awaiting in the mailbox.
 */
void
dm2s_receive(dm2s_t *dm2sp)
{
	queue_t	*rq = dm2sp->ms_rq;
	mblk_t	*mp;
	int	ret;
	uint32_t len;

	DPRINTF(DBG_DRV, ("dm2s_receive: called\n"));
	ASSERT(dm2sp != NULL);
	ASSERT(MUTEX_HELD(&dm2sp->ms_lock));
	if (rq == NULL) {
		return;
	}
	/*
	 * As the number of messages in the mailbox are pretty limited,
	 * it is safe to process all messages in one loop.
	 */
	while (DM2S_MBOX_READY(dm2sp) && ((ret = scf_mb_canget(dm2sp->ms_target,
	    dm2sp->ms_key, &len)) == 0)) {
		DPRINTF(DBG_MBOX, ("dm2s_receive: mb_canget len=%d\n", len));
		if (len == 0) {
			break;
		}
		mp = allocb(len, BPRI_MED);
		if (mp == NULL) {
			DPRINTF(DBG_WARN, ("dm2s_receive: allocb failed\n"));
			/*
			 * Start a bufcall so that we can retry again
			 * when memory becomes available.
			 */
			dm2sp->ms_rbufcid = qbufcall(rq, len, BPRI_MED,
			    dm2s_bufcall_rcv, dm2sp);
			if (dm2sp->ms_rbufcid == 0) {
				DPRINTF(DBG_WARN,
				    ("dm2s_receive: qbufcall failed\n"));
				/*
				 * if bufcall fails, start a timeout to
				 * initiate a re-try after some time.
				 */
				DTRACE_PROBE1(dm2s_rqtimeout__start,
				    dm2s_t, dm2sp);
				dm2sp->ms_rq_timeoutid = qtimeout(rq,
				    dm2s_rq_timeout, (void *)dm2sp,
				    drv_usectohz(DM2S_SM_TOUT));
			}
			break;
		}

		/*
		 * Only a single scatter/gather element is enough here.
		 */
		dm2sp->ms_sg_rcv.msc_dptr = (caddr_t)mp->b_wptr;
		dm2sp->ms_sg_rcv.msc_len = len;
		DPRINTF(DBG_MBOX, ("dm2s_receive: calling getmsg\n"));
		ret = scf_mb_getmsg(dm2sp->ms_target, dm2sp->ms_key, len, 1,
		    &dm2sp->ms_sg_rcv, 0);
		DPRINTF(DBG_MBOX, ("dm2s_receive: getmsg ret=%d\n", ret));
		if (ret != 0) {
			freemsg(mp);
			break;
		}
		DMPBYTES("dm2s: Getmsg: ", len, 1, &dm2sp->ms_sg_rcv);
		mp->b_wptr += len;
		/*
		 * Queue the messages in the rq, so that the service
		 * procedure handles sending the messages up the stream.
		 */
		putq(rq, mp);
	}

	if ((!DM2S_MBOX_READY(dm2sp)) || (ret != ENOMSG && ret != EMSGSIZE)) {
		/*
		 * Some thing went wrong, flush pending messages
		 * and initiate a hangup.
		 * Note: flushing the wq initiates a faster close.
		 */
		mutex_exit(&dm2sp->ms_lock);
		flushq(WR(rq), FLUSHDATA);
		(void) putnextctl(rq, M_HANGUP);
		DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp);
		mutex_enter(&dm2sp->ms_lock);
		DPRINTF(DBG_WARN, ("dm2s_receive: encountered unknown "
		    "condition - hangup ret=%d\n", ret));
	}
}
Example #8
0
/*
 * cvc_iosram_ops()
 *	Process commands sent to cvc from netcon_server via IOSRAM
 */
static void
cvc_iosram_ops(uint8_t op)
{
	int		rval = ESUCCESS;
	static uint8_t	stale_op = 0;

	ASSERT(MUTEX_HELD(&cvc_iosram_input_mutex));

	CVC_DBG1(CVC_DBG_IOSRAM_CNTL, "cntl msg 0x%x", op);

	/*
	 * If this is a repeated notice of a command that was previously
	 * processed but couldn't be cleared due to EAGAIN (tunnel switch in
	 * progress), just clear the data_valid flag and return.
	 */
	if (op == stale_op) {
		if (iosram_set_flag(IOSRAM_KEY_CONC, IOSRAM_DATA_INVALID,
		    IOSRAM_INT_NONE) == 0) {
			stale_op = 0;
		}
		return;
	}
	stale_op = 0;

	switch (op) {
		case CVC_IOSRAM_BREAK:		/* A console break (L1-A) */
			abort_sequence_enter((char *)NULL);
			break;

		case CVC_IOSRAM_DISCONNECT:	/* Break connection, hang up */
			if (cvcinput_q)
				(void) putnextctl(cvcinput_q, M_HANGUP);
			break;

		case CVC_IOSRAM_VIA_NET:	/* console via network */
			via_iosram = 0;
			break;

		case CVC_IOSRAM_VIA_IOSRAM:	/* console via iosram */
			via_iosram = 1;
			/*
			 * Tell cvcd to close any network connection it has.
			 */
			rw_enter(&cvclock, RW_READER);
			if (cvcoutput_q != NULL) {
				(void) putnextctl(cvcoutput_q, M_HANGUP);
			}
			rw_exit(&cvclock);
			break;

		case CVC_IOSRAM_WIN_RESIZE:	/* console window size data */
			/*
			 * In the case of window resizing, we don't want to
			 * record a stale_op value because we should always use
			 * the most recent winsize info, which could change
			 * between the time that we fail to clear the flag and
			 * the next time we try to process the command.  So,
			 * we'll just let cvc_win_resize clear the data_valid
			 * flag itself (hence the TRUE parameter) and not worry
			 * about whether or not it succeeds.
			 */
			cvc_win_resize(TRUE);
			return;
			/* NOTREACHED */

		default:
			cmn_err(CE_WARN, "cvc: unknown IOSRAM opcode %d", op);
			break;
	}

	/*
	 * Clear CONC's data_valid flag to indicate that the chunk is available
	 * for further communications.  If the flag can't be cleared due to an
	 * error, record the op value so we'll know to ignore it when we see it
	 * on the next poll.
	 */
	rval = iosram_set_flag(IOSRAM_KEY_CONC, IOSRAM_DATA_INVALID,
	    IOSRAM_INT_NONE);
	if (rval != 0) {
		stale_op = op;
		if (rval != EAGAIN) {
			cmn_err(CE_WARN,
			    "cvc_iosram_ops: set flag for cntlbuf ret %d",
			    rval);
		}
	}
}
Example #9
0
/**
 * ptem_r_msg - process a message on the read side
 * @q: read queue
 * @mp: the message to process
 *
 * Returns 1 when the caller (putp or srvp) needs to queue or requeue the
 * message.  Returns 0 when the message has been disposed and the caller must
 * release its reference to mp.
 *
 * Keep this away from the fast path.
 */
static streams_noinline __unlikely void
ptem_r_msg(queue_t *q, mblk_t *mp)
{
	struct iocblk *ioc = (typeof(ioc)) mp->b_rptr;
	int error = EINVAL;
	int count = 0;
	int rval = 0;
	mblk_t *bp;

	/* The Stream head is set to recognized all transparent terminal input-output controls and
	   pass them downstream as though they were I_STR input-output controls.  There is also the 
	   opportunity to register input-output controls with the Stream head using the TIOC_REPLY
	   message. */
	if (unlikely(ioc->ioc_count == TRANSPARENT)) {
		__swerr();
		goto nak;
	}
	if (!(bp = mp->b_cont))
		goto nak;

	switch (ioc->ioc_cmd) {
	case TCSBRK:
		/* When the ptem module receives an M_IOCTL message of type TCSBRK on its read-side 
		   queue, it sends an M_IOCACK message downstream and an M_BREAK message upstream. */
		if (!pullupmsg(bp, sizeof(int)))
			goto nak;
		if (!putnextctl(q, M_BREAK)) {
			error = EAGAIN;
			goto nak;
		}
		goto ack;
	case TIOCGWINSZ:
	{
		/* Keeps track of the informaiton needed for teh TIOCSWINSZ, TIOCGWINSZ, JWINSIZE,
		   input-output control commands. */
		struct ptem *p = PTEM_PRIV(q);
		extern void __struct_winsize_is_too_large_for_fastbuf(void);

		if (!(p->flags & PTEM_HAVE_WINSIZE))
			goto nak;
		if (FASTBUF < sizeof(struct winsize)) {
			__struct_winsize_is_too_large_for_fastbuf();
		}
		/* always have room in a fastbuf */
		count = sizeof(p->ws);
		bp->b_rptr = bp->b_datap->db_base;
		bp->b_wptr = bp->b_rptr + count;
		*(struct winsize *) bp->b_rptr = p->ws;
		goto ack;
	}
#ifdef JWINSIZE
	case JWINSIZE:
		/* Keeps track of the informaiton needed for teh TIOCSWINSZ, TIOCGWINSZ, JWINSIZE,
		   input-output control commands. */
	{
		struct ptem *p = PTEM_PRIV(q);
		struct jwinsize *jws;

		if (!(p->flags & PTEM_HAVE_WINSIZE))
			goto nak;
		if (FASTBUF < sizeof(struct jwinsize))
			__undefined_call_makes_compile_fail();
		/* always have room in a fastbuf */
		count = sizeof(*jws);
		bp->b_rptr = bp->b_datap->db_base;
		bp->b_wptr = bp->b_rptr + count;
		jws = (typeof(jws)) bp->b_rptr;
		jws->bytesx = p->ws.ws_col;
		jws->bytesy = p->ws.ws_row;
		jws->bitsx = p->ws.ws_xpixel;
		jws->bitsy = p->ws.ws_ypixel;
		goto ack;
	}
#endif				/* JWINSIZE */
	case TIOCSWINSZ:
		/* Keeps track of the informaiton needed for teh TIOCSWINSZ, TIOCGWINSZ, JWINSIZE,
		   input-output control commands. */
	{
		struct ptem *p = PTEM_PRIV(q);
		struct winsize *ws;
		int changed = 0;
		int zeroed = !(p->flags & PTEM_HAVE_WINSIZE);
		mblk_t *mb;

		if (!pullupmsg(bp, sizeof(*ws)))
			goto nak;
		if (!(mb = allocb(1, BPRI_MED))) {
			error = EAGAIN;
			goto nak;
		}
		ws = (typeof(ws)) bp->b_rptr;
		if (ws->ws_col != p->ws.ws_col) {
			if ((p->ws.ws_col = ws->ws_col))
				zeroed = 0;
			changed = 1;
		}
		if (ws->ws_row != p->ws.ws_row) {
			if ((p->ws.ws_row = ws->ws_row))
				zeroed = 0;
			changed = 1;
		}
		if (ws->ws_xpixel != p->ws.ws_xpixel) {
			if ((p->ws.ws_xpixel = ws->ws_xpixel))
				zeroed = 0;
			changed = 1;
		}
		if (ws->ws_ypixel != p->ws.ws_ypixel) {
			if ((p->ws.ws_ypixel = ws->ws_ypixel))
				zeroed = 0;
			changed = 1;
		}
		if (zeroed)
			p->flags &= ~PTEM_HAVE_WINSIZE;
		else
			p->flags |= PTEM_HAVE_WINSIZE;
		if (changed) {
			mb->b_datap->db_type = M_SIG;
			*mb->b_wptr++ = SIGWINCH;
			putnext(q, mb);
		} else
			freeb(mb);
		count = 0;
		goto ack;
	}
#ifdef TIOCSIGNAL
	case TIOCSIGNAL:
#endif				/* TIOCSIGNAL */
#ifdef O_TIOCSIGNAL
	case O_TIOCSIGNAL:
#endif				/* O_TIOCSIGNAL */
	{
		uint s;

		if (!pullupmsg(bp, sizeof(s)))
			goto nak;
		if ((s = *(uint *) bp->b_rptr) > _NSIG || s == 0)
			goto nak;
		if (!putnextctl1(q, M_PCSIG, s)) {
			error = EAGAIN;
			goto nak;
		}
		count = 0;
		goto ack;
	}
#ifdef TIOCREMOTE
	case TIOCREMOTE:
#endif				/* TIOCREMOTE */
#ifdef O_TIOCREMOTE
	case O_TIOCREMOTE:
#endif				/* O_TIOCREMOTE */
	{
		struct ptem *p = PTEM_PRIV(q);
		struct iocblk *ctl;
		mblk_t *mb;

		if (!pullupmsg(bp, sizeof(uint)))
			goto nak;
		if (!(mb = allocb(sizeof(*ctl), BPRI_MED))) {
			error = EAGAIN;
			goto nak;
		}
		mb->b_datap->db_type = M_CTL;
		ctl = (typeof(ctl)) mb->b_rptr;
		mb->b_wptr += sizeof(*ctl);
		bzero(ctl, sizeof(ctl));
		if (*(uint *) bp->b_rptr) {
			ctl->ioc_cmd = MC_NO_CANON;
			p->flags |= PTEM_REMOTE_MODE;
		} else {
			ctl->ioc_cmd = MC_DO_CANON;
			p->flags &= ~PTEM_REMOTE_MODE;
		}
		putnext(q, mb);
		count = 0;
		goto ack;
	}
	default:
		break;
	}
	putnext(q, mp);
	return;

      ack:
	mp->b_datap->db_type = M_IOCNAK;
	ioc->ioc_error = error;
	ioc->ioc_rval = -1;
	ioc->ioc_count = 0;
      reply:
	qreply(q, mp);
	return;
      nak:
	mp->b_datap->db_type = M_IOCACK;
	ioc->ioc_error = error;
	ioc->ioc_rval = rval;
	ioc->ioc_count = count;
	goto reply;
}
Example #10
0
/**
 * sl_w_ioctl: - process M_IOCTL message
 * @q: active queue (upper write queue)
 * @mp: the message
 *
 * Linking of streams: streams are linked under the multiplexing driver by opening an upper stream
 * and then linking a signalling link stream under the multiplexing driver.  Then the SL_SETLINK
 * input-output control is used with the multiplexer id to set the global-PPA and CLEI associated
 * with the signalling link.  The SL_GETLINK input-output control can be used at a later date to
 * determine the multiplexer id for a given signalling link stream.
 */
static struct int
sl_w_ioctl(queue_t *q, mblk_t *mp)
{
	struct iocblk *ioc = (struct iocblk *) mp->b_rptr;

	switch (ioc->ioc_cmd) {
	case I_LINK:
	case I_PLINK:
	{
		struct linkblk *l;

		if (!mp->b_cont)
			mi_copy_done(q, mp, EINVAL);

		l = (struct linkblk *) mp->b_cont->b_rptr;

		if (!(bot = kmem_alloc(sizeof(*bot), KM_NOSLEEP)))
			mi_copy_done(q, mp, ENOMEM);

		write_lock_str(&mux_lock, flags);
		bot->next = mux_links;
		bpt->prev = &mux_links;
		mux_links = bot;
		bot->dev = l->l_index;
		bot->rq = RD(l->l_qtop);
		bot->wq = l->l_qtop;
		bot->other = NULL;
		noenable(bot->rq);
		l->l_qtop->q_ptr = RD(l->l_qtop)->q_ptr = (void *) bot;
		write_unlock_str(&mux_lock, flags);
		mi_copy_done(q, mp, 0);
		return (0);
	}
	case I_UNLINK:
	case I_PUNLINK:
	{
		struct linkblk *l;

		if (!mp->b_cont)
			mi_copy_done(q, mp, EINVAL);

		l = (struct linkblk *) mp->b_cont->b_rptr;

		write_lock_str(&mux_lock, flags);
		for (bot = mux_list; bot; bot = bot->next)
			if (bot->dev == l->l_index)
				break;
		if (!bot) {
			write_unlock_str(&mux_lock, flags);
			mi_copy_done(q, mp, EINVAL);
			return (0);
		}
		/* Note that the lower multiplex driver put and service procedures must be prepared
		   to be invoked event after the M_IOCACK for the I_UNLINK or I_PUNLINK ioctl has
		   been returned.  THis is because the setq(9) back to the Stream head is not
		   performed until after the acknowledgement has been received.  We set q->q_ptr to
		   a null multiplex structure to keep the lower Stream functioning until the setq(9)
		   is performed. */
		l->l_qtop->q_ptr = RD(l->l_qtop)->q_ptr = &no_mux;
		if ((*bot->prev = bot->next)) {
			bot->next = NULL;
			bot->prev = &bot->next;
		}
		bot->other = NULL;
		kmem_free(bot, sizeof(*bot));
		/* hang up all upper streams that feed this lower stream */
		for (top = mux_opens; top; top = top->next) {
			if (top->other == bot) {
				putnextctl(top->rq, M_HANGUP);
				top->other = NULL;
			}
		}
		write_unlock_str(&mux_lock, flags);
		mi_copy_done(q, mp, 0);
		return (0);
	}
	case SL_SETLINK:
	{
		struct sl_mux_ppa *sm;

		/* This input-output control is used to set the global-PPA and CLEI associated with
		   a lower multiplex stream.  The argument is an sl_mux_ppa structure that contains
		   the multiplex id, the 32-bit PPA, and a CLEI string of up to 32 characters in
		   length. */
		mi_copyin(q, mp, NULL, sizeof(struct sl_mux_ppa));
		return (0);
	}
	case SL_GETLINK:
	{
		/* This input-output control is used to obtain the multiplex-id assocated with a
		   lower multiplex stream.  The argument is an sl_mux_ppa structure that contains a
		   32-bit PPA or CLEI string of up to 32 characters in length.  It returns the
		   multiplex id in the same structure. */
		mi_copyin(q, mp, NULL, sizeof(struct sl_mux_ppa));
		return (0);
	}
	default:
		if (mux->other && mux->other->rq) {
			if (bcanputnext(mux->other->rq, mp->b_band)) {
				putnext(mux->other->rq, mp);
				return (0);
			}
			return (-EBUSY);
		}
		break;
	}
	mi_copy_done(q, mp, EINVAL);
	return (0);
}