📄 tpqic02.c
字号:
#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 + -