1*32211Skarels /* vd.c 1.20 87/09/17 */ 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" 2530756Skarels #include "stat.h" 2624004Ssam 2729951Skarels #include "../tahoe/cpu.h" 2829951Skarels #include "../tahoe/mtpr.h" 2929951Skarels #include "../tahoe/pte.h" 3029951Skarels 3125675Ssam #include "../tahoevba/vbavar.h" 3225928Ssam #include "../tahoevba/vdreg.h" 3324004Ssam 34*32211Skarels #ifndef COMPAT_42 3530519Ssam #define COMPAT_42 36*32211Skarels #endif 3730519Ssam 3830519Ssam #define vdunit(dev) (minor(dev) >> 3) 3930519Ssam #define vdpart(dev) (minor(dev) & 0x07) 4030519Ssam #define vdminor(unit,part) (((unit) << 3) | (part)) 4124004Ssam 4224004Ssam struct vba_ctlr *vdminfo[NVD]; 4329564Ssam struct vba_device *vddinfo[NDK]; 4430756Skarels int vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy(); 4530519Ssam long vdaddr[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 }; 4625675Ssam struct vba_driver vddriver = 4730519Ssam { vdprobe, vdslave, vdattach, vddgo, vdaddr, "dk", vddinfo, "vd", vdminfo }; 4824004Ssam 4924004Ssam /* 5030519Ssam * Per-controller state. 5130519Ssam */ 5230519Ssam struct vdsoftc { 5330519Ssam u_short vd_flags; 5430519Ssam #define VD_INIT 0x1 /* controller initialized */ 5530519Ssam #define VD_STARTED 0x2 /* start command issued */ 5630519Ssam #define VD_DOSEEKS 0x4 /* should overlap seeks */ 5730756Skarels #define VD_SCATGATH 0x8 /* can do scatter-gather commands (correctly) */ 5830519Ssam u_short vd_type; /* controller type */ 5930519Ssam u_short vd_wticks; /* timeout */ 6030519Ssam struct mdcb vd_mdcb; /* master command block */ 6130519Ssam u_long vd_mdcbphys; /* physical address of vd_mdcb */ 6230519Ssam struct dcb vd_dcb; /* i/o command block */ 6330519Ssam u_long vd_dcbphys; /* physical address of vd_dcb */ 6430601Skarels struct vb_buf vd_rbuf; /* vba resources */ 6530519Ssam } vdsoftc[NVD]; 6630519Ssam 6730519Ssam /* 6825675Ssam * Per-drive state. 6925675Ssam */ 7030519Ssam struct dksoftc { 7130519Ssam u_short dk_state; /* open fsm */ 7230756Skarels u_short dk_copenpart; /* character units open on this drive */ 7330756Skarels u_short dk_bopenpart; /* block units open on this drive */ 7430756Skarels u_short dk_openpart; /* all units open on this drive */ 7530756Skarels #ifndef SECSIZE 7630756Skarels u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */ 7730756Skarels #endif SECSIZE 7830519Ssam u_int dk_curcyl; /* last selected cylinder */ 7930756Skarels struct skdcb dk_dcb; /* seek command block */ 8030519Ssam u_long dk_dcbphys; /* physical address of dk_dcb */ 8130519Ssam } dksoftc[NDK]; 8224004Ssam 8324004Ssam /* 8430519Ssam * Drive states. Used during steps of open/initialization. 8530519Ssam * States < OPEN (> 0) are transient, during an open operation. 8630519Ssam * OPENRAW is used for unabeled disks, to allow format operations. 8725675Ssam */ 8830519Ssam #define CLOSED 0 /* disk is closed */ 8930519Ssam #define WANTOPEN 1 /* open requested, not started */ 9030519Ssam #define WANTOPENRAW 2 /* open requested, no label */ 9130519Ssam #define RDLABEL 3 /* reading pack label */ 9230519Ssam #define OPEN 4 /* intialized and ready */ 9330519Ssam #define OPENRAW 5 /* open, no label */ 9424004Ssam 9530519Ssam struct buf rdkbuf[NDK]; /* raw i/o buffer headers */ 9630519Ssam struct buf dkutab[NDK]; /* i/o queue headers */ 9730519Ssam struct disklabel dklabel[NDK]; /* pack labels */ 9824004Ssam 9930519Ssam #define b_cylin b_resid 10030574Skarels #define b_track b_error /* used for seek commands */ 10130574Skarels #define b_seekf b_forw /* second queue on um_tab */ 10230574Skarels #define b_seekl b_back /* second queue on um_tab */ 10330519Ssam 10430519Ssam int vdwstart, vdwatch(); 10530519Ssam 10624004Ssam /* 10725675Ssam * See if the controller is really there; if so, initialize it. 10825675Ssam */ 10925857Ssam vdprobe(reg, vm) 11025857Ssam caddr_t reg; 11125857Ssam struct vba_ctlr *vm; 11225675Ssam { 11325857Ssam register br, cvec; /* must be r12, r11 */ 11430519Ssam register struct vddevice *vdaddr = (struct vddevice *)reg; 11530519Ssam struct vdsoftc *vd; 11630573Skarels int s; 11725857Ssam 11830370Skarels #ifdef lint 11930370Skarels br = 0; cvec = br; br = cvec; 12030370Skarels vdintr(0); 12130370Skarels #endif 12225857Ssam if (badaddr((caddr_t)reg, 2)) 12325675Ssam return (0); 12430519Ssam vd = &vdsoftc[vm->um_ctlr]; 12530519Ssam vdaddr->vdreset = 0xffffffff; 12625675Ssam DELAY(1000000); 12730519Ssam if (vdaddr->vdreset != (unsigned)0xffffffff) { 12830519Ssam vd->vd_type = VDTYPE_VDDC; 12930519Ssam vd->vd_flags &= ~VD_DOSEEKS; 13025675Ssam DELAY(1000000); 13125675Ssam } else { 13230519Ssam vd->vd_type = VDTYPE_SMDE; 13330519Ssam vd->vd_flags |= VD_DOSEEKS; 13430519Ssam vdaddr->vdrstclr = 0; 13525675Ssam DELAY(3000000); 13630519Ssam vdaddr->vdcsr = 0; 13730519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 13830519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 13930519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 14030519Ssam vdaddr->vdtcf_data = AM_ENPDA; 14130519Ssam vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS | 14229921Skarels XMD_32BIT | BSZ_16WRD | 14325925Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 14425675Ssam } 14530519Ssam vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb); 14630519Ssam vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb); 14730519Ssam vm->um_addr = reg; /* XXX */ 14830573Skarels s = spl7(); 14930519Ssam if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { 15030519Ssam printf("vd%d: %s cmd failed\n", vm->um_ctlr, 15130519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 15230573Skarels splx(s); 15330519Ssam return (0); 15430519Ssam } 15530756Skarels if (vd->vd_type == VDTYPE_SMDE) { 15630756Skarels vd->vd_dcb.trail.idtrail.date = 0; 15730756Skarels if (vdcmd(vm, VDOP_IDENT, 10)) { 15830756Skarels uncache(&vd->vd_dcb.trail.idtrail.date); 15930756Skarels if (vd->vd_dcb.trail.idtrail.date != 0) 16030756Skarels vd->vd_flags |= VD_SCATGATH; 16130756Skarels } 16230756Skarels } 16330573Skarels splx(s); 16425925Ssam /* 16525950Ssam * Allocate page tables and i/o buffer. 16625925Ssam */ 167*32211Skarels if (vbainit(&vd->vd_rbuf, MAXPHYS, 168*32211Skarels vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT) == 0) { 169*32211Skarels printf("vd%d: vbainit failed\n", vm->um_ctlr); 170*32211Skarels return (0); 171*32211Skarels } 17225857Ssam br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */ 17330519Ssam return (sizeof (struct vddevice)); 17425675Ssam } 17524004Ssam 17624004Ssam /* 17730519Ssam * See if a drive is really there. 17830519Ssam * 17930519Ssam * Can't read pack label here as various data structures 18030519Ssam * aren't setup for doing a read in a straightforward 18130519Ssam * manner. Instead just probe for the drive and leave 18230519Ssam * the pack label stuff to the attach routine. 18325675Ssam */ 18425675Ssam vdslave(vi, addr) 18525675Ssam register struct vba_device *vi; 18630519Ssam struct vddevice *vdaddr; 18725675Ssam { 18830519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 189*32211Skarels register struct dksoftc *dk = &dksoftc[vi->ui_unit]; 19030519Ssam struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 19124004Ssam 19230519Ssam if ((vd->vd_flags&VD_INIT) == 0) { 19330756Skarels printf("vd%d: %s controller%s\n", vi->ui_ctlr, 19430756Skarels vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE", 19530756Skarels (vd->vd_flags & VD_SCATGATH) ? " with scatter-gather" : ""); 19630519Ssam vd->vd_flags |= VD_INIT; 19725675Ssam } 19830519Ssam 19925675Ssam /* 20030519Ssam * Initialize label enough to do a reset on 20130519Ssam * the drive. The remainder of the default 20230519Ssam * label values will be filled in in vdinit 20330519Ssam * at attach time. 20425675Ssam */ 205*32211Skarels if (vd->vd_type == VDTYPE_SMDE) 206*32211Skarels lp->d_secsize = VD_MAXSECSIZE; 207*32211Skarels else 208*32211Skarels lp->d_secsize = VDDC_SECSIZE; 209*32211Skarels lp->d_nsectors = 72; /* only used on smd-e */ 21030519Ssam lp->d_ntracks = 24; 211*32211Skarels lp->d_ncylinders = 842; 212*32211Skarels lp->d_secpercyl = 72*24; 21324004Ssam 21430519Ssam /* 21530519Ssam * Initialize invariant portion of 21630519Ssam * dcb used for overlapped seeks. 21730519Ssam */ 21830519Ssam dk->dk_dcb.opcode = VDOP_SEEK; 21930519Ssam dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA; 22030519Ssam dk->dk_dcb.devselect = vi->ui_slave; 22130756Skarels dk->dk_dcb.trailcnt = sizeof (struct trseek) / sizeof (long); 22230519Ssam dk->dk_dcb.trail.sktrail.skaddr.sector = 0; 22330519Ssam dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb); 224*32211Skarels #ifndef SECSIZE 225*32211Skarels vd_setsecsize(dk, lp); 226*32211Skarels #endif 227*32211Skarels return (vdreset_drive(vi)); 228*32211Skarels } 229*32211Skarels 230*32211Skarels vdattach(vi) 231*32211Skarels register struct vba_device *vi; 232*32211Skarels { 233*32211Skarels register int unit = vi->ui_unit; 234*32211Skarels register struct disklabel *lp = &dklabel[unit]; 235*32211Skarels 23630601Skarels /* 23730601Skarels * Try to initialize device and read pack label. 23830601Skarels */ 23930601Skarels if (vdinit(vdminor(unit, 0), 0) != 0) { 24030601Skarels printf(": unknown drive type"); 24130601Skarels return; 24230601Skarels } 243*32211Skarels if (dksoftc[unit].dk_state == OPEN) 244*32211Skarels printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>", 245*32211Skarels lp->d_typename, lp->d_secsize, 246*32211Skarels lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors); 24730519Ssam /* 24830519Ssam * (60 / rpm) / (sectors per track * (bytes per sector / 2)) 24930519Ssam */ 25030519Ssam if (vi->ui_dk >= 0) 25130519Ssam dk_mspw[vi->ui_dk] = 120.0 / 25230519Ssam (lp->d_rpm * lp->d_nsectors * lp->d_secsize); 25330519Ssam #ifdef notyet 25430573Skarels addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp); 25530519Ssam #endif 25624004Ssam } 25724004Ssam 25830756Skarels vdopen(dev, flags, fmt) 25930519Ssam dev_t dev; 26030756Skarels int flags, fmt; 26124004Ssam { 26230519Ssam register unit = vdunit(dev); 26330519Ssam register struct disklabel *lp; 26430519Ssam register struct dksoftc *dk; 26530519Ssam register struct partition *pp; 26630519Ssam struct vba_device *vi; 26730756Skarels int s, error, part = vdpart(dev), mask = 1 << part; 26830519Ssam daddr_t start, end; 26924004Ssam 27030519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 27130519Ssam return (ENXIO); 27230519Ssam lp = &dklabel[unit]; 27330519Ssam dk = &dksoftc[unit]; 27430519Ssam 27530519Ssam s = spl7(); 27630519Ssam while (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 27730519Ssam dk->dk_state != CLOSED) 27830519Ssam sleep((caddr_t)dk, PZERO+1); 27930519Ssam splx(s); 28030519Ssam if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 28130519Ssam if (error = vdinit(dev, flags)) 28230519Ssam return (error); 28330573Skarels 28430573Skarels if (vdwstart == 0) { 28530573Skarels timeout(vdwatch, (caddr_t)0, hz); 28630573Skarels vdwstart++; 28730573Skarels } 28830519Ssam /* 28930519Ssam * Warn if a partion is opened 29030519Ssam * that overlaps another partition which is open 29130519Ssam * unless one is the "raw" partition (whole disk). 29230519Ssam */ 293*32211Skarels #define RAWPART 8 /* 'x' partition */ /* XXX */ 29430519Ssam if ((dk->dk_openpart & (1 << part)) == 0 && 29530519Ssam part != RAWPART) { 29630519Ssam pp = &lp->d_partitions[part]; 29730519Ssam start = pp->p_offset; 29830519Ssam end = pp->p_offset + pp->p_size; 29930519Ssam for (pp = lp->d_partitions; 30030519Ssam pp < &lp->d_partitions[lp->d_npartitions]; pp++) { 30130519Ssam if (pp->p_offset + pp->p_size <= start || 30230519Ssam pp->p_offset >= end) 30330519Ssam continue; 30430519Ssam if (pp - lp->d_partitions == RAWPART) 30530519Ssam continue; 30630519Ssam if (dk->dk_openpart & (1 << (pp - lp->d_partitions))) 30730519Ssam log(LOG_WARNING, 30830519Ssam "dk%d%c: overlaps open partition (%c)\n", 30930519Ssam unit, part + 'a', 31030519Ssam pp - lp->d_partitions + 'a'); 31130519Ssam } 31224004Ssam } 31330519Ssam if (part >= lp->d_npartitions) 31430519Ssam return (ENXIO); 31530756Skarels dk->dk_openpart |= mask; 31630756Skarels switch (fmt) { 31730756Skarels case S_IFCHR: 31830756Skarels dk->dk_copenpart |= mask; 31930756Skarels break; 32030756Skarels case S_IFBLK: 32130756Skarels dk->dk_bopenpart |= mask; 32230756Skarels break; 32330756Skarels } 32430519Ssam return (0); 32525675Ssam } 32624004Ssam 32730756Skarels vdclose(dev, flags, fmt) 32830519Ssam dev_t dev; 32930756Skarels int flags, fmt; 33024004Ssam { 33130519Ssam register int unit = vdunit(dev); 33230519Ssam register struct dksoftc *dk = &dksoftc[unit]; 33330756Skarels int part = vdpart(dev), mask = 1 << part; 33424004Ssam 33530756Skarels switch (fmt) { 33630756Skarels case S_IFCHR: 33730756Skarels dk->dk_copenpart &= ~mask; 33830756Skarels break; 33930756Skarels case S_IFBLK: 34030756Skarels dk->dk_bopenpart &= ~mask; 34130756Skarels break; 34230756Skarels } 34330756Skarels if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0) 34430756Skarels dk->dk_openpart &= ~mask; 34530519Ssam /* 34630519Ssam * Should wait for i/o to complete on this partition 34730519Ssam * even if others are open, but wait for work on blkflush(). 34830519Ssam */ 34930519Ssam if (dk->dk_openpart == 0) { 35030573Skarels int s = spl7(); 35130573Skarels while (dkutab[unit].b_actf) 35230573Skarels sleep((caddr_t)dk, PZERO-1); 35330519Ssam splx(s); 35430519Ssam dk->dk_state = CLOSED; 35524004Ssam } 35630756Skarels return (0); 35725675Ssam } 35824004Ssam 35930519Ssam vdinit(dev, flags) 36030519Ssam dev_t dev; 36130519Ssam int flags; 36225675Ssam { 36330519Ssam register struct disklabel *lp; 36430519Ssam register struct dksoftc *dk; 36530519Ssam struct vba_device *vi; 36630519Ssam int unit = vdunit(dev), error = 0; 36730756Skarels char *msg, *readdisklabel(); 36830519Ssam extern int cold; 36925675Ssam 37030519Ssam dk = &dksoftc[unit]; 37130519Ssam if (flags & O_NDELAY) { 37230519Ssam dk->dk_state = OPENRAW; 37330756Skarels return; 37430519Ssam } 37530519Ssam dk->dk_state = RDLABEL; 37630519Ssam lp = &dklabel[unit]; 37730519Ssam vi = vddinfo[unit]; 37830756Skarels if (msg = readdisklabel(dev, vdstrategy, lp)) { 37930519Ssam if (cold) 38030601Skarels printf(": %s", msg); 38130519Ssam else 382*32211Skarels log(LOG_ERR, "dk%d: %s\n", unit, msg); 38330519Ssam #ifdef COMPAT_42 38430756Skarels if (!vdmaptype(vi, lp)) 38530756Skarels dk->dk_state = OPENRAW; 38630756Skarels else 38730519Ssam dk->dk_state = OPEN; 38830519Ssam #else 38930519Ssam dk->dk_state = OPENRAW; 39030519Ssam #endif 39130756Skarels } else { 39230756Skarels /* 39330756Skarels * Now that we have the label, configure 39430756Skarels * the correct drive parameters. 39530756Skarels */ 396*32211Skarels if (vdreset_drive(vi)) 397*32211Skarels dk->dk_state = OPEN; 398*32211Skarels else { 39930756Skarels dk->dk_state = CLOSED; 40030756Skarels error = ENXIO; 401*32211Skarels } 40225675Ssam } 40330756Skarels #ifndef SECSIZE 404*32211Skarels vd_setsecsize(dk, lp); 405*32211Skarels #endif 40630519Ssam wakeup((caddr_t)dk); 40730519Ssam return (error); 40824004Ssam } 40924004Ssam 410*32211Skarels #ifndef SECSIZE 411*32211Skarels vd_setsecsize(dk, lp) 412*32211Skarels register struct dksoftc *dk; 413*32211Skarels register struct disklabel *lp; 414*32211Skarels { 415*32211Skarels int mul; 416*32211Skarels 417*32211Skarels /* 418*32211Skarels * Calculate scaling shift for mapping 419*32211Skarels * DEV_BSIZE blocks to drive sectors. 420*32211Skarels */ 421*32211Skarels mul = DEV_BSIZE / lp->d_secsize; 422*32211Skarels dk->dk_bshift = 0; 423*32211Skarels while ((mul >>= 1) > 0) 424*32211Skarels dk->dk_bshift++; 425*32211Skarels } 426*32211Skarels #endif SECSIZE 427*32211Skarels 42825675Ssam /*ARGSUSED*/ 42930519Ssam vddgo(vm) 43030519Ssam struct vba_device *vm; 43124004Ssam { 43224004Ssam 43324004Ssam } 43424004Ssam 43524004Ssam vdstrategy(bp) 43625675Ssam register struct buf *bp; 43724004Ssam { 43830519Ssam register struct vba_device *vi; 43930519Ssam register struct disklabel *lp; 44030519Ssam register struct dksoftc *dk; 44130519Ssam register int unit; 44230573Skarels register daddr_t sn; 44330519Ssam struct buf *dp; 44430573Skarels daddr_t sz, maxsz; 44530519Ssam int part, s; 44624004Ssam 44730519Ssam unit = vdunit(bp->b_dev); 448*32211Skarels if (unit >= NDK) { 44929954Skarels bp->b_error = ENXIO; 45025675Ssam goto bad; 45129954Skarels } 45230519Ssam vi = vddinfo[unit]; 45330519Ssam lp = &dklabel[unit]; 45430519Ssam if (vi == 0 || vi->ui_alive == 0) { 45530519Ssam bp->b_error = ENXIO; 45630519Ssam goto bad; 45730519Ssam } 45830519Ssam dk = &dksoftc[unit]; 45930519Ssam if (dk->dk_state < OPEN) 46030519Ssam goto q; 46130519Ssam part = vdpart(bp->b_dev); 46230519Ssam if ((dk->dk_openpart & (1 << part)) == 0) { 46330519Ssam bp->b_error = ENODEV; 46430519Ssam goto bad; 46530519Ssam } 466*32211Skarels sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize; 46730519Ssam maxsz = lp->d_partitions[part].p_size; 46830756Skarels #ifndef SECSIZE 46930756Skarels sn = bp->b_blkno << dk->dk_bshift; 47030756Skarels #else SECSIZE 47130573Skarels sn = bp->b_blkno; 47230756Skarels #endif SECSIZE 47330519Ssam if (sn < 0 || sn + sz > maxsz) { 47430519Ssam if (sn == maxsz) { 47529954Skarels bp->b_resid = bp->b_bcount; 47629954Skarels goto done; 47729954Skarels } 47830756Skarels sz = maxsz - sn; 47930573Skarels if (sz <= 0) { 48030573Skarels bp->b_error = EINVAL; 48130573Skarels goto bad; 48230573Skarels } 48330573Skarels bp->b_bcount = sz * lp->d_secsize; 48425675Ssam } 48530519Ssam bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl; 48630756Skarels #ifdef SECSIZE 48730756Skarels if (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0) 48830756Skarels panic("vdstrat blksize"); 48930756Skarels #endif SECSIZE 49030519Ssam q: 49125675Ssam s = spl7(); 49230519Ssam dp = &dkutab[vi->ui_unit]; 49330519Ssam disksort(dp, bp); 49430519Ssam if (!dp->b_active) { 49530519Ssam (void) vdustart(vi); 49630573Skarels if (!vi->ui_mi->um_tab.b_active) 49730519Ssam vdstart(vi->ui_mi); 49824004Ssam } 49930519Ssam splx(s); 50024004Ssam return; 50125675Ssam bad: 50229954Skarels bp->b_flags |= B_ERROR; 50329954Skarels done: 50430519Ssam biodone(bp); 50530519Ssam return; 50624004Ssam } 50724004Ssam 50830519Ssam vdustart(vi) 50930519Ssam register struct vba_device *vi; 51024004Ssam { 51130519Ssam register struct buf *bp, *dp; 51230519Ssam register struct vba_ctlr *vm; 51330519Ssam register int unit = vi->ui_unit; 51430519Ssam register struct dksoftc *dk; 51530519Ssam register struct vdsoftc *vd; 51630519Ssam struct disklabel *lp; 51724004Ssam 51830519Ssam dp = &dkutab[unit]; 51930519Ssam /* 52030519Ssam * If queue empty, nothing to do. 52130519Ssam */ 52230519Ssam if ((bp = dp->b_actf) == NULL) 52330519Ssam return; 52430519Ssam /* 52530574Skarels * If drive is off-cylinder and controller supports seeks, 52630574Skarels * place drive on seek queue for controller. 52730574Skarels * Otherwise, place on transfer queue. 52830519Ssam */ 52930519Ssam vd = &vdsoftc[vi->ui_ctlr]; 53030519Ssam dk = &dksoftc[unit]; 53130574Skarels vm = vi->ui_mi; 53230519Ssam if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) { 53330519Ssam lp = &dklabel[unit]; 53430574Skarels bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors; 53530574Skarels if (vm->um_tab.b_seekf == NULL) 53630574Skarels vm->um_tab.b_seekf = dp; 53730574Skarels else 53830574Skarels vm->um_tab.b_seekl->b_forw = dp; 53930574Skarels vm->um_tab.b_seekl = dp; 54030574Skarels } else { 54130574Skarels if (vm->um_tab.b_actf == NULL) 54230574Skarels vm->um_tab.b_actf = dp; 54330574Skarels else 54430574Skarels vm->um_tab.b_actl->b_forw = dp; 54530574Skarels vm->um_tab.b_actl = dp; 54630519Ssam } 54730573Skarels dp->b_forw = NULL; 54830573Skarels dp->b_active++; 54925675Ssam } 55025675Ssam 55125675Ssam /* 55230519Ssam * Start next transfer on a controller. 55330574Skarels * There are two queues of drives, the first on-cylinder 55430574Skarels * and the second off-cylinder from their next transfers. 55530574Skarels * Perform the first transfer for the first drive on the on-cylinder 55630574Skarels * queue, if any, otherwise the first transfer for the first drive 55730574Skarels * on the second queue. Initiate seeks on remaining drives on the 55830574Skarels * off-cylinder queue, then move them all to the on-cylinder queue. 55925675Ssam */ 56030519Ssam vdstart(vm) 56130519Ssam register struct vba_ctlr *vm; 56225675Ssam { 56325675Ssam register struct buf *bp; 56430519Ssam register struct vba_device *vi; 56530519Ssam register struct vdsoftc *vd; 56630519Ssam register struct dksoftc *dk; 56730519Ssam register struct disklabel *lp; 56830519Ssam register struct dcb **dcbp; 56930519Ssam struct mdcb *mdcb; 57030519Ssam struct buf *dp; 57130519Ssam int sn, tn; 57225675Ssam 57330519Ssam loop: 57430519Ssam /* 57530519Ssam * Pull a request off the controller queue. 57630519Ssam */ 57730574Skarels if ((dp = vm->um_tab.b_actf) == NULL && 57830574Skarels (dp = vm->um_tab.b_seekf) == NULL) 57930519Ssam return; 58030519Ssam if ((bp = dp->b_actf) == NULL) { 58130601Skarels if (dp == vm->um_tab.b_actf) 58230601Skarels vm->um_tab.b_actf = dp->b_forw; 58330601Skarels else 58430601Skarels vm->um_tab.b_seekf = dp->b_forw; 58530519Ssam goto loop; 58630519Ssam } 58725675Ssam 58824004Ssam /* 58930519Ssam * Mark controller busy, and determine 59030519Ssam * destination of this request. 59124004Ssam */ 59230519Ssam vm->um_tab.b_active++; 59330519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 59430519Ssam dk = &dksoftc[vi->ui_unit]; 59530756Skarels #ifndef SECSIZE 59630756Skarels sn = bp->b_blkno << dk->dk_bshift; 59730756Skarels #else SECSIZE 59830573Skarels sn = bp->b_blkno; 59930756Skarels #endif SECSIZE 60030519Ssam lp = &dklabel[vi->ui_unit]; 60130519Ssam sn %= lp->d_secpercyl; 60230519Ssam tn = sn / lp->d_nsectors; 60330519Ssam sn %= lp->d_nsectors; 60430519Ssam 60530519Ssam /* 60630519Ssam * Construct dcb for read/write command. 60730519Ssam */ 60830519Ssam vd = &vdsoftc[vm->um_ctlr]; 60930519Ssam vd->vd_dcb.intflg = DCBINT_DONE; 610*32211Skarels vd->vd_dcb.devselect = dk->dk_dcb.devselect; 61130519Ssam vd->vd_dcb.operrsta = 0; 61230519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 61330519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin; 61430519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 61530519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 61630574Skarels dk->dk_curcyl = bp->b_cylin; 61730574Skarels bp->b_track = 0; /* init overloaded field */ 61830756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 61930756Skarels if (vd->vd_flags & VD_SCATGATH && 62030756Skarels ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0) { 62130756Skarels vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW; 62230756Skarels vd->vd_dcb.trailcnt += vba_sgsetup(bp, &vd->vd_rbuf, 62330756Skarels &vd->vd_dcb.trail.sgtrail); 62430756Skarels } else { 62530756Skarels vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD; 62630756Skarels vd->vd_dcb.trail.rwtrail.memadr = 62730756Skarels vbasetup(bp, &vd->vd_rbuf, lp->d_secsize); 62830756Skarels vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1; 62930756Skarels } 63030574Skarels if (vi->ui_dk >= 0) { 63130574Skarels dk_busy |= 1<<vi->ui_dk; 63230574Skarels dk_xfer[vi->ui_dk]++; 63330574Skarels dk_wds[vi->ui_dk] += bp->b_bcount>>6; 63430574Skarels } 63530519Ssam 63630519Ssam /* 63730519Ssam * Look for any seeks to be performed on other drives on this 63830519Ssam * controller. If overlapped seeks exist, insert seek commands 63930519Ssam * on the controller's command queue before the transfer. 64030519Ssam */ 64130519Ssam dcbp = &vd->vd_mdcb.mdcb_head; 64230519Ssam 64330574Skarels if (dp == vm->um_tab.b_seekf) 64430574Skarels dp = dp->b_forw; 64530574Skarels else 64630574Skarels dp = vm->um_tab.b_seekf; 64730574Skarels for (; dp != NULL; dp = dp->b_forw) { 64830574Skarels if ((bp = dp->b_actf) == NULL) 64930574Skarels continue; 65030574Skarels vi = vddinfo[vdunit(bp->b_dev)]; 65130574Skarels dk = &dksoftc[vi->ui_unit]; 65230519Ssam dk->dk_curcyl = bp->b_cylin; 65330574Skarels if (vi->ui_dk >= 0) 65430574Skarels dk_seek[vi->ui_dk]++; 65530574Skarels dk->dk_dcb.operrsta = 0; 65630574Skarels dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin; 65730574Skarels dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track; 65830574Skarels *dcbp = (struct dcb *)dk->dk_dcbphys; 65930574Skarels dcbp = &dk->dk_dcb.nxtdcb; 66024004Ssam } 66130519Ssam *dcbp = (struct dcb *)vd->vd_dcbphys; 66230574Skarels if (vm->um_tab.b_actf) 66330574Skarels vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf; 66430574Skarels else 66530574Skarels vm->um_tab.b_actf = vm->um_tab.b_seekf; 66630601Skarels if (vm->um_tab.b_seekf) 66730601Skarels vm->um_tab.b_actl = vm->um_tab.b_seekl; 66830574Skarels vm->um_tab.b_seekf = 0; 66924004Ssam 67030519Ssam /* 67130519Ssam * Initiate operation. 67230519Ssam */ 67330519Ssam vd->vd_mdcb.mdcb_status = 0; 67430519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 67524004Ssam } 67624004Ssam 67730519Ssam #define DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE) 67824004Ssam /* 67924004Ssam * Handle a disk interrupt. 68024004Ssam */ 68125675Ssam vdintr(ctlr) 68230519Ssam register ctlr; 68324004Ssam { 68430519Ssam register struct buf *bp, *dp; 68530519Ssam register struct vba_ctlr *vm = vdminfo[ctlr]; 68630519Ssam register struct vba_device *vi; 68730519Ssam register struct vdsoftc *vd = &vdsoftc[ctlr]; 68830519Ssam register status; 68930601Skarels int ecode; 69030573Skarels struct dksoftc *dk; 69124004Ssam 69230519Ssam vd->vd_wticks = 0; 69330519Ssam if (!vm->um_tab.b_active) { 69425675Ssam printf("vd%d: stray interrupt\n", ctlr); 69524004Ssam return; 69624004Ssam } 69725675Ssam /* 69830519Ssam * Get device and block structures, and a pointer 69930519Ssam * to the vba_device for the drive. 70025675Ssam */ 70130519Ssam dp = vm->um_tab.b_actf; 70230519Ssam bp = dp->b_actf; 70330519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 70430574Skarels if (vi->ui_dk >= 0) 70530574Skarels dk_busy &= ~(1<<vi->ui_dk); 70630519Ssam /* 70730519Ssam * Check for and process errors on 70830519Ssam * either the drive or the controller. 70930519Ssam */ 71030519Ssam uncache(&vd->vd_dcb.operrsta); 71130519Ssam status = vd->vd_dcb.operrsta; 71230519Ssam if (status & VDERR_HARD) { 71330601Skarels if (vd->vd_type == VDTYPE_SMDE) { 71430601Skarels uncache(&vd->vd_dcb.err_code); 71530601Skarels ecode = vd->vd_dcb.err_code; 71630601Skarels } 71730519Ssam if (status & DCBS_WPT) { 71830519Ssam /* 71930519Ssam * Give up on write locked devices immediately. 72030519Ssam */ 72130573Skarels printf("dk%d: write locked\n", vi->ui_unit); 72230519Ssam bp->b_flags |= B_ERROR; 72330573Skarels } else if (status & VDERR_RETRY) { 724*32211Skarels int endline = 1; 725*32211Skarels 72630519Ssam if (status & VDERR_DRIVE) { 727*32211Skarels printf("dk%d%c: drive err %b, bn %d,", 728*32211Skarels vi->ui_unit, 'a' + vdpart(bp->b_dev), 729*32211Skarels status &~ DONTCARE, VDERRBITS, bp->b_blkno); 730*32211Skarels if (vd->vd_type == VDTYPE_SMDE) 731*32211Skarels printf(" ecode %x,", ecode); 732*32211Skarels printf(" resetting drive..."); 73330519Ssam if (!vdreset_drive(vi)) 73430519Ssam vi->ui_alive = 0; 735*32211Skarels } else if (status & VDERR_CTLR) { 736*32211Skarels printf("dk%d%c: controller err %b, bn %d,", 737*32211Skarels vi->ui_unit, 'a' + vdpart(bp->b_dev), 738*32211Skarels status &~ DONTCARE, VDERRBITS, bp->b_blkno); 739*32211Skarels if (vd->vd_type == VDTYPE_SMDE) 740*32211Skarels printf(" ecode %x,", ecode); 741*32211Skarels printf("resetting controller..."); 74230519Ssam vdreset_ctlr(vm); 743*32211Skarels } else 744*32211Skarels endline = 0; 74530519Ssam /* 74630519Ssam * Retry transfer once, unless reset failed. 74730519Ssam */ 748*32211Skarels if (!vi->ui_alive || dp->b_errcnt++ >= 2) { 749*32211Skarels if (endline) 750*32211Skarels printf("\n"); 75130519Ssam goto hard; 752*32211Skarels } 753*32211Skarels 754*32211Skarels if (endline) 755*32211Skarels printf(" retrying\n"); 75630519Ssam vm->um_tab.b_active = 0; /* force retry */ 75730519Ssam } else { 75830519Ssam hard: 75930519Ssam bp->b_flags |= B_ERROR; 76030519Ssam /* NEED TO ADJUST b_blkno to failed sector */ 76130519Ssam harderr(bp, "dk"); 76230519Ssam printf("status %x (%b)", status, 76330519Ssam status &~ DONTCARE, VDERRBITS); 76430601Skarels if (vd->vd_type == VDTYPE_SMDE) 76530601Skarels printf(" ecode %x", ecode); 76630519Ssam printf("\n"); 76730519Ssam } 76830519Ssam } else if (status & DCBS_SOFT) 76930519Ssam vdsofterr(vd, bp, &vd->vd_dcb); 77030519Ssam if (vm->um_tab.b_active) { 77130519Ssam vm->um_tab.b_active = 0; 77230519Ssam vm->um_tab.b_actf = dp->b_forw; 77330519Ssam dp->b_active = 0; 77430519Ssam dp->b_errcnt = 0; 77530519Ssam dp->b_actf = bp->av_forw; 77630519Ssam bp->b_resid = 0; 77730601Skarels vbadone(bp, &vd->vd_rbuf); 77830519Ssam biodone(bp); 77930370Skarels /* 78030519Ssam * If this unit has more work to do, 78130519Ssam * then start it up right away. 78230370Skarels */ 78330519Ssam if (dp->b_actf) 78430519Ssam vdustart(vi); 78530573Skarels else if ((dk = &dksoftc[vi->ui_unit])->dk_openpart == 0) 78630573Skarels wakeup((caddr_t)dk); 78724004Ssam } 78825675Ssam /* 78930519Ssam * If there are devices ready to 79030519Ssam * transfer, start the controller. 79125675Ssam */ 79230601Skarels if (vm->um_tab.b_actf || vm->um_tab.b_seekf) 79330519Ssam vdstart(vm); 79424004Ssam } 79524004Ssam 79630519Ssam vdsofterr(vd, bp, dcb) 79730519Ssam struct vdsoftc *vd; 79825675Ssam register struct buf *bp; 79930519Ssam register struct dcb *dcb; 80025675Ssam { 80130519Ssam int unit = vdunit(bp->b_dev), status = dcb->operrsta; 80230519Ssam char part = 'a' + vdpart(bp->b_dev); 80325675Ssam 804*32211Skarels if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) 80530519Ssam log(LOG_WARNING, "dk%d%c: soft error sn%d status %b ecode %x\n", 80630519Ssam unit, part, bp->b_blkno, status, VDERRBITS, dcb->err_code); 807*32211Skarels else 80830370Skarels log(LOG_WARNING, "dk%d%c: soft ecc sn%d\n", 80930370Skarels unit, part, bp->b_blkno); 81025675Ssam } 81125675Ssam 81224004Ssam vdread(dev, uio) 81325675Ssam dev_t dev; 81425675Ssam struct uio *uio; 81524004Ssam { 81630519Ssam register int unit = vdunit(dev); 81724004Ssam 81829564Ssam if (unit >= NDK) 81925675Ssam return (ENXIO); 82030519Ssam return (physio(vdstrategy, &rdkbuf[unit], dev, B_READ, minphys, uio)); 82124004Ssam } 82224004Ssam 82324004Ssam vdwrite(dev, uio) 82425675Ssam dev_t dev; 82525675Ssam struct uio *uio; 82624004Ssam { 82730519Ssam register int unit = vdunit(dev); 82824004Ssam 82929564Ssam if (unit >= NDK) 83025675Ssam return (ENXIO); 83130519Ssam return (physio(vdstrategy, &rdkbuf[unit], dev, B_WRITE, minphys, uio)); 83224004Ssam } 83324004Ssam 83430519Ssam vdioctl(dev, cmd, data, flag) 83525675Ssam dev_t dev; 83630519Ssam int cmd; 83730519Ssam caddr_t data; 83830519Ssam int flag; 83924004Ssam { 84030519Ssam int unit = vdunit(dev); 84130519Ssam register struct disklabel *lp = &dklabel[unit]; 84230519Ssam int error = 0; 84324004Ssam 84430519Ssam switch (cmd) { 84530519Ssam 84630519Ssam case DIOCGDINFO: 84730519Ssam *(struct disklabel *)data = *lp; 84830519Ssam break; 84930519Ssam 85030573Skarels case DIOCGPART: 85130573Skarels ((struct partinfo *)data)->disklab = lp; 85230573Skarels ((struct partinfo *)data)->part = 85330573Skarels &lp->d_partitions[vdpart(dev)]; 85430519Ssam break; 85530519Ssam 85630519Ssam case DIOCSDINFO: 85730519Ssam if ((flag & FWRITE) == 0) 85830519Ssam error = EBADF; 85930519Ssam else 86030519Ssam *lp = *(struct disklabel *)data; 86130519Ssam break; 86230519Ssam 86330519Ssam case DIOCWDINFO: { 86430519Ssam struct buf *bp; 86530519Ssam struct disklabel *dlp; 86630519Ssam 86730519Ssam if ((flag & FWRITE) == 0) { 86830519Ssam error = EBADF; 86930519Ssam break; 87030519Ssam } 87130519Ssam *lp = *(struct disklabel *)data; 87230519Ssam bp = geteblk(lp->d_secsize); 87330756Skarels bp->b_dev = makedev(major(dev), vdminor(vdunit(dev), 0)); 87430519Ssam bp->b_blkno = LABELSECTOR; 87530519Ssam bp->b_bcount = lp->d_secsize; 87630519Ssam bp->b_flags = B_READ; 87730519Ssam dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET); 87830519Ssam vdstrategy(bp); 87930519Ssam biowait(bp); 88030519Ssam if (bp->b_flags & B_ERROR) { 88130519Ssam error = u.u_error; /* XXX */ 88230519Ssam u.u_error = 0; 88330519Ssam goto bad; 88430519Ssam } 88530519Ssam *dlp = *lp; 88630519Ssam bp->b_flags = B_WRITE; 88730519Ssam vdstrategy(bp); 88830519Ssam biowait(bp); 88930519Ssam if (bp->b_flags & B_ERROR) { 89030519Ssam error = u.u_error; /* XXX */ 89130519Ssam u.u_error = 0; 89230519Ssam } 89330519Ssam bad: 89430519Ssam brelse(bp); 89530519Ssam break; 89625675Ssam } 89730519Ssam 89830519Ssam default: 89930519Ssam error = ENOTTY; 90030519Ssam break; 90124004Ssam } 90225675Ssam return (0); 90324004Ssam } 90424004Ssam 90525675Ssam /* 90630519Ssam * Watch for lost interrupts. 90725675Ssam */ 90830519Ssam vdwatch() 90930519Ssam { 91030519Ssam register struct vdsoftc *vd; 91130519Ssam register struct vba_ctlr *vm; 91225675Ssam register int ctlr, unit; 91330519Ssam 91430519Ssam timeout(vdwatch, (caddr_t)0, hz); 91530519Ssam for (ctlr = 0; ctlr < NVD; ctlr++) { 91630519Ssam vm = vdminfo[ctlr]; 91730519Ssam if (vm == 0 || vm->um_alive == 0) 91830519Ssam continue; 91930519Ssam vd = &vdsoftc[ctlr]; 92030601Skarels if (vm->um_tab.b_active && vd->vd_wticks++ >= 20) { 92130519Ssam vd->vd_wticks = 0; 92230519Ssam printf("vd%d: lost interrupt\n", ctlr); 92330519Ssam /* abort pending dcb's and restart controller */ 92430519Ssam } 92530519Ssam } 92630519Ssam } 92730519Ssam 92830519Ssam #define DBSIZE 64 /* controller limit with 1K sectors */ 92930519Ssam /* 93030519Ssam * Crash dump. 93130519Ssam */ 93230519Ssam vddump(dev) 93330519Ssam dev_t dev; 93424004Ssam { 93530519Ssam register struct vba_device *vi; 93630519Ssam register struct vba_ctlr *vm; 93730519Ssam register struct disklabel *lp; 93830519Ssam register struct vdsoftc *vd; 93930519Ssam struct dksoftc *dk; 94030519Ssam int part, unit, num; 94130601Skarels u_long start; 94224004Ssam 94330519Ssam start = 0; 94430519Ssam unit = vdunit(dev); 94530519Ssam if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 94630519Ssam return (ENXIO); 94730519Ssam dk = &dksoftc[unit]; 94830519Ssam if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 94930519Ssam return (ENXIO); 95030519Ssam lp = &dklabel[unit]; 95130519Ssam part = vdpart(dev); 95230519Ssam if (part >= lp->d_npartitions) 95330519Ssam return (ENXIO); 954*32211Skarels vm = vi->ui_mi; 95530519Ssam vdreset_ctlr(vm); 95630519Ssam if (dumplo < 0) 95730519Ssam return (EINVAL); 95830519Ssam /* 95930756Skarels * Maxfree is in pages, dumplo is in DEV_BSIZE units. 96030519Ssam */ 96130519Ssam num = maxfree * (NBPG / lp->d_secsize); 96230756Skarels dumplo *= DEV_BSIZE / lp->d_secsize; 96330519Ssam if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size) 96430519Ssam num = lp->d_partitions[vdpart(dev)].p_size - dumplo; 96530519Ssam vd = &vdsoftc[vm->um_ctlr]; 96630519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 96730519Ssam vd->vd_dcb.opcode = VDOP_WD; 968*32211Skarels vd->vd_dcb.devselect = dk->dk_dcb.devselect; 96930756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 97030519Ssam while (num > 0) { 97130519Ssam int nsec, cn, sn, tn; 97230519Ssam 97330519Ssam nsec = MIN(num, DBSIZE); 97430601Skarels sn = dumplo + start / lp->d_secsize; 97530519Ssam cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) / 97630519Ssam lp->d_secpercyl; 97730519Ssam sn %= lp->d_secpercyl; 97830519Ssam tn = sn / lp->d_nsectors; 97930519Ssam sn %= lp->d_nsectors; 98030519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 98130519Ssam vd->vd_dcb.trail.rwtrail.memadr = start; 98230519Ssam vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1; 98330519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = cn; 98430519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 98530519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 98630519Ssam vd->vd_dcb.operrsta = 0; 98730519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 98830519Ssam if (!vdpoll(vm, 5)) { 98930519Ssam printf(" during dump\n"); 99030519Ssam return (EIO); 99130519Ssam } 99230519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 99330519Ssam printf("dk%d: hard error, status=%b\n", unit, 99430519Ssam vd->vd_dcb.operrsta, VDERRBITS); 99530519Ssam return (EIO); 99630519Ssam } 99730519Ssam start += nsec * lp->d_secsize; 99830519Ssam num -= nsec; 99925675Ssam } 100030519Ssam return (0); 100124004Ssam } 100224004Ssam 100324004Ssam vdsize(dev) 100425675Ssam dev_t dev; 100524004Ssam { 100630519Ssam register int unit = vdunit(dev); 100730519Ssam register struct dksoftc *dk; 100830519Ssam struct vba_device *vi; 100930519Ssam struct disklabel *lp; 101024004Ssam 101130519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 || 101230519Ssam (dk = &dksoftc[unit])->dk_state != OPEN) 101325675Ssam return (-1); 101430519Ssam lp = &dklabel[unit]; 101530756Skarels #ifdef SECSIZE 101630573Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size); 101730756Skarels #else SECSIZE 101830756Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift); 101930756Skarels #endif SECSIZE 102024004Ssam } 102124004Ssam 102225675Ssam /* 102325675Ssam * Perform a controller reset. 102425675Ssam */ 102530519Ssam vdreset_ctlr(vm) 102630519Ssam register struct vba_ctlr *vm; 102724004Ssam { 102830519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 102930519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 103030519Ssam register int unit; 103130519Ssam struct vba_device *vi; 103225675Ssam 103330519Ssam VDRESET(vdaddr, vd->vd_type); 103430519Ssam if (vd->vd_type == VDTYPE_SMDE) { 103530519Ssam vdaddr->vdcsr = 0; 103630519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 103730519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 103830519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 103930519Ssam vdaddr->vdtcf_data = AM_ENPDA; 104030519Ssam vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD | 104125675Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 104225675Ssam } 104330519Ssam if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { 104430519Ssam printf("%s cmd failed\n", 104530519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 104630370Skarels return; 104725675Ssam } 104830519Ssam for (unit = 0; unit < NDK; unit++) 104930519Ssam if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive) 105030519Ssam (void) vdreset_drive(vi); 105130519Ssam } 105230519Ssam 105330519Ssam vdreset_drive(vi) 105430519Ssam register struct vba_device *vi; 105530519Ssam { 105630519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 105730519Ssam struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; 105830519Ssam struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 1059*32211Skarels register struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 1060*32211Skarels register struct dksoftc *dk = &dksoftc[vi->ui_unit]; 106130519Ssam 106230519Ssam top: 106330519Ssam vd->vd_dcb.opcode = VDOP_CONFIG; /* command */ 106430519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 106530519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 106630519Ssam vd->vd_dcb.operrsta = 0; 1067*32211Skarels vd->vd_dcb.devselect = vi->ui_slave | lp->d_devflags; 106830519Ssam vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders; 106930519Ssam vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks; 107030519Ssam if (vd->vd_type == VDTYPE_SMDE) { 107130756Skarels vd->vd_dcb.trailcnt = sizeof (struct treset) / sizeof (long); 107230519Ssam vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors; 107330601Skarels vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack; 1074*32211Skarels vd->vd_dcb.trail.rstrail.recovery = VDRF_NORMAL; 107530519Ssam } else 107630519Ssam vd->vd_dcb.trailcnt = 2; /* XXX */ 107730519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 107830519Ssam vd->vd_mdcb.mdcb_status = 0; 107930519Ssam VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type); 108030519Ssam if (!vdpoll(vm, 5)) { 108130519Ssam printf(" during config\n"); 108230519Ssam return (0); 108325675Ssam } 108430519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 1085*32211Skarels if (vd->vd_type == VDTYPE_SMDE) { 1086*32211Skarels if (lp->d_devflags == 0) { 1087*32211Skarels lp->d_devflags = VD_ESDI; 1088*32211Skarels goto top; 1089*32211Skarels } 1090*32211Skarels #ifdef notdef 1091*32211Skarels /* this doesn't work, STA_US isn't set(?) */ 1092*32211Skarels if ((vdaddr->vdstatus[vi->ui_slave] & STA_US) == 0) 1093*32211Skarels return (0); 1094*32211Skarels #endif 1095*32211Skarels } 109630519Ssam if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) 1097*32211Skarels printf("dk%d: config error %b ecode %x\n", vi->ui_unit, 1098*32211Skarels vd->vd_dcb.operrsta, VDERRBITS, vd->vd_dcb.err_code); 1099*32211Skarels else if ((vd->vd_flags & VD_STARTED) == 0) { 110030519Ssam int started; 110130519Ssam 1102*32211Skarels printf(" starting drives, wait ... "); 110330519Ssam vd->vd_flags |= VD_STARTED; 110430519Ssam started = (vdcmd(vm, VDOP_START, 10) == 1); 110530519Ssam DELAY(62000000); 1106*32211Skarels printf("done"); 1107*32211Skarels lp->d_devflags = 0; 110830519Ssam if (started) 110930519Ssam goto top; 111030519Ssam } 111130519Ssam return (0); 111230519Ssam } 1113*32211Skarels dk->dk_dcb.devselect |= lp->d_devflags; 111430519Ssam return (1); 111525675Ssam } 111624004Ssam 111725675Ssam /* 111830519Ssam * Perform a command w/o trailer. 111925675Ssam */ 112030519Ssam vdcmd(vm, cmd, t) 112130519Ssam register struct vba_ctlr *vm; 112225675Ssam { 112330519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 112425675Ssam 112530519Ssam vd->vd_dcb.opcode = cmd; /* command */ 112630519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 112730519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 112830519Ssam vd->vd_dcb.operrsta = 0; 112930519Ssam vd->vd_dcb.devselect = 0; 113030519Ssam vd->vd_dcb.trailcnt = 0; 113130519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 113230519Ssam vd->vd_mdcb.mdcb_status = 0; 113330519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 113430519Ssam if (!vdpoll(vm, t)) { 113530519Ssam printf(" during init\n"); 113630370Skarels return (0); 113730370Skarels } 113830519Ssam return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0); 113925675Ssam } 114025675Ssam 114125925Ssam /* 114230519Ssam * Poll controller until operation 114330519Ssam * completes or timeout expires. 114425925Ssam */ 114530519Ssam vdpoll(vm, t) 114630519Ssam register struct vba_ctlr *vm; 114725925Ssam register int t; 114825925Ssam { 114930519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 115030519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 115125925Ssam 115225925Ssam t *= 1000; 115330370Skarels for (;;) { 115430519Ssam uncache(&vd->vd_dcb.operrsta); 115530519Ssam if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT)) 115630370Skarels break; 115725925Ssam if (--t <= 0) { 115830519Ssam printf("vd%d: controller timeout", vm->um_ctlr); 115930519Ssam VDABORT(vdaddr, vd->vd_type); 116025925Ssam DELAY(30000); 116125925Ssam return (0); 116225925Ssam } 116330370Skarels DELAY(1000); 116425925Ssam } 116530519Ssam if (vd->vd_type == VDTYPE_SMDE) { 116630519Ssam do { 116725925Ssam DELAY(50); 116830519Ssam uncache(&vdaddr->vdcsr); 116930519Ssam } while (vdaddr->vdcsr & CS_GO); 1170*32211Skarels DELAY(300); 1171*32211Skarels uncache(&vd->vd_dcb.err_code); 117225925Ssam } 117325925Ssam DELAY(200); 117430519Ssam uncache(&vd->vd_dcb.operrsta); 117525925Ssam return (1); 117625925Ssam } 117725925Ssam 117830519Ssam #ifdef COMPAT_42 117930519Ssam struct vdst { 118030519Ssam int nsec; /* sectors/track */ 118130519Ssam int ntrack; /* tracks/cylinder */ 118230519Ssam int ncyl; /* cylinders */ 1183*32211Skarels int secsize; /* sector size */ 118430519Ssam char *name; /* type name */ 118530519Ssam struct { 118630519Ssam int off; /* partition offset in sectors */ 118730519Ssam int size; /* partition size in sectors */ 118830573Skarels } parts[8]; 118930519Ssam } vdst[] = { 1190*32211Skarels { 66, 23, 850, 512, "NEC 800", 1191*32211Skarels {0, 1290300}, /* a cyl 0 - 849 */ 1192*32211Skarels }, 1193*32211Skarels { 48, 24, 711, 512, "xsd", 119431039Skarels {0, 61056}, /* a cyl 0 - 52 */ 119531039Skarels {61056, 61056}, /* b cyl 53 - 105 */ 119631039Skarels {122112, 691200}, /* c cyl 106 - 705 */ 119731039Skarels {237312, 576000}, /* d cyl 206 - 705 */ 119831039Skarels {352512, 460800}, /* e cyl 306 - 705 */ 119931039Skarels {467712, 345600}, /* f cyl 406 - 705 */ 120031039Skarels {582912, 230400}, /* g cyl 506 - 705 */ 120131039Skarels {698112, 115200} /* h cyl 606 - 705 */ 120230573Skarels }, 1203*32211Skarels { 44, 20, 842, 512, "eagle", 120430601Skarels {0, 52800}, /* egl0a cyl 0 - 59 */ 120530601Skarels {52800, 66000}, /* egl0b cyl 60 - 134 */ 120630601Skarels {118800, 617760}, /* egl0c cyl 135 - 836 */ 120730756Skarels {736560, 4400}, /* egl0d cyl 837 - 841 */ 120831039Skarels {0, 736560}, /* egl0e cyl 0 - 836 */ 120931039Skarels {0, 740960}, /* egl0f cyl 0 - 841 */ 121030601Skarels {118800, 310640}, /* egl0g cyl 135 - 487 */ 121130601Skarels {429440, 307120} /* egl0h cyl 488 - 836 */ 121230573Skarels }, 1213*32211Skarels { 64, 10, 823, 512, "fuj", 121431039Skarels {0, 38400}, /* fuj0a cyl 0 - 59 */ 121531039Skarels {38400, 48000}, /* fuj0b cyl 60 - 134 */ 121631039Skarels {86400, 437120}, /* fuj0c cyl 135 - 817 */ 121731039Skarels {159360, 364160}, /* fuj0d cyl 249 - 817 */ 121831039Skarels {232320, 291200}, /* fuj0e cyl 363 - 817 */ 121931039Skarels {305280, 218240}, /* fuj0f cyl 477 - 817 */ 122031039Skarels {378240, 145280}, /* fuj0g cyl 591 - 817 */ 122131039Skarels {451200, 72320} /* fug0h cyl 705 - 817 */ 122230573Skarels }, 1223*32211Skarels { 32, 23, 850, 1024, "NEC 800-1024", 1224*32211Skarels {0, 703800}, /* a cyl 0 - 849 */ 1225*32211Skarels }, 1226*32211Skarels { 32, 24, 711, 512, "xfd", 122730756Skarels { 0, 40704 }, /* a cyl 0 - 52 */ 122830756Skarels { 40704, 40704 }, /* b cyl 53 - 105 */ 122930756Skarels { 81408, 460800 }, /* c cyl 106 - 705 */ 123030756Skarels { 0, 81408 }, /* d cyl 709 - 710 (a & b) */ 123130756Skarels { 0, 542208 }, /* e cyl 0 - 705 */ 123230756Skarels { 40704, 501504 }, /* f cyl 53 - 705 (b & c) */ 123330756Skarels { 81408, 230400 }, /* g cyl 106 - 405 (1/2 of c) */ 123430756Skarels { 311808,230400 } /* h cyl 406 - 705 (1/2 of c) */ 123530573Skarels }, 1236*32211Skarels { 32, 19, 823, 512, "smd", 123731039Skarels {0, 40128}, /* a cyl 0-65 */ 123831039Skarels {40128, 27360}, /* b cyl 66-110 */ 123931039Skarels {67488, 429856}, /* c cyl 111-817 */ 124031039Skarels {139232, 358112}, /* d cyl 229 - 817 */ 124131039Skarels {210976, 286368}, /* e cyl 347 - 817 */ 124231039Skarels {282720, 214624}, /* f cyl 465 - 817 */ 124331039Skarels {354464, 142880}, /* g cyl 583 - 817 */ 124431039Skarels {426208, 71136} /* h cyl 701 - 817 */ 124530573Skarels }, 1246*32211Skarels { 18, 15, 1224, 1024, "mxd", 1247*32211Skarels {0, 21600}, /* a cyl 0-79 */ 1248*32211Skarels {21600, 22410}, /* b cyl 80-162 */ 1249*32211Skarels {44010, 285120}, /* c cyl 163-1217 */ 1250*32211Skarels #ifdef notyet 1251*32211Skarels {x, 237600}, /* d cyl y - 1217 */ 1252*32211Skarels {x, 190080}, /* e cyl y - 1217 */ 1253*32211Skarels {x, 142560}, /* f cyl y - 1217 */ 1254*32211Skarels {x, 95040}, /* g cyl y - 1217 */ 1255*32211Skarels {x, 47520} /* h cyl 701 - 817 */ 1256*32211Skarels #endif 1257*32211Skarels }, 1258*32211Skarels { 32, 10, 823, 512, "fsd", 125930756Skarels {0, 19200}, /* a cyl 0 - 59 */ 126030756Skarels {19200, 24000}, /* b cyl 60 - 134 */ 126130756Skarels {43200, 218560}, /* c cyl 135 - 817 */ 126230573Skarels } 126330519Ssam }; 126430519Ssam #define NVDST (sizeof (vdst) / sizeof (vdst[0])) 126530519Ssam 126625675Ssam /* 126730519Ssam * Construct a label for an unlabeled pack. We 126830519Ssam * deduce the drive type by reading from the last 126930519Ssam * track on successively smaller drives until we 127030519Ssam * don't get an error. 127125675Ssam */ 127230519Ssam vdmaptype(vi, lp) 127330519Ssam register struct vba_device *vi; 127430519Ssam register struct disklabel *lp; 127525675Ssam { 127630519Ssam register struct vdsoftc *vd; 127730519Ssam register struct vdst *p; 1278*32211Skarels struct vba_ctlr *vm = vi->ui_mi; 127930519Ssam int i; 128025675Ssam 128130519Ssam vd = &vdsoftc[vi->ui_ctlr]; 128230519Ssam for (p = vdst; p < &vdst[NVDST]; p++) { 128330519Ssam if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32) 128430519Ssam continue; 128530519Ssam lp->d_nsectors = p->nsec; 128630519Ssam lp->d_ntracks = p->ntrack; 128730519Ssam lp->d_ncylinders = p->ncyl; 1288*32211Skarels lp->d_secsize = p->secsize; 128930519Ssam if (!vdreset_drive(vi)) 129030519Ssam return (0); 129130519Ssam vd->vd_dcb.opcode = VDOP_RD; 129230519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 129330519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 1294*32211Skarels vd->vd_dcb.devselect = dksoftc[vi->ui_unit].dk_dcb.devselect; 129530756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 129630601Skarels vd->vd_dcb.trail.rwtrail.memadr = 129730601Skarels vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf); 1298*32211Skarels vd->vd_dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof(short); 129930519Ssam vd->vd_dcb.operrsta = 0; 130030519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2; 130130519Ssam vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1; 130230519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1; 130330519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 130430519Ssam vd->vd_mdcb.mdcb_status = 0; 130530519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 130630519Ssam if (!vdpoll(vm, 60)) 130730519Ssam printf(" during probe\n"); 130830519Ssam if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0) 130930519Ssam break; 131024004Ssam } 1311*32211Skarels if (p >= &vdst[NVDST]) 131230519Ssam return (0); 1313*32211Skarels 131430573Skarels for (i = 0; i < 8; i++) { 131530519Ssam lp->d_partitions[i].p_offset = p->parts[i].off; 131630519Ssam lp->d_partitions[i].p_size = p->parts[i].size; 131730519Ssam } 131830573Skarels lp->d_npartitions = 8; 131930519Ssam lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 132030519Ssam lp->d_rpm = 3600; 132130519Ssam bcopy(p->name, lp->d_typename, 4); 132230519Ssam return (1); 132324004Ssam } 132430519Ssam #endif COMPAT_42 132524004Ssam #endif 1326