📄 tmscp.c
字号:
/*- * Copyright (c) 1991 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)tmscp.c 7.17 (Berkeley) 1/21/94 *//* * sccsid = "@(#)tmscp.c 1.24 (ULTRIX) 1/21/86"; *//************************************************************************ * * * Licensed from Digital Equipment Corporation * * Copyright (c) * * Digital Equipment Corporation * * Maynard, Massachusetts * * 1985, 1986 * * All rights reserved. * * * * The Information in this software is subject to change * * without notice and should not be construed as a commitment * * by Digital Equipment Corporation. Digital makes no * * representations about the suitability of this software for * * any purpose. It is supplied "As Is" without expressed or * * implied warranty. * * * * If the Regents of the University of California or its * * licensees modify the software in a manner creating * * diriviative copyright rights, appropriate copyright * * legends may be placed on the drivative work in addition * * to that set forth above. * * * ************************************************************************ * * tmscp.c - TMSCP (TK50/TU81) tape device driver * * Modification History: * * 06-Jan-86 - afd * Changed the probe routine to use DELAY (not TODR). This now * works for MicroVAXen as well. This eliminates the busy-wait * for MicroVAXen so a dead TK50 controller will not hang autoconf. * * 06-Dec-85 - afd * Fixed a bug in density selection. The "set unit characteristics" * command to select density, was clearing the "unit flags" field * where the CACHE bit was for TU81-E. Now the unit's "format" and * "unitflgs" are saved in tms_info struct. And are used on STUNT * commands. * * 19-Oct-85 - afd * Added support to the open routine to allow drives to be opened * for low density (800 or 1600 bpi) use. When the slave routine * initiates a "get-unit-char" cmd, the format menu for the unit * is saved in the tms_info structure. The format menu is used in the * start routine to select the proper low density. * * 02-Oct-85 - afd * When a tmscp-type controller is initializing, it is possible for * the sa reg to become 0 between states. Thus the init code in * the interrupt routine had to be modified to reflect this. * * 21-Sep-85 - afd * The TK50 declares a serious exception when a tape mark is encountered. * This causes problems to dd (& other UN*X utilities). So a flag * is set in the rsp() routine when a tape mark is encountered. If * this flag is set, the start() routine appends the Clear Serious * Exception modifier to the next command. * * 03-Sep-85 -- jaw * messed up previous edit.. * * 29-Aug-85 - jaw * fixed bugs in 8200 and 750 buffered datapath handling. * * 06-Aug-85 - afd * 1. When repositioning records or files, the count of items skipped * does NOT HAVE to be returned by controllers (& the TU81 doesn't). * So tmscprsp() had to be modified to stop reporting * residual count errors on reposition commands. * * 2. Fixed bug in the open routine which allowed multiple opens. * * 18-Jul-85 - afd * 1. Need to return status when mt status (or corresponding ioctl) is done. * Save resid, flags, endcode & status in tmscprsp() routine (except on * clear serious exception no-op). Return these fields when status * ioctl is done (in tmscpcommand()). How they are returned: * mt_resid = resid * mt_dsreg = flags|endcode * mt_erreg = status * * 2. Added latent support for enabling/disabling caching. This is * handled along with all other ioctl commands. * * 3. Need to issue a no-op on unrecognized ioctl in tmscpstart(), since * we have already commited to issuing a command at that point. * * 4. In tmscprsp() routine if encode is 0200 (invalid command issued); * We need to: Unlink the buffer from the I/O wait queue, * and signal iodone, so the higher level command can exit! * Just as if it were a valid command. * * 11-jul-85 -- jaw * fix bua/bda map registers. * * 19-Jun-85 -- jaw * VAX8200 name change. * * 06-Jun-85 - jaw * fixes for 8200. * * 9-Apr-85 - afd * Added timeout code to the probe routine, so if the controller * fails to init in 10 seconds we return failed status. * * 13-Mar-85 -jaw * Changes for support of the VAX8200 were merged in. * * 27-Feb-85 -tresvik * Changes for support of the VAX8600 were merged in. * */#include "tms.h"#if NTMSCP > 0#include "sys/param.h"#include "sys/systm.h"#include "sys/buf.h"#include "sys/conf.h"#include "sys/errno.h"#include "sys/file.h"#include "sys/map.h"#include "sys/vm.h"#include "sys/ioctl.h"#include "sys/syslog.h"#include "sys/mtio.h"#include "sys/cmap.h"#include "sys/uio.h"#include "sys/tprintf.h"#include "../include/pte.h"#include "../include/cpu.h"#include "../include/mtpr.h"#include "ubareg.h"#include "ubavar.h"#define TENSEC (1000)#define TMS_PRI LOG_INFO#define NRSPL2 3 /* log2 number of response packets */#define NCMDL2 3 /* log2 number of command packets */#define NRSP (1<<NRSPL2)#define NCMD (1<<NCMDL2)#include "tmscpreg.h"#include "../vax/tmscp.h"/* Software state per controller */struct tmscp_softc { short sc_state; /* state of controller */ short sc_mapped; /* Unibus map allocated for tmscp struct? */ int sc_ubainfo; /* Unibus mapping info */ struct tmscp *sc_tmscp; /* Unibus address of tmscp struct */ int sc_ivec; /* interrupt vector address */ short sc_credits; /* transfer credits */ short sc_lastcmd; /* pointer into command ring */ short sc_lastrsp; /* pointer into response ring */ short sc_ipl; /* interrupt priority (Q-bus) */} tmscp_softc[NTMSCP];struct tmscp { struct tmscpca tmscp_ca; /* communications area */ struct mscp tmscp_rsp[NRSP]; /* response packets */ struct mscp tmscp_cmd[NCMD]; /* command packets */} tmscp[NTMSCP];/* * Per drive-unit info */struct tms_info { daddr_t tms_dsize; /* Max user size from online pkt */ unsigned tms_type; /* Drive type int field */ int tms_resid; /* residual from last xfer */ u_char tms_endcode; /* last command endcode */ u_char tms_flags; /* last command end flags */ unsigned tms_status; /* Command status from last command */ char tms_openf; /* lock against multiple opens */ char tms_lastiow; /* last op was a write */ char tms_serex; /* set when serious exception occurs */ char tms_clserex; /* set when serex being cleared by no-op */ short tms_fmtmenu; /* the unit's format (density) menu */ short tms_unitflgs; /* unit flag parameters */ short tms_format; /* the unit's current format (density) */ tpr_t tms_tpr; /* tprintf handle */} tms_info[NTMS];struct uba_ctlr *tmscpminfo[NTMSCP];struct uba_device *tmsdinfo[NTMS];/* * ifdef other tmscp devices here if they allow more than 1 unit/controller */struct uba_device *tmscpip[NTMSCP][1];struct buf ctmscpbuf[NTMSCP]; /* internal cmd buffer (for ioctls) */struct buf tmsutab[NTMS]; /* Drive queue */struct buf tmscpwtab[NTMSCP]; /* I/O wait queue, per controller */int tmscpmicro[NTMSCP]; /* to store microcode level */short utoctlr[NTMS]; /* Slave unit to controller mapping */ /* filled in by the slave routine *//* Bits in minor device */#define TMSUNIT(dev) (minor(dev)&03)#define T_NOREWIND 04#define T_HIDENSITY 010/* Slave unit to controller mapping */#define TMSCPCTLR(dev) (utoctlr[TMSUNIT(dev)])/* * Internal (ioctl) command codes (these must also be declared in the * tmscpioctl routine). These correspond to ioctls in mtio.h */#define TMS_WRITM 0 /* write tape mark */#define TMS_FSF 1 /* forward space file */#define TMS_BSF 2 /* backward space file */#define TMS_FSR 3 /* forward space record */#define TMS_BSR 4 /* backward space record */#define TMS_REW 5 /* rewind tape */#define TMS_OFFL 6 /* rewind tape & mark unit offline */#define TMS_SENSE 7 /* noop - do a get unit status */#define TMS_CACHE 8 /* enable cache */#define TMS_NOCACHE 9 /* disable cache *//* These go last: after all real mt cmds, just bump the numbers up */#define TMS_CSE 10 /* clear serious exception */#define TMS_LOWDENSITY 11 /* set unit to low density */#define TMS_HIDENSITY 12 /* set unit to high density *//* * Controller states */#define S_IDLE 0 /* hasn't been initialized */#define S_STEP1 1 /* doing step 1 init */#define S_STEP2 2 /* doing step 2 init */#define S_STEP3 3 /* doing step 3 init */#define S_SCHAR 4 /* doing "set controller characteristics" */#define S_RUN 5 /* running */int tmscperror = 0; /* causes hex dump of packets */int tmscp_cp_wait = 0; /* Something to wait on for command */ /* packets and or credits. */int wakeup();extern int hz; /* Should find the right include */#ifdef DEBUG#define printd if (tmscpdebug) printfint tmscpdebug = 1;#define printd10 if(tmscpdebug >= 10) printf#endif int tmscpprobe(), tmscpslave(), tmscpattach(), tmscpintr();struct mscp *tmscpgetcp();#define DRVNAME "tms"#define CTRLNAME "tmscp"u_short tmscpstd[] = { 0174500, 0 };struct uba_driver tmscpdriver ={ tmscpprobe, tmscpslave, tmscpattach, 0, tmscpstd, DRVNAME, tmsdinfo, CTRLNAME, tmscpminfo, 0};#define b_qsize b_resid /* queue size per drive, in tmsutab */#define b_ubinfo b_resid /* Unibus mapping info, per buffer *//*************************************************************************/#define DELAYTEN 1000/* * Unfortunately qbgetpri can't be used because the TK50 doesn't flip the * TMSCP_STEP2 flag in the tmscpsa register until after the pending interrupt * has been acknowledged by the cpu. If you are at spl6(), the TMSCP_STEP2 * flag never gets set and you return (0). */tmscpprobe(reg, ctlr) caddr_t reg; /* address of the IP register */ int ctlr; /* index of controller in the tmscp_softc array */{ register int br, cvec; /* MUST be 1st (r11 & r10): IPL and intr vec */ register struct tmscp_softc *sc = &tmscp_softc[ctlr]; /* ptr to software controller structure */ struct tmscpdevice *tmscpaddr; /* ptr to tmscpdevice struct (IP & SA) */ int count; /* for probe delay time out */# ifdef lint br = 0; cvec = br; br = cvec; reg = reg; tmscpreset(0); tmscpintr(0);# endif tmscpaddr = (struct tmscpdevice *) reg; /* * Set host-settable interrupt vector. * Assign 0 to the ip register to start the tmscp-device initialization. * The device is not really initialized at this point, this is just to * find out if the device exists. */ sc->sc_ivec = (uba_hd[numuba].uh_lastiv -= 4); tmscpaddr->tmscpip = 0; count=0; while(count < DELAYTEN) { /* wait for at most 10 secs */ if((tmscpaddr->tmscpsa & TMSCP_STEP1) != 0) break; DELAY(10000); count=count+1; } if (count == DELAYTEN) return(0); tmscpaddr->tmscpsa = TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8)|TMSCP_IE|(sc->sc_ivec/4); count=0; while(count < DELAYTEN) { if((tmscpaddr->tmscpsa & TMSCP_STEP2) != 0) break; DELAY(10000); count = count+1; } if (count == DELAYTEN) return(0);#ifdef QBA sc->sc_ipl = br = 0x15;#endif return(sizeof (struct tmscpdevice));}/* * Try to find a slave (a drive) on the controller. * If the controller is not in the run state, call init to initialize it. */tmscpslave (ui, reg) struct uba_device *ui; /* ptr to the uba device structure */ caddr_t reg; /* addr of the device controller */{ register struct uba_ctlr *um = tmscpminfo[ui->ui_ctlr]; register struct tmscp_softc *sc = &tmscp_softc[ui->ui_ctlr]; register struct tms_info *tms = &tms_info[ui->ui_unit]; struct tmscpdevice *tmscpaddr; /* ptr to IP & SA */ struct mscp *mp; int i; /* Something to write into to start */ /* the tmscp polling */# ifdef lint reg = reg;# endif tmscpaddr = (struct tmscpdevice *)um->um_addr; /* * If its not in the run state, start the initialization process * (tmscpintr will complete it); if the initialization doesn't start; * then return. */ if(sc->sc_state != S_RUN) {# ifdef DEBUG printd("tmscpslave: ctlr not running: calling init \n");# endif if(!tmscpinit(ui->ui_ctlr)) return(0); } /* * Wait for the controller to come into the run state or go idle. * If it goes idle return. */# ifdef DEBUG i=1;# endif while(sc->sc_state != S_RUN && sc->sc_state != S_IDLE)# ifdef DEBUG if (tmscpaddr->tmscpsa & TMSCP_ERR && i) { printd("tmscp-device: fatal error (%o)\n", tmscpaddr->tmscpsa&0xffff); i=0; }# endif ; /* wait */ if(sc->sc_state == S_IDLE) { /* The tmscp device failed to initialize */ printf("tmscp controller failed to init\n"); return(0); } /* The controller is up so see if the drive is there */ if(0 == (mp = tmscpgetcp(um))) { printf("tmscp can't get command packet\n"); return(0); } /* Need to determine the drive type for generic driver */ mp->mscp_opcode = M_OP_GTUNT; /* This should give us the device type */ mp->mscp_unit = ui->ui_slave; mp->mscp_cmdref = (long) ui->ui_slave; tms->tms_status = 0; /* set to zero */ tmscpip[ui->ui_ctlr][ui->ui_slave] = ui; *((long *) mp->mscp_dscptr ) |= TMSCP_OWN | TMSCP_INT;/* maybe we should poll*/ i = tmscpaddr->tmscpip;#ifdef lint i = i;#endif while(!tms->tms_status) ; /* Wait for some status */# ifdef DEBUG printd("tmscpslave: status = %o\n",tms->tms_status & M_ST_MASK);# endif tmscpip[ui->ui_ctlr][ui->ui_slave] = 0; if(!tms->tms_type) /* packet from a GTUNT */ return(0); /* Failed No such drive */ else return(1); /* Got it and it is there */}/* * Set ui flags to zero to show device is not online & set tmscpip. * Unit to Controller mapping is set up here. * Open routine will issue the online command, later. */tmscpattach (ui) register struct uba_device *ui; /* ptr to unibus dev struct */{ ui->ui_flags = 0; tmscpip[ui->ui_ctlr][ui->ui_slave] = ui;# ifdef DEBUG /* * Check to see if the drive is available. * If not then just print debug. */ if(tms_info[ui->ui_unit].tms_status != M_ST_AVLBL) printd("tmscpattach: unavailable \n");# endif utoctlr[ui->ui_unit] = ui->ui_ctlr;}/* * TMSCP interrupt routine. */tmscpintr (d) int d; /* index to the controller */{ register struct uba_ctlr *um = tmscpminfo[d]; register struct tmscpdevice *tmscpaddr = (struct tmscpdevice *)um->um_addr; struct buf *bp; register int i; register struct tmscp_softc *sc = &tmscp_softc[d]; register struct tmscp *tm = &tmscp[d]; struct tmscp *ttm; struct mscp *mp;# ifdef DEBUG printd10("tmscpintr: state %d, tmscpsa %o\n", sc->sc_state, tmscpaddr->tmscpsa);# endif #ifdef QBA splx(sc->sc_ipl);#endif /* * How the interrupt is handled depends on the state of the controller. */ switch (sc->sc_state) { case S_IDLE: printf("tmscp%d: random interrupt ignored\n", d); return; /* Controller was in step 1 last, see if its gone to step 2 */ case S_STEP1:# define STEP1MASK 0174377# define STEP1GOOD (TMSCP_STEP2|TMSCP_IE|(NCMDL2<<3)|NRSPL2) for (i = 0; i < 150; i++) { if ((tmscpaddr->tmscpsa&STEP1MASK) != STEP1GOOD) { /* still in step 1 (wait 1/100 sec) */ DELAY(10000);# ifdef DEBUG printd("still in step 1, delaying\n");# endif DEBUG } else break; } if (i > 149) { sc->sc_state = S_IDLE; printf("failed to initialize, in step1: sa 0x%x", tmscpaddr->tmscpsa); wakeup((caddr_t)um); return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -