📄 ar.c
字号:
struct ardevice *araddr = sc->sc_addr; if (!sc->sc_opened) return (-1); sc->sc_state = ar_cmds[cmd]; for (;;) { if (araddr->arexc) { /* * This interrupt is from the true level of arexc. * * An error has occurred. Deal with it somehow. * If we are reading status, just do it; else do our own * RDST to find out the problem, and cancel the current * operation. */ if (sc->sc_state == RDSTinit) goto doit; Dprintf("ar*intr arexc set, old state %x\n", sc->sc_state); sc->sc_oldstate = sc->sc_state; sc->sc_state = RDSTinit; /* * Clear EdgeReady and enable it so the next arrdy * edge will be caught (possibly inside armachine()). */ araddr->arcatch = 0; araddr->arcatch = 1; while (!armachine(sc)) { /* Shouldn't happen! */ printf("ar*intr RDST did not return 1\n"); } if (!sc->sc_status.FileMark) { printf("ar: error %x\n", *(u_short *)&sc->sc_status); return (1); } /* Eof signaled now means that NEXT block is an EOF. */ sc->sc_eoflag = 1; return (0); } if (araddr->arrdy) { doit: araddr->arcatch = 0; araddr->arcatch = 1; if (armachine(sc)) return (0); } }}/* * State machine for archive tape drive controller. * This actually accomplishes things w.r.t. the tape drive. * Returns 0 if operation still in progress, 1 if finished. * Note that we may take further interrupts after claiming that an * operation is "finished". For example, we say a write is done when * we have transferred the last byte of the block; but there will be * an interrupt 5.5ms later to tell us it's ok to send the next block. * Eventually, we will rewind the tape asynchronously after the file is * closed, letting the user go free while it spins. FIXME: THIS CANNOT * BE DONE until we clean up the high level code so it doesn't clobber * our variables as it is setting up to call arstart_cmd(). */armachine(sc) register struct ar_softc *sc;{ register struct ardevice *araddr = sc->sc_addr; register int count, i, x; register char *byteptr;Dprintf("ar*machine(%x, %x) state %x\n", sc, araddr, sc->sc_state); switch (sc->sc_state) { case CMDOKinit: /* * If we got here the command state is ok, * i.e., not in the middle of a read or write. */ sc->sc_state = IDLEstate; sc->sc_cmdok = 1; return (1); case CLOSEinit: /* FIXME, this is time dependent and not documented in the Archive manual */ araddr->aronline = 0; /* Drop online; we're done. */ if (araddr->arrdy) goto IdleState; /* No interrupt will occur. */ else goto FinState; /* Rewinding; wait for interrupt. */#ifdef FIXME case CLOSEend: /* This is entered from READidle or WRidle. */ araddr->aronline = 0; /* Drop it, causing rewind. */ goto FinState; /* Interrupt will signal end of rew. */#endif case WFMinit: sc->sc_status.BOT = 0; araddr->ardata = ARCMD_WREOF; araddr->arreq = 1; goto CmdState; case RFMinit: araddr->ardata = ARCMD_RDEOF; araddr->arreq = 1; goto CmdState; case REWinit: araddr->ardata = ARCMD_REWIND; araddr->arreq = 1; goto CmdState; case TENSEinit: araddr->ardata = ARCMD_TENSION; araddr->arreq = 1; goto CmdState; case ERASEinit: araddr->ardata = ARCMD_ERASE; araddr->arreq = 1; goto CmdState; case SELinit: araddr->ardata = ARCMD_LED | (1 << sc->sc_drive); araddr->arreq = 1; goto CmdState; case DESELinit: araddr->ardata = 1 << sc->sc_drive; araddr->arreq = 1; goto CmdState; RDSTagain: printf("ar: RDST gave Exception, retrying\n"); /* Fall thru... */ case RDSTinit: byteptr = (char *) &sc->sc_status; /* We could have either arrdy or arexc; remember which */ count = 0; if (araddr->arrdy) count = 1; araddr->ardata = ARCMD_RDSTAT; araddr->arreq = 1; /* * Now wait for arrdy indicating command accepted. * Check for Exception, if we started with arrdy. * (It's not legal to do RDST all the time(!).) */ while (!araddr->arrdy) if (count && araddr->arexc) goto RDSTagain; /* Negate arreq, wait for arrdy to drop. */ araddr->arcatch = 0; /* Clear arrdyedge */ araddr->arcatch = 1; /* Catch edge */ araddr->arreq = 0; /* Now xfer a byte or six. */ do { /* Wait for edge of arrdy */ while (!araddr->arrdyedge) if (araddr->arexc) goto RDSTagain; *byteptr++ = araddr->ardata; araddr->arcatch = 0; /* Clear edge indicator */ araddr->arcatch = 1; /* Catch next one */ araddr->arreq = 1; /* Tell controller we have it */ /* Ready will fall within 250ns of our arreq, but we're supposed to keep it high for 20us */ DELAY(30); /* at least 20 usec */ araddr->arreq = 0; } while (byteptr < (char *)(&sc->sc_status) + sizeof (sc->sc_status)); /* * On exit from this loop, arcatch has been negated and * asserted, so it will correctly reflect the leading edge * of arrdy for the next command. */ sc->sc_oldstate = sc->sc_state; sc->sc_state = FINstate; /* Awaiting final interrupt *//* Dump status bytes after a command AR_STATUS */Dprintf("ar*RDST %x %d %d\n", *(unsigned short*)&sc->sc_status, sc->sc_status.SoftErrs, sc->sc_status.TapeStops);/* This code is obsolete since sc_qidle, and should be replaceable by a simple branch to RdWrFin. However, that doesn't work, so try this. JCGnu, 23Nov82 */ while (!araddr->arrdy) if (araddr->arexc) goto RDSTagain;/* We leave the edge of Ready caught in EdgeReady, but IdleState will disable interrupts on it. */ goto IdleState; case READcmd: case WRcmd: araddr->arreq = 0; goto next; case READinit: araddr->ardata = ARCMD_RDDATA; araddr->arreq = 1; goto next; case READburst: /* Read a block of data from the tape drive. */Dprintf("ar*READ addr %x count %x\n", sc->sc_bufptr, sc->sc_size); sc->sc_status.BOT = 0; while (!araddr->arrdy) { if (araddr->arexc) return (0); /* Not yet done */ Dprintf("ar*Read no READY\n"); } araddr->arburst = 1; /* Begin block xfer */ count = min(sc->sc_size, AR_BSIZE); byteptr = sc->sc_bufptr; for (i=0; i<count; i++) *byteptr++ = araddr->ardata; /* read data */ for (; i<AR_BSIZE; i++) x = araddr->ardata; /* read junk */#ifdef lint x = x; /* use it */#endif araddr->arburst = 0; sc->sc_oldstate = sc->sc_state; sc->sc_state = READfin; /* Like FINstate sorta */ break; case WRinit: araddr->ardata = ARCMD_WRDATA; araddr->arreq = 1; goto next; case WRburst: /* Write a block of data to the tape drive. */Dprintf("ar*WRITE addr %x count %x\n", sc->sc_bufptr, sc->sc_size); while (!araddr->arrdy) { if (araddr->arexc) return (0); /* Not done yet */ Dprintf("ar*Write no READY\n"); } araddr->arburst = 1; /* Begin block xfer */ count = AR_BSIZE; byteptr = sc->sc_bufptr; while (count--) araddr->ardata = *byteptr++; araddr->arburst = 0; sc->sc_oldstate = sc->sc_state; sc->sc_state = WRfin; /* Like FINstate sorta */Dprintf("ar*machine exiting done in state %x\n", sc->sc_state); /* * This code is a copy of the code at the end of this * switch statement, except that it returns 1 (operation * completed) instead of 0 (more needs doing) */ araddr->arrdyie = 1; araddr->arexcie = 1; return (1); case CMDstate: /* All commands that stop interacting once you say "do it" */ araddr->arreq = 0; /* Done with command */ goto FinState; /* Final interaction for this cmd */ IdleState: /* Drive is idle; set IDLEstate and disable */ sc->sc_oldstate = sc->sc_state; sc->sc_state = IDLEstate; goto DisAble; case WRfin: /* Entry after writing a block */ case READfin: /* Entry after reading a block */ case FINstate: /* Entry after any other command */ /* * Go to next sequential state - WRidle, READidle, IDLEstate. * Disable interrupts, and return. arstart_cmd() will later * put us into READ/WRburst or some commandinit state. */ sc->sc_oldstate = sc->sc_state; sc->sc_state = (enum ARstates)(1 +(int)sc->sc_state);DisAble:Dprintf("ar*machine idling\n"); araddr->arrdyie = 0; /* Negate arrdy interrupt */ return (1); /* Tell caller op is done */ case WRidle: /* Writing blocks, but none to write now */ case READidle: /* Reading blocks, but don't need one now */ case IDLEstate: /* Issuing commands, but don't have one now */ /* This can only happen if software triggers us. */ printf("ar: triggerred at idle %x\n", sc->sc_state); goto DisAble; /* Turn off interrupt enable again */ default: printf("ar: invalid state %d\n", sc->sc_state); goto FinState; /* Is this reasonable? */ next: /* Go to next sequential state */ sc->sc_oldstate = sc->sc_state; sc->sc_state = (enum ARstates)(1 +(int)sc->sc_state); break; FinState: sc->sc_oldstate = sc->sc_state; sc->sc_state = FINstate; break; CmdState: sc->sc_oldstate = sc->sc_state; sc->sc_state = CMDstate; break; }Dprintf("ar*machine exiting in state %x\n", sc->sc_state); /* Go to next state on the next leading edge of arrdy. */ araddr->arrdyie = 1; /* Interrupt on arrdy leading edge */ araddr->arexcie = 1; /* Interrupt on arexc too *//* FIXME. Figure out where to set and unset, leave alone otherwise. */ return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -