134528Skarels /* 234528Skarels * Copyright (c) 1988 Regents of the University of California. 334528Skarels * All rights reserved. 434528Skarels * 534528Skarels * Redistribution and use in source and binary forms are permitted 634528Skarels * provided that this notice is preserved and that due credit is given 734528Skarels * to the University of California at Berkeley. The name of the University 834528Skarels * may not be used to endorse or promote products derived from this 934528Skarels * software without specific prior written permission. This software 1034528Skarels * is provided ``as is'' without express or implied warranty. 1134528Skarels * 12*34710Skarels * @(#)vd.c 7.3 (Berkeley) 06/11/88 1334528Skarels */ 1424004Ssam 1529564Ssam #include "dk.h" 1624004Ssam #if NVD > 0 1724004Ssam /* 1830519Ssam * Versabus VDDC/SMDE driver. 1925675Ssam */ 2025675Ssam #include "param.h" 2125675Ssam #include "buf.h" 2225675Ssam #include "cmap.h" 2325675Ssam #include "conf.h" 2425675Ssam #include "dir.h" 2529564Ssam #include "dkstat.h" 2630519Ssam #include "disklabel.h" 2725675Ssam #include "map.h" 2830519Ssam #include "file.h" 2925675Ssam #include "systm.h" 3025675Ssam #include "user.h" 3125675Ssam #include "vmmac.h" 3225675Ssam #include "proc.h" 3325675Ssam #include "uio.h" 3430370Skarels #include "syslog.h" 3530370Skarels #include "kernel.h" 3630519Ssam #include "ioctl.h" 3730756Skarels #include "stat.h" 3824004Ssam 3929951Skarels #include "../tahoe/cpu.h" 4029951Skarels #include "../tahoe/mtpr.h" 4129951Skarels #include "../tahoe/pte.h" 4229951Skarels 4325675Ssam #include "../tahoevba/vbavar.h" 4425928Ssam #include "../tahoevba/vdreg.h" 4524004Ssam 4632211Skarels #ifndef COMPAT_42 4730519Ssam #define COMPAT_42 4832211Skarels #endif 4934396Skarels #define B_FORMAT B_XXX /* XXX */ 5030519Ssam 5130519Ssam #define vdunit(dev) (minor(dev) >> 3) 5230519Ssam #define vdpart(dev) (minor(dev) & 0x07) 5330519Ssam #define vdminor(unit,part) (((unit) << 3) | (part)) 5424004Ssam 5524004Ssam struct vba_ctlr *vdminfo[NVD]; 5629564Ssam struct vba_device *vddinfo[NDK]; 5730756Skarels int vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy(); 5834528Skarels long vdstd[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 }; 5925675Ssam struct vba_driver vddriver = 6034528Skarels { vdprobe, vdslave, vdattach, vddgo, vdstd, "dk", vddinfo, "vd", vdminfo }; 6124004Ssam 6224004Ssam /* 6330519Ssam * Per-controller state. 6430519Ssam */ 6530519Ssam struct vdsoftc { 6630519Ssam u_short vd_flags; 6730519Ssam #define VD_INIT 0x1 /* controller initialized */ 6830519Ssam #define VD_STARTED 0x2 /* start command issued */ 6930519Ssam #define VD_DOSEEKS 0x4 /* should overlap seeks */ 7030756Skarels #define VD_SCATGATH 0x8 /* can do scatter-gather commands (correctly) */ 7130519Ssam u_short vd_type; /* controller type */ 7230519Ssam u_short vd_wticks; /* timeout */ 7330519Ssam struct mdcb vd_mdcb; /* master command block */ 7430519Ssam u_long vd_mdcbphys; /* physical address of vd_mdcb */ 7530519Ssam struct dcb vd_dcb; /* i/o command block */ 7630519Ssam u_long vd_dcbphys; /* physical address of vd_dcb */ 7730601Skarels struct vb_buf vd_rbuf; /* vba resources */ 7830519Ssam } vdsoftc[NVD]; 7930519Ssam 8034396Skarels #define VDMAXTIME 20 /* max time for operation, sec. */ 8134396Skarels 8230519Ssam /* 8325675Ssam * Per-drive state. 8425675Ssam */ 8530519Ssam struct dksoftc { 8634076Skarels int dk_state; /* open fsm */ 8730756Skarels #ifndef SECSIZE 8830756Skarels u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */ 8930756Skarels #endif SECSIZE 9034076Skarels int dk_wlabel; /* label sector is currently writable */ 9132576Skarels u_long dk_copenpart; /* character units open on this drive */ 9232576Skarels u_long dk_bopenpart; /* block units open on this drive */ 9332576Skarels u_long dk_openpart; /* all units open on this drive */ 9430519Ssam u_int dk_curcyl; /* last selected cylinder */ 9530756Skarels struct skdcb dk_dcb; /* seek command block */ 9630519Ssam u_long dk_dcbphys; /* physical address of dk_dcb */ 9734396Skarels int df_reg[3]; /* for formatting, in-out parameters */ 9830519Ssam } dksoftc[NDK]; 9924004Ssam 10024004Ssam /* 10130519Ssam * Drive states. Used during steps of open/initialization. 10230519Ssam * States < OPEN (> 0) are transient, during an open operation. 10334076Skarels * OPENRAW is used for unlabeled disks, to allow format operations. 10425675Ssam */ 10530519Ssam #define CLOSED 0 /* disk is closed */ 10630519Ssam #define WANTOPEN 1 /* open requested, not started */ 10730519Ssam #define WANTOPENRAW 2 /* open requested, no label */ 10830519Ssam #define RDLABEL 3 /* reading pack label */ 10930519Ssam #define OPEN 4 /* intialized and ready */ 11030519Ssam #define OPENRAW 5 /* open, no label */ 11124004Ssam 11230519Ssam struct buf dkutab[NDK]; /* i/o queue headers */ 11330519Ssam struct disklabel dklabel[NDK]; /* pack labels */ 11424004Ssam 11530519Ssam #define b_cylin b_resid 11630574Skarels #define b_track b_error /* used for seek commands */ 11730574Skarels #define b_seekf b_forw /* second queue on um_tab */ 11830574Skarels #define b_seekl b_back /* second queue on um_tab */ 11930519Ssam 12030519Ssam int vdwstart, vdwatch(); 12130519Ssam 12224004Ssam /* 12325675Ssam * See if the controller is really there; if so, initialize it. 12425675Ssam */ 12525857Ssam vdprobe(reg, vm) 12625857Ssam caddr_t reg; 12725857Ssam struct vba_ctlr *vm; 12825675Ssam { 12925857Ssam register br, cvec; /* must be r12, r11 */ 13030519Ssam register struct vddevice *vdaddr = (struct vddevice *)reg; 13130519Ssam struct vdsoftc *vd; 13230573Skarels int s; 13325857Ssam 13430370Skarels #ifdef lint 13530370Skarels br = 0; cvec = br; br = cvec; 13630370Skarels vdintr(0); 13730370Skarels #endif 13825857Ssam if (badaddr((caddr_t)reg, 2)) 13925675Ssam return (0); 14030519Ssam vd = &vdsoftc[vm->um_ctlr]; 14130519Ssam vdaddr->vdreset = 0xffffffff; 14225675Ssam DELAY(1000000); 14330519Ssam if (vdaddr->vdreset != (unsigned)0xffffffff) { 14430519Ssam vd->vd_type = VDTYPE_VDDC; 14530519Ssam vd->vd_flags &= ~VD_DOSEEKS; 14625675Ssam DELAY(1000000); 14725675Ssam } else { 14830519Ssam vd->vd_type = VDTYPE_SMDE; 14930519Ssam vd->vd_flags |= VD_DOSEEKS; 15030519Ssam vdaddr->vdrstclr = 0; 15125675Ssam DELAY(3000000); 15230519Ssam vdaddr->vdcsr = 0; 15330519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 15430519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 15530519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 15630519Ssam vdaddr->vdtcf_data = AM_ENPDA; 15730519Ssam vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS | 15829921Skarels XMD_32BIT | BSZ_16WRD | 15925925Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 16025675Ssam } 16130519Ssam vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb); 16230519Ssam vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb); 16330519Ssam vm->um_addr = reg; /* XXX */ 16430573Skarels s = spl7(); 16530519Ssam if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { 16630519Ssam printf("vd%d: %s cmd failed\n", vm->um_ctlr, 16730519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 16830573Skarels splx(s); 16930519Ssam return (0); 17030519Ssam } 17130756Skarels if (vd->vd_type == VDTYPE_SMDE) { 17230756Skarels vd->vd_dcb.trail.idtrail.date = 0; 17330756Skarels if (vdcmd(vm, VDOP_IDENT, 10)) { 17430756Skarels uncache(&vd->vd_dcb.trail.idtrail.date); 17530756Skarels if (vd->vd_dcb.trail.idtrail.date != 0) 17630756Skarels vd->vd_flags |= VD_SCATGATH; 17730756Skarels } 17830756Skarels } 17930573Skarels splx(s); 18025925Ssam /* 18125950Ssam * Allocate page tables and i/o buffer. 18225925Ssam */ 18332211Skarels if (vbainit(&vd->vd_rbuf, MAXPHYS, 18432211Skarels vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT) == 0) { 18532211Skarels printf("vd%d: vbainit failed\n", vm->um_ctlr); 18632211Skarels return (0); 18732211Skarels } 18825857Ssam br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */ 18930519Ssam return (sizeof (struct vddevice)); 19025675Ssam } 19124004Ssam 19224004Ssam /* 19330519Ssam * See if a drive is really there. 19430519Ssam * 19530519Ssam * Can't read pack label here as various data structures 19630519Ssam * aren't setup for doing a read in a straightforward 19730519Ssam * manner. Instead just probe for the drive and leave 19830519Ssam * the pack label stuff to the attach routine. 19925675Ssam */ 20034076Skarels /* ARGSUSED */ 20134076Skarels vdslave(vi, vdaddr) 20225675Ssam register struct vba_device *vi; 20330519Ssam struct vddevice *vdaddr; 20425675Ssam { 20530519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 20632211Skarels register struct dksoftc *dk = &dksoftc[vi->ui_unit]; 20730519Ssam struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 20824004Ssam 20930519Ssam if ((vd->vd_flags&VD_INIT) == 0) { 21030756Skarels printf("vd%d: %s controller%s\n", vi->ui_ctlr, 21130756Skarels vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE", 21230756Skarels (vd->vd_flags & VD_SCATGATH) ? " with scatter-gather" : ""); 21330519Ssam vd->vd_flags |= VD_INIT; 21425675Ssam } 21530519Ssam 21625675Ssam /* 21730519Ssam * Initialize label enough to do a reset on 21830519Ssam * the drive. The remainder of the default 21930519Ssam * label values will be filled in in vdinit 22030519Ssam * at attach time. 22125675Ssam */ 22232211Skarels if (vd->vd_type == VDTYPE_SMDE) 22332211Skarels lp->d_secsize = VD_MAXSECSIZE; 22432211Skarels else 22532211Skarels lp->d_secsize = VDDC_SECSIZE; 22634396Skarels lp->d_nsectors = 66; /* only used on smd-e */ 22734076Skarels lp->d_ntracks = 23; 22834396Skarels lp->d_ncylinders = 850; 22934396Skarels lp->d_secpercyl = 66*23; 23034592Skarels lp->d_npartitions = 1; 23134592Skarels lp->d_partitions[0].p_offset = 0; 23234592Skarels lp->d_partitions[0].p_size = LABELSECTOR + 1; 23324004Ssam 23430519Ssam /* 23530519Ssam * Initialize invariant portion of 23630519Ssam * dcb used for overlapped seeks. 23730519Ssam */ 23830519Ssam dk->dk_dcb.opcode = VDOP_SEEK; 23930519Ssam dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA; 24030519Ssam dk->dk_dcb.devselect = vi->ui_slave; 24130756Skarels dk->dk_dcb.trailcnt = sizeof (struct trseek) / sizeof (long); 24230519Ssam dk->dk_dcb.trail.sktrail.skaddr.sector = 0; 24330519Ssam dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb); 24432211Skarels #ifndef SECSIZE 24532211Skarels vd_setsecsize(dk, lp); 24632211Skarels #endif 24732211Skarels return (vdreset_drive(vi)); 24832211Skarels } 24932211Skarels 25032211Skarels vdattach(vi) 25132211Skarels register struct vba_device *vi; 25232211Skarels { 25332211Skarels register int unit = vi->ui_unit; 25432211Skarels register struct disklabel *lp = &dklabel[unit]; 25532211Skarels 25630601Skarels /* 25730601Skarels * Try to initialize device and read pack label. 25830601Skarels */ 25930601Skarels if (vdinit(vdminor(unit, 0), 0) != 0) { 26030601Skarels printf(": unknown drive type"); 26130601Skarels return; 26230601Skarels } 26332211Skarels if (dksoftc[unit].dk_state == OPEN) 26432211Skarels printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>", 26532211Skarels lp->d_typename, lp->d_secsize, 26632211Skarels lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors); 26730519Ssam /* 26830519Ssam * (60 / rpm) / (sectors per track * (bytes per sector / 2)) 26930519Ssam */ 27030519Ssam if (vi->ui_dk >= 0) 27130519Ssam dk_mspw[vi->ui_dk] = 120.0 / 27230519Ssam (lp->d_rpm * lp->d_nsectors * lp->d_secsize); 27330519Ssam #ifdef notyet 27430573Skarels addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp); 27530519Ssam #endif 27624004Ssam } 27724004Ssam 27830756Skarels vdopen(dev, flags, fmt) 27930519Ssam dev_t dev; 28030756Skarels int flags, fmt; 28124004Ssam { 28230519Ssam register unit = vdunit(dev); 28330519Ssam register struct disklabel *lp; 28430519Ssam register struct dksoftc *dk; 28530519Ssam register struct partition *pp; 28630519Ssam struct vba_device *vi; 28730756Skarels int s, error, part = vdpart(dev), mask = 1 << part; 28830519Ssam daddr_t start, end; 28924004Ssam 29030519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 29130519Ssam return (ENXIO); 29230519Ssam lp = &dklabel[unit]; 29330519Ssam dk = &dksoftc[unit]; 29430519Ssam 29530519Ssam s = spl7(); 29630519Ssam while (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 29730519Ssam dk->dk_state != CLOSED) 29830519Ssam sleep((caddr_t)dk, PZERO+1); 29930519Ssam splx(s); 30030519Ssam if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 30130519Ssam if (error = vdinit(dev, flags)) 30230519Ssam return (error); 30330573Skarels 30430573Skarels if (vdwstart == 0) { 30530573Skarels timeout(vdwatch, (caddr_t)0, hz); 30630573Skarels vdwstart++; 30730573Skarels } 30830519Ssam /* 30930519Ssam * Warn if a partion is opened 31030519Ssam * that overlaps another partition which is open 31130519Ssam * unless one is the "raw" partition (whole disk). 31230519Ssam */ 31332211Skarels #define RAWPART 8 /* 'x' partition */ /* XXX */ 31432576Skarels if ((dk->dk_openpart & mask) == 0 && part != RAWPART) { 31530519Ssam pp = &lp->d_partitions[part]; 31630519Ssam start = pp->p_offset; 31730519Ssam end = pp->p_offset + pp->p_size; 31830519Ssam for (pp = lp->d_partitions; 31930519Ssam pp < &lp->d_partitions[lp->d_npartitions]; pp++) { 32030519Ssam if (pp->p_offset + pp->p_size <= start || 32130519Ssam pp->p_offset >= end) 32230519Ssam continue; 32330519Ssam if (pp - lp->d_partitions == RAWPART) 32430519Ssam continue; 32530519Ssam if (dk->dk_openpart & (1 << (pp - lp->d_partitions))) 32630519Ssam log(LOG_WARNING, 32730519Ssam "dk%d%c: overlaps open partition (%c)\n", 32830519Ssam unit, part + 'a', 32930519Ssam pp - lp->d_partitions + 'a'); 33030519Ssam } 33124004Ssam } 33230519Ssam if (part >= lp->d_npartitions) 33330519Ssam return (ENXIO); 33430756Skarels dk->dk_openpart |= mask; 33530756Skarels switch (fmt) { 33630756Skarels case S_IFCHR: 33730756Skarels dk->dk_copenpart |= mask; 33830756Skarels break; 33930756Skarels case S_IFBLK: 34030756Skarels dk->dk_bopenpart |= mask; 34130756Skarels break; 34230756Skarels } 34330519Ssam return (0); 34425675Ssam } 34524004Ssam 34634528Skarels /* ARGSUSED */ 34730756Skarels vdclose(dev, flags, fmt) 34830519Ssam dev_t dev; 34930756Skarels int flags, fmt; 35024004Ssam { 35130519Ssam register int unit = vdunit(dev); 35230519Ssam register struct dksoftc *dk = &dksoftc[unit]; 35330756Skarels int part = vdpart(dev), mask = 1 << part; 35424004Ssam 35530756Skarels switch (fmt) { 35630756Skarels case S_IFCHR: 35730756Skarels dk->dk_copenpart &= ~mask; 35830756Skarels break; 35930756Skarels case S_IFBLK: 36030756Skarels dk->dk_bopenpart &= ~mask; 36130756Skarels break; 36230756Skarels } 36330756Skarels if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0) 36430756Skarels dk->dk_openpart &= ~mask; 36530519Ssam /* 36630519Ssam * Should wait for i/o to complete on this partition 36730519Ssam * even if others are open, but wait for work on blkflush(). 36830519Ssam */ 36930519Ssam if (dk->dk_openpart == 0) { 37030573Skarels int s = spl7(); 37130573Skarels while (dkutab[unit].b_actf) 37230573Skarels sleep((caddr_t)dk, PZERO-1); 37330519Ssam splx(s); 37430519Ssam dk->dk_state = CLOSED; 37534076Skarels dk->dk_wlabel = 0; 37624004Ssam } 37730756Skarels return (0); 37825675Ssam } 37924004Ssam 38030519Ssam vdinit(dev, flags) 38130519Ssam dev_t dev; 38230519Ssam int flags; 38325675Ssam { 38430519Ssam register struct disklabel *lp; 38530519Ssam register struct dksoftc *dk; 38630519Ssam struct vba_device *vi; 38730519Ssam int unit = vdunit(dev), error = 0; 38830756Skarels char *msg, *readdisklabel(); 38930519Ssam extern int cold; 39025675Ssam 39130519Ssam dk = &dksoftc[unit]; 39230519Ssam if (flags & O_NDELAY) { 39330519Ssam dk->dk_state = OPENRAW; 39434528Skarels return (0); 39530519Ssam } 39630519Ssam dk->dk_state = RDLABEL; 39730519Ssam lp = &dklabel[unit]; 39830519Ssam vi = vddinfo[unit]; 39930756Skarels if (msg = readdisklabel(dev, vdstrategy, lp)) { 40034076Skarels if (cold) { 40130601Skarels printf(": %s", msg); 40234076Skarels dk->dk_state = CLOSED; 40334076Skarels } else { 40432211Skarels log(LOG_ERR, "dk%d: %s\n", unit, msg); 40534076Skarels dk->dk_state = OPENRAW; 40634076Skarels } 40730519Ssam #ifdef COMPAT_42 40834076Skarels if (vdmaptype(vi, lp)) 40930519Ssam dk->dk_state = OPEN; 41030519Ssam #endif 41130756Skarels } else { 41230756Skarels /* 41330756Skarels * Now that we have the label, configure 41430756Skarels * the correct drive parameters. 41530756Skarels */ 41632211Skarels if (vdreset_drive(vi)) 41732211Skarels dk->dk_state = OPEN; 41832211Skarels else { 41930756Skarels dk->dk_state = CLOSED; 42030756Skarels error = ENXIO; 42132211Skarels } 42225675Ssam } 42330756Skarels #ifndef SECSIZE 42432211Skarels vd_setsecsize(dk, lp); 42532211Skarels #endif 42630519Ssam wakeup((caddr_t)dk); 42730519Ssam return (error); 42824004Ssam } 42924004Ssam 43032211Skarels #ifndef SECSIZE 43132211Skarels vd_setsecsize(dk, lp) 43232211Skarels register struct dksoftc *dk; 43332211Skarels register struct disklabel *lp; 43432211Skarels { 43532211Skarels int mul; 43632211Skarels 43732211Skarels /* 43832211Skarels * Calculate scaling shift for mapping 43932211Skarels * DEV_BSIZE blocks to drive sectors. 44032211Skarels */ 44132211Skarels mul = DEV_BSIZE / lp->d_secsize; 44232211Skarels dk->dk_bshift = 0; 44332211Skarels while ((mul >>= 1) > 0) 44432211Skarels dk->dk_bshift++; 44532211Skarels } 44632211Skarels #endif SECSIZE 44732211Skarels 44825675Ssam /*ARGSUSED*/ 44930519Ssam vddgo(vm) 45030519Ssam struct vba_device *vm; 45124004Ssam { 45224004Ssam 45324004Ssam } 45424004Ssam 45524004Ssam vdstrategy(bp) 45625675Ssam register struct buf *bp; 45724004Ssam { 45830519Ssam register struct vba_device *vi; 45930519Ssam register struct disklabel *lp; 46030519Ssam register struct dksoftc *dk; 46130519Ssam register int unit; 46230573Skarels register daddr_t sn; 46330519Ssam struct buf *dp; 46430573Skarels daddr_t sz, maxsz; 46530519Ssam int part, s; 46624004Ssam 46730519Ssam unit = vdunit(bp->b_dev); 46832211Skarels if (unit >= NDK) { 46929954Skarels bp->b_error = ENXIO; 47025675Ssam goto bad; 47129954Skarels } 47230519Ssam vi = vddinfo[unit]; 47330519Ssam lp = &dklabel[unit]; 47430519Ssam if (vi == 0 || vi->ui_alive == 0) { 47530519Ssam bp->b_error = ENXIO; 47630519Ssam goto bad; 47730519Ssam } 47830519Ssam dk = &dksoftc[unit]; 47930519Ssam if (dk->dk_state < OPEN) 48030519Ssam goto q; 48134076Skarels if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) { 48234076Skarels bp->b_error = EROFS; 48334076Skarels goto bad; 48434076Skarels } 48530519Ssam part = vdpart(bp->b_dev); 48630519Ssam if ((dk->dk_openpart & (1 << part)) == 0) { 48730519Ssam bp->b_error = ENODEV; 48830519Ssam goto bad; 48930519Ssam } 49032211Skarels sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize; 49130519Ssam maxsz = lp->d_partitions[part].p_size; 49230756Skarels #ifndef SECSIZE 49330756Skarels sn = bp->b_blkno << dk->dk_bshift; 49430756Skarels #else SECSIZE 49530573Skarels sn = bp->b_blkno; 49630756Skarels #endif SECSIZE 49734076Skarels if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR && 49834076Skarels #if LABELSECTOR != 0 49934076Skarels sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR && 50034076Skarels #endif 50134076Skarels (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) { 50234076Skarels bp->b_error = EROFS; 50334076Skarels goto bad; 50434076Skarels } 50530519Ssam if (sn < 0 || sn + sz > maxsz) { 50630519Ssam if (sn == maxsz) { 50729954Skarels bp->b_resid = bp->b_bcount; 50829954Skarels goto done; 50929954Skarels } 51030756Skarels sz = maxsz - sn; 51130573Skarels if (sz <= 0) { 51230573Skarels bp->b_error = EINVAL; 51330573Skarels goto bad; 51430573Skarels } 51530573Skarels bp->b_bcount = sz * lp->d_secsize; 51625675Ssam } 51730519Ssam bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl; 51830756Skarels #ifdef SECSIZE 51930756Skarels if (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0) 52030756Skarels panic("vdstrat blksize"); 52130756Skarels #endif SECSIZE 52230519Ssam q: 52325675Ssam s = spl7(); 52430519Ssam dp = &dkutab[vi->ui_unit]; 52530519Ssam disksort(dp, bp); 52630519Ssam if (!dp->b_active) { 52730519Ssam (void) vdustart(vi); 52830573Skarels if (!vi->ui_mi->um_tab.b_active) 52930519Ssam vdstart(vi->ui_mi); 53024004Ssam } 53130519Ssam splx(s); 53224004Ssam return; 53325675Ssam bad: 53429954Skarels bp->b_flags |= B_ERROR; 53529954Skarels done: 53630519Ssam biodone(bp); 53730519Ssam return; 53824004Ssam } 53924004Ssam 54030519Ssam vdustart(vi) 54130519Ssam register struct vba_device *vi; 54224004Ssam { 54330519Ssam register struct buf *bp, *dp; 54430519Ssam register struct vba_ctlr *vm; 54530519Ssam register int unit = vi->ui_unit; 54630519Ssam register struct dksoftc *dk; 54730519Ssam register struct vdsoftc *vd; 54830519Ssam struct disklabel *lp; 54924004Ssam 55030519Ssam dp = &dkutab[unit]; 55130519Ssam /* 55230519Ssam * If queue empty, nothing to do. 55330519Ssam */ 55430519Ssam if ((bp = dp->b_actf) == NULL) 55530519Ssam return; 55630519Ssam /* 55730574Skarels * If drive is off-cylinder and controller supports seeks, 55830574Skarels * place drive on seek queue for controller. 55930574Skarels * Otherwise, place on transfer queue. 56030519Ssam */ 56130519Ssam vd = &vdsoftc[vi->ui_ctlr]; 56230519Ssam dk = &dksoftc[unit]; 56330574Skarels vm = vi->ui_mi; 56430519Ssam if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) { 56530519Ssam lp = &dklabel[unit]; 56630574Skarels bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors; 56730574Skarels if (vm->um_tab.b_seekf == NULL) 56830574Skarels vm->um_tab.b_seekf = dp; 56930574Skarels else 57030574Skarels vm->um_tab.b_seekl->b_forw = dp; 57130574Skarels vm->um_tab.b_seekl = dp; 57230574Skarels } else { 57330574Skarels if (vm->um_tab.b_actf == NULL) 57430574Skarels vm->um_tab.b_actf = dp; 57530574Skarels else 57630574Skarels vm->um_tab.b_actl->b_forw = dp; 57730574Skarels vm->um_tab.b_actl = dp; 57830519Ssam } 57930573Skarels dp->b_forw = NULL; 58030573Skarels dp->b_active++; 58125675Ssam } 58225675Ssam 58325675Ssam /* 58430519Ssam * Start next transfer on a controller. 58530574Skarels * There are two queues of drives, the first on-cylinder 58630574Skarels * and the second off-cylinder from their next transfers. 58730574Skarels * Perform the first transfer for the first drive on the on-cylinder 58830574Skarels * queue, if any, otherwise the first transfer for the first drive 58930574Skarels * on the second queue. Initiate seeks on remaining drives on the 59030574Skarels * off-cylinder queue, then move them all to the on-cylinder queue. 59125675Ssam */ 59230519Ssam vdstart(vm) 59330519Ssam register struct vba_ctlr *vm; 59425675Ssam { 59525675Ssam register struct buf *bp; 59630519Ssam register struct vba_device *vi; 59730519Ssam register struct vdsoftc *vd; 59830519Ssam register struct dksoftc *dk; 59930519Ssam register struct disklabel *lp; 60030519Ssam register struct dcb **dcbp; 60130519Ssam struct buf *dp; 60230519Ssam int sn, tn; 60325675Ssam 60430519Ssam loop: 60530519Ssam /* 60630519Ssam * Pull a request off the controller queue. 60730519Ssam */ 60830574Skarels if ((dp = vm->um_tab.b_actf) == NULL && 60930574Skarels (dp = vm->um_tab.b_seekf) == NULL) 61030519Ssam return; 61130519Ssam if ((bp = dp->b_actf) == NULL) { 61230601Skarels if (dp == vm->um_tab.b_actf) 61330601Skarels vm->um_tab.b_actf = dp->b_forw; 61430601Skarels else 61530601Skarels vm->um_tab.b_seekf = dp->b_forw; 61630519Ssam goto loop; 61730519Ssam } 61825675Ssam 61924004Ssam /* 62030519Ssam * Mark controller busy, and determine 62130519Ssam * destination of this request. 62224004Ssam */ 62330519Ssam vm->um_tab.b_active++; 62430519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 62530519Ssam dk = &dksoftc[vi->ui_unit]; 62630756Skarels #ifndef SECSIZE 62730756Skarels sn = bp->b_blkno << dk->dk_bshift; 62830756Skarels #else SECSIZE 62930573Skarels sn = bp->b_blkno; 63030756Skarels #endif SECSIZE 63130519Ssam lp = &dklabel[vi->ui_unit]; 63230519Ssam sn %= lp->d_secpercyl; 63330519Ssam tn = sn / lp->d_nsectors; 63430519Ssam sn %= lp->d_nsectors; 63530519Ssam 63630519Ssam /* 63730519Ssam * Construct dcb for read/write command. 63830519Ssam */ 63930519Ssam vd = &vdsoftc[vm->um_ctlr]; 64030519Ssam vd->vd_dcb.intflg = DCBINT_DONE; 64132211Skarels vd->vd_dcb.devselect = dk->dk_dcb.devselect; 64230519Ssam vd->vd_dcb.operrsta = 0; 64330519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 64430519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin; 64530519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 64630519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 64730574Skarels dk->dk_curcyl = bp->b_cylin; 64830574Skarels bp->b_track = 0; /* init overloaded field */ 64930756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 65034396Skarels if (bp->b_flags & B_FORMAT) 65134396Skarels vd->vd_dcb.opcode = dk->dk_op; 65234396Skarels else if (vd->vd_flags & VD_SCATGATH && 65334396Skarels ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0) 65430756Skarels vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW; 65534396Skarels else 65630756Skarels vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD; 65734396Skarels 65834396Skarels switch (vd->vd_dcb.opcode) { 65934396Skarels case VDOP_FSECT: 66034396Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 66134396Skarels vd->vd_dcb.trail.fmtrail.nsectors = bp->b_bcount / 66234396Skarels lp->d_secsize; 66334396Skarels vd->vd_dcb.trail.fmtrail.hdr = *(dskadr *)&dk->dk_althdr; 66434396Skarels vd->vd_dcb.trail.rwtrail.disk.cylinder |= dk->dk_fmtflags; 66534396Skarels goto setupaddr; 66634396Skarels 66734396Skarels case VDOP_RDRAW: 66834396Skarels case VDOP_RD: 66934396Skarels case VDOP_WD: 67034396Skarels vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1; 67134396Skarels setupaddr: 67230756Skarels vd->vd_dcb.trail.rwtrail.memadr = 67334528Skarels vbasetup(bp, &vd->vd_rbuf, (int)lp->d_secsize); 67434396Skarels break; 67534396Skarels 67634396Skarels case VDOP_RAS: 67734396Skarels case VDOP_GAW: 67834396Skarels vd->vd_dcb.trailcnt += vba_sgsetup(bp, &vd->vd_rbuf, 67934396Skarels &vd->vd_dcb.trail.sgtrail); 68034396Skarels break; 68130756Skarels } 68230574Skarels if (vi->ui_dk >= 0) { 68330574Skarels dk_busy |= 1<<vi->ui_dk; 68430574Skarels dk_xfer[vi->ui_dk]++; 68530574Skarels dk_wds[vi->ui_dk] += bp->b_bcount>>6; 68630574Skarels } 68730519Ssam 68830519Ssam /* 68930519Ssam * Look for any seeks to be performed on other drives on this 69030519Ssam * controller. If overlapped seeks exist, insert seek commands 69130519Ssam * on the controller's command queue before the transfer. 69230519Ssam */ 69330519Ssam dcbp = &vd->vd_mdcb.mdcb_head; 69430519Ssam 69530574Skarels if (dp == vm->um_tab.b_seekf) 69630574Skarels dp = dp->b_forw; 69730574Skarels else 69830574Skarels dp = vm->um_tab.b_seekf; 69930574Skarels for (; dp != NULL; dp = dp->b_forw) { 70030574Skarels if ((bp = dp->b_actf) == NULL) 70130574Skarels continue; 70230574Skarels vi = vddinfo[vdunit(bp->b_dev)]; 70330574Skarels dk = &dksoftc[vi->ui_unit]; 70430519Ssam dk->dk_curcyl = bp->b_cylin; 70530574Skarels if (vi->ui_dk >= 0) 70630574Skarels dk_seek[vi->ui_dk]++; 70730574Skarels dk->dk_dcb.operrsta = 0; 70830574Skarels dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin; 70930574Skarels dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track; 71030574Skarels *dcbp = (struct dcb *)dk->dk_dcbphys; 71130574Skarels dcbp = &dk->dk_dcb.nxtdcb; 71224004Ssam } 71330519Ssam *dcbp = (struct dcb *)vd->vd_dcbphys; 71430574Skarels if (vm->um_tab.b_actf) 71530574Skarels vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf; 71630574Skarels else 71730574Skarels vm->um_tab.b_actf = vm->um_tab.b_seekf; 71830601Skarels if (vm->um_tab.b_seekf) 71930601Skarels vm->um_tab.b_actl = vm->um_tab.b_seekl; 72030574Skarels vm->um_tab.b_seekf = 0; 72124004Ssam 72230519Ssam /* 72330519Ssam * Initiate operation. 72430519Ssam */ 72530519Ssam vd->vd_mdcb.mdcb_status = 0; 72630519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 72724004Ssam } 72824004Ssam 72930519Ssam #define DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE) 73024004Ssam /* 73124004Ssam * Handle a disk interrupt. 73224004Ssam */ 73325675Ssam vdintr(ctlr) 73430519Ssam register ctlr; 73524004Ssam { 73630519Ssam register struct buf *bp, *dp; 73730519Ssam register struct vba_ctlr *vm = vdminfo[ctlr]; 73830519Ssam register struct vba_device *vi; 73930519Ssam register struct vdsoftc *vd = &vdsoftc[ctlr]; 74030519Ssam register status; 74134528Skarels int timedout; 74230573Skarels struct dksoftc *dk; 74324004Ssam 74430519Ssam if (!vm->um_tab.b_active) { 74525675Ssam printf("vd%d: stray interrupt\n", ctlr); 74624004Ssam return; 74724004Ssam } 74825675Ssam /* 74930519Ssam * Get device and block structures, and a pointer 75030519Ssam * to the vba_device for the drive. 75125675Ssam */ 75230519Ssam dp = vm->um_tab.b_actf; 75330519Ssam bp = dp->b_actf; 75430519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 75534528Skarels dk = &dksoftc[vi->ui_unit]; 75630574Skarels if (vi->ui_dk >= 0) 75730574Skarels dk_busy &= ~(1<<vi->ui_dk); 75834396Skarels timedout = (vd->vd_wticks >= VDMAXTIME); 75930519Ssam /* 76030519Ssam * Check for and process errors on 76130519Ssam * either the drive or the controller. 76230519Ssam */ 76330519Ssam uncache(&vd->vd_dcb.operrsta); 76430519Ssam status = vd->vd_dcb.operrsta; 76534396Skarels if (bp->b_flags & B_FORMAT) { 76634396Skarels dk->dk_operrsta = status; 76734396Skarels uncache(&vd->vd_dcb.err_code); 76834396Skarels dk->dk_ecode = vd->vd_dcb.err_code; 76934396Skarels } 77034396Skarels if (status & VDERR_HARD || timedout) { 77134528Skarels if (vd->vd_type == VDTYPE_SMDE) 77230601Skarels uncache(&vd->vd_dcb.err_code); 77330519Ssam if (status & DCBS_WPT) { 77430519Ssam /* 77530519Ssam * Give up on write locked devices immediately. 77630519Ssam */ 77730573Skarels printf("dk%d: write locked\n", vi->ui_unit); 77830519Ssam bp->b_flags |= B_ERROR; 77934396Skarels } else if (status & VDERR_RETRY || timedout) { 78032211Skarels int endline = 1; 78132211Skarels 78234396Skarels if (status & VDERR_CTLR || timedout) { 78334396Skarels vdharderr("controller err", 78434396Skarels vd, bp, &vd->vd_dcb); 78534396Skarels printf("; resetting controller..."); 78634396Skarels vdreset_ctlr(vm); 78734396Skarels } else if (status & VDERR_DRIVE) { 78834396Skarels vdharderr("drive err", vd, bp, &vd->vd_dcb); 78934396Skarels printf("; resetting drive..."); 79030519Ssam if (!vdreset_drive(vi)) 79130519Ssam vi->ui_alive = 0; 79232211Skarels } else 79332211Skarels endline = 0; 79430519Ssam /* 79530519Ssam * Retry transfer once, unless reset failed. 79630519Ssam */ 79734396Skarels if (!vi->ui_alive || dp->b_errcnt++ >= 2 || 79834396Skarels bp->b_flags & B_FORMAT) { 79932211Skarels if (endline) 80032211Skarels printf("\n"); 80130519Ssam goto hard; 80232211Skarels } 80332211Skarels 80432211Skarels if (endline) 80532211Skarels printf(" retrying\n"); 80630519Ssam vm->um_tab.b_active = 0; /* force retry */ 80730519Ssam } else { 80830519Ssam hard: 80930519Ssam bp->b_flags |= B_ERROR; 81034396Skarels vdharderr("hard error", vd, bp, &vd->vd_dcb); 81130519Ssam printf("\n"); 81230519Ssam } 81330519Ssam } else if (status & DCBS_SOFT) 81434528Skarels vdsofterr(bp, &vd->vd_dcb); 81534396Skarels vd->vd_wticks = 0; 81630519Ssam if (vm->um_tab.b_active) { 81730519Ssam vm->um_tab.b_active = 0; 81830519Ssam vm->um_tab.b_actf = dp->b_forw; 81930519Ssam dp->b_active = 0; 82030519Ssam dp->b_errcnt = 0; 82130519Ssam dp->b_actf = bp->av_forw; 82230519Ssam bp->b_resid = 0; 82330601Skarels vbadone(bp, &vd->vd_rbuf); 82430519Ssam biodone(bp); 82530370Skarels /* 82630519Ssam * If this unit has more work to do, 82730519Ssam * then start it up right away. 82830370Skarels */ 82930519Ssam if (dp->b_actf) 83030519Ssam vdustart(vi); 83134528Skarels else if (dk->dk_openpart == 0) 83230573Skarels wakeup((caddr_t)dk); 83324004Ssam } 83425675Ssam /* 83530519Ssam * If there are devices ready to 83630519Ssam * transfer, start the controller. 83725675Ssam */ 83830601Skarels if (vm->um_tab.b_actf || vm->um_tab.b_seekf) 83930519Ssam vdstart(vm); 84024004Ssam } 84124004Ssam 84234396Skarels vdharderr(what, vd, bp, dcb) 84334396Skarels char *what; 84434396Skarels struct vdsoftc *vd; 84534396Skarels register struct buf *bp; 84634396Skarels register struct dcb *dcb; 84734396Skarels { 84834396Skarels int unit = vdunit(bp->b_dev), status = dcb->operrsta; 84934396Skarels register struct disklabel *lp = &dklabel[unit]; 85034528Skarels int blkdone; 85134396Skarels 85234396Skarels if (vd->vd_wticks < VDMAXTIME) 85334396Skarels status &= ~DONTCARE; 854*34710Skarels blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) * 855*34710Skarels lp->d_nsectors + dcb->err_sec - 856*34710Skarels lp->d_partitions[vdpart(bp->b_dev)].p_offset) >> 857*34710Skarels dksoftc[unit].dk_bshift) - bp->b_blkno; 85834528Skarels diskerr(bp, "dk", what, LOG_PRINTF, blkdone, lp); 85934528Skarels printf(", status %b", status, VDERRBITS); 86034396Skarels if (vd->vd_type == VDTYPE_SMDE) 86134396Skarels printf(" ecode %x", dcb->err_code); 86234396Skarels } 86334396Skarels 86434528Skarels vdsofterr(bp, dcb) 86525675Ssam register struct buf *bp; 86630519Ssam register struct dcb *dcb; 86725675Ssam { 86834562Skarels int unit = vdunit(bp->b_dev); 86934562Skarels struct disklabel *lp = &dklabel[unit]; 87034528Skarels int status = dcb->operrsta; 87134528Skarels int blkdone; 87225675Ssam 873*34710Skarels blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) * 874*34710Skarels lp->d_nsectors + dcb->err_sec - 875*34710Skarels lp->d_partitions[vdpart(bp->b_dev)].p_offset) >> 876*34710Skarels dksoftc[unit].dk_bshift) - bp->b_blkno; 87734528Skarels 87834528Skarels if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) { 87934528Skarels diskerr(bp, "dk", "soft error", LOG_WARNING, blkdone, lp); 88034528Skarels addlog(", status %b ecode %x\n", status, VDERRBITS, 88134396Skarels dcb->err_code); 88234528Skarels } else { 88334528Skarels diskerr(bp, "dk", "soft ecc", LOG_WARNING, blkdone, lp); 88434528Skarels addlog("\n"); 88534528Skarels } 88625675Ssam } 88725675Ssam 88830519Ssam vdioctl(dev, cmd, data, flag) 88925675Ssam dev_t dev; 89030519Ssam int cmd; 89130519Ssam caddr_t data; 89230519Ssam int flag; 89324004Ssam { 89432576Skarels register int unit = vdunit(dev); 89530519Ssam register struct disklabel *lp = &dklabel[unit]; 89634076Skarels register struct dksoftc *dk = &dksoftc[unit]; 89734640Skarels int error = 0, vdformat(); 89824004Ssam 89930519Ssam switch (cmd) { 90030519Ssam 90130519Ssam case DIOCGDINFO: 90230519Ssam *(struct disklabel *)data = *lp; 90330519Ssam break; 90430519Ssam 90530573Skarels case DIOCGPART: 90630573Skarels ((struct partinfo *)data)->disklab = lp; 90730573Skarels ((struct partinfo *)data)->part = 90830573Skarels &lp->d_partitions[vdpart(dev)]; 90930519Ssam break; 91030519Ssam 91130519Ssam case DIOCSDINFO: 91230519Ssam if ((flag & FWRITE) == 0) 91330519Ssam error = EBADF; 91430519Ssam else 91532576Skarels error = setdisklabel(lp, (struct disklabel *)data, 91634076Skarels (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart); 91734396Skarels if (error == 0 && dk->dk_state == OPENRAW && 91834396Skarels vdreset_drive(vddinfo[unit])) 91934076Skarels dk->dk_state = OPEN; 92030519Ssam break; 92130519Ssam 92234076Skarels case DIOCWLABEL: 92334076Skarels if ((flag & FWRITE) == 0) 92434076Skarels error = EBADF; 92534076Skarels else 92634076Skarels dk->dk_wlabel = *(int *)data; 92734076Skarels break; 92834076Skarels 92932576Skarels case DIOCWDINFO: 93032576Skarels if ((flag & FWRITE) == 0) 93130519Ssam error = EBADF; 93232576Skarels else if ((error = setdisklabel(lp, (struct disklabel *)data, 93334076Skarels (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) { 93434640Skarels int wlab; 93534640Skarels 93634076Skarels dk->dk_state = OPEN; 93734640Skarels /* simulate opening partition 0 so write succeeds */ 93834640Skarels dk->dk_openpart |= (1 << 0); /* XXX */ 93934640Skarels wlab = dk->dk_wlabel; 94034640Skarels dk->dk_wlabel = 1; 94132576Skarels error = writedisklabel(dev, vdstrategy, lp); 94234640Skarels dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart; 94334640Skarels dk->dk_wlabel = wlab; 94434076Skarels } 94530519Ssam break; 94630519Ssam 94734396Skarels case DIOCWFORMAT: 94834396Skarels { 94934396Skarels register struct format_op *fop; 95034396Skarels struct uio auio; 95134396Skarels struct iovec aiov; 95234396Skarels 95334396Skarels if ((flag & FWRITE) == 0) { 95434396Skarels error = EBADF; 95534396Skarels break; 95634396Skarels } 95734396Skarels fop = (struct format_op *)data; 95834396Skarels aiov.iov_base = fop->df_buf; 95934396Skarels aiov.iov_len = fop->df_count; 96034396Skarels auio.uio_iov = &aiov; 96134396Skarels auio.uio_iovcnt = 1; 96234396Skarels auio.uio_resid = fop->df_count; 96334396Skarels auio.uio_segflg = UIO_USERSPACE; 96434396Skarels auio.uio_offset = fop->df_startblk * lp->d_secsize; 96534396Skarels dk->dk_operrsta = fop->dk_operrsta; 96634396Skarels dk->dk_ecode = fop->dk_ecode; 96734396Skarels /* 96834396Skarels * Don't return errors, as the format op won't get copied 96934396Skarels * out if we return nonzero. Callers must check the returned 97034396Skarels * count. 97134396Skarels */ 97234396Skarels (void) physio(vdformat, (struct buf *)NULL, dev, 97334396Skarels (cmd == DIOCWFORMAT ? B_WRITE : B_READ), minphys, &auio); 97434396Skarels fop->df_count -= auio.uio_resid; 97534396Skarels fop->dk_operrsta = dk->dk_operrsta; 97634396Skarels fop->dk_ecode = dk->dk_ecode; 97734396Skarels break; 97834396Skarels } 97934396Skarels 98030519Ssam default: 98130519Ssam error = ENOTTY; 98230519Ssam break; 98324004Ssam } 98432606Skarels return (error); 98524004Ssam } 98624004Ssam 98734396Skarels vdformat(bp) 98834396Skarels struct buf *bp; 98934396Skarels { 99034396Skarels bp->b_flags |= B_FORMAT; 99134396Skarels vdstrategy(bp); 99234396Skarels } 99334396Skarels 99425675Ssam /* 99530519Ssam * Watch for lost interrupts. 99625675Ssam */ 99730519Ssam vdwatch() 99830519Ssam { 99930519Ssam register struct vdsoftc *vd; 100030519Ssam register struct vba_ctlr *vm; 100134528Skarels register int ctlr; 100234396Skarels int s; 100330519Ssam 100430519Ssam timeout(vdwatch, (caddr_t)0, hz); 100530519Ssam for (ctlr = 0; ctlr < NVD; ctlr++) { 100630519Ssam vm = vdminfo[ctlr]; 100730519Ssam if (vm == 0 || vm->um_alive == 0) 100830519Ssam continue; 100930519Ssam vd = &vdsoftc[ctlr]; 101034396Skarels s = spl7(); 101134396Skarels if (vm->um_tab.b_active && vd->vd_wticks++ >= VDMAXTIME) { 101230519Ssam printf("vd%d: lost interrupt\n", ctlr); 101334396Skarels #ifdef maybe 101434396Skarels VDABORT((struct vddevice *)vm->um_addr, vd->vd_type); 101534396Skarels #endif 101634396Skarels vdintr(ctlr); 101730519Ssam } 101834396Skarels splx(s); 101930519Ssam } 102030519Ssam } 102130519Ssam 102230519Ssam #define DBSIZE 64 /* controller limit with 1K sectors */ 102330519Ssam /* 102430519Ssam * Crash dump. 102530519Ssam */ 102630519Ssam vddump(dev) 102730519Ssam dev_t dev; 102824004Ssam { 102930519Ssam register struct vba_device *vi; 103030519Ssam register struct vba_ctlr *vm; 103130519Ssam register struct disklabel *lp; 103230519Ssam register struct vdsoftc *vd; 103330519Ssam struct dksoftc *dk; 103430519Ssam int part, unit, num; 103530601Skarels u_long start; 103624004Ssam 103730519Ssam start = 0; 103830519Ssam unit = vdunit(dev); 103930519Ssam if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 104030519Ssam return (ENXIO); 104130519Ssam dk = &dksoftc[unit]; 104234076Skarels if (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 104334076Skarels vdinit(vdminor(unit, 0), 0) != 0) 104430519Ssam return (ENXIO); 104530519Ssam lp = &dklabel[unit]; 104630519Ssam part = vdpart(dev); 104730519Ssam if (part >= lp->d_npartitions) 104830519Ssam return (ENXIO); 104932211Skarels vm = vi->ui_mi; 105030519Ssam vdreset_ctlr(vm); 105130519Ssam if (dumplo < 0) 105230519Ssam return (EINVAL); 105330519Ssam /* 105430756Skarels * Maxfree is in pages, dumplo is in DEV_BSIZE units. 105530519Ssam */ 105630519Ssam num = maxfree * (NBPG / lp->d_secsize); 105730756Skarels dumplo *= DEV_BSIZE / lp->d_secsize; 105830519Ssam if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size) 105930519Ssam num = lp->d_partitions[vdpart(dev)].p_size - dumplo; 106030519Ssam vd = &vdsoftc[vm->um_ctlr]; 106130519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 106230519Ssam vd->vd_dcb.opcode = VDOP_WD; 106332211Skarels vd->vd_dcb.devselect = dk->dk_dcb.devselect; 106430756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 106530519Ssam while (num > 0) { 106630519Ssam int nsec, cn, sn, tn; 106730519Ssam 106830519Ssam nsec = MIN(num, DBSIZE); 106930601Skarels sn = dumplo + start / lp->d_secsize; 107030519Ssam cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) / 107130519Ssam lp->d_secpercyl; 107230519Ssam sn %= lp->d_secpercyl; 107330519Ssam tn = sn / lp->d_nsectors; 107430519Ssam sn %= lp->d_nsectors; 107530519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 107630519Ssam vd->vd_dcb.trail.rwtrail.memadr = start; 107730519Ssam vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1; 107830519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = cn; 107930519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 108030519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 108130519Ssam vd->vd_dcb.operrsta = 0; 108230519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 108330519Ssam if (!vdpoll(vm, 5)) { 108430519Ssam printf(" during dump\n"); 108530519Ssam return (EIO); 108630519Ssam } 108730519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 108830519Ssam printf("dk%d: hard error, status=%b\n", unit, 108930519Ssam vd->vd_dcb.operrsta, VDERRBITS); 109030519Ssam return (EIO); 109130519Ssam } 109230519Ssam start += nsec * lp->d_secsize; 109330519Ssam num -= nsec; 109425675Ssam } 109530519Ssam return (0); 109624004Ssam } 109724004Ssam 109824004Ssam vdsize(dev) 109925675Ssam dev_t dev; 110024004Ssam { 110130519Ssam register int unit = vdunit(dev); 110230519Ssam register struct dksoftc *dk; 110330519Ssam struct vba_device *vi; 110430519Ssam struct disklabel *lp; 110524004Ssam 110630519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 || 110730519Ssam (dk = &dksoftc[unit])->dk_state != OPEN) 110825675Ssam return (-1); 110930519Ssam lp = &dklabel[unit]; 111030756Skarels #ifdef SECSIZE 111130573Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size); 111230756Skarels #else SECSIZE 111330756Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift); 111430756Skarels #endif SECSIZE 111524004Ssam } 111624004Ssam 111725675Ssam /* 111825675Ssam * Perform a controller reset. 111925675Ssam */ 112030519Ssam vdreset_ctlr(vm) 112130519Ssam register struct vba_ctlr *vm; 112224004Ssam { 112330519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 112430519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 112530519Ssam register int unit; 112630519Ssam struct vba_device *vi; 112725675Ssam 112830519Ssam VDRESET(vdaddr, vd->vd_type); 112930519Ssam if (vd->vd_type == VDTYPE_SMDE) { 113030519Ssam vdaddr->vdcsr = 0; 113130519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 113230519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 113330519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 113430519Ssam vdaddr->vdtcf_data = AM_ENPDA; 113530519Ssam vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD | 113625675Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 113725675Ssam } 113830519Ssam if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { 113930519Ssam printf("%s cmd failed\n", 114030519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 114130370Skarels return; 114225675Ssam } 114330519Ssam for (unit = 0; unit < NDK; unit++) 114430519Ssam if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive) 114530519Ssam (void) vdreset_drive(vi); 114630519Ssam } 114730519Ssam 114830519Ssam vdreset_drive(vi) 114930519Ssam register struct vba_device *vi; 115030519Ssam { 115130519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 115230519Ssam struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; 115330519Ssam struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 115432211Skarels register struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 115532211Skarels register struct dksoftc *dk = &dksoftc[vi->ui_unit]; 115630519Ssam 115730519Ssam top: 115830519Ssam vd->vd_dcb.opcode = VDOP_CONFIG; /* command */ 115930519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 116030519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 116130519Ssam vd->vd_dcb.operrsta = 0; 116232211Skarels vd->vd_dcb.devselect = vi->ui_slave | lp->d_devflags; 116330519Ssam vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders; 116430519Ssam vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks; 116530519Ssam if (vd->vd_type == VDTYPE_SMDE) { 116630756Skarels vd->vd_dcb.trailcnt = sizeof (struct treset) / sizeof (long); 116730519Ssam vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors; 116830601Skarels vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack; 116932211Skarels vd->vd_dcb.trail.rstrail.recovery = VDRF_NORMAL; 117030519Ssam } else 117130519Ssam vd->vd_dcb.trailcnt = 2; /* XXX */ 117230519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 117330519Ssam vd->vd_mdcb.mdcb_status = 0; 117430519Ssam VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type); 117530519Ssam if (!vdpoll(vm, 5)) { 117630519Ssam printf(" during config\n"); 117730519Ssam return (0); 117825675Ssam } 117930519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 118032211Skarels if (vd->vd_type == VDTYPE_SMDE) { 118132211Skarels if (lp->d_devflags == 0) { 118232211Skarels lp->d_devflags = VD_ESDI; 118332211Skarels goto top; 118432211Skarels } 118532211Skarels #ifdef notdef 118632211Skarels /* this doesn't work, STA_US isn't set(?) */ 118732211Skarels if ((vdaddr->vdstatus[vi->ui_slave] & STA_US) == 0) 118832211Skarels return (0); 118932211Skarels #endif 119032211Skarels } 119130519Ssam if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) 119232211Skarels printf("dk%d: config error %b ecode %x\n", vi->ui_unit, 119334396Skarels vd->vd_dcb.operrsta, VDERRBITS, 119434396Skarels (u_char) vd->vd_dcb.err_code); 119532211Skarels else if ((vd->vd_flags & VD_STARTED) == 0) { 119630519Ssam int started; 119730519Ssam 119832211Skarels printf(" starting drives, wait ... "); 119930519Ssam vd->vd_flags |= VD_STARTED; 120030519Ssam started = (vdcmd(vm, VDOP_START, 10) == 1); 120130519Ssam DELAY(62000000); 120232211Skarels printf("done"); 120332211Skarels lp->d_devflags = 0; 120430519Ssam if (started) 120530519Ssam goto top; 120630519Ssam } 120730519Ssam return (0); 120830519Ssam } 120932211Skarels dk->dk_dcb.devselect |= lp->d_devflags; 121030519Ssam return (1); 121125675Ssam } 121224004Ssam 121325675Ssam /* 121430519Ssam * Perform a command w/o trailer. 121525675Ssam */ 121630519Ssam vdcmd(vm, cmd, t) 121730519Ssam register struct vba_ctlr *vm; 121825675Ssam { 121930519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 122025675Ssam 122130519Ssam vd->vd_dcb.opcode = cmd; /* command */ 122230519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 122330519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 122430519Ssam vd->vd_dcb.operrsta = 0; 122530519Ssam vd->vd_dcb.devselect = 0; 122630519Ssam vd->vd_dcb.trailcnt = 0; 122730519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 122830519Ssam vd->vd_mdcb.mdcb_status = 0; 122930519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 123030519Ssam if (!vdpoll(vm, t)) { 123130519Ssam printf(" during init\n"); 123230370Skarels return (0); 123330370Skarels } 123430519Ssam return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0); 123525675Ssam } 123625675Ssam 123725925Ssam /* 123830519Ssam * Poll controller until operation 123930519Ssam * completes or timeout expires. 124025925Ssam */ 124130519Ssam vdpoll(vm, t) 124230519Ssam register struct vba_ctlr *vm; 124325925Ssam register int t; 124425925Ssam { 124530519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 124630519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 124725925Ssam 124825925Ssam t *= 1000; 124930370Skarels for (;;) { 125030519Ssam uncache(&vd->vd_dcb.operrsta); 125130519Ssam if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT)) 125230370Skarels break; 125325925Ssam if (--t <= 0) { 125430519Ssam printf("vd%d: controller timeout", vm->um_ctlr); 125530519Ssam VDABORT(vdaddr, vd->vd_type); 125625925Ssam return (0); 125725925Ssam } 125830370Skarels DELAY(1000); 125925925Ssam } 126030519Ssam if (vd->vd_type == VDTYPE_SMDE) { 126130519Ssam do { 126225925Ssam DELAY(50); 126330519Ssam uncache(&vdaddr->vdcsr); 126430519Ssam } while (vdaddr->vdcsr & CS_GO); 126532211Skarels DELAY(300); 126632211Skarels uncache(&vd->vd_dcb.err_code); 126725925Ssam } 126825925Ssam DELAY(200); 126930519Ssam uncache(&vd->vd_dcb.operrsta); 127025925Ssam return (1); 127125925Ssam } 127225925Ssam 127330519Ssam #ifdef COMPAT_42 127430519Ssam struct vdst { 127530519Ssam int nsec; /* sectors/track */ 127630519Ssam int ntrack; /* tracks/cylinder */ 127730519Ssam int ncyl; /* cylinders */ 127832211Skarels int secsize; /* sector size */ 127930519Ssam char *name; /* type name */ 128030519Ssam struct { 128130519Ssam int off; /* partition offset in sectors */ 128230519Ssam int size; /* partition size in sectors */ 128330573Skarels } parts[8]; 128430519Ssam } vdst[] = { 128532211Skarels { 66, 23, 850, 512, "NEC 800", 128632211Skarels {0, 1290300}, /* a cyl 0 - 849 */ 128732211Skarels }, 128832211Skarels { 48, 24, 711, 512, "xsd", 128931039Skarels {0, 61056}, /* a cyl 0 - 52 */ 129031039Skarels {61056, 61056}, /* b cyl 53 - 105 */ 129131039Skarels {122112, 691200}, /* c cyl 106 - 705 */ 129231039Skarels {237312, 576000}, /* d cyl 206 - 705 */ 129331039Skarels {352512, 460800}, /* e cyl 306 - 705 */ 129431039Skarels {467712, 345600}, /* f cyl 406 - 705 */ 129531039Skarels {582912, 230400}, /* g cyl 506 - 705 */ 129631039Skarels {698112, 115200} /* h cyl 606 - 705 */ 129730573Skarels }, 129832211Skarels { 44, 20, 842, 512, "eagle", 129930601Skarels {0, 52800}, /* egl0a cyl 0 - 59 */ 130030601Skarels {52800, 66000}, /* egl0b cyl 60 - 134 */ 130130601Skarels {118800, 617760}, /* egl0c cyl 135 - 836 */ 130230756Skarels {736560, 4400}, /* egl0d cyl 837 - 841 */ 130331039Skarels {0, 736560}, /* egl0e cyl 0 - 836 */ 130431039Skarels {0, 740960}, /* egl0f cyl 0 - 841 */ 130530601Skarels {118800, 310640}, /* egl0g cyl 135 - 487 */ 130630601Skarels {429440, 307120} /* egl0h cyl 488 - 836 */ 130730573Skarels }, 130832211Skarels { 64, 10, 823, 512, "fuj", 130931039Skarels {0, 38400}, /* fuj0a cyl 0 - 59 */ 131031039Skarels {38400, 48000}, /* fuj0b cyl 60 - 134 */ 131131039Skarels {86400, 437120}, /* fuj0c cyl 135 - 817 */ 131231039Skarels {159360, 364160}, /* fuj0d cyl 249 - 817 */ 131331039Skarels {232320, 291200}, /* fuj0e cyl 363 - 817 */ 131431039Skarels {305280, 218240}, /* fuj0f cyl 477 - 817 */ 131531039Skarels {378240, 145280}, /* fuj0g cyl 591 - 817 */ 131631039Skarels {451200, 72320} /* fug0h cyl 705 - 817 */ 131730573Skarels }, 131832211Skarels { 32, 24, 711, 512, "xfd", 131930756Skarels { 0, 40704 }, /* a cyl 0 - 52 */ 132030756Skarels { 40704, 40704 }, /* b cyl 53 - 105 */ 132130756Skarels { 81408, 460800 }, /* c cyl 106 - 705 */ 132230756Skarels { 0, 81408 }, /* d cyl 709 - 710 (a & b) */ 132330756Skarels { 0, 542208 }, /* e cyl 0 - 705 */ 132430756Skarels { 40704, 501504 }, /* f cyl 53 - 705 (b & c) */ 132530756Skarels { 81408, 230400 }, /* g cyl 106 - 405 (1/2 of c) */ 132630756Skarels { 311808,230400 } /* h cyl 406 - 705 (1/2 of c) */ 132730573Skarels }, 132832211Skarels { 32, 19, 823, 512, "smd", 132931039Skarels {0, 40128}, /* a cyl 0-65 */ 133031039Skarels {40128, 27360}, /* b cyl 66-110 */ 133131039Skarels {67488, 429856}, /* c cyl 111-817 */ 133231039Skarels {139232, 358112}, /* d cyl 229 - 817 */ 133331039Skarels {210976, 286368}, /* e cyl 347 - 817 */ 133431039Skarels {282720, 214624}, /* f cyl 465 - 817 */ 133531039Skarels {354464, 142880}, /* g cyl 583 - 817 */ 133631039Skarels {426208, 71136} /* h cyl 701 - 817 */ 133730573Skarels }, 133832211Skarels { 18, 15, 1224, 1024, "mxd", 133932211Skarels {0, 21600}, /* a cyl 0-79 */ 134032211Skarels {21600, 22410}, /* b cyl 80-162 */ 134132211Skarels {44010, 285120}, /* c cyl 163-1217 */ 134232211Skarels #ifdef notyet 134332211Skarels {x, 237600}, /* d cyl y - 1217 */ 134432211Skarels {x, 190080}, /* e cyl y - 1217 */ 134532211Skarels {x, 142560}, /* f cyl y - 1217 */ 134632211Skarels {x, 95040}, /* g cyl y - 1217 */ 134732211Skarels {x, 47520} /* h cyl 701 - 817 */ 134832211Skarels #endif 134932211Skarels }, 135032211Skarels { 32, 10, 823, 512, "fsd", 135130756Skarels {0, 19200}, /* a cyl 0 - 59 */ 135230756Skarels {19200, 24000}, /* b cyl 60 - 134 */ 135330756Skarels {43200, 218560}, /* c cyl 135 - 817 */ 135430573Skarels } 135530519Ssam }; 135630519Ssam #define NVDST (sizeof (vdst) / sizeof (vdst[0])) 135730519Ssam 135825675Ssam /* 135930519Ssam * Construct a label for an unlabeled pack. We 136030519Ssam * deduce the drive type by reading from the last 136130519Ssam * track on successively smaller drives until we 136230519Ssam * don't get an error. 136325675Ssam */ 136430519Ssam vdmaptype(vi, lp) 136530519Ssam register struct vba_device *vi; 136630519Ssam register struct disklabel *lp; 136725675Ssam { 136830519Ssam register struct vdsoftc *vd; 136930519Ssam register struct vdst *p; 137032211Skarels struct vba_ctlr *vm = vi->ui_mi; 137130519Ssam int i; 137225675Ssam 137330519Ssam vd = &vdsoftc[vi->ui_ctlr]; 137430519Ssam for (p = vdst; p < &vdst[NVDST]; p++) { 137530519Ssam if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32) 137630519Ssam continue; 137730519Ssam lp->d_nsectors = p->nsec; 137830519Ssam lp->d_ntracks = p->ntrack; 137930519Ssam lp->d_ncylinders = p->ncyl; 138032211Skarels lp->d_secsize = p->secsize; 138130519Ssam if (!vdreset_drive(vi)) 138230519Ssam return (0); 138330519Ssam vd->vd_dcb.opcode = VDOP_RD; 138430519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 138530519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 138632211Skarels vd->vd_dcb.devselect = dksoftc[vi->ui_unit].dk_dcb.devselect; 138730756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 138830601Skarels vd->vd_dcb.trail.rwtrail.memadr = 138930601Skarels vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf); 139032211Skarels vd->vd_dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof(short); 139130519Ssam vd->vd_dcb.operrsta = 0; 139230519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2; 139330519Ssam vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1; 139430519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1; 139530519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 139630519Ssam vd->vd_mdcb.mdcb_status = 0; 139730519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 139830519Ssam if (!vdpoll(vm, 60)) 139930519Ssam printf(" during probe\n"); 140030519Ssam if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0) 140130519Ssam break; 140224004Ssam } 140332211Skarels if (p >= &vdst[NVDST]) 140430519Ssam return (0); 140532211Skarels 140630573Skarels for (i = 0; i < 8; i++) { 140730519Ssam lp->d_partitions[i].p_offset = p->parts[i].off; 140830519Ssam lp->d_partitions[i].p_size = p->parts[i].size; 140930519Ssam } 141030573Skarels lp->d_npartitions = 8; 141130519Ssam lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 141230519Ssam lp->d_rpm = 3600; 141330519Ssam bcopy(p->name, lp->d_typename, 4); 141430519Ssam return (1); 141524004Ssam } 141630519Ssam #endif COMPAT_42 141724004Ssam #endif 1418