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

📄 tpqic02.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
static inline int is_exception(void){    return (inb(QIC02_STAT_PORT) & QIC02_STAT_EXCEPTION) == 0;} /* is_exception *//* Reset the tape drive and controller. * When reset fails, it marks  the drive as dead and all * requests (except reset) are to be ignored (ENXIO). */static int tape_reset(int verbose){    ifc_init();				/* reset interface card */    /* assert reset */    if (QIC02_TAPE_IFC == MOUNTAIN)    {	outb_p(ctlbits & ~MTN_QIC02_CTL_RESET_NOT, QIC02_CTL_PORT);    }    else /* WANGTEK, ARCHIVE */    {	outb_p(ctlbits | QIC02_CTL_RESET, QIC02_CTL_PORT);    }        /* Next, we need to wait >=25 usec. */    udelay(30);    /* after reset, we will be at BOT (modulo an automatic rewind) */    status_eof_detected = NO;    status_eom_detected = NO;    status_cmd_pending = 0;    need_rewind = YES;    doing_read = doing_write = NO;    ioctl_status.mt_fileno = ioctl_status.mt_blkno = 0;        /* de-assert reset */    if (QIC02_TAPE_IFC == MOUNTAIN)    {	outb_p(ctlbits | MTN_QIC02_CTL_RESET_NOT, QIC02_CTL_PORT);    }    else    {	outb_p(ctlbits & ~QIC02_CTL_RESET, QIC02_CTL_PORT);    }        /* KLUDGE FOR G++ BUG */    { int stat = inb_p(QIC02_STAT_PORT);	status_dead = ((stat & QIC02_STAT_RESETMASK) != QIC02_STAT_RESETVAL); }    /* if successful, inb(STAT) returned RESETVAL */    if (status_dead == YES)    {	printk(TPQIC02_NAME ": reset failed!\n");    }    else if (verbose)    {	printk(TPQIC02_NAME ": reset successful\n");    }        return (status_dead == YES)? TE_DEAD : TE_OK;} /* tape_reset *//* Notify tape drive of a new command. It only waits for the * command to be accepted, not for the actual command to complete. * * Before calling this routine, QIC02_CMD_PORT must have been loaded * with the command to be executed. * After this routine, the exception bit must be checked. * This routine is also used by rdstatus(), so in that case, any exception * must be ignored (`ignore_ex' flag). */static int notify_cmd(char cmd, short ignore_ex){	int i;	outb_p(cmd, QIC02_CMD_PORT);    /* output the command */	/* wait 1 usec before asserting /REQUEST */	udelay(1);	if ((!ignore_ex) && is_exception()) {		tpqputs(TPQD_ALWAYS, "*** exception detected in notify_cmd");		/** force a reset here **/		if (tape_reset(1)==TE_DEAD)			return TE_DEAD;		if (is_exception()) {			tpqputs(TPQD_ALWAYS, "exception persists after reset.");			tpqputs(TPQD_ALWAYS, " ^ exception ignored.");		}	}	outb_p(ctlbits | QIC02_CTL_REQUEST, QIC02_CTL_PORT);  /* set request bit */	i = TAPE_NOTIFY_TIMEOUT;	/* The specs say this takes about 500 usec, but there is no upper limit!	 * If the drive were busy retensioning or something like that,	 * it could be *much* longer!	 */	while ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) && (--i>0))		/*skip*/;			  /* wait for ready */	if (i==0) {		tpqputs(TPQD_ALWAYS, "timed out waiting for ready in notify_cmd");		status_dead = YES;		return TE_TIM;	}	outb_p(ctlbits & ~QIC02_CTL_REQUEST, QIC02_CTL_PORT); /* reset request bit */	i = TAPE_NOTIFY_TIMEOUT;	/* according to the specs this one should never time-out */	while (((inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) == 0) && (--i>0))		/*skip*/;			  /* wait for not ready */	if (i==0) {		tpqputs(TPQD_ALWAYS, "timed out waiting for !ready in notify_cmd");		status_dead = YES;		return TE_TIM;	}	/* command accepted */	return TE_OK;} /* notify_cmd *//* Wait for a command to complete, with timeout */static int wait_for_ready(time_t timeout){	int stat;	time_t spin_t;	/* Wait for ready or exception, without driving the loadavg up too much.	 * In most cases, the tape drive already has READY asserted,	 * so optimize for that case.	 *	 * First, busy wait a few usec:	 */	spin_t = 50;	while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && (--spin_t>0))		/*SKIP*/;	if ((stat & QIC02_STAT_READY) == 0)		return TE_OK;			/* covers 99.99% of all calls */	/* Then use schedule() a few times */	spin_t = 3;	/* max 0.03 sec busy waiting */	if (spin_t > timeout)		spin_t = timeout;	timeout -= spin_t;	spin_t += jiffies;	while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && time_before(jiffies, spin_t))		schedule();		/* don't waste all the CPU time */	if ((stat & QIC02_STAT_READY) == 0)		return TE_OK;	/* If we reach this point, we probably need to wait much longer, or	 * an exception occurred. Either case is not very time-critical.	 * Check the status port only a few times every second.	 * A interval of less than 0.10 sec will not be noticed by the user,	 * more than 0.40 sec may give noticeable delays.	 */	spin_t += timeout;	TPQDEB({printk("wait_for_ready: additional timeout: %d\n", spin_t);})		/* not ready and no exception && timeout not expired yet */	while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && time_before(jiffies, spin_t)) {		/* be `nice` to other processes on long operations... */		current->state = TASK_INTERRUPTIBLE;		/* nap 0.30 sec between checks, */		/* but could be woken up earlier by signals... */		schedule_timeout(3*HZ/10);	}	/* don't use jiffies for this test because it may have changed by now */	if ((stat & QIC02_STAT_MASK) == QIC02_STAT_MASK) {		tpqputs(TPQD_ALWAYS, "wait_for_ready() timed out");		return TE_TIM;	}	if ((stat & QIC02_STAT_EXCEPTION) == 0) {		tpqputs(TPQD_ALWAYS, "exception detected after waiting_for_ready");		return TE_EX;	} else {		return TE_OK;	}} /* wait_for_ready *//* Send some data to the drive */static int send_qic02_data(char sb[], unsigned size, int ignore_ex){	int i, stat;	for (i=0; i<size; i++) {		stat = wait_for_ready(TIM_S);		if (stat != TE_OK)			return stat;		stat = notify_cmd(sb[i], ignore_ex);		if (stat != TE_OK)			return stat;	}	return TE_OK;	} /* send_qic02_data *//* Send a QIC-02 command (`cmd') to the tape drive, with * a time-out (`timeout'). * This one is also used by tp_sense(), so we must have * a flag to disable exception checking (`ignore_ex').  * * On entry, the controller is supposed to be READY. */static int send_qic02_cmd(int cmd, time_t timeout, int ignore_ex){	int stat;	stat = inb_p(QIC02_STAT_PORT);	if ((stat & QIC02_STAT_EXCEPTION) == 0) {	/* if exception */		tpqputs(TPQD_ALWAYS, "send_qic02_cmd: Exception!");		return TE_EX;	}	if (stat & QIC02_STAT_READY) {			/* if not ready */		tpqputs(TPQD_ALWAYS, "send_qic02_cmd: not Ready!");		return TE_ERR;	}	/* assert(ready & !exception) */	/* Remember current command for later re-use with dma transfers.	 * (For reading/writing multiple blocks.)	 */	status_cmd_pending = cmd;	stat = notify_cmd(cmd, ignore_ex); /* tell drive new command was loaded, */					   /* inherit exception check. */	if (TP_HAVE_SEEK && (cmd == AR_QCMDV_SEEK_BLK)) {		/* This one needs to send 3 more bytes, MSB first */		stat = send_qic02_data(seek_addr_buf, sizeof(seek_addr_buf), ignore_ex);	}	if (stat != TE_OK) {		tpqputs(TPQD_ALWAYS, "send_qic02_cmd failed");	}	return stat;} /* send_qic02_cmd *//* Get drive status. Assume drive is ready or has exception set. * (or will be in <1000 usec.) * Extra parameters added because of 'Read Extended Status 3' command. */static int rdstatus(char *stp, unsigned size, char qcmd){	int	s, n;	char	*q = stp;	/* Try to busy-wait a few (700) usec, after that de-schedule.	 *	 * The problem is, if we don't de-schedule, performance will	 * drop to zero when the drive is not responding and if we	 * de-schedule immediately, we waste a lot of time because a	 * task switch is much longer than we usually have to wait here.	 */	n = 1000;	/* 500 is not enough on a 486/33 */	while ((n>0) && ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK))		n--;  /* wait for ready or exception or timeout */	if (n==0) {		/* n (above) should be chosen such that on your machine		 * you rarely ever see the message below, and it should		 * be small enough to give reasonable response time.]		 */		tpqputs(TPQD_ALWAYS, "waiting looong in rdstatus() -- drive dead?");		while ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK)			schedule();		tpqputs(TPQD_ALWAYS, "finished waiting in rdstatus()");	}	(void) notify_cmd(qcmd, 1);			/* send read status command */	/* ignore return code -- should always be ok, STAT may contain 	 * exception flag from previous exception which we are trying to clear.	 */	if (TP_DIAGS(current_tape_dev))		printk(TPQIC02_NAME ": reading status bytes: ");	for (q=stp; q<stp+size; q++)	{		do s = inb_p(QIC02_STAT_PORT);		while ((s & QIC02_STAT_MASK) == QIC02_STAT_MASK);	/* wait for ready or exception */		if ((s & QIC02_STAT_EXCEPTION) == 0) {		/* if exception */			tpqputs(TPQD_ALWAYS, "rdstatus: exception error");			ioctl_status.mt_erreg = 0;		/* dunno... */			return TE_NS;				/* error, shouldn't happen... */		}		*q = inb_p(QIC02_DATA_PORT);			/* read status byte */		if (TP_DIAGS(current_tape_dev))			printk("[%1d]=0x%x  ", q-stp, (unsigned) (*q) & 0xff);		outb_p(ctlbits | QIC02_CTL_REQUEST, QIC02_CTL_PORT);	/* set request */		while ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) == 0);	/* wait for not ready */		udelay(22);	/* delay >20 usec */		outb_p(ctlbits & ~QIC02_CTL_REQUEST, QIC02_CTL_PORT);	/* un-set request */	}	/* Specs say we should wait for READY here.	 * My drive doesn't seem to need it here yet, but others do?	 */	while (inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY)		/*skip*/;			  /* wait for ready */	if (TP_DIAGS(current_tape_dev))		printk("\n");	return TE_OK;} /* rdstatus *//* Get standard status (6 bytes). * The `.dec' and `.urc' fields are in MSB-first byte-order, * so they have to be swapped first. */static int get_status(volatile struct tpstatus *stp){	int stat = rdstatus((char *) stp, TPSTATSIZE, QCMD_RD_STAT);#if defined(i386) || defined(i486)	byte_swap_w(&(stp->dec));	byte_swap_w(&(stp->urc));#else	/* should probably swap status bytes #definition */#endif	return stat;} /* get_status */#if 0/* This fails for my Wangtek drive *//* get "Extended Status Register 3" (64 bytes) * * If the meaning of the returned bytes were known, the MT_TYPE * identifier could be used to decode them, since they are * "vendor unique". :-( */static int get_ext_status3(void){	char vus[64];	/* vendor unique status */	int stat, i;	tpqputs(TPQD_ALWAYS, "Attempting to read Extended Status 3...");	stat = rdstatus(vus, sizeof(vus), QCMD_RD_STAT_X3);	if (stat != TE_OK)		return stat;	tpqputs(TPQD_ALWAYS, "Returned status bytes:");	for (i=0; i<sizeof(vus); i++) {		if ( i % 8 == 0 )			printk("\n" TPQIC02_NAME ": %2d:");		printk(" %2x", vus[i] & 0xff);	}	printk("\n");	return TE_OK;} /* get_ext_status3 */#endif/* Read drive status and set generic status too. * NOTE: Once we do a tp_sense(), read/write transfers are killed. */static int tp_sense(int ignore){	unsigned err = 0, exnr = 0, gs = 0;	static void finish_rw(int cmd);	if (TPQDBG(SENSE_TEXT))		printk(TPQIC02_NAME ": tp_sense(ignore=0x%x) enter\n", ignore);	/* sense() is not allowed during a read or write cycle */	if (doing_write == YES)		tpqputs(TPQD_ALWAYS, "Warning: File Mark inserted because of sense() request");	/* The extra test is to avoid calling finish_rw during booting */	if ((doing_read!=NO) || (doing_write!=NO))		finish_rw(QCMD_RD_STAT);	if (get_status(&tperror) != TE_OK) {		tpqputs(TPQD_ALWAYS, "tp_sense: could not read tape drive status");		return TE_ERR;	}	err = tperror.exs;	/* get exception status bits */	if (err & (TP_ST0|TP_ST1))		printk(TPQIC02_NAME ": tp_sense: status: %x, error count: %d, underruns: %d\n",			tperror.exs, tperror.dec, tperror.urc);	else if ((tperror.dec!=0) || (tperror.urc!=0) || TPQDBG(SENSE_CNTS))		printk(TPQIC02_NAME ": tp_sense: no hard errors, soft error count: %d, underruns: %d\n",			tperror.dec, tperror.urc);	/* Set generic status. HP-UX defines these, but some extra would 	 * be useful. Problem is to remain compatible. [Do we want to be	 * compatible??]	 */	if (err & TP_ST0) {		if (err & TP_CNI)		/* no cartridge */			gs |= GMT_DR_OPEN(-1);		if (status_dead == NO)			gs |= GMT_ONLINE(-1);	/* always online */		if (err & TP_USL)		/* not online */			gs &= ~GMT_ONLINE(-1);		if (err & TP_WRP)			gs |= GMT_WR_PROT(-1);		if (err & TP_EOM) {		/* end of media */			gs |= GMT_EOT(-1);	/* not sure this is correct for writes */

⌨️ 快捷键说明

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