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

📄 tpqic02.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 5 页
字号:
#endif			status_eom_detected = status_eof_detected = NO;			return stat;		case MTWEOF:			tpqputs("MTWEOF write eof mark");			/* Plain GNU mt(1) 2.2 uses read-only mode for writing FM. :-( */			if (mode_access==READ)				return -EACCES;			/* allow tape movement after writing FM */			status_bytes_rd = status_bytes_wr;	/* Kludge-O-Matic */			status_bytes_wr = NO;			return do_qic_cmd(QCMD_WRT_FM, TIM_M);			/* not sure what to do with status_bytes when WFM should fail */		case MTREW:			tpqputs("MTREW rewinding tape");			if ((mode_access==WRITE) && status_bytes_wr)				return -EACCES;			status_eom_detected = status_eof_detected = NO;			return do_qic_cmd(QCMD_REWIND, TIM_R);		case MTOFFL:			tpqputs("MTOFFL rewinding & going offline"); /*---*/			/******* What exactly are we supposed to do, to take it offline????			 *****/			/* Doing a drive select will clear (unlock) the current drive.			 * But that requires support for multiple drives and locking.			 */			if ((mode_access==WRITE) && status_bytes_wr)				return -EACCES;			status_eom_detected = status_eof_detected = NO;			/**** do rewind depending on minor bits??? ***/			stat = do_qic_cmd(QCMD_REWIND, TIM_R);			return stat;		case MTNOP:			tpqputs("MTNOP setting status only");			/********** should do `read position' for drives that support it **********/			return (tp_sense(-1)==TE_OK)? 0 : -EIO;	/**** check return codes ****/		case MTRETEN:			tpqputs("MTRETEN retension tape");			if ((mode_access==WRITE) && status_bytes_wr)				return -EACCES;			status_eom_detected = status_eof_detected = NO;			return do_qic_cmd(QCMD_RETEN, TIM_R);		case MTBSFM:			/* Think think is like MTBSF, except that			 * we shouldn't skip the FM. Tricky.			 * Maybe use RD_FM_BCK, then do a SPACE_FWD?			 */			tpqputs("MTBSFM not supported");			if ((mode_access==WRITE) && status_bytes_wr)				return -EACCES;			return -ENXIO;		case MTFSFM:			/* I think this is like MTFSF, except that			 * we shouldn't skip the FM. Tricky.			 * Maybe use QCMD_RD_DATA until we get a TP_FIL exception?			 * But then the FM will have been skipped...			 * Maybe use RD_FM, then RD_FM_BCK, but not all			 * drives will support that!			 */			tpqputs("MTFSFM not supported");			if ((mode_access==WRITE) && status_bytes_wr)				return -EACCES;			return -ENXIO;		case MTEOM:			/* This should leave the tape ready for appending			 * another file to the end, such that it would append			 * after the last FM on tape.			 */			tpqputs("MTEOM search for End Of recorded Media");			if ((mode_access==WRITE) && status_bytes_wr)				return -EACCES;#ifdef TP_HAVE_EOD			/* Use faster seeking when possible.			 * This requires the absence of data beyond the EOM.			 */# if TAPE_QIC02_DRIVE == MT_ISWT5150			/* It seems that my drive does not always perform the			 * SEEK_EOD correctly, unless it is preceded by a			 * rewind command.			 */# if 0			status_eom_detected = status_eof_detected = NO;# endif			stat = do_qic_cmd(QCMD_REWIND, TIM_R);			if (stat)				return stat;			# endif			stat = do_qic_cmd(QCMD_SEEK_EOD, TIM_F);			/* After a successful seek, TP_EOR should be returned */#else			/* else just seek until the drive returns exception "No Data" */			stat = 0;			while ((stat==0) && (!status_eom_detected)) {				stat = do_qic_cmd(QCMD_RD_FM, TIM_F); /***** should use MTFSFM here???? ******/			}			if (tperror.exs & TP_NDT)				return 0;#endif			return stat;		case MTERASE:			tpqputs("MTERASE -- ERASE TAPE !");			if  ((tperror.exs & TP_ST0) && (tperror.exs & TP_WRP)) {				tpqputs("Cartridge is write-protected.");				return -EACCES;			} else {				time_t t = jiffies;				/* give user a few seconds to pull out tape */				while (jiffies - t < 3*HZ)					schedule();			}			/* Plain GNU mt(1) 2.2 erases a tape in O_RDONLY. :-( */			if (mode_access==READ) 				return -EACCES;			/* don't bother writing filemark */			status_eom_detected = status_eof_detected = NO;			return do_qic_cmd(QCMD_ERASE, TIM_R);		case MTRAS1:#ifdef TP_HAVE_RAS1			tpqputs("MTRAS1: non-destructive self test");			stat = do_qic_cmd(QCMD_SELF_TST1, TIM_R);			if (stat != 0) {				tpqputs("RAS1 failed");				return stat;			}			return (tp_sense(0)==TE_OK)? 0 : -EIO; /* get_ext_status3(); */#else			tpqputs("RAS1 not supported");			return -ENXIO;#endif		case MTRAS2:#ifdef TP_HAVE_RAS2			tpqputs("MTRAS2: destructive self test");			stat = do_qic_cmd(QCMD_SELF_TST2, TIM_R);			if (stat != 0) {				tpqputs("RAS2 failed");				return stat;			}			return (tp_sense(0)==TE_OK)? 0 : -EIO; /* get_ext_status3(); */#else			tpqputs("RAS2 not supported");			return -ENXIO;#endif#ifdef TP_HAVE_SEEK		case MTSEEK:			tpqputs("MTSEEK seeking block");			if ((mode_access==WRITE) && status_bytes_wr)				return -EACCES;			/* NOTE: address (24 bits) is in seek_addr_buf[] */			return do_qic_cmd(QCMDV_SEEK_BLK, TIM_F);#endif		default:			return -ENOTTY;	}} /* do_ioctl_cmd *//* dma_transfer(): This routine is called for every 512 bytes to be read * from/written to the tape controller. Speed is important here! * (There must be enough time left for the hd controller!) * When other devices use DMA they must ensure they use un-interruptible * double byte accesses to the DMA controller. Floppy.c is ok. * Must have interrupts disabled when this function is invoked, * otherwise, the double-byte transfers to the DMA controller will not * be atomic. That could lead to nasty problems when they are interrupted * by other DMA interrupt-routines. * * This routine merely does the least possible to keep * the transfers going: *	- set the DMA count register for the next 512 bytes *	- adjust the DMA address and page registers *	- adjust the timeout *	- tell the tape controller to start transferring * We assume the dma address and mode are, and remain, valid. */ static inline void dma_transfer(void){#if TAPE_QIC02_IFC == WANGTEK	outb_p(WT_CTL_ONLINE, QIC_CTL_PORT);	/* back to normal */#elif TAPE_QIC02_IFC == ARCHIVE	outb_p(0, AR_RESET_DMA_PORT);#endif	clear_dma_ff(TAPE_QIC02_DMA);	set_dma_mode(TAPE_QIC02_DMA, dma_mode);	set_dma_addr(TAPE_QIC02_DMA, buffaddr+dma_bytes_done);	/* full address */	set_dma_count(TAPE_QIC02_DMA, TAPE_BLKSIZE);	/* start tape DMA controller */#if TAPE_QIC02_IFC == WANGTEK	outb_p(WT_CTL_DMA | WT_CTL_ONLINE, QIC_CTL_PORT); /* trigger DMA transfer */#elif TAPE_QIC02_IFC == ARCHIVE	outb_p(AR_CTL_IEN | AR_CTL_DNIEN, QIC_CTL_PORT);  /* enable interrupts again */	outb_p(0, AR_START_DMA_PORT);			  /* start DMA transfer */	/* In dma_end() AR_RESET_DMA_PORT is written too. */#endif	/* start computer DMA controller */	enable_dma(TAPE_QIC02_DMA);	/* block transfer should start now, jumping to the 	 * interrupt routine when done or an exception was detected.	 */} /* dma_transfer *//* start_dma() sets a DMA transfer up between the tape controller and * the kernel tape_qic02_buf buffer. * Normally bytes_todo==dma_bytes_done at the end of a DMA transfer. If not, * a filemark was read, or an attempt to write beyond the End Of Tape  * was made. [Or some other bad thing happened.] * Must do a sense() before returning error. */static int start_dma(short mode, unsigned long bytes_todo)/* assume 'bytes_todo'>0 */{	int stat;		TPQPUTS("start_dma() enter");	TPQDEB({printk(TPQIC_NAME ": doing_read==%d, doing_write==%d\n", doing_read, doing_write);})	dma_bytes_done = 0;	dma_bytes_todo = bytes_todo;	status_error = NO;	/* dma_mode!=0 indicates that the dma controller is in use */	dma_mode = (mode == WRITE)? DMA_MODE_WRITE : DMA_MODE_READ;		/* Only give READ/WRITE DATA command to tape drive if we haven't	 * done that already. Otherwise the drive will rewind to the beginning	 * of the current file on tape. Any QIC command given other than	 * R/W FM will break the read/write transfer cycle.	 * do_qic_cmd() will terminate doing_{read,write}	 */	if ((doing_read == NO) && (doing_write == NO)) {		/* First, we have to clear the status -- maybe remove TP_FIL???		 */#if 0		/* Next dummy get status is to make sure CNI is valid,                   since we're only just starting a read/write it doesn't                   matter some exceptions are cleared by reading the status;                   we're only interested in CNI and WRP. -Eddy */		get_status((char *) &tperror);#else		/* TP_CNI should now be handled in open(). -Hennus */#endif		stat = tp_sense(((mode == WRITE)? 0 : TP_WRP) | TP_BOM | TP_FIL);		if (stat != TE_OK)			return stat;#if OBSOLETE		/************* not needed iff rd_status() would wait for ready!!!!!! **********/		if (wait_for_ready(TIM_S) != TE_OK) {	/*** not sure this is needed ***/			tpqputs("wait_for_ready failed in start_dma");			return -EIO;		}#endif		/* Tell the controller the data direction */		/* r/w, timeout medium, check exceptions, sets status_cmd_pending. */		stat = send_qic02_cmd((mode == WRITE)? QCMD_WRT_DATA : QCMD_RD_DATA, TIM_M, 0);		if (stat!=TE_OK) {			printk(TPQIC_NAME ": start_dma: init %s failed\n",				(mode == WRITE)? "write" : "read");			(void) tp_sense(0);			return stat;		}		/* Do this last, because sense() will clear the doing_{read,write}		 * flags, causing trouble next time around.		 */		if (wait_for_ready(TIM_M) != TE_OK)			return -EIO;		switch (mode) {			case READ:				doing_read = YES;				break;			case WRITE:				doing_write = YES;				break;			default:				printk(TPQIC_NAME ": requested unknown mode %d\n", mode);				panic(TPQIC_NAME ": invalid mode in start_dma()");		}	} else if (is_exception()) {		/* This is for Archive drives, to handle reads with 0 bytes		 * left for the last read request.		 *		 * ******** this also affects EOF/EOT handling! ************		 */		tpqputs("detected exception in start_dma() while transfer in progress");		status_error = YES;		return TE_END;	}	status_expect_int = YES;	/* This assumes tape is already positioned, but these	 * semi-'intelligent' drives are unpredictable...	 */	TIMERON(TIM_M*2);	/* initiate first data block read from/write to the tape controller */	cli();	dma_transfer();	sti();	TPQPUTS("start_dma() end");	return TE_OK;} /* start_dma *//* This cleans up after the dma transfer has completed * (or failed). If an exception occurred, a sense() * must be done. If the exception was caused by a FM, * sense() will set `status_eof_detected' and * `status_eom_detected', as required. */static void end_dma(unsigned long * bytes_done){	int stat = TE_OK;	TIMEROFF;	TPQPUTS("end_dma() enter");	disable_dma(TAPE_QIC02_DMA);	clear_dma_ff(TAPE_QIC02_DMA);#if TAPE_QIC02_IFC == WANGTEK	outb_p(WT_CTL_ONLINE, QIC_CTL_PORT);	/* back to normal */#elif TAPE_QIC02_IFC == ARCHIVE	outb_p(0, AR_RESET_DMA_PORT);#endif	stat = wait_for_ready(TIM_M);	if (status_error || (stat!=TE_OK)) {		tpqputs("DMA transfer exception");		stat = tp_sense((dma_mode==READ)? TP_WRP : 0);		/* no return here -- got to clean up first! */	}	/* take the tape controller offline */	/* finish off DMA stuff */	dma_mode = 0;	/* Note: The drive is left on-line, ready for the next	 * data transfer.	 * If the next command to the drive does not continue	 * the pending cycle, it must do 2 sense()s first.	 */	*bytes_done = dma_bytes_done;	status_expect_int = NO;	ioctl_status.mt_blkno += (dma_bytes_done / TAPE_BLKSIZE);	TPQPUTS("end_dma() exit");	/*** could return stat here ***/} /* end_dma *//*********** Below are the (public) OS-interface procedures ***********//* tape_qic02_times_out() is called when a DMA transfer doesn't complete * quickly enough. Usually this means there is something seriously wrong * with the hardware/software, but it could just be that the controller * has decided to do a long rewind, just when I didn't expect it. * Just try again. */static void tape_qic02_times_out(void){	printk("time-out in %s driver\n", TPQIC_NAME);	if ((status_cmd_pending>0) || dma_mode) {		/* takes tooo long, shut it down */		status_dead = YES;		status_cmd_pending = 0;		status_timer_on = NO;		status_expect_int = NO;		status_error = YES;		if (dma_mode) {			dma_mode = 0;	/* signal end to read/write routine */			wake_up(&tape_qic02_transfer);		}	}} /* tape_qic02_times_out *//* * Interrupt handling: * * 1) Interrupt is generated iff at the end of  *    a 512-DMA-block transfer. * 2) EXCEPTION is not raised unless something  *    is wrong or EOT/FM is detected. * 3) FM EXCEPTION is set *after* the last byte has

⌨️ 快捷键说明

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