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