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