Return to BSD News archive
Newsgroups: comp.bugs.2bsd Path: euryale.cc.adfa.oz.au!newshost.anu.edu.au!harbinger.cc.monash.edu.au!news.mel.connect.com.au!munnari.OZ.AU!news.ecn.uoknor.edu!news.cis.okstate.edu!news.ksu.ksu.edu!news.mid.net!crcnews.unl.edu!newspump.wustl.edu!news.ecn.bgu.edu!vixen.cso.uiuc.edu!newsfeed.internetmci.com!in1.uu.net!news.new-york.net!wlbr!sms From: sms@wlv.iipo.gtegsc.com (Steven M. Schultz) Subject: TU81 bug,statfs(2)+fstatfs(2)+getfsstat(2) missing, More (#286 4 of 4) Sender: news@wlbr.iipo.gtegsc.com (Steven M. Schultz) Organization: GTE Government Systems, Thousand Oaks CA USA Message-ID: <DKAHFL.9oq@wlbr.iipo.gtegsc.com> X-Nntp-Posting-Host: wlv.iipo.gtegsc.com Date: Thu, 28 Dec 1995 09:09:20 GMT Lines: 2768 Subject: TU81 bug,statfs(2)+fstatfs(2)+getfsstat(2) missing, More (#286 4 of 4) Index: sys/pdpuba,pdp,sys 2.11BSD Description: See #283. Repeat-By: See #283. Fix: This is #286, part 4 of 4. Refer to #283 for installation instructions. The following files are modified by this part of the update kit: /usr/src/sys/pdpuba/tmscp.c /usr/src/sys/pdpuba/tmscpreg.h /VERSION --------------------------cut here--------------------------- *** /usr/src/sys/pdpuba/tmscp.c.old Fri Dec 9 23:10:39 1994 --- /usr/src/sys/pdpuba/tmscp.c Fri Dec 22 20:49:26 1995 *************** *** 1,5 **** ! /* @(#)tmscp.c 1.4 (2.11BSD GTE) 12/9/94 */ #if !defined(lint) && defined(DOSCCS) static char *sccsid = "@(#)tmscp.c 1.24 (ULTRIX) 1/21/86"; #endif --- 1,7 ---- ! #define TMSDEBUG 1 + /* @(#)tmscp.c 1.5 (2.11BSD GTE) 1995/12/08 */ + #if !defined(lint) && defined(DOSCCS) static char *sccsid = "@(#)tmscp.c 1.24 (ULTRIX) 1/21/86"; #endif *************** *** 31,36 **** --- 33,60 ---- * tmscp.c - TMSCP (TK50/TU81) tape device driver * * Modification History: + * + * 14-Dec-95 - sms@wlv... + * Success! But the size of the driver is even more of a problem now. + * If the crash dump option is defined the driver could exceed the max + * size permitted for an overlay. The 'tmsdump' routine was moved to + * a separate file. This driver almost always must be in an overlay + * by itself now. + * + * 08-Dec-95 - sms@wlv... + * Begin serious surgery on this driver. The goals are: 1) to correctly + * handle TU81/81+ drives (do not set density unless at BOT), 2) support + * use of the cache on drives which implement it (TU81+), 3) improve + * error detection and reporting, 4) improve readability by replacing + * multipage 'switch' statements with calls to functions, 5) make it + * easier to add new capabilities and fix problems without wholescale + * changes again. + * + * 30-Nov-95 - sms@wlv... + * Experiment to see if M_MD_IMMED being set for the rewind on close + * obviates the need for skipping the iowait(). Success - only 2 ticks + * elapse doing the iowait!. + * * 02-Jan-93 - sms@wlv. [2.11BSD] * Remove unibus map ifdefs and rely on run time testing of 'ubmap' which * does the right thing and makes kernels easier to move between machines. *************** *** 187,200 **** #include "uio.h" #include "tty.h" #include "uba.h" - #define TMS_PRI LOG_INFO - - #define NRSPL2 3 /* log2 number of response packets */ - #define NCMDL2 3 /* log2 number of command packets */ - #define NRSP (1<<NRSPL2) - #define NCMD (1<<NCMDL2) - #include "tmscpreg.h" #include "../pdp/tmscp.h" #include "../machine/seg.h" --- 211,218 ---- #include "uio.h" #include "tty.h" #include "uba.h" + #include "kernel.h" #include "tmscpreg.h" #include "../pdp/tmscp.h" #include "../machine/seg.h" *************** *** 214,279 **** /* HI */ {0,M_TF_800,M_TF_PE,M_TF_PE,M_TF_GCR,M_TF_GCR,M_TF_GCR,M_TF_GCR} }; ! /* Software state per controller */ - struct tmscp_softc { - struct tmscpdevice *sc_addr; /* controller CSR address */ - short sc_state; /* state of controller */ - short sc_ivec; /* interrupt vector address */ - short sc_unit; /* CONTROLLER number - NOT drive unit # */ - short sc_credits; /* transfer credits */ - short sc_lastcmd; /* pointer into command ring */ - short sc_lastrsp; /* pointer into response ring */ - struct buf sc_cmdbuf; /* internal command buffer */ - struct buf sc_ctab; /* controller queue */ - struct buf sc_wtab; /* I/O wait queue for controller */ - struct tmscp *sc_com; /* communications area pointer */ - struct tms_info *sc_drives[4]; /* pointers to per drive info */ - } tmscp_softc[NTMSCP]; - - #define RINGBASE (4 * sizeof (short)) - - struct tmscp { - struct tmscpca tmscp_ca; /* communications area */ - struct mscp tmscp_rsp[NRSP]; /* response packets */ - struct mscp tmscp_cmd[NCMD]; /* command packets */ - }; /* 1896 bytes per controller! */ - memaddr tmscp[NTMSCP]; /* click addresses of ctrl comm area */ /* ! * Per drive-unit info ! */ ! struct tms_info { ! daddr_t tms_dsize; /* Max user size from online pkt */ ! long tms_type; /* Drive type field */ ! int tms_resid; /* residual from last xfer */ ! u_char tms_endcode; /* last command endcode */ ! u_char tms_flags; /* last command end flags */ ! unsigned tms_status; /* Command status from last command */ ! char tms_openf; /* lock against multiple opens */ ! char tms_lastiow; /* last op was a write */ ! char tms_serex; /* set when serious exception occurs */ ! char tms_clserex; /* set when serex being cleared by no-op */ ! short tms_fmtmenu; /* the unit's format (density) menu */ ! short tms_unitflgs; /* unit flag parameters */ ! short tms_format; /* the unit's current format (density) */ ! struct tty *tms_ttyp; /* record user's tty for errors */ ! struct buf tms_dtab; /* I/O tape drive queues */ ! short tms_online; /* 0=available, 1=online, -1=offline */ ! } tms_info[NTMS]; ! /* Bits in minor device */ ! #define TMSUNIT(dev) (minor(dev)&03) ! #define TMSCTLR(dev) ((minor(dev) >> 6) & 3) ! #define TMSDENS(dev) ((minor(dev) >> 3) & 3) ! #define FMTMASK (M_TF_800|M_TF_PE|M_TF_GCR) /* = 7 */ - #define T_NOREWIND 04 - - /* Size to map in when mapping a controller's command packet area */ - #define MAPBUFDESC (((btoc(sizeof (struct tmscp)) - 1) << 8) | RW) - /* * Internal (ioctl) command codes (these must also be declared in the * tmscpioctl routine). These correspond to ioctls in mtio.h --- 232,261 ---- /* HI */ {0,M_TF_800,M_TF_PE,M_TF_PE,M_TF_GCR,M_TF_GCR,M_TF_GCR,M_TF_GCR} }; ! struct tmscp_softc tmscp_softc[NTMSCP]; /* Controller info */ ! struct tms_info tms_info[NTMS]; /* Drive info */ memaddr tmscp[NTMSCP]; /* click addresses of ctrl comm area */ /* ! * Bit definitions for Tflags word above. These take the place of several ! * individual structure members in tms_info. ! */ ! #define _SEREX 0x0001 /* Serious Exception exists */ ! #define _CLSEREX 0x0002 /* Do Clear Serious Exception */ ! #define _EOM 0x0004 /* At End Of Media */ ! #define _BOM 0x0008 /* At Beginning Of Media */ ! #define _WRITTEN 0x0010 /* Tape has been Written */ ! #define _LOST 0x0020 /* Position lost error happened */ ! #define _BUFMARK 0x0040 /* Encountered a tape mark */ ! #define _HASCACHE 0x0080 /* Drive has cache capability */ ! #define _CACHE_ON 0x0100 /* Cache enabled */ ! #define _CACHE_LOST 0x0200 /* Cache data loss has happened */ ! #define _CACHE_WRITTEN 0x0400 /* Cache has been written */ ! #define _INUSE 0x0800 /* Drive is in use */ ! #define _ONLINE 0x1000 /* Drive is online */ /* * Internal (ioctl) command codes (these must also be declared in the * tmscpioctl routine). These correspond to ioctls in mtio.h *************** *** 288,296 **** #define TMS_SENSE 7 /* noop - do a get unit status */ #define TMS_CACHE 8 /* enable cache */ #define TMS_NOCACHE 9 /* disable cache */ /* These go last: after all real mt cmds, just bump the numbers up */ ! #define TMS_CSE 10 /* clear serious exception */ ! #define TMS_SETDENSITY 11 /* set unit density */ /* * Controller states --- 270,279 ---- #define TMS_SENSE 7 /* noop - do a get unit status */ #define TMS_CACHE 8 /* enable cache */ #define TMS_NOCACHE 9 /* disable cache */ + #define TMS_FLUSH 10 /* flush cache */ /* These go last: after all real mt cmds, just bump the numbers up */ ! #define TMS_CSE 11 /* clear serious exception */ ! #define TMS_SETDENSITY 12 /* set unit density */ /* * Controller states *************** *** 302,311 **** #define S_SCHAR 4 /* doing "set controller characteristics" */ #define S_RUN 5 /* running */ ! static char *tmscpstepfailed = "step%d init failed: sa 0x%x\n"; ! static char *tmscpfatalerr = "tms%d,%d: fatal error 0%o\n"; ! int tmscperror = 0; /* causes hex dump of packets */ int tmscp_cp_wait = 0; /* Something to wait on for command */ /* packets and or credits. */ int wakeup(); --- 285,294 ---- #define S_SCHAR 4 /* doing "set controller characteristics" */ #define S_RUN 5 /* running */ ! static char *tmscpstepfailed = "step%d init failed: sa %x\n"; ! char *tmscpfatalerr = "tms%d,%d: fatal error %x\n"; ! int tmscperror = 0; /* enable last failed packet return */ int tmscp_cp_wait = 0; /* Something to wait on for command */ /* packets and or credits. */ int wakeup(); *************** *** 312,322 **** extern int hz; /* Should find the right include */ extern long _iomap(); ! #ifdef TMSCP_DEBUG ! #define printd if (tmscpdebug) printf ! int tmscpdebug = 1; ! #define printd10 if(tmscpdebug >= 10) printf ! #endif struct mscp *tmscpgetcp(); --- 295,309 ---- extern int hz; /* Should find the right include */ extern long _iomap(); ! /* ! * Most of these only take effect when TMSDEBUG is defined. ! * ! * Bit 0 = print all non-successful response packets _except_ hitting a ! * tapemark (which really isn't an error). ! * Bit 1 = print datagram arrival message. ! * Bit 2 = print status of all response packets except datagrams. ! */ ! int tmscpprintf = 1; struct mscp *tmscpgetcp(); *************** *** 368,380 **** register struct tms_info *p; for (i = NTMS, p = tms_info; i--; p++) { ! if (p->tms_online == 0) return(p); } ! log(TMS_PRI, "tms: no drive descriptors\n"); return(NULL); } /* * TMSCP interrupt routine. */ --- 355,388 ---- register struct tms_info *p; for (i = NTMS, p = tms_info; i--; p++) { ! if ((p->Tflags & _INUSE) == 0) return(p); } ! log(LOG_INFO, "tms: !drives\n"); return(NULL); } + static int + wait_step(mask, good, csr, sc) + u_short mask, good; + register struct tmscpdevice *csr; + register struct tmscp_softc *sc; + { + register int i; + + for (i = 0; i < 150; i++) + { + if ((csr->tmscpsa & mask) == good) + return(0); + delay(10000L); /* still in step - wait 1/100 sec */ + } + sc->sc_state = S_IDLE; + sc->sc_ctab.b_active = 0; + log(LOG_INFO, tmscpstepfailed, sc->sc_state, csr->tmscpsa); + wakeup((caddr_t)&sc->sc_ctab); + return(-1); + } + /* * TMSCP interrupt routine. */ *************** *** 383,389 **** { register struct tmscpdevice *tmscpaddr; struct buf *bp; ! register int i; register struct tmscp_softc *sc = &tmscp_softc[dev]; register struct tmscp *tm = sc->sc_com; struct mscp *mp; --- 391,397 ---- { register struct tmscpdevice *tmscpaddr; struct buf *bp; ! int i; register struct tmscp_softc *sc = &tmscp_softc[dev]; register struct tmscp *tm = sc->sc_com; struct mscp *mp; *************** *** 390,398 **** segm seg5; tmscpaddr = sc->sc_addr; - #ifdef TMSCP_DEBUG - printd10("tmscpintr: state %d, tmscpsa %o\n", sc->sc_state, tmscpaddr->tmscpsa); - #endif /* * How the interrupt is handled depends on the state of the controller. --- 398,403 ---- *************** *** 400,406 **** switch (sc->sc_state) { case S_IDLE: ! printf("tms%d: random intr ignored\n", dev); return; /* Controller was in step 1 last, see if its gone to step 2 */ --- 405,411 ---- switch (sc->sc_state) { case S_IDLE: ! log(LOG_INFO, "tms%d: random intr\n", dev); return; /* Controller was in step 1 last, see if its gone to step 2 */ *************** *** 407,432 **** case S_STEP1: # define STEP1MASK 0174377 # define STEP1GOOD (TMSCP_STEP2|TMSCP_IE|(NCMDL2<<3)|NRSPL2) ! for (i = 0; i < 150; i++) ! { ! if ((tmscpaddr->tmscpsa&STEP1MASK) != STEP1GOOD) ! { /* still in step 1 (wait 1/100 sec) */ ! delay(10000L); ! #ifdef TMSCP_DEBUG ! printd("still in step 1, delaying\n"); ! #endif ! } ! else ! break; ! } ! if (i > 149) ! { ! sc->sc_state = S_IDLE; ! sc->sc_ctab.b_active = 0; ! printf(tmscpstepfailed,sc->sc_state,tmscpaddr->tmscpsa); ! wakeup((caddr_t)&sc->sc_ctab); return; - } tmscpaddr->tmscpsa = (short)sc->sc_ctab.b_un.b_addr; sc->sc_state = S_STEP2; return; --- 412,420 ---- case S_STEP1: # define STEP1MASK 0174377 # define STEP1GOOD (TMSCP_STEP2|TMSCP_IE|(NCMDL2<<3)|NRSPL2) ! ! if (wait_step(STEP1MASK, STEP1GOOD, tmscpaddr, sc) < 0) return; tmscpaddr->tmscpsa = (short)sc->sc_ctab.b_un.b_addr; sc->sc_state = S_STEP2; return; *************** *** 435,460 **** case S_STEP2: # define STEP2MASK 0174377 # define STEP2GOOD (TMSCP_STEP3|TMSCP_IE|(sc->sc_ivec/4)) ! for (i = 0; i < 150; i++) ! { ! if ((tmscpaddr->tmscpsa&STEP2MASK) != STEP2GOOD) ! { /* still in step 2 (wait 1/100 sec) */ ! delay(10000L); ! #ifdef TMSCP_DEBUG ! printd("still in step 2, delaying\n"); ! #endif ! } ! else ! break; ! } ! if (i > 149) ! { ! sc->sc_state = S_IDLE; ! sc->sc_ctab.b_active = 0; ! printf(tmscpstepfailed,sc->sc_state,tmscpaddr->tmscpsa); ! wakeup((caddr_t)&sc->sc_ctab); return; - } tmscpaddr->tmscpsa = sc->sc_ctab.b_xmem; sc->sc_state = S_STEP3; return; --- 423,431 ---- case S_STEP2: # define STEP2MASK 0174377 # define STEP2GOOD (TMSCP_STEP3|TMSCP_IE|(sc->sc_ivec/4)) ! ! if (wait_step(STEP2MASK, STEP2GOOD, tmscpaddr, sc) < 0) return; tmscpaddr->tmscpsa = sc->sc_ctab.b_xmem; sc->sc_state = S_STEP3; return; *************** *** 463,502 **** case S_STEP3: # define STEP3MASK 0174000 # define STEP3GOOD TMSCP_STEP4 ! for (i = 0; i < 150; i++) ! { ! if ((tmscpaddr->tmscpsa&STEP3MASK) != STEP3GOOD) ! { /* still in step 3 (wait 1/100 sec) */ ! delay(10000L); ! #ifdef TMSCP_DEBUG ! printd("still in step 3, delaying\n"); ! #endif ! } ! else ! break; ! } ! if (i > 149) ! { ! sc->sc_state = S_IDLE; ! sc->sc_ctab.b_active = 0; ! printf(tmscpstepfailed,sc->sc_state,tmscpaddr->tmscpsa); ! wakeup((caddr_t)&sc->sc_ctab); return; - } /* * Get microcode version and model number of controller; * Signal initialization complete (_GO) (to the controller); - * ask for Last Fail response if tmscperror is set; * Set state to "set controller characteristics". */ i = tmscpaddr->tmscpsa; ! tmscpaddr->tmscpsa = TMSCP_GO | (tmscperror? TMSCP_LF : 0); sc->sc_state = S_SCHAR; - #ifdef TMSCP_DEBUG - printd("tmscpintr: completed state %d \n", sc->sc_state); - printd("tmscp%d Version: %d model %d\n", dev, i & 0xf, (i >> 4) & 0xf); - #endif /* * Initialize the data structures (response and command queues). */ --- 434,454 ---- case S_STEP3: # define STEP3MASK 0174000 # define STEP3GOOD TMSCP_STEP4 ! ! if (wait_step(STEP3MASK, STEP3GOOD, tmscpaddr, sc) < 0) return; /* * Get microcode version and model number of controller; * Signal initialization complete (_GO) (to the controller); * Set state to "set controller characteristics". */ i = tmscpaddr->tmscpsa; ! tmscpaddr->tmscpsa = TMSCP_GO | TMSCP_LF; sc->sc_state = S_SCHAR; + log(LOG_INFO, "tms%d Ver %d Mod %d\n", dev, i & 0xf, + (i >> 4) & 0xf); + /* * Initialize the data structures (response and command queues). */ *************** *** 533,539 **** break; default: ! printf("tms%d: intr unknown state %d ignored\n",dev,sc->sc_state); return; } /* end switch */ --- 485,491 ---- break; default: ! log(LOG_INFO, "tms%d: state %d\n", dev, sc->sc_state); return; } /* end switch */ *************** *** 547,553 **** */ if (tmscpaddr->tmscpsa&TMSCP_ERR) { ! printf(tmscpfatalerr, dev, sc->sc_unit, tmscpaddr->tmscpsa); tmscpaddr->tmscpip = 0; sc->sc_state = S_IDLE; sc->sc_ctab.b_active = 0; --- 499,505 ---- */ if (tmscpaddr->tmscpsa&TMSCP_ERR) { ! log(LOG_INFO, tmscpfatalerr, dev, sc->sc_unit, tmscpaddr->tmscpsa); tmscpaddr->tmscpip = 0; sc->sc_state = S_IDLE; sc->sc_ctab.b_active = 0; *************** *** 584,596 **** /* * Check for command ring transition. (Should never happen!) */ ! if (tm->tmscp_ca.ca_cmdint) ! { ! #ifdef TMSCP_DEBUG ! printd("tmscpintr: command ring transition\n"); ! #endif tm->tmscp_ca.ca_cmdint = 0; - } restorseg5(seg5); if (tmscp_cp_wait) wakeup((caddr_t)&tmscp_cp_wait); --- 536,543 ---- /* * Check for command ring transition. (Should never happen!) */ ! if (tm->tmscp_ca.ca_cmdint) tm->tmscp_ca.ca_cmdint = 0; restorseg5(seg5); if (tmscp_cp_wait) wakeup((caddr_t)&tmscp_cp_wait); *************** *** 616,625 **** struct tmscpdevice *tmscpaddr; int s,i; - #ifdef TMSCP_DEBUG - printd("tmscpopen %d,%d\n", ctlr, unit); - if (tmscpdebug) delay(10000L); - #endif if (ctlr >= NTMSCP) return (ENXIO); sc = &tmscp_softc[ctlr]; --- 563,568 ---- *************** *** 629,648 **** tms = getdd(); if (!tms) return(ENXIO); ! tms->tms_online = -1; sc->sc_drives[unit] = tms; } ! if (tms->tms_openf) return(EBUSY); ! tms->tms_openf = 1; ! tms->tms_ttyp = u.u_ttyp; s = spl5(); if (sc->sc_state != S_RUN) { if (sc->sc_state == S_IDLE) ! if(!tkini(sc)) { ! printf("tms%d init failed\n", ctlr); (void) splx(s); return(ENXIO); } --- 572,591 ---- tms = getdd(); if (!tms) return(ENXIO); ! tms->Tflags &= ~_ONLINE; sc->sc_drives[unit] = tms; } ! if (tms->Tflags & _INUSE) return(EBUSY); ! tms->Tflags |= _INUSE; ! s = spl5(); if (sc->sc_state != S_RUN) { if (sc->sc_state == S_IDLE) ! if (!tkini(sc)) { ! log(LOG_INFO, "tms%d init fail\n", ctlr); (void) splx(s); return(ENXIO); } *************** *** 651,674 **** */ timeout(wakeup,(caddr_t)&sc->sc_ctab,11*hz); /* to be sure*/ sleep((caddr_t)&sc->sc_ctab, PSWP+1); ! if (sc->sc_state != S_RUN) { sc->sc_drives[unit] = NULL; ! tms->tms_online = tms->tms_openf = 0; (void) splx(s); ! return (EIO); } } /* ! * Check to see if the device is really there. ! * this code was taken from Fred Canters 11 driver */ tmscpaddr = (struct tmscpdevice *) sc->sc_addr; ! (void) splx(s); ! if(tms->tms_online == -1) { s = spl5(); ! while ((mp = tmscpgetcp(sc)) == 0) { tmscp_cp_wait++; sleep((caddr_t)&tmscp_cp_wait,PSWP+1); --- 594,619 ---- */ timeout(wakeup,(caddr_t)&sc->sc_ctab,11*hz); /* to be sure*/ sleep((caddr_t)&sc->sc_ctab, PSWP+1); ! if (sc->sc_state != S_RUN) { sc->sc_drives[unit] = NULL; ! tms->Tflags &= ~(_INUSE | _ONLINE); (void) splx(s); ! return(EIO); } } + (void) splx(s); + /* ! * If drive is not online get a command packet, sleeping if no ! * controller credits are available at the moment. Then start ! * the ONLINE process. */ tmscpaddr = (struct tmscpdevice *) sc->sc_addr; ! if (!(tms->Tflags & _ONLINE)) { s = spl5(); ! while ((mp = tmscpgetcp(sc)) == 0) { tmscp_cp_wait++; sleep((caddr_t)&tmscp_cp_wait,PSWP+1); *************** *** 680,688 **** mp->mscp_unit = unit; /* unit? */ mp->mscp_cmdref = (u_short)&tms->tms_type; /* need to sleep on something */ - #ifdef TMSCP_DEBUG - printd("tmscpopen: bring unit %d,%d online\n",ctlr, unit); - #endif ((Trl *)mp->mscp_dscptr)->hsh |= TMSCP_OWN | TMSCP_INT; normalseg5(); i = tmscpaddr->tmscpip; --- 625,630 ---- *************** *** 694,726 **** */ timeout(wakeup,(caddr_t) &tms->tms_type,240 * hz); sleep((caddr_t) &tms->tms_type,PSWP+1); } ! if (tms->tms_online == -1) { ! oops: tms->tms_online = tms->tms_openf = 0; sc->sc_drives[unit] = NULL; return(ENXIO); /* Didn't go online */ } ! /* ! * Get the unit characteristics (GTUNT). Done here because we ! * do not check for slave units at autoconfigure time. This really ! * only need be done once, but it's easier to do it on each open. ! * tmscpcommand() is used since the iodone() handling for GTUNT has ! * been fixed. ! */ ! tms->tms_type = 0; tmscpcommand(dev, TMS_SENSE, 1); ! if (tms->tms_type == 0) goto oops; ! tms->tms_lastiow = 0; ! /* ! * Set unit density using the density matrix. ! * This is done as an "internal" ioctl command so ! * that the command setup and response handling ! * is done thru "regular" command routines. ! */ tmscpcommand(dev, TMS_SETDENSITY, 1); ! return (0); } /* --- 636,673 ---- */ timeout(wakeup,(caddr_t) &tms->tms_type,240 * hz); sleep((caddr_t) &tms->tms_type,PSWP+1); + untimeout(wakeup, &tms->tms_type); } ! if (!(tms->Tflags & _ONLINE)) { ! oops: tms->Tflags = 0; sc->sc_drives[unit] = NULL; return(ENXIO); /* Didn't go online */ } ! /* ! * Get the unit characteristics (GTUNT). This 1) Verifies the drive ! * is really still online and 2) Retrieves information about the drive ! * such as density choices, cache presence, etc. ! */ ! tms->tms_flags = 0; ! tms->Tflags = _ONLINE | _INUSE; /* Clear all other flags */ tmscpcommand(dev, TMS_SENSE, 1); ! if (!(tms->Tflags & _ONLINE)) goto oops; ! ! /* ! * Next issue a reposition NOP by spacing forward 0 records. This returns ! * the current position (so we can tell if we're at BOT or not) and also ! * clears any serious exceptions outstanding. ! */ ! tmscpcommand(dev, TMS_CSE, 1); ! ! /* ! * Now go set the density - the lower level routines set the density if ! * the drive is at BOT. ! */ tmscpcommand(dev, TMS_SETDENSITY, 1); ! return(0); } /* *************** *** 729,780 **** * If tape was open for writing or last operation was * a write, then write two EOF's and backspace over the last one. * Unless this is a non-rewinding special file, rewind the tape. ! * ! * NOTE: ! * We want to be sure that any serious exception is cleared on the ! * close. A Clear Serious Exception (CSE) modifier is always done on ! * the rewind command. For the non-rewind case we check to see if the ! * "serex" field is set in the softc struct; if it is then issue a noop ! * command with the CSE modifier. ! * Make the tape available to others, by clearing openf flag. ! */ tmscpclose(dev, flag) register dev_t dev; register flag; ! { struct tmscp_softc *sc; register struct tms_info *tms; int unit = TMSUNIT(dev); - #ifdef TMSCP_DEBUG - printd("tmscpclose: %d,%d\n", TMSCTLR(dev), unit); - if(tmscpdebug)delay(10000L); - #endif sc = &tmscp_softc[TMSCTLR(dev)]; tms = sc->sc_drives[unit]; ! if (flag == FWRITE || (flag&FWRITE) && tms->tms_lastiow) { ! /* device, command, count */ ! tmscpcommand (dev, TMS_WRITM, 1); ! tmscpcommand (dev, TMS_WRITM, 1); ! tmscpcommand (dev, TMS_BSR, 1); ! } ! if ((minor(dev)&T_NOREWIND) == 0) ! /* ! * Don't hang waiting for rewind complete. ! */ ! tmscpcommand(dev, TMS_REW, 0); ! else ! if (tms->tms_serex) { ! #ifdef TMSCP_DEBUG ! printd("tmscpclose: clearing serex\n"); ! if (tmscpdebug)delay(10000L); ! #endif ! tmscpcommand(dev, TMS_CSE, 1); } ! tms->tms_openf = 0; ! } /* * Execute a command on the tape drive a specified number of times. --- 676,723 ---- * If tape was open for writing or last operation was * a write, then write two EOF's and backspace over the last one. * Unless this is a non-rewinding special file, rewind the tape. ! */ tmscpclose(dev, flag) register dev_t dev; register flag; ! { struct tmscp_softc *sc; register struct tms_info *tms; int unit = TMSUNIT(dev); sc = &tmscp_softc[TMSCTLR(dev)]; tms = sc->sc_drives[unit]; ! ! if ((tms->Tflags & _CACHE_ON) && (tms->Tflags & _CACHE_WRITTEN)) { ! /* ! * A misbehaving application has closed the device without flushing ! * the enabled cache by issuing a MTFLUSH - we'll do it for it. ! */ ! tmscpcommand(dev, TMS_FLUSH, 1); ! if (tms->tms_status != M_ST_SUCC) { ! /* ! * This is BAD news - the flush didn't work. The drive is in a serious ! * exception state, leave that alone for the non-rewind case so that further ! * operations fail. About all that can be done now is log the error. ! */ ! log(LOG_INFO, "tms%d,%d flush fail\n", ! TMSCTLR(dev), unit); ! tms->Tflags &= ~_CACHE_WRITTEN; } ! } ! tms->tms_flags &= ~MTF_CSE; ! if (tms->Tflags & _WRITTEN) ! tms_wrteof(dev, tms); ! tms->Tflags &= ~(_WRITTEN | _BUFMARK |_INUSE); ! if ((dev & T_NOREWIND) == 0) ! { ! tmscpcommand(dev, TMS_REW, 0); ! tms->Tflags &= ~(_LOST | _CLSEREX | _SEREX); ! } ! return(0); ! } /* * Execute a command on the tape drive a specified number of times. *************** *** 798,809 **** s = spl5(); while (bp->b_flags&B_BUSY) { - /* - * This special check is because B_BUSY never - * gets cleared in the non-waiting rewind case. - */ - if (bp->b_bcount == 0 && (bp->b_flags&B_DONE)) - break; bp->b_flags |= B_WANTED; sleep((caddr_t)bp, PRIBIO); } --- 741,746 ---- *************** *** 820,831 **** bp->b_resid = com; bp->b_blkno = 0; tmscpstrategy(bp); ! /* ! * In case of rewind from close, don't wait. ! * This is the only case where count can be 0. ! */ ! if (count == 0) ! return; iowait(bp); if (bp->b_flags&B_WANTED) wakeup((caddr_t)bp); --- 757,766 ---- bp->b_resid = com; bp->b_blkno = 0; tmscpstrategy(bp); ! /* ! * It is safe to wait here because the rewind done on a close specifies ! * the modifier M_MD_IMMED which causes an immediate return. ! */ iowait(bp); if (bp->b_flags&B_WANTED) wakeup((caddr_t)bp); *************** *** 874,881 **** register struct tmscp_softc *sc; { register struct mscp *mp = NULL; ! struct tmscpca *cp; ! register int i; int s; segm seg5; --- 809,816 ---- register struct tmscp_softc *sc; { register struct mscp *mp = NULL; ! register struct tmscpca *cp; ! int i; int s; segm seg5; *************** *** 888,902 **** * until some outstanding commands complete. */ i = sc->sc_lastcmd; ! #ifdef TMSCP_DEBUG ! printd10("tmscpgetcp: %d credits remain\n", sc->sc_credits); ! #endif ! if(((cp->ca_cmddsc[i].hsh&(TMSCP_OWN|TMSCP_INT))==TMSCP_INT) && ! (sc->sc_credits >= 2)) { sc->sc_credits--; /* This commits to issuing a command */ cp->ca_cmddsc[i].hsh &= ~TMSCP_INT; mp = &sc->sc_com->tmscp_cmd[i]; mp->mscp_unit = mp->mscp_modifier = 0; mp->mscp_opcode = mp->mscp_flags = 0; mp->mscp_bytecnt = 0; --- 823,836 ---- * until some outstanding commands complete. */ i = sc->sc_lastcmd; ! if (((cp->ca_cmddsc[i].hsh&(TMSCP_OWN|TMSCP_INT))==TMSCP_INT) && ! (sc->sc_credits >= 2)) { sc->sc_credits--; /* This commits to issuing a command */ cp->ca_cmddsc[i].hsh &= ~TMSCP_INT; mp = &sc->sc_com->tmscp_cmd[i]; + mp->mscp_cmdref = 0; + mp->mscp_mediaid = 0; mp->mscp_unit = mp->mscp_modifier = 0; mp->mscp_opcode = mp->mscp_flags = 0; mp->mscp_bytecnt = 0; *************** *** 933,943 **** while((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0) { ! #ifdef TMSCP_DEBUG ! printd("tkini: tmscpsa = 0%o\n",tmscpaddr->tmscpsa); ! delay(100000L); ! #endif ! if(tmscpaddr->tmscpsa & TMSCP_ERR) return(0); /* CHECK */ } tmscpaddr->tmscpsa=TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8)|TMSCP_IE|(sc->sc_ivec/4); --- 867,873 ---- while((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0) { ! if (tmscpaddr->tmscpsa & TMSCP_ERR) return(0); /* CHECK */ } tmscpaddr->tmscpsa=TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8)|TMSCP_IE|(sc->sc_ivec/4); *************** *** 967,982 **** saveseg5(seg5); /* save just once at top */ for(;;) { ! if ((dp = sc->sc_ctab.b_actf) == NULL) { ! /* ! * Release unneeded UBA resources and return ! * (drive was inactive) ! */ sc->sc_ctab.b_active = 0; break; } ! if ((bp = dp->b_actf) == NULL) { /* * No more requests for this drive, remove --- 897,909 ---- saveseg5(seg5); /* save just once at top */ for(;;) { ! if ((dp = sc->sc_ctab.b_actf) == NULL) { ! /* (drive was inactive) */ sc->sc_ctab.b_active = 0; break; } ! if ((bp = dp->b_actf) == NULL) { /* * No more requests for this drive, remove *************** *** 985,1015 **** */ dp->b_active = 0; sc->sc_ctab.b_actf = dp->b_forw; ! continue; /* Need to check for loop */ } sc->sc_ctab.b_active++; unit = TMSUNIT(bp->b_dev); tmscpaddr = (struct tmscpdevice *)sc->sc_addr; tms = sc->sc_drives[unit]; ! if ((tmscpaddr->tmscpsa&TMSCP_ERR) || sc->sc_state != S_RUN) { ! tprintf(tms->tms_ttyp, ! "tms%d,%d: hard error bn%ld\n", sc->sc_unit, unit, ! bp->b_blkno); ! log(TMS_PRI, "tms%d,%d: sa 0%o state %d\n", sc->sc_unit, unit, tmscpaddr->tmscpsa, sc->sc_state); (void)tkini(sc); /* SHOULD REQUEUE OUTSTANDING REQUESTS, LIKE TMSCPRESET */ break; } ! /* ! * Default is that last command was NOT a write command; ! * if a write command is done it will be detected in tmscprsp. ! */ ! tms->tms_lastiow = 0; ! if (tms->tms_online == -1) ! { /* not online */ ! if ((mp = tmscpgetcp(sc)) == NULL) break; mapseg5(tmscp[sc->sc_unit], MAPBUFDESC); mp->mscp_opcode = M_OP_ONLIN; --- 912,935 ---- */ dp->b_active = 0; sc->sc_ctab.b_actf = dp->b_forw; ! continue; } sc->sc_ctab.b_active++; unit = TMSUNIT(bp->b_dev); tmscpaddr = (struct tmscpdevice *)sc->sc_addr; tms = sc->sc_drives[unit]; ! if ((tmscpaddr->tmscpsa&TMSCP_ERR) || sc->sc_state != S_RUN) { ! log(LOG_INFO, "tms%d,%d: sa %x state %d\n", sc->sc_unit, unit, tmscpaddr->tmscpsa, sc->sc_state); (void)tkini(sc); /* SHOULD REQUEUE OUTSTANDING REQUESTS, LIKE TMSCPRESET */ break; } ! ! if (!(tms->Tflags & _ONLINE)) ! { ! if ((mp = tmscpgetcp(sc)) == NULL) break; mapseg5(tmscp[sc->sc_unit], MAPBUFDESC); mp->mscp_opcode = M_OP_ONLIN; *************** *** 1017,1030 **** dp->b_active = 2; sc->sc_ctab.b_actf = dp->b_forw; /* remove from controller q */ ((Trl *)mp->mscp_dscptr)->hsh |= TMSCP_OWN|TMSCP_INT; ! if (tmscpaddr->tmscpsa&TMSCP_ERR) ! printf(tmscpfatalerr, sc->sc_unit, TMSUNIT(bp->b_dev), tmscpaddr->tmscpsa); restorseg5(seg5); i = tmscpaddr->tmscpip; continue; } ! if ((mp = tmscpgetcp(sc)) == NULL) break; mapseg5(tmscp[sc->sc_unit], MAPBUFDESC); mp->mscp_cmdref = (u_short)bp; /* pointer to get back */ --- 937,950 ---- dp->b_active = 2; sc->sc_ctab.b_actf = dp->b_forw; /* remove from controller q */ ((Trl *)mp->mscp_dscptr)->hsh |= TMSCP_OWN|TMSCP_INT; ! if (tmscpaddr->tmscpsa&TMSCP_ERR) ! log(LOG_INFO, tmscpfatalerr, sc->sc_unit, TMSUNIT(bp->b_dev), tmscpaddr->tmscpsa); restorseg5(seg5); i = tmscpaddr->tmscpip; continue; } ! if ((mp = tmscpgetcp(sc)) == NULL) break; mapseg5(tmscp[sc->sc_unit], MAPBUFDESC); mp->mscp_cmdref = (u_short)bp; /* pointer to get back */ *************** *** 1034,1044 **** * tmscp command; by doing a switch on the "b_resid" field where * the command mneumonic is stored. */ ! if (bp == &sc->sc_cmdbuf) { - #ifdef TMSCP_DEBUG - printd("tmsstart: doing ioctl cmd %d\n", bp->b_resid); - #endif /* * The reccnt and tmkcnt fields are set to zero by the getcp * routine (as bytecnt and buffer fields). Thus reccnt and --- 954,961 ---- * tmscp command; by doing a switch on the "b_resid" field where * the command mneumonic is stored. */ ! if (bp == &sc->sc_cmdbuf) { /* * The reccnt and tmkcnt fields are set to zero by the getcp * routine (as bytecnt and buffer fields). Thus reccnt and *************** *** 1048,1135 **** switch ((int)bp->b_resid) { case TMS_WRITM: ! mp->mscp_opcode = M_OP_WRITM; break; case TMS_FSF: ! mp->mscp_opcode = M_OP_REPOS; ! mp->mscp_tmkcnt = bp->b_bcount; break; case TMS_BSF: ! mp->mscp_opcode = M_OP_REPOS; ! mp->mscp_modifier = M_MD_REVRS; ! mp->mscp_tmkcnt = bp->b_bcount; break; case TMS_FSR: ! mp->mscp_opcode = M_OP_REPOS; ! mp->mscp_modifier = M_MD_OBJCT; ! mp->mscp_reccnt = bp->b_bcount; break; case TMS_BSR: ! mp->mscp_opcode = M_OP_REPOS; ! mp->mscp_modifier = M_MD_REVRS | M_MD_OBJCT; ! mp->mscp_reccnt = bp->b_bcount; break; - /* - * Clear serious exception is done for Rewind & Available cmds - */ case TMS_REW: ! mp->mscp_opcode = M_OP_REPOS; ! mp->mscp_modifier = M_MD_REWND | M_MD_CLSEX; ! if (bp->b_bcount == 0) ! mp->mscp_modifier |= M_MD_IMMED; ! tms->tms_serex = 0; break; case TMS_OFFL: ! mp->mscp_opcode = M_OP_AVAIL; ! mp->mscp_modifier = M_MD_UNLOD | M_MD_CLSEX; ! tms->tms_serex = 0; break; case TMS_SENSE: mp->mscp_opcode = M_OP_GTUNT; break; case TMS_CACHE: - mp->mscp_opcode = M_OP_STUNT; tms->tms_unitflgs |= M_UF_WBKNV; ! mp->mscp_unitflgs = tms->tms_unitflgs; ! mp->mscp_format = tms->tms_format; ! /* default device dependant parameters */ ! mp->mscp_mediaid = 0; break; case TMS_NOCACHE: ! mp->mscp_opcode = M_OP_STUNT; ! tms->tms_unitflgs &= ~(M_UF_WBKNV); ! mp->mscp_unitflgs = tms->tms_unitflgs; ! mp->mscp_format = tms->tms_format; ! /* default device dependant parameters */ ! mp->mscp_mediaid = 0; break; case TMS_CSE: ! /* ! * This is a no-op command. It performs a ! * clear serious exception only. (Done on a ! * non-rewinding close after a serious exception.) ! */ ! mp->mscp_opcode = M_OP_REPOS; ! mp->mscp_modifier = M_MD_CLSEX; ! tms->tms_serex = 0; ! tms->tms_clserex = 1; break; case TMS_SETDENSITY: ! /* ! * Set the unit density ! */ ! mp->mscp_opcode = M_OP_STUNT; ! mp->mscp_unitflgs = tms->tms_unitflgs; ! mp->mscp_mediaid = 0; /* default device dependant parameters */ ! mp->mscp_format = Dmatrix[TMSDENS(bp->b_dev)][tms->tms_fmtmenu & FMTMASK]; ! #ifdef TMSCP_DEBUG ! printd("b_dev: 0%o fmtmenu: 0%o format: 0%o\n", bp->b_dev, tms->tms_fmtmenu, mp->mscp_format); ! delay(4000000L); ! #endif ! tms->tms_format = mp->mscp_format; break; default: ! printf("tms%d,%d bad ioctl\n",sc->sc_unit,mp->mscp_unit); /* Need a no-op. Reposition no amount */ mp->mscp_opcode = M_OP_REPOS; break; --- 965,1022 ---- switch ((int)bp->b_resid) { case TMS_WRITM: ! tms_wtm_st(mp, sc, 0); break; case TMS_FSF: ! tms_repos_st(mp, sc, 0); break; case TMS_BSF: ! tms_repos_st(mp, sc, M_MD_REVRS); break; case TMS_FSR: ! tms_reposrec_st(mp, sc, M_MD_OBJCT); break; case TMS_BSR: ! tms_reposrec_st(mp, sc, M_MD_OBJCT | M_MD_REVRS); break; case TMS_REW: ! if (bp->b_bcount) ! i = M_MD_REWND; ! else ! i = M_MD_REWND | M_MD_IMMED; ! tms_repos_st(mp, sc, i); break; case TMS_OFFL: ! tms_avail_st(mp, sc, M_MD_UNLOD); break; case TMS_SENSE: mp->mscp_opcode = M_OP_GTUNT; break; + case TMS_FLUSH: + mp->mscp_opcode = M_OP_FLUSH; + break; case TMS_CACHE: tms->tms_unitflgs |= M_UF_WBKNV; ! tms->tms_unitflgs &= ~M_UF_SCCHH; ! tms->Tflags |= _CACHE_ON; ! tms_stunt_st(mp, sc, 0); break; case TMS_NOCACHE: ! tms->tms_unitflgs &= ~M_UF_WBKNV; ! tms->tms_unitflgs |= M_UF_SCCHH; ! tms->Tflags &= ~_CACHE_ON; ! tms_stunt_st(mp, sc, 0); break; case TMS_CSE: ! bp->b_bcount = 0; /* 0 objects to skip */ ! tms_repos_st(mp, sc, M_MD_OBJCT); break; case TMS_SETDENSITY: ! tms->tms_format = Dmatrix[TMSDENS(bp->b_dev)][tms->tms_fmtmenu & FMTMASK]; ! tms_stunt_st(mp, sc, 0); break; default: ! log(LOG_INFO, "tms ioctl %x\n", bp->b_resid); /* Need a no-op. Reposition no amount */ mp->mscp_opcode = M_OP_REPOS; break; *************** *** 1142,1157 **** mp->mscp_buffer_l = (u_short) bp->b_un.b_addr; mp->mscp_buffer_h = bp->b_xmem; } ! if (tms->tms_serex == 2) /* if tape mark read */ { ! mp->mscp_modifier |= M_MD_CLSEX; /* clear serious exc */ ! tms->tms_serex = 0; } ((Trl *)mp->mscp_dscptr)->hsh |= TMSCP_OWN|TMSCP_INT; - #ifdef TMSCP_DEBUG - printd("tmsstart: opcode 0%o mod %o unit %d cnt %d\n",mp->mscp_opcode,mp->mscp_modifier,mp->mscp_unit,mp->mscp_bytecnt); - if(tmscpdebug)delay(100000L); - #endif i = tmscpaddr->tmscpip; /* initiate polling */ dp->b_qsize++; /* --- 1029,1045 ---- mp->mscp_buffer_l = (u_short) bp->b_un.b_addr; mp->mscp_buffer_h = bp->b_xmem; } ! ! if ((tms->Tflags & _CACHE_ON) && (mp->mscp_opcode == M_OP_WRITE)) ! tms->Tflags |= _CACHE_WRITTEN; ! if ((tms->Tflags & _BUFMARK) && (mp->mscp_opcode == M_OP_READ) && ! (tms->Tflags & _CLSEREX)) { ! tms->Tflags &= ~(_BUFMARK | _CLSEREX); ! mp->mscp_modifier |= M_MD_CLSEX; } + ((Trl *)mp->mscp_dscptr)->hsh |= TMSCP_OWN|TMSCP_INT; i = tmscpaddr->tmscpip; /* initiate polling */ dp->b_qsize++; /* *************** *** 1175,1181 **** dp->av_back = bp; if (tmscpaddr->tmscpsa&TMSCP_ERR) { ! printf(tmscpfatalerr,sc->sc_unit, mp->mscp_unit, tmscpaddr->tmscpsa); (void)tkini(sc); break; --- 1063,1069 ---- dp->av_back = bp; if (tmscpaddr->tmscpsa&TMSCP_ERR) { ! log(LOG_INFO, tmscpfatalerr,sc->sc_unit, mp->mscp_unit, tmscpaddr->tmscpsa); (void)tkini(sc); break; *************** *** 1209,1250 **** register struct mscp *mp; register struct tms_info *tms; struct buf *dp, *bp; ! int st; mp = &sc->sc_com->tmscp_rsp[i]; mp->mscp_header.tmscp_msglen = mscp_msglen; sc->sc_credits += mp->mscp_header.tmscp_credits & 0xf; /* low 4 bits */ ! if ((mp->mscp_header.tmscp_credits & 0xf0) > 0x10) /* Check */ return; ! #ifdef TMSCP_DEBUG ! printd("tmscprsp, opcode 0%o status 0%o\n",mp->mscp_opcode,mp->mscp_status&M_ST_MASK); ! printd(" SEG5: 0%o sc: 0%o mp: 0%o i: %d\n",*KDSA5, sc, mp, i); ! #endif /* * If it's an error log message (datagram), * pass it on for more extensive processing. */ ! if ((mp->mscp_header.tmscp_credits & 0xf0) == 0x10) ! { /* check */ tmserror(sc->sc_unit, (struct mslg *)mp); return; } ! st = mp->mscp_status&M_ST_MASK; /* ! * The controller interrupts as drive 0. * This means that you must check for controller interrupts ! * before you check to see if there is a drive 0. */ ! if((M_OP_STCON|M_OP_END) == mp->mscp_opcode) { ! if (st == M_ST_SUCC) ! { ! #ifdef TMSCP_DEBUG ! printd("ctlr has %d credits\n", mp->mscp_header.tmscp_credits & 0xf); ! printd("ctlr timeout = %d\n", mp->mscp_cnttmo); ! #endif sc->sc_state = S_RUN; - } else sc->sc_state = S_IDLE; sc->sc_ctab.b_active = 0; --- 1097,1137 ---- register struct mscp *mp; register struct tms_info *tms; struct buf *dp, *bp; ! int em_status, em_endcode; mp = &sc->sc_com->tmscp_rsp[i]; mp->mscp_header.tmscp_msglen = mscp_msglen; sc->sc_credits += mp->mscp_header.tmscp_credits & 0xf; /* low 4 bits */ ! if ((mp->mscp_header.tmscp_credits & 0xf0) > 0x10) /* Check */ return; ! /* * If it's an error log message (datagram), * pass it on for more extensive processing. */ ! if ((mp->mscp_header.tmscp_credits & 0xf0) == 0x10) ! { tmserror(sc->sc_unit, (struct mslg *)mp); return; } ! #ifdef TMSDEBUG ! if (tmscpprintf & 0x4) ! log(LOG_INFO, "tms%d,%d: op %x st %x\n", sc->sc_unit, ! mp->mscp_unit,mp->mscp_opcode, ! mp->mscp_status & M_ST_MASK); ! #endif ! ! em_status = mp->mscp_status&M_ST_MASK; ! em_endcode = mp->mscp_endcode & ~M_OP_END; /* ! * The controller interrupts as any drive. * This means that you must check for controller interrupts ! * before drive responses. */ ! if (em_endcode == M_OP_STCON) { ! if (em_status == M_ST_SUCC) sc->sc_state = S_RUN; else sc->sc_state = S_IDLE; sc->sc_ctab.b_active = 0; *************** *** 1251,1313 **** wakeup((caddr_t)&sc->sc_ctab); return; } ! if (mp->mscp_unit >= 4) return; tms = sc->sc_drives[mp->mscp_unit]; ! if (!tms) /* unopened unit coming online - ignore it */ return; ! /* ! * Save endcode, endflags, and status for mtioctl get unit status. ! * NOTE: Don't do this on Clear serious exception (reposition no-op); ! * which is done on close since this would ! * overwrite the real status we want. ! */ ! if (tms->tms_clserex != 1) ! { ! tms->tms_endcode = mp->mscp_opcode; ! tms->tms_flags = mp->mscp_flags; ! tms->tms_status = st; ! } ! else tms->tms_clserex = 0; ! switch (mp->mscp_opcode) { ! case M_OP_ONLIN|M_OP_END: ! tms->tms_type = mp->mscp_mediaid; ! dp = &tms->tms_dtab; ! if (st == M_ST_SUCC) { /* * Link the drive onto the controller queue */ dp->b_forw = NULL; ! if (sc->sc_ctab.b_actf == NULL) sc->sc_ctab.b_actf = dp; else sc->sc_ctab.b_actl->b_forw = dp; sc->sc_ctab.b_actl = dp; - tms->tms_online = 1; /* mark it online */ - tms->tms_dsize=(daddr_t)mp->mscp_maxwrt; - /* - * This define decodes the Media type identifier - */ - #ifdef TMSCP_DEBUG - printd("tmscprsp: %d,%d online mediaid 0x%lx format 0x%x\n", - sc->sc_unit, mp->mscp_unit, mp->mscp_mediaid, - mp->mscp_format); - #endif dp->b_active = 1; ! } /* end if st == M_ST_SUCC */ else { ! if (bp = dp->b_actf) ! tprintf(tms->tms_ttyp, ! "tms%d,%d: hard error bn%ld: OFFLINE\n", ! sc->sc_unit, mp->mscp_unit, bp->b_blkno); ! else ! tprintf(tms->tms_ttyp, ! "tms%d,%d: hard error: OFFLINE\n", ! sc->sc_unit, mp->mscp_unit); ! while (bp = dp->b_actf) { dp->b_actf = bp->av_forw; bp->b_flags |= B_ERROR; --- 1138,1180 ---- wakeup((caddr_t)&sc->sc_ctab); return; } ! if (mp->mscp_unit >= 4) return; tms = sc->sc_drives[mp->mscp_unit]; ! if (!tms) /* unopened unit coming online - ignore it */ return; ! dp = &tms->tms_dtab; ! switch (em_endcode) { ! case M_OP_ONLIN: ! if (em_status == M_ST_SUCC || em_status == M_ST_WRTPR) { + tms->Tflags |= _ONLINE; + tms->Tflags &= ~_CACHE_WRITTEN; + /* + * Normally this is done in the 'tms_check_ret' routine. The ONLIN case is + * special (well, ok - weird) in that it was never put on the I/O wait queue. + * Thus we need to do this here. + */ + tms->tms_endcode = em_endcode; + tms->tms_status = em_status; + tms->tms_type = mp->mscp_mediaid; + tms->tms_unitflgs = mp->mscp_unitflgs; + tms->tms_format = mp->mscp_format; /* * Link the drive onto the controller queue */ dp->b_forw = NULL; ! if (sc->sc_ctab.b_actf == NULL) sc->sc_ctab.b_actf = dp; else sc->sc_ctab.b_actl->b_forw = dp; sc->sc_ctab.b_actl = dp; dp->b_active = 1; ! } else { ! while (bp = dp->b_actf) { dp->b_actf = bp->av_forw; bp->b_flags |= B_ERROR; *************** *** 1314,1460 **** iodone(bp); } } ! if(mp->mscp_cmdref!=NULL) ! /* Seems to get lost sometimes in uda */ wakeup((caddr_t)mp->mscp_cmdref); ! break; /* * The AVAILABLE ATTENTION message occurs when the ! * unit becomes available after loading, ! * marking the unit offline (tms_online = -1) will force an * online command prior to using the unit. */ ! case M_OP_AVATN: ! tms->tms_online = -1; ! tms->tms_type = mp->mscp_mediaid; ! break; ! case M_OP_END: ! /* ! * An endcode without an opcode (0200) is an invalid command. ! * The mscp specification states that this would be a protocol ! * type error, such as illegal opcodes. The mscp spec. also ! * states that parameter error type of invalid commands should ! * return the normal end message for the command. This does not appear ! * to be the case. An invalid logical block number returned an endcode ! * of 0200 instead of the 0241 (read) that was expected. ! */ ! ! printf("tms%d,%d: invalid cmd endcode = %o status=%o\n", ! sc->sc_unit, mp->mscp_unit, mp->mscp_opcode, st); ! common: /* GTUNT finishes up thru here too */ ! bp = (struct buf *)mp->mscp_cmdref; ! /* ! * Unlink buffer from I/O wait queue. ! * And signal iodone, so the higher level command can exit! ! * ! */ ! bp->av_back->av_forw = bp->av_forw; ! bp->av_forw->av_back = bp->av_back; ! dp = &tms->tms_dtab; ! dp->b_qsize--; ! iodone(bp); ! break; ! case M_OP_WRITE|M_OP_END: ! /* mark the last io op as a write */ ! tms->tms_lastiow = 1; ! case M_OP_READ|M_OP_END: ! case M_OP_WRITM|M_OP_END: ! case M_OP_REPOS|M_OP_END: ! case M_OP_STUNT|M_OP_END: ! /* ! * The AVAILABLE message occurs when the mt ioctl "rewoffl" is ! * issued. For the ioctl, "rewoffl", a tmscp AVAILABLE command is ! * done with the UNLOAD modifier. This performs a rewind, followed ! * by marking the unit offline. So mark the unit offline ! * software wise as well (tms->tms_online = -1 and tms_open = 0). ! */ ! case M_OP_AVAIL|M_OP_END: ! #ifdef TMSCP_DEBUG ! printd("tmscprsp: position = %u,%u\n", mp->mscp_lbn_h,mp->mscp_lbn_l); ! #endif ! bp = (struct buf *)mp->mscp_cmdref; ! /* ! * Unlink buffer from I/O wait queue. ! */ ! bp->av_back->av_forw = bp->av_forw; ! bp->av_forw->av_back = bp->av_back; ! dp = &tms->tms_dtab; ! dp->b_qsize--; ! if (st == M_ST_OFFLN || st == M_ST_AVLBL) ! { ! tms->tms_online = -1; /* mark unit offline */ ! tms->tms_openf = 0; ! tms->tms_type = mp->mscp_mediaid; ! /* ! * Link the buffer onto the front of the drive queue ! */ ! if ((bp->av_forw = dp->b_actf) == 0) ! dp->b_actl = bp; ! dp->b_actf = bp; ! /* ! * Link the drive onto the controller queue ! */ ! if (dp->b_active == 0) ! { ! dp->b_forw = NULL; ! if (sc->sc_ctab.b_actf == NULL) ! sc->sc_ctab.b_actf = dp; ! else ! sc->sc_ctab.b_actl->b_forw = dp; ! sc->sc_ctab.b_actl = dp; ! dp->b_active = 1; ! } ! return; ! } ! if (st != M_ST_SUCC) ! { ! if (mp->mscp_flags & M_EF_SEREX) ! tms->tms_serex = 1; ! if (st != M_ST_TAPEM) ! { ! tprintf(tms->tms_ttyp, ! "tms%d,%d: hard err bn%ld status:0%o flags:0%o\n", ! sc->sc_unit, mp->mscp_unit, bp->b_blkno, ! mp->mscp_status, mp->mscp_flags); ! bp->b_flags |= B_ERROR; ! } ! else ! /* Hit a tape mark - Set serex flag to ! * a special value so we can clear the ! * serious exception on the next command. ! */ ! tms->tms_serex = 2; ! } ! /* ! * The tmscp spec states that controllers do not have to ! * report the number of records or files skipped. So on ! * reposition commands we go strictly by cmd status. ! */ ! if (mp->mscp_opcode != (M_OP_REPOS|M_OP_END)) ! bp->b_resid = bp->b_bcount - mp->mscp_bytecnt; ! else ! bp->b_resid = 0; ! tms->tms_resid = bp->b_resid; ! iodone(bp); ! break; ! ! case M_OP_GTUNT|M_OP_END: ! #ifdef TMSCP_DEBUG ! printd("tmscprsp: GTUNT end packet status = 0%o\n",st); ! printd("tmscprsp: %d,%d mediaid 0x%lx 0x%lx 0x%lx format=%d speed = %d\n", ! sc->sc_unit,mp->mscp_unit, mp->mscp_mediaid ! ,mp->mscp_unitid.val[0] ! ,mp->mscp_unitid.val[1] ! ,mp->mscp_format, mp->mscp_speed); ! #endif ! tms->tms_type = mp->mscp_mediaid; ! tms->tms_fmtmenu = mp->mscp_fmtmenu; ! tms->tms_unitflgs = mp->mscp_unitflgs; ! goto common; /* need to dequeue buffer and do iodone() */ ! default: ! printf("tms%d,%d unknown packet\n", sc->sc_unit,mp->mscp_unit); ! tmserror(sc->sc_unit, (struct mslg *)mp); } /* end switch mp->mscp_opcode */ } --- 1181,1229 ---- iodone(bp); } } ! if (mp->mscp_cmdref) wakeup((caddr_t)mp->mscp_cmdref); ! return; /* * The AVAILABLE ATTENTION message occurs when the ! * unit becomes available after loading. ! * Marking the unit offline will force an * online command prior to using the unit. */ ! case M_OP_AVATN: ! tms->Tflags &= ~_ONLINE; ! return; ! case 0: ! log(LOG_INFO, "tms%d,%d: inv end=%x st=%x\n", ! sc->sc_unit, mp->mscp_unit, em_endcode, em_status); ! tms_iodone(mp, tms); ! return; ! case M_OP_WRITE: ! case M_OP_READ: ! tms_rw_em(mp, sc); ! return; ! case M_OP_WRITM: ! tms_wtm_em(mp, sc); ! return; ! case M_OP_REPOS: ! tms_repos_em(mp, sc); ! return; ! case M_OP_STUNT: ! tms_stunt_em(mp, sc); ! return; ! case M_OP_AVAIL: ! tms_avail_em(mp, sc); ! return; ! case M_OP_GTUNT: ! tms_gtunt_em(mp, sc); ! return; ! case M_OP_FLUSH: ! tms_flush_em(mp, sc); ! return; default: ! log(LOG_INFO, "tms%d,%d bad rsp: %x\n", sc->sc_unit, ! mp->mscp_unit, em_endcode); ! return; } /* end switch mp->mscp_opcode */ } *************** *** 1464,1470 **** tmscpstrategy (bp) register struct buf *bp; ! { register struct buf *dp; register struct tmscp_softc *sc; struct tms_info *tms; --- 1233,1239 ---- tmscpstrategy (bp) register struct buf *bp; ! { register struct buf *dp; register struct tmscp_softc *sc; struct tms_info *tms; *************** *** 1473,1484 **** sc = &tmscp_softc[ctlr]; tms = sc->sc_drives[TMSUNIT(bp->b_dev)]; ! if (!tms || tms->tms_online != 1) { bp->b_flags |= B_ERROR; iodone(bp); return; } mapalloc(bp); s = spl5(); /* --- 1242,1265 ---- sc = &tmscp_softc[ctlr]; tms = sc->sc_drives[TMSUNIT(bp->b_dev)]; ! if (!tms || !(tms->Tflags & _ONLINE)) { bp->b_flags |= B_ERROR; iodone(bp); return; } + /* + * If we're at the end of the tape and no Clear Serious Exception has been + * done then return an error rather than reading off the end of the tape. + */ + if ((tms->tms_flags & MTF_CSE) == 0 && (tms->tms_flags & MTF_EOM)) + { + bp->b_resid = bp->b_bcount; + bp->b_error = ENOSPC; + bp->b_flags |= B_ERROR; + iodone(bp); + return; + } mapalloc(bp); s = spl5(); /* *************** *** 1507,1657 **** /* * If the controller is not active, start it. */ ! if (sc->sc_ctab.b_active == 0) ! { ! #ifdef TMSCP_DEBUG ! printd10("tmscpstrategy: Controller not active, starting it\n"); ! #endif (void) tmsstart(sc); - } splx(s); return; - } - - #ifdef TMSCP_DUMP - #define DBSIZE 16 - - tmsdump(dev) - dev_t dev; - { - register struct tmscpdevice *tmscpaddr; - register struct tmscp_softc *sc; - register struct mscp *mp; - daddr_t bn, dumpsize; - long paddr, maddr; - int unit = TMSUNIT(dev), count, ctlr = TMSCTLR(dev); - struct ubmap *ubp; - segm seg5; - - if (ctlr >= NTMSCP) - return (ENXIO); - sc = &tmscp_softc[ctlr]; - tmscpaddr = sc->sc_addr; - if (tmscpaddr == NULL) - return(ENXIO); - - paddr = _iomap(tmscp[sc->sc_unit]); - if (ubmap) { - ubp = UBMAP; - ubp->ub_lo = loint(paddr); - ubp->ub_hi = hiint(paddr); } - paddr += RINGBASE; - saveseg5(seg5); - mapseg5(tmscp[sc->sc_unit], MAPBUFDESC); - mp = sc->sc_com->tmscp_rsp; - sc->sc_com->tmscp_ca.ca_cmdint = sc->sc_com->tmscp_ca.ca_rspint = 0; - bzero(mp, 2 * sizeof (*mp)); - tmscpaddr->tmscpip = 0; - while ((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0) - if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT); - tmscpaddr->tmscpsa = TMSCP_ERR; - while ((tmscpaddr->tmscpsa & TMSCP_STEP2) == 0) - if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT); - tmscpaddr->tmscpsa = loint(paddr); - while ((tmscpaddr->tmscpsa & TMSCP_STEP3) == 0) - if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT); - tmscpaddr->tmscpsa = hiint(paddr); - while ((tmscpaddr->tmscpsa & TMSCP_STEP4) == 0) - if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT); - tmscpaddr->tmscpsa = TMSCP_GO; - - tmsginit(sc, sc->sc_com->tmscp_ca.ca_rspdsc, mp, 0, 2, 0); - - if (tmscpcmd(M_OP_STCON, unit, sc) == 0) { - return(EFAULT); - } - sc->sc_com->tmscp_cmd[0].mscp_unit = unit; - if (tmscpcmd(M_OP_ONLIN, unit, sc) == 0) { - return(EFAULT); - } - - dumpsize = 8 * 1024L; /* XXX */ - ubp = &UBMAP[1]; - for (paddr = 0; dumpsize > 0; dumpsize -= count) { - count = MIN(dumpsize, DBSIZE); - bn = paddr >> PGSHIFT; - maddr = paddr; - if (ubmap) { - ubp->ub_lo = loint(paddr); - ubp->ub_hi = hiint(paddr); - maddr = (u_int)(1 << 13); - } - /* write it to the tape */ - mp = &sc->sc_com->tmscp_rsp[1]; - mp->mscp_lbn_l = loint(bn); - mp->mscp_lbn_h = hiint(bn); - mp->mscp_bytecnt = count * NBPG; - mp->mscp_buffer_l = loint(maddr); - mp->mscp_buffer_h = hiint(maddr); - if (tmscpcmd(M_OP_WRITE, unit, sc) == 0) - return(EIO); - paddr += (DBSIZE << PGSHIFT); - } - restorseg5(seg5); - return (0); - } - - /* - * Perform a standalone tmscp command. This routine is only used by tmscpdump. - */ - - tmscpcmd(op, unit, sc) - int op; - int unit; - register struct tmscp_softc *sc; - { - int i; - register struct mscp *cmp, *rmp; - Trl *rlp; - - cmp = &sc->sc_com->tmscp_rsp[1]; - rmp = &sc->sc_com->tmscp_rsp[0]; - rlp = &sc->sc_com->tmscp_ca.ca_rspdsc[0]; - - cmp->mscp_opcode = op; - cmp->mscp_unit = unit; - cmp->mscp_header.tmscp_msglen = mscp_msglen; - rmp->mscp_header.tmscp_msglen = mscp_msglen; - rlp[0].hsh |= TMSCP_OWN|TMSCP_INT; - rlp[1].hsh |= TMSCP_OWN|TMSCP_INT; - if (sc->sc_addr->tmscpsa&TMSCP_ERR) - printf(tmscpfatalerr, sc->sc_unit, unit, sc->sc_addr->tmscpsa); - i = sc->sc_addr->tmscpip; - - while ((rlp[1].hsh & TMSCP_INT) == 0) - ; - while ((rlp[0].hsh & TMSCP_INT) == 0) - ; - - sc->sc_com->tmscp_ca.ca_rspint = 0; - sc->sc_com->tmscp_ca.ca_cmdint = 0; - if (rmp->mscp_opcode != (op|M_OP_END) || - (rmp->mscp_status&M_ST_MASK) != M_ST_SUCC) - { - printf("err: com %d opc 0x%x stat 0x%x\ndump ", op, - rmp->mscp_opcode, rmp->mscp_status); - return(0); - } - return(1); - } - #endif TMSCP_DUMP - - /* - * Catch ioctl commands, and call the "command" routine to do them. - */ - /* ARGSUSED */ tmscpioctl(dev, cmd, data, flag) dev_t dev; --- 1288,1299 ---- /* * If the controller is not active, start it. */ ! if (sc->sc_ctab.b_active == 0) (void) tmsstart(sc); splx(s); return; } /* ARGSUSED */ tmscpioctl(dev, cmd, data, flag) dev_t dev; *************** *** 1660,1720 **** int flag; { struct tmscp_softc *sc = &tmscp_softc[TMSCTLR(dev)]; ! register struct buf *bp = &sc->sc_cmdbuf; ! register callcount; /* number of times to call cmd routine */ ! register struct tms_info *tms; int fcount; /* number of files (or records) to space */ register struct mtop *mtop; /* mag tape cmd op to perform */ register struct mtget *mtget; /* mag tape struct to get info in */ /* we depend of the values and order of the TMS ioctl codes here */ ! static u_char tmsops[] = {TMS_WRITM,TMS_FSF,TMS_BSF,TMS_FSR,TMS_BSR,TMS_REW,TMS_OFFL,TMS_SENSE, ! TMS_CACHE,TMS_NOCACHE}; switch (cmd) { ! case MTIOCTOP: /* tape operation */ mtop = (struct mtop *)data; switch (mtop->mt_op) { ! case MTWEOF: ! callcount = mtop->mt_count; ! fcount = 1; ! break; ! case MTFSF: case MTBSF: ! case MTFSR: case MTBSR: ! callcount = 1; fcount = mtop->mt_count; break; ! case MTREW: case MTOFFL: case MTNOP: ! case MTCACHE: case MTNOCACHE: ! callcount = 1; ! fcount = 1; /* wait for this rewind */ break; default: ! return (ENXIO); } /* end switch mtop->mt_op */ ! if (callcount <= 0 || fcount <= 0) ! return (EINVAL); ! while (--callcount >= 0) { ! tmscpcommand(dev, tmsops[mtop->mt_op], fcount); ! if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) && ! bp->b_resid) ! return (EIO); ! if (bp->b_flags & B_ERROR) /* like hitting BOT */ ! break; } ! return (geterror(bp)); ! case MTIOCGET: /* * Return status info associated with the particular UNIT. */ - tms = sc->sc_drives[TMSUNIT(dev)]; - if (!tms) - return(ENXIO); mtget = (struct mtget *)data; mtget->mt_type = MT_ISTMSCP; mtget->mt_dsreg = tms->tms_flags << 8; --- 1302,1370 ---- int flag; { struct tmscp_softc *sc = &tmscp_softc[TMSCTLR(dev)]; ! struct buf *bp = &sc->sc_cmdbuf; ! register struct tms_info *tms = sc->sc_drives[TMSUNIT(dev)]; int fcount; /* number of files (or records) to space */ register struct mtop *mtop; /* mag tape cmd op to perform */ register struct mtget *mtget; /* mag tape struct to get info in */ /* we depend of the values and order of the TMS ioctl codes here */ ! static char tmsops[] = {TMS_WRITM,TMS_FSF,TMS_BSF,TMS_FSR,TMS_BSR,TMS_REW,TMS_OFFL,TMS_SENSE, ! TMS_CACHE,TMS_NOCACHE,TMS_FLUSH}; + if (!tms) + return(ENXIO); + if (cmd != MTIOCGET) + tms->tms_status = ~M_ST_SUCC; + if (tms->tms_position == 0) + tms->tms_flags |= MTF_BOM; + else + tms->tms_flags &= ~MTF_BOM; + switch (cmd) { ! case MTIOCTOP: mtop = (struct mtop *)data; switch (mtop->mt_op) { ! case MTWEOF: ! return(tms_wrteof(dev, tms)); ! case MTFSF: ! case MTBSF: ! case MTFSR: ! case MTBSR: fcount = mtop->mt_count; break; ! case MTFLUSH: ! case MTCACHE: ! case MTNOCACHE: ! if ((tms->Tflags & _HASCACHE|_ONLINE) != ! _HASCACHE|_ONLINE) ! return(0); ! case MTREW: ! case MTOFFL: ! case MTNOP: ! fcount = 1; break; default: ! return(ENXIO); } /* end switch mtop->mt_op */ ! if (fcount <= 0) ! return(EINVAL); ! tmscpcommand(dev, tmsops[mtop->mt_op], fcount); ! if (tms->tms_status != M_ST_SUCC) { ! if (tms->Tflags & _CLSEREX) ! tmscpcommand(dev, TMS_CSE, 1); ! return(EIO); } ! return(geterror(bp)); ! case MTIOCGET: /* * Return status info associated with the particular UNIT. */ mtget = (struct mtget *)data; mtget->mt_type = MT_ISTMSCP; mtget->mt_dsreg = tms->tms_flags << 8; *************** *** 1722,1798 **** mtget->mt_erreg = tms->tms_status; mtget->mt_resid = tms->tms_resid; break; - default: ! return (ENXIO); } return (0); } /* ! * Process an error log message * ! * Only minimal decoding is done, only "useful" ! * information is printed. Eventually should ! * send message to an error logger. ! */ ! tmserror(ctlr, mp) ! register int ctlr; ! register struct mslg *mp; ! { ! register i; ! #ifdef TMSCP_DEBUG ! printd("tmserror:\n"); #endif ! if(!(mp->mslg_flags & (M_LF_SUCC | M_LF_CONT))) ! log(TMS_PRI, "tms%d,%d: %s err ", ctlr, mp->mslg_unit, ! mp->mslg_flags & ( M_LF_SUCC | M_LF_CONT ) ? "soft" : "hard"); ! switch (mp->mslg_format) { ! case M_FM_CNTERR: ! log(TMS_PRI, "ctlr err event 0%o\n", mp->mslg_event); ! break; ! case M_FM_BUSADDR: ! log(TMS_PRI, "host memory access err, event 0%o, addr 0%o\n", ! mp->mslg_event, mp->mslg_busaddr); ! break; ! case M_FM_TAPETRN: ! log(TMS_PRI, "tape transfer err unit %d grp 0x%x event 0%o\n", ! mp->mslg_unit, mp->mslg_group, mp->mslg_event); ! break; ! case M_FM_STIERR: ! log(TMS_PRI, "STI err unit %d event 0%o\n", ! mp->mslg_unit, mp->mslg_event); ! #ifdef notdef ! /* too painful to do with log() */ ! for(i = 0; i < 62;i++) ! mprintf("\t0x%x",mp->mslg_stiunsucc[i] & 0xff); ! mprintf("\n"); #endif ! break; ! case M_FM_STIDEL: ! log(TMS_PRI, "STI Drive ErrorLog unit %d event 0%o\n", ! mp->mslg_unit, mp->mslg_event); ! break; ! case M_FM_STIFEL: ! log(TMS_PRI, "STI Formatter ErrorLog unit %d event 0%o\n", ! mp->mslg_unit, mp->mslg_event); ! break; ! default: ! log(TMS_PRI, "unknown err %d,%d format 0%o event 0%o\n", ! ctlr,mp->mslg_unit, mp->mslg_format, mp->mslg_event); } ! if (tmscperror) ! { ! register long *p = (long *)mp; ! for (i = 0; i < mp->mslg_header.tmscp_msglen; i += sizeof(*p)) ! printf("%x ", *p++); ! printf("\n"); ! } ! } #endif NTMSCP --- 1372,1945 ---- mtget->mt_erreg = tms->tms_status; mtget->mt_resid = tms->tms_resid; break; default: ! return(ENXIO); } return (0); } + tms_wrteof(dev, tms) + dev_t dev; + register struct tms_info *tms; + { + + tmscpcommand(dev, TMS_WRITM, 1); + if (tms->tms_status != M_ST_SUCC) + return(EIO); + tms->tms_status = ~M_ST_SUCC; + tmscpcommand(dev, TMS_WRITM, 1); + if (tms->tms_status != M_ST_SUCC) + return(EIO); + tms->Tflags &= ~_CACHE_WRITTEN; + tms->tms_status = ~M_ST_SUCC; + tmscpcommand(dev, TMS_BSR, 1); + if (tms->tms_status != M_ST_SUCC) + return(EIO); + return(0); + } + /* ! * Initialize the mscp packet for a STUNT command. If the drive is in a ! * 'cache lost' but 'written' state then clear it and log the error. ! */ ! ! tms_stunt_st(mp, sc, flgs) ! register struct mscp *mp; ! register struct tmscp_softc *sc; ! int flgs; ! { ! register struct tms_info *tms = sc->sc_drives[mp->mscp_unit]; ! ! mp->mscp_opcode = M_OP_STUNT; ! mp->mscp_modifier = flgs | M_MD_EXCAC; ! tms_cache_cmn(sc, tms, mp); ! ! /* ! * Set the unit flags - this includes the cache enable/disable flags. ! */ ! ! mp->mscp_unitflgs = tms->tms_unitflgs; ! ! /* ! * Only initialize the density if the position is not at BOT. On some ! * drives (notably the TU81) selecting a density other than the 'current' ! * (0) causes an illegal command error. ! */ ! if (tms->tms_position != 0) ! mp->mscp_format = 0; ! else ! mp->mscp_format = tms->tms_format; ! } ! ! /* ! * Initialize the mscp packet for a REPOS command. The 'flgs' parameter ! * specifies if the movement if forwards or backwards and if records or ! * tape marks (objects) are to be skipped. ! */ ! ! tms_repos_st(mp, sc, flgs) ! register struct mscp *mp; ! register struct tmscp_softc *sc; ! int flgs; ! { ! struct buf *bp = (struct buf *)mp->mscp_cmdref; ! register struct tms_info *tms = sc->sc_drives[mp->mscp_unit]; ! ! mp->mscp_opcode = M_OP_REPOS; ! mp->mscp_modifier = flgs | M_MD_CLSEX; ! tms->Tflags &= ~_CLSEREX; ! tms_cache_cmn(sc, tms, mp); /* shared code with tms_reposrec_st */ ! if (mp->mscp_modifier & M_MD_OBJCT) ! mp->mscp_reccnt = bp->b_bcount; ! else ! mp->mscp_tmkcnt = bp->b_bcount; ! } ! ! /* ! * Initialize the mscp packet for a REPOS 'record' command. Tape records do ! * not include tapemarks (which is why this is a separate routine from ! * tms_repos_st above). ! */ ! ! tms_reposrec_st(mp, sc, flgs) ! register struct mscp *mp; ! register struct tmscp_softc *sc; ! int flgs; ! { ! struct buf *bp = (struct buf *)mp->mscp_cmdref; ! register struct tms_info *tms = sc->sc_drives[mp->mscp_unit]; ! ! mp->mscp_opcode = M_OP_REPOS; ! mp->mscp_modifier = flgs; ! tms_cache_cmn(sc, tms, mp); ! mp->mscp_reccnt = bp->b_bcount; ! } ! ! /* ! * Initialize the mscp packet for an AVAIL command. The only time this is ! * done is on a 'rewoffl' command. ! */ ! ! tms_avail_st(mp, sc, flgs) ! register struct mscp *mp; ! register struct tmscp_softc *sc; ! int flgs; ! { ! register struct tms_info *tms = sc->sc_drives[mp->mscp_unit]; ! ! mp->mscp_opcode = M_OP_AVAIL; ! mp->mscp_modifier = flgs | M_MD_CLSEX; ! tms->Tflags &= ~_CLSEREX; ! if (tms->Tflags & _CACHE_LOST) ! { ! tms->Tflags &= ~(_CACHE_LOST | _CACHE_WRITTEN); ! mp->mscp_modifier |= M_MD_CDATL; ! } ! } ! ! /* ! * Initialize the mscp packet for a WTM (write tapemark) command. ! */ ! ! tms_wtm_st(mp, sc, flgs) ! register struct mscp *mp; ! register struct tmscp_softc *sc; ! int flgs; ! { ! register struct tms_info *tms = sc->sc_drives[mp->mscp_unit]; ! ! mp->mscp_opcode = M_OP_WRITM; ! mp->mscp_modifier = flgs | M_MD_CLSEX; ! tms->Tflags &= ~_CLSEREX; ! tms_cache_cmn(sc, tms, mp); ! } ! ! tms_cache_cmn(sc, tms, mp) ! register struct tmscp_softc *sc; ! register struct tms_info *tms; ! register struct mscp *mp; ! { ! ! if (tms->Tflags & _CACHE_LOST) ! { ! if (!(tms->Tflags & _CACHE_WRITTEN) || ! (tms->tms_flags & MTF_CSE)) ! { ! tms->Tflags &= ~(_CACHE_LOST | _CACHE_WRITTEN); ! mp->mscp_modifier |= M_MD_CDATL; ! } ! else ! log(LOG_INFO, "tms%d,%d cache lost\n", ! sc->sc_unit, mp->mscp_unit); ! } ! } ! ! /* ! * Process the end message from a REPOS command. Called from tmscprsp(). ! */ ! ! tms_repos_em(mp, sc) ! register struct mscp *mp; ! register struct tmscp_softc *sc; ! { ! register struct tms_info *tms = sc->sc_drives[mp->mscp_unit]; ! u_short em_status = mp->mscp_status & M_ST_MASK; ! ! (void)tms_check_ret(mp, sc); ! if (em_status == M_ST_SUCC) ! { ! if (tms->tms_position != mp->mscp_position) ! tms->Tflags &= ~_WRITTEN; ! if (tms->tms_position = mp->mscp_position) ! tms->tms_flags &= ~MTF_BOM; ! else ! { ! tms->tms_flags |= MTF_BOM; ! tms->Tflags &= ~_LOST; ! } ! tms->Tflags &= ~_CACHE_WRITTEN; ! } ! tms->tms_resid = 0; ! tms_iodone(mp, sc); ! } ! ! /* ! * Process the end message from a STUNT command. ! */ ! ! tms_stunt_em(mp, sc) ! register struct mscp *mp; ! register struct tmscp_softc *sc; ! { ! register struct tms_info *tms = sc->sc_drives[mp->mscp_unit]; ! u_short em_status = mp->mscp_status & M_ST_MASK; ! ! (void)tms_check_ret(mp, sc); ! tms->Tflags &= ~_CACHE_WRITTEN; ! if (em_status == M_ST_SUCC) ! { ! tms->tms_unitflgs = mp->mscp_unitflgs; ! tms->tms_format = mp->mscp_format; ! tms->tms_type = mp->mscp_mediaid; ! tms->Tflags |= _ONLINE; ! } ! tms->tms_resid = 0; ! tms_iodone(mp, sc); ! } ! ! /* ! * Process the end message from a WRITM (Write Tape Mark) command. ! */ ! ! tms_wtm_em(mp, sc) ! register struct mscp *mp; ! register struct tmscp_softc *sc; ! { ! register struct tms_info *tms = sc->sc_drives[mp->mscp_unit]; ! u_short em_status = mp->mscp_status & M_ST_MASK; ! ! if (em_status == M_ST_SUCC) ! { ! tms->Tflags &= ~_WRITTEN; ! tms->tms_position = mp->mscp_position; ! } ! (void)tms_check_ret(mp, sc); ! tms->tms_resid = 0; ! tms_iodone(mp, sc); ! } ! ! tms_avail_em(mp, sc) ! register struct mscp *mp; ! register struct tmscp_softc *sc; ! { ! register struct tms_info *tms = sc->sc_drives[mp->mscp_unit]; ! ! tms->Tflags &= ~_INUSE; ! (void)tms_check_ret(mp, sc); ! tms->Tflags &= ~_ONLINE; ! tms->tms_position = 0; ! tms->tms_flags |= MTF_BOM; ! if (tms->tms_status == M_ST_SUCC) ! tms->Tflags &= ~_CACHE_WRITTEN; ! tms->tms_resid = 0; ! tms_iodone(mp, sc); ! } ! ! tms_flush_em(mp, sc) ! register struct mscp *mp; ! register struct tmscp_softc *sc; ! { ! register struct tms_info *tms = sc->sc_drives[mp->mscp_unit]; ! u_short em_status = mp->mscp_status & M_ST_MASK; ! ! if (em_status == M_ST_SUCC) ! tms->Tflags &= ~_CACHE_WRITTEN; ! else ! log(LOG_INFO, "tms%d,%d flush fail\n",sc->sc_unit,mp->mscp_unit); ! tms->tms_position = mp->mscp_position; ! (void)tms_check_ret(mp, sc); ! tms->tms_resid = 0; ! tms_iodone(mp, sc); ! } ! ! tms_gtunt_em(mp, sc) ! register struct mscp *mp; ! register struct tmscp_softc *sc; ! { ! register struct tms_info *tms = sc->sc_drives[mp->mscp_unit]; ! u_short em_status = mp->mscp_status & M_ST_MASK; ! u_short em_flags = mp->mscp_unitflgs; ! ! (void)tms_check_ret(mp, sc); ! if (em_status == M_ST_SUCC) ! { ! tms->tms_format = mp->mscp_format; ! tms->tms_type = mp->mscp_mediaid; ! tms->tms_fmtmenu = mp->mscp_fmtmenu; ! tms->tms_unitflgs = mp->mscp_unitflgs; ! tms->Tflags |= _ONLINE; ! if (em_flags & (M_UF_WRTPH | M_UF_WRTPS | M_UF_WRTPD)) ! tms->tms_flags |= MTF_WRTLCK; ! else ! tms->tms_flags &= ~MTF_WRTLCK; ! if (em_flags & M_UF_CACH) ! { ! tms->Tflags |= _HASCACHE; ! if (tms->Tflags & _CACHE_ON) ! { ! tms->tms_unitflgs |= M_UF_WBKNV; ! tms->tms_unitflgs &= ~M_UF_SCCHH; ! } ! else ! { ! tms->tms_unitflgs &= ~M_UF_WBKNV; ! tms->tms_unitflgs |= M_UF_SCCHH; ! } ! } ! if (tms->tms_position == 0) ! tms->tms_flags |= MTF_BOM; ! else ! tms->tms_flags &= ~MTF_BOM; ! } ! tms->tms_resid = 0; ! tms_iodone(mp, sc); ! } ! ! tms_rw_em(mp, sc) ! register struct mscp *mp; ! register struct tmscp_softc *sc; ! { ! struct buf *bp = (struct buf *)mp->mscp_cmdref; ! register struct tms_info *tms = sc->sc_drives[mp->mscp_unit]; ! u_short em_status = mp->mscp_status & M_ST_MASK; ! ! tms->tms_flags &= ~MTF_WRITTEN; ! (void)tms_check_ret(mp, sc); ! if (em_status == M_ST_SUCC) ! { ! if ((tms->tms_endcode & ~M_OP_END) == M_OP_WRITE) ! { ! tms->Tflags |= _WRITTEN; ! tms->tms_flags |= MTF_WRITTEN; ! } ! else ! tms->Tflags &= ~_CACHE_WRITTEN; ! } ! tms->tms_resid = bp->b_bcount - mp->mscp_bytecnt; ! if (tms->tms_position = mp->mscp_position) ! tms->tms_flags &= ~MTF_BOM; ! else ! tms->tms_flags |= MTF_BOM; ! tms_iodone(mp, sc); ! } ! ! /* ! * This routine removes the buffer from the I/O wait queue, decrements the ! * drive queue size, stores the residual value in the buffer header and ! * calls iodone. ! */ ! ! tms_iodone(mp, sc) ! struct mscp *mp; ! struct tmscp_softc *sc; ! { ! struct tms_info *tms = sc->sc_drives[mp->mscp_unit]; ! register struct buf *bp = (struct buf *)mp->mscp_cmdref; ! register struct buf *dp = &tms->tms_dtab; ! u_short st = tms->tms_status; ! ! /* ! * Remove the buffer from the I/O wait queue. ! */ ! bp->av_back->av_forw = bp->av_forw; ! bp->av_forw->av_back = bp->av_back; ! dp->b_qsize--; ! /* ! * The weird (and not fully understood) treatment of the OFFLIN and AVLBL ! * status values was moved intact. It is not clear why the error bit can't ! * simply be set and iodone called as for other not successful status codes. ! */ ! if (st == M_ST_OFFLN || st == M_ST_AVLBL) ! { ! /* ! * Link buffer on to the front of the drive queue. ! */ ! if ((bp->av_forw = dp->b_actf) == 0) ! dp->b_actf = bp; ! dp->b_actf = bp; ! /* ! * Link the drive onto the controller queue. ! */ ! if (dp->b_active == 0) ! { ! dp->b_forw = NULL; ! if (sc->sc_ctab.b_actf == NULL) ! sc->sc_ctab.b_actf = dp; ! else ! sc->sc_ctab.b_actl->b_forw = dp; ! sc->sc_ctab.b_actl = dp; ! dp->b_active = 1; ! } ! return; ! } ! bp->b_resid = tms->tms_resid; ! iodone(bp); ! } ! ! /* ! * Check the return status of an mscp packet and adjust the drive's flags ! * appropriately. On error conditions set the error flag and code in the ! * buffer header. * ! * Many of the 'case' statements below are finer grained than strictly ! * necessary - this is done to provide easy access for logging of specific ! * conditions during debugging. ! */ ! tms_check_ret(mp, sc) ! struct mscp *mp; ! struct tmscp_softc *sc; ! { ! register struct tms_info *tms = sc->sc_drives[mp->mscp_unit]; ! register struct buf *bp = (struct buf *)mp->mscp_cmdref; ! u_short em_status = mp->mscp_status & M_ST_MASK; ! u_short em_subcode = mp->mscp_status >> M_ST_SBBIT; ! u_short em_flags = mp->mscp_flags; ! u_short em_endcode = mp->mscp_endcode & ~M_OP_END; ! char berr, unkerr; ! #ifdef TMSDEBUG ! if (em_status != M_ST_SUCC && em_status != M_ST_TAPEM && ! (tmscpprintf & 0x1)) ! log(LOG_INFO, "tms%d,%d st=%x sb=%x fl=%x en=%x\n", ! sc->sc_unit, mp->mscp_unit, ! em_status, em_subcode, em_flags, em_endcode); #endif ! tms->tms_endcode = mp->mscp_endcode; ! if (em_flags & M_EF_EOT) ! tms->tms_flags |= MTF_EOM; ! else ! tms->tms_flags &= ~MTF_EOM; ! if (em_flags & M_EF_DLS) ! tms->Tflags |= _CACHE_LOST; ! if (em_flags & M_EF_PLS) ! tms->Tflags |= _LOST; ! tms->tms_status = mp->mscp_status; ! berr = 0; ! unkerr = 0; ! switch (em_status) ! { ! case M_ST_SUCC: ! { ! switch (em_subcode) ! { ! case M_SC_DUPUN: /* Duplicate unit */ ! berr = ENXIO; ! break; ! case M_SC_ALONL: /* Already online */ ! case M_SC_STONL: /* Still online */ ! case M_SC_UNIGN: /* Unload ignored */ ! case M_SC_ROVOL: /* Readonly unit */ ! tms->Tflags |= _ONLINE; ! break; ! case M_SC_EOT: /* End of Tape */ ! tms->tms_flags |= MTF_EOM; ! break; ! } ! } ! break; ! case M_ST_OFFLN: ! tms->Tflags &= ~_ONLINE; ! if ((tms->Tflags & _CACHE_ON) && ! (tms->Tflags & _CACHE_WRITTEN)) ! log(LOG_INFO, "tms%d,%d cache loss2\n", ! sc->sc_unit, mp->mscp_unit); ! berr = ENXIO; ! break; ! case M_ST_WRTPR: /* Write Protected */ ! tms->tms_flags |= MTF_WRTLCK; ! berr = EACCES; /* Really an error ? */ ! break; ! case M_ST_ICMD: /* Byte count too big */ ! case M_ST_ABRTD: /* Command aborted */ ! case M_ST_COMP: /* Data Compare error */ ! case M_ST_DATA: /* Data error */ ! case M_ST_HSTBF: /* Host buffer error */ ! case M_ST_CNTLR: /* Controller error */ ! case M_ST_FMTER: /* Formatter error */ ! berr = EIO; ! break; ! case M_ST_AVLBL: /* Unit available */ ! tms->Tflags &= ~(_LOST | _CLSEREX | _SEREX | _ONLINE); ! break; ! case M_ST_BOT: /* Beginning of tape */ ! tms->tms_flags |= MTF_BOM; ! tms->tms_position = 0; ! break; ! case M_ST_TAPEM: /* Tape Mark */ ! tms->Tflags |= (_BUFMARK | _CLSEREX); ! break; ! case M_ST_SEX: /* Serious Exception */ ! if (em_flags & M_EF_EOT) ! { ! tms->tms_flags |= MTF_EOM; ! berr = ENOSPC; ! } ! else ! { ! tms->Tflags &= ~_CLSEREX; ! #ifdef TMSDEBUG ! log(LOG_INFO, "tms%d,%d serex, subcode %x\n", ! sc->sc_unit, mp->mscp_unit); #endif ! berr = EIO; ! } ! break; ! case M_ST_PLOST: /* Position Lost */ ! #ifdef TMSDEBUG ! log(LOG_INFO, "tms%d,%d plost\n", sc->sc_unit, ! mp->mscp_unit); ! #endif ! tms->Tflags |= (_LOST | _SEREX); ! tms->Tflags &= ~_CLSEREX; ! berr = EIO; ! break; ! case M_ST_LED: /* Logical end of dev */ ! tms->Tflags |= _CLSEREX; ! break; ! case M_ST_MFMTE: /* Media format err */ ! case M_ST_DRIVE: /* Drive error */ ! case M_ST_RDTRN: /* Record truncated */ ! tms->Tflags |= _SEREX; ! tms->Tflags &= ~_CLSEREX; ! case M_ST_LOADR: ! case M_ST_DIAG: /* Intern diag err */ ! case M_ST_IPARM: /* Invalid parameter */ ! berr = EIO; ! break; ! default: ! unkerr = 1; ! berr = EIO; ! break; ! } ! if (unkerr) ! log(LOG_INFO, "tms%d,%d: bad st/sb =%x/%x\n", ! sc->sc_unit, mp->mscp_unit, em_status, em_subcode); ! if (berr && bp) ! { ! bp->b_flags |= B_ERROR; ! bp->b_error = berr; ! } ! return; } ! /* ! * Process an error log datagram. ! * ! * No decoding is done - it wasn't worth the D space. If bit 1 is set ! * in the print flags then a simple message is generated out of (hopefully) ! * useful fields. ! * ! * Eventually a error log daemon will be written and the datagram sent to ! * it for capture and detailed analysis. Until then the logging in ! * 'tms_check_ret' and a few other strategic spots will have to suffice. ! */ ! u_short tms_datagrams[NTMSCP]; ! ! tmserror(ctlr, mp) ! int ctlr; ! register struct mslg *mp; ! { ! ! tms_datagrams[ctlr]++; ! if (tmscpprintf & 0x2) ! log(LOG_INFO, ! "tms%d,%d dgram fmt=%x evt=%x grp=%x flg=%x pos=%D\n", ! ctlr, mp->mslg_unit, mp->mslg_format, ! mp->mslg_event, mp->mslg_group, mp->mslg_flags, ! mp->mslg_position); ! } #endif NTMSCP *** /usr/src/sys/pdpuba/tmscpreg.h.old Tue Aug 14 13:13:46 1990 --- /usr/src/sys/pdpuba/tmscpreg.h Thu Dec 14 21:35:05 1995 *************** *** 1,6 **** /* @(#)tmscpreg.h 7.1 (Berkeley) 6/5/86 */ ! /* @(#)tmscpreg.h 1.1 11/2/84 84/09/25 */ /**************************************************************** * * --- 1,6 ---- /* @(#)tmscpreg.h 7.1 (Berkeley) 6/5/86 */ ! /* @(#)tmscpreg.h 1.2 (2.11BSD) 1995/12/14 */ /**************************************************************** * * *************** *** 58,63 **** --- 58,75 ---- /* * TMSCP Communications Area */ + + /* + * These defines were moved here so they could be shared between the + * driver and the crash dump module. + */ + #define NRSPL2 3 /* log2 number of response packets */ + #define NCMDL2 3 /* log2 number of command packets */ + #define NRSP (1<<NRSPL2) + #define NCMD (1<<NCMDL2) + #define RINGBASE (4 * sizeof (short)) + /* Size to map in when mapping a controller's command packet area */ + #define MAPBUFDESC (((btoc(sizeof (struct tmscp)) - 1) << 8) | RW) struct tmscpca { short ca_xxx1; /* unused */ *** /VERSION.old Tue Dec 5 20:42:46 1995 --- /VERSION Wed Dec 27 11:22:23 1995 *************** *** 1,4 **** ! Current Patch Level: 282 2.11 BSD ============ --- 1,4 ---- ! Current Patch Level: 286 2.11 BSD ============