xref: /csrg-svn/sys/vax/stand/rl.c (revision 10775)
1*10775Ssam /*	rl.c	4.1	83/02/08	*/
2*10775Ssam 
3*10775Ssam /*
4*10775Ssam  * Standalone RL02 disk driver
5*10775Ssam  */
6*10775Ssam #include "../machine/pte.h"
7*10775Ssam 
8*10775Ssam #include "../h/param.h"
9*10775Ssam #include "../h/inode.h"
10*10775Ssam #include "../h/fs.h"
11*10775Ssam 
12*10775Ssam #include "../vaxuba/rlreg.h"
13*10775Ssam #include "../vaxuba/ubareg.h"
14*10775Ssam 
15*10775Ssam #include "saio.h"
16*10775Ssam #include "savax.h"
17*10775Ssam 
18*10775Ssam u_short	rlstd[] = { 0774400 };
19*10775Ssam short	rl_off[] = { 0, 361, 0, -1, -1, -1, -1, -1 };
20*10775Ssam 
21*10775Ssam /* struct to keep state info about the controller */
22*10775Ssam struct	rl_stat {
23*10775Ssam 	short	rl_dn;		/* drive number */
24*10775Ssam 	short	rl_cylnhd;	/* cylinder and head */
25*10775Ssam 	u_short	rl_bleft;	/* bytes left to transfer */
26*10775Ssam 	u_short	rl_bpart;	/* bytes transferred */
27*10775Ssam } rl_stat[] = { -1, 0, 0, 0};
28*10775Ssam 
29*10775Ssam rlopen(io)
30*10775Ssam 	register struct iob *io;
31*10775Ssam {
32*10775Ssam 	register struct rldevice *rladdr =
33*10775Ssam 		(struct rldevice *)ubamem(io->i_unit, rlstd[0]);
34*10775Ssam 	register struct rl_stat *st = &rl_stat[0];
35*10775Ssam 	register int ctr = 0;
36*10775Ssam 
37*10775Ssam 	if (rl_off[io->i_boff] == -1 ||
38*10775Ssam 	    io->i_boff < 0 || io->i_boff > 7)
39*10775Ssam 		_stop("rl bad unit");
40*10775Ssam 
41*10775Ssam 	/*
42*10775Ssam 	 * DEC reports that:
43*10775Ssam 	 * For some unknown reason the RL02 (seems to be only drive 1)
44*10775Ssam 	 * does not return a valid drive status the first time that a
45*10775Ssam 	 * GET STATUS request is issued for the drive, in fact it can
46*10775Ssam 	 * take up to three or more GET STATUS requests to obtain the
47*10775Ssam 	 * correct status.
48*10775Ssam 	 * In order to overcome this, the driver has been modified to
49*10775Ssam 	 * issue a GET STATUS request and validate the drive status
50*10775Ssam 	 * returned.  If a valid status is not returned after eight
51*10775Ssam 	 * attempts, then an error message is printed.
52*10775Ssam 	 */
53*10775Ssam 	do {
54*10775Ssam 		rladdr->rlda.getstat = RL_RESET;
55*10775Ssam 		rladdr->rlcs = (io->i_unit <<8) | RL_GETSTAT; /* Get status*/
56*10775Ssam 		rlwait(rladdr);
57*10775Ssam 	} while( (rladdr->rlmp.getstat&RLMP_STATUS) != RLMP_STATOK && ++ctr<8 );
58*10775Ssam 
59*10775Ssam 	if ((rladdr->rlcs & RL_DE) || (ctr >= 8))
60*10775Ssam 		_stop("rl unit does not respond");
61*10775Ssam 
62*10775Ssam 	if ((rladdr->rlmp.getstat & RLMP_DT) == 0 )	/* NO RL01'S */
63*10775Ssam 		_stop("rl01 unit not supported");
64*10775Ssam 
65*10775Ssam 	/* Determine disk posistion */
66*10775Ssam 	rladdr->rlcs = (io->i_unit << 8) | RL_RHDR;
67*10775Ssam 	rlwait(rladdr);
68*10775Ssam 
69*10775Ssam 	/* save disk drive posistion */
70*10775Ssam 	st->rl_cylnhd = (rladdr->rlmp.readhdr & 0177700) >> 6;
71*10775Ssam 	st->rl_dn = io->i_unit;
72*10775Ssam 
73*10775Ssam 	/* byte offset for cylinder desired */
74*10775Ssam 	io->i_boff = rl_off[io->i_boff] * NRLBPSC * NRLTRKS * NRLSECT;
75*10775Ssam }
76*10775Ssam 
77*10775Ssam rlstrategy(io, func)
78*10775Ssam 	register struct iob *io;
79*10775Ssam {
80*10775Ssam 	register struct rldevice *rladdr =
81*10775Ssam 		(struct rldevice *)ubamem(io->i_unit, rlstd[0]);
82*10775Ssam 	register struct rl_stat *st = &rl_stat[0];
83*10775Ssam 	int com;
84*10775Ssam 	daddr_t bn;
85*10775Ssam 	short cn, sn, head;
86*10775Ssam 	int diff, ubinfo, ubaddr, errcnt = 0;
87*10775Ssam 
88*10775Ssam retry:
89*10775Ssam 	ubinfo = ubasetup(io, 1);
90*10775Ssam 	bn = io->i_bn;		/* block number */
91*10775Ssam 	cn = bn / 40;		/* 40 512 byte blocks per cylinder */
92*10775Ssam 	sn = (bn % 20) << 1;
93*10775Ssam 	head = (bn / 20) & 1;
94*10775Ssam 	st->rl_bleft = io->i_cc;	/* total number of bytes to trans */
95*10775Ssam 	ubaddr = ubinfo;
96*10775Ssam 
97*10775Ssam stupid_rl:
98*10775Ssam 	/* find out how many cylinders to seek */
99*10775Ssam 	diff = (st->rl_cylnhd >> 1) - cn;
100*10775Ssam 	if ( diff == 0 && (st->rl_cylnhd & 1) == head )
101*10775Ssam 		goto noseek;
102*10775Ssam 
103*10775Ssam 	/* first time or we switched drives */
104*10775Ssam 	st->rl_dn = io->i_unit;	/* drive number */
105*10775Ssam 
106*10775Ssam 	if ( diff < 0 )
107*10775Ssam 		rladdr->rlda.seek = -diff<<7 | RLDA_HGH | head << 4;
108*10775Ssam 	else
109*10775Ssam 		rladdr->rlda.seek = diff<<7 | RLDA_LOW | head << 4;
110*10775Ssam 	rladdr->rlcs = (st->rl_dn << 8) | RL_SEEK;
111*10775Ssam 
112*10775Ssam 	/* reset position of drive */
113*10775Ssam 	st->rl_cylnhd = (cn << 1) | head;
114*10775Ssam 
115*10775Ssam noseek:
116*10775Ssam 	/* wait for controller and drive */
117*10775Ssam 	while( (rladdr->rlcs & RL_DCRDY) != RL_DCRDY)
118*10775Ssam 		continue;
119*10775Ssam 
120*10775Ssam 	/* calculate the max number of bytes we can trans */
121*10775Ssam 	st->rl_bpart = NRLSECT * NRLBPSC - (sn * NRLBPSC);
122*10775Ssam 	if ( st->rl_bleft < st->rl_bpart )
123*10775Ssam 		st->rl_bpart = st->rl_bleft;
124*10775Ssam 
125*10775Ssam 	rladdr->rlda.rw = (st->rl_cylnhd << 6) | sn;
126*10775Ssam 	rladdr->rlmp.rw = -(st->rl_bpart >> 1);
127*10775Ssam 	rladdr->rlba = ubaddr;
128*10775Ssam 
129*10775Ssam 	com = (st->rl_dn << 8) | ((ubaddr>>12)&RL_BAE);
130*10775Ssam 
131*10775Ssam 	if (func == READ)
132*10775Ssam 		com |= RL_READ;
133*10775Ssam 	else
134*10775Ssam 		com |= RL_WRITE;
135*10775Ssam 	rladdr->rlcs = com;
136*10775Ssam 
137*10775Ssam 	/* wait for controller and drive */
138*10775Ssam 	while( (rladdr->rlcs & RL_DCRDY) != RL_DCRDY)
139*10775Ssam 		continue;
140*10775Ssam 
141*10775Ssam 	if (rladdr->rlcs & RL_ERR) {
142*10775Ssam 		int status;
143*10775Ssam 
144*10775Ssam 		if ( rladdr->rlcs & RL_DE ) {
145*10775Ssam 			rladdr->rlda.getstat = RL_GSTAT;
146*10775Ssam 			rladdr->rlcs = (st->rl_dn << 8) | RL_GETSTAT;
147*10775Ssam 			rlwait(rladdr);
148*10775Ssam 			status = rladdr->rlmp.getstat;
149*10775Ssam 			rladdr->rlda.getstat = RL_RESET;
150*10775Ssam 			rladdr->rlcs = (st->rl_dn <<8) | RL_GETSTAT;
151*10775Ssam 			rlwait(rladdr);
152*10775Ssam 		}
153*10775Ssam 		printf("rl error: (cyl,head,sec)=(%d,%d,%d) cs=%b mp=%b\n",
154*10775Ssam 		    cn, head, sn, rladdr->rlcs & 0xffff, RLCS_BITS,
155*10775Ssam 		    status, RLER_BITS);
156*10775Ssam 
157*10775Ssam 		/* Determine disk posistion */
158*10775Ssam 		rladdr->rlcs = (st->rl_dn << 8) | RL_RHDR;
159*10775Ssam 		rlwait(rladdr);
160*10775Ssam 
161*10775Ssam 		/* save disk drive posistion */
162*10775Ssam 		st->rl_cylnhd = (rladdr->rlmp.readhdr & 0177700) >> 6;
163*10775Ssam 
164*10775Ssam 		if (errcnt == 10) {
165*10775Ssam 			printf("rl: unrecovered error\n");
166*10775Ssam 			return (-1);
167*10775Ssam 		}
168*10775Ssam 		errcnt++;
169*10775Ssam 		goto retry;
170*10775Ssam 	}
171*10775Ssam 
172*10775Ssam 	/* do we have to finish off the rest of the transfer? */
173*10775Ssam 	if ( (st->rl_bleft -= st->rl_bpart) > 0 ) {
174*10775Ssam 		/* increment head and/or cylinder */
175*10775Ssam 		if ( ++head > 1 ) {
176*10775Ssam 			cn++;		/* want next cyl, head 0 sector 0 */
177*10775Ssam 			head = 0;
178*10775Ssam 		}
179*10775Ssam 
180*10775Ssam 		/* we always want sector to be zero */
181*10775Ssam 		sn = 0;
182*10775Ssam 
183*10775Ssam 		/*
184*10775Ssam 		 * standalone code for ubafree does what regular
185*10775Ssam 		 *   ubapurge does and we want to purge last transfer
186*10775Ssam 		 */
187*10775Ssam 		ubafree(io, ubinfo);
188*10775Ssam 
189*10775Ssam 		ubaddr = ubinfo + io->i_cc - st->rl_bleft;
190*10775Ssam 
191*10775Ssam 		goto stupid_rl;
192*10775Ssam 	}
193*10775Ssam 
194*10775Ssam 	ubafree(io, ubinfo);
195*10775Ssam 
196*10775Ssam 	if (errcnt)
197*10775Ssam 		printf("rl: recovered by retry\n");
198*10775Ssam 	return (io->i_cc);
199*10775Ssam }
200*10775Ssam 
201*10775Ssam rlwait(rladdr)
202*10775Ssam 	register struct rldevice *rladdr;
203*10775Ssam {
204*10775Ssam 
205*10775Ssam 	while ((rladdr->rlcs & RL_CRDY) == 0)
206*10775Ssam 		continue;
207*10775Ssam }
208