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