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

📄 tpqic02.c

📁 LINUX 1.0 内核c源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
				return -EACCES;
			return do_qic_cmd(QCMD_RD_FM, TIM_F);

		case MTBSF:
#ifdef TP_HAVE_BSF
			tpqputs("MTBSF backward searching filemark -- optional command");
			if ((mode_access==WRITE) && status_bytes_wr)
				return -EACCES;
			stat = do_qic_cmd(QCMD_RD_FM_BCK, TIM_F);
#else
			tpqputs("MTBSF not supported");
			stat = -ENXIO;
#endif
			status_eom_detected = status_eof_detected = NO;
			return stat;

		case MTFSR:
#ifdef TP_HAVE_FSR	/* This is an optional QIC-02 command */
			tpqputs("MTFSR forward space record");
			if ((mode_access==WRITE) && status_bytes_wr)
				return -EACCES;
			stat = do_qic_cmd(QCMD_SPACE_FWD, TIM_F);
#else
			/**** fake it by doing a read data block command? ******/
			tpqputs("MTFSR not supported");
			stat = -ENXIO;
#endif
			return stat;

		case MTBSR:
#ifdef TP_HAVE_BSR	/* This is an optional QIC-02 command */
			/* we need this for appending files with GNU tar!! */
			tpqputs("MTFSR backward space record");
			if ((mode_access==WRITE) && status_bytes_wr)
				return -EACCES;
			stat = do_qic_cmd(QCMD_SPACE_BCK, TIM_F);
#else
			tpqputs("MTBSR not supported");
			stat = -ENXIO;
#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 */

⌨️ 快捷键说明

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