📄 ts.c
字号:
#ifndef lintstatic char *sccsid = "@(#)ts.c 4.1 (ULTRIX) 7/2/90";#endif lint/************************************************************************ * * * Copyright (c) 1984, 1986, 1987, 1989 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//* * ts.c 6.1 07/29/83 * * Modification history * * TS11/TSU05/TSV05/TU80 tape driver * * 22-Jan-85 - Larry Cohen * * Derived from 4.2BSD labeled: ts.c 6.1 83/07/29. * Make probe routine interrupt device instead of hard wired * interrupt vectors. LSC001: * * 6-Mar-85 - Larry Cohen * * Make probe route interrupt correctly. LSC002: * * 13-Mar-85 - jaw * * Add support for VAX8200. * * 19-Jun-85 - jaw * * VAX8200 name change. * * 11-Jul-85 - jaw * * Fix bua/bda map registers. * * 6-Aug-85 - ricky palmer * * Added new ioctl functionality as well as new code to handle * EOT correctly. Driver now supports new minor number convention * to allow for more than 4 tape devices. V2.0 * * 8-Feb-86 - ricky palmer * * Added streaming tape support for ts05/tsv05 subsystem. V2.0 * * 18-Mar-86 - jaw * * br/cvec changed to NOT use registers. * * 19-Mar-86 - ricky palmer * * Added new DEVIOCGET ioctl request code. V2.0 * * 13-Jun-86 - jaw * * Fix to uba reset and drivers. * * 11-Jul-86 - ricky palmer * * Added adpt and nexus fields to DEVIOCGET code. * * 26-Aug-86 - rsp (Ricky Palmer) * * Cleaned up devioctl code to (1) zero out devget structure * upon entry and (2) use strlen instead of fixed storage * for bcopy's. * * 30-Oct-86 - lp * * TPMARK & HARDERR now prevent further n-buffered requests. * * 04-Dec-86 - pmk * * Changed mprintf to log just one entry. * * 08-Jul-87 - rsp * * Corrected attach routine to correctly fill in TS05 device string. * * 05-MAY-89 - dallas * Modified the ts_init and ts_probe routines to not set any of the * bits in the extended characteristics data word for the wrt. char. * command. The set of these bits are for diag's purposes only. To * bad the documentation leads you to believe that you should be * mucking with the word. Setting of the bits in the word really * confuses the controller. Also added global int ts_softerr and a * mprintf - for field service and css purposes. With adb the setting * of the int allows all soft errors to be reported to the errlog. * * 05-Jun-89 - Tim Burke * Added a new MTIOCTOP called MTFLUSH. This is used on caching drives * to force a flush of the controller's write back cache. Since this * is not a caching drive the MTFLUSH always returns ENXIO. * * 22-Jul-89 - kuo-hsiung hsieh * Added codes for mipsfair (DS_5400). * * 05-DEC-89 - Bill Dallas * In tswait changed the declaration of register int s to * register volatile int s This change is for the mips compiler * optimization of the assign out of the do while loop if * not declared as volatile. */#include "ts.h"#if NTS > 0 || defined(BINARY)#include "../data/ts_data.c"extern int cpu;u_short tsstd[] = { TSSTD, 0 };int tsprobe(), tsslave(), tsattach(), tsdgo(), tsintr();struct uba_driver zsdriver = { tsprobe, tsslave, tsattach, tsdgo, tsstd, "ts", tsdinfo, "zs", tsminfo, 0 };int ts_softerr = 0; /* declared for soft error reports..Field service * needs this.. Reasons for not streaming - dallas *//* * Determine if there is a controller for * a ts at address reg. The goal is to make the * device interrupt. */tsprobe(reg, ctrl) caddr_t reg; int ctrl;{ int i, ubaddr, uba_cmdaddr; struct ts_softc *sc;#ifdef lint tsintr(0);#endif lint ((struct tsdevice *)reg)->tssr = 0;/* * LSC001: * LSC002: */ DELAY(5000000); if ((((struct tsdevice *)reg)->tssr & TS_NBA) == 0) return(0); sc = &ts_softc[ctrl]; ctsbuf[ctrl].b_un.b_addr = (caddr_t)sc; ctsbuf[ctrl].b_bcount = sizeof(*sc); ubaddr = ubasetup(numuba, &ctsbuf[ctrl], 0); i = ubaddr & 0777777; sc->sc_ubaddr = (struct ts_softc *)i; uba_cmdaddr = (int)&sc->sc_ubaddr->sc_cmd; sc->sc_uba = (u_short)(uba_cmdaddr + ((uba_cmdaddr>>16)&3)); sc->sc_char.char_addr = (int)&sc->sc_ubaddr->sc_sts; sc->sc_char.char_size = sizeof(struct ts_sts); sc->sc_char.char_mode = TS_ESS; /* dallas get rid of following line these bits are only for diags. * and seems to really confuse the drive/controller * sc->sc_char.char_modext = TS_ENHSP|TS_ENBUF;*/ sc->sc_char.char_modext = 0; /* make sure 0 for tsv and tsu controllers, for ts11 controllers it ignores them. */ sc->sc_cmd.c_cmd = TS_ACK | TS_IE | TS_SETCHR; i = (int)&sc->sc_ubaddr->sc_char; sc->sc_cmd.c_loba = i; sc->sc_cmd.c_hiba = (i>>16)&3; sc->sc_cmd.c_size = sizeof(struct ts_char); ((struct tsdevice *)reg)->tsdb = sc->sc_uba; DELAY(5000000); if (cvec && cvec == 0x200) /* check for interrupt */ ubarelse(numuba, &ubaddr); /* release resources */ else sc->sc_mapped++; ((struct tsdevice *)reg)->tssr = 0; /* reset device so * first open * does not hang */ DELAY(100000); return (sizeof (struct tsdevice));}/* * TS11 only supports one drive per controller; * check for ui_slave == 0. */tsslave(ui, reg) struct uba_device *ui; caddr_t reg;{ if (ui->ui_slave) /* non-zero slave not allowed */ return(0); return (1);}/* * Record attachment of the unit to the controller. */tsattach(ui) struct uba_device *ui;{ register struct ts_softc *sc = &ts_softc[ui->ui_unit]; sc->sc_softcnt = 0; sc->sc_hardcnt = 0; if(sc->sc_sts.s_xs2 & TS_TU80) { bcopy(DEV_TU80,sc->sc_device,strlen(DEV_TU80)); } else { if(ui->ui_hd->uba_type & (UBAUVI|UBAUVII)) { bcopy(DEV_TS05,sc->sc_device,strlen(DEV_TS05)); } else { bcopy(DEV_TS11,sc->sc_device,strlen(DEV_TS11)); } }}/* * Open the device. Tapes are unique open * devices, so we refuse if it is already open. * We also check that a tape is available, and * don't block waiting here; if you want to wait * for a tape you should timeout in user code. */tsopen(dev, flag) register dev_t dev; register int flag;{ register struct uba_device *ui; register struct ts_softc *sc; register int unit = UNIT(dev); if (unit >= nNTS || (sc = &ts_softc[unit])->sc_openf || (ui = tsdinfo[unit]) == 0 || ui->ui_alive == 0) { return (ENXIO); } if ((sc->sc_sts.s_xs0 & TS_EOT) && (dis_eot_ts[unit] != DISEOT)) { sc->sc_flags &= DEV_EOM; } else { sc->sc_flags = 0; } sc->sc_category_flags = 0; if (tsinit(unit)) return (ENXIO); tscommand(dev, TS_SENSE, 1); sc->sc_category_flags |= DEV_1600BPI; if((strcmp(DEV_TS05,sc->sc_device)) == 0) { DELAY(100000); tscommand(dev, TS_SENSE, 1); } if ((sc->sc_sts.s_xs0 & TS_ONL) == 0) { sc->sc_flags |= DEV_OFFLINE; if(!(flag & FNDELAY)) { DEV_UGH(sc->sc_device,unit,"offline"); return(EIO); } } if (sc->sc_sts.s_xs0 & TS_WLK) { sc->sc_flags |= DEV_WRTLCK; } if ((flag & (FREAD|FWRITE)) == FWRITE && (sc->sc_sts.s_xs0 & TS_WLK)) { if(!(flag & FNDELAY)) { DEV_UGH(sc->sc_device,unit,"write locked"); return(EIO); } } sc->sc_openf = 1; sc->sc_blkno = (daddr_t)0; sc->sc_nxrec = INF; return (0);}/* * 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. */tsclose(dev, flag) register dev_t dev; register int flag;{ register struct ts_softc *sc = &ts_softc[UNIT(dev)]; register int unit = UNIT(dev); register int sel = SEL(dev); sc->sc_flags &= ~DEV_EOM; if (flag == FWRITE || (flag&FWRITE) && (sc->sc_flags & DEV_WRITTEN)) { tscommand(dev, TS_WEOF, 1); sc->sc_flags &= ~DEV_EOM; tscommand(dev, TS_WEOF, 1); sc->sc_flags &= ~DEV_EOM; tscommand(dev, TS_SREV, 1); sc->sc_flags &= ~DEV_EOM; } if (sel == MTHR) /* * 0 count means don't hang waiting for rewind complete * rather ctsbuf stays busy until the operation * completes preventing further opens from completing * by preventing a TS_SENSE from completing. */ tscommand(dev, TS_REW, 0); sc->sc_openf = 0; if ((sc->sc_sts.s_xs0 & TS_EOT) && (dis_eot_ts[unit] != DISEOT)) { sc->sc_flags |= DEV_EOM; }}/* * Initialize the TS11. Set up bus mapping for command * packets and set device characteristics. */tsinit(unit) register int unit;{ register struct ts_softc *sc = &ts_softc[unit]; register struct uba_ctlr *um = tsminfo[unit]; register struct tsdevice *addr = (struct tsdevice *)um->um_addr; register int i; /* * Map the command and message packets into bus * address space. We do all the command and message * packets at once to minimize the amount of bus * mapping necessary. */ if (sc->sc_mapped == 0) { ctsbuf[unit].b_un.b_addr = (caddr_t)sc; ctsbuf[unit].b_bcount = sizeof(*sc); i = ubasetup(um->um_ubanum, &ctsbuf[unit], 0); i &= 0777777; sc->sc_ubaddr = (struct ts_softc *)i; sc->sc_mapped++; } /* * Now initialize the TS11 controller. * Set the characteristics. */ if (addr->tssr & (TS_NBA|TS_OFL)) { addr->tssr = 0; /* subsystem initialize */ tswait(addr); i = (int)&sc->sc_ubaddr->sc_cmd; /* bus addr of cmd */ sc->sc_uba = (u_short)(i + ((i>>16)&3)); sc->sc_char.char_addr = (int)&sc->sc_ubaddr->sc_sts; sc->sc_char.char_size = sizeof(struct ts_sts); sc->sc_char.char_mode = TS_ESS; /* get rid of this line, bits only for diags and really * confuses the tsv05 * sc->sc_char.char_modext = TS_ENHSP|TS_ENBUF; */ sc->sc_char.char_modext = 0; /* for tsv and tsu controllers ts11 controllers ignore them. */ sc->sc_cmd.c_cmd = TS_ACK | TS_SETCHR; i = (int)&sc->sc_ubaddr->sc_char; sc->sc_cmd.c_loba = i; sc->sc_cmd.c_hiba = (i>>16)&3; sc->sc_cmd.c_size = sizeof(struct ts_char); addr->tsdb = sc->sc_uba; tswait(addr); if (addr->tssr & TS_NBA) return(1); } return(0);}/* * Execute a command on the tape drive * a specified number of times. */tscommand(dev, com, count) register dev_t dev; register int com; register int count;{ register struct buf *bp = &ctsbuf[UNIT(dev)]; register int s = splbio(); while (bp->b_flags & B_BUSY) { /* * This special check is because B_BUSY never * gets cleared in the non-waiting rewind case. */ if (bp->b_repcnt == 0 && (bp->b_flags & B_DONE)) break; bp->b_flags |= B_WANTED; sleep((caddr_t)bp, PRIBIO); } bp->b_flags = B_BUSY|B_READ; splx(s); bp->b_dev = dev; bp->b_repcnt = count; bp->b_command = com; bp->b_blkno = 0; tsstrategy(bp); /* * In case of rewind from close, don't wait. * This is the only case where count can be 0. */ if (count == 0) return; iowait(bp); if (bp->b_flags & B_WANTED) wakeup((caddr_t)bp); bp->b_flags &= B_ERROR;}/* * Queue a tape operation. */tsstrategy(bp) register struct buf *bp;{ register struct uba_ctlr *um; register struct ts_softc *sc = &ts_softc[UNIT(bp->b_dev)]; register struct buf *dp; register int s; int unit = UNIT(bp->b_dev); if ((sc->sc_flags & DEV_EOM) && !((sc->sc_flags & DEV_CSE) || (dis_eot_ts[unit] & DISEOT))) { bp->b_resid = bp->b_bcount; bp->b_error = ENOSPC; bp->b_flags |= B_ERROR; iodone(bp); return; } if((bp->b_flags&B_READ) && (bp->b_flags&B_RAWASYNC) && ((sc->sc_category_flags&DEV_TPMARK) || (sc->sc_flags&DEV_HARDERR))) { bp->b_error = EIO; bp->b_flags |= B_ERROR; iodone(bp); return; } /* * Put transfer at end of controller queue */ bp->av_forw = NULL; um = tsdinfo[unit]->ui_mi; s = splbio(); dp = &tsutab[unit]; if (dp->b_actf == NULL) dp->b_actf = bp; else dp->b_actl->av_forw = bp; dp->b_actl = bp; um->um_tab.b_actf = um->um_tab.b_actl = dp; /* * If the controller is not busy, get * it going. */ if (um->um_tab.b_active == 0) tsstart(um); splx(s);}/* * Start activity on a ts controller. */tsstart(um) register struct uba_ctlr *um;{ register struct tsdevice *addr = (struct tsdevice *)um->um_addr; register struct buf *bp; register struct ts_softc *sc; register struct ts_cmd *tc; struct uba_device *ui; int cmd, unit; daddr_t blkno;loop: /* * Start the controller if there is something for it to do. */ if ((bp = um->um_tab.b_actf->b_actf) == NULL) return; unit = UNIT(bp->b_dev); ui = tsdinfo[unit]; sc = &ts_softc[unit]; tc = &sc->sc_cmd; if ((sc->sc_flags & DEV_EOM) && !((sc->sc_flags & DEV_CSE) || (dis_eot_ts[unit] & DISEOT))) { bp->b_resid = bp->b_bcount; bp->b_error = ENOSPC; bp->b_flags |= B_ERROR; goto next; } if (((sc->sc_category_flags&DEV_TPMARK) ||(sc->sc_flags&DEV_HARDERR)) && (bp->b_flags & B_READ) && (bp->b_flags&B_RAWASYNC)) { bp->b_error = EIO; bp->b_flags |= B_ERROR; goto next; } /* * Default is that last command was NOT a write command; * if we do a write command we will notice this in tsintr(). */ sc->sc_flags &= ~DEV_WRITTEN; if (sc->sc_openf < 0 || (addr->tssr & TS_OFL)) { /* * Have had a hard error on a non-raw tape * or the tape unit is now unavailable * (e.g. taken off line). */ bp->b_flags |= B_ERROR; goto next; } if (bp == &ctsbuf[unit]) { /* * Execute control operation with the specified count. */ um->um_tab.b_active = bp->b_command == TS_REW ? SREW : SCOM; tc->c_repcnt = bp->b_repcnt; goto dobpcmd; } if (sc->sc_blkno != bdbtofsb(bp->b_blkno) && !um->um_tab.b_errcnt) sc->sc_blkno = bdbtofsb(bp->b_blkno); sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1; /* * If the data transfer command is in the correct place, * set up all the registers except the csr, and give * control over to the BUS adapter routines, to * wait for resources to start the i/o. */ if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { tc->c_size = bp->b_bcount; if ((bp->b_flags&B_READ) == 0) cmd = TS_WCOM; else cmd = TS_RCOM; if (um->um_tab.b_errcnt) { cmd |= TS_RETRY; sc->sc_softcnt++; sc->sc_flags |= DEV_RETRY; } um->um_tab.b_active = SIO; tc->c_cmd = TS_ACK | TS_CVC | TS_IE | cmd; (void) ubago(ui); return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -