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

📄 tmscp.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 4 页
字号:
			}		tmscpaddr->tmscpsa = ((int)&sc->sc_tmscp->tmscp_ca.ca_ringbase)			| ((cpu == VAX_780 || cpu == VAX_8600) ? TMSCP_PI : 0);		sc->sc_state = S_STEP2;		return;	/* Controller was in step 2 last, see if its gone to step 3 */	case S_STEP2:#		define STEP2MASK 0174377#		define STEP2GOOD (TMSCP_STEP3|TMSCP_IE|(sc->sc_ivec/4))		for (i = 0; i < 150; i++)			{			if ((tmscpaddr->tmscpsa&STEP2MASK) != STEP2GOOD)				{ /* still in step 2 (wait 1/100 sec) */				DELAY(10000);#				ifdef DEBUG				printd("still in step 2, delaying\n");#				endif DEBUG				}			else				break;			}		if (i > 149)			{			sc->sc_state = S_IDLE;			printf("failed to initialize, in step2: sa 0x%x", tmscpaddr->tmscpsa);			wakeup((caddr_t)um);			return;			}		tmscpaddr->tmscpsa = ((int)&sc->sc_tmscp->tmscp_ca.ca_ringbase)>>16;		sc->sc_state = S_STEP3;		return;	/* Controller was in step 3 last, see if its gone to step 4 */	case S_STEP3:#		define STEP3MASK 0174000#		define STEP3GOOD TMSCP_STEP4		for (i = 0; i < 150; i++)			{			if ((tmscpaddr->tmscpsa&STEP3MASK) != STEP3GOOD)				{ /* still in step 3 (wait 1/100 sec) */				DELAY(10000);#				ifdef DEBUG				printd("still in step 3, delaying\n");#				endif DEBUG				}			else				break;			}		if (i > 149)			{			sc->sc_state = S_IDLE;			printf("failed to initialize, in step3: sa 0x%x", tmscpaddr->tmscpsa);			wakeup((caddr_t)um);			return;			}		/*		 * Get microcode version and model number of controller;		 * Signal initialization complete (_GO) (to the controller);		 *    ask for Last Fail response if tmscperror is set;		 * Set state to "set controller characteristics".		 */		tmscpmicro[d] = tmscpaddr->tmscpsa;		tmscpaddr->tmscpsa = TMSCP_GO | (tmscperror? TMSCP_LF : 0);		sc->sc_state = S_SCHAR;#		ifdef DEBUG		printd("tmscpintr: completed state %d \n", sc->sc_state);		printd("tmscp%d Version %d model %d\n",d,tmscpmicro[d]&0xF,			(tmscpmicro[d]>>4) & 0xF);#		endif	    /*	     * Initialize the data structures (response and command queues).	     */	    ttm = sc->sc_tmscp;	    for (i = 0; i < NRSP; i++)		    {		    tm->tmscp_ca.ca_rspdsc[i] = TMSCP_OWN | TMSCP_INT | 			   (long)&ttm->tmscp_rsp[i].mscp_cmdref;		    tm->tmscp_rsp[i].mscp_dscptr = &tm->tmscp_ca.ca_rspdsc[i];		    tm->tmscp_rsp[i].mscp_header.tmscp_msglen = mscp_msglen;		    }	    for (i = 0; i < NCMD; i++)		    {		    tm->tmscp_ca.ca_cmddsc[i] = TMSCP_INT | 					(long)&ttm->tmscp_cmd[i].mscp_cmdref;		    tm->tmscp_cmd[i].mscp_dscptr = &tm->tmscp_ca.ca_cmddsc[i];		    tm->tmscp_cmd[i].mscp_header.tmscp_msglen = mscp_msglen;		    tm->tmscp_cmd[i].mscp_header.tmscp_vcid = 1;		    }	    bp = &tmscpwtab[d];	    bp->av_forw = bp->av_back = bp;	    sc->sc_lastcmd = 1;	    sc->sc_lastrsp = 0;	    mp = &tmscp[um->um_ctlr].tmscp_cmd[0];	    mp->mscp_unit = mp->mscp_modifier = 0;	    mp->mscp_flags = 0;	    mp->mscp_version = 0;	    mp->mscp_cntflgs = M_CF_ATTN|M_CF_MISC|M_CF_THIS;	    /*	     * A host time out value of 0 means that the controller will not	     * time out.  This is ok for the TK50.	     */	    mp->mscp_hsttmo = 0;	    mp->mscp_time.val[0] = 0;	    mp->mscp_time.val[1] = 0;	    mp->mscp_cntdep = 0;	    mp->mscp_opcode = M_OP_STCON;	    *((long *)mp->mscp_dscptr) |= TMSCP_OWN|TMSCP_INT;	    i = tmscpaddr->tmscpip;      /* initiate polling */	    return;	case S_SCHAR:	case S_RUN:		break;	default:	    printf("tmscp%d: interrupt in unknown state %d ignored\n",d,sc->sc_state);	    return;	}	/* end switch */	/*	 * The controller state is S_SCHAR or S_RUN	 */	/*	 * If the error bit is set in the SA register then print an error	 * message and reinitialize the controller.	 */	if (tmscpaddr->tmscpsa&TMSCP_ERR)		{		printf("tmscp%d: fatal error (%o)\n", d, tmscpaddr->tmscpsa&0xffff);		tmscpaddr->tmscpip = 0;		wakeup((caddr_t)um);		}	/*	 * Check for a buffer purge request. (Won't happen w/ TK50 on Q22 bus)	 */	if (tm->tmscp_ca.ca_bdp)		{		UBAPURGE(um->um_hd->uh_uba, tm->tmscp_ca.ca_bdp);		tm->tmscp_ca.ca_bdp = 0;		tmscpaddr->tmscpsa = 0;      /* signal purge complete */		}	/*	 * Check for response ring transition.	 */	if (tm->tmscp_ca.ca_rspint)		{		tm->tmscp_ca.ca_rspint = 0;		for (i = sc->sc_lastrsp;; i++)			{			i %= NRSP;			if (tm->tmscp_ca.ca_rspdsc[i]&TMSCP_OWN)			    break;			tmscprsp(um, tm, sc, i);			tm->tmscp_ca.ca_rspdsc[i] |= TMSCP_OWN;			}		sc->sc_lastrsp = i;		}	/*	 * Check for command ring transition.	 */	if (tm->tmscp_ca.ca_cmdint)		{#		ifdef DEBUG		printd("tmscpintr: command ring transition\n");#		endif				tm->tmscp_ca.ca_cmdint = 0;		}    	if(tmscp_cp_wait)		wakeup((caddr_t)&tmscp_cp_wait);    	(void) tmscpstart(um);}/* * Open a tmscp device and set the unit online.  If the controller is not  * in the run state, call init to initialize the tmscp controller first. *//* ARGSUSED */tmscpopen(dev, flag)	dev_t dev;	int flag;{	register int unit;	register struct uba_device *ui;	register struct tmscp_softc *sc;	register struct tms_info *tms;	register struct mscp *mp;	register struct uba_ctlr *um;	struct tmscpdevice *tmscpaddr;	int s,i;		unit = TMSUNIT(dev);#	ifdef DEBUG	printd("tmscpopen unit %d\n",unit);	if(tmscpdebug)DELAY(10000);#	endif	if (unit >= NTMS || (ui = tmsdinfo[unit]) == 0 || ui->ui_alive == 0)		return (ENXIO);	tms = &tms_info[ui->ui_unit];	if (tms->tms_openf)		return (EBUSY);	sc = &tmscp_softc[ui->ui_ctlr];	tms->tms_openf = 1;	tms->tms_tpr = tprintf_open();	s = spl5();	if (sc->sc_state != S_RUN)		{		if (sc->sc_state == S_IDLE)			if(!tmscpinit(ui->ui_ctlr))				{				printf("tmscp controller failed to init\n");				(void) splx(s);				tms->tms_openf = 0;				return(ENXIO);				}		/* 		 * Wait for initialization to complete		 */		timeout(wakeup,(caddr_t)ui->ui_mi,11*hz);	/* to be sure*/		sleep((caddr_t)ui->ui_mi, 0);		if (sc->sc_state != S_RUN)			{			(void) splx(s);			tms->tms_openf = 0;			return (EIO);			}		}	/*	 * Check to see if the device is really there.	 * this code was taken from Fred Canters 11 driver	 */	um = ui->ui_mi;	tmscpaddr = (struct tmscpdevice *) um->um_addr;	(void) splx(s);	if(ui->ui_flags == 0)		{		s = spl5();		while(0 ==(mp = tmscpgetcp(um)))			{			tmscp_cp_wait++;			sleep((caddr_t)&tmscp_cp_wait,PSWP+1);			tmscp_cp_wait--;			}		(void) splx(s);		mp->mscp_opcode = M_OP_ONLIN;		mp->mscp_unit = ui->ui_slave;		mp->mscp_cmdref = (long) & tms->tms_type;					    /* need to sleep on something */#		ifdef DEBUG		printd("tmscpopen: bring unit %d online\n",ui->ui_unit);#		endif			*((long *) mp->mscp_dscptr ) |= TMSCP_OWN | TMSCP_INT;		i = tmscpaddr->tmscpip;#ifdef lint		i = i;#endif		/* 		 * To make sure we wake up, timeout in 240 seconds.		 * Wakeup in tmscprsp routine.		 * 240 seconds (4 minutes) is necessary since a rewind		 * can take a few minutes.		 */		timeout(wakeup,(caddr_t) mp->mscp_cmdref,240 * hz);		sleep((caddr_t) mp->mscp_cmdref,PSWP+1);		}	if(ui->ui_flags == 0) {		tms->tms_openf = 0;		return(ENXIO);  /* Didn't go online */	}	tms->tms_lastiow = 0;	/*	 * If the high density device is not specified, set unit to low	 * density.  This is done as an "internal" ioctl command so	 * that the command setup and response handling	 * is done thru "regular" command routines.	 */	if ((minor(dev) & T_HIDENSITY) == 0)		tmscpcommand(dev, TMS_LOWDENSITY, 1);	else		tmscpcommand(dev, TMS_HIDENSITY, 1);	return (0);}/* * Close tape device. * * If tape was open for writing or last operation was * a write, then write two EOF's and backspace over the last one. * Unless this is a non-rewinding special file, rewind the tape. * * NOTE: *	We want to be sure that any serious exception is cleared on the *	close. A Clear Serious Exception (CSE) modifier is always done on *	the rewind command.  For the non-rewind case we check to see if the *	"serex" field is set in the softc struct; if it is then issue a noop *	command with the CSE modifier. * Make the tape available to others, by clearing openf flag. */tmscpclose(dev, flag)	register dev_t dev;	register flag;{	register struct tms_info *tms;	register struct uba_device *ui;	ui = tmsdinfo[TMSUNIT(dev)];#	ifdef DEBUG	printd("tmscpclose: ctlr =  %d\n",TMSCPCTLR(dev));	printd("tmscpclose: unit = %d\n",TMSUNIT(dev));	if(tmscpdebug)DELAY(10000);#	endif	tms = &tms_info[ui->ui_unit];	if (flag == FWRITE || (flag&FWRITE) && tms->tms_lastiow)		{		/*	   device, command, count */		tmscpcommand (dev, TMS_WRITM, 1);		tmscpcommand (dev, TMS_WRITM, 1);		tmscpcommand (dev, TMS_BSR, 1);		}	if ((minor(dev)&T_NOREWIND) == 0)		/*		 * Don't hang waiting for rewind complete.		 */		tmscpcommand(dev, TMS_REW, 0);	else		if (tms->tms_serex)			{#			ifdef DEBUG			printd("tmscpclose: clearing serex\n");			if(tmscpdebug)DELAY(10000);#			endif			tmscpcommand(dev, TMS_CSE, 1);			}	tprintf_close(tms->tms_tpr);	tms->tms_openf = 0;	return (0);}/* * Execute a command on the tape drive a specified number of times. * This routine sets up a buffer and calls the strategy routine which * links the buffer onto the drive's buffer queue. * The start routine will take care of creating a tmscp command packet * with the command.  The start routine is called by the strategy or the * interrupt routine. */tmscpcommand (dev, com, count)	register dev_t dev;	int com, count;{	register struct uba_device *ui;	register struct buf *bp;	register int s;	int unit = TMSUNIT(dev);	ui = tmsdinfo[unit];	bp = &ctmscpbuf[ui->ui_ctlr];	s = spl5();	while (bp->b_flags&B_BUSY)		{		/*		 * This special check is because B_BUSY never		 * gets cleared in the non-waiting rewind case.		 */		if (bp->b_bcount == 0 && (bp->b_flags&B_DONE))			break;		bp->b_flags |= B_WANTED;		sleep((caddr_t)bp, PRIBIO);		}	bp->b_flags = B_BUSY|B_READ;	splx(s);	/*	 * Load the buffer.  The b_count field gets used to hold the command	 * count.  the b_resid field gets used to hold the command mneumonic.	 * These 2 fields are "known" to be "safe" to use for this purpose.	 * (Most other drivers also use these fields in this way.)	 */	bp->b_dev = dev;	bp->b_bcount = count;	bp->b_resid = com;	bp->b_blkno = 0;	tmscpstrategy(bp);	/*	 * In case of rewind from close, don't wait.	 * This is the only case where count can be 0.	 */	if (count == 0)		return;	iowait(bp);	if (bp->b_flags&B_WANTED)		wakeup((caddr_t)bp);	bp->b_flags &= B_ERROR;}/* * Find an unused command packet */struct mscp *tmscpgetcp(um)	struct uba_ctlr *um;{	register struct mscp *mp;	register struct tmscpca *cp;	register struct tmscp_softc *sc;	register int i;	int	s;	s = spl5();	cp = &tmscp[um->um_ctlr].tmscp_ca;	sc = &tmscp_softc[um->um_ctlr];	/*	 * If no credits, can't issue any commands	 * until some outstanding commands complete.	 */	i = sc->sc_lastcmd;#  	ifdef DEBUG	printd10("tmscpgetcp: %d credits remain\n", sc->sc_credits);#	endif	if(((cp->ca_cmddsc[i]&(TMSCP_OWN|TMSCP_INT))==TMSCP_INT) &&	  (sc->sc_credits >= 2))		{		sc->sc_credits--;       /* This commits to issuing a command */		cp->ca_cmddsc[i] &= ~TMSCP_INT;		mp = &tmscp[um->um_ctlr].tmscp_cmd[i];		mp->mscp_unit = mp->mscp_modifier = 0;		mp->mscp_opcode = mp->mscp_flags = 0;		mp->mscp_bytecnt = mp->mscp_buffer = 0;		sc->sc_lastcmd = (i + 1) % NCMD;		(void) splx(s);		return(mp);		}	(void) splx(s);	return(NULL);}/* * Initialize a TMSCP device.  Set up UBA mapping registers, * initialize data structures, and start hardware * initialization sequence. */tmscpinit (d)	int d;			/* index to the controller */{	register struct tmscp_softc *sc;	register struct tmscp *t;  /* communications area; cmd & resp packets */	struct tmscpdevice *tmscpaddr;	struct uba_ctlr *um;	sc = &tmscp_softc[d];	um = tmscpminfo[d];	um->um_tab.b_active++;	t = &tmscp[d];	tmscpaddr = (struct tmscpdevice *)um->um_addr;	if (sc->sc_mapped == 0)		{		/*		 * Map the communications area and command		 * and response packets into Unibus address		 * space.		 */		sc->sc_ubainfo = uballoc(um->um_ubanum, (caddr_t)t, sizeof (struct tmscp), 0);		sc->sc_tmscp = (struct tmscp *)(UBAI_ADDR(sc->sc_ubainfo));		sc->sc_mapped = 1;		}	/*	 * Start the hardware initialization sequence.	 */	tmscpaddr->tmscpip = 0;              /* start initialization */	while((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0)		{#		ifdef DEBUG		printd("tmscpinit: tmscpsa = 0%o\n",tmscpaddr->tmscpsa);		DELAY(100000);#		endif		if(tmscpaddr->tmscpsa & TMSCP_ERR)			return(0);	/* CHECK */		}	tmscpaddr->tmscpsa=TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8)|TMSCP_IE|(sc->sc_ivec/4);	/*	 * Initialization continues in the interrupt routine.	 */	sc->sc_state = S_STEP1;	sc->sc_credits = 0;	return(1);}/* * Start I/O operation * This code is convoluted.  The majority of it was copied from the uda driver. */tmscpstart(um)	register struct uba_ctlr *um;{	register struct buf *bp, *dp;	register struct mscp *mp;	register struct tmscp_softc *sc;	register struct tms_info *tms;	register struct uba_device *ui;	struct   tmscpdevice *tmscpaddr;	struct   tmscp *tm = &tmscp[um->um_ctlr];	int i,tempi;	char ioctl;		/* flag: set true if its an IOCTL command */	sc = &tmscp_softc[um->um_ctlr];	    for(;;)	{	if ((dp = um->um_tab.b_actf) == NULL)		{		/*		 * Release unneeded UBA resources and return		 * (drive was inactive)		 */		um->um_tab.b_active = 0;		break;		}	if ((bp = dp->b_actf) == NULL)		{		/*

⌨️ 快捷键说明

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