⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsi_sii.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 5 页
字号:
	 * 128K data buffer allocation strategy:	 *	1KB  - SII controller for non READ/WRITE DMA transfers	 *	16KB - for each tape unit	 *	 8KB - for each cdrom unit	 *	??KB - for each disk unit	 * ?? is what's left after tapes and cdroms divided by # of disks.	 * ?? must be >= 8KB, should be >= 16KB, if not reduce	 * number of cdroms to 2, then number of tapes to 2.	 * If that don't fix it panic!	 * In any "real" configuration, we should	 * never hit these limits.	 */	if ((nNSII == 1) || (sii_firstcall == 0)) {	    dboff = 0x0;	    /*             * Setup 128 byte ram buffer slots for each target to	     * be used for non READ/WRITE DMA Transfers on the SII.	     */	    for(i=0; i<NDPS; i++) {		sc->sc_siidboff[i] = dboff;#ifdef vax		dboff += 128;#endif vax#ifdef mips		dboff += 256;#endif mips	    }#ifdef vax	    dboff = (1 * 1024);#endif vax#ifdef mips	    dboff = (2 * 1024);#endif mips	    /* determine rz slot size, must be > 16kb */	    cz_slotsize = tz_slotsize = rz_slotsize = 16 * 1024;	    for (cntlr=0; cntlr<nNSII; cntlr++) {		sc = &sz_softc[cntlr];		for (targid=0; targid<NDPS; targid++) {		    if (targid == sc->sc_sysid)			continue;		    if (sc->sc_alive[targid] == 0)			continue;		    sc->sc_dboff[targid][0] = dboff;		    sc->sc_dboff[targid][1] = dboff+SII_MAX_DMA_XFER_LENGTH;		    sc->sc_segcnt[targid] = 64 * 1024; /* Get rid of in freds code */		    dboff += rz_slotsize;		    PRINTD(targid, 0x20,			("sii_probe: cntlr=%d targid=%d devtype=%x ", cntlr,			targid, sc->sc_devtyp[targid]));		    PRINTD(targid, 0x20, ("req/ack=%d slotsize=%d\n",			     sc->sc_siireqack[targid], sc->sc_segcnt[targid]));		}	    }	}	if (sii_firstcall)	    sii_firstcall = 0;#ifdef SZDEBUG	PRINTD(-1, 0x8, ("sii_probe: done probing the SCSI bus\n"));	if(sii_debug_probe) {	    siidebug = save_siidebug;	    siitarget = save_siitarget;	}#endif SZDEBUG	return(alive);}/****************************************************************** * * Start a SCSI operation on the SII chip. * ******************************************************************/sii_scsistart(sc, targid, bp)register struct sz_softc *sc;int targid;register struct buf *bp;{    int cntlr = sc->sc_siinum;    register struct sii_regs *siiaddr = (struct sii_regs *)sc->sc_scsiaddr;    volatile char *stv;    int retval;    int timer;    int phase;    u_short cstat, dstat;    int flags;    /*     * If "bp" is "0" we use polled scsi mode, disallow reselect     * attempts, and disable interrupts for all DMA transfers. We      * poll for DMA completion instead of allowing interrupts.     */    siiaddr->sii_csr |= SII_SLE;#ifdef mips    wbflush();#endif mips    if(bp == (struct buf *)0) {        siiaddr->sii_csr &= ~(SII_RSE | SII_IE);	sc->scsi_polled_mode = 1;    }    else	{	 /* Have to clear out the rambuffer area.  It is possible for a target	    to not not return all the requested bytes.  We have to make sure	    that at least the extra bytes are cleared. */	    if(sc->sc_rzspecial[targid]) {		struct mode_sel_sns_params *msp;	      /* Some risk here using get_validbuf() w/out any error checking.		It is probably low, at this point the target should not be		doing anything, and ready for the upcomming command.  Note:		this should be moved into the DMA level code. */				msp = (struct mode_sel_sns_params *)sc->sc_rzparams[targid];		if(sc->sc_actcmd[targid] == SZ_MODSNS)		{		    stv = sc->sc_rambuff +			(sc->sc_dboff[targid][get_validbuf(sc, targid)] * 2);		    (sc->wmbzero)(stv, msp->msp_length);		}	    }        siiaddr->sii_csr |= (SII_RSE | SII_IE);        sc->scsi_polled_mode = 0;    }#ifdef mips    wbflush();#endif mips    /* Perform target arbitration and selection */    if((retval = sii_select_target(sc, targid)) != SZ_SUCCESS) {	return(retval);    }BEGIN_LOOP:    /* Loop through all bus phases until command complete */    sc->scsi_completed[targid] = 0;    sc->scsi_bus_idle = 0;    cstat = siiaddr->sii_cstat;    dstat = siiaddr->sii_dstat;    do {/*XPRINTF(XPR_NFS, "B: %x", sc->sc_siidmacount[targid],0,0,0);cprintf("B: %x %x", sc->sc_siidmacount[targid],bp,0,0);*/	if(cstat & (SII_CI|SII_DI)) {        /* Check for a BUS ERROR */        if(cstat & SII_BER) {  	    siiaddr->sii_cstat = SII_BER;#ifdef mips    wbflush();#endif mips	}        /* Check for a PARITY ERROR */	if(dstat & SII_IPE) {	    flags = SZ_HARDERR | SZ_LOGREGS;	    scsi_logerr(sc, 0, targid, SZ_ET_PARITY, 0, 0, flags);	    PRINTD(targid, 0x10, ("sii_scsistart: scsi %d parity error\n",		cntlr));	    goto HANDLE_ABORT;	}	/* Check for a BUS RESET */	if(cstat & SII_RST_ONBUS) {	    siiaddr->sii_cstat = SII_RST_ONBUS;#ifdef mips    wbflush();#endif mips	    scsi_logerr(sc, 0, -1, SZ_ET_BUSRST, 0, 0, SZ_HARDERR);	    PRINTD(targid, 0x10, ("sii_scsistart: scsi %d bus reset\n", cntlr));	    goto HANDLE_ABORT;	}        /* Check for a STATE CHANGE */        if(cstat & SII_SCH)	{	  /* If SZ_BUSYTARG is set, the target returned a BUSY status for the	    current command.   The target has disconnected from the bus.	    Return SZ_IP, and allow the interrupt handler take care of the	    disconnect. */	    if( bp && (sc->sc_szflags[targid] & SZ_BUSYTARG) )	    {		PRINTD(targid, 0x4,		    ("sii_scsistart: target %d BUSY rtn SZ_IP\n", targid ));		return(SZ_IP);	    }	    siiaddr->sii_cstat = SII_SCH;	/* clear the intr */#         ifdef mips	    wbflush();				/* wait for write buffers */#         endif mips            if(sii_state_change(sc, &targid) != SZ_SUCCESS)                goto HANDLE_ABORT;	}	/* If disconnected and went to BUS FREE STATE then break */	if(sc->scsi_bus_idle)	    break;        /* Check for a PHASE MISMATCH */        if(dstat & SII_MIS) {            /* Check for a BUS ERROR */            if(cstat & SII_BER) {  	        siiaddr->sii_cstat = SII_BER;#ifdef mips    wbflush();#endif mips	    }	    /* Always clear DID DMA flag on a phase change */	    sc->sc_szflags[targid] &= ~SZ_DID_DMA;            /* Handle the current bus phase */            if(sii_phase_change(sc, dstat) != SZ_SUCCESS)                goto HANDLE_ABORT;            /* Wait for the next bus phase */            if(!sc->scsi_completed[targid] && 		  !(sc->sc_szflags[targid] & (SZ_WAS_DISCON|SZ_DID_DMA))) {		timer = 1000;		while(--timer && !(siiaddr->sii_dstat & SII_MIS));    		dstat = siiaddr->sii_dstat;		if(!sc->scsi_polled_mode && (timer == 0) && 			!(dstat & (SII_CI|SII_DI)) && 				(sc->sc_actcmd[targid] != SZ_RQSNS)) {                    PRINTD(targid, 0x4,			("sii_scsistart: SII_MIS didn't set rtn SZ_IP\n"));		    return(SZ_IP);		}	    }	}	/* Check for fragmented DMA transfers (>8K) */	if(sc->scsi_polled_mode && !(dstat & SII_MIS) &&		(dstat & (SII_TBE|SII_IBF)) &&	  		((sc->sc_fstate == SZ_DATAI_PHA) || 				(sc->sc_fstate == SZ_DATAO_PHA))) {	    /* Restart the DMA transfer */	    if(!sii_restartdma(sc))		goto HANDLE_ABORT;	}	/* Sometimes the target stays in the same phase */	if((dstat & (SII_IBF|SII_TBE)) && 		!(dstat & SII_MIS) &&			((sc->sc_fstate != SZ_DATAI_PHA) &&				(sc->sc_fstate != SZ_DATAO_PHA))) {            /* Check for a BUS ERROR */            if(cstat & SII_BER) {  	        siiaddr->sii_cstat = SII_BER;#ifdef mips    wbflush();#endif mips	    }	    /* Handle the current bus phase */	    if(sii_phase_change(sc, dstat) != SZ_SUCCESS)	        goto HANDLE_ABORT;	}	}    dstat = siiaddr->sii_dstat;    cstat = siiaddr->sii_cstat;   /*   } while(sc->scsi_polled_mode && 	/* dont spin in here!!!! */    } while(!sc->scsi_bus_idle && 		!(sc->sc_szflags[targid] & (SZ_WAS_DISCON|SZ_DID_DMA)));/*XPRINTF(XPR_NFS, "E: %x", sc->sc_siidmacount[targid],0,0,0);cprintf("E: %x", sc->sc_siidmacount[targid],0,0,0);*/    /*     * Check the status of the current SCSI operation. If the SCSI     * operation completed or disconnected then start the next SCSI      * operation, otherwise wait for the DMA to complete.     *      */    if(sc->scsi_bus_idle || (sc->sc_szflags[targid] & SZ_WAS_DISCON)) {        if(sc->scsi_completed[targid]) {            PRINTD(targid, 0x4,		("sii_scsistart: COMMAND COMPLETED successfully\n"));	    sc->scsi_completed[targid] = 0;            sc->sc_active = 0;	    if (sc->sc_szflags[targid] & SZ_BUSYTARG)	        return(SZ_IP);    	    if(sc->sc_status[targid] == SZ_GOOD)	        return(SZ_SUCCESS);		    else	        return(SZ_RET_ERR);	        } 	else if(sc->sc_szflags[targid] & SZ_WAS_DISCON) {            PRINTD(targid, 0x4, 		("sii_scsistart: COMMAND IN PROGRESS disconnected\n"));	    return(SZ_IP);        }	else {            sc->sc_active = 0;#ifdef NO_TIMER	/* JAG */	    if(sc->sc_szflags[targid] & SZ_TIMERON) {	        untimeout(sii_timer, (caddr_t)sc->sc_unit[targid]);	        sc->sc_szflags[targid] &= ~SZ_TIMERON;	    }#endif NO_TIMER	/* JAG */	    return(SZ_RET_ERR);	}    }     else if(sc->sc_szflags[targid] & SZ_DID_DMA) {	/* Poll and busy wait for DMA completion */	if(sc->scsi_polled_mode) {            PRINTD(targid, 0x4, 		("sii_scsistart: COMMAND IN PROGRESS dma poll mode\n"));            siiaddr->sii_csr &= ~SII_IE;#ifdef mips    wbflush();#endif mips            SZWAIT_UNTIL((siiaddr->sii_dstat & SII_DNE),sii_wait_count,retval);	    siiaddr->sii_dstat = SII_DNE;#ifdef mips    wbflush();#endif mips	    sc->sc_szflags[targid] &= ~SZ_DID_DMA;	    /* Update the remaining dma count for this current transfer */	    if(sc->sc_siidmacount[targid] > SII_MAX_DMA_XFER_LENGTH)		sc->sc_siidmacount[targid] -= 			(SII_MAX_DMA_XFER_LENGTH - siiaddr->sii_dmlotc);	    else		sc->sc_siidmacount[targid] -= 			(sc->sc_siidmacount[targid] - siiaddr->sii_dmlotc);	    if(retval >= sii_wait_count)	        goto HANDLE_ABORT;	    else	    	goto BEGIN_LOOP;	}	/* Wait for interrupt to signal DMA completion */	else {            PRINTD(targid, 0x4,		("sii_scsistart: COMMAND IN PROGRESS dma interrupt mode\n"));	    return(SZ_IP);   	}    } else if(!sc->scsi_polled_mode)	return(SZ_IP); 	/* dont spin in here!!! */HANDLE_ABORT:    /* Abort the current SCSI operation due to error */    PRINTD(targid, 0x10,	("sii_scsistart: command aborted (bus=%d target=%d cmd=0x%x)\n",	    cntlr, targid, sc->sc_curcmd[targid]));    PRINTD(targid, 0x10, ("", sii_dumpregs(cntlr, 0)));	flags = SZ_HARDERR | SZ_LOGCMD | SZ_LOGREGS;	scsi_logerr(sc, 0, targid, SZ_ET_CMDABRTD, 0, 0, flags);    sii_reset(sc);    siiaddr->sii_cstat = 0xffff;    siiaddr->sii_dstat = 0xffff;#ifdef mips    wbflush();#endif mips    sc->sc_selstat[targid] = SZ_IDLE;    sc->sc_active = 0;    return(SZ_RET_ABORT);}/****************************************************************** * * Perform the arbitration/selection phases for the SII chip. * ******************************************************************/sii_select_target(sc, targid)register struct sz_softc *sc;int targid;{    int cntlr = sc->sc_siinum;    register struct sii_regs *siiaddr = (struct sii_regs *)sc->sc_scsiaddr;    int retval, i;    int retries = 3;    int sii_select_wait = 5000;    int sii_rse_flag;    /* Loop till retries exhausted */    for(i = 0; i < retries; i++) {      /*       * Determine if reselections are currently enabled.  If so,       * disable them during the selection.       */      sii_rse_flag = siiaddr->sii_csr & SII_RSE;      if (sii_rse_flag) {	   siiaddr->sii_csr &= ~SII_RSE;#ifdef mips    wbflush();#endif mips      }      /* Do a quick check on the bus to see if it is in the busy state.  If        BUSY or SEL is asserted, another device on the bus is in a selection	phase.  Return SZ_BUSBUSY.  SZ_BUSBUSY can be returned and the	statemachine can leave.  This is a single Initiator bus, and a	selection is either mine or a reselection, in which the interrupt	handler will be called. */	if( (siiaddr->sii_sc1 & (SII_SC1_BSY | SII_SC1_SEL)) !=0 )	{	    PRINTD(targid, 0x104,		("sii_select_target: Bus BUSY on select of ID %d\n",targid));	    /*	     * Turn reselections back on before leaving.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -