1*30601Skarels /* vd.c 1.17 87/03/10 */ 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 35*30601Skarels #define VDMAXIO (VDMAXPAGES * 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 struct mdcb vd_mdcb; /* master command block */ 5930519Ssam u_long vd_mdcbphys; /* physical address of vd_mdcb */ 6030519Ssam struct dcb vd_dcb; /* i/o command block */ 6130519Ssam u_long vd_dcbphys; /* physical address of vd_dcb */ 62*30601Skarels struct vb_buf vd_rbuf; /* vba resources */ 6330519Ssam } vdsoftc[NVD]; 6430519Ssam 6530519Ssam /* 6625675Ssam * Per-drive state. 6725675Ssam */ 6830519Ssam struct dksoftc { 6930519Ssam u_short dk_state; /* open fsm */ 7030519Ssam u_short dk_openpart; /* units open on this drive */ 7130519Ssam u_int dk_curcyl; /* last selected cylinder */ 7230519Ssam struct dcb dk_dcb; /* seek command block */ 7330519Ssam u_long dk_dcbphys; /* physical address of dk_dcb */ 7430519Ssam } dksoftc[NDK]; 7524004Ssam 7624004Ssam /* 7730519Ssam * Drive states. Used during steps of open/initialization. 7830519Ssam * States < OPEN (> 0) are transient, during an open operation. 7930519Ssam * OPENRAW is used for unabeled disks, to allow format operations. 8025675Ssam */ 8130519Ssam #define CLOSED 0 /* disk is closed */ 8230519Ssam #define WANTOPEN 1 /* open requested, not started */ 8330519Ssam #define WANTOPENRAW 2 /* open requested, no label */ 8430519Ssam #define RDLABEL 3 /* reading pack label */ 8530519Ssam #define OPEN 4 /* intialized and ready */ 8630519Ssam #define OPENRAW 5 /* open, no label */ 8724004Ssam 8830519Ssam struct buf rdkbuf[NDK]; /* raw i/o buffer headers */ 8930519Ssam struct buf dkutab[NDK]; /* i/o queue headers */ 9030519Ssam struct disklabel dklabel[NDK]; /* pack labels */ 9124004Ssam 9230519Ssam #define b_cylin b_resid 9330574Skarels #define b_track b_error /* used for seek commands */ 9430574Skarels #define b_seekf b_forw /* second queue on um_tab */ 9530574Skarels #define b_seekl b_back /* second queue on um_tab */ 9630519Ssam 9730519Ssam int vdwstart, vdwatch(); 9830519Ssam 9924004Ssam /* 10025675Ssam * See if the controller is really there; if so, initialize it. 10125675Ssam */ 10225857Ssam vdprobe(reg, vm) 10325857Ssam caddr_t reg; 10425857Ssam struct vba_ctlr *vm; 10525675Ssam { 10625857Ssam register br, cvec; /* must be r12, r11 */ 10730519Ssam register struct vddevice *vdaddr = (struct vddevice *)reg; 10830519Ssam struct vdsoftc *vd; 10930573Skarels int s; 11025857Ssam 11130370Skarels #ifdef lint 11230370Skarels br = 0; cvec = br; br = cvec; 11330370Skarels vdintr(0); 11430370Skarels #endif 11525857Ssam if (badaddr((caddr_t)reg, 2)) 11625675Ssam return (0); 11730519Ssam vd = &vdsoftc[vm->um_ctlr]; 11830519Ssam vdaddr->vdreset = 0xffffffff; 11925675Ssam DELAY(1000000); 12030519Ssam if (vdaddr->vdreset != (unsigned)0xffffffff) { 12130519Ssam vd->vd_type = VDTYPE_VDDC; 12230519Ssam vd->vd_flags &= ~VD_DOSEEKS; 12325675Ssam DELAY(1000000); 12425675Ssam } else { 12530519Ssam vd->vd_type = VDTYPE_SMDE; 12630519Ssam vd->vd_flags |= VD_DOSEEKS; 12730519Ssam vdaddr->vdrstclr = 0; 12825675Ssam DELAY(3000000); 12930519Ssam vdaddr->vdcsr = 0; 13030519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 13130519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 13230519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 13330519Ssam vdaddr->vdtcf_data = AM_ENPDA; 13430519Ssam vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS | 13529921Skarels XMD_32BIT | BSZ_16WRD | 13625925Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 13725675Ssam } 13830519Ssam vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb); 13930519Ssam vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb); 14030519Ssam vm->um_addr = reg; /* XXX */ 14130573Skarels s = spl7(); 14230519Ssam if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { 14330519Ssam printf("vd%d: %s cmd failed\n", vm->um_ctlr, 14430519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 14530573Skarels splx(s); 14630519Ssam return (0); 14730519Ssam } 14830573Skarels splx(s); 14925925Ssam /* 15025950Ssam * Allocate page tables and i/o buffer. 15125925Ssam */ 152*30601Skarels vbainit(&vd->vd_rbuf, VDMAXIO, 153*30601Skarels vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT); 15425857Ssam br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */ 15530519Ssam return (sizeof (struct vddevice)); 15625675Ssam } 15724004Ssam 15824004Ssam /* 15930519Ssam * See if a drive is really there. 16030519Ssam * 16130519Ssam * Can't read pack label here as various data structures 16230519Ssam * aren't setup for doing a read in a straightforward 16330519Ssam * manner. Instead just probe for the drive and leave 16430519Ssam * the pack label stuff to the attach routine. 16525675Ssam */ 16625675Ssam vdslave(vi, addr) 16725675Ssam register struct vba_device *vi; 16830519Ssam struct vddevice *vdaddr; 16925675Ssam { 17030519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 17130519Ssam struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 17224004Ssam 17330519Ssam if ((vd->vd_flags&VD_INIT) == 0) { 17425925Ssam printf("vd%d: %s controller\n", vi->ui_ctlr, 17530519Ssam vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE"); 17630519Ssam vd->vd_flags |= VD_INIT; 17725675Ssam } 17830519Ssam 17925675Ssam /* 18030519Ssam * Initialize label enough to do a reset on 18130519Ssam * the drive. The remainder of the default 18230519Ssam * label values will be filled in in vdinit 18330519Ssam * at attach time. 18425675Ssam */ 18530519Ssam lp->d_secsize = DEV_BSIZE / 2; /* XXX */ 186*30601Skarels if (vi->ui_ctlr) 187*30601Skarels lp->d_nsectors = 48; 188*30601Skarels else 18930519Ssam lp->d_nsectors = 32; 19030519Ssam lp->d_ntracks = 24; 19130519Ssam lp->d_ncylinders = 711; 19230519Ssam lp->d_secpercyl = 32*24; 19330519Ssam return (vdreset_drive(vi)); 19424004Ssam } 19524004Ssam 19630519Ssam vdattach(vi) 19730519Ssam register struct vba_device *vi; 19824004Ssam { 19930519Ssam register int unit = vi->ui_unit; 20030519Ssam register struct dksoftc *dk = &dksoftc[unit]; 20130519Ssam register struct disklabel *lp; 20225675Ssam 20330519Ssam /* 20430519Ssam * Initialize invariant portion of 20530519Ssam * dcb used for overlapped seeks. 20630519Ssam */ 20730519Ssam dk->dk_dcb.opcode = VDOP_SEEK; 20830519Ssam dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA; 20930519Ssam dk->dk_dcb.devselect = vi->ui_slave; 21030519Ssam dk->dk_dcb.trailcnt = sizeof (trseek) / sizeof (long); 21130519Ssam dk->dk_dcb.trail.sktrail.skaddr.sector = 0; 21230519Ssam dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb); 213*30601Skarels /* 214*30601Skarels * Try to initialize device and read pack label. 215*30601Skarels */ 216*30601Skarels if (vdinit(vdminor(unit, 0), 0) != 0) { 217*30601Skarels printf(": unknown drive type"); 218*30601Skarels return; 219*30601Skarels } 22030519Ssam lp = &dklabel[unit]; 22130519Ssam printf(": %s <ntrak %d, ncyl %d, nsec %d>", 22230519Ssam lp->d_typename, lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors); 22330519Ssam /* 22430519Ssam * (60 / rpm) / (sectors per track * (bytes per sector / 2)) 22530519Ssam */ 22630519Ssam if (vi->ui_dk >= 0) 22730519Ssam dk_mspw[vi->ui_dk] = 120.0 / 22830519Ssam (lp->d_rpm * lp->d_nsectors * lp->d_secsize); 22930519Ssam #ifdef notyet 23030573Skarels addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp); 23130519Ssam #endif 23224004Ssam } 23324004Ssam 23430519Ssam /*ARGSUSED*/ 23530519Ssam vdopen(dev, flags) 23630519Ssam dev_t dev; 23730519Ssam int flags; 23824004Ssam { 23930519Ssam register unit = vdunit(dev); 24030519Ssam register struct disklabel *lp; 24130519Ssam register struct dksoftc *dk; 24230519Ssam register struct partition *pp; 24330519Ssam struct vba_device *vi; 24430519Ssam int s, error, part = vdpart(dev); 24530519Ssam daddr_t start, end; 24624004Ssam 24730519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 24830519Ssam return (ENXIO); 24930519Ssam lp = &dklabel[unit]; 25030519Ssam dk = &dksoftc[unit]; 25130519Ssam 25230519Ssam s = spl7(); 25330519Ssam while (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 25430519Ssam dk->dk_state != CLOSED) 25530519Ssam sleep((caddr_t)dk, PZERO+1); 25630519Ssam splx(s); 25730519Ssam if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 25830519Ssam if (error = vdinit(dev, flags)) 25930519Ssam return (error); 26030573Skarels 26130573Skarels if (vdwstart == 0) { 26230573Skarels timeout(vdwatch, (caddr_t)0, hz); 26330573Skarels vdwstart++; 26430573Skarels } 26530519Ssam /* 26630519Ssam * Warn if a partion is opened 26730519Ssam * that overlaps another partition which is open 26830519Ssam * unless one is the "raw" partition (whole disk). 26930519Ssam */ 27030519Ssam #define RAWPART 2 /* 'c' partition */ /* XXX */ 27130519Ssam if ((dk->dk_openpart & (1 << part)) == 0 && 27230519Ssam part != RAWPART) { 27330519Ssam pp = &lp->d_partitions[part]; 27430519Ssam start = pp->p_offset; 27530519Ssam end = pp->p_offset + pp->p_size; 27630519Ssam for (pp = lp->d_partitions; 27730519Ssam pp < &lp->d_partitions[lp->d_npartitions]; pp++) { 27830519Ssam if (pp->p_offset + pp->p_size <= start || 27930519Ssam pp->p_offset >= end) 28030519Ssam continue; 28130519Ssam if (pp - lp->d_partitions == RAWPART) 28230519Ssam continue; 28330519Ssam if (dk->dk_openpart & (1 << (pp - lp->d_partitions))) 28430519Ssam log(LOG_WARNING, 28530519Ssam "dk%d%c: overlaps open partition (%c)\n", 28630519Ssam unit, part + 'a', 28730519Ssam pp - lp->d_partitions + 'a'); 28830519Ssam } 28924004Ssam } 29030519Ssam if (part >= lp->d_npartitions) 29130519Ssam return (ENXIO); 29230519Ssam dk->dk_openpart |= 1 << part; 29330519Ssam return (0); 29425675Ssam } 29524004Ssam 29630519Ssam vdclose(dev, flags) 29730519Ssam dev_t dev; 29830519Ssam int flags; 29924004Ssam { 30030519Ssam register int unit = vdunit(dev); 30130519Ssam register struct dksoftc *dk = &dksoftc[unit]; 302*30601Skarels int part = vdpart(dev); 30324004Ssam 30430519Ssam /* 30530519Ssam * Should wait for i/o to complete on this partition 30630519Ssam * even if others are open, but wait for work on blkflush(). 30730519Ssam */ 30830519Ssam if (dk->dk_openpart == 0) { 30930573Skarels int s = spl7(); 31030573Skarels while (dkutab[unit].b_actf) 31130573Skarels sleep((caddr_t)dk, PZERO-1); 31230519Ssam splx(s); 31330519Ssam dk->dk_state = CLOSED; 31424004Ssam } 31525675Ssam } 31624004Ssam 317*30601Skarels /* 318*30601Skarels * Read pack label. 319*30601Skarels */ 32030519Ssam vdinit(dev, flags) 32130519Ssam dev_t dev; 32230519Ssam int flags; 32325675Ssam { 32430519Ssam register struct buf *bp = NULL; 32530519Ssam register struct disklabel *lp; 32630519Ssam register struct dksoftc *dk; 32730519Ssam struct vba_device *vi; 32830519Ssam struct disklabel *dlp; 32930519Ssam int unit = vdunit(dev), error = 0; 330*30601Skarels char *msg = "no disk label"; 33130519Ssam extern int cold; 33225675Ssam 33330519Ssam dk = &dksoftc[unit]; 33430519Ssam if (flags & O_NDELAY) { 33530519Ssam dk->dk_state = OPENRAW; 33630519Ssam goto done; 33730519Ssam } 33830519Ssam 33930519Ssam /* 34030519Ssam * Initialize portion of the label 34130519Ssam * not set up in the slave routine. 34230519Ssam */ 34330519Ssam dk->dk_state = RDLABEL; 34430519Ssam lp = &dklabel[unit]; 34530519Ssam lp->d_secperunit = 0x1fffffff; 34630519Ssam lp->d_npartitions = 1; 34730519Ssam lp->d_partitions[0].p_size = 0x1fffffff; 34830519Ssam lp->d_partitions[0].p_offset = 0; 34930519Ssam 35030519Ssam bp = geteblk(DEV_BSIZE); /* max sector size */ 35130519Ssam bp->b_dev = dev; 35230519Ssam bp->b_blkno = LABELSECTOR; 35330519Ssam bp->b_bcount = DEV_BSIZE; 35430519Ssam bp->b_flags = B_BUSY | B_READ; 35530519Ssam bp->b_cylin = LABELSECTOR / lp->d_secpercyl; 35630519Ssam vdstrategy(bp); 35730519Ssam biowait(bp); 35830519Ssam if (bp->b_flags & B_ERROR) { 35930519Ssam error = u.u_error; /* XXX */ 36030519Ssam u.u_error = 0; 36130519Ssam dk->dk_state = CLOSED; 36230519Ssam goto done; 36330519Ssam } 36430519Ssam vi = vddinfo[unit]; 36530519Ssam dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET); 36630519Ssam if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC && 36730519Ssam dkcksum(dlp) == 0) { 36830519Ssam *lp = *dlp; 36930519Ssam /* 37030519Ssam * Now that we have the label, configure 37130519Ssam * the correct drive parameters. 37230519Ssam */ 37330519Ssam if (!vdreset_drive(vi)) 37430519Ssam dk->dk_state = CLOSED; 37530519Ssam else 37630519Ssam dk->dk_state = OPEN; 37725675Ssam } else { 378*30601Skarels if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC) 379*30601Skarels msg = "disk label corrupted"; 38030519Ssam if (cold) 381*30601Skarels printf(": %s", msg); 38230519Ssam else 383*30601Skarels log(LOG_ERR, "dk%d: %s\n", vi->ui_unit, msg); 384*30601Skarels printf("data %x %x %x, magic %x\n", bp->b_un.b_words[0], bp->b_un.b_words[1], bp->b_un.b_words[2], dlp->d_magic); 38530519Ssam #ifdef COMPAT_42 38630519Ssam if (!vdmaptype(vi, lp)) { 38730519Ssam error = ENXIO; 38830519Ssam dk->dk_state = CLOSED; 38930519Ssam } else 39030519Ssam dk->dk_state = OPEN; 39130519Ssam #else 39230519Ssam dk->dk_state = OPENRAW; 39330519Ssam #endif 39425675Ssam } 39530519Ssam done: 39630519Ssam if (bp) { 39730519Ssam bp->b_flags = B_INVAL | B_AGE; 39830519Ssam brelse(bp); 39930519Ssam } 40030519Ssam wakeup((caddr_t)dk); 40130519Ssam return (error); 40224004Ssam } 40324004Ssam 40425675Ssam /*ARGSUSED*/ 40530519Ssam vddgo(vm) 40630519Ssam struct vba_device *vm; 40724004Ssam { 40824004Ssam 40924004Ssam } 41024004Ssam 41124004Ssam vdstrategy(bp) 41225675Ssam register struct buf *bp; 41324004Ssam { 41430519Ssam register struct vba_device *vi; 41530519Ssam register struct disklabel *lp; 41630519Ssam register struct dksoftc *dk; 41730519Ssam register int unit; 41830573Skarels register daddr_t sn; 41930519Ssam struct buf *dp; 42030573Skarels daddr_t sz, maxsz; 42130519Ssam int part, s; 42224004Ssam 42330519Ssam unit = vdunit(bp->b_dev); 42430519Ssam if (unit > NDK) { 42529954Skarels bp->b_error = ENXIO; 42625675Ssam goto bad; 42729954Skarels } 42830519Ssam vi = vddinfo[unit]; 42930519Ssam lp = &dklabel[unit]; 43030519Ssam if (vi == 0 || vi->ui_alive == 0) { 43130519Ssam bp->b_error = ENXIO; 43230519Ssam goto bad; 43330519Ssam } 434*30601Skarels sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize; 43530519Ssam dk = &dksoftc[unit]; 43630519Ssam if (dk->dk_state < OPEN) 43730519Ssam goto q; 43830519Ssam part = vdpart(bp->b_dev); 43930519Ssam if ((dk->dk_openpart & (1 << part)) == 0) { 44030519Ssam bp->b_error = ENODEV; 44130519Ssam goto bad; 44230519Ssam } 44330519Ssam maxsz = lp->d_partitions[part].p_size; 44430573Skarels sn = bp->b_blkno; 44530519Ssam if (sn < 0 || sn + sz > maxsz) { 44630519Ssam if (sn == maxsz) { 44729954Skarels bp->b_resid = bp->b_bcount; 44829954Skarels goto done; 44929954Skarels } 45030573Skarels sz = maxsz - bp->b_blkno; 45130573Skarels if (sz <= 0) { 45230573Skarels bp->b_error = EINVAL; 45330573Skarels goto bad; 45430573Skarels } 45530573Skarels bp->b_bcount = sz * lp->d_secsize; 45625675Ssam } 45730519Ssam bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl; 45830519Ssam q: 45925675Ssam s = spl7(); 46030519Ssam dp = &dkutab[vi->ui_unit]; 46130519Ssam disksort(dp, bp); 46230519Ssam if (!dp->b_active) { 46330519Ssam (void) vdustart(vi); 46430573Skarels if (!vi->ui_mi->um_tab.b_active) 46530519Ssam vdstart(vi->ui_mi); 46624004Ssam } 46730519Ssam splx(s); 46824004Ssam return; 46925675Ssam bad: 47029954Skarels bp->b_flags |= B_ERROR; 47129954Skarels done: 47230519Ssam biodone(bp); 47330519Ssam return; 47424004Ssam } 47524004Ssam 47630519Ssam vdustart(vi) 47730519Ssam register struct vba_device *vi; 47824004Ssam { 47930519Ssam register struct buf *bp, *dp; 48030519Ssam register struct vba_ctlr *vm; 48130519Ssam register int unit = vi->ui_unit; 48230519Ssam register struct dksoftc *dk; 48330519Ssam register struct vdsoftc *vd; 48430519Ssam struct disklabel *lp; 48524004Ssam 48630519Ssam dp = &dkutab[unit]; 48730519Ssam /* 48830519Ssam * If queue empty, nothing to do. 48930519Ssam */ 49030519Ssam if ((bp = dp->b_actf) == NULL) 49130519Ssam return; 49230519Ssam /* 49330574Skarels * If drive is off-cylinder and controller supports seeks, 49430574Skarels * place drive on seek queue for controller. 49530574Skarels * Otherwise, place on transfer queue. 49630519Ssam */ 49730519Ssam vd = &vdsoftc[vi->ui_ctlr]; 49830519Ssam dk = &dksoftc[unit]; 49930574Skarels vm = vi->ui_mi; 50030519Ssam if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) { 50130519Ssam lp = &dklabel[unit]; 50230574Skarels bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors; 50330574Skarels if (vm->um_tab.b_seekf == NULL) 50430574Skarels vm->um_tab.b_seekf = dp; 50530574Skarels else 50630574Skarels vm->um_tab.b_seekl->b_forw = dp; 50730574Skarels vm->um_tab.b_seekl = dp; 50830574Skarels } else { 50930574Skarels if (vm->um_tab.b_actf == NULL) 51030574Skarels vm->um_tab.b_actf = dp; 51130574Skarels else 51230574Skarels vm->um_tab.b_actl->b_forw = dp; 51330574Skarels vm->um_tab.b_actl = dp; 51430519Ssam } 51530573Skarels dp->b_forw = NULL; 51630573Skarels dp->b_active++; 51725675Ssam } 51825675Ssam 51925675Ssam /* 52030519Ssam * Start next transfer on a controller. 52130574Skarels * There are two queues of drives, the first on-cylinder 52230574Skarels * and the second off-cylinder from their next transfers. 52330574Skarels * Perform the first transfer for the first drive on the on-cylinder 52430574Skarels * queue, if any, otherwise the first transfer for the first drive 52530574Skarels * on the second queue. Initiate seeks on remaining drives on the 52630574Skarels * off-cylinder queue, then move them all to the on-cylinder queue. 52725675Ssam */ 52830519Ssam vdstart(vm) 52930519Ssam register struct vba_ctlr *vm; 53025675Ssam { 53125675Ssam register struct buf *bp; 53230519Ssam register struct vba_device *vi; 53330519Ssam register struct vdsoftc *vd; 53430519Ssam register struct dksoftc *dk; 53530519Ssam register struct disklabel *lp; 53630519Ssam register int slave; 53730519Ssam register struct dcb **dcbp; 53830519Ssam struct mdcb *mdcb; 53930519Ssam struct buf *dp; 54030519Ssam int sn, tn; 54125675Ssam 54230519Ssam loop: 54330519Ssam /* 54430519Ssam * Pull a request off the controller queue. 54530519Ssam */ 54630574Skarels if ((dp = vm->um_tab.b_actf) == NULL && 54730574Skarels (dp = vm->um_tab.b_seekf) == NULL) 54830519Ssam return; 54930519Ssam if ((bp = dp->b_actf) == NULL) { 550*30601Skarels if (dp == vm->um_tab.b_actf) 551*30601Skarels vm->um_tab.b_actf = dp->b_forw; 552*30601Skarels else 553*30601Skarels vm->um_tab.b_seekf = dp->b_forw; 55430519Ssam goto loop; 55530519Ssam } 55625675Ssam 55724004Ssam /* 55830519Ssam * Mark controller busy, and determine 55930519Ssam * destination of this request. 56024004Ssam */ 56130519Ssam vm->um_tab.b_active++; 56230519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 56330519Ssam dk = &dksoftc[vi->ui_unit]; 56430573Skarels sn = bp->b_blkno; 56530519Ssam lp = &dklabel[vi->ui_unit]; 56630519Ssam sn %= lp->d_secpercyl; 56730519Ssam tn = sn / lp->d_nsectors; 56830519Ssam sn %= lp->d_nsectors; 56930519Ssam 57030519Ssam /* 57130519Ssam * Construct dcb for read/write command. 57230519Ssam */ 57330519Ssam vd = &vdsoftc[vm->um_ctlr]; 57430519Ssam slave = vi->ui_slave; 57530519Ssam vd->vd_dcb.opcode = (bp->b_flags & B_READ) ? VDOP_RD : VDOP_WD; 57630519Ssam vd->vd_dcb.intflg = DCBINT_DONE; 57730519Ssam vd->vd_dcb.devselect = slave; 57830519Ssam vd->vd_dcb.operrsta = 0; 57930519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 58030519Ssam vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long); 581*30601Skarels vd->vd_dcb.trail.rwtrail.memadr = 582*30601Skarels vbasetup(bp, &vd->vd_rbuf, lp->d_secsize); 58330519Ssam vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1; 58430519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin; 58530519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 58630519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 58730574Skarels dk->dk_curcyl = bp->b_cylin; 58830574Skarels bp->b_track = 0; /* init overloaded field */ 58930574Skarels if (vi->ui_dk >= 0) { 59030574Skarels dk_busy |= 1<<vi->ui_dk; 59130574Skarels dk_xfer[vi->ui_dk]++; 59230574Skarels dk_wds[vi->ui_dk] += bp->b_bcount>>6; 59330574Skarels } 59430519Ssam 59530519Ssam /* 59630519Ssam * Look for any seeks to be performed on other drives on this 59730519Ssam * controller. If overlapped seeks exist, insert seek commands 59830519Ssam * on the controller's command queue before the transfer. 59930519Ssam */ 60030519Ssam dcbp = &vd->vd_mdcb.mdcb_head; 60130519Ssam 60230574Skarels if (dp == vm->um_tab.b_seekf) 60330574Skarels dp = dp->b_forw; 60430574Skarels else 60530574Skarels dp = vm->um_tab.b_seekf; 60630574Skarels for (; dp != NULL; dp = dp->b_forw) { 60730574Skarels if ((bp = dp->b_actf) == NULL) 60830574Skarels continue; 60930574Skarels vi = vddinfo[vdunit(bp->b_dev)]; 61030574Skarels dk = &dksoftc[vi->ui_unit]; 61130519Ssam dk->dk_curcyl = bp->b_cylin; 61230574Skarels if (vi->ui_dk >= 0) 61330574Skarels dk_seek[vi->ui_dk]++; 61430574Skarels dk->dk_dcb.operrsta = 0; 61530574Skarels dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin; 61630574Skarels #ifdef notdef 61730574Skarels dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_daddr>>8; 61830574Skarels dk->dk_dcb.trail.sktrail.skaddr.sector = 61930574Skarels bp->b_daddr & 0xff; 62030574Skarels #else 62130574Skarels dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track; 62230574Skarels #endif 62330574Skarels *dcbp = (struct dcb *)dk->dk_dcbphys; 62430574Skarels dcbp = &dk->dk_dcb.nxtdcb; 62524004Ssam } 62630519Ssam *dcbp = (struct dcb *)vd->vd_dcbphys; 62730574Skarels if (vm->um_tab.b_actf) 62830574Skarels vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf; 62930574Skarels else 63030574Skarels vm->um_tab.b_actf = vm->um_tab.b_seekf; 631*30601Skarels if (vm->um_tab.b_seekf) 632*30601Skarels vm->um_tab.b_actl = vm->um_tab.b_seekl; 63330574Skarels vm->um_tab.b_seekf = 0; 63424004Ssam 63530519Ssam /* 63630519Ssam * Initiate operation. 63730519Ssam */ 63830519Ssam vd->vd_mdcb.mdcb_status = 0; 63930519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 64024004Ssam } 64124004Ssam 64230519Ssam #define DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE) 64324004Ssam /* 64424004Ssam * Handle a disk interrupt. 64524004Ssam */ 64625675Ssam vdintr(ctlr) 64730519Ssam register ctlr; 64824004Ssam { 64930519Ssam register struct buf *bp, *dp; 65030519Ssam register struct vba_ctlr *vm = vdminfo[ctlr]; 65130519Ssam register struct vba_device *vi; 65230519Ssam register struct vdsoftc *vd = &vdsoftc[ctlr]; 65330519Ssam register status; 654*30601Skarels int ecode; 65530573Skarels struct dksoftc *dk; 65624004Ssam 65730519Ssam vd->vd_wticks = 0; 65830519Ssam if (!vm->um_tab.b_active) { 65925675Ssam printf("vd%d: stray interrupt\n", ctlr); 66024004Ssam return; 66124004Ssam } 66225675Ssam /* 66330519Ssam * Get device and block structures, and a pointer 66430519Ssam * to the vba_device for the drive. 66525675Ssam */ 66630519Ssam dp = vm->um_tab.b_actf; 66730519Ssam bp = dp->b_actf; 66830519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 66930574Skarels if (vi->ui_dk >= 0) 67030574Skarels dk_busy &= ~(1<<vi->ui_dk); 67130519Ssam /* 67230519Ssam * Check for and process errors on 67330519Ssam * either the drive or the controller. 67430519Ssam */ 67530519Ssam uncache(&vd->vd_dcb.operrsta); 67630519Ssam status = vd->vd_dcb.operrsta; 67730519Ssam if (status & VDERR_HARD) { 678*30601Skarels if (vd->vd_type == VDTYPE_SMDE) { 679*30601Skarels uncache(&vd->vd_dcb.err_code); 680*30601Skarels ecode = vd->vd_dcb.err_code; 681*30601Skarels } 68230519Ssam if (status & DCBS_WPT) { 68330519Ssam /* 68430519Ssam * Give up on write locked devices immediately. 68530519Ssam */ 68630573Skarels printf("dk%d: write locked\n", vi->ui_unit); 68730519Ssam bp->b_flags |= B_ERROR; 68830573Skarels } else if (status & VDERR_RETRY) { 68930519Ssam if (status & VDERR_DRIVE) { 69030519Ssam if (!vdreset_drive(vi)) 69130519Ssam vi->ui_alive = 0; 69230519Ssam } else if (status & VDERR_CTLR) 69330519Ssam vdreset_ctlr(vm); 69430519Ssam /* 69530519Ssam * Retry transfer once, unless reset failed. 69630519Ssam */ 69730519Ssam if (!vi->ui_alive || bp->b_errcnt++ >= 2) 69830519Ssam goto hard; 69930519Ssam vm->um_tab.b_active = 0; /* force retry */ 70030519Ssam } else { 70130519Ssam hard: 70230519Ssam bp->b_flags |= B_ERROR; 70330519Ssam /* NEED TO ADJUST b_blkno to failed sector */ 70430519Ssam harderr(bp, "dk"); 70530519Ssam printf("status %x (%b)", status, 70630519Ssam status &~ DONTCARE, VDERRBITS); 707*30601Skarels if (vd->vd_type == VDTYPE_SMDE) 708*30601Skarels printf(" ecode %x", ecode); 70930519Ssam printf("\n"); 71030519Ssam } 71130519Ssam } else if (status & DCBS_SOFT) 71230519Ssam vdsofterr(vd, bp, &vd->vd_dcb); 71330519Ssam if (vm->um_tab.b_active) { 71430519Ssam vm->um_tab.b_active = 0; 71530519Ssam vm->um_tab.b_errcnt = 0; 71630519Ssam vm->um_tab.b_actf = dp->b_forw; 71730519Ssam dp->b_active = 0; 71830519Ssam dp->b_errcnt = 0; 71930519Ssam dp->b_actf = bp->av_forw; 72030519Ssam bp->b_resid = 0; 721*30601Skarels vbadone(bp, &vd->vd_rbuf); 72230519Ssam biodone(bp); 72330370Skarels /* 72430519Ssam * If this unit has more work to do, 72530519Ssam * then start it up right away. 72630370Skarels */ 72730519Ssam if (dp->b_actf) 72830519Ssam vdustart(vi); 72930573Skarels else if ((dk = &dksoftc[vi->ui_unit])->dk_openpart == 0) 73030573Skarels wakeup((caddr_t)dk); 73124004Ssam } 73225675Ssam /* 73330519Ssam * If there are devices ready to 73430519Ssam * transfer, start the controller. 73525675Ssam */ 736*30601Skarels if (vm->um_tab.b_actf || vm->um_tab.b_seekf) 73730519Ssam vdstart(vm); 73824004Ssam } 73924004Ssam 74030519Ssam vdsofterr(vd, bp, dcb) 74130519Ssam struct vdsoftc *vd; 74225675Ssam register struct buf *bp; 74330519Ssam register struct dcb *dcb; 74425675Ssam { 74530519Ssam int unit = vdunit(bp->b_dev), status = dcb->operrsta; 74630519Ssam char part = 'a' + vdpart(bp->b_dev); 74725675Ssam 748*30601Skarels if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) { 74930519Ssam if (vd->vd_type == VDTYPE_SMDE) 75030519Ssam uncache(&dcb->err_code); 75130519Ssam log(LOG_WARNING, "dk%d%c: soft error sn%d status %b ecode %x\n", 75230519Ssam unit, part, bp->b_blkno, status, VDERRBITS, dcb->err_code); 75330519Ssam } else 75430370Skarels log(LOG_WARNING, "dk%d%c: soft ecc sn%d\n", 75530370Skarels unit, part, bp->b_blkno); 75625675Ssam } 75725675Ssam 75824004Ssam vdread(dev, uio) 75925675Ssam dev_t dev; 76025675Ssam struct uio *uio; 76124004Ssam { 76230519Ssam register int unit = vdunit(dev); 76324004Ssam 76429564Ssam if (unit >= NDK) 76525675Ssam return (ENXIO); 76630519Ssam return (physio(vdstrategy, &rdkbuf[unit], dev, B_READ, minphys, uio)); 76724004Ssam } 76824004Ssam 76924004Ssam vdwrite(dev, uio) 77025675Ssam dev_t dev; 77125675Ssam struct uio *uio; 77224004Ssam { 77330519Ssam register int unit = vdunit(dev); 77424004Ssam 77529564Ssam if (unit >= NDK) 77625675Ssam return (ENXIO); 77730519Ssam return (physio(vdstrategy, &rdkbuf[unit], dev, B_WRITE, minphys, uio)); 77824004Ssam } 77924004Ssam 78030519Ssam vdioctl(dev, cmd, data, flag) 78125675Ssam dev_t dev; 78230519Ssam int cmd; 78330519Ssam caddr_t data; 78430519Ssam int flag; 78524004Ssam { 78630519Ssam int unit = vdunit(dev); 78730519Ssam register struct disklabel *lp = &dklabel[unit]; 78830519Ssam int error = 0; 78924004Ssam 79030519Ssam switch (cmd) { 79130519Ssam 79230519Ssam case DIOCGDINFO: 79330519Ssam *(struct disklabel *)data = *lp; 79430519Ssam break; 79530519Ssam 79630573Skarels case DIOCGPART: 79730573Skarels ((struct partinfo *)data)->disklab = lp; 79830573Skarels ((struct partinfo *)data)->part = 79930573Skarels &lp->d_partitions[vdpart(dev)]; 80030519Ssam break; 80130519Ssam 80230519Ssam case DIOCSDINFO: 80330519Ssam if ((flag & FWRITE) == 0) 80430519Ssam error = EBADF; 80530519Ssam else 80630519Ssam *lp = *(struct disklabel *)data; 80730519Ssam break; 80830519Ssam 80930519Ssam case DIOCWDINFO: { 81030519Ssam struct buf *bp; 81130519Ssam struct disklabel *dlp; 81230519Ssam 81330519Ssam if ((flag & FWRITE) == 0) { 81430519Ssam error = EBADF; 81530519Ssam break; 81630519Ssam } 81730519Ssam *lp = *(struct disklabel *)data; 81830519Ssam bp = geteblk(lp->d_secsize); 81930519Ssam bp->b_dev = dev; 82030519Ssam bp->b_blkno = LABELSECTOR; 82130519Ssam bp->b_bcount = lp->d_secsize; 82230519Ssam bp->b_flags = B_READ; 82330519Ssam dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET); 82430519Ssam vdstrategy(bp); 82530519Ssam biowait(bp); 82630519Ssam if (bp->b_flags & B_ERROR) { 82730519Ssam error = u.u_error; /* XXX */ 82830519Ssam u.u_error = 0; 82930519Ssam goto bad; 83030519Ssam } 83130519Ssam *dlp = *lp; 83230519Ssam bp->b_flags = B_WRITE; 83330519Ssam vdstrategy(bp); 83430519Ssam biowait(bp); 83530519Ssam if (bp->b_flags & B_ERROR) { 83630519Ssam error = u.u_error; /* XXX */ 83730519Ssam u.u_error = 0; 83830519Ssam } 83930519Ssam bad: 84030519Ssam brelse(bp); 84130519Ssam break; 84225675Ssam } 84330519Ssam 84430519Ssam default: 84530519Ssam error = ENOTTY; 84630519Ssam break; 84724004Ssam } 84825675Ssam return (0); 84924004Ssam } 85024004Ssam 85125675Ssam /* 85230519Ssam * Watch for lost interrupts. 85325675Ssam */ 85430519Ssam vdwatch() 85530519Ssam { 85630519Ssam register struct vdsoftc *vd; 85730519Ssam register struct vba_ctlr *vm; 85825675Ssam register int ctlr, unit; 85930519Ssam 86030519Ssam timeout(vdwatch, (caddr_t)0, hz); 86130519Ssam for (ctlr = 0; ctlr < NVD; ctlr++) { 86230519Ssam vm = vdminfo[ctlr]; 86330519Ssam if (vm == 0 || vm->um_alive == 0) 86430519Ssam continue; 86530519Ssam vd = &vdsoftc[ctlr]; 866*30601Skarels if (vm->um_tab.b_active && vd->vd_wticks++ >= 20) { 86730519Ssam vd->vd_wticks = 0; 86830519Ssam printf("vd%d: lost interrupt\n", ctlr); 86930519Ssam /* abort pending dcb's and restart controller */ 87030519Ssam } 87130519Ssam } 87230519Ssam } 87330519Ssam 87430519Ssam #define DBSIZE 64 /* controller limit with 1K sectors */ 87530519Ssam /* 87630519Ssam * Crash dump. 87730519Ssam */ 87830519Ssam vddump(dev) 87930519Ssam dev_t dev; 88024004Ssam { 88130519Ssam register struct vba_device *vi; 88230519Ssam register struct vba_ctlr *vm; 88330519Ssam register struct disklabel *lp; 88430519Ssam register struct vdsoftc *vd; 88530519Ssam struct dksoftc *dk; 88630519Ssam int part, unit, num; 887*30601Skarels u_long start; 88824004Ssam 88930519Ssam start = 0; 89030519Ssam unit = vdunit(dev); 89130519Ssam if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 89230519Ssam return (ENXIO); 89330519Ssam dk = &dksoftc[unit]; 89430519Ssam if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 89530519Ssam return (ENXIO); 89630519Ssam lp = &dklabel[unit]; 89730519Ssam part = vdpart(dev); 89830519Ssam if (part >= lp->d_npartitions) 89930519Ssam return (ENXIO); 90030519Ssam vm = vdminfo[vi->ui_ctlr]; 90130519Ssam vdreset_ctlr(vm); 90230519Ssam if (dumplo < 0) 90330519Ssam return (EINVAL); 90430519Ssam /* 90530573Skarels * Dumplo and maxfree are in pages. 90630519Ssam */ 90730519Ssam num = maxfree * (NBPG / lp->d_secsize); 90830573Skarels dumplo *= NBPG / lp->d_secsize; 90930519Ssam if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size) 91030519Ssam num = lp->d_partitions[vdpart(dev)].p_size - dumplo; 91130519Ssam vd = &vdsoftc[vm->um_ctlr]; 91230519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 91330519Ssam vd->vd_dcb.opcode = VDOP_WD; 91430519Ssam vd->vd_dcb.devselect = vi->ui_slave; 91530519Ssam vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long); 91630519Ssam while (num > 0) { 91730519Ssam int nsec, cn, sn, tn; 91830519Ssam 91930519Ssam nsec = MIN(num, DBSIZE); 920*30601Skarels sn = dumplo + start / lp->d_secsize; 92130519Ssam cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) / 92230519Ssam lp->d_secpercyl; 92330519Ssam sn %= lp->d_secpercyl; 92430519Ssam tn = sn / lp->d_nsectors; 92530519Ssam sn %= lp->d_nsectors; 92630519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 92730519Ssam vd->vd_dcb.trail.rwtrail.memadr = start; 92830519Ssam vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1; 92930519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = cn; 93030519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 93130519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 93230519Ssam vd->vd_dcb.operrsta = 0; 93330519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 93430519Ssam if (!vdpoll(vm, 5)) { 93530519Ssam printf(" during dump\n"); 93630519Ssam return (EIO); 93730519Ssam } 93830519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 93930519Ssam printf("dk%d: hard error, status=%b\n", unit, 94030519Ssam vd->vd_dcb.operrsta, VDERRBITS); 94130519Ssam return (EIO); 94230519Ssam } 94330519Ssam start += nsec * lp->d_secsize; 94430519Ssam num -= nsec; 94525675Ssam } 94630519Ssam return (0); 94724004Ssam } 94824004Ssam 94924004Ssam vdsize(dev) 95025675Ssam dev_t dev; 95124004Ssam { 95230519Ssam register int unit = vdunit(dev); 95330519Ssam register struct dksoftc *dk; 95430519Ssam struct vba_device *vi; 95530519Ssam struct disklabel *lp; 95624004Ssam 95730519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 || 95830519Ssam (dk = &dksoftc[unit])->dk_state != OPEN) 95925675Ssam return (-1); 96030519Ssam lp = &dklabel[unit]; 96130573Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size); 96224004Ssam } 96324004Ssam 96425675Ssam /* 96525675Ssam * Perform a controller reset. 96625675Ssam */ 96730519Ssam vdreset_ctlr(vm) 96830519Ssam register struct vba_ctlr *vm; 96924004Ssam { 97030519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 97130519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 97230519Ssam register int unit; 97330519Ssam struct vba_device *vi; 97425675Ssam 97530519Ssam VDRESET(vdaddr, vd->vd_type); 97630519Ssam if (vd->vd_type == VDTYPE_SMDE) { 97730519Ssam vdaddr->vdcsr = 0; 97830519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 97930519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 98030519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 98130519Ssam vdaddr->vdtcf_data = AM_ENPDA; 98230519Ssam vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD | 98325675Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 98425675Ssam } 98530519Ssam if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { 98630519Ssam printf("%s cmd failed\n", 98730519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 98830370Skarels return; 98925675Ssam } 99030519Ssam for (unit = 0; unit < NDK; unit++) 99130519Ssam if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive) 99230519Ssam (void) vdreset_drive(vi); 99330519Ssam } 99430519Ssam 99530519Ssam vdreset_drive(vi) 99630519Ssam register struct vba_device *vi; 99730519Ssam { 99830519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 99930519Ssam struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; 100030519Ssam struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 100130519Ssam struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 100230519Ssam 100330519Ssam top: 100430519Ssam vd->vd_dcb.opcode = VDOP_CONFIG; /* command */ 100530519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 100630519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 100730519Ssam vd->vd_dcb.operrsta = 0; 100830519Ssam vd->vd_dcb.devselect = vi->ui_slave; 100930519Ssam vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders; 101030519Ssam vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks; 101130519Ssam if (vd->vd_type == VDTYPE_SMDE) { 101230519Ssam vd->vd_dcb.trailcnt = sizeof (treset) / sizeof (long); 101330519Ssam vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors; 1014*30601Skarels vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack; 101530519Ssam vd->vd_dcb.trail.rstrail.recovery = 0x18f; 101630519Ssam } else 101730519Ssam vd->vd_dcb.trailcnt = 2; /* XXX */ 101830519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 101930519Ssam vd->vd_mdcb.mdcb_status = 0; 102030519Ssam VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type); 102130519Ssam if (!vdpoll(vm, 5)) { 102230519Ssam printf(" during config\n"); 102330519Ssam return (0); 102425675Ssam } 102530519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 102630519Ssam if (vd->vd_type == VDTYPE_SMDE && 102730519Ssam (vdaddr->vdstatus[vi->ui_slave]&STA_US) == 0) 102830519Ssam return (0); 102930519Ssam if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) 103030519Ssam printf("dk%d: config error\n", vi->ui_unit); 103130519Ssam else if ((vd->vd_flags&VD_STARTED) == 0) { 103230519Ssam int started; 103330519Ssam 103430519Ssam printf("vd%d: starting drives, wait ... ", vm->um_ctlr); 103530519Ssam vd->vd_flags |= VD_STARTED; 103630519Ssam started = (vdcmd(vm, VDOP_START, 10) == 1); 103730519Ssam DELAY(62000000); 103830519Ssam printf("\n"); 103930519Ssam if (started) 104030519Ssam goto top; 104130519Ssam } 104230519Ssam return (0); 104330519Ssam } 104430519Ssam return (1); 104525675Ssam } 104624004Ssam 104725675Ssam /* 104830519Ssam * Perform a command w/o trailer. 104925675Ssam */ 105030519Ssam vdcmd(vm, cmd, t) 105130519Ssam register struct vba_ctlr *vm; 105225675Ssam { 105330519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 105425675Ssam 105530519Ssam vd->vd_dcb.opcode = cmd; /* command */ 105630519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 105730519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 105830519Ssam vd->vd_dcb.operrsta = 0; 105930519Ssam vd->vd_dcb.devselect = 0; 106030519Ssam vd->vd_dcb.trailcnt = 0; 106130519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 106230519Ssam vd->vd_mdcb.mdcb_status = 0; 106330519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 106430519Ssam if (!vdpoll(vm, t)) { 106530519Ssam printf(" during init\n"); 106630370Skarels return (0); 106730370Skarels } 106830519Ssam return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0); 106925675Ssam } 107025675Ssam 107125925Ssam /* 107230519Ssam * Poll controller until operation 107330519Ssam * completes or timeout expires. 107425925Ssam */ 107530519Ssam vdpoll(vm, t) 107630519Ssam register struct vba_ctlr *vm; 107725925Ssam register int t; 107825925Ssam { 107930519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 108030519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 108125925Ssam 108225925Ssam t *= 1000; 108330370Skarels for (;;) { 108430519Ssam uncache(&vd->vd_dcb.operrsta); 108530519Ssam if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT)) 108630370Skarels break; 108725925Ssam if (--t <= 0) { 108830519Ssam printf("vd%d: controller timeout", vm->um_ctlr); 108930519Ssam VDABORT(vdaddr, vd->vd_type); 109025925Ssam DELAY(30000); 109125925Ssam return (0); 109225925Ssam } 109330370Skarels DELAY(1000); 109425925Ssam } 109530519Ssam if (vd->vd_type == VDTYPE_SMDE) { 109630519Ssam do { 109725925Ssam DELAY(50); 109830519Ssam uncache(&vdaddr->vdcsr); 109930519Ssam } while (vdaddr->vdcsr & CS_GO); 110025925Ssam DELAY(300); 110125925Ssam } 110225925Ssam DELAY(200); 110330519Ssam uncache(&vd->vd_dcb.operrsta); 110425925Ssam return (1); 110525925Ssam } 110625925Ssam 110730519Ssam #ifdef COMPAT_42 110830519Ssam struct vdst { 110930519Ssam int nsec; /* sectors/track */ 111030519Ssam int ntrack; /* tracks/cylinder */ 111130519Ssam int ncyl; /* cylinders */ 111230519Ssam char *name; /* type name */ 111330519Ssam struct { 111430519Ssam int off; /* partition offset in sectors */ 111530519Ssam int size; /* partition size in sectors */ 111630573Skarels } parts[8]; 111730519Ssam } vdst[] = { 111830573Skarels { 48, 24, 711, "xsd", 111930573Skarels {0, 30528}, /* a cyl 0 - 52 */ 112030573Skarels {30528, 30528}, /* b cyl 53 - 105 */ 112130573Skarels {61056, 345600}, /* c cyl 106 - 705 */ 112230573Skarels {118656, 288000}, /* d cyl 206 - 705 */ 112330573Skarels {176256, 230400}, /* e cyl 306 - 705 */ 112430573Skarels {233856, 172800}, /* f cyl 406 - 705 */ 112530573Skarels {291456, 115200}, /* g cyl 506 - 705 */ 112630573Skarels {349056, 57600} /* h cyl 606 - 705 */ 112730573Skarels }, 112830573Skarels { 44, 20, 842, "egl", 1129*30601Skarels {0, 52800}, /* egl0a cyl 0 - 59 */ 1130*30601Skarels {52800, 66000}, /* egl0b cyl 60 - 134 */ 1131*30601Skarels {118800, 617760}, /* egl0c cyl 135 - 836 */ 1132*30601Skarels {736560, 5280}, /* egl0d cyl 837 - 842 */ 1133*30601Skarels {0, 736560}, /* egl0e cyl 0 - 836 */ 1134*30601Skarels {0, 741840}, /* egl0f cyl 0 - 842 */ 1135*30601Skarels {118800, 310640}, /* egl0g cyl 135 - 487 */ 1136*30601Skarels {429440, 307120} /* egl0h cyl 488 - 836 */ 113730573Skarels }, 113830573Skarels { 64, 10, 823, "fuj", 113930573Skarels {0, 19200}, /* fuj0a cyl 0 - 59 */ 114030573Skarels {19200, 24000}, /* fuj0b cyl 60 - 134 */ 114130573Skarels {43200, 218560}, /* fuj0c cyl 135 - 817 */ 114230573Skarels {79680, 182080}, /* fuj0d cyl 249 - 817 */ 114330573Skarels {116160, 145600}, /* fuj0e cyl 363 - 817 */ 114430573Skarels {152640, 109120}, /* fuj0f cyl 477 - 817 */ 114530573Skarels {189120, 72640}, /* fuj0g cyl 591 - 817 */ 114630573Skarels {225600, 36160} /* fug0h cyl 705 - 817 */ 114730573Skarels }, 114830573Skarels { 32, 24, 711, "xfd", 114930573Skarels { 0, 20352 }, /* a cyl 0 - 52 */ 115030573Skarels { 20352, 20352 }, /* b cyl 53 - 105 */ 115130573Skarels { 40704, 230400 }, /* c cyl 106 - 705 */ 115230573Skarels { 0, 40704 }, /* d cyl 709 - 710 (a & b) */ 115330573Skarels { 0, 271104 }, /* e cyl 0 - 705 */ 115430573Skarels { 20352, 250752 }, /* f cyl 53 - 705 (b & c) */ 115530573Skarels { 40704, 115200 }, /* g cyl 106 - 405 (1/2 of c) */ 115630573Skarels { 155904,115200 } /* h cyl 406 - 705 (1/2 of c) */ 115730573Skarels }, 115830573Skarels { 32, 19, 823, "smd", 115930573Skarels {0, 20064}, /* a cyl 0-65 */ 116030573Skarels {20064, 13680}, /* b cyl 66-110 */ 116130573Skarels {33744, 214928}, /* c cyl 111-817 */ 116230573Skarels {69616, 179056}, /* d cyl 229 - 817 */ 116330573Skarels {105488, 143184}, /* e cyl 347 - 817 */ 116430573Skarels {141360, 107312}, /* f cyl 465 - 817 */ 116530573Skarels {177232, 71440}, /* g cyl 583 - 817 */ 116630573Skarels {213104, 35568} /* h cyl 701 - 817 */ 116730573Skarels }, 116830573Skarels { 32, 10, 823, "fsd", 116930573Skarels {0, 9600}, /* a cyl 0 - 59 */ 117030573Skarels {9600, 12000}, /* b cyl 60 - 134 */ 117130573Skarels {21600, 109280}, /* c cyl 135 - 817 */ 117230573Skarels {39840, 91040}, /* d cyl 249 - 817 */ 117330573Skarels {58080, 72800}, /* e cyl 363 - 817 */ 117430573Skarels {76320, 54560}, /* f cyl 477 - 817 */ 117530573Skarels {94560, 36320}, /* g cyl 591 - 817 */ 117630573Skarels {112800, 18080} /* h cyl 705 - 817 */ 117730573Skarels } 117830519Ssam }; 117930519Ssam #define NVDST (sizeof (vdst) / sizeof (vdst[0])) 118030519Ssam 118125675Ssam /* 118230519Ssam * Construct a label for an unlabeled pack. We 118330519Ssam * deduce the drive type by reading from the last 118430519Ssam * track on successively smaller drives until we 118530519Ssam * don't get an error. 118625675Ssam */ 118730519Ssam vdmaptype(vi, lp) 118830519Ssam register struct vba_device *vi; 118930519Ssam register struct disklabel *lp; 119025675Ssam { 119130519Ssam register struct vdsoftc *vd; 119230519Ssam register struct vdst *p; 119330519Ssam struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; 119430519Ssam int i; 119525675Ssam 119630519Ssam vd = &vdsoftc[vi->ui_ctlr]; 119730519Ssam for (p = vdst; p < &vdst[NVDST]; p++) { 119830519Ssam if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32) 119930519Ssam continue; 120030519Ssam lp->d_nsectors = p->nsec; 120130519Ssam lp->d_ntracks = p->ntrack; 120230519Ssam lp->d_ncylinders = p->ncyl; 120330519Ssam if (!vdreset_drive(vi)) 120430519Ssam return (0); 120530519Ssam vd->vd_dcb.opcode = VDOP_RD; 120630519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 120730519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 120830519Ssam vd->vd_dcb.devselect = vi->ui_slave; 120930519Ssam vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long); 1210*30601Skarels vd->vd_dcb.trail.rwtrail.memadr = 1211*30601Skarels vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf); 121230519Ssam vd->vd_dcb.trail.rwtrail.wcount = 512 / sizeof(short); 121330519Ssam vd->vd_dcb.operrsta = 0; 121430519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2; 121530519Ssam vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1; 121630519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1; 121730519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 121830519Ssam vd->vd_mdcb.mdcb_status = 0; 121930519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 122030519Ssam if (!vdpoll(vm, 60)) 122130519Ssam printf(" during probe\n"); 122230519Ssam if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0) 122330519Ssam break; 122424004Ssam } 122530519Ssam if (p >= &vdst[NVDST]) { 122630519Ssam printf("dk%d: unknown drive type\n", vi->ui_unit); 122730519Ssam return (0); 122830519Ssam } 122930573Skarels for (i = 0; i < 8; i++) { 123030519Ssam lp->d_partitions[i].p_offset = p->parts[i].off; 123130519Ssam lp->d_partitions[i].p_size = p->parts[i].size; 123230519Ssam } 123330573Skarels lp->d_npartitions = 8; 123430519Ssam lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 123530519Ssam lp->d_rpm = 3600; 123630519Ssam lp->d_secsize = 512; 123730519Ssam bcopy(p->name, lp->d_typename, 4); 123830519Ssam return (1); 123924004Ssam } 124030519Ssam #endif COMPAT_42 124124004Ssam #endif 1242