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

📄 scsi.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 5 页
字号:
		    */		    else {			sc->sz_modsel.pll = 0x0e;			sc->sz_modsel.bufmode = 0;			sc->sz_modsel.rdeclen = 0x08;			sc->sz_modsel.vulen = 1;			sc->sz_modsel.nof = 0;		    }		    break;		case SZ_TRKSEL:			return(SZ_RET_ERR);			break;		case SZ_RESUNIT:		case SZ_RELUNIT:#ifdef SZDEBUG 			printd("sz_bldpkt: unimplemented command 0x%x\n", 				cmd);#endif SZDEBUG			return (SZ_RET_ERR);			break;						default:#ifdef SZDEBUG			printd("sz_bldpkt: unknown command = 0x%x\n",				cmd);#endif SZDEBUG			return (SZ_RET_ERR);			break;	}	/*	 * We assume each unit is a single SCSI target device, i.e.,	 * no sub-units. So logical unit is always zero.	 * 	 * sz_read is used here to get to the fields in the 	 * structure for all commands.	 * TODO: need to worry about 12 byte commands?	 */	len = sz_cdb_length (cmd, targid);	if (len == 6) {	    len = 6;	    sc->sz_t_read.lun = 0;	    sc->sz_t_read.link = 0;	    sc->sz_t_read.flag = 0;	    sc->sz_t_read.mbz = 0;	}	sc->sz_opcode = cmd;	/*	 * Save the current command bytes for the error log.	 * Unless we are doing a request sense after a failed command.	 */	byteptr = (u_char *)&sc->sz_command;	if (sc->sc_curcmd[targid] == sc->sc_actcmd[targid]) {	    for (i = 0; i < len; i++)		sc->sc_cmdlog[targid][i] = *byteptr++;	    for (; i < 12; i++)		sc->sc_cmdlog[targid][i] = 0;	}	return(SZ_SUCCESS);}int	sz_szf_print = 0;int	sz_sp_szflags = 0;int	sz_rw_szflags = 0;/* * * Name:		sz_start	-Start routine (state machine) * * Abstract:		This routine is called to start or continue *			a data transfer or other type of command on a *			SCSI target device. This routine is a state *			machine for each target on each SCSI controller. *			The state machine keeps track of the target's *			progress thru all the steps necessary to do *			a data transfer or other type command. *			The state machine states/events are defined in *			the scsireg.h and scsivar.h header files. * * Inputs: * * sc			Pointer to the controller's sz_softc structure. * targid		Device SCSI target ID (0 - 7), or *			-1 start command on next ready target device. * * Outputs: * *			Calls sc_port_start routine to start command. *			Much sz_softc context is modified. * * Return Values:	None. * * Side Effects: *			Must backoff command and try later if bus busy. * */sz_start(sc, targid)register struct sz_softc *sc;int targid;{    int cntlr = sc - &sz_softc[0];    register struct sz_regs *szaddr = (struct sz_regs *)szmem + cntlr;    register struct nb_regs *sziaddr = (struct nb_regs *)nexus;    register struct buf *bp;    register struct buf *dp;    char *stv;			/* virtual address of st page tables	      */    struct pte *pte, *mpte;	/* used for mapping page table entries	      */    char *bufp;    unsigned v;    int o, npf;    struct proc *rp;    int ssrv;    int i;    int bcount;    short count;    u_char *byteptr;    struct uba_ctlr *um = szminfo[cntlr];    struct uba_device *ui;    int unit;    int part;    daddr_t blkno;    daddr_t badblk;    struct scsi_devtab *sdp;    struct tape_opt_tab *todp;    struct tape_info *ddp;    /*     * Just return if bus reset in progress.     */    if (sc->sc_rip)	return;	    if (targid != -1) {		/* we know the target ID */	/*	 * If the target ID is not minus one, just enter	 * the next state/event for that target.	 */	unit = sc->sc_unit[targid];	dp = &szutab[unit];	bp = dp->b_actf;    }    else {	/*	 * If the target ID is minus one, we were called from	 * szintr() because the currently active target	 * disconnected. Start I/O on the next target	 * with a request pending, but not already active.	 */	targid = sc->sc_lastid;	while (1) {	    targid++;	    if (targid >= NDPS)		targid = 0;	    if ((1 << targid) == sc->sc_sysid)		continue;		/* skip initiator */	    if (targid == sc->sc_lastid)		return;			/* no target ready to start I/O */	    /* TODO: need more checking (could be unknown target) */	    if (sc->sc_alive[targid] == 0)		continue;		/* non existent target */	    unit = sc->sc_unit[targid];	    dp = (struct buf *)&szutab[unit];	    if (dp->b_active)		continue;		/* target already active */	    if (dp->b_actf == NULL)		continue;		/* no request pending on this target */	     /* found one, start it */	    bp = dp->b_actf;	    break;	}    }    /*     * The sz_start routine is a state machine for each     * target device on each bus.     * The states are kept in the sz_softc structure.     * The state variables used in this state machine are:     *     *	sc->sc_xstate	used to dispatch to major states     *	sc->sc_xevent	used to dispatch to minor (sub)states     */    for (;;) {	/* forever */    switch(sc->sc_xstate[targid]) {/**/	case SZ_NEXT:	    switch(sc->sc_xevent[targid]) {		case SZ_CONT:		  /* Call the particular device completion routine. */		    bp = dp->b_actf;		    (*sc->device_comp[targid])(bp);		    /*		     * Find the next target with an I/O reuest pending		     * and is not already busy, and start I/O on it.		     */		    if (sc->sc_szflags[targid] & SZ_BUSYBUS)			return;		/* bus busy don't start next command */		    targid = sc->sc_lastid;		    while (1) {			targid++;			if (targid >= NDPS)			    targid = 0;			if ((1 << targid) == sc->sc_sysid)			    continue;		/* skip initiator */			/* TODO: need more checking, see comment above */			if (sc->sc_alive[targid] == 0)			    continue;		/* non existent target */			unit = sc->sc_unit[targid];			dp = (struct buf *)&szutab[unit];			if (dp->b_actf == NULL) {			    dp->b_active = 0;			    if (targid == sc->sc_lastid)				return;			    else				continue;			}			else {			    if (dp->b_active) {				if (targid == sc->sc_lastid)				    return;				else				    continue;			    }			}			bp = dp->b_actf;	/* MUST set buffer pointer */			dp->b_active = 1;	/* TODO: also set in LATER */			break;		    }		    continue;		/* takes us to SZ_BEGIN or SZ_RW_CONT */		    break;		/* NOTREACHED */		case SZ_BEGIN:		    if ((bp = dp->b_actf) == NULL) {			/* TODO: debug - remove later */			printf("sz_start: SZ_BEGIN with null bp ");			printf("t=%d un=%d last=%d dp=%x\n",			    targid, unit, sc->sc_lastid, dp);			dp->b_active = 0;			return;		    }		    sc->sc_szflags[targid] &= ~SZ_BUSYBUS;		    if((sc->sc_flags[targid] & DEV_EOM) && !((sc->sc_flags[targid] & DEV_CSE) ||			(dis_eot_sz[unit] & DISEOT))) {			bp->b_resid = bp->b_bcount;			bp->b_error = ENOSPC;			bp->b_flags |= B_ERROR;			sc->sc_xevent[targid] = SZ_CONT;			break;		    }		    /* 		     * For nbufio... If we are not at eot and DEV_CSE		     * is set then clear the flag. In other words the		     * dev_cse bit was set in response to a file mark		     * detected during nbufio...The reasoning for the		     * clear of the flag here is because of the previous		     * check and all operations begin life at this		     * state. We must notice the flag with the previous		     * if because the user have set the flag to get		     * past eot. This is allowed, else if not at 		     * eot the flag was set for nbufio and if we		     * what to notice eot we have to clear the flag.		    */		    if( !(sc->sc_flags[targid] & DEV_EOM) && 				(sc->sc_flags[targid] & DEV_CSE)) {			sc->sc_flags[targid] &= ~DEV_CSE;		    }		    if((bp->b_flags&B_READ) && (bp->b_flags&B_RAWASYNC) && 			((sc->sc_category_flags[targid]&DEV_TPMARK) ||			(sc->sc_flags[targid]&DEV_HARDERR))) {			bp->b_error = EIO;			bp->b_flags |= B_ERROR;			sc->sc_xevent[targid] = SZ_CONT;			break;		    }		    /* 		     * For fix block tape units check to see if tape mark		     * is pending.... IF so this is the next read and post		     * TPMARK AND clear the pending flag...		    */		    if((bp->b_flags & B_READ) && (bp->b_flags & B_RAWASYNC) && 			     (sc->sc_category_flags[targid] & TPMARK_PENDING)){			sc->sc_resid[targid] = bp->b_bcount;			sc->sc_xstate[targid] = SZ_NEXT;			sc->sc_xevent[targid] = SZ_CONT;			sc->sc_category_flags[targid] |= DEV_TPMARK;			sc->sc_category_flags[targid] &= ~TPMARK_PENDING;			break;		    }		    /* ok we have gotten to this point.... If 		     * we had nbuf io and a tpmark then we can't		     * get to here..... This is an operation, whether		     * control or (sync)read/write it does not matter we 		     * must clear out the tpmark indicator...		     * Ie straight reads will report the tpmark and		     * the next operation should get the next record..		     * tpmark cleared... for nbuf io we can't get here		     * and the only way to clear it is with MTCSE ioctl.		     * see mtio(4). Now there are side effects to this		     * that mimicks the tmscp class driver.. on a tmscp		     * class device if a control operation/write operation		     * issused to the device the tpmark indicator is cleared		     * and the operation is declared a success so if we		     * clear DEV_TPMARK here we are golden...Give the man		     * a beer.		    */		    sc->sc_category_flags[targid] &= ~DEV_TPMARK;		    		    /* 		     * clear out the short record indicator left over		     * from last operation...........		     * This is done for reads/writes control and		     * nbuf i/o. Reasoning is that we report the short 		     * record status for the previous command. It		     * it is up to the programmer to get status if they		     * want it. If not any new operation must start		     * with a clean slate so clear short rec indicator.		    */		    sc->sc_category_flags[targid] &= ~DEV_SHRTREC;		    /* log progress */		    sc->sc_progress = time;		  /* Check to see what path is required for this command. */		    if((bp == &cszbuf[unit]) ||			((sc->sc_bbr_active[targid] == 1) &&			(sc->sc_bbr_oper[targid] == SZ_SP_START)))		    {			/* 			 * execute control operation with the specified count			 */			if (bp->b_comand == SZ_REWIND) {			    sc->sc_flags[targid] &= ~DEV_EOM;			}			else {			}	    	    	sc->sc_xstate[targid] = SZ_SP_START;			sc->sc_xevent[targid] = SZ_CONT;	    	    	break;		    }		    /*		     * If it's not a control operation, it must be		     * data.		     */		    sc->sc_xstate[targid] = SZ_RW_START;		    sc->sc_xevent[targid] = SZ_CONT;		    break;		default:			;	    }	    break;	/*	 * Start a non data transfer command.	 */	case SZ_SP_START:	    /* remember where we are in case target returns busy status */	    sc->sc_pxstate[targid] = SZ_SP_START;	    /*	     * Forgive the gotos, but.....	     * The SELWAIT? flags tell us we must restart processing	     * at the point where we call scsistart, because either	     * a select timed out or completed during the timeout.	     */	    if (sc->sc_xevent[targid] == SZ_SELWAIT1)		goto sz_sp_s1;	    if (sc->sc_xevent[targid] == SZ_SELWAIT2)		goto sz_sp_s2;	    /*	     * Clear DEV_WRITTEN flag only for commands	     * which would actually change tape position	     * from the last (possible) write.	     * TODO: deal with SZ_ERASE, SZ_UNLOAD, SZ_VFY	     */	    if (sc->sc_devtyp[targid] & SZ_TAPE) {		switch (bp->b_comand) {		case SZ_REWIND:		case SZ_WFM:		case SZ_P_BSPACEF:		case SZ_P_FSPACEF:		case SZ_P_BSPACER:		case SZ_P_FSPACER:		    sc->sc_flags[targid] &= ~DEV_WRITTEN;		default:		    break;		}	    }	    /*	     * The write to b_resid has to follow the	     * read of b_command. This is because both	     * b_command and b_resid are the same field	     * (overloaded).  The write to b_resid destroys	     * the data in b_command.  This is a black	     * hole waiting to be fallen into!	     *	     * NOTE:	     *	     * We fell into the black hole described above!	     * This code can be executed more than once for	     * a command. This happens if the command has to	     * be restarted after waiting for the bus to free up.	     * To avoid the black hole, the read of b_command	     * is only done the first time thru this code path.	     *	     * NOTE:	     *	     * The above bug is fixed. The command is now called	     * b_comand and is stored in the b_gid buffer field.	     */	    if (sc->sc_selstat[targid] != SZ_BBWAIT) {		sc->sc_bp[targid] = bp;	    }	    sc->sc_curcmd[targid] = bp->b_comand;	    dp->b_active = 1;	    sc->sc_lastid = targid;	    bp->b_resid = 0;	    sc->sc_resid[targid] = 0;	/* makes debug output look cleaner */	    sc->sc_c_status[targid] = SZ_GOOD;	    /* TODO: debug - check for left over bits in szflags */	    sz_sp_szflags = sc->sc_szflags[targid];	    if (sz_szf_print && (sc->sc_szflags[targid] != SZ_NORMAL))		printf("SP_START: szflags = %X\n", sc->sc_szflags[targid]);	    /* TODO: end of debug */	    sc->sc_szflags[targid] = SZ_NORMAL;	    sz_bldpkt(sc, targid, sc->sc_curcmd[targid], 0, bp->b_bcount);sz_sp_s1:				/* restart due to select timeout */	    bp = sc->sc_bp[targid];	/* restore buffer pointer */	    if(sc->sc_rzspecial[targid]) {		struct mode_sel_sns_params *msp;			msp = (struct mode_sel_sns_params *)sc->sc_rzparams[targid];		stv = sc->sc_rambuff + sc->sc_dboff[targid];		if(sc->sc_actcmd[targid] == SZ_MODSNS)		 

⌨️ 快捷键说明

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