# 2.11BSD#431 - /usr/src/sys/pdpuba/tmscp.c

##### Functions

    getdd             X
    tkini             X
    tmsVec            X
    tms_avail_em      X
    tms_avail_st      X
    tms_cache_cmn     X
    tms_check_ret     X
    tms_clrerr        X
    tms_flush_em      X
    tms_gtunt_em      X
    tms_iodone        X
    tms_repos_em      X
    tms_repos_st      X
    tms_reposrec_st   X
    tms_rw_em         X
    tms_stunt_em      X
    tms_stunt_st      X
    tms_wrteof        X
    tms_wtm_em        X
    tms_wtm_st        X
    tmsattach         X
    tmscpclose        X
    tmscpcommand      X
    tmscpgetcp        X
    tmscpioctl        X
    tmscpopen         X
    tmscprsp          X
    tmscpstrategy     X
    tmserror          X
    tmsginit          X
    tmsintr           X
    tmsstart          X
    tmswatchdog       X

##### Variables

    Dmatrix           X
    tms_datagrams     X
    tms_info          X
    tmscp             X
    tmscp_cp_wait     X
    tmscp_softc       X
    tmscpcache        X
    tmscpfatalerr     X
    tmscpprintf       X

##### Macros

    STEP1GOOD         X
    STEP1MASK         X
    STEP2GOOD         X
    STEP2MASK         X
    STEP3GOOD         X
    STEP3MASK         X
    S_IDLE            X
    S_RUN             X
    S_SCHAR           X
    S_STEP1           X
    S_STEP2           X
    S_STEP3           X
    TMSDEBUG          X
    TMS_BSF           X
    TMS_BSR           X
    TMS_CACHE         X
    TMS_CSE           X
    TMS_FLUSH         X
    TMS_FSF           X
    TMS_FSR           X
    TMS_NOCACHE       X
    TMS_OFFL          X
    TMS_REW           X
    TMS_SENSE         X
    TMS_SETDENSITY    X
    TMS_WRITM         X
    _BUFMARK          X
    _CACHE_LOST       X
    _CACHE_ON         X
    _CACHE_WRITTEN    X
    _CLSEREX          X
    _HASCACHE         X
    _INUSE            X
    _LOST             X
    _ONLINE           X
    _SEREX            X
    b_qsize           X

       1: #define TMSDEBUG    1
       2:
       3: /*	@(#)tmscp.c	1.12 (2.11BSD) 1999/2/25 */
       4:
       5: #if !defined(lint) && defined(DOSCCS)
       6: static  char    *sccsid = "@(#)tmscp.c	1.24	(ULTRIX)	1/21/86";
       7: #endif
       8:
       9: /************************************************************************
      10:  *        Licensed from Digital Equipment Corporation 			*
      11:  *                       Copyright (c) 					*
      12:  *               Digital Equipment Corporation				*
      13:  *                   Maynard, Massachusetts 				*
      14:  *                         1985, 1986 					*
      15:  *                    All rights reserved. 				*
      16:  *									*
      17:  *        The Information in this software is subject to change 	*
      18:  *   without notice and should not be construed as a commitment 	*
      19:  *   by  Digital  Equipment  Corporation.   Digital   makes  no 	*
      20:  *   representations about the suitability of this software for 	*
      21:  *   any purpose.  It is supplied "As Is" without expressed  or 	*
      22:  *   implied  warranty. 						*
      23:  *									*
      24:  *        If the Regents of the University of California or its 	*
      25:  *   licensees modify the software in a manner creating  		*
      26:  *   diriviative copyright rights, appropriate copyright  		*
      27:  *   legends may be placed on  the drivative work in addition  		*
      28:  *   to that set forth above. 						*
      29:  ************************************************************************
      30:  *
      31:  * tmscp.c - TMSCP (TK50/TU81) tape device driver
      32:  *
      33:  * Modification History:
      34:  * 25-Feb-99 - sms
      35:  *	Fix density selection to preserve the high byte of m_format.  This
      36:  *	is required devices (such as the TK70) which have a nonzero value
      37:  *	in this field.
      38:  *
      39:  * 22-Feb-99 - sms
      40:  *	Add timeout logic to tmscpcommand to catch hardware going catatonic.
      41:  *	When tmscpcommand() was first created the only use was to issue a
      42:  *	nonblocking rewind upon close.  Tmscpcommand is now called for many
      43:  *	other functions some of which can leave a process (and the drive) hung
      44:  *	unless a timeout is done.
      45:  *
      46:  *	Remove special treatment of OFFLINE and AVLBL status codes in
      47:  *	tms_iodone().  The code is suspected of having been a bug even in
      48:  *	its old location but is definitely causing problems now - if a read
      49:  *	completes with a 'AVLBL' status the drive is hung because an iodone()
      50:  *	is never performed.
      51:  *
      52:  *	Minor cleanup done thruout (reduce D space consumption ,etc).
      53:  *
      54:  * 24-Apr-98 - sms
      55:  *	An incorrect pointer was being passed to tms_iodone() from tmscprsp()
      56:  *	when dealing with the 'invalid endcode' case.  While that value should
      57:  * 	never be generated by normal hardware the kernel should not panic.
      58:  *
      59:  * 07-Mar-98 - sms
      60:  *	Fix a bug that caused EOM to be 'sticky'.  Once EndOfMedia was detected
      61:  *	the only way to clear it was to unload and reload the tape.  Remove
      62:  *	unused flag definitions.  Only use a single 'written' flag instead of
      63:  *	two (one in tms_flags and another in Tflags).
      64:  *
      65:  * 01-Feb-98 - sms
      66:  *	Initially the thought was the driver was broken sometime around June
      67:  *	1996.  After adding additional logging and the 'sysctl' interface it
      68:  *	was discovered (eventually after several long nights) that both my
      69:  *	TK50 and another person's TU81+ had developed hardware problems.  The
      70:  *	better logging and sysctl changes were retained for future use ;)
      71:  *
      72:  *	Failure to 'online' a drive was changed to return EIO instead of ENXIO
      73:  *	because 'device not configured' means the drive is not present.
      74:  *
      75:  *	A 'sysctl' interface was added so that 'tmscpprintf' could be changed
      76:  *	without rebooting/recompiling the system.  Also sysctl can be used to
      77:  *	set the cache on/off status even if a tape is not at the load point -
      78:  *	the setting takes effect on the next open().
      79:  *
      80:  * 14-May-96 - sms
      81:  *	Missing parens caused mtflush,mtcache,mtnocache to be always skipped.
      82:  *	The use cache bit was being cleared in tmscpopen(). The use cache bit
      83:  *	is sticky in that once set via MTCACHE it stays set until cleared by
      84:  *	MTNOCACHE.
      85:  *
      86:  * 14-Dec-95 - sms@wlv...
      87:  *	Success!  But the size of the driver is even more of a problem now.
      88:  *	If the crash dump option is defined the driver could exceed the max
      89:  *	size permitted for an overlay.  The 'tmsdump' routine was moved to
      90:  *	a separate file.  This driver almost always must be in an overlay
      91:  *	by itself now.
      92:  *
      93:  * 08-Dec-95 - sms@wlv...
      94:  *	Begin serious surgery on this driver.  The goals are: 1) to correctly
      95:  *	handle TU81/81+ drives (do not set density unless at BOT), 2) support
      96:  *	use of the cache on drives which implement it (TU81+), 3) improve
      97:  *	error detection and reporting, 4) improve readability by replacing
      98:  *	multipage 'switch' statements with calls to functions, 5) make it
      99:  *	easier to add new capabilities and fix problems without wholescale
     100:  *	changes again.
     101:  *
     102:  * 30-Nov-95 - sms@wlv...
     103:  *	Experiment to see if M_MD_IMMED being set for the rewind on close
     104:  *	obviates the need for skipping the iowait().  Success - only 2 ticks
     105:  *	elapse doing the iowait!.
     106:  *
     107:  * 02-Jan-93 - sms@wlv. [2.11BSD]
     108:  *	Remove unibus map ifdefs and rely on run time testing of 'ubmap' which
     109:  * 	does the right thing and makes kernels easier to move between machines.
     110:  *
     111:  * 20-Nov-92 - sms@wlv.iipo.gtegsc.com [2.11BSD]
     112:  *	Add tmsVec() for autoconfig to use in passing the vector from /etc/dtab
     113:  *	to this driver.  The previous scheme of having a fixed vector with
     114:  *	all TMSCP vectors contiguous has been removed.
     115:  *
     116:  * 23-May-91 - sms@wlv.iipo.gtegsc.com [2.11BSD]
     117:  *	Minor typo in the multicontroller support fixed.  Major overhaul
     118:  *	of the density selection, apparently some TMSCP controllers
     119:  *	do not treat 0 in the mscp_format word as meaning the highest
     120:  *	density, instead leaving the drive in the current/last-used
     121:  *	density.
     122:  *
     123:  * 29-Mar-91 - sms@wlv.iipo.gtegsc.com [2.11BSD]
     124:  *	Major changes to 1) support multiple drives per controller
     125:  *	(the maximum number of drives per controller is 4 for now in order
     126:  *	to maximize compatibility with existing minor device numbers - the
     127:  *	norewind and density bit stay in the same place) and 2) more
     128:  *	importantly reduce the bloat of this driver.  The command
     129:  *	packet area is now allocated from an external heap setup at boot
     130:  *	time (the MSCP, ra.c driver also does this).  Allocating from an
     131:  * 	external arena save approximately 2kb of kernel D space PER CONTROLLER
     132:  *	and costs little in speed because the amount of remapping involved is
     133:  *	quite small.
     134:  *
     135:  *	The 'errinfo' routine was removed in the interest of space savings,
     136:  *	the error code was already being printed out in hex and it's not
     137:  *	worth eating up another 250 or so bytes of kernel D space to pretty
     138:  *	print messages for which tmscp.h provides the cross reference (I space
     139:  *	is also saved by not printing the messages).  Besides, the ra.c (MSCP)
     140:  *	driver doesn't do it and it is worth a degree of non 4.3BSD verisimility
     141:  *	to save a significant amount of space.
     142:  *
     143:  *	The tms_type field should have been a 'long' (mediatype).  Since the
     144:  *	drives are not probed at autoconfigure time a GTUNT (TMS_SENSE) command
     145:  *	is done at open() time to fetch the format/density menu and unit flags.
     146:  *	iodone() proccessing was missing for the GTUNT function in tmscprsp()
     147:  *	causing hangs in both open and ioctl functions.
     148:  *
     149:  *	Multiple controller support made to work, the top 2 bits of the minor
     150:  *	device number are used to designate the controller, thus there is
     151:  *	a maximum of 4 TMSCP controllers per system.
     152:  *
     153:  * 17-Jun-90,14Aug90 - sms@wlv.iipo.gtegsc.com
     154:  *	Began porting to 2.10.1BSD/2.11BSD.  Multiple drives per controller
     155:  *	NOT supported, although multiple controllers are (maybe).  Programmable
     156:  *	vectors don't work very well with the autoconfigure scheme in use.
     157:  *	the define TMSCP_VEC will have to be adjusted in tms.h (see
     158:  *	conf/config and the sample config files).  For patching purposes
     159:  *	the global "TMSvec" is declared and initialized with TMSCP_VEC.
     160:  *
     161:  * 06-Jan-86 - afd
     162:  *	Changed the probe routine to use DELAY (not TODR).  This now
     163:  *	works for MicroVAXen as well.  This eliminates the busy-wait
     164:  *	for MicroVAXen so a dead TK50 controller will not hang autoconf.
     165:  *
     166:  * 06-Dec-85 - afd
     167:  *	Fixed a bug in density selection.  The "set unit characteristics"
     168:  *	command to select density, was clearing the "unit flags" field
     169:  *	where the CACHE bit was for TU81-E.  Now the unit's "format" and
     170:  *	"unitflgs" are saved in tms_info struct.  And are used on STUNT
     171:  *	commands.
     172:  *
     173:  * 19-Oct-85 - afd
     174:  *	Added support to the open routine to allow drives to be opened
     175:  *	for low density (800 or 1600 bpi) use.  When the slave routine
     176:  *	initiates a "get-unit-char" cmd, the format menu for the unit
     177:  *	is saved in the tms_info structure. The format menu is used in the
     178:  *	start routine to select the proper low density.
     179:  *
     180:  * 02-Oct-85 - afd
     181:  *	When a tmscp-type controller is initializing, it is possible for
     182:  *	the sa reg to become 0 between states.  Thus the init code in
     183:  *	the interrupt routine had to be modified to reflect this.
     184:  *
     185:  * 21-Sep-85 - afd
     186:  *	The TK50 declares a serious exception when a tape mark is encountered.
     187:  *	This causes problems to dd (& other UN*X utilities).  So a flag
     188:  *	is set in the rsp() routine when a tape mark is encountered.  If
     189:  *	this flag is set, the start() routine appends the Clear Serious
     190:  *	Exception modifier to the next command.
     191:  *
     192:  * 03-Sep-85 -- jaw
     193:  *	messed up previous edit..
     194:  *
     195:  * 29-Aug-85 - jaw
     196:  *	fixed bugs in 8200 and 750 buffered datapath handling.
     197:  *
     198:  * 06-Aug-85 - afd
     199:  *   1. When repositioning records or files, the count of items skipped
     200:  *	does NOT HAVE to be returned by controllers (& the TU81 doesn't).
     201:  *	So tmscprsp() had to be modified to stop reporting
     202:  *	residual count errors on reposition commands.
     203:  *
     204:  *   2. Fixed bug in the open routine which allowed multiple opens.
     205:  *
     206:  * 18-Jul-85 - afd
     207:  *   1. Need to return status when mt status (or corresponding ioctl) is done.
     208:  *	Save resid, flags, endcode & status in tmscprsp() routine (except on
     209:  *	clear serious exception no-op).  Return these fields when status
     210:  *	ioctl is done (in tmscpcommand()).  How they are returned:
     211:  *		mt_resid = resid
     212:  *		mt_dsreg = flags|endcode
     213:  *		mt_erreg = status
     214:  *
     215:  *   2. Added latent support for enabling/disabling caching.  This is
     216:  *	handled along with all other ioctl commands.
     217:  *
     218:  *   3. Need to issue a no-op on unrecognized ioctl in tmsstart(), since
     219:  *	we have already commited to issuing a command at that point.
     220:  *
     221:  *   4. In tmscprsp() routine if encode is 0200 (invalid command issued);
     222:  *	We need to: Unlink the buffer from the I/O wait queue,
     223:  *	and signal iodone, so the higher level command can exit!
     224:  *	Just as if it were a valid command.
     225:  *
     226:  * 11-jul-85 -- jaw
     227:  *	fix bua/bda map registers.
     228:  *
     229:  * 19-Jun-85 -- jaw
     230:  *	VAX8200 name change.
     231:  *
     232:  * 06-Jun-85 - jaw
     233:  *	fixes for 8200.
     234:  *
     235:  * 9-Apr-85 - afd
     236:  *	Added timeout code to the probe routine, so if the controller
     237:  *	fails to init in 10 seconds we return failed status.
     238:  *
     239:  * 13-Mar-85 -jaw
     240:  *	Changes for support of the VAX8200 were merged in.
     241:  *
     242:  * 27-Feb-85 -tresvik
     243:  *	Changes for support of the VAX8600 were merged in.
     244:  *
     245:  */
     246:
     247: #include "tms.h"
     248: #if NTMSCP > 0
     249:
     250: #include "param.h"
     251: #include "systm.h"
     252: #include "buf.h"
     253: #include "conf.h"
     254: #include "user.h"
     255: #include "file.h"
     256: #include "map.h"
     257: #include "ioctl.h"
     258: #include "syslog.h"
     259: #include "mtio.h"
     260: #include "uio.h"
     261: #include "tty.h"
     262: #include "uba.h"
     263: #include "kernel.h"
     264:
     265: #include "tmscpreg.h"
     266: #include "../pdp/tmscp.h"
     267: #include "../machine/seg.h"
     268:
     269: /*
     270:  * The density array is indexed by the density bits (bits 3 and 4) of the
     271:  * minor device number AND the format menu returned for the drive.  Since
     272:  * only 3 densities are apparently supported by TMSCP (no DPE/3200bpi), the
     273:  * second MEDium table is a copy of the first MEDium entry.
     274: */
     275:
     276:     char    Dmatrix[4][8] =
     277:         {
     278: /* LOW */   {0,M_TF_800,M_TF_PE,M_TF_800,M_TF_GCR,M_TF_800,M_TF_PE,M_TF_800},
     279: /* MED1 */  {0,M_TF_800,M_TF_PE,M_TF_800,M_TF_GCR,M_TF_800,M_TF_PE,M_TF_PE },
     280: /* MED2 */  {0,M_TF_800,M_TF_PE,M_TF_800,M_TF_GCR,M_TF_800,M_TF_PE,M_TF_PE },
     281: /* HI */    {0,M_TF_800,M_TF_PE,M_TF_PE,M_TF_GCR,M_TF_GCR,M_TF_GCR,M_TF_GCR}
     282:         };
     283:
     284: struct  tmscp_softc tmscp_softc[NTMSCP];    /* Controller info */
     285: struct  tms_info tms_info[NTMS];        /* Drive info */
     286:
     287:     memaddr tmscp[NTMSCP];      /* click addresses of ctrl comm area */
     288:
     289: /*
     290:  * Tflags definitions.  These take the place of several
     291:  * individual structure members in tms_info.
     292: */
     293:
     294: #define _SEREX      0x0001      /* Serious Exception exists */
     295: #define _CLSEREX    0x0002      /* Do Clear Serious Exception */
     296: #define _LOST       0x0004      /* Position lost error happened */
     297: #define _BUFMARK    0x0008      /* Encountered a tape mark */
     298: #define _HASCACHE   0x0010      /* Drive has cache capability */
     299: #define _CACHE_ON   0x0020      /* Cache enabled */
     300: #define _CACHE_LOST 0x0040      /* Cache data loss has happened */
     301: #define _CACHE_WRITTEN  0x0080      /* Cache has been written */
     302: #define _INUSE      0x0100      /* Drive is in use */
     303: #define _ONLINE     0x0200      /* Drive is online */
     304:
     305: /*
     306:  * Internal (ioctl) command codes (these must also be declared in the
     307:  * tmscpioctl routine).  These correspond to ioctls in mtio.h
     308:  */
     309: #define TMS_WRITM   0       /* write tape mark */
     310: #define TMS_FSF     1       /* forward space file */
     311: #define TMS_BSF     2       /* backward space file */
     312: #define TMS_FSR     3       /* forward space record */
     313: #define TMS_BSR     4       /* backward space record */
     314: #define TMS_REW     5       /* rewind tape */
     315: #define TMS_OFFL    6       /* rewind tape & mark unit offline */
     316: #define TMS_SENSE   7       /* noop - do a get unit status */
     317: #define TMS_CACHE   8       /* enable cache */
     318: #define TMS_NOCACHE 9       /* disable cache */
     319: #define TMS_FLUSH   10      /* flush cache */
     320: /* These go last: after all real mt cmds, just bump the numbers up */
     321: #define TMS_CSE     11      /* clear serious exception */
     322: #define TMS_SETDENSITY  12      /* set unit density */
     323:
     324: /*
     325:  * Controller states
     326:  */
     327: #define S_IDLE  0               /* hasn't been initialized */
     328: #define S_STEP1 1               /* doing step 1 init */
     329: #define S_STEP2 2               /* doing step 2 init */
     330: #define S_STEP3 3               /* doing step 3 init */
     331: #define S_SCHAR 4               /* doing "set controller characteristics" */
     332: #define S_RUN   5               /* running */
     333:
     334: static  char *tmscpstepfailed = "step%d init failed: sa %x\n";
     335:     char *tmscpfatalerr = "tms%d,%d: fatal error %x\n";
     336:
     337: int tmscp_cp_wait = 0;  /* Something to wait on for command */
     338:                 /* packets and or credits. */
     339: int wakeup();
     340:     int tmswatchdog();
     341: extern  int hz;     /* Should find the right include */
     342: extern  long    _iomap();
     343: extern  u_int   tmscp_cache;    /* See pdp/kern_pdp.c */
     344:
     345: /*
     346:  * Bit 0 = print all non-successful response packets _except_ hitting a
     347:  *	   tapemark (which really isn't an error).
     348:  * Bit 1 = print datagram arrival message.
     349:  * Bit 2 = print status of all response packets except datagrams.
     350:  * Bit 3 = enable debugging print and log statements not covered above
     351: */
     352: int tmscpprintf = 1;
     353:
     354: /*
     355:  * This is settable via "sysctl -w machdep.tmscp.cache=0xXXXX".  There is one
     356:  * bit per drive.  Bit 0 is the first drive on the first controller, bit 4 is
     357:  * the first drive on the second controller, and so on.
     358:  *
     359: */
     360:
     361: int tmscpcache = 0;
     362:
     363: struct  mscp *tmscpgetcp();
     364:
     365: #define b_qsize         b_resid         /* queue size per drive, in tmsutab */
     366:
     367: tmsVec(ctlr, vector)
     368:     int ctlr, vector;
     369:     {
     370:     register struct tmscp_softc *sc = &tmscp_softc[ctlr];
     371:
     372:     if  (ctlr >= NTMSCP || sc->sc_ivec)
     373:         return(-1);
     374:     sc->sc_ivec = vector;
     375:     return(0);
     376:     }
     377:
     378: /*
     379:  * Open routine will issue the online command, later.
     380:  *
     381:  * This routine attaches controllers, not drives - sc_unit and 'unit' are
     382:  * the controller number not a drive unit number.  sc_com is initialized
     383:  * to SEG5 because all communication areas are mapped to the same virtual
     384:  * address now.
     385:  */
     386: tmsattach(addr, unit)
     387:     struct tmscpdevice *addr;
     388:     register int unit;
     389: {
     390:     register struct tmscp_softc *sc = &tmscp_softc[unit];
     391:
     392:     if (unit >= NTMSCP)
     393:         return(0);
     394:     if (sc->sc_addr == NULL && addr != NULL) {
     395:         tmscp[unit] = (memaddr)_ioget(sizeof (struct tmscp));
     396:         if (tmscp[unit] == NULL)
     397:             return(0);
     398:         sc->sc_addr = addr;
     399:         sc->sc_unit = unit;
     400:         sc->sc_com = (struct tmscp *)SEG5;
     401:         return (1);
     402:     }
     403:     return(0);
     404: }
     405:
     406: struct tms_info *
     407: getdd()
     408:     {
     409:     register struct tms_info *p;
     410:
     411:     for (p = tms_info; p < &tms_info[NTMS]; p++)
     412:         {
     413:         if  (p->tms_type == 0)
     414:             {
     415: /*
     416:  * Set the type with a placeholder value - we may have to sleep waiting for
     417:  * the drive to come on line and we don't want this slot to be grabbed again.
     418:  * The online response will load the real drive type.
     419: */
     420:             p->tms_type = 1;    /* XXX */
     421:             return(p);
     422:             }
     423:         }
     424:     log(LOG_INFO, "tms: !drives\n");
     425:     return(NULL);
     426:     }
     427:
     428: static int
     429: wait_step(mask, good, csr, sc)
     430:     u_short mask, good;
     431:     register struct tmscpdevice *csr;
     432:     register struct tmscp_softc *sc;
     433:     {
     434:     register int i;
     435:
     436:     for (i = 0; i < 150; i++)
     437:         {
     438:         if  ((csr->tmscpsa & mask) == good)
     439:             return(0);
     440:         delay(10000L);      /* still in step - wait 1/100 sec */
     441:         }
     442:     sc->sc_state = S_IDLE;
     443:     sc->sc_ctab.b_active = 0;
     444:     log(LOG_INFO, tmscpstepfailed, sc->sc_state, csr->tmscpsa);
     445:     wakeup((caddr_t)&sc->sc_ctab);
     446:     return(-1);
     447:     }
     448:
     449: /*
     450:  * TMSCP interrupt routine.
     451:  */
     452: tmsintr(dev)
     453:     dev_t dev;
     454: {
     455:     register struct tmscpdevice *tmscpaddr;
     456:     struct buf *bp;
     457:     int i;
     458:     register struct tmscp_softc *sc = &tmscp_softc[dev];
     459:     register struct tmscp *tm = sc->sc_com;
     460:     struct mscp *mp;
     461:     segm seg5;
     462:
     463:     tmscpaddr = sc->sc_addr;
     464:
     465:     /*
     466: 	 * How the interrupt is handled depends on the state of the controller.
     467: 	 */
     468:     switch (sc->sc_state) {
     469:
     470:     case S_IDLE:
     471:         log(LOG_INFO, "tms%d: rand intr\n", dev);
     472:         return;
     473:
     474:     /* Controller was in step 1 last, see if its gone to step 2 */
     475:     case S_STEP1:
     476: #		define STEP1MASK 0174377
     477: #		define STEP1GOOD (TMSCP_STEP2|TMSCP_IE|(NCMDL2<<3)|NRSPL2)
     478:
     479:         if  (wait_step(STEP1MASK, STEP1GOOD, tmscpaddr, sc) < 0)
     480:             return;
     481:         tmscpaddr->tmscpsa = (short)sc->sc_ctab.b_un.b_addr;
     482:         sc->sc_state = S_STEP2;
     483:         return;
     484:
     485:     /* Controller was in step 2 last, see if its gone to step 3 */
     486:     case S_STEP2:
     487: #		define STEP2MASK 0174377
     488: #		define STEP2GOOD (TMSCP_STEP3|TMSCP_IE|(sc->sc_ivec/4))
     489:
     490:         if  (wait_step(STEP2MASK, STEP2GOOD, tmscpaddr, sc) < 0)
     491:             return;
     492:         tmscpaddr->tmscpsa = sc->sc_ctab.b_xmem;
     493:         sc->sc_state = S_STEP3;
     494:         return;
     495:
     496:     /* Controller was in step 3 last, see if its gone to step 4 */
     497:     case S_STEP3:
     498: #		define STEP3MASK 0174000
     499: #		define STEP3GOOD TMSCP_STEP4
     500:
     501:         if  (wait_step(STEP3MASK, STEP3GOOD, tmscpaddr, sc) < 0)
     502:             return;
     503:         /*
     504: 		 * Get microcode version and model number of controller;
     505: 		 * Signal initialization complete (_GO) (to the controller);
     506: 		 * Set state to "set controller characteristics".
     507: 		 */
     508:         i = tmscpaddr->tmscpsa;
     509:         tmscpaddr->tmscpsa = TMSCP_GO | TMSCP_LF;
     510:         sc->sc_state = S_SCHAR;
     511:
     512:         log(LOG_INFO, "tms%d Ver %d Mod %d\n", dev, i & 0xf,
     513:             (i >> 4) & 0xf);
     514:
     515:         /*
     516: 	     * Initialize the data structures (response and command queues).
     517: 	     */
     518:         saveseg5(seg5);
     519:         mapseg5(tmscp[sc->sc_unit], MAPBUFDESC);
     520:         tmsginit(sc, sc->sc_com->tmscp_ca.ca_rspdsc, sc->sc_com->tmscp_rsp,
     521:             0, NRSP, TMSCP_OWN|TMSCP_INT);
     522:         tmsginit(sc, sc->sc_com->tmscp_ca.ca_cmddsc, sc->sc_com->tmscp_cmd,
     523:             NRSP, NCMD, TMSCP_INT);
     524:         bp = &sc->sc_wtab;
     525:         bp->av_forw = bp->av_back = bp;
     526:         sc->sc_lastcmd = 1;
     527:         sc->sc_lastrsp = 0;
     528:         mp = sc->sc_com->tmscp_cmd;
     529:         mp->mscp_unit = mp->mscp_modifier = 0;
     530:         mp->mscp_flags = 0;
     531:         mp->mscp_version = 0;
     532:         mp->mscp_cntflgs = M_CF_ATTN|M_CF_MISC|M_CF_THIS;
     533:         /*
     534: 	     * A host time out value of 0 means that the controller will not
     535: 	     * time out.  This is ok for the TK50.
     536: 	     */
     537:         mp->mscp_hsttmo = 0;
     538:         bzero(&mp->mscp_time, sizeof (mp->mscp_time));
     539:         mp->mscp_cntdep = 0;
     540:         mp->mscp_opcode = M_OP_STCON;
     541:         ((Trl *)mp->mscp_dscptr)->hsh |= (TMSCP_OWN|TMSCP_INT);
     542:         i = tmscpaddr->tmscpip;      /* initiate polling */
     543:         restorseg5(seg5);
     544:         return;
     545:
     546:     case S_SCHAR:
     547:     case S_RUN:
     548:         break;
     549:
     550:     default:
     551:         log(LOG_INFO, "tms%d: ST %d\n", dev, sc->sc_state);
     552:         return;
     553:     }   /* end switch */
     554:
     555:     /*
     556: 	 * The controller state is S_SCHAR or S_RUN
     557: 	 */
     558:
     559:     /*
     560: 	 * If the error bit is set in the SA register then print an error
     561: 	 * message and reinitialize the controller.
     562: 	 */
     563:     if (tmscpaddr->tmscpsa&TMSCP_ERR)
     564:         {
     565:         log(LOG_INFO, tmscpfatalerr, dev, sc->sc_unit, tmscpaddr->tmscpsa);
     566:         tmscpaddr->tmscpip = 0;
     567:         sc->sc_state = S_IDLE;
     568:         sc->sc_ctab.b_active = 0;
     569:         wakeup((caddr_t)&sc->sc_ctab);
     570:         }
     571:     /*
     572: 	 * Check for a buffer purge request. (Won't happen w/ TK50 on Q22 bus)
     573: 	 */
     574:     saveseg5(seg5);
     575:     mapseg5(tmscp[sc->sc_unit], MAPBUFDESC);
     576:     if (tm->tmscp_ca.ca_bdp)
     577:         {
     578:         tm->tmscp_ca.ca_bdp = 0;
     579:         tmscpaddr->tmscpsa = 0;      /* signal purge complete */
     580:         }
     581:
     582:     /*
     583: 	 * Check for response ring transition.
     584: 	 */
     585:     if (tm->tmscp_ca.ca_rspint)
     586:         {
     587:         tm->tmscp_ca.ca_rspint = 0;
     588:         for (i = sc->sc_lastrsp;; i++)
     589:             {
     590:             i %= NRSP;
     591:             if (tm->tmscp_ca.ca_rspdsc[i].hsh&TMSCP_OWN)
     592:                 break;
     593:             tmscprsp(sc, i);
     594:             tm->tmscp_ca.ca_rspdsc[i].hsh |= TMSCP_OWN;
     595:             }
     596:         sc->sc_lastrsp = i;
     597:         }
     598:
     599:     /*
     600: 	 * Check for command ring transition. (Should never happen!)
     601: 	 */
     602:     if  (tm->tmscp_ca.ca_cmdint)
     603:         tm->tmscp_ca.ca_cmdint = 0;
     604:     restorseg5(seg5);
     605:         if (tmscp_cp_wait)
     606:         wakeup((caddr_t)&tmscp_cp_wait);
     607:         (void) tmsstart(sc);
     608: }
     609:
     610:
     611: /*
     612:  * Open a tmscp device and set the unit online.  If the controller is not
     613:  * in the run state, call init to initialize the tmscp controller first.
     614:  */
     615:
     616: /* ARGSUSED */
     617: tmscpopen(dev, flag)
     618:     dev_t dev;
     619:     int flag;
     620: {
     621:     register int unit = TMSUNIT(dev);
     622:     int ctlr = TMSCTLR(dev);
     623:     register struct tmscp_softc *sc;
     624:     register struct tms_info *tms;
     625:     register struct mscp *mp;
     626:     struct tmscpdevice *tmscpaddr;
     627:     u_short cmdref;
     628:     int s,i;
     629:
     630:     if (ctlr >= NTMSCP)
     631:         return (ENXIO);
     632:     sc = &tmscp_softc[ctlr];
     633:     if (sc->sc_addr == NULL)
     634:         return (ENXIO);
     635:     if ((tms = sc->sc_drives[unit]) == NULL) {
     636:         tms = getdd();
     637:         if (!tms)
     638:             return(ENXIO);
     639:         tms->Tflags = 0;
     640:         sc->sc_drives[unit] = tms;
     641:     }
     642:     else if (tms->Tflags & _INUSE)
     643:         return(EBUSY);
     644:     tms->Tflags |= _INUSE;
     645:
     646:     s = spl5();
     647:     if (sc->sc_state != S_RUN)
     648:         {
     649:         if (sc->sc_state == S_IDLE)
     650:             if  (!tkini(sc))
     651:                 {
     652:                 log(LOG_INFO, "tms%d init\n", ctlr);
     653:                 sc->sc_drives[unit] = NULL;
     654:                 tms->Tflags = 0;
     655:                 tms->tms_type = 0;
     656:                 (void) splx(s);
     657:                 return(ENXIO);
     658:                 }
     659:         /*
     660: 		 * Wait for initialization to complete
     661: 		 */
     662:         timeout(wakeup,(caddr_t)&sc->sc_ctab,11*hz);    /* to be sure*/
     663:         sleep((caddr_t)&sc->sc_ctab, PSWP+1);
     664:         if  (sc->sc_state != S_RUN)
     665:             {
     666:             sc->sc_drives[unit] = NULL;
     667:             tms->Tflags = 0;
     668:             tms->tms_type = 0;
     669:             (void) splx(s);
     670:             return(EIO);
     671:             }
     672:         }
     673:     (void) splx(s);
     674:
     675:     /*
     676: 	 * If drive is not online get a command packet, sleeping if no
     677: 	 * controller credits are available at the moment.  Then start
     678: 	 * the ONLINE process.
     679: 	 */
     680:     tmscpaddr = (struct tmscpdevice *) sc->sc_addr;
     681:     if  (!(tms->Tflags & _ONLINE))
     682:         {
     683:         s = spl5();
     684:         while   ((mp = tmscpgetcp(sc)) == 0)
     685:             {
     686:             tmscp_cp_wait++;
     687:             sleep((caddr_t)&tmscp_cp_wait,PSWP+1);
     688:             tmscp_cp_wait--;
     689:             }
     690:         (void) splx(s);
     691:         mapseg5(tmscp[sc->sc_unit], MAPBUFDESC);
     692:         mp->mscp_opcode = M_OP_ONLIN;
     693:         mp->mscp_unit = unit;       /* unit? */
     694:         tms_clrerr(tms, mp);
     695:     /* calculate this once instead of 4 times */
     696:         cmdref = (u_short)&tms->tms_type;
     697:         mp->mscp_cmdref = cmdref;   /* need to sleep on something */
     698:         ((Trl *)mp->mscp_dscptr)->hsh |= (TMSCP_OWN | TMSCP_INT);
     699:         normalseg5();
     700:         i = tmscpaddr->tmscpip;
     701:         /*
     702: 		 * To make sure we wake up, timeout in 240 seconds.
     703: 		 * Wakeup in tmscprsp routine.
     704: 		 * 240 seconds (4 minutes) is necessary since a rewind
     705: 		 * can take a few minutes.
     706: 		 */
     707:         timeout(wakeup,(caddr_t) cmdref,240 * hz);
     708:         sleep((caddr_t)cmdref,PSWP+1);
     709:         untimeout(wakeup, cmdref);
     710:         }
     711:     if  (!(tms->Tflags & _ONLINE))
     712:         {
     713: oops:       tms->Tflags = 0;
     714:         tms->tms_type = 0;
     715:         sc->sc_drives[unit] = NULL;
     716:         return(EIO);  /* Didn't go online */
     717:         }
     718: /*
     719:  * Get the unit characteristics (GTUNT).  This 1) Verifies the drive
     720:  * is really still online and 2) Retrieves information about the drive
     721:  * such as density choices, cache presence, etc.
     722: */
     723:     tms->tms_flags = 0;
     724:     if  (tmscpcache & ((1 << unit) << (4 * ctlr)))
     725:         tms->Tflags |= _CACHE_ON;
     726:     i = tms->Tflags & _CACHE_ON;
     727:     tms->Tflags = _ONLINE | _INUSE | i; /* Clear all other flags */
     728:     tmscpcommand(dev, TMS_SENSE, 1);
     729:     if  (!(tms->Tflags & _ONLINE))
     730:         goto oops;
     731:
     732: /*
     733:  * Next issue a reposition NOP by spacing forward 0 records.  This returns
     734:  * the current position (so we can tell if we're at BOT or not) and also
     735:  * clears any serious exceptions outstanding.
     736: */
     737:     tmscpcommand(dev, TMS_CSE, 1);
     738:
     739: /*
     740:  * Now go set the density - the lower level routines set the density if
     741:  * the drive is at BOT.
     742: */
     743:     tmscpcommand(dev, TMS_SETDENSITY, 1);
     744:     return(0);
     745: }
     746:
     747: /*
     748:  * Close tape device.
     749:  *
     750:  * If tape was open for writing or last operation was
     751:  * a write, then write two EOF's and backspace over the last one.
     752:  * Unless this is a non-rewinding special file, rewind the tape.
     753: */
     754: tmscpclose(dev, flag)
     755:     register dev_t dev;
     756:     register flag;
     757:     {
     758:     struct tmscp_softc *sc;
     759:     register struct tms_info *tms;
     760:     int unit = TMSUNIT(dev);
     761:
     762:     sc = &tmscp_softc[TMSCTLR(dev)];
     763:     tms = sc->sc_drives[unit];
     764:
     765:     if  ((tms->Tflags & _CACHE_ON) && (tms->Tflags & _CACHE_WRITTEN))
     766:         {
     767: /*
     768:  * A misbehaving application has closed the device without flushing
     769:  * the enabled cache by issuing a MTFLUSH - we'll do it for it.
     770: */
     771:         tmscpcommand(dev, TMS_FLUSH, 1);
     772:         if  (tms->tms_status != M_ST_SUCC)
     773:             {
     774: /*
     775:  * This is BAD news - the flush didn't work.  The drive is in a serious
     776:  * exception state, leave that alone for the non-rewind case so that further
     777:  * operations fail.  About all that can be done now is log the error.
     778: */
     779:             log(LOG_INFO, "tms%d,%d flsh\n", TMSCTLR(dev), unit);
     780:             tms->Tflags &= ~_CACHE_WRITTEN;
     781:             }
     782:         }
     783:     if  (tms->tms_flags & MTF_WRITTEN)
     784:         tms_wrteof(dev, tms);
     785:     tms->Tflags &= ~(_BUFMARK | _INUSE);
     786:     if  ((dev & T_NOREWIND) == 0)
     787:         {
     788:         tmscpcommand(dev, TMS_REW, 0);
     789:         tms->Tflags &= ~(_LOST | _CLSEREX | _SEREX);
     790:         }
     791:     return(0);
     792:     }
     793:
     794: /*
     795:  * Execute a command on the tape drive a specified number of times.
     796:  * This routine sets up a buffer and calls the strategy routine which
     797:  * links the buffer onto the drive's buffer queue.
     798:  * The start routine will take care of creating a tmscp command packet
     799:  * with the command.  The start routine is called by the strategy or the
     800:  * interrupt routine.
     801:  */
     802:
     803: tmscpcommand(dev, com, count)
     804:     register dev_t dev;
     805:     int com, count;
     806: {
     807:     register struct buf *bp;
     808:     register int s;
     809:     int unit = TMSUNIT(dev);
     810:
     811:     bp = &tmscp_softc[TMSCTLR(dev)].sc_cmdbuf;
     812:
     813:     s = spl5();
     814:     while   (bp->b_flags&B_BUSY)
     815:         {
     816:         bp->b_flags |= B_WANTED;
     817:         sleep((caddr_t)bp, PRIBIO);
     818:         }
     819:     bp->b_flags = B_BUSY|B_READ;
     820:     splx(s);
     821:     /*
     822: 	 * Load the buffer.  The b_count field gets used to hold the command
     823: 	 * count.  the b_resid field gets used to hold the command mneumonic.
     824: 	 * These 2 fields are "known" to be "safe" to use for this purpose.
     825: 	 * (Most other drivers also use these fields in this way.)
     826: 	 */
     827:     bp->b_dev = dev;
     828:     bp->b_bcount = count;
     829:     bp->b_resid = com;
     830:     bp->b_blkno = 0;
     831: /*
     832:  * Start the timer before entering the strategy routine.  If it declares
     833:  * an immediate error it will also perform an iodone which will cause us
     834:  * to fall thru and cancel the timer.
     835: */
     836:     timeout(tmswatchdog, bp, 240 * hz);
     837:     tmscpstrategy(bp);
     838:     iowait(bp);
     839:     untimeout(tmswatchdog, bp);
     840:     if  (bp->b_flags & B_WANTED)    /* Anyone waiting above? */
     841:         wakeup(bp);
     842:     bp->b_flags &= B_ERROR;     /* Clears B_BUSY */
     843: }
     844:
     845: /*
     846:  * If this routine is called then  (after 4 minutes) something is hung.
     847:  * Set the I/O done flag, set error to be ETIMEDOUT, and issue the wakeup.
     848: */
     849: tmswatchdog(bp)
     850:     struct  buf *bp;
     851:     {
     852:
     853:     bp->b_error = ETIMEDOUT;
     854:     biodone(bp);
     855:     }
     856:
     857: /*
     858:  * Init mscp communications area
     859:  */
     860: tmsginit(sc, com, msgs, offset, length, flags)
     861:     register struct tmscp_softc *sc;
     862:     register    Trl     *com;
     863:     register struct mscp        *msgs;
     864:     int             offset;
     865:     int             length;
     866:     int             flags;
     867: {
     868:     long                vaddr;
     869:
     870:     /*
     871: 	 * Figure out virtual address of message
     872: 	 * skip comm area and mscp messages header and previous messages
     873: 	 *
     874: 	 * N.B. Assumes SEG5 has been remapped to the comm area for this
     875: 	 * controller.
     876: 	 */
     877:     vaddr = _iomap(tmscp[sc->sc_unit]);
     878:     vaddr += sizeof(struct tmscpca)         /* skip comm area */
     879:         +sizeof(struct mscp_header);        /* m_cmdref disp */
     880:     vaddr += offset * sizeof(struct mscp);      /* skip previous */
     881:     while (length--) {
     882:         com->lsh = loint(vaddr);
     883:         com->hsh = flags | hiint(vaddr);
     884:         msgs->mscp_dscptr = (long *)com;
     885:         msgs->mscp_header.mscp_msglen = sizeof(struct mscp);
     886:         msgs->mscp_header.mscp_vcid = 1; /* tape VCID = 1 */
     887:         ++com; ++msgs; vaddr += sizeof(struct mscp);
     888:     }
     889: }
     890:
     891: /*
     892:  * Find an unused command packet
     893:  */
     894: struct mscp *
     895: tmscpgetcp(sc)
     896:     register struct tmscp_softc *sc;
     897: {
     898:     register struct mscp *mp = NULL;
     899:     register struct tmscpca *cp;
     900:     int i;
     901:     int s;
     902:     segm seg5;
     903:
     904:     s = spl5();
     905:     saveseg5(seg5);
     906:     mapseg5(tmscp[sc->sc_unit], MAPBUFDESC);
     907:     cp = &sc->sc_com->tmscp_ca;
     908:     /*
     909: 	 * If no credits, can't issue any commands
     910: 	 * until some outstanding commands complete.
     911: 	 */
     912:     i = sc->sc_lastcmd;
     913:     if  (((cp->ca_cmddsc[i].hsh&(TMSCP_OWN|TMSCP_INT))==TMSCP_INT) &&
     914:           (sc->sc_credits >= 2))
     915:         {
     916:         sc->sc_credits--;       /* This commits to issuing a command */
     917:         cp->ca_cmddsc[i].hsh &= ~TMSCP_INT;
     918:         mp = &sc->sc_com->tmscp_cmd[i];
     919:         mp->mscp_cmdref = 0;
     920:         mp->mscp_modifier = 0;
     921:         mp->mscp_flags = 0;
     922:         bzero(&mp->un, sizeof (mp->un));
     923:         sc->sc_lastcmd = (i + 1) % NCMD;
     924:         }
     925:     restorseg5(seg5);
     926:     (void) splx(s);
     927:     return(mp);
     928: }
     929:
     930: /*
     931:  * Initialize a TMSCP device.  Set up UBA mapping registers,
     932:  * initialize data structures, and start hardware
     933:  * initialization sequence.
     934:  */
     935: tkini(sc)
     936:     register struct tmscp_softc *sc;
     937: {
     938:     register struct tmscpdevice *tmscpaddr;
     939:     long adr;
     940:
     941:     sc->sc_ctab.b_active++;
     942:     adr = _iomap(tmscp[sc->sc_unit]) + (u_int)RINGBASE;
     943:     sc->sc_ctab.b_un.b_addr = (caddr_t)loint(adr);
     944:     sc->sc_ctab.b_xmem = hiint(adr);
     945:     tmscpaddr = sc->sc_addr;
     946:
     947:     /*
     948: 	 * Start the hardware initialization sequence.
     949: 	 */
     950:     tmscpaddr->tmscpip = 0;              /* start initialization */
     951:
     952:     while((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0)
     953:         {
     954:         if  (tmscpaddr->tmscpsa & TMSCP_ERR)
     955:             return(0);  /* CHECK */
     956:         }
     957:     tmscpaddr->tmscpsa=TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8)|TMSCP_IE|(sc->sc_ivec/4);
     958:     /*
     959: 	 * Initialization continues in the interrupt routine.
     960: 	 */
     961:     sc->sc_state = S_STEP1;
     962:     sc->sc_credits = 0;
     963:     return(1);
     964: }
     965:
     966: /*
     967:  * Start I/O operation
     968:  * This code is convoluted.  The majority of it was copied from the uda driver.
     969:  */
     970:
     971: tmsstart(sc)
     972:     register struct tmscp_softc *sc;
     973: {
     974:     register struct mscp *mp;
     975:     register struct buf *bp, *dp;
     976:     register struct tms_info *tms;
     977:     struct   tmscpdevice *tmscpaddr;
     978:     int i, unit;
     979:     segm seg5;
     980:
     981:      saveseg5(seg5);        /* save just once at top */
     982:      for(;;)
     983:     {
     984:     if  ((dp = sc->sc_ctab.b_actf) == NULL)
     985:         {
     986:         /* (drive was inactive) */
     987:         sc->sc_ctab.b_active = 0;
     988:         break;
     989:         }
     990:     if  ((bp = dp->b_actf) == NULL)
     991:         {
     992:         /*
     993: 		 * No more requests for this drive, remove
     994: 		 * from controller queue and look at next drive.
     995: 		 * We know we're at the head of the controller queue.
     996: 		 */
     997:         dp->b_active = 0;
     998:         sc->sc_ctab.b_actf = dp->b_forw;
     999:         continue;
    1000:         }
    1001:     sc->sc_ctab.b_active++;
    1002:     unit = TMSUNIT(bp->b_dev);
    1003:     tmscpaddr = (struct tmscpdevice *)sc->sc_addr;
    1004:     tms = sc->sc_drives[unit];
    1005:     if  ((tmscpaddr->tmscpsa&TMSCP_ERR) || sc->sc_state != S_RUN)
    1006:         {
    1007:         log(LOG_INFO, "tms%d,%d: sa %x st %d\n", sc->sc_unit,
    1008:             unit, tmscpaddr->tmscpsa, sc->sc_state);
    1009:         (void)tkini(sc);
    1010:         /* SHOULD REQUEUE OUTSTANDING REQUESTS, LIKE TMSCPRESET */
    1011:         break;
    1012:         }
    1013:
    1014:     if  (!(tms->Tflags & _ONLINE))
    1015:         {
    1016:         if  ((mp = tmscpgetcp(sc)) == NULL)
    1017:             break;
    1018:         mapseg5(tmscp[sc->sc_unit], MAPBUFDESC);
    1019:         mp->mscp_opcode = M_OP_ONLIN;
    1020:         mp->mscp_unit = unit;
    1021:         tms_clrerr(tms, mp);
    1022:         dp->b_active = 2;
    1023:         sc->sc_ctab.b_actf = dp->b_forw; /* remove from controller q */
    1024:         ((Trl *)mp->mscp_dscptr)->hsh |= (TMSCP_OWN|TMSCP_INT);
    1025:         if  (tmscpaddr->tmscpsa&TMSCP_ERR)
    1026:             log(LOG_INFO, tmscpfatalerr, sc->sc_unit,
    1027:                     TMSUNIT(bp->b_dev), tmscpaddr->tmscpsa);
    1028:         restorseg5(seg5);
    1029:         i = tmscpaddr->tmscpip;
    1030:         continue;
    1031:         }
    1032:     if  ((mp = tmscpgetcp(sc)) == NULL)
    1033:         break;
    1034:     mapseg5(tmscp[sc->sc_unit], MAPBUFDESC);
    1035:     mp->mscp_cmdref = (u_short)bp;      /* pointer to get back */
    1036:     mp->mscp_unit = unit;
    1037:     /*
    1038: 	 * If its an ioctl-type command then set up the appropriate
    1039: 	 * tmscp command;  by doing a switch on the "b_resid" field where
    1040: 	 * the command mneumonic is stored.
    1041: 	 */
    1042:     if  (bp == &sc->sc_cmdbuf)
    1043:         {
    1044:         /*
    1045: 		 * The reccnt and tmkcnt fields are set to zero by the getcp
    1046: 		 * routine (as bytecnt and buffer fields).  Thus reccnt and
    1047: 		 * tmkcnt are only modified here if they need to be set to
    1048: 		 * a non-zero value.
    1049: 		 */
    1050:         switch ((int)bp->b_resid) {
    1051:
    1052:         case TMS_WRITM:
    1053:             tms_wtm_st(mp, sc, 0);
    1054:             break;
    1055:         case TMS_FSF:
    1056:             tms_repos_st(mp, sc, 0);
    1057:             break;
    1058:         case TMS_BSF:
    1059:             tms_repos_st(mp, sc, M_MD_REVRS);
    1060:             break;
    1061:         case TMS_FSR:
    1062:             tms_reposrec_st(mp, sc, M_MD_OBJCT);
    1063:             break;
    1064:         case TMS_BSR:
    1065:             tms_reposrec_st(mp, sc, M_MD_OBJCT | M_MD_REVRS);
    1066:             break;
    1067:         case TMS_REW:
    1068:             if  (bp->b_bcount)
    1069:                 i = M_MD_REWND;
    1070:             else
    1071:                 i = M_MD_REWND | M_MD_IMMED;
    1072:             bp->b_bcount = 0;   /* XXX */
    1073:             tms_repos_st(mp, sc, i);
    1074:             break;
    1075:         case TMS_OFFL:
    1076:             tms_avail_st(mp, sc, M_MD_UNLOD);
    1077:             break;
    1078:         case TMS_SENSE:
    1079:             mp->mscp_opcode = M_OP_GTUNT;
    1080:             break;
    1081:         case TMS_FLUSH:
    1082:             mp->mscp_opcode = M_OP_FLUSH;
    1083:             break;
    1084:         case TMS_CACHE:
    1085:             tms->tms_unitflgs |= M_UF_WBKNV;
    1086:             tms->tms_unitflgs &= ~M_UF_SCCHH;
    1087:             tms->Tflags |= _CACHE_ON;
    1088:             tms_stunt_st(mp, sc, 0);
    1089:             break;
    1090:         case TMS_NOCACHE:
    1091:             tms->tms_unitflgs &= ~M_UF_WBKNV;
    1092:             tms->tms_unitflgs |= M_UF_SCCHH;
    1093:             tms->Tflags &= ~_CACHE_ON;
    1094:             tms_stunt_st(mp, sc, 0);
    1095:             break;
    1096:         case TMS_CSE:
    1097:             bp->b_bcount = 0;   /* 0 objects to skip */
    1098:             tms_repos_st(mp, sc, M_MD_OBJCT);
    1099:             break;
    1100:         case TMS_SETDENSITY:
    1101:             tms->tms_format &= ~M_TF_MASK;
    1102:             tms->tms_format |= Dmatrix[TMSDENS(bp->b_dev)][tms->tms_fmtmenu & FMTMASK];
    1103:             tms_stunt_st(mp, sc, 0);
    1104:             break;
    1105:         default:
    1106:             log(LOG_INFO, "ioctl %x\n", bp->b_resid);
    1107:             /* Need a no-op. Reposition no amount */
    1108:             mp->mscp_opcode = M_OP_REPOS;
    1109:             break;
    1110:         }   /* end switch (bp->b_resid) */
    1111:         }
    1112:     else    /* Its a read/write command (not an ioctl) */
    1113:         {
    1114:         mp->mscp_opcode = bp->b_flags&B_READ ? M_OP_READ : M_OP_WRITE;
    1115:         mp->mscp_bytecnt = bp->b_bcount;
    1116:         mp->mscp_buffer_l = (u_short) bp->b_un.b_addr;
    1117:         mp->mscp_buffer_h = bp->b_xmem;
    1118:         }
    1119:
    1120:     if  ((tms->Tflags & _CACHE_ON) && (mp->mscp_opcode == M_OP_WRITE))
    1121:         tms->Tflags |= _CACHE_WRITTEN;
    1122:     if  ((tms->Tflags & _BUFMARK) && (mp->mscp_opcode == M_OP_READ) &&
    1123:          (tms->Tflags & _CLSEREX))
    1124:         {
    1125:         tms->Tflags &= ~(_BUFMARK | _CLSEREX);
    1126:         mp->mscp_modifier |= M_MD_CLSEX;
    1127:         }
    1128:
    1129:     if  (tmscpprintf & 0x8)
    1130:         {
    1131:         log(LOG_INFO, "tms%d,%d -> op %x fl %x mod %x\n",
    1132:             sc->sc_unit, mp->mscp_unit,
    1133:             mp->mscp_opcode, mp->mscp_flags, mp->mscp_modifier);
    1134:         }
    1135:
    1136:     ((Trl *)mp->mscp_dscptr)->hsh |= (TMSCP_OWN|TMSCP_INT);
    1137:     i = tmscpaddr->tmscpip;              /* initiate polling */
    1138:     dp->b_qsize++;
    1139:     /*
    1140: 	 * Move drive to the end of the controller queue
    1141: 	 */
    1142:     if (dp->b_forw != NULL)
    1143:         {
    1144:         sc->sc_ctab.b_actf = dp->b_forw;
    1145:         sc->sc_ctab.b_actl->b_forw = dp;
    1146:         sc->sc_ctab.b_actl = dp;
    1147:         dp->b_forw = NULL;
    1148:         }
    1149:     /*
    1150: 	 * Move buffer to I/O wait queue
    1151: 	 */
    1152:     dp->b_actf = bp->av_forw;
    1153:     dp = &sc->sc_wtab;
    1154:     bp->av_forw = dp;
    1155:     bp->av_back = dp->av_back;
    1156:     dp->av_back->av_forw = bp;
    1157:     dp->av_back = bp;
    1158:     if (tmscpaddr->tmscpsa&TMSCP_ERR)
    1159:         {
    1160:         log(LOG_INFO, tmscpfatalerr,sc->sc_unit,
    1161:             mp->mscp_unit, tmscpaddr->tmscpsa);
    1162:         (void)tkini(sc);
    1163:         break;
    1164:         }
    1165:     }   /* end for */
    1166:     /*
    1167:      * Check for response ring transitions lost in the
    1168:      * Race condition.  Map SEG5 in case we escaped early from the for().
    1169:      */
    1170:     mapseg5(tmscp[sc->sc_unit], MAPBUFDESC);
    1171:     for (i = sc->sc_lastrsp;; i++)
    1172:         {
    1173:         i %= NRSP;
    1174:         if (sc->sc_com->tmscp_ca.ca_rspdsc[i].hsh&TMSCP_OWN)
    1175:             break;
    1176:         tmscprsp(sc, i);
    1177:         sc->sc_com->tmscp_ca.ca_rspdsc[i].hsh |= TMSCP_OWN;
    1178:         }
    1179:     sc->sc_lastrsp = i;
    1180:     restorseg5(seg5);
    1181: }
    1182:
    1183:
    1184: /*
    1185:  * Process a response packet.  N.B.  Assumes SEG5 maps comm area for controller
    1186:  */
    1187: tmscprsp(sc, i)
    1188:     register struct tmscp_softc *sc;
    1189:     int i;
    1190: {
    1191:     register struct mscp *mp;
    1192:     register struct tms_info *tms;
    1193:     struct buf *dp, *bp;
    1194:     int em_status, em_endcode;
    1195:
    1196:     mp = &sc->sc_com->tmscp_rsp[i];
    1197:     mp->mscp_header.mscp_msglen = sizeof (struct mscp);
    1198:     sc->sc_credits += mp->mscp_header.mscp_credits & 0xf;  /* low 4 bits */
    1199:     if  ((mp->mscp_header.mscp_credits & 0xf0) > 0x10)  /* Check */
    1200:         return;
    1201:
    1202:     /*
    1203: 	 * If it's an error log message (datagram),
    1204: 	 * pass it on for more extensive processing.
    1205: 	 */
    1206:     if  ((mp->mscp_header.mscp_credits & 0xf0) == 0x10)
    1207:         {
    1208:         tmserror(sc->sc_unit, (struct mslg *)mp);
    1209:         return;
    1210:         }
    1211:
    1212:     if  (tmscpprintf & 0x4)
    1213:         log(LOG_INFO, "tms%d,%d: op %x st %x\n", sc->sc_unit,
    1214:             mp->mscp_unit,mp->mscp_opcode,
    1215:             mp->mscp_status & M_ST_MASK);
    1216:
    1217:     em_status = mp->mscp_status&M_ST_MASK;
    1218:     em_endcode = mp->mscp_endcode & ~M_OP_END;
    1219:     /*
    1220: 	 * The controller interrupts as any drive.
    1221: 	 * This means that you must check for controller interrupts
    1222: 	 * before drive responses.
    1223: 	 */
    1224:     if  (em_endcode == M_OP_STCON)
    1225:         {
    1226:         if  (em_status == M_ST_SUCC)
    1227:             sc->sc_state = S_RUN;
    1228:         else
    1229:             sc->sc_state = S_IDLE;
    1230:         sc->sc_ctab.b_active = 0;
    1231:         wakeup((caddr_t)&sc->sc_ctab);
    1232:         return;
    1233:         }
    1234:     if  (mp->mscp_unit >= 4)
    1235:         return;
    1236:     tms = sc->sc_drives[mp->mscp_unit];
    1237:     if  (!tms)      /* unopened unit coming online - ignore it */
    1238:         return;
    1239:     dp = &tms->tms_dtab;
    1240:
    1241:     switch (em_endcode) {
    1242:     case    M_OP_ONLIN:
    1243:         if  (em_status == M_ST_SUCC || em_status == M_ST_WRTPR)
    1244:             {
    1245:             tms->Tflags |= _ONLINE;
    1246:             tms->Tflags &= ~_CACHE_WRITTEN;
    1247: /*
    1248:  * Normally this is done in the 'tms_check_ret' routine.  The ONLIN case is
    1249:  * special (well, ok - weird) in that it was never put on the I/O wait queue.
    1250:  * Thus we need to do this here.
    1251: */
    1252:             tms->tms_endcode = em_endcode;
    1253:             tms->tms_status = em_status;
    1254:             tms->tms_type = mp->mscp_mediaid;
    1255:             tms->tms_unitflgs = mp->mscp_unitflgs;
    1256:             tms->tms_format = mp->mscp_format;
    1257:             /*
    1258: 			 * Link the drive onto the controller queue
    1259: 			 */
    1260:             dp->b_forw = NULL;
    1261:             if  (sc->sc_ctab.b_actf == NULL)
    1262:                 sc->sc_ctab.b_actf = dp;
    1263:             else
    1264:                 sc->sc_ctab.b_actl->b_forw = dp;
    1265:             sc->sc_ctab.b_actl = dp;
    1266:             dp->b_active = 1;
    1267:             }
    1268:         else
    1269:             {
    1270:             while   (bp = dp->b_actf)
    1271:                 {
    1272:                 dp->b_actf = bp->av_forw;
    1273:                 bp->b_flags |= B_ERROR;
    1274:                 iodone(bp);
    1275:                 }
    1276:             }
    1277:         if  (mp->mscp_cmdref)
    1278:             wakeup((caddr_t)mp->mscp_cmdref);
    1279:         return;
    1280:     /*
    1281: 	 * The AVAILABLE ATTENTION message occurs when the
    1282: 	 * unit becomes available after loading.
    1283: 	 * Marking the unit offline will force an
    1284: 	 * online command prior to using the unit.
    1285: 	 */
    1286:     case    M_OP_AVATN:
    1287:         tms->Tflags &= ~_ONLINE;
    1288:         return;
    1289: /*
    1290:  * An endcode with no opcode (0x80) is an invalid command.  This is supposed
    1291:  * to indicate a protocol error (illegal opcode, parameter error, etc) but
    1292:  * without the real opcode we don't know which command (reposition, write,
    1293:  * read, ...) failed.  So, just declare I/O done and hope for the best.
    1294: */
    1295:     case    0:
    1296:         if  (tmscpprintf & 0x8)
    1297:             log(LOG_INFO, "tms%d,%d: inv end=%x st=%x\n",
    1298:                 sc->sc_unit,mp->mscp_unit,em_endcode,em_status);
    1299:         tms_iodone(mp, sc);
    1300:         return;
    1301:     case    M_OP_WRITE:
    1302:     case    M_OP_READ:
    1303:         tms_rw_em(mp, sc);
    1304:         return;
    1305:     case    M_OP_WRITM:
    1306:         tms_wtm_em(mp, sc);
    1307:         return;
    1308:     case    M_OP_REPOS:
    1309:         tms_repos_em(mp, sc);
    1310:         return;
    1311:     case    M_OP_STUNT:
    1312:         tms_stunt_em(mp, sc);
    1313:         return;
    1314:     case    M_OP_AVAIL:
    1315:         tms_avail_em(mp, sc);
    1316:         return;
    1317:     case    M_OP_GTUNT:
    1318:         tms_gtunt_em(mp, sc);
    1319:         return;
    1320:     case    M_OP_FLUSH:
    1321:         tms_flush_em(mp, sc);
    1322:         return;
    1323:     default:
    1324:         if  (tmscpprintf & 0x8)
    1325:             log(LOG_INFO, "tms%d,%d rsp %x\n", sc->sc_unit,
    1326:                 mp->mscp_unit, em_endcode);
    1327:         return;
    1328:     }   /* end switch mp->mscp_opcode */
    1329: }
    1330:
    1331: /*
    1332:  * Manage buffers and perform block mode read and write operations.
    1333:  */
    1334:
    1335: tmscpstrategy (bp)
    1336:     register struct buf *bp;
    1337:     {
    1338:     register struct buf *dp;
    1339:     register struct tmscp_softc *sc;
    1340:     struct  tms_info *tms;
    1341:     int ctlr = TMSCTLR(bp->b_dev);
    1342:     int s;
    1343:
    1344:     sc = &tmscp_softc[ctlr];
    1345:     tms = sc->sc_drives[TMSUNIT(bp->b_dev)];
    1346:     if  (!tms || !(tms->Tflags & _ONLINE))
    1347:         {
    1348:         bp->b_flags |= B_ERROR;
    1349:         iodone(bp);
    1350:         return;
    1351:         }
    1352: /*
    1353:  * If we're at the end of the tape and this is not an 'ioctl' command
    1354:  * then return an error rather than reading or writing off the end of the tape.
    1355:  * Ioctl commands are allowed to proceed so that tapemarks can be written and
    1356:  * repositioning (rewind, etc) can be done.
    1357: */
    1358:     if  ((tms->tms_flags & MTF_EOM) && bp != &sc->sc_cmdbuf)
    1359:         {
    1360:         bp->b_resid = bp->b_bcount;
    1361:         bp->b_error = ENOSPC;
    1362:         bp->b_flags |= B_ERROR;
    1363:         iodone(bp);
    1364:         return;
    1365:         }
    1366:     mapalloc(bp);
    1367:     s = spl5();
    1368:     /*
    1369: 	 * Link the buffer onto the drive queue
    1370: 	 */
    1371:     dp = &tms->tms_dtab;
    1372:     if (dp->b_actf == 0)
    1373:         dp->b_actf = bp;
    1374:     else
    1375:         dp->b_actl->av_forw = bp;
    1376:     dp->b_actl = bp;
    1377:     bp->av_forw = 0;
    1378:     /*
    1379: 	 * Link the drive onto the controller queue
    1380: 	 */
    1381:     if (dp->b_active == 0)
    1382:         {
    1383:         dp->b_forw = NULL;
    1384:         if (sc->sc_ctab.b_actf == NULL)
    1385:             sc->sc_ctab.b_actf = dp;
    1386:         else
    1387:             sc->sc_ctab.b_actl->b_forw = dp;
    1388:         sc->sc_ctab.b_actl = dp;
    1389:         dp->b_active = 1;
    1390:         }
    1391:     /*
    1392: 	 * If the controller is not active, start it.
    1393: 	 */
    1394:     if  (sc->sc_ctab.b_active == 0)
    1395:         (void) tmsstart(sc);
    1396:     splx(s);
    1397:     return;
    1398:     }
    1399:
    1400: /* ARGSUSED */
    1401: tmscpioctl(dev, cmd, data, flag)
    1402:     dev_t dev;
    1403:     int cmd;
    1404:     caddr_t data;
    1405:     int flag;
    1406: {
    1407:     struct tmscp_softc *sc = &tmscp_softc[TMSCTLR(dev)];
    1408:     struct buf *bp = &sc->sc_cmdbuf;
    1409:     register struct tms_info *tms = sc->sc_drives[TMSUNIT(dev)];
    1410:     int fcount;     /* number of files (or records) to space */
    1411:     register struct mtop *mtop; /* mag tape cmd op to perform */
    1412:     register struct mtget *mtget;   /* mag tape struct to get info in */
    1413:
    1414:     /* we depend of the values and order of the TMS ioctl codes here */
    1415:     static char tmsops[] =
    1416:      {TMS_WRITM,TMS_FSF,TMS_BSF,TMS_FSR,TMS_BSR,TMS_REW,TMS_OFFL,TMS_SENSE,
    1417:       TMS_CACHE,TMS_NOCACHE,TMS_FLUSH};
    1418:
    1419:     if  (!tms)
    1420:         return(ENXIO);
    1421:     if  (cmd != MTIOCGET)
    1422:         tms->tms_status = ~M_ST_SUCC;
    1423:     if  (tms->tms_position == 0)
    1424:         tms->tms_flags |= MTF_BOM;
    1425:     else
    1426:         tms->tms_flags &= ~MTF_BOM;
    1427:
    1428:     switch (cmd) {
    1429:     case    MTIOCTOP:
    1430:         mtop = (struct mtop *)data;
    1431:         switch (mtop->mt_op) {
    1432:
    1433:         case    MTWEOF:
    1434:             return(tms_wrteof(dev, tms));
    1435:         case    MTFSF:
    1436:         case    MTBSF:
    1437:         case    MTFSR:
    1438:         case    MTBSR:
    1439:             fcount = mtop->mt_count;
    1440:             break;
    1441:         case    MTFLUSH:
    1442:         case    MTCACHE:
    1443:         case    MTNOCACHE:
    1444:             if  ((tms->Tflags & (_HASCACHE|_ONLINE)) !=
    1445:                  (_HASCACHE|_ONLINE))
    1446:                 return(0);
    1447:         case    MTREW:
    1448:         case    MTOFFL:
    1449:         case    MTNOP:
    1450:             fcount = 1;
    1451:             break;
    1452:         default:
    1453:             return(ENXIO);
    1454:         }   /* end switch mtop->mt_op */
    1455:
    1456:         if  (fcount <= 0)
    1457:             return(EINVAL);
    1458:         tmscpcommand(dev, tmsops[mtop->mt_op], fcount);
    1459:         if  (tms->tms_status != M_ST_SUCC)
    1460:             {
    1461:             if  (tms->Tflags & _CLSEREX)
    1462:                 tmscpcommand(dev, TMS_CSE, 1);
    1463:             return(EIO);
    1464:             }
    1465:         return(geterror(bp));
    1466:
    1467:     case    MTIOCGET:
    1468:         /*
    1469: 		 * Return status info associated with the particular UNIT.
    1470: 		 */
    1471:         mtget = (struct mtget *)data;
    1472:         mtget->mt_type = MT_ISTMSCP;
    1473:         mtget->mt_dsreg = tms->tms_flags << 8;
    1474:         mtget->mt_dsreg |= tms->tms_endcode;
    1475:         mtget->mt_erreg = tms->tms_status;
    1476:         mtget->mt_resid = tms->tms_resid;
    1477:         break;
    1478:     default:
    1479:         return(ENXIO);
    1480:     }
    1481:     return (0);
    1482: }
    1483:
    1484: tms_wrteof(dev, tms)
    1485:     dev_t   dev;
    1486:     register struct tms_info *tms;
    1487:     {
    1488:
    1489:     tmscpcommand(dev, TMS_WRITM, 1);
    1490:     if  (tms->tms_status != M_ST_SUCC)
    1491:         return(EIO);
    1492:     tms->tms_status = ~M_ST_SUCC;
    1493:     tmscpcommand(dev, TMS_WRITM, 1);
    1494:     if  (tms->tms_status != M_ST_SUCC)
    1495:         return(EIO);
    1496:     tms->Tflags &= ~_CACHE_WRITTEN;
    1497:     tms->tms_status = ~M_ST_SUCC;
    1498:     tmscpcommand(dev, TMS_BSR, 1);
    1499:     if  (tms->tms_status != M_ST_SUCC)
    1500:         return(EIO);
    1501:     return(0);
    1502:     }
    1503:
    1504: /*
    1505:  * Initialize the mscp packet for a STUNT command.  If the drive is in a
    1506:  * 'cache lost' but 'written' state then clear it and log the error.
    1507: */
    1508:
    1509: tms_stunt_st(mp, sc, flgs)
    1510:     register struct mscp    *mp;
    1511:     register struct tmscp_softc *sc;
    1512:     int flgs;
    1513:     {
    1514:     register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
    1515:
    1516:     mp->mscp_opcode = M_OP_STUNT;
    1517:     mp->mscp_modifier = flgs | M_MD_EXCAC;
    1518:     tms_cache_cmn(sc, tms, mp);
    1519:
    1520: /*
    1521:  * Set the unit flags - this includes the cache enable/disable flags.
    1522: */
    1523:
    1524:     mp->mscp_unitflgs = tms->tms_unitflgs;
    1525:
    1526: /*
    1527:  * Only initialize the density if the position is not at BOT.  On some
    1528:  * drives (notably the TU81) selecting a density other than the 'current'
    1529:  * (0) causes an illegal command error.
    1530: */
    1531:     if  (tms->tms_position != 0)
    1532:         mp->mscp_format = 0;
    1533:     else
    1534:         mp->mscp_format = tms->tms_format;
    1535:     }
    1536:
    1537: /*
    1538:  * Initialize the mscp packet for a REPOS command.  The 'flgs' parameter
    1539:  * specifies if the movement if forwards or backwards and if records or
    1540:  * tape marks (objects) are to be skipped.
    1541: */
    1542:
    1543: tms_repos_st(mp, sc, flgs)
    1544:     register struct mscp    *mp;
    1545:     register struct tmscp_softc *sc;
    1546:     int flgs;
    1547:     {
    1548:     struct  buf *bp = (struct buf *)mp->mscp_cmdref;
    1549:     register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
    1550:
    1551:     mp->mscp_opcode = M_OP_REPOS;
    1552:     mp->mscp_modifier = flgs | M_MD_CLSEX;
    1553:     tms->Tflags &= ~_CLSEREX;
    1554:     tms_cache_cmn(sc, tms, mp); /* shared code with tms_reposrec_st */
    1555:     if  (mp->mscp_modifier & M_MD_OBJCT)
    1556:         mp->mscp_reccnt = bp->b_bcount;
    1557:     else
    1558:         mp->mscp_tmkcnt = bp->b_bcount;
    1559:     }
    1560:
    1561: /*
    1562:  * Initialize the mscp packet for a REPOS 'record' command.  Tape records do
    1563:  * not include tapemarks (which is why this is a separate routine from
    1564:  * tms_repos_st above).
    1565: */
    1566:
    1567: tms_reposrec_st(mp, sc, flgs)
    1568:     register struct mscp    *mp;
    1569:     register struct tmscp_softc *sc;
    1570:     int flgs;
    1571:     {
    1572:     struct  buf *bp = (struct buf *)mp->mscp_cmdref;
    1573:     register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
    1574:
    1575:     mp->mscp_opcode = M_OP_REPOS;
    1576:     mp->mscp_modifier = flgs;
    1577:     tms_cache_cmn(sc, tms, mp);
    1578:     mp->mscp_reccnt = bp->b_bcount;
    1579:     }
    1580:
    1581: /*
    1582:  * Initialize the mscp packet for an AVAIL command.  The only time this is
    1583:  * done is on a 'rewoffl' command.
    1584: */
    1585:
    1586: tms_avail_st(mp, sc, flgs)
    1587:     register struct mscp    *mp;
    1588:     struct  tmscp_softc *sc;
    1589:     int flgs;
    1590:     {
    1591:     register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
    1592:
    1593:     mp->mscp_opcode = M_OP_AVAIL;
    1594:     mp->mscp_modifier = flgs;
    1595:     tms_clrerr(tms, mp);
    1596:     }
    1597:
    1598: tms_clrerr(tms, mp)
    1599:     register struct tms_info *tms;
    1600:     register struct mscp *mp;
    1601:     {
    1602:
    1603:     mp->mscp_modifier |= M_MD_CLSEX;
    1604:     tms->Tflags &= ~_CLSEREX;
    1605:     if  (tms->Tflags & _CACHE_LOST)
    1606:         {
    1607:         tms->Tflags &= ~(_CACHE_LOST | _CACHE_WRITTEN);
    1608:         mp->mscp_modifier |= M_MD_CDATL;
    1609:         }
    1610:     }
    1611:
    1612: /*
    1613:  * Initialize the mscp packet for a WTM (write tapemark) command.
    1614: */
    1615:
    1616: tms_wtm_st(mp, sc, flgs)
    1617:     register struct mscp    *mp;
    1618:     register struct tmscp_softc *sc;
    1619:     int flgs;
    1620:     {
    1621:     register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
    1622:
    1623:     mp->mscp_opcode = M_OP_WRITM;
    1624:     mp->mscp_modifier = flgs | M_MD_CLSEX;
    1625:     tms->Tflags &= ~_CLSEREX;
    1626:     tms_cache_cmn(sc, tms, mp);
    1627:     }
    1628:
    1629: tms_cache_cmn(sc, tms, mp)
    1630:     register struct tmscp_softc *sc;
    1631:     register struct tms_info *tms;
    1632:     register struct mscp *mp;
    1633:     {
    1634:
    1635:     if  (tms->Tflags & _CACHE_LOST)
    1636:         {
    1637:         if  (!(tms->Tflags & _CACHE_WRITTEN))
    1638:             {
    1639:             tms->Tflags &= ~(_CACHE_LOST | _CACHE_WRITTEN);
    1640:             mp->mscp_modifier |= M_MD_CDATL;
    1641:             }
    1642:         else
    1643:             log(LOG_INFO, "tms%d,%d clost\n",
    1644:                 sc->sc_unit, mp->mscp_unit);
    1645:         }
    1646:     }
    1647:
    1648: /*
    1649:  * Process the end message from a REPOS command.  Called from tmscprsp().
    1650: */
    1651:
    1652: tms_repos_em(mp, sc)
    1653:     register struct mscp *mp;
    1654:     register struct tmscp_softc *sc;
    1655:     {
    1656:     register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
    1657:     u_short em_status = mp->mscp_status & M_ST_MASK;
    1658:
    1659:     (void)tms_check_ret(mp, sc);
    1660:     if  (em_status == M_ST_SUCC)
    1661:         {
    1662:         if  (tms->tms_position != mp->mscp_position)
    1663:             tms->tms_flags &= ~MTF_WRITTEN;
    1664:         if  (tms->tms_position = mp->mscp_position)
    1665:             tms->tms_flags &= ~MTF_BOM;
    1666:         else
    1667:             {
    1668:             tms->tms_flags |= MTF_BOM;
    1669:             tms->Tflags &= ~_LOST;
    1670:             }
    1671:         tms->Tflags &= ~_CACHE_WRITTEN;
    1672:         }
    1673:     tms->tms_resid = 0;
    1674:     tms_iodone(mp, sc);
    1675:     }
    1676:
    1677: /*
    1678:  * Process the end message from a STUNT command.
    1679: */
    1680:
    1681: tms_stunt_em(mp, sc)
    1682:     register struct mscp *mp;
    1683:     register struct tmscp_softc *sc;
    1684:     {
    1685:     register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
    1686:     u_short em_status = mp->mscp_status & M_ST_MASK;
    1687:
    1688:     (void)tms_check_ret(mp, sc);
    1689:     tms->Tflags &= ~_CACHE_WRITTEN;
    1690:     if  (em_status == M_ST_SUCC)
    1691:         {
    1692:         tms->tms_unitflgs = mp->mscp_unitflgs;
    1693:         tms->tms_format = mp->mscp_format;
    1694:         tms->tms_type = mp->mscp_mediaid;
    1695:         tms->Tflags |= _ONLINE;
    1696:         }
    1697:     tms->tms_resid = 0;
    1698:     tms_iodone(mp, sc);
    1699:     }
    1700:
    1701: /*
    1702:  * Process the end message from a WRITM (Write Tape Mark) command.
    1703: */
    1704:
    1705: tms_wtm_em(mp, sc)
    1706:     register struct mscp *mp;
    1707:     register struct tmscp_softc *sc;
    1708:     {
    1709:     register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
    1710:     u_short em_status = mp->mscp_status & M_ST_MASK;
    1711:
    1712:     if  (em_status == M_ST_SUCC)
    1713:         {
    1714:         tms->tms_flags &= ~MTF_WRITTEN;
    1715:         tms->tms_position = mp->mscp_position;
    1716:         }
    1717:     (void)tms_check_ret(mp, sc);
    1718:     tms->tms_resid = 0;
    1719:     tms_iodone(mp, sc);
    1720:     }
    1721:
    1722: tms_avail_em(mp, sc)
    1723:     register struct mscp *mp;
    1724:     register struct tmscp_softc *sc;
    1725:     {
    1726:     register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
    1727:
    1728:     (void)tms_check_ret(mp, sc);
    1729:     tms->Tflags &= ~(_INUSE | _ONLINE);
    1730:     tms->tms_position = 0;
    1731:     tms->tms_flags |= MTF_BOM;
    1732:     if  (tms->tms_status == M_ST_SUCC)
    1733:         tms->Tflags &= ~_CACHE_WRITTEN;
    1734:     tms->tms_resid = 0;
    1735:     tms_iodone(mp, sc);
    1736:     }
    1737:
    1738: tms_flush_em(mp, sc)
    1739:     register struct mscp *mp;
    1740:     register struct tmscp_softc *sc;
    1741:     {
    1742:     register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
    1743:     u_short em_status = mp->mscp_status & M_ST_MASK;
    1744:
    1745:     if  (em_status == M_ST_SUCC)
    1746:         tms->Tflags &= ~_CACHE_WRITTEN;
    1747:     else
    1748:         log(LOG_INFO, "tms%d,%d Flush\n",sc->sc_unit,mp->mscp_unit);
    1749:     tms->tms_position = mp->mscp_position;
    1750:     (void)tms_check_ret(mp, sc);
    1751:     tms->tms_resid = 0;
    1752:     tms_iodone(mp, sc);
    1753:     }
    1754:
    1755: tms_gtunt_em(mp, sc)
    1756:     register struct mscp *mp;
    1757:     register struct tmscp_softc *sc;
    1758:     {
    1759:     register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
    1760:     u_short em_status = mp->mscp_status & M_ST_MASK;
    1761:     u_short em_flags = mp->mscp_unitflgs;
    1762:
    1763:     (void)tms_check_ret(mp, sc);
    1764:     if  (em_status == M_ST_SUCC)
    1765:         {
    1766:         tms->tms_format = mp->mscp_format;
    1767:         tms->tms_type = mp->mscp_mediaid;
    1768:         tms->tms_fmtmenu = mp->mscp_fmtmenu;
    1769:         tms->tms_unitflgs = mp->mscp_unitflgs;
    1770:         tms->Tflags |= _ONLINE;
    1771:         if  (em_flags & (M_UF_WRTPH | M_UF_WRTPS | M_UF_WRTPD))
    1772:             tms->tms_flags |= MTF_WRTLCK;
    1773:         else
    1774:             tms->tms_flags &= ~MTF_WRTLCK;
    1775:         if  (em_flags & M_UF_CACH)
    1776:             {
    1777:             tms->Tflags |= _HASCACHE;
    1778:             if  (tms->Tflags & _CACHE_ON)
    1779:                 {
    1780:                 tms->tms_unitflgs |= M_UF_WBKNV;
    1781:                 tms->tms_unitflgs &= ~M_UF_SCCHH;
    1782:                 }
    1783:             else
    1784:                 {
    1785:                 tms->tms_unitflgs &= ~M_UF_WBKNV;
    1786:                 tms->tms_unitflgs |= M_UF_SCCHH;
    1787:                 }
    1788:             }
    1789:         if  (tms->tms_position == 0)
    1790:             tms->tms_flags |= MTF_BOM;
    1791:         else
    1792:             tms->tms_flags &= ~MTF_BOM;
    1793:         }
    1794:     tms->tms_resid = 0;
    1795:     tms_iodone(mp, sc);
    1796:     }
    1797:
    1798: tms_rw_em(mp, sc)
    1799:     register struct mscp *mp;
    1800:     register struct tmscp_softc *sc;
    1801:     {
    1802:     struct  buf *bp = (struct buf *)mp->mscp_cmdref;
    1803:     register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
    1804:     u_short em_status = mp->mscp_status & M_ST_MASK;
    1805:
    1806:     tms->tms_flags &= ~MTF_WRITTEN;
    1807:     (void)tms_check_ret(mp, sc);
    1808:     if  (em_status == M_ST_SUCC)
    1809:         {
    1810:         if  ((tms->tms_endcode & ~M_OP_END) == M_OP_WRITE)
    1811:             tms->tms_flags |= MTF_WRITTEN;
    1812:         else
    1813:             tms->Tflags &= ~_CACHE_WRITTEN;
    1814:         }
    1815:     tms->tms_resid = bp->b_bcount - mp->mscp_bytecnt;
    1816:     if  (tms->tms_position = mp->mscp_position)
    1817:         tms->tms_flags &= ~MTF_BOM;
    1818:     else
    1819:         tms->tms_flags |= MTF_BOM;
    1820:     tms_iodone(mp, sc);
    1821:     }
    1822:
    1823: tms_iodone(mp, sc)
    1824:     struct  mscp    *mp;
    1825:     struct  tmscp_softc *sc;
    1826:     {
    1827:     struct  tms_info *tms = sc->sc_drives[mp->mscp_unit];
    1828:     register struct buf *bp = (struct buf *)mp->mscp_cmdref;
    1829:     register struct buf *dp = &tms->tms_dtab;
    1830:
    1831: /*
    1832:  * Remove the buffer from the I/O wait queue.  Set the residual count and
    1833:  * declare the I/O done.
    1834: */
    1835:     bp->av_back->av_forw = bp->av_forw;
    1836:     bp->av_forw->av_back = bp->av_back;
    1837:     dp->b_qsize--;
    1838:     bp->b_resid = tms->tms_resid;
    1839:     iodone(bp);
    1840:     }
    1841:
    1842: /*
    1843:  * Check the return status of an mscp packet and adjust the drive's flags
    1844:  * appropriately.  On error conditions set the error flag and code in the
    1845:  * buffer header.
    1846:  *
    1847:  * Many of the 'case' statements below are finer grained than strictly
    1848:  * necessary - this is done to provide easy access for logging of specific
    1849:  * conditions during debugging.
    1850: */
    1851:
    1852: tms_check_ret(mp, sc)
    1853:     struct  mscp    *mp;
    1854:     struct  tmscp_softc *sc;
    1855:     {
    1856:     register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
    1857:     register struct buf *bp = (struct buf *)mp->mscp_cmdref;
    1858:     u_short em_status = mp->mscp_status & M_ST_MASK;
    1859:     u_short em_subcode = mp->mscp_status >> M_ST_SBBIT;
    1860:     u_short em_flags = mp->mscp_flags;
    1861:     u_short em_endcode = mp->mscp_endcode & ~M_OP_END;
    1862:     char    berr, unkerr;
    1863:
    1864:     if  (em_status != M_ST_SUCC && em_status != M_ST_TAPEM &&
    1865:             (tmscpprintf & 0x1))
    1866:         log(LOG_INFO, "tms%d,%d st=%x sb=%x fl=%x en=%x\n",
    1867:             sc->sc_unit, mp->mscp_unit,
    1868:             em_status, em_subcode, em_flags, em_endcode);
    1869:     tms->tms_endcode = mp->mscp_endcode;
    1870:     if  (em_flags & M_EF_EOT)
    1871:         tms->tms_flags |= MTF_EOM;
    1872:     else
    1873:         tms->tms_flags &= ~MTF_EOM;
    1874:     if  (em_flags & M_EF_DLS)
    1875:         tms->Tflags |= _CACHE_LOST;
    1876:     if  (em_flags & M_EF_PLS)
    1877:         tms->Tflags |= _LOST;
    1878:     tms->tms_status = mp->mscp_status;
    1879:
    1880:     berr = 0;
    1881:     unkerr = 0;
    1882:
    1883:     switch  (em_status)
    1884:         {
    1885:         case    M_ST_SUCC:
    1886:             {
    1887:             switch  (em_subcode)
    1888:                 {
    1889:                 case    M_SC_DUPUN: /* Duplicate unit */
    1890:                     berr = ENXIO;
    1891:                     break;
    1892:                 case    M_SC_ALONL: /* Already online */
    1893:                 case    M_SC_STONL: /* Still online */
    1894:                 case    M_SC_UNIGN: /* Unload ignored */
    1895:                 case    M_SC_ROVOL: /* Readonly unit */
    1896:                     tms->Tflags |= _ONLINE;
    1897:                     break;
    1898:                 case    M_SC_EOT:   /* End of Tape */
    1899:                     tms->tms_flags |= MTF_EOM;
    1900:                     break;
    1901:                 }
    1902:             }
    1903:             break;
    1904:         case    M_ST_OFFLN:
    1905:             tms->Tflags &= ~_ONLINE;
    1906:             if  ((tms->Tflags & _CACHE_ON) &&
    1907:                  (tms->Tflags & _CACHE_WRITTEN))
    1908:                 log(LOG_INFO, "tms%d,%d closs2\n",
    1909:                     sc->sc_unit, mp->mscp_unit);
    1910:             berr = ENXIO;
    1911:             break;
    1912:         case    M_ST_WRTPR:         /* Write Protected */
    1913:             tms->tms_flags |= MTF_WRTLCK;
    1914:             berr = EACCES;          /* Really an error ? */
    1915:             break;
    1916:         case    M_ST_ICMD:          /* Byte count too big */
    1917:         case    M_ST_ABRTD:         /* Command aborted */
    1918:         case    M_ST_COMP:          /* Data Compare error */
    1919:         case    M_ST_DATA:          /* Data error */
    1920:         case    M_ST_HSTBF:         /* Host buffer error */
    1921:         case    M_ST_CNTLR:         /* Controller error */
    1922:         case    M_ST_FMTER:         /* Formatter error */
    1923:             berr = EIO;
    1924:             break;
    1925:         case    M_ST_AVLBL:         /* Unit available */
    1926:             tms->Tflags &= ~(_LOST | _CLSEREX | _SEREX | _ONLINE);
    1927:             break;
    1928:         case    M_ST_BOT:           /* Beginning of tape */
    1929:             tms->tms_flags |= MTF_BOM;
    1930:             tms->tms_position = 0;
    1931:             break;
    1932:         case    M_ST_TAPEM:         /* Tape Mark */
    1933:             tms->Tflags |= (_BUFMARK | _CLSEREX);
    1934:             break;
    1935:         case    M_ST_SEX:           /* Serious Exception */
    1936:             if  (em_flags & M_EF_EOT)
    1937:                 {
    1938:                 tms->tms_flags |= MTF_EOM;
    1939:                 berr = ENOSPC;
    1940:                 }
    1941:             else
    1942:                 {
    1943:                 tms->Tflags &= ~_CLSEREX;
    1944:                 log(LOG_INFO, "tms%d,%d serex sb %x\n",
    1945:                     sc->sc_unit, mp->mscp_unit, em_subcode);
    1946:                 berr = EIO;
    1947:                 }
    1948:             break;
    1949:         case    M_ST_PLOST:         /* Position Lost */
    1950:             log(LOG_INFO, "tms%d,%d plost\n", sc->sc_unit,
    1951:                     mp->mscp_unit);
    1952:             tms->Tflags |= (_LOST | _SEREX);
    1953:             tms->Tflags &= ~_CLSEREX;
    1954:             berr = EIO;
    1955:             break;
    1956:         case    M_ST_LED:           /* Logical end of dev */
    1957:             tms->Tflags |= _CLSEREX;
    1958:             break;
    1959:         case    M_ST_MFMTE:         /* Media format err */
    1960:         case    M_ST_DRIVE:         /* Drive error */
    1961:         case    M_ST_RDTRN:         /* Record truncated */
    1962:             tms->Tflags |= _SEREX;
    1963:             tms->Tflags &= ~_CLSEREX;
    1964:         case    M_ST_LOADR:
    1965:         case    M_ST_DIAG:          /* Intern diag err */
    1966:         case    M_ST_IPARM:         /* Invalid parameter */
    1967:             berr = EIO;
    1968:             break;
    1969:         default:
    1970:             unkerr = 1;
    1971:             berr = EIO;
    1972:             break;
    1973:         }
    1974:     if  (unkerr)
    1975:         log(LOG_INFO, "tms%d,%d: st/sb =%x/%x\n",
    1976:             sc->sc_unit, mp->mscp_unit, em_status, em_subcode);
    1977:     if  (berr && bp)
    1978:         {
    1979:         bp->b_flags |= B_ERROR;
    1980:         bp->b_error = berr;
    1981:         }
    1982:     return;
    1983:     }
    1984:
    1985: /*
    1986:  * Process an error log datagram.
    1987:  *
    1988:  * No decoding is done - it wasn't worth the D space.  If bit 1 is set
    1989:  * in the print flags then a simple message is generated out of (hopefully)
    1990:  * useful fields.
    1991:  *
    1992:  * Eventually a error log daemon will be written and the datagram sent to
    1993:  * it for capture and detailed analysis.  Until then the logging in
    1994:  * 'tms_check_ret' and a few other strategic spots will have to suffice.
    1995:  */
    1996:
    1997:     u_short tms_datagrams[NTMSCP];
    1998:
    1999: tmserror(ctlr, mp)
    2000:     int ctlr;
    2001:     register struct mslg *mp;
    2002:     {
    2003:
    2004:     tms_datagrams[ctlr]++;
    2005:     if  (tmscpprintf & 0x2)
    2006:         log(LOG_INFO,
    2007:         "tms%d,%d dgram fmt=%x evt=%x grp=%x flg=%x pos=%D\n",
    2008:             ctlr, mp->mslg_unit, mp->mslg_format,
    2009:             mp->mslg_event, mp->mslg_group, mp->mslg_flags,
    2010:             mp->mslg_position);
    2011:     }
    2012: #endif NTMSCP

