/*
 * Wait for request-line to become inactive. When it doesn't return 0.
 * Otherwise return != 0.
 */
extern inline int wait_req_false(void)
{
	int	timeout = 2500000;

	while ((GET_5380_REG(NCR5380_IDSTAT) & SC_S_REQ) && --timeout)
		delay(1);
	return (!(GET_5380_REG(NCR5380_IDSTAT) & SC_S_REQ));
}
Example #2
0
static __inline__ void
scsi_clr_ipend(void)
{
	int tmp;

	tmp = GET_5380_REG(NCR5380_IRCV);
	scsi_clear_irq();
}
/*
 * The body of the driver.
 */
static void
scsi_main(struct ncr_softc *sc)
{
	SC_REQ	*req, *prev;
	int	itype;
	int	sps;

	/*
	 * While running in the driver SCSI-interrupts are disabled.
	 */
	scsi_idisable();
	ENABLE_NCR5380(sc);

	PID("scsi_main1");
	for (;;) {
	    sps = splbio();
	    if (!connected) {
		/*
		 * Check if it is fair keep any exclusive access to DMA
		 * claimed. If not, stop queueing new jobs so the discon_q
		 * will be eventually drained and DMA can be given up.
		 */
		if (!fair_to_keep_dma())
			goto main_exit;

		/*
		 * Search through the issue-queue for a command
		 * destined for a target that isn't busy.
		 */
		prev = NULL;
		for (req=issue_q; req != NULL; prev = req, req = req->next) {
			if (!(busy & (1 << req->targ_id))) {
				/*
				 * Found one, remove it from the issue queue
				 */
				if (prev == NULL) 
					issue_q = req->next;
				else prev->next = req->next;
				req->next = NULL;
				break;
			}
		}

		/*
		 * When a request has just ended, we get here before an other
		 * device detects that the bus is free and that it can
		 * reconnect. The problem is that when this happens, we always
		 * baffle the device because our (initiator) id is higher. This
		 * can cause a sort of starvation on slow devices. So we check
		 * for a pending reselection here.
		 * Note that 'connected' will be non-null if the reselection
		 * succeeds.
		 */
		if ((GET_5380_REG(NCR5380_IDSTAT) & (SC_S_SEL|SC_S_IO))
						== (SC_S_SEL|SC_S_IO)){
			if (req != NULL) {
				req->next = issue_q; 
				issue_q = req;
			}
			splx(sps);

			reselect(sc);
			scsi_clr_ipend();
			goto connected;
		}

		/*
		 * The host is not connected and there is no request
		 * pending, exit.
		 */
		if (req == NULL) {
			PID("scsi_main2");
			goto main_exit;
		}

		/*
		 * Re-enable interrupts before handling the request.
		 */
		splx(sps);

#ifdef DBG_REQ
		if (dbg_target_mask & (1 << req->targ_id))
			show_request(req, "TARGET");
#endif
		/*
		 * We found a request. Try to connect to the target. If the
		 * initiator fails arbitration, the command is put back in the
		 * issue queue.
		 */
		if (scsi_select(req, 0)) {
			sps = splbio();
			req->next = issue_q; 
			issue_q = req;
			splx(sps);
#ifdef DBG_REQ
			if (dbg_target_mask & (1 << req->targ_id))
				ncr_tprint(req, "Select failed\n");
#endif
		}
	    }
	    else splx(sps);
connected:
	    if (connected) {
		/*
		 * If the host is currently connected but a 'real-DMA' transfer
		 * is in progress, the 'end-of-DMA' interrupt restarts main.
		 * So quit.
		 */
		sps = splbio();
		if (connected && (connected->dr_flag & DRIVER_IN_DMA)) {
			PID("scsi_main3");
			goto main_exit;
		}
		splx(sps);

		/*
		 * Let the target guide us through the bus-phases
		 */
		while (information_transfer(sc) == -1)
			;
	    }
	}
	/* NEVER TO REACH HERE */
	panic("ncr5380-SCSI: not designed to come here");

main_exit:
	/*
	 * We enter here with interrupts disabled. We are about to exit main
	 * so interrupts should be re-enabled. Because interrupts are edge
	 * triggered, we could already have missed the interrupt. Therefore
	 * we check the IRQ-line here and re-enter when we really missed a
	 * valid interrupt.
	 */
	PID("scsi_main4");
	scsi_ienable();

	/*
	 * If we're not currently connected, enable reselection
	 * interrupts.
	 */
	if (!connected)
		SET_5380_REG(NCR5380_IDSTAT, SC_HOST_ID);

	if (scsi_ipending()) {
		if ((itype = check_intr(sc)) != INTR_SPURIOUS) {
			scsi_idisable();
			splx(sps);

			if (itype == INTR_RESEL)
				reselect(sc);
#ifdef REAL_DMA
			else dma_ready();
#else
			else {
				if (pdma_ready())
					goto connected;
				panic("Got DMA interrupt without DMA");
			}
#endif
			scsi_clr_ipend();
			goto connected;
		}