예제 #1
0
int
ghd_intr(ccc_t *cccp, void *intr_status)
{
	int (*statfunc)(void *, void *) = cccp->ccc_get_status;
	void (*processfunc)(void *, void *) = cccp->ccc_process_intr;
	kmutex_t *waitq_mutexp = &cccp->ccc_waitq_mutex;
	kmutex_t *hba_mutexp = &cccp->ccc_hba_mutex;
	void		  *handle = cccp->ccc_hba_handle;
	int		   rc = DDI_INTR_UNCLAIMED;
	int		   more;


	mutex_enter(hba_mutexp);

	GDBG_INTR(("ghd_intr(): cccp=0x%p status=0x%p\n",
	    (void *)cccp, intr_status));

	for (;;) {
		more = FALSE;

		/* process the interrupt status */
		while ((*statfunc)(handle, intr_status)) {
			(*processfunc)(handle, intr_status);
			rc = DDI_INTR_CLAIMED;
			more = TRUE;
		}
		mutex_enter(waitq_mutexp);
		if (ghd_waitq_process_and_mutex_hold(cccp)) {
			ASSERT(mutex_owned(hba_mutexp));
			mutex_exit(waitq_mutexp);
			continue;
		}
		if (more) {
			mutex_exit(waitq_mutexp);
			continue;
		}
		GDBG_INTR(("ghd_intr(): done cccp=0x%p status=0x%p rc %d\n",
		    (void *)cccp, intr_status, rc));
		/*
		 * Release the mutexes in the opposite order that they
		 * were acquired to prevent requests queued by
		 * ghd_transport() from getting hung up in the wait queue.
		 */
		mutex_exit(hba_mutexp);
		mutex_exit(waitq_mutexp);
		return (rc);
	}
}
예제 #2
0
파일: ghd_waitq.c 프로젝트: andreiw/polaris
void
ghd_waitq_process_and_mutex_exit(ccc_t *cccp)
{
	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
	ASSERT(mutex_owned(&cccp->ccc_waitq_mutex));

	GDBG_WAITQ(("ghd_waitq_process_and_mutex_exit: cccp 0x%p\n", cccp));

	(void) ghd_waitq_process_and_mutex_hold(cccp);

	/*
	 * Release the mutexes in the opposite order that they
	 * were acquired to prevent requests queued by
	 * ghd_transport() from getting hung up in the wait queue.
	 */
	mutex_exit(&cccp->ccc_hba_mutex);
	mutex_exit(&cccp->ccc_waitq_mutex);
}
예제 #3
0
static int
ghd_poll(ccc_t	*cccp,
	gpoll_t	 polltype,
	ulong_t	 polltime,
	gcmd_t	*poll_gcmdp,
	gtgt_t	*gtgtp,
	void	*intr_status)
{
	gcmd_t	*gcmdp;
	L2el_t	 gcmd_hold_queue;
	int	 got_it = FALSE;
	clock_t  poll_lbolt;
	clock_t	 start_lbolt;
	clock_t	 current_lbolt;


	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
	L2_INIT(&gcmd_hold_queue);

	/* Que hora es? */
	poll_lbolt = drv_usectohz((clock_t)polltime);
	start_lbolt = ddi_get_lbolt();

	/* unqueue and save all CMD/CCBs until I find the right one */
	while (!got_it) {

		/* Give up yet? */
		current_lbolt = ddi_get_lbolt();
		if (poll_lbolt && (current_lbolt - start_lbolt >= poll_lbolt))
			break;

		/*
		 * delay 1 msec each time around the loop (this is an
		 * arbitrary delay value, any value should work) except
		 * zero because some devices don't like being polled too
		 * fast and it saturates the bus on an MP system.
		 */
		drv_usecwait(1000);

		/*
		 * check for any new device status
		 */
		if ((*cccp->ccc_get_status)(cccp->ccc_hba_handle, intr_status))
			(*cccp->ccc_process_intr)(cccp->ccc_hba_handle,
			    intr_status);

		/*
		 * If something completed then try to start the
		 * next request from the wait queue. Don't release
		 * the HBA mutex because I don't know whether my
		 * request(s) is/are on the done queue yet.
		 */
		mutex_enter(&cccp->ccc_waitq_mutex);
		(void) ghd_waitq_process_and_mutex_hold(cccp);
		mutex_exit(&cccp->ccc_waitq_mutex);

		/*
		 * Process the first of any timed-out requests.
		 */
		ghd_timer_poll(cccp, GHD_TIMER_POLL_ONE);

		/*
		 * Unqueue all the completed requests, look for mine
		 */
		while (gcmdp = ghd_doneq_get(cccp)) {
			/*
			 * If we got one and it's my request, then
			 * we're done.
			 */
			if (gcmdp == poll_gcmdp) {
				poll_gcmdp->cmd_state = GCMD_STATE_IDLE;
				got_it = TRUE;
				continue;
			}
			/* fifo queue the other cmds on my local list */
			L2_add(&gcmd_hold_queue, &gcmdp->cmd_q, gcmdp);
		}


		/*
		 * Check whether we're done yet.
		 */
		switch (polltype) {
		case GHD_POLL_DEVICE:
			/*
			 * wait for everything queued on a specific device
			 */
			if (GDEV_NACTIVE(gtgtp->gt_gdevp) == 0)
				got_it = TRUE;
			break;

		case GHD_POLL_ALL:
			/*
			 * if waiting for all outstanding requests and
			 * if active list is now empty then exit
			 */
			if (GHBA_NACTIVE(cccp) == 0)
				got_it = TRUE;
			break;

		case GHD_POLL_REQUEST:
			break;

		}
	}

	if (L2_EMPTY(&gcmd_hold_queue)) {
		ASSERT(!mutex_owned(&cccp->ccc_waitq_mutex));
		ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
		return (got_it);
	}

	/*
	 * copy the local gcmd_hold_queue back to the doneq so
	 * that the order of completion callbacks is preserved
	 */
	while (gcmdp = L2_next(&gcmd_hold_queue)) {
		L2_delete(&gcmdp->cmd_q);
		GHD_DONEQ_PUT_TAIL(cccp, gcmdp);
	}

	ASSERT(!mutex_owned(&cccp->ccc_waitq_mutex));
	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
	return (got_it);
}