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