Пример #1
0
void
bshw_smit_xfer_stop(struct ct_softc *ct)
{
	struct scsi_low_softc *slp = &ct->sc_sclow;
	struct bshw_softc *bs = ct->ct_hw;
	struct targ_info *ti;
	struct sc_p *sp = &slp->sl_scp;
	u_int count;

	bshw_lc_smit_stop(ct);

	ti = slp->sl_Tnexus;
	if (ti == NULL)
		return;

	if (ti->ti_phase == PH_DATA)
	{
		count = cthw_get_count(&ct->sc_ch);
		if (count < bs->sc_sdatalen)
		{
			if (sp->scp_direction == SCSI_LOW_READ &&
			    count != bs->sc_edatalen)
				goto bad;

			count = bs->sc_sdatalen - count;
			if (count > (u_int) sp->scp_datalen)
				goto bad;

			sp->scp_data += count;
			sp->scp_datalen -= count;
		}
		else if (count > bs->sc_sdatalen)
		{
bad:
			device_printf(slp->sl_dev,
			    "smit_xfer_end: cnt error\n");
			slp->sl_error |= PDMAERR;
		}
		scsi_low_data_finish(slp);
	}
	else
	{
		device_printf(slp->sl_dev, "smit_xfer_end: phase miss\n");
		slp->sl_error |= PDMAERR;
	}
}
Пример #2
0
/**************************************************************
 * PDMA functions
 **************************************************************/
static __inline void
stg_pdma_end(struct stg_softc *sc, struct targ_info *ti)
{
	struct scsi_low_softc *slp = &sc->sc_sclow;
	bus_space_tag_t iot = sc->sc_iot;
	bus_space_handle_t ioh = sc->sc_ioh;
	struct slccb *cb = slp->sl_Qnexus;
	u_int len, tres;

	slp->sl_flags &= ~HW_PDMASTART;
	sc->sc_icinit &= ~ICTL_FIFO;
	sc->sc_dataout_timeout = 0;

	if (cb == NULL)
	{
		slp->sl_error |= PDMAERR;
		goto out;
	}

	if (ti->ti_phase == PH_DATA)
	{
		len = bus_space_read_2(iot, ioh, tmc_fdcnt);
		if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE)
		{
			if (len != 0)
			{
				tres = len + slp->sl_scp.scp_datalen;
				if (tres <= (u_int) cb->ccb_scp.scp_datalen)
				{
					slp->sl_scp.scp_data -= len;
					slp->sl_scp.scp_datalen = tres;
				}
				else
				{
					slp->sl_error |= PDMAERR;
					kprintf("%s len %x >= datalen %x\n",
						slp->sl_xname,
						len, slp->sl_scp.scp_datalen);
				}
			}
		}
		else if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
		{
			if (len != 0)
			{
				slp->sl_error |= PDMAERR;
				kprintf("%s: len %x left in fifo\n",
					slp->sl_xname, len);
			}
		}
		scsi_low_data_finish(slp);
	}
	else
	{

		kprintf("%s data phase miss\n", slp->sl_xname);
		slp->sl_error |= PDMAERR;
	}

