📄 ar.c
字号:
#ifndef lintstatic char sccsid[] = "@(#)ar.c 1.1 92/07/30 Copyr 1986 Sun Micro";#endif/* * Copyright (c) 1986 by Sun Microsystems, Inc. *//* * Standalone Driver for Archive Intelligent Streaming Tape */#include <stand/saio.h>#include <stand/param.h>#include <sundev/arreg.h>#include <stand/ardef.h>#define min(a,b) ((a) < (b) ? (a) : (b))int ardebug = 0;#define Dprintf if (ardebug) printf/* Trace all writes to control reg */#define DebugTrace Dprintf(ar_ctrl_hdr, *(long*)(2+(char*)araddr))/* Define assorted debugging strings to save repeating them N times */#ifdef DEBUGchar ar_bits[] = ARCH_LONG_CTRL_BITS;char ar_ctrl_hdr[] = "ar* Bits: %x\n";char ar_set_hdr[] = "ar* CMD: %x\n";#endif DEBUGchar ar_stat_bits[] = ARCH_BITS;/* * Standard I/O addresses. */#define NARADDR 2u_long araddrs[] = { 0x200, 0x208};/* * What resources we need to run */struct devinfo arinfo = { sizeof (struct ardevice), /* I/O regs */ 0, /* no DMA */ sizeof (struct ar_softc), /* work area */ NARADDR, araddrs, MAP_MBIO, DEV_BSIZE, /* transfer size */};/* * What facilities we export to the world */int aropen(), arclose(), arstrategy();extern int xxboot(), xxprobe();struct boottab ardriver = { "ar", xxprobe, xxboot, aropen, arclose, arstrategy, "ar: Multibus Archive tape controller", &arinfo,}; /* * Translation between generic tape commands and initial states of * the Archive state machine. */enum ARstates ar_cmds[] = { /* CLOSE */ CLOSEinit, /* REWIND */ REWinit, /* STATUS */ RDSTinit, /* READ */ READinit, /* WRITE */ WRinit, /* WEOF */ WFMinit, /* ERASE */ ERASEinit, /* SELECT */ SELinit, /* DELSELECT */ DESELinit, /* TENSE */ TENSEinit, /* SKIPFILE */ RFMinit, /* CMD OK? */ CMDOKinit,};#define SPININIT 1000000/* * Initialize a controller */aropen(sip) register struct saioreq *sip;{ register struct ar_softc *sc; register int count; register struct ardevice *araddr; int skip; sc = (struct ar_softc *)sip->si_devdata; araddr = sc->sc_addr = (struct ardevice *)sip->si_devaddr; sc->sc_lastiow = 0; sc->sc_state = IDLEstate;/* sc->sc_status = 0; Doesn't work, so leave it alone. */ sc->sc_size = 0; sc->sc_bufptr = (char *) 0x1ff001; /* very funny buf addr *//* sc->sc_attached had better already be 1. */ sc->sc_initted = 0; /* until later */ sc->sc_opened = 0; /* until later */ sc->sc_drive = 0; sc->sc_histate = 0;/* sc->sc_addr had better already be initialized. */ sc->sc_qidle = 1; sc->sc_eoflag = 0; sc->sc_cmdok = 0; sc->sc_selecteddev = -1;/* When adding new fields to softc, be sure to initialize them here. *//* FIXME, should initialize buffer headers here too */ araddr->arunwedge = 1; /* Take it out of burst mode wedge */ araddr->arburst = 0; araddr->arreq = 0; araddr->arxfer = 0; araddr->arcatch = 0; araddr->arexcie = 0; araddr->arrdyie = 0; /* * If tape is up from previous system operation, * take it down gently. */ if (araddr->aronline) {Dprintf("ar*init tape online\n"); araddr->aronline = 0; /* Writes TM (if writing) & rewinds */ } count = SPININIT; while (!araddr->arrdy && !araddr->arexc && count) count--;if (count == 0) Dprintf("ar: Timeout waiting for Ready at %x\n", araddr);if (araddr->arrdy) Dprintf("ar*init arrdy on before reset\n");if (araddr->arexc) Dprintf("ar*init arexc on before reset\n"); /* Tape is ready or exceptional. Reset it for good measure. */#ifdef PRFDprintf("ar*init about to arreset\n");#endif PRF araddr->arreset = 1;#ifdef PRFDprintf("ar*init asserted arreset\n");#endif PRF DELAY(25); /* at least 13 usec */ araddr->arreset = 0;#ifdef PRFDprintf("ar*init Reset complete\n");#endif PRF count = SPININIT; while (!araddr->arexc && count) count--; if (count == 0) {Dprintf("ar: Timeout waiting for Exception after reset\n"); return (-1); } /* Now read back status from the reset. */ sc->sc_initted = 1; /* Must do first so interrupt OK */ sc->sc_opened = 1; /* Must do first so interrupt OK */ araddr->aronline = 1; /* Must do first so RDST microcode doesn't play games with arrdy line. See comments in open(). */ if (arcmd(sc, AR_STATUS)) {Dprintf("ar*init Error from command STATUS\n"); araddr->aronline = 0; sc->sc_initted = 0; /* Try again on next open */ sc->sc_opened = 0; /* Try again on next open */ return (-1); } /* * FIXME, this is a kludge. open() won't select the drive unless * the in-core status claims we are at BOT, since the tape drive * will reject the command if indeed a tape was in use and is not * at BOT. However, tapes at BOT after a Reset do not necessarily * indicate BOT in their status. We should probably do a rewind * here instead, if the tape exists. */ sc->sc_status.BOT = 1; /* Pretend we're at BOT for open() */ /* * There is a problem in the Archive in that after each command, * it goes thru a cleanup routine. If aronline is not asserted, * this cleanup routine drops arrdy while it rewinds the tape * to BOT. It deasserts arrdy for 90 us even if the tape is * already at BOT. This causes us problems because we get a arrdy * interrupt and then discover that arrdy is gone. * * The problem has been circumvented at the low level by checking * for arrdy in the interrupt routine, and looping until it (or * arexc) comes on. We attempt to fix the problem here, to avoid * looping at SPL(), by having aronline always on when we are doing * anything. * * The problem seems especially a problem for us on Select and Read * Status commands. (That's because those are the only commands we * do with aronline deasserted.) * * This info was obtained from Lou Domshy, Mgr. of Product Mgmt and * Applications Engineering(?) at the Archive factory, 714-641-0279, * on 1 December 1982, by John Gilmore of Sun Microsystems. */ araddr->aronline = 1; /* Let ctrlr know we are doing a series */ /* * First select the drive we're interested in. * * Since the select command doesn't work when we aren't at BOT, * we just have to hope the same drive is still selected as last * time. FIXME. We should record this info in softc and keep it * up to date. FIXME: also, I'm not happy about using status.BOT * here, even tho it should always be up to date. -- JCGnu 22Nov82 */ sc->sc_cmdok = 0; (void) arcmd(sc, AR_CMDOK); /* See if OK to issue cmds */ /* * Now get its status and check on a few things. */ if (sc->sc_cmdok) { if (arcmd(sc, AR_STATUS)) { /* interrupted */Dprintf("ar*open command STATUS error\n"); goto err; } if (sc->sc_status.NoDrive) { printf("ar: no drive\n"); goto err; } if (sc->sc_status.NoCart) { printf("ar: no cartridge in drive\n"); goto err; } } if ((sip->si_flgs&F_WRITE) && sc->sc_status.WriteProt) { printf("ar: cartridge is write protected\n"); goto err; } sc->sc_lastiow = 0; skip = sip->si_boff; while (skip--) { arcmd(sc, AR_SKIPFILE); arcmd(sc, AR_STATUS); } sc->sc_eoflag = 0;Dprintf("ar*open exiting\n"); return (0);err: arcmd(sc, AR_DESELECT); araddr->aronline = 0; sc->sc_opened = 0; return (-1);}/* * Close tape device. * * If tape was open for writing or last operation was * a write, then write two EOF's and backspace over the last one. * Unless this is a non-rewinding special file, rewind the tape. * Make the tape available to others. */arclose(sip) struct saioreq *sip;{ register struct ar_softc *sc = (struct ar_softc *)sip->si_devdata; register struct ardevice *araddr = sc->sc_addr; /* * Write file mark and rewind, by dropping aronline. * FIXME. These 3 commands should be moved into AR_CLOSE * in order that the user program can continue while the * tape is rewinding. */ arcmd(sc, AR_CLOSE); /* Shut down things */ araddr->aronline = 1; /* After rewind, set aronline */ /* See comments in open() about aronline and read status cmds */ /* FIXME, this might screw low level code if it affects arrdy */ arcmd(sc, AR_STATUS); /* Read block counts */ arcmd(sc, AR_DESELECT); /* Turn LED off */ sc->sc_selecteddev = -1; sc->sc_eoflag = 0; /* Not at eof after rewind */ sc->sc_opened = 0; /* Available to be opened again */Dprintf("ar*close exiting\n");}arstrategy(sip, rw) register struct saioreq *sip; int rw;{ register struct ar_softc *sc = (struct ar_softc *)sip->si_devdata; int func = (rw == WRITE) ? AR_WRITE : AR_READ; if (sc->sc_eoflag) { sc->sc_eoflag = 0; return (0); } sc->sc_size = sip->si_cc; sc->sc_bufptr = sip->si_ma; if (arcmd(sc, func)) return (-1); return (sip->si_cc);}/* * Begin execution of a device command for the device pointed to by * sc. The command begins execution in state newstate. * * This is HARDWARE oriented software. It doesn't know or care of * state of buffers, etc. Its result reflects what the hardware is * doing, not what the software is doing. * * The device is assumed to be in one of the FIN or IDLE states: * IDLEstate, FINstate, READfin, READidle, WRfin, or WRidle. * This is a requirement, since various fields in sc have already * been set up for us, and the use of those fields would conflict * with their use by the interrupt routine if we weren't idle or fin. * * Our result is: * 0 if the operation completed normally * 1 if the operation completed abnormally * */arcmd(sc, cmd) register struct ar_softc *sc;{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -