1*1625a9a8Skarels /* @(#)tmscp.c 5.1 (Berkeley) 02/11/86 */ 2bc5e3c50Skarels 3bc5e3c50Skarels #ifndef lint 4bc5e3c50Skarels static char *sccsid = "@(#)tmscp.c 1.24 (ULTRIX) 1/21/86"; 5bc5e3c50Skarels #endif lint 6bc5e3c50Skarels 7bc5e3c50Skarels 8bc5e3c50Skarels /************************************************************************ 9bc5e3c50Skarels * * 10bc5e3c50Skarels * Copyright (c) 1985 by * 11bc5e3c50Skarels * Digital Equipment Corporation, Maynard, MA * 12bc5e3c50Skarels * * 13bc5e3c50Skarels * Permission to use, copy, modify, and distribute this software * 14bc5e3c50Skarels * and its documentation is hereby granted to licensees of the * 15bc5e3c50Skarels * Regents of the University of California pursuant to their * 16bc5e3c50Skarels * license agreement for the "Fourth Berkeley Software * 17bc5e3c50Skarels * Distribution". * 18bc5e3c50Skarels * * 19bc5e3c50Skarels * The information in this software is subject to change without * 20bc5e3c50Skarels * notice and should not be construed as a commitment by Digital * 21bc5e3c50Skarels * Equipment Corporation. Digital makes no representations * 22bc5e3c50Skarels * about suitability of this software for any purpose. It is * 23bc5e3c50Skarels * supplied "as is" without express or implied warranty. * 24bc5e3c50Skarels * * 25bc5e3c50Skarels * This software is not subject to any license of the American * 26bc5e3c50Skarels * Telephone and Telegraph Company. * 27bc5e3c50Skarels * * 28bc5e3c50Skarels ************************************************************************ 29bc5e3c50Skarels * 30bc5e3c50Skarels * tmscp.c - TMSCP (TK50/TU81) tape device driver 31bc5e3c50Skarels * 32bc5e3c50Skarels * Modification History: 33bc5e3c50Skarels * 34bc5e3c50Skarels * 06-Jan-86 - afd 35bc5e3c50Skarels * Changed the probe routine to use DELAY (not TODR). This now 36bc5e3c50Skarels * works for MicroVAXen as well. This eliminates the busy-wait 37bc5e3c50Skarels * for MicroVAXen so a dead TK50 controller will not hang autoconf. 38bc5e3c50Skarels * 39bc5e3c50Skarels * 06-Dec-85 - afd 40bc5e3c50Skarels * Fixed a bug in density selection. The "set unit characteristics" 41bc5e3c50Skarels * command to select density, was clearing the "unit flags" field 42bc5e3c50Skarels * where the CACHE bit was for TU81-E. Now the unit's "format" and 43bc5e3c50Skarels * "unitflgs" are saved in tms_info struct. And are used on STUNT 44bc5e3c50Skarels * commands. 45bc5e3c50Skarels * 46bc5e3c50Skarels * 19-Oct-85 - afd 47bc5e3c50Skarels * Added support to the open routine to allow drives to be opened 48bc5e3c50Skarels * for low density (800 or 1600 bpi) use. When the slave routine 49bc5e3c50Skarels * initiates a "get-unit-char" cmd, the format menu for the unit 50bc5e3c50Skarels * is saved in the tms_info structure. The format menu is used in the 51bc5e3c50Skarels * start routine to select the proper low density. 52bc5e3c50Skarels * 53bc5e3c50Skarels * 02-Oct-85 - afd 54bc5e3c50Skarels * When a tmscp-type controller is initializing, it is possible for 55bc5e3c50Skarels * the sa reg to become 0 between states. Thus the init code in 56bc5e3c50Skarels * the interrupt routine had to be modified to reflect this. 57bc5e3c50Skarels * 58bc5e3c50Skarels * 21-Sep-85 - afd 59bc5e3c50Skarels * The TK50 declares a serious exception when a tape mark is encountered. 60bc5e3c50Skarels * This causes problems to dd (& other UN*X utilities). So a flag 61bc5e3c50Skarels * is set in the rsp() routine when a tape mark is encountered. If 62bc5e3c50Skarels * this flag is set, the start() routine appends the Clear Serious 63bc5e3c50Skarels * Exception modifier to the next command. 64bc5e3c50Skarels * 65bc5e3c50Skarels * 03-Sep-85 -- jaw 66bc5e3c50Skarels * messed up previous edit.. 67bc5e3c50Skarels * 68bc5e3c50Skarels * 29-Aug-85 - jaw 69bc5e3c50Skarels * fixed bugs in 8200 and 750 buffered datapath handling. 70bc5e3c50Skarels * 71bc5e3c50Skarels * 06-Aug-85 - afd 72bc5e3c50Skarels * 1. When repositioning records or files, the count of items skipped 73bc5e3c50Skarels * does NOT HAVE to be returned by controllers (& the TU81 doesn't). 74bc5e3c50Skarels * So tmscprsp() had to be modified to stop reporting 75bc5e3c50Skarels * residual count errors on reposition commands. 76bc5e3c50Skarels * 77bc5e3c50Skarels * 2. Fixed bug in the open routine which allowed multiple opens. 78bc5e3c50Skarels * 79bc5e3c50Skarels * 18-Jul-85 - afd 80bc5e3c50Skarels * 1. Need to return status when mt status (or corresponding ioctl) is done. 81bc5e3c50Skarels * Save resid, flags, endcode & status in tmscprsp() routine (except on 82bc5e3c50Skarels * clear serious exception no-op). Return these fields when status 83bc5e3c50Skarels * ioctl is done (in tmscpcommand()). How they are returned: 84bc5e3c50Skarels * mt_resid = resid 85bc5e3c50Skarels * mt_dsreg = flags|endcode 86bc5e3c50Skarels * mt_erreg = status 87bc5e3c50Skarels * 88bc5e3c50Skarels * 2. Added latent support for enabling/disabling caching. This is 89bc5e3c50Skarels * handled along with all other ioctl commands. 90bc5e3c50Skarels * 91bc5e3c50Skarels * 3. Need to issue a no-op on unrecognized ioctl in tmscpstart(), since 92bc5e3c50Skarels * we have already commited to issuing a command at that point. 93bc5e3c50Skarels * 94bc5e3c50Skarels * 4. In tmscprsp() routine if encode is 0200 (invalid command issued); 95bc5e3c50Skarels * We need to: Unlink the buffer from the I/O wait queue, 96bc5e3c50Skarels * and signal iodone, so the higher level command can exit! 97bc5e3c50Skarels * Just as if it were a valid command. 98bc5e3c50Skarels * 99bc5e3c50Skarels * 11-jul-85 -- jaw 100bc5e3c50Skarels * fix bua/bda map registers. 101bc5e3c50Skarels * 102bc5e3c50Skarels * 19-Jun-85 -- jaw 103bc5e3c50Skarels * VAX8200 name change. 104bc5e3c50Skarels * 105bc5e3c50Skarels * 06-Jun-85 - jaw 106bc5e3c50Skarels * fixes for 8200. 107bc5e3c50Skarels * 108bc5e3c50Skarels * 9-Apr-85 - afd 109bc5e3c50Skarels * Added timeout code to the probe routine, so if the controller 110bc5e3c50Skarels * fails to init in 10 seconds we return failed status. 111bc5e3c50Skarels * 112bc5e3c50Skarels * 13-Mar-85 -jaw 113bc5e3c50Skarels * Changes for support of the VAX8200 were merged in. 114bc5e3c50Skarels * 115bc5e3c50Skarels * 27-Feb-85 -tresvik 116bc5e3c50Skarels * Changes for support of the VAX8600 were merged in. 117bc5e3c50Skarels * 118bc5e3c50Skarels */ 119bc5e3c50Skarels 120bc5e3c50Skarels #include "tms.h" 121*1625a9a8Skarels #if NTMSCP > 0 122bc5e3c50Skarels 123*1625a9a8Skarels #include "../vax/pte.h" 124*1625a9a8Skarels 125*1625a9a8Skarels #include "param.h" 126*1625a9a8Skarels #include "systm.h" 127*1625a9a8Skarels #include "buf.h" 128*1625a9a8Skarels #include "conf.h" 129*1625a9a8Skarels #include "dir.h" 130*1625a9a8Skarels #include "user.h" 131*1625a9a8Skarels #include "file.h" 132*1625a9a8Skarels #include "map.h" 133*1625a9a8Skarels #include "vm.h" 134*1625a9a8Skarels #include "ioctl.h" 135*1625a9a8Skarels #include "syslog.h" 136*1625a9a8Skarels #include "mtio.h" 137*1625a9a8Skarels #include "cmap.h" 138*1625a9a8Skarels #include "uio.h" 139*1625a9a8Skarels 140*1625a9a8Skarels #include "../vax/cpu.h" 141*1625a9a8Skarels #include "../vax/mtpr.h" 142*1625a9a8Skarels #include "ubareg.h" 143*1625a9a8Skarels #include "ubavar.h" 144*1625a9a8Skarels 145*1625a9a8Skarels #define TENSEC (1000) 146*1625a9a8Skarels #define TMS_PRI LOG_INFO 147*1625a9a8Skarels 148*1625a9a8Skarels #define NRSPL2 3 /* log2 number of response packets */ 149*1625a9a8Skarels #define NCMDL2 3 /* log2 number of command packets */ 150*1625a9a8Skarels #define NRSP (1<<NRSPL2) 151*1625a9a8Skarels #define NCMD (1<<NCMDL2) 152*1625a9a8Skarels 153*1625a9a8Skarels #include "tmscpreg.h" 154*1625a9a8Skarels #include "../vax/tmscp.h" 155*1625a9a8Skarels 156*1625a9a8Skarels /* Software state per controller */ 157*1625a9a8Skarels 158*1625a9a8Skarels struct tmscp_softc { 159*1625a9a8Skarels short sc_state; /* state of controller */ 160*1625a9a8Skarels short sc_mapped; /* Unibus map allocated for tmscp struct? */ 161*1625a9a8Skarels int sc_ubainfo; /* Unibus mapping info */ 162*1625a9a8Skarels struct tmscp *sc_tmscp; /* Unibus address of tmscp struct */ 163*1625a9a8Skarels int sc_ivec; /* interrupt vector address */ 164*1625a9a8Skarels short sc_credits; /* transfer credits */ 165*1625a9a8Skarels short sc_lastcmd; /* pointer into command ring */ 166*1625a9a8Skarels short sc_lastrsp; /* pointer into response ring */ 167*1625a9a8Skarels } tmscp_softc[NTMSCP]; 168*1625a9a8Skarels 169*1625a9a8Skarels struct tmscp { 170*1625a9a8Skarels struct tmscpca tmscp_ca; /* communications area */ 171*1625a9a8Skarels struct mscp tmscp_rsp[NRSP]; /* response packets */ 172*1625a9a8Skarels struct mscp tmscp_cmd[NCMD]; /* command packets */ 173*1625a9a8Skarels } tmscp[NTMSCP]; 174*1625a9a8Skarels 175*1625a9a8Skarels /* 176*1625a9a8Skarels * Per drive-unit info 177*1625a9a8Skarels */ 178*1625a9a8Skarels struct tms_info { 179*1625a9a8Skarels daddr_t tms_dsize; /* Max user size from online pkt */ 180*1625a9a8Skarels unsigned tms_type; /* Drive type int field */ 181*1625a9a8Skarels int tms_resid; /* residual from last xfer */ 182*1625a9a8Skarels u_char tms_endcode; /* last command endcode */ 183*1625a9a8Skarels u_char tms_flags; /* last command end flags */ 184*1625a9a8Skarels unsigned tms_status; /* Command status from last command */ 185*1625a9a8Skarels char tms_openf; /* lock against multiple opens */ 186*1625a9a8Skarels char tms_lastiow; /* last op was a write */ 187*1625a9a8Skarels char tms_serex; /* set when serious exception occurs */ 188*1625a9a8Skarels char tms_clserex; /* set when serex being cleared by no-op */ 189*1625a9a8Skarels short tms_fmtmenu; /* the unit's format (density) menu */ 190*1625a9a8Skarels short tms_unitflgs; /* unit flag parameters */ 191*1625a9a8Skarels short tms_format; /* the unit's current format (density) */ 192*1625a9a8Skarels struct tty *tms_ttyp; /* record user's tty for errors */ 193*1625a9a8Skarels } tms_info[NTMS]; 194*1625a9a8Skarels struct uba_ctlr *tmscpminfo[NTMSCP]; 195*1625a9a8Skarels struct uba_device *tmsdinfo[NTMS]; 196*1625a9a8Skarels /* 197*1625a9a8Skarels * ifdef other tmscp devices here if they allow more than 1 unit/controller 198*1625a9a8Skarels */ 199*1625a9a8Skarels struct uba_device *tmscpip[NTMSCP][1]; 200*1625a9a8Skarels struct buf rtmsbuf[NTMS]; /* raw i/o buffer */ 201*1625a9a8Skarels struct buf ctmscpbuf[NTMSCP]; /* internal cmd buffer (for ioctls) */ 202*1625a9a8Skarels struct buf tmsutab[NTMS]; /* Drive queue */ 203*1625a9a8Skarels struct buf tmscpwtab[NTMSCP]; /* I/O wait queue, per controller */ 204*1625a9a8Skarels int tmscpmicro[NTMSCP]; /* to store microcode level */ 205*1625a9a8Skarels short utoctlr[NTMS]; /* Slave unit to controller mapping */ 206*1625a9a8Skarels /* filled in by the slave routine */ 207bc5e3c50Skarels 208bc5e3c50Skarels /* Bits in minor device */ 209bc5e3c50Skarels #define TMSUNIT(dev) (minor(dev)&03) 210bc5e3c50Skarels #define T_NOREWIND 04 211bc5e3c50Skarels #define T_HIDENSITY 010 212bc5e3c50Skarels 213bc5e3c50Skarels /* Slave unit to controller mapping */ 214bc5e3c50Skarels #define TMSCPCTLR(dev) (utoctlr[TMSUNIT(dev)]) 215bc5e3c50Skarels 216bc5e3c50Skarels /* 217bc5e3c50Skarels * Internal (ioctl) command codes (these must also be declared in the 218bc5e3c50Skarels * tmscpioctl routine). These correspond to ioctls in mtio.h 219bc5e3c50Skarels */ 220bc5e3c50Skarels #define TMS_WRITM 0 /* write tape mark */ 221bc5e3c50Skarels #define TMS_FSF 1 /* forward space file */ 222bc5e3c50Skarels #define TMS_BSF 2 /* backward space file */ 223bc5e3c50Skarels #define TMS_FSR 3 /* forward space record */ 224bc5e3c50Skarels #define TMS_BSR 4 /* backward space record */ 225bc5e3c50Skarels #define TMS_REW 5 /* rewind tape */ 226bc5e3c50Skarels #define TMS_OFFL 6 /* rewind tape & mark unit offline */ 227bc5e3c50Skarels #define TMS_SENSE 7 /* noop - do a get unit status */ 228bc5e3c50Skarels #define TMS_CACHE 8 /* enable cache */ 229bc5e3c50Skarels #define TMS_NOCACHE 9 /* disable cache */ 230bc5e3c50Skarels /* These go last: after all real mt cmds, just bump the numbers up */ 231bc5e3c50Skarels #define TMS_CSE 10 /* clear serious exception */ 232bc5e3c50Skarels #define TMS_LOWDENSITY 11 /* set unit to low density */ 233bc5e3c50Skarels #define TMS_HIDENSITY 12 /* set unit to high density */ 234bc5e3c50Skarels 235bc5e3c50Skarels /* 236bc5e3c50Skarels * Controller states 237bc5e3c50Skarels */ 238bc5e3c50Skarels #define S_IDLE 0 /* hasn't been initialized */ 239bc5e3c50Skarels #define S_STEP1 1 /* doing step 1 init */ 240bc5e3c50Skarels #define S_STEP2 2 /* doing step 2 init */ 241bc5e3c50Skarels #define S_STEP3 3 /* doing step 3 init */ 242bc5e3c50Skarels #define S_SCHAR 4 /* doing "set controller characteristics" */ 243bc5e3c50Skarels #define S_RUN 5 /* running */ 244bc5e3c50Skarels 245bc5e3c50Skarels int tmscperror = 0; /* causes hex dump of packets */ 246bc5e3c50Skarels int tmscp_cp_wait = 0; /* Something to wait on for command */ 247bc5e3c50Skarels /* packets and or credits. */ 248bc5e3c50Skarels int wakeup(); 249bc5e3c50Skarels extern int hz; /* Should find the right include */ 250bc5e3c50Skarels 251bc5e3c50Skarels #ifdef DEBUG 252bc5e3c50Skarels #define printd if (tmscpdebug) printf 253bc5e3c50Skarels int tmscpdebug = 1; 254bc5e3c50Skarels #define printd10 if(tmscpdebug >= 10) printf 255bc5e3c50Skarels #endif 256bc5e3c50Skarels 257bc5e3c50Skarels int tmscpprobe(), tmscpslave(), tmscpattach(), tmscpintr(); 258bc5e3c50Skarels struct mscp *tmscpgetcp(); 259bc5e3c50Skarels 260bc5e3c50Skarels #define DRVNAME "tms" 261bc5e3c50Skarels #define CTRLNAME "tmscp" 262bc5e3c50Skarels 263bc5e3c50Skarels u_short tmscpstd[] = { 0174500, 0 }; 264bc5e3c50Skarels struct uba_driver tmscpdriver = 265bc5e3c50Skarels { tmscpprobe, tmscpslave, tmscpattach, 0, tmscpstd, DRVNAME, tmsdinfo, CTRLNAME 266bc5e3c50Skarels , tmscpminfo, 0}; 267bc5e3c50Skarels 268bc5e3c50Skarels #define b_qsize b_resid /* queue size per drive, in tmsutab */ 269bc5e3c50Skarels #define b_ubinfo b_resid /* Unibus mapping info, per buffer */ 270bc5e3c50Skarels 271bc5e3c50Skarels 272bc5e3c50Skarels /*************************************************************************/ 273bc5e3c50Skarels 274bc5e3c50Skarels #define DELAYTEN 1000 275bc5e3c50Skarels 276bc5e3c50Skarels tmscpprobe(reg, ctlr) 277bc5e3c50Skarels caddr_t reg; /* address of the IP register */ 278*1625a9a8Skarels int ctlr; /* index of controller in the tmscp_softc array */ 279bc5e3c50Skarels { 280bc5e3c50Skarels register int br, cvec; /* MUST be 1st (r11 & r10): IPL and intr vec */ 281bc5e3c50Skarels register struct tmscp_softc *sc = &tmscp_softc[ctlr]; 282bc5e3c50Skarels /* ptr to software controller structure */ 283*1625a9a8Skarels struct tmscpdevice *tmscpaddr; /* ptr to tmscpdevice struct (IP & SA) */ 284*1625a9a8Skarels struct uba_ctlr *um; /* UNUSED ptr to uba_ctlr (controller) struct */ 285bc5e3c50Skarels int count; /* for probe delay time out */ 286bc5e3c50Skarels 287bc5e3c50Skarels # ifdef lint 288bc5e3c50Skarels br = 0; cvec = br; br = cvec; reg = reg; 289bc5e3c50Skarels tmscpreset(0); tmscpintr(0); 290bc5e3c50Skarels # endif 291bc5e3c50Skarels 292bc5e3c50Skarels tmscpaddr = (struct tmscpdevice *) reg; 293bc5e3c50Skarels /* 294bc5e3c50Skarels * Set host-settable interrupt vector. 295*1625a9a8Skarels * Assign 0 to the ip register to start the tmscp-device initialization. 296bc5e3c50Skarels * The device is not really initialized at this point, this is just to 297bc5e3c50Skarels * find out if the device exists. 298bc5e3c50Skarels */ 299bc5e3c50Skarels sc->sc_ivec = (uba_hd[numuba].uh_lastiv -= 4); 300bc5e3c50Skarels tmscpaddr->tmscpip = 0; 301bc5e3c50Skarels 302bc5e3c50Skarels count=0; 303bc5e3c50Skarels while(count < DELAYTEN) 304bc5e3c50Skarels { /* wait for at most 10 secs */ 305bc5e3c50Skarels if((tmscpaddr->tmscpsa & TMSCP_STEP1) != 0) 306bc5e3c50Skarels break; 307bc5e3c50Skarels DELAY(10000); 308bc5e3c50Skarels count=count+1; 309bc5e3c50Skarels } 310bc5e3c50Skarels if (count == DELAYTEN) 311bc5e3c50Skarels return(0); 312bc5e3c50Skarels 313*1625a9a8Skarels tmscpaddr->tmscpsa = TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8)|TMSCP_IE|(sc->sc_ivec/4); 314bc5e3c50Skarels 315bc5e3c50Skarels count=0; 316bc5e3c50Skarels while(count < DELAYTEN) 317bc5e3c50Skarels { 318bc5e3c50Skarels if((tmscpaddr->tmscpsa & TMSCP_STEP2) != 0) 319bc5e3c50Skarels break; 320bc5e3c50Skarels DELAY(10000); 321bc5e3c50Skarels count = count+1; 322bc5e3c50Skarels } 323bc5e3c50Skarels if (count == DELAYTEN) 324bc5e3c50Skarels return(0); 325bc5e3c50Skarels 326bc5e3c50Skarels return(sizeof (struct tmscpdevice)); 327bc5e3c50Skarels } 328bc5e3c50Skarels 329bc5e3c50Skarels /* 330bc5e3c50Skarels * Try to find a slave (a drive) on the controller. 331bc5e3c50Skarels * If the controller is not in the run state, call init to initialize it. 332bc5e3c50Skarels */ 333bc5e3c50Skarels tmscpslave (ui, reg) 334bc5e3c50Skarels struct uba_device *ui; /* ptr to the uba device structure */ 335bc5e3c50Skarels caddr_t reg; /* addr of the device controller */ 336bc5e3c50Skarels { 337bc5e3c50Skarels register struct uba_ctlr *um = tmscpminfo[ui->ui_ctlr]; 338bc5e3c50Skarels register struct tmscp_softc *sc = &tmscp_softc[ui->ui_ctlr]; 339*1625a9a8Skarels register struct tms_info *tms = &tms_info[ui->ui_unit]; 340bc5e3c50Skarels struct tmscpdevice *tmscpaddr; /* ptr to IP & SA */ 341bc5e3c50Skarels struct mscp *mp; 342bc5e3c50Skarels int i; /* Something to write into to start */ 343bc5e3c50Skarels /* the tmscp polling */ 344bc5e3c50Skarels 345bc5e3c50Skarels # ifdef lint 346bc5e3c50Skarels ui = ui; reg = reg; i = i; 347bc5e3c50Skarels # endif 348bc5e3c50Skarels tmscpaddr = (struct tmscpdevice *)um->um_addr; 349bc5e3c50Skarels /* 350bc5e3c50Skarels * If its not in the run state, start the initialization process 351bc5e3c50Skarels * (tmscpintr will complete it); if the initialization doesn't start; 352bc5e3c50Skarels * then return. 353bc5e3c50Skarels */ 354bc5e3c50Skarels if(sc->sc_state != S_RUN) 355bc5e3c50Skarels { 356bc5e3c50Skarels # ifdef DEBUG 357bc5e3c50Skarels printd("tmscpslave: ctlr not running: calling init \n"); 358bc5e3c50Skarels # endif 359bc5e3c50Skarels if(!tmscpinit(ui->ui_ctlr)) 360bc5e3c50Skarels return(0); 361bc5e3c50Skarels } 362bc5e3c50Skarels /* 363bc5e3c50Skarels * Wait for the controller to come into the run state or go idle. 364bc5e3c50Skarels * If it goes idle return. 365bc5e3c50Skarels */ 366bc5e3c50Skarels # ifdef DEBUG 367bc5e3c50Skarels i=1; 368bc5e3c50Skarels # endif 369bc5e3c50Skarels while(sc->sc_state != S_RUN && sc->sc_state != S_IDLE) 370bc5e3c50Skarels # ifdef DEBUG 371bc5e3c50Skarels if (tmscpaddr->tmscpsa & TMSCP_ERR && i) 372bc5e3c50Skarels { 373*1625a9a8Skarels printd("tmscp-device: fatal error (%o)\n", tmscpaddr->tmscpsa&0xffff); 374bc5e3c50Skarels i=0; 375bc5e3c50Skarels } 376bc5e3c50Skarels # endif 377bc5e3c50Skarels ; /* wait */ 378bc5e3c50Skarels if(sc->sc_state == S_IDLE) 379bc5e3c50Skarels { /* The tmscp device failed to initialize */ 380bc5e3c50Skarels printf("tmscp controller failed to init\n"); 381bc5e3c50Skarels return(0); 382bc5e3c50Skarels } 383bc5e3c50Skarels /* The controller is up so see if the drive is there */ 384bc5e3c50Skarels if(0 == (mp = tmscpgetcp(um))) 385bc5e3c50Skarels { 386bc5e3c50Skarels printf("tmscp can't get command packet\n"); 387bc5e3c50Skarels return(0); 388bc5e3c50Skarels } 389bc5e3c50Skarels /* Need to determine the drive type for generic driver */ 390*1625a9a8Skarels mp->mscp_opcode = M_OP_GTUNT; /* This should give us the device type */ 391bc5e3c50Skarels mp->mscp_unit = ui->ui_slave; 392bc5e3c50Skarels mp->mscp_cmdref = (long) ui->ui_slave; 393*1625a9a8Skarels tms->tms_status = 0; /* set to zero */ 394bc5e3c50Skarels tmscpip[ui->ui_ctlr][ui->ui_slave] = ui; 395*1625a9a8Skarels *((long *) mp->mscp_dscptr ) |= TMSCP_OWN | TMSCP_INT;/* maybe we should poll*/ 396bc5e3c50Skarels i = tmscpaddr->tmscpip; 397*1625a9a8Skarels while(!tms->tms_status) 398bc5e3c50Skarels ; /* Wait for some status */ 399bc5e3c50Skarels # ifdef DEBUG 400*1625a9a8Skarels printd("tmscpslave: status = %o\n",tms->tms_status & M_ST_MASK); 401bc5e3c50Skarels # endif 402bc5e3c50Skarels tmscpip[ui->ui_ctlr][ui->ui_slave] = 0; 403*1625a9a8Skarels if(!tms->tms_type) /* packet from a GTUNT */ 404bc5e3c50Skarels return(0); /* Failed No such drive */ 405bc5e3c50Skarels else 406bc5e3c50Skarels return(1); /* Got it and it is there */ 407bc5e3c50Skarels } 408bc5e3c50Skarels 409bc5e3c50Skarels 410bc5e3c50Skarels /* 411bc5e3c50Skarels * Set ui flags to zero to show device is not online & set tmscpip. 412bc5e3c50Skarels * Unit to Controller mapping is set up here. 413bc5e3c50Skarels * Open routine will issue the online command, later. 414bc5e3c50Skarels */ 415bc5e3c50Skarels tmscpattach (ui) 416bc5e3c50Skarels register struct uba_device *ui; /* ptr to unibus dev struct */ 417bc5e3c50Skarels { 418*1625a9a8Skarels register struct uba_ctlr *um = ui->ui_mi; /* ptr to controller struct */ 419*1625a9a8Skarels struct tmscpdevice *tmscpaddr = (struct tmscpdevice *) um->um_addr; /* IP & SA */ 420bc5e3c50Skarels struct mscp *mp; 421bc5e3c50Skarels int i; /* Assign to here to start the tmscp-dev polling */ 422bc5e3c50Skarels 423bc5e3c50Skarels # ifdef lint 424bc5e3c50Skarels i = i; 425bc5e3c50Skarels # endif lint 426bc5e3c50Skarels ui->ui_flags = 0; 427bc5e3c50Skarels tmscpip[ui->ui_ctlr][ui->ui_slave] = ui; 428bc5e3c50Skarels # ifdef DEBUG 429bc5e3c50Skarels /* 430bc5e3c50Skarels * Check to see if the drive is available. 431bc5e3c50Skarels * If not then just print debug. 432bc5e3c50Skarels */ 433bc5e3c50Skarels if(tms_info[ui->ui_unit].tms_status != M_ST_AVLBL) 434bc5e3c50Skarels printd("tmscpattach: unavailable \n"); 435bc5e3c50Skarels # endif 436bc5e3c50Skarels utoctlr[ui->ui_unit] = ui->ui_ctlr; 437bc5e3c50Skarels } 438bc5e3c50Skarels 439bc5e3c50Skarels 440bc5e3c50Skarels /* 441bc5e3c50Skarels * TMSCP interrupt routine. 442bc5e3c50Skarels */ 443bc5e3c50Skarels tmscpintr (d) 444bc5e3c50Skarels int d; /* index to the controller */ 445bc5e3c50Skarels { 446bc5e3c50Skarels register struct uba_ctlr *um = tmscpminfo[d]; 447*1625a9a8Skarels register struct tmscpdevice *tmscpaddr = (struct tmscpdevice *)um->um_addr; 448bc5e3c50Skarels struct buf *bp; 449bc5e3c50Skarels register int i; 450bc5e3c50Skarels register struct tmscp_softc *sc = &tmscp_softc[d]; 451bc5e3c50Skarels register struct tmscp *tm = &tmscp[d]; 452bc5e3c50Skarels struct tmscp *ttm; 453bc5e3c50Skarels struct mscp *mp; 454bc5e3c50Skarels 455bc5e3c50Skarels # ifdef DEBUG 456*1625a9a8Skarels printd10("tmscpintr: state %d, tmscpsa %o\n", sc->sc_state, tmscpaddr->tmscpsa); 457bc5e3c50Skarels # endif 458bc5e3c50Skarels 459bc5e3c50Skarels /* 460bc5e3c50Skarels * How the interrupt is handled depends on the state of the controller. 461bc5e3c50Skarels */ 462bc5e3c50Skarels switch (sc->sc_state) { 463bc5e3c50Skarels 464bc5e3c50Skarels case S_IDLE: 465bc5e3c50Skarels printf("tmscp%d: random interrupt ignored\n", d); 466bc5e3c50Skarels return; 467bc5e3c50Skarels 468bc5e3c50Skarels /* Controller was in step 1 last, see if its gone to step 2 */ 469bc5e3c50Skarels case S_STEP1: 470bc5e3c50Skarels # define STEP1MASK 0174377 471bc5e3c50Skarels # define STEP1GOOD (TMSCP_STEP2|TMSCP_IE|(NCMDL2<<3)|NRSPL2) 472bc5e3c50Skarels for (i = 0; i < 150; i++) 473bc5e3c50Skarels { 474bc5e3c50Skarels if ((tmscpaddr->tmscpsa&STEP1MASK) != STEP1GOOD) 475bc5e3c50Skarels { /* still in step 1 (wait 1/100 sec) */ 476bc5e3c50Skarels DELAY(10000); 477bc5e3c50Skarels # ifdef DEBUG 478bc5e3c50Skarels printd("still in step 1, delaying\n"); 479bc5e3c50Skarels # endif DEBUG 480bc5e3c50Skarels } 481bc5e3c50Skarels else 482bc5e3c50Skarels break; 483bc5e3c50Skarels } 484bc5e3c50Skarels if (i > 149) 485bc5e3c50Skarels { 486bc5e3c50Skarels sc->sc_state = S_IDLE; 487*1625a9a8Skarels printf("failed to initialize, in step1: sa 0x%x", tmscpaddr->tmscpsa); 488bc5e3c50Skarels wakeup((caddr_t)um); 489bc5e3c50Skarels return; 490bc5e3c50Skarels } 491bc5e3c50Skarels tmscpaddr->tmscpsa = ((int)&sc->sc_tmscp->tmscp_ca.ca_ringbase) 492bc5e3c50Skarels | ((cpu == VAX_780 || cpu == VAX_8600) ? TMSCP_PI : 0); 493bc5e3c50Skarels sc->sc_state = S_STEP2; 494bc5e3c50Skarels return; 495bc5e3c50Skarels 496bc5e3c50Skarels /* Controller was in step 2 last, see if its gone to step 3 */ 497bc5e3c50Skarels case S_STEP2: 498bc5e3c50Skarels # define STEP2MASK 0174377 499bc5e3c50Skarels # define STEP2GOOD (TMSCP_STEP3|TMSCP_IE|(sc->sc_ivec/4)) 500bc5e3c50Skarels for (i = 0; i < 150; i++) 501bc5e3c50Skarels { 502bc5e3c50Skarels if ((tmscpaddr->tmscpsa&STEP2MASK) != STEP2GOOD) 503bc5e3c50Skarels { /* still in step 2 (wait 1/100 sec) */ 504bc5e3c50Skarels DELAY(10000); 505bc5e3c50Skarels # ifdef DEBUG 506bc5e3c50Skarels printd("still in step 2, delaying\n"); 507bc5e3c50Skarels # endif DEBUG 508bc5e3c50Skarels } 509bc5e3c50Skarels else 510bc5e3c50Skarels break; 511bc5e3c50Skarels } 512bc5e3c50Skarels if (i > 149) 513bc5e3c50Skarels { 514bc5e3c50Skarels sc->sc_state = S_IDLE; 515*1625a9a8Skarels printf("failed to initialize, in step2: sa 0x%x", tmscpaddr->tmscpsa); 516bc5e3c50Skarels wakeup((caddr_t)um); 517bc5e3c50Skarels return; 518bc5e3c50Skarels } 519*1625a9a8Skarels tmscpaddr->tmscpsa = ((int)&sc->sc_tmscp->tmscp_ca.ca_ringbase)>>16; 520bc5e3c50Skarels sc->sc_state = S_STEP3; 521bc5e3c50Skarels return; 522bc5e3c50Skarels 523bc5e3c50Skarels /* Controller was in step 3 last, see if its gone to step 4 */ 524bc5e3c50Skarels case S_STEP3: 525bc5e3c50Skarels # define STEP3MASK 0174000 526bc5e3c50Skarels # define STEP3GOOD TMSCP_STEP4 527bc5e3c50Skarels for (i = 0; i < 150; i++) 528bc5e3c50Skarels { 529bc5e3c50Skarels if ((tmscpaddr->tmscpsa&STEP3MASK) != STEP3GOOD) 530bc5e3c50Skarels { /* still in step 3 (wait 1/100 sec) */ 531bc5e3c50Skarels DELAY(10000); 532bc5e3c50Skarels # ifdef DEBUG 533bc5e3c50Skarels printd("still in step 3, delaying\n"); 534bc5e3c50Skarels # endif DEBUG 535bc5e3c50Skarels } 536bc5e3c50Skarels else 537bc5e3c50Skarels break; 538bc5e3c50Skarels } 539bc5e3c50Skarels if (i > 149) 540bc5e3c50Skarels { 541bc5e3c50Skarels sc->sc_state = S_IDLE; 542*1625a9a8Skarels printf("failed to initialize, in step3: sa 0x%x", tmscpaddr->tmscpsa); 543bc5e3c50Skarels wakeup((caddr_t)um); 544bc5e3c50Skarels return; 545bc5e3c50Skarels } 546bc5e3c50Skarels /* 547bc5e3c50Skarels * Get microcode version and model number of controller; 548bc5e3c50Skarels * Signal initialization complete (_GO) (to the controller); 549bc5e3c50Skarels * ask for Last Fail response if tmscperror is set; 550bc5e3c50Skarels * Set state to "set controller characteristics". 551bc5e3c50Skarels */ 552bc5e3c50Skarels tmscpmicro[d] = tmscpaddr->tmscpsa; 553bc5e3c50Skarels tmscpaddr->tmscpsa = TMSCP_GO | (tmscperror? TMSCP_LF : 0); 554bc5e3c50Skarels sc->sc_state = S_SCHAR; 555bc5e3c50Skarels # ifdef DEBUG 556bc5e3c50Skarels printd("tmscpintr: completed state %d \n", sc->sc_state); 557bc5e3c50Skarels printd("tmscp%d Version %d model %d\n",d,tmscpmicro[d]&0xF, 558bc5e3c50Skarels (tmscpmicro[d]>>4) & 0xF); 559bc5e3c50Skarels # endif 560bc5e3c50Skarels 561bc5e3c50Skarels /* 562bc5e3c50Skarels * Initialize the data structures (response and command queues). 563bc5e3c50Skarels */ 564bc5e3c50Skarels ttm = sc->sc_tmscp; 565bc5e3c50Skarels for (i = 0; i < NRSP; i++) 566bc5e3c50Skarels { 567bc5e3c50Skarels tm->tmscp_ca.ca_rspdsc[i] = TMSCP_OWN | TMSCP_INT | 568*1625a9a8Skarels (long)&ttm->tmscp_rsp[i].mscp_cmdref; 569bc5e3c50Skarels tm->tmscp_rsp[i].mscp_dscptr = &tm->tmscp_ca.ca_rspdsc[i]; 570bc5e3c50Skarels tm->tmscp_rsp[i].mscp_header.tmscp_msglen = mscp_msglen; 571bc5e3c50Skarels } 572bc5e3c50Skarels for (i = 0; i < NCMD; i++) 573bc5e3c50Skarels { 574bc5e3c50Skarels tm->tmscp_ca.ca_cmddsc[i] = TMSCP_INT | 575bc5e3c50Skarels (long)&ttm->tmscp_cmd[i].mscp_cmdref; 576bc5e3c50Skarels tm->tmscp_cmd[i].mscp_dscptr = &tm->tmscp_ca.ca_cmddsc[i]; 577bc5e3c50Skarels tm->tmscp_cmd[i].mscp_header.tmscp_msglen = mscp_msglen; 578bc5e3c50Skarels tm->tmscp_cmd[i].mscp_header.tmscp_vcid = 1; 579bc5e3c50Skarels } 580bc5e3c50Skarels bp = &tmscpwtab[d]; 581bc5e3c50Skarels bp->av_forw = bp->av_back = bp; 582bc5e3c50Skarels sc->sc_lastcmd = 1; 583bc5e3c50Skarels sc->sc_lastrsp = 0; 584bc5e3c50Skarels mp = &tmscp[um->um_ctlr].tmscp_cmd[0]; 585bc5e3c50Skarels mp->mscp_unit = mp->mscp_modifier = 0; 586bc5e3c50Skarels mp->mscp_flags = 0; 587bc5e3c50Skarels mp->mscp_version = 0; 588bc5e3c50Skarels mp->mscp_cntflgs = M_CF_ATTN|M_CF_MISC|M_CF_THIS; 589bc5e3c50Skarels /* 590bc5e3c50Skarels * A host time out value of 0 means that the controller will not 591bc5e3c50Skarels * time out. This is ok for the TK50. 592bc5e3c50Skarels */ 593bc5e3c50Skarels mp->mscp_hsttmo = 0; 594bc5e3c50Skarels mp->mscp_time.val[0] = 0; 595bc5e3c50Skarels mp->mscp_time.val[1] = 0; 596bc5e3c50Skarels mp->mscp_cntdep = 0; 597bc5e3c50Skarels mp->mscp_opcode = M_OP_STCON; 598bc5e3c50Skarels *((long *)mp->mscp_dscptr) |= TMSCP_OWN|TMSCP_INT; 599bc5e3c50Skarels i = tmscpaddr->tmscpip; /* initiate polling */ 600bc5e3c50Skarels return; 601bc5e3c50Skarels 602bc5e3c50Skarels case S_SCHAR: 603bc5e3c50Skarels case S_RUN: 604bc5e3c50Skarels break; 605bc5e3c50Skarels 606bc5e3c50Skarels default: 607*1625a9a8Skarels printf("tmscp%d: interrupt in unknown state %d ignored\n",d,sc->sc_state); 608bc5e3c50Skarels return; 609bc5e3c50Skarels } /* end switch */ 610bc5e3c50Skarels 611bc5e3c50Skarels /* 612bc5e3c50Skarels * The controller state is S_SCHAR or S_RUN 613bc5e3c50Skarels */ 614bc5e3c50Skarels 615bc5e3c50Skarels /* 616bc5e3c50Skarels * If the error bit is set in the SA register then print an error 617bc5e3c50Skarels * message and reinitialize the controller. 618bc5e3c50Skarels */ 619bc5e3c50Skarels if (tmscpaddr->tmscpsa&TMSCP_ERR) 620bc5e3c50Skarels { 621*1625a9a8Skarels printf("tmscp%d: fatal error (%o)\n", d, tmscpaddr->tmscpsa&0xffff); 622bc5e3c50Skarels tmscpaddr->tmscpip = 0; 623bc5e3c50Skarels wakeup((caddr_t)um); 624bc5e3c50Skarels } 625bc5e3c50Skarels /* 626bc5e3c50Skarels * Check for a buffer purge request. (Won't happen w/ TK50 on Q22 bus) 627bc5e3c50Skarels */ 628bc5e3c50Skarels if (tm->tmscp_ca.ca_bdp) 629bc5e3c50Skarels { 630bc5e3c50Skarels /* 631bc5e3c50Skarels * THIS IS A KLUDGE. 632bc5e3c50Skarels * Maybe we should change the entire 633bc5e3c50Skarels * UBA interface structure. 634bc5e3c50Skarels */ 635bc5e3c50Skarels int s = spl6(); 636bc5e3c50Skarels i = um->um_ubinfo; 637bc5e3c50Skarels # ifdef DEBUG 638bc5e3c50Skarels printd("tmscp: purge bdp %d\n", tm->tmscp_ca.ca_bdp); 639bc5e3c50Skarels # endif 640bc5e3c50Skarels um->um_ubinfo = tm->tmscp_ca.ca_bdp<<28; 641bc5e3c50Skarels ubapurge(um); 642bc5e3c50Skarels um->um_ubinfo = i; 643bc5e3c50Skarels (void) splx(s); 644bc5e3c50Skarels tm->tmscp_ca.ca_bdp = 0; 645bc5e3c50Skarels tmscpaddr->tmscpsa = 0; /* signal purge complete */ 646bc5e3c50Skarels } 647bc5e3c50Skarels 648bc5e3c50Skarels /* 649bc5e3c50Skarels * Check for response ring transition. 650bc5e3c50Skarels */ 651bc5e3c50Skarels if (tm->tmscp_ca.ca_rspint) 652bc5e3c50Skarels { 653bc5e3c50Skarels tm->tmscp_ca.ca_rspint = 0; 654bc5e3c50Skarels for (i = sc->sc_lastrsp;; i++) 655bc5e3c50Skarels { 656bc5e3c50Skarels i %= NRSP; 657bc5e3c50Skarels if (tm->tmscp_ca.ca_rspdsc[i]&TMSCP_OWN) 658bc5e3c50Skarels break; 659bc5e3c50Skarels tmscprsp(um, tm, sc, i); 660bc5e3c50Skarels tm->tmscp_ca.ca_rspdsc[i] |= TMSCP_OWN; 661bc5e3c50Skarels } 662bc5e3c50Skarels sc->sc_lastrsp = i; 663bc5e3c50Skarels } 664bc5e3c50Skarels 665bc5e3c50Skarels /* 666bc5e3c50Skarels * Check for command ring transition. 667bc5e3c50Skarels */ 668bc5e3c50Skarels if (tm->tmscp_ca.ca_cmdint) 669bc5e3c50Skarels { 670bc5e3c50Skarels # ifdef DEBUG 671bc5e3c50Skarels printd("tmscpintr: command ring transition\n"); 672bc5e3c50Skarels # endif 673bc5e3c50Skarels tm->tmscp_ca.ca_cmdint = 0; 674bc5e3c50Skarels } 675bc5e3c50Skarels if(tmscp_cp_wait) 676bc5e3c50Skarels wakeup(&tmscp_cp_wait); 677bc5e3c50Skarels (void) tmscpstart(um); 678bc5e3c50Skarels } 679bc5e3c50Skarels 680bc5e3c50Skarels 681bc5e3c50Skarels /* 682bc5e3c50Skarels * Open a tmscp device and set the unit online. If the controller is not 683bc5e3c50Skarels * in the run state, call init to initialize the tmscp controller first. 684bc5e3c50Skarels */ 685bc5e3c50Skarels 686bc5e3c50Skarels tmscpopen(dev, flag) 687bc5e3c50Skarels dev_t dev; 688bc5e3c50Skarels int flag; 689bc5e3c50Skarels { 690bc5e3c50Skarels register int unit; 691bc5e3c50Skarels register struct uba_device *ui; 692bc5e3c50Skarels register struct tmscp_softc *sc; 693*1625a9a8Skarels register struct tms_info *tms; 694bc5e3c50Skarels register struct mscp *mp; 695bc5e3c50Skarels register struct uba_ctlr *um; 696bc5e3c50Skarels struct tmscpdevice *tmscpaddr; 697bc5e3c50Skarels int s,i; 698bc5e3c50Skarels extern quota; 699bc5e3c50Skarels 700bc5e3c50Skarels # ifdef lint 701bc5e3c50Skarels flag = flag; i = i; 702bc5e3c50Skarels # endif 703bc5e3c50Skarels unit = TMSUNIT(dev); 704bc5e3c50Skarels # ifdef DEBUG 705bc5e3c50Skarels printd("tmscpopen unit %d\n",unit); 706bc5e3c50Skarels if(tmscpdebug)DELAY(10000); 707bc5e3c50Skarels # endif 708*1625a9a8Skarels if (unit >= NTMS || (ui = tmsdinfo[unit]) == 0 || ui->ui_alive == 0) 709bc5e3c50Skarels return (ENXIO); 710*1625a9a8Skarels tms = &tms_info[ui->ui_unit]; 711*1625a9a8Skarels if (tms->tms_openf) 712*1625a9a8Skarels return (EBUSY); 713bc5e3c50Skarels sc = &tmscp_softc[ui->ui_ctlr]; 714*1625a9a8Skarels tms->tms_openf = 1; 715*1625a9a8Skarels tms->tms_ttyp = u.u_ttyp; 716bc5e3c50Skarels s = spl5(); 717bc5e3c50Skarels if (sc->sc_state != S_RUN) 718bc5e3c50Skarels { 719bc5e3c50Skarels if (sc->sc_state == S_IDLE) 720bc5e3c50Skarels if(!tmscpinit(ui->ui_ctlr)) 721bc5e3c50Skarels { 722bc5e3c50Skarels printf("tmscp controller failed to init\n"); 723bc5e3c50Skarels (void) splx(s); 724bc5e3c50Skarels return(ENXIO); 725bc5e3c50Skarels } 726bc5e3c50Skarels /* 727bc5e3c50Skarels * Wait for initialization to complete 728bc5e3c50Skarels */ 729bc5e3c50Skarels timeout(wakeup,(caddr_t)ui->ui_mi,11*hz); /* to be sure*/ 730bc5e3c50Skarels sleep((caddr_t)ui->ui_mi, 0); 731bc5e3c50Skarels if (sc->sc_state != S_RUN) 732bc5e3c50Skarels { 733bc5e3c50Skarels (void) splx(s); 734*1625a9a8Skarels tms->tms_openf = 0; 735bc5e3c50Skarels return (EIO); 736bc5e3c50Skarels } 737bc5e3c50Skarels } 738bc5e3c50Skarels /* 739bc5e3c50Skarels * Check to see if the device is really there. 740bc5e3c50Skarels * this code was taken from Fred Canters 11 driver 741bc5e3c50Skarels */ 742bc5e3c50Skarels um = ui->ui_mi; 743bc5e3c50Skarels tmscpaddr = (struct tmscpdevice *) um->um_addr; 744bc5e3c50Skarels (void) splx(s); 745bc5e3c50Skarels if(ui->ui_flags == 0) 746bc5e3c50Skarels { 747bc5e3c50Skarels s = spl5(); 748bc5e3c50Skarels while(0 ==(mp = tmscpgetcp(um))) 749bc5e3c50Skarels { 750bc5e3c50Skarels tmscp_cp_wait++; 751bc5e3c50Skarels sleep(&tmscp_cp_wait,PSWP+1); 752bc5e3c50Skarels tmscp_cp_wait--; 753bc5e3c50Skarels } 754bc5e3c50Skarels (void) splx(s); 755bc5e3c50Skarels mp->mscp_opcode = M_OP_ONLIN; 756bc5e3c50Skarels mp->mscp_unit = ui->ui_slave; 757*1625a9a8Skarels mp->mscp_cmdref = (long) & tms->tms_type; 758bc5e3c50Skarels /* need to sleep on something */ 759bc5e3c50Skarels # ifdef DEBUG 760bc5e3c50Skarels printd("tmscpopen: bring unit %d online\n",ui->ui_unit); 761bc5e3c50Skarels # endif 762bc5e3c50Skarels *((long *) mp->mscp_dscptr ) |= TMSCP_OWN | TMSCP_INT; 763bc5e3c50Skarels i = tmscpaddr->tmscpip; 764bc5e3c50Skarels /* 765bc5e3c50Skarels * To make sure we wake up, timeout in 240 seconds. 766bc5e3c50Skarels * Wakeup in tmscprsp routine. 767bc5e3c50Skarels * 240 seconds (4 minutes) is necessary since a rewind 768bc5e3c50Skarels * can take a few minutes. 769bc5e3c50Skarels */ 770bc5e3c50Skarels timeout(wakeup,(caddr_t) mp->mscp_cmdref,240 * hz); 771bc5e3c50Skarels sleep((caddr_t) mp->mscp_cmdref,PSWP+1); 772bc5e3c50Skarels } 773*1625a9a8Skarels if(ui->ui_flags == 0) { 774*1625a9a8Skarels tms->tms_openf = 0; 775bc5e3c50Skarels return(ENXIO); /* Didn't go online */ 776*1625a9a8Skarels } 777*1625a9a8Skarels tms->tms_lastiow = 0; 778bc5e3c50Skarels /* 779bc5e3c50Skarels * If the high density device is not specified, set unit to low 780bc5e3c50Skarels * density. This is done as an "internal" ioctl command so 781bc5e3c50Skarels * that the command setup and response handling 782bc5e3c50Skarels * is done thru "regular" command routines. 783bc5e3c50Skarels */ 784bc5e3c50Skarels if ((minor(dev) & T_HIDENSITY) == 0) 785bc5e3c50Skarels tmscpcommand(dev, TMS_LOWDENSITY, 1); 786bc5e3c50Skarels else 787bc5e3c50Skarels tmscpcommand(dev, TMS_HIDENSITY, 1); 788bc5e3c50Skarels return (0); 789bc5e3c50Skarels } 790bc5e3c50Skarels 791bc5e3c50Skarels 792bc5e3c50Skarels /* 793bc5e3c50Skarels * Close tape device. 794bc5e3c50Skarels * 795bc5e3c50Skarels * If tape was open for writing or last operation was 796bc5e3c50Skarels * a write, then write two EOF's and backspace over the last one. 797bc5e3c50Skarels * Unless this is a non-rewinding special file, rewind the tape. 798bc5e3c50Skarels * 799bc5e3c50Skarels * NOTE: 800bc5e3c50Skarels * We want to be sure that any serious exception is cleared on the 801bc5e3c50Skarels * close. A Clear Serious Exception (CSE) modifier is always done on 802bc5e3c50Skarels * the rewind command. For the non-rewind case we check to see if the 803bc5e3c50Skarels * "serex" field is set in the softc struct; if it is then issue a noop 804bc5e3c50Skarels * command with the CSE modifier. 805bc5e3c50Skarels * Make the tape available to others, by clearing openf flag. 806bc5e3c50Skarels */ 807bc5e3c50Skarels tmscpclose(dev, flag) 808bc5e3c50Skarels register dev_t dev; 809bc5e3c50Skarels register flag; 810bc5e3c50Skarels { 811bc5e3c50Skarels register struct tmscp_softc *sc = &tmscp_softc[TMSCPCTLR(dev)]; 812*1625a9a8Skarels register struct tms_info *tms; 813bc5e3c50Skarels register struct uba_device *ui; 814bc5e3c50Skarels 815bc5e3c50Skarels ui = tmsdinfo[TMSUNIT(dev)]; 816bc5e3c50Skarels # ifdef DEBUG 817bc5e3c50Skarels printd("tmscpclose: ctlr = %d\n",TMSCPCTLR(dev)); 818bc5e3c50Skarels printd("tmscpclose: unit = %d\n",TMSUNIT(dev)); 819bc5e3c50Skarels if(tmscpdebug)DELAY(10000); 820bc5e3c50Skarels # endif 821*1625a9a8Skarels tms = &tms_info[ui->ui_unit]; 822*1625a9a8Skarels if (flag == FWRITE || (flag&FWRITE) && tms->tms_lastiow) 823bc5e3c50Skarels { 824bc5e3c50Skarels /* device, command, count */ 825bc5e3c50Skarels tmscpcommand (dev, TMS_WRITM, 1); 826bc5e3c50Skarels tmscpcommand (dev, TMS_WRITM, 1); 827bc5e3c50Skarels tmscpcommand (dev, TMS_BSR, 1); 828bc5e3c50Skarels } 829bc5e3c50Skarels if ((minor(dev)&T_NOREWIND) == 0) 830bc5e3c50Skarels /* 831bc5e3c50Skarels * Don't hang waiting for rewind complete. 832bc5e3c50Skarels */ 833bc5e3c50Skarels tmscpcommand(dev, TMS_REW, 0); 834bc5e3c50Skarels else 835*1625a9a8Skarels if (tms->tms_serex) 836bc5e3c50Skarels { 837bc5e3c50Skarels # ifdef DEBUG 838bc5e3c50Skarels printd("tmscpclose: clearing serex\n"); 839bc5e3c50Skarels if(tmscpdebug)DELAY(10000); 840bc5e3c50Skarels # endif 841bc5e3c50Skarels tmscpcommand(dev, TMS_CSE, 1); 842bc5e3c50Skarels } 843*1625a9a8Skarels tms->tms_openf = 0; 844bc5e3c50Skarels } 845bc5e3c50Skarels 846bc5e3c50Skarels 847bc5e3c50Skarels /* 848bc5e3c50Skarels * Execute a command on the tape drive a specified number of times. 849bc5e3c50Skarels * This routine sets up a buffer and calls the strategy routine which 850bc5e3c50Skarels * links the buffer onto the drive's buffer queue. 851bc5e3c50Skarels * The start routine will take care of creating a tmscp command packet 852bc5e3c50Skarels * with the command. The start routine is called by the strategy or the 853bc5e3c50Skarels * interrupt routine. 854bc5e3c50Skarels */ 855bc5e3c50Skarels 856bc5e3c50Skarels tmscpcommand (dev, com, count) 857bc5e3c50Skarels register dev_t dev; 858bc5e3c50Skarels int com, count; 859bc5e3c50Skarels { 860bc5e3c50Skarels register struct uba_device *ui; 861bc5e3c50Skarels register struct buf *bp; 862bc5e3c50Skarels register int s; 863bc5e3c50Skarels int unit = TMSUNIT(dev); 864bc5e3c50Skarels 865*1625a9a8Skarels if (unit >= NTMS) 866bc5e3c50Skarels return (ENXIO); 867bc5e3c50Skarels ui = tmsdinfo[unit]; 868bc5e3c50Skarels bp = &ctmscpbuf[ui->ui_ctlr]; 869bc5e3c50Skarels 870bc5e3c50Skarels s = spl5(); 871bc5e3c50Skarels while (bp->b_flags&B_BUSY) 872bc5e3c50Skarels { 873bc5e3c50Skarels /* 874bc5e3c50Skarels * This special check is because B_BUSY never 875bc5e3c50Skarels * gets cleared in the non-waiting rewind case. 876bc5e3c50Skarels */ 877bc5e3c50Skarels if (bp->b_bcount == 0 && (bp->b_flags&B_DONE)) 878bc5e3c50Skarels break; 879bc5e3c50Skarels bp->b_flags |= B_WANTED; 880bc5e3c50Skarels sleep((caddr_t)bp, PRIBIO); 881bc5e3c50Skarels } 882bc5e3c50Skarels bp->b_flags = B_BUSY|B_READ; 883bc5e3c50Skarels splx(s); 884bc5e3c50Skarels /* 885bc5e3c50Skarels * Load the buffer. The b_count field gets used to hold the command 886bc5e3c50Skarels * count. the b_resid field gets used to hold the command mneumonic. 887bc5e3c50Skarels * These 2 fields are "known" to be "safe" to use for this purpose. 888bc5e3c50Skarels * (Most other drivers also use these fields in this way.) 889bc5e3c50Skarels */ 890bc5e3c50Skarels bp->b_dev = dev; 891bc5e3c50Skarels bp->b_bcount = count; 892bc5e3c50Skarels bp->b_resid = com; 893bc5e3c50Skarels bp->b_blkno = 0; 894bc5e3c50Skarels tmscpstrategy(bp); 895bc5e3c50Skarels /* 896bc5e3c50Skarels * In case of rewind from close, don't wait. 897bc5e3c50Skarels * This is the only case where count can be 0. 898bc5e3c50Skarels */ 899bc5e3c50Skarels if (count == 0) 900bc5e3c50Skarels return; 901bc5e3c50Skarels iowait(bp); 902bc5e3c50Skarels if (bp->b_flags&B_WANTED) 903bc5e3c50Skarels wakeup((caddr_t)bp); 904bc5e3c50Skarels bp->b_flags &= B_ERROR; 905bc5e3c50Skarels } 906bc5e3c50Skarels 907bc5e3c50Skarels /* 908bc5e3c50Skarels * Find an unused command packet 909bc5e3c50Skarels */ 910bc5e3c50Skarels struct mscp * 911bc5e3c50Skarels tmscpgetcp(um) 912bc5e3c50Skarels struct uba_ctlr *um; 913bc5e3c50Skarels { 914bc5e3c50Skarels register struct mscp *mp; 915bc5e3c50Skarels register struct tmscpca *cp; 916bc5e3c50Skarels register struct tmscp_softc *sc; 917bc5e3c50Skarels register int i; 918bc5e3c50Skarels int s; 919bc5e3c50Skarels 920bc5e3c50Skarels s = spl5(); 921bc5e3c50Skarels cp = &tmscp[um->um_ctlr].tmscp_ca; 922bc5e3c50Skarels sc = &tmscp_softc[um->um_ctlr]; 923bc5e3c50Skarels /* 924bc5e3c50Skarels * If no credits, can't issue any commands 925bc5e3c50Skarels * until some outstanding commands complete. 926bc5e3c50Skarels */ 927bc5e3c50Skarels i = sc->sc_lastcmd; 928bc5e3c50Skarels # ifdef DEBUG 929bc5e3c50Skarels printd10("tmscpgetcp: %d credits remain\n", sc->sc_credits); 930bc5e3c50Skarels # endif 931bc5e3c50Skarels if(((cp->ca_cmddsc[i]&(TMSCP_OWN|TMSCP_INT))==TMSCP_INT) && 932bc5e3c50Skarels (sc->sc_credits >= 2)) 933bc5e3c50Skarels { 934bc5e3c50Skarels sc->sc_credits--; /* This commits to issuing a command */ 935bc5e3c50Skarels cp->ca_cmddsc[i] &= ~TMSCP_INT; 936bc5e3c50Skarels mp = &tmscp[um->um_ctlr].tmscp_cmd[i]; 937bc5e3c50Skarels mp->mscp_unit = mp->mscp_modifier = 0; 938bc5e3c50Skarels mp->mscp_opcode = mp->mscp_flags = 0; 939bc5e3c50Skarels mp->mscp_bytecnt = mp->mscp_buffer = 0; 940bc5e3c50Skarels sc->sc_lastcmd = (i + 1) % NCMD; 941bc5e3c50Skarels (void) splx(s); 942bc5e3c50Skarels return(mp); 943bc5e3c50Skarels } 944bc5e3c50Skarels (void) splx(s); 945bc5e3c50Skarels return(NULL); 946bc5e3c50Skarels } 947bc5e3c50Skarels 948bc5e3c50Skarels 949bc5e3c50Skarels /* 950bc5e3c50Skarels * Initialize a TMSCP device. Set up UBA mapping registers, 951bc5e3c50Skarels * initialize data structures, and start hardware 952bc5e3c50Skarels * initialization sequence. 953bc5e3c50Skarels */ 954bc5e3c50Skarels tmscpinit (d) 955bc5e3c50Skarels int d; /* index to the controller */ 956bc5e3c50Skarels { 957bc5e3c50Skarels register struct tmscp_softc *sc; 958*1625a9a8Skarels register struct tmscp *t; /* communications area; cmd & resp packets */ 959bc5e3c50Skarels struct tmscpdevice *tmscpaddr; 960bc5e3c50Skarels struct uba_ctlr *um; 961bc5e3c50Skarels 962bc5e3c50Skarels sc = &tmscp_softc[d]; 963bc5e3c50Skarels um = tmscpminfo[d]; 964bc5e3c50Skarels um->um_tab.b_active++; 965bc5e3c50Skarels t = &tmscp[d]; 966bc5e3c50Skarels tmscpaddr = (struct tmscpdevice *)um->um_addr; 967bc5e3c50Skarels if (sc->sc_mapped == 0) 968bc5e3c50Skarels { 969bc5e3c50Skarels /* 970bc5e3c50Skarels * Map the communications area and command 971bc5e3c50Skarels * and response packets into Unibus address 972bc5e3c50Skarels * space. 973bc5e3c50Skarels */ 974*1625a9a8Skarels sc->sc_ubainfo = uballoc(um->um_ubanum, (caddr_t)t, sizeof (struct tmscp), 0); 975bc5e3c50Skarels # ifdef MVAX 976bc5e3c50Skarels if (cpu == MVAX_I) 977*1625a9a8Skarels sc->sc_tmscp = (struct tmscp *)(sc->sc_ubainfo & 0x3fffff); 978bc5e3c50Skarels else 979bc5e3c50Skarels # endif MVAX 980*1625a9a8Skarels sc->sc_tmscp = (struct tmscp *)(sc->sc_ubainfo & 0x3ffff); 981bc5e3c50Skarels sc->sc_mapped = 1; 982bc5e3c50Skarels } 983bc5e3c50Skarels 984bc5e3c50Skarels /* 985bc5e3c50Skarels * Start the hardware initialization sequence. 986bc5e3c50Skarels */ 987bc5e3c50Skarels tmscpaddr->tmscpip = 0; /* start initialization */ 988bc5e3c50Skarels 989bc5e3c50Skarels while((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0) 990bc5e3c50Skarels { 991bc5e3c50Skarels # ifdef DEBUG 992bc5e3c50Skarels printd("tmscpinit: tmscpsa = 0%o\n",tmscpaddr->tmscpsa); 993bc5e3c50Skarels DELAY(100000); 994bc5e3c50Skarels # endif 995bc5e3c50Skarels if(tmscpaddr->tmscpsa & TMSCP_ERR) 996bc5e3c50Skarels return(0); /* CHECK */ 997bc5e3c50Skarels } 998*1625a9a8Skarels tmscpaddr->tmscpsa=TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8)|TMSCP_IE|(sc->sc_ivec/4); 999bc5e3c50Skarels /* 1000bc5e3c50Skarels * Initialization continues in the interrupt routine. 1001bc5e3c50Skarels */ 1002bc5e3c50Skarels sc->sc_state = S_STEP1; 1003bc5e3c50Skarels sc->sc_credits = 0; 1004bc5e3c50Skarels return(1); 1005bc5e3c50Skarels } 1006bc5e3c50Skarels 1007bc5e3c50Skarels 1008bc5e3c50Skarels /* 1009bc5e3c50Skarels * Start I/O operation 1010bc5e3c50Skarels * This code is convoluted. The majority of it was copied from the uda driver. 1011bc5e3c50Skarels */ 1012bc5e3c50Skarels 1013bc5e3c50Skarels tmscpstart(um) 1014bc5e3c50Skarels register struct uba_ctlr *um; 1015bc5e3c50Skarels { 1016bc5e3c50Skarels register struct buf *bp, *dp; 1017bc5e3c50Skarels register struct mscp *mp; 1018bc5e3c50Skarels register struct tmscp_softc *sc; 1019*1625a9a8Skarels register struct tms_info *tms; 1020bc5e3c50Skarels register struct uba_device *ui; 1021bc5e3c50Skarels struct tmscpdevice *tmscpaddr; 1022bc5e3c50Skarels struct tmscp *tm = &tmscp[um->um_ctlr]; 1023bc5e3c50Skarels int i,tempi; 1024bc5e3c50Skarels char ioctl; /* flag: set true if its an IOCTL command */ 1025bc5e3c50Skarels 1026bc5e3c50Skarels sc = &tmscp_softc[um->um_ctlr]; 1027bc5e3c50Skarels 1028bc5e3c50Skarels for(;;) 1029bc5e3c50Skarels { 1030bc5e3c50Skarels if ((dp = um->um_tab.b_actf) == NULL) 1031bc5e3c50Skarels { 1032bc5e3c50Skarels /* 1033bc5e3c50Skarels * Release unneeded UBA resources and return 1034bc5e3c50Skarels * (drive was inactive) 1035bc5e3c50Skarels */ 1036bc5e3c50Skarels um->um_tab.b_active = 0; 1037bc5e3c50Skarels break; 1038bc5e3c50Skarels } 1039bc5e3c50Skarels if ((bp = dp->b_actf) == NULL) 1040bc5e3c50Skarels { 1041bc5e3c50Skarels /* 1042bc5e3c50Skarels * No more requests for this drive, remove 1043bc5e3c50Skarels * from controller queue and look at next drive. 1044bc5e3c50Skarels * We know we're at the head of the controller queue. 1045bc5e3c50Skarels */ 1046bc5e3c50Skarels dp->b_active = 0; 1047bc5e3c50Skarels um->um_tab.b_actf = dp->b_forw; 1048bc5e3c50Skarels continue; /* Need to check for loop */ 1049bc5e3c50Skarels } 1050bc5e3c50Skarels um->um_tab.b_active++; 1051bc5e3c50Skarels tmscpaddr = (struct tmscpdevice *)um->um_addr; 1052*1625a9a8Skarels ui = tmsdinfo[(TMSUNIT(bp->b_dev))]; 1053*1625a9a8Skarels tms = &tms_info[ui->ui_unit]; 1054bc5e3c50Skarels if ((tmscpaddr->tmscpsa&TMSCP_ERR) || sc->sc_state != S_RUN) 1055bc5e3c50Skarels { 1056*1625a9a8Skarels tprintf(tms->tms_ttyp, 1057*1625a9a8Skarels "tms%d: hard error bn%d\n", 1058*1625a9a8Skarels minor(bp->b_dev)&03, bp->b_blkno); 1059*1625a9a8Skarels log(TMS_PRI, "tmscp%d: sa 0%o, state %d\n",um->um_ctlr, 1060bc5e3c50Skarels tmscpaddr->tmscpsa&0xffff, sc->sc_state); 1061bc5e3c50Skarels tmscpinit(um->um_ctlr); 1062bc5e3c50Skarels /* SHOULD REQUEUE OUTSTANDING REQUESTS, LIKE TMSCPRESET */ 1063bc5e3c50Skarels break; 1064bc5e3c50Skarels } 1065bc5e3c50Skarels /* 1066bc5e3c50Skarels * Default is that last command was NOT a write command; 1067bc5e3c50Skarels * if a write command is done it will be detected in tmscprsp. 1068bc5e3c50Skarels */ 1069*1625a9a8Skarels tms->tms_lastiow = 0; 1070bc5e3c50Skarels if (ui->ui_flags == 0) 1071bc5e3c50Skarels { /* not online */ 1072bc5e3c50Skarels if ((mp = tmscpgetcp(um)) == NULL) 1073bc5e3c50Skarels break; 1074bc5e3c50Skarels mp->mscp_opcode = M_OP_ONLIN; 1075bc5e3c50Skarels mp->mscp_unit = ui->ui_slave; 1076bc5e3c50Skarels dp->b_active = 2; 1077bc5e3c50Skarels um->um_tab.b_actf = dp->b_forw; /* remove from controller q */ 1078bc5e3c50Skarels *((long *)mp->mscp_dscptr) |= TMSCP_OWN|TMSCP_INT; 1079bc5e3c50Skarels if (tmscpaddr->tmscpsa&TMSCP_ERR) 1080bc5e3c50Skarels printf("tmscp%d fatal error (0%o)\n",um->um_ctlr, 1081bc5e3c50Skarels tmscpaddr->tmscpsa&0xffff); 1082bc5e3c50Skarels i = tmscpaddr->tmscpip; 1083bc5e3c50Skarels continue; 1084bc5e3c50Skarels } 1085bc5e3c50Skarels switch (cpu) { 1086bc5e3c50Skarels 1087bc5e3c50Skarels case VAX_8600: 1088bc5e3c50Skarels case VAX_780: 1089bc5e3c50Skarels i = UBA_NEEDBDP|UBA_CANTWAIT; 1090bc5e3c50Skarels break; 1091bc5e3c50Skarels case VAX_750: 1092bc5e3c50Skarels i = um->um_ubinfo|UBA_HAVEBDP|UBA_CANTWAIT; 1093bc5e3c50Skarels break; 1094bc5e3c50Skarels case VAX_730: 1095bc5e3c50Skarels i = UBA_CANTWAIT; 1096bc5e3c50Skarels break; 1097bc5e3c50Skarels } /* end switch (cpu) */ 1098bc5e3c50Skarels /* 1099*1625a9a8Skarels * If command is an ioctl command then set the ioctl flag for later use. 1100bc5e3c50Skarels * If not (i.e. it is a read or write) then attempt 1101bc5e3c50Skarels * to set up a buffer pointer. 1102bc5e3c50Skarels */ 1103bc5e3c50Skarels ioctl = 0; 1104bc5e3c50Skarels if (bp == &ctmscpbuf[um->um_ctlr]) 1105bc5e3c50Skarels ioctl = 1; 1106bc5e3c50Skarels else 1107bc5e3c50Skarels if ((i = ubasetup(um->um_ubanum, bp, i)) == 0) 1108bc5e3c50Skarels { 1109bc5e3c50Skarels if(dp->b_qsize != 0) 1110bc5e3c50Skarels break; /* When a command completes and */ 1111*1625a9a8Skarels /* frees a bdp tmscpstart will be called */ 1112bc5e3c50Skarels if ((mp = tmscpgetcp(um)) == NULL) 1113bc5e3c50Skarels break; 1114bc5e3c50Skarels # ifdef DEBUG 1115*1625a9a8Skarels printd("tmscpstart: GTUNT %d ubasetup = %d\n",ui->ui_unit, i); 1116bc5e3c50Skarels if(tmscpdebug)DELAY(10000); 1117bc5e3c50Skarels # endif 1118bc5e3c50Skarels mp->mscp_opcode = M_OP_GTUNT; 1119bc5e3c50Skarels mp->mscp_unit = ui->ui_slave; 1120bc5e3c50Skarels *((long *)mp->mscp_dscptr) |= TMSCP_OWN|TMSCP_INT; 1121bc5e3c50Skarels if (tmscpaddr->tmscpsa&TMSCP_ERR) 1122*1625a9a8Skarels printf("tmscp%d: fatal error (0%o)\n",um->um_ctlr, 1123bc5e3c50Skarels tmscpaddr->tmscpsa&0xffff); 1124bc5e3c50Skarels i = tmscpaddr->tmscpip; /* initiate polling */ 1125bc5e3c50Skarels break; 1126bc5e3c50Skarels } 1127*1625a9a8Skarels # if defined(VAX750) 1128*1625a9a8Skarels if (cpu == VAX_750) 1129bc5e3c50Skarels tempi = i & 0xfffffff; /* mask off bdp */ 1130bc5e3c50Skarels else 1131bc5e3c50Skarels # endif 1132bc5e3c50Skarels tempi = i; 1133bc5e3c50Skarels if ((mp = tmscpgetcp(um)) == NULL) 1134bc5e3c50Skarels { 1135bc5e3c50Skarels if (!ioctl) /* only need to release if NOT ioctl */ 1136bc5e3c50Skarels ubarelse(um->um_ubanum,&tempi); 1137bc5e3c50Skarels break; 1138bc5e3c50Skarels } 1139bc5e3c50Skarels mp->mscp_cmdref = (long)bp; /* pointer to get back */ 1140bc5e3c50Skarels mp->mscp_unit = ui->ui_slave; 1141bc5e3c50Skarels /* 1142bc5e3c50Skarels * If its an ioctl-type command then set up the appropriate 1143bc5e3c50Skarels * tmscp command; by doing a switch on the "b_resid" field where 1144bc5e3c50Skarels * the command mneumonic is stored. 1145bc5e3c50Skarels */ 1146bc5e3c50Skarels if (ioctl) 1147bc5e3c50Skarels { 1148bc5e3c50Skarels # ifdef DEBUG 1149bc5e3c50Skarels printd("tmscpstart: doing ioctl cmd %d\n", bp->b_resid); 1150bc5e3c50Skarels # endif 1151bc5e3c50Skarels /* 1152bc5e3c50Skarels * The reccnt and tmkcnt fields are set to zero by the getcp 1153bc5e3c50Skarels * routine (as bytecnt and buffer fields). Thus reccnt and 1154bc5e3c50Skarels * tmkcnt are only modified here if they need to be set to 1155bc5e3c50Skarels * a non-zero value. 1156bc5e3c50Skarels */ 1157bc5e3c50Skarels switch (bp->b_resid) { 1158bc5e3c50Skarels 1159bc5e3c50Skarels case TMS_WRITM: 1160bc5e3c50Skarels mp->mscp_opcode = M_OP_WRITM; 1161bc5e3c50Skarels break; 1162bc5e3c50Skarels case TMS_FSF: 1163bc5e3c50Skarels mp->mscp_opcode = M_OP_REPOS; 1164bc5e3c50Skarels mp->mscp_tmkcnt = bp->b_bcount; 1165bc5e3c50Skarels break; 1166bc5e3c50Skarels case TMS_BSF: 1167bc5e3c50Skarels mp->mscp_opcode = M_OP_REPOS; 1168bc5e3c50Skarels mp->mscp_modifier = M_MD_REVRS; 1169bc5e3c50Skarels mp->mscp_tmkcnt = bp->b_bcount; 1170bc5e3c50Skarels break; 1171bc5e3c50Skarels case TMS_FSR: 1172bc5e3c50Skarels mp->mscp_opcode = M_OP_REPOS; 1173bc5e3c50Skarels mp->mscp_modifier = M_MD_OBJCT; 1174bc5e3c50Skarels mp->mscp_reccnt = bp->b_bcount; 1175bc5e3c50Skarels break; 1176bc5e3c50Skarels case TMS_BSR: 1177bc5e3c50Skarels mp->mscp_opcode = M_OP_REPOS; 1178bc5e3c50Skarels mp->mscp_modifier = M_MD_REVRS | M_MD_OBJCT; 1179bc5e3c50Skarels mp->mscp_reccnt = bp->b_bcount; 1180bc5e3c50Skarels break; 1181bc5e3c50Skarels /* 1182bc5e3c50Skarels * Clear serious exception is done for Rewind & Available cmds 1183bc5e3c50Skarels */ 1184bc5e3c50Skarels case TMS_REW: 1185bc5e3c50Skarels mp->mscp_opcode = M_OP_REPOS; 1186bc5e3c50Skarels mp->mscp_modifier = M_MD_REWND | M_MD_CLSEX; 1187bc5e3c50Skarels if (bp->b_bcount == 0) 1188bc5e3c50Skarels mp->mscp_modifier |= M_MD_IMMED; 1189*1625a9a8Skarels tms->tms_serex = 0; 1190bc5e3c50Skarels break; 1191bc5e3c50Skarels case TMS_OFFL: 1192bc5e3c50Skarels mp->mscp_opcode = M_OP_AVAIL; 1193bc5e3c50Skarels mp->mscp_modifier = M_MD_UNLOD | M_MD_CLSEX; 1194*1625a9a8Skarels tms->tms_serex = 0; 1195bc5e3c50Skarels break; 1196bc5e3c50Skarels case TMS_SENSE: 1197bc5e3c50Skarels mp->mscp_opcode = M_OP_GTUNT; 1198bc5e3c50Skarels break; 1199bc5e3c50Skarels case TMS_CACHE: 1200bc5e3c50Skarels mp->mscp_opcode = M_OP_STUNT; 1201*1625a9a8Skarels tms->tms_unitflgs |= M_UF_WBKNV; 1202*1625a9a8Skarels mp->mscp_unitflgs = tms->tms_unitflgs; 1203*1625a9a8Skarels mp->mscp_format = tms->tms_format; 1204bc5e3c50Skarels /* default device dependant parameters */ 1205bc5e3c50Skarels mp->mscp_mediaid = 0; 1206bc5e3c50Skarels break; 1207bc5e3c50Skarels case TMS_NOCACHE: 1208bc5e3c50Skarels mp->mscp_opcode = M_OP_STUNT; 1209*1625a9a8Skarels tms->tms_unitflgs &= ~(M_UF_WBKNV); 1210*1625a9a8Skarels mp->mscp_unitflgs = tms->tms_unitflgs; 1211*1625a9a8Skarels mp->mscp_format = tms->tms_format; 1212bc5e3c50Skarels /* default device dependant parameters */ 1213bc5e3c50Skarels mp->mscp_mediaid = 0; 1214bc5e3c50Skarels break; 1215bc5e3c50Skarels case TMS_CSE: 1216bc5e3c50Skarels /* 1217bc5e3c50Skarels * This is a no-op command. It performs a 1218bc5e3c50Skarels * clear serious exception only. (Done on a 1219bc5e3c50Skarels * non-rewinding close after a serious exception.) 1220bc5e3c50Skarels */ 1221bc5e3c50Skarels mp->mscp_opcode = M_OP_REPOS; 1222bc5e3c50Skarels mp->mscp_modifier = M_MD_CLSEX; 1223*1625a9a8Skarels tms->tms_serex = 0; 1224*1625a9a8Skarels tms->tms_clserex = 1; 1225bc5e3c50Skarels break; 1226bc5e3c50Skarels case TMS_LOWDENSITY: 1227bc5e3c50Skarels /* 1228bc5e3c50Skarels * Set the unit to low density 1229bc5e3c50Skarels */ 1230bc5e3c50Skarels mp->mscp_opcode = M_OP_STUNT; 1231*1625a9a8Skarels mp->mscp_unitflgs = tms->tms_unitflgs; 1232*1625a9a8Skarels mp->mscp_mediaid = 0; /* default device dependant parameters */ 1233*1625a9a8Skarels if ((tms->tms_fmtmenu & M_TF_800) != 0) 1234bc5e3c50Skarels mp->mscp_format = M_TF_800; 1235bc5e3c50Skarels else 1236*1625a9a8Skarels mp->mscp_format = M_TF_PE & tms->tms_fmtmenu; 1237*1625a9a8Skarels tms->tms_format = mp->mscp_format; 1238bc5e3c50Skarels break; 1239bc5e3c50Skarels case TMS_HIDENSITY: 1240bc5e3c50Skarels /* 1241bc5e3c50Skarels * Set the unit to high density (format == 0) 1242bc5e3c50Skarels */ 1243bc5e3c50Skarels mp->mscp_opcode = M_OP_STUNT; 1244*1625a9a8Skarels mp->mscp_unitflgs = tms->tms_unitflgs; 1245*1625a9a8Skarels mp->mscp_mediaid = 0; /* default device dependant parameters */ 1246bc5e3c50Skarels mp->mscp_format = 0; 1247*1625a9a8Skarels tms->tms_format = 0; 1248bc5e3c50Skarels break; 1249bc5e3c50Skarels default: 1250bc5e3c50Skarels printf("Bad ioctl on tms unit %d\n", ui->ui_unit); 1251bc5e3c50Skarels /* Need a no-op. Reposition no amount */ 1252bc5e3c50Skarels mp->mscp_opcode = M_OP_REPOS; 1253bc5e3c50Skarels break; 1254bc5e3c50Skarels } /* end switch (bp->b_resid) */ 1255bc5e3c50Skarels } 1256bc5e3c50Skarels else /* Its a read/write command (not an ioctl) */ 1257bc5e3c50Skarels { 1258bc5e3c50Skarels mp->mscp_opcode = bp->b_flags&B_READ ? M_OP_READ : M_OP_WRITE; 1259bc5e3c50Skarels mp->mscp_bytecnt = bp->b_bcount; 1260bc5e3c50Skarels # if MVAX 1261bc5e3c50Skarels if (cpu == MVAX_I) 1262bc5e3c50Skarels { 1263bc5e3c50Skarels mp->mscp_buffer = (i & 0x3ffff) | TMSCP_MAP; 1264*1625a9a8Skarels mp->mscp_mapbase = (long)&(uba_hd[um->um_ubanum].uh_physuba->uba_map[0]); 1265bc5e3c50Skarels } 1266bc5e3c50Skarels else 1267bc5e3c50Skarels # endif MVAX 1268bc5e3c50Skarels mp->mscp_buffer = (i & 0x3ffff) | (((i>>28)&0xf)<<24); 1269bc5e3c50Skarels 1270bc5e3c50Skarels bp->b_ubinfo = tempi; /* save mapping info */ 1271bc5e3c50Skarels } 1272*1625a9a8Skarels if (tms->tms_serex == 2) /* if tape mark read */ 1273bc5e3c50Skarels { 1274*1625a9a8Skarels mp->mscp_modifier |= M_MD_CLSEX; /* clear serious exc */ 1275*1625a9a8Skarels tms->tms_serex = 0; 1276bc5e3c50Skarels } 1277bc5e3c50Skarels *((long *)mp->mscp_dscptr) |= TMSCP_OWN|TMSCP_INT; 1278bc5e3c50Skarels # ifdef DEBUG 1279*1625a9a8Skarels printd("tmscpstart: opcode 0%o mod %o unit %d cnt %d\n",mp->mscp_opcode,mp->mscp_modifier,mp->mscp_unit,mp->mscp_bytecnt); 1280bc5e3c50Skarels if(tmscpdebug)DELAY(100000); 1281bc5e3c50Skarels # endif 1282bc5e3c50Skarels i = tmscpaddr->tmscpip; /* initiate polling */ 1283bc5e3c50Skarels dp->b_qsize++; 1284bc5e3c50Skarels /* 1285bc5e3c50Skarels * Move drive to the end of the controller queue 1286bc5e3c50Skarels */ 1287bc5e3c50Skarels if (dp->b_forw != NULL) 1288bc5e3c50Skarels { 1289bc5e3c50Skarels um->um_tab.b_actf = dp->b_forw; 1290bc5e3c50Skarels um->um_tab.b_actl->b_forw = dp; 1291bc5e3c50Skarels um->um_tab.b_actl = dp; 1292bc5e3c50Skarels dp->b_forw = NULL; 1293bc5e3c50Skarels } 1294bc5e3c50Skarels /* 1295bc5e3c50Skarels * Move buffer to I/O wait queue 1296bc5e3c50Skarels */ 1297bc5e3c50Skarels dp->b_actf = bp->av_forw; 1298bc5e3c50Skarels dp = &tmscpwtab[um->um_ctlr]; 1299bc5e3c50Skarels bp->av_forw = dp; 1300bc5e3c50Skarels bp->av_back = dp->av_back; 1301bc5e3c50Skarels dp->av_back->av_forw = bp; 1302bc5e3c50Skarels dp->av_back = bp; 1303bc5e3c50Skarels if (tmscpaddr->tmscpsa&TMSCP_ERR) 1304bc5e3c50Skarels { 1305*1625a9a8Skarels printf("tmscp%d: fatal error (0%o)\n", um->um_ctlr, tmscpaddr->tmscpsa&0xffff); 1306bc5e3c50Skarels tmscpinit(um->um_ctlr); 1307bc5e3c50Skarels break; 1308bc5e3c50Skarels } 1309bc5e3c50Skarels } /* end for */ 1310bc5e3c50Skarels /* 1311bc5e3c50Skarels * Check for response ring transitions lost in the 1312bc5e3c50Skarels * Race condition 1313bc5e3c50Skarels */ 1314bc5e3c50Skarels for (i = sc->sc_lastrsp;; i++) 1315bc5e3c50Skarels { 1316bc5e3c50Skarels i %= NRSP; 1317bc5e3c50Skarels if (tm->tmscp_ca.ca_rspdsc[i]&TMSCP_OWN) 1318bc5e3c50Skarels break; 1319bc5e3c50Skarels tmscprsp(um, tm, sc, i); 1320bc5e3c50Skarels tm->tmscp_ca.ca_rspdsc[i] |= TMSCP_OWN; 1321bc5e3c50Skarels } 1322bc5e3c50Skarels sc->sc_lastrsp = i; 1323bc5e3c50Skarels } 1324bc5e3c50Skarels 1325bc5e3c50Skarels 1326bc5e3c50Skarels /* 1327bc5e3c50Skarels * Process a response packet 1328bc5e3c50Skarels */ 1329bc5e3c50Skarels tmscprsp(um, tm, sc, i) 1330bc5e3c50Skarels register struct uba_ctlr *um; 1331bc5e3c50Skarels register struct tmscp *tm; 1332bc5e3c50Skarels register struct tmscp_softc *sc; 1333bc5e3c50Skarels int i; 1334bc5e3c50Skarels { 1335bc5e3c50Skarels register struct mscp *mp; 1336*1625a9a8Skarels register struct tms_info *tms; 1337bc5e3c50Skarels struct uba_device *ui; 1338bc5e3c50Skarels struct buf *dp, *bp, nullbp; 1339bc5e3c50Skarels int st; 1340bc5e3c50Skarels 1341bc5e3c50Skarels mp = &tm->tmscp_rsp[i]; 1342bc5e3c50Skarels mp->mscp_header.tmscp_msglen = mscp_msglen; 1343*1625a9a8Skarels sc->sc_credits += mp->mscp_header.tmscp_credits & 0xf; /* low 4 bits */ 1344bc5e3c50Skarels if ((mp->mscp_header.tmscp_credits & 0xf0) > 0x10) /* Check */ 1345bc5e3c50Skarels return; 1346bc5e3c50Skarels # ifdef DEBUG 1347*1625a9a8Skarels printd("tmscprsp, opcode 0%o status 0%o\n",mp->mscp_opcode,mp->mscp_status&M_ST_MASK); 1348bc5e3c50Skarels # endif 1349bc5e3c50Skarels /* 1350bc5e3c50Skarels * If it's an error log message (datagram), 1351bc5e3c50Skarels * pass it on for more extensive processing. 1352bc5e3c50Skarels */ 1353bc5e3c50Skarels if ((mp->mscp_header.tmscp_credits & 0xf0) == 0x10) 1354bc5e3c50Skarels { /* check */ 1355bc5e3c50Skarels tmserror(um, (struct mslg *)mp); 1356bc5e3c50Skarels return; 1357bc5e3c50Skarels } 1358bc5e3c50Skarels st = mp->mscp_status&M_ST_MASK; 1359bc5e3c50Skarels /* 1360bc5e3c50Skarels * The controller interrupts as drive 0. 1361bc5e3c50Skarels * This means that you must check for controller interrupts 1362bc5e3c50Skarels * before you check to see if there is a drive 0. 1363bc5e3c50Skarels */ 1364bc5e3c50Skarels if((M_OP_STCON|M_OP_END) == mp->mscp_opcode) 1365bc5e3c50Skarels { 1366bc5e3c50Skarels if (st == M_ST_SUCC) 1367bc5e3c50Skarels { 1368bc5e3c50Skarels # ifdef DEBUG 1369*1625a9a8Skarels printd("ctlr has %d credits\n", mp->mscp_header.tmscp_credits & 0xf); 1370bc5e3c50Skarels printd("ctlr timeout = %d\n", mp->mscp_cnttmo); 1371bc5e3c50Skarels # endif 1372bc5e3c50Skarels sc->sc_state = S_RUN; 1373bc5e3c50Skarels } 1374bc5e3c50Skarels else 1375bc5e3c50Skarels sc->sc_state = S_IDLE; 1376bc5e3c50Skarels um->um_tab.b_active = 0; 1377bc5e3c50Skarels wakeup((caddr_t)um); 1378bc5e3c50Skarels return; 1379bc5e3c50Skarels } 1380*1625a9a8Skarels if (mp->mscp_unit >= NTMS) 1381bc5e3c50Skarels return; 1382bc5e3c50Skarels if ((ui = tmscpip[um->um_ctlr][mp->mscp_unit]) == 0) 1383bc5e3c50Skarels return; 1384*1625a9a8Skarels tms = &tms_info[ui->ui_unit]; 1385bc5e3c50Skarels /* 1386bc5e3c50Skarels * Save endcode, endflags, and status for mtioctl get unit status. 1387bc5e3c50Skarels * NOTE: Don't do this on Clear serious exception (reposition no-op); 1388bc5e3c50Skarels * which is done on close since this would 1389bc5e3c50Skarels * overwrite the real status we want. 1390bc5e3c50Skarels */ 1391*1625a9a8Skarels if (tms->tms_clserex != 1) 1392bc5e3c50Skarels { 1393*1625a9a8Skarels tms->tms_endcode = mp->mscp_opcode; 1394*1625a9a8Skarels tms->tms_flags = mp->mscp_flags; 1395*1625a9a8Skarels tms->tms_status = st; 1396bc5e3c50Skarels } 1397*1625a9a8Skarels else tms->tms_clserex = 0; 1398bc5e3c50Skarels 1399bc5e3c50Skarels switch (mp->mscp_opcode) { 1400bc5e3c50Skarels case M_OP_ONLIN|M_OP_END: 1401*1625a9a8Skarels tms->tms_type = mp->mscp_mediaid; 1402bc5e3c50Skarels dp = &tmsutab[ui->ui_unit]; 1403bc5e3c50Skarels if (st == M_ST_SUCC) 1404bc5e3c50Skarels { 1405bc5e3c50Skarels /* 1406bc5e3c50Skarels * Link the drive onto the controller queue 1407bc5e3c50Skarels */ 1408bc5e3c50Skarels dp->b_forw = NULL; 1409bc5e3c50Skarels if (um->um_tab.b_actf == NULL) 1410bc5e3c50Skarels um->um_tab.b_actf = dp; 1411bc5e3c50Skarels else 1412bc5e3c50Skarels um->um_tab.b_actl->b_forw = dp; 1413bc5e3c50Skarels um->um_tab.b_actl = dp; 1414bc5e3c50Skarels ui->ui_flags = 1; /* mark it online */ 1415*1625a9a8Skarels tms->tms_dsize=(daddr_t)mp->mscp_maxwrt; 1416bc5e3c50Skarels # ifdef DEBUG 1417bc5e3c50Skarels printd("tmscprsp: unit %d online\n", mp->mscp_unit); 1418bc5e3c50Skarels # endif 1419bc5e3c50Skarels /* 1420bc5e3c50Skarels * This define decodes the Media type identifier 1421bc5e3c50Skarels */ 1422*1625a9a8Skarels # define F_to_C(x,i) ( ((x)->mscp_mediaid) >> (i*5+7) & 0x1f ? ( ( (((x)->mscp_mediaid) >>( i*5 + 7)) & 0x1f) + 'A' - 1): ' ') 1423bc5e3c50Skarels # ifdef DEBUG 1424bc5e3c50Skarels printd("tmscprsp: unit %d online %x %c%c %c%c%c%d\n" 1425bc5e3c50Skarels ,mp->mscp_unit, mp->mscp_mediaid ,F_to_C(mp,4) 1426bc5e3c50Skarels ,F_to_C(mp,3), F_to_C(mp,2) 1427*1625a9a8Skarels ,F_to_C(mp,1), F_to_C(mp,0), mp->mscp_mediaid & 0x7f); 1428bc5e3c50Skarels # endif 1429bc5e3c50Skarels dp->b_active = 1; 1430bc5e3c50Skarels } /* end if st == M_ST_SUCC */ 1431bc5e3c50Skarels else 1432bc5e3c50Skarels { 1433bc5e3c50Skarels if(dp->b_actf) 1434*1625a9a8Skarels tprintf(tms->tms_ttyp, 1435*1625a9a8Skarels "tms%d: hard error bn%d: OFFLINE\n", 1436*1625a9a8Skarels minor(bp->b_dev)&03, bp->b_blkno); 1437bc5e3c50Skarels else 1438*1625a9a8Skarels tprintf(tms->tms_ttyp, 1439*1625a9a8Skarels "tms%d: hard error: OFFLINE\n", 1440*1625a9a8Skarels minor(bp->b_dev)&03); 1441bc5e3c50Skarels while (bp = dp->b_actf) 1442bc5e3c50Skarels { 1443bc5e3c50Skarels dp->b_actf = bp->av_forw; 1444bc5e3c50Skarels bp->b_flags |= B_ERROR; 1445bc5e3c50Skarels iodone(bp); 1446bc5e3c50Skarels } 1447bc5e3c50Skarels } 1448bc5e3c50Skarels if(mp->mscp_cmdref!=NULL) 1449bc5e3c50Skarels /* Seems to get lost sometimes in uda */ 1450bc5e3c50Skarels wakeup((caddr_t *) mp->mscp_cmdref); 1451bc5e3c50Skarels break; 1452bc5e3c50Skarels /* 1453bc5e3c50Skarels * The AVAILABLE ATTENTION message occurs when the 1454bc5e3c50Skarels * unit becomes available after loading, 1455bc5e3c50Skarels * marking the unit offline (ui_flags = 0) will force an 1456bc5e3c50Skarels * online command prior to using the unit. 1457bc5e3c50Skarels */ 1458bc5e3c50Skarels case M_OP_AVATN: 1459bc5e3c50Skarels ui->ui_flags = 0; 1460*1625a9a8Skarels tms->tms_type = mp->mscp_mediaid; 1461bc5e3c50Skarels break; 1462bc5e3c50Skarels case M_OP_END: 1463bc5e3c50Skarels /* 1464bc5e3c50Skarels * An endcode without an opcode (0200) is an invalid command. 1465bc5e3c50Skarels * The mscp specification states that this would be a protocol 1466bc5e3c50Skarels * type error, such as illegal opcodes. The mscp spec. also 1467bc5e3c50Skarels * states that parameter error type of invalid commands should 1468*1625a9a8Skarels * return the normal end message for the command. This does not appear 1469*1625a9a8Skarels * to be the case. An invalid logical block number returned an endcode 1470bc5e3c50Skarels * of 0200 instead of the 0241 (read) that was expected. 1471bc5e3c50Skarels */ 1472bc5e3c50Skarels 1473bc5e3c50Skarels printf("tmscp%d: invalid cmd, endcode = %o, status=%o\n", 1474bc5e3c50Skarels um->um_ctlr, mp->mscp_opcode, st); 1475bc5e3c50Skarels bp = (struct buf *)mp->mscp_cmdref; 1476bc5e3c50Skarels /* 1477bc5e3c50Skarels * Unlink buffer from I/O wait queue. 1478bc5e3c50Skarels * And signal iodone, so the higher level command can exit! 1479bc5e3c50Skarels * 1480bc5e3c50Skarels */ 1481bc5e3c50Skarels bp->av_back->av_forw = bp->av_forw; 1482bc5e3c50Skarels bp->av_forw->av_back = bp->av_back; 1483bc5e3c50Skarels dp = &tmsutab[ui->ui_unit]; 1484bc5e3c50Skarels dp->b_qsize--; 1485bc5e3c50Skarels iodone(bp); 1486bc5e3c50Skarels break; 1487bc5e3c50Skarels case M_OP_WRITE|M_OP_END: 1488bc5e3c50Skarels /* mark the last io op as a write */ 1489*1625a9a8Skarels tms->tms_lastiow = 1; 1490bc5e3c50Skarels case M_OP_READ|M_OP_END: 1491bc5e3c50Skarels case M_OP_WRITM|M_OP_END: 1492bc5e3c50Skarels case M_OP_REPOS|M_OP_END: 1493bc5e3c50Skarels case M_OP_STUNT|M_OP_END: 1494bc5e3c50Skarels /* 1495bc5e3c50Skarels * The AVAILABLE message occurs when the mt ioctl "rewoffl" is 1496bc5e3c50Skarels * issued. For the ioctl, "rewoffl", a tmscp AVAILABLE command is 1497bc5e3c50Skarels * done with the UNLOAD modifier. This performs a rewind, followed 1498bc5e3c50Skarels * by marking the unit offline. So mark the unit offline 1499bc5e3c50Skarels * software wise as well (ui_flags = 0 and 1500*1625a9a8Skarels * tms->tms_openf = 0). 1501bc5e3c50Skarels */ 1502bc5e3c50Skarels case M_OP_AVAIL|M_OP_END: 1503bc5e3c50Skarels # ifdef DEBUG 1504bc5e3c50Skarels printd("tmscprsp: position = %d\n", mp->mscp_lbn); 1505bc5e3c50Skarels # endif 1506bc5e3c50Skarels bp = (struct buf *)mp->mscp_cmdref; 1507bc5e3c50Skarels /* 1508*1625a9a8Skarels * Only need to release buffer if the command was read or write. 1509bc5e3c50Skarels * No ubasetup was done in "tmscpstart" if it was an ioctl cmd. 1510bc5e3c50Skarels */ 1511bc5e3c50Skarels if (mp->mscp_opcode == (M_OP_READ|M_OP_END) || 1512bc5e3c50Skarels mp->mscp_opcode == (M_OP_WRITE|M_OP_END)) 1513bc5e3c50Skarels ubarelse(um->um_ubanum, (int *)&bp->b_ubinfo); 1514bc5e3c50Skarels /* 1515bc5e3c50Skarels * Unlink buffer from I/O wait queue. 1516bc5e3c50Skarels */ 1517bc5e3c50Skarels bp->av_back->av_forw = bp->av_forw; 1518bc5e3c50Skarels bp->av_forw->av_back = bp->av_back; 1519*1625a9a8Skarels # if defined(VAX750) 1520*1625a9a8Skarels if (cpu == VAX_750) { 1521*1625a9a8Skarels if ((tmscpwtab[um->um_ctlr].av_forw == &tmscpwtab[um->um_ctlr]) && 1522bc5e3c50Skarels (um->um_ubinfo != 0)) { 1523bc5e3c50Skarels ubarelse(um->um_ubanum, &um->um_ubinfo); 1524bc5e3c50Skarels } 1525bc5e3c50Skarels else { 1526bc5e3c50Skarels if (mp->mscp_opcode == (M_OP_READ|M_OP_END) || 1527bc5e3c50Skarels mp->mscp_opcode == (M_OP_WRITE|M_OP_END)) 1528*1625a9a8Skarels UBAPURGE(uba_hd[um->um_ubanum].uh_uba,(um->um_ubinfo >>28) & 0x0f); 1529bc5e3c50Skarels } 1530bc5e3c50Skarels } 1531bc5e3c50Skarels # endif 1532bc5e3c50Skarels dp = &tmsutab[ui->ui_unit]; 1533bc5e3c50Skarels dp->b_qsize--; 1534bc5e3c50Skarels if (st == M_ST_OFFLN || st == M_ST_AVLBL) 1535bc5e3c50Skarels { 1536bc5e3c50Skarels ui->ui_flags = 0; /* mark unit offline */ 1537*1625a9a8Skarels tms->tms_openf = 0; 1538*1625a9a8Skarels tms->tms_type = mp->mscp_mediaid; 1539bc5e3c50Skarels /* 1540bc5e3c50Skarels * Link the buffer onto the front of the drive queue 1541bc5e3c50Skarels */ 1542bc5e3c50Skarels if ((bp->av_forw = dp->b_actf) == 0) 1543bc5e3c50Skarels dp->b_actl = bp; 1544bc5e3c50Skarels dp->b_actf = bp; 1545bc5e3c50Skarels /* 1546bc5e3c50Skarels * Link the drive onto the controller queue 1547bc5e3c50Skarels */ 1548bc5e3c50Skarels if (dp->b_active == 0) 1549bc5e3c50Skarels { 1550bc5e3c50Skarels dp->b_forw = NULL; 1551bc5e3c50Skarels if (um->um_tab.b_actf == NULL) 1552bc5e3c50Skarels um->um_tab.b_actf = dp; 1553bc5e3c50Skarels else 1554bc5e3c50Skarels um->um_tab.b_actl->b_forw = dp; 1555bc5e3c50Skarels um->um_tab.b_actl = dp; 1556bc5e3c50Skarels dp->b_active = 1; 1557bc5e3c50Skarels } 1558*1625a9a8Skarels # if defined(VAX750) 1559*1625a9a8Skarels if (cpu == VAX_750 && um->um_ubinfo == 0) 1560*1625a9a8Skarels um->um_ubinfo = uballoc(um->um_ubanum, (caddr_t)0, 0, UBA_NEEDBDP); 1561bc5e3c50Skarels # endif 1562bc5e3c50Skarels return; 1563bc5e3c50Skarels } 1564bc5e3c50Skarels if (st != M_ST_SUCC) 1565bc5e3c50Skarels { 1566bc5e3c50Skarels if (mp->mscp_flags & M_EF_SEREX) 1567*1625a9a8Skarels tms->tms_serex = 1; 1568bc5e3c50Skarels if (st != M_ST_TAPEM) 1569bc5e3c50Skarels { 1570*1625a9a8Skarels tprintf(tms->tms_ttyp, 1571*1625a9a8Skarels "tms%d: hard error bn%d\n", 1572*1625a9a8Skarels minor(bp->b_dev)&03, bp->b_blkno); 1573*1625a9a8Skarels errinfo(st); /* produces more info */ 1574bc5e3c50Skarels # ifdef DEBUG 1575*1625a9a8Skarels printd("tmscprsp: error; status sub-code = 0%o, flags = 0%o\n", 1576*1625a9a8Skarels (mp->mscp_status & 177740)>>5, mp->mscp_flags); 1577bc5e3c50Skarels # endif 1578bc5e3c50Skarels bp->b_flags |= B_ERROR; 1579bc5e3c50Skarels } 1580bc5e3c50Skarels else 1581bc5e3c50Skarels /* Hit a tape mark - Set serex flag to 1582bc5e3c50Skarels * a special value so we can clear the 1583bc5e3c50Skarels * serious exception on the next command. 1584bc5e3c50Skarels */ 1585*1625a9a8Skarels tms->tms_serex = 2; 1586bc5e3c50Skarels } 1587bc5e3c50Skarels /* 1588bc5e3c50Skarels * The tmscp spec states that controllers do not have to 1589bc5e3c50Skarels * report the number of records or files skipped. So on 1590bc5e3c50Skarels * reposition commands we go strictly by cmd status. 1591bc5e3c50Skarels */ 1592bc5e3c50Skarels if (mp->mscp_opcode != (M_OP_REPOS|M_OP_END)) 1593bc5e3c50Skarels bp->b_resid = bp->b_bcount - mp->mscp_bytecnt; 1594bc5e3c50Skarels else 1595bc5e3c50Skarels bp->b_resid = 0; 1596*1625a9a8Skarels tms->tms_resid = bp->b_resid; 1597bc5e3c50Skarels iodone(bp); 1598bc5e3c50Skarels break; 1599bc5e3c50Skarels 1600bc5e3c50Skarels case M_OP_GTUNT|M_OP_END: 1601bc5e3c50Skarels # ifdef DEBUG 1602bc5e3c50Skarels printd("tmscprsp: GTUNT end packet status = 0%o\n",st); 1603*1625a9a8Skarels printd("tmscprsp: unit %d mediaid %x %c%c %c%c%c%d %x %x t=%d\n" 1604bc5e3c50Skarels ,mp->mscp_unit, mp->mscp_mediaid 1605bc5e3c50Skarels ,F_to_C(mp,4),F_to_C(mp,3),F_to_C(mp,2) 1606bc5e3c50Skarels ,F_to_C(mp,1),F_to_C(mp,0) 1607bc5e3c50Skarels ,mp->mscp_mediaid & 0x7f 1608bc5e3c50Skarels ,mp->mscp_unitid.val[0] 1609bc5e3c50Skarels ,mp->mscp_unitid.val[1] 1610bc5e3c50Skarels ,mp->mscp_format); 1611bc5e3c50Skarels # endif 1612*1625a9a8Skarels tms->tms_type = mp->mscp_mediaid; 1613*1625a9a8Skarels tms->tms_fmtmenu = mp->mscp_fmtmenu; 1614*1625a9a8Skarels tms->tms_unitflgs = mp->mscp_unitflgs; 1615bc5e3c50Skarels break; 1616bc5e3c50Skarels 1617bc5e3c50Skarels default: 1618bc5e3c50Skarels printf("tmscp unknown packet\n"); 1619bc5e3c50Skarels tmserror(um, (struct mslg *)mp); 1620bc5e3c50Skarels } /* end switch mp->mscp_opcode */ 1621bc5e3c50Skarels } 1622bc5e3c50Skarels 1623bc5e3c50Skarels 1624bc5e3c50Skarels /* 1625bc5e3c50Skarels * Give a meaningful error when the mscp_status field returns an error code. 1626bc5e3c50Skarels */ 1627bc5e3c50Skarels 1628bc5e3c50Skarels errinfo(st) 1629bc5e3c50Skarels int st; /* the status code */ 1630bc5e3c50Skarels { 1631bc5e3c50Skarels switch(st) { 1632bc5e3c50Skarels case M_ST_ICMD: 1633bc5e3c50Skarels printf("invalid command\n"); 1634bc5e3c50Skarels break; 1635bc5e3c50Skarels case M_ST_ABRTD: 1636bc5e3c50Skarels printf("command aborted\n"); 1637bc5e3c50Skarels break; 1638bc5e3c50Skarels case M_ST_OFFLN: 1639bc5e3c50Skarels printf("unit offline\n"); 1640bc5e3c50Skarels break; 1641bc5e3c50Skarels case M_ST_WRTPR: 1642bc5e3c50Skarels printf("unit write protected\n"); 1643bc5e3c50Skarels break; 1644bc5e3c50Skarels case M_ST_COMP: 1645bc5e3c50Skarels printf("compare error\n"); 1646bc5e3c50Skarels break; 1647bc5e3c50Skarels case M_ST_DATA: 1648bc5e3c50Skarels printf("data error\n"); 1649bc5e3c50Skarels break; 1650bc5e3c50Skarels case M_ST_HSTBF: 1651bc5e3c50Skarels printf("host buffer access error\n"); 1652bc5e3c50Skarels break; 1653bc5e3c50Skarels case M_ST_CNTLR: 1654bc5e3c50Skarels printf("controller error\n"); 1655bc5e3c50Skarels break; 1656bc5e3c50Skarels case M_ST_DRIVE: 1657bc5e3c50Skarels printf("drive error\n"); 1658bc5e3c50Skarels break; 1659bc5e3c50Skarels case M_ST_FMTER: 1660bc5e3c50Skarels printf("formatter error\n"); 1661bc5e3c50Skarels break; 1662bc5e3c50Skarels case M_ST_BOT: 1663bc5e3c50Skarels printf("BOT encountered\n"); 1664bc5e3c50Skarels break; 1665bc5e3c50Skarels case M_ST_TAPEM: 1666bc5e3c50Skarels printf("tape mark encountered\n"); 1667bc5e3c50Skarels break; 1668bc5e3c50Skarels case M_ST_RDTRN: 1669bc5e3c50Skarels printf("record data truncated\n"); 1670bc5e3c50Skarels break; 1671bc5e3c50Skarels case M_ST_PLOST: 1672bc5e3c50Skarels printf("position lost\n"); 1673bc5e3c50Skarels break; 1674bc5e3c50Skarels case M_ST_SEX: 1675bc5e3c50Skarels printf("serious exception\n"); 1676bc5e3c50Skarels break; 1677bc5e3c50Skarels case M_ST_LED: 1678bc5e3c50Skarels printf("LEOT detected\n"); 1679bc5e3c50Skarels break; 1680bc5e3c50Skarels } 1681bc5e3c50Skarels } 1682bc5e3c50Skarels 1683bc5e3c50Skarels 1684bc5e3c50Skarels /* 1685bc5e3c50Skarels * Manage buffers and perform block mode read and write operations. 1686bc5e3c50Skarels */ 1687bc5e3c50Skarels 1688bc5e3c50Skarels tmscpstrategy (bp) 1689bc5e3c50Skarels register struct buf *bp; 1690bc5e3c50Skarels { 1691bc5e3c50Skarels register struct uba_device *ui; 1692bc5e3c50Skarels register struct uba_ctlr *um; 1693bc5e3c50Skarels register struct buf *dp; 1694bc5e3c50Skarels register int unit = TMSUNIT(bp->b_dev); 1695bc5e3c50Skarels int s; 1696bc5e3c50Skarels 1697*1625a9a8Skarels if (unit >= NTMS) 1698bc5e3c50Skarels { 1699bc5e3c50Skarels # ifdef DEBUG 1700bc5e3c50Skarels printd ("tmscpstrategy: bad unit # %d\n",unit); 1701bc5e3c50Skarels # endif 1702bc5e3c50Skarels bp->b_flags |= B_ERROR; 1703bc5e3c50Skarels iodone(bp); 1704bc5e3c50Skarels return; 1705bc5e3c50Skarels } 1706bc5e3c50Skarels ui = tmsdinfo[unit]; 1707bc5e3c50Skarels um = ui->ui_mi; 1708bc5e3c50Skarels if (ui == 0 || ui->ui_alive == 0) 1709bc5e3c50Skarels { 1710bc5e3c50Skarels bp->b_flags |= B_ERROR; 1711bc5e3c50Skarels iodone(bp); 1712bc5e3c50Skarels return; 1713bc5e3c50Skarels } 1714bc5e3c50Skarels s = spl5(); 1715bc5e3c50Skarels /* 1716bc5e3c50Skarels * Link the buffer onto the drive queue 1717bc5e3c50Skarels */ 1718bc5e3c50Skarels dp = &tmsutab[ui->ui_unit]; 1719bc5e3c50Skarels if (dp->b_actf == 0) 1720bc5e3c50Skarels dp->b_actf = bp; 1721bc5e3c50Skarels else 1722bc5e3c50Skarels dp->b_actl->av_forw = bp; 1723bc5e3c50Skarels dp->b_actl = bp; 1724bc5e3c50Skarels bp->av_forw = 0; 1725bc5e3c50Skarels /* 1726bc5e3c50Skarels * Link the drive onto the controller queue 1727bc5e3c50Skarels */ 1728bc5e3c50Skarels if (dp->b_active == 0) 1729bc5e3c50Skarels { 1730bc5e3c50Skarels dp->b_forw = NULL; 1731bc5e3c50Skarels if (um->um_tab.b_actf == NULL) 1732bc5e3c50Skarels um->um_tab.b_actf = dp; 1733bc5e3c50Skarels else 1734bc5e3c50Skarels um->um_tab.b_actl->b_forw = dp; 1735bc5e3c50Skarels um->um_tab.b_actl = dp; 1736bc5e3c50Skarels dp->b_active = 1; 1737bc5e3c50Skarels } 1738bc5e3c50Skarels /* 1739bc5e3c50Skarels * If the controller is not active, start it. 1740bc5e3c50Skarels */ 1741bc5e3c50Skarels if (um->um_tab.b_active == 0) 1742bc5e3c50Skarels { 1743*1625a9a8Skarels # if defined(VAX750) 1744*1625a9a8Skarels if (cpu == VAX_750 1745*1625a9a8Skarels && tmscpwtab[um->um_ctlr].av_forw == &tmscpwtab[um->um_ctlr]) 1746bc5e3c50Skarels { 1747bc5e3c50Skarels if (um->um_ubinfo != 0) 1748*1625a9a8Skarels log(TMS_PRI, "tmscpstrategy: ubinfo 0x%x\n", 1749*1625a9a8Skarels um->um_ubinfo); 1750bc5e3c50Skarels else 1751*1625a9a8Skarels um->um_ubinfo = uballoc(um->um_ubanum, (caddr_t)0, 0, UBA_NEEDBDP); 1752bc5e3c50Skarels } 1753bc5e3c50Skarels # endif 1754bc5e3c50Skarels # ifdef DEBUG 1755*1625a9a8Skarels printd10("tmscpstrategy: Controller not active, starting it\n"); 1756bc5e3c50Skarels # endif 1757bc5e3c50Skarels (void) tmscpstart(um); 1758bc5e3c50Skarels } 1759bc5e3c50Skarels splx(s); 1760bc5e3c50Skarels return; 1761bc5e3c50Skarels } 1762bc5e3c50Skarels 1763bc5e3c50Skarels #define DBSIZE 32 1764bc5e3c50Skarels 1765bc5e3c50Skarels #define ca_Rspdsc ca_rspdsc[0] 1766bc5e3c50Skarels #define ca_Cmddsc ca_rspdsc[1] 1767bc5e3c50Skarels #define tmscp_Rsp tmscp_rsp[0] 1768bc5e3c50Skarels #define tmscp_Cmd tmscp_cmd[0] 1769bc5e3c50Skarels 1770bc5e3c50Skarels struct tmscp tmscpd[NTMSCP]; 1771bc5e3c50Skarels 1772bc5e3c50Skarels tmscpdump(dev) 1773bc5e3c50Skarels dev_t dev; 1774bc5e3c50Skarels { 1775bc5e3c50Skarels struct tmscpdevice *tmscpaddr; 1776bc5e3c50Skarels struct tmscp *tmscp_ubaddr; 1777bc5e3c50Skarels char *start; 1778bc5e3c50Skarels int num, blk, unit; 1779bc5e3c50Skarels register struct uba_regs *uba; 1780bc5e3c50Skarels register struct uba_device *ui; 1781bc5e3c50Skarels register struct tmscp *tmscpp; 1782bc5e3c50Skarels register struct pte *io; 1783bc5e3c50Skarels register int i; 1784bc5e3c50Skarels 1785bc5e3c50Skarels unit = minor(dev) & 03; 1786*1625a9a8Skarels if (unit >= NTMS) 1787bc5e3c50Skarels return (ENXIO); 1788bc5e3c50Skarels # define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 1789bc5e3c50Skarels ui = phys(struct uba_device *, tmsdinfo[unit]); 1790bc5e3c50Skarels if (ui->ui_alive == 0) 1791bc5e3c50Skarels return (ENXIO); 1792bc5e3c50Skarels uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 1793bc5e3c50Skarels ubainit(uba); 1794bc5e3c50Skarels tmscpaddr = (struct tmscpdevice *)ui->ui_physaddr; 1795bc5e3c50Skarels DELAY(2000000); 1796bc5e3c50Skarels tmscpp = phys(struct tmscp *, &tmscpd[ui->ui_ctlr]); 1797bc5e3c50Skarels 1798bc5e3c50Skarels num = btoc(sizeof(struct tmscp)) + 1; 1799bc5e3c50Skarels io = &uba->uba_map[NUBMREG-num]; 1800bc5e3c50Skarels for(i = 0; i<num; i++) 1801bc5e3c50Skarels *(int *)io++ = UBAMR_MRV|(btop(tmscpp)+i); 1802*1625a9a8Skarels tmscp_ubaddr = (struct tmscp *)(((int)tmscpp & PGOFSET)|((NUBMREG-num)<<9)); 1803bc5e3c50Skarels 1804bc5e3c50Skarels tmscpaddr->tmscpip = 0; 1805bc5e3c50Skarels while ((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0) 1806bc5e3c50Skarels if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT); 1807bc5e3c50Skarels tmscpaddr->tmscpsa = TMSCP_ERR; 1808bc5e3c50Skarels while ((tmscpaddr->tmscpsa & TMSCP_STEP2) == 0) 1809bc5e3c50Skarels if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT); 1810bc5e3c50Skarels tmscpaddr->tmscpsa = (short)&tmscp_ubaddr->tmscp_ca.ca_ringbase; 1811bc5e3c50Skarels while ((tmscpaddr->tmscpsa & TMSCP_STEP3) == 0) 1812bc5e3c50Skarels if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT); 1813*1625a9a8Skarels tmscpaddr->tmscpsa = (short)(((int)&tmscp_ubaddr->tmscp_ca.ca_ringbase) >> 16); 1814bc5e3c50Skarels while ((tmscpaddr->tmscpsa & TMSCP_STEP4) == 0) 1815bc5e3c50Skarels if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT); 1816bc5e3c50Skarels tmscpaddr->tmscpsa = TMSCP_GO; 1817*1625a9a8Skarels tmscpp->tmscp_ca.ca_Rspdsc = (long)&tmscp_ubaddr->tmscp_Rsp.mscp_cmdref; 1818*1625a9a8Skarels tmscpp->tmscp_ca.ca_Cmddsc = (long)&tmscp_ubaddr->tmscp_Cmd.mscp_cmdref; 1819bc5e3c50Skarels tmscpp->tmscp_Cmd.mscp_header.tmscp_vcid = 1; /* for tape */ 1820bc5e3c50Skarels tmscpp->tmscp_Cmd.mscp_cntflgs = 0; 1821bc5e3c50Skarels tmscpp->tmscp_Cmd.mscp_version = 0; 1822bc5e3c50Skarels if (tmscpcmd(M_OP_STCON, tmscpp, tmscpaddr) == 0) { 1823bc5e3c50Skarels return(EFAULT); 1824bc5e3c50Skarels } 1825bc5e3c50Skarels tmscpp->tmscp_Cmd.mscp_unit = ui->ui_slave; 1826bc5e3c50Skarels if (tmscpcmd(M_OP_ONLIN, tmscpp, tmscpaddr) == 0) { 1827bc5e3c50Skarels return(EFAULT); 1828bc5e3c50Skarels } 1829bc5e3c50Skarels 1830bc5e3c50Skarels num = maxfree; 1831bc5e3c50Skarels start = 0; 1832bc5e3c50Skarels while (num > 0) 1833bc5e3c50Skarels { 1834bc5e3c50Skarels blk = num > DBSIZE ? DBSIZE : num; 1835bc5e3c50Skarels io = uba->uba_map; 1836bc5e3c50Skarels for (i = 0; i < blk; i++) 1837bc5e3c50Skarels *(int *)io++ = (btop(start)+i) | UBAMR_MRV; 1838bc5e3c50Skarels *(int *)io = 0; 1839bc5e3c50Skarels tmscpp->tmscp_Cmd.mscp_lbn = btop(start); 1840bc5e3c50Skarels tmscpp->tmscp_Cmd.mscp_unit = ui->ui_slave; 1841bc5e3c50Skarels tmscpp->tmscp_Cmd.mscp_bytecnt = blk*NBPG; 1842bc5e3c50Skarels # ifdef MVAX 1843bc5e3c50Skarels if( cpu == MVAX_I ) 1844bc5e3c50Skarels tmscpp->tmscp_Cmd.mscp_buffer = (long) start; 1845bc5e3c50Skarels else 1846bc5e3c50Skarels # endif MVAX 1847bc5e3c50Skarels tmscpp->tmscp_Cmd.mscp_buffer = 0; 1848bc5e3c50Skarels if (tmscpcmd(M_OP_WRITE, tmscpp, tmscpaddr) == 0) 1849bc5e3c50Skarels return(EIO); 1850bc5e3c50Skarels start += blk*NBPG; 1851bc5e3c50Skarels num -= blk; 1852bc5e3c50Skarels } 1853bc5e3c50Skarels return (0); 1854bc5e3c50Skarels } 1855bc5e3c50Skarels 1856bc5e3c50Skarels 1857bc5e3c50Skarels /* 1858bc5e3c50Skarels * Perform a standalone tmscp command. This routine is only used by tmscpdump. 1859bc5e3c50Skarels */ 1860bc5e3c50Skarels 1861bc5e3c50Skarels tmscpcmd(op, tmscpp, tmscpaddr) 1862bc5e3c50Skarels int op; 1863bc5e3c50Skarels register struct tmscp *tmscpp; 1864bc5e3c50Skarels struct tmscpdevice *tmscpaddr; 1865bc5e3c50Skarels { 1866bc5e3c50Skarels int i; 1867bc5e3c50Skarels 1868bc5e3c50Skarels # ifdef lint 1869bc5e3c50Skarels i = i; 1870bc5e3c50Skarels # endif 1871bc5e3c50Skarels 1872bc5e3c50Skarels tmscpp->tmscp_Cmd.mscp_opcode = op; 1873bc5e3c50Skarels tmscpp->tmscp_Rsp.mscp_header.tmscp_msglen = mscp_msglen; 1874bc5e3c50Skarels tmscpp->tmscp_Cmd.mscp_header.tmscp_msglen = mscp_msglen; 1875bc5e3c50Skarels tmscpp->tmscp_ca.ca_Rspdsc |= TMSCP_OWN|TMSCP_INT; 1876bc5e3c50Skarels tmscpp->tmscp_ca.ca_Cmddsc |= TMSCP_OWN|TMSCP_INT; 1877bc5e3c50Skarels if (tmscpaddr->tmscpsa&TMSCP_ERR) 1878bc5e3c50Skarels printf("tmscp fatal error (0%o)\n", tmscpaddr->tmscpsa&0xffff); 1879bc5e3c50Skarels i = tmscpaddr->tmscpip; 1880bc5e3c50Skarels for (;;) 1881bc5e3c50Skarels { 1882bc5e3c50Skarels if (tmscpp->tmscp_ca.ca_cmdint) 1883bc5e3c50Skarels tmscpp->tmscp_ca.ca_cmdint = 0; 1884bc5e3c50Skarels if (tmscpp->tmscp_ca.ca_rspint) 1885bc5e3c50Skarels break; 1886bc5e3c50Skarels } 1887bc5e3c50Skarels tmscpp->tmscp_ca.ca_rspint = 0; 1888bc5e3c50Skarels if (tmscpp->tmscp_Rsp.mscp_opcode != (op|M_OP_END) || 1889bc5e3c50Skarels (tmscpp->tmscp_Rsp.mscp_status&M_ST_MASK) != M_ST_SUCC) 1890bc5e3c50Skarels { 1891bc5e3c50Skarels printf("error: com %d opc 0x%x stat 0x%x\ndump ", op, 1892*1625a9a8Skarels tmscpp->tmscp_Rsp.mscp_opcode, tmscpp->tmscp_Rsp.mscp_status); 1893bc5e3c50Skarels return(0); 1894bc5e3c50Skarels } 1895bc5e3c50Skarels return(1); 1896bc5e3c50Skarels } 1897bc5e3c50Skarels 1898bc5e3c50Skarels 1899bc5e3c50Skarels /* 1900bc5e3c50Skarels * Perform raw read 1901bc5e3c50Skarels */ 1902bc5e3c50Skarels 1903bc5e3c50Skarels tmscpread(dev, uio) 1904bc5e3c50Skarels dev_t dev; 1905bc5e3c50Skarels struct uio *uio; 1906bc5e3c50Skarels { 1907bc5e3c50Skarels register int unit = TMSUNIT(dev); 1908bc5e3c50Skarels 1909*1625a9a8Skarels if (unit >= NTMS) 1910bc5e3c50Skarels return (ENXIO); 1911*1625a9a8Skarels return (physio(tmscpstrategy, &rtmsbuf[unit], dev, B_READ, minphys, uio)); 1912bc5e3c50Skarels } 1913bc5e3c50Skarels 1914bc5e3c50Skarels 1915bc5e3c50Skarels /* 1916bc5e3c50Skarels * Perform raw write 1917bc5e3c50Skarels */ 1918bc5e3c50Skarels 1919bc5e3c50Skarels tmscpwrite(dev, uio) 1920bc5e3c50Skarels dev_t dev; 1921bc5e3c50Skarels struct uio *uio; 1922bc5e3c50Skarels { 1923bc5e3c50Skarels register int unit = TMSUNIT(dev); 1924bc5e3c50Skarels 1925*1625a9a8Skarels if (unit >= NTMS) 1926bc5e3c50Skarels return (ENXIO); 1927*1625a9a8Skarels return (physio(tmscpstrategy, &rtmsbuf[unit], dev, B_WRITE, minphys, uio)); 1928bc5e3c50Skarels } 1929bc5e3c50Skarels 1930bc5e3c50Skarels 1931bc5e3c50Skarels /* 1932bc5e3c50Skarels * Catch ioctl commands, and call the "command" routine to do them. 1933bc5e3c50Skarels */ 1934bc5e3c50Skarels 1935bc5e3c50Skarels tmscpioctl(dev, cmd, data, flag) 1936bc5e3c50Skarels dev_t dev; 1937bc5e3c50Skarels int cmd; 1938bc5e3c50Skarels caddr_t data; 1939bc5e3c50Skarels int flag; 1940bc5e3c50Skarels { 1941bc5e3c50Skarels register struct tmscp_softc *sc = &tmscp_softc[TMSCPCTLR(dev)]; 1942bc5e3c50Skarels register struct buf *bp = &ctmscpbuf[TMSCPCTLR(dev)]; 1943bc5e3c50Skarels register callcount; /* number of times to call cmd routine */ 1944bc5e3c50Skarels register struct uba_device *ui; 1945*1625a9a8Skarels register struct tms_info *tms; 1946bc5e3c50Skarels int fcount; /* number of files (or records) to space */ 1947bc5e3c50Skarels struct mtop *mtop; /* mag tape cmd op to perform */ 1948bc5e3c50Skarels struct mtget *mtget; /* mag tape struct to get info in */ 1949bc5e3c50Skarels 1950bc5e3c50Skarels /* we depend of the values and order of the TMS ioctl codes here */ 1951bc5e3c50Skarels static tmsops[] = 1952bc5e3c50Skarels {TMS_WRITM,TMS_FSF,TMS_BSF,TMS_FSR,TMS_BSR,TMS_REW,TMS_OFFL,TMS_SENSE, 1953bc5e3c50Skarels TMS_CACHE,TMS_NOCACHE}; 1954bc5e3c50Skarels 1955bc5e3c50Skarels switch (cmd) { 1956bc5e3c50Skarels case MTIOCTOP: /* tape operation */ 1957bc5e3c50Skarels mtop = (struct mtop *)data; 1958bc5e3c50Skarels switch (mtop->mt_op) { 1959bc5e3c50Skarels 1960bc5e3c50Skarels case MTWEOF: 1961bc5e3c50Skarels callcount = mtop->mt_count; 1962bc5e3c50Skarels fcount = 1; 1963bc5e3c50Skarels break; 1964bc5e3c50Skarels case MTFSF: case MTBSF: 1965bc5e3c50Skarels case MTFSR: case MTBSR: 1966bc5e3c50Skarels callcount = 1; 1967bc5e3c50Skarels fcount = mtop->mt_count; 1968bc5e3c50Skarels break; 1969bc5e3c50Skarels case MTREW: case MTOFFL: case MTNOP: 1970bc5e3c50Skarels case MTCACHE: case MTNOCACHE: 1971bc5e3c50Skarels callcount = 1; 1972bc5e3c50Skarels fcount = 1; /* wait for this rewind */ 1973bc5e3c50Skarels break; 1974bc5e3c50Skarels default: 1975bc5e3c50Skarels return (ENXIO); 1976bc5e3c50Skarels } /* end switch mtop->mt_op */ 1977bc5e3c50Skarels 1978bc5e3c50Skarels if (callcount <= 0 || fcount <= 0) 1979bc5e3c50Skarels return (EINVAL); 1980bc5e3c50Skarels while (--callcount >= 0) 1981bc5e3c50Skarels { 1982bc5e3c50Skarels tmscpcommand(dev, tmsops[mtop->mt_op], fcount); 1983bc5e3c50Skarels if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) && 1984bc5e3c50Skarels bp->b_resid) 1985bc5e3c50Skarels return (EIO); 1986bc5e3c50Skarels if (bp->b_flags & B_ERROR) /* like hitting BOT */ 1987bc5e3c50Skarels break; 1988bc5e3c50Skarels } 1989bc5e3c50Skarels return (geterror(bp)); 1990bc5e3c50Skarels 1991bc5e3c50Skarels case MTIOCGET: 1992bc5e3c50Skarels /* 1993bc5e3c50Skarels * Return status info associated with the particular UNIT. 1994bc5e3c50Skarels */ 1995bc5e3c50Skarels ui = tmsdinfo[TMSUNIT(dev)]; 1996*1625a9a8Skarels tms = &tms_info[ui->ui_unit]; 1997bc5e3c50Skarels mtget = (struct mtget *)data; 1998bc5e3c50Skarels mtget->mt_type = MT_ISTMSCP; 1999*1625a9a8Skarels mtget->mt_dsreg = tms->tms_flags << 8; 2000*1625a9a8Skarels mtget->mt_dsreg |= tms->tms_endcode; 2001*1625a9a8Skarels mtget->mt_erreg = tms->tms_status; 2002*1625a9a8Skarels mtget->mt_resid = tms->tms_resid; 2003bc5e3c50Skarels break; 2004bc5e3c50Skarels 2005bc5e3c50Skarels default: 2006bc5e3c50Skarels return (ENXIO); 2007bc5e3c50Skarels } 2008bc5e3c50Skarels return (0); 2009bc5e3c50Skarels } 2010bc5e3c50Skarels 2011bc5e3c50Skarels 2012bc5e3c50Skarels /* 2013bc5e3c50Skarels * Reset (for raw mode use only). 2014bc5e3c50Skarels */ 2015bc5e3c50Skarels 2016bc5e3c50Skarels tmscpreset (uban) 2017bc5e3c50Skarels int uban; 2018bc5e3c50Skarels { 2019bc5e3c50Skarels register struct uba_ctlr *um; 2020bc5e3c50Skarels register struct uba_device *ui; 2021bc5e3c50Skarels register struct buf *bp, *dp; 2022bc5e3c50Skarels register int unit; 2023bc5e3c50Skarels struct buf *nbp; 2024bc5e3c50Skarels int d; 2025bc5e3c50Skarels 2026bc5e3c50Skarels for (d = 0; d < NTMSCP; d++) 2027bc5e3c50Skarels { 2028bc5e3c50Skarels if ((um = tmscpminfo[d]) == 0 || um->um_ubanum != uban || 2029bc5e3c50Skarels um->um_alive == 0) 2030bc5e3c50Skarels continue; 2031bc5e3c50Skarels printf(" tmscp%d", d); 2032bc5e3c50Skarels um->um_tab.b_active = 0; 2033bc5e3c50Skarels um->um_tab.b_actf = um->um_tab.b_actl = 0; 2034bc5e3c50Skarels tmscp_softc[d].sc_state = S_IDLE; 2035bc5e3c50Skarels tmscp_softc[d].sc_mapped = 0; 2036*1625a9a8Skarels for (unit = 0; unit < NTMS; unit++) 2037bc5e3c50Skarels { 2038bc5e3c50Skarels if ((ui = tmsdinfo[unit]) == 0) 2039bc5e3c50Skarels continue; 2040bc5e3c50Skarels if (ui->ui_alive == 0 || ui->ui_mi != um) 2041bc5e3c50Skarels continue; 2042bc5e3c50Skarels tmsutab[unit].b_active = 0; 2043bc5e3c50Skarels tmsutab[unit].b_qsize = 0; 2044bc5e3c50Skarels } 2045bc5e3c50Skarels for (bp = tmscpwtab[d].av_forw; bp != &tmscpwtab[d]; bp = nbp) 2046bc5e3c50Skarels { 2047bc5e3c50Skarels nbp = bp->av_forw; 2048bc5e3c50Skarels bp->b_ubinfo = 0; 2049bc5e3c50Skarels /* 2050bc5e3c50Skarels * Link the buffer onto the drive queue 2051bc5e3c50Skarels */ 2052bc5e3c50Skarels dp = &tmsutab[TMSUNIT(bp->b_dev)]; 2053bc5e3c50Skarels if (dp->b_actf == 0) 2054bc5e3c50Skarels dp->b_actf = bp; 2055bc5e3c50Skarels else 2056bc5e3c50Skarels dp->b_actl->av_forw = bp; 2057bc5e3c50Skarels dp->b_actl = bp; 2058bc5e3c50Skarels bp->av_forw = 0; 2059bc5e3c50Skarels /* 2060bc5e3c50Skarels * Link the drive onto the controller queue 2061bc5e3c50Skarels */ 2062bc5e3c50Skarels if (dp->b_active == 0) 2063bc5e3c50Skarels { 2064bc5e3c50Skarels dp->b_forw = NULL; 2065bc5e3c50Skarels if (um->um_tab.b_actf == NULL) 2066bc5e3c50Skarels um->um_tab.b_actf = dp; 2067bc5e3c50Skarels else 2068bc5e3c50Skarels um->um_tab.b_actl->b_forw = dp; 2069bc5e3c50Skarels um->um_tab.b_actl = dp; 2070bc5e3c50Skarels dp->b_active = 1; 2071bc5e3c50Skarels } 2072bc5e3c50Skarels } 2073bc5e3c50Skarels tmscpinit(d); 2074bc5e3c50Skarels } 2075bc5e3c50Skarels } 2076bc5e3c50Skarels 2077bc5e3c50Skarels 2078bc5e3c50Skarels /* 2079bc5e3c50Skarels * Process an error log message 2080bc5e3c50Skarels * 2081bc5e3c50Skarels * Only minimal decoding is done, only "useful" 2082bc5e3c50Skarels * information is printed. Eventually should 2083bc5e3c50Skarels * send message to an error logger. 2084bc5e3c50Skarels */ 2085bc5e3c50Skarels 2086bc5e3c50Skarels tmserror(um, mp) 2087bc5e3c50Skarels register struct uba_ctlr *um; 2088bc5e3c50Skarels register struct mslg *mp; 2089bc5e3c50Skarels { 2090bc5e3c50Skarels register i; 2091bc5e3c50Skarels 2092bc5e3c50Skarels # ifdef DEBUG 2093bc5e3c50Skarels printd("tmserror:\n"); 2094bc5e3c50Skarels # endif 2095bc5e3c50Skarels if(!(mp->mslg_flags & (M_LF_SUCC | M_LF_CONT))) 2096*1625a9a8Skarels log(TMS_PRI, "tmscp%d: %s error, ", um->um_ctlr, 2097bc5e3c50Skarels mp->mslg_flags & ( M_LF_SUCC | M_LF_CONT ) ? "soft" : "hard"); 2098bc5e3c50Skarels 2099bc5e3c50Skarels switch (mp->mslg_format) { 2100bc5e3c50Skarels 2101bc5e3c50Skarels case M_FM_CNTERR: 2102*1625a9a8Skarels log(TMS_PRI, "controller error, event 0%o\n", mp->mslg_event); 2103bc5e3c50Skarels break; 2104bc5e3c50Skarels case M_FM_BUSADDR: 2105*1625a9a8Skarels log(TMS_PRI, "host memory access error, event 0%o, addr 0%o\n", 2106bc5e3c50Skarels mp->mslg_event, mp->mslg_busaddr); 2107bc5e3c50Skarels break; 2108bc5e3c50Skarels case M_FM_TAPETRN: 2109*1625a9a8Skarels log(TMS_PRI, "tape transfer error, unit %d, grp 0x%x, event 0%o\n", 2110bc5e3c50Skarels mp->mslg_unit, mp->mslg_group, mp->mslg_event); 2111bc5e3c50Skarels break; 2112bc5e3c50Skarels case M_FM_STIERR: 2113*1625a9a8Skarels log(TMS_PRI, "STI error, unit %d, event 0%o\n", 2114bc5e3c50Skarels mp->mslg_unit, mp->mslg_event); 2115*1625a9a8Skarels #ifdef notdef 2116*1625a9a8Skarels /* too painful to do with log() */ 2117bc5e3c50Skarels for(i = 0; i < 62;i++) 2118bc5e3c50Skarels mprintf("\t0x%x",mp->mslg_stiunsucc[i] & 0xff); 2119bc5e3c50Skarels mprintf("\n"); 2120*1625a9a8Skarels #endif 2121bc5e3c50Skarels break; 2122bc5e3c50Skarels case M_FM_STIDEL: 2123*1625a9a8Skarels log(TMS_PRI, "STI Drive Error Log, unit %d, event 0%o\n", 2124bc5e3c50Skarels mp->mslg_unit, mp->mslg_event); 2125bc5e3c50Skarels break; 2126bc5e3c50Skarels case M_FM_STIFEL: 2127*1625a9a8Skarels log(TMS_PRI, "STI Formatter Error Log, unit %d, event 0%o\n", 2128bc5e3c50Skarels mp->mslg_unit, mp->mslg_event); 2129bc5e3c50Skarels break; 2130bc5e3c50Skarels default: 2131*1625a9a8Skarels log(TMS_PRI, "unknown error, unit %d, format 0%o, event 0%o\n", 2132bc5e3c50Skarels mp->mslg_unit, mp->mslg_format, mp->mslg_event); 2133bc5e3c50Skarels } 2134bc5e3c50Skarels 2135bc5e3c50Skarels if (tmscperror) 2136bc5e3c50Skarels { 2137bc5e3c50Skarels register long *p = (long *)mp; 2138bc5e3c50Skarels 2139bc5e3c50Skarels for (i = 0; i < mp->mslg_header.tmscp_msglen; i += sizeof(*p)) 2140bc5e3c50Skarels printf("%x ", *p++); 2141bc5e3c50Skarels printf("\n"); 2142bc5e3c50Skarels } 2143bc5e3c50Skarels } 2144bc5e3c50Skarels #endif 2145