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