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

📄 tpqic02.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
			status_eom_detected = YES;			/* I don't know whether drive always reports EOF at or before EOM. */			status_eof_detected = YES;		}		/** if (err & TP_UDA) "Unrecoverable data error" **/		/** if (err & TP_BNL) "Bad block not located" **/		if (err & TP_FIL) {			gs |= GMT_EOF(-1);			status_eof_detected = YES;		}	}	if (err & TP_ST1) {		/** if (err & TP_ILL) "Illegal command" **/		/** if (err & TP_NDT) "No data detected" **/		/** if (err & TP_MBD) "Marginal block detected" **/		if (err & TP_BOM)			gs |= GMT_BOT(-1);	/* beginning of tape */	}	ioctl_status.mt_gstat = gs;	ioctl_status.mt_dsreg = tperror.exs;	/* "drive status" */	ioctl_status.mt_erreg = tperror.dec;	/* "sense key error" */	if (err & (TP_ST0|TP_ST1)) {		/* My Wangtek occasionally reports `status' 1212 which should be ignored. */		exnr = decode_qic_exception_nr(err);		handle_qic_exception(exnr, err);		/* update driver state wrt drive status */		report_qic_exception(exnr);	}	err &= ~ignore;		/* mask unwanted errors -- not the correct way, use exception nrs?? */	if (((err & TP_ST0) && (err & REPORT_ERR0)) ||	    ((err & TP_ST1) && (err & REPORT_ERR1)))		return TE_ERR;	return TE_OK;} /* tp_sense *//* Wait for a wind or rewind operation to finish or * to time-out. (May take very long). */static int wait_for_rewind(time_t timeout){	int stat;	stat = inb(QIC02_STAT_PORT) & QIC02_STAT_MASK;	if (TPQDBG(REWIND))		printk(TPQIC02_NAME ": Waiting for (re-)wind to finish: stat=0x%x\n", stat);	stat = wait_for_ready(timeout);	if (stat != TE_OK) {			tpqputs(TPQD_ALWAYS, "(re-) winding failed\n");	}	return stat;} /* wait_for_rewind *//* Perform a full QIC02 command, and wait for completion, * check status when done. Complain about exceptions. * * This function should return an OS error code when * something goes wrong, 0 otherwise. */static int ll_do_qic_cmd(int cmd, time_t timeout){	int stat;	if (status_dead == YES) {		tpqputs(TPQD_ALWAYS, "Drive is dead. Do a `mt reset`.");		return -ENXIO;			/* User should do an MTRESET. */	}	stat = wait_for_ready(timeout);		/* wait for ready or exception */	if (stat == TE_EX) {		if (tp_sense(TP_WRP|TP_BOM|TP_EOM|TP_FIL)!=TE_OK)			return -EIO;		/* else nothing to worry about, I hope */		stat = TE_OK;	}	if (stat != TE_OK) {		printk(TPQIC02_NAME ": ll_do_qic_cmd(%x, %ld) failed\n", cmd, (long) timeout);		return -EIO;	}#if OBSOLETE	/* wait for ready since it may not be active immediately after reading status */	while ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) != 0);#endif	stat = send_qic02_cmd(cmd, timeout, 0);	/* (checks for exceptions) */	if (cmd==QCMD_RD_FM) {		status_eof_detected = NO;		ioctl_status.mt_fileno++;		/* Should update block count as well, but can't.		 * Can do a `read address' for some drives, when MTNOP is done.		 */	} else if (cmd==QCMD_WRT_FM) {		status_eof_detected = NO;		ioctl_status.mt_fileno++;	} else if ((cmd==QCMD_REWIND) || (cmd==QCMD_ERASE) || (cmd==QCMD_RETEN)) {		status_eof_detected = NO;		status_eom_detected = NO;		status_eot_detected = NO;		need_rewind = NO;		ioctl_status.mt_fileno = ioctl_status.mt_blkno = 0;		extra_blocks_left = BLOCKS_BEYOND_EW;		return_write_eof = NO;		return_read_eof = NO;		reported_read_eof = NO;		reported_write_eof = NO;	}	/* sense() will set eof/eom as required */	if (stat==TE_EX) {		if (tp_sense(TP_WRP|TP_BOM|TP_EOM|TP_FIL)!=TE_OK) {			printk(TPQIC02_NAME ": Exception persist in ll_do_qic_cmd[1](%x, %ld)", cmd, (long) timeout);			status_dead = YES;			return -ENXIO;			/* if rdstatus fails too, we're in trouble */		}	}	else if (stat!=TE_OK) {		printk(TPQIC02_NAME ": ll_do_qic_cmd: send_qic02_cmd failed, stat = 0x%x\n", stat);		return -EIO;	/*** -EIO is probably not always appropriate */	}	if (timeout == TIM_R)		stat = wait_for_rewind(timeout);	else		stat = wait_for_ready(timeout);	if (stat==TE_EX) {		if (tp_sense((cmd==QCMD_SEEK_EOD ?		/*****************************/		      TP_EOR|TP_NDT|TP_UDA|TP_BNL|TP_WRP|TP_BOM|TP_EOM|TP_FIL :		      TP_WRP|TP_BOM|TP_EOM|TP_FIL))!=TE_OK) {			printk(TPQIC02_NAME ": Exception persist in ll_do_qic_cmd[2](%x, %ld)\n", cmd, (long) timeout);			if (cmd!=QCMD_RD_FM)				status_dead = YES;			return -ENXIO;			/* if rdstatus fails too, we're in trouble */		}	}	else if (stat!=TE_OK) {		printk(TPQIC02_NAME ": ll_do_qic_cmd %x: wait failed, stat == 0x%x\n", cmd, stat);		return -EIO;	}	return 0;} /* ll_do_qic_cmd *//*  * Problem: What to do when the user cancels a read/write operation * in-progress? * * "Deactivating ONLINE during a READ also causes the" * "tape to be rewound to BOT." Ditto for WRITEs, except * a FM is written first. "The host may alternatively terminate * the READ/WRITE command by issuing a RFM/WFM command." * * For READs: * Neither option will leave the tape positioned where it was. * Another (better?) solution is to terminate the READ by two * subsequent sense() operations, the first to stop the current * READ cycle, the second to clear the `Illegal command' exception, * because the QIC-02 specs didn't anticipate this. This is * delayed until actually needed, so a tar listing can be aborted * by the user and continued later. * If anybody has a better solution, let me know! [Also, let me * know if your drive (mine is a Wangtek5150EQ) does not accept * this sequence for canceling the read-cycle.] * * For WRITEs it's simple: Just do a WRITE_FM, leaving the tape * positioned after the FM. */static void terminate_read(int cmd){	if (doing_read == YES) {		doing_read = NO;		if (cmd != QCMD_RD_FM) {			/* if the command is a RFM, there is no need to do this			 * because a RFM will legally terminate the read-cycle.			 */			tpqputs(TPQD_ALWAYS, "terminating pending read-cycle");			/* I'm not too sure about this part  -- hhb */			if (QIC02_TAPE_IFC == MOUNTAIN) {				/* Mountain reference says can terminate by de-asserting online */				ctlbits &= ~MTN_QIC02_CTL_ONLINE;			} 			if (tp_sense(TP_FIL|TP_EOM|TP_WRP) != TE_OK) {				tpqputs(TPQD_ALWAYS, "finish_rw[read1]: ignore the 2 lines above");				if (is_exception()) {					if (tp_sense(TP_ILL|TP_FIL|TP_EOM|TP_WRP) != TE_OK)						tpqputs(TPQD_ALWAYS, "finish_rw[read2]: read cycle error");				}			}		}	}} /* terminate_read */static void terminate_write(int cmd){	int stat;	if (doing_write == YES) {		doing_write = NO;		/* Finish writing by appending a FileMark at the end. */		if (cmd != QCMD_WRT_FM) {			/* finish off write cycle */			stat = ll_do_qic_cmd(QCMD_WRT_FM, TIM_M);			if (stat != TE_OK)				tpqputs(TPQD_ALWAYS, "Couldn't finish write cycle properly");			(void) tp_sense(0);		}		/* If there is an EOF token waiting to be returned to		 * the (writing) application, discard it now.		 * We could be at EOT, so don't reset return_write_eof.		 */		reported_write_eof=YES;	}} /* terminate_write *//* terminate read or write cycle because of command `cmd' */static void finish_rw(int cmd){	if (wait_for_ready(TIM_S) != TE_OK) {		tpqputs(TPQD_ALWAYS, "error: drive not ready in finish_rw() !");		return;	}	terminate_read(cmd);	terminate_write(cmd);} /* finish_rw *//* Perform a QIC command through ll_do_qic_cmd(). * If necessary, rewind the tape first. * Return an OS error code if something goes wrong, 0 if all is well. */static int do_qic_cmd(int cmd, time_t timeout){	int stat;	finish_rw(cmd);	if (need_rewind) {		tpqputs(TPQD_REWIND, "Rewinding tape...");		stat = ll_do_qic_cmd(QCMD_REWIND, TIM_R);		if (stat != 0) {			printk(TPQIC02_NAME ": rewind failed in do_qic_cmd(). stat=0x%2x", stat);			return stat;		}		need_rewind = NO;		if (cmd==QCMD_REWIND)	/* don't wind beyond BOT ;-) */			return 0;	}	return ll_do_qic_cmd(cmd, timeout);} /* do_qic_cmd *//* Not all ioctls are supported for all drives. Some rely on * optional QIC-02 commands. Check tpqic02.h for configuration. * Some of these commands may require ONLINE to be active. */static int do_ioctl_cmd(int cmd){	int stat;	/* It is not permitted to read or wind the tape after bytes have	 * been written. It is not permitted to write the tape while in	 * read mode.	 * We try to be kind and allow reading again after writing a FM...	 */	switch (cmd) {		case MTRESET:			/* reset verbose */			return (tape_reset(1)==TE_OK)? 0 : -EIO;		case MTFSF:			tpqputs(TPQD_IOCTLS, "MTFSF forward searching filemark");			if ((mode_access==WRITE) && status_bytes_wr)				return -EACCES;			return do_qic_cmd(QCMD_RD_FM, TIM_F);		case MTBSF:			if (TP_HAVE_BSF) {				tpqputs(TPQD_IOCTLS, "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 {				stat = -ENXIO;			}			status_eom_detected = status_eof_detected = NO;			return stat;		case MTFSR:			if (TP_HAVE_FSR) { /* This is an optional QIC-02 command */				tpqputs(TPQD_IOCTLS, "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(TPQD_IOCTLS, "MTFSR not supported");				stat = -ENXIO;			}			return stat;		case MTBSR:			if (TP_HAVE_BSR) { /* This is an optional QIC-02 command */				/* we need this for appending files with GNU tar!! */				tpqputs(TPQD_IOCTLS, "MTFSR backward space record");				if ((mode_access==WRITE) && status_bytes_wr)					return -EACCES;				stat = do_qic_cmd(QCMD_SPACE_BCK, TIM_F);			} else {				tpqputs(TPQD_IOCTLS, "MTBSR not supported");				stat = -ENXIO;			}			status_eom_detected = status_eof_detected = NO;			return stat;		case MTWEOF:			tpqputs(TPQD_IOCTLS, "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(TPQD_IOCTLS, "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(TPQD_IOCTLS, "MTOFFL rewinding & going 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(TPQD_IOCTLS, "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(TPQD_IOCTLS, "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(TPQD_IOCTLS, "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(TPQD_IOCTLS, "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(TPQD_IOCTLS, "MTEOM search for End Of recorded Media");			if ((mode_access==WRITE) && status_bytes_wr)				return -EACCES;			if (TP_HAVE_EOD) {				/* Use faster seeking when possible.				 * This requires the absence of data beyond the EOM.				 * 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;				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" */

⌨️ 快捷键说明

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