Exemplo n.º 1
0
static void
recover(queue_t *q, mblk_t *mp, size_t size)
{
	bufcall_id_t bid;
	timeout_id_t tid;
	struct	telmod_info	*tmip = (struct telmod_info *)q->q_ptr;

	ASSERT(mp->b_datap->db_type < QPCTL);
	noenable(q);
	(void) putbq(q, mp);

	/*
	 * Make sure there is at most one outstanding request per queue.
	 */
	if (q->q_flag & QREADR) {
		if (tmip->rtimoutid || tmip->rbufcid) {
			return;
		}
	} else {
		if (tmip->wtimoutid || tmip->wbufcid) {
			return;
		}
	}
	if (!(bid = qbufcall(RD(q), size, BPRI_MED, telmod_buffer, q))) {
		tid = qtimeout(RD(q), telmod_timer, q, SIMWAIT);
		if (q->q_flag & QREADR)
			tmip->rtimoutid = tid;
		else
			tmip->wtimoutid = tid;
	} else	{
		if (q->q_flag & QREADR)
			tmip->rbufcid = bid;
		else
			tmip->wbufcid = bid;
	}
}
Exemplo n.º 2
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));
	}
}
Exemplo n.º 3
0
/*ARGSUSED*/
static int
telmodopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *credp)
{
	struct telmod_info	*tmip;
	mblk_t *bp;
	union T_primitives *tp;
	int	error;

	if (sflag != MODOPEN)
		return (EINVAL);

	if (q->q_ptr != NULL) {
		/* It's already attached. */
		return (0);
	}
	/*
	 * Allocate state structure.
	 */
	tmip = kmem_zalloc(sizeof (*tmip), KM_SLEEP);

	/*
	 * Cross-link.
	 */
	q->q_ptr = tmip;
	WR(q)->q_ptr = tmip;

	noenable(q);
	tmip->flags |= TEL_STOPPED;
	qprocson(q);

	/*
	 * Since TCP operates in the TLI-inspired brain-dead fashion,
	 * the connection will revert to bound state if the connection
	 * is reset by the client.  We must send a T_UNBIND_REQ in
	 * that case so the port doesn't get "wedged" (preventing
	 * inetd from being able to restart the listener).  Allocate
	 * it here, so that we don't need to worry about allocb()
	 * failures later.
	 */
	while ((tmip->unbind_mp = allocb(sizeof (union T_primitives),
	    BPRI_HI)) == NULL) {
		bufcall_id_t id = qbufcall(q, sizeof (union T_primitives),
		    BPRI_HI, dummy_callback, NULL);
		if (!qwait_sig(q)) {
			qunbufcall(q, id);
			error = EINTR;
			goto fail;
		}
		qunbufcall(q, id);
	}
	tmip->unbind_mp->b_wptr = tmip->unbind_mp->b_rptr +
	    sizeof (struct T_unbind_req);
	tmip->unbind_mp->b_datap->db_type = M_PROTO;
	tp = (union T_primitives *)tmip->unbind_mp->b_rptr;
	tp->type = T_UNBIND_REQ;
	/*
	 * Send a M_PROTO msg of type T_DATA_REQ (this is unique for
	 * read queue since only write queue can get T_DATA_REQ).
	 * Readstream routine in telnet daemon will do a getmsg() till
	 * it receives this proto message
	 */
	while ((bp = allocb(sizeof (union T_primitives), BPRI_HI)) == NULL) {
		bufcall_id_t id = qbufcall(q, sizeof (union T_primitives),
		    BPRI_HI, dummy_callback, NULL);
		if (!qwait_sig(q)) {
			qunbufcall(q, id);
			error = EINTR;
			goto fail;
		}
		qunbufcall(q, id);
	}
	bp->b_datap->db_type = M_PROTO;
	bp->b_wptr = bp->b_rptr + sizeof (union T_primitives);
	tp = (union T_primitives *)bp->b_rptr;
	tp->type = T_DATA_REQ;
	tp->data_req.MORE_flag = 0;

	putnext(q, bp);
	return (0);

fail:
	qprocsoff(q);
	if (tmip->unbind_mp != NULL) {
		freemsg(tmip->unbind_mp);
	}
	kmem_free(tmip, sizeof (struct telmod_info));
	q->q_ptr = NULL;
	WR(q)->q_ptr = NULL;
	return (error);
}
Exemplo n.º 4
0
/*
 * Returns 1 if the caller should put the message (bp) back on the queue
 */
static int
mouse8042_initiate_reset(queue_t *q, mblk_t *mp, struct mouse_state *state)
{
	mutex_enter(&state->reset_mutex);
	/*
	 * If we're in the middle of a reset, put the message back on the queue
	 * for processing later.
	 */
	if (state->reset_state != MSE_RESET_IDLE) {
		/*
		 * We noenable the queue again here in case it was backenabled
		 * by an upper-level module.
		 */
		noenable(q);

		mutex_exit(&state->reset_mutex);
		return (1);
	}

	/*
	 * Drop the reset state lock before allocating the response message and
	 * grabbing the 8042 exclusive-access lock (since those operations
	 * may take an extended period of time to complete).
	 */
	mutex_exit(&state->reset_mutex);

	if (state->reply_mp == NULL)
		state->reply_mp = allocb(2, BPRI_MED);
	if (state->reset_ack_mp == NULL)
		state->reset_ack_mp = allocb(1, BPRI_MED);

	if (state->reply_mp == NULL || state->reset_ack_mp == NULL) {
		/*
		 * Allocation failed -- set up a bufcall to enable the queue
		 * whenever there is enough memory to allocate the response
		 * message.
		 */
		state->bc_id = qbufcall(q, (state->reply_mp == NULL) ? 2 : 1,
		    BPRI_MED, (void (*)(void *))qenable, q);

		if (state->bc_id == 0) {
			/*
			 * If the qbufcall failed, we cannot proceed, so use the
			 * message we were sent to respond with an error.
			 */
			*mp->b_rptr = MSEERROR;
			mp->b_wptr = mp->b_rptr + 1;
			qreply(q, mp);
			return (0);
		}

		return (1);
	} else {
		/* Bufcall completed successfully (or wasn't needed) */
		state->bc_id = 0;
	}

	/*
	 * Gain exclusive access to the 8042 for the duration of the reset.
	 * The unlock will occur when the reset has either completed or timed
	 * out.
	 */
	(void) ddi_get8(state->ms_handle,
	    state->ms_addr + I8042_LOCK);

	mutex_enter(&state->reset_mutex);

	state->reset_state = MSE_RESET_PRE;
	noenable(q);

	state->reset_tid = qtimeout(q,
	    mouse8042_reset_timeout,
	    state,
	    drv_usectohz(
	    MOUSE8042_RESET_TIMEOUT_USECS));

	ddi_put8(state->ms_handle,
	    state->ms_addr +
	    I8042_INT_OUTPUT_DATA, MSERESET);

	mp->b_rptr++;

	mutex_exit(&state->reset_mutex);
	return (1);
}