out:
	bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
}
Пример #3
0
static int
ct_poll(void *arg)
{
	struct ct_softc *ct = arg;
	struct scsi_low_softc *slp = &ct->sc_sclow;
	struct ct_bus_access_handle *chp = &ct->sc_ch;
	struct targ_info *ti;
	struct buf *bp;
	u_int derror, flags;
	int len, satgo, error;
	u_int8_t scsi_status, regv;

again:
	if (slp->sl_flags & HW_INACTIVE)
		return 0;

	/**************************************************
	 * Get status & bus phase
	 **************************************************/
	if ((ct_stat_read_1(chp) & STR_INT) == 0)
		return 0;

	scsi_status = ct_cr_read_1(chp, wd3s_stat);
	if (scsi_status == ((u_int8_t) -1))
		return 1;

	/**************************************************
	 * Check reselection, or nexus
	 **************************************************/
	if (scsi_status == BSR_RESEL || scsi_status == BSR_AFM_RESEL)
	{
		if (ct_reselected(ct, scsi_status) == EJUSTRETURN)
			return 1;
	}

	if ((ti = slp->sl_Tnexus) == NULL)
		return 1;

	/**************************************************
	 * Debug section
	 **************************************************/
#ifdef	CT_DEBUG
	if (ct_debug > 0)
	{
		scsi_low_print(slp, NULL);
		device_printf(slp->sl_dev, "scsi_status 0x%x\n\n", 
		       (u_int) scsi_status);
#ifdef	KDB
		if (ct_debug > 1)
			kdb_enter(KDB_WHY_CAM, "ct");
#endif	/* KDB */
	}
#endif	/* CT_DEBUG */

	/**************************************************
	 * Internal scsi phase
	 **************************************************/
	satgo = ct->sc_satgo;
	ct->sc_satgo &= ~CT_SAT_GOING;

	switch (ti->ti_phase)
	{
	case PH_SELSTART:
		if ((satgo & CT_SAT_GOING) == 0)
		{
			if (scsi_status != BSR_SELECTED)
			{
				ct_phase_error(ct, scsi_status);
				return 1;
			}
			scsi_low_arbit_win(slp);
			SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
			return 1;
		}
		else
		{
			scsi_low_arbit_win(slp);
			SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); /* XXX */
		}
		break;

	case PH_RESEL:
	    	if ((scsi_status & BSR_PHVALID) == 0 ||
		    (scsi_status & BSR_PM) != BSR_MSGIN)
		{
			scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, 
				 "phase miss after reselect");
			return 1;
		}
		break;

	default:
		if (slp->sl_flags & HW_PDMASTART)
		{
			slp->sl_flags &= ~HW_PDMASTART;
			if (ct->sc_dma & CT_DMA_DMASTART)
			{
				(*ct->ct_dma_xfer_stop) (ct);
				ct->sc_dma &= ~CT_DMA_DMASTART;
			}
			else if (ct->sc_dma & CT_DMA_PIOSTART)
			{
				(*ct->ct_pio_xfer_stop) (ct);
				ct->sc_dma &= ~CT_DMA_PIOSTART;
			}
			else
			{
				scsi_low_data_finish(slp);
			}
		}
		break;
	}

	/**************************************************
	 * parse scsi phase
	 **************************************************/
	if (scsi_status & BSR_PHVALID)
	{
		/**************************************************
		 * Normal SCSI phase.
		 **************************************************/
		if ((scsi_status & BSR_CM) == BSR_CMDABT)
		{
			ct_phase_error(ct, scsi_status);
			return 1;
		}

		switch (scsi_status & BSR_PM)
		{
		case BSR_DATAOUT:
			SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
			if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0)
			{
				ct_attention(ct);
			}
			goto common_data_phase;

		case BSR_DATAIN:
			SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
			if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0)
			{
				ct_attention(ct);
			}

