Commit | Line | Data |
---|---|---|
4f42a6a1 | 1 | /* vd.c 1.15 87/02/28 */ |
210a9f40 | 2 | |
ad409ece | 3 | #include "dk.h" |
210a9f40 SL |
4 | #if NVD > 0 |
5 | /* | |
7bae1a62 | 6 | * Versabus VDDC/SMDE driver. |
9d915fad | 7 | */ |
9d915fad SL |
8 | #include "param.h" |
9 | #include "buf.h" | |
10 | #include "cmap.h" | |
11 | #include "conf.h" | |
12 | #include "dir.h" | |
ad409ece | 13 | #include "dkstat.h" |
7bae1a62 | 14 | #include "disklabel.h" |
9d915fad | 15 | #include "map.h" |
7bae1a62 | 16 | #include "file.h" |
9d915fad SL |
17 | #include "systm.h" |
18 | #include "user.h" | |
19 | #include "vmmac.h" | |
20 | #include "proc.h" | |
21 | #include "uio.h" | |
82bc5dc5 MK |
22 | #include "syslog.h" |
23 | #include "kernel.h" | |
7bae1a62 | 24 | #include "ioctl.h" |
9d915fad | 25 | |
997cf0e7 MK |
26 | #include "../tahoe/cpu.h" |
27 | #include "../tahoe/mtpr.h" | |
28 | #include "../tahoe/pte.h" | |
29 | ||
9d915fad | 30 | #include "../tahoevba/vbavar.h" |
c7c48d07 | 31 | #include "../tahoevba/vdreg.h" |
9d915fad | 32 | |
7bae1a62 | 33 | #define COMPAT_42 |
210a9f40 | 34 | |
7bae1a62 | 35 | #define VDMAXIO (MAXBPTE*NBPG) |
9d915fad | 36 | |
7bae1a62 SL |
37 | #define vdunit(dev) (minor(dev) >> 3) |
38 | #define vdpart(dev) (minor(dev) & 0x07) | |
39 | #define vdminor(unit,part) (((unit) << 3) | (part)) | |
210a9f40 SL |
40 | |
41 | struct vba_ctlr *vdminfo[NVD]; | |
ad409ece | 42 | struct vba_device *vddinfo[NDK]; |
9d915fad | 43 | int vdprobe(), vdslave(), vdattach(), vddgo(); |
7bae1a62 | 44 | long vdaddr[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 }; |
9d915fad | 45 | struct vba_driver vddriver = |
7bae1a62 SL |
46 | { vdprobe, vdslave, vdattach, vddgo, vdaddr, "dk", vddinfo, "vd", vdminfo }; |
47 | ||
48 | /* | |
49 | * Per-controller state. | |
50 | */ | |
51 | struct vdsoftc { | |
52 | u_short vd_flags; | |
53 | #define VD_INIT 0x1 /* controller initialized */ | |
54 | #define VD_STARTED 0x2 /* start command issued */ | |
55 | #define VD_DOSEEKS 0x4 /* should overlap seeks */ | |
56 | u_short vd_type; /* controller type */ | |
57 | u_short vd_wticks; /* timeout */ | |
58 | u_short vd_offcyl; /* off cylinder bitmask */ | |
59 | struct mdcb vd_mdcb; /* master command block */ | |
60 | u_long vd_mdcbphys; /* physical address of vd_mdcb */ | |
61 | struct dcb vd_dcb; /* i/o command block */ | |
62 | u_long vd_dcbphys; /* physical address of vd_dcb */ | |
63 | struct pte *vd_map; /* i/o page map */ | |
64 | caddr_t vd_utl; /* mapped i/o space */ | |
65 | caddr_t vd_rawbuf; /* buffer for raw+swap i/o */ | |
66 | } vdsoftc[NVD]; | |
210a9f40 SL |
67 | |
68 | /* | |
9d915fad SL |
69 | * Per-drive state. |
70 | */ | |
7bae1a62 SL |
71 | struct dksoftc { |
72 | u_short dk_state; /* open fsm */ | |
73 | u_short dk_openpart; /* units open on this drive */ | |
7bae1a62 SL |
74 | u_short dk_curdaddr; /* last selected track & sector */ |
75 | u_int dk_curcyl; /* last selected cylinder */ | |
76 | struct dcb dk_dcb; /* seek command block */ | |
77 | u_long dk_dcbphys; /* physical address of dk_dcb */ | |
78 | } dksoftc[NDK]; | |
210a9f40 SL |
79 | |
80 | /* | |
7bae1a62 SL |
81 | * Drive states. Used during steps of open/initialization. |
82 | * States < OPEN (> 0) are transient, during an open operation. | |
83 | * OPENRAW is used for unabeled disks, to allow format operations. | |
9d915fad | 84 | */ |
7bae1a62 SL |
85 | #define CLOSED 0 /* disk is closed */ |
86 | #define WANTOPEN 1 /* open requested, not started */ | |
87 | #define WANTOPENRAW 2 /* open requested, no label */ | |
88 | #define RDLABEL 3 /* reading pack label */ | |
89 | #define OPEN 4 /* intialized and ready */ | |
90 | #define OPENRAW 5 /* open, no label */ | |
91 | ||
92 | struct buf rdkbuf[NDK]; /* raw i/o buffer headers */ | |
93 | struct buf dkutab[NDK]; /* i/o queue headers */ | |
94 | struct disklabel dklabel[NDK]; /* pack labels */ | |
95 | ||
96 | #define b_cylin b_resid | |
97 | #define b_daddr b_error | |
98 | ||
99 | int vdwstart, vdwatch(); | |
210a9f40 SL |
100 | |
101 | /* | |
9d915fad SL |
102 | * See if the controller is really there; if so, initialize it. |
103 | */ | |
336ca318 SL |
104 | vdprobe(reg, vm) |
105 | caddr_t reg; | |
106 | struct vba_ctlr *vm; | |
210a9f40 | 107 | { |
336ca318 | 108 | register br, cvec; /* must be r12, r11 */ |
7bae1a62 SL |
109 | register struct vddevice *vdaddr = (struct vddevice *)reg; |
110 | struct vdsoftc *vd; | |
4f42a6a1 | 111 | int s; |
336ca318 | 112 | |
82bc5dc5 MK |
113 | #ifdef lint |
114 | br = 0; cvec = br; br = cvec; | |
115 | vdintr(0); | |
116 | #endif | |
336ca318 | 117 | if (badaddr((caddr_t)reg, 2)) |
9d915fad | 118 | return (0); |
7bae1a62 SL |
119 | vd = &vdsoftc[vm->um_ctlr]; |
120 | vdaddr->vdreset = 0xffffffff; | |
9d915fad | 121 | DELAY(1000000); |
7bae1a62 SL |
122 | if (vdaddr->vdreset != (unsigned)0xffffffff) { |
123 | vd->vd_type = VDTYPE_VDDC; | |
124 | vd->vd_flags &= ~VD_DOSEEKS; | |
9d915fad SL |
125 | DELAY(1000000); |
126 | } else { | |
7bae1a62 SL |
127 | vd->vd_type = VDTYPE_SMDE; |
128 | vd->vd_flags |= VD_DOSEEKS; | |
129 | vdaddr->vdrstclr = 0; | |
9d915fad | 130 | DELAY(3000000); |
7bae1a62 SL |
131 | vdaddr->vdcsr = 0; |
132 | vdaddr->vdtcf_mdcb = AM_ENPDA; | |
133 | vdaddr->vdtcf_dcb = AM_ENPDA; | |
134 | vdaddr->vdtcf_trail = AM_ENPDA; | |
135 | vdaddr->vdtcf_data = AM_ENPDA; | |
136 | vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS | | |
227f7a3e | 137 | XMD_32BIT | BSZ_16WRD | |
7c4f3479 | 138 | CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; |
210a9f40 | 139 | } |
7bae1a62 SL |
140 | vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb); |
141 | vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb); | |
142 | vm->um_addr = reg; /* XXX */ | |
4f42a6a1 | 143 | s = spl7(); |
7bae1a62 SL |
144 | if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { |
145 | printf("vd%d: %s cmd failed\n", vm->um_ctlr, | |
146 | vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); | |
4f42a6a1 | 147 | splx(s); |
7bae1a62 SL |
148 | return (0); |
149 | } | |
4f42a6a1 | 150 | splx(s); |
7c4f3479 | 151 | /* |
f60fa697 | 152 | * Allocate page tables and i/o buffer. |
7c4f3479 | 153 | */ |
7bae1a62 SL |
154 | vbmapalloc(btoc(VDMAXIO)+1, &vd->vd_map, &vd->vd_utl); |
155 | vd->vd_rawbuf = calloc(VDMAXIO); | |
336ca318 | 156 | br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */ |
7bae1a62 | 157 | return (sizeof (struct vddevice)); |
9d915fad | 158 | } |
210a9f40 SL |
159 | |
160 | /* | |
7bae1a62 SL |
161 | * See if a drive is really there. |
162 | * | |
163 | * Can't read pack label here as various data structures | |
164 | * aren't setup for doing a read in a straightforward | |
165 | * manner. Instead just probe for the drive and leave | |
166 | * the pack label stuff to the attach routine. | |
9d915fad SL |
167 | */ |
168 | vdslave(vi, addr) | |
169 | register struct vba_device *vi; | |
7bae1a62 | 170 | struct vddevice *vdaddr; |
210a9f40 | 171 | { |
7bae1a62 SL |
172 | register struct disklabel *lp = &dklabel[vi->ui_unit]; |
173 | struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; | |
9d915fad | 174 | |
7bae1a62 | 175 | if ((vd->vd_flags&VD_INIT) == 0) { |
7c4f3479 | 176 | printf("vd%d: %s controller\n", vi->ui_ctlr, |
7bae1a62 SL |
177 | vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE"); |
178 | vd->vd_flags |= VD_INIT; | |
210a9f40 | 179 | } |
7bae1a62 | 180 | |
210a9f40 | 181 | /* |
7bae1a62 SL |
182 | * Initialize label enough to do a reset on |
183 | * the drive. The remainder of the default | |
184 | * label values will be filled in in vdinit | |
185 | * at attach time. | |
210a9f40 | 186 | */ |
7bae1a62 SL |
187 | lp->d_secsize = DEV_BSIZE / 2; /* XXX */ |
188 | lp->d_nsectors = 32; | |
189 | lp->d_ntracks = 24; | |
190 | lp->d_ncylinders = 711; | |
191 | lp->d_secpercyl = 32*24; | |
192 | return (vdreset_drive(vi)); | |
9d915fad SL |
193 | } |
194 | ||
7bae1a62 SL |
195 | /* |
196 | * Read pack label. | |
197 | */ | |
198 | vdattach(vi) | |
199 | register struct vba_device *vi; | |
9d915fad | 200 | { |
7bae1a62 SL |
201 | register int unit = vi->ui_unit; |
202 | register struct dksoftc *dk = &dksoftc[unit]; | |
203 | register struct disklabel *lp; | |
204 | ||
7bae1a62 SL |
205 | /* |
206 | * Try to initialize device and read pack label. | |
207 | */ | |
208 | if (vdinit(vdminor(unit, 0), 0) != 0) { | |
209 | printf(": unknown drive type"); | |
210 | return; | |
9d915fad | 211 | } |
7bae1a62 SL |
212 | /* |
213 | * Initialize invariant portion of | |
214 | * dcb used for overlapped seeks. | |
215 | */ | |
216 | dk->dk_dcb.opcode = VDOP_SEEK; | |
217 | dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA; | |
218 | dk->dk_dcb.devselect = vi->ui_slave; | |
219 | dk->dk_dcb.trailcnt = sizeof (trseek) / sizeof (long); | |
220 | dk->dk_dcb.trail.sktrail.skaddr.sector = 0; | |
221 | dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb); | |
222 | lp = &dklabel[unit]; | |
223 | printf(": %s <ntrak %d, ncyl %d, nsec %d>", | |
224 | lp->d_typename, lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors); | |
225 | /* | |
226 | * (60 / rpm) / (sectors per track * (bytes per sector / 2)) | |
227 | */ | |
228 | if (vi->ui_dk >= 0) | |
229 | dk_mspw[vi->ui_dk] = 120.0 / | |
230 | (lp->d_rpm * lp->d_nsectors * lp->d_secsize); | |
231 | #ifdef notyet | |
4f42a6a1 | 232 | addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp); |
7bae1a62 | 233 | #endif |
9d915fad SL |
234 | } |
235 | ||
7bae1a62 SL |
236 | /*ARGSUSED*/ |
237 | vdopen(dev, flags) | |
238 | dev_t dev; | |
239 | int flags; | |
9d915fad | 240 | { |
7bae1a62 SL |
241 | register unit = vdunit(dev); |
242 | register struct disklabel *lp; | |
243 | register struct dksoftc *dk; | |
244 | register struct partition *pp; | |
245 | struct vba_device *vi; | |
246 | int s, error, part = vdpart(dev); | |
247 | daddr_t start, end; | |
248 | ||
249 | if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) | |
250 | return (ENXIO); | |
251 | lp = &dklabel[unit]; | |
252 | dk = &dksoftc[unit]; | |
9d915fad | 253 | |
7bae1a62 SL |
254 | s = spl7(); |
255 | while (dk->dk_state != OPEN && dk->dk_state != OPENRAW && | |
256 | dk->dk_state != CLOSED) | |
257 | sleep((caddr_t)dk, PZERO+1); | |
258 | splx(s); | |
259 | if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) | |
260 | if (error = vdinit(dev, flags)) | |
261 | return (error); | |
4f42a6a1 MK |
262 | |
263 | if (vdwstart == 0) { | |
264 | timeout(vdwatch, (caddr_t)0, hz); | |
265 | vdwstart++; | |
266 | } | |
7bae1a62 SL |
267 | /* |
268 | * Warn if a partion is opened | |
269 | * that overlaps another partition which is open | |
270 | * unless one is the "raw" partition (whole disk). | |
271 | */ | |
272 | #define RAWPART 2 /* 'c' partition */ /* XXX */ | |
273 | if ((dk->dk_openpart & (1 << part)) == 0 && | |
274 | part != RAWPART) { | |
275 | pp = &lp->d_partitions[part]; | |
276 | start = pp->p_offset; | |
277 | end = pp->p_offset + pp->p_size; | |
278 | for (pp = lp->d_partitions; | |
279 | pp < &lp->d_partitions[lp->d_npartitions]; pp++) { | |
280 | if (pp->p_offset + pp->p_size <= start || | |
281 | pp->p_offset >= end) | |
282 | continue; | |
283 | if (pp - lp->d_partitions == RAWPART) | |
284 | continue; | |
285 | if (dk->dk_openpart & (1 << (pp - lp->d_partitions))) | |
286 | log(LOG_WARNING, | |
287 | "dk%d%c: overlaps open partition (%c)\n", | |
288 | unit, part + 'a', | |
289 | pp - lp->d_partitions + 'a'); | |
290 | } | |
9d915fad | 291 | } |
7bae1a62 SL |
292 | if (part >= lp->d_npartitions) |
293 | return (ENXIO); | |
294 | dk->dk_openpart |= 1 << part; | |
295 | return (0); | |
9d915fad SL |
296 | } |
297 | ||
7bae1a62 SL |
298 | vdclose(dev, flags) |
299 | dev_t dev; | |
300 | int flags; | |
9d915fad | 301 | { |
7bae1a62 SL |
302 | register int unit = vdunit(dev); |
303 | register struct dksoftc *dk = &dksoftc[unit]; | |
304 | ||
305 | dk->dk_openpart &= ~(1 << vdpart(dev)); | |
7bae1a62 SL |
306 | /* |
307 | * Should wait for i/o to complete on this partition | |
308 | * even if others are open, but wait for work on blkflush(). | |
309 | */ | |
310 | if (dk->dk_openpart == 0) { | |
4f42a6a1 MK |
311 | int s = spl7(); |
312 | while (dkutab[unit].b_actf) | |
313 | sleep((caddr_t)dk, PZERO-1); | |
7bae1a62 SL |
314 | splx(s); |
315 | dk->dk_state = CLOSED; | |
210a9f40 | 316 | } |
210a9f40 SL |
317 | } |
318 | ||
7bae1a62 SL |
319 | vdinit(dev, flags) |
320 | dev_t dev; | |
321 | int flags; | |
210a9f40 | 322 | { |
7bae1a62 SL |
323 | register struct buf *bp = NULL; |
324 | register struct disklabel *lp; | |
325 | register struct dksoftc *dk; | |
326 | struct vba_device *vi; | |
327 | struct disklabel *dlp; | |
328 | int unit = vdunit(dev), error = 0; | |
329 | extern int cold; | |
330 | ||
331 | dk = &dksoftc[unit]; | |
332 | if (flags & O_NDELAY) { | |
333 | dk->dk_state = OPENRAW; | |
334 | goto done; | |
335 | } | |
336 | ||
337 | /* | |
338 | * Initialize portion of the label | |
339 | * not set up in the slave routine. | |
340 | */ | |
7bae1a62 SL |
341 | dk->dk_state = RDLABEL; |
342 | lp = &dklabel[unit]; | |
343 | lp->d_secperunit = 0x1fffffff; | |
344 | lp->d_npartitions = 1; | |
345 | lp->d_partitions[0].p_size = 0x1fffffff; | |
346 | lp->d_partitions[0].p_offset = 0; | |
347 | ||
348 | bp = geteblk(DEV_BSIZE); /* max sector size */ | |
349 | bp->b_dev = dev; | |
350 | bp->b_blkno = LABELSECTOR; | |
351 | bp->b_bcount = DEV_BSIZE; | |
352 | bp->b_flags = B_BUSY | B_READ; | |
353 | bp->b_cylin = LABELSECTOR / lp->d_secpercyl; | |
354 | vdstrategy(bp); | |
355 | biowait(bp); | |
356 | if (bp->b_flags & B_ERROR) { | |
357 | error = u.u_error; /* XXX */ | |
358 | u.u_error = 0; | |
359 | dk->dk_state = CLOSED; | |
360 | goto done; | |
361 | } | |
362 | vi = vddinfo[unit]; | |
363 | dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET); | |
364 | if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC && | |
365 | dkcksum(dlp) == 0) { | |
366 | *lp = *dlp; | |
367 | /* | |
368 | * Now that we have the label, configure | |
369 | * the correct drive parameters. | |
370 | */ | |
371 | if (!vdreset_drive(vi)) | |
372 | dk->dk_state = CLOSED; | |
373 | else | |
374 | dk->dk_state = OPEN; | |
9d915fad | 375 | } else { |
7bae1a62 SL |
376 | if (cold) |
377 | printf(": no disk label"); | |
378 | else | |
379 | log(LOG_ERR, "dk%d: no disk label\n", vi->ui_unit); | |
380 | #ifdef COMPAT_42 | |
381 | if (!vdmaptype(vi, lp)) { | |
382 | error = ENXIO; | |
383 | dk->dk_state = CLOSED; | |
384 | } else | |
385 | dk->dk_state = OPEN; | |
386 | #else | |
387 | dk->dk_state = OPENRAW; | |
388 | #endif | |
9d915fad | 389 | } |
7bae1a62 | 390 | done: |
7bae1a62 SL |
391 | if (bp) { |
392 | bp->b_flags = B_INVAL | B_AGE; | |
393 | brelse(bp); | |
394 | } | |
395 | wakeup((caddr_t)dk); | |
396 | return (error); | |
210a9f40 SL |
397 | } |
398 | ||
9d915fad | 399 | /*ARGSUSED*/ |
7bae1a62 SL |
400 | vddgo(vm) |
401 | struct vba_device *vm; | |
210a9f40 | 402 | { |
9d915fad | 403 | |
210a9f40 SL |
404 | } |
405 | ||
406 | vdstrategy(bp) | |
9d915fad | 407 | register struct buf *bp; |
210a9f40 | 408 | { |
7bae1a62 SL |
409 | register struct vba_device *vi; |
410 | register struct disklabel *lp; | |
411 | register struct dksoftc *dk; | |
412 | register int unit; | |
4f42a6a1 | 413 | register daddr_t sn; |
7bae1a62 | 414 | struct buf *dp; |
4f42a6a1 | 415 | daddr_t sz, maxsz; |
7bae1a62 SL |
416 | int part, s; |
417 | ||
418 | sz = bp->b_bcount; | |
419 | sz = (sz + DEV_BSIZE - 1) >> DEV_BSHIFT; | |
420 | unit = vdunit(bp->b_dev); | |
421 | if (unit > NDK) { | |
422 | bp->b_error = ENXIO; | |
423 | goto bad; | |
424 | } | |
425 | vi = vddinfo[unit]; | |
426 | lp = &dklabel[unit]; | |
427 | if (vi == 0 || vi->ui_alive == 0) { | |
1e9609f2 | 428 | bp->b_error = ENXIO; |
9d915fad | 429 | goto bad; |
1e9609f2 | 430 | } |
7bae1a62 SL |
431 | dk = &dksoftc[unit]; |
432 | if (dk->dk_state < OPEN) | |
433 | goto q; | |
434 | part = vdpart(bp->b_dev); | |
435 | if ((dk->dk_openpart & (1 << part)) == 0) { | |
436 | bp->b_error = ENODEV; | |
437 | goto bad; | |
438 | } | |
439 | maxsz = lp->d_partitions[part].p_size; | |
4f42a6a1 | 440 | sn = bp->b_blkno; |
7bae1a62 SL |
441 | if (sn < 0 || sn + sz > maxsz) { |
442 | if (sn == maxsz) { | |
1e9609f2 MK |
443 | bp->b_resid = bp->b_bcount; |
444 | goto done; | |
445 | } | |
4f42a6a1 MK |
446 | sz = maxsz - bp->b_blkno; |
447 | if (sz <= 0) { | |
448 | bp->b_error = EINVAL; | |
449 | goto bad; | |
450 | } | |
451 | bp->b_bcount = sz * lp->d_secsize; | |
210a9f40 | 452 | } |
7bae1a62 SL |
453 | bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl; |
454 | q: | |
455 | vbasetup(bp, lp->d_secsize); | |
9d915fad | 456 | s = spl7(); |
7bae1a62 SL |
457 | dp = &dkutab[vi->ui_unit]; |
458 | disksort(dp, bp); | |
459 | if (!dp->b_active) { | |
460 | (void) vdustart(vi); | |
4f42a6a1 | 461 | if (!vi->ui_mi->um_tab.b_active) |
7bae1a62 | 462 | vdstart(vi->ui_mi); |
9d915fad | 463 | } |
7bae1a62 | 464 | splx(s); |
210a9f40 | 465 | return; |
9d915fad | 466 | bad: |
1e9609f2 MK |
467 | bp->b_flags |= B_ERROR; |
468 | done: | |
7bae1a62 SL |
469 | biodone(bp); |
470 | return; | |
210a9f40 SL |
471 | } |
472 | ||
7bae1a62 SL |
473 | vdustart(vi) |
474 | register struct vba_device *vi; | |
9d915fad | 475 | { |
7bae1a62 SL |
476 | register struct buf *bp, *dp; |
477 | register struct vba_ctlr *vm; | |
478 | register int unit = vi->ui_unit; | |
479 | register struct dksoftc *dk; | |
480 | register struct vdsoftc *vd; | |
481 | struct disklabel *lp; | |
482 | ||
7bae1a62 SL |
483 | dp = &dkutab[unit]; |
484 | /* | |
485 | * If queue empty, nothing to do. | |
486 | */ | |
487 | if ((bp = dp->b_actf) == NULL) | |
488 | return; | |
489 | /* | |
490 | * If drive is off-cylinder, mark unit to force | |
491 | * overlap seek with next transfer on this controller. | |
492 | */ | |
493 | vd = &vdsoftc[vi->ui_ctlr]; | |
494 | dk = &dksoftc[unit]; | |
495 | if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) { | |
7bae1a62 | 496 | lp = &dklabel[unit]; |
4f42a6a1 | 497 | bp->b_daddr = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors; |
7bae1a62 SL |
498 | if (bp->b_daddr != dk->dk_curdaddr) |
499 | vd->vd_offcyl |= 1 << vi->ui_slave; | |
500 | } | |
501 | /* | |
502 | * If controller is not busy, place request on the | |
4f42a6a1 | 503 | * controller's ready queue). |
7bae1a62 | 504 | */ |
4f42a6a1 MK |
505 | dp->b_forw = NULL; |
506 | vm = vi->ui_mi; | |
507 | if (vm->um_tab.b_actf == NULL) | |
508 | vm->um_tab.b_actf = dp; | |
509 | else | |
510 | vm->um_tab.b_actl->b_forw = dp; | |
511 | vm->um_tab.b_actl = dp; | |
512 | dp->b_active++; | |
9d915fad SL |
513 | } |
514 | ||
515 | /* | |
7bae1a62 | 516 | * Start next transfer on a controller. |
9d915fad | 517 | */ |
7bae1a62 SL |
518 | vdstart(vm) |
519 | register struct vba_ctlr *vm; | |
9d915fad | 520 | { |
9d915fad | 521 | register struct buf *bp; |
7bae1a62 SL |
522 | register struct vba_device *vi; |
523 | register struct vdsoftc *vd; | |
524 | register struct dksoftc *dk; | |
525 | register struct disklabel *lp; | |
526 | register int slave; | |
527 | register struct dcb **dcbp; | |
528 | struct mdcb *mdcb; | |
529 | struct buf *dp; | |
530 | int sn, tn; | |
531 | ||
532 | loop: | |
533 | /* | |
534 | * Pull a request off the controller queue. | |
535 | */ | |
536 | if ((dp = vm->um_tab.b_actf) == NULL) | |
537 | return; | |
538 | if ((bp = dp->b_actf) == NULL) { | |
539 | vm->um_tab.b_actf = dp->b_forw; | |
540 | goto loop; | |
541 | } | |
9d915fad | 542 | |
210a9f40 | 543 | /* |
7bae1a62 SL |
544 | * Mark controller busy, and determine |
545 | * destination of this request. | |
210a9f40 | 546 | */ |
7bae1a62 SL |
547 | vm->um_tab.b_active++; |
548 | vi = vddinfo[vdunit(bp->b_dev)]; | |
549 | dk = &dksoftc[vi->ui_unit]; | |
4f42a6a1 | 550 | sn = bp->b_blkno; |
7bae1a62 SL |
551 | lp = &dklabel[vi->ui_unit]; |
552 | sn %= lp->d_secpercyl; | |
553 | tn = sn / lp->d_nsectors; | |
554 | sn %= lp->d_nsectors; | |
210a9f40 | 555 | |
7bae1a62 SL |
556 | /* |
557 | * Construct dcb for read/write command. | |
558 | */ | |
559 | vd = &vdsoftc[vm->um_ctlr]; | |
560 | slave = vi->ui_slave; | |
561 | vd->vd_dcb.opcode = (bp->b_flags & B_READ) ? VDOP_RD : VDOP_WD; | |
562 | vd->vd_dcb.intflg = DCBINT_DONE; | |
563 | vd->vd_dcb.devselect = slave; | |
564 | vd->vd_dcb.operrsta = 0; | |
565 | vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ | |
566 | vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long); | |
567 | vd->vd_dcb.trail.rwtrail.memadr = (char *) | |
568 | vbastart(bp, vd->vd_rawbuf, (long *)vd->vd_map, vd->vd_utl); | |
569 | vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1; | |
570 | vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin; | |
571 | vd->vd_dcb.trail.rwtrail.disk.track = tn; | |
572 | vd->vd_dcb.trail.rwtrail.disk.sector = sn; | |
9d915fad | 573 | |
7bae1a62 SL |
574 | /* |
575 | * Look for any seeks to be performed on other drives on this | |
576 | * controller. If overlapped seeks exist, insert seek commands | |
577 | * on the controller's command queue before the transfer. | |
578 | */ | |
579 | dcbp = &vd->vd_mdcb.mdcb_head; | |
580 | if (vd->vd_offcyl &~ (1<<slave)) { | |
581 | register struct dksoftc *tdk; | |
582 | register struct buf *tp; | |
583 | ||
584 | for (dp = dp->b_forw; dp != NULL; dp = dp->b_forw) { | |
585 | if ((tp = dp->b_actf) == NULL) | |
586 | continue; | |
587 | slave = (vi = vddinfo[vdunit(tp->b_dev)])->ui_slave; | |
588 | if ((vd->vd_offcyl & (1<<slave)) == 0) | |
589 | continue; | |
590 | vd->vd_offcyl &= ~(1 << slave); | |
591 | tdk = &dksoftc[vi->ui_unit]; | |
592 | if (tdk->dk_curcyl != tp->b_cylin) { | |
593 | tdk->dk_curcyl = tp->b_cylin; | |
594 | dk_seek[vi->ui_dk]++; | |
595 | } | |
596 | tdk->dk_curdaddr = tp->b_daddr; | |
597 | tdk->dk_dcb.operrsta = 0; | |
598 | tdk->dk_dcb.trail.sktrail.skaddr.cylinder = tp->b_cylin; | |
599 | tdk->dk_dcb.trail.sktrail.skaddr.track = tp->b_daddr>>8; | |
600 | tdk->dk_dcb.trail.sktrail.skaddr.sector = | |
601 | tp->b_daddr & 0xff; | |
602 | *dcbp = (struct dcb *)tdk->dk_dcbphys; | |
603 | dcbp = &tdk->dk_dcb.nxtdcb; | |
604 | } | |
605 | } else { | |
606 | dk->dk_curcyl = bp->b_cylin; | |
607 | dk->dk_curdaddr = (tn << 8) | sn; | |
608 | vd->vd_offcyl = 0; | |
9d915fad | 609 | } |
7bae1a62 SL |
610 | *dcbp = (struct dcb *)vd->vd_dcbphys; |
611 | ||
612 | /* | |
613 | * Initiate operation. | |
614 | */ | |
615 | bp->b_daddr = 0; /* init overloaded field */ | |
616 | if (vi->ui_dk >= 0) { | |
617 | dk_busy |= 1<<vi->ui_dk; | |
618 | dk_xfer[vi->ui_dk]++; | |
619 | dk_wds[vi->ui_dk] += bp->b_bcount>>6; | |
9d915fad | 620 | } |
7bae1a62 SL |
621 | vd->vd_mdcb.mdcb_status = 0; |
622 | VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); | |
9d915fad | 623 | } |
210a9f40 | 624 | |
7bae1a62 | 625 | #define DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE) |
210a9f40 SL |
626 | /* |
627 | * Handle a disk interrupt. | |
628 | */ | |
9d915fad | 629 | vdintr(ctlr) |
7bae1a62 | 630 | register ctlr; |
210a9f40 | 631 | { |
7bae1a62 SL |
632 | register struct buf *bp, *dp; |
633 | register struct vba_ctlr *vm = vdminfo[ctlr]; | |
634 | register struct vba_device *vi; | |
635 | register struct vdsoftc *vd = &vdsoftc[ctlr]; | |
636 | register status; | |
4f42a6a1 | 637 | struct dksoftc *dk; |
7bae1a62 SL |
638 | |
639 | vd->vd_wticks = 0; | |
640 | if (!vm->um_tab.b_active) { | |
9d915fad | 641 | printf("vd%d: stray interrupt\n", ctlr); |
210a9f40 SL |
642 | return; |
643 | } | |
9d915fad | 644 | /* |
7bae1a62 SL |
645 | * Get device and block structures, and a pointer |
646 | * to the vba_device for the drive. | |
9d915fad | 647 | */ |
7bae1a62 SL |
648 | dp = vm->um_tab.b_actf; |
649 | bp = dp->b_actf; | |
650 | vi = vddinfo[vdunit(bp->b_dev)]; | |
651 | dk_busy &= ~(1<<vi->ui_dk); | |
652 | /* | |
653 | * Check for and process errors on | |
654 | * either the drive or the controller. | |
655 | */ | |
656 | uncache(&vd->vd_dcb.operrsta); | |
657 | status = vd->vd_dcb.operrsta; | |
658 | if (status & VDERR_HARD) { | |
659 | if (status & DCBS_WPT) { | |
660 | /* | |
661 | * Give up on write locked devices immediately. | |
662 | */ | |
4f42a6a1 | 663 | printf("dk%d: write locked\n", vi->ui_unit); |
7bae1a62 | 664 | bp->b_flags |= B_ERROR; |
4f42a6a1 | 665 | } else if (status & VDERR_RETRY) { |
7bae1a62 SL |
666 | if (status & VDERR_DRIVE) { |
667 | if (!vdreset_drive(vi)) | |
668 | vi->ui_alive = 0; | |
669 | } else if (status & VDERR_CTLR) | |
670 | vdreset_ctlr(vm); | |
671 | /* | |
672 | * Retry transfer once, unless reset failed. | |
673 | */ | |
674 | if (!vi->ui_alive || bp->b_errcnt++ >= 2) | |
675 | goto hard; | |
676 | vm->um_tab.b_active = 0; /* force retry */ | |
677 | } else { | |
678 | hard: | |
679 | bp->b_flags |= B_ERROR; | |
680 | /* NEED TO ADJUST b_blkno to failed sector */ | |
681 | harderr(bp, "dk"); | |
682 | printf("status %x (%b)", status, | |
683 | status &~ DONTCARE, VDERRBITS); | |
684 | if (vd->vd_type == VDTYPE_SMDE) { | |
685 | uncache(&vd->vd_dcb.err_code); | |
686 | printf(" ecode %x", vd->vd_dcb.err_code); | |
687 | } | |
688 | printf("\n"); | |
9d915fad | 689 | } |
7bae1a62 SL |
690 | } else if (status & DCBS_SOFT) |
691 | vdsofterr(vd, bp, &vd->vd_dcb); | |
692 | if (vm->um_tab.b_active) { | |
693 | vm->um_tab.b_active = 0; | |
694 | vm->um_tab.b_errcnt = 0; | |
695 | vm->um_tab.b_actf = dp->b_forw; | |
696 | dp->b_active = 0; | |
697 | dp->b_errcnt = 0; | |
698 | dp->b_actf = bp->av_forw; | |
9d915fad | 699 | bp->b_resid = 0; |
7bae1a62 SL |
700 | vbadone(bp, vd->vd_rawbuf, (long *)vd->vd_map, vd->vd_utl); |
701 | biodone(bp); | |
702 | /* | |
703 | * If this unit has more work to do, | |
704 | * then start it up right away. | |
705 | */ | |
706 | if (dp->b_actf) | |
707 | vdustart(vi); | |
4f42a6a1 MK |
708 | else if ((dk = &dksoftc[vi->ui_unit])->dk_openpart == 0) |
709 | wakeup((caddr_t)dk); | |
210a9f40 | 710 | } |
9d915fad | 711 | /* |
7bae1a62 SL |
712 | * If there are devices ready to |
713 | * transfer, start the controller. | |
9d915fad | 714 | */ |
7bae1a62 SL |
715 | if (vm->um_tab.b_actf) |
716 | vdstart(vm); | |
210a9f40 SL |
717 | } |
718 | ||
7bae1a62 SL |
719 | vdsofterr(vd, bp, dcb) |
720 | struct vdsoftc *vd; | |
9d915fad | 721 | register struct buf *bp; |
7bae1a62 | 722 | register struct dcb *dcb; |
9d915fad | 723 | { |
7bae1a62 SL |
724 | int unit = vdunit(bp->b_dev), status = dcb->operrsta; |
725 | char part = 'a' + vdpart(bp->b_dev); | |
82bc5dc5 | 726 | |
7bae1a62 SL |
727 | if (status != (DCBS_DCE|DCBS_CCD|DCBS_SOFT|DCBS_ERR)) { |
728 | if (vd->vd_type == VDTYPE_SMDE) | |
729 | uncache(&dcb->err_code); | |
730 | log(LOG_WARNING, "dk%d%c: soft error sn%d status %b ecode %x\n", | |
731 | unit, part, bp->b_blkno, status, VDERRBITS, dcb->err_code); | |
732 | } else | |
82bc5dc5 MK |
733 | log(LOG_WARNING, "dk%d%c: soft ecc sn%d\n", |
734 | unit, part, bp->b_blkno); | |
9d915fad | 735 | } |
210a9f40 SL |
736 | |
737 | vdread(dev, uio) | |
9d915fad SL |
738 | dev_t dev; |
739 | struct uio *uio; | |
210a9f40 | 740 | { |
7bae1a62 | 741 | register int unit = vdunit(dev); |
210a9f40 | 742 | |
ad409ece | 743 | if (unit >= NDK) |
9d915fad | 744 | return (ENXIO); |
7bae1a62 | 745 | return (physio(vdstrategy, &rdkbuf[unit], dev, B_READ, minphys, uio)); |
210a9f40 SL |
746 | } |
747 | ||
748 | vdwrite(dev, uio) | |
9d915fad SL |
749 | dev_t dev; |
750 | struct uio *uio; | |
210a9f40 | 751 | { |
7bae1a62 | 752 | register int unit = vdunit(dev); |
210a9f40 | 753 | |
ad409ece | 754 | if (unit >= NDK) |
9d915fad | 755 | return (ENXIO); |
7bae1a62 | 756 | return (physio(vdstrategy, &rdkbuf[unit], dev, B_WRITE, minphys, uio)); |
210a9f40 SL |
757 | } |
758 | ||
7bae1a62 | 759 | vdioctl(dev, cmd, data, flag) |
9d915fad | 760 | dev_t dev; |
7bae1a62 SL |
761 | int cmd; |
762 | caddr_t data; | |
763 | int flag; | |
210a9f40 | 764 | { |
7bae1a62 SL |
765 | int unit = vdunit(dev); |
766 | register struct disklabel *lp = &dklabel[unit]; | |
767 | int error = 0; | |
768 | ||
769 | switch (cmd) { | |
770 | ||
771 | case DIOCGDINFO: | |
772 | *(struct disklabel *)data = *lp; | |
773 | break; | |
774 | ||
4f42a6a1 MK |
775 | case DIOCGPART: |
776 | ((struct partinfo *)data)->disklab = lp; | |
777 | ((struct partinfo *)data)->part = | |
778 | &lp->d_partitions[vdpart(dev)]; | |
7bae1a62 SL |
779 | break; |
780 | ||
781 | case DIOCSDINFO: | |
782 | if ((flag & FWRITE) == 0) | |
783 | error = EBADF; | |
784 | else | |
785 | *lp = *(struct disklabel *)data; | |
786 | break; | |
787 | ||
788 | case DIOCWDINFO: { | |
789 | struct buf *bp; | |
790 | struct disklabel *dlp; | |
791 | ||
792 | if ((flag & FWRITE) == 0) { | |
793 | error = EBADF; | |
794 | break; | |
795 | } | |
796 | *lp = *(struct disklabel *)data; | |
797 | bp = geteblk(lp->d_secsize); | |
798 | bp->b_dev = dev; | |
799 | bp->b_blkno = LABELSECTOR; | |
800 | bp->b_bcount = lp->d_secsize; | |
801 | bp->b_flags = B_READ; | |
802 | dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET); | |
803 | vdstrategy(bp); | |
804 | biowait(bp); | |
805 | if (bp->b_flags & B_ERROR) { | |
806 | error = u.u_error; /* XXX */ | |
807 | u.u_error = 0; | |
808 | goto bad; | |
809 | } | |
810 | *dlp = *lp; | |
811 | bp->b_flags = B_WRITE; | |
812 | vdstrategy(bp); | |
813 | biowait(bp); | |
814 | if (bp->b_flags & B_ERROR) { | |
815 | error = u.u_error; /* XXX */ | |
816 | u.u_error = 0; | |
817 | } | |
818 | bad: | |
819 | brelse(bp); | |
820 | break; | |
821 | } | |
822 | ||
823 | default: | |
824 | error = ENOTTY; | |
825 | break; | |
210a9f40 | 826 | } |
9d915fad | 827 | return (0); |
210a9f40 SL |
828 | } |
829 | ||
9d915fad | 830 | /* |
7bae1a62 | 831 | * Watch for lost interrupts. |
9d915fad | 832 | */ |
7bae1a62 | 833 | vdwatch() |
210a9f40 | 834 | { |
7bae1a62 SL |
835 | register struct vdsoftc *vd; |
836 | register struct vba_ctlr *vm; | |
837 | register int ctlr, unit; | |
838 | ||
839 | timeout(vdwatch, (caddr_t)0, hz); | |
840 | for (ctlr = 0; ctlr < NVD; ctlr++) { | |
841 | vm = vdminfo[ctlr]; | |
842 | if (vm == 0 || vm->um_alive == 0) | |
843 | continue; | |
844 | vd = &vdsoftc[ctlr]; | |
845 | if (!vm->um_tab.b_active) { | |
846 | for (unit = 0; unit < NDK; unit++) | |
847 | if (dkutab[unit].b_active && | |
848 | vddinfo[unit]->ui_mi == vm) | |
849 | goto active; | |
850 | vd->vd_wticks = 0; | |
851 | continue; | |
852 | } | |
853 | active: | |
854 | vd->vd_wticks++; | |
855 | if (vd->vd_wticks >= 20) { | |
856 | vd->vd_wticks = 0; | |
857 | printf("vd%d: lost interrupt\n", ctlr); | |
858 | /* abort pending dcb's and restart controller */ | |
859 | } | |
9d915fad | 860 | } |
7bae1a62 SL |
861 | } |
862 | ||
863 | #define DBSIZE 64 /* controller limit with 1K sectors */ | |
864 | /* | |
865 | * Crash dump. | |
866 | */ | |
867 | vddump(dev) | |
868 | dev_t dev; | |
869 | { | |
870 | register struct vba_device *vi; | |
871 | register struct vba_ctlr *vm; | |
872 | register struct disklabel *lp; | |
873 | register struct vdsoftc *vd; | |
874 | struct dksoftc *dk; | |
875 | int part, unit, num; | |
876 | caddr_t start; | |
877 | ||
878 | start = 0; | |
879 | unit = vdunit(dev); | |
880 | if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) | |
881 | return (ENXIO); | |
882 | dk = &dksoftc[unit]; | |
883 | if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) | |
884 | return (ENXIO); | |
885 | lp = &dklabel[unit]; | |
886 | part = vdpart(dev); | |
887 | if (part >= lp->d_npartitions) | |
888 | return (ENXIO); | |
889 | vm = vdminfo[vi->ui_ctlr]; | |
890 | vdreset_ctlr(vm); | |
891 | if (dumplo < 0) | |
892 | return (EINVAL); | |
893 | /* | |
4f42a6a1 | 894 | * Dumplo and maxfree are in pages. |
7bae1a62 SL |
895 | */ |
896 | num = maxfree * (NBPG / lp->d_secsize); | |
4f42a6a1 | 897 | dumplo *= NBPG / lp->d_secsize; |
7bae1a62 SL |
898 | if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size) |
899 | num = lp->d_partitions[vdpart(dev)].p_size - dumplo; | |
900 | vd = &vdsoftc[vm->um_ctlr]; | |
901 | vd->vd_dcb.intflg = DCBINT_NONE; | |
902 | vd->vd_dcb.opcode = VDOP_WD; | |
903 | vd->vd_dcb.devselect = vi->ui_slave; | |
904 | vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long); | |
905 | while (num > 0) { | |
906 | int nsec, cn, sn, tn; | |
907 | ||
908 | nsec = MIN(num, DBSIZE); | |
909 | sn = dumplo + (unsigned)start / lp->d_secsize; | |
910 | cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) / | |
911 | lp->d_secpercyl; | |
912 | sn %= lp->d_secpercyl; | |
913 | tn = sn / lp->d_nsectors; | |
914 | sn %= lp->d_nsectors; | |
915 | vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; | |
916 | vd->vd_dcb.trail.rwtrail.memadr = start; | |
917 | vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1; | |
918 | vd->vd_dcb.trail.rwtrail.disk.cylinder = cn; | |
919 | vd->vd_dcb.trail.rwtrail.disk.track = tn; | |
920 | vd->vd_dcb.trail.rwtrail.disk.sector = sn; | |
921 | vd->vd_dcb.operrsta = 0; | |
922 | VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); | |
923 | if (!vdpoll(vm, 5)) { | |
924 | printf(" during dump\n"); | |
925 | return (EIO); | |
926 | } | |
927 | if (vd->vd_dcb.operrsta & VDERR_HARD) { | |
928 | printf("dk%d: hard error, status=%b\n", unit, | |
929 | vd->vd_dcb.operrsta, VDERRBITS); | |
930 | return (EIO); | |
931 | } | |
932 | start += nsec * lp->d_secsize; | |
933 | num -= nsec; | |
9d915fad | 934 | } |
7bae1a62 | 935 | return (0); |
210a9f40 SL |
936 | } |
937 | ||
938 | vdsize(dev) | |
9d915fad | 939 | dev_t dev; |
210a9f40 | 940 | { |
7bae1a62 SL |
941 | register int unit = vdunit(dev); |
942 | register struct dksoftc *dk; | |
943 | struct vba_device *vi; | |
944 | struct disklabel *lp; | |
210a9f40 | 945 | |
7bae1a62 SL |
946 | if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 || |
947 | (dk = &dksoftc[unit])->dk_state != OPEN) | |
9d915fad | 948 | return (-1); |
7bae1a62 | 949 | lp = &dklabel[unit]; |
4f42a6a1 | 950 | return ((int)lp->d_partitions[vdpart(dev)].p_size); |
210a9f40 SL |
951 | } |
952 | ||
9d915fad SL |
953 | /* |
954 | * Perform a controller reset. | |
955 | */ | |
7bae1a62 SL |
956 | vdreset_ctlr(vm) |
957 | register struct vba_ctlr *vm; | |
210a9f40 | 958 | { |
7bae1a62 SL |
959 | register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; |
960 | register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; | |
961 | register int unit; | |
962 | struct vba_device *vi; | |
9d915fad | 963 | |
7bae1a62 SL |
964 | VDRESET(vdaddr, vd->vd_type); |
965 | if (vd->vd_type == VDTYPE_SMDE) { | |
966 | vdaddr->vdcsr = 0; | |
967 | vdaddr->vdtcf_mdcb = AM_ENPDA; | |
968 | vdaddr->vdtcf_dcb = AM_ENPDA; | |
969 | vdaddr->vdtcf_trail = AM_ENPDA; | |
970 | vdaddr->vdtcf_data = AM_ENPDA; | |
971 | vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD | | |
9d915fad SL |
972 | CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; |
973 | } | |
7bae1a62 SL |
974 | if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { |
975 | printf("%s cmd failed\n", | |
976 | vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); | |
82bc5dc5 | 977 | return; |
9d915fad | 978 | } |
7bae1a62 SL |
979 | for (unit = 0; unit < NDK; unit++) |
980 | if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive) | |
981 | (void) vdreset_drive(vi); | |
982 | } | |
983 | ||
984 | vdreset_drive(vi) | |
985 | register struct vba_device *vi; | |
986 | { | |
987 | register struct disklabel *lp = &dklabel[vi->ui_unit]; | |
988 | struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; | |
989 | struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; | |
990 | struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; | |
991 | ||
992 | top: | |
993 | vd->vd_dcb.opcode = VDOP_CONFIG; /* command */ | |
994 | vd->vd_dcb.intflg = DCBINT_NONE; | |
995 | vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ | |
996 | vd->vd_dcb.operrsta = 0; | |
997 | vd->vd_dcb.devselect = vi->ui_slave; | |
998 | vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders; | |
999 | vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks; | |
1000 | if (vd->vd_type == VDTYPE_SMDE) { | |
1001 | vd->vd_dcb.trailcnt = sizeof (treset) / sizeof (long); | |
1002 | vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors; | |
1003 | vd->vd_dcb.trail.rstrail.slip_sec = lp->d_trackskew; | |
1004 | vd->vd_dcb.trail.rstrail.recovery = 0x18f; | |
1005 | } else | |
1006 | vd->vd_dcb.trailcnt = 2; /* XXX */ | |
1007 | vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; | |
1008 | vd->vd_mdcb.mdcb_status = 0; | |
1009 | VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type); | |
1010 | if (!vdpoll(vm, 5)) { | |
1011 | printf(" during config\n"); | |
1012 | return (0); | |
9d915fad | 1013 | } |
7bae1a62 SL |
1014 | if (vd->vd_dcb.operrsta & VDERR_HARD) { |
1015 | if (vd->vd_type == VDTYPE_SMDE && | |
1016 | (vdaddr->vdstatus[vi->ui_slave]&STA_US) == 0) | |
1017 | return (0); | |
1018 | if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) | |
1019 | printf("dk%d: config error\n", vi->ui_unit); | |
1020 | else if ((vd->vd_flags&VD_STARTED) == 0) { | |
1021 | int started; | |
1022 | ||
1023 | printf("vd%d: starting drives, wait ... ", vm->um_ctlr); | |
1024 | vd->vd_flags |= VD_STARTED; | |
1025 | started = (vdcmd(vm, VDOP_START, 10) == 1); | |
1026 | DELAY(62000000); | |
1027 | printf("\n"); | |
1028 | if (started) | |
1029 | goto top; | |
1030 | } | |
1031 | return (0); | |
1032 | } | |
1033 | return (1); | |
9d915fad | 1034 | } |
210a9f40 | 1035 | |
9d915fad | 1036 | /* |
7bae1a62 | 1037 | * Perform a command w/o trailer. |
9d915fad | 1038 | */ |
7bae1a62 SL |
1039 | vdcmd(vm, cmd, t) |
1040 | register struct vba_ctlr *vm; | |
9d915fad | 1041 | { |
7bae1a62 SL |
1042 | register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; |
1043 | ||
1044 | vd->vd_dcb.opcode = cmd; /* command */ | |
1045 | vd->vd_dcb.intflg = DCBINT_NONE; | |
1046 | vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ | |
1047 | vd->vd_dcb.operrsta = 0; | |
1048 | vd->vd_dcb.devselect = 0; | |
1049 | vd->vd_dcb.trailcnt = 0; | |
1050 | vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; | |
1051 | vd->vd_mdcb.mdcb_status = 0; | |
1052 | VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); | |
1053 | if (!vdpoll(vm, t)) { | |
1054 | printf(" during init\n"); | |
82bc5dc5 MK |
1055 | return (0); |
1056 | } | |
7bae1a62 | 1057 | return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0); |
9d915fad SL |
1058 | } |
1059 | ||
7c4f3479 | 1060 | /* |
7bae1a62 SL |
1061 | * Poll controller until operation |
1062 | * completes or timeout expires. | |
7c4f3479 | 1063 | */ |
7bae1a62 SL |
1064 | vdpoll(vm, t) |
1065 | register struct vba_ctlr *vm; | |
7c4f3479 SL |
1066 | register int t; |
1067 | { | |
7bae1a62 SL |
1068 | register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; |
1069 | register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; | |
7c4f3479 SL |
1070 | |
1071 | t *= 1000; | |
82bc5dc5 | 1072 | for (;;) { |
7bae1a62 SL |
1073 | uncache(&vd->vd_dcb.operrsta); |
1074 | if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT)) | |
82bc5dc5 | 1075 | break; |
7c4f3479 | 1076 | if (--t <= 0) { |
7bae1a62 SL |
1077 | printf("vd%d: controller timeout", vm->um_ctlr); |
1078 | VDABORT(vdaddr, vd->vd_type); | |
7c4f3479 | 1079 | DELAY(30000); |
7c4f3479 SL |
1080 | return (0); |
1081 | } | |
82bc5dc5 | 1082 | DELAY(1000); |
7c4f3479 | 1083 | } |
7bae1a62 SL |
1084 | if (vd->vd_type == VDTYPE_SMDE) { |
1085 | do { | |
82bc5dc5 | 1086 | DELAY(50); |
7bae1a62 SL |
1087 | uncache(&vdaddr->vdcsr); |
1088 | } while (vdaddr->vdcsr & CS_GO); | |
7c4f3479 SL |
1089 | DELAY(300); |
1090 | } | |
1091 | DELAY(200); | |
7bae1a62 | 1092 | uncache(&vd->vd_dcb.operrsta); |
7c4f3479 SL |
1093 | return (1); |
1094 | } | |
1095 | ||
7bae1a62 SL |
1096 | #ifdef COMPAT_42 |
1097 | struct vdst { | |
1098 | int nsec; /* sectors/track */ | |
1099 | int ntrack; /* tracks/cylinder */ | |
1100 | int ncyl; /* cylinders */ | |
1101 | char *name; /* type name */ | |
1102 | struct { | |
1103 | int off; /* partition offset in sectors */ | |
1104 | int size; /* partition size in sectors */ | |
4f42a6a1 | 1105 | } parts[8]; |
7bae1a62 | 1106 | } vdst[] = { |
4f42a6a1 MK |
1107 | { 48, 24, 711, "xsd", |
1108 | {0, 30528}, /* a cyl 0 - 52 */ | |
1109 | {30528, 30528}, /* b cyl 53 - 105 */ | |
1110 | {61056, 345600}, /* c cyl 106 - 705 */ | |
1111 | {118656, 288000}, /* d cyl 206 - 705 */ | |
1112 | {176256, 230400}, /* e cyl 306 - 705 */ | |
1113 | {233856, 172800}, /* f cyl 406 - 705 */ | |
1114 | {291456, 115200}, /* g cyl 506 - 705 */ | |
1115 | {349056, 57600} /* h cyl 606 - 705 */ | |
1116 | }, | |
1117 | { 44, 20, 842, "egl", | |
1118 | {0, 26400}, /* egl0a cyl 0 - 59 */ | |
1119 | {26400, 33000}, /* egl0b cyl 60 - 134 */ | |
1120 | {59400, 308880}, /* egl0c cyl 135 - 836 */ | |
1121 | {368280, 2640}, /* egl0d cyl 837 - 842 */ | |
1122 | {0, 368280}, /* egl0e cyl 0 - 836 */ | |
1123 | {0, 370920}, /* egl0f cyl 0 - 842 */ | |
1124 | {59400, 155320}, /* egl0g cyl 135 - 487 */ | |
1125 | {214720, 153560} /* egl0h cyl 488 - 836 */ | |
1126 | }, | |
1127 | { 64, 10, 823, "fuj", | |
1128 | {0, 19200}, /* fuj0a cyl 0 - 59 */ | |
1129 | {19200, 24000}, /* fuj0b cyl 60 - 134 */ | |
1130 | {43200, 218560}, /* fuj0c cyl 135 - 817 */ | |
1131 | {79680, 182080}, /* fuj0d cyl 249 - 817 */ | |
1132 | {116160, 145600}, /* fuj0e cyl 363 - 817 */ | |
1133 | {152640, 109120}, /* fuj0f cyl 477 - 817 */ | |
1134 | {189120, 72640}, /* fuj0g cyl 591 - 817 */ | |
1135 | {225600, 36160} /* fug0h cyl 705 - 817 */ | |
1136 | }, | |
1137 | { 32, 24, 711, "xfd", | |
1138 | { 0, 20352 }, /* a cyl 0 - 52 */ | |
1139 | { 20352, 20352 }, /* b cyl 53 - 105 */ | |
1140 | { 40704, 230400 }, /* c cyl 106 - 705 */ | |
1141 | { 0, 40704 }, /* d cyl 709 - 710 (a & b) */ | |
1142 | { 0, 271104 }, /* e cyl 0 - 705 */ | |
1143 | { 20352, 250752 }, /* f cyl 53 - 705 (b & c) */ | |
1144 | { 40704, 115200 }, /* g cyl 106 - 405 (1/2 of c) */ | |
1145 | { 155904,115200 } /* h cyl 406 - 705 (1/2 of c) */ | |
1146 | }, | |
1147 | { 32, 19, 823, "smd", | |
1148 | {0, 20064}, /* a cyl 0-65 */ | |
1149 | {20064, 13680}, /* b cyl 66-110 */ | |
1150 | {33744, 214928}, /* c cyl 111-817 */ | |
1151 | {69616, 179056}, /* d cyl 229 - 817 */ | |
1152 | {105488, 143184}, /* e cyl 347 - 817 */ | |
1153 | {141360, 107312}, /* f cyl 465 - 817 */ | |
1154 | {177232, 71440}, /* g cyl 583 - 817 */ | |
1155 | {213104, 35568} /* h cyl 701 - 817 */ | |
1156 | }, | |
1157 | { 32, 10, 823, "fsd", | |
1158 | {0, 9600}, /* a cyl 0 - 59 */ | |
1159 | {9600, 12000}, /* b cyl 60 - 134 */ | |
1160 | {21600, 109280}, /* c cyl 135 - 817 */ | |
1161 | {39840, 91040}, /* d cyl 249 - 817 */ | |
1162 | {58080, 72800}, /* e cyl 363 - 817 */ | |
1163 | {76320, 54560}, /* f cyl 477 - 817 */ | |
1164 | {94560, 36320}, /* g cyl 591 - 817 */ | |
1165 | {112800, 18080} /* h cyl 705 - 817 */ | |
1166 | } | |
7bae1a62 SL |
1167 | }; |
1168 | #define NVDST (sizeof (vdst) / sizeof (vdst[0])) | |
1169 | ||
9d915fad | 1170 | /* |
7bae1a62 SL |
1171 | * Construct a label for an unlabeled pack. We |
1172 | * deduce the drive type by reading from the last | |
1173 | * track on successively smaller drives until we | |
1174 | * don't get an error. | |
9d915fad | 1175 | */ |
7bae1a62 SL |
1176 | vdmaptype(vi, lp) |
1177 | register struct vba_device *vi; | |
1178 | register struct disklabel *lp; | |
9d915fad | 1179 | { |
7bae1a62 SL |
1180 | register struct vdsoftc *vd; |
1181 | register struct vdst *p; | |
1182 | struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; | |
1183 | int i; | |
9d915fad | 1184 | |
7bae1a62 SL |
1185 | vd = &vdsoftc[vi->ui_ctlr]; |
1186 | for (p = vdst; p < &vdst[NVDST]; p++) { | |
1187 | if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32) | |
1188 | continue; | |
1189 | lp->d_nsectors = p->nsec; | |
1190 | lp->d_ntracks = p->ntrack; | |
1191 | lp->d_ncylinders = p->ncyl; | |
1192 | if (!vdreset_drive(vi)) | |
1193 | return (0); | |
1194 | vd->vd_dcb.opcode = VDOP_RD; | |
1195 | vd->vd_dcb.intflg = DCBINT_NONE; | |
1196 | vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ | |
1197 | vd->vd_dcb.devselect = vi->ui_slave; | |
1198 | vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long); | |
1199 | vd->vd_dcb.trail.rwtrail.memadr = (char *) | |
1200 | vtoph((struct proc *)0, (unsigned)vd->vd_rawbuf); | |
1201 | vd->vd_dcb.trail.rwtrail.wcount = 512 / sizeof(short); | |
1202 | vd->vd_dcb.operrsta = 0; | |
1203 | vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2; | |
1204 | vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1; | |
1205 | vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1; | |
1206 | vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; | |
1207 | vd->vd_mdcb.mdcb_status = 0; | |
1208 | VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); | |
1209 | if (!vdpoll(vm, 60)) | |
1210 | printf(" during probe\n"); | |
1211 | if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0) | |
1212 | break; | |
210a9f40 | 1213 | } |
7bae1a62 SL |
1214 | if (p >= &vdst[NVDST]) { |
1215 | printf("dk%d: unknown drive type\n", vi->ui_unit); | |
1216 | return (0); | |
1217 | } | |
4f42a6a1 | 1218 | for (i = 0; i < 8; i++) { |
7bae1a62 SL |
1219 | lp->d_partitions[i].p_offset = p->parts[i].off; |
1220 | lp->d_partitions[i].p_size = p->parts[i].size; | |
1221 | } | |
4f42a6a1 | 1222 | lp->d_npartitions = 8; |
7bae1a62 SL |
1223 | lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; |
1224 | lp->d_rpm = 3600; | |
1225 | lp->d_secsize = 512; | |
1226 | bcopy(p->name, lp->d_typename, 4); | |
1227 | return (1); | |
210a9f40 | 1228 | } |
7bae1a62 | 1229 | #endif COMPAT_42 |
9d915fad | 1230 | #endif |