1*30573Skarels /* vd.c 1.15 87/02/28 */ 224004Ssam 329564Ssam #include "dk.h" 424004Ssam #if NVD > 0 524004Ssam /* 630519Ssam * Versabus VDDC/SMDE driver. 725675Ssam */ 825675Ssam #include "param.h" 925675Ssam #include "buf.h" 1025675Ssam #include "cmap.h" 1125675Ssam #include "conf.h" 1225675Ssam #include "dir.h" 1329564Ssam #include "dkstat.h" 1430519Ssam #include "disklabel.h" 1525675Ssam #include "map.h" 1630519Ssam #include "file.h" 1725675Ssam #include "systm.h" 1825675Ssam #include "user.h" 1925675Ssam #include "vmmac.h" 2025675Ssam #include "proc.h" 2125675Ssam #include "uio.h" 2230370Skarels #include "syslog.h" 2330370Skarels #include "kernel.h" 2430519Ssam #include "ioctl.h" 2524004Ssam 2629951Skarels #include "../tahoe/cpu.h" 2729951Skarels #include "../tahoe/mtpr.h" 2829951Skarels #include "../tahoe/pte.h" 2929951Skarels 3025675Ssam #include "../tahoevba/vbavar.h" 3125928Ssam #include "../tahoevba/vdreg.h" 3224004Ssam 3330519Ssam #define COMPAT_42 3430519Ssam 3525925Ssam #define VDMAXIO (MAXBPTE*NBPG) 3624004Ssam 3730519Ssam #define vdunit(dev) (minor(dev) >> 3) 3830519Ssam #define vdpart(dev) (minor(dev) & 0x07) 3930519Ssam #define vdminor(unit,part) (((unit) << 3) | (part)) 4024004Ssam 4124004Ssam struct vba_ctlr *vdminfo[NVD]; 4229564Ssam struct vba_device *vddinfo[NDK]; 4325675Ssam int vdprobe(), vdslave(), vdattach(), vddgo(); 4430519Ssam long vdaddr[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 }; 4525675Ssam struct vba_driver vddriver = 4630519Ssam { vdprobe, vdslave, vdattach, vddgo, vdaddr, "dk", vddinfo, "vd", vdminfo }; 4724004Ssam 4824004Ssam /* 4930519Ssam * Per-controller state. 5030519Ssam */ 5130519Ssam struct vdsoftc { 5230519Ssam u_short vd_flags; 5330519Ssam #define VD_INIT 0x1 /* controller initialized */ 5430519Ssam #define VD_STARTED 0x2 /* start command issued */ 5530519Ssam #define VD_DOSEEKS 0x4 /* should overlap seeks */ 5630519Ssam u_short vd_type; /* controller type */ 5730519Ssam u_short vd_wticks; /* timeout */ 5830519Ssam u_short vd_offcyl; /* off cylinder bitmask */ 5930519Ssam struct mdcb vd_mdcb; /* master command block */ 6030519Ssam u_long vd_mdcbphys; /* physical address of vd_mdcb */ 6130519Ssam struct dcb vd_dcb; /* i/o command block */ 6230519Ssam u_long vd_dcbphys; /* physical address of vd_dcb */ 6330519Ssam struct pte *vd_map; /* i/o page map */ 6430519Ssam caddr_t vd_utl; /* mapped i/o space */ 6530519Ssam caddr_t vd_rawbuf; /* buffer for raw+swap i/o */ 6630519Ssam } vdsoftc[NVD]; 6730519Ssam 6830519Ssam /* 6925675Ssam * Per-drive state. 7025675Ssam */ 7130519Ssam struct dksoftc { 7230519Ssam u_short dk_state; /* open fsm */ 7330519Ssam u_short dk_openpart; /* units open on this drive */ 7430519Ssam u_short dk_curdaddr; /* last selected track & sector */ 7530519Ssam u_int dk_curcyl; /* last selected cylinder */ 7630519Ssam struct dcb dk_dcb; /* seek command block */ 7730519Ssam u_long dk_dcbphys; /* physical address of dk_dcb */ 7830519Ssam } dksoftc[NDK]; 7924004Ssam 8024004Ssam /* 8130519Ssam * Drive states. Used during steps of open/initialization. 8230519Ssam * States < OPEN (> 0) are transient, during an open operation. 8330519Ssam * OPENRAW is used for unabeled disks, to allow format operations. 8425675Ssam */ 8530519Ssam #define CLOSED 0 /* disk is closed */ 8630519Ssam #define WANTOPEN 1 /* open requested, not started */ 8730519Ssam #define WANTOPENRAW 2 /* open requested, no label */ 8830519Ssam #define RDLABEL 3 /* reading pack label */ 8930519Ssam #define OPEN 4 /* intialized and ready */ 9030519Ssam #define OPENRAW 5 /* open, no label */ 9124004Ssam 9230519Ssam struct buf rdkbuf[NDK]; /* raw i/o buffer headers */ 9330519Ssam struct buf dkutab[NDK]; /* i/o queue headers */ 9430519Ssam struct disklabel dklabel[NDK]; /* pack labels */ 9524004Ssam 9630519Ssam #define b_cylin b_resid 9730519Ssam #define b_daddr b_error 9830519Ssam 9930519Ssam int vdwstart, vdwatch(); 10030519Ssam 10124004Ssam /* 10225675Ssam * See if the controller is really there; if so, initialize it. 10325675Ssam */ 10425857Ssam vdprobe(reg, vm) 10525857Ssam caddr_t reg; 10625857Ssam struct vba_ctlr *vm; 10725675Ssam { 10825857Ssam register br, cvec; /* must be r12, r11 */ 10930519Ssam register struct vddevice *vdaddr = (struct vddevice *)reg; 11030519Ssam struct vdsoftc *vd; 111*30573Skarels int s; 11225857Ssam 11330370Skarels #ifdef lint 11430370Skarels br = 0; cvec = br; br = cvec; 11530370Skarels vdintr(0); 11630370Skarels #endif 11725857Ssam if (badaddr((caddr_t)reg, 2)) 11825675Ssam return (0); 11930519Ssam vd = &vdsoftc[vm->um_ctlr]; 12030519Ssam vdaddr->vdreset = 0xffffffff; 12125675Ssam DELAY(1000000); 12230519Ssam if (vdaddr->vdreset != (unsigned)0xffffffff) { 12330519Ssam vd->vd_type = VDTYPE_VDDC; 12430519Ssam vd->vd_flags &= ~VD_DOSEEKS; 12525675Ssam DELAY(1000000); 12625675Ssam } else { 12730519Ssam vd->vd_type = VDTYPE_SMDE; 12830519Ssam vd->vd_flags |= VD_DOSEEKS; 12930519Ssam vdaddr->vdrstclr = 0; 13025675Ssam DELAY(3000000); 13130519Ssam vdaddr->vdcsr = 0; 13230519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 13330519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 13430519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 13530519Ssam vdaddr->vdtcf_data = AM_ENPDA; 13630519Ssam vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS | 13729921Skarels XMD_32BIT | BSZ_16WRD | 13825925Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 13925675Ssam } 14030519Ssam vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb); 14130519Ssam vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb); 14230519Ssam vm->um_addr = reg; /* XXX */ 143*30573Skarels s = spl7(); 14430519Ssam if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { 14530519Ssam printf("vd%d: %s cmd failed\n", vm->um_ctlr, 14630519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 147*30573Skarels splx(s); 14830519Ssam return (0); 14930519Ssam } 150*30573Skarels splx(s); 15125925Ssam /* 15225950Ssam * Allocate page tables and i/o buffer. 15325925Ssam */ 15430519Ssam vbmapalloc(btoc(VDMAXIO)+1, &vd->vd_map, &vd->vd_utl); 15530519Ssam vd->vd_rawbuf = calloc(VDMAXIO); 15625857Ssam br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */ 15730519Ssam return (sizeof (struct vddevice)); 15825675Ssam } 15924004Ssam 16024004Ssam /* 16130519Ssam * See if a drive is really there. 16230519Ssam * 16330519Ssam * Can't read pack label here as various data structures 16430519Ssam * aren't setup for doing a read in a straightforward 16530519Ssam * manner. Instead just probe for the drive and leave 16630519Ssam * the pack label stuff to the attach routine. 16725675Ssam */ 16825675Ssam vdslave(vi, addr) 16925675Ssam register struct vba_device *vi; 17030519Ssam struct vddevice *vdaddr; 17125675Ssam { 17230519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 17330519Ssam struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 17424004Ssam 17530519Ssam if ((vd->vd_flags&VD_INIT) == 0) { 17625925Ssam printf("vd%d: %s controller\n", vi->ui_ctlr, 17730519Ssam vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE"); 17830519Ssam vd->vd_flags |= VD_INIT; 17925675Ssam } 18030519Ssam 18125675Ssam /* 18230519Ssam * Initialize label enough to do a reset on 18330519Ssam * the drive. The remainder of the default 18430519Ssam * label values will be filled in in vdinit 18530519Ssam * at attach time. 18625675Ssam */ 18730519Ssam lp->d_secsize = DEV_BSIZE / 2; /* XXX */ 18830519Ssam lp->d_nsectors = 32; 18930519Ssam lp->d_ntracks = 24; 19030519Ssam lp->d_ncylinders = 711; 19130519Ssam lp->d_secpercyl = 32*24; 19230519Ssam return (vdreset_drive(vi)); 19324004Ssam } 19424004Ssam 19530519Ssam /* 19630519Ssam * Read pack label. 19730519Ssam */ 19830519Ssam vdattach(vi) 19930519Ssam register struct vba_device *vi; 20024004Ssam { 20130519Ssam register int unit = vi->ui_unit; 20230519Ssam register struct dksoftc *dk = &dksoftc[unit]; 20330519Ssam register struct disklabel *lp; 20425675Ssam 20530519Ssam /* 20630519Ssam * Try to initialize device and read pack label. 20730519Ssam */ 20830519Ssam if (vdinit(vdminor(unit, 0), 0) != 0) { 20930519Ssam printf(": unknown drive type"); 21030519Ssam return; 21125675Ssam } 21230519Ssam /* 21330519Ssam * Initialize invariant portion of 21430519Ssam * dcb used for overlapped seeks. 21530519Ssam */ 21630519Ssam dk->dk_dcb.opcode = VDOP_SEEK; 21730519Ssam dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA; 21830519Ssam dk->dk_dcb.devselect = vi->ui_slave; 21930519Ssam dk->dk_dcb.trailcnt = sizeof (trseek) / sizeof (long); 22030519Ssam dk->dk_dcb.trail.sktrail.skaddr.sector = 0; 22130519Ssam dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb); 22230519Ssam lp = &dklabel[unit]; 22330519Ssam printf(": %s <ntrak %d, ncyl %d, nsec %d>", 22430519Ssam lp->d_typename, lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors); 22530519Ssam /* 22630519Ssam * (60 / rpm) / (sectors per track * (bytes per sector / 2)) 22730519Ssam */ 22830519Ssam if (vi->ui_dk >= 0) 22930519Ssam dk_mspw[vi->ui_dk] = 120.0 / 23030519Ssam (lp->d_rpm * lp->d_nsectors * lp->d_secsize); 23130519Ssam #ifdef notyet 232*30573Skarels addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp); 23330519Ssam #endif 23424004Ssam } 23524004Ssam 23630519Ssam /*ARGSUSED*/ 23730519Ssam vdopen(dev, flags) 23830519Ssam dev_t dev; 23930519Ssam int flags; 24024004Ssam { 24130519Ssam register unit = vdunit(dev); 24230519Ssam register struct disklabel *lp; 24330519Ssam register struct dksoftc *dk; 24430519Ssam register struct partition *pp; 24530519Ssam struct vba_device *vi; 24630519Ssam int s, error, part = vdpart(dev); 24730519Ssam daddr_t start, end; 24824004Ssam 24930519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 25030519Ssam return (ENXIO); 25130519Ssam lp = &dklabel[unit]; 25230519Ssam dk = &dksoftc[unit]; 25330519Ssam 25430519Ssam s = spl7(); 25530519Ssam while (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 25630519Ssam dk->dk_state != CLOSED) 25730519Ssam sleep((caddr_t)dk, PZERO+1); 25830519Ssam splx(s); 25930519Ssam if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 26030519Ssam if (error = vdinit(dev, flags)) 26130519Ssam return (error); 262*30573Skarels 263*30573Skarels if (vdwstart == 0) { 264*30573Skarels timeout(vdwatch, (caddr_t)0, hz); 265*30573Skarels vdwstart++; 266*30573Skarels } 26730519Ssam /* 26830519Ssam * Warn if a partion is opened 26930519Ssam * that overlaps another partition which is open 27030519Ssam * unless one is the "raw" partition (whole disk). 27130519Ssam */ 27230519Ssam #define RAWPART 2 /* 'c' partition */ /* XXX */ 27330519Ssam if ((dk->dk_openpart & (1 << part)) == 0 && 27430519Ssam part != RAWPART) { 27530519Ssam pp = &lp->d_partitions[part]; 27630519Ssam start = pp->p_offset; 27730519Ssam end = pp->p_offset + pp->p_size; 27830519Ssam for (pp = lp->d_partitions; 27930519Ssam pp < &lp->d_partitions[lp->d_npartitions]; pp++) { 28030519Ssam if (pp->p_offset + pp->p_size <= start || 28130519Ssam pp->p_offset >= end) 28230519Ssam continue; 28330519Ssam if (pp - lp->d_partitions == RAWPART) 28430519Ssam continue; 28530519Ssam if (dk->dk_openpart & (1 << (pp - lp->d_partitions))) 28630519Ssam log(LOG_WARNING, 28730519Ssam "dk%d%c: overlaps open partition (%c)\n", 28830519Ssam unit, part + 'a', 28930519Ssam pp - lp->d_partitions + 'a'); 29030519Ssam } 29124004Ssam } 29230519Ssam if (part >= lp->d_npartitions) 29330519Ssam return (ENXIO); 29430519Ssam dk->dk_openpart |= 1 << part; 29530519Ssam return (0); 29625675Ssam } 29724004Ssam 29830519Ssam vdclose(dev, flags) 29930519Ssam dev_t dev; 30030519Ssam int flags; 30124004Ssam { 30230519Ssam register int unit = vdunit(dev); 30330519Ssam register struct dksoftc *dk = &dksoftc[unit]; 30424004Ssam 30530519Ssam dk->dk_openpart &= ~(1 << vdpart(dev)); 30630519Ssam /* 30730519Ssam * Should wait for i/o to complete on this partition 30830519Ssam * even if others are open, but wait for work on blkflush(). 30930519Ssam */ 31030519Ssam if (dk->dk_openpart == 0) { 311*30573Skarels int s = spl7(); 312*30573Skarels while (dkutab[unit].b_actf) 313*30573Skarels sleep((caddr_t)dk, PZERO-1); 31430519Ssam splx(s); 31530519Ssam dk->dk_state = CLOSED; 31624004Ssam } 31725675Ssam } 31824004Ssam 31930519Ssam vdinit(dev, flags) 32030519Ssam dev_t dev; 32130519Ssam int flags; 32225675Ssam { 32330519Ssam register struct buf *bp = NULL; 32430519Ssam register struct disklabel *lp; 32530519Ssam register struct dksoftc *dk; 32630519Ssam struct vba_device *vi; 32730519Ssam struct disklabel *dlp; 32830519Ssam int unit = vdunit(dev), error = 0; 32930519Ssam extern int cold; 33025675Ssam 33130519Ssam dk = &dksoftc[unit]; 33230519Ssam if (flags & O_NDELAY) { 33330519Ssam dk->dk_state = OPENRAW; 33430519Ssam goto done; 33530519Ssam } 33630519Ssam 33730519Ssam /* 33830519Ssam * Initialize portion of the label 33930519Ssam * not set up in the slave routine. 34030519Ssam */ 34130519Ssam dk->dk_state = RDLABEL; 34230519Ssam lp = &dklabel[unit]; 34330519Ssam lp->d_secperunit = 0x1fffffff; 34430519Ssam lp->d_npartitions = 1; 34530519Ssam lp->d_partitions[0].p_size = 0x1fffffff; 34630519Ssam lp->d_partitions[0].p_offset = 0; 34730519Ssam 34830519Ssam bp = geteblk(DEV_BSIZE); /* max sector size */ 34930519Ssam bp->b_dev = dev; 35030519Ssam bp->b_blkno = LABELSECTOR; 35130519Ssam bp->b_bcount = DEV_BSIZE; 35230519Ssam bp->b_flags = B_BUSY | B_READ; 35330519Ssam bp->b_cylin = LABELSECTOR / lp->d_secpercyl; 35430519Ssam vdstrategy(bp); 35530519Ssam biowait(bp); 35630519Ssam if (bp->b_flags & B_ERROR) { 35730519Ssam error = u.u_error; /* XXX */ 35830519Ssam u.u_error = 0; 35930519Ssam dk->dk_state = CLOSED; 36030519Ssam goto done; 36130519Ssam } 36230519Ssam vi = vddinfo[unit]; 36330519Ssam dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET); 36430519Ssam if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC && 36530519Ssam dkcksum(dlp) == 0) { 36630519Ssam *lp = *dlp; 36730519Ssam /* 36830519Ssam * Now that we have the label, configure 36930519Ssam * the correct drive parameters. 37030519Ssam */ 37130519Ssam if (!vdreset_drive(vi)) 37230519Ssam dk->dk_state = CLOSED; 37330519Ssam else 37430519Ssam dk->dk_state = OPEN; 37525675Ssam } else { 37630519Ssam if (cold) 37730519Ssam printf(": no disk label"); 37830519Ssam else 37930519Ssam log(LOG_ERR, "dk%d: no disk label\n", vi->ui_unit); 38030519Ssam #ifdef COMPAT_42 38130519Ssam if (!vdmaptype(vi, lp)) { 38230519Ssam error = ENXIO; 38330519Ssam dk->dk_state = CLOSED; 38430519Ssam } else 38530519Ssam dk->dk_state = OPEN; 38630519Ssam #else 38730519Ssam dk->dk_state = OPENRAW; 38830519Ssam #endif 38925675Ssam } 39030519Ssam done: 39130519Ssam if (bp) { 39230519Ssam bp->b_flags = B_INVAL | B_AGE; 39330519Ssam brelse(bp); 39430519Ssam } 39530519Ssam wakeup((caddr_t)dk); 39630519Ssam return (error); 39724004Ssam } 39824004Ssam 39925675Ssam /*ARGSUSED*/ 40030519Ssam vddgo(vm) 40130519Ssam struct vba_device *vm; 40224004Ssam { 40324004Ssam 40424004Ssam } 40524004Ssam 40624004Ssam vdstrategy(bp) 40725675Ssam register struct buf *bp; 40824004Ssam { 40930519Ssam register struct vba_device *vi; 41030519Ssam register struct disklabel *lp; 41130519Ssam register struct dksoftc *dk; 41230519Ssam register int unit; 413*30573Skarels register daddr_t sn; 41430519Ssam struct buf *dp; 415*30573Skarels daddr_t sz, maxsz; 41630519Ssam int part, s; 41724004Ssam 41830519Ssam sz = bp->b_bcount; 41930519Ssam sz = (sz + DEV_BSIZE - 1) >> DEV_BSHIFT; 42030519Ssam unit = vdunit(bp->b_dev); 42130519Ssam if (unit > NDK) { 42229954Skarels bp->b_error = ENXIO; 42325675Ssam goto bad; 42429954Skarels } 42530519Ssam vi = vddinfo[unit]; 42630519Ssam lp = &dklabel[unit]; 42730519Ssam if (vi == 0 || vi->ui_alive == 0) { 42830519Ssam bp->b_error = ENXIO; 42930519Ssam goto bad; 43030519Ssam } 43130519Ssam dk = &dksoftc[unit]; 43230519Ssam if (dk->dk_state < OPEN) 43330519Ssam goto q; 43430519Ssam part = vdpart(bp->b_dev); 43530519Ssam if ((dk->dk_openpart & (1 << part)) == 0) { 43630519Ssam bp->b_error = ENODEV; 43730519Ssam goto bad; 43830519Ssam } 43930519Ssam maxsz = lp->d_partitions[part].p_size; 440*30573Skarels sn = bp->b_blkno; 44130519Ssam if (sn < 0 || sn + sz > maxsz) { 44230519Ssam if (sn == maxsz) { 44329954Skarels bp->b_resid = bp->b_bcount; 44429954Skarels goto done; 44529954Skarels } 446*30573Skarels sz = maxsz - bp->b_blkno; 447*30573Skarels if (sz <= 0) { 448*30573Skarels bp->b_error = EINVAL; 449*30573Skarels goto bad; 450*30573Skarels } 451*30573Skarels bp->b_bcount = sz * lp->d_secsize; 45225675Ssam } 45330519Ssam bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl; 45430519Ssam q: 45530519Ssam vbasetup(bp, lp->d_secsize); 45625675Ssam s = spl7(); 45730519Ssam dp = &dkutab[vi->ui_unit]; 45830519Ssam disksort(dp, bp); 45930519Ssam if (!dp->b_active) { 46030519Ssam (void) vdustart(vi); 461*30573Skarels if (!vi->ui_mi->um_tab.b_active) 46230519Ssam vdstart(vi->ui_mi); 46324004Ssam } 46430519Ssam splx(s); 46524004Ssam return; 46625675Ssam bad: 46729954Skarels bp->b_flags |= B_ERROR; 46829954Skarels done: 46930519Ssam biodone(bp); 47030519Ssam return; 47124004Ssam } 47224004Ssam 47330519Ssam vdustart(vi) 47430519Ssam register struct vba_device *vi; 47524004Ssam { 47630519Ssam register struct buf *bp, *dp; 47730519Ssam register struct vba_ctlr *vm; 47830519Ssam register int unit = vi->ui_unit; 47930519Ssam register struct dksoftc *dk; 48030519Ssam register struct vdsoftc *vd; 48130519Ssam struct disklabel *lp; 48224004Ssam 48330519Ssam dp = &dkutab[unit]; 48430519Ssam /* 48530519Ssam * If queue empty, nothing to do. 48630519Ssam */ 48730519Ssam if ((bp = dp->b_actf) == NULL) 48830519Ssam return; 48930519Ssam /* 49030519Ssam * If drive is off-cylinder, mark unit to force 49130519Ssam * overlap seek with next transfer on this controller. 49230519Ssam */ 49330519Ssam vd = &vdsoftc[vi->ui_ctlr]; 49430519Ssam dk = &dksoftc[unit]; 49530519Ssam if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) { 49630519Ssam lp = &dklabel[unit]; 497*30573Skarels bp->b_daddr = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors; 49830519Ssam if (bp->b_daddr != dk->dk_curdaddr) 49930519Ssam vd->vd_offcyl |= 1 << vi->ui_slave; 50030519Ssam } 50130519Ssam /* 50230519Ssam * If controller is not busy, place request on the 503*30573Skarels * controller's ready queue). 50430519Ssam */ 505*30573Skarels dp->b_forw = NULL; 506*30573Skarels vm = vi->ui_mi; 507*30573Skarels if (vm->um_tab.b_actf == NULL) 508*30573Skarels vm->um_tab.b_actf = dp; 509*30573Skarels else 510*30573Skarels vm->um_tab.b_actl->b_forw = dp; 511*30573Skarels vm->um_tab.b_actl = dp; 512*30573Skarels dp->b_active++; 51325675Ssam } 51425675Ssam 51525675Ssam /* 51630519Ssam * Start next transfer on a controller. 51725675Ssam */ 51830519Ssam vdstart(vm) 51930519Ssam register struct vba_ctlr *vm; 52025675Ssam { 52125675Ssam register struct buf *bp; 52230519Ssam register struct vba_device *vi; 52330519Ssam register struct vdsoftc *vd; 52430519Ssam register struct dksoftc *dk; 52530519Ssam register struct disklabel *lp; 52630519Ssam register int slave; 52730519Ssam register struct dcb **dcbp; 52830519Ssam struct mdcb *mdcb; 52930519Ssam struct buf *dp; 53030519Ssam int sn, tn; 53125675Ssam 53230519Ssam loop: 53330519Ssam /* 53430519Ssam * Pull a request off the controller queue. 53530519Ssam */ 53630519Ssam if ((dp = vm->um_tab.b_actf) == NULL) 53730519Ssam return; 53830519Ssam if ((bp = dp->b_actf) == NULL) { 53930519Ssam vm->um_tab.b_actf = dp->b_forw; 54030519Ssam goto loop; 54130519Ssam } 54225675Ssam 54324004Ssam /* 54430519Ssam * Mark controller busy, and determine 54530519Ssam * destination of this request. 54624004Ssam */ 54730519Ssam vm->um_tab.b_active++; 54830519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 54930519Ssam dk = &dksoftc[vi->ui_unit]; 550*30573Skarels sn = bp->b_blkno; 55130519Ssam lp = &dklabel[vi->ui_unit]; 55230519Ssam sn %= lp->d_secpercyl; 55330519Ssam tn = sn / lp->d_nsectors; 55430519Ssam sn %= lp->d_nsectors; 55530519Ssam 55630519Ssam /* 55730519Ssam * Construct dcb for read/write command. 55830519Ssam */ 55930519Ssam vd = &vdsoftc[vm->um_ctlr]; 56030519Ssam slave = vi->ui_slave; 56130519Ssam vd->vd_dcb.opcode = (bp->b_flags & B_READ) ? VDOP_RD : VDOP_WD; 56230519Ssam vd->vd_dcb.intflg = DCBINT_DONE; 56330519Ssam vd->vd_dcb.devselect = slave; 56430519Ssam vd->vd_dcb.operrsta = 0; 56530519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 56630519Ssam vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long); 56730519Ssam vd->vd_dcb.trail.rwtrail.memadr = (char *) 56830519Ssam vbastart(bp, vd->vd_rawbuf, (long *)vd->vd_map, vd->vd_utl); 56930519Ssam vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1; 57030519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin; 57130519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 57230519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 57330519Ssam 57430519Ssam /* 57530519Ssam * Look for any seeks to be performed on other drives on this 57630519Ssam * controller. If overlapped seeks exist, insert seek commands 57730519Ssam * on the controller's command queue before the transfer. 57830519Ssam */ 57930519Ssam dcbp = &vd->vd_mdcb.mdcb_head; 58030519Ssam if (vd->vd_offcyl &~ (1<<slave)) { 58130519Ssam register struct dksoftc *tdk; 58230519Ssam register struct buf *tp; 58330519Ssam 58430519Ssam for (dp = dp->b_forw; dp != NULL; dp = dp->b_forw) { 58530519Ssam if ((tp = dp->b_actf) == NULL) 58630519Ssam continue; 58730519Ssam slave = (vi = vddinfo[vdunit(tp->b_dev)])->ui_slave; 58830519Ssam if ((vd->vd_offcyl & (1<<slave)) == 0) 58930519Ssam continue; 59030519Ssam vd->vd_offcyl &= ~(1 << slave); 59130519Ssam tdk = &dksoftc[vi->ui_unit]; 59230519Ssam if (tdk->dk_curcyl != tp->b_cylin) { 59330519Ssam tdk->dk_curcyl = tp->b_cylin; 59430519Ssam dk_seek[vi->ui_dk]++; 59530519Ssam } 59630519Ssam tdk->dk_curdaddr = tp->b_daddr; 59730519Ssam tdk->dk_dcb.operrsta = 0; 59830519Ssam tdk->dk_dcb.trail.sktrail.skaddr.cylinder = tp->b_cylin; 59930519Ssam tdk->dk_dcb.trail.sktrail.skaddr.track = tp->b_daddr>>8; 60030519Ssam tdk->dk_dcb.trail.sktrail.skaddr.sector = 60130519Ssam tp->b_daddr & 0xff; 60230519Ssam *dcbp = (struct dcb *)tdk->dk_dcbphys; 60330519Ssam dcbp = &tdk->dk_dcb.nxtdcb; 60430519Ssam } 60525675Ssam } else { 60630519Ssam dk->dk_curcyl = bp->b_cylin; 60730519Ssam dk->dk_curdaddr = (tn << 8) | sn; 60830519Ssam vd->vd_offcyl = 0; 60924004Ssam } 61030519Ssam *dcbp = (struct dcb *)vd->vd_dcbphys; 61124004Ssam 61230519Ssam /* 61330519Ssam * Initiate operation. 61430519Ssam */ 61530519Ssam bp->b_daddr = 0; /* init overloaded field */ 61630519Ssam if (vi->ui_dk >= 0) { 61730519Ssam dk_busy |= 1<<vi->ui_dk; 61830519Ssam dk_xfer[vi->ui_dk]++; 61930519Ssam dk_wds[vi->ui_dk] += bp->b_bcount>>6; 62024004Ssam } 62130519Ssam vd->vd_mdcb.mdcb_status = 0; 62230519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 62324004Ssam } 62424004Ssam 62530519Ssam #define DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE) 62624004Ssam /* 62724004Ssam * Handle a disk interrupt. 62824004Ssam */ 62925675Ssam vdintr(ctlr) 63030519Ssam register ctlr; 63124004Ssam { 63230519Ssam register struct buf *bp, *dp; 63330519Ssam register struct vba_ctlr *vm = vdminfo[ctlr]; 63430519Ssam register struct vba_device *vi; 63530519Ssam register struct vdsoftc *vd = &vdsoftc[ctlr]; 63630519Ssam register status; 637*30573Skarels struct dksoftc *dk; 63824004Ssam 63930519Ssam vd->vd_wticks = 0; 64030519Ssam if (!vm->um_tab.b_active) { 64125675Ssam printf("vd%d: stray interrupt\n", ctlr); 64224004Ssam return; 64324004Ssam } 64425675Ssam /* 64530519Ssam * Get device and block structures, and a pointer 64630519Ssam * to the vba_device for the drive. 64725675Ssam */ 64830519Ssam dp = vm->um_tab.b_actf; 64930519Ssam bp = dp->b_actf; 65030519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 65130519Ssam dk_busy &= ~(1<<vi->ui_dk); 65230519Ssam /* 65330519Ssam * Check for and process errors on 65430519Ssam * either the drive or the controller. 65530519Ssam */ 65630519Ssam uncache(&vd->vd_dcb.operrsta); 65730519Ssam status = vd->vd_dcb.operrsta; 65830519Ssam if (status & VDERR_HARD) { 65930519Ssam if (status & DCBS_WPT) { 66030519Ssam /* 66130519Ssam * Give up on write locked devices immediately. 66230519Ssam */ 663*30573Skarels printf("dk%d: write locked\n", vi->ui_unit); 66430519Ssam bp->b_flags |= B_ERROR; 665*30573Skarels } else if (status & VDERR_RETRY) { 66630519Ssam if (status & VDERR_DRIVE) { 66730519Ssam if (!vdreset_drive(vi)) 66830519Ssam vi->ui_alive = 0; 66930519Ssam } else if (status & VDERR_CTLR) 67030519Ssam vdreset_ctlr(vm); 67130519Ssam /* 67230519Ssam * Retry transfer once, unless reset failed. 67330519Ssam */ 67430519Ssam if (!vi->ui_alive || bp->b_errcnt++ >= 2) 67530519Ssam goto hard; 67630519Ssam vm->um_tab.b_active = 0; /* force retry */ 67730519Ssam } else { 67830519Ssam hard: 67930519Ssam bp->b_flags |= B_ERROR; 68030519Ssam /* NEED TO ADJUST b_blkno to failed sector */ 68130519Ssam harderr(bp, "dk"); 68230519Ssam printf("status %x (%b)", status, 68330519Ssam status &~ DONTCARE, VDERRBITS); 68430519Ssam if (vd->vd_type == VDTYPE_SMDE) { 68530519Ssam uncache(&vd->vd_dcb.err_code); 68630519Ssam printf(" ecode %x", vd->vd_dcb.err_code); 68730519Ssam } 68830519Ssam printf("\n"); 68930519Ssam } 69030519Ssam } else if (status & DCBS_SOFT) 69130519Ssam vdsofterr(vd, bp, &vd->vd_dcb); 69230519Ssam if (vm->um_tab.b_active) { 69330519Ssam vm->um_tab.b_active = 0; 69430519Ssam vm->um_tab.b_errcnt = 0; 69530519Ssam vm->um_tab.b_actf = dp->b_forw; 69630519Ssam dp->b_active = 0; 69730519Ssam dp->b_errcnt = 0; 69830519Ssam dp->b_actf = bp->av_forw; 69930519Ssam bp->b_resid = 0; 70030519Ssam vbadone(bp, vd->vd_rawbuf, (long *)vd->vd_map, vd->vd_utl); 70130519Ssam biodone(bp); 70230370Skarels /* 70330519Ssam * If this unit has more work to do, 70430519Ssam * then start it up right away. 70530370Skarels */ 70630519Ssam if (dp->b_actf) 70730519Ssam vdustart(vi); 708*30573Skarels else if ((dk = &dksoftc[vi->ui_unit])->dk_openpart == 0) 709*30573Skarels wakeup((caddr_t)dk); 71024004Ssam } 71125675Ssam /* 71230519Ssam * If there are devices ready to 71330519Ssam * transfer, start the controller. 71425675Ssam */ 71530519Ssam if (vm->um_tab.b_actf) 71630519Ssam vdstart(vm); 71724004Ssam } 71824004Ssam 71930519Ssam vdsofterr(vd, bp, dcb) 72030519Ssam struct vdsoftc *vd; 72125675Ssam register struct buf *bp; 72230519Ssam register struct dcb *dcb; 72325675Ssam { 72430519Ssam int unit = vdunit(bp->b_dev), status = dcb->operrsta; 72530519Ssam char part = 'a' + vdpart(bp->b_dev); 72625675Ssam 72730519Ssam if (status != (DCBS_DCE|DCBS_CCD|DCBS_SOFT|DCBS_ERR)) { 72830519Ssam if (vd->vd_type == VDTYPE_SMDE) 72930519Ssam uncache(&dcb->err_code); 73030519Ssam log(LOG_WARNING, "dk%d%c: soft error sn%d status %b ecode %x\n", 73130519Ssam unit, part, bp->b_blkno, status, VDERRBITS, dcb->err_code); 73230519Ssam } else 73330370Skarels log(LOG_WARNING, "dk%d%c: soft ecc sn%d\n", 73430370Skarels unit, part, bp->b_blkno); 73525675Ssam } 73625675Ssam 73724004Ssam vdread(dev, uio) 73825675Ssam dev_t dev; 73925675Ssam struct uio *uio; 74024004Ssam { 74130519Ssam register int unit = vdunit(dev); 74224004Ssam 74329564Ssam if (unit >= NDK) 74425675Ssam return (ENXIO); 74530519Ssam return (physio(vdstrategy, &rdkbuf[unit], dev, B_READ, minphys, uio)); 74624004Ssam } 74724004Ssam 74824004Ssam vdwrite(dev, uio) 74925675Ssam dev_t dev; 75025675Ssam struct uio *uio; 75124004Ssam { 75230519Ssam register int unit = vdunit(dev); 75324004Ssam 75429564Ssam if (unit >= NDK) 75525675Ssam return (ENXIO); 75630519Ssam return (physio(vdstrategy, &rdkbuf[unit], dev, B_WRITE, minphys, uio)); 75724004Ssam } 75824004Ssam 75930519Ssam vdioctl(dev, cmd, data, flag) 76025675Ssam dev_t dev; 76130519Ssam int cmd; 76230519Ssam caddr_t data; 76330519Ssam int flag; 76424004Ssam { 76530519Ssam int unit = vdunit(dev); 76630519Ssam register struct disklabel *lp = &dklabel[unit]; 76730519Ssam int error = 0; 76824004Ssam 76930519Ssam switch (cmd) { 77030519Ssam 77130519Ssam case DIOCGDINFO: 77230519Ssam *(struct disklabel *)data = *lp; 77330519Ssam break; 77430519Ssam 775*30573Skarels case DIOCGPART: 776*30573Skarels ((struct partinfo *)data)->disklab = lp; 777*30573Skarels ((struct partinfo *)data)->part = 778*30573Skarels &lp->d_partitions[vdpart(dev)]; 77930519Ssam break; 78030519Ssam 78130519Ssam case DIOCSDINFO: 78230519Ssam if ((flag & FWRITE) == 0) 78330519Ssam error = EBADF; 78430519Ssam else 78530519Ssam *lp = *(struct disklabel *)data; 78630519Ssam break; 78730519Ssam 78830519Ssam case DIOCWDINFO: { 78930519Ssam struct buf *bp; 79030519Ssam struct disklabel *dlp; 79130519Ssam 79230519Ssam if ((flag & FWRITE) == 0) { 79330519Ssam error = EBADF; 79430519Ssam break; 79530519Ssam } 79630519Ssam *lp = *(struct disklabel *)data; 79730519Ssam bp = geteblk(lp->d_secsize); 79830519Ssam bp->b_dev = dev; 79930519Ssam bp->b_blkno = LABELSECTOR; 80030519Ssam bp->b_bcount = lp->d_secsize; 80130519Ssam bp->b_flags = B_READ; 80230519Ssam dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET); 80330519Ssam vdstrategy(bp); 80430519Ssam biowait(bp); 80530519Ssam if (bp->b_flags & B_ERROR) { 80630519Ssam error = u.u_error; /* XXX */ 80730519Ssam u.u_error = 0; 80830519Ssam goto bad; 80930519Ssam } 81030519Ssam *dlp = *lp; 81130519Ssam bp->b_flags = B_WRITE; 81230519Ssam vdstrategy(bp); 81330519Ssam biowait(bp); 81430519Ssam if (bp->b_flags & B_ERROR) { 81530519Ssam error = u.u_error; /* XXX */ 81630519Ssam u.u_error = 0; 81730519Ssam } 81830519Ssam bad: 81930519Ssam brelse(bp); 82030519Ssam break; 82125675Ssam } 82230519Ssam 82330519Ssam default: 82430519Ssam error = ENOTTY; 82530519Ssam break; 82624004Ssam } 82725675Ssam return (0); 82824004Ssam } 82924004Ssam 83025675Ssam /* 83130519Ssam * Watch for lost interrupts. 83225675Ssam */ 83330519Ssam vdwatch() 83430519Ssam { 83530519Ssam register struct vdsoftc *vd; 83630519Ssam register struct vba_ctlr *vm; 83725675Ssam register int ctlr, unit; 83830519Ssam 83930519Ssam timeout(vdwatch, (caddr_t)0, hz); 84030519Ssam for (ctlr = 0; ctlr < NVD; ctlr++) { 84130519Ssam vm = vdminfo[ctlr]; 84230519Ssam if (vm == 0 || vm->um_alive == 0) 84330519Ssam continue; 84430519Ssam vd = &vdsoftc[ctlr]; 84530519Ssam if (!vm->um_tab.b_active) { 84630519Ssam for (unit = 0; unit < NDK; unit++) 84730519Ssam if (dkutab[unit].b_active && 84830519Ssam vddinfo[unit]->ui_mi == vm) 84930519Ssam goto active; 85030519Ssam vd->vd_wticks = 0; 85130519Ssam continue; 85230519Ssam } 85330519Ssam active: 85430519Ssam vd->vd_wticks++; 85530519Ssam if (vd->vd_wticks >= 20) { 85630519Ssam vd->vd_wticks = 0; 85730519Ssam printf("vd%d: lost interrupt\n", ctlr); 85830519Ssam /* abort pending dcb's and restart controller */ 85930519Ssam } 86030519Ssam } 86130519Ssam } 86230519Ssam 86330519Ssam #define DBSIZE 64 /* controller limit with 1K sectors */ 86430519Ssam /* 86530519Ssam * Crash dump. 86630519Ssam */ 86730519Ssam vddump(dev) 86830519Ssam dev_t dev; 86924004Ssam { 87030519Ssam register struct vba_device *vi; 87130519Ssam register struct vba_ctlr *vm; 87230519Ssam register struct disklabel *lp; 87330519Ssam register struct vdsoftc *vd; 87430519Ssam struct dksoftc *dk; 87530519Ssam int part, unit, num; 87630519Ssam caddr_t start; 87724004Ssam 87830519Ssam start = 0; 87930519Ssam unit = vdunit(dev); 88030519Ssam if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 88130519Ssam return (ENXIO); 88230519Ssam dk = &dksoftc[unit]; 88330519Ssam if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 88430519Ssam return (ENXIO); 88530519Ssam lp = &dklabel[unit]; 88630519Ssam part = vdpart(dev); 88730519Ssam if (part >= lp->d_npartitions) 88830519Ssam return (ENXIO); 88930519Ssam vm = vdminfo[vi->ui_ctlr]; 89030519Ssam vdreset_ctlr(vm); 89130519Ssam if (dumplo < 0) 89230519Ssam return (EINVAL); 89330519Ssam /* 894*30573Skarels * Dumplo and maxfree are in pages. 89530519Ssam */ 89630519Ssam num = maxfree * (NBPG / lp->d_secsize); 897*30573Skarels dumplo *= NBPG / lp->d_secsize; 89830519Ssam if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size) 89930519Ssam num = lp->d_partitions[vdpart(dev)].p_size - dumplo; 90030519Ssam vd = &vdsoftc[vm->um_ctlr]; 90130519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 90230519Ssam vd->vd_dcb.opcode = VDOP_WD; 90330519Ssam vd->vd_dcb.devselect = vi->ui_slave; 90430519Ssam vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long); 90530519Ssam while (num > 0) { 90630519Ssam int nsec, cn, sn, tn; 90730519Ssam 90830519Ssam nsec = MIN(num, DBSIZE); 90930519Ssam sn = dumplo + (unsigned)start / lp->d_secsize; 91030519Ssam cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) / 91130519Ssam lp->d_secpercyl; 91230519Ssam sn %= lp->d_secpercyl; 91330519Ssam tn = sn / lp->d_nsectors; 91430519Ssam sn %= lp->d_nsectors; 91530519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 91630519Ssam vd->vd_dcb.trail.rwtrail.memadr = start; 91730519Ssam vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1; 91830519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = cn; 91930519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 92030519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 92130519Ssam vd->vd_dcb.operrsta = 0; 92230519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 92330519Ssam if (!vdpoll(vm, 5)) { 92430519Ssam printf(" during dump\n"); 92530519Ssam return (EIO); 92630519Ssam } 92730519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 92830519Ssam printf("dk%d: hard error, status=%b\n", unit, 92930519Ssam vd->vd_dcb.operrsta, VDERRBITS); 93030519Ssam return (EIO); 93130519Ssam } 93230519Ssam start += nsec * lp->d_secsize; 93330519Ssam num -= nsec; 93425675Ssam } 93530519Ssam return (0); 93624004Ssam } 93724004Ssam 93824004Ssam vdsize(dev) 93925675Ssam dev_t dev; 94024004Ssam { 94130519Ssam register int unit = vdunit(dev); 94230519Ssam register struct dksoftc *dk; 94330519Ssam struct vba_device *vi; 94430519Ssam struct disklabel *lp; 94524004Ssam 94630519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 || 94730519Ssam (dk = &dksoftc[unit])->dk_state != OPEN) 94825675Ssam return (-1); 94930519Ssam lp = &dklabel[unit]; 950*30573Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size); 95124004Ssam } 95224004Ssam 95325675Ssam /* 95425675Ssam * Perform a controller reset. 95525675Ssam */ 95630519Ssam vdreset_ctlr(vm) 95730519Ssam register struct vba_ctlr *vm; 95824004Ssam { 95930519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 96030519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 96130519Ssam register int unit; 96230519Ssam struct vba_device *vi; 96325675Ssam 96430519Ssam VDRESET(vdaddr, vd->vd_type); 96530519Ssam if (vd->vd_type == VDTYPE_SMDE) { 96630519Ssam vdaddr->vdcsr = 0; 96730519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 96830519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 96930519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 97030519Ssam vdaddr->vdtcf_data = AM_ENPDA; 97130519Ssam vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD | 97225675Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 97325675Ssam } 97430519Ssam if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { 97530519Ssam printf("%s cmd failed\n", 97630519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 97730370Skarels return; 97825675Ssam } 97930519Ssam for (unit = 0; unit < NDK; unit++) 98030519Ssam if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive) 98130519Ssam (void) vdreset_drive(vi); 98230519Ssam } 98330519Ssam 98430519Ssam vdreset_drive(vi) 98530519Ssam register struct vba_device *vi; 98630519Ssam { 98730519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 98830519Ssam struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; 98930519Ssam struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 99030519Ssam struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 99130519Ssam 99230519Ssam top: 99330519Ssam vd->vd_dcb.opcode = VDOP_CONFIG; /* command */ 99430519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 99530519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 99630519Ssam vd->vd_dcb.operrsta = 0; 99730519Ssam vd->vd_dcb.devselect = vi->ui_slave; 99830519Ssam vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders; 99930519Ssam vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks; 100030519Ssam if (vd->vd_type == VDTYPE_SMDE) { 100130519Ssam vd->vd_dcb.trailcnt = sizeof (treset) / sizeof (long); 100230519Ssam vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors; 100330519Ssam vd->vd_dcb.trail.rstrail.slip_sec = lp->d_trackskew; 100430519Ssam vd->vd_dcb.trail.rstrail.recovery = 0x18f; 100530519Ssam } else 100630519Ssam vd->vd_dcb.trailcnt = 2; /* XXX */ 100730519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 100830519Ssam vd->vd_mdcb.mdcb_status = 0; 100930519Ssam VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type); 101030519Ssam if (!vdpoll(vm, 5)) { 101130519Ssam printf(" during config\n"); 101230519Ssam return (0); 101325675Ssam } 101430519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 101530519Ssam if (vd->vd_type == VDTYPE_SMDE && 101630519Ssam (vdaddr->vdstatus[vi->ui_slave]&STA_US) == 0) 101730519Ssam return (0); 101830519Ssam if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) 101930519Ssam printf("dk%d: config error\n", vi->ui_unit); 102030519Ssam else if ((vd->vd_flags&VD_STARTED) == 0) { 102130519Ssam int started; 102230519Ssam 102330519Ssam printf("vd%d: starting drives, wait ... ", vm->um_ctlr); 102430519Ssam vd->vd_flags |= VD_STARTED; 102530519Ssam started = (vdcmd(vm, VDOP_START, 10) == 1); 102630519Ssam DELAY(62000000); 102730519Ssam printf("\n"); 102830519Ssam if (started) 102930519Ssam goto top; 103030519Ssam } 103130519Ssam return (0); 103230519Ssam } 103330519Ssam return (1); 103425675Ssam } 103524004Ssam 103625675Ssam /* 103730519Ssam * Perform a command w/o trailer. 103825675Ssam */ 103930519Ssam vdcmd(vm, cmd, t) 104030519Ssam register struct vba_ctlr *vm; 104125675Ssam { 104230519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 104325675Ssam 104430519Ssam vd->vd_dcb.opcode = cmd; /* command */ 104530519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 104630519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 104730519Ssam vd->vd_dcb.operrsta = 0; 104830519Ssam vd->vd_dcb.devselect = 0; 104930519Ssam vd->vd_dcb.trailcnt = 0; 105030519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 105130519Ssam vd->vd_mdcb.mdcb_status = 0; 105230519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 105330519Ssam if (!vdpoll(vm, t)) { 105430519Ssam printf(" during init\n"); 105530370Skarels return (0); 105630370Skarels } 105730519Ssam return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0); 105825675Ssam } 105925675Ssam 106025925Ssam /* 106130519Ssam * Poll controller until operation 106230519Ssam * completes or timeout expires. 106325925Ssam */ 106430519Ssam vdpoll(vm, t) 106530519Ssam register struct vba_ctlr *vm; 106625925Ssam register int t; 106725925Ssam { 106830519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 106930519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 107025925Ssam 107125925Ssam t *= 1000; 107230370Skarels for (;;) { 107330519Ssam uncache(&vd->vd_dcb.operrsta); 107430519Ssam if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT)) 107530370Skarels break; 107625925Ssam if (--t <= 0) { 107730519Ssam printf("vd%d: controller timeout", vm->um_ctlr); 107830519Ssam VDABORT(vdaddr, vd->vd_type); 107925925Ssam DELAY(30000); 108025925Ssam return (0); 108125925Ssam } 108230370Skarels DELAY(1000); 108325925Ssam } 108430519Ssam if (vd->vd_type == VDTYPE_SMDE) { 108530519Ssam do { 108625925Ssam DELAY(50); 108730519Ssam uncache(&vdaddr->vdcsr); 108830519Ssam } while (vdaddr->vdcsr & CS_GO); 108925925Ssam DELAY(300); 109025925Ssam } 109125925Ssam DELAY(200); 109230519Ssam uncache(&vd->vd_dcb.operrsta); 109325925Ssam return (1); 109425925Ssam } 109525925Ssam 109630519Ssam #ifdef COMPAT_42 109730519Ssam struct vdst { 109830519Ssam int nsec; /* sectors/track */ 109930519Ssam int ntrack; /* tracks/cylinder */ 110030519Ssam int ncyl; /* cylinders */ 110130519Ssam char *name; /* type name */ 110230519Ssam struct { 110330519Ssam int off; /* partition offset in sectors */ 110430519Ssam int size; /* partition size in sectors */ 1105*30573Skarels } parts[8]; 110630519Ssam } vdst[] = { 1107*30573Skarels { 48, 24, 711, "xsd", 1108*30573Skarels {0, 30528}, /* a cyl 0 - 52 */ 1109*30573Skarels {30528, 30528}, /* b cyl 53 - 105 */ 1110*30573Skarels {61056, 345600}, /* c cyl 106 - 705 */ 1111*30573Skarels {118656, 288000}, /* d cyl 206 - 705 */ 1112*30573Skarels {176256, 230400}, /* e cyl 306 - 705 */ 1113*30573Skarels {233856, 172800}, /* f cyl 406 - 705 */ 1114*30573Skarels {291456, 115200}, /* g cyl 506 - 705 */ 1115*30573Skarels {349056, 57600} /* h cyl 606 - 705 */ 1116*30573Skarels }, 1117*30573Skarels { 44, 20, 842, "egl", 1118*30573Skarels {0, 26400}, /* egl0a cyl 0 - 59 */ 1119*30573Skarels {26400, 33000}, /* egl0b cyl 60 - 134 */ 1120*30573Skarels {59400, 308880}, /* egl0c cyl 135 - 836 */ 1121*30573Skarels {368280, 2640}, /* egl0d cyl 837 - 842 */ 1122*30573Skarels {0, 368280}, /* egl0e cyl 0 - 836 */ 1123*30573Skarels {0, 370920}, /* egl0f cyl 0 - 842 */ 1124*30573Skarels {59400, 155320}, /* egl0g cyl 135 - 487 */ 1125*30573Skarels {214720, 153560} /* egl0h cyl 488 - 836 */ 1126*30573Skarels }, 1127*30573Skarels { 64, 10, 823, "fuj", 1128*30573Skarels {0, 19200}, /* fuj0a cyl 0 - 59 */ 1129*30573Skarels {19200, 24000}, /* fuj0b cyl 60 - 134 */ 1130*30573Skarels {43200, 218560}, /* fuj0c cyl 135 - 817 */ 1131*30573Skarels {79680, 182080}, /* fuj0d cyl 249 - 817 */ 1132*30573Skarels {116160, 145600}, /* fuj0e cyl 363 - 817 */ 1133*30573Skarels {152640, 109120}, /* fuj0f cyl 477 - 817 */ 1134*30573Skarels {189120, 72640}, /* fuj0g cyl 591 - 817 */ 1135*30573Skarels {225600, 36160} /* fug0h cyl 705 - 817 */ 1136*30573Skarels }, 1137*30573Skarels { 32, 24, 711, "xfd", 1138*30573Skarels { 0, 20352 }, /* a cyl 0 - 52 */ 1139*30573Skarels { 20352, 20352 }, /* b cyl 53 - 105 */ 1140*30573Skarels { 40704, 230400 }, /* c cyl 106 - 705 */ 1141*30573Skarels { 0, 40704 }, /* d cyl 709 - 710 (a & b) */ 1142*30573Skarels { 0, 271104 }, /* e cyl 0 - 705 */ 1143*30573Skarels { 20352, 250752 }, /* f cyl 53 - 705 (b & c) */ 1144*30573Skarels { 40704, 115200 }, /* g cyl 106 - 405 (1/2 of c) */ 1145*30573Skarels { 155904,115200 } /* h cyl 406 - 705 (1/2 of c) */ 1146*30573Skarels }, 1147*30573Skarels { 32, 19, 823, "smd", 1148*30573Skarels {0, 20064}, /* a cyl 0-65 */ 1149*30573Skarels {20064, 13680}, /* b cyl 66-110 */ 1150*30573Skarels {33744, 214928}, /* c cyl 111-817 */ 1151*30573Skarels {69616, 179056}, /* d cyl 229 - 817 */ 1152*30573Skarels {105488, 143184}, /* e cyl 347 - 817 */ 1153*30573Skarels {141360, 107312}, /* f cyl 465 - 817 */ 1154*30573Skarels {177232, 71440}, /* g cyl 583 - 817 */ 1155*30573Skarels {213104, 35568} /* h cyl 701 - 817 */ 1156*30573Skarels }, 1157*30573Skarels { 32, 10, 823, "fsd", 1158*30573Skarels {0, 9600}, /* a cyl 0 - 59 */ 1159*30573Skarels {9600, 12000}, /* b cyl 60 - 134 */ 1160*30573Skarels {21600, 109280}, /* c cyl 135 - 817 */ 1161*30573Skarels {39840, 91040}, /* d cyl 249 - 817 */ 1162*30573Skarels {58080, 72800}, /* e cyl 363 - 817 */ 1163*30573Skarels {76320, 54560}, /* f cyl 477 - 817 */ 1164*30573Skarels {94560, 36320}, /* g cyl 591 - 817 */ 1165*30573Skarels {112800, 18080} /* h cyl 705 - 817 */ 1166*30573Skarels } 116730519Ssam }; 116830519Ssam #define NVDST (sizeof (vdst) / sizeof (vdst[0])) 116930519Ssam 117025675Ssam /* 117130519Ssam * Construct a label for an unlabeled pack. We 117230519Ssam * deduce the drive type by reading from the last 117330519Ssam * track on successively smaller drives until we 117430519Ssam * don't get an error. 117525675Ssam */ 117630519Ssam vdmaptype(vi, lp) 117730519Ssam register struct vba_device *vi; 117830519Ssam register struct disklabel *lp; 117925675Ssam { 118030519Ssam register struct vdsoftc *vd; 118130519Ssam register struct vdst *p; 118230519Ssam struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; 118330519Ssam int i; 118425675Ssam 118530519Ssam vd = &vdsoftc[vi->ui_ctlr]; 118630519Ssam for (p = vdst; p < &vdst[NVDST]; p++) { 118730519Ssam if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32) 118830519Ssam continue; 118930519Ssam lp->d_nsectors = p->nsec; 119030519Ssam lp->d_ntracks = p->ntrack; 119130519Ssam lp->d_ncylinders = p->ncyl; 119230519Ssam if (!vdreset_drive(vi)) 119330519Ssam return (0); 119430519Ssam vd->vd_dcb.opcode = VDOP_RD; 119530519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 119630519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 119730519Ssam vd->vd_dcb.devselect = vi->ui_slave; 119830519Ssam vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long); 119930519Ssam vd->vd_dcb.trail.rwtrail.memadr = (char *) 120030519Ssam vtoph((struct proc *)0, (unsigned)vd->vd_rawbuf); 120130519Ssam vd->vd_dcb.trail.rwtrail.wcount = 512 / sizeof(short); 120230519Ssam vd->vd_dcb.operrsta = 0; 120330519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2; 120430519Ssam vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1; 120530519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1; 120630519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 120730519Ssam vd->vd_mdcb.mdcb_status = 0; 120830519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 120930519Ssam if (!vdpoll(vm, 60)) 121030519Ssam printf(" during probe\n"); 121130519Ssam if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0) 121230519Ssam break; 121324004Ssam } 121430519Ssam if (p >= &vdst[NVDST]) { 121530519Ssam printf("dk%d: unknown drive type\n", vi->ui_unit); 121630519Ssam return (0); 121730519Ssam } 1218*30573Skarels for (i = 0; i < 8; i++) { 121930519Ssam lp->d_partitions[i].p_offset = p->parts[i].off; 122030519Ssam lp->d_partitions[i].p_size = p->parts[i].size; 122130519Ssam } 1222*30573Skarels lp->d_npartitions = 8; 122330519Ssam lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 122430519Ssam lp->d_rpm = 3600; 122530519Ssam lp->d_secsize = 512; 122630519Ssam bcopy(p->name, lp->d_typename, 4); 122730519Ssam return (1); 122824004Ssam } 122930519Ssam #endif COMPAT_42 123024004Ssam #endif 1231