Commit | Line | Data |
---|---|---|
ef960e6f | 1 | /* vd.c 7.10 88/06/14 */ |
4006c5e1 | 2 | |
39b72d60 | 3 | /* |
bff99b3e | 4 | * Stand alone driver for the VDDC/SMDE controller |
4006c5e1 | 5 | */ |
39b72d60 SL |
6 | #include "../machine/mtpr.h" |
7 | ||
8 | #include "param.h" | |
9 | #include "inode.h" | |
10 | #include "fs.h" | |
bdfd2fb7 | 11 | #include "buf.h" |
bff99b3e SL |
12 | #include "disklabel.h" |
13 | #include "saio.h" | |
14 | ||
1a9cb196 | 15 | #include "../tahoevba/vdreg.h" |
1a9cb196 | 16 | #include "../tahoevba/vbaparam.h" |
39b72d60 | 17 | |
bff99b3e | 18 | #define COMPAT_42 1 |
39b72d60 | 19 | |
cb69d88e | 20 | #define NVD 4 /* controllers */ |
bff99b3e | 21 | #define NDRIVE 8 /* drives per controller */ |
39b72d60 | 22 | |
bff99b3e SL |
23 | #define VDADDR(ctlr) ((struct vddevice *)vdaddrs[ctlr]) |
24 | long vdaddrs[NVD] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300 }; | |
39b72d60 | 25 | |
bff99b3e SL |
26 | u_char vdinit[NVD]; /* controller initialized */ |
27 | u_char vdtype[NVD]; /* controller type */ | |
cb69d88e | 28 | u_char dkconfigured[NVD][NDRIVE]; /* unit configured */ |
7d68510b | 29 | u_char dkflags[NVD][NDRIVE]; /* unit flags */ |
39b72d60 | 30 | |
cb69d88e | 31 | static struct disklabel dklabel[NVD][NDRIVE]; /* pack label */ |
7d68510b MK |
32 | static struct mdcb mdcb; |
33 | static struct dcb dcb; | |
34 | static char lbuf[DEV_BSIZE]; | |
39b72d60 SL |
35 | |
36 | vdopen(io) | |
4006c5e1 | 37 | register struct iob *io; |
39b72d60 | 38 | { |
cb69d88e | 39 | register int ctlr = io->i_ctlr; |
bff99b3e | 40 | register struct dkinfo *dk; |
bdfd2fb7 | 41 | register struct disklabel *lp, *dlp; |
bff99b3e | 42 | int error; |
39b72d60 | 43 | |
cb69d88e KB |
44 | if ((u_int)io->i_adapt) |
45 | return (EADAPT); | |
46 | if ((u_int)ctlr >= NVD) | |
47 | return (ECTLR); | |
bff99b3e SL |
48 | if (!vdinit[ctlr] && (error = vdreset_ctlr(ctlr, io->i_unit))) |
49 | return (error); | |
cb69d88e KB |
50 | lp = &dklabel[io->i_ctlr][io->i_unit]; |
51 | if (!dkconfigured[io->i_ctlr][io->i_unit]) { | |
bff99b3e SL |
52 | struct iob tio; |
53 | ||
54 | /* | |
55 | * Read in the pack label. | |
56 | */ | |
7d68510b MK |
57 | lp->d_secsize = 1024; |
58 | lp->d_nsectors = 72; | |
bff99b3e SL |
59 | lp->d_ntracks = 24; |
60 | lp->d_ncylinders = 711; | |
7d68510b | 61 | lp->d_secpercyl = 72*24; |
bff99b3e SL |
62 | if (!vdreset_drive(io)) |
63 | return (ENXIO); | |
64 | tio = *io; | |
65 | tio.i_bn = LABELSECTOR; | |
66 | tio.i_ma = lbuf; | |
67 | tio.i_cc = DEV_BSIZE; | |
68 | tio.i_flgs |= F_RDDATA; | |
cb69d88e KB |
69 | if (vdstrategy(&tio, READ) != DEV_BSIZE) |
70 | return (ERDLAB); | |
bdfd2fb7 | 71 | dlp = (struct disklabel *)(lbuf + LABELOFFSET); |
cb69d88e | 72 | if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) |
bff99b3e | 73 | #ifdef COMPAT_42 |
cb69d88e KB |
74 | { |
75 | printf("dk%d: unlabeled\n", io->i_unit); | |
bff99b3e SL |
76 | if (error = vdmaptype(io)) |
77 | return (error); | |
cb69d88e | 78 | } |
bff99b3e | 79 | #else |
cb69d88e | 80 | return (EUNLAB); |
bff99b3e | 81 | #endif |
cb69d88e | 82 | else { |
bdfd2fb7 | 83 | *lp = *dlp; |
7d68510b MK |
84 | if (!vdreset_drive(io)) |
85 | return (ENXIO); | |
86 | } | |
cb69d88e | 87 | dkconfigured[io->i_ctlr][io->i_unit] = 1; |
39b72d60 | 88 | } |
cb69d88e KB |
89 | if (io->i_part < 0 || io->i_part >= lp->d_npartitions || |
90 | lp->d_partitions[io->i_part].p_size == 0) | |
91 | return (EPART); | |
bff99b3e | 92 | io->i_boff = |
cb69d88e | 93 | (lp->d_partitions[io->i_part].p_offset * lp->d_secsize) / DEV_BSIZE; |
bff99b3e | 94 | return (0); |
39b72d60 SL |
95 | } |
96 | ||
bff99b3e SL |
97 | /* |
98 | * Reset and initialize the controller. | |
99 | */ | |
100 | vdreset_ctlr(ctlr, unit) | |
101 | register int ctlr, unit; | |
39b72d60 | 102 | { |
bff99b3e SL |
103 | register int i; |
104 | register struct vddevice *vdaddr = VDADDR(ctlr); | |
39b72d60 | 105 | |
bff99b3e SL |
106 | if (badaddr(vdaddr, 2)) { |
107 | printf("vd%d: %x: invalid csr\n", ctlr, vdaddr); | |
108 | return (ENXIO); | |
39b72d60 | 109 | } |
bff99b3e SL |
110 | /* probe further to find what kind of controller it is */ |
111 | vdaddr->vdreset = 0xffffffff; | |
39b72d60 | 112 | DELAY(1000000); |
bff99b3e SL |
113 | if (vdaddr->vdreset != 0xffffffff) { |
114 | vdtype[ctlr] = VDTYPE_VDDC; | |
39b72d60 | 115 | DELAY(1000000); |
4006c5e1 | 116 | } else { |
bff99b3e SL |
117 | vdtype[ctlr] = VDTYPE_SMDE; |
118 | vdaddr->vdrstclr = 0; | |
39b72d60 | 119 | DELAY(3000000); |
bff99b3e SL |
120 | vdaddr->vdcsr = 0; |
121 | vdaddr->vdtcf_mdcb = AM_ENPDA; | |
122 | vdaddr->vdtcf_dcb = AM_ENPDA; | |
123 | vdaddr->vdtcf_trail = AM_ENPDA; | |
124 | vdaddr->vdtcf_data = AM_ENPDA; | |
125 | vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS | | |
126 | XMD_32BIT | BSZ_16WRD | | |
127 | CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; | |
39b72d60 | 128 | } |
bff99b3e SL |
129 | if (!vdcmd(ctlr, 0, VDOP_INIT, 10) || |
130 | !vdcmd(ctlr, 0, VDOP_DIAG, 10)) { | |
131 | vderror(unit, dcb.opcode == VDOP_INIT ? "init" : "diag", &dcb); | |
132 | return (EIO); | |
39b72d60 | 133 | } |
bff99b3e | 134 | vdinit[ctlr] = 1; |
cb69d88e KB |
135 | for (i = NDRIVE - 1; i >= 0; i--) |
136 | dkconfigured[ctlr][i] = 0; | |
bff99b3e | 137 | return (0); |
39b72d60 SL |
138 | } |
139 | ||
bff99b3e SL |
140 | /* |
141 | * Reset and configure a drive's parameters. | |
142 | */ | |
143 | vdreset_drive(io) | |
4006c5e1 | 144 | register struct iob *io; |
39b72d60 | 145 | { |
cb69d88e KB |
146 | register int ctlr = io->i_ctlr, slave = io->i_unit; |
147 | register struct disklabel *lp = &dklabel[io->i_ctlr][io->i_unit]; | |
bff99b3e SL |
148 | register struct vddevice *vdaddr = VDADDR(ctlr); |
149 | int pass = 0, type = vdtype[ctlr], error; | |
7d68510b | 150 | int devflags = dkflags[ctlr][slave]; /* starts with 0 */ |
4006c5e1 | 151 | |
bff99b3e SL |
152 | again: |
153 | dcb.opcode = VDOP_CONFIG; /* command */ | |
154 | dcb.intflg = DCBINT_NONE; | |
155 | dcb.nxtdcb = (struct dcb *)0; /* end of chain */ | |
156 | dcb.operrsta = 0; | |
7d68510b | 157 | dcb.devselect = slave | devflags; |
bff99b3e SL |
158 | dcb.trail.rstrail.ncyl = lp->d_ncylinders; |
159 | dcb.trail.rstrail.nsurfaces = lp->d_ntracks; | |
160 | if (type == VDTYPE_SMDE) { | |
bdfd2fb7 | 161 | dcb.trailcnt = sizeof (struct treset) / sizeof (long); |
bff99b3e | 162 | dcb.trail.rstrail.nsectors = lp->d_nsectors; |
7d68510b MK |
163 | dcb.trail.rstrail.slip_sec = lp->d_trackskew; |
164 | dcb.trail.rstrail.recovery = VDRF_NORMAL; | |
bff99b3e SL |
165 | } else |
166 | dcb.trailcnt = 2; /* XXX */ | |
167 | mdcb.mdcb_head = &dcb; | |
168 | mdcb.mdcb_status = 0; | |
169 | VDGO(vdaddr, (u_long)&mdcb, type); | |
170 | if (!vdpoll(vdaddr, &dcb, 10, type)) { | |
171 | if (pass++ != 0) { | |
172 | printf(" during drive configuration.\n"); | |
173 | return (0); | |
174 | } | |
175 | VDRESET(vdaddr, type); | |
176 | if (error = vdreset_ctlr(ctlr, io->i_unit)) | |
177 | return (error); | |
178 | goto again; | |
39b72d60 | 179 | } |
7d68510b MK |
180 | if ((dcb.operrsta & VDERR_HARD) == 0) { /* success */ |
181 | dkflags[ctlr][slave] = devflags; | |
bff99b3e | 182 | return (1); |
7d68510b MK |
183 | } |
184 | if (devflags == 0) { | |
185 | devflags = VD_ESDI; | |
186 | goto again; | |
187 | } | |
bff99b3e SL |
188 | if (type == VDTYPE_SMDE && (vdaddr->vdstatus[slave] & STA_US) == 0) { |
189 | printf("dk%d: nonexistent drive\n", io->i_unit); | |
190 | return (0); | |
191 | } | |
192 | if ((dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) { | |
193 | vderror(io->i_unit, "config", &dcb); | |
194 | return (0); | |
195 | } | |
7d68510b | 196 | devflags = 0; |
bff99b3e SL |
197 | if (pass++) /* give up */ |
198 | return (0); | |
199 | /* | |
200 | * Try to spin up drive with remote command. | |
201 | */ | |
202 | if (!vdcmd(ctlr, 0, VDOP_START, 62)) { | |
203 | vderror(io->i_unit, "start", &dcb); | |
204 | return (0); | |
39b72d60 | 205 | } |
7f6fe1b4 | 206 | DELAY(62000000); |
bff99b3e | 207 | goto again; |
39b72d60 SL |
208 | } |
209 | ||
bff99b3e SL |
210 | vdcmd(ctlr, unit, cmd, time) |
211 | register int ctlr; | |
212 | int unit, cmd, time; | |
39b72d60 | 213 | { |
bff99b3e | 214 | register struct vddevice *vdaddr = VDADDR(ctlr); |
39b72d60 | 215 | |
bff99b3e SL |
216 | dcb.opcode = cmd; |
217 | dcb.intflg = DCBINT_NONE; | |
218 | dcb.nxtdcb = (struct dcb *)0; /* end of chain */ | |
39b72d60 | 219 | dcb.operrsta = 0; |
7d68510b | 220 | dcb.devselect = unit | dkflags[ctlr][unit]; |
bff99b3e SL |
221 | dcb.trailcnt = 0; |
222 | mdcb.mdcb_head = &dcb; | |
223 | mdcb.mdcb_status = 0; | |
224 | VDGO(vdaddr, (u_long)&mdcb, vdtype[ctlr]); | |
225 | if (!vdpoll(vdaddr, &dcb, time, vdtype[ctlr])) | |
226 | _stop(" during initialization operation.\n"); | |
227 | return ((dcb.operrsta & VDERR_HARD) == 0); | |
39b72d60 SL |
228 | } |
229 | ||
bff99b3e | 230 | vdstrategy(io, cmd) |
4006c5e1 | 231 | register struct iob *io; |
bff99b3e | 232 | int cmd; |
39b72d60 | 233 | { |
bff99b3e | 234 | register struct disklabel *lp; |
7d68510b | 235 | int ctlr, cn, tn, sn, slave, retries = 0; |
bff99b3e SL |
236 | daddr_t bn; |
237 | struct vddevice *vdaddr; | |
4006c5e1 SL |
238 | |
239 | if (io->i_cc == 0 || io->i_cc > 65535) { | |
240 | printf("dk%d: invalid transfer size %d\n", io->i_unit, | |
241 | io->i_cc); | |
d4285b3c | 242 | io->i_error = EIO; |
4006c5e1 | 243 | return (-1); |
39b72d60 | 244 | } |
cb69d88e | 245 | lp = &dklabel[io->i_ctlr][io->i_unit]; |
bff99b3e SL |
246 | bn = io->i_bn * (DEV_BSIZE / lp->d_secsize); |
247 | cn = bn / lp->d_secpercyl; | |
248 | sn = bn % lp->d_secpercyl; | |
249 | tn = sn / lp->d_nsectors; | |
250 | sn = sn % lp->d_nsectors; | |
39b72d60 | 251 | |
7d68510b | 252 | top: |
bff99b3e SL |
253 | dcb.opcode = (cmd == READ ? VDOP_RD : VDOP_WD); |
254 | dcb.intflg = DCBINT_NONE; | |
255 | dcb.nxtdcb = (struct dcb *)0; /* end of chain */ | |
39b72d60 | 256 | dcb.operrsta = 0; |
cb69d88e KB |
257 | ctlr = io->i_ctlr; |
258 | slave = io->i_unit; | |
7d68510b | 259 | dcb.devselect = slave | dkflags[ctlr][slave]; |
bdfd2fb7 MK |
260 | dcb.trailcnt = sizeof (struct trrw) / sizeof (int); |
261 | dcb.trail.rwtrail.memadr = (u_long)io->i_ma; | |
bff99b3e SL |
262 | dcb.trail.rwtrail.wcount = (io->i_cc + 1) / sizeof (short); |
263 | dcb.trail.rwtrail.disk.cylinder = cn; | |
264 | dcb.trail.rwtrail.disk.track = tn; | |
265 | dcb.trail.rwtrail.disk.sector = sn; | |
266 | mdcb.mdcb_head = &dcb; | |
267 | mdcb.mdcb_status = 0; | |
bff99b3e SL |
268 | vdaddr = VDADDR(ctlr); |
269 | VDGO(vdaddr, (u_long)&mdcb, vdtype[ctlr]); | |
270 | if (!vdpoll(vdaddr, &dcb, 60, vdtype[ctlr])) | |
4006c5e1 | 271 | _stop(" during i/o operation.\n"); |
bff99b3e | 272 | if (dcb.operrsta & VDERR_HARD) { |
7d68510b MK |
273 | if (retries++ == 0 && vdreset_ctlr(ctlr, io->i_unit) == 0 && |
274 | vdreset_drive(io)) | |
275 | goto top; | |
bff99b3e SL |
276 | vderror(io->i_unit, cmd == READ ? "read" : "write", &dcb); |
277 | io->i_error = EIO; | |
278 | return (-1); | |
279 | } | |
280 | mtpr(PADC, 0); | |
281 | return (io->i_cc); | |
39b72d60 SL |
282 | } |
283 | ||
bff99b3e SL |
284 | vderror(unit, cmd, dcb) |
285 | int unit; | |
286 | char *cmd; | |
287 | struct dcb *dcb; | |
39b72d60 | 288 | { |
4006c5e1 | 289 | |
bff99b3e SL |
290 | printf("dk%d: %s error; status %b", unit, cmd, |
291 | dcb->operrsta, VDERRBITS); | |
292 | if (dcb->err_code) | |
293 | printf(", code %x", dcb->err_code); | |
39b72d60 | 294 | printf("\n"); |
39b72d60 SL |
295 | } |
296 | ||
1a9cb196 | 297 | /* |
bff99b3e SL |
298 | * Poll controller until operation |
299 | * completes or timeout expires. | |
1a9cb196 | 300 | */ |
bff99b3e SL |
301 | vdpoll(vdaddr, dcb, t, type) |
302 | register struct vddevice *vdaddr; | |
303 | register struct dcb *dcb; | |
1a9cb196 SL |
304 | register int t, type; |
305 | { | |
306 | ||
307 | t *= 1000; | |
d4285b3c | 308 | for (;;) { |
1a9cb196 | 309 | uncache(&dcb->operrsta); |
bff99b3e | 310 | if (dcb->operrsta & (DCBS_DONE|DCBS_ABORT)) |
d4285b3c | 311 | break; |
1a9cb196 SL |
312 | if (--t <= 0) { |
313 | printf("vd: controller timeout"); | |
bff99b3e | 314 | VDABORT(vdaddr, type); |
1a9cb196 SL |
315 | DELAY(30000); |
316 | uncache(&dcb->operrsta); | |
317 | return (0); | |
318 | } | |
d4285b3c | 319 | DELAY(1000); |
1a9cb196 | 320 | } |
bff99b3e | 321 | if (type == VDTYPE_SMDE) { |
d4285b3c | 322 | for (;;) { |
bff99b3e SL |
323 | uncache(&vdaddr->vdcsr); |
324 | if ((vdaddr->vdcsr & CS_GO) == 0) | |
d4285b3c SL |
325 | break; |
326 | DELAY(50); | |
1a9cb196 SL |
327 | } |
328 | DELAY(300); | |
7f6fe1b4 | 329 | uncache(&dcb->err_code); |
1a9cb196 SL |
330 | } |
331 | DELAY(200); | |
332 | uncache(&dcb->operrsta); | |
333 | return (1); | |
334 | } | |
bff99b3e SL |
335 | |
336 | #ifdef COMPAT_42 | |
337 | struct dkcompat { | |
338 | int nsectors; /* sectors per track */ | |
339 | int ntracks; /* tracks per cylinder */ | |
340 | int ncylinders; /* cylinders per drive */ | |
7d68510b | 341 | int secsize; /* sector size */ |
bff99b3e SL |
342 | #define NPART 2 |
343 | int poff[NPART]; /* [a+b] for bootstrapping */ | |
344 | } dkcompat[] = { | |
ef960e6f | 345 | { 64, 20, 842, 512, 0, 61440 }, /* 2361a eagle */ |
7d68510b MK |
346 | { 48, 24, 711, 512, 0, 61056 }, /* xsd */ |
347 | { 44, 20, 842, 512, 0, 52800 }, /* eagle */ | |
348 | { 64, 10, 823, 512, 0, 38400 }, /* fuji 360 */ | |
349 | { 32, 24, 711, 512, 0, 40704 }, /* xfd */ | |
350 | { 32, 19, 823, 512, 0, 40128 }, /* smd */ | |
351 | { 32, 10, 823, 512, 0, 19200 }, /* fsd */ | |
352 | { 18, 15, 1224, 1024, 0, 21600 }, /* mxd */ | |
bff99b3e SL |
353 | }; |
354 | #define NDKCOMPAT (sizeof (dkcompat) / sizeof (dkcompat[0])) | |
355 | ||
356 | /* | |
357 | * Identify and configure drive from above table | |
358 | * by trying to read the last sector until a description | |
359 | * is found for which we're successful. | |
360 | */ | |
361 | vdmaptype(io) | |
362 | struct iob *io; | |
363 | { | |
cb69d88e | 364 | register struct disklabel *lp = &dklabel[io->i_ctlr][io->i_unit]; |
bff99b3e | 365 | register struct dkcompat *dp; |
7d68510b | 366 | int i, ctlr, slave, type; |
bff99b3e SL |
367 | struct vddevice *vdaddr; |
368 | ||
cb69d88e KB |
369 | ctlr = io->i_ctlr; |
370 | slave = io->i_unit; | |
bff99b3e SL |
371 | vdaddr = VDADDR(ctlr); |
372 | type = vdtype[ctlr]; | |
373 | for (dp = dkcompat; dp < &dkcompat[NDKCOMPAT]; dp++) { | |
374 | if (type == VDTYPE_VDDC && dp->nsectors != 32) | |
375 | continue; | |
376 | lp->d_nsectors = dp->nsectors; | |
377 | lp->d_ntracks = dp->ntracks; | |
378 | lp->d_ncylinders = dp->ncylinders; | |
7d68510b | 379 | lp->d_secsize = dp->secsize; |
bff99b3e SL |
380 | if (!vdreset_drive(io)) /* set drive parameters */ |
381 | return (EIO); | |
382 | dcb.opcode = VDOP_RD; | |
383 | dcb.intflg = DCBINT_NONE; | |
384 | dcb.nxtdcb = (struct dcb *)0; /* end of chain */ | |
7d68510b | 385 | dcb.devselect = slave | dkflags[ctlr][slave]; |
bff99b3e | 386 | dcb.operrsta = 0; |
bdfd2fb7 MK |
387 | dcb.trailcnt = sizeof (struct trrw) / sizeof (long); |
388 | dcb.trail.rwtrail.memadr = (u_long)lbuf; | |
7d68510b | 389 | dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof (short); |
bff99b3e SL |
390 | dcb.trail.rwtrail.disk.cylinder = dp->ncylinders - 2; |
391 | dcb.trail.rwtrail.disk.track = dp->ntracks - 1; | |
392 | dcb.trail.rwtrail.disk.sector = dp->nsectors - 1; | |
393 | mdcb.mdcb_head = &dcb; | |
394 | mdcb.mdcb_status = 0; | |
395 | VDGO(vdaddr, (u_long)&mdcb, type); | |
396 | if (!vdpoll(vdaddr, &dcb, 60, type)) | |
397 | _stop(" during i/o operation.\n"); | |
398 | if (dcb.operrsta & VDERR_HARD) | |
399 | continue; | |
400 | /* simulate necessary parts of disk label */ | |
401 | lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; | |
402 | lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; | |
403 | lp->d_npartitions = NPART; | |
404 | for (i = 0; i < NPART; i++) { | |
405 | lp->d_partitions[i].p_offset = dp->poff[i]; | |
406 | lp->d_partitions[i].p_size = | |
407 | lp->d_secperunit - dp->poff[i]; | |
408 | } | |
409 | return (0); | |
410 | } | |
411 | printf("dk%d: unknown drive type\n", io->i_unit); | |
412 | return (ENXIO); | |
413 | } | |
414 | #endif |