134528Skarels /*
234528Skarels * Copyright (c) 1988 Regents of the University of California.
334528Skarels * All rights reserved.
434528Skarels *
535056Skarels * This code is derived from software contributed to Berkeley by
635056Skarels * Computer Consoles Inc.
735056Skarels *
844534Sbostic * %sccs.include.redist.c%
934528Skarels *
10*55599Skarels * @(#)vd.c 7.15 (Berkeley) 07/23/92
1134528Skarels */
1224004Ssam
1329564Ssam #include "dk.h"
1424004Ssam #if NVD > 0
1524004Ssam /*
1630519Ssam * Versabus VDDC/SMDE driver.
1725675Ssam */
1845798Sbostic #include "sys/param.h"
1945798Sbostic #include "sys/buf.h"
2045798Sbostic #include "sys/cmap.h"
2145798Sbostic #include "sys/conf.h"
2245798Sbostic #include "sys/dkstat.h"
2345798Sbostic #include "sys/disklabel.h"
2445798Sbostic #include "sys/map.h"
2545798Sbostic #include "sys/file.h"
2645798Sbostic #include "sys/systm.h"
2745798Sbostic #include "sys/user.h"
2845798Sbostic #include "sys/vmmac.h"
2945798Sbostic #include "sys/proc.h"
3045798Sbostic #include "sys/syslog.h"
3145798Sbostic #include "sys/kernel.h"
3245798Sbostic #include "sys/ioctl.h"
3345798Sbostic #include "sys/stat.h"
3424004Ssam
3545798Sbostic #include "../include/cpu.h"
3645798Sbostic #include "../include/mtpr.h"
3745798Sbostic #include "../include/pte.h"
3829951Skarels
3945798Sbostic #include "../vba/vbavar.h"
4045798Sbostic #include "../vba/vdreg.h"
4124004Ssam
4232211Skarels #ifndef COMPAT_42
4330519Ssam #define COMPAT_42
4432211Skarels #endif
4534396Skarels #define B_FORMAT B_XXX /* XXX */
4630519Ssam
4730519Ssam #define vdunit(dev) (minor(dev) >> 3)
4830519Ssam #define vdpart(dev) (minor(dev) & 0x07)
4930519Ssam #define vdminor(unit,part) (((unit) << 3) | (part))
5024004Ssam
5124004Ssam struct vba_ctlr *vdminfo[NVD];
5229564Ssam struct vba_device *vddinfo[NDK];
5330756Skarels int vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy();
5434528Skarels long vdstd[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 };
5525675Ssam struct vba_driver vddriver =
5634528Skarels { vdprobe, vdslave, vdattach, vddgo, vdstd, "dk", vddinfo, "vd", vdminfo };
5724004Ssam
5824004Ssam /*
5930519Ssam * Per-controller state.
6030519Ssam */
6130519Ssam struct vdsoftc {
6230519Ssam u_short vd_flags;
6340737Skarels #define VD_PRINT 0x1 /* controller info printed */
6430519Ssam #define VD_STARTED 0x2 /* start command issued */
6530519Ssam #define VD_DOSEEKS 0x4 /* should overlap seeks */
6630756Skarels #define VD_SCATGATH 0x8 /* can do scatter-gather commands (correctly) */
6735082Skarels #define VD_LOCKED 0x10 /* locked for direct controller access */
6835082Skarels #define VD_WAIT 0x20 /* someone needs direct controller access */
6930519Ssam u_short vd_type; /* controller type */
7030519Ssam u_short vd_wticks; /* timeout */
7140737Skarels u_short vd_secsize; /* sector size for controller */
7230519Ssam struct mdcb vd_mdcb; /* master command block */
7330519Ssam u_long vd_mdcbphys; /* physical address of vd_mdcb */
7430519Ssam struct dcb vd_dcb; /* i/o command block */
7530519Ssam u_long vd_dcbphys; /* physical address of vd_dcb */
7630601Skarels struct vb_buf vd_rbuf; /* vba resources */
7730519Ssam } vdsoftc[NVD];
7830519Ssam
7934396Skarels #define VDMAXTIME 20 /* max time for operation, sec. */
8034396Skarels
8130519Ssam /*
8225675Ssam * Per-drive state.
8325675Ssam */
8430519Ssam struct dksoftc {
8534076Skarels int dk_state; /* open fsm */
8630756Skarels #ifndef SECSIZE
8730756Skarels u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */
8830756Skarels #endif SECSIZE
8934076Skarels int dk_wlabel; /* label sector is currently writable */
9032576Skarels u_long dk_copenpart; /* character units open on this drive */
9132576Skarels u_long dk_bopenpart; /* block units open on this drive */
9232576Skarels u_long dk_openpart; /* all units open on this drive */
9330519Ssam u_int dk_curcyl; /* last selected cylinder */
9430756Skarels struct skdcb dk_dcb; /* seek command block */
9530519Ssam u_long dk_dcbphys; /* physical address of dk_dcb */
9634396Skarels int df_reg[3]; /* for formatting, in-out parameters */
9730519Ssam } dksoftc[NDK];
9824004Ssam
9924004Ssam /*
10030519Ssam * Drive states. Used during steps of open/initialization.
10130519Ssam * States < OPEN (> 0) are transient, during an open operation.
10234076Skarels * OPENRAW is used for unlabeled disks, to allow format operations.
10325675Ssam */
10430519Ssam #define CLOSED 0 /* disk is closed */
10530519Ssam #define WANTOPEN 1 /* open requested, not started */
10630519Ssam #define WANTOPENRAW 2 /* open requested, no label */
10730519Ssam #define RDLABEL 3 /* reading pack label */
10830519Ssam #define OPEN 4 /* intialized and ready */
10930519Ssam #define OPENRAW 5 /* open, no label */
11024004Ssam
11130519Ssam struct buf dkutab[NDK]; /* i/o queue headers */
11230519Ssam struct disklabel dklabel[NDK]; /* pack labels */
11324004Ssam
11430519Ssam #define b_cylin b_resid
11530574Skarels #define b_track b_error /* used for seek commands */
11630574Skarels #define b_seekf b_forw /* second queue on um_tab */
11730574Skarels #define b_seekl b_back /* second queue on um_tab */
11830519Ssam
11930519Ssam int vdwstart, vdwatch();
12030519Ssam
12124004Ssam /*
12225675Ssam * See if the controller is really there; if so, initialize it.
12325675Ssam */
vdprobe(reg,vm)12425857Ssam vdprobe(reg, vm)
12525857Ssam caddr_t reg;
12625857Ssam struct vba_ctlr *vm;
12725675Ssam {
12825857Ssam register br, cvec; /* must be r12, r11 */
12930519Ssam register struct vddevice *vdaddr = (struct vddevice *)reg;
13030519Ssam struct vdsoftc *vd;
13130573Skarels int s;
13225857Ssam
13330370Skarels #ifdef lint
13430370Skarels br = 0; cvec = br; br = cvec;
13530370Skarels vdintr(0);
13630370Skarels #endif
13725857Ssam if (badaddr((caddr_t)reg, 2))
13825675Ssam return (0);
13930519Ssam vd = &vdsoftc[vm->um_ctlr];
14030519Ssam vdaddr->vdreset = 0xffffffff;
14125675Ssam DELAY(1000000);
14230519Ssam if (vdaddr->vdreset != (unsigned)0xffffffff) {
14330519Ssam vd->vd_type = VDTYPE_VDDC;
14430519Ssam vd->vd_flags &= ~VD_DOSEEKS;
14525675Ssam DELAY(1000000);
14625675Ssam } else {
14730519Ssam vd->vd_type = VDTYPE_SMDE;
14830519Ssam vd->vd_flags |= VD_DOSEEKS;
14930519Ssam vdaddr->vdrstclr = 0;
15025675Ssam DELAY(3000000);
15125675Ssam }
15230519Ssam vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb);
15330519Ssam vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb);
15430519Ssam vm->um_addr = reg; /* XXX */
15530573Skarels s = spl7();
15640737Skarels if (vdinit_ctlr(vm, vd) == 0) {
15730573Skarels splx(s);
15830519Ssam return (0);
15930519Ssam }
16030756Skarels if (vd->vd_type == VDTYPE_SMDE) {
16140737Skarels #ifdef notdef
16240737Skarels /*
16340737Skarels * Attempt PROBE to get all drive status;
16440737Skarels * we take advantage of this in vdreset_drive
16540737Skarels * to try to avoid guessing games.
16640737Skarels */
16740737Skarels (void) vdcmd(vm, VDOP_PROBE, 5, 0);
16840737Skarels #endif
16940737Skarels /*
17040737Skarels * Check for scatter-gather by checking firmware date
17140737Skarels * with IDENT command. The date is printed when
17240737Skarels * vdslave is first called, thus this must be
17340737Skarels * the last controller operation in vdprobe.
17440737Skarels */
17530756Skarels vd->vd_dcb.trail.idtrail.date = 0;
17635413Skarels if (vdcmd(vm, VDOP_IDENT, 10, 0)) {
17730756Skarels uncache(&vd->vd_dcb.trail.idtrail.date);
17830756Skarels if (vd->vd_dcb.trail.idtrail.date != 0)
17930756Skarels vd->vd_flags |= VD_SCATGATH;
18030756Skarels }
18130756Skarels }
18230573Skarels splx(s);
18325925Ssam /*
18425950Ssam * Allocate page tables and i/o buffer.
18525925Ssam */
18632211Skarels if (vbainit(&vd->vd_rbuf, MAXPHYS,
18732211Skarels vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT) == 0) {
18832211Skarels printf("vd%d: vbainit failed\n", vm->um_ctlr);
18932211Skarels return (0);
19032211Skarels }
19125857Ssam br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */
19230519Ssam return (sizeof (struct vddevice));
19325675Ssam }
19424004Ssam
19524004Ssam /*
19630519Ssam * See if a drive is really there.
19730519Ssam *
19830519Ssam * Can't read pack label here as various data structures
19930519Ssam * aren't setup for doing a read in a straightforward
20030519Ssam * manner. Instead just probe for the drive and leave
20130519Ssam * the pack label stuff to the attach routine.
20225675Ssam */
20334076Skarels /* ARGSUSED */
vdslave(vi,vdaddr)20434076Skarels vdslave(vi, vdaddr)
20525675Ssam register struct vba_device *vi;
20630519Ssam struct vddevice *vdaddr;
20725675Ssam {
20830519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit];
20932211Skarels register struct dksoftc *dk = &dksoftc[vi->ui_unit];
21030519Ssam struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
21140737Skarels int bcd();
21224004Ssam
21340737Skarels if ((vd->vd_flags&VD_PRINT) == 0) {
21435413Skarels printf("vd%d: %s controller", vi->ui_ctlr,
21535413Skarels vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE");
21635413Skarels if (vd->vd_flags & VD_SCATGATH) {
21735413Skarels char rev[5];
21835413Skarels
21935413Skarels bcopy((caddr_t)&vd->vd_dcb.trail.idtrail.rev, rev,
22035413Skarels sizeof(vd->vd_dcb.trail.idtrail.rev));
22135413Skarels printf(" firmware rev %s (%d-%d-%d)", rev,
22240737Skarels bcd((vd->vd_dcb.trail.idtrail.date >> 8) & 0xff),
22340737Skarels bcd(vd->vd_dcb.trail.idtrail.date & 0xff),
22440737Skarels bcd((vd->vd_dcb.trail.idtrail.date >> 16)&0xffff));
22535413Skarels }
22635413Skarels printf("\n");
22740737Skarels vd->vd_flags |= VD_PRINT;
22825675Ssam }
22930519Ssam
23025675Ssam /*
23130519Ssam * Initialize label enough to do a reset on
23230519Ssam * the drive. The remainder of the default
23330519Ssam * label values will be filled in in vdinit
23430519Ssam * at attach time.
23525675Ssam */
23632211Skarels if (vd->vd_type == VDTYPE_SMDE)
23732211Skarels lp->d_secsize = VD_MAXSECSIZE;
23832211Skarels else
23932211Skarels lp->d_secsize = VDDC_SECSIZE;
24034396Skarels lp->d_nsectors = 66; /* only used on smd-e */
24134076Skarels lp->d_ntracks = 23;
24234396Skarels lp->d_ncylinders = 850;
24334396Skarels lp->d_secpercyl = 66*23;
24435413Skarels lp->d_rpm = 3600;
24534592Skarels lp->d_npartitions = 1;
24634592Skarels lp->d_partitions[0].p_offset = 0;
24734592Skarels lp->d_partitions[0].p_size = LABELSECTOR + 1;
24824004Ssam
24930519Ssam /*
25030519Ssam * Initialize invariant portion of
25130519Ssam * dcb used for overlapped seeks.
25230519Ssam */
25330519Ssam dk->dk_dcb.opcode = VDOP_SEEK;
25430519Ssam dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA;
25530519Ssam dk->dk_dcb.devselect = vi->ui_slave;
25630756Skarels dk->dk_dcb.trailcnt = sizeof (struct trseek) / sizeof (long);
25730519Ssam dk->dk_dcb.trail.sktrail.skaddr.sector = 0;
25830519Ssam dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb);
25932211Skarels #ifndef SECSIZE
26032211Skarels vd_setsecsize(dk, lp);
26132211Skarels #endif
26232211Skarels return (vdreset_drive(vi));
26332211Skarels }
26432211Skarels
26540737Skarels static int
bcd(n)26640737Skarels bcd(n)
26740737Skarels register u_int n;
26840737Skarels {
26940737Skarels register int bin = 0;
27040737Skarels register int mul = 1;
27140737Skarels
27240737Skarels while (n) {
27340737Skarels bin += (n & 0xf) * mul;
27440737Skarels n >>= 4;
27540737Skarels mul *= 10;
27640737Skarels }
27740737Skarels return (bin);
27840737Skarels }
27940737Skarels
vdattach(vi)28032211Skarels vdattach(vi)
28132211Skarels register struct vba_device *vi;
28232211Skarels {
28332211Skarels register int unit = vi->ui_unit;
28432211Skarels register struct disklabel *lp = &dklabel[unit];
28532211Skarels
28630601Skarels /*
28730601Skarels * Try to initialize device and read pack label.
28830601Skarels */
28930601Skarels if (vdinit(vdminor(unit, 0), 0) != 0) {
29030601Skarels printf(": unknown drive type");
29130601Skarels return;
29230601Skarels }
29332211Skarels if (dksoftc[unit].dk_state == OPEN)
29432211Skarels printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>",
29532211Skarels lp->d_typename, lp->d_secsize,
29632211Skarels lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors);
29730519Ssam /*
29830519Ssam * (60 / rpm) / (sectors per track * (bytes per sector / 2))
29930519Ssam */
30030519Ssam if (vi->ui_dk >= 0)
30138170Smckusick dk_wpms[vi->ui_dk] =
30238170Smckusick (lp->d_rpm * lp->d_nsectors * lp->d_secsize) / 120;
30330519Ssam #ifdef notyet
30430573Skarels addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp);
30530519Ssam #endif
30624004Ssam }
30724004Ssam
vdopen(dev,flags,fmt)30830756Skarels vdopen(dev, flags, fmt)
30930519Ssam dev_t dev;
31030756Skarels int flags, fmt;
31124004Ssam {
31230519Ssam register unit = vdunit(dev);
31330519Ssam register struct disklabel *lp;
31430519Ssam register struct dksoftc *dk;
31530519Ssam register struct partition *pp;
31630519Ssam struct vba_device *vi;
31740737Skarels int s, error = 0, part = vdpart(dev), mask = 1 << part;
31830519Ssam daddr_t start, end;
31924004Ssam
32030519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
32130519Ssam return (ENXIO);
32230519Ssam lp = &dklabel[unit];
32330519Ssam dk = &dksoftc[unit];
32430519Ssam
32530519Ssam s = spl7();
32630519Ssam while (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
32730519Ssam dk->dk_state != CLOSED)
32840737Skarels if (error = tsleep((caddr_t)dk, (PZERO+1) | PCATCH, devopn, 0))
32940737Skarels break;
33030519Ssam splx(s);
33140737Skarels if (error)
33240737Skarels return (error);
33330519Ssam if (dk->dk_state != OPEN && dk->dk_state != OPENRAW)
33430519Ssam if (error = vdinit(dev, flags))
33530519Ssam return (error);
33630573Skarels
33730573Skarels if (vdwstart == 0) {
33830573Skarels timeout(vdwatch, (caddr_t)0, hz);
33930573Skarels vdwstart++;
34030573Skarels }
34130519Ssam /*
34230519Ssam * Warn if a partion is opened
34330519Ssam * that overlaps another partition which is open
34430519Ssam * unless one is the "raw" partition (whole disk).
34530519Ssam */
34632211Skarels #define RAWPART 8 /* 'x' partition */ /* XXX */
34732576Skarels if ((dk->dk_openpart & mask) == 0 && part != RAWPART) {
34830519Ssam pp = &lp->d_partitions[part];
34930519Ssam start = pp->p_offset;
35030519Ssam end = pp->p_offset + pp->p_size;
35130519Ssam for (pp = lp->d_partitions;
35230519Ssam pp < &lp->d_partitions[lp->d_npartitions]; pp++) {
35330519Ssam if (pp->p_offset + pp->p_size <= start ||
35430519Ssam pp->p_offset >= end)
35530519Ssam continue;
35630519Ssam if (pp - lp->d_partitions == RAWPART)
35730519Ssam continue;
35830519Ssam if (dk->dk_openpart & (1 << (pp - lp->d_partitions)))
35930519Ssam log(LOG_WARNING,
36030519Ssam "dk%d%c: overlaps open partition (%c)\n",
36130519Ssam unit, part + 'a',
36230519Ssam pp - lp->d_partitions + 'a');
36330519Ssam }
36424004Ssam }
36530519Ssam if (part >= lp->d_npartitions)
36630519Ssam return (ENXIO);
36730756Skarels dk->dk_openpart |= mask;
36830756Skarels switch (fmt) {
36930756Skarels case S_IFCHR:
37030756Skarels dk->dk_copenpart |= mask;
37130756Skarels break;
37230756Skarels case S_IFBLK:
37330756Skarels dk->dk_bopenpart |= mask;
37430756Skarels break;
37530756Skarels }
37630519Ssam return (0);
37725675Ssam }
37824004Ssam
37934528Skarels /* ARGSUSED */
vdclose(dev,flags,fmt)38030756Skarels vdclose(dev, flags, fmt)
38130519Ssam dev_t dev;
38230756Skarels int flags, fmt;
38324004Ssam {
38430519Ssam register int unit = vdunit(dev);
38530519Ssam register struct dksoftc *dk = &dksoftc[unit];
38630756Skarels int part = vdpart(dev), mask = 1 << part;
38724004Ssam
38830756Skarels switch (fmt) {
38930756Skarels case S_IFCHR:
39030756Skarels dk->dk_copenpart &= ~mask;
39130756Skarels break;
39230756Skarels case S_IFBLK:
39330756Skarels dk->dk_bopenpart &= ~mask;
39430756Skarels break;
39530756Skarels }
39630756Skarels if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0)
39730756Skarels dk->dk_openpart &= ~mask;
39830519Ssam /*
39930519Ssam * Should wait for i/o to complete on this partition
40030519Ssam * even if others are open, but wait for work on blkflush().
40130519Ssam */
40230519Ssam if (dk->dk_openpart == 0) {
40330573Skarels int s = spl7();
40430573Skarels while (dkutab[unit].b_actf)
40530573Skarels sleep((caddr_t)dk, PZERO-1);
40630519Ssam splx(s);
40730519Ssam dk->dk_state = CLOSED;
40834076Skarels dk->dk_wlabel = 0;
40924004Ssam }
41030756Skarels return (0);
41125675Ssam }
41224004Ssam
vdinit(dev,flags)41330519Ssam vdinit(dev, flags)
41430519Ssam dev_t dev;
41530519Ssam int flags;
41625675Ssam {
41730519Ssam register struct disklabel *lp;
41830519Ssam register struct dksoftc *dk;
41930519Ssam struct vba_device *vi;
42030519Ssam int unit = vdunit(dev), error = 0;
42130756Skarels char *msg, *readdisklabel();
42230519Ssam extern int cold;
42325675Ssam
42430519Ssam dk = &dksoftc[unit];
42530519Ssam if (flags & O_NDELAY) {
42630519Ssam dk->dk_state = OPENRAW;
42734528Skarels return (0);
42830519Ssam }
42930519Ssam dk->dk_state = RDLABEL;
43030519Ssam lp = &dklabel[unit];
43130519Ssam vi = vddinfo[unit];
43230756Skarels if (msg = readdisklabel(dev, vdstrategy, lp)) {
43334076Skarels if (cold) {
43430601Skarels printf(": %s", msg);
43534076Skarels dk->dk_state = CLOSED;
43634076Skarels } else {
43732211Skarels log(LOG_ERR, "dk%d: %s\n", unit, msg);
43834076Skarels dk->dk_state = OPENRAW;
43934076Skarels }
44030519Ssam #ifdef COMPAT_42
44135082Skarels vdlock(vi->ui_ctlr);
44234076Skarels if (vdmaptype(vi, lp))
44330519Ssam dk->dk_state = OPEN;
44435082Skarels vdunlock(vi->ui_ctlr);
44530519Ssam #endif
44630756Skarels } else {
44730756Skarels /*
44830756Skarels * Now that we have the label, configure
44930756Skarels * the correct drive parameters.
45030756Skarels */
45135082Skarels vdlock(vi->ui_ctlr);
45232211Skarels if (vdreset_drive(vi))
45332211Skarels dk->dk_state = OPEN;
45432211Skarels else {
45530756Skarels dk->dk_state = CLOSED;
45630756Skarels error = ENXIO;
45732211Skarels }
45835082Skarels vdunlock(vi->ui_ctlr);
45925675Ssam }
46030756Skarels #ifndef SECSIZE
46132211Skarels vd_setsecsize(dk, lp);
46232211Skarels #endif
46330519Ssam wakeup((caddr_t)dk);
46430519Ssam return (error);
46524004Ssam }
46624004Ssam
46732211Skarels #ifndef SECSIZE
vd_setsecsize(dk,lp)46832211Skarels vd_setsecsize(dk, lp)
46932211Skarels register struct dksoftc *dk;
47032211Skarels register struct disklabel *lp;
47132211Skarels {
47232211Skarels int mul;
47332211Skarels
47432211Skarels /*
47532211Skarels * Calculate scaling shift for mapping
47632211Skarels * DEV_BSIZE blocks to drive sectors.
47732211Skarels */
47832211Skarels mul = DEV_BSIZE / lp->d_secsize;
47932211Skarels dk->dk_bshift = 0;
48032211Skarels while ((mul >>= 1) > 0)
48132211Skarels dk->dk_bshift++;
48232211Skarels }
48332211Skarels #endif SECSIZE
48432211Skarels
48525675Ssam /*ARGSUSED*/
48630519Ssam vddgo(vm)
48730519Ssam struct vba_device *vm;
48824004Ssam {
48924004Ssam
49024004Ssam }
49124004Ssam
vdstrategy(bp)49224004Ssam vdstrategy(bp)
49325675Ssam register struct buf *bp;
49424004Ssam {
49530519Ssam register struct vba_device *vi;
49630519Ssam register struct disklabel *lp;
49730519Ssam register struct dksoftc *dk;
49830519Ssam register int unit;
49930573Skarels register daddr_t sn;
50030519Ssam struct buf *dp;
50130573Skarels daddr_t sz, maxsz;
50230519Ssam int part, s;
50324004Ssam
50430519Ssam unit = vdunit(bp->b_dev);
50532211Skarels if (unit >= NDK) {
50629954Skarels bp->b_error = ENXIO;
50725675Ssam goto bad;
50829954Skarels }
50930519Ssam vi = vddinfo[unit];
51030519Ssam lp = &dklabel[unit];
51130519Ssam if (vi == 0 || vi->ui_alive == 0) {
51230519Ssam bp->b_error = ENXIO;
51330519Ssam goto bad;
51430519Ssam }
51530519Ssam dk = &dksoftc[unit];
51640737Skarels if (dk->dk_state < OPEN) {
51740737Skarels if (dk->dk_state == CLOSED) {
51840737Skarels bp->b_error = EIO;
51940737Skarels goto bad;
52040737Skarels }
52130519Ssam goto q;
52240737Skarels }
52334076Skarels if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) {
52434076Skarels bp->b_error = EROFS;
52534076Skarels goto bad;
52634076Skarels }
52730519Ssam part = vdpart(bp->b_dev);
52830519Ssam if ((dk->dk_openpart & (1 << part)) == 0) {
52930519Ssam bp->b_error = ENODEV;
53030519Ssam goto bad;
53130519Ssam }
53232211Skarels sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize;
53330519Ssam maxsz = lp->d_partitions[part].p_size;
53430756Skarels #ifndef SECSIZE
53530756Skarels sn = bp->b_blkno << dk->dk_bshift;
53630756Skarels #else SECSIZE
53730573Skarels sn = bp->b_blkno;
53830756Skarels #endif SECSIZE
53934076Skarels if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR &&
54034076Skarels #if LABELSECTOR != 0
54134076Skarels sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR &&
54234076Skarels #endif
54334076Skarels (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) {
54434076Skarels bp->b_error = EROFS;
54534076Skarels goto bad;
54634076Skarels }
54730519Ssam if (sn < 0 || sn + sz > maxsz) {
54830519Ssam if (sn == maxsz) {
54929954Skarels bp->b_resid = bp->b_bcount;
55029954Skarels goto done;
55129954Skarels }
55230756Skarels sz = maxsz - sn;
55330573Skarels if (sz <= 0) {
55430573Skarels bp->b_error = EINVAL;
55530573Skarels goto bad;
55630573Skarels }
55730573Skarels bp->b_bcount = sz * lp->d_secsize;
55825675Ssam }
55930519Ssam bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl;
56030756Skarels #ifdef SECSIZE
56130756Skarels if (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0)
56230756Skarels panic("vdstrat blksize");
56330756Skarels #endif SECSIZE
56430519Ssam q:
56525675Ssam s = spl7();
56630519Ssam dp = &dkutab[vi->ui_unit];
56730519Ssam disksort(dp, bp);
56830519Ssam if (!dp->b_active) {
56930519Ssam (void) vdustart(vi);
57030573Skarels if (!vi->ui_mi->um_tab.b_active)
57130519Ssam vdstart(vi->ui_mi);
57224004Ssam }
57330519Ssam splx(s);
57424004Ssam return;
57525675Ssam bad:
57629954Skarels bp->b_flags |= B_ERROR;
57729954Skarels done:
57830519Ssam biodone(bp);
57930519Ssam return;
58024004Ssam }
58124004Ssam
vdustart(vi)58230519Ssam vdustart(vi)
58330519Ssam register struct vba_device *vi;
58424004Ssam {
58530519Ssam register struct buf *bp, *dp;
58630519Ssam register struct vba_ctlr *vm;
58730519Ssam register int unit = vi->ui_unit;
58830519Ssam register struct dksoftc *dk;
58930519Ssam register struct vdsoftc *vd;
59030519Ssam struct disklabel *lp;
59124004Ssam
59230519Ssam dp = &dkutab[unit];
59330519Ssam /*
59430519Ssam * If queue empty, nothing to do.
59530519Ssam */
59630519Ssam if ((bp = dp->b_actf) == NULL)
59730519Ssam return;
59830519Ssam /*
59930574Skarels * If drive is off-cylinder and controller supports seeks,
60030574Skarels * place drive on seek queue for controller.
60130574Skarels * Otherwise, place on transfer queue.
60230519Ssam */
60330519Ssam vd = &vdsoftc[vi->ui_ctlr];
60430519Ssam dk = &dksoftc[unit];
60530574Skarels vm = vi->ui_mi;
60630519Ssam if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) {
60730519Ssam lp = &dklabel[unit];
60830574Skarels bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors;
60930574Skarels if (vm->um_tab.b_seekf == NULL)
61030574Skarels vm->um_tab.b_seekf = dp;
61130574Skarels else
61230574Skarels vm->um_tab.b_seekl->b_forw = dp;
61330574Skarels vm->um_tab.b_seekl = dp;
61430574Skarels } else {
61530574Skarels if (vm->um_tab.b_actf == NULL)
61630574Skarels vm->um_tab.b_actf = dp;
61730574Skarels else
61830574Skarels vm->um_tab.b_actl->b_forw = dp;
61930574Skarels vm->um_tab.b_actl = dp;
62030519Ssam }
62130573Skarels dp->b_forw = NULL;
62230573Skarels dp->b_active++;
62325675Ssam }
62425675Ssam
62525675Ssam /*
62630519Ssam * Start next transfer on a controller.
62730574Skarels * There are two queues of drives, the first on-cylinder
62830574Skarels * and the second off-cylinder from their next transfers.
62930574Skarels * Perform the first transfer for the first drive on the on-cylinder
63030574Skarels * queue, if any, otherwise the first transfer for the first drive
63130574Skarels * on the second queue. Initiate seeks on remaining drives on the
63230574Skarels * off-cylinder queue, then move them all to the on-cylinder queue.
63325675Ssam */
vdstart(vm)63430519Ssam vdstart(vm)
63530519Ssam register struct vba_ctlr *vm;
63625675Ssam {
63725675Ssam register struct buf *bp;
63830519Ssam register struct vba_device *vi;
63930519Ssam register struct vdsoftc *vd;
64030519Ssam register struct dksoftc *dk;
64130519Ssam register struct disklabel *lp;
64230519Ssam register struct dcb **dcbp;
64330519Ssam struct buf *dp;
64430519Ssam int sn, tn;
64525675Ssam
64630519Ssam loop:
64730519Ssam /*
64830519Ssam * Pull a request off the controller queue.
64930519Ssam */
65030574Skarels if ((dp = vm->um_tab.b_actf) == NULL &&
65130574Skarels (dp = vm->um_tab.b_seekf) == NULL)
65230519Ssam return;
65330519Ssam if ((bp = dp->b_actf) == NULL) {
65430601Skarels if (dp == vm->um_tab.b_actf)
65530601Skarels vm->um_tab.b_actf = dp->b_forw;
65630601Skarels else
65730601Skarels vm->um_tab.b_seekf = dp->b_forw;
65830519Ssam goto loop;
65930519Ssam }
66025675Ssam
66124004Ssam /*
66230519Ssam * Mark controller busy, and determine
66330519Ssam * destination of this request.
66424004Ssam */
66530519Ssam vm->um_tab.b_active++;
66630519Ssam vi = vddinfo[vdunit(bp->b_dev)];
66730519Ssam dk = &dksoftc[vi->ui_unit];
66830756Skarels #ifndef SECSIZE
66930756Skarels sn = bp->b_blkno << dk->dk_bshift;
67030756Skarels #else SECSIZE
67130573Skarels sn = bp->b_blkno;
67230756Skarels #endif SECSIZE
67330519Ssam lp = &dklabel[vi->ui_unit];
67430519Ssam sn %= lp->d_secpercyl;
67530519Ssam tn = sn / lp->d_nsectors;
67630519Ssam sn %= lp->d_nsectors;
67730519Ssam
67830519Ssam /*
67930519Ssam * Construct dcb for read/write command.
68030519Ssam */
68130519Ssam vd = &vdsoftc[vm->um_ctlr];
68230519Ssam vd->vd_dcb.intflg = DCBINT_DONE;
68332211Skarels vd->vd_dcb.devselect = dk->dk_dcb.devselect;
68430519Ssam vd->vd_dcb.operrsta = 0;
68530519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */
68630519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin;
68730519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn;
68830519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn;
68930574Skarels dk->dk_curcyl = bp->b_cylin;
69030574Skarels bp->b_track = 0; /* init overloaded field */
69130756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
69234396Skarels if (bp->b_flags & B_FORMAT)
69334396Skarels vd->vd_dcb.opcode = dk->dk_op;
69434396Skarels else if (vd->vd_flags & VD_SCATGATH &&
69534396Skarels ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0)
69630756Skarels vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW;
69734396Skarels else
69830756Skarels vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD;
69934396Skarels
70034396Skarels switch (vd->vd_dcb.opcode) {
70134396Skarels case VDOP_FSECT:
70240737Skarels vd->vd_dcb.trailcnt = sizeof (struct trfmt) / sizeof (long);
70334396Skarels vd->vd_dcb.trail.fmtrail.nsectors = bp->b_bcount /
70434396Skarels lp->d_secsize;
70534396Skarels vd->vd_dcb.trail.fmtrail.hdr = *(dskadr *)&dk->dk_althdr;
70634396Skarels vd->vd_dcb.trail.rwtrail.disk.cylinder |= dk->dk_fmtflags;
70734396Skarels goto setupaddr;
70834396Skarels
70934396Skarels case VDOP_RDRAW:
71034396Skarels case VDOP_RD:
71140737Skarels case VDOP_RHDE:
71234396Skarels case VDOP_WD:
71334396Skarels vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1;
71434396Skarels setupaddr:
71530756Skarels vd->vd_dcb.trail.rwtrail.memadr =
71634528Skarels vbasetup(bp, &vd->vd_rbuf, (int)lp->d_secsize);
71734396Skarels break;
71834396Skarels
71934396Skarels case VDOP_RAS:
72034396Skarels case VDOP_GAW:
72135712Sbostic vd->vd_dcb.trailcnt += vd_sgsetup(bp, &vd->vd_rbuf,
72234396Skarels &vd->vd_dcb.trail.sgtrail);
72334396Skarels break;
72430756Skarels }
72530574Skarels if (vi->ui_dk >= 0) {
72630574Skarels dk_busy |= 1<<vi->ui_dk;
72730574Skarels dk_xfer[vi->ui_dk]++;
72830574Skarels dk_wds[vi->ui_dk] += bp->b_bcount>>6;
72930574Skarels }
73030519Ssam
73130519Ssam /*
73230519Ssam * Look for any seeks to be performed on other drives on this
73330519Ssam * controller. If overlapped seeks exist, insert seek commands
73430519Ssam * on the controller's command queue before the transfer.
73530519Ssam */
73630519Ssam dcbp = &vd->vd_mdcb.mdcb_head;
73730519Ssam
73830574Skarels if (dp == vm->um_tab.b_seekf)
73930574Skarels dp = dp->b_forw;
74030574Skarels else
74130574Skarels dp = vm->um_tab.b_seekf;
74230574Skarels for (; dp != NULL; dp = dp->b_forw) {
74330574Skarels if ((bp = dp->b_actf) == NULL)
74430574Skarels continue;
74530574Skarels vi = vddinfo[vdunit(bp->b_dev)];
74630574Skarels dk = &dksoftc[vi->ui_unit];
74730519Ssam dk->dk_curcyl = bp->b_cylin;
74830574Skarels if (vi->ui_dk >= 0)
74930574Skarels dk_seek[vi->ui_dk]++;
75030574Skarels dk->dk_dcb.operrsta = 0;
75130574Skarels dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin;
75230574Skarels dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track;
75330574Skarels *dcbp = (struct dcb *)dk->dk_dcbphys;
75430574Skarels dcbp = &dk->dk_dcb.nxtdcb;
75524004Ssam }
75630519Ssam *dcbp = (struct dcb *)vd->vd_dcbphys;
75730574Skarels if (vm->um_tab.b_actf)
75830574Skarels vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf;
75930574Skarels else
76030574Skarels vm->um_tab.b_actf = vm->um_tab.b_seekf;
76130601Skarels if (vm->um_tab.b_seekf)
76230601Skarels vm->um_tab.b_actl = vm->um_tab.b_seekl;
76330574Skarels vm->um_tab.b_seekf = 0;
76424004Ssam
76530519Ssam /*
76630519Ssam * Initiate operation.
76730519Ssam */
76830519Ssam vd->vd_mdcb.mdcb_status = 0;
76930519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
77024004Ssam }
77124004Ssam
77235082Skarels /*
77335082Skarels * Wait for controller to finish current operation
77435082Skarels * so that direct controller accesses can be done.
77535082Skarels */
vdlock(ctlr)77635082Skarels vdlock(ctlr)
77735082Skarels {
77835082Skarels register struct vba_ctlr *vm = vdminfo[ctlr];
77935082Skarels register struct vdsoftc *vd = &vdsoftc[ctlr];
78035082Skarels int s;
78135082Skarels
78235082Skarels s = spl7();
78335082Skarels while (vm->um_tab.b_active || vd->vd_flags & VD_LOCKED) {
78435082Skarels vd->vd_flags |= VD_WAIT;
78535082Skarels sleep((caddr_t)vd, PRIBIO);
78635082Skarels }
78735082Skarels vd->vd_flags |= VD_LOCKED;
78835082Skarels splx(s);
78935082Skarels }
79035082Skarels
79135082Skarels /*
79235082Skarels * Continue normal operations after pausing for
79335082Skarels * munging the controller directly.
79435082Skarels */
vdunlock(ctlr)79535082Skarels vdunlock(ctlr)
79635082Skarels {
79735082Skarels register struct vba_ctlr *vm = vdminfo[ctlr];
79835082Skarels register struct vdsoftc *vd = &vdsoftc[ctlr];
79935082Skarels
80035082Skarels vd->vd_flags &= ~VD_LOCKED;
80135082Skarels if (vd->vd_flags & VD_WAIT) {
80235082Skarels vd->vd_flags &= ~VD_WAIT;
80335082Skarels wakeup((caddr_t)vd);
80435082Skarels } else if (vm->um_tab.b_actf || vm->um_tab.b_seekf)
80535082Skarels vdstart(vm);
80635082Skarels }
80735082Skarels
80830519Ssam #define DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE)
80924004Ssam /*
81024004Ssam * Handle a disk interrupt.
81124004Ssam */
vdintr(ctlr)81225675Ssam vdintr(ctlr)
81330519Ssam register ctlr;
81424004Ssam {
81530519Ssam register struct buf *bp, *dp;
81630519Ssam register struct vba_ctlr *vm = vdminfo[ctlr];
81730519Ssam register struct vba_device *vi;
81830519Ssam register struct vdsoftc *vd = &vdsoftc[ctlr];
81930519Ssam register status;
82034528Skarels int timedout;
82130573Skarels struct dksoftc *dk;
82224004Ssam
82330519Ssam if (!vm->um_tab.b_active) {
82425675Ssam printf("vd%d: stray interrupt\n", ctlr);
82524004Ssam return;
82624004Ssam }
82725675Ssam /*
82830519Ssam * Get device and block structures, and a pointer
82930519Ssam * to the vba_device for the drive.
83025675Ssam */
83130519Ssam dp = vm->um_tab.b_actf;
83230519Ssam bp = dp->b_actf;
83330519Ssam vi = vddinfo[vdunit(bp->b_dev)];
83434528Skarels dk = &dksoftc[vi->ui_unit];
83530574Skarels if (vi->ui_dk >= 0)
83630574Skarels dk_busy &= ~(1<<vi->ui_dk);
83734396Skarels timedout = (vd->vd_wticks >= VDMAXTIME);
83830519Ssam /*
83930519Ssam * Check for and process errors on
84030519Ssam * either the drive or the controller.
84130519Ssam */
84230519Ssam uncache(&vd->vd_dcb.operrsta);
84330519Ssam status = vd->vd_dcb.operrsta;
84434396Skarels if (bp->b_flags & B_FORMAT) {
84534396Skarels dk->dk_operrsta = status;
84634396Skarels uncache(&vd->vd_dcb.err_code);
84740737Skarels /* ecodecnt gets err_code + err_wcnt from the same longword */
84840737Skarels dk->dk_ecodecnt = *(long *)&vd->vd_dcb.err_code;
84940737Skarels uncache(&vd->vd_dcb.err_trk);
85040737Skarels /* erraddr gets error trk/sec/cyl from the same longword */
85140737Skarels dk->dk_erraddr = *(long *)&vd->vd_dcb.err_trk;
85240737Skarels } else if (status & VDERR_HARD || timedout) {
85334528Skarels if (vd->vd_type == VDTYPE_SMDE)
85430601Skarels uncache(&vd->vd_dcb.err_code);
85530519Ssam if (status & DCBS_WPT) {
85630519Ssam /*
85730519Ssam * Give up on write locked devices immediately.
85830519Ssam */
85930573Skarels printf("dk%d: write locked\n", vi->ui_unit);
86030519Ssam bp->b_flags |= B_ERROR;
86134396Skarels } else if (status & VDERR_RETRY || timedout) {
86234396Skarels if (status & VDERR_CTLR || timedout) {
86340737Skarels vdharderr(timedout ?
86440737Skarels "controller timeout" : "controller err",
86534396Skarels vd, bp, &vd->vd_dcb);
86634396Skarels printf("; resetting controller...");
86734396Skarels vdreset_ctlr(vm);
86834396Skarels } else if (status & VDERR_DRIVE) {
86934396Skarels vdharderr("drive err", vd, bp, &vd->vd_dcb);
87034396Skarels printf("; resetting drive...");
87130519Ssam if (!vdreset_drive(vi))
87240737Skarels dk->dk_state = CLOSED;
87332211Skarels } else
87440737Skarels vdharderr("data err", vd, bp, &vd->vd_dcb);
87530519Ssam /*
87630519Ssam * Retry transfer once, unless reset failed.
87730519Ssam */
87840737Skarels if (!vi->ui_alive || dp->b_errcnt++ >= 1) {
87940737Skarels printf("\n");
88030519Ssam goto hard;
88132211Skarels }
88232211Skarels
88340737Skarels printf(" retrying\n");
88430519Ssam vm->um_tab.b_active = 0; /* force retry */
88530519Ssam } else {
88640737Skarels vdharderr("hard error", vd, bp, &vd->vd_dcb);
88740737Skarels printf("\n");
88830519Ssam hard:
88930519Ssam bp->b_flags |= B_ERROR;
89030519Ssam }
89130519Ssam } else if (status & DCBS_SOFT)
89234528Skarels vdsofterr(bp, &vd->vd_dcb);
89340737Skarels if (vd->vd_wticks > 3) {
89440737Skarels vd->vd_dcb.err_code = vd->vd_wticks;
89540737Skarels vdharderr("slow transfer (ecode is sec.)", vd, bp, &vd->vd_dcb);
89640737Skarels printf("\n");
89740737Skarels }
89834396Skarels vd->vd_wticks = 0;
89930519Ssam if (vm->um_tab.b_active) {
90030519Ssam vm->um_tab.b_active = 0;
90130519Ssam vm->um_tab.b_actf = dp->b_forw;
90230519Ssam dp->b_active = 0;
90330519Ssam dp->b_errcnt = 0;
90430519Ssam dp->b_actf = bp->av_forw;
90530519Ssam bp->b_resid = 0;
90630601Skarels vbadone(bp, &vd->vd_rbuf);
90730519Ssam biodone(bp);
90830370Skarels /*
90930519Ssam * If this unit has more work to do,
91030519Ssam * then start it up right away.
91130370Skarels */
91230519Ssam if (dp->b_actf)
91330519Ssam vdustart(vi);
91434528Skarels else if (dk->dk_openpart == 0)
91530573Skarels wakeup((caddr_t)dk);
91624004Ssam }
91725675Ssam /*
91830519Ssam * If there are devices ready to
91930519Ssam * transfer, start the controller.
92025675Ssam */
92135082Skarels if (vd->vd_flags & VD_WAIT) {
92235082Skarels vd->vd_flags &= ~VD_WAIT;
92335082Skarels wakeup((caddr_t)vd);
92435082Skarels } else if (vm->um_tab.b_actf || vm->um_tab.b_seekf)
92530519Ssam vdstart(vm);
92624004Ssam }
92724004Ssam
vdharderr(what,vd,bp,dcb)92834396Skarels vdharderr(what, vd, bp, dcb)
92934396Skarels char *what;
93034396Skarels struct vdsoftc *vd;
93134396Skarels register struct buf *bp;
93234396Skarels register struct dcb *dcb;
93334396Skarels {
93434396Skarels int unit = vdunit(bp->b_dev), status = dcb->operrsta;
93534396Skarels register struct disklabel *lp = &dklabel[unit];
93634528Skarels int blkdone;
93734396Skarels
93834396Skarels if (vd->vd_wticks < VDMAXTIME)
93934396Skarels status &= ~DONTCARE;
94034710Skarels blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) *
94134710Skarels lp->d_nsectors + dcb->err_sec -
94234710Skarels lp->d_partitions[vdpart(bp->b_dev)].p_offset) >>
94334710Skarels dksoftc[unit].dk_bshift) - bp->b_blkno;
94434528Skarels diskerr(bp, "dk", what, LOG_PRINTF, blkdone, lp);
94534528Skarels printf(", status %b", status, VDERRBITS);
94634396Skarels if (vd->vd_type == VDTYPE_SMDE)
94734396Skarels printf(" ecode %x", dcb->err_code);
94834396Skarels }
94934396Skarels
vdsofterr(bp,dcb)95034528Skarels vdsofterr(bp, dcb)
95125675Ssam register struct buf *bp;
95230519Ssam register struct dcb *dcb;
95325675Ssam {
95434562Skarels int unit = vdunit(bp->b_dev);
95534562Skarels struct disklabel *lp = &dklabel[unit];
95634528Skarels int status = dcb->operrsta;
95734528Skarels int blkdone;
95825675Ssam
95934710Skarels blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) *
96034710Skarels lp->d_nsectors + dcb->err_sec -
96134710Skarels lp->d_partitions[vdpart(bp->b_dev)].p_offset) >>
96234710Skarels dksoftc[unit].dk_bshift) - bp->b_blkno;
96334528Skarels
96434528Skarels if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) {
96534528Skarels diskerr(bp, "dk", "soft error", LOG_WARNING, blkdone, lp);
96634528Skarels addlog(", status %b ecode %x\n", status, VDERRBITS,
96734396Skarels dcb->err_code);
96834528Skarels } else {
96934528Skarels diskerr(bp, "dk", "soft ecc", LOG_WARNING, blkdone, lp);
97034528Skarels addlog("\n");
97134528Skarels }
97225675Ssam }
97325675Ssam
vdioctl(dev,cmd,data,flag)97430519Ssam vdioctl(dev, cmd, data, flag)
97525675Ssam dev_t dev;
97630519Ssam int cmd;
97730519Ssam caddr_t data;
97830519Ssam int flag;
97924004Ssam {
98032576Skarels register int unit = vdunit(dev);
98130519Ssam register struct disklabel *lp = &dklabel[unit];
98234076Skarels register struct dksoftc *dk = &dksoftc[unit];
98334640Skarels int error = 0, vdformat();
98424004Ssam
98530519Ssam switch (cmd) {
98630519Ssam
98730519Ssam case DIOCGDINFO:
98830519Ssam *(struct disklabel *)data = *lp;
98930519Ssam break;
99030519Ssam
99130573Skarels case DIOCGPART:
99230573Skarels ((struct partinfo *)data)->disklab = lp;
99330573Skarels ((struct partinfo *)data)->part =
99430573Skarels &lp->d_partitions[vdpart(dev)];
99530519Ssam break;
99630519Ssam
99730519Ssam case DIOCSDINFO:
99830519Ssam if ((flag & FWRITE) == 0)
99930519Ssam error = EBADF;
100030519Ssam else
100132576Skarels error = setdisklabel(lp, (struct disklabel *)data,
100234076Skarels (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart);
100334396Skarels if (error == 0 && dk->dk_state == OPENRAW &&
100434396Skarels vdreset_drive(vddinfo[unit]))
100534076Skarels dk->dk_state = OPEN;
100630519Ssam break;
100730519Ssam
100834076Skarels case DIOCWLABEL:
100934076Skarels if ((flag & FWRITE) == 0)
101034076Skarels error = EBADF;
101134076Skarels else
101234076Skarels dk->dk_wlabel = *(int *)data;
101334076Skarels break;
101434076Skarels
101532576Skarels case DIOCWDINFO:
101632576Skarels if ((flag & FWRITE) == 0)
101730519Ssam error = EBADF;
101832576Skarels else if ((error = setdisklabel(lp, (struct disklabel *)data,
101934076Skarels (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) {
102034640Skarels int wlab;
102134640Skarels
102235413Skarels if (error == 0 && dk->dk_state == OPENRAW &&
102335413Skarels vdreset_drive(vddinfo[unit]))
102435413Skarels dk->dk_state = OPEN;
102534640Skarels /* simulate opening partition 0 so write succeeds */
102634640Skarels dk->dk_openpart |= (1 << 0); /* XXX */
102734640Skarels wlab = dk->dk_wlabel;
102834640Skarels dk->dk_wlabel = 1;
102932576Skarels error = writedisklabel(dev, vdstrategy, lp);
103034640Skarels dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;
103134640Skarels dk->dk_wlabel = wlab;
103234076Skarels }
103330519Ssam break;
103430519Ssam
103534396Skarels case DIOCWFORMAT:
103634396Skarels {
103734396Skarels register struct format_op *fop;
103834396Skarels struct uio auio;
103934396Skarels struct iovec aiov;
104034396Skarels
104134396Skarels if ((flag & FWRITE) == 0) {
104234396Skarels error = EBADF;
104334396Skarels break;
104434396Skarels }
104534396Skarels fop = (struct format_op *)data;
104634396Skarels aiov.iov_base = fop->df_buf;
104734396Skarels aiov.iov_len = fop->df_count;
104834396Skarels auio.uio_iov = &aiov;
104934396Skarels auio.uio_iovcnt = 1;
105034396Skarels auio.uio_resid = fop->df_count;
105134396Skarels auio.uio_segflg = UIO_USERSPACE;
105234396Skarels auio.uio_offset = fop->df_startblk * lp->d_secsize;
105340737Skarels /* This assumes one active format operation per disk... */
105440737Skarels dk->dk_op = fop->dk_op;
105540737Skarels dk->dk_althdr = fop->dk_althdr;
105640737Skarels dk->dk_fmtflags = fop->dk_fmtflags;
105734396Skarels /*
105834396Skarels * Don't return errors, as the format op won't get copied
105934396Skarels * out if we return nonzero. Callers must check the returned
106040737Skarels * registers and count.
106134396Skarels */
106240737Skarels error = physio(vdformat, (struct buf *)NULL, dev,
106340737Skarels B_WRITE, minphys, &auio);
106440737Skarels if (error == EIO)
106540737Skarels error = 0;
106634396Skarels fop->df_count -= auio.uio_resid;
106740737Skarels /* This assumes one active format operation per disk... */
106834396Skarels fop->dk_operrsta = dk->dk_operrsta;
106940737Skarels fop->dk_ecodecnt = dk->dk_ecodecnt;
107040737Skarels fop->dk_erraddr = dk->dk_erraddr;
107134396Skarels break;
107234396Skarels }
107334396Skarels
107430519Ssam default:
107530519Ssam error = ENOTTY;
107630519Ssam break;
107724004Ssam }
107832606Skarels return (error);
107924004Ssam }
108024004Ssam
108134396Skarels vdformat(bp)
108234396Skarels struct buf *bp;
108334396Skarels {
108434396Skarels bp->b_flags |= B_FORMAT;
108534396Skarels vdstrategy(bp);
108634396Skarels }
108734396Skarels
108825675Ssam /*
108930519Ssam * Watch for lost interrupts.
109025675Ssam */
vdwatch()109130519Ssam vdwatch()
109230519Ssam {
109330519Ssam register struct vdsoftc *vd;
109430519Ssam register struct vba_ctlr *vm;
109534528Skarels register int ctlr;
109634396Skarels int s;
109730519Ssam
109830519Ssam timeout(vdwatch, (caddr_t)0, hz);
109930519Ssam for (ctlr = 0; ctlr < NVD; ctlr++) {
110030519Ssam vm = vdminfo[ctlr];
110130519Ssam if (vm == 0 || vm->um_alive == 0)
110230519Ssam continue;
110330519Ssam vd = &vdsoftc[ctlr];
110434396Skarels s = spl7();
110534396Skarels if (vm->um_tab.b_active && vd->vd_wticks++ >= VDMAXTIME) {
110630519Ssam printf("vd%d: lost interrupt\n", ctlr);
110734396Skarels #ifdef maybe
110834396Skarels VDABORT((struct vddevice *)vm->um_addr, vd->vd_type);
110934396Skarels #endif
111034396Skarels vdintr(ctlr);
111130519Ssam }
111234396Skarels splx(s);
111330519Ssam }
111430519Ssam }
111530519Ssam
111630519Ssam #define DBSIZE 64 /* controller limit with 1K sectors */
111730519Ssam /*
111830519Ssam * Crash dump.
111930519Ssam */
vddump(dev)112030519Ssam vddump(dev)
112130519Ssam dev_t dev;
112224004Ssam {
112330519Ssam register struct vba_device *vi;
112430519Ssam register struct vba_ctlr *vm;
112530519Ssam register struct disklabel *lp;
112630519Ssam register struct vdsoftc *vd;
112730519Ssam struct dksoftc *dk;
112830519Ssam int part, unit, num;
112930601Skarels u_long start;
113024004Ssam
113130519Ssam start = 0;
113230519Ssam unit = vdunit(dev);
113330519Ssam if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
113430519Ssam return (ENXIO);
113530519Ssam dk = &dksoftc[unit];
113634076Skarels if (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
113734076Skarels vdinit(vdminor(unit, 0), 0) != 0)
113830519Ssam return (ENXIO);
113930519Ssam lp = &dklabel[unit];
114030519Ssam part = vdpart(dev);
114130519Ssam if (part >= lp->d_npartitions)
114230519Ssam return (ENXIO);
114332211Skarels vm = vi->ui_mi;
114430519Ssam vdreset_ctlr(vm);
114530519Ssam if (dumplo < 0)
114630519Ssam return (EINVAL);
114730519Ssam /*
114830756Skarels * Maxfree is in pages, dumplo is in DEV_BSIZE units.
114930519Ssam */
115030519Ssam num = maxfree * (NBPG / lp->d_secsize);
115130756Skarels dumplo *= DEV_BSIZE / lp->d_secsize;
115230519Ssam if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size)
115330519Ssam num = lp->d_partitions[vdpart(dev)].p_size - dumplo;
115430519Ssam vd = &vdsoftc[vm->um_ctlr];
115530519Ssam vd->vd_dcb.intflg = DCBINT_NONE;
115630519Ssam vd->vd_dcb.opcode = VDOP_WD;
115732211Skarels vd->vd_dcb.devselect = dk->dk_dcb.devselect;
115830756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
115930519Ssam while (num > 0) {
116030519Ssam int nsec, cn, sn, tn;
116130519Ssam
116230519Ssam nsec = MIN(num, DBSIZE);
116330601Skarels sn = dumplo + start / lp->d_secsize;
116430519Ssam cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) /
116530519Ssam lp->d_secpercyl;
116630519Ssam sn %= lp->d_secpercyl;
116730519Ssam tn = sn / lp->d_nsectors;
116830519Ssam sn %= lp->d_nsectors;
116930519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
117030519Ssam vd->vd_dcb.trail.rwtrail.memadr = start;
117130519Ssam vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1;
117230519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = cn;
117330519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn;
117430519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn;
117530519Ssam vd->vd_dcb.operrsta = 0;
117630519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
117730519Ssam if (!vdpoll(vm, 5)) {
117830519Ssam printf(" during dump\n");
117930519Ssam return (EIO);
118030519Ssam }
118130519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) {
118230519Ssam printf("dk%d: hard error, status=%b\n", unit,
118330519Ssam vd->vd_dcb.operrsta, VDERRBITS);
118430519Ssam return (EIO);
118530519Ssam }
118630519Ssam start += nsec * lp->d_secsize;
118730519Ssam num -= nsec;
118825675Ssam }
118930519Ssam return (0);
119024004Ssam }
119124004Ssam
vdsize(dev)119224004Ssam vdsize(dev)
119325675Ssam dev_t dev;
119424004Ssam {
119530519Ssam register int unit = vdunit(dev);
119630519Ssam register struct dksoftc *dk;
119730519Ssam struct vba_device *vi;
119830519Ssam struct disklabel *lp;
119924004Ssam
120030519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 ||
120130519Ssam (dk = &dksoftc[unit])->dk_state != OPEN)
120225675Ssam return (-1);
120330519Ssam lp = &dklabel[unit];
120430756Skarels #ifdef SECSIZE
120530573Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size);
120630756Skarels #else SECSIZE
120730756Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift);
120830756Skarels #endif SECSIZE
120924004Ssam }
121024004Ssam
121125675Ssam /*
121240737Skarels * Initialize controller.
121325675Ssam */
121440737Skarels vdinit_ctlr(vm, vd)
121540737Skarels struct vba_ctlr *vm;
121640737Skarels struct vdsoftc *vd;
121724004Ssam {
121830519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
121940737Skarels
122030519Ssam if (vd->vd_type == VDTYPE_SMDE) {
122130519Ssam vdaddr->vdcsr = 0;
122230519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA;
122330519Ssam vdaddr->vdtcf_dcb = AM_ENPDA;
122430519Ssam vdaddr->vdtcf_trail = AM_ENPDA;
122530519Ssam vdaddr->vdtcf_data = AM_ENPDA;
122640737Skarels vdaddr->vdccf = CCF_SEN | CCF_DIU | CCF_STS | CCF_RFE |
122740737Skarels XMD_32BIT | BSZ_16WRD |
122825675Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
122925675Ssam }
123035413Skarels if (!vdcmd(vm, VDOP_INIT, 10, 0) || !vdcmd(vm, VDOP_DIAG, 10, 0)) {
123140737Skarels printf("vd%d: %s cmd failed\n", vm->um_ctlr,
123230519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
123340737Skarels return (0);
123440737Skarels }
123540737Skarels vd->vd_secsize = vdaddr->vdsecsize << 1;
123640737Skarels return (1);
123740737Skarels }
123840737Skarels
123940737Skarels /*
124040737Skarels * Perform a controller reset.
124140737Skarels */
vdreset_ctlr(vm)124240737Skarels vdreset_ctlr(vm)
124340737Skarels register struct vba_ctlr *vm;
124440737Skarels {
124540737Skarels register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
124640737Skarels register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
124740737Skarels register int unit;
124840737Skarels struct vba_device *vi;
124940737Skarels
125040737Skarels VDRESET(vdaddr, vd->vd_type);
125140737Skarels if (vdinit_ctlr(vm, vd) == 0)
125230370Skarels return;
125330519Ssam for (unit = 0; unit < NDK; unit++)
1254*55599Skarels if ((vi = vddinfo[unit]) && vi->ui_mi == vm && vi->ui_alive)
125530519Ssam (void) vdreset_drive(vi);
125630519Ssam }
125730519Ssam
vdreset_drive(vi)125830519Ssam vdreset_drive(vi)
125930519Ssam register struct vba_device *vi;
126030519Ssam {
126130519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit];
126230519Ssam struct vba_ctlr *vm = vdminfo[vi->ui_ctlr];
126330519Ssam struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
126432211Skarels register struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
126532211Skarels register struct dksoftc *dk = &dksoftc[vi->ui_unit];
126640737Skarels int config_status, config_ecode, saw_drive = 0;
126730519Ssam
126840737Skarels #ifdef notdef
126940737Skarels /*
127040737Skarels * check for ESDI distribution panel already configured,
127140737Skarels * e.g. on boot drive, or if PROBE on controller actually
127240737Skarels * worked. Status will be zero if drive hasn't
127340737Skarels * been probed yet.
127440737Skarels */
127540737Skarels #if STA_ESDI != 0
127640737Skarels if ((vdaddr->vdstatus[vi->ui_slave] & STA_TYPE) == STA_ESDI)
127740737Skarels lp->d_devflags |= VD_ESDI;
127840737Skarels #endif
127940737Skarels #endif
128030519Ssam top:
128130519Ssam vd->vd_dcb.opcode = VDOP_CONFIG; /* command */
128230519Ssam vd->vd_dcb.intflg = DCBINT_NONE;
128330519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */
128430519Ssam vd->vd_dcb.operrsta = 0;
128532211Skarels vd->vd_dcb.devselect = vi->ui_slave | lp->d_devflags;
128630519Ssam vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders;
128730519Ssam vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks;
128830519Ssam if (vd->vd_type == VDTYPE_SMDE) {
128930756Skarels vd->vd_dcb.trailcnt = sizeof (struct treset) / sizeof (long);
129030519Ssam vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors;
129130601Skarels vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack;
129240737Skarels vd->vd_dcb.trail.rstrail.recovery =
129340737Skarels (lp->d_flags & D_REMOVABLE) ? VDRF_NORMAL :
129440737Skarels (VDRF_NORMAL &~ (VDRF_OSP|VDRF_OSM));
129530519Ssam } else
129630519Ssam vd->vd_dcb.trailcnt = 2; /* XXX */
129730519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
129830519Ssam vd->vd_mdcb.mdcb_status = 0;
129930519Ssam VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type);
130030519Ssam if (!vdpoll(vm, 5)) {
130130519Ssam printf(" during config\n");
130230519Ssam return (0);
130325675Ssam }
130440737Skarels config_status = vd->vd_dcb.operrsta;
130540737Skarels config_ecode = (u_char)vd->vd_dcb.err_code;
130640737Skarels if (config_status & VDERR_HARD) {
130732211Skarels if (vd->vd_type == VDTYPE_SMDE) {
130840737Skarels /*
130940737Skarels * If drive status was updated successfully,
131040737Skarels * STA_US (unit selected) should be set
131140737Skarels * if the drive is attached and powered up.
131240737Skarels * (But only if we've guessed right on SMD
131340737Skarels * vs. ESDI; if that flag is wrong, we won't
131440737Skarels * see the drive.) If we don't see STA_US
131540737Skarels * with either SMD or ESDI set for the unit,
131640737Skarels * we assume that the drive doesn't exist,
131740737Skarels * and don't wait for it to spin up.
131840737Skarels */
131940737Skarels (void) vdcmd(vm, VDOP_STATUS, 5, vi->ui_slave);
132040737Skarels uncache(&vdaddr->vdstatus[vi->ui_slave]);
132140737Skarels if (vdaddr->vdstatus[vi->ui_slave] & STA_US)
132240737Skarels saw_drive = 1;
132340737Skarels else if (lp->d_devflags == 0) {
132432211Skarels lp->d_devflags = VD_ESDI;
132532211Skarels goto top;
132632211Skarels }
132740737Skarels } else
132840737Skarels saw_drive = 1;
132940737Skarels if ((config_status & (DCBS_OCYL|DCBS_NRDY)) == 0)
133032211Skarels printf("dk%d: config error %b ecode %x\n", vi->ui_unit,
133140737Skarels config_status, VDERRBITS, config_ecode);
133240737Skarels else if ((vd->vd_flags & VD_STARTED) == 0 && saw_drive) {
133330519Ssam int started;
133430519Ssam
133532211Skarels printf(" starting drives, wait ... ");
133630519Ssam vd->vd_flags |= VD_STARTED;
133730519Ssam started = (vdcmd(vm, VDOP_START, 10) == 1);
133830519Ssam DELAY(62000000);
133935413Skarels printf("done\n");
134032211Skarels lp->d_devflags = 0;
134130519Ssam if (started)
134230519Ssam goto top;
134330519Ssam }
134430519Ssam return (0);
134530519Ssam }
134632211Skarels dk->dk_dcb.devselect |= lp->d_devflags;
134730519Ssam return (1);
134825675Ssam }
134924004Ssam
135025675Ssam /*
135130519Ssam * Perform a command w/o trailer.
135225675Ssam */
vdcmd(vm,cmd,t,slave)135335413Skarels vdcmd(vm, cmd, t, slave)
135430519Ssam register struct vba_ctlr *vm;
135525675Ssam {
135630519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
135725675Ssam
135830519Ssam vd->vd_dcb.opcode = cmd; /* command */
135930519Ssam vd->vd_dcb.intflg = DCBINT_NONE;
136030519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */
136130519Ssam vd->vd_dcb.operrsta = 0;
136235413Skarels vd->vd_dcb.devselect = slave;
136330519Ssam vd->vd_dcb.trailcnt = 0;
136430519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
136530519Ssam vd->vd_mdcb.mdcb_status = 0;
136630519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
136730519Ssam if (!vdpoll(vm, t)) {
136830519Ssam printf(" during init\n");
136930370Skarels return (0);
137030370Skarels }
137130519Ssam return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0);
137225675Ssam }
137325675Ssam
137425925Ssam /*
137530519Ssam * Poll controller until operation
137630519Ssam * completes or timeout expires.
137725925Ssam */
vdpoll(vm,t)137830519Ssam vdpoll(vm, t)
137930519Ssam register struct vba_ctlr *vm;
138025925Ssam register int t;
138125925Ssam {
138230519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
138330519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
138425925Ssam
138525925Ssam t *= 1000;
138630370Skarels for (;;) {
138730519Ssam uncache(&vd->vd_dcb.operrsta);
138830519Ssam if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT))
138930370Skarels break;
139025925Ssam if (--t <= 0) {
139130519Ssam printf("vd%d: controller timeout", vm->um_ctlr);
139230519Ssam VDABORT(vdaddr, vd->vd_type);
139325925Ssam return (0);
139425925Ssam }
139530370Skarels DELAY(1000);
139625925Ssam }
139730519Ssam if (vd->vd_type == VDTYPE_SMDE) {
139830519Ssam do {
139925925Ssam DELAY(50);
140030519Ssam uncache(&vdaddr->vdcsr);
140130519Ssam } while (vdaddr->vdcsr & CS_GO);
140232211Skarels DELAY(300);
140332211Skarels uncache(&vd->vd_dcb.err_code);
140425925Ssam }
140525925Ssam DELAY(200);
140630519Ssam uncache(&vd->vd_dcb.operrsta);
140725925Ssam return (1);
140825925Ssam }
140925925Ssam
141030519Ssam #ifdef COMPAT_42
141130519Ssam struct vdst {
141230519Ssam int nsec; /* sectors/track */
141330519Ssam int ntrack; /* tracks/cylinder */
141430519Ssam int ncyl; /* cylinders */
141532211Skarels int secsize; /* sector size */
141630519Ssam char *name; /* type name */
141730519Ssam struct {
141830519Ssam int off; /* partition offset in sectors */
141930519Ssam int size; /* partition size in sectors */
142030573Skarels } parts[8];
142130519Ssam } vdst[] = {
142232211Skarels { 66, 23, 850, 512, "NEC 800",
142332211Skarels {0, 1290300}, /* a cyl 0 - 849 */
142432211Skarels },
142534737Sbostic { 64, 20, 842, 512, "2361a",
142634737Sbostic {0, 61440}, /* a cyl 0 - 47 */
142734737Sbostic {61440, 67840}, /* b cyl 48 - 100 */
142834737Sbostic {129280, 942080}, /* c cyl 101 - 836 */
142934737Sbostic {0, 1071360}, /* d cyl 0 - 836 */
143034737Sbostic {449280, 311040}, /* e cyl 351 - 593 */
143134737Sbostic {760320, 311040}, /* f cyl 594 - 836 */
143234737Sbostic {449280, 622080}, /* g cyl 351 - 836 */
143334737Sbostic {129280, 320000} /* h cyl 101 - 350 */
143434737Sbostic },
143532211Skarels { 48, 24, 711, 512, "xsd",
143631039Skarels {0, 61056}, /* a cyl 0 - 52 */
143731039Skarels {61056, 61056}, /* b cyl 53 - 105 */
143831039Skarels {122112, 691200}, /* c cyl 106 - 705 */
143931039Skarels {237312, 576000}, /* d cyl 206 - 705 */
144031039Skarels {352512, 460800}, /* e cyl 306 - 705 */
144131039Skarels {467712, 345600}, /* f cyl 406 - 705 */
144231039Skarels {582912, 230400}, /* g cyl 506 - 705 */
144331039Skarels {698112, 115200} /* h cyl 606 - 705 */
144430573Skarels },
144532211Skarels { 44, 20, 842, 512, "eagle",
144630601Skarels {0, 52800}, /* egl0a cyl 0 - 59 */
144730601Skarels {52800, 66000}, /* egl0b cyl 60 - 134 */
144830601Skarels {118800, 617760}, /* egl0c cyl 135 - 836 */
144930756Skarels {736560, 4400}, /* egl0d cyl 837 - 841 */
145031039Skarels {0, 736560}, /* egl0e cyl 0 - 836 */
145131039Skarels {0, 740960}, /* egl0f cyl 0 - 841 */
145230601Skarels {118800, 310640}, /* egl0g cyl 135 - 487 */
145330601Skarels {429440, 307120} /* egl0h cyl 488 - 836 */
145430573Skarels },
145532211Skarels { 64, 10, 823, 512, "fuj",
145631039Skarels {0, 38400}, /* fuj0a cyl 0 - 59 */
145731039Skarels {38400, 48000}, /* fuj0b cyl 60 - 134 */
145831039Skarels {86400, 437120}, /* fuj0c cyl 135 - 817 */
145931039Skarels {159360, 364160}, /* fuj0d cyl 249 - 817 */
146031039Skarels {232320, 291200}, /* fuj0e cyl 363 - 817 */
146131039Skarels {305280, 218240}, /* fuj0f cyl 477 - 817 */
146231039Skarels {378240, 145280}, /* fuj0g cyl 591 - 817 */
146331039Skarels {451200, 72320} /* fug0h cyl 705 - 817 */
146430573Skarels },
146532211Skarels { 32, 24, 711, 512, "xfd",
146630756Skarels { 0, 40704 }, /* a cyl 0 - 52 */
146730756Skarels { 40704, 40704 }, /* b cyl 53 - 105 */
146830756Skarels { 81408, 460800 }, /* c cyl 106 - 705 */
146930756Skarels { 0, 81408 }, /* d cyl 709 - 710 (a & b) */
147030756Skarels { 0, 542208 }, /* e cyl 0 - 705 */
147130756Skarels { 40704, 501504 }, /* f cyl 53 - 705 (b & c) */
147230756Skarels { 81408, 230400 }, /* g cyl 106 - 405 (1/2 of c) */
147330756Skarels { 311808,230400 } /* h cyl 406 - 705 (1/2 of c) */
147430573Skarels },
147532211Skarels { 32, 19, 823, 512, "smd",
147631039Skarels {0, 40128}, /* a cyl 0-65 */
147731039Skarels {40128, 27360}, /* b cyl 66-110 */
147831039Skarels {67488, 429856}, /* c cyl 111-817 */
147931039Skarels {139232, 358112}, /* d cyl 229 - 817 */
148031039Skarels {210976, 286368}, /* e cyl 347 - 817 */
148131039Skarels {282720, 214624}, /* f cyl 465 - 817 */
148231039Skarels {354464, 142880}, /* g cyl 583 - 817 */
148331039Skarels {426208, 71136} /* h cyl 701 - 817 */
148430573Skarels },
148532211Skarels { 18, 15, 1224, 1024, "mxd",
148632211Skarels {0, 21600}, /* a cyl 0-79 */
148732211Skarels {21600, 22410}, /* b cyl 80-162 */
148832211Skarels {44010, 285120}, /* c cyl 163-1217 */
148932211Skarels #ifdef notyet
149032211Skarels {x, 237600}, /* d cyl y - 1217 */
149132211Skarels {x, 190080}, /* e cyl y - 1217 */
149232211Skarels {x, 142560}, /* f cyl y - 1217 */
149332211Skarels {x, 95040}, /* g cyl y - 1217 */
149432211Skarels {x, 47520} /* h cyl 701 - 817 */
149532211Skarels #endif
149632211Skarels },
149732211Skarels { 32, 10, 823, 512, "fsd",
149830756Skarels {0, 19200}, /* a cyl 0 - 59 */
149930756Skarels {19200, 24000}, /* b cyl 60 - 134 */
150030756Skarels {43200, 218560}, /* c cyl 135 - 817 */
150130573Skarels }
150230519Ssam };
150330519Ssam #define NVDST (sizeof (vdst) / sizeof (vdst[0]))
150430519Ssam
150525675Ssam /*
150630519Ssam * Construct a label for an unlabeled pack. We
150730519Ssam * deduce the drive type by reading from the last
150830519Ssam * track on successively smaller drives until we
150930519Ssam * don't get an error.
151025675Ssam */
vdmaptype(vi,lp)151130519Ssam vdmaptype(vi, lp)
151230519Ssam register struct vba_device *vi;
151330519Ssam register struct disklabel *lp;
151425675Ssam {
151530519Ssam register struct vdsoftc *vd;
151630519Ssam register struct vdst *p;
151732211Skarels struct vba_ctlr *vm = vi->ui_mi;
151830519Ssam int i;
151925675Ssam
152030519Ssam vd = &vdsoftc[vi->ui_ctlr];
152130519Ssam for (p = vdst; p < &vdst[NVDST]; p++) {
152230519Ssam if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32)
152330519Ssam continue;
152430519Ssam lp->d_nsectors = p->nsec;
152530519Ssam lp->d_ntracks = p->ntrack;
152630519Ssam lp->d_ncylinders = p->ncyl;
152732211Skarels lp->d_secsize = p->secsize;
152835413Skarels DELAY(100000);
152930519Ssam if (!vdreset_drive(vi))
153030519Ssam return (0);
153135413Skarels DELAY(100000);
153230519Ssam vd->vd_dcb.opcode = VDOP_RD;
153330519Ssam vd->vd_dcb.intflg = DCBINT_NONE;
153430519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */
153532211Skarels vd->vd_dcb.devselect = dksoftc[vi->ui_unit].dk_dcb.devselect;
153630756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
153730601Skarels vd->vd_dcb.trail.rwtrail.memadr =
153830601Skarels vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf);
153932211Skarels vd->vd_dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof(short);
154030519Ssam vd->vd_dcb.operrsta = 0;
154130519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2;
154230519Ssam vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1;
154330519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1;
154430519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
154530519Ssam vd->vd_mdcb.mdcb_status = 0;
154630519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
154730519Ssam if (!vdpoll(vm, 60))
154830519Ssam printf(" during probe\n");
154930519Ssam if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0)
155030519Ssam break;
155124004Ssam }
155232211Skarels if (p >= &vdst[NVDST])
155330519Ssam return (0);
155432211Skarels
155530573Skarels for (i = 0; i < 8; i++) {
155630519Ssam lp->d_partitions[i].p_offset = p->parts[i].off;
155730519Ssam lp->d_partitions[i].p_size = p->parts[i].size;
155830519Ssam }
155930573Skarels lp->d_npartitions = 8;
156030519Ssam lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
156130519Ssam bcopy(p->name, lp->d_typename, 4);
156230519Ssam return (1);
156324004Ssam }
156430519Ssam #endif COMPAT_42
156524004Ssam #endif
1566