common_data_phase:
			if (slp->sl_scp.scp_datalen > 0)
			{
				slp->sl_flags |= HW_PDMASTART;
				if ((ct->sc_xmode & CT_XMODE_PIO) != 0)
				{
					error = (*ct->ct_pio_xfer_start) (ct);
					if (error == 0)
					{
						ct->sc_dma |= CT_DMA_PIOSTART;
						return 1;
					}
				}

				if ((ct->sc_xmode & CT_XMODE_DMA) != 0)
				{
					error = (*ct->ct_dma_xfer_start) (ct);
					if (error == 0)
					{
						ct->sc_dma |= CT_DMA_DMASTART;
						return 1;
					}
				}
			}
			else
			{	
				if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
				{
					if (!(slp->sl_flags & HW_READ_PADDING))
					{
						device_printf(slp->sl_dev,
						    "read padding required\n");
						return 1;
					}
				}
				else
				{
					if (!(slp->sl_flags & HW_WRITE_PADDING))
					{
						device_printf(slp->sl_dev,
						    "write padding required\n");
						return 1;
					}
				}
				slp->sl_flags |= HW_PDMASTART;
			}

			ct_io_xfer(ct);
			return 1;

		case BSR_CMDOUT:
			SCSI_LOW_SETUP_PHASE(ti, PH_CMD);
			if (scsi_low_cmd(slp, ti) != 0)
			{
				ct_attention(ct);
			}

			if (ct_xfer(ct, slp->sl_scp.scp_cmd,
				    slp->sl_scp.scp_cmdlen,
				    SCSI_LOW_WRITE, &derror) != 0)
			{
				device_printf(slp->sl_dev,
				    "scsi cmd xfer short\n");
			}
			return 1;

		case BSR_STATIN:
			SCSI_LOW_SETUP_PHASE(ti, PH_STAT);
			if ((ct_io_control & CT_USE_CCSEQ) != 0)
			{
				if (scsi_low_is_msgout_continue(ti, 0) != 0 ||
				    ct->sc_atten != 0)
				{
					ct_xfer(ct, &regv, 1, SCSI_LOW_READ,
						&derror);
					scsi_low_statusin(slp, ti,
						  	  regv | derror);
				}
				else
				{
					ct->sc_satgo |= CT_SAT_GOING;
					cthw_set_count(chp, 0);
					cthw_phase_bypass(ct, 0x41);
				}
			}
			else
			{
				ct_xfer(ct, &regv, 1, SCSI_LOW_READ, &derror);
				scsi_low_statusin(slp, ti, regv | derror);
			}
			return 1;

		case BSR_UNSPINFO0:
		case BSR_UNSPINFO1:
			device_printf(slp->sl_dev, "illegal bus phase (0x%x)\n",
				(u_int) scsi_status);
			scsi_low_print(slp, ti);
			return 1;

		case BSR_MSGOUT:
			SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
			flags = SCSI_LOW_MSGOUT_UNIFY;
		        if (ti->ti_ophase != ti->ti_phase)
				flags |= SCSI_LOW_MSGOUT_INIT;
			len = scsi_low_msgout(slp, ti, flags);

			if (len > 1 && slp->sl_atten == 0)
			{
				ct_attention(ct);
			}

			if (ct_xfer(ct, ti->ti_msgoutstr, len, 
				    SCSI_LOW_WRITE, &derror) != 0)
			{
				device_printf(slp->sl_dev,
				    "scsi msgout xfer short\n");
			}
			SCSI_LOW_DEASSERT_ATN(slp);
			ct->sc_atten = 0;
			return 1;

		case BSR_MSGIN:/* msg in */
			SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);

			ct_xfer(ct, &regv, 1, SCSI_LOW_READ, &derror);
			if (scsi_low_msgin(slp, ti, regv | derror) == 0)
			{
				if (scsi_low_is_msgout_continue(ti, 0) != 0)
				{
					/* XXX: scsi_low_attetion */
					scsi_low_attention(slp);
				}
			}

			if ((ct_io_control & CT_FAST_INTR) != 0)
			{
				if (ct_catch_intr(ct) == 0)
					goto again;
			}
			return 1;
		}
	}
	else
	{
		/**************************************************
		 * Special SCSI phase
		 **************************************************/
		switch (scsi_status)
		{
		case BSR_SATSDP: /* SAT with save data pointer */
			SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
			ct->sc_satgo |= CT_SAT_GOING;
			scsi_low_msgin(slp, ti, MSG_SAVESP);
			cthw_phase_bypass(ct, 0x41);
			return 1;

		case BSR_SATFIN: /* SAT COMPLETE */
			/*
			 * emulate statusin => msgin
			 */
			SCSI_LOW_SETUP_PHASE(ti, PH_STAT);
			scsi_low_statusin(slp, ti, ct_cr_read_1(chp, wd3s_lun));

			SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
			scsi_low_msgin(slp, ti, MSG_COMP);

			scsi_low_disconnected(slp, ti);
			return 1;

		case BSR_ACKREQ: /* negate ACK */
			if (ct->sc_atten != 0)
			{
				ct_attention(ct);
			}

			ct_cr_write_1(chp, wd3s_cmd, WD3S_NEGATE_ACK);
			if ((ct_io_control & CT_FAST_INTR) != 0)
			{
				/* XXX:
				 * Should clear a pending interrupt and
				 * sync with a next interrupt!
				 */
				ct_catch_intr(ct);
			}
			return 1;

		case BSR_DISC: /* disconnect */
			if (slp->sl_msgphase == MSGPH_NULL &&
			    (satgo & CT_SAT_GOING) != 0)
			{
				/*
				 * emulate disconnect msg
				 */
				SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
				scsi_low_msgin(slp, ti, MSG_DISCON);
			}	
			scsi_low_disconnected(slp, ti);
			return 1;

		default:
			break;
		}
	}

	ct_phase_error(ct, scsi_status);
	return 1;
}