Ejemplo n.º 1
0
extern inline void finish_req(SC_REQ *reqp)
{
	int			sps;
	struct scsipi_xfer	*xs = reqp->xs;

#ifdef REAL_DMA
	/*
	 * If we bounced, free the bounce buffer
	 */
	if (reqp->dr_flag & DRIVER_BOUNCING) 
		free_bounceb(reqp->bounceb);
#endif /* REAL_DMA */
#ifdef DBG_REQ
	if (dbg_target_mask & (1 << reqp->targ_id))
		show_request(reqp, "DONE");
#endif
#ifdef DBG_ERR_RET
	if (reqp->xs->error != 0)
		show_request(reqp, "ERR_RET");
#endif
	/*
	 * Return request to free-q
	 */
	sps = splbio();
	reqp->next = free_head;
	free_head  = reqp;
	splx(sps);

	xs->xs_status |= XS_STS_DONE;
	if (!(reqp->dr_flag & DRIVER_LINKCHK))
		scsipi_done(xs);
}
Ejemplo n.º 2
0
BOOL DR_ClearFeature(void)
{
#ifdef DEBUG
   show_request("CF");
#endif
   return(TRUE);
}
Ejemplo n.º 3
0
BOOL DR_SetFeature(void)
{
#ifdef DEBUG
   show_request("SF");
#endif
   return(TRUE);
}
Ejemplo n.º 4
0
BOOL DR_GetDescriptor(void)
{
#ifdef DEBUG
   show_request("GD");
#endif
   return(TRUE);
}
Ejemplo n.º 5
0
BOOL DR_SetInterface(void)       // Called when a Set Interface command is received
{
#ifdef DEBUG
   show_request("SI");
#endif
   AlternateSetting = SETUPDAT[2];
   return(TRUE);            // Handled by user code
}
Ejemplo n.º 6
0
BOOL DR_SetConfiguration(void)   // Called when a Set Configuration command is received
{
#ifdef DEBUG
   show_request("SC");
#endif
   Configuration = SETUPDAT[2];
   return(TRUE);            // Handled by user code
}
Ejemplo n.º 7
0
BOOL DR_GetInterface(void)       // Called when a Set Interface command is received
{
#ifdef DEBUG
   show_request("GI");
#endif
   EP0BUF[0] = AlternateSetting;
   EP0BCH = 0;
   EP0BCL = 1;
   return(TRUE);            // Handled by user code
}
Ejemplo n.º 8
0
BOOL DR_GetConfiguration(void)   // Called when a Get Configuration command is received
{
#ifdef DEBUG
   show_request("GC");
#endif
   EP0BUF[0] = Configuration;
   EP0BCH = 0;
   EP0BCL = 1;
   return(TRUE);            // Handled by user code
}
Ejemplo n.º 9
0
/*
 * 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;
		}
Ejemplo n.º 10
0
/*
 * Carry out a request from the high level driver.
 */
