1*49431Sbostic /*-
2*49431Sbostic * Copyright (c) 1991 The Regents of the University of California.
3*49431Sbostic * All rights reserved.
4*49431Sbostic *
5*49431Sbostic * This code is derived from software contributed to Berkeley by
6*49431Sbostic * Computer Consoles Inc.
7*49431Sbostic *
8*49431Sbostic * %sccs.include.proprietary.c%
9*49431Sbostic *
10*49431Sbostic * @(#)cy.c 7.13 (Berkeley) 05/08/91
11*49431Sbostic */
1225867Ssam
1325867Ssam /*
1425867Ssam * Cypher tape driver. Stand alone version.
1525867Ssam */
1645796Sbostic #include "../include/pte.h"
1745796Sbostic #include "../include/mtpr.h"
1825867Ssam
1943457Sroot #include "sys/param.h"
2043457Sroot #include "sys/time.h"
2125867Ssam
2245796Sbostic #include "stand/saio.h"
2325867Ssam
2430514Skarels #define CYERROR
2545796Sbostic #include "../vba/cyreg.h"
2645796Sbostic #include "../vba/vbaparam.h"
2725931Ssam
2830514Skarels /*
2930514Skarels * NB: this driver assumes unit 0 throughout.
3030514Skarels */
3125867Ssam long cystd[] = { 0xf4000, 0 };
3225931Ssam #define CYADDR(i) (cystd[i] + (int)VBIOBASE)
3325867Ssam
3430514Skarels struct cyscp *cyscp[] = { (struct cyscp *)0xc06, (struct cyscp *)0 };
3530514Skarels #define CYSCP(i) (cyscp[i])
3625867Ssam
3730514Skarels struct cyscp *SCP;
3830514Skarels struct cyscb scb;
3930514Skarels struct cyccb ccb;
4030514Skarels struct cytpb tpb;
4130514Skarels struct cytpb cycool; /* tape parameter block to clear interrupts */
4230514Skarels #ifdef notdef
4330314Ssam int cyblocksize = 1024; /* foreign tape size as found in open routine */
4430514Skarels #endif
4530514Skarels int cybufsize; /* controller buffer size */
4630314Ssam long cyblock; /* next block number for i/o */
4730314Ssam
4825867Ssam /*
4925867Ssam * Reset the controller.
5025867Ssam */
cyopen(io)5125867Ssam cyopen(io)
5225867Ssam register struct iob *io;
5325867Ssam {
5430314Ssam register ctlradr = CYADDR(0);
5534465Sbostic register int skip;
5625867Ssam
5734465Sbostic if ((u_int)io->i_adapt)
5834465Sbostic return (EADAPT);
5934465Sbostic if ((u_int)io->i_ctlr)
6034465Sbostic return (ECTLR);
6130514Skarels SCP = CYSCP(0); /* absolute - for setup */
6230514Skarels CY_RESET(ctlradr); /* reset the controller */
6325867Ssam /*
6425867Ssam * Initialize the system configuration pointer
6525867Ssam */
6630514Skarels SCP->csp_buswidth = 1; /* system width = 16 bits. */
6730514Skarels SCP->csp_unused = 0;
6825867Ssam /* initialize the pointer to the system configuration block */
6930514Skarels cyldmba(SCP->csp_scb, (caddr_t)&scb);
7025867Ssam /*
7125867Ssam * Initialize the system configuration block.
7225867Ssam */
7330514Skarels scb.csb_fixed = CSB_FIXED; /* fixed value */
7425867Ssam /* initialize the pointer to the channel control block */
7530514Skarels cyldmba(scb.csb_ccb, (caddr_t)&ccb);
7625867Ssam /*
7725867Ssam * Initialize the channel control block.
7825867Ssam */
7930514Skarels ccb.cbcw = CBCW_IE; /* normal interrupts */
8025867Ssam /* initialize the pointer to the tape parameter block */
8130514Skarels cyldmba(ccb.cbtpb, (caddr_t)&tpb);
8225867Ssam /*
8330514Skarels * set the command to be CY_NOP.
8425867Ssam */
8530514Skarels tpb.tpcmd = CY_NOP;
8630514Skarels /*
8730514Skarels * TPB not used on first attention
8830514Skarels */
8930514Skarels tpb.tpcontrol = CYCW_LOCK | CYCW_16BITS;
9030514Skarels ccb.cbgate = GATE_CLOSED;
9130514Skarels CY_GO(ctlradr); /* execute! */
9225867Ssam cywait(10*1000);
9325867Ssam /*
9430514Skarels * set the command to be CY_CONFIGURE.
9530514Skarels * NO interrupt on completion.
9625867Ssam */
9730514Skarels tpb.tpcmd = CY_CONFIG;
9830514Skarels tpb.tpcontrol = CYCW_LOCK | CYCW_16BITS;
9930514Skarels tpb.tpstatus = 0;
10030514Skarels ccb.cbgate = GATE_CLOSED;
10130514Skarels CY_GO(ctlradr); /* execute! */
10225867Ssam cywait(10*1000);
10330514Skarels uncache(&tpb.tpstatus);
10430514Skarels if (tpb.tpstatus & CYS_ERR) {
10530314Ssam printf("Cypher initialization error!\n");
10630759Skarels cy_print_error(tpb.tpcmd, tpb.tpstatus);
10730854Skarels return (ENXIO);
10825867Ssam }
10930514Skarels uncache(&tpb.tpcount);
11030514Skarels cybufsize = tpb.tpcount;
11130854Skarels if (cycmd(io, CY_REW) == -1) {
11230854Skarels printf("cy%d: Rewind failed!\n", io->i_unit);
11330854Skarels return (ENXIO);
11430854Skarels }
11534465Sbostic for (skip = io->i_part; skip--;)
11630854Skarels if (cycmd(io, CY_FSF) == -1) {
11730854Skarels printf("cy%d: seek failure!\n", io->i_unit);
11830854Skarels return (ENXIO);
11930854Skarels }
12030514Skarels #ifdef notdef
12125867Ssam #ifdef NOBLOCK
12225867Ssam if (io->i_flgs & F_READ) {
12330514Skarels cyblocksize = cycmd(io, CY_READFORN);
12430314Ssam if (cyblocksize == -1)
12530314Ssam _stop("Read foreign tape failed\n");
12630314Ssam cyblock++; /* XXX force backspace record */
12730514Skarels if (cycmd(io, CY_SFORW) == -1)
12830314Ssam _stop("Backspace after read foreign failed\n");
12925867Ssam }
13025867Ssam #endif
13130514Skarels #endif
13230854Skarels return (0);
13325867Ssam }
13425867Ssam
cyclose(io)13525867Ssam cyclose(io)
13625867Ssam register struct iob *io;
13725867Ssam {
13830314Ssam
13930514Skarels if (io->i_flgs & F_WRITE) { /* if writing, write file marks */
14030514Skarels cycmd(io, CY_WEOF);
14130514Skarels cycmd(io, CY_WEOF);
14230514Skarels }
14330514Skarels cycmd(io, CY_REW);
14425867Ssam }
14525867Ssam
cystrategy(io,func)14630314Ssam cystrategy(io, func)
14725867Ssam register struct iob *io;
14830314Ssam register func;
14925867Ssam {
15030759Skarels register count;
15125867Ssam
15225867Ssam #ifndef NOBLOCK
15330514Skarels if (func != CY_SFORW && func != CY_REW && io->i_bn != cyblock) {
15430514Skarels cycmd(io, CY_SFORW);
15530514Skarels tpb.tprec = 0;
15625867Ssam }
15749096Sbostic if (func == F_READ || func == F_WRITE) {
15825867Ssam struct iob liob;
15925867Ssam register struct iob *lio = &liob;
16025867Ssam
16125867Ssam liob = *io;
16230314Ssam while (lio->i_cc > 0) {
16330759Skarels if ((count = cycmd(lio, func)) == 0) {
16430759Skarels printf("cy%d: I/O error bn %d\n",
16530759Skarels io->i_unit, io->i_bn);
16630314Ssam return (-1);
16730759Skarels }
16825867Ssam lio->i_cc -= count;
16925867Ssam lio->i_ma += count;
17025867Ssam }
17130314Ssam return (io->i_cc);
17225867Ssam }
17325867Ssam #endif
17430759Skarels count = cycmd(io, func);
17530759Skarels if (count == -1)
17630759Skarels printf("cy%d: I/O error bn %d\n", io->i_unit, io->i_bn);
17730759Skarels return (count);
17825867Ssam }
17925867Ssam
cycmd(io,func)18030314Ssam cycmd(io, func)
18125867Ssam register struct iob *io;
18230314Ssam long func;
18325867Ssam {
18430314Ssam register ctlradr = CYADDR(0);
18530314Ssam int timeout = 0;
18630514Skarels int err;
18725867Ssam short j;
18825867Ssam
18930514Skarels cywait(9000); /* shouldn't be needed */
19034465Sbostic #define PACKUNIT(unit) (((unit&1)<<11)|((unit&2)<<9)|((unit&4)>>2))
19134465Sbostic tpb.tpcontrol = CYCW_LOCK | CYCW_16BITS | PACKUNIT(io->i_unit);
19230514Skarels tpb.tpstatus = 0;
19330514Skarels tpb.tpcount = 0;
19430514Skarels cyldmba(ccb.cbtpb, (caddr_t)&tpb);
19530514Skarels tpb.tpcmd = func;
19630314Ssam switch (func) {
19749096Sbostic case F_READ:
19830514Skarels #ifdef notdef
19930314Ssam if (io->i_cc > cyblocksize)
20030514Skarels tpb.tpsize = htoms(cyblocksize);
20130314Ssam else
20230514Skarels #endif
20330514Skarels tpb.tpsize = htoms(io->i_cc);
20430514Skarels cyldmba(tpb.tpdata, io->i_ma);
20530514Skarels tpb.tpcmd = CY_RCOM;
20630314Ssam cyblock++;
20725867Ssam break;
20849096Sbostic case F_WRITE:
20930514Skarels tpb.tpcmd = CY_WCOM;
21030514Skarels tpb.tpsize = htoms(io->i_cc);
21130514Skarels cyldmba(tpb.tpdata, io->i_ma);
21230314Ssam cyblock++;
21325867Ssam break;
21430514Skarels case CY_SFORW:
21525867Ssam if ((j = io->i_bn - cyblock) < 0) {
21625867Ssam j = -j;
21730514Skarels tpb.tpcontrol |= CYCW_REV;
21825867Ssam cyblock -= j;
21930314Ssam } else
22025867Ssam cyblock += j;
22130514Skarels tpb.tprec = htoms(j);
22230314Ssam timeout = 60*5;
22325867Ssam break;
22430514Skarels case CY_FSF:
22530514Skarels tpb.tprec = htoms(1);
22630314Ssam /* fall thru... */
22730514Skarels case CY_REW:
22825867Ssam cyblock = 0;
22930314Ssam timeout = 60*5;
23025867Ssam break;
23125867Ssam }
23230514Skarels ccb.cbgate = GATE_CLOSED;
23330514Skarels CY_GO(ctlradr); /* execute! */
23430314Ssam if (timeout == 0)
23530314Ssam timeout = 10;
23630314Ssam cywait(timeout*1000);
23725867Ssam /*
23825867Ssam * First we clear the interrupt and close the gate.
23925867Ssam */
24025867Ssam mtpr(PADC, 0);
24130514Skarels ccb.cbgate = GATE_CLOSED;
24230514Skarels cyldmba(ccb.cbtpb, (caddr_t)&cycool);
24330514Skarels cycool.tpcontrol = CYCW_LOCK; /* No INTERRUPTS */
24430514Skarels CY_GO(ctlradr);
24525867Ssam cywait(20000);
24630514Skarels uncache(&tpb.tpstatus);
24730759Skarels if ((err = (tpb.tpstatus & CYS_ERR)) &&
24830514Skarels err != CYER_FM && (err != CYER_STROBE || tpb.tpcmd != CY_RCOM)) {
24930759Skarels cy_print_error(tpb.tpcmd, tpb.tpstatus);
25030314Ssam io->i_error = EIO;
25130314Ssam return (-1);
25225867Ssam }
25330514Skarels uncache(&tpb.tpcount);
25430514Skarels return ((int)htoms(tpb.tpcount));
25525867Ssam }
25634465Sbostic
cy_print_error(op,status)25730759Skarels cy_print_error(op, status)
25830759Skarels int op, status;
25925867Ssam {
26030514Skarels register char *message;
26130314Ssam
26230514Skarels if ((status & CYS_ERR) < NCYERROR)
26330514Skarels message = cyerror[status & CYS_ERR];
26430514Skarels else
26530514Skarels message = "unknown error";
26630759Skarels printf("cy0: cmd %x %s, status=%b.\n", op, message, status, CYS_BITS);
26725867Ssam }
26825867Ssam
cywait(timeout)26925867Ssam cywait(timeout)
27030314Ssam register timeout;
27125867Ssam {
27230314Ssam do {
27325867Ssam DELAY(1000);
27430514Skarels uncache(&ccb.cbgate);
27530514Skarels } while (ccb.cbgate != GATE_OPEN && --timeout > 0);
27630314Ssam if (timeout <= 0)
27730314Ssam _stop("cy: Transfer timeout");
27825867Ssam }
27925867Ssam
28025867Ssam /*
28130514Skarels * Load a 20 bit pointer into a Tapemaster pointer.
28225867Ssam */
cyldmba(reg,value)28330514Skarels cyldmba(reg, value)
28430514Skarels register caddr_t reg;
28530514Skarels caddr_t value;
28625867Ssam {
28730514Skarels register int v = (int)value;
28830314Ssam
28930514Skarels *reg++ = v;
29030514Skarels *reg++ = v >> 8;
29130514Skarels *reg++ = 0;
29230514Skarels *reg = (v&0xf0000) >> 12;
29325867Ssam }
294