134528Skarels /* 234528Skarels * Copyright (c) 1988 Regents of the University of California. 334528Skarels * All rights reserved. 434528Skarels * 535056Skarels * This code is derived from software contributed to Berkeley by 635056Skarels * Computer Consoles Inc. 735056Skarels * 8*44534Sbostic * %sccs.include.redist.c% 934528Skarels * 10*44534Sbostic * @(#)vd.c 7.12 (Berkeley) 06/28/90 1134528Skarels */ 1224004Ssam 1329564Ssam #include "dk.h" 1424004Ssam #if NVD > 0 1524004Ssam /* 1630519Ssam * Versabus VDDC/SMDE driver. 1725675Ssam */ 1825675Ssam #include "param.h" 1925675Ssam #include "buf.h" 2025675Ssam #include "cmap.h" 2125675Ssam #include "conf.h" 2229564Ssam #include "dkstat.h" 2330519Ssam #include "disklabel.h" 2425675Ssam #include "map.h" 2530519Ssam #include "file.h" 2625675Ssam #include "systm.h" 2725675Ssam #include "user.h" 2825675Ssam #include "vmmac.h" 2925675Ssam #include "proc.h" 3030370Skarels #include "syslog.h" 3130370Skarels #include "kernel.h" 3230519Ssam #include "ioctl.h" 3330756Skarels #include "stat.h" 3424004Ssam 3529951Skarels #include "../tahoe/cpu.h" 3629951Skarels #include "../tahoe/mtpr.h" 3729951Skarels #include "../tahoe/pte.h" 3829951Skarels 3925675Ssam #include "../tahoevba/vbavar.h" 4025928Ssam #include "../tahoevba/vdreg.h" 4124004Ssam 4232211Skarels #ifndef COMPAT_42 4330519Ssam #define COMPAT_42 4432211Skarels #endif 4534396Skarels #define B_FORMAT B_XXX /* XXX */ 4630519Ssam 4730519Ssam #define vdunit(dev) (minor(dev) >> 3) 4830519Ssam #define vdpart(dev) (minor(dev) & 0x07) 4930519Ssam #define vdminor(unit,part) (((unit) << 3) | (part)) 5024004Ssam 5124004Ssam struct vba_ctlr *vdminfo[NVD]; 5229564Ssam struct vba_device *vddinfo[NDK]; 5330756Skarels int vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy(); 5434528Skarels long vdstd[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 }; 5525675Ssam struct vba_driver vddriver = 5634528Skarels { vdprobe, vdslave, vdattach, vddgo, vdstd, "dk", vddinfo, "vd", vdminfo }; 5724004Ssam 5824004Ssam /* 5930519Ssam * Per-controller state. 6030519Ssam */ 6130519Ssam struct vdsoftc { 6230519Ssam u_short vd_flags; 6340737Skarels #define VD_PRINT 0x1 /* controller info printed */ 6430519Ssam #define VD_STARTED 0x2 /* start command issued */ 6530519Ssam #define VD_DOSEEKS 0x4 /* should overlap seeks */ 6630756Skarels #define VD_SCATGATH 0x8 /* can do scatter-gather commands (correctly) */ 6735082Skarels #define VD_LOCKED 0x10 /* locked for direct controller access */ 6835082Skarels #define VD_WAIT 0x20 /* someone needs direct controller access */ 6930519Ssam u_short vd_type; /* controller type */ 7030519Ssam u_short vd_wticks; /* timeout */ 7140737Skarels u_short vd_secsize; /* sector size for controller */ 7230519Ssam struct mdcb vd_mdcb; /* master command block */ 7330519Ssam u_long vd_mdcbphys; /* physical address of vd_mdcb */ 7430519Ssam struct dcb vd_dcb; /* i/o command block */ 7530519Ssam u_long vd_dcbphys; /* physical address of vd_dcb */ 7630601Skarels struct vb_buf vd_rbuf; /* vba resources */ 7730519Ssam } vdsoftc[NVD]; 7830519Ssam 7934396Skarels #define VDMAXTIME 20 /* max time for operation, sec. */ 8034396Skarels 8130519Ssam /* 8225675Ssam * Per-drive state. 8325675Ssam */ 8430519Ssam struct dksoftc { 8534076Skarels int dk_state; /* open fsm */ 8630756Skarels #ifndef SECSIZE 8730756Skarels u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */ 8830756Skarels #endif SECSIZE 8934076Skarels int dk_wlabel; /* label sector is currently writable */ 9032576Skarels u_long dk_copenpart; /* character units open on this drive */ 9132576Skarels u_long dk_bopenpart; /* block units open on this drive */ 9232576Skarels u_long dk_openpart; /* all units open on this drive */ 9330519Ssam u_int dk_curcyl; /* last selected cylinder */ 9430756Skarels struct skdcb dk_dcb; /* seek command block */ 9530519Ssam u_long dk_dcbphys; /* physical address of dk_dcb */ 9634396Skarels int df_reg[3]; /* for formatting, in-out parameters */ 9730519Ssam } dksoftc[NDK]; 9824004Ssam 9924004Ssam /* 10030519Ssam * Drive states. Used during steps of open/initialization. 10130519Ssam * States < OPEN (> 0) are transient, during an open operation. 10234076Skarels * OPENRAW is used for unlabeled disks, to allow format operations. 10325675Ssam */ 10430519Ssam #define CLOSED 0 /* disk is closed */ 10530519Ssam #define WANTOPEN 1 /* open requested, not started */ 10630519Ssam #define WANTOPENRAW 2 /* open requested, no label */ 10730519Ssam #define RDLABEL 3 /* reading pack label */ 10830519Ssam #define OPEN 4 /* intialized and ready */ 10930519Ssam #define OPENRAW 5 /* open, no label */ 11024004Ssam 11130519Ssam struct buf dkutab[NDK]; /* i/o queue headers */ 11230519Ssam struct disklabel dklabel[NDK]; /* pack labels */ 11324004Ssam 11430519Ssam #define b_cylin b_resid 11530574Skarels #define b_track b_error /* used for seek commands */ 11630574Skarels #define b_seekf b_forw /* second queue on um_tab */ 11730574Skarels #define b_seekl b_back /* second queue on um_tab */ 11830519Ssam 11930519Ssam int vdwstart, vdwatch(); 12030519Ssam 12124004Ssam /* 12225675Ssam * See if the controller is really there; if so, initialize it. 12325675Ssam */ 12425857Ssam vdprobe(reg, vm) 12525857Ssam caddr_t reg; 12625857Ssam struct vba_ctlr *vm; 12725675Ssam { 12825857Ssam register br, cvec; /* must be r12, r11 */ 12930519Ssam register struct vddevice *vdaddr = (struct vddevice *)reg; 13030519Ssam struct vdsoftc *vd; 13130573Skarels int s; 13225857Ssam 13330370Skarels #ifdef lint 13430370Skarels br = 0; cvec = br; br = cvec; 13530370Skarels vdintr(0); 13630370Skarels #endif 13725857Ssam if (badaddr((caddr_t)reg, 2)) 13825675Ssam return (0); 13930519Ssam vd = &vdsoftc[vm->um_ctlr]; 14030519Ssam vdaddr->vdreset = 0xffffffff; 14125675Ssam DELAY(1000000); 14230519Ssam if (vdaddr->vdreset != (unsigned)0xffffffff) { 14330519Ssam vd->vd_type = VDTYPE_VDDC; 14430519Ssam vd->vd_flags &= ~VD_DOSEEKS; 14525675Ssam DELAY(1000000); 14625675Ssam } else { 14730519Ssam vd->vd_type = VDTYPE_SMDE; 14830519Ssam vd->vd_flags |= VD_DOSEEKS; 14930519Ssam vdaddr->vdrstclr = 0; 15025675Ssam DELAY(3000000); 15125675Ssam } 15230519Ssam vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb); 15330519Ssam vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb); 15430519Ssam vm->um_addr = reg; /* XXX */ 15530573Skarels s = spl7(); 15640737Skarels if (vdinit_ctlr(vm, vd) == 0) { 15730573Skarels splx(s); 15830519Ssam return (0); 15930519Ssam } 16030756Skarels if (vd->vd_type == VDTYPE_SMDE) { 16140737Skarels #ifdef notdef 16240737Skarels /* 16340737Skarels * Attempt PROBE to get all drive status; 16440737Skarels * we take advantage of this in vdreset_drive 16540737Skarels * to try to avoid guessing games. 16640737Skarels */ 16740737Skarels (void) vdcmd(vm, VDOP_PROBE, 5, 0); 16840737Skarels #endif 16940737Skarels /* 17040737Skarels * Check for scatter-gather by checking firmware date 17140737Skarels * with IDENT command. The date is printed when 17240737Skarels * vdslave is first called, thus this must be 17340737Skarels * the last controller operation in vdprobe. 17440737Skarels */ 17530756Skarels vd->vd_dcb.trail.idtrail.date = 0; 17635413Skarels if (vdcmd(vm, VDOP_IDENT, 10, 0)) { 17730756Skarels uncache(&vd->vd_dcb.trail.idtrail.date); 17830756Skarels if (vd->vd_dcb.trail.idtrail.date != 0) 17930756Skarels vd->vd_flags |= VD_SCATGATH; 18030756Skarels } 18130756Skarels } 18230573Skarels splx(s); 18325925Ssam /* 18425950Ssam * Allocate page tables and i/o buffer. 18525925Ssam */ 18632211Skarels if (vbainit(&vd->vd_rbuf, MAXPHYS, 18732211Skarels vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT) == 0) { 18832211Skarels printf("vd%d: vbainit failed\n", vm->um_ctlr); 18932211Skarels return (0); 19032211Skarels } 19125857Ssam br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */ 19230519Ssam return (sizeof (struct vddevice)); 19325675Ssam } 19424004Ssam 19524004Ssam /* 19630519Ssam * See if a drive is really there. 19730519Ssam * 19830519Ssam * Can't read pack label here as various data structures 19930519Ssam * aren't setup for doing a read in a straightforward 20030519Ssam * manner. Instead just probe for the drive and leave 20130519Ssam * the pack label stuff to the attach routine. 20225675Ssam */ 20334076Skarels /* ARGSUSED */ 20434076Skarels vdslave(vi, vdaddr) 20525675Ssam register struct vba_device *vi; 20630519Ssam struct vddevice *vdaddr; 20725675Ssam { 20830519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 20932211Skarels register struct dksoftc *dk = &dksoftc[vi->ui_unit]; 21030519Ssam struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 21140737Skarels int bcd(); 21224004Ssam 21340737Skarels if ((vd->vd_flags&VD_PRINT) == 0) { 21435413Skarels printf("vd%d: %s controller", vi->ui_ctlr, 21535413Skarels vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE"); 21635413Skarels if (vd->vd_flags & VD_SCATGATH) { 21735413Skarels char rev[5]; 21835413Skarels 21935413Skarels bcopy((caddr_t)&vd->vd_dcb.trail.idtrail.rev, rev, 22035413Skarels sizeof(vd->vd_dcb.trail.idtrail.rev)); 22135413Skarels printf(" firmware rev %s (%d-%d-%d)", rev, 22240737Skarels bcd((vd->vd_dcb.trail.idtrail.date >> 8) & 0xff), 22340737Skarels bcd(vd->vd_dcb.trail.idtrail.date & 0xff), 22440737Skarels bcd((vd->vd_dcb.trail.idtrail.date >> 16)&0xffff)); 22535413Skarels } 22635413Skarels printf("\n"); 22740737Skarels vd->vd_flags |= VD_PRINT; 22825675Ssam } 22930519Ssam 23025675Ssam /* 23130519Ssam * Initialize label enough to do a reset on 23230519Ssam * the drive. The remainder of the default 23330519Ssam * label values will be filled in in vdinit 23430519Ssam * at attach time. 23525675Ssam */ 23632211Skarels if (vd->vd_type == VDTYPE_SMDE) 23732211Skarels lp->d_secsize = VD_MAXSECSIZE; 23832211Skarels else 23932211Skarels lp->d_secsize = VDDC_SECSIZE; 24034396Skarels lp->d_nsectors = 66; /* only used on smd-e */ 24134076Skarels lp->d_ntracks = 23; 24234396Skarels lp->d_ncylinders = 850; 24334396Skarels lp->d_secpercyl = 66*23; 24435413Skarels lp->d_rpm = 3600; 24534592Skarels lp->d_npartitions = 1; 24634592Skarels lp->d_partitions[0].p_offset = 0; 24734592Skarels lp->d_partitions[0].p_size = LABELSECTOR + 1; 24824004Ssam 24930519Ssam /* 25030519Ssam * Initialize invariant portion of 25130519Ssam * dcb used for overlapped seeks. 25230519Ssam */ 25330519Ssam dk->dk_dcb.opcode = VDOP_SEEK; 25430519Ssam dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA; 25530519Ssam dk->dk_dcb.devselect = vi->ui_slave; 25630756Skarels dk->dk_dcb.trailcnt = sizeof (struct trseek) / sizeof (long); 25730519Ssam dk->dk_dcb.trail.sktrail.skaddr.sector = 0; 25830519Ssam dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb); 25932211Skarels #ifndef SECSIZE 26032211Skarels vd_setsecsize(dk, lp); 26132211Skarels #endif 26232211Skarels return (vdreset_drive(vi)); 26332211Skarels } 26432211Skarels 26540737Skarels static int 26640737Skarels bcd(n) 26740737Skarels register u_int n; 26840737Skarels { 26940737Skarels register int bin = 0; 27040737Skarels register int mul = 1; 27140737Skarels 27240737Skarels while (n) { 27340737Skarels bin += (n & 0xf) * mul; 27440737Skarels n >>= 4; 27540737Skarels mul *= 10; 27640737Skarels } 27740737Skarels return (bin); 27840737Skarels } 27940737Skarels 28032211Skarels vdattach(vi) 28132211Skarels register struct vba_device *vi; 28232211Skarels { 28332211Skarels register int unit = vi->ui_unit; 28432211Skarels register struct disklabel *lp = &dklabel[unit]; 28532211Skarels 28630601Skarels /* 28730601Skarels * Try to initialize device and read pack label. 28830601Skarels */ 28930601Skarels if (vdinit(vdminor(unit, 0), 0) != 0) { 29030601Skarels printf(": unknown drive type"); 29130601Skarels return; 29230601Skarels } 29332211Skarels if (dksoftc[unit].dk_state == OPEN) 29432211Skarels printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>", 29532211Skarels lp->d_typename, lp->d_secsize, 29632211Skarels lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors); 29730519Ssam /* 29830519Ssam * (60 / rpm) / (sectors per track * (bytes per sector / 2)) 29930519Ssam */ 30030519Ssam if (vi->ui_dk >= 0) 30138170Smckusick dk_wpms[vi->ui_dk] = 30238170Smckusick (lp->d_rpm * lp->d_nsectors * lp->d_secsize) / 120; 30330519Ssam #ifdef notyet 30430573Skarels addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp); 30530519Ssam #endif 30624004Ssam } 30724004Ssam 30830756Skarels vdopen(dev, flags, fmt) 30930519Ssam dev_t dev; 31030756Skarels int flags, fmt; 31124004Ssam { 31230519Ssam register unit = vdunit(dev); 31330519Ssam register struct disklabel *lp; 31430519Ssam register struct dksoftc *dk; 31530519Ssam register struct partition *pp; 31630519Ssam struct vba_device *vi; 31740737Skarels int s, error = 0, part = vdpart(dev), mask = 1 << part; 31830519Ssam daddr_t start, end; 31924004Ssam 32030519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 32130519Ssam return (ENXIO); 32230519Ssam lp = &dklabel[unit]; 32330519Ssam dk = &dksoftc[unit]; 32430519Ssam 32530519Ssam s = spl7(); 32630519Ssam while (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 32730519Ssam dk->dk_state != CLOSED) 32840737Skarels if (error = tsleep((caddr_t)dk, (PZERO+1) | PCATCH, devopn, 0)) 32940737Skarels break; 33030519Ssam splx(s); 33140737Skarels if (error) 33240737Skarels return (error); 33330519Ssam if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 33430519Ssam if (error = vdinit(dev, flags)) 33530519Ssam return (error); 33630573Skarels 33730573Skarels if (vdwstart == 0) { 33830573Skarels timeout(vdwatch, (caddr_t)0, hz); 33930573Skarels vdwstart++; 34030573Skarels } 34130519Ssam /* 34230519Ssam * Warn if a partion is opened 34330519Ssam * that overlaps another partition which is open 34430519Ssam * unless one is the "raw" partition (whole disk). 34530519Ssam */ 34632211Skarels #define RAWPART 8 /* 'x' partition */ /* XXX */ 34732576Skarels if ((dk->dk_openpart & mask) == 0 && part != RAWPART) { 34830519Ssam pp = &lp->d_partitions[part]; 34930519Ssam start = pp->p_offset; 35030519Ssam end = pp->p_offset + pp->p_size; 35130519Ssam for (pp = lp->d_partitions; 35230519Ssam pp < &lp->d_partitions[lp->d_npartitions]; pp++) { 35330519Ssam if (pp->p_offset + pp->p_size <= start || 35430519Ssam pp->p_offset >= end) 35530519Ssam continue; 35630519Ssam if (pp - lp->d_partitions == RAWPART) 35730519Ssam continue; 35830519Ssam if (dk->dk_openpart & (1 << (pp - lp->d_partitions))) 35930519Ssam log(LOG_WARNING, 36030519Ssam "dk%d%c: overlaps open partition (%c)\n", 36130519Ssam unit, part + 'a', 36230519Ssam pp - lp->d_partitions + 'a'); 36330519Ssam } 36424004Ssam } 36530519Ssam if (part >= lp->d_npartitions) 36630519Ssam return (ENXIO); 36730756Skarels dk->dk_openpart |= mask; 36830756Skarels switch (fmt) { 36930756Skarels case S_IFCHR: 37030756Skarels dk->dk_copenpart |= mask; 37130756Skarels break; 37230756Skarels case S_IFBLK: 37330756Skarels dk->dk_bopenpart |= mask; 37430756Skarels break; 37530756Skarels } 37630519Ssam return (0); 37725675Ssam } 37824004Ssam 37934528Skarels /* ARGSUSED */ 38030756Skarels vdclose(dev, flags, fmt) 38130519Ssam dev_t dev; 38230756Skarels int flags, fmt; 38324004Ssam { 38430519Ssam register int unit = vdunit(dev); 38530519Ssam register struct dksoftc *dk = &dksoftc[unit]; 38630756Skarels int part = vdpart(dev), mask = 1 << part; 38724004Ssam 38830756Skarels switch (fmt) { 38930756Skarels case S_IFCHR: 39030756Skarels dk->dk_copenpart &= ~mask; 39130756Skarels break; 39230756Skarels case S_IFBLK: 39330756Skarels dk->dk_bopenpart &= ~mask; 39430756Skarels break; 39530756Skarels } 39630756Skarels if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0) 39730756Skarels dk->dk_openpart &= ~mask; 39830519Ssam /* 39930519Ssam * Should wait for i/o to complete on this partition 40030519Ssam * even if others are open, but wait for work on blkflush(). 40130519Ssam */ 40230519Ssam if (dk->dk_openpart == 0) { 40330573Skarels int s = spl7(); 40430573Skarels while (dkutab[unit].b_actf) 40530573Skarels sleep((caddr_t)dk, PZERO-1); 40630519Ssam splx(s); 40730519Ssam dk->dk_state = CLOSED; 40834076Skarels dk->dk_wlabel = 0; 40924004Ssam } 41030756Skarels return (0); 41125675Ssam } 41224004Ssam 41330519Ssam vdinit(dev, flags) 41430519Ssam dev_t dev; 41530519Ssam int flags; 41625675Ssam { 41730519Ssam register struct disklabel *lp; 41830519Ssam register struct dksoftc *dk; 41930519Ssam struct vba_device *vi; 42030519Ssam int unit = vdunit(dev), error = 0; 42130756Skarels char *msg, *readdisklabel(); 42230519Ssam extern int cold; 42325675Ssam 42430519Ssam dk = &dksoftc[unit]; 42530519Ssam if (flags & O_NDELAY) { 42630519Ssam dk->dk_state = OPENRAW; 42734528Skarels return (0); 42830519Ssam } 42930519Ssam dk->dk_state = RDLABEL; 43030519Ssam lp = &dklabel[unit]; 43130519Ssam vi = vddinfo[unit]; 43230756Skarels if (msg = readdisklabel(dev, vdstrategy, lp)) { 43334076Skarels if (cold) { 43430601Skarels printf(": %s", msg); 43534076Skarels dk->dk_state = CLOSED; 43634076Skarels } else { 43732211Skarels log(LOG_ERR, "dk%d: %s\n", unit, msg); 43834076Skarels dk->dk_state = OPENRAW; 43934076Skarels } 44030519Ssam #ifdef COMPAT_42 44135082Skarels vdlock(vi->ui_ctlr); 44234076Skarels if (vdmaptype(vi, lp)) 44330519Ssam dk->dk_state = OPEN; 44435082Skarels vdunlock(vi->ui_ctlr); 44530519Ssam #endif 44630756Skarels } else { 44730756Skarels /* 44830756Skarels * Now that we have the label, configure 44930756Skarels * the correct drive parameters. 45030756Skarels */ 45135082Skarels vdlock(vi->ui_ctlr); 45232211Skarels if (vdreset_drive(vi)) 45332211Skarels dk->dk_state = OPEN; 45432211Skarels else { 45530756Skarels dk->dk_state = CLOSED; 45630756Skarels error = ENXIO; 45732211Skarels } 45835082Skarels vdunlock(vi->ui_ctlr); 45925675Ssam } 46030756Skarels #ifndef SECSIZE 46132211Skarels vd_setsecsize(dk, lp); 46232211Skarels #endif 46330519Ssam wakeup((caddr_t)dk); 46430519Ssam return (error); 46524004Ssam } 46624004Ssam 46732211Skarels #ifndef SECSIZE 46832211Skarels vd_setsecsize(dk, lp) 46932211Skarels register struct dksoftc *dk; 47032211Skarels register struct disklabel *lp; 47132211Skarels { 47232211Skarels int mul; 47332211Skarels 47432211Skarels /* 47532211Skarels * Calculate scaling shift for mapping 47632211Skarels * DEV_BSIZE blocks to drive sectors. 47732211Skarels */ 47832211Skarels mul = DEV_BSIZE / lp->d_secsize; 47932211Skarels dk->dk_bshift = 0; 48032211Skarels while ((mul >>= 1) > 0) 48132211Skarels dk->dk_bshift++; 48232211Skarels } 48332211Skarels #endif SECSIZE 48432211Skarels 48525675Ssam /*ARGSUSED*/ 48630519Ssam vddgo(vm) 48730519Ssam struct vba_device *vm; 48824004Ssam { 48924004Ssam 49024004Ssam } 49124004Ssam 49224004Ssam vdstrategy(bp) 49325675Ssam register struct buf *bp; 49424004Ssam { 49530519Ssam register struct vba_device *vi; 49630519Ssam register struct disklabel *lp; 49730519Ssam register struct dksoftc *dk; 49830519Ssam register int unit; 49930573Skarels register daddr_t sn; 50030519Ssam struct buf *dp; 50130573Skarels daddr_t sz, maxsz; 50230519Ssam int part, s; 50324004Ssam 50430519Ssam unit = vdunit(bp->b_dev); 50532211Skarels if (unit >= NDK) { 50629954Skarels bp->b_error = ENXIO; 50725675Ssam goto bad; 50829954Skarels } 50930519Ssam vi = vddinfo[unit]; 51030519Ssam lp = &dklabel[unit]; 51130519Ssam if (vi == 0 || vi->ui_alive == 0) { 51230519Ssam bp->b_error = ENXIO; 51330519Ssam goto bad; 51430519Ssam } 51530519Ssam dk = &dksoftc[unit]; 51640737Skarels if (dk->dk_state < OPEN) { 51740737Skarels if (dk->dk_state == CLOSED) { 51840737Skarels bp->b_error = EIO; 51940737Skarels goto bad; 52040737Skarels } 52130519Ssam goto q; 52240737Skarels } 52334076Skarels if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) { 52434076Skarels bp->b_error = EROFS; 52534076Skarels goto bad; 52634076Skarels } 52730519Ssam part = vdpart(bp->b_dev); 52830519Ssam if ((dk->dk_openpart & (1 << part)) == 0) { 52930519Ssam bp->b_error = ENODEV; 53030519Ssam goto bad; 53130519Ssam } 53232211Skarels sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize; 53330519Ssam maxsz = lp->d_partitions[part].p_size; 53430756Skarels #ifndef SECSIZE 53530756Skarels sn = bp->b_blkno << dk->dk_bshift; 53630756Skarels #else SECSIZE 53730573Skarels sn = bp->b_blkno; 53830756Skarels #endif SECSIZE 53934076Skarels if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR && 54034076Skarels #if LABELSECTOR != 0 54134076Skarels sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR && 54234076Skarels #endif 54334076Skarels (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) { 54434076Skarels bp->b_error = EROFS; 54534076Skarels goto bad; 54634076Skarels } 54730519Ssam if (sn < 0 || sn + sz > maxsz) { 54830519Ssam if (sn == maxsz) { 54929954Skarels bp->b_resid = bp->b_bcount; 55029954Skarels goto done; 55129954Skarels } 55230756Skarels sz = maxsz - sn; 55330573Skarels if (sz <= 0) { 55430573Skarels bp->b_error = EINVAL; 55530573Skarels goto bad; 55630573Skarels } 55730573Skarels bp->b_bcount = sz * lp->d_secsize; 55825675Ssam } 55930519Ssam bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl; 56030756Skarels #ifdef SECSIZE 56130756Skarels if (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0) 56230756Skarels panic("vdstrat blksize"); 56330756Skarels #endif SECSIZE 56430519Ssam q: 56525675Ssam s = spl7(); 56630519Ssam dp = &dkutab[vi->ui_unit]; 56730519Ssam disksort(dp, bp); 56830519Ssam if (!dp->b_active) { 56930519Ssam (void) vdustart(vi); 57030573Skarels if (!vi->ui_mi->um_tab.b_active) 57130519Ssam vdstart(vi->ui_mi); 57224004Ssam } 57330519Ssam splx(s); 57424004Ssam return; 57525675Ssam bad: 57629954Skarels bp->b_flags |= B_ERROR; 57729954Skarels done: 57830519Ssam biodone(bp); 57930519Ssam return; 58024004Ssam } 58124004Ssam 58230519Ssam vdustart(vi) 58330519Ssam register struct vba_device *vi; 58424004Ssam { 58530519Ssam register struct buf *bp, *dp; 58630519Ssam register struct vba_ctlr *vm; 58730519Ssam register int unit = vi->ui_unit; 58830519Ssam register struct dksoftc *dk; 58930519Ssam register struct vdsoftc *vd; 59030519Ssam struct disklabel *lp; 59124004Ssam 59230519Ssam dp = &dkutab[unit]; 59330519Ssam /* 59430519Ssam * If queue empty, nothing to do. 59530519Ssam */ 59630519Ssam if ((bp = dp->b_actf) == NULL) 59730519Ssam return; 59830519Ssam /* 59930574Skarels * If drive is off-cylinder and controller supports seeks, 60030574Skarels * place drive on seek queue for controller. 60130574Skarels * Otherwise, place on transfer queue. 60230519Ssam */ 60330519Ssam vd = &vdsoftc[vi->ui_ctlr]; 60430519Ssam dk = &dksoftc[unit]; 60530574Skarels vm = vi->ui_mi; 60630519Ssam if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) { 60730519Ssam lp = &dklabel[unit]; 60830574Skarels bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors; 60930574Skarels if (vm->um_tab.b_seekf == NULL) 61030574Skarels vm->um_tab.b_seekf = dp; 61130574Skarels else 61230574Skarels vm->um_tab.b_seekl->b_forw = dp; 61330574Skarels vm->um_tab.b_seekl = dp; 61430574Skarels } else { 61530574Skarels if (vm->um_tab.b_actf == NULL) 61630574Skarels vm->um_tab.b_actf = dp; 61730574Skarels else 61830574Skarels vm->um_tab.b_actl->b_forw = dp; 61930574Skarels vm->um_tab.b_actl = dp; 62030519Ssam } 62130573Skarels dp->b_forw = NULL; 62230573Skarels dp->b_active++; 62325675Ssam } 62425675Ssam 62525675Ssam /* 62630519Ssam * Start next transfer on a controller. 62730574Skarels * There are two queues of drives, the first on-cylinder 62830574Skarels * and the second off-cylinder from their next transfers. 62930574Skarels * Perform the first transfer for the first drive on the on-cylinder 63030574Skarels * queue, if any, otherwise the first transfer for the first drive 63130574Skarels * on the second queue. Initiate seeks on remaining drives on the 63230574Skarels * off-cylinder queue, then move them all to the on-cylinder queue. 63325675Ssam */ 63430519Ssam vdstart(vm) 63530519Ssam register struct vba_ctlr *vm; 63625675Ssam { 63725675Ssam register struct buf *bp; 63830519Ssam register struct vba_device *vi; 63930519Ssam register struct vdsoftc *vd; 64030519Ssam register struct dksoftc *dk; 64130519Ssam register struct disklabel *lp; 64230519Ssam register struct dcb **dcbp; 64330519Ssam struct buf *dp; 64430519Ssam int sn, tn; 64525675Ssam 64630519Ssam loop: 64730519Ssam /* 64830519Ssam * Pull a request off the controller queue. 64930519Ssam */ 65030574Skarels if ((dp = vm->um_tab.b_actf) == NULL && 65130574Skarels (dp = vm->um_tab.b_seekf) == NULL) 65230519Ssam return; 65330519Ssam if ((bp = dp->b_actf) == NULL) { 65430601Skarels if (dp == vm->um_tab.b_actf) 65530601Skarels vm->um_tab.b_actf = dp->b_forw; 65630601Skarels else 65730601Skarels vm->um_tab.b_seekf = dp->b_forw; 65830519Ssam goto loop; 65930519Ssam } 66025675Ssam 66124004Ssam /* 66230519Ssam * Mark controller busy, and determine 66330519Ssam * destination of this request. 66424004Ssam */ 66530519Ssam vm->um_tab.b_active++; 66630519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 66730519Ssam dk = &dksoftc[vi->ui_unit]; 66830756Skarels #ifndef SECSIZE 66930756Skarels sn = bp->b_blkno << dk->dk_bshift; 67030756Skarels #else SECSIZE 67130573Skarels sn = bp->b_blkno; 67230756Skarels #endif SECSIZE 67330519Ssam lp = &dklabel[vi->ui_unit]; 67430519Ssam sn %= lp->d_secpercyl; 67530519Ssam tn = sn / lp->d_nsectors; 67630519Ssam sn %= lp->d_nsectors; 67730519Ssam 67830519Ssam /* 67930519Ssam * Construct dcb for read/write command. 68030519Ssam */ 68130519Ssam vd = &vdsoftc[vm->um_ctlr]; 68230519Ssam vd->vd_dcb.intflg = DCBINT_DONE; 68332211Skarels vd->vd_dcb.devselect = dk->dk_dcb.devselect; 68430519Ssam vd->vd_dcb.operrsta = 0; 68530519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 68630519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin; 68730519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 68830519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 68930574Skarels dk->dk_curcyl = bp->b_cylin; 69030574Skarels bp->b_track = 0; /* init overloaded field */ 69130756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 69234396Skarels if (bp->b_flags & B_FORMAT) 69334396Skarels vd->vd_dcb.opcode = dk->dk_op; 69434396Skarels else if (vd->vd_flags & VD_SCATGATH && 69534396Skarels ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0) 69630756Skarels vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW; 69734396Skarels else 69830756Skarels vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD; 69934396Skarels 70034396Skarels switch (vd->vd_dcb.opcode) { 70134396Skarels case VDOP_FSECT: 70240737Skarels vd->vd_dcb.trailcnt = sizeof (struct trfmt) / sizeof (long); 70334396Skarels vd->vd_dcb.trail.fmtrail.nsectors = bp->b_bcount / 70434396Skarels lp->d_secsize; 70534396Skarels vd->vd_dcb.trail.fmtrail.hdr = *(dskadr *)&dk->dk_althdr; 70634396Skarels vd->vd_dcb.trail.rwtrail.disk.cylinder |= dk->dk_fmtflags; 70734396Skarels goto setupaddr; 70834396Skarels 70934396Skarels case VDOP_RDRAW: 71034396Skarels case VDOP_RD: 71140737Skarels case VDOP_RHDE: 71234396Skarels case VDOP_WD: 71334396Skarels vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1; 71434396Skarels setupaddr: 71530756Skarels vd->vd_dcb.trail.rwtrail.memadr = 71634528Skarels vbasetup(bp, &vd->vd_rbuf, (int)lp->d_secsize); 71734396Skarels break; 71834396Skarels 71934396Skarels case VDOP_RAS: 72034396Skarels case VDOP_GAW: 72135712Sbostic vd->vd_dcb.trailcnt += vd_sgsetup(bp, &vd->vd_rbuf, 72234396Skarels &vd->vd_dcb.trail.sgtrail); 72334396Skarels break; 72430756Skarels } 72530574Skarels if (vi->ui_dk >= 0) { 72630574Skarels dk_busy |= 1<<vi->ui_dk; 72730574Skarels dk_xfer[vi->ui_dk]++; 72830574Skarels dk_wds[vi->ui_dk] += bp->b_bcount>>6; 72930574Skarels } 73030519Ssam 73130519Ssam /* 73230519Ssam * Look for any seeks to be performed on other drives on this 73330519Ssam * controller. If overlapped seeks exist, insert seek commands 73430519Ssam * on the controller's command queue before the transfer. 73530519Ssam */ 73630519Ssam dcbp = &vd->vd_mdcb.mdcb_head; 73730519Ssam 73830574Skarels if (dp == vm->um_tab.b_seekf) 73930574Skarels dp = dp->b_forw; 74030574Skarels else 74130574Skarels dp = vm->um_tab.b_seekf; 74230574Skarels for (; dp != NULL; dp = dp->b_forw) { 74330574Skarels if ((bp = dp->b_actf) == NULL) 74430574Skarels continue; 74530574Skarels vi = vddinfo[vdunit(bp->b_dev)]; 74630574Skarels dk = &dksoftc[vi->ui_unit]; 74730519Ssam dk->dk_curcyl = bp->b_cylin; 74830574Skarels if (vi->ui_dk >= 0) 74930574Skarels dk_seek[vi->ui_dk]++; 75030574Skarels dk->dk_dcb.operrsta = 0; 75130574Skarels dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin; 75230574Skarels dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track; 75330574Skarels *dcbp = (struct dcb *)dk->dk_dcbphys; 75430574Skarels dcbp = &dk->dk_dcb.nxtdcb; 75524004Ssam } 75630519Ssam *dcbp = (struct dcb *)vd->vd_dcbphys; 75730574Skarels if (vm->um_tab.b_actf) 75830574Skarels vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf; 75930574Skarels else 76030574Skarels vm->um_tab.b_actf = vm->um_tab.b_seekf; 76130601Skarels if (vm->um_tab.b_seekf) 76230601Skarels vm->um_tab.b_actl = vm->um_tab.b_seekl; 76330574Skarels vm->um_tab.b_seekf = 0; 76424004Ssam 76530519Ssam /* 76630519Ssam * Initiate operation. 76730519Ssam */ 76830519Ssam vd->vd_mdcb.mdcb_status = 0; 76930519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 77024004Ssam } 77124004Ssam 77235082Skarels /* 77335082Skarels * Wait for controller to finish current operation 77435082Skarels * so that direct controller accesses can be done. 77535082Skarels */ 77635082Skarels vdlock(ctlr) 77735082Skarels { 77835082Skarels register struct vba_ctlr *vm = vdminfo[ctlr]; 77935082Skarels register struct vdsoftc *vd = &vdsoftc[ctlr]; 78035082Skarels int s; 78135082Skarels 78235082Skarels s = spl7(); 78335082Skarels while (vm->um_tab.b_active || vd->vd_flags & VD_LOCKED) { 78435082Skarels vd->vd_flags |= VD_WAIT; 78535082Skarels sleep((caddr_t)vd, PRIBIO); 78635082Skarels } 78735082Skarels vd->vd_flags |= VD_LOCKED; 78835082Skarels splx(s); 78935082Skarels } 79035082Skarels 79135082Skarels /* 79235082Skarels * Continue normal operations after pausing for 79335082Skarels * munging the controller directly. 79435082Skarels */ 79535082Skarels vdunlock(ctlr) 79635082Skarels { 79735082Skarels register struct vba_ctlr *vm = vdminfo[ctlr]; 79835082Skarels register struct vdsoftc *vd = &vdsoftc[ctlr]; 79935082Skarels 80035082Skarels vd->vd_flags &= ~VD_LOCKED; 80135082Skarels if (vd->vd_flags & VD_WAIT) { 80235082Skarels vd->vd_flags &= ~VD_WAIT; 80335082Skarels wakeup((caddr_t)vd); 80435082Skarels } else if (vm->um_tab.b_actf || vm->um_tab.b_seekf) 80535082Skarels vdstart(vm); 80635082Skarels } 80735082Skarels 80830519Ssam #define DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE) 80924004Ssam /* 81024004Ssam * Handle a disk interrupt. 81124004Ssam */ 81225675Ssam vdintr(ctlr) 81330519Ssam register ctlr; 81424004Ssam { 81530519Ssam register struct buf *bp, *dp; 81630519Ssam register struct vba_ctlr *vm = vdminfo[ctlr]; 81730519Ssam register struct vba_device *vi; 81830519Ssam register struct vdsoftc *vd = &vdsoftc[ctlr]; 81930519Ssam register status; 82034528Skarels int timedout; 82130573Skarels struct dksoftc *dk; 82224004Ssam 82330519Ssam if (!vm->um_tab.b_active) { 82425675Ssam printf("vd%d: stray interrupt\n", ctlr); 82524004Ssam return; 82624004Ssam } 82725675Ssam /* 82830519Ssam * Get device and block structures, and a pointer 82930519Ssam * to the vba_device for the drive. 83025675Ssam */ 83130519Ssam dp = vm->um_tab.b_actf; 83230519Ssam bp = dp->b_actf; 83330519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 83434528Skarels dk = &dksoftc[vi->ui_unit]; 83530574Skarels if (vi->ui_dk >= 0) 83630574Skarels dk_busy &= ~(1<<vi->ui_dk); 83734396Skarels timedout = (vd->vd_wticks >= VDMAXTIME); 83830519Ssam /* 83930519Ssam * Check for and process errors on 84030519Ssam * either the drive or the controller. 84130519Ssam */ 84230519Ssam uncache(&vd->vd_dcb.operrsta); 84330519Ssam status = vd->vd_dcb.operrsta; 84434396Skarels if (bp->b_flags & B_FORMAT) { 84534396Skarels dk->dk_operrsta = status; 84634396Skarels uncache(&vd->vd_dcb.err_code); 84740737Skarels /* ecodecnt gets err_code + err_wcnt from the same longword */ 84840737Skarels dk->dk_ecodecnt = *(long *)&vd->vd_dcb.err_code; 84940737Skarels uncache(&vd->vd_dcb.err_trk); 85040737Skarels /* erraddr gets error trk/sec/cyl from the same longword */ 85140737Skarels dk->dk_erraddr = *(long *)&vd->vd_dcb.err_trk; 85240737Skarels } else if (status & VDERR_HARD || timedout) { 85334528Skarels if (vd->vd_type == VDTYPE_SMDE) 85430601Skarels uncache(&vd->vd_dcb.err_code); 85530519Ssam if (status & DCBS_WPT) { 85630519Ssam /* 85730519Ssam * Give up on write locked devices immediately. 85830519Ssam */ 85930573Skarels printf("dk%d: write locked\n", vi->ui_unit); 86030519Ssam bp->b_flags |= B_ERROR; 86134396Skarels } else if (status & VDERR_RETRY || timedout) { 86234396Skarels if (status & VDERR_CTLR || timedout) { 86340737Skarels vdharderr(timedout ? 86440737Skarels "controller timeout" : "controller err", 86534396Skarels vd, bp, &vd->vd_dcb); 86634396Skarels printf("; resetting controller..."); 86734396Skarels vdreset_ctlr(vm); 86834396Skarels } else if (status & VDERR_DRIVE) { 86934396Skarels vdharderr("drive err", vd, bp, &vd->vd_dcb); 87034396Skarels printf("; resetting drive..."); 87130519Ssam if (!vdreset_drive(vi)) 87240737Skarels dk->dk_state = CLOSED; 87332211Skarels } else 87440737Skarels vdharderr("data err", vd, bp, &vd->vd_dcb); 87530519Ssam /* 87630519Ssam * Retry transfer once, unless reset failed. 87730519Ssam */ 87840737Skarels if (!vi->ui_alive || dp->b_errcnt++ >= 1) { 87940737Skarels printf("\n"); 88030519Ssam goto hard; 88132211Skarels } 88232211Skarels 88340737Skarels printf(" retrying\n"); 88430519Ssam vm->um_tab.b_active = 0; /* force retry */ 88530519Ssam } else { 88640737Skarels vdharderr("hard error", vd, bp, &vd->vd_dcb); 88740737Skarels printf("\n"); 88830519Ssam hard: 88930519Ssam bp->b_flags |= B_ERROR; 89030519Ssam } 89130519Ssam } else if (status & DCBS_SOFT) 89234528Skarels vdsofterr(bp, &vd->vd_dcb); 89340737Skarels if (vd->vd_wticks > 3) { 89440737Skarels vd->vd_dcb.err_code = vd->vd_wticks; 89540737Skarels vdharderr("slow transfer (ecode is sec.)", vd, bp, &vd->vd_dcb); 89640737Skarels printf("\n"); 89740737Skarels } 89834396Skarels vd->vd_wticks = 0; 89930519Ssam if (vm->um_tab.b_active) { 90030519Ssam vm->um_tab.b_active = 0; 90130519Ssam vm->um_tab.b_actf = dp->b_forw; 90230519Ssam dp->b_active = 0; 90330519Ssam dp->b_errcnt = 0; 90430519Ssam dp->b_actf = bp->av_forw; 90530519Ssam bp->b_resid = 0; 90630601Skarels vbadone(bp, &vd->vd_rbuf); 90730519Ssam biodone(bp); 90830370Skarels /* 90930519Ssam * If this unit has more work to do, 91030519Ssam * then start it up right away. 91130370Skarels */ 91230519Ssam if (dp->b_actf) 91330519Ssam vdustart(vi); 91434528Skarels else if (dk->dk_openpart == 0) 91530573Skarels wakeup((caddr_t)dk); 91624004Ssam } 91725675Ssam /* 91830519Ssam * If there are devices ready to 91930519Ssam * transfer, start the controller. 92025675Ssam */ 92135082Skarels if (vd->vd_flags & VD_WAIT) { 92235082Skarels vd->vd_flags &= ~VD_WAIT; 92335082Skarels wakeup((caddr_t)vd); 92435082Skarels } else if (vm->um_tab.b_actf || vm->um_tab.b_seekf) 92530519Ssam vdstart(vm); 92624004Ssam } 92724004Ssam 92834396Skarels vdharderr(what, vd, bp, dcb) 92934396Skarels char *what; 93034396Skarels struct vdsoftc *vd; 93134396Skarels register struct buf *bp; 93234396Skarels register struct dcb *dcb; 93334396Skarels { 93434396Skarels int unit = vdunit(bp->b_dev), status = dcb->operrsta; 93534396Skarels register struct disklabel *lp = &dklabel[unit]; 93634528Skarels int blkdone; 93734396Skarels 93834396Skarels if (vd->vd_wticks < VDMAXTIME) 93934396Skarels status &= ~DONTCARE; 94034710Skarels blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) * 94134710Skarels lp->d_nsectors + dcb->err_sec - 94234710Skarels lp->d_partitions[vdpart(bp->b_dev)].p_offset) >> 94334710Skarels dksoftc[unit].dk_bshift) - bp->b_blkno; 94434528Skarels diskerr(bp, "dk", what, LOG_PRINTF, blkdone, lp); 94534528Skarels printf(", status %b", status, VDERRBITS); 94634396Skarels if (vd->vd_type == VDTYPE_SMDE) 94734396Skarels printf(" ecode %x", dcb->err_code); 94834396Skarels } 94934396Skarels 95034528Skarels vdsofterr(bp, dcb) 95125675Ssam register struct buf *bp; 95230519Ssam register struct dcb *dcb; 95325675Ssam { 95434562Skarels int unit = vdunit(bp->b_dev); 95534562Skarels struct disklabel *lp = &dklabel[unit]; 95634528Skarels int status = dcb->operrsta; 95734528Skarels int blkdone; 95825675Ssam 95934710Skarels blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) * 96034710Skarels lp->d_nsectors + dcb->err_sec - 96134710Skarels lp->d_partitions[vdpart(bp->b_dev)].p_offset) >> 96234710Skarels dksoftc[unit].dk_bshift) - bp->b_blkno; 96334528Skarels 96434528Skarels if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) { 96534528Skarels diskerr(bp, "dk", "soft error", LOG_WARNING, blkdone, lp); 96634528Skarels addlog(", status %b ecode %x\n", status, VDERRBITS, 96734396Skarels dcb->err_code); 96834528Skarels } else { 96934528Skarels diskerr(bp, "dk", "soft ecc", LOG_WARNING, blkdone, lp); 97034528Skarels addlog("\n"); 97134528Skarels } 97225675Ssam } 97325675Ssam 97430519Ssam vdioctl(dev, cmd, data, flag) 97525675Ssam dev_t dev; 97630519Ssam int cmd; 97730519Ssam caddr_t data; 97830519Ssam int flag; 97924004Ssam { 98032576Skarels register int unit = vdunit(dev); 98130519Ssam register struct disklabel *lp = &dklabel[unit]; 98234076Skarels register struct dksoftc *dk = &dksoftc[unit]; 98334640Skarels int error = 0, vdformat(); 98424004Ssam 98530519Ssam switch (cmd) { 98630519Ssam 98730519Ssam case DIOCGDINFO: 98830519Ssam *(struct disklabel *)data = *lp; 98930519Ssam break; 99030519Ssam 99130573Skarels case DIOCGPART: 99230573Skarels ((struct partinfo *)data)->disklab = lp; 99330573Skarels ((struct partinfo *)data)->part = 99430573Skarels &lp->d_partitions[vdpart(dev)]; 99530519Ssam break; 99630519Ssam 99730519Ssam case DIOCSDINFO: 99830519Ssam if ((flag & FWRITE) == 0) 99930519Ssam error = EBADF; 100030519Ssam else 100132576Skarels error = setdisklabel(lp, (struct disklabel *)data, 100234076Skarels (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart); 100334396Skarels if (error == 0 && dk->dk_state == OPENRAW && 100434396Skarels vdreset_drive(vddinfo[unit])) 100534076Skarels dk->dk_state = OPEN; 100630519Ssam break; 100730519Ssam 100834076Skarels case DIOCWLABEL: 100934076Skarels if ((flag & FWRITE) == 0) 101034076Skarels error = EBADF; 101134076Skarels else 101234076Skarels dk->dk_wlabel = *(int *)data; 101334076Skarels break; 101434076Skarels 101532576Skarels case DIOCWDINFO: 101632576Skarels if ((flag & FWRITE) == 0) 101730519Ssam error = EBADF; 101832576Skarels else if ((error = setdisklabel(lp, (struct disklabel *)data, 101934076Skarels (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) { 102034640Skarels int wlab; 102134640Skarels 102235413Skarels if (error == 0 && dk->dk_state == OPENRAW && 102335413Skarels vdreset_drive(vddinfo[unit])) 102435413Skarels dk->dk_state = OPEN; 102534640Skarels /* simulate opening partition 0 so write succeeds */ 102634640Skarels dk->dk_openpart |= (1 << 0); /* XXX */ 102734640Skarels wlab = dk->dk_wlabel; 102834640Skarels dk->dk_wlabel = 1; 102932576Skarels error = writedisklabel(dev, vdstrategy, lp); 103034640Skarels dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart; 103134640Skarels dk->dk_wlabel = wlab; 103234076Skarels } 103330519Ssam break; 103430519Ssam 103534396Skarels case DIOCWFORMAT: 103634396Skarels { 103734396Skarels register struct format_op *fop; 103834396Skarels struct uio auio; 103934396Skarels struct iovec aiov; 104034396Skarels 104134396Skarels if ((flag & FWRITE) == 0) { 104234396Skarels error = EBADF; 104334396Skarels break; 104434396Skarels } 104534396Skarels fop = (struct format_op *)data; 104634396Skarels aiov.iov_base = fop->df_buf; 104734396Skarels aiov.iov_len = fop->df_count; 104834396Skarels auio.uio_iov = &aiov; 104934396Skarels auio.uio_iovcnt = 1; 105034396Skarels auio.uio_resid = fop->df_count; 105134396Skarels auio.uio_segflg = UIO_USERSPACE; 105234396Skarels auio.uio_offset = fop->df_startblk * lp->d_secsize; 105340737Skarels /* This assumes one active format operation per disk... */ 105440737Skarels dk->dk_op = fop->dk_op; 105540737Skarels dk->dk_althdr = fop->dk_althdr; 105640737Skarels dk->dk_fmtflags = fop->dk_fmtflags; 105734396Skarels /* 105834396Skarels * Don't return errors, as the format op won't get copied 105934396Skarels * out if we return nonzero. Callers must check the returned 106040737Skarels * registers and count. 106134396Skarels */ 106240737Skarels error = physio(vdformat, (struct buf *)NULL, dev, 106340737Skarels B_WRITE, minphys, &auio); 106440737Skarels if (error == EIO) 106540737Skarels error = 0; 106634396Skarels fop->df_count -= auio.uio_resid; 106740737Skarels /* This assumes one active format operation per disk... */ 106834396Skarels fop->dk_operrsta = dk->dk_operrsta; 106940737Skarels fop->dk_ecodecnt = dk->dk_ecodecnt; 107040737Skarels fop->dk_erraddr = dk->dk_erraddr; 107134396Skarels break; 107234396Skarels } 107334396Skarels 107430519Ssam default: 107530519Ssam error = ENOTTY; 107630519Ssam break; 107724004Ssam } 107832606Skarels return (error); 107924004Ssam } 108024004Ssam 108134396Skarels vdformat(bp) 108234396Skarels struct buf *bp; 108334396Skarels { 108434396Skarels bp->b_flags |= B_FORMAT; 108534396Skarels vdstrategy(bp); 108634396Skarels } 108734396Skarels 108825675Ssam /* 108930519Ssam * Watch for lost interrupts. 109025675Ssam */ 109130519Ssam vdwatch() 109230519Ssam { 109330519Ssam register struct vdsoftc *vd; 109430519Ssam register struct vba_ctlr *vm; 109534528Skarels register int ctlr; 109634396Skarels int s; 109730519Ssam 109830519Ssam timeout(vdwatch, (caddr_t)0, hz); 109930519Ssam for (ctlr = 0; ctlr < NVD; ctlr++) { 110030519Ssam vm = vdminfo[ctlr]; 110130519Ssam if (vm == 0 || vm->um_alive == 0) 110230519Ssam continue; 110330519Ssam vd = &vdsoftc[ctlr]; 110434396Skarels s = spl7(); 110534396Skarels if (vm->um_tab.b_active && vd->vd_wticks++ >= VDMAXTIME) { 110630519Ssam printf("vd%d: lost interrupt\n", ctlr); 110734396Skarels #ifdef maybe 110834396Skarels VDABORT((struct vddevice *)vm->um_addr, vd->vd_type); 110934396Skarels #endif 111034396Skarels vdintr(ctlr); 111130519Ssam } 111234396Skarels splx(s); 111330519Ssam } 111430519Ssam } 111530519Ssam 111630519Ssam #define DBSIZE 64 /* controller limit with 1K sectors */ 111730519Ssam /* 111830519Ssam * Crash dump. 111930519Ssam */ 112030519Ssam vddump(dev) 112130519Ssam dev_t dev; 112224004Ssam { 112330519Ssam register struct vba_device *vi; 112430519Ssam register struct vba_ctlr *vm; 112530519Ssam register struct disklabel *lp; 112630519Ssam register struct vdsoftc *vd; 112730519Ssam struct dksoftc *dk; 112830519Ssam int part, unit, num; 112930601Skarels u_long start; 113024004Ssam 113130519Ssam start = 0; 113230519Ssam unit = vdunit(dev); 113330519Ssam if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 113430519Ssam return (ENXIO); 113530519Ssam dk = &dksoftc[unit]; 113634076Skarels if (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 113734076Skarels vdinit(vdminor(unit, 0), 0) != 0) 113830519Ssam return (ENXIO); 113930519Ssam lp = &dklabel[unit]; 114030519Ssam part = vdpart(dev); 114130519Ssam if (part >= lp->d_npartitions) 114230519Ssam return (ENXIO); 114332211Skarels vm = vi->ui_mi; 114430519Ssam vdreset_ctlr(vm); 114530519Ssam if (dumplo < 0) 114630519Ssam return (EINVAL); 114730519Ssam /* 114830756Skarels * Maxfree is in pages, dumplo is in DEV_BSIZE units. 114930519Ssam */ 115030519Ssam num = maxfree * (NBPG / lp->d_secsize); 115130756Skarels dumplo *= DEV_BSIZE / lp->d_secsize; 115230519Ssam if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size) 115330519Ssam num = lp->d_partitions[vdpart(dev)].p_size - dumplo; 115430519Ssam vd = &vdsoftc[vm->um_ctlr]; 115530519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 115630519Ssam vd->vd_dcb.opcode = VDOP_WD; 115732211Skarels vd->vd_dcb.devselect = dk->dk_dcb.devselect; 115830756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 115930519Ssam while (num > 0) { 116030519Ssam int nsec, cn, sn, tn; 116130519Ssam 116230519Ssam nsec = MIN(num, DBSIZE); 116330601Skarels sn = dumplo + start / lp->d_secsize; 116430519Ssam cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) / 116530519Ssam lp->d_secpercyl; 116630519Ssam sn %= lp->d_secpercyl; 116730519Ssam tn = sn / lp->d_nsectors; 116830519Ssam sn %= lp->d_nsectors; 116930519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 117030519Ssam vd->vd_dcb.trail.rwtrail.memadr = start; 117130519Ssam vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1; 117230519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = cn; 117330519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 117430519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 117530519Ssam vd->vd_dcb.operrsta = 0; 117630519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 117730519Ssam if (!vdpoll(vm, 5)) { 117830519Ssam printf(" during dump\n"); 117930519Ssam return (EIO); 118030519Ssam } 118130519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 118230519Ssam printf("dk%d: hard error, status=%b\n", unit, 118330519Ssam vd->vd_dcb.operrsta, VDERRBITS); 118430519Ssam return (EIO); 118530519Ssam } 118630519Ssam start += nsec * lp->d_secsize; 118730519Ssam num -= nsec; 118825675Ssam } 118930519Ssam return (0); 119024004Ssam } 119124004Ssam 119224004Ssam vdsize(dev) 119325675Ssam dev_t dev; 119424004Ssam { 119530519Ssam register int unit = vdunit(dev); 119630519Ssam register struct dksoftc *dk; 119730519Ssam struct vba_device *vi; 119830519Ssam struct disklabel *lp; 119924004Ssam 120030519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 || 120130519Ssam (dk = &dksoftc[unit])->dk_state != OPEN) 120225675Ssam return (-1); 120330519Ssam lp = &dklabel[unit]; 120430756Skarels #ifdef SECSIZE 120530573Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size); 120630756Skarels #else SECSIZE 120730756Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift); 120830756Skarels #endif SECSIZE 120924004Ssam } 121024004Ssam 121125675Ssam /* 121240737Skarels * Initialize controller. 121325675Ssam */ 121440737Skarels vdinit_ctlr(vm, vd) 121540737Skarels struct vba_ctlr *vm; 121640737Skarels struct vdsoftc *vd; 121724004Ssam { 121830519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 121940737Skarels 122030519Ssam if (vd->vd_type == VDTYPE_SMDE) { 122130519Ssam vdaddr->vdcsr = 0; 122230519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 122330519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 122430519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 122530519Ssam vdaddr->vdtcf_data = AM_ENPDA; 122640737Skarels vdaddr->vdccf = CCF_SEN | CCF_DIU | CCF_STS | CCF_RFE | 122740737Skarels XMD_32BIT | BSZ_16WRD | 122825675Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 122925675Ssam } 123035413Skarels if (!vdcmd(vm, VDOP_INIT, 10, 0) || !vdcmd(vm, VDOP_DIAG, 10, 0)) { 123140737Skarels printf("vd%d: %s cmd failed\n", vm->um_ctlr, 123230519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 123340737Skarels return (0); 123440737Skarels } 123540737Skarels vd->vd_secsize = vdaddr->vdsecsize << 1; 123640737Skarels return (1); 123740737Skarels } 123840737Skarels 123940737Skarels /* 124040737Skarels * Perform a controller reset. 124140737Skarels */ 124240737Skarels vdreset_ctlr(vm) 124340737Skarels register struct vba_ctlr *vm; 124440737Skarels { 124540737Skarels register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 124640737Skarels register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 124740737Skarels register int unit; 124840737Skarels struct vba_device *vi; 124940737Skarels 125040737Skarels VDRESET(vdaddr, vd->vd_type); 125140737Skarels if (vdinit_ctlr(vm, vd) == 0) 125230370Skarels return; 125330519Ssam for (unit = 0; unit < NDK; unit++) 125430519Ssam if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive) 125530519Ssam (void) vdreset_drive(vi); 125630519Ssam } 125730519Ssam 125830519Ssam vdreset_drive(vi) 125930519Ssam register struct vba_device *vi; 126030519Ssam { 126130519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 126230519Ssam struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; 126330519Ssam struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 126432211Skarels register struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 126532211Skarels register struct dksoftc *dk = &dksoftc[vi->ui_unit]; 126640737Skarels int config_status, config_ecode, saw_drive = 0; 126730519Ssam 126840737Skarels #ifdef notdef 126940737Skarels /* 127040737Skarels * check for ESDI distribution panel already configured, 127140737Skarels * e.g. on boot drive, or if PROBE on controller actually 127240737Skarels * worked. Status will be zero if drive hasn't 127340737Skarels * been probed yet. 127440737Skarels */ 127540737Skarels #if STA_ESDI != 0 127640737Skarels if ((vdaddr->vdstatus[vi->ui_slave] & STA_TYPE) == STA_ESDI) 127740737Skarels lp->d_devflags |= VD_ESDI; 127840737Skarels #endif 127940737Skarels #endif 128030519Ssam top: 128130519Ssam vd->vd_dcb.opcode = VDOP_CONFIG; /* command */ 128230519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 128330519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 128430519Ssam vd->vd_dcb.operrsta = 0; 128532211Skarels vd->vd_dcb.devselect = vi->ui_slave | lp->d_devflags; 128630519Ssam vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders; 128730519Ssam vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks; 128830519Ssam if (vd->vd_type == VDTYPE_SMDE) { 128930756Skarels vd->vd_dcb.trailcnt = sizeof (struct treset) / sizeof (long); 129030519Ssam vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors; 129130601Skarels vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack; 129240737Skarels vd->vd_dcb.trail.rstrail.recovery = 129340737Skarels (lp->d_flags & D_REMOVABLE) ? VDRF_NORMAL : 129440737Skarels (VDRF_NORMAL &~ (VDRF_OSP|VDRF_OSM)); 129530519Ssam } else 129630519Ssam vd->vd_dcb.trailcnt = 2; /* XXX */ 129730519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 129830519Ssam vd->vd_mdcb.mdcb_status = 0; 129930519Ssam VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type); 130030519Ssam if (!vdpoll(vm, 5)) { 130130519Ssam printf(" during config\n"); 130230519Ssam return (0); 130325675Ssam } 130440737Skarels config_status = vd->vd_dcb.operrsta; 130540737Skarels config_ecode = (u_char)vd->vd_dcb.err_code; 130640737Skarels if (config_status & VDERR_HARD) { 130732211Skarels if (vd->vd_type == VDTYPE_SMDE) { 130840737Skarels /* 130940737Skarels * If drive status was updated successfully, 131040737Skarels * STA_US (unit selected) should be set 131140737Skarels * if the drive is attached and powered up. 131240737Skarels * (But only if we've guessed right on SMD 131340737Skarels * vs. ESDI; if that flag is wrong, we won't 131440737Skarels * see the drive.) If we don't see STA_US 131540737Skarels * with either SMD or ESDI set for the unit, 131640737Skarels * we assume that the drive doesn't exist, 131740737Skarels * and don't wait for it to spin up. 131840737Skarels */ 131940737Skarels (void) vdcmd(vm, VDOP_STATUS, 5, vi->ui_slave); 132040737Skarels uncache(&vdaddr->vdstatus[vi->ui_slave]); 132140737Skarels if (vdaddr->vdstatus[vi->ui_slave] & STA_US) 132240737Skarels saw_drive = 1; 132340737Skarels else if (lp->d_devflags == 0) { 132432211Skarels lp->d_devflags = VD_ESDI; 132532211Skarels goto top; 132632211Skarels } 132740737Skarels } else 132840737Skarels saw_drive = 1; 132940737Skarels if ((config_status & (DCBS_OCYL|DCBS_NRDY)) == 0) 133032211Skarels printf("dk%d: config error %b ecode %x\n", vi->ui_unit, 133140737Skarels config_status, VDERRBITS, config_ecode); 133240737Skarels else if ((vd->vd_flags & VD_STARTED) == 0 && saw_drive) { 133330519Ssam int started; 133430519Ssam 133532211Skarels printf(" starting drives, wait ... "); 133630519Ssam vd->vd_flags |= VD_STARTED; 133730519Ssam started = (vdcmd(vm, VDOP_START, 10) == 1); 133830519Ssam DELAY(62000000); 133935413Skarels printf("done\n"); 134032211Skarels lp->d_devflags = 0; 134130519Ssam if (started) 134230519Ssam goto top; 134330519Ssam } 134430519Ssam return (0); 134530519Ssam } 134632211Skarels dk->dk_dcb.devselect |= lp->d_devflags; 134730519Ssam return (1); 134825675Ssam } 134924004Ssam 135025675Ssam /* 135130519Ssam * Perform a command w/o trailer. 135225675Ssam */ 135335413Skarels vdcmd(vm, cmd, t, slave) 135430519Ssam register struct vba_ctlr *vm; 135525675Ssam { 135630519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 135725675Ssam 135830519Ssam vd->vd_dcb.opcode = cmd; /* command */ 135930519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 136030519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 136130519Ssam vd->vd_dcb.operrsta = 0; 136235413Skarels vd->vd_dcb.devselect = slave; 136330519Ssam vd->vd_dcb.trailcnt = 0; 136430519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 136530519Ssam vd->vd_mdcb.mdcb_status = 0; 136630519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 136730519Ssam if (!vdpoll(vm, t)) { 136830519Ssam printf(" during init\n"); 136930370Skarels return (0); 137030370Skarels } 137130519Ssam return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0); 137225675Ssam } 137325675Ssam 137425925Ssam /* 137530519Ssam * Poll controller until operation 137630519Ssam * completes or timeout expires. 137725925Ssam */ 137830519Ssam vdpoll(vm, t) 137930519Ssam register struct vba_ctlr *vm; 138025925Ssam register int t; 138125925Ssam { 138230519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 138330519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 138425925Ssam 138525925Ssam t *= 1000; 138630370Skarels for (;;) { 138730519Ssam uncache(&vd->vd_dcb.operrsta); 138830519Ssam if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT)) 138930370Skarels break; 139025925Ssam if (--t <= 0) { 139130519Ssam printf("vd%d: controller timeout", vm->um_ctlr); 139230519Ssam VDABORT(vdaddr, vd->vd_type); 139325925Ssam return (0); 139425925Ssam } 139530370Skarels DELAY(1000); 139625925Ssam } 139730519Ssam if (vd->vd_type == VDTYPE_SMDE) { 139830519Ssam do { 139925925Ssam DELAY(50); 140030519Ssam uncache(&vdaddr->vdcsr); 140130519Ssam } while (vdaddr->vdcsr & CS_GO); 140232211Skarels DELAY(300); 140332211Skarels uncache(&vd->vd_dcb.err_code); 140425925Ssam } 140525925Ssam DELAY(200); 140630519Ssam uncache(&vd->vd_dcb.operrsta); 140725925Ssam return (1); 140825925Ssam } 140925925Ssam 141030519Ssam #ifdef COMPAT_42 141130519Ssam struct vdst { 141230519Ssam int nsec; /* sectors/track */ 141330519Ssam int ntrack; /* tracks/cylinder */ 141430519Ssam int ncyl; /* cylinders */ 141532211Skarels int secsize; /* sector size */ 141630519Ssam char *name; /* type name */ 141730519Ssam struct { 141830519Ssam int off; /* partition offset in sectors */ 141930519Ssam int size; /* partition size in sectors */ 142030573Skarels } parts[8]; 142130519Ssam } vdst[] = { 142232211Skarels { 66, 23, 850, 512, "NEC 800", 142332211Skarels {0, 1290300}, /* a cyl 0 - 849 */ 142432211Skarels }, 142534737Sbostic { 64, 20, 842, 512, "2361a", 142634737Sbostic {0, 61440}, /* a cyl 0 - 47 */ 142734737Sbostic {61440, 67840}, /* b cyl 48 - 100 */ 142834737Sbostic {129280, 942080}, /* c cyl 101 - 836 */ 142934737Sbostic {0, 1071360}, /* d cyl 0 - 836 */ 143034737Sbostic {449280, 311040}, /* e cyl 351 - 593 */ 143134737Sbostic {760320, 311040}, /* f cyl 594 - 836 */ 143234737Sbostic {449280, 622080}, /* g cyl 351 - 836 */ 143334737Sbostic {129280, 320000} /* h cyl 101 - 350 */ 143434737Sbostic }, 143532211Skarels { 48, 24, 711, 512, "xsd", 143631039Skarels {0, 61056}, /* a cyl 0 - 52 */ 143731039Skarels {61056, 61056}, /* b cyl 53 - 105 */ 143831039Skarels {122112, 691200}, /* c cyl 106 - 705 */ 143931039Skarels {237312, 576000}, /* d cyl 206 - 705 */ 144031039Skarels {352512, 460800}, /* e cyl 306 - 705 */ 144131039Skarels {467712, 345600}, /* f cyl 406 - 705 */ 144231039Skarels {582912, 230400}, /* g cyl 506 - 705 */ 144331039Skarels {698112, 115200} /* h cyl 606 - 705 */ 144430573Skarels }, 144532211Skarels { 44, 20, 842, 512, "eagle", 144630601Skarels {0, 52800}, /* egl0a cyl 0 - 59 */ 144730601Skarels {52800, 66000}, /* egl0b cyl 60 - 134 */ 144830601Skarels {118800, 617760}, /* egl0c cyl 135 - 836 */ 144930756Skarels {736560, 4400}, /* egl0d cyl 837 - 841 */ 145031039Skarels {0, 736560}, /* egl0e cyl 0 - 836 */ 145131039Skarels {0, 740960}, /* egl0f cyl 0 - 841 */ 145230601Skarels {118800, 310640}, /* egl0g cyl 135 - 487 */ 145330601Skarels {429440, 307120} /* egl0h cyl 488 - 836 */ 145430573Skarels }, 145532211Skarels { 64, 10, 823, 512, "fuj", 145631039Skarels {0, 38400}, /* fuj0a cyl 0 - 59 */ 145731039Skarels {38400, 48000}, /* fuj0b cyl 60 - 134 */ 145831039Skarels {86400, 437120}, /* fuj0c cyl 135 - 817 */ 145931039Skarels {159360, 364160}, /* fuj0d cyl 249 - 817 */ 146031039Skarels {232320, 291200}, /* fuj0e cyl 363 - 817 */ 146131039Skarels {305280, 218240}, /* fuj0f cyl 477 - 817 */ 146231039Skarels {378240, 145280}, /* fuj0g cyl 591 - 817 */ 146331039Skarels {451200, 72320} /* fug0h cyl 705 - 817 */ 146430573Skarels }, 146532211Skarels { 32, 24, 711, 512, "xfd", 146630756Skarels { 0, 40704 }, /* a cyl 0 - 52 */ 146730756Skarels { 40704, 40704 }, /* b cyl 53 - 105 */ 146830756Skarels { 81408, 460800 }, /* c cyl 106 - 705 */ 146930756Skarels { 0, 81408 }, /* d cyl 709 - 710 (a & b) */ 147030756Skarels { 0, 542208 }, /* e cyl 0 - 705 */ 147130756Skarels { 40704, 501504 }, /* f cyl 53 - 705 (b & c) */ 147230756Skarels { 81408, 230400 }, /* g cyl 106 - 405 (1/2 of c) */ 147330756Skarels { 311808,230400 } /* h cyl 406 - 705 (1/2 of c) */ 147430573Skarels }, 147532211Skarels { 32, 19, 823, 512, "smd", 147631039Skarels {0, 40128}, /* a cyl 0-65 */ 147731039Skarels {40128, 27360}, /* b cyl 66-110 */ 147831039Skarels {67488, 429856}, /* c cyl 111-817 */ 147931039Skarels {139232, 358112}, /* d cyl 229 - 817 */ 148031039Skarels {210976, 286368}, /* e cyl 347 - 817 */ 148131039Skarels {282720, 214624}, /* f cyl 465 - 817 */ 148231039Skarels {354464, 142880}, /* g cyl 583 - 817 */ 148331039Skarels {426208, 71136} /* h cyl 701 - 817 */ 148430573Skarels }, 148532211Skarels { 18, 15, 1224, 1024, "mxd", 148632211Skarels {0, 21600}, /* a cyl 0-79 */ 148732211Skarels {21600, 22410}, /* b cyl 80-162 */ 148832211Skarels {44010, 285120}, /* c cyl 163-1217 */ 148932211Skarels #ifdef notyet 149032211Skarels {x, 237600}, /* d cyl y - 1217 */ 149132211Skarels {x, 190080}, /* e cyl y - 1217 */ 149232211Skarels {x, 142560}, /* f cyl y - 1217 */ 149332211Skarels {x, 95040}, /* g cyl y - 1217 */ 149432211Skarels {x, 47520} /* h cyl 701 - 817 */ 149532211Skarels #endif 149632211Skarels }, 149732211Skarels { 32, 10, 823, 512, "fsd", 149830756Skarels {0, 19200}, /* a cyl 0 - 59 */ 149930756Skarels {19200, 24000}, /* b cyl 60 - 134 */ 150030756Skarels {43200, 218560}, /* c cyl 135 - 817 */ 150130573Skarels } 150230519Ssam }; 150330519Ssam #define NVDST (sizeof (vdst) / sizeof (vdst[0])) 150430519Ssam 150525675Ssam /* 150630519Ssam * Construct a label for an unlabeled pack. We 150730519Ssam * deduce the drive type by reading from the last 150830519Ssam * track on successively smaller drives until we 150930519Ssam * don't get an error. 151025675Ssam */ 151130519Ssam vdmaptype(vi, lp) 151230519Ssam register struct vba_device *vi; 151330519Ssam register struct disklabel *lp; 151425675Ssam { 151530519Ssam register struct vdsoftc *vd; 151630519Ssam register struct vdst *p; 151732211Skarels struct vba_ctlr *vm = vi->ui_mi; 151830519Ssam int i; 151925675Ssam 152030519Ssam vd = &vdsoftc[vi->ui_ctlr]; 152130519Ssam for (p = vdst; p < &vdst[NVDST]; p++) { 152230519Ssam if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32) 152330519Ssam continue; 152430519Ssam lp->d_nsectors = p->nsec; 152530519Ssam lp->d_ntracks = p->ntrack; 152630519Ssam lp->d_ncylinders = p->ncyl; 152732211Skarels lp->d_secsize = p->secsize; 152835413Skarels DELAY(100000); 152930519Ssam if (!vdreset_drive(vi)) 153030519Ssam return (0); 153135413Skarels DELAY(100000); 153230519Ssam vd->vd_dcb.opcode = VDOP_RD; 153330519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 153430519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 153532211Skarels vd->vd_dcb.devselect = dksoftc[vi->ui_unit].dk_dcb.devselect; 153630756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 153730601Skarels vd->vd_dcb.trail.rwtrail.memadr = 153830601Skarels vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf); 153932211Skarels vd->vd_dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof(short); 154030519Ssam vd->vd_dcb.operrsta = 0; 154130519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2; 154230519Ssam vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1; 154330519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1; 154430519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 154530519Ssam vd->vd_mdcb.mdcb_status = 0; 154630519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 154730519Ssam if (!vdpoll(vm, 60)) 154830519Ssam printf(" during probe\n"); 154930519Ssam if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0) 155030519Ssam break; 155124004Ssam } 155232211Skarels if (p >= &vdst[NVDST]) 155330519Ssam return (0); 155432211Skarels 155530573Skarels for (i = 0; i < 8; i++) { 155630519Ssam lp->d_partitions[i].p_offset = p->parts[i].off; 155730519Ssam lp->d_partitions[i].p_size = p->parts[i].size; 155830519Ssam } 155930573Skarels lp->d_npartitions = 8; 156030519Ssam lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 156130519Ssam bcopy(p->name, lp->d_typename, 4); 156230519Ssam return (1); 156324004Ssam } 156430519Ssam #endif COMPAT_42 156524004Ssam #endif 1566