127479Skjd
2*49100Sbostic /* @(#)tmscp.c 7.7 (Berkeley) 05/04/91 */
327479Skjd
427479Skjd /****************************************************************
527479Skjd * *
627479Skjd * Licensed from Digital Equipment Corporation *
727479Skjd * Copyright (c) *
827479Skjd * Digital Equipment Corporation *
927479Skjd * Maynard, Massachusetts *
1027479Skjd * 1985, 1986 *
1127479Skjd * All rights reserved. *
1227479Skjd * *
1327479Skjd * The Information in this software is subject to change *
1427479Skjd * without notice and should not be construed as a commitment *
1527479Skjd * by Digital Equipment Corporation. Digital makes no *
1627479Skjd * representations about the suitability of this software for *
1727479Skjd * any purpose. It is supplied "As Is" without expressed or *
1827479Skjd * implied warranty. *
1927479Skjd * *
2027479Skjd * If the Regents of the University of California or its *
2127479Skjd * licensees modify the software in a manner creating *
2227479Skjd * diriviative copyright rights, appropriate copyright *
2327479Skjd * legends may be placed on the drivative work in addition *
2427479Skjd * to that set forth above. *
2527479Skjd ***************************************************************/
2627479Skjd /*
2727479Skjd * tmscp.c - TMSCP (TK50/TU81) standalone driver
2827479Skjd */
2927479Skjd
3027479Skjd # ifndef lint
3127479Skjd static char *sccsid = "@(#)tmscp.c 1.5 (ULTRIX) 4/18/86";
3227479Skjd # endif not lint
3327479Skjd
3427479Skjd /* ------------------------------------------------------------------------
3527479Skjd * Modification History: /sys/stand/tmscp.c
3627479Skjd *
3727479Skjd * 3-15-85 afd
3827479Skjd * Don't ask for an interrupt when commands are issued and
3927479Skjd * check ownership bit in the response descriptor to detect when a
4027479Skjd * command is complete. Necessary due to the TU81's failure to set
4127479Skjd * the response interrupt field in the communications area.
4227479Skjd *
4327479Skjd * ------------------------------------------------------------------------
4427479Skjd */
4527479Skjd
4645803Sbostic #include "sys/param.h"
4733408Skarels
4845803Sbostic #include "../include/pte.h"
4933408Skarels
5045803Sbostic #include "stand/saio.h"
5127479Skjd #include "savax.h"
5227479Skjd
5327479Skjd /*
5427479Skjd * Parameters for the communications area
5527479Skjd * (Only 1 cmd & 1 rsp packet)
5627479Skjd */
5727479Skjd #define NRSPL2 0
5827479Skjd #define NCMDL2 0
5927479Skjd #define NRSP (1<<NRSPL2)
6027479Skjd #define NCMD (1<<NCMDL2)
6127479Skjd
6245803Sbostic #include "../uba/tmscpreg.h"
6345803Sbostic #include "../uba/ubareg.h"
6427479Skjd #include "../vax/tmscp.h"
6527479Skjd
6633646Sbostic #define MAXCTLR 1 /* all addresses must be specified */
6733646Sbostic u_short tmscpstd[MAXCTLR] = { 0174500 };
6827479Skjd
6927479Skjd struct iob ctmscpbuf;
7027479Skjd
7127479Skjd struct tmscpdevice *tmscpaddr = 0;
7227479Skjd
7327479Skjd struct tmscp {
7427479Skjd struct tmscpca tmscp_ca;
7527479Skjd struct mscp tmscp_rsp;
7627479Skjd struct mscp tmscp_cmd;
7733646Sbostic } tmscp;
7827479Skjd
7927479Skjd struct tmscp *tmscp_ubaddr; /* Unibus address of tmscp structure */
8027479Skjd
8127479Skjd struct mscp *tmscpcmd();
8227479Skjd
8327479Skjd int tmscp_offline = 1; /* Flag to prevent multiple STCON */
8427479Skjd int tms_offline[4] = {1,1,1,1}; /* Flag to prevent multiple ONLIN */
8527479Skjd
8627479Skjd /*
8727479Skjd * Open a tmscp device. Initialize the controller and set the unit online.
8827479Skjd */
tmscpopen(io)8927479Skjd tmscpopen(io)
9027479Skjd register struct iob *io;
9127479Skjd {
9227479Skjd register struct mscp *mp;
9327479Skjd int i;
9427479Skjd
9533646Sbostic if ((u_int)io->i_ctlr >= MAXCTLR)
9633646Sbostic return (ECTLR);
9727479Skjd /*
9827479Skjd * Have the tmscp controller characteristics already been set up
9927479Skjd * (STCON)?
10027479Skjd */
10133646Sbostic if (tmscp_offline) {
10227479Skjd if (tmscpaddr == 0)
10333646Sbostic tmscpaddr = (struct tmscpdevice *)ubamem(io->i_adapt, tmscpstd[0]);
10433646Sbostic if (tmscp_ubaddr == 0) {
10536514Smckusick ctmscpbuf = *io;
10627479Skjd ctmscpbuf.i_ma = (caddr_t)&tmscp;
10727479Skjd ctmscpbuf.i_cc = sizeof(tmscp);
10827479Skjd tmscp_ubaddr = (struct tmscp *)ubasetup(&ctmscpbuf, 2);
10933646Sbostic }
11027479Skjd /*
11127479Skjd * Initialize the tmscp device and wait for the 4 steps
11227479Skjd * to complete.
11327479Skjd */
11427479Skjd tmscpaddr->tmscpip = 0;
11533646Sbostic while ((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0);
11627479Skjd tmscpaddr->tmscpsa =TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8);
11727479Skjd
11833646Sbostic while ((tmscpaddr->tmscpsa & TMSCP_STEP2) == 0);
11927479Skjd # define STEP1MASK 0174377
12027479Skjd # define STEP1GOOD (TMSCP_STEP2|TMSCP_IE|(NCMDL2<<3)|NRSPL2)
12127479Skjd if ((tmscpaddr->tmscpsa&STEP1MASK) != STEP1GOOD)
12227479Skjd printf("tmscpopen: step 1 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff);
12327479Skjd tmscpaddr->tmscpsa = (short)&tmscp_ubaddr->tmscp_ca.ca_ringbase;
12427479Skjd
12533646Sbostic while ((tmscpaddr->tmscpsa & TMSCP_STEP3) == 0);
12627479Skjd # define STEP2MASK 0174377
12727479Skjd # define STEP2GOOD (TMSCP_STEP3)
12827479Skjd if ((tmscpaddr->tmscpsa&STEP2MASK) != STEP2GOOD)
12927479Skjd printf("tmscpopen: step 2 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff);
13027479Skjd tmscpaddr->tmscpsa = (short)(((int)&tmscp_ubaddr->tmscp_ca.ca_ringbase) >> 16);
13127479Skjd
13233646Sbostic while ((tmscpaddr->tmscpsa & TMSCP_STEP4) == 0);
13327479Skjd # define STEP3MASK 0174000
13427479Skjd # define STEP3GOOD TMSCP_STEP4
13527479Skjd if ((tmscpaddr->tmscpsa&STEP3MASK) != STEP3GOOD)
13627479Skjd printf("tmscpopen: step 3 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff);
13727479Skjd tmscpaddr->tmscpsa = TMSCP_GO;
13827479Skjd
13927479Skjd /*
14027479Skjd * Init cmd & rsp area
14127479Skjd */
14227479Skjd tmscp.tmscp_ca.ca_cmddsc[0] = (long)&tmscp_ubaddr->tmscp_cmd.mscp_cmdref;
14327479Skjd tmscp.tmscp_cmd.mscp_dscptr = tmscp.tmscp_ca.ca_cmddsc;
14427479Skjd tmscp.tmscp_cmd.mscp_header.tmscp_vcid = 1; /* for tape */
14527479Skjd
14627479Skjd tmscp.tmscp_ca.ca_rspdsc[0] = (long)&tmscp_ubaddr->tmscp_rsp.mscp_cmdref;
14727479Skjd tmscp.tmscp_rsp.mscp_dscptr = tmscp.tmscp_ca.ca_rspdsc;
14827479Skjd tmscp.tmscp_cmd.mscp_cntflgs = 0;
14933646Sbostic if (tmscpcmd(M_OP_STCON, 0) == 0) {
15033408Skarels printf("tms: open error, STCON\n");
15133408Skarels return (EIO);
15233646Sbostic }
15327479Skjd tmscp_offline = 0;
15433646Sbostic }
15527479Skjd tmscp.tmscp_cmd.mscp_unit = io->i_unit&03;
15627479Skjd /*
15727479Skjd * Has this unit been issued an ONLIN?
15827479Skjd */
15933646Sbostic if (tms_offline[tmscp.tmscp_cmd.mscp_unit]) {
16033646Sbostic if ((mp = tmscpcmd(M_OP_ONLIN, 0)) == 0) {
16133408Skarels _stop("tms: open error, ONLIN\n");
16233408Skarels return (EIO);
16333646Sbostic }
16427479Skjd tms_offline[tmscp.tmscp_cmd.mscp_unit] = 0;
16533408Skarels }
16633646Sbostic /*
16733646Sbostic * This makes no sense, but I could be wrong... KB
16833646Sbostic *
16933646Sbostic * if ((u_int)io->i_part > 3)
17033646Sbostic * return (EPART);
17133646Sbostic */
17233646Sbostic if (io->i_part) {
17327479Skjd /*
17427479Skjd * Skip forward the appropriate number of files on the tape.
17527479Skjd */
17633646Sbostic tmscp.tmscp_cmd.mscp_tmkcnt = io->i_part;
17733646Sbostic (void)tmscpcmd(M_OP_REPOS, 0);
17827479Skjd tmscp.tmscp_cmd.mscp_tmkcnt = 0;
17933646Sbostic }
18033408Skarels return (0);
18127479Skjd }
18227479Skjd
18327479Skjd /*
18427479Skjd * Close the device (rewind it to BOT)
18527479Skjd */
tmscpclose(io)18627479Skjd tmscpclose(io)
18727479Skjd register struct iob *io;
18827479Skjd {
18933646Sbostic (void)tmscpcmd(M_OP_REPOS, M_MD_REWND);
19027479Skjd }
19127479Skjd
19227479Skjd /*
19327479Skjd * Set up tmscp command packet. Cause the controller to poll to pick up
19427479Skjd * the command.
19527479Skjd */
19627479Skjd struct mscp *
tmscpcmd(op,mod)19727479Skjd tmscpcmd(op,mod)
19827479Skjd int op, mod; /* opcode and modifier (usu 0) */
19927479Skjd {
20027479Skjd struct mscp *mp; /* ptr to cmd packet */
20127479Skjd int i; /* read into to init polling */
20227479Skjd
20327479Skjd tmscp.tmscp_cmd.mscp_opcode = op;
20427479Skjd tmscp.tmscp_cmd.mscp_modifier = mod;
20527479Skjd tmscp.tmscp_cmd.mscp_header.tmscp_msglen = mscp_msglen;
20627479Skjd tmscp.tmscp_ca.ca_cmddsc[0] |= TMSCP_OWN; /* | TMSCP_INT */
20727479Skjd tmscp.tmscp_rsp.mscp_header.tmscp_msglen = mscp_msglen;
20827479Skjd tmscp.tmscp_ca.ca_rspdsc[0] |= TMSCP_OWN; /* | TMSCP_INT */
20927479Skjd
21027479Skjd i = tmscpaddr->tmscpip;
21133646Sbostic for (;;) {
21233646Sbostic if (tmscpaddr->tmscpsa & TMSCP_ERR) {
21327479Skjd printf("tmscpcmd: Fatal error sa=%o\n", tmscpaddr->tmscpsa & 0xffff);
21427479Skjd return(0);
21533646Sbostic }
21627479Skjd
21727479Skjd if (tmscp.tmscp_ca.ca_cmdint)
21827479Skjd tmscp.tmscp_ca.ca_cmdint = 0;
21927479Skjd /*
22027479Skjd * This is to handle the case of devices not setting the
22127479Skjd * interrupt field in the communications area. Some
22227479Skjd * devices (early TU81's) only clear the ownership field
22327479Skjd * in the Response Descriptor.
22433646Sbostic *
22533646Sbostic *
22633646Sbostic * if (tmscp.tmscp_ca.ca_rspint)
22733646Sbostic * break;
22827479Skjd */
22927479Skjd if (!(tmscp.tmscp_ca.ca_rspdsc[0] & (TMSCP_OWN)))
23027479Skjd break;
23133646Sbostic }
23227479Skjd tmscp.tmscp_ca.ca_rspint = 0;
23327479Skjd mp = &tmscp.tmscp_rsp;
23427479Skjd if (mp->mscp_opcode != (op|M_OP_END) ||
23533646Sbostic (mp->mscp_status&M_ST_MASK) != M_ST_SUCC) {
23633646Sbostic /*
23733646Sbostic * Detect hitting tape mark. This signifies the end of the
23827479Skjd * tape mini-root file. We don't want to return an error
23927479Skjd * condition to the strategy routine.
24027479Skjd */
24133646Sbostic if ((mp->mscp_status & M_ST_MASK) != M_ST_TAPEM)
24233646Sbostic return(0);
24333646Sbostic }
24427479Skjd return(mp);
24527479Skjd }
24627479Skjd
24727479Skjd /*
24827479Skjd * Set up to do reads and writes; call tmscpcmd to issue the cmd.
24927479Skjd */
tmscpstrategy(io,func)25027479Skjd tmscpstrategy(io, func)
25127479Skjd register struct iob *io;
25227479Skjd int func;
25327479Skjd {
25427479Skjd register struct mscp *mp;
25527479Skjd int ubinfo;
25627479Skjd
25727479Skjd ubinfo = ubasetup(io, 1);
25827479Skjd mp = &tmscp.tmscp_cmd;
25927479Skjd mp->mscp_lbn = io->i_bn;
26027479Skjd mp->mscp_unit = io->i_unit&03;
26127479Skjd mp->mscp_bytecnt = io->i_cc;
26227479Skjd mp->mscp_buffer = (ubinfo & 0x3fffff) | (((ubinfo>>28)&0xf)<<24);
263*49100Sbostic if ((mp = tmscpcmd(func == F_READ ? M_OP_READ : M_OP_WRITE, 0)) == 0) {
26427479Skjd ubafree(io, ubinfo);
26527479Skjd printf("tms: I/O error\n");
26627479Skjd return(-1);
26733646Sbostic }
26827479Skjd ubafree(io, ubinfo);
26927479Skjd /*
27027479Skjd * Detect hitting tape mark so we do it gracefully and return a
27127479Skjd * character count of 0 to signify end of copy. Rewind the tape
27227479Skjd * before returning.
27327479Skjd */
27427479Skjd if ((mp->mscp_status & M_ST_MASK) == M_ST_TAPEM)
27527479Skjd return(0);
27627479Skjd return(io->i_cc);
27727479Skjd }
278