1*30519Ssam /* vd.c 1.14 87/02/18 */ 224004Ssam 329564Ssam #include "dk.h" 424004Ssam #if NVD > 0 524004Ssam /* 6*30519Ssam * 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" 14*30519Ssam #include "disklabel.h" 1525675Ssam #include "map.h" 16*30519Ssam #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" 24*30519Ssam #include "ioctl.h" 2524004Ssam 2629951Skarels #include "../tahoe/cpu.h" 2729951Skarels #include "../tahoe/mtpr.h" 2829951Skarels #include "../tahoe/pte.h" 2929951Skarels 3025675Ssam #include "../tahoevba/vbavar.h" 3125928Ssam #include "../tahoevba/vdreg.h" 3224004Ssam 33*30519Ssam #define COMPAT_42 34*30519Ssam 3525925Ssam #define VDMAXIO (MAXBPTE*NBPG) 3624004Ssam 37*30519Ssam #define vdunit(dev) (minor(dev) >> 3) 38*30519Ssam #define vdpart(dev) (minor(dev) & 0x07) 39*30519Ssam #define vdminor(unit,part) (((unit) << 3) | (part)) 4024004Ssam 4124004Ssam struct vba_ctlr *vdminfo[NVD]; 4229564Ssam struct vba_device *vddinfo[NDK]; 4325675Ssam int vdprobe(), vdslave(), vdattach(), vddgo(); 44*30519Ssam long vdaddr[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 }; 4525675Ssam struct vba_driver vddriver = 46*30519Ssam { vdprobe, vdslave, vdattach, vddgo, vdaddr, "dk", vddinfo, "vd", vdminfo }; 4724004Ssam 4824004Ssam /* 49*30519Ssam * Per-controller state. 50*30519Ssam */ 51*30519Ssam struct vdsoftc { 52*30519Ssam u_short vd_flags; 53*30519Ssam #define VD_INIT 0x1 /* controller initialized */ 54*30519Ssam #define VD_STARTED 0x2 /* start command issued */ 55*30519Ssam #define VD_DOSEEKS 0x4 /* should overlap seeks */ 56*30519Ssam u_short vd_type; /* controller type */ 57*30519Ssam u_short vd_wticks; /* timeout */ 58*30519Ssam u_short vd_offcyl; /* off cylinder bitmask */ 59*30519Ssam struct mdcb vd_mdcb; /* master command block */ 60*30519Ssam u_long vd_mdcbphys; /* physical address of vd_mdcb */ 61*30519Ssam struct dcb vd_dcb; /* i/o command block */ 62*30519Ssam u_long vd_dcbphys; /* physical address of vd_dcb */ 63*30519Ssam struct pte *vd_map; /* i/o page map */ 64*30519Ssam caddr_t vd_utl; /* mapped i/o space */ 65*30519Ssam caddr_t vd_rawbuf; /* buffer for raw+swap i/o */ 66*30519Ssam } vdsoftc[NVD]; 67*30519Ssam 68*30519Ssam /* 6925675Ssam * Per-drive state. 7025675Ssam */ 71*30519Ssam struct dksoftc { 72*30519Ssam u_short dk_state; /* open fsm */ 73*30519Ssam u_short dk_openpart; /* units open on this drive */ 74*30519Ssam u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */ 75*30519Ssam u_short dk_curdaddr; /* last selected track & sector */ 76*30519Ssam u_int dk_curcyl; /* last selected cylinder */ 77*30519Ssam struct dcb dk_dcb; /* seek command block */ 78*30519Ssam u_long dk_dcbphys; /* physical address of dk_dcb */ 79*30519Ssam } dksoftc[NDK]; 8024004Ssam 8124004Ssam /* 82*30519Ssam * Drive states. Used during steps of open/initialization. 83*30519Ssam * States < OPEN (> 0) are transient, during an open operation. 84*30519Ssam * OPENRAW is used for unabeled disks, to allow format operations. 8525675Ssam */ 86*30519Ssam #define CLOSED 0 /* disk is closed */ 87*30519Ssam #define WANTOPEN 1 /* open requested, not started */ 88*30519Ssam #define WANTOPENRAW 2 /* open requested, no label */ 89*30519Ssam #define RDLABEL 3 /* reading pack label */ 90*30519Ssam #define OPEN 4 /* intialized and ready */ 91*30519Ssam #define OPENRAW 5 /* open, no label */ 9224004Ssam 93*30519Ssam struct buf rdkbuf[NDK]; /* raw i/o buffer headers */ 94*30519Ssam struct buf dkutab[NDK]; /* i/o queue headers */ 95*30519Ssam struct disklabel dklabel[NDK]; /* pack labels */ 9624004Ssam 97*30519Ssam #define b_cylin b_resid 98*30519Ssam #define b_daddr b_error 99*30519Ssam 100*30519Ssam int vdwstart, vdwatch(); 101*30519Ssam 10224004Ssam /* 10325675Ssam * See if the controller is really there; if so, initialize it. 10425675Ssam */ 10525857Ssam vdprobe(reg, vm) 10625857Ssam caddr_t reg; 10725857Ssam struct vba_ctlr *vm; 10825675Ssam { 10925857Ssam register br, cvec; /* must be r12, r11 */ 110*30519Ssam register struct vddevice *vdaddr = (struct vddevice *)reg; 111*30519Ssam struct vdsoftc *vd; 11225857Ssam 11330370Skarels #ifdef lint 11430370Skarels br = 0; cvec = br; br = cvec; 11530370Skarels vdintr(0); 11630370Skarels #endif 11725857Ssam if (badaddr((caddr_t)reg, 2)) 11825675Ssam return (0); 119*30519Ssam vd = &vdsoftc[vm->um_ctlr]; 120*30519Ssam vdaddr->vdreset = 0xffffffff; 12125675Ssam DELAY(1000000); 122*30519Ssam if (vdaddr->vdreset != (unsigned)0xffffffff) { 123*30519Ssam vd->vd_type = VDTYPE_VDDC; 124*30519Ssam vd->vd_flags &= ~VD_DOSEEKS; 12525675Ssam DELAY(1000000); 12625675Ssam } else { 127*30519Ssam vd->vd_type = VDTYPE_SMDE; 128*30519Ssam vd->vd_flags |= VD_DOSEEKS; 129*30519Ssam vdaddr->vdrstclr = 0; 13025675Ssam DELAY(3000000); 131*30519Ssam vdaddr->vdcsr = 0; 132*30519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 133*30519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 134*30519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 135*30519Ssam vdaddr->vdtcf_data = AM_ENPDA; 136*30519Ssam vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS | 13729921Skarels XMD_32BIT | BSZ_16WRD | 13825925Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 13925675Ssam } 140*30519Ssam vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb); 141*30519Ssam vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb); 142*30519Ssam vm->um_addr = reg; /* XXX */ 143*30519Ssam if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { 144*30519Ssam printf("vd%d: %s cmd failed\n", vm->um_ctlr, 145*30519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 146*30519Ssam return (0); 147*30519Ssam } 14825925Ssam /* 14925950Ssam * Allocate page tables and i/o buffer. 15025925Ssam */ 151*30519Ssam vbmapalloc(btoc(VDMAXIO)+1, &vd->vd_map, &vd->vd_utl); 152*30519Ssam vd->vd_rawbuf = calloc(VDMAXIO); 15325857Ssam br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */ 154*30519Ssam return (sizeof (struct vddevice)); 15525675Ssam } 15624004Ssam 15724004Ssam /* 158*30519Ssam * See if a drive is really there. 159*30519Ssam * 160*30519Ssam * Can't read pack label here as various data structures 161*30519Ssam * aren't setup for doing a read in a straightforward 162*30519Ssam * manner. Instead just probe for the drive and leave 163*30519Ssam * the pack label stuff to the attach routine. 16425675Ssam */ 16525675Ssam vdslave(vi, addr) 16625675Ssam register struct vba_device *vi; 167*30519Ssam struct vddevice *vdaddr; 16825675Ssam { 169*30519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 170*30519Ssam struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 17124004Ssam 172*30519Ssam if ((vd->vd_flags&VD_INIT) == 0) { 17325925Ssam printf("vd%d: %s controller\n", vi->ui_ctlr, 174*30519Ssam vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE"); 175*30519Ssam vd->vd_flags |= VD_INIT; 17625675Ssam } 177*30519Ssam 17825675Ssam /* 179*30519Ssam * Initialize label enough to do a reset on 180*30519Ssam * the drive. The remainder of the default 181*30519Ssam * label values will be filled in in vdinit 182*30519Ssam * at attach time. 18325675Ssam */ 184*30519Ssam lp->d_secsize = DEV_BSIZE / 2; /* XXX */ 185*30519Ssam lp->d_nsectors = 32; 186*30519Ssam lp->d_ntracks = 24; 187*30519Ssam lp->d_ncylinders = 711; 188*30519Ssam lp->d_secpercyl = 32*24; 189*30519Ssam return (vdreset_drive(vi)); 19024004Ssam } 19124004Ssam 192*30519Ssam /* 193*30519Ssam * Read pack label. 194*30519Ssam */ 195*30519Ssam vdattach(vi) 196*30519Ssam register struct vba_device *vi; 19724004Ssam { 198*30519Ssam register int unit = vi->ui_unit; 199*30519Ssam register struct dksoftc *dk = &dksoftc[unit]; 200*30519Ssam register struct disklabel *lp; 20125675Ssam 202*30519Ssam if (vdwstart == 0) { 203*30519Ssam timeout(vdwatch, (caddr_t)0, hz); 204*30519Ssam vdwstart++; 20525675Ssam } 206*30519Ssam /* 207*30519Ssam * Try to initialize device and read pack label. 208*30519Ssam */ 209*30519Ssam if (vdinit(vdminor(unit, 0), 0) != 0) { 210*30519Ssam printf(": unknown drive type"); 211*30519Ssam return; 21225675Ssam } 213*30519Ssam /* 214*30519Ssam * Initialize invariant portion of 215*30519Ssam * dcb used for overlapped seeks. 216*30519Ssam */ 217*30519Ssam dk->dk_dcb.opcode = VDOP_SEEK; 218*30519Ssam dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA; 219*30519Ssam dk->dk_dcb.devselect = vi->ui_slave; 220*30519Ssam dk->dk_dcb.trailcnt = sizeof (trseek) / sizeof (long); 221*30519Ssam dk->dk_dcb.trail.sktrail.skaddr.sector = 0; 222*30519Ssam dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb); 223*30519Ssam lp = &dklabel[unit]; 224*30519Ssam printf(": %s <ntrak %d, ncyl %d, nsec %d>", 225*30519Ssam lp->d_typename, lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors); 226*30519Ssam /* 227*30519Ssam * (60 / rpm) / (sectors per track * (bytes per sector / 2)) 228*30519Ssam */ 229*30519Ssam if (vi->ui_dk >= 0) 230*30519Ssam dk_mspw[vi->ui_dk] = 120.0 / 231*30519Ssam (lp->d_rpm * lp->d_nsectors * lp->d_secsize); 232*30519Ssam #ifdef notyet 233*30519Ssam addwap(makedev(VDMAJOR, vdminor(unit, 0)), &dklabel[unit]); 234*30519Ssam #endif 23524004Ssam } 23624004Ssam 237*30519Ssam /*ARGSUSED*/ 238*30519Ssam vdopen(dev, flags) 239*30519Ssam dev_t dev; 240*30519Ssam int flags; 24124004Ssam { 242*30519Ssam register unit = vdunit(dev); 243*30519Ssam register struct disklabel *lp; 244*30519Ssam register struct dksoftc *dk; 245*30519Ssam register struct partition *pp; 246*30519Ssam struct vba_device *vi; 247*30519Ssam int s, error, part = vdpart(dev); 248*30519Ssam daddr_t start, end; 24924004Ssam 250*30519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 251*30519Ssam return (ENXIO); 252*30519Ssam lp = &dklabel[unit]; 253*30519Ssam dk = &dksoftc[unit]; 254*30519Ssam 255*30519Ssam s = spl7(); 256*30519Ssam while (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 257*30519Ssam dk->dk_state != CLOSED) 258*30519Ssam sleep((caddr_t)dk, PZERO+1); 259*30519Ssam splx(s); 260*30519Ssam if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 261*30519Ssam if (error = vdinit(dev, flags)) 262*30519Ssam return (error); 263*30519Ssam /* 264*30519Ssam * Warn if a partion is opened 265*30519Ssam * that overlaps another partition which is open 266*30519Ssam * unless one is the "raw" partition (whole disk). 267*30519Ssam */ 268*30519Ssam #define RAWPART 2 /* 'c' partition */ /* XXX */ 269*30519Ssam if ((dk->dk_openpart & (1 << part)) == 0 && 270*30519Ssam part != RAWPART) { 271*30519Ssam pp = &lp->d_partitions[part]; 272*30519Ssam start = pp->p_offset; 273*30519Ssam end = pp->p_offset + pp->p_size; 274*30519Ssam for (pp = lp->d_partitions; 275*30519Ssam pp < &lp->d_partitions[lp->d_npartitions]; pp++) { 276*30519Ssam if (pp->p_offset + pp->p_size <= start || 277*30519Ssam pp->p_offset >= end) 278*30519Ssam continue; 279*30519Ssam if (pp - lp->d_partitions == RAWPART) 280*30519Ssam continue; 281*30519Ssam if (dk->dk_openpart & (1 << (pp - lp->d_partitions))) 282*30519Ssam log(LOG_WARNING, 283*30519Ssam "dk%d%c: overlaps open partition (%c)\n", 284*30519Ssam unit, part + 'a', 285*30519Ssam pp - lp->d_partitions + 'a'); 286*30519Ssam } 28724004Ssam } 288*30519Ssam if (part >= lp->d_npartitions) 289*30519Ssam return (ENXIO); 290*30519Ssam dk->dk_openpart |= 1 << part; 291*30519Ssam return (0); 29225675Ssam } 29324004Ssam 294*30519Ssam vdclose(dev, flags) 295*30519Ssam dev_t dev; 296*30519Ssam int flags; 29724004Ssam { 298*30519Ssam register int unit = vdunit(dev); 299*30519Ssam register struct dksoftc *dk = &dksoftc[unit]; 30024004Ssam 301*30519Ssam dk->dk_openpart &= ~(1 << vdpart(dev)); 302*30519Ssam #ifdef notdef 303*30519Ssam /* 304*30519Ssam * Should wait for i/o to complete on this partition 305*30519Ssam * even if others are open, but wait for work on blkflush(). 306*30519Ssam */ 307*30519Ssam if (dk->dk_openpart == 0) { 308*30519Ssam struct vba_device *vi = vddinfo[unit]; 309*30519Ssam int s; 310*30519Ssam 311*30519Ssam s = spl7(); 312*30519Ssam /* can't sleep on b_actf, it might be async. */ 313*30519Ssam while (vi->ui_tab.b_actf) 314*30519Ssam sleep((caddr_t)&vi->ui_tab.b_actf, PZERO-1); 315*30519Ssam splx(s); 316*30519Ssam dk->dk_state = CLOSED; 31724004Ssam } 318*30519Ssam #endif 31925675Ssam } 32024004Ssam 321*30519Ssam vdinit(dev, flags) 322*30519Ssam dev_t dev; 323*30519Ssam int flags; 32425675Ssam { 325*30519Ssam register struct buf *bp = NULL; 326*30519Ssam register struct disklabel *lp; 327*30519Ssam register struct dksoftc *dk; 328*30519Ssam struct vba_device *vi; 329*30519Ssam struct disklabel *dlp; 330*30519Ssam int unit = vdunit(dev), error = 0; 331*30519Ssam extern int cold; 33225675Ssam 333*30519Ssam dk = &dksoftc[unit]; 334*30519Ssam if (flags & O_NDELAY) { 335*30519Ssam dk->dk_state = OPENRAW; 336*30519Ssam goto done; 337*30519Ssam } 338*30519Ssam 339*30519Ssam /* 340*30519Ssam * Initialize portion of the label 341*30519Ssam * not set up in the slave routine. 342*30519Ssam */ 343*30519Ssam dk->dk_bshift = 1; /* DEV_BSIZE / 512 */ 344*30519Ssam dk->dk_state = RDLABEL; 345*30519Ssam lp = &dklabel[unit]; 346*30519Ssam lp->d_secperunit = 0x1fffffff; 347*30519Ssam lp->d_npartitions = 1; 348*30519Ssam lp->d_partitions[0].p_size = 0x1fffffff; 349*30519Ssam lp->d_partitions[0].p_offset = 0; 350*30519Ssam 351*30519Ssam bp = geteblk(DEV_BSIZE); /* max sector size */ 352*30519Ssam bp->b_dev = dev; 353*30519Ssam bp->b_blkno = LABELSECTOR; 354*30519Ssam bp->b_bcount = DEV_BSIZE; 355*30519Ssam bp->b_flags = B_BUSY | B_READ; 356*30519Ssam bp->b_cylin = LABELSECTOR / lp->d_secpercyl; 357*30519Ssam vdstrategy(bp); 358*30519Ssam biowait(bp); 359*30519Ssam if (bp->b_flags & B_ERROR) { 360*30519Ssam error = u.u_error; /* XXX */ 361*30519Ssam u.u_error = 0; 362*30519Ssam dk->dk_state = CLOSED; 363*30519Ssam goto done; 364*30519Ssam } 365*30519Ssam vi = vddinfo[unit]; 366*30519Ssam dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET); 367*30519Ssam if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC && 368*30519Ssam dkcksum(dlp) == 0) { 369*30519Ssam *lp = *dlp; 370*30519Ssam /* 371*30519Ssam * Now that we have the label, configure 372*30519Ssam * the correct drive parameters. 373*30519Ssam */ 374*30519Ssam if (!vdreset_drive(vi)) 375*30519Ssam dk->dk_state = CLOSED; 376*30519Ssam else 377*30519Ssam dk->dk_state = OPEN; 37825675Ssam } else { 379*30519Ssam if (cold) 380*30519Ssam printf(": no disk label"); 381*30519Ssam else 382*30519Ssam log(LOG_ERR, "dk%d: no disk label\n", vi->ui_unit); 383*30519Ssam #ifdef COMPAT_42 384*30519Ssam if (!vdmaptype(vi, lp)) { 385*30519Ssam error = ENXIO; 386*30519Ssam dk->dk_state = CLOSED; 387*30519Ssam } else 388*30519Ssam dk->dk_state = OPEN; 389*30519Ssam #else 390*30519Ssam dk->dk_state = OPENRAW; 391*30519Ssam #endif 39225675Ssam } 393*30519Ssam done: 39424004Ssam /* 395*30519Ssam * If open, calculate scaling shift for 396*30519Ssam * mapping DEV_BSIZE blocks to drive sectors. 39724004Ssam */ 398*30519Ssam if (dk->dk_state == OPEN || dk->dk_state == OPENRAW) { 399*30519Ssam int mul = DEV_BSIZE / lp->d_secsize; 400*30519Ssam dk->dk_bshift = 0; 401*30519Ssam while ((mul >>= 1) > 0) 402*30519Ssam dk->dk_bshift++; 403*30519Ssam } 404*30519Ssam if (bp) { 405*30519Ssam bp->b_flags = B_INVAL | B_AGE; 406*30519Ssam brelse(bp); 407*30519Ssam } 408*30519Ssam wakeup((caddr_t)dk); 409*30519Ssam return (error); 41024004Ssam } 41124004Ssam 41225675Ssam /*ARGSUSED*/ 413*30519Ssam vddgo(vm) 414*30519Ssam struct vba_device *vm; 41524004Ssam { 41624004Ssam 41724004Ssam } 41824004Ssam 41924004Ssam vdstrategy(bp) 42025675Ssam register struct buf *bp; 42124004Ssam { 422*30519Ssam register struct vba_device *vi; 423*30519Ssam register struct disklabel *lp; 424*30519Ssam register struct dksoftc *dk; 425*30519Ssam register int unit; 426*30519Ssam struct buf *dp; 427*30519Ssam daddr_t sz, sn, maxsz; 428*30519Ssam int part, s; 42924004Ssam 430*30519Ssam sz = bp->b_bcount; 431*30519Ssam sz = (sz + DEV_BSIZE - 1) >> DEV_BSHIFT; 432*30519Ssam unit = vdunit(bp->b_dev); 433*30519Ssam if (unit > NDK) { 43429954Skarels bp->b_error = ENXIO; 43525675Ssam goto bad; 43629954Skarels } 437*30519Ssam vi = vddinfo[unit]; 438*30519Ssam lp = &dklabel[unit]; 439*30519Ssam if (vi == 0 || vi->ui_alive == 0) { 440*30519Ssam bp->b_error = ENXIO; 441*30519Ssam goto bad; 442*30519Ssam } 443*30519Ssam dk = &dksoftc[unit]; 444*30519Ssam if (dk->dk_state < OPEN) 445*30519Ssam goto q; 446*30519Ssam part = vdpart(bp->b_dev); 447*30519Ssam if ((dk->dk_openpart & (1 << part)) == 0) { 448*30519Ssam bp->b_error = ENODEV; 449*30519Ssam goto bad; 450*30519Ssam } 451*30519Ssam maxsz = lp->d_partitions[part].p_size; 452*30519Ssam sn = bp->b_blkno << dk->dk_bshift; 453*30519Ssam if (sn < 0 || sn + sz > maxsz) { 454*30519Ssam if (sn == maxsz) { 45529954Skarels bp->b_resid = bp->b_bcount; 45629954Skarels goto done; 45729954Skarels } 458*30519Ssam bp->b_error = EINVAL; 459*30519Ssam goto bad; 46025675Ssam } 461*30519Ssam bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl; 462*30519Ssam q: 463*30519Ssam vbasetup(bp, lp->d_secsize); 46425675Ssam s = spl7(); 465*30519Ssam dp = &dkutab[vi->ui_unit]; 466*30519Ssam disksort(dp, bp); 467*30519Ssam if (!dp->b_active) { 468*30519Ssam (void) vdustart(vi); 469*30519Ssam bp = &vi->ui_mi->um_tab; 470*30519Ssam if (bp->b_actf && !bp->b_active) 471*30519Ssam vdstart(vi->ui_mi); 47224004Ssam } 473*30519Ssam splx(s); 47424004Ssam return; 47525675Ssam bad: 47629954Skarels bp->b_flags |= B_ERROR; 47729954Skarels done: 478*30519Ssam biodone(bp); 479*30519Ssam return; 48024004Ssam } 48124004Ssam 482*30519Ssam vdustart(vi) 483*30519Ssam register struct vba_device *vi; 48424004Ssam { 485*30519Ssam register struct buf *bp, *dp; 486*30519Ssam register struct vba_ctlr *vm; 487*30519Ssam register int unit = vi->ui_unit; 488*30519Ssam register struct dksoftc *dk; 489*30519Ssam register struct vdsoftc *vd; 490*30519Ssam struct disklabel *lp; 49124004Ssam 492*30519Ssam dk_busy &= ~(1<<vi->ui_dk); 493*30519Ssam dp = &dkutab[unit]; 494*30519Ssam /* 495*30519Ssam * If queue empty, nothing to do. 496*30519Ssam */ 497*30519Ssam if ((bp = dp->b_actf) == NULL) 498*30519Ssam return; 499*30519Ssam /* 500*30519Ssam * If drive is off-cylinder, mark unit to force 501*30519Ssam * overlap seek with next transfer on this controller. 502*30519Ssam */ 503*30519Ssam vd = &vdsoftc[vi->ui_ctlr]; 504*30519Ssam dk = &dksoftc[unit]; 505*30519Ssam if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) { 506*30519Ssam int sn = bp->b_blkno << dk->dk_bshift; 507*30519Ssam lp = &dklabel[unit]; 508*30519Ssam bp->b_daddr = (sn % lp->d_secpercyl) / lp->d_nsectors; 509*30519Ssam if (bp->b_daddr != dk->dk_curdaddr) 510*30519Ssam vd->vd_offcyl |= 1 << vi->ui_slave; 511*30519Ssam } 512*30519Ssam /* 513*30519Ssam * If controller is not busy, place request on the 514*30519Ssam * controller's ready queue (unless its already there). 515*30519Ssam */ 516*30519Ssam if (!dp->b_active) { 517*30519Ssam dp->b_forw = NULL; 518*30519Ssam vm = vi->ui_mi; 519*30519Ssam if (vm->um_tab.b_actf == NULL) 520*30519Ssam vm->um_tab.b_actf = dp; 521*30519Ssam else 522*30519Ssam vm->um_tab.b_actl->b_forw = dp; 523*30519Ssam vm->um_tab.b_actl = dp; 524*30519Ssam dp->b_active++; 525*30519Ssam } 52625675Ssam } 52725675Ssam 52825675Ssam /* 529*30519Ssam * Start next transfer on a controller. 53025675Ssam */ 531*30519Ssam vdstart(vm) 532*30519Ssam register struct vba_ctlr *vm; 53325675Ssam { 53425675Ssam register struct buf *bp; 535*30519Ssam register struct vba_device *vi; 536*30519Ssam register struct vdsoftc *vd; 537*30519Ssam register struct dksoftc *dk; 538*30519Ssam register struct disklabel *lp; 539*30519Ssam register int slave; 540*30519Ssam register struct dcb **dcbp; 541*30519Ssam struct mdcb *mdcb; 542*30519Ssam struct buf *dp; 543*30519Ssam int sn, tn; 54425675Ssam 545*30519Ssam loop: 546*30519Ssam /* 547*30519Ssam * Pull a request off the controller queue. 548*30519Ssam */ 549*30519Ssam if ((dp = vm->um_tab.b_actf) == NULL) 550*30519Ssam return; 551*30519Ssam if ((bp = dp->b_actf) == NULL) { 552*30519Ssam vm->um_tab.b_actf = dp->b_forw; 553*30519Ssam goto loop; 554*30519Ssam } 55525675Ssam 55624004Ssam /* 557*30519Ssam * Mark controller busy, and determine 558*30519Ssam * destination of this request. 55924004Ssam */ 560*30519Ssam vm->um_tab.b_active++; 561*30519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 562*30519Ssam dk = &dksoftc[vi->ui_unit]; 563*30519Ssam sn = bp->b_blkno << dk->dk_bshift; 564*30519Ssam lp = &dklabel[vi->ui_unit]; 565*30519Ssam sn %= lp->d_secpercyl; 566*30519Ssam tn = sn / lp->d_nsectors; 567*30519Ssam sn %= lp->d_nsectors; 568*30519Ssam 569*30519Ssam /* 570*30519Ssam * Construct dcb for read/write command. 571*30519Ssam */ 572*30519Ssam vd = &vdsoftc[vm->um_ctlr]; 573*30519Ssam slave = vi->ui_slave; 574*30519Ssam vd->vd_dcb.opcode = (bp->b_flags & B_READ) ? VDOP_RD : VDOP_WD; 575*30519Ssam vd->vd_dcb.intflg = DCBINT_DONE; 576*30519Ssam vd->vd_dcb.devselect = slave; 577*30519Ssam vd->vd_dcb.operrsta = 0; 578*30519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 579*30519Ssam vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long); 580*30519Ssam vd->vd_dcb.trail.rwtrail.memadr = (char *) 581*30519Ssam vbastart(bp, vd->vd_rawbuf, (long *)vd->vd_map, vd->vd_utl); 582*30519Ssam vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1; 583*30519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin; 584*30519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 585*30519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 586*30519Ssam 587*30519Ssam /* 588*30519Ssam * Look for any seeks to be performed on other drives on this 589*30519Ssam * controller. If overlapped seeks exist, insert seek commands 590*30519Ssam * on the controller's command queue before the transfer. 591*30519Ssam */ 592*30519Ssam dcbp = &vd->vd_mdcb.mdcb_head; 593*30519Ssam if (vd->vd_offcyl &~ (1<<slave)) { 594*30519Ssam register struct dksoftc *tdk; 595*30519Ssam register struct buf *tp; 596*30519Ssam 597*30519Ssam for (dp = dp->b_forw; dp != NULL; dp = dp->b_forw) { 598*30519Ssam if ((tp = dp->b_actf) == NULL) 599*30519Ssam continue; 600*30519Ssam slave = (vi = vddinfo[vdunit(tp->b_dev)])->ui_slave; 601*30519Ssam if ((vd->vd_offcyl & (1<<slave)) == 0) 602*30519Ssam continue; 603*30519Ssam vd->vd_offcyl &= ~(1 << slave); 604*30519Ssam tdk = &dksoftc[vi->ui_unit]; 605*30519Ssam if (tdk->dk_curcyl != tp->b_cylin) { 606*30519Ssam tdk->dk_curcyl = tp->b_cylin; 607*30519Ssam dk_seek[vi->ui_dk]++; 608*30519Ssam } 609*30519Ssam tdk->dk_curdaddr = tp->b_daddr; 610*30519Ssam tdk->dk_dcb.operrsta = 0; 611*30519Ssam tdk->dk_dcb.trail.sktrail.skaddr.cylinder = tp->b_cylin; 612*30519Ssam tdk->dk_dcb.trail.sktrail.skaddr.track = tp->b_daddr>>8; 613*30519Ssam tdk->dk_dcb.trail.sktrail.skaddr.sector = 614*30519Ssam tp->b_daddr & 0xff; 615*30519Ssam *dcbp = (struct dcb *)tdk->dk_dcbphys; 616*30519Ssam dcbp = &tdk->dk_dcb.nxtdcb; 617*30519Ssam } 61825675Ssam } else { 619*30519Ssam dk->dk_curcyl = bp->b_cylin; 620*30519Ssam dk->dk_curdaddr = (tn << 8) | sn; 621*30519Ssam vd->vd_offcyl = 0; 62224004Ssam } 623*30519Ssam *dcbp = (struct dcb *)vd->vd_dcbphys; 62424004Ssam 625*30519Ssam /* 626*30519Ssam * Initiate operation. 627*30519Ssam */ 628*30519Ssam bp->b_daddr = 0; /* init overloaded field */ 629*30519Ssam if (vi->ui_dk >= 0) { 630*30519Ssam dk_busy |= 1<<vi->ui_dk; 631*30519Ssam dk_xfer[vi->ui_dk]++; 632*30519Ssam dk_wds[vi->ui_dk] += bp->b_bcount>>6; 63324004Ssam } 634*30519Ssam vd->vd_mdcb.mdcb_status = 0; 635*30519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 63624004Ssam } 63724004Ssam 638*30519Ssam #define DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE) 63924004Ssam /* 64024004Ssam * Handle a disk interrupt. 64124004Ssam */ 64225675Ssam vdintr(ctlr) 643*30519Ssam register ctlr; 64424004Ssam { 645*30519Ssam register struct buf *bp, *dp; 646*30519Ssam register struct vba_ctlr *vm = vdminfo[ctlr]; 647*30519Ssam register struct vba_device *vi; 648*30519Ssam register struct vdsoftc *vd = &vdsoftc[ctlr]; 649*30519Ssam register status; 65024004Ssam 651*30519Ssam vd->vd_wticks = 0; 652*30519Ssam if (!vm->um_tab.b_active) { 65325675Ssam printf("vd%d: stray interrupt\n", ctlr); 65424004Ssam return; 65524004Ssam } 65625675Ssam /* 657*30519Ssam * Get device and block structures, and a pointer 658*30519Ssam * to the vba_device for the drive. 65925675Ssam */ 660*30519Ssam dp = vm->um_tab.b_actf; 661*30519Ssam bp = dp->b_actf; 662*30519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 663*30519Ssam dk_busy &= ~(1<<vi->ui_dk); 664*30519Ssam /* 665*30519Ssam * Check for and process errors on 666*30519Ssam * either the drive or the controller. 667*30519Ssam */ 668*30519Ssam uncache(&vd->vd_dcb.operrsta); 669*30519Ssam status = vd->vd_dcb.operrsta; 670*30519Ssam if (status & VDERR_HARD) { 671*30519Ssam if (status & DCBS_WPT) { 672*30519Ssam /* 673*30519Ssam * Give up on write locked devices immediately. 674*30519Ssam */ 675*30519Ssam printf("dk%d: write locked\n", vdunit(bp->b_dev)); 676*30519Ssam bp->b_flags |= B_ERROR; 677*30519Ssam } else if (status & VDERR_SOFT) { 678*30519Ssam if (status & VDERR_DRIVE) { 679*30519Ssam if (!vdreset_drive(vi)) 680*30519Ssam vi->ui_alive = 0; 681*30519Ssam } else if (status & VDERR_CTLR) 682*30519Ssam vdreset_ctlr(vm); 683*30519Ssam /* 684*30519Ssam * Retry transfer once, unless reset failed. 685*30519Ssam */ 686*30519Ssam if (!vi->ui_alive || bp->b_errcnt++ >= 2) 687*30519Ssam goto hard; 688*30519Ssam vm->um_tab.b_active = 0; /* force retry */ 689*30519Ssam } else { 690*30519Ssam hard: 691*30519Ssam bp->b_flags |= B_ERROR; 692*30519Ssam /* NEED TO ADJUST b_blkno to failed sector */ 693*30519Ssam harderr(bp, "dk"); 694*30519Ssam printf("status %x (%b)", status, 695*30519Ssam status &~ DONTCARE, VDERRBITS); 696*30519Ssam if (vd->vd_type == VDTYPE_SMDE) { 697*30519Ssam uncache(&vd->vd_dcb.err_code); 698*30519Ssam printf(" ecode %x", vd->vd_dcb.err_code); 699*30519Ssam } 700*30519Ssam printf("\n"); 701*30519Ssam } 702*30519Ssam } else if (status & DCBS_SOFT) 703*30519Ssam vdsofterr(vd, bp, &vd->vd_dcb); 704*30519Ssam if (vm->um_tab.b_active) { 705*30519Ssam vm->um_tab.b_active = 0; 706*30519Ssam vm->um_tab.b_errcnt = 0; 707*30519Ssam vm->um_tab.b_actf = dp->b_forw; 708*30519Ssam dp->b_active = 0; 709*30519Ssam dp->b_errcnt = 0; 710*30519Ssam dp->b_actf = bp->av_forw; 711*30519Ssam bp->b_resid = 0; 712*30519Ssam vbadone(bp, vd->vd_rawbuf, (long *)vd->vd_map, vd->vd_utl); 713*30519Ssam biodone(bp); 71430370Skarels /* 715*30519Ssam * If this unit has more work to do, 716*30519Ssam * then start it up right away. 71730370Skarels */ 718*30519Ssam if (dp->b_actf) 719*30519Ssam vdustart(vi); 72024004Ssam } 72125675Ssam /* 722*30519Ssam * If there are devices ready to 723*30519Ssam * transfer, start the controller. 72425675Ssam */ 725*30519Ssam if (vm->um_tab.b_actf) 726*30519Ssam vdstart(vm); 72724004Ssam } 72824004Ssam 729*30519Ssam vdsofterr(vd, bp, dcb) 730*30519Ssam struct vdsoftc *vd; 73125675Ssam register struct buf *bp; 732*30519Ssam register struct dcb *dcb; 73325675Ssam { 734*30519Ssam int unit = vdunit(bp->b_dev), status = dcb->operrsta; 735*30519Ssam char part = 'a' + vdpart(bp->b_dev); 73625675Ssam 737*30519Ssam if (status != (DCBS_DCE|DCBS_CCD|DCBS_SOFT|DCBS_ERR)) { 738*30519Ssam if (vd->vd_type == VDTYPE_SMDE) 739*30519Ssam uncache(&dcb->err_code); 740*30519Ssam log(LOG_WARNING, "dk%d%c: soft error sn%d status %b ecode %x\n", 741*30519Ssam unit, part, bp->b_blkno, status, VDERRBITS, dcb->err_code); 742*30519Ssam } else 74330370Skarels log(LOG_WARNING, "dk%d%c: soft ecc sn%d\n", 74430370Skarels unit, part, bp->b_blkno); 74525675Ssam } 74625675Ssam 74724004Ssam vdread(dev, uio) 74825675Ssam dev_t dev; 74925675Ssam struct uio *uio; 75024004Ssam { 751*30519Ssam register int unit = vdunit(dev); 75224004Ssam 75329564Ssam if (unit >= NDK) 75425675Ssam return (ENXIO); 755*30519Ssam return (physio(vdstrategy, &rdkbuf[unit], dev, B_READ, minphys, uio)); 75624004Ssam } 75724004Ssam 75824004Ssam vdwrite(dev, uio) 75925675Ssam dev_t dev; 76025675Ssam struct uio *uio; 76124004Ssam { 762*30519Ssam register int unit = vdunit(dev); 76324004Ssam 76429564Ssam if (unit >= NDK) 76525675Ssam return (ENXIO); 766*30519Ssam return (physio(vdstrategy, &rdkbuf[unit], dev, B_WRITE, minphys, uio)); 76724004Ssam } 76824004Ssam 769*30519Ssam vdioctl(dev, cmd, data, flag) 77025675Ssam dev_t dev; 771*30519Ssam int cmd; 772*30519Ssam caddr_t data; 773*30519Ssam int flag; 77424004Ssam { 775*30519Ssam int unit = vdunit(dev); 776*30519Ssam register struct disklabel *lp = &dklabel[unit]; 777*30519Ssam int error = 0; 77824004Ssam 779*30519Ssam switch (cmd) { 780*30519Ssam 781*30519Ssam case DIOCGDINFO: 782*30519Ssam *(struct disklabel *)data = *lp; 783*30519Ssam break; 784*30519Ssam 785*30519Ssam case DIOCGDINFOP: 786*30519Ssam *(struct disklabel **)data = lp; 787*30519Ssam break; 788*30519Ssam 789*30519Ssam case DIOCSDINFO: 790*30519Ssam if ((flag & FWRITE) == 0) 791*30519Ssam error = EBADF; 792*30519Ssam else 793*30519Ssam *lp = *(struct disklabel *)data; 794*30519Ssam break; 795*30519Ssam 796*30519Ssam case DIOCWDINFO: { 797*30519Ssam struct buf *bp; 798*30519Ssam struct disklabel *dlp; 799*30519Ssam 800*30519Ssam if ((flag & FWRITE) == 0) { 801*30519Ssam error = EBADF; 802*30519Ssam break; 803*30519Ssam } 804*30519Ssam *lp = *(struct disklabel *)data; 805*30519Ssam bp = geteblk(lp->d_secsize); 806*30519Ssam bp->b_dev = dev; 807*30519Ssam bp->b_blkno = LABELSECTOR; 808*30519Ssam bp->b_bcount = lp->d_secsize; 809*30519Ssam bp->b_flags = B_READ; 810*30519Ssam dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET); 811*30519Ssam vdstrategy(bp); 812*30519Ssam biowait(bp); 813*30519Ssam if (bp->b_flags & B_ERROR) { 814*30519Ssam error = u.u_error; /* XXX */ 815*30519Ssam u.u_error = 0; 816*30519Ssam goto bad; 817*30519Ssam } 818*30519Ssam *dlp = *lp; 819*30519Ssam bp->b_flags = B_WRITE; 820*30519Ssam vdstrategy(bp); 821*30519Ssam biowait(bp); 822*30519Ssam if (bp->b_flags & B_ERROR) { 823*30519Ssam error = u.u_error; /* XXX */ 824*30519Ssam u.u_error = 0; 825*30519Ssam } 826*30519Ssam bad: 827*30519Ssam brelse(bp); 828*30519Ssam break; 82925675Ssam } 830*30519Ssam 831*30519Ssam default: 832*30519Ssam error = ENOTTY; 833*30519Ssam break; 83424004Ssam } 83525675Ssam return (0); 83624004Ssam } 83724004Ssam 83825675Ssam /* 839*30519Ssam * Watch for lost interrupts. 84025675Ssam */ 841*30519Ssam vdwatch() 842*30519Ssam { 843*30519Ssam register struct vdsoftc *vd; 844*30519Ssam register struct vba_ctlr *vm; 84525675Ssam register int ctlr, unit; 846*30519Ssam 847*30519Ssam timeout(vdwatch, (caddr_t)0, hz); 848*30519Ssam for (ctlr = 0; ctlr < NVD; ctlr++) { 849*30519Ssam vm = vdminfo[ctlr]; 850*30519Ssam if (vm == 0 || vm->um_alive == 0) 851*30519Ssam continue; 852*30519Ssam vd = &vdsoftc[ctlr]; 853*30519Ssam if (!vm->um_tab.b_active) { 854*30519Ssam for (unit = 0; unit < NDK; unit++) 855*30519Ssam if (dkutab[unit].b_active && 856*30519Ssam vddinfo[unit]->ui_mi == vm) 857*30519Ssam goto active; 858*30519Ssam vd->vd_wticks = 0; 859*30519Ssam continue; 860*30519Ssam } 861*30519Ssam active: 862*30519Ssam vd->vd_wticks++; 863*30519Ssam if (vd->vd_wticks >= 20) { 864*30519Ssam vd->vd_wticks = 0; 865*30519Ssam printf("vd%d: lost interrupt\n", ctlr); 866*30519Ssam /* abort pending dcb's and restart controller */ 867*30519Ssam } 868*30519Ssam } 869*30519Ssam } 870*30519Ssam 871*30519Ssam #define DBSIZE 64 /* controller limit with 1K sectors */ 872*30519Ssam /* 873*30519Ssam * Crash dump. 874*30519Ssam */ 875*30519Ssam vddump(dev) 876*30519Ssam dev_t dev; 87724004Ssam { 878*30519Ssam register struct vba_device *vi; 879*30519Ssam register struct vba_ctlr *vm; 880*30519Ssam register struct disklabel *lp; 881*30519Ssam register struct vdsoftc *vd; 882*30519Ssam struct dksoftc *dk; 883*30519Ssam int part, unit, num; 884*30519Ssam caddr_t start; 88524004Ssam 886*30519Ssam start = 0; 887*30519Ssam unit = vdunit(dev); 888*30519Ssam if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 889*30519Ssam return (ENXIO); 890*30519Ssam dk = &dksoftc[unit]; 891*30519Ssam if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 892*30519Ssam return (ENXIO); 893*30519Ssam lp = &dklabel[unit]; 894*30519Ssam part = vdpart(dev); 895*30519Ssam if (part >= lp->d_npartitions) 896*30519Ssam return (ENXIO); 897*30519Ssam vm = vdminfo[vi->ui_ctlr]; 898*30519Ssam vdreset_ctlr(vm); 899*30519Ssam if (dumplo < 0) 900*30519Ssam return (EINVAL); 901*30519Ssam /* 902*30519Ssam * Dumplo and maxfree are in pages; 903*30519Ssam * dumplo will change soon (XXX). 904*30519Ssam */ 905*30519Ssam num = maxfree * (NBPG / lp->d_secsize); 906*30519Ssam dumplo *= NBPG / lp->d_secsize; /* XXX */ 907*30519Ssam if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size) 908*30519Ssam num = lp->d_partitions[vdpart(dev)].p_size - dumplo; 909*30519Ssam vd = &vdsoftc[vm->um_ctlr]; 910*30519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 911*30519Ssam vd->vd_dcb.opcode = VDOP_WD; 912*30519Ssam vd->vd_dcb.devselect = vi->ui_slave; 913*30519Ssam vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long); 914*30519Ssam while (num > 0) { 915*30519Ssam int nsec, cn, sn, tn; 916*30519Ssam 917*30519Ssam nsec = MIN(num, DBSIZE); 918*30519Ssam sn = dumplo + (unsigned)start / lp->d_secsize; 919*30519Ssam cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) / 920*30519Ssam lp->d_secpercyl; 921*30519Ssam sn %= lp->d_secpercyl; 922*30519Ssam tn = sn / lp->d_nsectors; 923*30519Ssam sn %= lp->d_nsectors; 924*30519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 925*30519Ssam vd->vd_dcb.trail.rwtrail.memadr = start; 926*30519Ssam vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1; 927*30519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = cn; 928*30519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 929*30519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 930*30519Ssam vd->vd_dcb.operrsta = 0; 931*30519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 932*30519Ssam if (!vdpoll(vm, 5)) { 933*30519Ssam printf(" during dump\n"); 934*30519Ssam return (EIO); 935*30519Ssam } 936*30519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 937*30519Ssam printf("dk%d: hard error, status=%b\n", unit, 938*30519Ssam vd->vd_dcb.operrsta, VDERRBITS); 939*30519Ssam return (EIO); 940*30519Ssam } 941*30519Ssam start += nsec * lp->d_secsize; 942*30519Ssam num -= nsec; 94325675Ssam } 944*30519Ssam return (0); 94524004Ssam } 94624004Ssam 94724004Ssam vdsize(dev) 94825675Ssam dev_t dev; 94924004Ssam { 950*30519Ssam register int unit = vdunit(dev); 951*30519Ssam register struct dksoftc *dk; 952*30519Ssam struct vba_device *vi; 953*30519Ssam struct disklabel *lp; 95424004Ssam 955*30519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 || 956*30519Ssam (dk = &dksoftc[unit])->dk_state != OPEN) 95725675Ssam return (-1); 958*30519Ssam lp = &dklabel[unit]; 959*30519Ssam return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift); 96024004Ssam } 96124004Ssam 96225675Ssam /* 96325675Ssam * Perform a controller reset. 96425675Ssam */ 965*30519Ssam vdreset_ctlr(vm) 966*30519Ssam register struct vba_ctlr *vm; 96724004Ssam { 968*30519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 969*30519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 970*30519Ssam register int unit; 971*30519Ssam struct vba_device *vi; 97225675Ssam 973*30519Ssam VDRESET(vdaddr, vd->vd_type); 974*30519Ssam if (vd->vd_type == VDTYPE_SMDE) { 975*30519Ssam vdaddr->vdcsr = 0; 976*30519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 977*30519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 978*30519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 979*30519Ssam vdaddr->vdtcf_data = AM_ENPDA; 980*30519Ssam vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD | 98125675Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 98225675Ssam } 983*30519Ssam if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { 984*30519Ssam printf("%s cmd failed\n", 985*30519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 98630370Skarels return; 98725675Ssam } 988*30519Ssam for (unit = 0; unit < NDK; unit++) 989*30519Ssam if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive) 990*30519Ssam (void) vdreset_drive(vi); 991*30519Ssam } 992*30519Ssam 993*30519Ssam vdreset_drive(vi) 994*30519Ssam register struct vba_device *vi; 995*30519Ssam { 996*30519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 997*30519Ssam struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; 998*30519Ssam struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 999*30519Ssam struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 1000*30519Ssam 1001*30519Ssam top: 1002*30519Ssam vd->vd_dcb.opcode = VDOP_CONFIG; /* command */ 1003*30519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 1004*30519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 1005*30519Ssam vd->vd_dcb.operrsta = 0; 1006*30519Ssam vd->vd_dcb.devselect = vi->ui_slave; 1007*30519Ssam vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders; 1008*30519Ssam vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks; 1009*30519Ssam if (vd->vd_type == VDTYPE_SMDE) { 1010*30519Ssam vd->vd_dcb.trailcnt = sizeof (treset) / sizeof (long); 1011*30519Ssam vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors; 1012*30519Ssam vd->vd_dcb.trail.rstrail.slip_sec = lp->d_trackskew; 1013*30519Ssam vd->vd_dcb.trail.rstrail.recovery = 0x18f; 1014*30519Ssam } else 1015*30519Ssam vd->vd_dcb.trailcnt = 2; /* XXX */ 1016*30519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 1017*30519Ssam vd->vd_mdcb.mdcb_status = 0; 1018*30519Ssam VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type); 1019*30519Ssam if (!vdpoll(vm, 5)) { 1020*30519Ssam printf(" during config\n"); 1021*30519Ssam return (0); 102225675Ssam } 1023*30519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 1024*30519Ssam if (vd->vd_type == VDTYPE_SMDE && 1025*30519Ssam (vdaddr->vdstatus[vi->ui_slave]&STA_US) == 0) 1026*30519Ssam return (0); 1027*30519Ssam if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) 1028*30519Ssam printf("dk%d: config error\n", vi->ui_unit); 1029*30519Ssam else if ((vd->vd_flags&VD_STARTED) == 0) { 1030*30519Ssam int started; 1031*30519Ssam 1032*30519Ssam printf("vd%d: starting drives, wait ... ", vm->um_ctlr); 1033*30519Ssam vd->vd_flags |= VD_STARTED; 1034*30519Ssam started = (vdcmd(vm, VDOP_START, 10) == 1); 1035*30519Ssam DELAY(62000000); 1036*30519Ssam printf("\n"); 1037*30519Ssam if (started) 1038*30519Ssam goto top; 1039*30519Ssam } 1040*30519Ssam return (0); 1041*30519Ssam } 1042*30519Ssam return (1); 104325675Ssam } 104424004Ssam 104525675Ssam /* 1046*30519Ssam * Perform a command w/o trailer. 104725675Ssam */ 1048*30519Ssam vdcmd(vm, cmd, t) 1049*30519Ssam register struct vba_ctlr *vm; 105025675Ssam { 1051*30519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 105225675Ssam 1053*30519Ssam vd->vd_dcb.opcode = cmd; /* command */ 1054*30519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 1055*30519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 1056*30519Ssam vd->vd_dcb.operrsta = 0; 1057*30519Ssam vd->vd_dcb.devselect = 0; 1058*30519Ssam vd->vd_dcb.trailcnt = 0; 1059*30519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 1060*30519Ssam vd->vd_mdcb.mdcb_status = 0; 1061*30519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 1062*30519Ssam if (!vdpoll(vm, t)) { 1063*30519Ssam printf(" during init\n"); 106430370Skarels return (0); 106530370Skarels } 1066*30519Ssam return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0); 106725675Ssam } 106825675Ssam 106925925Ssam /* 1070*30519Ssam * Poll controller until operation 1071*30519Ssam * completes or timeout expires. 107225925Ssam */ 1073*30519Ssam vdpoll(vm, t) 1074*30519Ssam register struct vba_ctlr *vm; 107525925Ssam register int t; 107625925Ssam { 1077*30519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 1078*30519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 107925925Ssam 108025925Ssam t *= 1000; 108130370Skarels for (;;) { 1082*30519Ssam uncache(&vd->vd_dcb.operrsta); 1083*30519Ssam if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT)) 108430370Skarels break; 108525925Ssam if (--t <= 0) { 1086*30519Ssam printf("vd%d: controller timeout", vm->um_ctlr); 1087*30519Ssam VDABORT(vdaddr, vd->vd_type); 108825925Ssam DELAY(30000); 108925925Ssam return (0); 109025925Ssam } 109130370Skarels DELAY(1000); 109225925Ssam } 1093*30519Ssam if (vd->vd_type == VDTYPE_SMDE) { 1094*30519Ssam do { 109525925Ssam DELAY(50); 1096*30519Ssam uncache(&vdaddr->vdcsr); 1097*30519Ssam } while (vdaddr->vdcsr & CS_GO); 109825925Ssam DELAY(300); 109925925Ssam } 110025925Ssam DELAY(200); 1101*30519Ssam uncache(&vd->vd_dcb.operrsta); 110225925Ssam return (1); 110325925Ssam } 110425925Ssam 1105*30519Ssam #ifdef COMPAT_42 1106*30519Ssam struct vdst { 1107*30519Ssam int nsec; /* sectors/track */ 1108*30519Ssam int ntrack; /* tracks/cylinder */ 1109*30519Ssam int ncyl; /* cylinders */ 1110*30519Ssam char *name; /* type name */ 1111*30519Ssam struct { 1112*30519Ssam int off; /* partition offset in sectors */ 1113*30519Ssam int size; /* partition size in sectors */ 1114*30519Ssam } parts[3]; 1115*30519Ssam } vdst[] = { 1116*30519Ssam { 48, 24, 711, "xsd", {0,61056}, {61056,61056}, {122112,691200} }, 1117*30519Ssam { 44, 20, 842, "egl", {0,52800}, {52800,66000}, {118800,617760} }, 1118*30519Ssam { 64, 10, 823, "fuj", {0,38400}, {38400,48000}, { 86400,437120} }, 1119*30519Ssam { 32, 24, 711, "xfd", {0,40704}, {40704,40704}, { 81408,460800} }, 1120*30519Ssam { 32, 19, 823, "smd", {0,40128}, {40128,27360}, { 67488,429856} }, 1121*30519Ssam { 32, 10, 823, "fsd", {0,19200}, {19200,24000}, { 43200,218560} } 1122*30519Ssam }; 1123*30519Ssam #define NVDST (sizeof (vdst) / sizeof (vdst[0])) 1124*30519Ssam 112525675Ssam /* 1126*30519Ssam * Construct a label for an unlabeled pack. We 1127*30519Ssam * deduce the drive type by reading from the last 1128*30519Ssam * track on successively smaller drives until we 1129*30519Ssam * don't get an error. 113025675Ssam */ 1131*30519Ssam vdmaptype(vi, lp) 1132*30519Ssam register struct vba_device *vi; 1133*30519Ssam register struct disklabel *lp; 113425675Ssam { 1135*30519Ssam register struct vdsoftc *vd; 1136*30519Ssam register struct vdst *p; 1137*30519Ssam struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; 1138*30519Ssam int i; 113925675Ssam 1140*30519Ssam vd = &vdsoftc[vi->ui_ctlr]; 1141*30519Ssam for (p = vdst; p < &vdst[NVDST]; p++) { 1142*30519Ssam if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32) 1143*30519Ssam continue; 1144*30519Ssam lp->d_nsectors = p->nsec; 1145*30519Ssam lp->d_ntracks = p->ntrack; 1146*30519Ssam lp->d_ncylinders = p->ncyl; 1147*30519Ssam if (!vdreset_drive(vi)) 1148*30519Ssam return (0); 1149*30519Ssam vd->vd_dcb.opcode = VDOP_RD; 1150*30519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 1151*30519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 1152*30519Ssam vd->vd_dcb.devselect = vi->ui_slave; 1153*30519Ssam vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long); 1154*30519Ssam vd->vd_dcb.trail.rwtrail.memadr = (char *) 1155*30519Ssam vtoph((struct proc *)0, (unsigned)vd->vd_rawbuf); 1156*30519Ssam vd->vd_dcb.trail.rwtrail.wcount = 512 / sizeof(short); 1157*30519Ssam vd->vd_dcb.operrsta = 0; 1158*30519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2; 1159*30519Ssam vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1; 1160*30519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1; 1161*30519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 1162*30519Ssam vd->vd_mdcb.mdcb_status = 0; 1163*30519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 1164*30519Ssam if (!vdpoll(vm, 60)) 1165*30519Ssam printf(" during probe\n"); 1166*30519Ssam if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0) 1167*30519Ssam break; 116824004Ssam } 1169*30519Ssam if (p >= &vdst[NVDST]) { 1170*30519Ssam printf("dk%d: unknown drive type\n", vi->ui_unit); 1171*30519Ssam return (0); 1172*30519Ssam } 1173*30519Ssam for (i = 0; i < 3; i++) { 1174*30519Ssam lp->d_partitions[i].p_offset = p->parts[i].off; 1175*30519Ssam lp->d_partitions[i].p_size = p->parts[i].size; 1176*30519Ssam } 1177*30519Ssam lp->d_npartitions = 3; 1178*30519Ssam lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 1179*30519Ssam lp->d_rpm = 3600; 1180*30519Ssam lp->d_secsize = 512; 1181*30519Ssam bcopy(p->name, lp->d_typename, 4); 1182*30519Ssam return (1); 118324004Ssam } 1184*30519Ssam #endif COMPAT_42 118524004Ssam #endif 1186