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*35082Skarels * @(#)vd.c 7.7 (Berkeley) 07/16/88 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" 3225675Ssam #include "dir.h" 3329564Ssam #include "dkstat.h" 3430519Ssam #include "disklabel.h" 3525675Ssam #include "map.h" 3630519Ssam #include "file.h" 3725675Ssam #include "systm.h" 3825675Ssam #include "user.h" 3925675Ssam #include "vmmac.h" 4025675Ssam #include "proc.h" 4125675Ssam #include "uio.h" 4230370Skarels #include "syslog.h" 4330370Skarels #include "kernel.h" 4430519Ssam #include "ioctl.h" 4530756Skarels #include "stat.h" 4624004Ssam 4729951Skarels #include "../tahoe/cpu.h" 4829951Skarels #include "../tahoe/mtpr.h" 4929951Skarels #include "../tahoe/pte.h" 5029951Skarels 5125675Ssam #include "../tahoevba/vbavar.h" 5225928Ssam #include "../tahoevba/vdreg.h" 5324004Ssam 5432211Skarels #ifndef COMPAT_42 5530519Ssam #define COMPAT_42 5632211Skarels #endif 5734396Skarels #define B_FORMAT B_XXX /* XXX */ 5830519Ssam 5930519Ssam #define vdunit(dev) (minor(dev) >> 3) 6030519Ssam #define vdpart(dev) (minor(dev) & 0x07) 6130519Ssam #define vdminor(unit,part) (((unit) << 3) | (part)) 6224004Ssam 6324004Ssam struct vba_ctlr *vdminfo[NVD]; 6429564Ssam struct vba_device *vddinfo[NDK]; 6530756Skarels int vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy(); 6634528Skarels long vdstd[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 }; 6725675Ssam struct vba_driver vddriver = 6834528Skarels { vdprobe, vdslave, vdattach, vddgo, vdstd, "dk", vddinfo, "vd", vdminfo }; 6924004Ssam 7024004Ssam /* 7130519Ssam * Per-controller state. 7230519Ssam */ 7330519Ssam struct vdsoftc { 7430519Ssam u_short vd_flags; 7530519Ssam #define VD_INIT 0x1 /* controller initialized */ 7630519Ssam #define VD_STARTED 0x2 /* start command issued */ 7730519Ssam #define VD_DOSEEKS 0x4 /* should overlap seeks */ 7830756Skarels #define VD_SCATGATH 0x8 /* can do scatter-gather commands (correctly) */ 79*35082Skarels #define VD_LOCKED 0x10 /* locked for direct controller access */ 80*35082Skarels #define VD_WAIT 0x20 /* someone needs direct controller access */ 8130519Ssam u_short vd_type; /* controller type */ 8230519Ssam u_short vd_wticks; /* timeout */ 8330519Ssam struct mdcb vd_mdcb; /* master command block */ 8430519Ssam u_long vd_mdcbphys; /* physical address of vd_mdcb */ 8530519Ssam struct dcb vd_dcb; /* i/o command block */ 8630519Ssam u_long vd_dcbphys; /* physical address of vd_dcb */ 8730601Skarels struct vb_buf vd_rbuf; /* vba resources */ 8830519Ssam } vdsoftc[NVD]; 8930519Ssam 9034396Skarels #define VDMAXTIME 20 /* max time for operation, sec. */ 9134396Skarels 9230519Ssam /* 9325675Ssam * Per-drive state. 9425675Ssam */ 9530519Ssam struct dksoftc { 9634076Skarels int dk_state; /* open fsm */ 9730756Skarels #ifndef SECSIZE 9830756Skarels u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */ 9930756Skarels #endif SECSIZE 10034076Skarels int dk_wlabel; /* label sector is currently writable */ 10132576Skarels u_long dk_copenpart; /* character units open on this drive */ 10232576Skarels u_long dk_bopenpart; /* block units open on this drive */ 10332576Skarels u_long dk_openpart; /* all units open on this drive */ 10430519Ssam u_int dk_curcyl; /* last selected cylinder */ 10530756Skarels struct skdcb dk_dcb; /* seek command block */ 10630519Ssam u_long dk_dcbphys; /* physical address of dk_dcb */ 10734396Skarels int df_reg[3]; /* for formatting, in-out parameters */ 10830519Ssam } dksoftc[NDK]; 10924004Ssam 11024004Ssam /* 11130519Ssam * Drive states. Used during steps of open/initialization. 11230519Ssam * States < OPEN (> 0) are transient, during an open operation. 11334076Skarels * OPENRAW is used for unlabeled disks, to allow format operations. 11425675Ssam */ 11530519Ssam #define CLOSED 0 /* disk is closed */ 11630519Ssam #define WANTOPEN 1 /* open requested, not started */ 11730519Ssam #define WANTOPENRAW 2 /* open requested, no label */ 11830519Ssam #define RDLABEL 3 /* reading pack label */ 11930519Ssam #define OPEN 4 /* intialized and ready */ 12030519Ssam #define OPENRAW 5 /* open, no label */ 12124004Ssam 12230519Ssam struct buf dkutab[NDK]; /* i/o queue headers */ 12330519Ssam struct disklabel dklabel[NDK]; /* pack labels */ 12424004Ssam 12530519Ssam #define b_cylin b_resid 12630574Skarels #define b_track b_error /* used for seek commands */ 12730574Skarels #define b_seekf b_forw /* second queue on um_tab */ 12830574Skarels #define b_seekl b_back /* second queue on um_tab */ 12930519Ssam 13030519Ssam int vdwstart, vdwatch(); 13130519Ssam 13224004Ssam /* 13325675Ssam * See if the controller is really there; if so, initialize it. 13425675Ssam */ 13525857Ssam vdprobe(reg, vm) 13625857Ssam caddr_t reg; 13725857Ssam struct vba_ctlr *vm; 13825675Ssam { 13925857Ssam register br, cvec; /* must be r12, r11 */ 14030519Ssam register struct vddevice *vdaddr = (struct vddevice *)reg; 14130519Ssam struct vdsoftc *vd; 14230573Skarels int s; 14325857Ssam 14430370Skarels #ifdef lint 14530370Skarels br = 0; cvec = br; br = cvec; 14630370Skarels vdintr(0); 14730370Skarels #endif 14825857Ssam if (badaddr((caddr_t)reg, 2)) 14925675Ssam return (0); 15030519Ssam vd = &vdsoftc[vm->um_ctlr]; 15130519Ssam vdaddr->vdreset = 0xffffffff; 15225675Ssam DELAY(1000000); 15330519Ssam if (vdaddr->vdreset != (unsigned)0xffffffff) { 15430519Ssam vd->vd_type = VDTYPE_VDDC; 15530519Ssam vd->vd_flags &= ~VD_DOSEEKS; 15625675Ssam DELAY(1000000); 15725675Ssam } else { 15830519Ssam vd->vd_type = VDTYPE_SMDE; 15930519Ssam vd->vd_flags |= VD_DOSEEKS; 16030519Ssam vdaddr->vdrstclr = 0; 16125675Ssam DELAY(3000000); 16230519Ssam vdaddr->vdcsr = 0; 16330519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 16430519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 16530519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 16630519Ssam vdaddr->vdtcf_data = AM_ENPDA; 16730519Ssam vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS | 16829921Skarels XMD_32BIT | BSZ_16WRD | 16925925Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 17025675Ssam } 17130519Ssam vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb); 17230519Ssam vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb); 17330519Ssam vm->um_addr = reg; /* XXX */ 17430573Skarels s = spl7(); 17530519Ssam if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { 17630519Ssam printf("vd%d: %s cmd failed\n", vm->um_ctlr, 17730519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 17830573Skarels splx(s); 17930519Ssam return (0); 18030519Ssam } 18130756Skarels if (vd->vd_type == VDTYPE_SMDE) { 18230756Skarels vd->vd_dcb.trail.idtrail.date = 0; 18330756Skarels if (vdcmd(vm, VDOP_IDENT, 10)) { 18430756Skarels uncache(&vd->vd_dcb.trail.idtrail.date); 18530756Skarels if (vd->vd_dcb.trail.idtrail.date != 0) 18630756Skarels vd->vd_flags |= VD_SCATGATH; 18730756Skarels } 18830756Skarels } 18930573Skarels splx(s); 19025925Ssam /* 19125950Ssam * Allocate page tables and i/o buffer. 19225925Ssam */ 19332211Skarels if (vbainit(&vd->vd_rbuf, MAXPHYS, 19432211Skarels vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT) == 0) { 19532211Skarels printf("vd%d: vbainit failed\n", vm->um_ctlr); 19632211Skarels return (0); 19732211Skarels } 19825857Ssam br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */ 19930519Ssam return (sizeof (struct vddevice)); 20025675Ssam } 20124004Ssam 20224004Ssam /* 20330519Ssam * See if a drive is really there. 20430519Ssam * 20530519Ssam * Can't read pack label here as various data structures 20630519Ssam * aren't setup for doing a read in a straightforward 20730519Ssam * manner. Instead just probe for the drive and leave 20830519Ssam * the pack label stuff to the attach routine. 20925675Ssam */ 21034076Skarels /* ARGSUSED */ 21134076Skarels vdslave(vi, vdaddr) 21225675Ssam register struct vba_device *vi; 21330519Ssam struct vddevice *vdaddr; 21425675Ssam { 21530519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 21632211Skarels register struct dksoftc *dk = &dksoftc[vi->ui_unit]; 21730519Ssam struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 21824004Ssam 21930519Ssam if ((vd->vd_flags&VD_INIT) == 0) { 22030756Skarels printf("vd%d: %s controller%s\n", vi->ui_ctlr, 22130756Skarels vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE", 22230756Skarels (vd->vd_flags & VD_SCATGATH) ? " with scatter-gather" : ""); 22330519Ssam vd->vd_flags |= VD_INIT; 22425675Ssam } 22530519Ssam 22625675Ssam /* 22730519Ssam * Initialize label enough to do a reset on 22830519Ssam * the drive. The remainder of the default 22930519Ssam * label values will be filled in in vdinit 23030519Ssam * at attach time. 23125675Ssam */ 23232211Skarels if (vd->vd_type == VDTYPE_SMDE) 23332211Skarels lp->d_secsize = VD_MAXSECSIZE; 23432211Skarels else 23532211Skarels lp->d_secsize = VDDC_SECSIZE; 23634396Skarels lp->d_nsectors = 66; /* only used on smd-e */ 23734076Skarels lp->d_ntracks = 23; 23834396Skarels lp->d_ncylinders = 850; 23934396Skarels lp->d_secpercyl = 66*23; 24034592Skarels lp->d_npartitions = 1; 24134592Skarels lp->d_partitions[0].p_offset = 0; 24234592Skarels lp->d_partitions[0].p_size = LABELSECTOR + 1; 24324004Ssam 24430519Ssam /* 24530519Ssam * Initialize invariant portion of 24630519Ssam * dcb used for overlapped seeks. 24730519Ssam */ 24830519Ssam dk->dk_dcb.opcode = VDOP_SEEK; 24930519Ssam dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA; 25030519Ssam dk->dk_dcb.devselect = vi->ui_slave; 25130756Skarels dk->dk_dcb.trailcnt = sizeof (struct trseek) / sizeof (long); 25230519Ssam dk->dk_dcb.trail.sktrail.skaddr.sector = 0; 25330519Ssam dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb); 25432211Skarels #ifndef SECSIZE 25532211Skarels vd_setsecsize(dk, lp); 25632211Skarels #endif 25732211Skarels return (vdreset_drive(vi)); 25832211Skarels } 25932211Skarels 26032211Skarels vdattach(vi) 26132211Skarels register struct vba_device *vi; 26232211Skarels { 26332211Skarels register int unit = vi->ui_unit; 26432211Skarels register struct disklabel *lp = &dklabel[unit]; 26532211Skarels 26630601Skarels /* 26730601Skarels * Try to initialize device and read pack label. 26830601Skarels */ 26930601Skarels if (vdinit(vdminor(unit, 0), 0) != 0) { 27030601Skarels printf(": unknown drive type"); 27130601Skarels return; 27230601Skarels } 27332211Skarels if (dksoftc[unit].dk_state == OPEN) 27432211Skarels printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>", 27532211Skarels lp->d_typename, lp->d_secsize, 27632211Skarels lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors); 27730519Ssam /* 27830519Ssam * (60 / rpm) / (sectors per track * (bytes per sector / 2)) 27930519Ssam */ 28030519Ssam if (vi->ui_dk >= 0) 28130519Ssam dk_mspw[vi->ui_dk] = 120.0 / 28230519Ssam (lp->d_rpm * lp->d_nsectors * lp->d_secsize); 28330519Ssam #ifdef notyet 28430573Skarels addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp); 28530519Ssam #endif 28624004Ssam } 28724004Ssam 28830756Skarels vdopen(dev, flags, fmt) 28930519Ssam dev_t dev; 29030756Skarels int flags, fmt; 29124004Ssam { 29230519Ssam register unit = vdunit(dev); 29330519Ssam register struct disklabel *lp; 29430519Ssam register struct dksoftc *dk; 29530519Ssam register struct partition *pp; 29630519Ssam struct vba_device *vi; 29730756Skarels int s, error, part = vdpart(dev), mask = 1 << part; 29830519Ssam daddr_t start, end; 29924004Ssam 30030519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 30130519Ssam return (ENXIO); 30230519Ssam lp = &dklabel[unit]; 30330519Ssam dk = &dksoftc[unit]; 30430519Ssam 30530519Ssam s = spl7(); 30630519Ssam while (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 30730519Ssam dk->dk_state != CLOSED) 30830519Ssam sleep((caddr_t)dk, PZERO+1); 30930519Ssam splx(s); 31030519Ssam if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 31130519Ssam if (error = vdinit(dev, flags)) 31230519Ssam return (error); 31330573Skarels 31430573Skarels if (vdwstart == 0) { 31530573Skarels timeout(vdwatch, (caddr_t)0, hz); 31630573Skarels vdwstart++; 31730573Skarels } 31830519Ssam /* 31930519Ssam * Warn if a partion is opened 32030519Ssam * that overlaps another partition which is open 32130519Ssam * unless one is the "raw" partition (whole disk). 32230519Ssam */ 32332211Skarels #define RAWPART 8 /* 'x' partition */ /* XXX */ 32432576Skarels if ((dk->dk_openpart & mask) == 0 && part != RAWPART) { 32530519Ssam pp = &lp->d_partitions[part]; 32630519Ssam start = pp->p_offset; 32730519Ssam end = pp->p_offset + pp->p_size; 32830519Ssam for (pp = lp->d_partitions; 32930519Ssam pp < &lp->d_partitions[lp->d_npartitions]; pp++) { 33030519Ssam if (pp->p_offset + pp->p_size <= start || 33130519Ssam pp->p_offset >= end) 33230519Ssam continue; 33330519Ssam if (pp - lp->d_partitions == RAWPART) 33430519Ssam continue; 33530519Ssam if (dk->dk_openpart & (1 << (pp - lp->d_partitions))) 33630519Ssam log(LOG_WARNING, 33730519Ssam "dk%d%c: overlaps open partition (%c)\n", 33830519Ssam unit, part + 'a', 33930519Ssam pp - lp->d_partitions + 'a'); 34030519Ssam } 34124004Ssam } 34230519Ssam if (part >= lp->d_npartitions) 34330519Ssam return (ENXIO); 34430756Skarels dk->dk_openpart |= mask; 34530756Skarels switch (fmt) { 34630756Skarels case S_IFCHR: 34730756Skarels dk->dk_copenpart |= mask; 34830756Skarels break; 34930756Skarels case S_IFBLK: 35030756Skarels dk->dk_bopenpart |= mask; 35130756Skarels break; 35230756Skarels } 35330519Ssam return (0); 35425675Ssam } 35524004Ssam 35634528Skarels /* ARGSUSED */ 35730756Skarels vdclose(dev, flags, fmt) 35830519Ssam dev_t dev; 35930756Skarels int flags, fmt; 36024004Ssam { 36130519Ssam register int unit = vdunit(dev); 36230519Ssam register struct dksoftc *dk = &dksoftc[unit]; 36330756Skarels int part = vdpart(dev), mask = 1 << part; 36424004Ssam 36530756Skarels switch (fmt) { 36630756Skarels case S_IFCHR: 36730756Skarels dk->dk_copenpart &= ~mask; 36830756Skarels break; 36930756Skarels case S_IFBLK: 37030756Skarels dk->dk_bopenpart &= ~mask; 37130756Skarels break; 37230756Skarels } 37330756Skarels if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0) 37430756Skarels dk->dk_openpart &= ~mask; 37530519Ssam /* 37630519Ssam * Should wait for i/o to complete on this partition 37730519Ssam * even if others are open, but wait for work on blkflush(). 37830519Ssam */ 37930519Ssam if (dk->dk_openpart == 0) { 38030573Skarels int s = spl7(); 38130573Skarels while (dkutab[unit].b_actf) 38230573Skarels sleep((caddr_t)dk, PZERO-1); 38330519Ssam splx(s); 38430519Ssam dk->dk_state = CLOSED; 38534076Skarels dk->dk_wlabel = 0; 38624004Ssam } 38730756Skarels return (0); 38825675Ssam } 38924004Ssam 39030519Ssam vdinit(dev, flags) 39130519Ssam dev_t dev; 39230519Ssam int flags; 39325675Ssam { 39430519Ssam register struct disklabel *lp; 39530519Ssam register struct dksoftc *dk; 39630519Ssam struct vba_device *vi; 39730519Ssam int unit = vdunit(dev), error = 0; 39830756Skarels char *msg, *readdisklabel(); 39930519Ssam extern int cold; 40025675Ssam 40130519Ssam dk = &dksoftc[unit]; 40230519Ssam if (flags & O_NDELAY) { 40330519Ssam dk->dk_state = OPENRAW; 40434528Skarels return (0); 40530519Ssam } 40630519Ssam dk->dk_state = RDLABEL; 40730519Ssam lp = &dklabel[unit]; 40830519Ssam vi = vddinfo[unit]; 40930756Skarels if (msg = readdisklabel(dev, vdstrategy, lp)) { 41034076Skarels if (cold) { 41130601Skarels printf(": %s", msg); 41234076Skarels dk->dk_state = CLOSED; 41334076Skarels } else { 41432211Skarels log(LOG_ERR, "dk%d: %s\n", unit, msg); 41534076Skarels dk->dk_state = OPENRAW; 41634076Skarels } 41730519Ssam #ifdef COMPAT_42 418*35082Skarels vdlock(vi->ui_ctlr); 41934076Skarels if (vdmaptype(vi, lp)) 42030519Ssam dk->dk_state = OPEN; 421*35082Skarels vdunlock(vi->ui_ctlr); 42230519Ssam #endif 42330756Skarels } else { 42430756Skarels /* 42530756Skarels * Now that we have the label, configure 42630756Skarels * the correct drive parameters. 42730756Skarels */ 428*35082Skarels vdlock(vi->ui_ctlr); 42932211Skarels if (vdreset_drive(vi)) 43032211Skarels dk->dk_state = OPEN; 43132211Skarels else { 43230756Skarels dk->dk_state = CLOSED; 43330756Skarels error = ENXIO; 43432211Skarels } 435*35082Skarels vdunlock(vi->ui_ctlr); 43625675Ssam } 43730756Skarels #ifndef SECSIZE 43832211Skarels vd_setsecsize(dk, lp); 43932211Skarels #endif 44030519Ssam wakeup((caddr_t)dk); 44130519Ssam return (error); 44224004Ssam } 44324004Ssam 44432211Skarels #ifndef SECSIZE 44532211Skarels vd_setsecsize(dk, lp) 44632211Skarels register struct dksoftc *dk; 44732211Skarels register struct disklabel *lp; 44832211Skarels { 44932211Skarels int mul; 45032211Skarels 45132211Skarels /* 45232211Skarels * Calculate scaling shift for mapping 45332211Skarels * DEV_BSIZE blocks to drive sectors. 45432211Skarels */ 45532211Skarels mul = DEV_BSIZE / lp->d_secsize; 45632211Skarels dk->dk_bshift = 0; 45732211Skarels while ((mul >>= 1) > 0) 45832211Skarels dk->dk_bshift++; 45932211Skarels } 46032211Skarels #endif SECSIZE 46132211Skarels 46225675Ssam /*ARGSUSED*/ 46330519Ssam vddgo(vm) 46430519Ssam struct vba_device *vm; 46524004Ssam { 46624004Ssam 46724004Ssam } 46824004Ssam 46924004Ssam vdstrategy(bp) 47025675Ssam register struct buf *bp; 47124004Ssam { 47230519Ssam register struct vba_device *vi; 47330519Ssam register struct disklabel *lp; 47430519Ssam register struct dksoftc *dk; 47530519Ssam register int unit; 47630573Skarels register daddr_t sn; 47730519Ssam struct buf *dp; 47830573Skarels daddr_t sz, maxsz; 47930519Ssam int part, s; 48024004Ssam 48130519Ssam unit = vdunit(bp->b_dev); 48232211Skarels if (unit >= NDK) { 48329954Skarels bp->b_error = ENXIO; 48425675Ssam goto bad; 48529954Skarels } 48630519Ssam vi = vddinfo[unit]; 48730519Ssam lp = &dklabel[unit]; 48830519Ssam if (vi == 0 || vi->ui_alive == 0) { 48930519Ssam bp->b_error = ENXIO; 49030519Ssam goto bad; 49130519Ssam } 49230519Ssam dk = &dksoftc[unit]; 49330519Ssam if (dk->dk_state < OPEN) 49430519Ssam goto q; 49534076Skarels if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) { 49634076Skarels bp->b_error = EROFS; 49734076Skarels goto bad; 49834076Skarels } 49930519Ssam part = vdpart(bp->b_dev); 50030519Ssam if ((dk->dk_openpart & (1 << part)) == 0) { 50130519Ssam bp->b_error = ENODEV; 50230519Ssam goto bad; 50330519Ssam } 50432211Skarels sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize; 50530519Ssam maxsz = lp->d_partitions[part].p_size; 50630756Skarels #ifndef SECSIZE 50730756Skarels sn = bp->b_blkno << dk->dk_bshift; 50830756Skarels #else SECSIZE 50930573Skarels sn = bp->b_blkno; 51030756Skarels #endif SECSIZE 51134076Skarels if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR && 51234076Skarels #if LABELSECTOR != 0 51334076Skarels sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR && 51434076Skarels #endif 51534076Skarels (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) { 51634076Skarels bp->b_error = EROFS; 51734076Skarels goto bad; 51834076Skarels } 51930519Ssam if (sn < 0 || sn + sz > maxsz) { 52030519Ssam if (sn == maxsz) { 52129954Skarels bp->b_resid = bp->b_bcount; 52229954Skarels goto done; 52329954Skarels } 52430756Skarels sz = maxsz - sn; 52530573Skarels if (sz <= 0) { 52630573Skarels bp->b_error = EINVAL; 52730573Skarels goto bad; 52830573Skarels } 52930573Skarels bp->b_bcount = sz * lp->d_secsize; 53025675Ssam } 53130519Ssam bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl; 53230756Skarels #ifdef SECSIZE 53330756Skarels if (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0) 53430756Skarels panic("vdstrat blksize"); 53530756Skarels #endif SECSIZE 53630519Ssam q: 53725675Ssam s = spl7(); 53830519Ssam dp = &dkutab[vi->ui_unit]; 53930519Ssam disksort(dp, bp); 54030519Ssam if (!dp->b_active) { 54130519Ssam (void) vdustart(vi); 54230573Skarels if (!vi->ui_mi->um_tab.b_active) 54330519Ssam vdstart(vi->ui_mi); 54424004Ssam } 54530519Ssam splx(s); 54624004Ssam return; 54725675Ssam bad: 54829954Skarels bp->b_flags |= B_ERROR; 54929954Skarels done: 55030519Ssam biodone(bp); 55130519Ssam return; 55224004Ssam } 55324004Ssam 55430519Ssam vdustart(vi) 55530519Ssam register struct vba_device *vi; 55624004Ssam { 55730519Ssam register struct buf *bp, *dp; 55830519Ssam register struct vba_ctlr *vm; 55930519Ssam register int unit = vi->ui_unit; 56030519Ssam register struct dksoftc *dk; 56130519Ssam register struct vdsoftc *vd; 56230519Ssam struct disklabel *lp; 56324004Ssam 56430519Ssam dp = &dkutab[unit]; 56530519Ssam /* 56630519Ssam * If queue empty, nothing to do. 56730519Ssam */ 56830519Ssam if ((bp = dp->b_actf) == NULL) 56930519Ssam return; 57030519Ssam /* 57130574Skarels * If drive is off-cylinder and controller supports seeks, 57230574Skarels * place drive on seek queue for controller. 57330574Skarels * Otherwise, place on transfer queue. 57430519Ssam */ 57530519Ssam vd = &vdsoftc[vi->ui_ctlr]; 57630519Ssam dk = &dksoftc[unit]; 57730574Skarels vm = vi->ui_mi; 57830519Ssam if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) { 57930519Ssam lp = &dklabel[unit]; 58030574Skarels bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors; 58130574Skarels if (vm->um_tab.b_seekf == NULL) 58230574Skarels vm->um_tab.b_seekf = dp; 58330574Skarels else 58430574Skarels vm->um_tab.b_seekl->b_forw = dp; 58530574Skarels vm->um_tab.b_seekl = dp; 58630574Skarels } else { 58730574Skarels if (vm->um_tab.b_actf == NULL) 58830574Skarels vm->um_tab.b_actf = dp; 58930574Skarels else 59030574Skarels vm->um_tab.b_actl->b_forw = dp; 59130574Skarels vm->um_tab.b_actl = dp; 59230519Ssam } 59330573Skarels dp->b_forw = NULL; 59430573Skarels dp->b_active++; 59525675Ssam } 59625675Ssam 59725675Ssam /* 59830519Ssam * Start next transfer on a controller. 59930574Skarels * There are two queues of drives, the first on-cylinder 60030574Skarels * and the second off-cylinder from their next transfers. 60130574Skarels * Perform the first transfer for the first drive on the on-cylinder 60230574Skarels * queue, if any, otherwise the first transfer for the first drive 60330574Skarels * on the second queue. Initiate seeks on remaining drives on the 60430574Skarels * off-cylinder queue, then move them all to the on-cylinder queue. 60525675Ssam */ 60630519Ssam vdstart(vm) 60730519Ssam register struct vba_ctlr *vm; 60825675Ssam { 60925675Ssam register struct buf *bp; 61030519Ssam register struct vba_device *vi; 61130519Ssam register struct vdsoftc *vd; 61230519Ssam register struct dksoftc *dk; 61330519Ssam register struct disklabel *lp; 61430519Ssam register struct dcb **dcbp; 61530519Ssam struct buf *dp; 61630519Ssam int sn, tn; 61725675Ssam 61830519Ssam loop: 61930519Ssam /* 62030519Ssam * Pull a request off the controller queue. 62130519Ssam */ 62230574Skarels if ((dp = vm->um_tab.b_actf) == NULL && 62330574Skarels (dp = vm->um_tab.b_seekf) == NULL) 62430519Ssam return; 62530519Ssam if ((bp = dp->b_actf) == NULL) { 62630601Skarels if (dp == vm->um_tab.b_actf) 62730601Skarels vm->um_tab.b_actf = dp->b_forw; 62830601Skarels else 62930601Skarels vm->um_tab.b_seekf = dp->b_forw; 63030519Ssam goto loop; 63130519Ssam } 63225675Ssam 63324004Ssam /* 63430519Ssam * Mark controller busy, and determine 63530519Ssam * destination of this request. 63624004Ssam */ 63730519Ssam vm->um_tab.b_active++; 63830519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 63930519Ssam dk = &dksoftc[vi->ui_unit]; 64030756Skarels #ifndef SECSIZE 64130756Skarels sn = bp->b_blkno << dk->dk_bshift; 64230756Skarels #else SECSIZE 64330573Skarels sn = bp->b_blkno; 64430756Skarels #endif SECSIZE 64530519Ssam lp = &dklabel[vi->ui_unit]; 64630519Ssam sn %= lp->d_secpercyl; 64730519Ssam tn = sn / lp->d_nsectors; 64830519Ssam sn %= lp->d_nsectors; 64930519Ssam 65030519Ssam /* 65130519Ssam * Construct dcb for read/write command. 65230519Ssam */ 65330519Ssam vd = &vdsoftc[vm->um_ctlr]; 65430519Ssam vd->vd_dcb.intflg = DCBINT_DONE; 65532211Skarels vd->vd_dcb.devselect = dk->dk_dcb.devselect; 65630519Ssam vd->vd_dcb.operrsta = 0; 65730519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 65830519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin; 65930519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 66030519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 66130574Skarels dk->dk_curcyl = bp->b_cylin; 66230574Skarels bp->b_track = 0; /* init overloaded field */ 66330756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 66434396Skarels if (bp->b_flags & B_FORMAT) 66534396Skarels vd->vd_dcb.opcode = dk->dk_op; 66634396Skarels else if (vd->vd_flags & VD_SCATGATH && 66734396Skarels ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0) 66830756Skarels vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW; 66934396Skarels else 67030756Skarels vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD; 67134396Skarels 67234396Skarels switch (vd->vd_dcb.opcode) { 67334396Skarels case VDOP_FSECT: 67434396Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 67534396Skarels vd->vd_dcb.trail.fmtrail.nsectors = bp->b_bcount / 67634396Skarels lp->d_secsize; 67734396Skarels vd->vd_dcb.trail.fmtrail.hdr = *(dskadr *)&dk->dk_althdr; 67834396Skarels vd->vd_dcb.trail.rwtrail.disk.cylinder |= dk->dk_fmtflags; 67934396Skarels goto setupaddr; 68034396Skarels 68134396Skarels case VDOP_RDRAW: 68234396Skarels case VDOP_RD: 68334396Skarels case VDOP_WD: 68434396Skarels vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1; 68534396Skarels setupaddr: 68630756Skarels vd->vd_dcb.trail.rwtrail.memadr = 68734528Skarels vbasetup(bp, &vd->vd_rbuf, (int)lp->d_secsize); 68834396Skarels break; 68934396Skarels 69034396Skarels case VDOP_RAS: 69134396Skarels case VDOP_GAW: 69234396Skarels vd->vd_dcb.trailcnt += vba_sgsetup(bp, &vd->vd_rbuf, 69334396Skarels &vd->vd_dcb.trail.sgtrail); 69434396Skarels break; 69530756Skarels } 69630574Skarels if (vi->ui_dk >= 0) { 69730574Skarels dk_busy |= 1<<vi->ui_dk; 69830574Skarels dk_xfer[vi->ui_dk]++; 69930574Skarels dk_wds[vi->ui_dk] += bp->b_bcount>>6; 70030574Skarels } 70130519Ssam 70230519Ssam /* 70330519Ssam * Look for any seeks to be performed on other drives on this 70430519Ssam * controller. If overlapped seeks exist, insert seek commands 70530519Ssam * on the controller's command queue before the transfer. 70630519Ssam */ 70730519Ssam dcbp = &vd->vd_mdcb.mdcb_head; 70830519Ssam 70930574Skarels if (dp == vm->um_tab.b_seekf) 71030574Skarels dp = dp->b_forw; 71130574Skarels else 71230574Skarels dp = vm->um_tab.b_seekf; 71330574Skarels for (; dp != NULL; dp = dp->b_forw) { 71430574Skarels if ((bp = dp->b_actf) == NULL) 71530574Skarels continue; 71630574Skarels vi = vddinfo[vdunit(bp->b_dev)]; 71730574Skarels dk = &dksoftc[vi->ui_unit]; 71830519Ssam dk->dk_curcyl = bp->b_cylin; 71930574Skarels if (vi->ui_dk >= 0) 72030574Skarels dk_seek[vi->ui_dk]++; 72130574Skarels dk->dk_dcb.operrsta = 0; 72230574Skarels dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin; 72330574Skarels dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track; 72430574Skarels *dcbp = (struct dcb *)dk->dk_dcbphys; 72530574Skarels dcbp = &dk->dk_dcb.nxtdcb; 72624004Ssam } 72730519Ssam *dcbp = (struct dcb *)vd->vd_dcbphys; 72830574Skarels if (vm->um_tab.b_actf) 72930574Skarels vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf; 73030574Skarels else 73130574Skarels vm->um_tab.b_actf = vm->um_tab.b_seekf; 73230601Skarels if (vm->um_tab.b_seekf) 73330601Skarels vm->um_tab.b_actl = vm->um_tab.b_seekl; 73430574Skarels vm->um_tab.b_seekf = 0; 73524004Ssam 73630519Ssam /* 73730519Ssam * Initiate operation. 73830519Ssam */ 73930519Ssam vd->vd_mdcb.mdcb_status = 0; 74030519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 74124004Ssam } 74224004Ssam 743*35082Skarels /* 744*35082Skarels * Wait for controller to finish current operation 745*35082Skarels * so that direct controller accesses can be done. 746*35082Skarels */ 747*35082Skarels vdlock(ctlr) 748*35082Skarels { 749*35082Skarels register struct vba_ctlr *vm = vdminfo[ctlr]; 750*35082Skarels register struct vdsoftc *vd = &vdsoftc[ctlr]; 751*35082Skarels int s; 752*35082Skarels 753*35082Skarels s = spl7(); 754*35082Skarels while (vm->um_tab.b_active || vd->vd_flags & VD_LOCKED) { 755*35082Skarels vd->vd_flags |= VD_WAIT; 756*35082Skarels sleep((caddr_t)vd, PRIBIO); 757*35082Skarels } 758*35082Skarels vd->vd_flags |= VD_LOCKED; 759*35082Skarels splx(s); 760*35082Skarels } 761*35082Skarels 762*35082Skarels /* 763*35082Skarels * Continue normal operations after pausing for 764*35082Skarels * munging the controller directly. 765*35082Skarels */ 766*35082Skarels vdunlock(ctlr) 767*35082Skarels { 768*35082Skarels register struct vba_ctlr *vm = vdminfo[ctlr]; 769*35082Skarels register struct vdsoftc *vd = &vdsoftc[ctlr]; 770*35082Skarels 771*35082Skarels vd->vd_flags &= ~VD_LOCKED; 772*35082Skarels if (vd->vd_flags & VD_WAIT) { 773*35082Skarels vd->vd_flags &= ~VD_WAIT; 774*35082Skarels wakeup((caddr_t)vd); 775*35082Skarels } else if (vm->um_tab.b_actf || vm->um_tab.b_seekf) 776*35082Skarels vdstart(vm); 777*35082Skarels } 778*35082Skarels 77930519Ssam #define DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE) 78024004Ssam /* 78124004Ssam * Handle a disk interrupt. 78224004Ssam */ 78325675Ssam vdintr(ctlr) 78430519Ssam register ctlr; 78524004Ssam { 78630519Ssam register struct buf *bp, *dp; 78730519Ssam register struct vba_ctlr *vm = vdminfo[ctlr]; 78830519Ssam register struct vba_device *vi; 78930519Ssam register struct vdsoftc *vd = &vdsoftc[ctlr]; 79030519Ssam register status; 79134528Skarels int timedout; 79230573Skarels struct dksoftc *dk; 79324004Ssam 79430519Ssam if (!vm->um_tab.b_active) { 79525675Ssam printf("vd%d: stray interrupt\n", ctlr); 79624004Ssam return; 79724004Ssam } 79825675Ssam /* 79930519Ssam * Get device and block structures, and a pointer 80030519Ssam * to the vba_device for the drive. 80125675Ssam */ 80230519Ssam dp = vm->um_tab.b_actf; 80330519Ssam bp = dp->b_actf; 80430519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 80534528Skarels dk = &dksoftc[vi->ui_unit]; 80630574Skarels if (vi->ui_dk >= 0) 80730574Skarels dk_busy &= ~(1<<vi->ui_dk); 80834396Skarels timedout = (vd->vd_wticks >= VDMAXTIME); 80930519Ssam /* 81030519Ssam * Check for and process errors on 81130519Ssam * either the drive or the controller. 81230519Ssam */ 81330519Ssam uncache(&vd->vd_dcb.operrsta); 81430519Ssam status = vd->vd_dcb.operrsta; 81534396Skarels if (bp->b_flags & B_FORMAT) { 81634396Skarels dk->dk_operrsta = status; 81734396Skarels uncache(&vd->vd_dcb.err_code); 81834396Skarels dk->dk_ecode = vd->vd_dcb.err_code; 81934396Skarels } 82034396Skarels if (status & VDERR_HARD || timedout) { 82134528Skarels if (vd->vd_type == VDTYPE_SMDE) 82230601Skarels uncache(&vd->vd_dcb.err_code); 82330519Ssam if (status & DCBS_WPT) { 82430519Ssam /* 82530519Ssam * Give up on write locked devices immediately. 82630519Ssam */ 82730573Skarels printf("dk%d: write locked\n", vi->ui_unit); 82830519Ssam bp->b_flags |= B_ERROR; 82934396Skarels } else if (status & VDERR_RETRY || timedout) { 83032211Skarels int endline = 1; 83132211Skarels 83234396Skarels if (status & VDERR_CTLR || timedout) { 83334396Skarels vdharderr("controller err", 83434396Skarels vd, bp, &vd->vd_dcb); 83534396Skarels printf("; resetting controller..."); 83634396Skarels vdreset_ctlr(vm); 83734396Skarels } else if (status & VDERR_DRIVE) { 83834396Skarels vdharderr("drive err", vd, bp, &vd->vd_dcb); 83934396Skarels printf("; resetting drive..."); 84030519Ssam if (!vdreset_drive(vi)) 84130519Ssam vi->ui_alive = 0; 84232211Skarels } else 84332211Skarels endline = 0; 84430519Ssam /* 84530519Ssam * Retry transfer once, unless reset failed. 84630519Ssam */ 84734396Skarels if (!vi->ui_alive || dp->b_errcnt++ >= 2 || 84834396Skarels bp->b_flags & B_FORMAT) { 84932211Skarels if (endline) 85032211Skarels printf("\n"); 85130519Ssam goto hard; 85232211Skarels } 85332211Skarels 85432211Skarels if (endline) 85532211Skarels printf(" retrying\n"); 85630519Ssam vm->um_tab.b_active = 0; /* force retry */ 85730519Ssam } else { 85830519Ssam hard: 85930519Ssam bp->b_flags |= B_ERROR; 86034396Skarels vdharderr("hard error", vd, bp, &vd->vd_dcb); 86130519Ssam printf("\n"); 86230519Ssam } 86330519Ssam } else if (status & DCBS_SOFT) 86434528Skarels vdsofterr(bp, &vd->vd_dcb); 86534396Skarels vd->vd_wticks = 0; 86630519Ssam if (vm->um_tab.b_active) { 86730519Ssam vm->um_tab.b_active = 0; 86830519Ssam vm->um_tab.b_actf = dp->b_forw; 86930519Ssam dp->b_active = 0; 87030519Ssam dp->b_errcnt = 0; 87130519Ssam dp->b_actf = bp->av_forw; 87230519Ssam bp->b_resid = 0; 87330601Skarels vbadone(bp, &vd->vd_rbuf); 87430519Ssam biodone(bp); 87530370Skarels /* 87630519Ssam * If this unit has more work to do, 87730519Ssam * then start it up right away. 87830370Skarels */ 87930519Ssam if (dp->b_actf) 88030519Ssam vdustart(vi); 88134528Skarels else if (dk->dk_openpart == 0) 88230573Skarels wakeup((caddr_t)dk); 88324004Ssam } 88425675Ssam /* 88530519Ssam * If there are devices ready to 88630519Ssam * transfer, start the controller. 88725675Ssam */ 888*35082Skarels if (vd->vd_flags & VD_WAIT) { 889*35082Skarels vd->vd_flags &= ~VD_WAIT; 890*35082Skarels wakeup((caddr_t)vd); 891*35082Skarels } else if (vm->um_tab.b_actf || vm->um_tab.b_seekf) 89230519Ssam vdstart(vm); 89324004Ssam } 89424004Ssam 89534396Skarels vdharderr(what, vd, bp, dcb) 89634396Skarels char *what; 89734396Skarels struct vdsoftc *vd; 89834396Skarels register struct buf *bp; 89934396Skarels register struct dcb *dcb; 90034396Skarels { 90134396Skarels int unit = vdunit(bp->b_dev), status = dcb->operrsta; 90234396Skarels register struct disklabel *lp = &dklabel[unit]; 90334528Skarels int blkdone; 90434396Skarels 90534396Skarels if (vd->vd_wticks < VDMAXTIME) 90634396Skarels status &= ~DONTCARE; 90734710Skarels blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) * 90834710Skarels lp->d_nsectors + dcb->err_sec - 90934710Skarels lp->d_partitions[vdpart(bp->b_dev)].p_offset) >> 91034710Skarels dksoftc[unit].dk_bshift) - bp->b_blkno; 91134528Skarels diskerr(bp, "dk", what, LOG_PRINTF, blkdone, lp); 91234528Skarels printf(", status %b", status, VDERRBITS); 91334396Skarels if (vd->vd_type == VDTYPE_SMDE) 91434396Skarels printf(" ecode %x", dcb->err_code); 91534396Skarels } 91634396Skarels 91734528Skarels vdsofterr(bp, dcb) 91825675Ssam register struct buf *bp; 91930519Ssam register struct dcb *dcb; 92025675Ssam { 92134562Skarels int unit = vdunit(bp->b_dev); 92234562Skarels struct disklabel *lp = &dklabel[unit]; 92334528Skarels int status = dcb->operrsta; 92434528Skarels int blkdone; 92525675Ssam 92634710Skarels blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) * 92734710Skarels lp->d_nsectors + dcb->err_sec - 92834710Skarels lp->d_partitions[vdpart(bp->b_dev)].p_offset) >> 92934710Skarels dksoftc[unit].dk_bshift) - bp->b_blkno; 93034528Skarels 93134528Skarels if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) { 93234528Skarels diskerr(bp, "dk", "soft error", LOG_WARNING, blkdone, lp); 93334528Skarels addlog(", status %b ecode %x\n", status, VDERRBITS, 93434396Skarels dcb->err_code); 93534528Skarels } else { 93634528Skarels diskerr(bp, "dk", "soft ecc", LOG_WARNING, blkdone, lp); 93734528Skarels addlog("\n"); 93834528Skarels } 93925675Ssam } 94025675Ssam 94130519Ssam vdioctl(dev, cmd, data, flag) 94225675Ssam dev_t dev; 94330519Ssam int cmd; 94430519Ssam caddr_t data; 94530519Ssam int flag; 94624004Ssam { 94732576Skarels register int unit = vdunit(dev); 94830519Ssam register struct disklabel *lp = &dklabel[unit]; 94934076Skarels register struct dksoftc *dk = &dksoftc[unit]; 95034640Skarels int error = 0, vdformat(); 95124004Ssam 95230519Ssam switch (cmd) { 95330519Ssam 95430519Ssam case DIOCGDINFO: 95530519Ssam *(struct disklabel *)data = *lp; 95630519Ssam break; 95730519Ssam 95830573Skarels case DIOCGPART: 95930573Skarels ((struct partinfo *)data)->disklab = lp; 96030573Skarels ((struct partinfo *)data)->part = 96130573Skarels &lp->d_partitions[vdpart(dev)]; 96230519Ssam break; 96330519Ssam 96430519Ssam case DIOCSDINFO: 96530519Ssam if ((flag & FWRITE) == 0) 96630519Ssam error = EBADF; 96730519Ssam else 96832576Skarels error = setdisklabel(lp, (struct disklabel *)data, 96934076Skarels (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart); 97034396Skarels if (error == 0 && dk->dk_state == OPENRAW && 97134396Skarels vdreset_drive(vddinfo[unit])) 97234076Skarels dk->dk_state = OPEN; 97330519Ssam break; 97430519Ssam 97534076Skarels case DIOCWLABEL: 97634076Skarels if ((flag & FWRITE) == 0) 97734076Skarels error = EBADF; 97834076Skarels else 97934076Skarels dk->dk_wlabel = *(int *)data; 98034076Skarels break; 98134076Skarels 98232576Skarels case DIOCWDINFO: 98332576Skarels if ((flag & FWRITE) == 0) 98430519Ssam error = EBADF; 98532576Skarels else if ((error = setdisklabel(lp, (struct disklabel *)data, 98634076Skarels (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) { 98734640Skarels int wlab; 98834640Skarels 98934076Skarels dk->dk_state = OPEN; 99034640Skarels /* simulate opening partition 0 so write succeeds */ 99134640Skarels dk->dk_openpart |= (1 << 0); /* XXX */ 99234640Skarels wlab = dk->dk_wlabel; 99334640Skarels dk->dk_wlabel = 1; 99432576Skarels error = writedisklabel(dev, vdstrategy, lp); 99534640Skarels dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart; 99634640Skarels dk->dk_wlabel = wlab; 99734076Skarels } 99830519Ssam break; 99930519Ssam 100034396Skarels case DIOCWFORMAT: 100134396Skarels { 100234396Skarels register struct format_op *fop; 100334396Skarels struct uio auio; 100434396Skarels struct iovec aiov; 100534396Skarels 100634396Skarels if ((flag & FWRITE) == 0) { 100734396Skarels error = EBADF; 100834396Skarels break; 100934396Skarels } 101034396Skarels fop = (struct format_op *)data; 101134396Skarels aiov.iov_base = fop->df_buf; 101234396Skarels aiov.iov_len = fop->df_count; 101334396Skarels auio.uio_iov = &aiov; 101434396Skarels auio.uio_iovcnt = 1; 101534396Skarels auio.uio_resid = fop->df_count; 101634396Skarels auio.uio_segflg = UIO_USERSPACE; 101734396Skarels auio.uio_offset = fop->df_startblk * lp->d_secsize; 101834396Skarels dk->dk_operrsta = fop->dk_operrsta; 101934396Skarels dk->dk_ecode = fop->dk_ecode; 102034396Skarels /* 102134396Skarels * Don't return errors, as the format op won't get copied 102234396Skarels * out if we return nonzero. Callers must check the returned 102334396Skarels * count. 102434396Skarels */ 102534396Skarels (void) physio(vdformat, (struct buf *)NULL, dev, 102634396Skarels (cmd == DIOCWFORMAT ? B_WRITE : B_READ), minphys, &auio); 102734396Skarels fop->df_count -= auio.uio_resid; 102834396Skarels fop->dk_operrsta = dk->dk_operrsta; 102934396Skarels fop->dk_ecode = dk->dk_ecode; 103034396Skarels break; 103134396Skarels } 103234396Skarels 103330519Ssam default: 103430519Ssam error = ENOTTY; 103530519Ssam break; 103624004Ssam } 103732606Skarels return (error); 103824004Ssam } 103924004Ssam 104034396Skarels vdformat(bp) 104134396Skarels struct buf *bp; 104234396Skarels { 104334396Skarels bp->b_flags |= B_FORMAT; 104434396Skarels vdstrategy(bp); 104534396Skarels } 104634396Skarels 104725675Ssam /* 104830519Ssam * Watch for lost interrupts. 104925675Ssam */ 105030519Ssam vdwatch() 105130519Ssam { 105230519Ssam register struct vdsoftc *vd; 105330519Ssam register struct vba_ctlr *vm; 105434528Skarels register int ctlr; 105534396Skarels int s; 105630519Ssam 105730519Ssam timeout(vdwatch, (caddr_t)0, hz); 105830519Ssam for (ctlr = 0; ctlr < NVD; ctlr++) { 105930519Ssam vm = vdminfo[ctlr]; 106030519Ssam if (vm == 0 || vm->um_alive == 0) 106130519Ssam continue; 106230519Ssam vd = &vdsoftc[ctlr]; 106334396Skarels s = spl7(); 106434396Skarels if (vm->um_tab.b_active && vd->vd_wticks++ >= VDMAXTIME) { 106530519Ssam printf("vd%d: lost interrupt\n", ctlr); 106634396Skarels #ifdef maybe 106734396Skarels VDABORT((struct vddevice *)vm->um_addr, vd->vd_type); 106834396Skarels #endif 106934396Skarels vdintr(ctlr); 107030519Ssam } 107134396Skarels splx(s); 107230519Ssam } 107330519Ssam } 107430519Ssam 107530519Ssam #define DBSIZE 64 /* controller limit with 1K sectors */ 107630519Ssam /* 107730519Ssam * Crash dump. 107830519Ssam */ 107930519Ssam vddump(dev) 108030519Ssam dev_t dev; 108124004Ssam { 108230519Ssam register struct vba_device *vi; 108330519Ssam register struct vba_ctlr *vm; 108430519Ssam register struct disklabel *lp; 108530519Ssam register struct vdsoftc *vd; 108630519Ssam struct dksoftc *dk; 108730519Ssam int part, unit, num; 108830601Skarels u_long start; 108924004Ssam 109030519Ssam start = 0; 109130519Ssam unit = vdunit(dev); 109230519Ssam if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 109330519Ssam return (ENXIO); 109430519Ssam dk = &dksoftc[unit]; 109534076Skarels if (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 109634076Skarels vdinit(vdminor(unit, 0), 0) != 0) 109730519Ssam return (ENXIO); 109830519Ssam lp = &dklabel[unit]; 109930519Ssam part = vdpart(dev); 110030519Ssam if (part >= lp->d_npartitions) 110130519Ssam return (ENXIO); 110232211Skarels vm = vi->ui_mi; 110330519Ssam vdreset_ctlr(vm); 110430519Ssam if (dumplo < 0) 110530519Ssam return (EINVAL); 110630519Ssam /* 110730756Skarels * Maxfree is in pages, dumplo is in DEV_BSIZE units. 110830519Ssam */ 110930519Ssam num = maxfree * (NBPG / lp->d_secsize); 111030756Skarels dumplo *= DEV_BSIZE / lp->d_secsize; 111130519Ssam if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size) 111230519Ssam num = lp->d_partitions[vdpart(dev)].p_size - dumplo; 111330519Ssam vd = &vdsoftc[vm->um_ctlr]; 111430519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 111530519Ssam vd->vd_dcb.opcode = VDOP_WD; 111632211Skarels vd->vd_dcb.devselect = dk->dk_dcb.devselect; 111730756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 111830519Ssam while (num > 0) { 111930519Ssam int nsec, cn, sn, tn; 112030519Ssam 112130519Ssam nsec = MIN(num, DBSIZE); 112230601Skarels sn = dumplo + start / lp->d_secsize; 112330519Ssam cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) / 112430519Ssam lp->d_secpercyl; 112530519Ssam sn %= lp->d_secpercyl; 112630519Ssam tn = sn / lp->d_nsectors; 112730519Ssam sn %= lp->d_nsectors; 112830519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 112930519Ssam vd->vd_dcb.trail.rwtrail.memadr = start; 113030519Ssam vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1; 113130519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = cn; 113230519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 113330519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 113430519Ssam vd->vd_dcb.operrsta = 0; 113530519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 113630519Ssam if (!vdpoll(vm, 5)) { 113730519Ssam printf(" during dump\n"); 113830519Ssam return (EIO); 113930519Ssam } 114030519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 114130519Ssam printf("dk%d: hard error, status=%b\n", unit, 114230519Ssam vd->vd_dcb.operrsta, VDERRBITS); 114330519Ssam return (EIO); 114430519Ssam } 114530519Ssam start += nsec * lp->d_secsize; 114630519Ssam num -= nsec; 114725675Ssam } 114830519Ssam return (0); 114924004Ssam } 115024004Ssam 115124004Ssam vdsize(dev) 115225675Ssam dev_t dev; 115324004Ssam { 115430519Ssam register int unit = vdunit(dev); 115530519Ssam register struct dksoftc *dk; 115630519Ssam struct vba_device *vi; 115730519Ssam struct disklabel *lp; 115824004Ssam 115930519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 || 116030519Ssam (dk = &dksoftc[unit])->dk_state != OPEN) 116125675Ssam return (-1); 116230519Ssam lp = &dklabel[unit]; 116330756Skarels #ifdef SECSIZE 116430573Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size); 116530756Skarels #else SECSIZE 116630756Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift); 116730756Skarels #endif SECSIZE 116824004Ssam } 116924004Ssam 117025675Ssam /* 117125675Ssam * Perform a controller reset. 117225675Ssam */ 117330519Ssam vdreset_ctlr(vm) 117430519Ssam register struct vba_ctlr *vm; 117524004Ssam { 117630519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 117730519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 117830519Ssam register int unit; 117930519Ssam struct vba_device *vi; 118025675Ssam 118130519Ssam VDRESET(vdaddr, vd->vd_type); 118230519Ssam if (vd->vd_type == VDTYPE_SMDE) { 118330519Ssam vdaddr->vdcsr = 0; 118430519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 118530519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 118630519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 118730519Ssam vdaddr->vdtcf_data = AM_ENPDA; 118830519Ssam vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD | 118925675Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 119025675Ssam } 119130519Ssam if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { 119230519Ssam printf("%s cmd failed\n", 119330519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 119430370Skarels return; 119525675Ssam } 119630519Ssam for (unit = 0; unit < NDK; unit++) 119730519Ssam if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive) 119830519Ssam (void) vdreset_drive(vi); 119930519Ssam } 120030519Ssam 120130519Ssam vdreset_drive(vi) 120230519Ssam register struct vba_device *vi; 120330519Ssam { 120430519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 120530519Ssam struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; 120630519Ssam struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 120732211Skarels register struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 120832211Skarels register struct dksoftc *dk = &dksoftc[vi->ui_unit]; 120930519Ssam 121030519Ssam top: 121130519Ssam vd->vd_dcb.opcode = VDOP_CONFIG; /* command */ 121230519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 121330519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 121430519Ssam vd->vd_dcb.operrsta = 0; 121532211Skarels vd->vd_dcb.devselect = vi->ui_slave | lp->d_devflags; 121630519Ssam vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders; 121730519Ssam vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks; 121830519Ssam if (vd->vd_type == VDTYPE_SMDE) { 121930756Skarels vd->vd_dcb.trailcnt = sizeof (struct treset) / sizeof (long); 122030519Ssam vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors; 122130601Skarels vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack; 122232211Skarels vd->vd_dcb.trail.rstrail.recovery = VDRF_NORMAL; 122330519Ssam } else 122430519Ssam vd->vd_dcb.trailcnt = 2; /* XXX */ 122530519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 122630519Ssam vd->vd_mdcb.mdcb_status = 0; 122730519Ssam VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type); 122830519Ssam if (!vdpoll(vm, 5)) { 122930519Ssam printf(" during config\n"); 123030519Ssam return (0); 123125675Ssam } 123230519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 123332211Skarels if (vd->vd_type == VDTYPE_SMDE) { 123432211Skarels if (lp->d_devflags == 0) { 123532211Skarels lp->d_devflags = VD_ESDI; 123632211Skarels goto top; 123732211Skarels } 123832211Skarels #ifdef notdef 123932211Skarels /* this doesn't work, STA_US isn't set(?) */ 124032211Skarels if ((vdaddr->vdstatus[vi->ui_slave] & STA_US) == 0) 124132211Skarels return (0); 124232211Skarels #endif 124332211Skarels } 124430519Ssam if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) 124532211Skarels printf("dk%d: config error %b ecode %x\n", vi->ui_unit, 124634396Skarels vd->vd_dcb.operrsta, VDERRBITS, 124734396Skarels (u_char) vd->vd_dcb.err_code); 124832211Skarels else if ((vd->vd_flags & VD_STARTED) == 0) { 124930519Ssam int started; 125030519Ssam 125132211Skarels printf(" starting drives, wait ... "); 125230519Ssam vd->vd_flags |= VD_STARTED; 125330519Ssam started = (vdcmd(vm, VDOP_START, 10) == 1); 125430519Ssam DELAY(62000000); 125532211Skarels printf("done"); 125632211Skarels lp->d_devflags = 0; 125730519Ssam if (started) 125830519Ssam goto top; 125930519Ssam } 126030519Ssam return (0); 126130519Ssam } 126232211Skarels dk->dk_dcb.devselect |= lp->d_devflags; 126330519Ssam return (1); 126425675Ssam } 126524004Ssam 126625675Ssam /* 126730519Ssam * Perform a command w/o trailer. 126825675Ssam */ 126930519Ssam vdcmd(vm, cmd, t) 127030519Ssam register struct vba_ctlr *vm; 127125675Ssam { 127230519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 127325675Ssam 127430519Ssam vd->vd_dcb.opcode = cmd; /* command */ 127530519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 127630519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 127730519Ssam vd->vd_dcb.operrsta = 0; 127830519Ssam vd->vd_dcb.devselect = 0; 127930519Ssam vd->vd_dcb.trailcnt = 0; 128030519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 128130519Ssam vd->vd_mdcb.mdcb_status = 0; 128230519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 128330519Ssam if (!vdpoll(vm, t)) { 128430519Ssam printf(" during init\n"); 128530370Skarels return (0); 128630370Skarels } 128730519Ssam return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0); 128825675Ssam } 128925675Ssam 129025925Ssam /* 129130519Ssam * Poll controller until operation 129230519Ssam * completes or timeout expires. 129325925Ssam */ 129430519Ssam vdpoll(vm, t) 129530519Ssam register struct vba_ctlr *vm; 129625925Ssam register int t; 129725925Ssam { 129830519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 129930519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 130025925Ssam 130125925Ssam t *= 1000; 130230370Skarels for (;;) { 130330519Ssam uncache(&vd->vd_dcb.operrsta); 130430519Ssam if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT)) 130530370Skarels break; 130625925Ssam if (--t <= 0) { 130730519Ssam printf("vd%d: controller timeout", vm->um_ctlr); 130830519Ssam VDABORT(vdaddr, vd->vd_type); 130925925Ssam return (0); 131025925Ssam } 131130370Skarels DELAY(1000); 131225925Ssam } 131330519Ssam if (vd->vd_type == VDTYPE_SMDE) { 131430519Ssam do { 131525925Ssam DELAY(50); 131630519Ssam uncache(&vdaddr->vdcsr); 131730519Ssam } while (vdaddr->vdcsr & CS_GO); 131832211Skarels DELAY(300); 131932211Skarels uncache(&vd->vd_dcb.err_code); 132025925Ssam } 132125925Ssam DELAY(200); 132230519Ssam uncache(&vd->vd_dcb.operrsta); 132325925Ssam return (1); 132425925Ssam } 132525925Ssam 132630519Ssam #ifdef COMPAT_42 132730519Ssam struct vdst { 132830519Ssam int nsec; /* sectors/track */ 132930519Ssam int ntrack; /* tracks/cylinder */ 133030519Ssam int ncyl; /* cylinders */ 133132211Skarels int secsize; /* sector size */ 133230519Ssam char *name; /* type name */ 133330519Ssam struct { 133430519Ssam int off; /* partition offset in sectors */ 133530519Ssam int size; /* partition size in sectors */ 133630573Skarels } parts[8]; 133730519Ssam } vdst[] = { 133832211Skarels { 66, 23, 850, 512, "NEC 800", 133932211Skarels {0, 1290300}, /* a cyl 0 - 849 */ 134032211Skarels }, 134134737Sbostic { 64, 20, 842, 512, "2361a", 134234737Sbostic {0, 61440}, /* a cyl 0 - 47 */ 134334737Sbostic {61440, 67840}, /* b cyl 48 - 100 */ 134434737Sbostic {129280, 942080}, /* c cyl 101 - 836 */ 134534737Sbostic {0, 1071360}, /* d cyl 0 - 836 */ 134634737Sbostic {449280, 311040}, /* e cyl 351 - 593 */ 134734737Sbostic {760320, 311040}, /* f cyl 594 - 836 */ 134834737Sbostic {449280, 622080}, /* g cyl 351 - 836 */ 134934737Sbostic {129280, 320000} /* h cyl 101 - 350 */ 135034737Sbostic }, 135132211Skarels { 48, 24, 711, 512, "xsd", 135231039Skarels {0, 61056}, /* a cyl 0 - 52 */ 135331039Skarels {61056, 61056}, /* b cyl 53 - 105 */ 135431039Skarels {122112, 691200}, /* c cyl 106 - 705 */ 135531039Skarels {237312, 576000}, /* d cyl 206 - 705 */ 135631039Skarels {352512, 460800}, /* e cyl 306 - 705 */ 135731039Skarels {467712, 345600}, /* f cyl 406 - 705 */ 135831039Skarels {582912, 230400}, /* g cyl 506 - 705 */ 135931039Skarels {698112, 115200} /* h cyl 606 - 705 */ 136030573Skarels }, 136132211Skarels { 44, 20, 842, 512, "eagle", 136230601Skarels {0, 52800}, /* egl0a cyl 0 - 59 */ 136330601Skarels {52800, 66000}, /* egl0b cyl 60 - 134 */ 136430601Skarels {118800, 617760}, /* egl0c cyl 135 - 836 */ 136530756Skarels {736560, 4400}, /* egl0d cyl 837 - 841 */ 136631039Skarels {0, 736560}, /* egl0e cyl 0 - 836 */ 136731039Skarels {0, 740960}, /* egl0f cyl 0 - 841 */ 136830601Skarels {118800, 310640}, /* egl0g cyl 135 - 487 */ 136930601Skarels {429440, 307120} /* egl0h cyl 488 - 836 */ 137030573Skarels }, 137132211Skarels { 64, 10, 823, 512, "fuj", 137231039Skarels {0, 38400}, /* fuj0a cyl 0 - 59 */ 137331039Skarels {38400, 48000}, /* fuj0b cyl 60 - 134 */ 137431039Skarels {86400, 437120}, /* fuj0c cyl 135 - 817 */ 137531039Skarels {159360, 364160}, /* fuj0d cyl 249 - 817 */ 137631039Skarels {232320, 291200}, /* fuj0e cyl 363 - 817 */ 137731039Skarels {305280, 218240}, /* fuj0f cyl 477 - 817 */ 137831039Skarels {378240, 145280}, /* fuj0g cyl 591 - 817 */ 137931039Skarels {451200, 72320} /* fug0h cyl 705 - 817 */ 138030573Skarels }, 138132211Skarels { 32, 24, 711, 512, "xfd", 138230756Skarels { 0, 40704 }, /* a cyl 0 - 52 */ 138330756Skarels { 40704, 40704 }, /* b cyl 53 - 105 */ 138430756Skarels { 81408, 460800 }, /* c cyl 106 - 705 */ 138530756Skarels { 0, 81408 }, /* d cyl 709 - 710 (a & b) */ 138630756Skarels { 0, 542208 }, /* e cyl 0 - 705 */ 138730756Skarels { 40704, 501504 }, /* f cyl 53 - 705 (b & c) */ 138830756Skarels { 81408, 230400 }, /* g cyl 106 - 405 (1/2 of c) */ 138930756Skarels { 311808,230400 } /* h cyl 406 - 705 (1/2 of c) */ 139030573Skarels }, 139132211Skarels { 32, 19, 823, 512, "smd", 139231039Skarels {0, 40128}, /* a cyl 0-65 */ 139331039Skarels {40128, 27360}, /* b cyl 66-110 */ 139431039Skarels {67488, 429856}, /* c cyl 111-817 */ 139531039Skarels {139232, 358112}, /* d cyl 229 - 817 */ 139631039Skarels {210976, 286368}, /* e cyl 347 - 817 */ 139731039Skarels {282720, 214624}, /* f cyl 465 - 817 */ 139831039Skarels {354464, 142880}, /* g cyl 583 - 817 */ 139931039Skarels {426208, 71136} /* h cyl 701 - 817 */ 140030573Skarels }, 140132211Skarels { 18, 15, 1224, 1024, "mxd", 140232211Skarels {0, 21600}, /* a cyl 0-79 */ 140332211Skarels {21600, 22410}, /* b cyl 80-162 */ 140432211Skarels {44010, 285120}, /* c cyl 163-1217 */ 140532211Skarels #ifdef notyet 140632211Skarels {x, 237600}, /* d cyl y - 1217 */ 140732211Skarels {x, 190080}, /* e cyl y - 1217 */ 140832211Skarels {x, 142560}, /* f cyl y - 1217 */ 140932211Skarels {x, 95040}, /* g cyl y - 1217 */ 141032211Skarels {x, 47520} /* h cyl 701 - 817 */ 141132211Skarels #endif 141232211Skarels }, 141332211Skarels { 32, 10, 823, 512, "fsd", 141430756Skarels {0, 19200}, /* a cyl 0 - 59 */ 141530756Skarels {19200, 24000}, /* b cyl 60 - 134 */ 141630756Skarels {43200, 218560}, /* c cyl 135 - 817 */ 141730573Skarels } 141830519Ssam }; 141930519Ssam #define NVDST (sizeof (vdst) / sizeof (vdst[0])) 142030519Ssam 142125675Ssam /* 142230519Ssam * Construct a label for an unlabeled pack. We 142330519Ssam * deduce the drive type by reading from the last 142430519Ssam * track on successively smaller drives until we 142530519Ssam * don't get an error. 142625675Ssam */ 142730519Ssam vdmaptype(vi, lp) 142830519Ssam register struct vba_device *vi; 142930519Ssam register struct disklabel *lp; 143025675Ssam { 143130519Ssam register struct vdsoftc *vd; 143230519Ssam register struct vdst *p; 143332211Skarels struct vba_ctlr *vm = vi->ui_mi; 143430519Ssam int i; 143525675Ssam 143630519Ssam vd = &vdsoftc[vi->ui_ctlr]; 143730519Ssam for (p = vdst; p < &vdst[NVDST]; p++) { 143830519Ssam if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32) 143930519Ssam continue; 144030519Ssam lp->d_nsectors = p->nsec; 144130519Ssam lp->d_ntracks = p->ntrack; 144230519Ssam lp->d_ncylinders = p->ncyl; 144332211Skarels lp->d_secsize = p->secsize; 144430519Ssam if (!vdreset_drive(vi)) 144530519Ssam return (0); 144630519Ssam vd->vd_dcb.opcode = VDOP_RD; 144730519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 144830519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 144932211Skarels vd->vd_dcb.devselect = dksoftc[vi->ui_unit].dk_dcb.devselect; 145030756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 145130601Skarels vd->vd_dcb.trail.rwtrail.memadr = 145230601Skarels vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf); 145332211Skarels vd->vd_dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof(short); 145430519Ssam vd->vd_dcb.operrsta = 0; 145530519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2; 145630519Ssam vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1; 145730519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1; 145830519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 145930519Ssam vd->vd_mdcb.mdcb_status = 0; 146030519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 146130519Ssam if (!vdpoll(vm, 60)) 146230519Ssam printf(" during probe\n"); 146330519Ssam if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0) 146430519Ssam break; 146524004Ssam } 146632211Skarels if (p >= &vdst[NVDST]) 146730519Ssam return (0); 146832211Skarels 146930573Skarels for (i = 0; i < 8; i++) { 147030519Ssam lp->d_partitions[i].p_offset = p->parts[i].off; 147130519Ssam lp->d_partitions[i].p_size = p->parts[i].size; 147230519Ssam } 147330573Skarels lp->d_npartitions = 8; 147430519Ssam lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 147530519Ssam lp->d_rpm = 3600; 147630519Ssam bcopy(p->name, lp->d_typename, 4); 147730519Ssam return (1); 147824004Ssam } 147930519Ssam #endif COMPAT_42 148024004Ssam #endif 1481