#### Defined functions

getdd defined in line 406; used 1 times

- in line 636

tkini defined in line 935; used 3 times

- in line 650, 1009, 1162

tmsVec defined in line 367; never used
tms_avail_em defined in line 1722; used 1 times

- in line 1315

tms_avail_st defined in line 1586; used 1 times

- in line 1076

tms_cache_cmn defined in line 1629; used 4 times

- in line 1518, 1554, 1577, 1626

tms_check_ret defined in line 1852; used 7 times

- in line 1659, 1688, 1717, 1728, 1750, 1763, 1807

tms_clrerr defined in line 1598; used 3 times

- in line 694, 1021, 1595

tms_flush_em defined in line 1738; used 1 times

- in line 1321

tms_gtunt_em defined in line 1755; used 1 times

- in line 1318

tms_iodone defined in line 1823; used 8 times

- in line 1299, 1674, 1698, 1719, 1735, 1752, 1795, 1820

tms_repos_em defined in line 1652; used 1 times

- in line 1309

tms_repos_st defined in line 1543; used 4 times

- in line 1056-1059(2), 1073, 1098

tms_reposrec_st defined in line 1567; used 2 times

- in line 1062-1065(2)

tms_rw_em defined in line 1798; used 1 times

- in line 1303

tms_stunt_em defined in line 1681; used 1 times

- in line 1312

tms_stunt_st defined in line 1509; used 3 times

- in line 1088, 1094, 1103

tms_wrteof defined in line 1484; used 2 times

- in line 784, 1434

tms_wtm_em defined in line 1705; used 1 times

- in line 1306

tms_wtm_st defined in line 1616; used 1 times

- in line 1053

tmsattach defined in line 386; never used
tmscpclose defined in line 754; never used
tmscpcommand defined in line 803; used 10 times

- in line 728, 737, 743, 771, 788, 1458-1462(2), 1489-1498(3)

tmscpgetcp defined in line 894; used 4 times

- in line 363, 684, 1016, 1032

tmscpioctl defined in line 1401; never used
tmscpopen defined in line 617; never used
tmscprsp defined in line 1187; used 2 times

- in line 593, 1176

tmscpstrategy defined in line 1335; used 1 times

- in line 837

tmserror defined in line 1999; used 1 times

- in line 1208

tmsginit defined in line 860; used 3 times

- in line 520-522(2)
- in /usr/src/sys/pdpuba/tmscpdump.c line 80

tmsintr defined in line 452; used 1 times

- in /usr/src/sys/pdp/scb.s line 380

tmsstart defined in line 971; used 2 times

- in line 607, 1395

tmswatchdog defined in line 849; used 3 times

- in line 340, 836-839(2)

wait_step defined in line 428; used 3 times

- in line 479, 490, 501

#### Defined variables

Dmatrix defined in line 276; used 1 times

- in line 1102

sccsid defined in line 6; never used
tms_datagrams defined in line 1997; used 1 times

- in line 2004

tms_info defined in line 285; used 2 times

- in line 411(2)

tmscp defined in line 287; used 13 times

- in line 395-396(2), 519, 575, 691, 877, 906, 942, 1018, 1034, 1170
- in /usr/src/sys/pdpuba/tmscpdump.c line 53, 61

tmscp_cp_wait defined in line 337; used 5 times

- in line 605-606(2), 686-688(3)

tmscp_softc defined in line 284; used 9 times

- in line 370, 390, 458, 632, 762, 811, 1344, 1407
- in /usr/src/sys/pdpuba/tmscpdump.c line 48

tmscpcache defined in line 361; used 2 times

- in line 724
- in /usr/src/sys/pdp/kern_pdp.c line 237

tmscpfatalerr defined in line 335; used 4 times

- in line 565, 1026, 1160
- in /usr/src/sys/pdpuba/tmscpdump.c line 140

tmscpprintf defined in line 352; used 7 times

- in line 1129, 1212, 1296, 1324, 1865, 2005
- in /usr/src/sys/pdp/kern_pdp.c line 240

tmscpstepfailed defined in line 334; used 1 times

- in line 444

#### Defined macros

STEP1GOOD defined in line 477; used 1 times

- in line 479

STEP1MASK defined in line 476; used 1 times

- in line 479

STEP2GOOD defined in line 488; used 1 times

- in line 490

STEP2MASK defined in line 487; used 1 times

- in line 490

STEP3GOOD defined in line 499; used 1 times

- in line 501

STEP3MASK defined in line 498; used 1 times

- in line 501

S_IDLE defined in line 327; used 4 times

- in line 442, 567, 649, 1229

S_RUN defined in line 332; used 4 times

- in line 647, 664, 1005, 1227

S_SCHAR defined in line 331; used 1 times

- in line 510

S_STEP1 defined in line 328; used 1 times

- in line 961

S_STEP2 defined in line 329; used 1 times

- in line 482

S_STEP3 defined in line 330; used 1 times

- in line 493

TMSDEBUG defined in line 1; never used
TMS_BSF defined in line 311; used 1 times

- in line 1416

TMS_BSR defined in line 313; used 2 times

- in line 1416, 1498

TMS_CACHE defined in line 317; used 1 times

- in line 1417

TMS_CSE defined in line 321; used 2 times

- in line 737, 1462

TMS_FLUSH defined in line 319; used 2 times

- in line 771, 1417

TMS_FSF defined in line 310; used 1 times

- in line 1416

TMS_FSR defined in line 312; used 1 times

- in line 1416

TMS_NOCACHE defined in line 318; used 1 times

- in line 1417

TMS_OFFL defined in line 315; used 1 times

- in line 1416

TMS_REW defined in line 314; used 2 times

- in line 788, 1416

TMS_SENSE defined in line 316; used 2 times

- in line 728, 1416

TMS_SETDENSITY defined in line 322; used 1 times

- in line 743

TMS_WRITM defined in line 309; used 3 times

- in line 1416, 1489-1493(2)

_BUFMARK defined in line 297; used 4 times

- in line 785, 1122-1125(2), 1933

_CACHE_LOST defined in line 300; used 5 times

- in line 1605-1607(2), 1635-1639(2), 1875

_CACHE_ON defined in line 299; used 8 times

- in line 725-726(2), 765, 1087, 1093, 1120, 1778, 1906

_CACHE_WRITTEN defined in line 301; used 14 times

- in line 765, 780, 1121, 1246, 1496, 1607, 1637-1639(2), 1671, 1689, 1733, 1746, 1813, 1907

_CLSEREX defined in line 295; used 13 times

- in line 789, 1123-1125(2), 1461, 1553, 1604, 1625, 1926, 1933, 1943, 1953-1957(2), 1963

_HASCACHE defined in line 298; used 3 times

- in line 1444-1445(2), 1777

_INUSE defined in line 302; used 5 times

- in line 642-644(2), 727, 785, 1729

_LOST defined in line 296; used 5 times

- in line 789, 1669, 1877, 1926, 1952

_ONLINE defined in line 303; used 16 times

- in line 681, 711, 727-729(2), 1014, 1245, 1287, 1346, 1444-1445(2), 1695, 1729, 1770, 1896, 1905, 1926

_SEREX defined in line 294; used 4 times

- in line 789, 1926, 1952, 1962

b_qsize defined in line 365; used 2 times

- in line 1138, 1837

Last modified: 1999-02-27 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 4849 |