1*34076Skarels /* vd.c 1.23 88/04/23 */ 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 3432211Skarels #ifndef COMPAT_42 3530519Ssam #define COMPAT_42 3632211Skarels #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 { 71*34076Skarels int dk_state; /* open fsm */ 7230756Skarels #ifndef SECSIZE 7330756Skarels u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */ 7430756Skarels #endif SECSIZE 75*34076Skarels int dk_wlabel; /* label sector is currently writable */ 7632576Skarels u_long dk_copenpart; /* character units open on this drive */ 7732576Skarels u_long dk_bopenpart; /* block units open on this drive */ 7832576Skarels u_long dk_openpart; /* all units open on this drive */ 7930519Ssam u_int dk_curcyl; /* last selected cylinder */ 8030756Skarels struct skdcb dk_dcb; /* seek command block */ 8130519Ssam u_long dk_dcbphys; /* physical address of dk_dcb */ 8230519Ssam } dksoftc[NDK]; 8324004Ssam 8424004Ssam /* 8530519Ssam * Drive states. Used during steps of open/initialization. 8630519Ssam * States < OPEN (> 0) are transient, during an open operation. 87*34076Skarels * OPENRAW is used for unlabeled disks, to allow format operations. 8825675Ssam */ 8930519Ssam #define CLOSED 0 /* disk is closed */ 9030519Ssam #define WANTOPEN 1 /* open requested, not started */ 9130519Ssam #define WANTOPENRAW 2 /* open requested, no label */ 9230519Ssam #define RDLABEL 3 /* reading pack label */ 9330519Ssam #define OPEN 4 /* intialized and ready */ 9430519Ssam #define OPENRAW 5 /* open, no label */ 9524004Ssam 9630519Ssam struct buf rdkbuf[NDK]; /* raw i/o buffer headers */ 9730519Ssam struct buf dkutab[NDK]; /* i/o queue headers */ 9830519Ssam struct disklabel dklabel[NDK]; /* pack labels */ 9924004Ssam 10030519Ssam #define b_cylin b_resid 10130574Skarels #define b_track b_error /* used for seek commands */ 10230574Skarels #define b_seekf b_forw /* second queue on um_tab */ 10330574Skarels #define b_seekl b_back /* second queue on um_tab */ 10430519Ssam 10530519Ssam int vdwstart, vdwatch(); 10630519Ssam 10724004Ssam /* 10825675Ssam * See if the controller is really there; if so, initialize it. 10925675Ssam */ 11025857Ssam vdprobe(reg, vm) 11125857Ssam caddr_t reg; 11225857Ssam struct vba_ctlr *vm; 11325675Ssam { 11425857Ssam register br, cvec; /* must be r12, r11 */ 11530519Ssam register struct vddevice *vdaddr = (struct vddevice *)reg; 11630519Ssam struct vdsoftc *vd; 11730573Skarels int s; 11825857Ssam 11930370Skarels #ifdef lint 12030370Skarels br = 0; cvec = br; br = cvec; 12130370Skarels vdintr(0); 12230370Skarels #endif 12325857Ssam if (badaddr((caddr_t)reg, 2)) 12425675Ssam return (0); 12530519Ssam vd = &vdsoftc[vm->um_ctlr]; 12630519Ssam vdaddr->vdreset = 0xffffffff; 12725675Ssam DELAY(1000000); 12830519Ssam if (vdaddr->vdreset != (unsigned)0xffffffff) { 12930519Ssam vd->vd_type = VDTYPE_VDDC; 13030519Ssam vd->vd_flags &= ~VD_DOSEEKS; 13125675Ssam DELAY(1000000); 13225675Ssam } else { 13330519Ssam vd->vd_type = VDTYPE_SMDE; 13430519Ssam vd->vd_flags |= VD_DOSEEKS; 13530519Ssam vdaddr->vdrstclr = 0; 13625675Ssam DELAY(3000000); 13730519Ssam vdaddr->vdcsr = 0; 13830519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 13930519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 14030519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 14130519Ssam vdaddr->vdtcf_data = AM_ENPDA; 14230519Ssam vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS | 14329921Skarels XMD_32BIT | BSZ_16WRD | 14425925Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 14525675Ssam } 14630519Ssam vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb); 14730519Ssam vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb); 14830519Ssam vm->um_addr = reg; /* XXX */ 14930573Skarels s = spl7(); 15030519Ssam if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { 15130519Ssam printf("vd%d: %s cmd failed\n", vm->um_ctlr, 15230519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 15330573Skarels splx(s); 15430519Ssam return (0); 15530519Ssam } 15630756Skarels if (vd->vd_type == VDTYPE_SMDE) { 15730756Skarels vd->vd_dcb.trail.idtrail.date = 0; 15830756Skarels if (vdcmd(vm, VDOP_IDENT, 10)) { 15930756Skarels uncache(&vd->vd_dcb.trail.idtrail.date); 16030756Skarels if (vd->vd_dcb.trail.idtrail.date != 0) 16130756Skarels vd->vd_flags |= VD_SCATGATH; 16230756Skarels } 16330756Skarels } 16430573Skarels splx(s); 16525925Ssam /* 16625950Ssam * Allocate page tables and i/o buffer. 16725925Ssam */ 16832211Skarels if (vbainit(&vd->vd_rbuf, MAXPHYS, 16932211Skarels vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT) == 0) { 17032211Skarels printf("vd%d: vbainit failed\n", vm->um_ctlr); 17132211Skarels return (0); 17232211Skarels } 17325857Ssam br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */ 17430519Ssam return (sizeof (struct vddevice)); 17525675Ssam } 17624004Ssam 17724004Ssam /* 17830519Ssam * See if a drive is really there. 17930519Ssam * 18030519Ssam * Can't read pack label here as various data structures 18130519Ssam * aren't setup for doing a read in a straightforward 18230519Ssam * manner. Instead just probe for the drive and leave 18330519Ssam * the pack label stuff to the attach routine. 18425675Ssam */ 185*34076Skarels /* ARGSUSED */ 186*34076Skarels vdslave(vi, vdaddr) 18725675Ssam register struct vba_device *vi; 18830519Ssam struct vddevice *vdaddr; 18925675Ssam { 19030519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 19132211Skarels register struct dksoftc *dk = &dksoftc[vi->ui_unit]; 19230519Ssam struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 19324004Ssam 19430519Ssam if ((vd->vd_flags&VD_INIT) == 0) { 19530756Skarels printf("vd%d: %s controller%s\n", vi->ui_ctlr, 19630756Skarels vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE", 19730756Skarels (vd->vd_flags & VD_SCATGATH) ? " with scatter-gather" : ""); 19830519Ssam vd->vd_flags |= VD_INIT; 19925675Ssam } 20030519Ssam 20125675Ssam /* 20230519Ssam * Initialize label enough to do a reset on 20330519Ssam * the drive. The remainder of the default 20430519Ssam * label values will be filled in in vdinit 20530519Ssam * at attach time. 20625675Ssam */ 20732211Skarels if (vd->vd_type == VDTYPE_SMDE) 20832211Skarels lp->d_secsize = VD_MAXSECSIZE; 20932211Skarels else 21032211Skarels lp->d_secsize = VDDC_SECSIZE; 211*34076Skarels lp->d_nsectors = 68; /* only used on smd-e */ 212*34076Skarels lp->d_ntracks = 23; 21332211Skarels lp->d_ncylinders = 842; 214*34076Skarels lp->d_secpercyl = 68*23; 21524004Ssam 21630519Ssam /* 21730519Ssam * Initialize invariant portion of 21830519Ssam * dcb used for overlapped seeks. 21930519Ssam */ 22030519Ssam dk->dk_dcb.opcode = VDOP_SEEK; 22130519Ssam dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA; 22230519Ssam dk->dk_dcb.devselect = vi->ui_slave; 22330756Skarels dk->dk_dcb.trailcnt = sizeof (struct trseek) / sizeof (long); 22430519Ssam dk->dk_dcb.trail.sktrail.skaddr.sector = 0; 22530519Ssam dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb); 22632211Skarels #ifndef SECSIZE 22732211Skarels vd_setsecsize(dk, lp); 22832211Skarels #endif 22932211Skarels return (vdreset_drive(vi)); 23032211Skarels } 23132211Skarels 23232211Skarels vdattach(vi) 23332211Skarels register struct vba_device *vi; 23432211Skarels { 23532211Skarels register int unit = vi->ui_unit; 23632211Skarels register struct disklabel *lp = &dklabel[unit]; 23732211Skarels 23830601Skarels /* 23930601Skarels * Try to initialize device and read pack label. 24030601Skarels */ 24130601Skarels if (vdinit(vdminor(unit, 0), 0) != 0) { 24230601Skarels printf(": unknown drive type"); 24330601Skarels return; 24430601Skarels } 24532211Skarels if (dksoftc[unit].dk_state == OPEN) 24632211Skarels printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>", 24732211Skarels lp->d_typename, lp->d_secsize, 24832211Skarels lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors); 24930519Ssam /* 25030519Ssam * (60 / rpm) / (sectors per track * (bytes per sector / 2)) 25130519Ssam */ 25230519Ssam if (vi->ui_dk >= 0) 25330519Ssam dk_mspw[vi->ui_dk] = 120.0 / 25430519Ssam (lp->d_rpm * lp->d_nsectors * lp->d_secsize); 25530519Ssam #ifdef notyet 25630573Skarels addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp); 25730519Ssam #endif 25824004Ssam } 25924004Ssam 26030756Skarels vdopen(dev, flags, fmt) 26130519Ssam dev_t dev; 26230756Skarels int flags, fmt; 26324004Ssam { 26430519Ssam register unit = vdunit(dev); 26530519Ssam register struct disklabel *lp; 26630519Ssam register struct dksoftc *dk; 26730519Ssam register struct partition *pp; 26830519Ssam struct vba_device *vi; 26930756Skarels int s, error, part = vdpart(dev), mask = 1 << part; 27030519Ssam daddr_t start, end; 27124004Ssam 27230519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 27330519Ssam return (ENXIO); 27430519Ssam lp = &dklabel[unit]; 27530519Ssam dk = &dksoftc[unit]; 27630519Ssam 27730519Ssam s = spl7(); 27830519Ssam while (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 27930519Ssam dk->dk_state != CLOSED) 28030519Ssam sleep((caddr_t)dk, PZERO+1); 28130519Ssam splx(s); 28230519Ssam if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 28330519Ssam if (error = vdinit(dev, flags)) 28430519Ssam return (error); 28530573Skarels 28630573Skarels if (vdwstart == 0) { 28730573Skarels timeout(vdwatch, (caddr_t)0, hz); 28830573Skarels vdwstart++; 28930573Skarels } 29030519Ssam /* 29130519Ssam * Warn if a partion is opened 29230519Ssam * that overlaps another partition which is open 29330519Ssam * unless one is the "raw" partition (whole disk). 29430519Ssam */ 29532211Skarels #define RAWPART 8 /* 'x' partition */ /* XXX */ 29632576Skarels if ((dk->dk_openpart & mask) == 0 && part != RAWPART) { 29730519Ssam pp = &lp->d_partitions[part]; 29830519Ssam start = pp->p_offset; 29930519Ssam end = pp->p_offset + pp->p_size; 30030519Ssam for (pp = lp->d_partitions; 30130519Ssam pp < &lp->d_partitions[lp->d_npartitions]; pp++) { 30230519Ssam if (pp->p_offset + pp->p_size <= start || 30330519Ssam pp->p_offset >= end) 30430519Ssam continue; 30530519Ssam if (pp - lp->d_partitions == RAWPART) 30630519Ssam continue; 30730519Ssam if (dk->dk_openpart & (1 << (pp - lp->d_partitions))) 30830519Ssam log(LOG_WARNING, 30930519Ssam "dk%d%c: overlaps open partition (%c)\n", 31030519Ssam unit, part + 'a', 31130519Ssam pp - lp->d_partitions + 'a'); 31230519Ssam } 31324004Ssam } 31430519Ssam if (part >= lp->d_npartitions) 31530519Ssam return (ENXIO); 31630756Skarels dk->dk_openpart |= mask; 31730756Skarels switch (fmt) { 31830756Skarels case S_IFCHR: 31930756Skarels dk->dk_copenpart |= mask; 32030756Skarels break; 32130756Skarels case S_IFBLK: 32230756Skarels dk->dk_bopenpart |= mask; 32330756Skarels break; 32430756Skarels } 32530519Ssam return (0); 32625675Ssam } 32724004Ssam 32830756Skarels vdclose(dev, flags, fmt) 32930519Ssam dev_t dev; 33030756Skarels int flags, fmt; 33124004Ssam { 33230519Ssam register int unit = vdunit(dev); 33330519Ssam register struct dksoftc *dk = &dksoftc[unit]; 33430756Skarels int part = vdpart(dev), mask = 1 << part; 33524004Ssam 33630756Skarels switch (fmt) { 33730756Skarels case S_IFCHR: 33830756Skarels dk->dk_copenpart &= ~mask; 33930756Skarels break; 34030756Skarels case S_IFBLK: 34130756Skarels dk->dk_bopenpart &= ~mask; 34230756Skarels break; 34330756Skarels } 34430756Skarels if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0) 34530756Skarels dk->dk_openpart &= ~mask; 34630519Ssam /* 34730519Ssam * Should wait for i/o to complete on this partition 34830519Ssam * even if others are open, but wait for work on blkflush(). 34930519Ssam */ 35030519Ssam if (dk->dk_openpart == 0) { 35130573Skarels int s = spl7(); 35230573Skarels while (dkutab[unit].b_actf) 35330573Skarels sleep((caddr_t)dk, PZERO-1); 35430519Ssam splx(s); 35530519Ssam dk->dk_state = CLOSED; 356*34076Skarels dk->dk_wlabel = 0; 35724004Ssam } 35830756Skarels return (0); 35925675Ssam } 36024004Ssam 36130519Ssam vdinit(dev, flags) 36230519Ssam dev_t dev; 36330519Ssam int flags; 36425675Ssam { 36530519Ssam register struct disklabel *lp; 36630519Ssam register struct dksoftc *dk; 36730519Ssam struct vba_device *vi; 36830519Ssam int unit = vdunit(dev), error = 0; 36930756Skarels char *msg, *readdisklabel(); 37030519Ssam extern int cold; 37125675Ssam 37230519Ssam dk = &dksoftc[unit]; 37330519Ssam if (flags & O_NDELAY) { 37430519Ssam dk->dk_state = OPENRAW; 37530756Skarels return; 37630519Ssam } 37730519Ssam dk->dk_state = RDLABEL; 37830519Ssam lp = &dklabel[unit]; 37930519Ssam vi = vddinfo[unit]; 38030756Skarels if (msg = readdisklabel(dev, vdstrategy, lp)) { 381*34076Skarels if (cold) { 38230601Skarels printf(": %s", msg); 383*34076Skarels dk->dk_state = CLOSED; 384*34076Skarels } else { 38532211Skarels log(LOG_ERR, "dk%d: %s\n", unit, msg); 386*34076Skarels dk->dk_state = OPENRAW; 387*34076Skarels } 38830519Ssam #ifdef COMPAT_42 389*34076Skarels if (vdmaptype(vi, lp)) 39030519Ssam dk->dk_state = OPEN; 39130519Ssam #endif 39230756Skarels } else { 39330756Skarels /* 39430756Skarels * Now that we have the label, configure 39530756Skarels * the correct drive parameters. 39630756Skarels */ 39732211Skarels if (vdreset_drive(vi)) 39832211Skarels dk->dk_state = OPEN; 39932211Skarels else { 40030756Skarels dk->dk_state = CLOSED; 40130756Skarels error = ENXIO; 40232211Skarels } 40325675Ssam } 40430756Skarels #ifndef SECSIZE 40532211Skarels vd_setsecsize(dk, lp); 40632211Skarels #endif 40730519Ssam wakeup((caddr_t)dk); 40830519Ssam return (error); 40924004Ssam } 41024004Ssam 41132211Skarels #ifndef SECSIZE 41232211Skarels vd_setsecsize(dk, lp) 41332211Skarels register struct dksoftc *dk; 41432211Skarels register struct disklabel *lp; 41532211Skarels { 41632211Skarels int mul; 41732211Skarels 41832211Skarels /* 41932211Skarels * Calculate scaling shift for mapping 42032211Skarels * DEV_BSIZE blocks to drive sectors. 42132211Skarels */ 42232211Skarels mul = DEV_BSIZE / lp->d_secsize; 42332211Skarels dk->dk_bshift = 0; 42432211Skarels while ((mul >>= 1) > 0) 42532211Skarels dk->dk_bshift++; 42632211Skarels } 42732211Skarels #endif SECSIZE 42832211Skarels 42925675Ssam /*ARGSUSED*/ 43030519Ssam vddgo(vm) 43130519Ssam struct vba_device *vm; 43224004Ssam { 43324004Ssam 43424004Ssam } 43524004Ssam 43624004Ssam vdstrategy(bp) 43725675Ssam register struct buf *bp; 43824004Ssam { 43930519Ssam register struct vba_device *vi; 44030519Ssam register struct disklabel *lp; 44130519Ssam register struct dksoftc *dk; 44230519Ssam register int unit; 44330573Skarels register daddr_t sn; 44430519Ssam struct buf *dp; 44530573Skarels daddr_t sz, maxsz; 44630519Ssam int part, s; 44724004Ssam 44830519Ssam unit = vdunit(bp->b_dev); 44932211Skarels if (unit >= NDK) { 45029954Skarels bp->b_error = ENXIO; 45125675Ssam goto bad; 45229954Skarels } 45330519Ssam vi = vddinfo[unit]; 45430519Ssam lp = &dklabel[unit]; 45530519Ssam if (vi == 0 || vi->ui_alive == 0) { 45630519Ssam bp->b_error = ENXIO; 45730519Ssam goto bad; 45830519Ssam } 45930519Ssam dk = &dksoftc[unit]; 46030519Ssam if (dk->dk_state < OPEN) 46130519Ssam goto q; 462*34076Skarels if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) { 463*34076Skarels bp->b_error = EROFS; 464*34076Skarels goto bad; 465*34076Skarels } 46630519Ssam part = vdpart(bp->b_dev); 46730519Ssam if ((dk->dk_openpart & (1 << part)) == 0) { 46830519Ssam bp->b_error = ENODEV; 46930519Ssam goto bad; 47030519Ssam } 47132211Skarels sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize; 47230519Ssam maxsz = lp->d_partitions[part].p_size; 47330756Skarels #ifndef SECSIZE 47430756Skarels sn = bp->b_blkno << dk->dk_bshift; 47530756Skarels #else SECSIZE 47630573Skarels sn = bp->b_blkno; 47730756Skarels #endif SECSIZE 478*34076Skarels if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR && 479*34076Skarels #if LABELSECTOR != 0 480*34076Skarels sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR && 481*34076Skarels #endif 482*34076Skarels (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) { 483*34076Skarels bp->b_error = EROFS; 484*34076Skarels goto bad; 485*34076Skarels } 48630519Ssam if (sn < 0 || sn + sz > maxsz) { 48730519Ssam if (sn == maxsz) { 48829954Skarels bp->b_resid = bp->b_bcount; 48929954Skarels goto done; 49029954Skarels } 49130756Skarels sz = maxsz - sn; 49230573Skarels if (sz <= 0) { 49330573Skarels bp->b_error = EINVAL; 49430573Skarels goto bad; 49530573Skarels } 49630573Skarels bp->b_bcount = sz * lp->d_secsize; 49725675Ssam } 49830519Ssam bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl; 49930756Skarels #ifdef SECSIZE 50030756Skarels if (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0) 50130756Skarels panic("vdstrat blksize"); 50230756Skarels #endif SECSIZE 50330519Ssam q: 50425675Ssam s = spl7(); 50530519Ssam dp = &dkutab[vi->ui_unit]; 50630519Ssam disksort(dp, bp); 50730519Ssam if (!dp->b_active) { 50830519Ssam (void) vdustart(vi); 50930573Skarels if (!vi->ui_mi->um_tab.b_active) 51030519Ssam vdstart(vi->ui_mi); 51124004Ssam } 51230519Ssam splx(s); 51324004Ssam return; 51425675Ssam bad: 51529954Skarels bp->b_flags |= B_ERROR; 51629954Skarels done: 51730519Ssam biodone(bp); 51830519Ssam return; 51924004Ssam } 52024004Ssam 52130519Ssam vdustart(vi) 52230519Ssam register struct vba_device *vi; 52324004Ssam { 52430519Ssam register struct buf *bp, *dp; 52530519Ssam register struct vba_ctlr *vm; 52630519Ssam register int unit = vi->ui_unit; 52730519Ssam register struct dksoftc *dk; 52830519Ssam register struct vdsoftc *vd; 52930519Ssam struct disklabel *lp; 53024004Ssam 53130519Ssam dp = &dkutab[unit]; 53230519Ssam /* 53330519Ssam * If queue empty, nothing to do. 53430519Ssam */ 53530519Ssam if ((bp = dp->b_actf) == NULL) 53630519Ssam return; 53730519Ssam /* 53830574Skarels * If drive is off-cylinder and controller supports seeks, 53930574Skarels * place drive on seek queue for controller. 54030574Skarels * Otherwise, place on transfer queue. 54130519Ssam */ 54230519Ssam vd = &vdsoftc[vi->ui_ctlr]; 54330519Ssam dk = &dksoftc[unit]; 54430574Skarels vm = vi->ui_mi; 54530519Ssam if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) { 54630519Ssam lp = &dklabel[unit]; 54730574Skarels bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors; 54830574Skarels if (vm->um_tab.b_seekf == NULL) 54930574Skarels vm->um_tab.b_seekf = dp; 55030574Skarels else 55130574Skarels vm->um_tab.b_seekl->b_forw = dp; 55230574Skarels vm->um_tab.b_seekl = dp; 55330574Skarels } else { 55430574Skarels if (vm->um_tab.b_actf == NULL) 55530574Skarels vm->um_tab.b_actf = dp; 55630574Skarels else 55730574Skarels vm->um_tab.b_actl->b_forw = dp; 55830574Skarels vm->um_tab.b_actl = dp; 55930519Ssam } 56030573Skarels dp->b_forw = NULL; 56130573Skarels dp->b_active++; 56225675Ssam } 56325675Ssam 56425675Ssam /* 56530519Ssam * Start next transfer on a controller. 56630574Skarels * There are two queues of drives, the first on-cylinder 56730574Skarels * and the second off-cylinder from their next transfers. 56830574Skarels * Perform the first transfer for the first drive on the on-cylinder 56930574Skarels * queue, if any, otherwise the first transfer for the first drive 57030574Skarels * on the second queue. Initiate seeks on remaining drives on the 57130574Skarels * off-cylinder queue, then move them all to the on-cylinder queue. 57225675Ssam */ 57330519Ssam vdstart(vm) 57430519Ssam register struct vba_ctlr *vm; 57525675Ssam { 57625675Ssam register struct buf *bp; 57730519Ssam register struct vba_device *vi; 57830519Ssam register struct vdsoftc *vd; 57930519Ssam register struct dksoftc *dk; 58030519Ssam register struct disklabel *lp; 58130519Ssam register struct dcb **dcbp; 58230519Ssam struct mdcb *mdcb; 58330519Ssam struct buf *dp; 58430519Ssam int sn, tn; 58525675Ssam 58630519Ssam loop: 58730519Ssam /* 58830519Ssam * Pull a request off the controller queue. 58930519Ssam */ 59030574Skarels if ((dp = vm->um_tab.b_actf) == NULL && 59130574Skarels (dp = vm->um_tab.b_seekf) == NULL) 59230519Ssam return; 59330519Ssam if ((bp = dp->b_actf) == NULL) { 59430601Skarels if (dp == vm->um_tab.b_actf) 59530601Skarels vm->um_tab.b_actf = dp->b_forw; 59630601Skarels else 59730601Skarels vm->um_tab.b_seekf = dp->b_forw; 59830519Ssam goto loop; 59930519Ssam } 60025675Ssam 60124004Ssam /* 60230519Ssam * Mark controller busy, and determine 60330519Ssam * destination of this request. 60424004Ssam */ 60530519Ssam vm->um_tab.b_active++; 60630519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 60730519Ssam dk = &dksoftc[vi->ui_unit]; 60830756Skarels #ifndef SECSIZE 60930756Skarels sn = bp->b_blkno << dk->dk_bshift; 61030756Skarels #else SECSIZE 61130573Skarels sn = bp->b_blkno; 61230756Skarels #endif SECSIZE 61330519Ssam lp = &dklabel[vi->ui_unit]; 61430519Ssam sn %= lp->d_secpercyl; 61530519Ssam tn = sn / lp->d_nsectors; 61630519Ssam sn %= lp->d_nsectors; 61730519Ssam 61830519Ssam /* 61930519Ssam * Construct dcb for read/write command. 62030519Ssam */ 62130519Ssam vd = &vdsoftc[vm->um_ctlr]; 62230519Ssam vd->vd_dcb.intflg = DCBINT_DONE; 62332211Skarels vd->vd_dcb.devselect = dk->dk_dcb.devselect; 62430519Ssam vd->vd_dcb.operrsta = 0; 62530519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 62630519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin; 62730519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 62830519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 62930574Skarels dk->dk_curcyl = bp->b_cylin; 63030574Skarels bp->b_track = 0; /* init overloaded field */ 63130756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 63230756Skarels if (vd->vd_flags & VD_SCATGATH && 63330756Skarels ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0) { 63430756Skarels vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW; 63530756Skarels vd->vd_dcb.trailcnt += vba_sgsetup(bp, &vd->vd_rbuf, 63630756Skarels &vd->vd_dcb.trail.sgtrail); 63730756Skarels } else { 63830756Skarels vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD; 63930756Skarels vd->vd_dcb.trail.rwtrail.memadr = 64030756Skarels vbasetup(bp, &vd->vd_rbuf, lp->d_secsize); 64130756Skarels vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1; 64230756Skarels } 64330574Skarels if (vi->ui_dk >= 0) { 64430574Skarels dk_busy |= 1<<vi->ui_dk; 64530574Skarels dk_xfer[vi->ui_dk]++; 64630574Skarels dk_wds[vi->ui_dk] += bp->b_bcount>>6; 64730574Skarels } 64830519Ssam 64930519Ssam /* 65030519Ssam * Look for any seeks to be performed on other drives on this 65130519Ssam * controller. If overlapped seeks exist, insert seek commands 65230519Ssam * on the controller's command queue before the transfer. 65330519Ssam */ 65430519Ssam dcbp = &vd->vd_mdcb.mdcb_head; 65530519Ssam 65630574Skarels if (dp == vm->um_tab.b_seekf) 65730574Skarels dp = dp->b_forw; 65830574Skarels else 65930574Skarels dp = vm->um_tab.b_seekf; 66030574Skarels for (; dp != NULL; dp = dp->b_forw) { 66130574Skarels if ((bp = dp->b_actf) == NULL) 66230574Skarels continue; 66330574Skarels vi = vddinfo[vdunit(bp->b_dev)]; 66430574Skarels dk = &dksoftc[vi->ui_unit]; 66530519Ssam dk->dk_curcyl = bp->b_cylin; 66630574Skarels if (vi->ui_dk >= 0) 66730574Skarels dk_seek[vi->ui_dk]++; 66830574Skarels dk->dk_dcb.operrsta = 0; 66930574Skarels dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin; 67030574Skarels dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track; 67130574Skarels *dcbp = (struct dcb *)dk->dk_dcbphys; 67230574Skarels dcbp = &dk->dk_dcb.nxtdcb; 67324004Ssam } 67430519Ssam *dcbp = (struct dcb *)vd->vd_dcbphys; 67530574Skarels if (vm->um_tab.b_actf) 67630574Skarels vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf; 67730574Skarels else 67830574Skarels vm->um_tab.b_actf = vm->um_tab.b_seekf; 67930601Skarels if (vm->um_tab.b_seekf) 68030601Skarels vm->um_tab.b_actl = vm->um_tab.b_seekl; 68130574Skarels vm->um_tab.b_seekf = 0; 68224004Ssam 68330519Ssam /* 68430519Ssam * Initiate operation. 68530519Ssam */ 68630519Ssam vd->vd_mdcb.mdcb_status = 0; 68730519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 68824004Ssam } 68924004Ssam 69030519Ssam #define DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE) 69124004Ssam /* 69224004Ssam * Handle a disk interrupt. 69324004Ssam */ 69425675Ssam vdintr(ctlr) 69530519Ssam register ctlr; 69624004Ssam { 69730519Ssam register struct buf *bp, *dp; 69830519Ssam register struct vba_ctlr *vm = vdminfo[ctlr]; 69930519Ssam register struct vba_device *vi; 70030519Ssam register struct vdsoftc *vd = &vdsoftc[ctlr]; 70130519Ssam register status; 70230601Skarels int ecode; 70330573Skarels struct dksoftc *dk; 70424004Ssam 70530519Ssam vd->vd_wticks = 0; 70630519Ssam if (!vm->um_tab.b_active) { 70725675Ssam printf("vd%d: stray interrupt\n", ctlr); 70824004Ssam return; 70924004Ssam } 71025675Ssam /* 71130519Ssam * Get device and block structures, and a pointer 71230519Ssam * to the vba_device for the drive. 71325675Ssam */ 71430519Ssam dp = vm->um_tab.b_actf; 71530519Ssam bp = dp->b_actf; 71630519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 71730574Skarels if (vi->ui_dk >= 0) 71830574Skarels dk_busy &= ~(1<<vi->ui_dk); 71930519Ssam /* 72030519Ssam * Check for and process errors on 72130519Ssam * either the drive or the controller. 72230519Ssam */ 72330519Ssam uncache(&vd->vd_dcb.operrsta); 72430519Ssam status = vd->vd_dcb.operrsta; 72530519Ssam if (status & VDERR_HARD) { 72630601Skarels if (vd->vd_type == VDTYPE_SMDE) { 72730601Skarels uncache(&vd->vd_dcb.err_code); 72830601Skarels ecode = vd->vd_dcb.err_code; 72930601Skarels } 73030519Ssam if (status & DCBS_WPT) { 73130519Ssam /* 73230519Ssam * Give up on write locked devices immediately. 73330519Ssam */ 73430573Skarels printf("dk%d: write locked\n", vi->ui_unit); 73530519Ssam bp->b_flags |= B_ERROR; 73630573Skarels } else if (status & VDERR_RETRY) { 73732211Skarels int endline = 1; 73832211Skarels 73930519Ssam if (status & VDERR_DRIVE) { 74032211Skarels printf("dk%d%c: drive err %b, bn %d,", 74132211Skarels vi->ui_unit, 'a' + vdpart(bp->b_dev), 74232211Skarels status &~ DONTCARE, VDERRBITS, bp->b_blkno); 74332211Skarels if (vd->vd_type == VDTYPE_SMDE) 74432211Skarels printf(" ecode %x,", ecode); 74532211Skarels printf(" resetting drive..."); 74630519Ssam if (!vdreset_drive(vi)) 74730519Ssam vi->ui_alive = 0; 74832211Skarels } else if (status & VDERR_CTLR) { 74932211Skarels printf("dk%d%c: controller err %b, bn %d,", 75032211Skarels vi->ui_unit, 'a' + vdpart(bp->b_dev), 75132211Skarels status &~ DONTCARE, VDERRBITS, bp->b_blkno); 75232211Skarels if (vd->vd_type == VDTYPE_SMDE) 75332211Skarels printf(" ecode %x,", ecode); 75432211Skarels printf("resetting controller..."); 75530519Ssam vdreset_ctlr(vm); 75632211Skarels } else 75732211Skarels endline = 0; 75830519Ssam /* 75930519Ssam * Retry transfer once, unless reset failed. 76030519Ssam */ 76132211Skarels if (!vi->ui_alive || dp->b_errcnt++ >= 2) { 76232211Skarels if (endline) 76332211Skarels printf("\n"); 76430519Ssam goto hard; 76532211Skarels } 76632211Skarels 76732211Skarels if (endline) 76832211Skarels printf(" retrying\n"); 76930519Ssam vm->um_tab.b_active = 0; /* force retry */ 77030519Ssam } else { 77130519Ssam hard: 77230519Ssam bp->b_flags |= B_ERROR; 77330519Ssam /* NEED TO ADJUST b_blkno to failed sector */ 77430519Ssam harderr(bp, "dk"); 77530519Ssam printf("status %x (%b)", status, 77630519Ssam status &~ DONTCARE, VDERRBITS); 77730601Skarels if (vd->vd_type == VDTYPE_SMDE) 77830601Skarels printf(" ecode %x", ecode); 77930519Ssam printf("\n"); 78030519Ssam } 78130519Ssam } else if (status & DCBS_SOFT) 78230519Ssam vdsofterr(vd, bp, &vd->vd_dcb); 78330519Ssam if (vm->um_tab.b_active) { 78430519Ssam vm->um_tab.b_active = 0; 78530519Ssam vm->um_tab.b_actf = dp->b_forw; 78630519Ssam dp->b_active = 0; 78730519Ssam dp->b_errcnt = 0; 78830519Ssam dp->b_actf = bp->av_forw; 78930519Ssam bp->b_resid = 0; 79030601Skarels vbadone(bp, &vd->vd_rbuf); 79130519Ssam biodone(bp); 79230370Skarels /* 79330519Ssam * If this unit has more work to do, 79430519Ssam * then start it up right away. 79530370Skarels */ 79630519Ssam if (dp->b_actf) 79730519Ssam vdustart(vi); 79830573Skarels else if ((dk = &dksoftc[vi->ui_unit])->dk_openpart == 0) 79930573Skarels wakeup((caddr_t)dk); 80024004Ssam } 80125675Ssam /* 80230519Ssam * If there are devices ready to 80330519Ssam * transfer, start the controller. 80425675Ssam */ 80530601Skarels if (vm->um_tab.b_actf || vm->um_tab.b_seekf) 80630519Ssam vdstart(vm); 80724004Ssam } 80824004Ssam 80930519Ssam vdsofterr(vd, bp, dcb) 81030519Ssam struct vdsoftc *vd; 81125675Ssam register struct buf *bp; 81230519Ssam register struct dcb *dcb; 81325675Ssam { 81430519Ssam int unit = vdunit(bp->b_dev), status = dcb->operrsta; 81530519Ssam char part = 'a' + vdpart(bp->b_dev); 81625675Ssam 81732211Skarels if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) 81830519Ssam log(LOG_WARNING, "dk%d%c: soft error sn%d status %b ecode %x\n", 81930519Ssam unit, part, bp->b_blkno, status, VDERRBITS, dcb->err_code); 82032211Skarels else 82130370Skarels log(LOG_WARNING, "dk%d%c: soft ecc sn%d\n", 82230370Skarels unit, part, bp->b_blkno); 82325675Ssam } 82425675Ssam 82524004Ssam vdread(dev, uio) 82625675Ssam dev_t dev; 82725675Ssam struct uio *uio; 82824004Ssam { 82930519Ssam register int unit = vdunit(dev); 83024004Ssam 83129564Ssam if (unit >= NDK) 83225675Ssam return (ENXIO); 83330519Ssam return (physio(vdstrategy, &rdkbuf[unit], dev, B_READ, minphys, uio)); 83424004Ssam } 83524004Ssam 83624004Ssam vdwrite(dev, uio) 83725675Ssam dev_t dev; 83825675Ssam struct uio *uio; 83924004Ssam { 84030519Ssam register int unit = vdunit(dev); 84124004Ssam 84229564Ssam if (unit >= NDK) 84325675Ssam return (ENXIO); 84430519Ssam return (physio(vdstrategy, &rdkbuf[unit], dev, B_WRITE, minphys, uio)); 84524004Ssam } 84624004Ssam 84730519Ssam vdioctl(dev, cmd, data, flag) 84825675Ssam dev_t dev; 84930519Ssam int cmd; 85030519Ssam caddr_t data; 85130519Ssam int flag; 85224004Ssam { 85332576Skarels register int unit = vdunit(dev); 85430519Ssam register struct disklabel *lp = &dklabel[unit]; 855*34076Skarels register struct dksoftc *dk = &dksoftc[unit]; 856*34076Skarels int error = 0, wlab; 85724004Ssam 85830519Ssam switch (cmd) { 85930519Ssam 86030519Ssam case DIOCGDINFO: 86130519Ssam *(struct disklabel *)data = *lp; 86230519Ssam break; 86330519Ssam 86430573Skarels case DIOCGPART: 86530573Skarels ((struct partinfo *)data)->disklab = lp; 86630573Skarels ((struct partinfo *)data)->part = 86730573Skarels &lp->d_partitions[vdpart(dev)]; 86830519Ssam break; 86930519Ssam 87030519Ssam case DIOCSDINFO: 87130519Ssam if ((flag & FWRITE) == 0) 87230519Ssam error = EBADF; 87330519Ssam else 87432576Skarels error = setdisklabel(lp, (struct disklabel *)data, 875*34076Skarels (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart); 876*34076Skarels if (error == 0) 877*34076Skarels dk->dk_state = OPEN; 87830519Ssam break; 87930519Ssam 880*34076Skarels case DIOCWLABEL: 881*34076Skarels if ((flag & FWRITE) == 0) 882*34076Skarels error = EBADF; 883*34076Skarels else 884*34076Skarels dk->dk_wlabel = *(int *)data; 885*34076Skarels break; 886*34076Skarels 88732576Skarels case DIOCWDINFO: 888*34076Skarels /* simulate opening partition 0 so write succeeds */ 889*34076Skarels dk->dk_openpart |= (1 << 0); /* XXX */ 890*34076Skarels wlab = dk->dk_wlabel; 891*34076Skarels dk->dk_wlabel = 1; 89232576Skarels if ((flag & FWRITE) == 0) 89330519Ssam error = EBADF; 89432576Skarels else if ((error = setdisklabel(lp, (struct disklabel *)data, 895*34076Skarels (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) { 896*34076Skarels dk->dk_state = OPEN; 89732576Skarels error = writedisklabel(dev, vdstrategy, lp); 898*34076Skarels } 899*34076Skarels dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart; 900*34076Skarels dk->dk_wlabel = wlab; 90130519Ssam break; 90230519Ssam 90330519Ssam default: 90430519Ssam error = ENOTTY; 90530519Ssam break; 90624004Ssam } 90732606Skarels return (error); 90824004Ssam } 90924004Ssam 91025675Ssam /* 91130519Ssam * Watch for lost interrupts. 91225675Ssam */ 91330519Ssam vdwatch() 91430519Ssam { 91530519Ssam register struct vdsoftc *vd; 91630519Ssam register struct vba_ctlr *vm; 91725675Ssam register int ctlr, unit; 91830519Ssam 91930519Ssam timeout(vdwatch, (caddr_t)0, hz); 92030519Ssam for (ctlr = 0; ctlr < NVD; ctlr++) { 92130519Ssam vm = vdminfo[ctlr]; 92230519Ssam if (vm == 0 || vm->um_alive == 0) 92330519Ssam continue; 92430519Ssam vd = &vdsoftc[ctlr]; 92530601Skarels if (vm->um_tab.b_active && vd->vd_wticks++ >= 20) { 92630519Ssam vd->vd_wticks = 0; 92730519Ssam printf("vd%d: lost interrupt\n", ctlr); 92830519Ssam /* abort pending dcb's and restart controller */ 92930519Ssam } 93030519Ssam } 93130519Ssam } 93230519Ssam 93330519Ssam #define DBSIZE 64 /* controller limit with 1K sectors */ 93430519Ssam /* 93530519Ssam * Crash dump. 93630519Ssam */ 93730519Ssam vddump(dev) 93830519Ssam dev_t dev; 93924004Ssam { 94030519Ssam register struct vba_device *vi; 94130519Ssam register struct vba_ctlr *vm; 94230519Ssam register struct disklabel *lp; 94330519Ssam register struct vdsoftc *vd; 94430519Ssam struct dksoftc *dk; 94530519Ssam int part, unit, num; 94630601Skarels u_long start; 94724004Ssam 94830519Ssam start = 0; 94930519Ssam unit = vdunit(dev); 95030519Ssam if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 95130519Ssam return (ENXIO); 95230519Ssam dk = &dksoftc[unit]; 953*34076Skarels if (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 954*34076Skarels vdinit(vdminor(unit, 0), 0) != 0) 95530519Ssam return (ENXIO); 95630519Ssam lp = &dklabel[unit]; 95730519Ssam part = vdpart(dev); 95830519Ssam if (part >= lp->d_npartitions) 95930519Ssam return (ENXIO); 96032211Skarels vm = vi->ui_mi; 96130519Ssam vdreset_ctlr(vm); 96230519Ssam if (dumplo < 0) 96330519Ssam return (EINVAL); 96430519Ssam /* 96530756Skarels * Maxfree is in pages, dumplo is in DEV_BSIZE units. 96630519Ssam */ 96730519Ssam num = maxfree * (NBPG / lp->d_secsize); 96830756Skarels dumplo *= DEV_BSIZE / lp->d_secsize; 96930519Ssam if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size) 97030519Ssam num = lp->d_partitions[vdpart(dev)].p_size - dumplo; 97130519Ssam vd = &vdsoftc[vm->um_ctlr]; 97230519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 97330519Ssam vd->vd_dcb.opcode = VDOP_WD; 97432211Skarels vd->vd_dcb.devselect = dk->dk_dcb.devselect; 97530756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 97630519Ssam while (num > 0) { 97730519Ssam int nsec, cn, sn, tn; 97830519Ssam 97930519Ssam nsec = MIN(num, DBSIZE); 98030601Skarels sn = dumplo + start / lp->d_secsize; 98130519Ssam cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) / 98230519Ssam lp->d_secpercyl; 98330519Ssam sn %= lp->d_secpercyl; 98430519Ssam tn = sn / lp->d_nsectors; 98530519Ssam sn %= lp->d_nsectors; 98630519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 98730519Ssam vd->vd_dcb.trail.rwtrail.memadr = start; 98830519Ssam vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1; 98930519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = cn; 99030519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 99130519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 99230519Ssam vd->vd_dcb.operrsta = 0; 99330519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 99430519Ssam if (!vdpoll(vm, 5)) { 99530519Ssam printf(" during dump\n"); 99630519Ssam return (EIO); 99730519Ssam } 99830519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 99930519Ssam printf("dk%d: hard error, status=%b\n", unit, 100030519Ssam vd->vd_dcb.operrsta, VDERRBITS); 100130519Ssam return (EIO); 100230519Ssam } 100330519Ssam start += nsec * lp->d_secsize; 100430519Ssam num -= nsec; 100525675Ssam } 100630519Ssam return (0); 100724004Ssam } 100824004Ssam 100924004Ssam vdsize(dev) 101025675Ssam dev_t dev; 101124004Ssam { 101230519Ssam register int unit = vdunit(dev); 101330519Ssam register struct dksoftc *dk; 101430519Ssam struct vba_device *vi; 101530519Ssam struct disklabel *lp; 101624004Ssam 101730519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 || 101830519Ssam (dk = &dksoftc[unit])->dk_state != OPEN) 101925675Ssam return (-1); 102030519Ssam lp = &dklabel[unit]; 102130756Skarels #ifdef SECSIZE 102230573Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size); 102330756Skarels #else SECSIZE 102430756Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift); 102530756Skarels #endif SECSIZE 102624004Ssam } 102724004Ssam 102825675Ssam /* 102925675Ssam * Perform a controller reset. 103025675Ssam */ 103130519Ssam vdreset_ctlr(vm) 103230519Ssam register struct vba_ctlr *vm; 103324004Ssam { 103430519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 103530519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 103630519Ssam register int unit; 103730519Ssam struct vba_device *vi; 103825675Ssam 103930519Ssam VDRESET(vdaddr, vd->vd_type); 104030519Ssam if (vd->vd_type == VDTYPE_SMDE) { 104130519Ssam vdaddr->vdcsr = 0; 104230519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 104330519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 104430519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 104530519Ssam vdaddr->vdtcf_data = AM_ENPDA; 104630519Ssam vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD | 104725675Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 104825675Ssam } 104930519Ssam if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { 105030519Ssam printf("%s cmd failed\n", 105130519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 105230370Skarels return; 105325675Ssam } 105430519Ssam for (unit = 0; unit < NDK; unit++) 105530519Ssam if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive) 105630519Ssam (void) vdreset_drive(vi); 105730519Ssam } 105830519Ssam 105930519Ssam vdreset_drive(vi) 106030519Ssam register struct vba_device *vi; 106130519Ssam { 106230519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 106330519Ssam struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; 106430519Ssam struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 106532211Skarels register struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 106632211Skarels register struct dksoftc *dk = &dksoftc[vi->ui_unit]; 106730519Ssam 106830519Ssam top: 106930519Ssam vd->vd_dcb.opcode = VDOP_CONFIG; /* command */ 107030519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 107130519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 107230519Ssam vd->vd_dcb.operrsta = 0; 107332211Skarels vd->vd_dcb.devselect = vi->ui_slave | lp->d_devflags; 107430519Ssam vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders; 107530519Ssam vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks; 107630519Ssam if (vd->vd_type == VDTYPE_SMDE) { 107730756Skarels vd->vd_dcb.trailcnt = sizeof (struct treset) / sizeof (long); 107830519Ssam vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors; 107930601Skarels vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack; 108032211Skarels vd->vd_dcb.trail.rstrail.recovery = VDRF_NORMAL; 108130519Ssam } else 108230519Ssam vd->vd_dcb.trailcnt = 2; /* XXX */ 108330519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 108430519Ssam vd->vd_mdcb.mdcb_status = 0; 108530519Ssam VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type); 108630519Ssam if (!vdpoll(vm, 5)) { 108730519Ssam printf(" during config\n"); 108830519Ssam return (0); 108925675Ssam } 109030519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 109132211Skarels if (vd->vd_type == VDTYPE_SMDE) { 109232211Skarels if (lp->d_devflags == 0) { 109332211Skarels lp->d_devflags = VD_ESDI; 109432211Skarels goto top; 109532211Skarels } 109632211Skarels #ifdef notdef 109732211Skarels /* this doesn't work, STA_US isn't set(?) */ 109832211Skarels if ((vdaddr->vdstatus[vi->ui_slave] & STA_US) == 0) 109932211Skarels return (0); 110032211Skarels #endif 110132211Skarels } 110230519Ssam if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) 110332211Skarels printf("dk%d: config error %b ecode %x\n", vi->ui_unit, 110432211Skarels vd->vd_dcb.operrsta, VDERRBITS, vd->vd_dcb.err_code); 110532211Skarels else if ((vd->vd_flags & VD_STARTED) == 0) { 110630519Ssam int started; 110730519Ssam 110832211Skarels printf(" starting drives, wait ... "); 110930519Ssam vd->vd_flags |= VD_STARTED; 111030519Ssam started = (vdcmd(vm, VDOP_START, 10) == 1); 111130519Ssam DELAY(62000000); 111232211Skarels printf("done"); 111332211Skarels lp->d_devflags = 0; 111430519Ssam if (started) 111530519Ssam goto top; 111630519Ssam } 111730519Ssam return (0); 111830519Ssam } 111932211Skarels dk->dk_dcb.devselect |= lp->d_devflags; 112030519Ssam return (1); 112125675Ssam } 112224004Ssam 112325675Ssam /* 112430519Ssam * Perform a command w/o trailer. 112525675Ssam */ 112630519Ssam vdcmd(vm, cmd, t) 112730519Ssam register struct vba_ctlr *vm; 112825675Ssam { 112930519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 113025675Ssam 113130519Ssam vd->vd_dcb.opcode = cmd; /* command */ 113230519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 113330519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 113430519Ssam vd->vd_dcb.operrsta = 0; 113530519Ssam vd->vd_dcb.devselect = 0; 113630519Ssam vd->vd_dcb.trailcnt = 0; 113730519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 113830519Ssam vd->vd_mdcb.mdcb_status = 0; 113930519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 114030519Ssam if (!vdpoll(vm, t)) { 114130519Ssam printf(" during init\n"); 114230370Skarels return (0); 114330370Skarels } 114430519Ssam return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0); 114525675Ssam } 114625675Ssam 114725925Ssam /* 114830519Ssam * Poll controller until operation 114930519Ssam * completes or timeout expires. 115025925Ssam */ 115130519Ssam vdpoll(vm, t) 115230519Ssam register struct vba_ctlr *vm; 115325925Ssam register int t; 115425925Ssam { 115530519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 115630519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 115725925Ssam 115825925Ssam t *= 1000; 115930370Skarels for (;;) { 116030519Ssam uncache(&vd->vd_dcb.operrsta); 116130519Ssam if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT)) 116230370Skarels break; 116325925Ssam if (--t <= 0) { 116430519Ssam printf("vd%d: controller timeout", vm->um_ctlr); 116530519Ssam VDABORT(vdaddr, vd->vd_type); 116625925Ssam DELAY(30000); 116725925Ssam return (0); 116825925Ssam } 116930370Skarels DELAY(1000); 117025925Ssam } 117130519Ssam if (vd->vd_type == VDTYPE_SMDE) { 117230519Ssam do { 117325925Ssam DELAY(50); 117430519Ssam uncache(&vdaddr->vdcsr); 117530519Ssam } while (vdaddr->vdcsr & CS_GO); 117632211Skarels DELAY(300); 117732211Skarels uncache(&vd->vd_dcb.err_code); 117825925Ssam } 117925925Ssam DELAY(200); 118030519Ssam uncache(&vd->vd_dcb.operrsta); 118125925Ssam return (1); 118225925Ssam } 118325925Ssam 118430519Ssam #ifdef COMPAT_42 118530519Ssam struct vdst { 118630519Ssam int nsec; /* sectors/track */ 118730519Ssam int ntrack; /* tracks/cylinder */ 118830519Ssam int ncyl; /* cylinders */ 118932211Skarels int secsize; /* sector size */ 119030519Ssam char *name; /* type name */ 119130519Ssam struct { 119230519Ssam int off; /* partition offset in sectors */ 119330519Ssam int size; /* partition size in sectors */ 119430573Skarels } parts[8]; 119530519Ssam } vdst[] = { 119632211Skarels { 66, 23, 850, 512, "NEC 800", 119732211Skarels {0, 1290300}, /* a cyl 0 - 849 */ 119832211Skarels }, 119932211Skarels { 48, 24, 711, 512, "xsd", 120031039Skarels {0, 61056}, /* a cyl 0 - 52 */ 120131039Skarels {61056, 61056}, /* b cyl 53 - 105 */ 120231039Skarels {122112, 691200}, /* c cyl 106 - 705 */ 120331039Skarels {237312, 576000}, /* d cyl 206 - 705 */ 120431039Skarels {352512, 460800}, /* e cyl 306 - 705 */ 120531039Skarels {467712, 345600}, /* f cyl 406 - 705 */ 120631039Skarels {582912, 230400}, /* g cyl 506 - 705 */ 120731039Skarels {698112, 115200} /* h cyl 606 - 705 */ 120830573Skarels }, 120932211Skarels { 44, 20, 842, 512, "eagle", 121030601Skarels {0, 52800}, /* egl0a cyl 0 - 59 */ 121130601Skarels {52800, 66000}, /* egl0b cyl 60 - 134 */ 121230601Skarels {118800, 617760}, /* egl0c cyl 135 - 836 */ 121330756Skarels {736560, 4400}, /* egl0d cyl 837 - 841 */ 121431039Skarels {0, 736560}, /* egl0e cyl 0 - 836 */ 121531039Skarels {0, 740960}, /* egl0f cyl 0 - 841 */ 121630601Skarels {118800, 310640}, /* egl0g cyl 135 - 487 */ 121730601Skarels {429440, 307120} /* egl0h cyl 488 - 836 */ 121830573Skarels }, 121932211Skarels { 64, 10, 823, 512, "fuj", 122031039Skarels {0, 38400}, /* fuj0a cyl 0 - 59 */ 122131039Skarels {38400, 48000}, /* fuj0b cyl 60 - 134 */ 122231039Skarels {86400, 437120}, /* fuj0c cyl 135 - 817 */ 122331039Skarels {159360, 364160}, /* fuj0d cyl 249 - 817 */ 122431039Skarels {232320, 291200}, /* fuj0e cyl 363 - 817 */ 122531039Skarels {305280, 218240}, /* fuj0f cyl 477 - 817 */ 122631039Skarels {378240, 145280}, /* fuj0g cyl 591 - 817 */ 122731039Skarels {451200, 72320} /* fug0h cyl 705 - 817 */ 122830573Skarels }, 122932211Skarels { 32, 24, 711, 512, "xfd", 123030756Skarels { 0, 40704 }, /* a cyl 0 - 52 */ 123130756Skarels { 40704, 40704 }, /* b cyl 53 - 105 */ 123230756Skarels { 81408, 460800 }, /* c cyl 106 - 705 */ 123330756Skarels { 0, 81408 }, /* d cyl 709 - 710 (a & b) */ 123430756Skarels { 0, 542208 }, /* e cyl 0 - 705 */ 123530756Skarels { 40704, 501504 }, /* f cyl 53 - 705 (b & c) */ 123630756Skarels { 81408, 230400 }, /* g cyl 106 - 405 (1/2 of c) */ 123730756Skarels { 311808,230400 } /* h cyl 406 - 705 (1/2 of c) */ 123830573Skarels }, 123932211Skarels { 32, 19, 823, 512, "smd", 124031039Skarels {0, 40128}, /* a cyl 0-65 */ 124131039Skarels {40128, 27360}, /* b cyl 66-110 */ 124231039Skarels {67488, 429856}, /* c cyl 111-817 */ 124331039Skarels {139232, 358112}, /* d cyl 229 - 817 */ 124431039Skarels {210976, 286368}, /* e cyl 347 - 817 */ 124531039Skarels {282720, 214624}, /* f cyl 465 - 817 */ 124631039Skarels {354464, 142880}, /* g cyl 583 - 817 */ 124731039Skarels {426208, 71136} /* h cyl 701 - 817 */ 124830573Skarels }, 124932211Skarels { 18, 15, 1224, 1024, "mxd", 125032211Skarels {0, 21600}, /* a cyl 0-79 */ 125132211Skarels {21600, 22410}, /* b cyl 80-162 */ 125232211Skarels {44010, 285120}, /* c cyl 163-1217 */ 125332211Skarels #ifdef notyet 125432211Skarels {x, 237600}, /* d cyl y - 1217 */ 125532211Skarels {x, 190080}, /* e cyl y - 1217 */ 125632211Skarels {x, 142560}, /* f cyl y - 1217 */ 125732211Skarels {x, 95040}, /* g cyl y - 1217 */ 125832211Skarels {x, 47520} /* h cyl 701 - 817 */ 125932211Skarels #endif 126032211Skarels }, 126132211Skarels { 32, 10, 823, 512, "fsd", 126230756Skarels {0, 19200}, /* a cyl 0 - 59 */ 126330756Skarels {19200, 24000}, /* b cyl 60 - 134 */ 126430756Skarels {43200, 218560}, /* c cyl 135 - 817 */ 126530573Skarels } 126630519Ssam }; 126730519Ssam #define NVDST (sizeof (vdst) / sizeof (vdst[0])) 126830519Ssam 126925675Ssam /* 127030519Ssam * Construct a label for an unlabeled pack. We 127130519Ssam * deduce the drive type by reading from the last 127230519Ssam * track on successively smaller drives until we 127330519Ssam * don't get an error. 127425675Ssam */ 127530519Ssam vdmaptype(vi, lp) 127630519Ssam register struct vba_device *vi; 127730519Ssam register struct disklabel *lp; 127825675Ssam { 127930519Ssam register struct vdsoftc *vd; 128030519Ssam register struct vdst *p; 128132211Skarels struct vba_ctlr *vm = vi->ui_mi; 128230519Ssam int i; 128325675Ssam 128430519Ssam vd = &vdsoftc[vi->ui_ctlr]; 128530519Ssam for (p = vdst; p < &vdst[NVDST]; p++) { 128630519Ssam if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32) 128730519Ssam continue; 128830519Ssam lp->d_nsectors = p->nsec; 128930519Ssam lp->d_ntracks = p->ntrack; 129030519Ssam lp->d_ncylinders = p->ncyl; 129132211Skarels lp->d_secsize = p->secsize; 129230519Ssam if (!vdreset_drive(vi)) 129330519Ssam return (0); 129430519Ssam vd->vd_dcb.opcode = VDOP_RD; 129530519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 129630519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 129732211Skarels vd->vd_dcb.devselect = dksoftc[vi->ui_unit].dk_dcb.devselect; 129830756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 129930601Skarels vd->vd_dcb.trail.rwtrail.memadr = 130030601Skarels vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf); 130132211Skarels vd->vd_dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof(short); 130230519Ssam vd->vd_dcb.operrsta = 0; 130330519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2; 130430519Ssam vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1; 130530519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1; 130630519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 130730519Ssam vd->vd_mdcb.mdcb_status = 0; 130830519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 130930519Ssam if (!vdpoll(vm, 60)) 131030519Ssam printf(" during probe\n"); 131130519Ssam if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0) 131230519Ssam break; 131324004Ssam } 131432211Skarels if (p >= &vdst[NVDST]) 131530519Ssam return (0); 131632211Skarels 131730573Skarels for (i = 0; i < 8; i++) { 131830519Ssam lp->d_partitions[i].p_offset = p->parts[i].off; 131930519Ssam lp->d_partitions[i].p_size = p->parts[i].size; 132030519Ssam } 132130573Skarels lp->d_npartitions = 8; 132230519Ssam lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 132330519Ssam lp->d_rpm = 3600; 132430519Ssam bcopy(p->name, lp->d_typename, 4); 132530519Ssam return (1); 132624004Ssam } 132730519Ssam #endif COMPAT_42 132824004Ssam #endif 1329