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