1*30756Skarels /* vd.c 1.18 87/04/02 */ 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" 25*30756Skarels #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 3430519Ssam #define COMPAT_42 3530519Ssam 3630519Ssam #define vdunit(dev) (minor(dev) >> 3) 3730519Ssam #define vdpart(dev) (minor(dev) & 0x07) 3830519Ssam #define vdminor(unit,part) (((unit) << 3) | (part)) 3924004Ssam 4024004Ssam struct vba_ctlr *vdminfo[NVD]; 4129564Ssam struct vba_device *vddinfo[NDK]; 42*30756Skarels int vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy(); 4330519Ssam long vdaddr[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 }; 4425675Ssam struct vba_driver vddriver = 4530519Ssam { vdprobe, vdslave, vdattach, vddgo, vdaddr, "dk", vddinfo, "vd", vdminfo }; 4624004Ssam 4724004Ssam /* 4830519Ssam * Per-controller state. 4930519Ssam */ 5030519Ssam struct vdsoftc { 5130519Ssam u_short vd_flags; 5230519Ssam #define VD_INIT 0x1 /* controller initialized */ 5330519Ssam #define VD_STARTED 0x2 /* start command issued */ 5430519Ssam #define VD_DOSEEKS 0x4 /* should overlap seeks */ 55*30756Skarels #define VD_SCATGATH 0x8 /* can do scatter-gather commands (correctly) */ 5630519Ssam u_short vd_type; /* controller type */ 5730519Ssam u_short vd_wticks; /* timeout */ 5830519Ssam struct mdcb vd_mdcb; /* master command block */ 5930519Ssam u_long vd_mdcbphys; /* physical address of vd_mdcb */ 6030519Ssam struct dcb vd_dcb; /* i/o command block */ 6130519Ssam u_long vd_dcbphys; /* physical address of vd_dcb */ 6230601Skarels struct vb_buf vd_rbuf; /* vba resources */ 6330519Ssam } vdsoftc[NVD]; 6430519Ssam 6530519Ssam /* 6625675Ssam * Per-drive state. 6725675Ssam */ 6830519Ssam struct dksoftc { 6930519Ssam u_short dk_state; /* open fsm */ 70*30756Skarels u_short dk_copenpart; /* character units open on this drive */ 71*30756Skarels u_short dk_bopenpart; /* block units open on this drive */ 72*30756Skarels u_short dk_openpart; /* all units open on this drive */ 73*30756Skarels #ifndef SECSIZE 74*30756Skarels u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */ 75*30756Skarels #endif SECSIZE 7630519Ssam u_int dk_curcyl; /* last selected cylinder */ 77*30756Skarels struct skdcb dk_dcb; /* seek command block */ 7830519Ssam u_long dk_dcbphys; /* physical address of dk_dcb */ 7930519Ssam } dksoftc[NDK]; 8024004Ssam 8124004Ssam /* 8230519Ssam * Drive states. Used during steps of open/initialization. 8330519Ssam * States < OPEN (> 0) are transient, during an open operation. 8430519Ssam * OPENRAW is used for unabeled disks, to allow format operations. 8525675Ssam */ 8630519Ssam #define CLOSED 0 /* disk is closed */ 8730519Ssam #define WANTOPEN 1 /* open requested, not started */ 8830519Ssam #define WANTOPENRAW 2 /* open requested, no label */ 8930519Ssam #define RDLABEL 3 /* reading pack label */ 9030519Ssam #define OPEN 4 /* intialized and ready */ 9130519Ssam #define OPENRAW 5 /* open, no label */ 9224004Ssam 9330519Ssam struct buf rdkbuf[NDK]; /* raw i/o buffer headers */ 9430519Ssam struct buf dkutab[NDK]; /* i/o queue headers */ 9530519Ssam struct disklabel dklabel[NDK]; /* pack labels */ 9624004Ssam 9730519Ssam #define b_cylin b_resid 9830574Skarels #define b_track b_error /* used for seek commands */ 9930574Skarels #define b_seekf b_forw /* second queue on um_tab */ 10030574Skarels #define b_seekl b_back /* second queue on um_tab */ 10130519Ssam 10230519Ssam int vdwstart, vdwatch(); 10330519Ssam 10424004Ssam /* 10525675Ssam * See if the controller is really there; if so, initialize it. 10625675Ssam */ 10725857Ssam vdprobe(reg, vm) 10825857Ssam caddr_t reg; 10925857Ssam struct vba_ctlr *vm; 11025675Ssam { 11125857Ssam register br, cvec; /* must be r12, r11 */ 11230519Ssam register struct vddevice *vdaddr = (struct vddevice *)reg; 11330519Ssam struct vdsoftc *vd; 11430573Skarels int s; 11525857Ssam 11630370Skarels #ifdef lint 11730370Skarels br = 0; cvec = br; br = cvec; 11830370Skarels vdintr(0); 11930370Skarels #endif 12025857Ssam if (badaddr((caddr_t)reg, 2)) 12125675Ssam return (0); 12230519Ssam vd = &vdsoftc[vm->um_ctlr]; 12330519Ssam vdaddr->vdreset = 0xffffffff; 12425675Ssam DELAY(1000000); 12530519Ssam if (vdaddr->vdreset != (unsigned)0xffffffff) { 12630519Ssam vd->vd_type = VDTYPE_VDDC; 12730519Ssam vd->vd_flags &= ~VD_DOSEEKS; 12825675Ssam DELAY(1000000); 12925675Ssam } else { 13030519Ssam vd->vd_type = VDTYPE_SMDE; 13130519Ssam vd->vd_flags |= VD_DOSEEKS; 13230519Ssam vdaddr->vdrstclr = 0; 13325675Ssam DELAY(3000000); 13430519Ssam vdaddr->vdcsr = 0; 13530519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 13630519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 13730519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 13830519Ssam vdaddr->vdtcf_data = AM_ENPDA; 13930519Ssam vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS | 14029921Skarels XMD_32BIT | BSZ_16WRD | 14125925Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 14225675Ssam } 14330519Ssam vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb); 14430519Ssam vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb); 14530519Ssam vm->um_addr = reg; /* XXX */ 14630573Skarels s = spl7(); 14730519Ssam if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { 14830519Ssam printf("vd%d: %s cmd failed\n", vm->um_ctlr, 14930519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 15030573Skarels splx(s); 15130519Ssam return (0); 15230519Ssam } 153*30756Skarels if (vd->vd_type == VDTYPE_SMDE) { 154*30756Skarels vd->vd_dcb.trail.idtrail.date = 0; 155*30756Skarels if (vdcmd(vm, VDOP_IDENT, 10)) { 156*30756Skarels uncache(&vd->vd_dcb.trail.idtrail.date); 157*30756Skarels if (vd->vd_dcb.trail.idtrail.date != 0) 158*30756Skarels vd->vd_flags |= VD_SCATGATH; 159*30756Skarels } 160*30756Skarels } 16130573Skarels splx(s); 16225925Ssam /* 16325950Ssam * Allocate page tables and i/o buffer. 16425925Ssam */ 165*30756Skarels vbainit(&vd->vd_rbuf, MAXPHYS, 16630601Skarels vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT); 16725857Ssam br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */ 16830519Ssam return (sizeof (struct vddevice)); 16925675Ssam } 17024004Ssam 17124004Ssam /* 17230519Ssam * See if a drive is really there. 17330519Ssam * 17430519Ssam * Can't read pack label here as various data structures 17530519Ssam * aren't setup for doing a read in a straightforward 17630519Ssam * manner. Instead just probe for the drive and leave 17730519Ssam * the pack label stuff to the attach routine. 17825675Ssam */ 17925675Ssam vdslave(vi, addr) 18025675Ssam register struct vba_device *vi; 18130519Ssam struct vddevice *vdaddr; 18225675Ssam { 18330519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 18430519Ssam struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 18524004Ssam 18630519Ssam if ((vd->vd_flags&VD_INIT) == 0) { 187*30756Skarels printf("vd%d: %s controller%s\n", vi->ui_ctlr, 188*30756Skarels vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE", 189*30756Skarels (vd->vd_flags & VD_SCATGATH) ? " with scatter-gather" : ""); 19030519Ssam vd->vd_flags |= VD_INIT; 19125675Ssam } 19230519Ssam 19325675Ssam /* 19430519Ssam * Initialize label enough to do a reset on 19530519Ssam * the drive. The remainder of the default 19630519Ssam * label values will be filled in in vdinit 19730519Ssam * at attach time. 19825675Ssam */ 19930519Ssam lp->d_secsize = DEV_BSIZE / 2; /* XXX */ 20030519Ssam lp->d_nsectors = 32; 20130519Ssam lp->d_ntracks = 24; 20230519Ssam lp->d_ncylinders = 711; 20330519Ssam lp->d_secpercyl = 32*24; 20430519Ssam return (vdreset_drive(vi)); 20524004Ssam } 20624004Ssam 20730519Ssam vdattach(vi) 20830519Ssam register struct vba_device *vi; 20924004Ssam { 21030519Ssam register int unit = vi->ui_unit; 21130519Ssam register struct dksoftc *dk = &dksoftc[unit]; 21230519Ssam register struct disklabel *lp; 21325675Ssam 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; 221*30756Skarels 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); 22430601Skarels /* 22530601Skarels * Try to initialize device and read pack label. 22630601Skarels */ 22730601Skarels if (vdinit(vdminor(unit, 0), 0) != 0) { 22830601Skarels printf(": unknown drive type"); 22930601Skarels return; 23030601Skarels } 23130519Ssam lp = &dklabel[unit]; 23230519Ssam printf(": %s <ntrak %d, ncyl %d, nsec %d>", 23330519Ssam lp->d_typename, lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors); 23430519Ssam /* 23530519Ssam * (60 / rpm) / (sectors per track * (bytes per sector / 2)) 23630519Ssam */ 23730519Ssam if (vi->ui_dk >= 0) 23830519Ssam dk_mspw[vi->ui_dk] = 120.0 / 23930519Ssam (lp->d_rpm * lp->d_nsectors * lp->d_secsize); 24030519Ssam #ifdef notyet 24130573Skarels addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp); 24230519Ssam #endif 24324004Ssam } 24424004Ssam 245*30756Skarels vdopen(dev, flags, fmt) 24630519Ssam dev_t dev; 247*30756Skarels int flags, fmt; 24824004Ssam { 24930519Ssam register unit = vdunit(dev); 25030519Ssam register struct disklabel *lp; 25130519Ssam register struct dksoftc *dk; 25230519Ssam register struct partition *pp; 25330519Ssam struct vba_device *vi; 254*30756Skarels int s, error, part = vdpart(dev), mask = 1 << part; 25530519Ssam daddr_t start, end; 25624004Ssam 25730519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 25830519Ssam return (ENXIO); 25930519Ssam lp = &dklabel[unit]; 26030519Ssam dk = &dksoftc[unit]; 26130519Ssam 26230519Ssam s = spl7(); 26330519Ssam while (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 26430519Ssam dk->dk_state != CLOSED) 26530519Ssam sleep((caddr_t)dk, PZERO+1); 26630519Ssam splx(s); 26730519Ssam if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 26830519Ssam if (error = vdinit(dev, flags)) 26930519Ssam return (error); 27030573Skarels 27130573Skarels if (vdwstart == 0) { 27230573Skarels timeout(vdwatch, (caddr_t)0, hz); 27330573Skarels vdwstart++; 27430573Skarels } 27530519Ssam /* 27630519Ssam * Warn if a partion is opened 27730519Ssam * that overlaps another partition which is open 27830519Ssam * unless one is the "raw" partition (whole disk). 27930519Ssam */ 28030519Ssam #define RAWPART 2 /* 'c' partition */ /* XXX */ 28130519Ssam if ((dk->dk_openpart & (1 << part)) == 0 && 28230519Ssam part != RAWPART) { 28330519Ssam pp = &lp->d_partitions[part]; 28430519Ssam start = pp->p_offset; 28530519Ssam end = pp->p_offset + pp->p_size; 28630519Ssam for (pp = lp->d_partitions; 28730519Ssam pp < &lp->d_partitions[lp->d_npartitions]; pp++) { 28830519Ssam if (pp->p_offset + pp->p_size <= start || 28930519Ssam pp->p_offset >= end) 29030519Ssam continue; 29130519Ssam if (pp - lp->d_partitions == RAWPART) 29230519Ssam continue; 29330519Ssam if (dk->dk_openpart & (1 << (pp - lp->d_partitions))) 29430519Ssam log(LOG_WARNING, 29530519Ssam "dk%d%c: overlaps open partition (%c)\n", 29630519Ssam unit, part + 'a', 29730519Ssam pp - lp->d_partitions + 'a'); 29830519Ssam } 29924004Ssam } 30030519Ssam if (part >= lp->d_npartitions) 30130519Ssam return (ENXIO); 302*30756Skarels dk->dk_openpart |= mask; 303*30756Skarels switch (fmt) { 304*30756Skarels case S_IFCHR: 305*30756Skarels dk->dk_copenpart |= mask; 306*30756Skarels break; 307*30756Skarels case S_IFBLK: 308*30756Skarels dk->dk_bopenpart |= mask; 309*30756Skarels break; 310*30756Skarels } 31130519Ssam return (0); 31225675Ssam } 31324004Ssam 314*30756Skarels vdclose(dev, flags, fmt) 31530519Ssam dev_t dev; 316*30756Skarels int flags, fmt; 31724004Ssam { 31830519Ssam register int unit = vdunit(dev); 31930519Ssam register struct dksoftc *dk = &dksoftc[unit]; 320*30756Skarels int part = vdpart(dev), mask = 1 << part; 32124004Ssam 322*30756Skarels switch (fmt) { 323*30756Skarels case S_IFCHR: 324*30756Skarels dk->dk_copenpart &= ~mask; 325*30756Skarels break; 326*30756Skarels case S_IFBLK: 327*30756Skarels dk->dk_bopenpart &= ~mask; 328*30756Skarels break; 329*30756Skarels } 330*30756Skarels if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0) 331*30756Skarels dk->dk_openpart &= ~mask; 33230519Ssam /* 33330519Ssam * Should wait for i/o to complete on this partition 33430519Ssam * even if others are open, but wait for work on blkflush(). 33530519Ssam */ 33630519Ssam if (dk->dk_openpart == 0) { 33730573Skarels int s = spl7(); 33830573Skarels while (dkutab[unit].b_actf) 33930573Skarels sleep((caddr_t)dk, PZERO-1); 34030519Ssam splx(s); 34130519Ssam dk->dk_state = CLOSED; 34224004Ssam } 343*30756Skarels return (0); 34425675Ssam } 34524004Ssam 34630519Ssam vdinit(dev, flags) 34730519Ssam dev_t dev; 34830519Ssam int flags; 34925675Ssam { 35030519Ssam register struct disklabel *lp; 35130519Ssam register struct dksoftc *dk; 35230519Ssam struct vba_device *vi; 35330519Ssam int unit = vdunit(dev), error = 0; 354*30756Skarels char *msg, *readdisklabel(); 35530519Ssam extern int cold; 35625675Ssam 35730519Ssam dk = &dksoftc[unit]; 358*30756Skarels #ifndef SECSIZE 359*30756Skarels dk->dk_bshift = 1; /* DEV_BSIZE / 512 */ 360*30756Skarels #endif SECSIZE 36130519Ssam if (flags & O_NDELAY) { 36230519Ssam dk->dk_state = OPENRAW; 363*30756Skarels return; 36430519Ssam } 36530519Ssam dk->dk_state = RDLABEL; 36630519Ssam lp = &dklabel[unit]; 36730519Ssam vi = vddinfo[unit]; 368*30756Skarels if (msg = readdisklabel(dev, vdstrategy, lp)) { 36930519Ssam if (cold) 37030601Skarels printf(": %s", msg); 37130519Ssam else 37230601Skarels log(LOG_ERR, "dk%d: %s\n", vi->ui_unit, msg); 37330519Ssam #ifdef COMPAT_42 374*30756Skarels if (!vdmaptype(vi, lp)) 375*30756Skarels dk->dk_state = OPENRAW; 376*30756Skarels else 37730519Ssam dk->dk_state = OPEN; 37830519Ssam #else 37930519Ssam dk->dk_state = OPENRAW; 38030519Ssam #endif 381*30756Skarels } else { 382*30756Skarels /* 383*30756Skarels * Now that we have the label, configure 384*30756Skarels * the correct drive parameters. 385*30756Skarels */ 386*30756Skarels if (!vdreset_drive(vi)) { 387*30756Skarels dk->dk_state = CLOSED; 388*30756Skarels error = ENXIO; 389*30756Skarels } else 390*30756Skarels dk->dk_state = OPEN; 39125675Ssam } 392*30756Skarels #ifndef SECSIZE 393*30756Skarels /* 394*30756Skarels * If open, calculate scaling shift for 395*30756Skarels * mapping DEV_BSIZE blocks to drive sectors. 396*30756Skarels */ 397*30756Skarels if (dk->dk_state == OPEN || dk->dk_state == OPENRAW) { 398*30756Skarels int mul = DEV_BSIZE / lp->d_secsize; 399*30756Skarels dk->dk_bshift = 0; 400*30756Skarels while ((mul >>= 1) > 0) 401*30756Skarels dk->dk_bshift++; 40230519Ssam } 403*30756Skarels #endif SECSIZE 40430519Ssam wakeup((caddr_t)dk); 40530519Ssam return (error); 40624004Ssam } 40724004Ssam 40825675Ssam /*ARGSUSED*/ 40930519Ssam vddgo(vm) 41030519Ssam struct vba_device *vm; 41124004Ssam { 41224004Ssam 41324004Ssam } 41424004Ssam 41524004Ssam vdstrategy(bp) 41625675Ssam register struct buf *bp; 41724004Ssam { 41830519Ssam register struct vba_device *vi; 41930519Ssam register struct disklabel *lp; 42030519Ssam register struct dksoftc *dk; 42130519Ssam register int unit; 42230573Skarels register daddr_t sn; 42330519Ssam struct buf *dp; 42430573Skarels daddr_t sz, maxsz; 42530519Ssam int part, s; 42624004Ssam 42730519Ssam unit = vdunit(bp->b_dev); 42830519Ssam if (unit > NDK) { 42929954Skarels bp->b_error = ENXIO; 43025675Ssam goto bad; 43129954Skarels } 43230519Ssam vi = vddinfo[unit]; 43330519Ssam lp = &dklabel[unit]; 43430519Ssam if (vi == 0 || vi->ui_alive == 0) { 43530519Ssam bp->b_error = ENXIO; 43630519Ssam goto bad; 43730519Ssam } 43830601Skarels sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize; 43930519Ssam dk = &dksoftc[unit]; 44030519Ssam if (dk->dk_state < OPEN) 44130519Ssam goto q; 44230519Ssam part = vdpart(bp->b_dev); 44330519Ssam if ((dk->dk_openpart & (1 << part)) == 0) { 44430519Ssam bp->b_error = ENODEV; 44530519Ssam goto bad; 44630519Ssam } 44730519Ssam maxsz = lp->d_partitions[part].p_size; 448*30756Skarels #ifndef SECSIZE 449*30756Skarels sn = bp->b_blkno << dk->dk_bshift; 450*30756Skarels #else SECSIZE 45130573Skarels sn = bp->b_blkno; 452*30756Skarels #endif SECSIZE 45330519Ssam if (sn < 0 || sn + sz > maxsz) { 45430519Ssam if (sn == maxsz) { 45529954Skarels bp->b_resid = bp->b_bcount; 45629954Skarels goto done; 45729954Skarels } 458*30756Skarels sz = maxsz - sn; 45930573Skarels if (sz <= 0) { 46030573Skarels bp->b_error = EINVAL; 46130573Skarels goto bad; 46230573Skarels } 46330573Skarels bp->b_bcount = sz * lp->d_secsize; 46425675Ssam } 46530519Ssam bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl; 466*30756Skarels #ifdef SECSIZE 467*30756Skarels if (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0) 468*30756Skarels panic("vdstrat blksize"); 469*30756Skarels #endif SECSIZE 47030519Ssam q: 47125675Ssam s = spl7(); 47230519Ssam dp = &dkutab[vi->ui_unit]; 47330519Ssam disksort(dp, bp); 47430519Ssam if (!dp->b_active) { 47530519Ssam (void) vdustart(vi); 47630573Skarels if (!vi->ui_mi->um_tab.b_active) 47730519Ssam vdstart(vi->ui_mi); 47824004Ssam } 47930519Ssam splx(s); 48024004Ssam return; 48125675Ssam bad: 48229954Skarels bp->b_flags |= B_ERROR; 48329954Skarels done: 48430519Ssam biodone(bp); 48530519Ssam return; 48624004Ssam } 48724004Ssam 48830519Ssam vdustart(vi) 48930519Ssam register struct vba_device *vi; 49024004Ssam { 49130519Ssam register struct buf *bp, *dp; 49230519Ssam register struct vba_ctlr *vm; 49330519Ssam register int unit = vi->ui_unit; 49430519Ssam register struct dksoftc *dk; 49530519Ssam register struct vdsoftc *vd; 49630519Ssam struct disklabel *lp; 49724004Ssam 49830519Ssam dp = &dkutab[unit]; 49930519Ssam /* 50030519Ssam * If queue empty, nothing to do. 50130519Ssam */ 50230519Ssam if ((bp = dp->b_actf) == NULL) 50330519Ssam return; 50430519Ssam /* 50530574Skarels * If drive is off-cylinder and controller supports seeks, 50630574Skarels * place drive on seek queue for controller. 50730574Skarels * Otherwise, place on transfer queue. 50830519Ssam */ 50930519Ssam vd = &vdsoftc[vi->ui_ctlr]; 51030519Ssam dk = &dksoftc[unit]; 51130574Skarels vm = vi->ui_mi; 51230519Ssam if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) { 51330519Ssam lp = &dklabel[unit]; 51430574Skarels bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors; 51530574Skarels if (vm->um_tab.b_seekf == NULL) 51630574Skarels vm->um_tab.b_seekf = dp; 51730574Skarels else 51830574Skarels vm->um_tab.b_seekl->b_forw = dp; 51930574Skarels vm->um_tab.b_seekl = dp; 52030574Skarels } else { 52130574Skarels if (vm->um_tab.b_actf == NULL) 52230574Skarels vm->um_tab.b_actf = dp; 52330574Skarels else 52430574Skarels vm->um_tab.b_actl->b_forw = dp; 52530574Skarels vm->um_tab.b_actl = dp; 52630519Ssam } 52730573Skarels dp->b_forw = NULL; 52830573Skarels dp->b_active++; 52925675Ssam } 53025675Ssam 53125675Ssam /* 53230519Ssam * Start next transfer on a controller. 53330574Skarels * There are two queues of drives, the first on-cylinder 53430574Skarels * and the second off-cylinder from their next transfers. 53530574Skarels * Perform the first transfer for the first drive on the on-cylinder 53630574Skarels * queue, if any, otherwise the first transfer for the first drive 53730574Skarels * on the second queue. Initiate seeks on remaining drives on the 53830574Skarels * off-cylinder queue, then move them all to the on-cylinder queue. 53925675Ssam */ 54030519Ssam vdstart(vm) 54130519Ssam register struct vba_ctlr *vm; 54225675Ssam { 54325675Ssam register struct buf *bp; 54430519Ssam register struct vba_device *vi; 54530519Ssam register struct vdsoftc *vd; 54630519Ssam register struct dksoftc *dk; 54730519Ssam register struct disklabel *lp; 54830519Ssam register int slave; 54930519Ssam register struct dcb **dcbp; 55030519Ssam struct mdcb *mdcb; 55130519Ssam struct buf *dp; 55230519Ssam int sn, tn; 55325675Ssam 55430519Ssam loop: 55530519Ssam /* 55630519Ssam * Pull a request off the controller queue. 55730519Ssam */ 55830574Skarels if ((dp = vm->um_tab.b_actf) == NULL && 55930574Skarels (dp = vm->um_tab.b_seekf) == NULL) 56030519Ssam return; 56130519Ssam if ((bp = dp->b_actf) == NULL) { 56230601Skarels if (dp == vm->um_tab.b_actf) 56330601Skarels vm->um_tab.b_actf = dp->b_forw; 56430601Skarels else 56530601Skarels vm->um_tab.b_seekf = dp->b_forw; 56630519Ssam goto loop; 56730519Ssam } 56825675Ssam 56924004Ssam /* 57030519Ssam * Mark controller busy, and determine 57130519Ssam * destination of this request. 57224004Ssam */ 57330519Ssam vm->um_tab.b_active++; 57430519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 57530519Ssam dk = &dksoftc[vi->ui_unit]; 576*30756Skarels #ifndef SECSIZE 577*30756Skarels sn = bp->b_blkno << dk->dk_bshift; 578*30756Skarels #else SECSIZE 57930573Skarels sn = bp->b_blkno; 580*30756Skarels #endif SECSIZE 58130519Ssam lp = &dklabel[vi->ui_unit]; 58230519Ssam sn %= lp->d_secpercyl; 58330519Ssam tn = sn / lp->d_nsectors; 58430519Ssam sn %= lp->d_nsectors; 58530519Ssam 58630519Ssam /* 58730519Ssam * Construct dcb for read/write command. 58830519Ssam */ 58930519Ssam vd = &vdsoftc[vm->um_ctlr]; 59030519Ssam slave = vi->ui_slave; 59130519Ssam vd->vd_dcb.intflg = DCBINT_DONE; 59230519Ssam vd->vd_dcb.devselect = slave; 59330519Ssam vd->vd_dcb.operrsta = 0; 59430519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 59530519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin; 59630519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 59730519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 59830574Skarels dk->dk_curcyl = bp->b_cylin; 59930574Skarels bp->b_track = 0; /* init overloaded field */ 600*30756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 601*30756Skarels if (vd->vd_flags & VD_SCATGATH && 602*30756Skarels ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0) { 603*30756Skarels vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW; 604*30756Skarels vd->vd_dcb.trailcnt += vba_sgsetup(bp, &vd->vd_rbuf, 605*30756Skarels &vd->vd_dcb.trail.sgtrail); 606*30756Skarels } else { 607*30756Skarels vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD; 608*30756Skarels vd->vd_dcb.trail.rwtrail.memadr = 609*30756Skarels vbasetup(bp, &vd->vd_rbuf, lp->d_secsize); 610*30756Skarels vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1; 611*30756Skarels } 61230574Skarels if (vi->ui_dk >= 0) { 61330574Skarels dk_busy |= 1<<vi->ui_dk; 61430574Skarels dk_xfer[vi->ui_dk]++; 61530574Skarels dk_wds[vi->ui_dk] += bp->b_bcount>>6; 61630574Skarels } 61730519Ssam 61830519Ssam /* 61930519Ssam * Look for any seeks to be performed on other drives on this 62030519Ssam * controller. If overlapped seeks exist, insert seek commands 62130519Ssam * on the controller's command queue before the transfer. 62230519Ssam */ 62330519Ssam dcbp = &vd->vd_mdcb.mdcb_head; 62430519Ssam 62530574Skarels if (dp == vm->um_tab.b_seekf) 62630574Skarels dp = dp->b_forw; 62730574Skarels else 62830574Skarels dp = vm->um_tab.b_seekf; 62930574Skarels for (; dp != NULL; dp = dp->b_forw) { 63030574Skarels if ((bp = dp->b_actf) == NULL) 63130574Skarels continue; 63230574Skarels vi = vddinfo[vdunit(bp->b_dev)]; 63330574Skarels dk = &dksoftc[vi->ui_unit]; 63430519Ssam dk->dk_curcyl = bp->b_cylin; 63530574Skarels if (vi->ui_dk >= 0) 63630574Skarels dk_seek[vi->ui_dk]++; 63730574Skarels dk->dk_dcb.operrsta = 0; 63830574Skarels dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin; 63930574Skarels dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track; 64030574Skarels *dcbp = (struct dcb *)dk->dk_dcbphys; 64130574Skarels dcbp = &dk->dk_dcb.nxtdcb; 64224004Ssam } 64330519Ssam *dcbp = (struct dcb *)vd->vd_dcbphys; 64430574Skarels if (vm->um_tab.b_actf) 64530574Skarels vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf; 64630574Skarels else 64730574Skarels vm->um_tab.b_actf = vm->um_tab.b_seekf; 64830601Skarels if (vm->um_tab.b_seekf) 64930601Skarels vm->um_tab.b_actl = vm->um_tab.b_seekl; 65030574Skarels vm->um_tab.b_seekf = 0; 65124004Ssam 65230519Ssam /* 65330519Ssam * Initiate operation. 65430519Ssam */ 65530519Ssam vd->vd_mdcb.mdcb_status = 0; 65630519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 65724004Ssam } 65824004Ssam 65930519Ssam #define DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE) 66024004Ssam /* 66124004Ssam * Handle a disk interrupt. 66224004Ssam */ 66325675Ssam vdintr(ctlr) 66430519Ssam register ctlr; 66524004Ssam { 66630519Ssam register struct buf *bp, *dp; 66730519Ssam register struct vba_ctlr *vm = vdminfo[ctlr]; 66830519Ssam register struct vba_device *vi; 66930519Ssam register struct vdsoftc *vd = &vdsoftc[ctlr]; 67030519Ssam register status; 67130601Skarels int ecode; 67230573Skarels struct dksoftc *dk; 67324004Ssam 67430519Ssam vd->vd_wticks = 0; 67530519Ssam if (!vm->um_tab.b_active) { 67625675Ssam printf("vd%d: stray interrupt\n", ctlr); 67724004Ssam return; 67824004Ssam } 67925675Ssam /* 68030519Ssam * Get device and block structures, and a pointer 68130519Ssam * to the vba_device for the drive. 68225675Ssam */ 68330519Ssam dp = vm->um_tab.b_actf; 68430519Ssam bp = dp->b_actf; 68530519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 68630574Skarels if (vi->ui_dk >= 0) 68730574Skarels dk_busy &= ~(1<<vi->ui_dk); 68830519Ssam /* 68930519Ssam * Check for and process errors on 69030519Ssam * either the drive or the controller. 69130519Ssam */ 69230519Ssam uncache(&vd->vd_dcb.operrsta); 69330519Ssam status = vd->vd_dcb.operrsta; 69430519Ssam if (status & VDERR_HARD) { 69530601Skarels if (vd->vd_type == VDTYPE_SMDE) { 69630601Skarels uncache(&vd->vd_dcb.err_code); 69730601Skarels ecode = vd->vd_dcb.err_code; 69830601Skarels } 69930519Ssam if (status & DCBS_WPT) { 70030519Ssam /* 70130519Ssam * Give up on write locked devices immediately. 70230519Ssam */ 70330573Skarels printf("dk%d: write locked\n", vi->ui_unit); 70430519Ssam bp->b_flags |= B_ERROR; 70530573Skarels } else if (status & VDERR_RETRY) { 70630519Ssam if (status & VDERR_DRIVE) { 70730519Ssam if (!vdreset_drive(vi)) 70830519Ssam vi->ui_alive = 0; 70930519Ssam } else if (status & VDERR_CTLR) 71030519Ssam vdreset_ctlr(vm); 71130519Ssam /* 71230519Ssam * Retry transfer once, unless reset failed. 71330519Ssam */ 71430519Ssam if (!vi->ui_alive || bp->b_errcnt++ >= 2) 71530519Ssam goto hard; 71630519Ssam vm->um_tab.b_active = 0; /* force retry */ 71730519Ssam } else { 71830519Ssam hard: 71930519Ssam bp->b_flags |= B_ERROR; 72030519Ssam /* NEED TO ADJUST b_blkno to failed sector */ 72130519Ssam harderr(bp, "dk"); 72230519Ssam printf("status %x (%b)", status, 72330519Ssam status &~ DONTCARE, VDERRBITS); 72430601Skarels if (vd->vd_type == VDTYPE_SMDE) 72530601Skarels printf(" ecode %x", ecode); 72630519Ssam printf("\n"); 72730519Ssam } 72830519Ssam } else if (status & DCBS_SOFT) 72930519Ssam vdsofterr(vd, bp, &vd->vd_dcb); 73030519Ssam if (vm->um_tab.b_active) { 73130519Ssam vm->um_tab.b_active = 0; 73230519Ssam vm->um_tab.b_errcnt = 0; 73330519Ssam vm->um_tab.b_actf = dp->b_forw; 73430519Ssam dp->b_active = 0; 73530519Ssam dp->b_errcnt = 0; 73630519Ssam dp->b_actf = bp->av_forw; 73730519Ssam bp->b_resid = 0; 73830601Skarels vbadone(bp, &vd->vd_rbuf); 73930519Ssam biodone(bp); 74030370Skarels /* 74130519Ssam * If this unit has more work to do, 74230519Ssam * then start it up right away. 74330370Skarels */ 74430519Ssam if (dp->b_actf) 74530519Ssam vdustart(vi); 74630573Skarels else if ((dk = &dksoftc[vi->ui_unit])->dk_openpart == 0) 74730573Skarels wakeup((caddr_t)dk); 74824004Ssam } 74925675Ssam /* 75030519Ssam * If there are devices ready to 75130519Ssam * transfer, start the controller. 75225675Ssam */ 75330601Skarels if (vm->um_tab.b_actf || vm->um_tab.b_seekf) 75430519Ssam vdstart(vm); 75524004Ssam } 75624004Ssam 75730519Ssam vdsofterr(vd, bp, dcb) 75830519Ssam struct vdsoftc *vd; 75925675Ssam register struct buf *bp; 76030519Ssam register struct dcb *dcb; 76125675Ssam { 76230519Ssam int unit = vdunit(bp->b_dev), status = dcb->operrsta; 76330519Ssam char part = 'a' + vdpart(bp->b_dev); 76425675Ssam 76530601Skarels if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) { 76630519Ssam if (vd->vd_type == VDTYPE_SMDE) 76730519Ssam uncache(&dcb->err_code); 76830519Ssam log(LOG_WARNING, "dk%d%c: soft error sn%d status %b ecode %x\n", 76930519Ssam unit, part, bp->b_blkno, status, VDERRBITS, dcb->err_code); 77030519Ssam } else 77130370Skarels log(LOG_WARNING, "dk%d%c: soft ecc sn%d\n", 77230370Skarels unit, part, bp->b_blkno); 77325675Ssam } 77425675Ssam 77524004Ssam vdread(dev, uio) 77625675Ssam dev_t dev; 77725675Ssam struct uio *uio; 77824004Ssam { 77930519Ssam register int unit = vdunit(dev); 78024004Ssam 78129564Ssam if (unit >= NDK) 78225675Ssam return (ENXIO); 78330519Ssam return (physio(vdstrategy, &rdkbuf[unit], dev, B_READ, minphys, uio)); 78424004Ssam } 78524004Ssam 78624004Ssam vdwrite(dev, uio) 78725675Ssam dev_t dev; 78825675Ssam struct uio *uio; 78924004Ssam { 79030519Ssam register int unit = vdunit(dev); 79124004Ssam 79229564Ssam if (unit >= NDK) 79325675Ssam return (ENXIO); 79430519Ssam return (physio(vdstrategy, &rdkbuf[unit], dev, B_WRITE, minphys, uio)); 79524004Ssam } 79624004Ssam 79730519Ssam vdioctl(dev, cmd, data, flag) 79825675Ssam dev_t dev; 79930519Ssam int cmd; 80030519Ssam caddr_t data; 80130519Ssam int flag; 80224004Ssam { 80330519Ssam int unit = vdunit(dev); 80430519Ssam register struct disklabel *lp = &dklabel[unit]; 80530519Ssam int error = 0; 80624004Ssam 80730519Ssam switch (cmd) { 80830519Ssam 80930519Ssam case DIOCGDINFO: 81030519Ssam *(struct disklabel *)data = *lp; 81130519Ssam break; 81230519Ssam 81330573Skarels case DIOCGPART: 81430573Skarels ((struct partinfo *)data)->disklab = lp; 81530573Skarels ((struct partinfo *)data)->part = 81630573Skarels &lp->d_partitions[vdpart(dev)]; 81730519Ssam break; 81830519Ssam 81930519Ssam case DIOCSDINFO: 82030519Ssam if ((flag & FWRITE) == 0) 82130519Ssam error = EBADF; 82230519Ssam else 82330519Ssam *lp = *(struct disklabel *)data; 82430519Ssam break; 82530519Ssam 82630519Ssam case DIOCWDINFO: { 82730519Ssam struct buf *bp; 82830519Ssam struct disklabel *dlp; 82930519Ssam 83030519Ssam if ((flag & FWRITE) == 0) { 83130519Ssam error = EBADF; 83230519Ssam break; 83330519Ssam } 83430519Ssam *lp = *(struct disklabel *)data; 83530519Ssam bp = geteblk(lp->d_secsize); 836*30756Skarels bp->b_dev = makedev(major(dev), vdminor(vdunit(dev), 0)); 83730519Ssam bp->b_blkno = LABELSECTOR; 83830519Ssam bp->b_bcount = lp->d_secsize; 83930519Ssam bp->b_flags = B_READ; 84030519Ssam dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET); 84130519Ssam vdstrategy(bp); 84230519Ssam biowait(bp); 84330519Ssam if (bp->b_flags & B_ERROR) { 84430519Ssam error = u.u_error; /* XXX */ 84530519Ssam u.u_error = 0; 84630519Ssam goto bad; 84730519Ssam } 84830519Ssam *dlp = *lp; 84930519Ssam bp->b_flags = B_WRITE; 85030519Ssam vdstrategy(bp); 85130519Ssam biowait(bp); 85230519Ssam if (bp->b_flags & B_ERROR) { 85330519Ssam error = u.u_error; /* XXX */ 85430519Ssam u.u_error = 0; 85530519Ssam } 85630519Ssam bad: 85730519Ssam brelse(bp); 85830519Ssam break; 85925675Ssam } 86030519Ssam 86130519Ssam default: 86230519Ssam error = ENOTTY; 86330519Ssam break; 86424004Ssam } 86525675Ssam return (0); 86624004Ssam } 86724004Ssam 86825675Ssam /* 86930519Ssam * Watch for lost interrupts. 87025675Ssam */ 87130519Ssam vdwatch() 87230519Ssam { 87330519Ssam register struct vdsoftc *vd; 87430519Ssam register struct vba_ctlr *vm; 87525675Ssam register int ctlr, unit; 87630519Ssam 87730519Ssam timeout(vdwatch, (caddr_t)0, hz); 87830519Ssam for (ctlr = 0; ctlr < NVD; ctlr++) { 87930519Ssam vm = vdminfo[ctlr]; 88030519Ssam if (vm == 0 || vm->um_alive == 0) 88130519Ssam continue; 88230519Ssam vd = &vdsoftc[ctlr]; 88330601Skarels if (vm->um_tab.b_active && vd->vd_wticks++ >= 20) { 88430519Ssam vd->vd_wticks = 0; 88530519Ssam printf("vd%d: lost interrupt\n", ctlr); 88630519Ssam /* abort pending dcb's and restart controller */ 88730519Ssam } 88830519Ssam } 88930519Ssam } 89030519Ssam 89130519Ssam #define DBSIZE 64 /* controller limit with 1K sectors */ 89230519Ssam /* 89330519Ssam * Crash dump. 89430519Ssam */ 89530519Ssam vddump(dev) 89630519Ssam dev_t dev; 89724004Ssam { 89830519Ssam register struct vba_device *vi; 89930519Ssam register struct vba_ctlr *vm; 90030519Ssam register struct disklabel *lp; 90130519Ssam register struct vdsoftc *vd; 90230519Ssam struct dksoftc *dk; 90330519Ssam int part, unit, num; 90430601Skarels u_long start; 90524004Ssam 90630519Ssam start = 0; 90730519Ssam unit = vdunit(dev); 90830519Ssam if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 90930519Ssam return (ENXIO); 91030519Ssam dk = &dksoftc[unit]; 91130519Ssam if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 91230519Ssam return (ENXIO); 91330519Ssam lp = &dklabel[unit]; 91430519Ssam part = vdpart(dev); 91530519Ssam if (part >= lp->d_npartitions) 91630519Ssam return (ENXIO); 91730519Ssam vm = vdminfo[vi->ui_ctlr]; 91830519Ssam vdreset_ctlr(vm); 91930519Ssam if (dumplo < 0) 92030519Ssam return (EINVAL); 92130519Ssam /* 922*30756Skarels * Maxfree is in pages, dumplo is in DEV_BSIZE units. 92330519Ssam */ 92430519Ssam num = maxfree * (NBPG / lp->d_secsize); 925*30756Skarels dumplo *= DEV_BSIZE / lp->d_secsize; 92630519Ssam if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size) 92730519Ssam num = lp->d_partitions[vdpart(dev)].p_size - dumplo; 92830519Ssam vd = &vdsoftc[vm->um_ctlr]; 92930519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 93030519Ssam vd->vd_dcb.opcode = VDOP_WD; 93130519Ssam vd->vd_dcb.devselect = vi->ui_slave; 932*30756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 93330519Ssam while (num > 0) { 93430519Ssam int nsec, cn, sn, tn; 93530519Ssam 93630519Ssam nsec = MIN(num, DBSIZE); 93730601Skarels sn = dumplo + start / lp->d_secsize; 93830519Ssam cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) / 93930519Ssam lp->d_secpercyl; 94030519Ssam sn %= lp->d_secpercyl; 94130519Ssam tn = sn / lp->d_nsectors; 94230519Ssam sn %= lp->d_nsectors; 94330519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 94430519Ssam vd->vd_dcb.trail.rwtrail.memadr = start; 94530519Ssam vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1; 94630519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = cn; 94730519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 94830519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 94930519Ssam vd->vd_dcb.operrsta = 0; 95030519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 95130519Ssam if (!vdpoll(vm, 5)) { 95230519Ssam printf(" during dump\n"); 95330519Ssam return (EIO); 95430519Ssam } 95530519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 95630519Ssam printf("dk%d: hard error, status=%b\n", unit, 95730519Ssam vd->vd_dcb.operrsta, VDERRBITS); 95830519Ssam return (EIO); 95930519Ssam } 96030519Ssam start += nsec * lp->d_secsize; 96130519Ssam num -= nsec; 96225675Ssam } 96330519Ssam return (0); 96424004Ssam } 96524004Ssam 96624004Ssam vdsize(dev) 96725675Ssam dev_t dev; 96824004Ssam { 96930519Ssam register int unit = vdunit(dev); 97030519Ssam register struct dksoftc *dk; 97130519Ssam struct vba_device *vi; 97230519Ssam struct disklabel *lp; 97324004Ssam 97430519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 || 97530519Ssam (dk = &dksoftc[unit])->dk_state != OPEN) 97625675Ssam return (-1); 97730519Ssam lp = &dklabel[unit]; 978*30756Skarels #ifdef SECSIZE 97930573Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size); 980*30756Skarels #else SECSIZE 981*30756Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift); 982*30756Skarels #endif SECSIZE 98324004Ssam } 98424004Ssam 98525675Ssam /* 98625675Ssam * Perform a controller reset. 98725675Ssam */ 98830519Ssam vdreset_ctlr(vm) 98930519Ssam register struct vba_ctlr *vm; 99024004Ssam { 99130519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 99230519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 99330519Ssam register int unit; 99430519Ssam struct vba_device *vi; 99525675Ssam 99630519Ssam VDRESET(vdaddr, vd->vd_type); 99730519Ssam if (vd->vd_type == VDTYPE_SMDE) { 99830519Ssam vdaddr->vdcsr = 0; 99930519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 100030519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 100130519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 100230519Ssam vdaddr->vdtcf_data = AM_ENPDA; 100330519Ssam vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD | 100425675Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 100525675Ssam } 100630519Ssam if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { 100730519Ssam printf("%s cmd failed\n", 100830519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 100930370Skarels return; 101025675Ssam } 101130519Ssam for (unit = 0; unit < NDK; unit++) 101230519Ssam if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive) 101330519Ssam (void) vdreset_drive(vi); 101430519Ssam } 101530519Ssam 101630519Ssam vdreset_drive(vi) 101730519Ssam register struct vba_device *vi; 101830519Ssam { 101930519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 102030519Ssam struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; 102130519Ssam struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 102230519Ssam struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 102330519Ssam 102430519Ssam top: 102530519Ssam vd->vd_dcb.opcode = VDOP_CONFIG; /* command */ 102630519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 102730519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 102830519Ssam vd->vd_dcb.operrsta = 0; 102930519Ssam vd->vd_dcb.devselect = vi->ui_slave; 103030519Ssam vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders; 103130519Ssam vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks; 103230519Ssam if (vd->vd_type == VDTYPE_SMDE) { 1033*30756Skarels vd->vd_dcb.trailcnt = sizeof (struct treset) / sizeof (long); 103430519Ssam vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors; 103530601Skarels vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack; 103630519Ssam vd->vd_dcb.trail.rstrail.recovery = 0x18f; 103730519Ssam } else 103830519Ssam vd->vd_dcb.trailcnt = 2; /* XXX */ 103930519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 104030519Ssam vd->vd_mdcb.mdcb_status = 0; 104130519Ssam VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type); 104230519Ssam if (!vdpoll(vm, 5)) { 104330519Ssam printf(" during config\n"); 104430519Ssam return (0); 104525675Ssam } 104630519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 104730519Ssam if (vd->vd_type == VDTYPE_SMDE && 104830519Ssam (vdaddr->vdstatus[vi->ui_slave]&STA_US) == 0) 104930519Ssam return (0); 105030519Ssam if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) 105130519Ssam printf("dk%d: config error\n", vi->ui_unit); 105230519Ssam else if ((vd->vd_flags&VD_STARTED) == 0) { 105330519Ssam int started; 105430519Ssam 105530519Ssam printf("vd%d: starting drives, wait ... ", vm->um_ctlr); 105630519Ssam vd->vd_flags |= VD_STARTED; 105730519Ssam started = (vdcmd(vm, VDOP_START, 10) == 1); 105830519Ssam DELAY(62000000); 105930519Ssam printf("\n"); 106030519Ssam if (started) 106130519Ssam goto top; 106230519Ssam } 106330519Ssam return (0); 106430519Ssam } 106530519Ssam return (1); 106625675Ssam } 106724004Ssam 106825675Ssam /* 106930519Ssam * Perform a command w/o trailer. 107025675Ssam */ 107130519Ssam vdcmd(vm, cmd, t) 107230519Ssam register struct vba_ctlr *vm; 107325675Ssam { 107430519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 107525675Ssam 107630519Ssam vd->vd_dcb.opcode = cmd; /* command */ 107730519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 107830519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 107930519Ssam vd->vd_dcb.operrsta = 0; 108030519Ssam vd->vd_dcb.devselect = 0; 108130519Ssam vd->vd_dcb.trailcnt = 0; 108230519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 108330519Ssam vd->vd_mdcb.mdcb_status = 0; 108430519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 108530519Ssam if (!vdpoll(vm, t)) { 108630519Ssam printf(" during init\n"); 108730370Skarels return (0); 108830370Skarels } 108930519Ssam return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0); 109025675Ssam } 109125675Ssam 109225925Ssam /* 109330519Ssam * Poll controller until operation 109430519Ssam * completes or timeout expires. 109525925Ssam */ 109630519Ssam vdpoll(vm, t) 109730519Ssam register struct vba_ctlr *vm; 109825925Ssam register int t; 109925925Ssam { 110030519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 110130519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 110225925Ssam 110325925Ssam t *= 1000; 110430370Skarels for (;;) { 110530519Ssam uncache(&vd->vd_dcb.operrsta); 110630519Ssam if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT)) 110730370Skarels break; 110825925Ssam if (--t <= 0) { 110930519Ssam printf("vd%d: controller timeout", vm->um_ctlr); 111030519Ssam VDABORT(vdaddr, vd->vd_type); 111125925Ssam DELAY(30000); 111225925Ssam return (0); 111325925Ssam } 111430370Skarels DELAY(1000); 111525925Ssam } 111630519Ssam if (vd->vd_type == VDTYPE_SMDE) { 111730519Ssam do { 111825925Ssam DELAY(50); 111930519Ssam uncache(&vdaddr->vdcsr); 112030519Ssam } while (vdaddr->vdcsr & CS_GO); 112125925Ssam DELAY(300); 112225925Ssam } 112325925Ssam DELAY(200); 112430519Ssam uncache(&vd->vd_dcb.operrsta); 112525925Ssam return (1); 112625925Ssam } 112725925Ssam 112830519Ssam #ifdef COMPAT_42 112930519Ssam struct vdst { 113030519Ssam int nsec; /* sectors/track */ 113130519Ssam int ntrack; /* tracks/cylinder */ 113230519Ssam int ncyl; /* cylinders */ 113330519Ssam char *name; /* type name */ 113430519Ssam struct { 113530519Ssam int off; /* partition offset in sectors */ 113630519Ssam int size; /* partition size in sectors */ 113730573Skarels } parts[8]; 113830519Ssam } vdst[] = { 113930573Skarels { 48, 24, 711, "xsd", 114030573Skarels {0, 30528}, /* a cyl 0 - 52 */ 114130573Skarels {30528, 30528}, /* b cyl 53 - 105 */ 114230573Skarels {61056, 345600}, /* c cyl 106 - 705 */ 114330573Skarels {118656, 288000}, /* d cyl 206 - 705 */ 114430573Skarels {176256, 230400}, /* e cyl 306 - 705 */ 114530573Skarels {233856, 172800}, /* f cyl 406 - 705 */ 114630573Skarels {291456, 115200}, /* g cyl 506 - 705 */ 114730573Skarels {349056, 57600} /* h cyl 606 - 705 */ 114830573Skarels }, 114930573Skarels { 44, 20, 842, "egl", 115030601Skarels {0, 52800}, /* egl0a cyl 0 - 59 */ 115130601Skarels {52800, 66000}, /* egl0b cyl 60 - 134 */ 115230601Skarels {118800, 617760}, /* egl0c cyl 135 - 836 */ 1153*30756Skarels {736560, 4400}, /* egl0d cyl 837 - 841 */ 115430601Skarels {0, 736560}, /* egl0e cyl 0 - 836 */ 1155*30756Skarels {0, 740960}, /* egl0f cyl 0 - 841 */ 115630601Skarels {118800, 310640}, /* egl0g cyl 135 - 487 */ 115730601Skarels {429440, 307120} /* egl0h cyl 488 - 836 */ 115830573Skarels }, 115930573Skarels { 64, 10, 823, "fuj", 116030573Skarels {0, 19200}, /* fuj0a cyl 0 - 59 */ 116130573Skarels {19200, 24000}, /* fuj0b cyl 60 - 134 */ 116230573Skarels {43200, 218560}, /* fuj0c cyl 135 - 817 */ 116330573Skarels {79680, 182080}, /* fuj0d cyl 249 - 817 */ 116430573Skarels {116160, 145600}, /* fuj0e cyl 363 - 817 */ 116530573Skarels {152640, 109120}, /* fuj0f cyl 477 - 817 */ 116630573Skarels {189120, 72640}, /* fuj0g cyl 591 - 817 */ 116730573Skarels {225600, 36160} /* fug0h cyl 705 - 817 */ 116830573Skarels }, 116930573Skarels { 32, 24, 711, "xfd", 1170*30756Skarels { 0, 40704 }, /* a cyl 0 - 52 */ 1171*30756Skarels { 40704, 40704 }, /* b cyl 53 - 105 */ 1172*30756Skarels { 81408, 460800 }, /* c cyl 106 - 705 */ 1173*30756Skarels { 0, 81408 }, /* d cyl 709 - 710 (a & b) */ 1174*30756Skarels { 0, 542208 }, /* e cyl 0 - 705 */ 1175*30756Skarels { 40704, 501504 }, /* f cyl 53 - 705 (b & c) */ 1176*30756Skarels { 81408, 230400 }, /* g cyl 106 - 405 (1/2 of c) */ 1177*30756Skarels { 311808,230400 } /* h cyl 406 - 705 (1/2 of c) */ 117830573Skarels }, 117930573Skarels { 32, 19, 823, "smd", 118030573Skarels {0, 20064}, /* a cyl 0-65 */ 118130573Skarels {20064, 13680}, /* b cyl 66-110 */ 118230573Skarels {33744, 214928}, /* c cyl 111-817 */ 118330573Skarels {69616, 179056}, /* d cyl 229 - 817 */ 118430573Skarels {105488, 143184}, /* e cyl 347 - 817 */ 118530573Skarels {141360, 107312}, /* f cyl 465 - 817 */ 118630573Skarels {177232, 71440}, /* g cyl 583 - 817 */ 118730573Skarels {213104, 35568} /* h cyl 701 - 817 */ 118830573Skarels }, 118930573Skarels { 32, 10, 823, "fsd", 1190*30756Skarels {0, 19200}, /* a cyl 0 - 59 */ 1191*30756Skarels {19200, 24000}, /* b cyl 60 - 134 */ 1192*30756Skarels {43200, 218560}, /* c cyl 135 - 817 */ 119330573Skarels } 119430519Ssam }; 119530519Ssam #define NVDST (sizeof (vdst) / sizeof (vdst[0])) 119630519Ssam 119725675Ssam /* 119830519Ssam * Construct a label for an unlabeled pack. We 119930519Ssam * deduce the drive type by reading from the last 120030519Ssam * track on successively smaller drives until we 120130519Ssam * don't get an error. 120225675Ssam */ 120330519Ssam vdmaptype(vi, lp) 120430519Ssam register struct vba_device *vi; 120530519Ssam register struct disklabel *lp; 120625675Ssam { 120730519Ssam register struct vdsoftc *vd; 120830519Ssam register struct vdst *p; 120930519Ssam struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; 121030519Ssam int i; 121125675Ssam 121230519Ssam vd = &vdsoftc[vi->ui_ctlr]; 121330519Ssam for (p = vdst; p < &vdst[NVDST]; p++) { 121430519Ssam if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32) 121530519Ssam continue; 121630519Ssam lp->d_nsectors = p->nsec; 121730519Ssam lp->d_ntracks = p->ntrack; 121830519Ssam lp->d_ncylinders = p->ncyl; 121930519Ssam if (!vdreset_drive(vi)) 122030519Ssam return (0); 122130519Ssam vd->vd_dcb.opcode = VDOP_RD; 122230519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 122330519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 122430519Ssam vd->vd_dcb.devselect = vi->ui_slave; 1225*30756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 122630601Skarels vd->vd_dcb.trail.rwtrail.memadr = 122730601Skarels vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf); 122830519Ssam vd->vd_dcb.trail.rwtrail.wcount = 512 / sizeof(short); 122930519Ssam vd->vd_dcb.operrsta = 0; 123030519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2; 123130519Ssam vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1; 123230519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1; 123330519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 123430519Ssam vd->vd_mdcb.mdcb_status = 0; 123530519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 123630519Ssam if (!vdpoll(vm, 60)) 123730519Ssam printf(" during probe\n"); 123830519Ssam if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0) 123930519Ssam break; 124024004Ssam } 124130519Ssam if (p >= &vdst[NVDST]) { 124230519Ssam printf("dk%d: unknown drive type\n", vi->ui_unit); 124330519Ssam return (0); 124430519Ssam } 124530573Skarels for (i = 0; i < 8; i++) { 124630519Ssam lp->d_partitions[i].p_offset = p->parts[i].off; 124730519Ssam lp->d_partitions[i].p_size = p->parts[i].size; 124830519Ssam } 124930573Skarels lp->d_npartitions = 8; 125030519Ssam lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 125130519Ssam lp->d_rpm = 3600; 125230519Ssam lp->d_secsize = 512; 125330519Ssam bcopy(p->name, lp->d_typename, 4); 125430519Ssam return (1); 125524004Ssam } 125630519Ssam #endif COMPAT_42 125724004Ssam #endif 1258