📄 tpqic02.c
字号:
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; } return stat; case MTERASE: tpqputs(TPQD_IOCTLS, "MTERASE -- ERASE TAPE !"); if ((tperror.exs & TP_ST0) && (tperror.exs & TP_WRP)) { tpqputs(TPQD_ALWAYS, "Cartridge is write-protected."); return -EACCES; } else { time_t t = jiffies; /* Plain GNU mt(1) 2.2 erases a tape in O_RDONLY. :-( */ if (mode_access==READ) return -EACCES; /* give user a few seconds to pull out tape */ while (jiffies - t < 4*HZ) schedule(); } /* don't bother writing filemark first */ status_eom_detected = status_eof_detected = NO; return do_qic_cmd(QCMD_ERASE, TIM_R); case MTRAS1: if (TP_HAVE_RAS1) { tpqputs(TPQD_IOCTLS, "MTRAS1: non-destructive self test"); stat = do_qic_cmd(QCMD_SELF_TST1, TIM_R); if (stat != 0) { tpqputs(TPQD_ALWAYS, "RAS1 failed"); return stat; } return (tp_sense(0)==TE_OK)? 0 : -EIO; /* get_ext_status3(); */ } tpqputs(TPQD_IOCTLS, "RAS1 not supported"); return -ENXIO; case MTRAS2: if (TP_HAVE_RAS2) { tpqputs(TPQD_IOCTLS, "MTRAS2: destructive self test"); stat = do_qic_cmd(QCMD_SELF_TST2, TIM_R); if (stat != 0) { tpqputs(TPQD_ALWAYS, "RAS2 failed"); return stat; } return (tp_sense(0)==TE_OK)? 0 : -EIO; /* get_ext_status3(); */ } tpqputs(TPQD_IOCTLS, "RAS2 not supported"); return -ENXIO; case MTSEEK: if (TP_HAVE_SEEK && (QIC02_TAPE_IFC==ARCHIVE)) { tpqputs(TPQD_IOCTLS, "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(AR_QCMDV_SEEK_BLK, TIM_F); } else return -ENOTTY; 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){ unsigned long flags; if (QIC02_TAPE_IFC == WANGTEK) /* or EVEREX */ outb_p(WT_CTL_ONLINE, QIC02_CTL_PORT); /* back to normal */ else if (QIC02_TAPE_IFC == ARCHIVE) outb_p(0, AR_RESET_DMA_PORT); else /* QIC02_TAPE_IFC == MOUNTAIN */ outb_p(ctlbits, QIC02_CTL_PORT); flags=claim_dma_lock(); clear_dma_ff(QIC02_TAPE_DMA); set_dma_mode(QIC02_TAPE_DMA, dma_mode); set_dma_addr(QIC02_TAPE_DMA, buffaddr+dma_bytes_done); /* full address */ set_dma_count(QIC02_TAPE_DMA, TAPE_BLKSIZE); /* start tape DMA controller */ if (QIC02_TAPE_IFC == WANGTEK) /* or EVEREX */ outb_p(WT_CTL_DMA | WT_CTL_ONLINE, QIC02_CTL_PORT); /* trigger DMA transfer */ else if (QIC02_TAPE_IFC == ARCHIVE) { outb_p(AR_CTL_IEN | AR_CTL_DNIEN, QIC02_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. */ } else /* QIC02_TAPE_IFC == MOUNTAIN */ { inb(MTN_R_DESELECT_DMA_PORT); outb_p(ctlbits | (MTN_CTL_EXC_IEN | MTN_CTL_DNIEN), QIC02_CTL_PORT); outb_p(0, MTN_W_SELECT_DMA_PORT); /* start DMA transfer */ if (dma_mode == DMA_MODE_WRITE) outb_p(0, MTN_W_DMA_WRITE_PORT); /* start DMA transfer */ } /* start computer DMA controller */ enable_dma(QIC02_TAPE_DMA); release_dma_lock(flags); /* 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 qic02_tape_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; unsigned long flags; tpqputs(TPQD_DEBUG, "start_dma() enter"); TPQDEB({printk(TPQIC02_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(&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(TPQD_ALWAYS, "wait_for_ready failed in start_dma"); return -EIO; }#endif if (QIC02_TAPE_IFC == MOUNTAIN) { /* Set control bits to select ONLINE during command */ ctlbits |= MTN_QIC02_CTL_ONLINE; } /* 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(TPQIC02_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(TPQIC02_NAME ": requested unknown mode %d\n", mode); panic(TPQIC02_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(TPQD_ALWAYS, "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 */ save_flags(flags); cli(); dma_transfer(); restore_flags(flags); 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; unsigned long flags; TIMEROFF; TPQPUTS("end_dma() enter"); flags=claim_dma_lock(); disable_dma(QIC02_TAPE_DMA); clear_dma_ff(QIC02_TAPE_DMA); release_dma_lock(flags); if (QIC02_TAPE_IFC == WANGTEK) /* or EVEREX */ outb_p(WT_CTL_ONLINE, QIC02_CTL_PORT); /* back to normal */ else if (QIC02_TAPE_IFC == ARCHIVE) outb_p(0, AR_RESET_DMA_PORT); else /* QIC02_TAPE_IFC == MOUNTAIN */ { /* Clear control bits, de-select ONLINE during tp_sense */ ctlbits &= ~MTN_QIC02_CTL_ONLINE; } stat = wait_for_ready(TIM_M); if (status_error || (stat!=TE_OK)) { tpqputs(TPQD_DMAX, "DMA transfer exception"); stat = tp_sense((dma_mode==READ)? TP_WRP : 0); /* no return here -- got to clean up first! */ } else /* if (QIC02_TAPE_IFC == MOUNTAIN) */ { outb_p(ctlbits, QIC02_CTL_PORT); } if (QIC02_TAPE_IFC == MOUNTAIN) inb(MTN_R_DESELECT_DMA_PORT); /* 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 ***********//* qic02_tape_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 qic02_tape_times_out(void){ printk("time-out in %s driver\n", TPQIC02_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(&qic02_tape_transfer); } }} /* qic02_tape_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 * been transferred by DMA. By the time the interrupt * is handled, the EXCEPTION may already be set. * * So, * 1) On EXCEPTION, assume data has been transferred, so * continue as usual, but set a flag to indicate the * exception was detected. * Do a sense status when the flag is found set. * 2) Do not attempt to continue a transfer after an exception. * [??? What about marginal blocks???????] *//* qic02_tape_interrupt() is called when the tape controller completes * a DMA transfer. * We are not allowed to sleep here! * * Check if the transfer was successful, check if we need to transfer * more. If the buffer contains enough data/is empty enough, signal the * read/write() thread to copy to/from user space. * When we are finished, set flags to indicate end, disable timer. * NOTE: This *must* be fast! */static void qic02_tape_interrupt(int irq, void *dev_id, struct pt_regs *regs){ int stat, r, i; unsigned long flags; TIMEROFF; if (status_expect_int) {#ifdef WANT_EXTRA_FULL_DEBUGGING if (TP_DIAGS(current_tape_dev)) printk("@");#endif stat = inb(QIC02_STAT_PORT); /* Knock, knock */ if (QIC02_TAPE_IFC == ARCHIVE) { /* "Who's there?" */ if (((stat & (AR_STAT_DMADONE)) == 0) && ((stat & (QIC02_STAT_EXCEPTION)) != 0)) { TIMERCONT; return; /* "Linux with IRQ sharing" */ } } if ((stat & QIC02_STAT_EXCEPTION) == 0) { /* exception occurred */ /* Possible causes for an exception during a transfer: * - during a write-cycle: end of tape (EW) hole detected. * - during a read-cycle: filemark or EOD detected. * - something went wrong * So don't continue with the next block. */ tpqputs(TPQD_ALWAYS, "isr: exception on tape controller"); printk(" status %02x\n", stat); status_error = TE_EX; dma_bytes_done += TAPE_BLKSIZE; dma_mode = 0; /* wake up rw() */ status_expect_int = NO; wake_up(&qic02_tape_transfer); return; } /* return if tape controller not ready, or * if dma channel hasn't finished last byte yet. */ r = 0; /* Skip next ready check for Archive controller because * it may be busy reading ahead. Weird. --hhb */ if (QIC02_TAPE_IFC == WANGTEK) /* I think this is a drive-dependency, not IFC -- hhb */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -