149567Sbostic /*-
2*65776Sbostic * Copyright (c) 1991
3*65776Sbostic * The Regents of the University of California. All rights reserved.
4*65776Sbostic * (c) UNIX System Laboratories, Inc.
5*65776Sbostic * All or some portions of this file are derived from material licensed
6*65776Sbostic * to the University of California by American Telephone and Telegraph
7*65776Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8*65776Sbostic * the permission of UNIX System Laboratories, Inc.
949567Sbostic *
1049567Sbostic * %sccs.include.redist.c%
1149567Sbostic *
12*65776Sbostic * @(#)tmscp.c 7.17 (Berkeley) 01/21/94
1349567Sbostic */
1426135Skarels
1549567Sbostic /*
1649567Sbostic * sccsid = "@(#)tmscp.c 1.24 (ULTRIX) 1/21/86";
1749567Sbostic */
1826127Skarels
1926127Skarels /************************************************************************
2026127Skarels * *
2127468Skjd * Licensed from Digital Equipment Corporation *
2227468Skjd * Copyright (c) *
2327468Skjd * Digital Equipment Corporation *
2427468Skjd * Maynard, Massachusetts *
2527468Skjd * 1985, 1986 *
2627468Skjd * All rights reserved. *
2726127Skarels * *
2827468Skjd * The Information in this software is subject to change *
2927468Skjd * without notice and should not be construed as a commitment *
3027468Skjd * by Digital Equipment Corporation. Digital makes no *
3127468Skjd * representations about the suitability of this software for *
3227468Skjd * any purpose. It is supplied "As Is" without expressed or *
3327468Skjd * implied warranty. *
3426127Skarels * *
3527468Skjd * If the Regents of the University of California or its *
3627468Skjd * licensees modify the software in a manner creating *
3727468Skjd * diriviative copyright rights, appropriate copyright *
3827468Skjd * legends may be placed on the drivative work in addition *
3927468Skjd * to that set forth above. *
4026127Skarels * *
4126127Skarels ************************************************************************
4226127Skarels *
4326127Skarels * tmscp.c - TMSCP (TK50/TU81) tape device driver
4426127Skarels *
4526127Skarels * Modification History:
4626127Skarels *
4726127Skarels * 06-Jan-86 - afd
4826127Skarels * Changed the probe routine to use DELAY (not TODR). This now
4926127Skarels * works for MicroVAXen as well. This eliminates the busy-wait
5026127Skarels * for MicroVAXen so a dead TK50 controller will not hang autoconf.
5126127Skarels *
5226127Skarels * 06-Dec-85 - afd
5326127Skarels * Fixed a bug in density selection. The "set unit characteristics"
5426127Skarels * command to select density, was clearing the "unit flags" field
5526127Skarels * where the CACHE bit was for TU81-E. Now the unit's "format" and
5626127Skarels * "unitflgs" are saved in tms_info struct. And are used on STUNT
5726127Skarels * commands.
5826127Skarels *
5926127Skarels * 19-Oct-85 - afd
6026127Skarels * Added support to the open routine to allow drives to be opened
6126127Skarels * for low density (800 or 1600 bpi) use. When the slave routine
6226127Skarels * initiates a "get-unit-char" cmd, the format menu for the unit
6326127Skarels * is saved in the tms_info structure. The format menu is used in the
6426127Skarels * start routine to select the proper low density.
6526127Skarels *
6626127Skarels * 02-Oct-85 - afd
6726127Skarels * When a tmscp-type controller is initializing, it is possible for
6826127Skarels * the sa reg to become 0 between states. Thus the init code in
6926127Skarels * the interrupt routine had to be modified to reflect this.
7026127Skarels *
7126127Skarels * 21-Sep-85 - afd
7226127Skarels * The TK50 declares a serious exception when a tape mark is encountered.
7326127Skarels * This causes problems to dd (& other UN*X utilities). So a flag
7426127Skarels * is set in the rsp() routine when a tape mark is encountered. If
7526127Skarels * this flag is set, the start() routine appends the Clear Serious
7626127Skarels * Exception modifier to the next command.
7726127Skarels *
7826127Skarels * 03-Sep-85 -- jaw
7926127Skarels * messed up previous edit..
8026127Skarels *
8126127Skarels * 29-Aug-85 - jaw
8226127Skarels * fixed bugs in 8200 and 750 buffered datapath handling.
8326127Skarels *
8426127Skarels * 06-Aug-85 - afd
8526127Skarels * 1. When repositioning records or files, the count of items skipped
8626127Skarels * does NOT HAVE to be returned by controllers (& the TU81 doesn't).
8726127Skarels * So tmscprsp() had to be modified to stop reporting
8826127Skarels * residual count errors on reposition commands.
8926127Skarels *
9026127Skarels * 2. Fixed bug in the open routine which allowed multiple opens.
9126127Skarels *
9226127Skarels * 18-Jul-85 - afd
9326127Skarels * 1. Need to return status when mt status (or corresponding ioctl) is done.
9426127Skarels * Save resid, flags, endcode & status in tmscprsp() routine (except on
9526127Skarels * clear serious exception no-op). Return these fields when status
9626127Skarels * ioctl is done (in tmscpcommand()). How they are returned:
9726127Skarels * mt_resid = resid
9826127Skarels * mt_dsreg = flags|endcode
9926127Skarels * mt_erreg = status
10026127Skarels *
10126127Skarels * 2. Added latent support for enabling/disabling caching. This is
10226127Skarels * handled along with all other ioctl commands.
10326127Skarels *
10426127Skarels * 3. Need to issue a no-op on unrecognized ioctl in tmscpstart(), since
10526127Skarels * we have already commited to issuing a command at that point.
10626127Skarels *
10726127Skarels * 4. In tmscprsp() routine if encode is 0200 (invalid command issued);
10826127Skarels * We need to: Unlink the buffer from the I/O wait queue,
10926127Skarels * and signal iodone, so the higher level command can exit!
11026127Skarels * Just as if it were a valid command.
11126127Skarels *
11226127Skarels * 11-jul-85 -- jaw
11326127Skarels * fix bua/bda map registers.
11426127Skarels *
11526127Skarels * 19-Jun-85 -- jaw
11626127Skarels * VAX8200 name change.
11726127Skarels *
11826127Skarels * 06-Jun-85 - jaw
11926127Skarels * fixes for 8200.
12026127Skarels *
12126127Skarels * 9-Apr-85 - afd
12226127Skarels * Added timeout code to the probe routine, so if the controller
12326127Skarels * fails to init in 10 seconds we return failed status.
12426127Skarels *
12526127Skarels * 13-Mar-85 -jaw
12626127Skarels * Changes for support of the VAX8200 were merged in.
12726127Skarels *
12826127Skarels * 27-Feb-85 -tresvik
12926127Skarels * Changes for support of the VAX8600 were merged in.
13026127Skarels *
13126127Skarels */
13226135Skarels
13326127Skarels #include "tms.h"
13426135Skarels #if NTMSCP > 0
13526135Skarels
13645807Sbostic #include "sys/param.h"
13745807Sbostic #include "sys/systm.h"
13845807Sbostic #include "sys/buf.h"
13945807Sbostic #include "sys/conf.h"
14045807Sbostic #include "sys/errno.h"
14145807Sbostic #include "sys/file.h"
14245807Sbostic #include "sys/map.h"
14345807Sbostic #include "sys/vm.h"
14445807Sbostic #include "sys/ioctl.h"
14545807Sbostic #include "sys/syslog.h"
14645807Sbostic #include "sys/mtio.h"
14745807Sbostic #include "sys/cmap.h"
14845807Sbostic #include "sys/uio.h"
14945807Sbostic #include "sys/tprintf.h"
15026135Skarels
15145807Sbostic #include "../include/pte.h"
15245807Sbostic #include "../include/cpu.h"
15345807Sbostic #include "../include/mtpr.h"
15426135Skarels #include "ubareg.h"
15526135Skarels #include "ubavar.h"
15626135Skarels
15726135Skarels #define TENSEC (1000)
15826135Skarels #define TMS_PRI LOG_INFO
15926135Skarels
16026135Skarels #define NRSPL2 3 /* log2 number of response packets */
16126135Skarels #define NCMDL2 3 /* log2 number of command packets */
16226135Skarels #define NRSP (1<<NRSPL2)
16326135Skarels #define NCMD (1<<NCMDL2)
16426135Skarels
16526135Skarels #include "tmscpreg.h"
16626135Skarels #include "../vax/tmscp.h"
16726135Skarels
16826135Skarels /* Software state per controller */
16926135Skarels
17026135Skarels struct tmscp_softc {
17126135Skarels short sc_state; /* state of controller */
17226135Skarels short sc_mapped; /* Unibus map allocated for tmscp struct? */
17326135Skarels int sc_ubainfo; /* Unibus mapping info */
17426135Skarels struct tmscp *sc_tmscp; /* Unibus address of tmscp struct */
17526135Skarels int sc_ivec; /* interrupt vector address */
17626135Skarels short sc_credits; /* transfer credits */
17726135Skarels short sc_lastcmd; /* pointer into command ring */
17826135Skarels short sc_lastrsp; /* pointer into response ring */
17936035Skarels short sc_ipl; /* interrupt priority (Q-bus) */
18026135Skarels } tmscp_softc[NTMSCP];
18126135Skarels
18226135Skarels struct tmscp {
18326135Skarels struct tmscpca tmscp_ca; /* communications area */
18426135Skarels struct mscp tmscp_rsp[NRSP]; /* response packets */
18526135Skarels struct mscp tmscp_cmd[NCMD]; /* command packets */
18626135Skarels } tmscp[NTMSCP];
18726135Skarels
18826135Skarels /*
18926135Skarels * Per drive-unit info
19026135Skarels */
19126135Skarels struct tms_info {
19226135Skarels daddr_t tms_dsize; /* Max user size from online pkt */
19326135Skarels unsigned tms_type; /* Drive type int field */
19426135Skarels int tms_resid; /* residual from last xfer */
19526135Skarels u_char tms_endcode; /* last command endcode */
19626135Skarels u_char tms_flags; /* last command end flags */
19726135Skarels unsigned tms_status; /* Command status from last command */
19826135Skarels char tms_openf; /* lock against multiple opens */
19926135Skarels char tms_lastiow; /* last op was a write */
20026135Skarels char tms_serex; /* set when serious exception occurs */
20126135Skarels char tms_clserex; /* set when serex being cleared by no-op */
20226135Skarels short tms_fmtmenu; /* the unit's format (density) menu */
20326135Skarels short tms_unitflgs; /* unit flag parameters */
20426135Skarels short tms_format; /* the unit's current format (density) */
20544394Smarc tpr_t tms_tpr; /* tprintf handle */
20626135Skarels } tms_info[NTMS];
20726135Skarels struct uba_ctlr *tmscpminfo[NTMSCP];
20826135Skarels struct uba_device *tmsdinfo[NTMS];
20926135Skarels /*
21026135Skarels * ifdef other tmscp devices here if they allow more than 1 unit/controller
21126135Skarels */
21226135Skarels struct uba_device *tmscpip[NTMSCP][1];
21326135Skarels struct buf ctmscpbuf[NTMSCP]; /* internal cmd buffer (for ioctls) */
21426135Skarels struct buf tmsutab[NTMS]; /* Drive queue */
21526135Skarels struct buf tmscpwtab[NTMSCP]; /* I/O wait queue, per controller */
21626135Skarels int tmscpmicro[NTMSCP]; /* to store microcode level */
21726135Skarels short utoctlr[NTMS]; /* Slave unit to controller mapping */
21826135Skarels /* filled in by the slave routine */
21926135Skarels
22026127Skarels /* Bits in minor device */
22126127Skarels #define TMSUNIT(dev) (minor(dev)&03)
22226127Skarels #define T_NOREWIND 04
22326127Skarels #define T_HIDENSITY 010
22426135Skarels
22526127Skarels /* Slave unit to controller mapping */
22626127Skarels #define TMSCPCTLR(dev) (utoctlr[TMSUNIT(dev)])
22726135Skarels
22826127Skarels /*
22926127Skarels * Internal (ioctl) command codes (these must also be declared in the
23026127Skarels * tmscpioctl routine). These correspond to ioctls in mtio.h
23126127Skarels */
23226127Skarels #define TMS_WRITM 0 /* write tape mark */
23326127Skarels #define TMS_FSF 1 /* forward space file */
23426127Skarels #define TMS_BSF 2 /* backward space file */
23526127Skarels #define TMS_FSR 3 /* forward space record */
23626127Skarels #define TMS_BSR 4 /* backward space record */
23726127Skarels #define TMS_REW 5 /* rewind tape */
23826127Skarels #define TMS_OFFL 6 /* rewind tape & mark unit offline */
23926127Skarels #define TMS_SENSE 7 /* noop - do a get unit status */
24026127Skarels #define TMS_CACHE 8 /* enable cache */
24126127Skarels #define TMS_NOCACHE 9 /* disable cache */
24226127Skarels /* These go last: after all real mt cmds, just bump the numbers up */
24326127Skarels #define TMS_CSE 10 /* clear serious exception */
24426127Skarels #define TMS_LOWDENSITY 11 /* set unit to low density */
24526127Skarels #define TMS_HIDENSITY 12 /* set unit to high density */
24626135Skarels
24726127Skarels /*
24826127Skarels * Controller states
24926127Skarels */
25026127Skarels #define S_IDLE 0 /* hasn't been initialized */
25126127Skarels #define S_STEP1 1 /* doing step 1 init */
25226127Skarels #define S_STEP2 2 /* doing step 2 init */
25326127Skarels #define S_STEP3 3 /* doing step 3 init */
25426127Skarels #define S_SCHAR 4 /* doing "set controller characteristics" */
25526127Skarels #define S_RUN 5 /* running */
25626135Skarels
25726127Skarels int tmscperror = 0; /* causes hex dump of packets */
25826127Skarels int tmscp_cp_wait = 0; /* Something to wait on for command */
25926127Skarels /* packets and or credits. */
26026127Skarels int wakeup();
26126127Skarels extern int hz; /* Should find the right include */
26226135Skarels
26326127Skarels #ifdef DEBUG
26426127Skarels #define printd if (tmscpdebug) printf
26526127Skarels int tmscpdebug = 1;
26626127Skarels #define printd10 if(tmscpdebug >= 10) printf
26726127Skarels #endif
26826135Skarels
26926127Skarels int tmscpprobe(), tmscpslave(), tmscpattach(), tmscpintr();
27026127Skarels struct mscp *tmscpgetcp();
27126135Skarels
27226127Skarels #define DRVNAME "tms"
27326127Skarels #define CTRLNAME "tmscp"
27426135Skarels
27526127Skarels u_short tmscpstd[] = { 0174500, 0 };
27626127Skarels struct uba_driver tmscpdriver =
27726127Skarels { tmscpprobe, tmscpslave, tmscpattach, 0, tmscpstd, DRVNAME, tmsdinfo, CTRLNAME
27826127Skarels , tmscpminfo, 0};
27926135Skarels
28026127Skarels #define b_qsize b_resid /* queue size per drive, in tmsutab */
28126127Skarels #define b_ubinfo b_resid /* Unibus mapping info, per buffer */
28226135Skarels
28326135Skarels
28426127Skarels /*************************************************************************/
28526135Skarels
28626127Skarels #define DELAYTEN 1000
28726135Skarels
28839419Smckusick /*
28939419Smckusick * Unfortunately qbgetpri can't be used because the TK50 doesn't flip the
29039419Smckusick * TMSCP_STEP2 flag in the tmscpsa register until after the pending interrupt
29139419Smckusick * has been acknowledged by the cpu. If you are at spl6(), the TMSCP_STEP2
29239419Smckusick * flag never gets set and you return (0).
29339419Smckusick */
tmscpprobe(reg,ctlr)29426127Skarels tmscpprobe(reg, ctlr)
29526127Skarels caddr_t reg; /* address of the IP register */
29626135Skarels int ctlr; /* index of controller in the tmscp_softc array */
29726127Skarels {
29826127Skarels register int br, cvec; /* MUST be 1st (r11 & r10): IPL and intr vec */
29926127Skarels register struct tmscp_softc *sc = &tmscp_softc[ctlr];
30026127Skarels /* ptr to software controller structure */
30126135Skarels struct tmscpdevice *tmscpaddr; /* ptr to tmscpdevice struct (IP & SA) */
30239419Smckusick int count; /* for probe delay time out */
30326135Skarels
30426127Skarels # ifdef lint
30526127Skarels br = 0; cvec = br; br = cvec; reg = reg;
30626127Skarels tmscpreset(0); tmscpintr(0);
30726127Skarels # endif
30826135Skarels
30926127Skarels tmscpaddr = (struct tmscpdevice *) reg;
31026127Skarels /*
31126127Skarels * Set host-settable interrupt vector.
31226135Skarels * Assign 0 to the ip register to start the tmscp-device initialization.
31326127Skarels * The device is not really initialized at this point, this is just to
31426127Skarels * find out if the device exists.
31526127Skarels */
31626127Skarels sc->sc_ivec = (uba_hd[numuba].uh_lastiv -= 4);
31726127Skarels tmscpaddr->tmscpip = 0;
31826135Skarels
31926127Skarels count=0;
32026127Skarels while(count < DELAYTEN)
32126127Skarels { /* wait for at most 10 secs */
32226127Skarels if((tmscpaddr->tmscpsa & TMSCP_STEP1) != 0)
32326127Skarels break;
32426127Skarels DELAY(10000);
32526127Skarels count=count+1;
32626127Skarels }
32739419Smckusick if (count == DELAYTEN)
32826127Skarels return(0);
32926135Skarels
33026135Skarels tmscpaddr->tmscpsa = TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8)|TMSCP_IE|(sc->sc_ivec/4);
33126135Skarels
33226127Skarels count=0;
33326127Skarels while(count < DELAYTEN)
33426127Skarels {
33526135Skarels if((tmscpaddr->tmscpsa & TMSCP_STEP2) != 0)
33626127Skarels break;
33726127Skarels DELAY(10000);
33826127Skarels count = count+1;
33926127Skarels }
34039419Smckusick if (count == DELAYTEN)
34126127Skarels return(0);
34226135Skarels
34335401Stef #ifdef QBA
34439419Smckusick sc->sc_ipl = br = 0x15;
34534523Skarels #endif
34626127Skarels return(sizeof (struct tmscpdevice));
34726127Skarels }
34826135Skarels
34926127Skarels /*
35026127Skarels * Try to find a slave (a drive) on the controller.
35126127Skarels * If the controller is not in the run state, call init to initialize it.
35226127Skarels */
35326127Skarels tmscpslave (ui, reg)
35426127Skarels struct uba_device *ui; /* ptr to the uba device structure */
35526127Skarels caddr_t reg; /* addr of the device controller */
35626127Skarels {
35726127Skarels register struct uba_ctlr *um = tmscpminfo[ui->ui_ctlr];
35826127Skarels register struct tmscp_softc *sc = &tmscp_softc[ui->ui_ctlr];
35926135Skarels register struct tms_info *tms = &tms_info[ui->ui_unit];
36026127Skarels struct tmscpdevice *tmscpaddr; /* ptr to IP & SA */
36126127Skarels struct mscp *mp;
36226127Skarels int i; /* Something to write into to start */
36326127Skarels /* the tmscp polling */
36426135Skarels
36526127Skarels # ifdef lint
36626293Skarels reg = reg;
36726127Skarels # endif
36826127Skarels tmscpaddr = (struct tmscpdevice *)um->um_addr;
36926127Skarels /*
37026127Skarels * If its not in the run state, start the initialization process
37126127Skarels * (tmscpintr will complete it); if the initialization doesn't start;
37226127Skarels * then return.
37326127Skarels */
37426127Skarels if(sc->sc_state != S_RUN)
37526127Skarels {
37626127Skarels # ifdef DEBUG
37726127Skarels printd("tmscpslave: ctlr not running: calling init \n");
37826127Skarels # endif
37926127Skarels if(!tmscpinit(ui->ui_ctlr))
38026127Skarels return(0);
38126127Skarels }
38226127Skarels /*
38326127Skarels * Wait for the controller to come into the run state or go idle.
38426127Skarels * If it goes idle return.
38526127Skarels */
38626127Skarels # ifdef DEBUG
38726127Skarels i=1;
38826127Skarels # endif
38926127Skarels while(sc->sc_state != S_RUN && sc->sc_state != S_IDLE)
39026127Skarels # ifdef DEBUG
39126127Skarels if (tmscpaddr->tmscpsa & TMSCP_ERR && i)
39226127Skarels {
39326135Skarels printd("tmscp-device: fatal error (%o)\n", tmscpaddr->tmscpsa&0xffff);
39426127Skarels i=0;
39526127Skarels }
39626127Skarels # endif
39726127Skarels ; /* wait */
39826127Skarels if(sc->sc_state == S_IDLE)
39926127Skarels { /* The tmscp device failed to initialize */
40026127Skarels printf("tmscp controller failed to init\n");
40126127Skarels return(0);
40226127Skarels }
40326127Skarels /* The controller is up so see if the drive is there */
40426127Skarels if(0 == (mp = tmscpgetcp(um)))
40526127Skarels {
40626127Skarels printf("tmscp can't get command packet\n");
40726127Skarels return(0);
40826127Skarels }
40926127Skarels /* Need to determine the drive type for generic driver */
41026135Skarels mp->mscp_opcode = M_OP_GTUNT; /* This should give us the device type */
41126127Skarels mp->mscp_unit = ui->ui_slave;
41226127Skarels mp->mscp_cmdref = (long) ui->ui_slave;
41326135Skarels tms->tms_status = 0; /* set to zero */
41426127Skarels tmscpip[ui->ui_ctlr][ui->ui_slave] = ui;
41526135Skarels *((long *) mp->mscp_dscptr ) |= TMSCP_OWN | TMSCP_INT;/* maybe we should poll*/
41626127Skarels i = tmscpaddr->tmscpip;
41726293Skarels #ifdef lint
41826293Skarels i = i;
41926293Skarels #endif
42026135Skarels while(!tms->tms_status)
42126127Skarels ; /* Wait for some status */
42226127Skarels # ifdef DEBUG
42326135Skarels printd("tmscpslave: status = %o\n",tms->tms_status & M_ST_MASK);
42426135Skarels # endif
42526127Skarels tmscpip[ui->ui_ctlr][ui->ui_slave] = 0;
42626135Skarels if(!tms->tms_type) /* packet from a GTUNT */
42726127Skarels return(0); /* Failed No such drive */
42826127Skarels else
42926127Skarels return(1); /* Got it and it is there */
43026127Skarels }
43126135Skarels
43226135Skarels
43326127Skarels /*
43426127Skarels * Set ui flags to zero to show device is not online & set tmscpip.
43526127Skarels * Unit to Controller mapping is set up here.
43626127Skarels * Open routine will issue the online command, later.
43726127Skarels */
tmscpattach(ui)43826127Skarels tmscpattach (ui)
43926127Skarels register struct uba_device *ui; /* ptr to unibus dev struct */
44026127Skarels {
44126135Skarels
44226127Skarels ui->ui_flags = 0;
44326127Skarels tmscpip[ui->ui_ctlr][ui->ui_slave] = ui;
44426127Skarels # ifdef DEBUG
44526127Skarels /*
44626127Skarels * Check to see if the drive is available.
44726127Skarels * If not then just print debug.
44826127Skarels */
44926127Skarels if(tms_info[ui->ui_unit].tms_status != M_ST_AVLBL)
45026127Skarels printd("tmscpattach: unavailable \n");
45126127Skarels # endif
45226127Skarels utoctlr[ui->ui_unit] = ui->ui_ctlr;
45326127Skarels }
45426135Skarels
45526135Skarels
45626127Skarels /*
45726127Skarels * TMSCP interrupt routine.
45826127Skarels */
tmscpintr(d)45926127Skarels tmscpintr (d)
46026127Skarels int d; /* index to the controller */
46126127Skarels {
46226127Skarels register struct uba_ctlr *um = tmscpminfo[d];
46326135Skarels register struct tmscpdevice *tmscpaddr = (struct tmscpdevice *)um->um_addr;
46426127Skarels struct buf *bp;
46526127Skarels register int i;
46626127Skarels register struct tmscp_softc *sc = &tmscp_softc[d];
46726127Skarels register struct tmscp *tm = &tmscp[d];
46826127Skarels struct tmscp *ttm;
46926127Skarels struct mscp *mp;
47026135Skarels
47126127Skarels # ifdef DEBUG
47226135Skarels printd10("tmscpintr: state %d, tmscpsa %o\n", sc->sc_state, tmscpaddr->tmscpsa);
47326127Skarels # endif
47426135Skarels
47536035Skarels #ifdef QBA
47636035Skarels splx(sc->sc_ipl);
47736035Skarels #endif
47826127Skarels /*
47926127Skarels * How the interrupt is handled depends on the state of the controller.
48026127Skarels */
48126127Skarels switch (sc->sc_state) {
48226135Skarels
48326127Skarels case S_IDLE:
48426127Skarels printf("tmscp%d: random interrupt ignored\n", d);
48526127Skarels return;
48626135Skarels
48726127Skarels /* Controller was in step 1 last, see if its gone to step 2 */
48826127Skarels case S_STEP1:
48926127Skarels # define STEP1MASK 0174377
49026127Skarels # define STEP1GOOD (TMSCP_STEP2|TMSCP_IE|(NCMDL2<<3)|NRSPL2)
49126127Skarels for (i = 0; i < 150; i++)
49226127Skarels {
49326127Skarels if ((tmscpaddr->tmscpsa&STEP1MASK) != STEP1GOOD)
49426127Skarels { /* still in step 1 (wait 1/100 sec) */
49526127Skarels DELAY(10000);
49626127Skarels # ifdef DEBUG
49726127Skarels printd("still in step 1, delaying\n");
49826127Skarels # endif DEBUG
49926127Skarels }
50026127Skarels else
50126127Skarels break;
50226127Skarels }
50326127Skarels if (i > 149)
50426127Skarels {
50526127Skarels sc->sc_state = S_IDLE;
50626135Skarels printf("failed to initialize, in step1: sa 0x%x", tmscpaddr->tmscpsa);
50726127Skarels wakeup((caddr_t)um);
50826127Skarels return;
50926127Skarels }
51026127Skarels tmscpaddr->tmscpsa = ((int)&sc->sc_tmscp->tmscp_ca.ca_ringbase)
51126127Skarels | ((cpu == VAX_780 || cpu == VAX_8600) ? TMSCP_PI : 0);
51226127Skarels sc->sc_state = S_STEP2;
51326127Skarels return;
51426135Skarels
51526127Skarels /* Controller was in step 2 last, see if its gone to step 3 */
51626127Skarels case S_STEP2:
51726127Skarels # define STEP2MASK 0174377
51826127Skarels # define STEP2GOOD (TMSCP_STEP3|TMSCP_IE|(sc->sc_ivec/4))
51926127Skarels for (i = 0; i < 150; i++)
52026127Skarels {
52126127Skarels if ((tmscpaddr->tmscpsa&STEP2MASK) != STEP2GOOD)
52226127Skarels { /* still in step 2 (wait 1/100 sec) */
52326127Skarels DELAY(10000);
52426127Skarels # ifdef DEBUG
52526127Skarels printd("still in step 2, delaying\n");
52626127Skarels # endif DEBUG
52726127Skarels }
52826127Skarels else
52926127Skarels break;
53026127Skarels }
53126127Skarels if (i > 149)
53226127Skarels {
53326127Skarels sc->sc_state = S_IDLE;
53426135Skarels printf("failed to initialize, in step2: sa 0x%x", tmscpaddr->tmscpsa);
53526127Skarels wakeup((caddr_t)um);
53626127Skarels return;
53726127Skarels }
53826135Skarels tmscpaddr->tmscpsa = ((int)&sc->sc_tmscp->tmscp_ca.ca_ringbase)>>16;
53926127Skarels sc->sc_state = S_STEP3;
54026127Skarels return;
54126135Skarels
54226127Skarels /* Controller was in step 3 last, see if its gone to step 4 */
54326127Skarels case S_STEP3:
54426127Skarels # define STEP3MASK 0174000
54526127Skarels # define STEP3GOOD TMSCP_STEP4
54626127Skarels for (i = 0; i < 150; i++)
54726127Skarels {
54826127Skarels if ((tmscpaddr->tmscpsa&STEP3MASK) != STEP3GOOD)
54926127Skarels { /* still in step 3 (wait 1/100 sec) */
55026127Skarels DELAY(10000);
55126127Skarels # ifdef DEBUG
55226127Skarels printd("still in step 3, delaying\n");
55326127Skarels # endif DEBUG
55426127Skarels }
55526127Skarels else
55626127Skarels break;
55726127Skarels }
55826127Skarels if (i > 149)
55926127Skarels {
56026127Skarels sc->sc_state = S_IDLE;
56126135Skarels printf("failed to initialize, in step3: sa 0x%x", tmscpaddr->tmscpsa);
56226127Skarels wakeup((caddr_t)um);
56326127Skarels return;
56426127Skarels }
56526127Skarels /*
56626127Skarels * Get microcode version and model number of controller;
56726127Skarels * Signal initialization complete (_GO) (to the controller);
56826127Skarels * ask for Last Fail response if tmscperror is set;
56926127Skarels * Set state to "set controller characteristics".
57026127Skarels */
57126127Skarels tmscpmicro[d] = tmscpaddr->tmscpsa;
57226127Skarels tmscpaddr->tmscpsa = TMSCP_GO | (tmscperror? TMSCP_LF : 0);
57326127Skarels sc->sc_state = S_SCHAR;
57426127Skarels # ifdef DEBUG
57526127Skarels printd("tmscpintr: completed state %d \n", sc->sc_state);
57626127Skarels printd("tmscp%d Version %d model %d\n",d,tmscpmicro[d]&0xF,
57726127Skarels (tmscpmicro[d]>>4) & 0xF);
57826127Skarels # endif
57926135Skarels
58026127Skarels /*
58126127Skarels * Initialize the data structures (response and command queues).
58226127Skarels */
58326127Skarels ttm = sc->sc_tmscp;
58426127Skarels for (i = 0; i < NRSP; i++)
58526127Skarels {
58626127Skarels tm->tmscp_ca.ca_rspdsc[i] = TMSCP_OWN | TMSCP_INT |
58726135Skarels (long)&ttm->tmscp_rsp[i].mscp_cmdref;
58826127Skarels tm->tmscp_rsp[i].mscp_dscptr = &tm->tmscp_ca.ca_rspdsc[i];
58926127Skarels tm->tmscp_rsp[i].mscp_header.tmscp_msglen = mscp_msglen;
59026127Skarels }
59126127Skarels for (i = 0; i < NCMD; i++)
59226127Skarels {
59326127Skarels tm->tmscp_ca.ca_cmddsc[i] = TMSCP_INT |
59426127Skarels (long)&ttm->tmscp_cmd[i].mscp_cmdref;
59526127Skarels tm->tmscp_cmd[i].mscp_dscptr = &tm->tmscp_ca.ca_cmddsc[i];
59626127Skarels tm->tmscp_cmd[i].mscp_header.tmscp_msglen = mscp_msglen;
59726127Skarels tm->tmscp_cmd[i].mscp_header.tmscp_vcid = 1;
59826127Skarels }
59926127Skarels bp = &tmscpwtab[d];
60026127Skarels bp->av_forw = bp->av_back = bp;
60126127Skarels sc->sc_lastcmd = 1;
60226127Skarels sc->sc_lastrsp = 0;
60326127Skarels mp = &tmscp[um->um_ctlr].tmscp_cmd[0];
60426127Skarels mp->mscp_unit = mp->mscp_modifier = 0;
60526127Skarels mp->mscp_flags = 0;
60626127Skarels mp->mscp_version = 0;
60726127Skarels mp->mscp_cntflgs = M_CF_ATTN|M_CF_MISC|M_CF_THIS;
60826127Skarels /*
60926127Skarels * A host time out value of 0 means that the controller will not
61026127Skarels * time out. This is ok for the TK50.
61126127Skarels */
61226127Skarels mp->mscp_hsttmo = 0;
61326127Skarels mp->mscp_time.val[0] = 0;
61426127Skarels mp->mscp_time.val[1] = 0;
61526127Skarels mp->mscp_cntdep = 0;
61626127Skarels mp->mscp_opcode = M_OP_STCON;
61726127Skarels *((long *)mp->mscp_dscptr) |= TMSCP_OWN|TMSCP_INT;
61826127Skarels i = tmscpaddr->tmscpip; /* initiate polling */
61926127Skarels return;
62026135Skarels
62126127Skarels case S_SCHAR:
62226127Skarels case S_RUN:
62326127Skarels break;
62426135Skarels
62526127Skarels default:
62626135Skarels printf("tmscp%d: interrupt in unknown state %d ignored\n",d,sc->sc_state);
62726127Skarels return;
62826127Skarels } /* end switch */
62926135Skarels
63026127Skarels /*
63126127Skarels * The controller state is S_SCHAR or S_RUN
63226127Skarels */
63326135Skarels
63426127Skarels /*
63526127Skarels * If the error bit is set in the SA register then print an error
63626127Skarels * message and reinitialize the controller.
63726127Skarels */
63826127Skarels if (tmscpaddr->tmscpsa&TMSCP_ERR)
63926127Skarels {
64026135Skarels printf("tmscp%d: fatal error (%o)\n", d, tmscpaddr->tmscpsa&0xffff);
64126127Skarels tmscpaddr->tmscpip = 0;
64226127Skarels wakeup((caddr_t)um);
64326127Skarels }
64426127Skarels /*
64526127Skarels * Check for a buffer purge request. (Won't happen w/ TK50 on Q22 bus)
64626127Skarels */
64726127Skarels if (tm->tmscp_ca.ca_bdp)
64826127Skarels {
64926370Skarels UBAPURGE(um->um_hd->uh_uba, tm->tmscp_ca.ca_bdp);
65026127Skarels tm->tmscp_ca.ca_bdp = 0;
65126127Skarels tmscpaddr->tmscpsa = 0; /* signal purge complete */
65226127Skarels }
65326135Skarels
65426127Skarels /*
65526127Skarels * Check for response ring transition.
65626127Skarels */
65726127Skarels if (tm->tmscp_ca.ca_rspint)
65826127Skarels {
65926127Skarels tm->tmscp_ca.ca_rspint = 0;
66026127Skarels for (i = sc->sc_lastrsp;; i++)
66126127Skarels {
66226127Skarels i %= NRSP;
66326127Skarels if (tm->tmscp_ca.ca_rspdsc[i]&TMSCP_OWN)
66426127Skarels break;
66526127Skarels tmscprsp(um, tm, sc, i);
66626127Skarels tm->tmscp_ca.ca_rspdsc[i] |= TMSCP_OWN;
66726127Skarels }
66826127Skarels sc->sc_lastrsp = i;
66926127Skarels }
67026135Skarels
67126127Skarels /*
67226127Skarels * Check for command ring transition.
67326127Skarels */
67426127Skarels if (tm->tmscp_ca.ca_cmdint)
67526127Skarels {
67626127Skarels # ifdef DEBUG
67726127Skarels printd("tmscpintr: command ring transition\n");
67826127Skarels # endif
67926127Skarels tm->tmscp_ca.ca_cmdint = 0;
68026127Skarels }
68126127Skarels if(tmscp_cp_wait)
68226370Skarels wakeup((caddr_t)&tmscp_cp_wait);
68326127Skarels (void) tmscpstart(um);
68426127Skarels }
68526135Skarels
68626135Skarels
68726127Skarels /*
68826127Skarels * Open a tmscp device and set the unit online. If the controller is not
68926127Skarels * in the run state, call init to initialize the tmscp controller first.
69026127Skarels */
69126135Skarels
69226293Skarels /* ARGSUSED */
tmscpopen(dev,flag)69326127Skarels tmscpopen(dev, flag)
69426127Skarels dev_t dev;
69526127Skarels int flag;
69626127Skarels {
69726127Skarels register int unit;
69826127Skarels register struct uba_device *ui;
69926127Skarels register struct tmscp_softc *sc;
70026135Skarels register struct tms_info *tms;
70126127Skarels register struct mscp *mp;
70226127Skarels register struct uba_ctlr *um;
70326127Skarels struct tmscpdevice *tmscpaddr;
70426127Skarels int s,i;
70526127Skarels
70626127Skarels unit = TMSUNIT(dev);
70726127Skarels # ifdef DEBUG
70826127Skarels printd("tmscpopen unit %d\n",unit);
70926127Skarels if(tmscpdebug)DELAY(10000);
71026127Skarels # endif
71126135Skarels if (unit >= NTMS || (ui = tmsdinfo[unit]) == 0 || ui->ui_alive == 0)
71226127Skarels return (ENXIO);
71326135Skarels tms = &tms_info[ui->ui_unit];
71426135Skarels if (tms->tms_openf)
71526135Skarels return (EBUSY);
71626127Skarels sc = &tmscp_softc[ui->ui_ctlr];
71726135Skarels tms->tms_openf = 1;
71844394Smarc tms->tms_tpr = tprintf_open();
71926127Skarels s = spl5();
72026127Skarels if (sc->sc_state != S_RUN)
72126127Skarels {
72226127Skarels if (sc->sc_state == S_IDLE)
72326127Skarels if(!tmscpinit(ui->ui_ctlr))
72426127Skarels {
72526127Skarels printf("tmscp controller failed to init\n");
72626127Skarels (void) splx(s);
72730917Skarels tms->tms_openf = 0;
72826127Skarels return(ENXIO);
72926127Skarels }
73026127Skarels /*
73126127Skarels * Wait for initialization to complete
73226127Skarels */
73326127Skarels timeout(wakeup,(caddr_t)ui->ui_mi,11*hz); /* to be sure*/
73426127Skarels sleep((caddr_t)ui->ui_mi, 0);
73526127Skarels if (sc->sc_state != S_RUN)
73626127Skarels {
73726127Skarels (void) splx(s);
73826135Skarels tms->tms_openf = 0;
73926127Skarels return (EIO);
74026127Skarels }
74126127Skarels }
74226127Skarels /*
74326127Skarels * Check to see if the device is really there.
74426127Skarels * this code was taken from Fred Canters 11 driver
74526127Skarels */
74626127Skarels um = ui->ui_mi;
74726127Skarels tmscpaddr = (struct tmscpdevice *) um->um_addr;
74826127Skarels (void) splx(s);
74926127Skarels if(ui->ui_flags == 0)
75026127Skarels {
75126127Skarels s = spl5();
75226127Skarels while(0 ==(mp = tmscpgetcp(um)))
75326127Skarels {
75426127Skarels tmscp_cp_wait++;
75526370Skarels sleep((caddr_t)&tmscp_cp_wait,PSWP+1);
75626127Skarels tmscp_cp_wait--;
75726127Skarels }
75826127Skarels (void) splx(s);
75926127Skarels mp->mscp_opcode = M_OP_ONLIN;
76026127Skarels mp->mscp_unit = ui->ui_slave;
76126135Skarels mp->mscp_cmdref = (long) & tms->tms_type;
76226127Skarels /* need to sleep on something */
76326127Skarels # ifdef DEBUG
76426127Skarels printd("tmscpopen: bring unit %d online\n",ui->ui_unit);
76526127Skarels # endif
76626127Skarels *((long *) mp->mscp_dscptr ) |= TMSCP_OWN | TMSCP_INT;
76726127Skarels i = tmscpaddr->tmscpip;
76826293Skarels #ifdef lint
76926293Skarels i = i;
77026293Skarels #endif
77126127Skarels /*
77226127Skarels * To make sure we wake up, timeout in 240 seconds.
77326127Skarels * Wakeup in tmscprsp routine.
77426127Skarels * 240 seconds (4 minutes) is necessary since a rewind
77526127Skarels * can take a few minutes.
77626127Skarels */
77726127Skarels timeout(wakeup,(caddr_t) mp->mscp_cmdref,240 * hz);
77826127Skarels sleep((caddr_t) mp->mscp_cmdref,PSWP+1);
77926127Skarels }
78026135Skarels if(ui->ui_flags == 0) {
78126135Skarels tms->tms_openf = 0;
78226127Skarels return(ENXIO); /* Didn't go online */
78326135Skarels }
78426135Skarels tms->tms_lastiow = 0;
78526127Skarels /*
78626127Skarels * If the high density device is not specified, set unit to low
78726127Skarels * density. This is done as an "internal" ioctl command so
78826127Skarels * that the command setup and response handling
78926127Skarels * is done thru "regular" command routines.
79026127Skarels */
79126127Skarels if ((minor(dev) & T_HIDENSITY) == 0)
79226127Skarels tmscpcommand(dev, TMS_LOWDENSITY, 1);
79326127Skarels else
79426127Skarels tmscpcommand(dev, TMS_HIDENSITY, 1);
79526127Skarels return (0);
79626127Skarels }
79726135Skarels
79826135Skarels
79926127Skarels /*
80026127Skarels * Close tape device.
80126127Skarels *
80226127Skarels * If tape was open for writing or last operation was
80326127Skarels * a write, then write two EOF's and backspace over the last one.
80426127Skarels * Unless this is a non-rewinding special file, rewind the tape.
80526127Skarels *
80626127Skarels * NOTE:
80726127Skarels * We want to be sure that any serious exception is cleared on the
80826127Skarels * close. A Clear Serious Exception (CSE) modifier is always done on
80926127Skarels * the rewind command. For the non-rewind case we check to see if the
81026127Skarels * "serex" field is set in the softc struct; if it is then issue a noop
81126127Skarels * command with the CSE modifier.
81226127Skarels * Make the tape available to others, by clearing openf flag.
81326127Skarels */
tmscpclose(dev,flag)81426127Skarels tmscpclose(dev, flag)
81526127Skarels register dev_t dev;
81626127Skarels register flag;
81726127Skarels {
81826135Skarels register struct tms_info *tms;
81926127Skarels register struct uba_device *ui;
82026135Skarels
82126127Skarels ui = tmsdinfo[TMSUNIT(dev)];
82226127Skarels # ifdef DEBUG
82326127Skarels printd("tmscpclose: ctlr = %d\n",TMSCPCTLR(dev));
82426127Skarels printd("tmscpclose: unit = %d\n",TMSUNIT(dev));
82526127Skarels if(tmscpdebug)DELAY(10000);
82626127Skarels # endif
82726135Skarels tms = &tms_info[ui->ui_unit];
82826135Skarels if (flag == FWRITE || (flag&FWRITE) && tms->tms_lastiow)
82926127Skarels {
83026127Skarels /* device, command, count */
83126127Skarels tmscpcommand (dev, TMS_WRITM, 1);
83226127Skarels tmscpcommand (dev, TMS_WRITM, 1);
83326127Skarels tmscpcommand (dev, TMS_BSR, 1);
83426127Skarels }
83526127Skarels if ((minor(dev)&T_NOREWIND) == 0)
83626127Skarels /*
83726127Skarels * Don't hang waiting for rewind complete.
83826127Skarels */
83926127Skarels tmscpcommand(dev, TMS_REW, 0);
84026127Skarels else
84126135Skarels if (tms->tms_serex)
84226127Skarels {
84326127Skarels # ifdef DEBUG
84426127Skarels printd("tmscpclose: clearing serex\n");
84526127Skarels if(tmscpdebug)DELAY(10000);
84626127Skarels # endif
84726127Skarels tmscpcommand(dev, TMS_CSE, 1);
84826127Skarels }
84944394Smarc tprintf_close(tms->tms_tpr);
85026135Skarels tms->tms_openf = 0;
85140814Smarc return (0);
85226127Skarels }
85326135Skarels
85426135Skarels
85526127Skarels /*
85626127Skarels * Execute a command on the tape drive a specified number of times.
85726127Skarels * This routine sets up a buffer and calls the strategy routine which
85826127Skarels * links the buffer onto the drive's buffer queue.
85926127Skarels * The start routine will take care of creating a tmscp command packet
86026127Skarels * with the command. The start routine is called by the strategy or the
86126127Skarels * interrupt routine.
86226127Skarels */
86326135Skarels
tmscpcommand(dev,com,count)86426127Skarels tmscpcommand (dev, com, count)
86526127Skarels register dev_t dev;
86626127Skarels int com, count;
86726127Skarels {
86826127Skarels register struct uba_device *ui;
86926127Skarels register struct buf *bp;
87026127Skarels register int s;
87126127Skarels int unit = TMSUNIT(dev);
87226135Skarels
87326127Skarels ui = tmsdinfo[unit];
87426127Skarels bp = &ctmscpbuf[ui->ui_ctlr];
87526135Skarels
87626127Skarels s = spl5();
87726127Skarels while (bp->b_flags&B_BUSY)
87826127Skarels {
87926127Skarels /*
88026127Skarels * This special check is because B_BUSY never
88126127Skarels * gets cleared in the non-waiting rewind case.
88226127Skarels */
88326127Skarels if (bp->b_bcount == 0 && (bp->b_flags&B_DONE))
88426127Skarels break;
88526127Skarels bp->b_flags |= B_WANTED;
88626127Skarels sleep((caddr_t)bp, PRIBIO);
88726127Skarels }
88826127Skarels bp->b_flags = B_BUSY|B_READ;
88926127Skarels splx(s);
89026127Skarels /*
89126127Skarels * Load the buffer. The b_count field gets used to hold the command
89226127Skarels * count. the b_resid field gets used to hold the command mneumonic.
89326127Skarels * These 2 fields are "known" to be "safe" to use for this purpose.
89426127Skarels * (Most other drivers also use these fields in this way.)
89526127Skarels */
89626127Skarels bp->b_dev = dev;
89726127Skarels bp->b_bcount = count;
89826127Skarels bp->b_resid = com;
89926127Skarels bp->b_blkno = 0;
90026127Skarels tmscpstrategy(bp);
90126127Skarels /*
90226127Skarels * In case of rewind from close, don't wait.
90326127Skarels * This is the only case where count can be 0.
90426127Skarels */
90526127Skarels if (count == 0)
90626127Skarels return;
90726127Skarels iowait(bp);
90826127Skarels if (bp->b_flags&B_WANTED)
90926127Skarels wakeup((caddr_t)bp);
91026127Skarels bp->b_flags &= B_ERROR;
91126127Skarels }
91226135Skarels
91326127Skarels /*
91426127Skarels * Find an unused command packet
91526127Skarels */
91626127Skarels struct mscp *
tmscpgetcp(um)91726127Skarels tmscpgetcp(um)
91826127Skarels struct uba_ctlr *um;
91926127Skarels {
92026127Skarels register struct mscp *mp;
92126127Skarels register struct tmscpca *cp;
92226127Skarels register struct tmscp_softc *sc;
92326127Skarels register int i;
92426127Skarels int s;
92526135Skarels
92626127Skarels s = spl5();
92726127Skarels cp = &tmscp[um->um_ctlr].tmscp_ca;
92826127Skarels sc = &tmscp_softc[um->um_ctlr];
92926127Skarels /*
93026127Skarels * If no credits, can't issue any commands
93126127Skarels * until some outstanding commands complete.
93226127Skarels */
93326127Skarels i = sc->sc_lastcmd;
93426127Skarels # ifdef DEBUG
93526127Skarels printd10("tmscpgetcp: %d credits remain\n", sc->sc_credits);
93626127Skarels # endif
93726127Skarels if(((cp->ca_cmddsc[i]&(TMSCP_OWN|TMSCP_INT))==TMSCP_INT) &&
93826127Skarels (sc->sc_credits >= 2))
93926127Skarels {
94026127Skarels sc->sc_credits--; /* This commits to issuing a command */
94126127Skarels cp->ca_cmddsc[i] &= ~TMSCP_INT;
94226127Skarels mp = &tmscp[um->um_ctlr].tmscp_cmd[i];
94326127Skarels mp->mscp_unit = mp->mscp_modifier = 0;
94426127Skarels mp->mscp_opcode = mp->mscp_flags = 0;
94526127Skarels mp->mscp_bytecnt = mp->mscp_buffer = 0;
94626127Skarels sc->sc_lastcmd = (i + 1) % NCMD;
94726127Skarels (void) splx(s);
94826127Skarels return(mp);
94926127Skarels }
95026127Skarels (void) splx(s);
95126127Skarels return(NULL);
95226127Skarels }
95326135Skarels
95426135Skarels
95526127Skarels /*
95626127Skarels * Initialize a TMSCP device. Set up UBA mapping registers,
95726127Skarels * initialize data structures, and start hardware
95826127Skarels * initialization sequence.
95926127Skarels */
tmscpinit(d)96026127Skarels tmscpinit (d)
96126127Skarels int d; /* index to the controller */
96226127Skarels {
96326127Skarels register struct tmscp_softc *sc;
96426135Skarels register struct tmscp *t; /* communications area; cmd & resp packets */
96526127Skarels struct tmscpdevice *tmscpaddr;
96626127Skarels struct uba_ctlr *um;
96726135Skarels
96826127Skarels sc = &tmscp_softc[d];
96926127Skarels um = tmscpminfo[d];
97026127Skarels um->um_tab.b_active++;
97126127Skarels t = &tmscp[d];
97226127Skarels tmscpaddr = (struct tmscpdevice *)um->um_addr;
97326127Skarels if (sc->sc_mapped == 0)
97426127Skarels {
97526127Skarels /*
97626127Skarels * Map the communications area and command
97726127Skarels * and response packets into Unibus address
97826127Skarels * space.
97926127Skarels */
98026135Skarels sc->sc_ubainfo = uballoc(um->um_ubanum, (caddr_t)t, sizeof (struct tmscp), 0);
98136035Skarels sc->sc_tmscp = (struct tmscp *)(UBAI_ADDR(sc->sc_ubainfo));
98226127Skarels sc->sc_mapped = 1;
98326127Skarels }
98426135Skarels
98526127Skarels /*
98626127Skarels * Start the hardware initialization sequence.
98726127Skarels */
98826127Skarels tmscpaddr->tmscpip = 0; /* start initialization */
98926135Skarels
99026127Skarels while((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0)
99126127Skarels {
99226127Skarels # ifdef DEBUG
99326127Skarels printd("tmscpinit: tmscpsa = 0%o\n",tmscpaddr->tmscpsa);
99426127Skarels DELAY(100000);
99526127Skarels # endif
99626127Skarels if(tmscpaddr->tmscpsa & TMSCP_ERR)
99726127Skarels return(0); /* CHECK */
99826127Skarels }
99926135Skarels tmscpaddr->tmscpsa=TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8)|TMSCP_IE|(sc->sc_ivec/4);
100026127Skarels /*
100126127Skarels * Initialization continues in the interrupt routine.
100226127Skarels */
100326127Skarels sc->sc_state = S_STEP1;
100426127Skarels sc->sc_credits = 0;
100526127Skarels return(1);
100626127Skarels }
100726135Skarels
100826135Skarels
100926127Skarels /*
101026127Skarels * Start I/O operation
101126127Skarels * This code is convoluted. The majority of it was copied from the uda driver.
101226127Skarels */
101326135Skarels
tmscpstart(um)101426127Skarels tmscpstart(um)
101526127Skarels register struct uba_ctlr *um;
101626127Skarels {
101726127Skarels register struct buf *bp, *dp;
101826127Skarels register struct mscp *mp;
101926127Skarels register struct tmscp_softc *sc;
102026135Skarels register struct tms_info *tms;
102126127Skarels register struct uba_device *ui;
102226127Skarels struct tmscpdevice *tmscpaddr;
102326127Skarels struct tmscp *tm = &tmscp[um->um_ctlr];
102426127Skarels int i,tempi;
102526127Skarels char ioctl; /* flag: set true if its an IOCTL command */
102626135Skarels
102726127Skarels sc = &tmscp_softc[um->um_ctlr];
102826127Skarels
102926127Skarels for(;;)
103026127Skarels {
103126127Skarels if ((dp = um->um_tab.b_actf) == NULL)
103226127Skarels {
103326127Skarels /*
103426127Skarels * Release unneeded UBA resources and return
103526127Skarels * (drive was inactive)
103626127Skarels */
103726127Skarels um->um_tab.b_active = 0;
103826127Skarels break;
103926127Skarels }
104026127Skarels if ((bp = dp->b_actf) == NULL)
104126127Skarels {
104226127Skarels /*
104326127Skarels * No more requests for this drive, remove
104426127Skarels * from controller queue and look at next drive.
104526127Skarels * We know we're at the head of the controller queue.
104626127Skarels */
104726127Skarels dp->b_active = 0;
104826127Skarels um->um_tab.b_actf = dp->b_forw;
104926127Skarels continue; /* Need to check for loop */
105026127Skarels }
105126127Skarels um->um_tab.b_active++;
105226127Skarels tmscpaddr = (struct tmscpdevice *)um->um_addr;
105326135Skarels ui = tmsdinfo[(TMSUNIT(bp->b_dev))];
105426135Skarels tms = &tms_info[ui->ui_unit];
105526127Skarels if ((tmscpaddr->tmscpsa&TMSCP_ERR) || sc->sc_state != S_RUN)
105626127Skarels {
105744394Smarc tprintf(tms->tms_tpr,
105826135Skarels "tms%d: hard error bn%d\n",
105926135Skarels minor(bp->b_dev)&03, bp->b_blkno);
106026135Skarels log(TMS_PRI, "tmscp%d: sa 0%o, state %d\n",um->um_ctlr,
106126127Skarels tmscpaddr->tmscpsa&0xffff, sc->sc_state);
106226370Skarels (void)tmscpinit(um->um_ctlr);
106326127Skarels /* SHOULD REQUEUE OUTSTANDING REQUESTS, LIKE TMSCPRESET */
106426127Skarels break;
106526127Skarels }
106626127Skarels /*
106726127Skarels * Default is that last command was NOT a write command;
106826127Skarels * if a write command is done it will be detected in tmscprsp.
106926127Skarels */
107026135Skarels tms->tms_lastiow = 0;
107126127Skarels if (ui->ui_flags == 0)
107226127Skarels { /* not online */
107326127Skarels if ((mp = tmscpgetcp(um)) == NULL)
107426127Skarels break;
107526127Skarels mp->mscp_opcode = M_OP_ONLIN;
107626127Skarels mp->mscp_unit = ui->ui_slave;
107726127Skarels dp->b_active = 2;
107826127Skarels um->um_tab.b_actf = dp->b_forw; /* remove from controller q */
107926127Skarels *((long *)mp->mscp_dscptr) |= TMSCP_OWN|TMSCP_INT;
108026127Skarels if (tmscpaddr->tmscpsa&TMSCP_ERR)
108126127Skarels printf("tmscp%d fatal error (0%o)\n",um->um_ctlr,
108226127Skarels tmscpaddr->tmscpsa&0xffff);
108326127Skarels i = tmscpaddr->tmscpip;
108426127Skarels continue;
108526127Skarels }
108626127Skarels switch (cpu) {
108726135Skarels
108826127Skarels case VAX_8600:
108926127Skarels case VAX_780:
109026127Skarels i = UBA_NEEDBDP|UBA_CANTWAIT;
109126127Skarels break;
109226127Skarels case VAX_750:
109326127Skarels i = um->um_ubinfo|UBA_HAVEBDP|UBA_CANTWAIT;
109426127Skarels break;
109526127Skarels case VAX_730:
109636556Smckusick case VAX_630:
109726127Skarels i = UBA_CANTWAIT;
109826127Skarels break;
109926127Skarels } /* end switch (cpu) */
110026127Skarels /*
110126135Skarels * If command is an ioctl command then set the ioctl flag for later use.
110226127Skarels * If not (i.e. it is a read or write) then attempt
110326127Skarels * to set up a buffer pointer.
110426127Skarels */
110526127Skarels ioctl = 0;
110626127Skarels if (bp == &ctmscpbuf[um->um_ctlr])
110726127Skarels ioctl = 1;
110826127Skarels else
110926127Skarels if ((i = ubasetup(um->um_ubanum, bp, i)) == 0)
111026127Skarels {
111126127Skarels if(dp->b_qsize != 0)
111226127Skarels break; /* When a command completes and */
111326135Skarels /* frees a bdp tmscpstart will be called */
111426127Skarels if ((mp = tmscpgetcp(um)) == NULL)
111526127Skarels break;
111626127Skarels # ifdef DEBUG
111726135Skarels printd("tmscpstart: GTUNT %d ubasetup = %d\n",ui->ui_unit, i);
111826127Skarels if(tmscpdebug)DELAY(10000);
111926127Skarels # endif
112026127Skarels mp->mscp_opcode = M_OP_GTUNT;
112126127Skarels mp->mscp_unit = ui->ui_slave;
112226127Skarels *((long *)mp->mscp_dscptr) |= TMSCP_OWN|TMSCP_INT;
112326127Skarels if (tmscpaddr->tmscpsa&TMSCP_ERR)
112426135Skarels printf("tmscp%d: fatal error (0%o)\n",um->um_ctlr,
112526127Skarels tmscpaddr->tmscpsa&0xffff);
112626127Skarels i = tmscpaddr->tmscpip; /* initiate polling */
112726127Skarels break;
112826127Skarels }
112926135Skarels # if defined(VAX750)
113026135Skarels if (cpu == VAX_750)
113126127Skarels tempi = i & 0xfffffff; /* mask off bdp */
113226127Skarels else
113326127Skarels # endif
113426127Skarels tempi = i;
113526127Skarels if ((mp = tmscpgetcp(um)) == NULL)
113626127Skarels {
113726127Skarels if (!ioctl) /* only need to release if NOT ioctl */
113826127Skarels ubarelse(um->um_ubanum,&tempi);
113926127Skarels break;
114026127Skarels }
114126127Skarels mp->mscp_cmdref = (long)bp; /* pointer to get back */
114226127Skarels mp->mscp_unit = ui->ui_slave;
114326127Skarels /*
114426127Skarels * If its an ioctl-type command then set up the appropriate
114526127Skarels * tmscp command; by doing a switch on the "b_resid" field where
114626127Skarels * the command mneumonic is stored.
114726127Skarels */
114826127Skarels if (ioctl)
114926127Skarels {
115026127Skarels # ifdef DEBUG
115126127Skarels printd("tmscpstart: doing ioctl cmd %d\n", bp->b_resid);
115226127Skarels # endif
115326127Skarels /*
115426127Skarels * The reccnt and tmkcnt fields are set to zero by the getcp
115526127Skarels * routine (as bytecnt and buffer fields). Thus reccnt and
115626127Skarels * tmkcnt are only modified here if they need to be set to
115726127Skarels * a non-zero value.
115826127Skarels */
115926293Skarels switch ((int)bp->b_resid) {
116026135Skarels
116126127Skarels case TMS_WRITM:
116226127Skarels mp->mscp_opcode = M_OP_WRITM;
116326127Skarels break;
116426127Skarels case TMS_FSF:
116526127Skarels mp->mscp_opcode = M_OP_REPOS;
116626127Skarels mp->mscp_tmkcnt = bp->b_bcount;
116726127Skarels break;
116826127Skarels case TMS_BSF:
116926127Skarels mp->mscp_opcode = M_OP_REPOS;
117026127Skarels mp->mscp_modifier = M_MD_REVRS;
117126127Skarels mp->mscp_tmkcnt = bp->b_bcount;
117226127Skarels break;
117326127Skarels case TMS_FSR:
117426127Skarels mp->mscp_opcode = M_OP_REPOS;
117526127Skarels mp->mscp_modifier = M_MD_OBJCT;
117626127Skarels mp->mscp_reccnt = bp->b_bcount;
117726127Skarels break;
117826127Skarels case TMS_BSR:
117926127Skarels mp->mscp_opcode = M_OP_REPOS;
118026127Skarels mp->mscp_modifier = M_MD_REVRS | M_MD_OBJCT;
118126127Skarels mp->mscp_reccnt = bp->b_bcount;
118226127Skarels break;
118326127Skarels /*
118426127Skarels * Clear serious exception is done for Rewind & Available cmds
118526127Skarels */
118626127Skarels case TMS_REW:
118726127Skarels mp->mscp_opcode = M_OP_REPOS;
118826127Skarels mp->mscp_modifier = M_MD_REWND | M_MD_CLSEX;
118926127Skarels if (bp->b_bcount == 0)
119026127Skarels mp->mscp_modifier |= M_MD_IMMED;
119126135Skarels tms->tms_serex = 0;
119226127Skarels break;
119326127Skarels case TMS_OFFL:
119426127Skarels mp->mscp_opcode = M_OP_AVAIL;
119526127Skarels mp->mscp_modifier = M_MD_UNLOD | M_MD_CLSEX;
119626135Skarels tms->tms_serex = 0;
119726127Skarels break;
119826127Skarels case TMS_SENSE:
119926127Skarels mp->mscp_opcode = M_OP_GTUNT;
120026127Skarels break;
120126127Skarels case TMS_CACHE:
120226127Skarels mp->mscp_opcode = M_OP_STUNT;
120326135Skarels tms->tms_unitflgs |= M_UF_WBKNV;
120426135Skarels mp->mscp_unitflgs = tms->tms_unitflgs;
120526135Skarels mp->mscp_format = tms->tms_format;
120626127Skarels /* default device dependant parameters */
120726127Skarels mp->mscp_mediaid = 0;
120826127Skarels break;
120926127Skarels case TMS_NOCACHE:
121026127Skarels mp->mscp_opcode = M_OP_STUNT;
121126135Skarels tms->tms_unitflgs &= ~(M_UF_WBKNV);
121226135Skarels mp->mscp_unitflgs = tms->tms_unitflgs;
121326135Skarels mp->mscp_format = tms->tms_format;
121426127Skarels /* default device dependant parameters */
121526127Skarels mp->mscp_mediaid = 0;
121626127Skarels break;
121726127Skarels case TMS_CSE:
121826127Skarels /*
121926127Skarels * This is a no-op command. It performs a
122026127Skarels * clear serious exception only. (Done on a
122126127Skarels * non-rewinding close after a serious exception.)
122226127Skarels */
122326127Skarels mp->mscp_opcode = M_OP_REPOS;
122426127Skarels mp->mscp_modifier = M_MD_CLSEX;
122526135Skarels tms->tms_serex = 0;
122626135Skarels tms->tms_clserex = 1;
122726127Skarels break;
122826127Skarels case TMS_LOWDENSITY:
122926127Skarels /*
123026127Skarels * Set the unit to low density
123126127Skarels */
123226127Skarels mp->mscp_opcode = M_OP_STUNT;
123326135Skarels mp->mscp_unitflgs = tms->tms_unitflgs;
123426135Skarels mp->mscp_mediaid = 0; /* default device dependant parameters */
123526135Skarels if ((tms->tms_fmtmenu & M_TF_800) != 0)
123626127Skarels mp->mscp_format = M_TF_800;
123726127Skarels else
123826135Skarels mp->mscp_format = M_TF_PE & tms->tms_fmtmenu;
123926135Skarels tms->tms_format = mp->mscp_format;
124026127Skarels break;
124126127Skarels case TMS_HIDENSITY:
124226127Skarels /*
124326127Skarels * Set the unit to high density (format == 0)
124426127Skarels */
124526127Skarels mp->mscp_opcode = M_OP_STUNT;
124626135Skarels mp->mscp_unitflgs = tms->tms_unitflgs;
124726135Skarels mp->mscp_mediaid = 0; /* default device dependant parameters */
124826127Skarels mp->mscp_format = 0;
124926135Skarels tms->tms_format = 0;
125026127Skarels break;
125126127Skarels default:
125226127Skarels printf("Bad ioctl on tms unit %d\n", ui->ui_unit);
125326127Skarels /* Need a no-op. Reposition no amount */
125426127Skarels mp->mscp_opcode = M_OP_REPOS;
125526127Skarels break;
125626127Skarels } /* end switch (bp->b_resid) */
125726127Skarels }
125826127Skarels else /* Its a read/write command (not an ioctl) */
125926127Skarels {
126026127Skarels mp->mscp_opcode = bp->b_flags&B_READ ? M_OP_READ : M_OP_WRITE;
126126127Skarels mp->mscp_bytecnt = bp->b_bcount;
126236035Skarels mp->mscp_buffer = UBAI_ADDR(i) | (UBAI_BDP(i) << 24);
126326135Skarels
126426127Skarels bp->b_ubinfo = tempi; /* save mapping info */
126526127Skarels }
126626135Skarels if (tms->tms_serex == 2) /* if tape mark read */
126726127Skarels {
126826135Skarels mp->mscp_modifier |= M_MD_CLSEX; /* clear serious exc */
126926135Skarels tms->tms_serex = 0;
127026127Skarels }
127126127Skarels *((long *)mp->mscp_dscptr) |= TMSCP_OWN|TMSCP_INT;
127226127Skarels # ifdef DEBUG
127326135Skarels printd("tmscpstart: opcode 0%o mod %o unit %d cnt %d\n",mp->mscp_opcode,mp->mscp_modifier,mp->mscp_unit,mp->mscp_bytecnt);
127426127Skarels if(tmscpdebug)DELAY(100000);
127526127Skarels # endif
127626127Skarels i = tmscpaddr->tmscpip; /* initiate polling */
127726127Skarels dp->b_qsize++;
127826127Skarels /*
127926127Skarels * Move drive to the end of the controller queue
128026127Skarels */
128126127Skarels if (dp->b_forw != NULL)
128226127Skarels {
128326127Skarels um->um_tab.b_actf = dp->b_forw;
128426127Skarels um->um_tab.b_actl->b_forw = dp;
128526127Skarels um->um_tab.b_actl = dp;
128626127Skarels dp->b_forw = NULL;
128726127Skarels }
128826127Skarels /*
128926127Skarels * Move buffer to I/O wait queue
129026127Skarels */
129126127Skarels dp->b_actf = bp->av_forw;
129226127Skarels dp = &tmscpwtab[um->um_ctlr];
129326127Skarels bp->av_forw = dp;
129426127Skarels bp->av_back = dp->av_back;
129526127Skarels dp->av_back->av_forw = bp;
129626127Skarels dp->av_back = bp;
129726127Skarels if (tmscpaddr->tmscpsa&TMSCP_ERR)
129826127Skarels {
129926135Skarels printf("tmscp%d: fatal error (0%o)\n", um->um_ctlr, tmscpaddr->tmscpsa&0xffff);
130026370Skarels (void)tmscpinit(um->um_ctlr);
130126127Skarels break;
130226127Skarels }
130326127Skarels } /* end for */
130426127Skarels /*
130526127Skarels * Check for response ring transitions lost in the
130626127Skarels * Race condition
130726127Skarels */
130826127Skarels for (i = sc->sc_lastrsp;; i++)
130926127Skarels {
131026127Skarels i %= NRSP;
131126127Skarels if (tm->tmscp_ca.ca_rspdsc[i]&TMSCP_OWN)
131226127Skarels break;
131326127Skarels tmscprsp(um, tm, sc, i);
131426127Skarels tm->tmscp_ca.ca_rspdsc[i] |= TMSCP_OWN;
131526127Skarels }
131626127Skarels sc->sc_lastrsp = i;
131726127Skarels }
131826135Skarels
131926135Skarels
132026127Skarels /*
132126127Skarels * Process a response packet
132226127Skarels */
tmscprsp(um,tm,sc,i)132326127Skarels tmscprsp(um, tm, sc, i)
132426127Skarels register struct uba_ctlr *um;
132526127Skarels register struct tmscp *tm;
132626127Skarels register struct tmscp_softc *sc;
132726127Skarels int i;
132826127Skarels {
132926127Skarels register struct mscp *mp;
133026135Skarels register struct tms_info *tms;
133126127Skarels struct uba_device *ui;
133226293Skarels struct buf *dp, *bp;
133326127Skarels int st;
133426135Skarels
133526127Skarels mp = &tm->tmscp_rsp[i];
133626127Skarels mp->mscp_header.tmscp_msglen = mscp_msglen;
133726135Skarels sc->sc_credits += mp->mscp_header.tmscp_credits & 0xf; /* low 4 bits */
133826127Skarels if ((mp->mscp_header.tmscp_credits & 0xf0) > 0x10) /* Check */
133926127Skarels return;
134026127Skarels # ifdef DEBUG
134126135Skarels printd("tmscprsp, opcode 0%o status 0%o\n",mp->mscp_opcode,mp->mscp_status&M_ST_MASK);
134226127Skarels # endif
134326127Skarels /*
134426127Skarels * If it's an error log message (datagram),
134526127Skarels * pass it on for more extensive processing.
134626127Skarels */
134726127Skarels if ((mp->mscp_header.tmscp_credits & 0xf0) == 0x10)
134826127Skarels { /* check */
134926127Skarels tmserror(um, (struct mslg *)mp);
135026127Skarels return;
135126127Skarels }
135226127Skarels st = mp->mscp_status&M_ST_MASK;
135326127Skarels /*
135426127Skarels * The controller interrupts as drive 0.
135526127Skarels * This means that you must check for controller interrupts
135626127Skarels * before you check to see if there is a drive 0.
135726127Skarels */
135826127Skarels if((M_OP_STCON|M_OP_END) == mp->mscp_opcode)
135926127Skarels {
136026127Skarels if (st == M_ST_SUCC)
136126127Skarels {
136226127Skarels # ifdef DEBUG
136326135Skarels printd("ctlr has %d credits\n", mp->mscp_header.tmscp_credits & 0xf);
136426127Skarels printd("ctlr timeout = %d\n", mp->mscp_cnttmo);
136526127Skarels # endif
136626127Skarels sc->sc_state = S_RUN;
136726127Skarels }
136826127Skarels else
136926127Skarels sc->sc_state = S_IDLE;
137026127Skarels um->um_tab.b_active = 0;
137126127Skarels wakeup((caddr_t)um);
137226127Skarels return;
137326127Skarels }
137426135Skarels if (mp->mscp_unit >= NTMS)
137526127Skarels return;
137626127Skarels if ((ui = tmscpip[um->um_ctlr][mp->mscp_unit]) == 0)
137726127Skarels return;
137826135Skarels tms = &tms_info[ui->ui_unit];
137926127Skarels /*
138026127Skarels * Save endcode, endflags, and status for mtioctl get unit status.
138126127Skarels * NOTE: Don't do this on Clear serious exception (reposition no-op);
138226127Skarels * which is done on close since this would
138326127Skarels * overwrite the real status we want.
138426127Skarels */
138526135Skarels if (tms->tms_clserex != 1)
138626127Skarels {
138726135Skarels tms->tms_endcode = mp->mscp_opcode;
138826135Skarels tms->tms_flags = mp->mscp_flags;
138926135Skarels tms->tms_status = st;
139026127Skarels }
139126135Skarels else tms->tms_clserex = 0;
139226135Skarels
139326127Skarels switch (mp->mscp_opcode) {
139426127Skarels case M_OP_ONLIN|M_OP_END:
139526135Skarels tms->tms_type = mp->mscp_mediaid;
139626127Skarels dp = &tmsutab[ui->ui_unit];
139726127Skarels if (st == M_ST_SUCC)
139826127Skarels {
139926127Skarels /*
140026127Skarels * Link the drive onto the controller queue
140126127Skarels */
140226127Skarels dp->b_forw = NULL;
140326127Skarels if (um->um_tab.b_actf == NULL)
140426127Skarels um->um_tab.b_actf = dp;
140526127Skarels else
140626127Skarels um->um_tab.b_actl->b_forw = dp;
140726127Skarels um->um_tab.b_actl = dp;
140826127Skarels ui->ui_flags = 1; /* mark it online */
140926135Skarels tms->tms_dsize=(daddr_t)mp->mscp_maxwrt;
141026127Skarels # ifdef DEBUG
141126127Skarels printd("tmscprsp: unit %d online\n", mp->mscp_unit);
141226127Skarels # endif
141326127Skarels /*
141426127Skarels * This define decodes the Media type identifier
141526127Skarels */
141626135Skarels # define F_to_C(x,i) ( ((x)->mscp_mediaid) >> (i*5+7) & 0x1f ? ( ( (((x)->mscp_mediaid) >>( i*5 + 7)) & 0x1f) + 'A' - 1): ' ')
141726127Skarels # ifdef DEBUG
141826127Skarels printd("tmscprsp: unit %d online %x %c%c %c%c%c%d\n"
141926127Skarels ,mp->mscp_unit, mp->mscp_mediaid ,F_to_C(mp,4)
142026127Skarels ,F_to_C(mp,3), F_to_C(mp,2)
142126135Skarels ,F_to_C(mp,1), F_to_C(mp,0), mp->mscp_mediaid & 0x7f);
142226127Skarels # endif
142326127Skarels dp->b_active = 1;
142426127Skarels } /* end if st == M_ST_SUCC */
142526127Skarels else
142626127Skarels {
142726293Skarels if (bp = dp->b_actf)
142844394Smarc tprintf(tms->tms_tpr,
142926135Skarels "tms%d: hard error bn%d: OFFLINE\n",
143026135Skarels minor(bp->b_dev)&03, bp->b_blkno);
143126127Skarels else
143244394Smarc tprintf(tms->tms_tpr,
143326135Skarels "tms%d: hard error: OFFLINE\n",
143426293Skarels ui->ui_unit);
143526127Skarels while (bp = dp->b_actf)
143626127Skarels {
143726127Skarels dp->b_actf = bp->av_forw;
143826127Skarels bp->b_flags |= B_ERROR;
143926127Skarels iodone(bp);
144026127Skarels }
144126127Skarels }
144226127Skarels if(mp->mscp_cmdref!=NULL)
144326127Skarels /* Seems to get lost sometimes in uda */
144426370Skarels wakeup((caddr_t)mp->mscp_cmdref);
144526127Skarels break;
144626127Skarels /*
144726127Skarels * The AVAILABLE ATTENTION message occurs when the
144826127Skarels * unit becomes available after loading,
144926127Skarels * marking the unit offline (ui_flags = 0) will force an
145026127Skarels * online command prior to using the unit.
145126127Skarels */
145226127Skarels case M_OP_AVATN:
145326127Skarels ui->ui_flags = 0;
145426135Skarels tms->tms_type = mp->mscp_mediaid;
145526127Skarels break;
145626127Skarels case M_OP_END:
145726127Skarels /*
145826127Skarels * An endcode without an opcode (0200) is an invalid command.
145926127Skarels * The mscp specification states that this would be a protocol
146026127Skarels * type error, such as illegal opcodes. The mscp spec. also
146126127Skarels * states that parameter error type of invalid commands should
146226135Skarels * return the normal end message for the command. This does not appear
146326135Skarels * to be the case. An invalid logical block number returned an endcode
146426127Skarels * of 0200 instead of the 0241 (read) that was expected.
146526127Skarels */
146626127Skarels
146726127Skarels printf("tmscp%d: invalid cmd, endcode = %o, status=%o\n",
146826127Skarels um->um_ctlr, mp->mscp_opcode, st);
146926127Skarels bp = (struct buf *)mp->mscp_cmdref;
147026127Skarels /*
147126127Skarels * Unlink buffer from I/O wait queue.
147226127Skarels * And signal iodone, so the higher level command can exit!
147326127Skarels *
147426127Skarels */
147526127Skarels bp->av_back->av_forw = bp->av_forw;
147626127Skarels bp->av_forw->av_back = bp->av_back;
147726127Skarels dp = &tmsutab[ui->ui_unit];
147826127Skarels dp->b_qsize--;
147926127Skarels iodone(bp);
148026127Skarels break;
148126127Skarels case M_OP_WRITE|M_OP_END:
148226127Skarels /* mark the last io op as a write */
148326135Skarels tms->tms_lastiow = 1;
148426127Skarels case M_OP_READ|M_OP_END:
148526127Skarels case M_OP_WRITM|M_OP_END:
148626127Skarels case M_OP_REPOS|M_OP_END:
148726127Skarels case M_OP_STUNT|M_OP_END:
148826127Skarels /*
148926127Skarels * The AVAILABLE message occurs when the mt ioctl "rewoffl" is
149026127Skarels * issued. For the ioctl, "rewoffl", a tmscp AVAILABLE command is
149126127Skarels * done with the UNLOAD modifier. This performs a rewind, followed
149226127Skarels * by marking the unit offline. So mark the unit offline
149326127Skarels * software wise as well (ui_flags = 0 and
149426135Skarels * tms->tms_openf = 0).
149526127Skarels */
149626127Skarels case M_OP_AVAIL|M_OP_END:
149726127Skarels # ifdef DEBUG
149826127Skarels printd("tmscprsp: position = %d\n", mp->mscp_lbn);
149926127Skarels # endif
150026127Skarels bp = (struct buf *)mp->mscp_cmdref;
150126127Skarels /*
150226135Skarels * Only need to release buffer if the command was read or write.
150326127Skarels * No ubasetup was done in "tmscpstart" if it was an ioctl cmd.
150426127Skarels */
150526127Skarels if (mp->mscp_opcode == (M_OP_READ|M_OP_END) ||
150626127Skarels mp->mscp_opcode == (M_OP_WRITE|M_OP_END))
150726127Skarels ubarelse(um->um_ubanum, (int *)&bp->b_ubinfo);
150826127Skarels /*
150926127Skarels * Unlink buffer from I/O wait queue.
151026127Skarels */
151126127Skarels bp->av_back->av_forw = bp->av_forw;
151226127Skarels bp->av_forw->av_back = bp->av_back;
151326135Skarels # if defined(VAX750)
151426135Skarels if (cpu == VAX_750) {
151526135Skarels if ((tmscpwtab[um->um_ctlr].av_forw == &tmscpwtab[um->um_ctlr]) &&
151626127Skarels (um->um_ubinfo != 0)) {
151726127Skarels ubarelse(um->um_ubanum, &um->um_ubinfo);
151826127Skarels }
151926127Skarels else {
152026127Skarels if (mp->mscp_opcode == (M_OP_READ|M_OP_END) ||
152126127Skarels mp->mscp_opcode == (M_OP_WRITE|M_OP_END))
152226135Skarels UBAPURGE(uba_hd[um->um_ubanum].uh_uba,(um->um_ubinfo >>28) & 0x0f);
152326127Skarels }
152426127Skarels }
152526127Skarels # endif
152626127Skarels dp = &tmsutab[ui->ui_unit];
152726127Skarels dp->b_qsize--;
152826127Skarels if (st == M_ST_OFFLN || st == M_ST_AVLBL)
152926127Skarels {
153026127Skarels ui->ui_flags = 0; /* mark unit offline */
153126135Skarels tms->tms_openf = 0;
153226135Skarels tms->tms_type = mp->mscp_mediaid;
153326127Skarels /*
153426127Skarels * Link the buffer onto the front of the drive queue
153526127Skarels */
153626127Skarels if ((bp->av_forw = dp->b_actf) == 0)
153726127Skarels dp->b_actl = bp;
153826127Skarels dp->b_actf = bp;
153926127Skarels /*
154026127Skarels * Link the drive onto the controller queue
154126127Skarels */
154226127Skarels if (dp->b_active == 0)
154326127Skarels {
154426127Skarels dp->b_forw = NULL;
154526127Skarels if (um->um_tab.b_actf == NULL)
154626127Skarels um->um_tab.b_actf = dp;
154726127Skarels else
154826127Skarels um->um_tab.b_actl->b_forw = dp;
154926127Skarels um->um_tab.b_actl = dp;
155026127Skarels dp->b_active = 1;
155126127Skarels }
155226135Skarels # if defined(VAX750)
155326135Skarels if (cpu == VAX_750 && um->um_ubinfo == 0)
155426135Skarels um->um_ubinfo = uballoc(um->um_ubanum, (caddr_t)0, 0, UBA_NEEDBDP);
155526127Skarels # endif
155626127Skarels return;
155726127Skarels }
155826127Skarels if (st != M_ST_SUCC)
155926127Skarels {
156026127Skarels if (mp->mscp_flags & M_EF_SEREX)
156126135Skarels tms->tms_serex = 1;
156226127Skarels if (st != M_ST_TAPEM)
156326127Skarels {
156444394Smarc tprintf(tms->tms_tpr,
156526135Skarels "tms%d: hard error bn%d\n",
156626135Skarels minor(bp->b_dev)&03, bp->b_blkno);
156726135Skarels errinfo(st); /* produces more info */
156826127Skarels # ifdef DEBUG
156926135Skarels printd("tmscprsp: error; status sub-code = 0%o, flags = 0%o\n",
157026135Skarels (mp->mscp_status & 177740)>>5, mp->mscp_flags);
157126127Skarels # endif
157226127Skarels bp->b_flags |= B_ERROR;
157326127Skarels }
157426127Skarels else
157526127Skarels /* Hit a tape mark - Set serex flag to
157626127Skarels * a special value so we can clear the
157726127Skarels * serious exception on the next command.
157826127Skarels */
157926135Skarels tms->tms_serex = 2;
158026127Skarels }
158126127Skarels /*
158226127Skarels * The tmscp spec states that controllers do not have to
158326127Skarels * report the number of records or files skipped. So on
158426127Skarels * reposition commands we go strictly by cmd status.
158526127Skarels */
158626127Skarels if (mp->mscp_opcode != (M_OP_REPOS|M_OP_END))
158726127Skarels bp->b_resid = bp->b_bcount - mp->mscp_bytecnt;
158826127Skarels else
158926127Skarels bp->b_resid = 0;
159026135Skarels tms->tms_resid = bp->b_resid;
159126127Skarels iodone(bp);
159226127Skarels break;
159326135Skarels
159426127Skarels case M_OP_GTUNT|M_OP_END:
159526127Skarels # ifdef DEBUG
159626127Skarels printd("tmscprsp: GTUNT end packet status = 0%o\n",st);
159726135Skarels printd("tmscprsp: unit %d mediaid %x %c%c %c%c%c%d %x %x t=%d\n"
159826127Skarels ,mp->mscp_unit, mp->mscp_mediaid
159926127Skarels ,F_to_C(mp,4),F_to_C(mp,3),F_to_C(mp,2)
160026127Skarels ,F_to_C(mp,1),F_to_C(mp,0)
160126127Skarels ,mp->mscp_mediaid & 0x7f
160226127Skarels ,mp->mscp_unitid.val[0]
160326127Skarels ,mp->mscp_unitid.val[1]
160426127Skarels ,mp->mscp_format);
160526127Skarels # endif
160626135Skarels tms->tms_type = mp->mscp_mediaid;
160726135Skarels tms->tms_fmtmenu = mp->mscp_fmtmenu;
160826135Skarels tms->tms_unitflgs = mp->mscp_unitflgs;
160926127Skarels break;
161026135Skarels
161126127Skarels default:
161226127Skarels printf("tmscp unknown packet\n");
161326127Skarels tmserror(um, (struct mslg *)mp);
161426127Skarels } /* end switch mp->mscp_opcode */
161526127Skarels }
161626135Skarels
161726135Skarels
161826127Skarels /*
161926127Skarels * Give a meaningful error when the mscp_status field returns an error code.
162026127Skarels */
162126135Skarels
errinfo(st)162226127Skarels errinfo(st)
162326127Skarels int st; /* the status code */
162426127Skarels {
162526127Skarels switch(st) {
162626127Skarels case M_ST_ICMD:
162726127Skarels printf("invalid command\n");
162826127Skarels break;
162926127Skarels case M_ST_ABRTD:
163026127Skarels printf("command aborted\n");
163126127Skarels break;
163226127Skarels case M_ST_OFFLN:
163326127Skarels printf("unit offline\n");
163426127Skarels break;
163526127Skarels case M_ST_WRTPR:
163626127Skarels printf("unit write protected\n");
163726127Skarels break;
163826127Skarels case M_ST_COMP:
163926127Skarels printf("compare error\n");
164026127Skarels break;
164126127Skarels case M_ST_DATA:
164226127Skarels printf("data error\n");
164326127Skarels break;
164426127Skarels case M_ST_HSTBF:
164526127Skarels printf("host buffer access error\n");
164626127Skarels break;
164726127Skarels case M_ST_CNTLR:
164826127Skarels printf("controller error\n");
164926127Skarels break;
165026127Skarels case M_ST_DRIVE:
165126127Skarels printf("drive error\n");
165226127Skarels break;
165326127Skarels case M_ST_FMTER:
165426127Skarels printf("formatter error\n");
165526127Skarels break;
165626127Skarels case M_ST_BOT:
165726127Skarels printf("BOT encountered\n");
165826127Skarels break;
165926127Skarels case M_ST_TAPEM:
166026127Skarels printf("tape mark encountered\n");
166126127Skarels break;
166226127Skarels case M_ST_RDTRN:
166326127Skarels printf("record data truncated\n");
166426127Skarels break;
166526127Skarels case M_ST_PLOST:
166626127Skarels printf("position lost\n");
166726127Skarels break;
166826127Skarels case M_ST_SEX:
166926127Skarels printf("serious exception\n");
167026127Skarels break;
167126127Skarels case M_ST_LED:
167226127Skarels printf("LEOT detected\n");
167326127Skarels break;
167426127Skarels }
167526127Skarels }
167626135Skarels
167726135Skarels
167826127Skarels /*
167926127Skarels * Manage buffers and perform block mode read and write operations.
168026127Skarels */
168126135Skarels
tmscpstrategy(bp)168226127Skarels tmscpstrategy (bp)
168326127Skarels register struct buf *bp;
168426127Skarels {
168526127Skarels register struct uba_device *ui;
168626127Skarels register struct uba_ctlr *um;
168726127Skarels register struct buf *dp;
168826127Skarels register int unit = TMSUNIT(bp->b_dev);
168926127Skarels int s;
169026135Skarels
169126135Skarels if (unit >= NTMS)
169226127Skarels {
169326127Skarels # ifdef DEBUG
169426127Skarels printd ("tmscpstrategy: bad unit # %d\n",unit);
169526127Skarels # endif
169626127Skarels bp->b_flags |= B_ERROR;
169726127Skarels iodone(bp);
169826127Skarels return;
169926127Skarels }
170026127Skarels ui = tmsdinfo[unit];
170126127Skarels um = ui->ui_mi;
170226127Skarels if (ui == 0 || ui->ui_alive == 0)
170326127Skarels {
170426127Skarels bp->b_flags |= B_ERROR;
170526127Skarels iodone(bp);
170626127Skarels return;
170726127Skarels }
170826127Skarels s = spl5();
170926127Skarels /*
171026127Skarels * Link the buffer onto the drive queue
171126127Skarels */
171226127Skarels dp = &tmsutab[ui->ui_unit];
171326127Skarels if (dp->b_actf == 0)
171426127Skarels dp->b_actf = bp;
171526127Skarels else
171626127Skarels dp->b_actl->av_forw = bp;
171726127Skarels dp->b_actl = bp;
171826127Skarels bp->av_forw = 0;
171926127Skarels /*
172026127Skarels * Link the drive onto the controller queue
172126127Skarels */
172226127Skarels if (dp->b_active == 0)
172326127Skarels {
172426127Skarels dp->b_forw = NULL;
172526127Skarels if (um->um_tab.b_actf == NULL)
172626127Skarels um->um_tab.b_actf = dp;
172726127Skarels else
172826127Skarels um->um_tab.b_actl->b_forw = dp;
172926127Skarels um->um_tab.b_actl = dp;
173026127Skarels dp->b_active = 1;
173126127Skarels }
173226127Skarels /*
173326127Skarels * If the controller is not active, start it.
173426127Skarels */
173526127Skarels if (um->um_tab.b_active == 0)
173626127Skarels {
173726135Skarels # if defined(VAX750)
173826135Skarels if (cpu == VAX_750
173926135Skarels && tmscpwtab[um->um_ctlr].av_forw == &tmscpwtab[um->um_ctlr])
174026127Skarels {
174126127Skarels if (um->um_ubinfo != 0)
174226135Skarels log(TMS_PRI, "tmscpstrategy: ubinfo 0x%x\n",
174326135Skarels um->um_ubinfo);
174426127Skarels else
174526135Skarels um->um_ubinfo = uballoc(um->um_ubanum, (caddr_t)0, 0, UBA_NEEDBDP);
174626127Skarels }
174726127Skarels # endif
174826127Skarels # ifdef DEBUG
174926135Skarels printd10("tmscpstrategy: Controller not active, starting it\n");
175026127Skarels # endif
175126127Skarels (void) tmscpstart(um);
175226127Skarels }
175326127Skarels splx(s);
175426127Skarels return;
175526127Skarels }
175626135Skarels
175726127Skarels #define DBSIZE 32
175826135Skarels
175926127Skarels #define ca_Rspdsc ca_rspdsc[0]
176026127Skarels #define ca_Cmddsc ca_rspdsc[1]
176126127Skarels #define tmscp_Rsp tmscp_rsp[0]
176226127Skarels #define tmscp_Cmd tmscp_cmd[0]
176326135Skarels
176426127Skarels struct tmscp tmscpd[NTMSCP];
176526135Skarels
tmscpdump(dev)176626127Skarels tmscpdump(dev)
176726127Skarels dev_t dev;
176826127Skarels {
176926127Skarels struct tmscpdevice *tmscpaddr;
177026127Skarels struct tmscp *tmscp_ubaddr;
177126127Skarels char *start;
177226127Skarels int num, blk, unit;
177326127Skarels register struct uba_regs *uba;
177426127Skarels register struct uba_device *ui;
177526127Skarels register struct tmscp *tmscpp;
177626127Skarels register struct pte *io;
177726127Skarels register int i;
177826135Skarels
177926127Skarels unit = minor(dev) & 03;
178026135Skarels if (unit >= NTMS)
178126127Skarels return (ENXIO);
178226127Skarels # define phys(cast, addr) ((cast)((int)addr & 0x7fffffff))
178326127Skarels ui = phys(struct uba_device *, tmsdinfo[unit]);
178426127Skarels if (ui->ui_alive == 0)
178526127Skarels return (ENXIO);
178626127Skarels uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba;
178726135Skarels ubainit(uba);
178826127Skarels tmscpaddr = (struct tmscpdevice *)ui->ui_physaddr;
178926127Skarels DELAY(2000000);
179026127Skarels tmscpp = phys(struct tmscp *, &tmscpd[ui->ui_ctlr]);
179126135Skarels
179226127Skarels num = btoc(sizeof(struct tmscp)) + 1;
179326127Skarels io = &uba->uba_map[NUBMREG-num];
179426127Skarels for(i = 0; i<num; i++)
179526127Skarels *(int *)io++ = UBAMR_MRV|(btop(tmscpp)+i);
179626135Skarels tmscp_ubaddr = (struct tmscp *)(((int)tmscpp & PGOFSET)|((NUBMREG-num)<<9));
179726135Skarels
179826127Skarels tmscpaddr->tmscpip = 0;
179926127Skarels while ((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0)
180026127Skarels if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT);
180126127Skarels tmscpaddr->tmscpsa = TMSCP_ERR;
180226127Skarels while ((tmscpaddr->tmscpsa & TMSCP_STEP2) == 0)
180326127Skarels if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT);
180426127Skarels tmscpaddr->tmscpsa = (short)&tmscp_ubaddr->tmscp_ca.ca_ringbase;
180526127Skarels while ((tmscpaddr->tmscpsa & TMSCP_STEP3) == 0)
180626127Skarels if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT);
180726135Skarels tmscpaddr->tmscpsa = (short)(((int)&tmscp_ubaddr->tmscp_ca.ca_ringbase) >> 16);
180826127Skarels while ((tmscpaddr->tmscpsa & TMSCP_STEP4) == 0)
180926127Skarels if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT);
181026127Skarels tmscpaddr->tmscpsa = TMSCP_GO;
181126135Skarels tmscpp->tmscp_ca.ca_Rspdsc = (long)&tmscp_ubaddr->tmscp_Rsp.mscp_cmdref;
181226135Skarels tmscpp->tmscp_ca.ca_Cmddsc = (long)&tmscp_ubaddr->tmscp_Cmd.mscp_cmdref;
181326127Skarels tmscpp->tmscp_Cmd.mscp_header.tmscp_vcid = 1; /* for tape */
181426127Skarels tmscpp->tmscp_Cmd.mscp_cntflgs = 0;
181526127Skarels tmscpp->tmscp_Cmd.mscp_version = 0;
181626127Skarels if (tmscpcmd(M_OP_STCON, tmscpp, tmscpaddr) == 0) {
181726127Skarels return(EFAULT);
181826127Skarels }
181926127Skarels tmscpp->tmscp_Cmd.mscp_unit = ui->ui_slave;
182026127Skarels if (tmscpcmd(M_OP_ONLIN, tmscpp, tmscpaddr) == 0) {
182126127Skarels return(EFAULT);
182226127Skarels }
182326135Skarels
182426127Skarels num = maxfree;
182526127Skarels start = 0;
182626127Skarels while (num > 0)
182726127Skarels {
182826127Skarels blk = num > DBSIZE ? DBSIZE : num;
182926127Skarels io = uba->uba_map;
183026127Skarels for (i = 0; i < blk; i++)
183126127Skarels *(int *)io++ = (btop(start)+i) | UBAMR_MRV;
183226127Skarels *(int *)io = 0;
183326127Skarels tmscpp->tmscp_Cmd.mscp_lbn = btop(start);
183426127Skarels tmscpp->tmscp_Cmd.mscp_unit = ui->ui_slave;
183526127Skarels tmscpp->tmscp_Cmd.mscp_bytecnt = blk*NBPG;
183626127Skarels # ifdef MVAX
183726127Skarels if( cpu == MVAX_I )
183826127Skarels tmscpp->tmscp_Cmd.mscp_buffer = (long) start;
183926127Skarels else
184026127Skarels # endif MVAX
184126127Skarels tmscpp->tmscp_Cmd.mscp_buffer = 0;
184226127Skarels if (tmscpcmd(M_OP_WRITE, tmscpp, tmscpaddr) == 0)
184326127Skarels return(EIO);
184426127Skarels start += blk*NBPG;
184526127Skarels num -= blk;
184626127Skarels }
184726127Skarels return (0);
184826127Skarels }
184926135Skarels
185026135Skarels
185126127Skarels /*
185226127Skarels * Perform a standalone tmscp command. This routine is only used by tmscpdump.
185326127Skarels */
185426135Skarels
tmscpcmd(op,tmscpp,tmscpaddr)185526127Skarels tmscpcmd(op, tmscpp, tmscpaddr)
185626127Skarels int op;
185726127Skarels register struct tmscp *tmscpp;
185826127Skarels struct tmscpdevice *tmscpaddr;
185926127Skarels {
186026127Skarels int i;
186126135Skarels
186226135Skarels
186326127Skarels tmscpp->tmscp_Cmd.mscp_opcode = op;
186426127Skarels tmscpp->tmscp_Rsp.mscp_header.tmscp_msglen = mscp_msglen;
186526127Skarels tmscpp->tmscp_Cmd.mscp_header.tmscp_msglen = mscp_msglen;
186626127Skarels tmscpp->tmscp_ca.ca_Rspdsc |= TMSCP_OWN|TMSCP_INT;
186726127Skarels tmscpp->tmscp_ca.ca_Cmddsc |= TMSCP_OWN|TMSCP_INT;
186826127Skarels if (tmscpaddr->tmscpsa&TMSCP_ERR)
186926127Skarels printf("tmscp fatal error (0%o)\n", tmscpaddr->tmscpsa&0xffff);
187026127Skarels i = tmscpaddr->tmscpip;
187126293Skarels #ifdef lint
187226293Skarels i = i;
187326293Skarels #endif
187426127Skarels for (;;)
187526127Skarels {
187626127Skarels if (tmscpp->tmscp_ca.ca_cmdint)
187726127Skarels tmscpp->tmscp_ca.ca_cmdint = 0;
187826127Skarels if (tmscpp->tmscp_ca.ca_rspint)
187926127Skarels break;
188026127Skarels }
188126127Skarels tmscpp->tmscp_ca.ca_rspint = 0;
188226127Skarels if (tmscpp->tmscp_Rsp.mscp_opcode != (op|M_OP_END) ||
188326127Skarels (tmscpp->tmscp_Rsp.mscp_status&M_ST_MASK) != M_ST_SUCC)
188426127Skarels {
188526127Skarels printf("error: com %d opc 0x%x stat 0x%x\ndump ", op,
188626135Skarels tmscpp->tmscp_Rsp.mscp_opcode, tmscpp->tmscp_Rsp.mscp_status);
188726127Skarels return(0);
188826127Skarels }
188926127Skarels return(1);
189026127Skarels }
189126135Skarels
189226127Skarels /*
189326127Skarels * Catch ioctl commands, and call the "command" routine to do them.
189426127Skarels */
189526135Skarels
189626293Skarels /* ARGSUSED */
tmscpioctl(dev,cmd,data,flag)189726127Skarels tmscpioctl(dev, cmd, data, flag)
189826127Skarels dev_t dev;
189926127Skarels int cmd;
190026127Skarels caddr_t data;
190126127Skarels int flag;
190226127Skarels {
190326127Skarels register struct buf *bp = &ctmscpbuf[TMSCPCTLR(dev)];
190426127Skarels register callcount; /* number of times to call cmd routine */
190526127Skarels register struct uba_device *ui;
190626135Skarels register struct tms_info *tms;
190726127Skarels int fcount; /* number of files (or records) to space */
190840911Ssklower int error = 0;
190926293Skarels register struct mtop *mtop; /* mag tape cmd op to perform */
191026293Skarels register struct mtget *mtget; /* mag tape struct to get info in */
191126135Skarels
191226127Skarels /* we depend of the values and order of the TMS ioctl codes here */
191326127Skarels static tmsops[] =
191426127Skarels {TMS_WRITM,TMS_FSF,TMS_BSF,TMS_FSR,TMS_BSR,TMS_REW,TMS_OFFL,TMS_SENSE,
191526127Skarels TMS_CACHE,TMS_NOCACHE};
191626135Skarels
191726127Skarels switch (cmd) {
191826127Skarels case MTIOCTOP: /* tape operation */
191926127Skarels mtop = (struct mtop *)data;
192026127Skarels switch (mtop->mt_op) {
192126135Skarels
192226127Skarels case MTWEOF:
192326127Skarels callcount = mtop->mt_count;
192426127Skarels fcount = 1;
192526127Skarels break;
192626127Skarels case MTFSF: case MTBSF:
192726127Skarels case MTFSR: case MTBSR:
192826127Skarels callcount = 1;
192926127Skarels fcount = mtop->mt_count;
193026127Skarels break;
193126127Skarels case MTREW: case MTOFFL: case MTNOP:
193226127Skarels case MTCACHE: case MTNOCACHE:
193326127Skarels callcount = 1;
193426127Skarels fcount = 1; /* wait for this rewind */
193526127Skarels break;
193626127Skarels default:
193726127Skarels return (ENXIO);
193826127Skarels } /* end switch mtop->mt_op */
193926135Skarels
194026127Skarels if (callcount <= 0 || fcount <= 0)
194126127Skarels return (EINVAL);
194226127Skarels while (--callcount >= 0)
194326127Skarels {
194426127Skarels tmscpcommand(dev, tmsops[mtop->mt_op], fcount);
194526127Skarels if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) &&
194626127Skarels bp->b_resid)
194726127Skarels return (EIO);
194826127Skarels if (bp->b_flags & B_ERROR) /* like hitting BOT */
194926127Skarels break;
195026127Skarels }
195140911Ssklower if (bp->b_flags&B_ERROR)
195240911Ssklower if ((error = bp->b_error)==0)
195340911Ssklower return (EIO);
195440911Ssklower return (error);
195526135Skarels
195626127Skarels case MTIOCGET:
195726127Skarels /*
195826127Skarels * Return status info associated with the particular UNIT.
195926127Skarels */
196026127Skarels ui = tmsdinfo[TMSUNIT(dev)];
196126135Skarels tms = &tms_info[ui->ui_unit];
196226127Skarels mtget = (struct mtget *)data;
196326127Skarels mtget->mt_type = MT_ISTMSCP;
196426135Skarels mtget->mt_dsreg = tms->tms_flags << 8;
196526135Skarels mtget->mt_dsreg |= tms->tms_endcode;
196626135Skarels mtget->mt_erreg = tms->tms_status;
196726135Skarels mtget->mt_resid = tms->tms_resid;
196826127Skarels break;
196926135Skarels
197026127Skarels default:
197126127Skarels return (ENXIO);
197226127Skarels }
197326127Skarels return (0);
197426127Skarels }
197526135Skarels
197626135Skarels
197726127Skarels /*
197826127Skarels * Reset (for raw mode use only).
197926127Skarels */
198026135Skarels
tmscpreset(uban)198126127Skarels tmscpreset (uban)
198226127Skarels int uban;
198326127Skarels {
198426127Skarels register struct uba_ctlr *um;
198526127Skarels register struct uba_device *ui;
198626127Skarels register struct buf *bp, *dp;
198726127Skarels register int unit;
198826127Skarels struct buf *nbp;
198926127Skarels int d;
199026135Skarels
199126127Skarels for (d = 0; d < NTMSCP; d++)
199226127Skarels {
199326127Skarels if ((um = tmscpminfo[d]) == 0 || um->um_ubanum != uban ||
199426127Skarels um->um_alive == 0)
199526127Skarels continue;
199626127Skarels printf(" tmscp%d", d);
199726127Skarels um->um_tab.b_active = 0;
199826127Skarels um->um_tab.b_actf = um->um_tab.b_actl = 0;
199926127Skarels tmscp_softc[d].sc_state = S_IDLE;
200026127Skarels tmscp_softc[d].sc_mapped = 0;
200126135Skarels for (unit = 0; unit < NTMS; unit++)
200226127Skarels {
200326127Skarels if ((ui = tmsdinfo[unit]) == 0)
200426127Skarels continue;
200526127Skarels if (ui->ui_alive == 0 || ui->ui_mi != um)
200626127Skarels continue;
200726127Skarels tmsutab[unit].b_active = 0;
200826127Skarels tmsutab[unit].b_qsize = 0;
200926127Skarels }
201026127Skarels for (bp = tmscpwtab[d].av_forw; bp != &tmscpwtab[d]; bp = nbp)
201126127Skarels {
201226127Skarels nbp = bp->av_forw;
201326127Skarels bp->b_ubinfo = 0;
201426127Skarels /*
201526127Skarels * Link the buffer onto the drive queue
201626127Skarels */
201726127Skarels dp = &tmsutab[TMSUNIT(bp->b_dev)];
201826127Skarels if (dp->b_actf == 0)
201926127Skarels dp->b_actf = bp;
202026127Skarels else
202126127Skarels dp->b_actl->av_forw = bp;
202226127Skarels dp->b_actl = bp;
202326127Skarels bp->av_forw = 0;
202426127Skarels /*
202526127Skarels * Link the drive onto the controller queue
202626127Skarels */
202726127Skarels if (dp->b_active == 0)
202826127Skarels {
202926127Skarels dp->b_forw = NULL;
203026127Skarels if (um->um_tab.b_actf == NULL)
203126127Skarels um->um_tab.b_actf = dp;
203226127Skarels else
203326127Skarels um->um_tab.b_actl->b_forw = dp;
203426127Skarels um->um_tab.b_actl = dp;
203526127Skarels dp->b_active = 1;
203626127Skarels }
203726127Skarels }
203826370Skarels (void)tmscpinit(d);
203926127Skarels }
204026127Skarels }
204126135Skarels
204226135Skarels
204326127Skarels /*
204426127Skarels * Process an error log message
204526127Skarels *
204626127Skarels * Only minimal decoding is done, only "useful"
204726127Skarels * information is printed. Eventually should
204826127Skarels * send message to an error logger.
204926127Skarels */
205026135Skarels
tmserror(um,mp)205126127Skarels tmserror(um, mp)
205226127Skarels register struct uba_ctlr *um;
205326127Skarels register struct mslg *mp;
205426127Skarels {
205526127Skarels register i;
205626135Skarels
205726127Skarels # ifdef DEBUG
205826127Skarels printd("tmserror:\n");
205926127Skarels # endif
206026127Skarels if(!(mp->mslg_flags & (M_LF_SUCC | M_LF_CONT)))
206126135Skarels log(TMS_PRI, "tmscp%d: %s error, ", um->um_ctlr,
206226127Skarels mp->mslg_flags & ( M_LF_SUCC | M_LF_CONT ) ? "soft" : "hard");
206326135Skarels
206426127Skarels switch (mp->mslg_format) {
206526135Skarels
206626127Skarels case M_FM_CNTERR:
206726135Skarels log(TMS_PRI, "controller error, event 0%o\n", mp->mslg_event);
206826127Skarels break;
206926127Skarels case M_FM_BUSADDR:
207026135Skarels log(TMS_PRI, "host memory access error, event 0%o, addr 0%o\n",
207126127Skarels mp->mslg_event, mp->mslg_busaddr);
207226127Skarels break;
207326127Skarels case M_FM_TAPETRN:
207426135Skarels log(TMS_PRI, "tape transfer error, unit %d, grp 0x%x, event 0%o\n",
207526127Skarels mp->mslg_unit, mp->mslg_group, mp->mslg_event);
207626127Skarels break;
207726127Skarels case M_FM_STIERR:
207826135Skarels log(TMS_PRI, "STI error, unit %d, event 0%o\n",
207926127Skarels mp->mslg_unit, mp->mslg_event);
208026135Skarels #ifdef notdef
208126135Skarels /* too painful to do with log() */
208226127Skarels for(i = 0; i < 62;i++)
208326127Skarels mprintf("\t0x%x",mp->mslg_stiunsucc[i] & 0xff);
208426127Skarels mprintf("\n");
208526135Skarels #endif
208626127Skarels break;
208726127Skarels case M_FM_STIDEL:
208826135Skarels log(TMS_PRI, "STI Drive Error Log, unit %d, event 0%o\n",
208926127Skarels mp->mslg_unit, mp->mslg_event);
209026127Skarels break;
209126127Skarels case M_FM_STIFEL:
209226135Skarels log(TMS_PRI, "STI Formatter Error Log, unit %d, event 0%o\n",
209326127Skarels mp->mslg_unit, mp->mslg_event);
209426127Skarels break;
209526127Skarels default:
209626135Skarels log(TMS_PRI, "unknown error, unit %d, format 0%o, event 0%o\n",
209726127Skarels mp->mslg_unit, mp->mslg_format, mp->mslg_event);
209826127Skarels }
209926135Skarels
210026127Skarels if (tmscperror)
210126127Skarels {
210226127Skarels register long *p = (long *)mp;
210326135Skarels
210426127Skarels for (i = 0; i < mp->mslg_header.tmscp_msglen; i += sizeof(*p))
210526127Skarels printf("%x ", *p++);
210626127Skarels printf("\n");
210726127Skarels }
210826127Skarels }
210926127Skarels #endif
2110