static void
ncr5380_scsi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req,
    void *arg)
{
	struct scsipi_xfer *xs;
	struct ncr_softc *sc = device_private(chan->chan_adapter->adapt_dev);
	int	sps, flags;
	SC_REQ	*reqp, *link, *tmp;

	switch (req) {
	case ADAPTER_REQ_RUN_XFER:
		xs = arg;
		flags = xs->xs_control;

		/*
		 * We do not queue RESET commands
		 */
		if (flags & XS_CTL_RESET) {
			scsi_reset_verbose(sc, "Got reset-command");
			scsipi_done(xs);
			return;
		}

		/*
		 * Get a request block
		 */
		sps = splbio();
		if ((reqp = free_head) == 0) {
			xs->error = XS_RESOURCE_SHORTAGE;
			scsipi_done(xs);
			return;
		}
		free_head  = reqp->next;
		reqp->next = NULL;
		splx(sps);

		/*
		 * Initialize our private fields
		 */
		reqp->dr_flag   = (flags & XS_CTL_POLL) ? DRIVER_NOINT : 0;
		reqp->phase     = NR_PHASE;
		reqp->msgout    = MSG_NOOP;
		reqp->status    = SCSGOOD;
		reqp->message   = 0xff;
		reqp->link      = NULL;
		reqp->xs        = xs;
		reqp->targ_id   = xs->xs_periph->periph_target;
		reqp->targ_lun  = xs->xs_periph->periph_lun;
		reqp->xdata_ptr = (u_char*)xs->data;
		reqp->xdata_len = xs->datalen;
		memcpy(&reqp->xcmd, xs->cmd, xs->cmdlen);
		reqp->xcmd_len = xs->cmdlen;
		reqp->xcmd.bytes[0] |= reqp->targ_lun << 5;

#ifdef REAL_DMA
		/*
		 * Check if DMA can be used on this request
		 */
		if (scsi_dmaok(reqp))
			reqp->dr_flag |= DRIVER_DMAOK;
#endif /* REAL_DMA */

		/*
		 * Insert the command into the issue queue. Note that
		 * 'REQUEST SENSE' commands are inserted at the head of the
		 * queue since any command will clear the existing contingent
		 * allegience condition and the sense data is only valid while
		 * the condition exists.
		 * When possible, link the command to a previous command to
		 * the same target. This is not very sensible when AUTO_SENSE
		 * is not defined!  Interrupts are disabled while we are
		 * fiddling with the issue-queue.
		 */
		sps = splbio();
		link = NULL;
		if ((issue_q == NULL) ||
		    (reqp->xcmd.opcode == SCSI_REQUEST_SENSE)) {
			reqp->next = issue_q;
			issue_q    = reqp;
		} else {
			tmp  = issue_q;
			do {
				if (!link && (tmp->targ_id == reqp->targ_id) &&
				    !tmp->link)
					link = tmp;
			} while (tmp->next && (tmp = tmp->next));
			tmp->next = reqp;
#ifdef AUTO_SENSE
			if (link && (ncr_will_link & (1<<reqp->targ_id))) {
				link->link = reqp;
				link->xcmd.bytes[link->xs->cmdlen-2] |= 1;
			}
#endif
		}
#ifdef AUTO_SENSE
		/*
		 * If we haven't already, check the target for link support.
		 * Do this by prefixing the current command with a dummy
		 * Request_Sense command, link the dummy to the current
		 * command, and insert the dummy command at the head of the
		 * issue queue.  Set the DRIVER_LINKCHK flag so that we'll
		 * ignore the results of the dummy command, since we only
		 * care about whether it was accepted or not.
		 */
		if (!link && !(ncr_test_link & (1<<reqp->targ_id)) &&
		    (tmp = free_head) && !(reqp->dr_flag & DRIVER_NOINT)) {
			free_head = tmp->next;
			tmp->dr_flag =
			    (reqp->dr_flag & ~DRIVER_DMAOK) | DRIVER_LINKCHK;
			tmp->phase = NR_PHASE;
			tmp->msgout = MSG_NOOP;
			tmp->status = SCSGOOD;
			tmp->xs = reqp->xs;
			tmp->targ_id = reqp->targ_id;
			tmp->targ_lun = reqp->targ_lun;
			memcpy(&tmp->xcmd, sense_cmd, sizeof(sense_cmd));
			tmp->xcmd_len = sizeof(sense_cmd);
			tmp->xdata_ptr = (u_char *)&tmp->xs->sense.scsi_sense;
			tmp->xdata_len = sizeof(tmp->xs->sense.scsi_sense);
			ncr_test_link |= 1<<tmp->targ_id;
			tmp->link = reqp;
			tmp->xcmd.bytes[sizeof(sense_cmd)-2] |= 1;
			tmp->next = issue_q;
			issue_q = tmp;
#ifdef DBG_REQ
			if (dbg_target_mask & (1 << tmp->targ_id))
				show_request(tmp, "LINKCHK");
#endif
		}
#endif
		splx(sps);

#ifdef DBG_REQ
		if (dbg_target_mask & (1 << reqp->targ_id))
			show_request(reqp,
			    (reqp->xcmd.opcode == SCSI_REQUEST_SENSE) ?
			    "HEAD":"TAIL");
#endif

		run_main(sc);
		return;

	case ADAPTER_REQ_GROW_RESOURCES:
		/* XXX Not supported. */
		return;

	case ADAPTER_REQ_SET_XFER_MODE:
		/* XXX Not supported. */
		return;
	}
}
Ejemplo n.º 11
0
BOOL DR_VendorCmnd(void)
{
#ifdef DEBUG
   show_request("VC");
#endif

   switch(SETUPDAT[1])
   {
     case 0x00: // 0x40, 0x00: reset
     {
       VC_Reset_IN();
       VC_Reset_OUT();
       break;
     }
     // 0x40, 0x01: set modem control
     // 0x40, 0x02: set flow control
     // 0x40, 0x03: set baud rate
     // 0x40, 0x04: set line property
     case 0x05: // 0xC0, 0x05: ? get status? reset?
     {
#if 0
        VC_Reset_IN();
        VC_Reset_OUT();
#endif
        EP0BUF[0] = 0x36;
        EP0BUF[1] = 0x83;
        EP0BCH = 0;
        EP0BCL = 2; // Arm endpoint with # bytes to transfer
        break;
     }
     // 0x40, 0x09: set latency timer
     // 0xC0, 0x0A: get latency timer
     // 0x40, 0x0B: set bitbang mode (mode << 8)
     // 0xC0, 0x0C: get pins
     case 0x90: // 0xC0, 0x90: read eeprom ([4] has word addr)
     {
        BYTE addr = (SETUPDAT[4]<<1) & 0x7F;
        EP0BUF[0] = PROM[addr];
        EP0BUF[1] = PROM[addr+1];
        EP0BCH = 0;
        EP0BCL = 2; // Arm endpoint with # bytes to transfer
        break;
     }
     // 0x40, 0x91: write eeprom
     // 0x40, 0x92: erase eeprom
     default:
     {
        if(SETUPDAT[0] == 0xC0)
        {
          EP0BUF[0] = 0x36;
          EP0BUF[1] = 0x83;
          EP0BCH = 0;
          EP0BCL = 2; // Arm endpoint with # bytes to transfer
        };
     }
   };

   EP0CS |= bmHSNAK; // Acknowledge handshake phase of device request

   return(FALSE); // no error; command handled OK
}