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