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 * 834528Skarels * Redistribution and use in source and binary forms are permitted 934866Sbostic * provided that the above copyright notice and this paragraph are 1034866Sbostic * duplicated in all such forms and that any documentation, 1134866Sbostic * advertising materials, and other materials related to such 1234866Sbostic * distribution and use acknowledge that the software was developed 1334866Sbostic * by the University of California, Berkeley. The name of the 1434866Sbostic * University may not be used to endorse or promote products derived 1534866Sbostic * from this software without specific prior written permission. 1634866Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1734866Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1834866Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1934528Skarels * 20*40737Skarels * @(#)vd.c 7.11 (Berkeley) 04/03/90 2134528Skarels */ 2224004Ssam 2329564Ssam #include "dk.h" 2424004Ssam #if NVD > 0 2524004Ssam /* 2630519Ssam * Versabus VDDC/SMDE driver. 2725675Ssam */ 2825675Ssam #include "param.h" 2925675Ssam #include "buf.h" 3025675Ssam #include "cmap.h" 3125675Ssam #include "conf.h" 3229564Ssam #include "dkstat.h" 3330519Ssam #include "disklabel.h" 3425675Ssam #include "map.h" 3530519Ssam #include "file.h" 3625675Ssam #include "systm.h" 3725675Ssam #include "user.h" 3825675Ssam #include "vmmac.h" 3925675Ssam #include "proc.h" 4030370Skarels #include "syslog.h" 4130370Skarels #include "kernel.h" 4230519Ssam #include "ioctl.h" 4330756Skarels #include "stat.h" 4424004Ssam 4529951Skarels #include "../tahoe/cpu.h" 4629951Skarels #include "../tahoe/mtpr.h" 4729951Skarels #include "../tahoe/pte.h" 4829951Skarels 4925675Ssam #include "../tahoevba/vbavar.h" 5025928Ssam #include "../tahoevba/vdreg.h" 5124004Ssam 5232211Skarels #ifndef COMPAT_42 5330519Ssam #define COMPAT_42 5432211Skarels #endif 5534396Skarels #define B_FORMAT B_XXX /* XXX */ 5630519Ssam 5730519Ssam #define vdunit(dev) (minor(dev) >> 3) 5830519Ssam #define vdpart(dev) (minor(dev) & 0x07) 5930519Ssam #define vdminor(unit,part) (((unit) << 3) | (part)) 6024004Ssam 6124004Ssam struct vba_ctlr *vdminfo[NVD]; 6229564Ssam struct vba_device *vddinfo[NDK]; 6330756Skarels int vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy(); 6434528Skarels long vdstd[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 }; 6525675Ssam struct vba_driver vddriver = 6634528Skarels { vdprobe, vdslave, vdattach, vddgo, vdstd, "dk", vddinfo, "vd", vdminfo }; 6724004Ssam 6824004Ssam /* 6930519Ssam * Per-controller state. 7030519Ssam */ 7130519Ssam struct vdsoftc { 7230519Ssam u_short vd_flags; 73*40737Skarels #define VD_PRINT 0x1 /* controller info printed */ 7430519Ssam #define VD_STARTED 0x2 /* start command issued */ 7530519Ssam #define VD_DOSEEKS 0x4 /* should overlap seeks */ 7630756Skarels #define VD_SCATGATH 0x8 /* can do scatter-gather commands (correctly) */ 7735082Skarels #define VD_LOCKED 0x10 /* locked for direct controller access */ 7835082Skarels #define VD_WAIT 0x20 /* someone needs direct controller access */ 7930519Ssam u_short vd_type; /* controller type */ 8030519Ssam u_short vd_wticks; /* timeout */ 81*40737Skarels u_short vd_secsize; /* sector size for controller */ 8230519Ssam struct mdcb vd_mdcb; /* master command block */ 8330519Ssam u_long vd_mdcbphys; /* physical address of vd_mdcb */ 8430519Ssam struct dcb vd_dcb; /* i/o command block */ 8530519Ssam u_long vd_dcbphys; /* physical address of vd_dcb */ 8630601Skarels struct vb_buf vd_rbuf; /* vba resources */ 8730519Ssam } vdsoftc[NVD]; 8830519Ssam 8934396Skarels #define VDMAXTIME 20 /* max time for operation, sec. */ 9034396Skarels 9130519Ssam /* 9225675Ssam * Per-drive state. 9325675Ssam */ 9430519Ssam struct dksoftc { 9534076Skarels int dk_state; /* open fsm */ 9630756Skarels #ifndef SECSIZE 9730756Skarels u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */ 9830756Skarels #endif SECSIZE 9934076Skarels int dk_wlabel; /* label sector is currently writable */ 10032576Skarels u_long dk_copenpart; /* character units open on this drive */ 10132576Skarels u_long dk_bopenpart; /* block units open on this drive */ 10232576Skarels u_long dk_openpart; /* all units open on this drive */ 10330519Ssam u_int dk_curcyl; /* last selected cylinder */ 10430756Skarels struct skdcb dk_dcb; /* seek command block */ 10530519Ssam u_long dk_dcbphys; /* physical address of dk_dcb */ 10634396Skarels int df_reg[3]; /* for formatting, in-out parameters */ 10730519Ssam } dksoftc[NDK]; 10824004Ssam 10924004Ssam /* 11030519Ssam * Drive states. Used during steps of open/initialization. 11130519Ssam * States < OPEN (> 0) are transient, during an open operation. 11234076Skarels * OPENRAW is used for unlabeled disks, to allow format operations. 11325675Ssam */ 11430519Ssam #define CLOSED 0 /* disk is closed */ 11530519Ssam #define WANTOPEN 1 /* open requested, not started */ 11630519Ssam #define WANTOPENRAW 2 /* open requested, no label */ 11730519Ssam #define RDLABEL 3 /* reading pack label */ 11830519Ssam #define OPEN 4 /* intialized and ready */ 11930519Ssam #define OPENRAW 5 /* open, no label */ 12024004Ssam 12130519Ssam struct buf dkutab[NDK]; /* i/o queue headers */ 12230519Ssam struct disklabel dklabel[NDK]; /* pack labels */ 12324004Ssam 12430519Ssam #define b_cylin b_resid 12530574Skarels #define b_track b_error /* used for seek commands */ 12630574Skarels #define b_seekf b_forw /* second queue on um_tab */ 12730574Skarels #define b_seekl b_back /* second queue on um_tab */ 12830519Ssam 12930519Ssam int vdwstart, vdwatch(); 13030519Ssam 13124004Ssam /* 13225675Ssam * See if the controller is really there; if so, initialize it. 13325675Ssam */ 13425857Ssam vdprobe(reg, vm) 13525857Ssam caddr_t reg; 13625857Ssam struct vba_ctlr *vm; 13725675Ssam { 13825857Ssam register br, cvec; /* must be r12, r11 */ 13930519Ssam register struct vddevice *vdaddr = (struct vddevice *)reg; 14030519Ssam struct vdsoftc *vd; 14130573Skarels int s; 14225857Ssam 14330370Skarels #ifdef lint 14430370Skarels br = 0; cvec = br; br = cvec; 14530370Skarels vdintr(0); 14630370Skarels #endif 14725857Ssam if (badaddr((caddr_t)reg, 2)) 14825675Ssam return (0); 14930519Ssam vd = &vdsoftc[vm->um_ctlr]; 15030519Ssam vdaddr->vdreset = 0xffffffff; 15125675Ssam DELAY(1000000); 15230519Ssam if (vdaddr->vdreset != (unsigned)0xffffffff) { 15330519Ssam vd->vd_type = VDTYPE_VDDC; 15430519Ssam vd->vd_flags &= ~VD_DOSEEKS; 15525675Ssam DELAY(1000000); 15625675Ssam } else { 15730519Ssam vd->vd_type = VDTYPE_SMDE; 15830519Ssam vd->vd_flags |= VD_DOSEEKS; 15930519Ssam vdaddr->vdrstclr = 0; 16025675Ssam DELAY(3000000); 16125675Ssam } 16230519Ssam vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb); 16330519Ssam vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb); 16430519Ssam vm->um_addr = reg; /* XXX */ 16530573Skarels s = spl7(); 166*40737Skarels if (vdinit_ctlr(vm, vd) == 0) { 16730573Skarels splx(s); 16830519Ssam return (0); 16930519Ssam } 17030756Skarels if (vd->vd_type == VDTYPE_SMDE) { 171*40737Skarels #ifdef notdef 172*40737Skarels /* 173*40737Skarels * Attempt PROBE to get all drive status; 174*40737Skarels * we take advantage of this in vdreset_drive 175*40737Skarels * to try to avoid guessing games. 176*40737Skarels */ 177*40737Skarels (void) vdcmd(vm, VDOP_PROBE, 5, 0); 178*40737Skarels #endif 179*40737Skarels /* 180*40737Skarels * Check for scatter-gather by checking firmware date 181*40737Skarels * with IDENT command. The date is printed when 182*40737Skarels * vdslave is first called, thus this must be 183*40737Skarels * the last controller operation in vdprobe. 184*40737Skarels */ 18530756Skarels vd->vd_dcb.trail.idtrail.date = 0; 18635413Skarels if (vdcmd(vm, VDOP_IDENT, 10, 0)) { 18730756Skarels uncache(&vd->vd_dcb.trail.idtrail.date); 18830756Skarels if (vd->vd_dcb.trail.idtrail.date != 0) 18930756Skarels vd->vd_flags |= VD_SCATGATH; 19030756Skarels } 19130756Skarels } 19230573Skarels splx(s); 19325925Ssam /* 19425950Ssam * Allocate page tables and i/o buffer. 19525925Ssam */ 19632211Skarels if (vbainit(&vd->vd_rbuf, MAXPHYS, 19732211Skarels vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT) == 0) { 19832211Skarels printf("vd%d: vbainit failed\n", vm->um_ctlr); 19932211Skarels return (0); 20032211Skarels } 20125857Ssam br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */ 20230519Ssam return (sizeof (struct vddevice)); 20325675Ssam } 20424004Ssam 20524004Ssam /* 20630519Ssam * See if a drive is really there. 20730519Ssam * 20830519Ssam * Can't read pack label here as various data structures 20930519Ssam * aren't setup for doing a read in a straightforward 21030519Ssam * manner. Instead just probe for the drive and leave 21130519Ssam * the pack label stuff to the attach routine. 21225675Ssam */ 21334076Skarels /* ARGSUSED */ 21434076Skarels vdslave(vi, vdaddr) 21525675Ssam register struct vba_device *vi; 21630519Ssam struct vddevice *vdaddr; 21725675Ssam { 21830519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 21932211Skarels register struct dksoftc *dk = &dksoftc[vi->ui_unit]; 22030519Ssam struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 221*40737Skarels int bcd(); 22224004Ssam 223*40737Skarels if ((vd->vd_flags&VD_PRINT) == 0) { 22435413Skarels printf("vd%d: %s controller", vi->ui_ctlr, 22535413Skarels vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE"); 22635413Skarels if (vd->vd_flags & VD_SCATGATH) { 22735413Skarels char rev[5]; 22835413Skarels 22935413Skarels bcopy((caddr_t)&vd->vd_dcb.trail.idtrail.rev, rev, 23035413Skarels sizeof(vd->vd_dcb.trail.idtrail.rev)); 23135413Skarels printf(" firmware rev %s (%d-%d-%d)", rev, 232*40737Skarels bcd((vd->vd_dcb.trail.idtrail.date >> 8) & 0xff), 233*40737Skarels bcd(vd->vd_dcb.trail.idtrail.date & 0xff), 234*40737Skarels bcd((vd->vd_dcb.trail.idtrail.date >> 16)&0xffff)); 23535413Skarels } 23635413Skarels printf("\n"); 237*40737Skarels vd->vd_flags |= VD_PRINT; 23825675Ssam } 23930519Ssam 24025675Ssam /* 24130519Ssam * Initialize label enough to do a reset on 24230519Ssam * the drive. The remainder of the default 24330519Ssam * label values will be filled in in vdinit 24430519Ssam * at attach time. 24525675Ssam */ 24632211Skarels if (vd->vd_type == VDTYPE_SMDE) 24732211Skarels lp->d_secsize = VD_MAXSECSIZE; 24832211Skarels else 24932211Skarels lp->d_secsize = VDDC_SECSIZE; 25034396Skarels lp->d_nsectors = 66; /* only used on smd-e */ 25134076Skarels lp->d_ntracks = 23; 25234396Skarels lp->d_ncylinders = 850; 25334396Skarels lp->d_secpercyl = 66*23; 25435413Skarels lp->d_rpm = 3600; 25534592Skarels lp->d_npartitions = 1; 25634592Skarels lp->d_partitions[0].p_offset = 0; 25734592Skarels lp->d_partitions[0].p_size = LABELSECTOR + 1; 25824004Ssam 25930519Ssam /* 26030519Ssam * Initialize invariant portion of 26130519Ssam * dcb used for overlapped seeks. 26230519Ssam */ 26330519Ssam dk->dk_dcb.opcode = VDOP_SEEK; 26430519Ssam dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA; 26530519Ssam dk->dk_dcb.devselect = vi->ui_slave; 26630756Skarels dk->dk_dcb.trailcnt = sizeof (struct trseek) / sizeof (long); 26730519Ssam dk->dk_dcb.trail.sktrail.skaddr.sector = 0; 26830519Ssam dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb); 26932211Skarels #ifndef SECSIZE 27032211Skarels vd_setsecsize(dk, lp); 27132211Skarels #endif 27232211Skarels return (vdreset_drive(vi)); 27332211Skarels } 27432211Skarels 275*40737Skarels static int 276*40737Skarels bcd(n) 277*40737Skarels register u_int n; 278*40737Skarels { 279*40737Skarels register int bin = 0; 280*40737Skarels register int mul = 1; 281*40737Skarels 282*40737Skarels while (n) { 283*40737Skarels bin += (n & 0xf) * mul; 284*40737Skarels n >>= 4; 285*40737Skarels mul *= 10; 286*40737Skarels } 287*40737Skarels return (bin); 288*40737Skarels } 289*40737Skarels 29032211Skarels vdattach(vi) 29132211Skarels register struct vba_device *vi; 29232211Skarels { 29332211Skarels register int unit = vi->ui_unit; 29432211Skarels register struct disklabel *lp = &dklabel[unit]; 29532211Skarels 29630601Skarels /* 29730601Skarels * Try to initialize device and read pack label. 29830601Skarels */ 29930601Skarels if (vdinit(vdminor(unit, 0), 0) != 0) { 30030601Skarels printf(": unknown drive type"); 30130601Skarels return; 30230601Skarels } 30332211Skarels if (dksoftc[unit].dk_state == OPEN) 30432211Skarels printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>", 30532211Skarels lp->d_typename, lp->d_secsize, 30632211Skarels lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors); 30730519Ssam /* 30830519Ssam * (60 / rpm) / (sectors per track * (bytes per sector / 2)) 30930519Ssam */ 31030519Ssam if (vi->ui_dk >= 0) 31138170Smckusick dk_wpms[vi->ui_dk] = 31238170Smckusick (lp->d_rpm * lp->d_nsectors * lp->d_secsize) / 120; 31330519Ssam #ifdef notyet 31430573Skarels addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp); 31530519Ssam #endif 31624004Ssam } 31724004Ssam 31830756Skarels vdopen(dev, flags, fmt) 31930519Ssam dev_t dev; 32030756Skarels int flags, fmt; 32124004Ssam { 32230519Ssam register unit = vdunit(dev); 32330519Ssam register struct disklabel *lp; 32430519Ssam register struct dksoftc *dk; 32530519Ssam register struct partition *pp; 32630519Ssam struct vba_device *vi; 327*40737Skarels int s, error = 0, part = vdpart(dev), mask = 1 << part; 32830519Ssam daddr_t start, end; 32924004Ssam 33030519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 33130519Ssam return (ENXIO); 33230519Ssam lp = &dklabel[unit]; 33330519Ssam dk = &dksoftc[unit]; 33430519Ssam 33530519Ssam s = spl7(); 33630519Ssam while (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 33730519Ssam dk->dk_state != CLOSED) 338*40737Skarels if (error = tsleep((caddr_t)dk, (PZERO+1) | PCATCH, devopn, 0)) 339*40737Skarels break; 34030519Ssam splx(s); 341*40737Skarels if (error) 342*40737Skarels return (error); 34330519Ssam if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 34430519Ssam if (error = vdinit(dev, flags)) 34530519Ssam return (error); 34630573Skarels 34730573Skarels if (vdwstart == 0) { 34830573Skarels timeout(vdwatch, (caddr_t)0, hz); 34930573Skarels vdwstart++; 35030573Skarels } 35130519Ssam /* 35230519Ssam * Warn if a partion is opened 35330519Ssam * that overlaps another partition which is open 35430519Ssam * unless one is the "raw" partition (whole disk). 35530519Ssam */ 35632211Skarels #define RAWPART 8 /* 'x' partition */ /* XXX */ 35732576Skarels if ((dk->dk_openpart & mask) == 0 && part != RAWPART) { 35830519Ssam pp = &lp->d_partitions[part]; 35930519Ssam start = pp->p_offset; 36030519Ssam end = pp->p_offset + pp->p_size; 36130519Ssam for (pp = lp->d_partitions; 36230519Ssam pp < &lp->d_partitions[lp->d_npartitions]; pp++) { 36330519Ssam if (pp->p_offset + pp->p_size <= start || 36430519Ssam pp->p_offset >= end) 36530519Ssam continue; 36630519Ssam if (pp - lp->d_partitions == RAWPART) 36730519Ssam continue; 36830519Ssam if (dk->dk_openpart & (1 << (pp - lp->d_partitions))) 36930519Ssam log(LOG_WARNING, 37030519Ssam "dk%d%c: overlaps open partition (%c)\n", 37130519Ssam unit, part + 'a', 37230519Ssam pp - lp->d_partitions + 'a'); 37330519Ssam } 37424004Ssam } 37530519Ssam if (part >= lp->d_npartitions) 37630519Ssam return (ENXIO); 37730756Skarels dk->dk_openpart |= mask; 37830756Skarels switch (fmt) { 37930756Skarels case S_IFCHR: 38030756Skarels dk->dk_copenpart |= mask; 38130756Skarels break; 38230756Skarels case S_IFBLK: 38330756Skarels dk->dk_bopenpart |= mask; 38430756Skarels break; 38530756Skarels } 38630519Ssam return (0); 38725675Ssam } 38824004Ssam 38934528Skarels /* ARGSUSED */ 39030756Skarels vdclose(dev, flags, fmt) 39130519Ssam dev_t dev; 39230756Skarels int flags, fmt; 39324004Ssam { 39430519Ssam register int unit = vdunit(dev); 39530519Ssam register struct dksoftc *dk = &dksoftc[unit]; 39630756Skarels int part = vdpart(dev), mask = 1 << part; 39724004Ssam 39830756Skarels switch (fmt) { 39930756Skarels case S_IFCHR: 40030756Skarels dk->dk_copenpart &= ~mask; 40130756Skarels break; 40230756Skarels case S_IFBLK: 40330756Skarels dk->dk_bopenpart &= ~mask; 40430756Skarels break; 40530756Skarels } 40630756Skarels if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0) 40730756Skarels dk->dk_openpart &= ~mask; 40830519Ssam /* 40930519Ssam * Should wait for i/o to complete on this partition 41030519Ssam * even if others are open, but wait for work on blkflush(). 41130519Ssam */ 41230519Ssam if (dk->dk_openpart == 0) { 41330573Skarels int s = spl7(); 41430573Skarels while (dkutab[unit].b_actf) 41530573Skarels sleep((caddr_t)dk, PZERO-1); 41630519Ssam splx(s); 41730519Ssam dk->dk_state = CLOSED; 41834076Skarels dk->dk_wlabel = 0; 41924004Ssam } 42030756Skarels return (0); 42125675Ssam } 42224004Ssam 42330519Ssam vdinit(dev, flags) 42430519Ssam dev_t dev; 42530519Ssam int flags; 42625675Ssam { 42730519Ssam register struct disklabel *lp; 42830519Ssam register struct dksoftc *dk; 42930519Ssam struct vba_device *vi; 43030519Ssam int unit = vdunit(dev), error = 0; 43130756Skarels char *msg, *readdisklabel(); 43230519Ssam extern int cold; 43325675Ssam 43430519Ssam dk = &dksoftc[unit]; 43530519Ssam if (flags & O_NDELAY) { 43630519Ssam dk->dk_state = OPENRAW; 43734528Skarels return (0); 43830519Ssam } 43930519Ssam dk->dk_state = RDLABEL; 44030519Ssam lp = &dklabel[unit]; 44130519Ssam vi = vddinfo[unit]; 44230756Skarels if (msg = readdisklabel(dev, vdstrategy, lp)) { 44334076Skarels if (cold) { 44430601Skarels printf(": %s", msg); 44534076Skarels dk->dk_state = CLOSED; 44634076Skarels } else { 44732211Skarels log(LOG_ERR, "dk%d: %s\n", unit, msg); 44834076Skarels dk->dk_state = OPENRAW; 44934076Skarels } 45030519Ssam #ifdef COMPAT_42 45135082Skarels vdlock(vi->ui_ctlr); 45234076Skarels if (vdmaptype(vi, lp)) 45330519Ssam dk->dk_state = OPEN; 45435082Skarels vdunlock(vi->ui_ctlr); 45530519Ssam #endif 45630756Skarels } else { 45730756Skarels /* 45830756Skarels * Now that we have the label, configure 45930756Skarels * the correct drive parameters. 46030756Skarels */ 46135082Skarels vdlock(vi->ui_ctlr); 46232211Skarels if (vdreset_drive(vi)) 46332211Skarels dk->dk_state = OPEN; 46432211Skarels else { 46530756Skarels dk->dk_state = CLOSED; 46630756Skarels error = ENXIO; 46732211Skarels } 46835082Skarels vdunlock(vi->ui_ctlr); 46925675Ssam } 47030756Skarels #ifndef SECSIZE 47132211Skarels vd_setsecsize(dk, lp); 47232211Skarels #endif 47330519Ssam wakeup((caddr_t)dk); 47430519Ssam return (error); 47524004Ssam } 47624004Ssam 47732211Skarels #ifndef SECSIZE 47832211Skarels vd_setsecsize(dk, lp) 47932211Skarels register struct dksoftc *dk; 48032211Skarels register struct disklabel *lp; 48132211Skarels { 48232211Skarels int mul; 48332211Skarels 48432211Skarels /* 48532211Skarels * Calculate scaling shift for mapping 48632211Skarels * DEV_BSIZE blocks to drive sectors. 48732211Skarels */ 48832211Skarels mul = DEV_BSIZE / lp->d_secsize; 48932211Skarels dk->dk_bshift = 0; 49032211Skarels while ((mul >>= 1) > 0) 49132211Skarels dk->dk_bshift++; 49232211Skarels } 49332211Skarels #endif SECSIZE 49432211Skarels 49525675Ssam /*ARGSUSED*/ 49630519Ssam vddgo(vm) 49730519Ssam struct vba_device *vm; 49824004Ssam { 49924004Ssam 50024004Ssam } 50124004Ssam 50224004Ssam vdstrategy(bp) 50325675Ssam register struct buf *bp; 50424004Ssam { 50530519Ssam register struct vba_device *vi; 50630519Ssam register struct disklabel *lp; 50730519Ssam register struct dksoftc *dk; 50830519Ssam register int unit; 50930573Skarels register daddr_t sn; 51030519Ssam struct buf *dp; 51130573Skarels daddr_t sz, maxsz; 51230519Ssam int part, s; 51324004Ssam 51430519Ssam unit = vdunit(bp->b_dev); 51532211Skarels if (unit >= NDK) { 51629954Skarels bp->b_error = ENXIO; 51725675Ssam goto bad; 51829954Skarels } 51930519Ssam vi = vddinfo[unit]; 52030519Ssam lp = &dklabel[unit]; 52130519Ssam if (vi == 0 || vi->ui_alive == 0) { 52230519Ssam bp->b_error = ENXIO; 52330519Ssam goto bad; 52430519Ssam } 52530519Ssam dk = &dksoftc[unit]; 526*40737Skarels if (dk->dk_state < OPEN) { 527*40737Skarels if (dk->dk_state == CLOSED) { 528*40737Skarels bp->b_error = EIO; 529*40737Skarels goto bad; 530*40737Skarels } 53130519Ssam goto q; 532*40737Skarels } 53334076Skarels if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) { 53434076Skarels bp->b_error = EROFS; 53534076Skarels goto bad; 53634076Skarels } 53730519Ssam part = vdpart(bp->b_dev); 53830519Ssam if ((dk->dk_openpart & (1 << part)) == 0) { 53930519Ssam bp->b_error = ENODEV; 54030519Ssam goto bad; 54130519Ssam } 54232211Skarels sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize; 54330519Ssam maxsz = lp->d_partitions[part].p_size; 54430756Skarels #ifndef SECSIZE 54530756Skarels sn = bp->b_blkno << dk->dk_bshift; 54630756Skarels #else SECSIZE 54730573Skarels sn = bp->b_blkno; 54830756Skarels #endif SECSIZE 54934076Skarels if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR && 55034076Skarels #if LABELSECTOR != 0 55134076Skarels sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR && 55234076Skarels #endif 55334076Skarels (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) { 55434076Skarels bp->b_error = EROFS; 55534076Skarels goto bad; 55634076Skarels } 55730519Ssam if (sn < 0 || sn + sz > maxsz) { 55830519Ssam if (sn == maxsz) { 55929954Skarels bp->b_resid = bp->b_bcount; 56029954Skarels goto done; 56129954Skarels } 56230756Skarels sz = maxsz - sn; 56330573Skarels if (sz <= 0) { 56430573Skarels bp->b_error = EINVAL; 56530573Skarels goto bad; 56630573Skarels } 56730573Skarels bp->b_bcount = sz * lp->d_secsize; 56825675Ssam } 56930519Ssam bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl; 57030756Skarels #ifdef SECSIZE 57130756Skarels if (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0) 57230756Skarels panic("vdstrat blksize"); 57330756Skarels #endif SECSIZE 57430519Ssam q: 57525675Ssam s = spl7(); 57630519Ssam dp = &dkutab[vi->ui_unit]; 57730519Ssam disksort(dp, bp); 57830519Ssam if (!dp->b_active) { 57930519Ssam (void) vdustart(vi); 58030573Skarels if (!vi->ui_mi->um_tab.b_active) 58130519Ssam vdstart(vi->ui_mi); 58224004Ssam } 58330519Ssam splx(s); 58424004Ssam return; 58525675Ssam bad: 58629954Skarels bp->b_flags |= B_ERROR; 58729954Skarels done: 58830519Ssam biodone(bp); 58930519Ssam return; 59024004Ssam } 59124004Ssam 59230519Ssam vdustart(vi) 59330519Ssam register struct vba_device *vi; 59424004Ssam { 59530519Ssam register struct buf *bp, *dp; 59630519Ssam register struct vba_ctlr *vm; 59730519Ssam register int unit = vi->ui_unit; 59830519Ssam register struct dksoftc *dk; 59930519Ssam register struct vdsoftc *vd; 60030519Ssam struct disklabel *lp; 60124004Ssam 60230519Ssam dp = &dkutab[unit]; 60330519Ssam /* 60430519Ssam * If queue empty, nothing to do. 60530519Ssam */ 60630519Ssam if ((bp = dp->b_actf) == NULL) 60730519Ssam return; 60830519Ssam /* 60930574Skarels * If drive is off-cylinder and controller supports seeks, 61030574Skarels * place drive on seek queue for controller. 61130574Skarels * Otherwise, place on transfer queue. 61230519Ssam */ 61330519Ssam vd = &vdsoftc[vi->ui_ctlr]; 61430519Ssam dk = &dksoftc[unit]; 61530574Skarels vm = vi->ui_mi; 61630519Ssam if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) { 61730519Ssam lp = &dklabel[unit]; 61830574Skarels bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors; 61930574Skarels if (vm->um_tab.b_seekf == NULL) 62030574Skarels vm->um_tab.b_seekf = dp; 62130574Skarels else 62230574Skarels vm->um_tab.b_seekl->b_forw = dp; 62330574Skarels vm->um_tab.b_seekl = dp; 62430574Skarels } else { 62530574Skarels if (vm->um_tab.b_actf == NULL) 62630574Skarels vm->um_tab.b_actf = dp; 62730574Skarels else 62830574Skarels vm->um_tab.b_actl->b_forw = dp; 62930574Skarels vm->um_tab.b_actl = dp; 63030519Ssam } 63130573Skarels dp->b_forw = NULL; 63230573Skarels dp->b_active++; 63325675Ssam } 63425675Ssam 63525675Ssam /* 63630519Ssam * Start next transfer on a controller. 63730574Skarels * There are two queues of drives, the first on-cylinder 63830574Skarels * and the second off-cylinder from their next transfers. 63930574Skarels * Perform the first transfer for the first drive on the on-cylinder 64030574Skarels * queue, if any, otherwise the first transfer for the first drive 64130574Skarels * on the second queue. Initiate seeks on remaining drives on the 64230574Skarels * off-cylinder queue, then move them all to the on-cylinder queue. 64325675Ssam */ 64430519Ssam vdstart(vm) 64530519Ssam register struct vba_ctlr *vm; 64625675Ssam { 64725675Ssam register struct buf *bp; 64830519Ssam register struct vba_device *vi; 64930519Ssam register struct vdsoftc *vd; 65030519Ssam register struct dksoftc *dk; 65130519Ssam register struct disklabel *lp; 65230519Ssam register struct dcb **dcbp; 65330519Ssam struct buf *dp; 65430519Ssam int sn, tn; 65525675Ssam 65630519Ssam loop: 65730519Ssam /* 65830519Ssam * Pull a request off the controller queue. 65930519Ssam */ 66030574Skarels if ((dp = vm->um_tab.b_actf) == NULL && 66130574Skarels (dp = vm->um_tab.b_seekf) == NULL) 66230519Ssam return; 66330519Ssam if ((bp = dp->b_actf) == NULL) { 66430601Skarels if (dp == vm->um_tab.b_actf) 66530601Skarels vm->um_tab.b_actf = dp->b_forw; 66630601Skarels else 66730601Skarels vm->um_tab.b_seekf = dp->b_forw; 66830519Ssam goto loop; 66930519Ssam } 67025675Ssam 67124004Ssam /* 67230519Ssam * Mark controller busy, and determine 67330519Ssam * destination of this request. 67424004Ssam */ 67530519Ssam vm->um_tab.b_active++; 67630519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 67730519Ssam dk = &dksoftc[vi->ui_unit]; 67830756Skarels #ifndef SECSIZE 67930756Skarels sn = bp->b_blkno << dk->dk_bshift; 68030756Skarels #else SECSIZE 68130573Skarels sn = bp->b_blkno; 68230756Skarels #endif SECSIZE 68330519Ssam lp = &dklabel[vi->ui_unit]; 68430519Ssam sn %= lp->d_secpercyl; 68530519Ssam tn = sn / lp->d_nsectors; 68630519Ssam sn %= lp->d_nsectors; 68730519Ssam 68830519Ssam /* 68930519Ssam * Construct dcb for read/write command. 69030519Ssam */ 69130519Ssam vd = &vdsoftc[vm->um_ctlr]; 69230519Ssam vd->vd_dcb.intflg = DCBINT_DONE; 69332211Skarels vd->vd_dcb.devselect = dk->dk_dcb.devselect; 69430519Ssam vd->vd_dcb.operrsta = 0; 69530519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 69630519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin; 69730519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 69830519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 69930574Skarels dk->dk_curcyl = bp->b_cylin; 70030574Skarels bp->b_track = 0; /* init overloaded field */ 70130756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 70234396Skarels if (bp->b_flags & B_FORMAT) 70334396Skarels vd->vd_dcb.opcode = dk->dk_op; 70434396Skarels else if (vd->vd_flags & VD_SCATGATH && 70534396Skarels ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0) 70630756Skarels vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW; 70734396Skarels else 70830756Skarels vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD; 70934396Skarels 71034396Skarels switch (vd->vd_dcb.opcode) { 71134396Skarels case VDOP_FSECT: 712*40737Skarels vd->vd_dcb.trailcnt = sizeof (struct trfmt) / sizeof (long); 71334396Skarels vd->vd_dcb.trail.fmtrail.nsectors = bp->b_bcount / 71434396Skarels lp->d_secsize; 71534396Skarels vd->vd_dcb.trail.fmtrail.hdr = *(dskadr *)&dk->dk_althdr; 71634396Skarels vd->vd_dcb.trail.rwtrail.disk.cylinder |= dk->dk_fmtflags; 71734396Skarels goto setupaddr; 71834396Skarels 71934396Skarels case VDOP_RDRAW: 72034396Skarels case VDOP_RD: 721*40737Skarels case VDOP_RHDE: 72234396Skarels case VDOP_WD: 72334396Skarels vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1; 72434396Skarels setupaddr: 72530756Skarels vd->vd_dcb.trail.rwtrail.memadr = 72634528Skarels vbasetup(bp, &vd->vd_rbuf, (int)lp->d_secsize); 72734396Skarels break; 72834396Skarels 72934396Skarels case VDOP_RAS: 73034396Skarels case VDOP_GAW: 73135712Sbostic vd->vd_dcb.trailcnt += vd_sgsetup(bp, &vd->vd_rbuf, 73234396Skarels &vd->vd_dcb.trail.sgtrail); 73334396Skarels break; 73430756Skarels } 73530574Skarels if (vi->ui_dk >= 0) { 73630574Skarels dk_busy |= 1<<vi->ui_dk; 73730574Skarels dk_xfer[vi->ui_dk]++; 73830574Skarels dk_wds[vi->ui_dk] += bp->b_bcount>>6; 73930574Skarels } 74030519Ssam 74130519Ssam /* 74230519Ssam * Look for any seeks to be performed on other drives on this 74330519Ssam * controller. If overlapped seeks exist, insert seek commands 74430519Ssam * on the controller's command queue before the transfer. 74530519Ssam */ 74630519Ssam dcbp = &vd->vd_mdcb.mdcb_head; 74730519Ssam 74830574Skarels if (dp == vm->um_tab.b_seekf) 74930574Skarels dp = dp->b_forw; 75030574Skarels else 75130574Skarels dp = vm->um_tab.b_seekf; 75230574Skarels for (; dp != NULL; dp = dp->b_forw) { 75330574Skarels if ((bp = dp->b_actf) == NULL) 75430574Skarels continue; 75530574Skarels vi = vddinfo[vdunit(bp->b_dev)]; 75630574Skarels dk = &dksoftc[vi->ui_unit]; 75730519Ssam dk->dk_curcyl = bp->b_cylin; 75830574Skarels if (vi->ui_dk >= 0) 75930574Skarels dk_seek[vi->ui_dk]++; 76030574Skarels dk->dk_dcb.operrsta = 0; 76130574Skarels dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin; 76230574Skarels dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track; 76330574Skarels *dcbp = (struct dcb *)dk->dk_dcbphys; 76430574Skarels dcbp = &dk->dk_dcb.nxtdcb; 76524004Ssam } 76630519Ssam *dcbp = (struct dcb *)vd->vd_dcbphys; 76730574Skarels if (vm->um_tab.b_actf) 76830574Skarels vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf; 76930574Skarels else 77030574Skarels vm->um_tab.b_actf = vm->um_tab.b_seekf; 77130601Skarels if (vm->um_tab.b_seekf) 77230601Skarels vm->um_tab.b_actl = vm->um_tab.b_seekl; 77330574Skarels vm->um_tab.b_seekf = 0; 77424004Ssam 77530519Ssam /* 77630519Ssam * Initiate operation. 77730519Ssam */ 77830519Ssam vd->vd_mdcb.mdcb_status = 0; 77930519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 78024004Ssam } 78124004Ssam 78235082Skarels /* 78335082Skarels * Wait for controller to finish current operation 78435082Skarels * so that direct controller accesses can be done. 78535082Skarels */ 78635082Skarels vdlock(ctlr) 78735082Skarels { 78835082Skarels register struct vba_ctlr *vm = vdminfo[ctlr]; 78935082Skarels register struct vdsoftc *vd = &vdsoftc[ctlr]; 79035082Skarels int s; 79135082Skarels 79235082Skarels s = spl7(); 79335082Skarels while (vm->um_tab.b_active || vd->vd_flags & VD_LOCKED) { 79435082Skarels vd->vd_flags |= VD_WAIT; 79535082Skarels sleep((caddr_t)vd, PRIBIO); 79635082Skarels } 79735082Skarels vd->vd_flags |= VD_LOCKED; 79835082Skarels splx(s); 79935082Skarels } 80035082Skarels 80135082Skarels /* 80235082Skarels * Continue normal operations after pausing for 80335082Skarels * munging the controller directly. 80435082Skarels */ 80535082Skarels vdunlock(ctlr) 80635082Skarels { 80735082Skarels register struct vba_ctlr *vm = vdminfo[ctlr]; 80835082Skarels register struct vdsoftc *vd = &vdsoftc[ctlr]; 80935082Skarels 81035082Skarels vd->vd_flags &= ~VD_LOCKED; 81135082Skarels if (vd->vd_flags & VD_WAIT) { 81235082Skarels vd->vd_flags &= ~VD_WAIT; 81335082Skarels wakeup((caddr_t)vd); 81435082Skarels } else if (vm->um_tab.b_actf || vm->um_tab.b_seekf) 81535082Skarels vdstart(vm); 81635082Skarels } 81735082Skarels 81830519Ssam #define DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE) 81924004Ssam /* 82024004Ssam * Handle a disk interrupt. 82124004Ssam */ 82225675Ssam vdintr(ctlr) 82330519Ssam register ctlr; 82424004Ssam { 82530519Ssam register struct buf *bp, *dp; 82630519Ssam register struct vba_ctlr *vm = vdminfo[ctlr]; 82730519Ssam register struct vba_device *vi; 82830519Ssam register struct vdsoftc *vd = &vdsoftc[ctlr]; 82930519Ssam register status; 83034528Skarels int timedout; 83130573Skarels struct dksoftc *dk; 83224004Ssam 83330519Ssam if (!vm->um_tab.b_active) { 83425675Ssam printf("vd%d: stray interrupt\n", ctlr); 83524004Ssam return; 83624004Ssam } 83725675Ssam /* 83830519Ssam * Get device and block structures, and a pointer 83930519Ssam * to the vba_device for the drive. 84025675Ssam */ 84130519Ssam dp = vm->um_tab.b_actf; 84230519Ssam bp = dp->b_actf; 84330519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 84434528Skarels dk = &dksoftc[vi->ui_unit]; 84530574Skarels if (vi->ui_dk >= 0) 84630574Skarels dk_busy &= ~(1<<vi->ui_dk); 84734396Skarels timedout = (vd->vd_wticks >= VDMAXTIME); 84830519Ssam /* 84930519Ssam * Check for and process errors on 85030519Ssam * either the drive or the controller. 85130519Ssam */ 85230519Ssam uncache(&vd->vd_dcb.operrsta); 85330519Ssam status = vd->vd_dcb.operrsta; 85434396Skarels if (bp->b_flags & B_FORMAT) { 85534396Skarels dk->dk_operrsta = status; 85634396Skarels uncache(&vd->vd_dcb.err_code); 857*40737Skarels /* ecodecnt gets err_code + err_wcnt from the same longword */ 858*40737Skarels dk->dk_ecodecnt = *(long *)&vd->vd_dcb.err_code; 859*40737Skarels uncache(&vd->vd_dcb.err_trk); 860*40737Skarels /* erraddr gets error trk/sec/cyl from the same longword */ 861*40737Skarels dk->dk_erraddr = *(long *)&vd->vd_dcb.err_trk; 862*40737Skarels } else if (status & VDERR_HARD || timedout) { 86334528Skarels if (vd->vd_type == VDTYPE_SMDE) 86430601Skarels uncache(&vd->vd_dcb.err_code); 86530519Ssam if (status & DCBS_WPT) { 86630519Ssam /* 86730519Ssam * Give up on write locked devices immediately. 86830519Ssam */ 86930573Skarels printf("dk%d: write locked\n", vi->ui_unit); 87030519Ssam bp->b_flags |= B_ERROR; 87134396Skarels } else if (status & VDERR_RETRY || timedout) { 87234396Skarels if (status & VDERR_CTLR || timedout) { 873*40737Skarels vdharderr(timedout ? 874*40737Skarels "controller timeout" : "controller err", 87534396Skarels vd, bp, &vd->vd_dcb); 87634396Skarels printf("; resetting controller..."); 87734396Skarels vdreset_ctlr(vm); 87834396Skarels } else if (status & VDERR_DRIVE) { 87934396Skarels vdharderr("drive err", vd, bp, &vd->vd_dcb); 88034396Skarels printf("; resetting drive..."); 88130519Ssam if (!vdreset_drive(vi)) 882*40737Skarels dk->dk_state = CLOSED; 88332211Skarels } else 884*40737Skarels vdharderr("data err", vd, bp, &vd->vd_dcb); 88530519Ssam /* 88630519Ssam * Retry transfer once, unless reset failed. 88730519Ssam */ 888*40737Skarels if (!vi->ui_alive || dp->b_errcnt++ >= 1) { 889*40737Skarels printf("\n"); 89030519Ssam goto hard; 89132211Skarels } 89232211Skarels 893*40737Skarels printf(" retrying\n"); 89430519Ssam vm->um_tab.b_active = 0; /* force retry */ 89530519Ssam } else { 896*40737Skarels vdharderr("hard error", vd, bp, &vd->vd_dcb); 897*40737Skarels printf("\n"); 89830519Ssam hard: 89930519Ssam bp->b_flags |= B_ERROR; 90030519Ssam } 90130519Ssam } else if (status & DCBS_SOFT) 90234528Skarels vdsofterr(bp, &vd->vd_dcb); 903*40737Skarels if (vd->vd_wticks > 3) { 904*40737Skarels vd->vd_dcb.err_code = vd->vd_wticks; 905*40737Skarels vdharderr("slow transfer (ecode is sec.)", vd, bp, &vd->vd_dcb); 906*40737Skarels printf("\n"); 907*40737Skarels } 90834396Skarels vd->vd_wticks = 0; 90930519Ssam if (vm->um_tab.b_active) { 91030519Ssam vm->um_tab.b_active = 0; 91130519Ssam vm->um_tab.b_actf = dp->b_forw; 91230519Ssam dp->b_active = 0; 91330519Ssam dp->b_errcnt = 0; 91430519Ssam dp->b_actf = bp->av_forw; 91530519Ssam bp->b_resid = 0; 91630601Skarels vbadone(bp, &vd->vd_rbuf); 91730519Ssam biodone(bp); 91830370Skarels /* 91930519Ssam * If this unit has more work to do, 92030519Ssam * then start it up right away. 92130370Skarels */ 92230519Ssam if (dp->b_actf) 92330519Ssam vdustart(vi); 92434528Skarels else if (dk->dk_openpart == 0) 92530573Skarels wakeup((caddr_t)dk); 92624004Ssam } 92725675Ssam /* 92830519Ssam * If there are devices ready to 92930519Ssam * transfer, start the controller. 93025675Ssam */ 93135082Skarels if (vd->vd_flags & VD_WAIT) { 93235082Skarels vd->vd_flags &= ~VD_WAIT; 93335082Skarels wakeup((caddr_t)vd); 93435082Skarels } else if (vm->um_tab.b_actf || vm->um_tab.b_seekf) 93530519Ssam vdstart(vm); 93624004Ssam } 93724004Ssam 93834396Skarels vdharderr(what, vd, bp, dcb) 93934396Skarels char *what; 94034396Skarels struct vdsoftc *vd; 94134396Skarels register struct buf *bp; 94234396Skarels register struct dcb *dcb; 94334396Skarels { 94434396Skarels int unit = vdunit(bp->b_dev), status = dcb->operrsta; 94534396Skarels register struct disklabel *lp = &dklabel[unit]; 94634528Skarels int blkdone; 94734396Skarels 94834396Skarels if (vd->vd_wticks < VDMAXTIME) 94934396Skarels status &= ~DONTCARE; 95034710Skarels blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) * 95134710Skarels lp->d_nsectors + dcb->err_sec - 95234710Skarels lp->d_partitions[vdpart(bp->b_dev)].p_offset) >> 95334710Skarels dksoftc[unit].dk_bshift) - bp->b_blkno; 95434528Skarels diskerr(bp, "dk", what, LOG_PRINTF, blkdone, lp); 95534528Skarels printf(", status %b", status, VDERRBITS); 95634396Skarels if (vd->vd_type == VDTYPE_SMDE) 95734396Skarels printf(" ecode %x", dcb->err_code); 95834396Skarels } 95934396Skarels 96034528Skarels vdsofterr(bp, dcb) 96125675Ssam register struct buf *bp; 96230519Ssam register struct dcb *dcb; 96325675Ssam { 96434562Skarels int unit = vdunit(bp->b_dev); 96534562Skarels struct disklabel *lp = &dklabel[unit]; 96634528Skarels int status = dcb->operrsta; 96734528Skarels int blkdone; 96825675Ssam 96934710Skarels blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) * 97034710Skarels lp->d_nsectors + dcb->err_sec - 97134710Skarels lp->d_partitions[vdpart(bp->b_dev)].p_offset) >> 97234710Skarels dksoftc[unit].dk_bshift) - bp->b_blkno; 97334528Skarels 97434528Skarels if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) { 97534528Skarels diskerr(bp, "dk", "soft error", LOG_WARNING, blkdone, lp); 97634528Skarels addlog(", status %b ecode %x\n", status, VDERRBITS, 97734396Skarels dcb->err_code); 97834528Skarels } else { 97934528Skarels diskerr(bp, "dk", "soft ecc", LOG_WARNING, blkdone, lp); 98034528Skarels addlog("\n"); 98134528Skarels } 98225675Ssam } 98325675Ssam 98430519Ssam vdioctl(dev, cmd, data, flag) 98525675Ssam dev_t dev; 98630519Ssam int cmd; 98730519Ssam caddr_t data; 98830519Ssam int flag; 98924004Ssam { 99032576Skarels register int unit = vdunit(dev); 99130519Ssam register struct disklabel *lp = &dklabel[unit]; 99234076Skarels register struct dksoftc *dk = &dksoftc[unit]; 99334640Skarels int error = 0, vdformat(); 99424004Ssam 99530519Ssam switch (cmd) { 99630519Ssam 99730519Ssam case DIOCGDINFO: 99830519Ssam *(struct disklabel *)data = *lp; 99930519Ssam break; 100030519Ssam 100130573Skarels case DIOCGPART: 100230573Skarels ((struct partinfo *)data)->disklab = lp; 100330573Skarels ((struct partinfo *)data)->part = 100430573Skarels &lp->d_partitions[vdpart(dev)]; 100530519Ssam break; 100630519Ssam 100730519Ssam case DIOCSDINFO: 100830519Ssam if ((flag & FWRITE) == 0) 100930519Ssam error = EBADF; 101030519Ssam else 101132576Skarels error = setdisklabel(lp, (struct disklabel *)data, 101234076Skarels (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart); 101334396Skarels if (error == 0 && dk->dk_state == OPENRAW && 101434396Skarels vdreset_drive(vddinfo[unit])) 101534076Skarels dk->dk_state = OPEN; 101630519Ssam break; 101730519Ssam 101834076Skarels case DIOCWLABEL: 101934076Skarels if ((flag & FWRITE) == 0) 102034076Skarels error = EBADF; 102134076Skarels else 102234076Skarels dk->dk_wlabel = *(int *)data; 102334076Skarels break; 102434076Skarels 102532576Skarels case DIOCWDINFO: 102632576Skarels if ((flag & FWRITE) == 0) 102730519Ssam error = EBADF; 102832576Skarels else if ((error = setdisklabel(lp, (struct disklabel *)data, 102934076Skarels (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) { 103034640Skarels int wlab; 103134640Skarels 103235413Skarels if (error == 0 && dk->dk_state == OPENRAW && 103335413Skarels vdreset_drive(vddinfo[unit])) 103435413Skarels dk->dk_state = OPEN; 103534640Skarels /* simulate opening partition 0 so write succeeds */ 103634640Skarels dk->dk_openpart |= (1 << 0); /* XXX */ 103734640Skarels wlab = dk->dk_wlabel; 103834640Skarels dk->dk_wlabel = 1; 103932576Skarels error = writedisklabel(dev, vdstrategy, lp); 104034640Skarels dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart; 104134640Skarels dk->dk_wlabel = wlab; 104234076Skarels } 104330519Ssam break; 104430519Ssam 104534396Skarels case DIOCWFORMAT: 104634396Skarels { 104734396Skarels register struct format_op *fop; 104834396Skarels struct uio auio; 104934396Skarels struct iovec aiov; 105034396Skarels 105134396Skarels if ((flag & FWRITE) == 0) { 105234396Skarels error = EBADF; 105334396Skarels break; 105434396Skarels } 105534396Skarels fop = (struct format_op *)data; 105634396Skarels aiov.iov_base = fop->df_buf; 105734396Skarels aiov.iov_len = fop->df_count; 105834396Skarels auio.uio_iov = &aiov; 105934396Skarels auio.uio_iovcnt = 1; 106034396Skarels auio.uio_resid = fop->df_count; 106134396Skarels auio.uio_segflg = UIO_USERSPACE; 106234396Skarels auio.uio_offset = fop->df_startblk * lp->d_secsize; 1063*40737Skarels /* This assumes one active format operation per disk... */ 1064*40737Skarels dk->dk_op = fop->dk_op; 1065*40737Skarels dk->dk_althdr = fop->dk_althdr; 1066*40737Skarels dk->dk_fmtflags = fop->dk_fmtflags; 106734396Skarels /* 106834396Skarels * Don't return errors, as the format op won't get copied 106934396Skarels * out if we return nonzero. Callers must check the returned 1070*40737Skarels * registers and count. 107134396Skarels */ 1072*40737Skarels error = physio(vdformat, (struct buf *)NULL, dev, 1073*40737Skarels B_WRITE, minphys, &auio); 1074*40737Skarels if (error == EIO) 1075*40737Skarels error = 0; 107634396Skarels fop->df_count -= auio.uio_resid; 1077*40737Skarels /* This assumes one active format operation per disk... */ 107834396Skarels fop->dk_operrsta = dk->dk_operrsta; 1079*40737Skarels fop->dk_ecodecnt = dk->dk_ecodecnt; 1080*40737Skarels fop->dk_erraddr = dk->dk_erraddr; 108134396Skarels break; 108234396Skarels } 108334396Skarels 108430519Ssam default: 108530519Ssam error = ENOTTY; 108630519Ssam break; 108724004Ssam } 108832606Skarels return (error); 108924004Ssam } 109024004Ssam 109134396Skarels vdformat(bp) 109234396Skarels struct buf *bp; 109334396Skarels { 109434396Skarels bp->b_flags |= B_FORMAT; 109534396Skarels vdstrategy(bp); 109634396Skarels } 109734396Skarels 109825675Ssam /* 109930519Ssam * Watch for lost interrupts. 110025675Ssam */ 110130519Ssam vdwatch() 110230519Ssam { 110330519Ssam register struct vdsoftc *vd; 110430519Ssam register struct vba_ctlr *vm; 110534528Skarels register int ctlr; 110634396Skarels int s; 110730519Ssam 110830519Ssam timeout(vdwatch, (caddr_t)0, hz); 110930519Ssam for (ctlr = 0; ctlr < NVD; ctlr++) { 111030519Ssam vm = vdminfo[ctlr]; 111130519Ssam if (vm == 0 || vm->um_alive == 0) 111230519Ssam continue; 111330519Ssam vd = &vdsoftc[ctlr]; 111434396Skarels s = spl7(); 111534396Skarels if (vm->um_tab.b_active && vd->vd_wticks++ >= VDMAXTIME) { 111630519Ssam printf("vd%d: lost interrupt\n", ctlr); 111734396Skarels #ifdef maybe 111834396Skarels VDABORT((struct vddevice *)vm->um_addr, vd->vd_type); 111934396Skarels #endif 112034396Skarels vdintr(ctlr); 112130519Ssam } 112234396Skarels splx(s); 112330519Ssam } 112430519Ssam } 112530519Ssam 112630519Ssam #define DBSIZE 64 /* controller limit with 1K sectors */ 112730519Ssam /* 112830519Ssam * Crash dump. 112930519Ssam */ 113030519Ssam vddump(dev) 113130519Ssam dev_t dev; 113224004Ssam { 113330519Ssam register struct vba_device *vi; 113430519Ssam register struct vba_ctlr *vm; 113530519Ssam register struct disklabel *lp; 113630519Ssam register struct vdsoftc *vd; 113730519Ssam struct dksoftc *dk; 113830519Ssam int part, unit, num; 113930601Skarels u_long start; 114024004Ssam 114130519Ssam start = 0; 114230519Ssam unit = vdunit(dev); 114330519Ssam if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 114430519Ssam return (ENXIO); 114530519Ssam dk = &dksoftc[unit]; 114634076Skarels if (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 114734076Skarels vdinit(vdminor(unit, 0), 0) != 0) 114830519Ssam return (ENXIO); 114930519Ssam lp = &dklabel[unit]; 115030519Ssam part = vdpart(dev); 115130519Ssam if (part >= lp->d_npartitions) 115230519Ssam return (ENXIO); 115332211Skarels vm = vi->ui_mi; 115430519Ssam vdreset_ctlr(vm); 115530519Ssam if (dumplo < 0) 115630519Ssam return (EINVAL); 115730519Ssam /* 115830756Skarels * Maxfree is in pages, dumplo is in DEV_BSIZE units. 115930519Ssam */ 116030519Ssam num = maxfree * (NBPG / lp->d_secsize); 116130756Skarels dumplo *= DEV_BSIZE / lp->d_secsize; 116230519Ssam if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size) 116330519Ssam num = lp->d_partitions[vdpart(dev)].p_size - dumplo; 116430519Ssam vd = &vdsoftc[vm->um_ctlr]; 116530519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 116630519Ssam vd->vd_dcb.opcode = VDOP_WD; 116732211Skarels vd->vd_dcb.devselect = dk->dk_dcb.devselect; 116830756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 116930519Ssam while (num > 0) { 117030519Ssam int nsec, cn, sn, tn; 117130519Ssam 117230519Ssam nsec = MIN(num, DBSIZE); 117330601Skarels sn = dumplo + start / lp->d_secsize; 117430519Ssam cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) / 117530519Ssam lp->d_secpercyl; 117630519Ssam sn %= lp->d_secpercyl; 117730519Ssam tn = sn / lp->d_nsectors; 117830519Ssam sn %= lp->d_nsectors; 117930519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 118030519Ssam vd->vd_dcb.trail.rwtrail.memadr = start; 118130519Ssam vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1; 118230519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = cn; 118330519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 118430519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 118530519Ssam vd->vd_dcb.operrsta = 0; 118630519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 118730519Ssam if (!vdpoll(vm, 5)) { 118830519Ssam printf(" during dump\n"); 118930519Ssam return (EIO); 119030519Ssam } 119130519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 119230519Ssam printf("dk%d: hard error, status=%b\n", unit, 119330519Ssam vd->vd_dcb.operrsta, VDERRBITS); 119430519Ssam return (EIO); 119530519Ssam } 119630519Ssam start += nsec * lp->d_secsize; 119730519Ssam num -= nsec; 119825675Ssam } 119930519Ssam return (0); 120024004Ssam } 120124004Ssam 120224004Ssam vdsize(dev) 120325675Ssam dev_t dev; 120424004Ssam { 120530519Ssam register int unit = vdunit(dev); 120630519Ssam register struct dksoftc *dk; 120730519Ssam struct vba_device *vi; 120830519Ssam struct disklabel *lp; 120924004Ssam 121030519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 || 121130519Ssam (dk = &dksoftc[unit])->dk_state != OPEN) 121225675Ssam return (-1); 121330519Ssam lp = &dklabel[unit]; 121430756Skarels #ifdef SECSIZE 121530573Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size); 121630756Skarels #else SECSIZE 121730756Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift); 121830756Skarels #endif SECSIZE 121924004Ssam } 122024004Ssam 122125675Ssam /* 1222*40737Skarels * Initialize controller. 122325675Ssam */ 1224*40737Skarels vdinit_ctlr(vm, vd) 1225*40737Skarels struct vba_ctlr *vm; 1226*40737Skarels struct vdsoftc *vd; 122724004Ssam { 122830519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 1229*40737Skarels 123030519Ssam if (vd->vd_type == VDTYPE_SMDE) { 123130519Ssam vdaddr->vdcsr = 0; 123230519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 123330519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 123430519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 123530519Ssam vdaddr->vdtcf_data = AM_ENPDA; 1236*40737Skarels vdaddr->vdccf = CCF_SEN | CCF_DIU | CCF_STS | CCF_RFE | 1237*40737Skarels XMD_32BIT | BSZ_16WRD | 123825675Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 123925675Ssam } 124035413Skarels if (!vdcmd(vm, VDOP_INIT, 10, 0) || !vdcmd(vm, VDOP_DIAG, 10, 0)) { 1241*40737Skarels printf("vd%d: %s cmd failed\n", vm->um_ctlr, 124230519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 1243*40737Skarels return (0); 1244*40737Skarels } 1245*40737Skarels vd->vd_secsize = vdaddr->vdsecsize << 1; 1246*40737Skarels return (1); 1247*40737Skarels } 1248*40737Skarels 1249*40737Skarels /* 1250*40737Skarels * Perform a controller reset. 1251*40737Skarels */ 1252*40737Skarels vdreset_ctlr(vm) 1253*40737Skarels register struct vba_ctlr *vm; 1254*40737Skarels { 1255*40737Skarels register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 1256*40737Skarels register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 1257*40737Skarels register int unit; 1258*40737Skarels struct vba_device *vi; 1259*40737Skarels 1260*40737Skarels VDRESET(vdaddr, vd->vd_type); 1261*40737Skarels if (vdinit_ctlr(vm, vd) == 0) 126230370Skarels return; 126330519Ssam for (unit = 0; unit < NDK; unit++) 126430519Ssam if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive) 126530519Ssam (void) vdreset_drive(vi); 126630519Ssam } 126730519Ssam 126830519Ssam vdreset_drive(vi) 126930519Ssam register struct vba_device *vi; 127030519Ssam { 127130519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 127230519Ssam struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; 127330519Ssam struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 127432211Skarels register struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 127532211Skarels register struct dksoftc *dk = &dksoftc[vi->ui_unit]; 1276*40737Skarels int config_status, config_ecode, saw_drive = 0; 127730519Ssam 1278*40737Skarels #ifdef notdef 1279*40737Skarels /* 1280*40737Skarels * check for ESDI distribution panel already configured, 1281*40737Skarels * e.g. on boot drive, or if PROBE on controller actually 1282*40737Skarels * worked. Status will be zero if drive hasn't 1283*40737Skarels * been probed yet. 1284*40737Skarels */ 1285*40737Skarels #if STA_ESDI != 0 1286*40737Skarels if ((vdaddr->vdstatus[vi->ui_slave] & STA_TYPE) == STA_ESDI) 1287*40737Skarels lp->d_devflags |= VD_ESDI; 1288*40737Skarels #endif 1289*40737Skarels #endif 129030519Ssam top: 129130519Ssam vd->vd_dcb.opcode = VDOP_CONFIG; /* command */ 129230519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 129330519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 129430519Ssam vd->vd_dcb.operrsta = 0; 129532211Skarels vd->vd_dcb.devselect = vi->ui_slave | lp->d_devflags; 129630519Ssam vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders; 129730519Ssam vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks; 129830519Ssam if (vd->vd_type == VDTYPE_SMDE) { 129930756Skarels vd->vd_dcb.trailcnt = sizeof (struct treset) / sizeof (long); 130030519Ssam vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors; 130130601Skarels vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack; 1302*40737Skarels vd->vd_dcb.trail.rstrail.recovery = 1303*40737Skarels (lp->d_flags & D_REMOVABLE) ? VDRF_NORMAL : 1304*40737Skarels (VDRF_NORMAL &~ (VDRF_OSP|VDRF_OSM)); 130530519Ssam } else 130630519Ssam vd->vd_dcb.trailcnt = 2; /* XXX */ 130730519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 130830519Ssam vd->vd_mdcb.mdcb_status = 0; 130930519Ssam VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type); 131030519Ssam if (!vdpoll(vm, 5)) { 131130519Ssam printf(" during config\n"); 131230519Ssam return (0); 131325675Ssam } 1314*40737Skarels config_status = vd->vd_dcb.operrsta; 1315*40737Skarels config_ecode = (u_char)vd->vd_dcb.err_code; 1316*40737Skarels if (config_status & VDERR_HARD) { 131732211Skarels if (vd->vd_type == VDTYPE_SMDE) { 1318*40737Skarels /* 1319*40737Skarels * If drive status was updated successfully, 1320*40737Skarels * STA_US (unit selected) should be set 1321*40737Skarels * if the drive is attached and powered up. 1322*40737Skarels * (But only if we've guessed right on SMD 1323*40737Skarels * vs. ESDI; if that flag is wrong, we won't 1324*40737Skarels * see the drive.) If we don't see STA_US 1325*40737Skarels * with either SMD or ESDI set for the unit, 1326*40737Skarels * we assume that the drive doesn't exist, 1327*40737Skarels * and don't wait for it to spin up. 1328*40737Skarels */ 1329*40737Skarels (void) vdcmd(vm, VDOP_STATUS, 5, vi->ui_slave); 1330*40737Skarels uncache(&vdaddr->vdstatus[vi->ui_slave]); 1331*40737Skarels if (vdaddr->vdstatus[vi->ui_slave] & STA_US) 1332*40737Skarels saw_drive = 1; 1333*40737Skarels else if (lp->d_devflags == 0) { 133432211Skarels lp->d_devflags = VD_ESDI; 133532211Skarels goto top; 133632211Skarels } 1337*40737Skarels } else 1338*40737Skarels saw_drive = 1; 1339*40737Skarels if ((config_status & (DCBS_OCYL|DCBS_NRDY)) == 0) 134032211Skarels printf("dk%d: config error %b ecode %x\n", vi->ui_unit, 1341*40737Skarels config_status, VDERRBITS, config_ecode); 1342*40737Skarels else if ((vd->vd_flags & VD_STARTED) == 0 && saw_drive) { 134330519Ssam int started; 134430519Ssam 134532211Skarels printf(" starting drives, wait ... "); 134630519Ssam vd->vd_flags |= VD_STARTED; 134730519Ssam started = (vdcmd(vm, VDOP_START, 10) == 1); 134830519Ssam DELAY(62000000); 134935413Skarels printf("done\n"); 135032211Skarels lp->d_devflags = 0; 135130519Ssam if (started) 135230519Ssam goto top; 135330519Ssam } 135430519Ssam return (0); 135530519Ssam } 135632211Skarels dk->dk_dcb.devselect |= lp->d_devflags; 135730519Ssam return (1); 135825675Ssam } 135924004Ssam 136025675Ssam /* 136130519Ssam * Perform a command w/o trailer. 136225675Ssam */ 136335413Skarels vdcmd(vm, cmd, t, slave) 136430519Ssam register struct vba_ctlr *vm; 136525675Ssam { 136630519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 136725675Ssam 136830519Ssam vd->vd_dcb.opcode = cmd; /* command */ 136930519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 137030519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 137130519Ssam vd->vd_dcb.operrsta = 0; 137235413Skarels vd->vd_dcb.devselect = slave; 137330519Ssam vd->vd_dcb.trailcnt = 0; 137430519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 137530519Ssam vd->vd_mdcb.mdcb_status = 0; 137630519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 137730519Ssam if (!vdpoll(vm, t)) { 137830519Ssam printf(" during init\n"); 137930370Skarels return (0); 138030370Skarels } 138130519Ssam return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0); 138225675Ssam } 138325675Ssam 138425925Ssam /* 138530519Ssam * Poll controller until operation 138630519Ssam * completes or timeout expires. 138725925Ssam */ 138830519Ssam vdpoll(vm, t) 138930519Ssam register struct vba_ctlr *vm; 139025925Ssam register int t; 139125925Ssam { 139230519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 139330519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 139425925Ssam 139525925Ssam t *= 1000; 139630370Skarels for (;;) { 139730519Ssam uncache(&vd->vd_dcb.operrsta); 139830519Ssam if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT)) 139930370Skarels break; 140025925Ssam if (--t <= 0) { 140130519Ssam printf("vd%d: controller timeout", vm->um_ctlr); 140230519Ssam VDABORT(vdaddr, vd->vd_type); 140325925Ssam return (0); 140425925Ssam } 140530370Skarels DELAY(1000); 140625925Ssam } 140730519Ssam if (vd->vd_type == VDTYPE_SMDE) { 140830519Ssam do { 140925925Ssam DELAY(50); 141030519Ssam uncache(&vdaddr->vdcsr); 141130519Ssam } while (vdaddr->vdcsr & CS_GO); 141232211Skarels DELAY(300); 141332211Skarels uncache(&vd->vd_dcb.err_code); 141425925Ssam } 141525925Ssam DELAY(200); 141630519Ssam uncache(&vd->vd_dcb.operrsta); 141725925Ssam return (1); 141825925Ssam } 141925925Ssam 142030519Ssam #ifdef COMPAT_42 142130519Ssam struct vdst { 142230519Ssam int nsec; /* sectors/track */ 142330519Ssam int ntrack; /* tracks/cylinder */ 142430519Ssam int ncyl; /* cylinders */ 142532211Skarels int secsize; /* sector size */ 142630519Ssam char *name; /* type name */ 142730519Ssam struct { 142830519Ssam int off; /* partition offset in sectors */ 142930519Ssam int size; /* partition size in sectors */ 143030573Skarels } parts[8]; 143130519Ssam } vdst[] = { 143232211Skarels { 66, 23, 850, 512, "NEC 800", 143332211Skarels {0, 1290300}, /* a cyl 0 - 849 */ 143432211Skarels }, 143534737Sbostic { 64, 20, 842, 512, "2361a", 143634737Sbostic {0, 61440}, /* a cyl 0 - 47 */ 143734737Sbostic {61440, 67840}, /* b cyl 48 - 100 */ 143834737Sbostic {129280, 942080}, /* c cyl 101 - 836 */ 143934737Sbostic {0, 1071360}, /* d cyl 0 - 836 */ 144034737Sbostic {449280, 311040}, /* e cyl 351 - 593 */ 144134737Sbostic {760320, 311040}, /* f cyl 594 - 836 */ 144234737Sbostic {449280, 622080}, /* g cyl 351 - 836 */ 144334737Sbostic {129280, 320000} /* h cyl 101 - 350 */ 144434737Sbostic }, 144532211Skarels { 48, 24, 711, 512, "xsd", 144631039Skarels {0, 61056}, /* a cyl 0 - 52 */ 144731039Skarels {61056, 61056}, /* b cyl 53 - 105 */ 144831039Skarels {122112, 691200}, /* c cyl 106 - 705 */ 144931039Skarels {237312, 576000}, /* d cyl 206 - 705 */ 145031039Skarels {352512, 460800}, /* e cyl 306 - 705 */ 145131039Skarels {467712, 345600}, /* f cyl 406 - 705 */ 145231039Skarels {582912, 230400}, /* g cyl 506 - 705 */ 145331039Skarels {698112, 115200} /* h cyl 606 - 705 */ 145430573Skarels }, 145532211Skarels { 44, 20, 842, 512, "eagle", 145630601Skarels {0, 52800}, /* egl0a cyl 0 - 59 */ 145730601Skarels {52800, 66000}, /* egl0b cyl 60 - 134 */ 145830601Skarels {118800, 617760}, /* egl0c cyl 135 - 836 */ 145930756Skarels {736560, 4400}, /* egl0d cyl 837 - 841 */ 146031039Skarels {0, 736560}, /* egl0e cyl 0 - 836 */ 146131039Skarels {0, 740960}, /* egl0f cyl 0 - 841 */ 146230601Skarels {118800, 310640}, /* egl0g cyl 135 - 487 */ 146330601Skarels {429440, 307120} /* egl0h cyl 488 - 836 */ 146430573Skarels }, 146532211Skarels { 64, 10, 823, 512, "fuj", 146631039Skarels {0, 38400}, /* fuj0a cyl 0 - 59 */ 146731039Skarels {38400, 48000}, /* fuj0b cyl 60 - 134 */ 146831039Skarels {86400, 437120}, /* fuj0c cyl 135 - 817 */ 146931039Skarels {159360, 364160}, /* fuj0d cyl 249 - 817 */ 147031039Skarels {232320, 291200}, /* fuj0e cyl 363 - 817 */ 147131039Skarels {305280, 218240}, /* fuj0f cyl 477 - 817 */ 147231039Skarels {378240, 145280}, /* fuj0g cyl 591 - 817 */ 147331039Skarels {451200, 72320} /* fug0h cyl 705 - 817 */ 147430573Skarels }, 147532211Skarels { 32, 24, 711, 512, "xfd", 147630756Skarels { 0, 40704 }, /* a cyl 0 - 52 */ 147730756Skarels { 40704, 40704 }, /* b cyl 53 - 105 */ 147830756Skarels { 81408, 460800 }, /* c cyl 106 - 705 */ 147930756Skarels { 0, 81408 }, /* d cyl 709 - 710 (a & b) */ 148030756Skarels { 0, 542208 }, /* e cyl 0 - 705 */ 148130756Skarels { 40704, 501504 }, /* f cyl 53 - 705 (b & c) */ 148230756Skarels { 81408, 230400 }, /* g cyl 106 - 405 (1/2 of c) */ 148330756Skarels { 311808,230400 } /* h cyl 406 - 705 (1/2 of c) */ 148430573Skarels }, 148532211Skarels { 32, 19, 823, 512, "smd", 148631039Skarels {0, 40128}, /* a cyl 0-65 */ 148731039Skarels {40128, 27360}, /* b cyl 66-110 */ 148831039Skarels {67488, 429856}, /* c cyl 111-817 */ 148931039Skarels {139232, 358112}, /* d cyl 229 - 817 */ 149031039Skarels {210976, 286368}, /* e cyl 347 - 817 */ 149131039Skarels {282720, 214624}, /* f cyl 465 - 817 */ 149231039Skarels {354464, 142880}, /* g cyl 583 - 817 */ 149331039Skarels {426208, 71136} /* h cyl 701 - 817 */ 149430573Skarels }, 149532211Skarels { 18, 15, 1224, 1024, "mxd", 149632211Skarels {0, 21600}, /* a cyl 0-79 */ 149732211Skarels {21600, 22410}, /* b cyl 80-162 */ 149832211Skarels {44010, 285120}, /* c cyl 163-1217 */ 149932211Skarels #ifdef notyet 150032211Skarels {x, 237600}, /* d cyl y - 1217 */ 150132211Skarels {x, 190080}, /* e cyl y - 1217 */ 150232211Skarels {x, 142560}, /* f cyl y - 1217 */ 150332211Skarels {x, 95040}, /* g cyl y - 1217 */ 150432211Skarels {x, 47520} /* h cyl 701 - 817 */ 150532211Skarels #endif 150632211Skarels }, 150732211Skarels { 32, 10, 823, 512, "fsd", 150830756Skarels {0, 19200}, /* a cyl 0 - 59 */ 150930756Skarels {19200, 24000}, /* b cyl 60 - 134 */ 151030756Skarels {43200, 218560}, /* c cyl 135 - 817 */ 151130573Skarels } 151230519Ssam }; 151330519Ssam #define NVDST (sizeof (vdst) / sizeof (vdst[0])) 151430519Ssam 151525675Ssam /* 151630519Ssam * Construct a label for an unlabeled pack. We 151730519Ssam * deduce the drive type by reading from the last 151830519Ssam * track on successively smaller drives until we 151930519Ssam * don't get an error. 152025675Ssam */ 152130519Ssam vdmaptype(vi, lp) 152230519Ssam register struct vba_device *vi; 152330519Ssam register struct disklabel *lp; 152425675Ssam { 152530519Ssam register struct vdsoftc *vd; 152630519Ssam register struct vdst *p; 152732211Skarels struct vba_ctlr *vm = vi->ui_mi; 152830519Ssam int i; 152925675Ssam 153030519Ssam vd = &vdsoftc[vi->ui_ctlr]; 153130519Ssam for (p = vdst; p < &vdst[NVDST]; p++) { 153230519Ssam if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32) 153330519Ssam continue; 153430519Ssam lp->d_nsectors = p->nsec; 153530519Ssam lp->d_ntracks = p->ntrack; 153630519Ssam lp->d_ncylinders = p->ncyl; 153732211Skarels lp->d_secsize = p->secsize; 153835413Skarels DELAY(100000); 153930519Ssam if (!vdreset_drive(vi)) 154030519Ssam return (0); 154135413Skarels DELAY(100000); 154230519Ssam vd->vd_dcb.opcode = VDOP_RD; 154330519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 154430519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 154532211Skarels vd->vd_dcb.devselect = dksoftc[vi->ui_unit].dk_dcb.devselect; 154630756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 154730601Skarels vd->vd_dcb.trail.rwtrail.memadr = 154830601Skarels vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf); 154932211Skarels vd->vd_dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof(short); 155030519Ssam vd->vd_dcb.operrsta = 0; 155130519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2; 155230519Ssam vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1; 155330519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1; 155430519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 155530519Ssam vd->vd_mdcb.mdcb_status = 0; 155630519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 155730519Ssam if (!vdpoll(vm, 60)) 155830519Ssam printf(" during probe\n"); 155930519Ssam if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0) 156030519Ssam break; 156124004Ssam } 156232211Skarels if (p >= &vdst[NVDST]) 156330519Ssam return (0); 156432211Skarels 156530573Skarels for (i = 0; i < 8; i++) { 156630519Ssam lp->d_partitions[i].p_offset = p->parts[i].off; 156730519Ssam lp->d_partitions[i].p_size = p->parts[i].size; 156830519Ssam } 156930573Skarels lp->d_npartitions = 8; 157030519Ssam lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 157130519Ssam bcopy(p->name, lp->d_typename, 4); 157230519Ssam return (1); 157324004Ssam } 157430519Ssam #endif COMPAT_42 157524004Ssam #endif 1576