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*35413Skarels * @(#)vd.c 7.8 (Berkeley) 08/27/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) */ 7935082Skarels #define VD_LOCKED 0x10 /* locked for direct controller access */ 8035082Skarels #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; 167*35413Skarels vdaddr->vdccf = CCF_SEN | CCF_DIU | 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(); 175*35413Skarels if (!vdcmd(vm, VDOP_INIT, 10, 0) || !vdcmd(vm, VDOP_DIAG, 10, 0)) { 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; 183*35413Skarels if (vdcmd(vm, VDOP_IDENT, 10, 0)) { 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) { 220*35413Skarels printf("vd%d: %s controller", vi->ui_ctlr, 221*35413Skarels vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE"); 222*35413Skarels if (vd->vd_flags & VD_SCATGATH) { 223*35413Skarels char rev[5]; 224*35413Skarels 225*35413Skarels bcopy((caddr_t)&vd->vd_dcb.trail.idtrail.rev, rev, 226*35413Skarels sizeof(vd->vd_dcb.trail.idtrail.rev)); 227*35413Skarels printf(" firmware rev %s (%d-%d-%d)", rev, 228*35413Skarels (vd->vd_dcb.trail.idtrail.date >> 8) & 0xff, 229*35413Skarels vd->vd_dcb.trail.idtrail.date & 0xff, 230*35413Skarels (vd->vd_dcb.trail.idtrail.date >> 16) & 0xffff); 231*35413Skarels } 232*35413Skarels printf("\n"); 23330519Ssam vd->vd_flags |= VD_INIT; 23425675Ssam } 23530519Ssam 23625675Ssam /* 23730519Ssam * Initialize label enough to do a reset on 23830519Ssam * the drive. The remainder of the default 23930519Ssam * label values will be filled in in vdinit 24030519Ssam * at attach time. 24125675Ssam */ 24232211Skarels if (vd->vd_type == VDTYPE_SMDE) 24332211Skarels lp->d_secsize = VD_MAXSECSIZE; 24432211Skarels else 24532211Skarels lp->d_secsize = VDDC_SECSIZE; 24634396Skarels lp->d_nsectors = 66; /* only used on smd-e */ 24734076Skarels lp->d_ntracks = 23; 24834396Skarels lp->d_ncylinders = 850; 24934396Skarels lp->d_secpercyl = 66*23; 250*35413Skarels lp->d_rpm = 3600; 25134592Skarels lp->d_npartitions = 1; 25234592Skarels lp->d_partitions[0].p_offset = 0; 25334592Skarels lp->d_partitions[0].p_size = LABELSECTOR + 1; 25424004Ssam 25530519Ssam /* 25630519Ssam * Initialize invariant portion of 25730519Ssam * dcb used for overlapped seeks. 25830519Ssam */ 25930519Ssam dk->dk_dcb.opcode = VDOP_SEEK; 26030519Ssam dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA; 26130519Ssam dk->dk_dcb.devselect = vi->ui_slave; 26230756Skarels dk->dk_dcb.trailcnt = sizeof (struct trseek) / sizeof (long); 26330519Ssam dk->dk_dcb.trail.sktrail.skaddr.sector = 0; 26430519Ssam dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb); 26532211Skarels #ifndef SECSIZE 26632211Skarels vd_setsecsize(dk, lp); 26732211Skarels #endif 26832211Skarels return (vdreset_drive(vi)); 26932211Skarels } 27032211Skarels 27132211Skarels vdattach(vi) 27232211Skarels register struct vba_device *vi; 27332211Skarels { 27432211Skarels register int unit = vi->ui_unit; 27532211Skarels register struct disklabel *lp = &dklabel[unit]; 27632211Skarels 27730601Skarels /* 27830601Skarels * Try to initialize device and read pack label. 27930601Skarels */ 28030601Skarels if (vdinit(vdminor(unit, 0), 0) != 0) { 28130601Skarels printf(": unknown drive type"); 28230601Skarels return; 28330601Skarels } 28432211Skarels if (dksoftc[unit].dk_state == OPEN) 28532211Skarels printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>", 28632211Skarels lp->d_typename, lp->d_secsize, 28732211Skarels lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors); 28830519Ssam /* 28930519Ssam * (60 / rpm) / (sectors per track * (bytes per sector / 2)) 29030519Ssam */ 29130519Ssam if (vi->ui_dk >= 0) 29230519Ssam dk_mspw[vi->ui_dk] = 120.0 / 29330519Ssam (lp->d_rpm * lp->d_nsectors * lp->d_secsize); 29430519Ssam #ifdef notyet 29530573Skarels addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp); 29630519Ssam #endif 29724004Ssam } 29824004Ssam 29930756Skarels vdopen(dev, flags, fmt) 30030519Ssam dev_t dev; 30130756Skarels int flags, fmt; 30224004Ssam { 30330519Ssam register unit = vdunit(dev); 30430519Ssam register struct disklabel *lp; 30530519Ssam register struct dksoftc *dk; 30630519Ssam register struct partition *pp; 30730519Ssam struct vba_device *vi; 30830756Skarels int s, error, part = vdpart(dev), mask = 1 << part; 30930519Ssam daddr_t start, end; 31024004Ssam 31130519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 31230519Ssam return (ENXIO); 31330519Ssam lp = &dklabel[unit]; 31430519Ssam dk = &dksoftc[unit]; 31530519Ssam 31630519Ssam s = spl7(); 31730519Ssam while (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 31830519Ssam dk->dk_state != CLOSED) 31930519Ssam sleep((caddr_t)dk, PZERO+1); 32030519Ssam splx(s); 32130519Ssam if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 32230519Ssam if (error = vdinit(dev, flags)) 32330519Ssam return (error); 32430573Skarels 32530573Skarels if (vdwstart == 0) { 32630573Skarels timeout(vdwatch, (caddr_t)0, hz); 32730573Skarels vdwstart++; 32830573Skarels } 32930519Ssam /* 33030519Ssam * Warn if a partion is opened 33130519Ssam * that overlaps another partition which is open 33230519Ssam * unless one is the "raw" partition (whole disk). 33330519Ssam */ 33432211Skarels #define RAWPART 8 /* 'x' partition */ /* XXX */ 33532576Skarels if ((dk->dk_openpart & mask) == 0 && part != RAWPART) { 33630519Ssam pp = &lp->d_partitions[part]; 33730519Ssam start = pp->p_offset; 33830519Ssam end = pp->p_offset + pp->p_size; 33930519Ssam for (pp = lp->d_partitions; 34030519Ssam pp < &lp->d_partitions[lp->d_npartitions]; pp++) { 34130519Ssam if (pp->p_offset + pp->p_size <= start || 34230519Ssam pp->p_offset >= end) 34330519Ssam continue; 34430519Ssam if (pp - lp->d_partitions == RAWPART) 34530519Ssam continue; 34630519Ssam if (dk->dk_openpart & (1 << (pp - lp->d_partitions))) 34730519Ssam log(LOG_WARNING, 34830519Ssam "dk%d%c: overlaps open partition (%c)\n", 34930519Ssam unit, part + 'a', 35030519Ssam pp - lp->d_partitions + 'a'); 35130519Ssam } 35224004Ssam } 35330519Ssam if (part >= lp->d_npartitions) 35430519Ssam return (ENXIO); 35530756Skarels dk->dk_openpart |= mask; 35630756Skarels switch (fmt) { 35730756Skarels case S_IFCHR: 35830756Skarels dk->dk_copenpart |= mask; 35930756Skarels break; 36030756Skarels case S_IFBLK: 36130756Skarels dk->dk_bopenpart |= mask; 36230756Skarels break; 36330756Skarels } 36430519Ssam return (0); 36525675Ssam } 36624004Ssam 36734528Skarels /* ARGSUSED */ 36830756Skarels vdclose(dev, flags, fmt) 36930519Ssam dev_t dev; 37030756Skarels int flags, fmt; 37124004Ssam { 37230519Ssam register int unit = vdunit(dev); 37330519Ssam register struct dksoftc *dk = &dksoftc[unit]; 37430756Skarels int part = vdpart(dev), mask = 1 << part; 37524004Ssam 37630756Skarels switch (fmt) { 37730756Skarels case S_IFCHR: 37830756Skarels dk->dk_copenpart &= ~mask; 37930756Skarels break; 38030756Skarels case S_IFBLK: 38130756Skarels dk->dk_bopenpart &= ~mask; 38230756Skarels break; 38330756Skarels } 38430756Skarels if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0) 38530756Skarels dk->dk_openpart &= ~mask; 38630519Ssam /* 38730519Ssam * Should wait for i/o to complete on this partition 38830519Ssam * even if others are open, but wait for work on blkflush(). 38930519Ssam */ 39030519Ssam if (dk->dk_openpart == 0) { 39130573Skarels int s = spl7(); 39230573Skarels while (dkutab[unit].b_actf) 39330573Skarels sleep((caddr_t)dk, PZERO-1); 39430519Ssam splx(s); 39530519Ssam dk->dk_state = CLOSED; 39634076Skarels dk->dk_wlabel = 0; 39724004Ssam } 39830756Skarels return (0); 39925675Ssam } 40024004Ssam 40130519Ssam vdinit(dev, flags) 40230519Ssam dev_t dev; 40330519Ssam int flags; 40425675Ssam { 40530519Ssam register struct disklabel *lp; 40630519Ssam register struct dksoftc *dk; 40730519Ssam struct vba_device *vi; 40830519Ssam int unit = vdunit(dev), error = 0; 40930756Skarels char *msg, *readdisklabel(); 41030519Ssam extern int cold; 41125675Ssam 41230519Ssam dk = &dksoftc[unit]; 41330519Ssam if (flags & O_NDELAY) { 41430519Ssam dk->dk_state = OPENRAW; 41534528Skarels return (0); 41630519Ssam } 41730519Ssam dk->dk_state = RDLABEL; 41830519Ssam lp = &dklabel[unit]; 41930519Ssam vi = vddinfo[unit]; 42030756Skarels if (msg = readdisklabel(dev, vdstrategy, lp)) { 42134076Skarels if (cold) { 42230601Skarels printf(": %s", msg); 42334076Skarels dk->dk_state = CLOSED; 42434076Skarels } else { 42532211Skarels log(LOG_ERR, "dk%d: %s\n", unit, msg); 42634076Skarels dk->dk_state = OPENRAW; 42734076Skarels } 42830519Ssam #ifdef COMPAT_42 42935082Skarels vdlock(vi->ui_ctlr); 43034076Skarels if (vdmaptype(vi, lp)) 43130519Ssam dk->dk_state = OPEN; 43235082Skarels vdunlock(vi->ui_ctlr); 43330519Ssam #endif 43430756Skarels } else { 43530756Skarels /* 43630756Skarels * Now that we have the label, configure 43730756Skarels * the correct drive parameters. 43830756Skarels */ 43935082Skarels vdlock(vi->ui_ctlr); 44032211Skarels if (vdreset_drive(vi)) 44132211Skarels dk->dk_state = OPEN; 44232211Skarels else { 44330756Skarels dk->dk_state = CLOSED; 44430756Skarels error = ENXIO; 44532211Skarels } 44635082Skarels vdunlock(vi->ui_ctlr); 44725675Ssam } 44830756Skarels #ifndef SECSIZE 44932211Skarels vd_setsecsize(dk, lp); 45032211Skarels #endif 45130519Ssam wakeup((caddr_t)dk); 45230519Ssam return (error); 45324004Ssam } 45424004Ssam 45532211Skarels #ifndef SECSIZE 45632211Skarels vd_setsecsize(dk, lp) 45732211Skarels register struct dksoftc *dk; 45832211Skarels register struct disklabel *lp; 45932211Skarels { 46032211Skarels int mul; 46132211Skarels 46232211Skarels /* 46332211Skarels * Calculate scaling shift for mapping 46432211Skarels * DEV_BSIZE blocks to drive sectors. 46532211Skarels */ 46632211Skarels mul = DEV_BSIZE / lp->d_secsize; 46732211Skarels dk->dk_bshift = 0; 46832211Skarels while ((mul >>= 1) > 0) 46932211Skarels dk->dk_bshift++; 47032211Skarels } 47132211Skarels #endif SECSIZE 47232211Skarels 47325675Ssam /*ARGSUSED*/ 47430519Ssam vddgo(vm) 47530519Ssam struct vba_device *vm; 47624004Ssam { 47724004Ssam 47824004Ssam } 47924004Ssam 48024004Ssam vdstrategy(bp) 48125675Ssam register struct buf *bp; 48224004Ssam { 48330519Ssam register struct vba_device *vi; 48430519Ssam register struct disklabel *lp; 48530519Ssam register struct dksoftc *dk; 48630519Ssam register int unit; 48730573Skarels register daddr_t sn; 48830519Ssam struct buf *dp; 48930573Skarels daddr_t sz, maxsz; 49030519Ssam int part, s; 49124004Ssam 49230519Ssam unit = vdunit(bp->b_dev); 49332211Skarels if (unit >= NDK) { 49429954Skarels bp->b_error = ENXIO; 49525675Ssam goto bad; 49629954Skarels } 49730519Ssam vi = vddinfo[unit]; 49830519Ssam lp = &dklabel[unit]; 49930519Ssam if (vi == 0 || vi->ui_alive == 0) { 50030519Ssam bp->b_error = ENXIO; 50130519Ssam goto bad; 50230519Ssam } 50330519Ssam dk = &dksoftc[unit]; 50430519Ssam if (dk->dk_state < OPEN) 50530519Ssam goto q; 50634076Skarels if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) { 50734076Skarels bp->b_error = EROFS; 50834076Skarels goto bad; 50934076Skarels } 51030519Ssam part = vdpart(bp->b_dev); 51130519Ssam if ((dk->dk_openpart & (1 << part)) == 0) { 51230519Ssam bp->b_error = ENODEV; 51330519Ssam goto bad; 51430519Ssam } 51532211Skarels sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize; 51630519Ssam maxsz = lp->d_partitions[part].p_size; 51730756Skarels #ifndef SECSIZE 51830756Skarels sn = bp->b_blkno << dk->dk_bshift; 51930756Skarels #else SECSIZE 52030573Skarels sn = bp->b_blkno; 52130756Skarels #endif SECSIZE 52234076Skarels if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR && 52334076Skarels #if LABELSECTOR != 0 52434076Skarels sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR && 52534076Skarels #endif 52634076Skarels (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) { 52734076Skarels bp->b_error = EROFS; 52834076Skarels goto bad; 52934076Skarels } 53030519Ssam if (sn < 0 || sn + sz > maxsz) { 53130519Ssam if (sn == maxsz) { 53229954Skarels bp->b_resid = bp->b_bcount; 53329954Skarels goto done; 53429954Skarels } 53530756Skarels sz = maxsz - sn; 53630573Skarels if (sz <= 0) { 53730573Skarels bp->b_error = EINVAL; 53830573Skarels goto bad; 53930573Skarels } 54030573Skarels bp->b_bcount = sz * lp->d_secsize; 54125675Ssam } 54230519Ssam bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl; 54330756Skarels #ifdef SECSIZE 54430756Skarels if (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0) 54530756Skarels panic("vdstrat blksize"); 54630756Skarels #endif SECSIZE 54730519Ssam q: 54825675Ssam s = spl7(); 54930519Ssam dp = &dkutab[vi->ui_unit]; 55030519Ssam disksort(dp, bp); 55130519Ssam if (!dp->b_active) { 55230519Ssam (void) vdustart(vi); 55330573Skarels if (!vi->ui_mi->um_tab.b_active) 55430519Ssam vdstart(vi->ui_mi); 55524004Ssam } 55630519Ssam splx(s); 55724004Ssam return; 55825675Ssam bad: 55929954Skarels bp->b_flags |= B_ERROR; 56029954Skarels done: 56130519Ssam biodone(bp); 56230519Ssam return; 56324004Ssam } 56424004Ssam 56530519Ssam vdustart(vi) 56630519Ssam register struct vba_device *vi; 56724004Ssam { 56830519Ssam register struct buf *bp, *dp; 56930519Ssam register struct vba_ctlr *vm; 57030519Ssam register int unit = vi->ui_unit; 57130519Ssam register struct dksoftc *dk; 57230519Ssam register struct vdsoftc *vd; 57330519Ssam struct disklabel *lp; 57424004Ssam 57530519Ssam dp = &dkutab[unit]; 57630519Ssam /* 57730519Ssam * If queue empty, nothing to do. 57830519Ssam */ 57930519Ssam if ((bp = dp->b_actf) == NULL) 58030519Ssam return; 58130519Ssam /* 58230574Skarels * If drive is off-cylinder and controller supports seeks, 58330574Skarels * place drive on seek queue for controller. 58430574Skarels * Otherwise, place on transfer queue. 58530519Ssam */ 58630519Ssam vd = &vdsoftc[vi->ui_ctlr]; 58730519Ssam dk = &dksoftc[unit]; 58830574Skarels vm = vi->ui_mi; 58930519Ssam if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) { 59030519Ssam lp = &dklabel[unit]; 59130574Skarels bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors; 59230574Skarels if (vm->um_tab.b_seekf == NULL) 59330574Skarels vm->um_tab.b_seekf = dp; 59430574Skarels else 59530574Skarels vm->um_tab.b_seekl->b_forw = dp; 59630574Skarels vm->um_tab.b_seekl = dp; 59730574Skarels } else { 59830574Skarels if (vm->um_tab.b_actf == NULL) 59930574Skarels vm->um_tab.b_actf = dp; 60030574Skarels else 60130574Skarels vm->um_tab.b_actl->b_forw = dp; 60230574Skarels vm->um_tab.b_actl = dp; 60330519Ssam } 60430573Skarels dp->b_forw = NULL; 60530573Skarels dp->b_active++; 60625675Ssam } 60725675Ssam 60825675Ssam /* 60930519Ssam * Start next transfer on a controller. 61030574Skarels * There are two queues of drives, the first on-cylinder 61130574Skarels * and the second off-cylinder from their next transfers. 61230574Skarels * Perform the first transfer for the first drive on the on-cylinder 61330574Skarels * queue, if any, otherwise the first transfer for the first drive 61430574Skarels * on the second queue. Initiate seeks on remaining drives on the 61530574Skarels * off-cylinder queue, then move them all to the on-cylinder queue. 61625675Ssam */ 61730519Ssam vdstart(vm) 61830519Ssam register struct vba_ctlr *vm; 61925675Ssam { 62025675Ssam register struct buf *bp; 62130519Ssam register struct vba_device *vi; 62230519Ssam register struct vdsoftc *vd; 62330519Ssam register struct dksoftc *dk; 62430519Ssam register struct disklabel *lp; 62530519Ssam register struct dcb **dcbp; 62630519Ssam struct buf *dp; 62730519Ssam int sn, tn; 62825675Ssam 62930519Ssam loop: 63030519Ssam /* 63130519Ssam * Pull a request off the controller queue. 63230519Ssam */ 63330574Skarels if ((dp = vm->um_tab.b_actf) == NULL && 63430574Skarels (dp = vm->um_tab.b_seekf) == NULL) 63530519Ssam return; 63630519Ssam if ((bp = dp->b_actf) == NULL) { 63730601Skarels if (dp == vm->um_tab.b_actf) 63830601Skarels vm->um_tab.b_actf = dp->b_forw; 63930601Skarels else 64030601Skarels vm->um_tab.b_seekf = dp->b_forw; 64130519Ssam goto loop; 64230519Ssam } 64325675Ssam 64424004Ssam /* 64530519Ssam * Mark controller busy, and determine 64630519Ssam * destination of this request. 64724004Ssam */ 64830519Ssam vm->um_tab.b_active++; 64930519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 65030519Ssam dk = &dksoftc[vi->ui_unit]; 65130756Skarels #ifndef SECSIZE 65230756Skarels sn = bp->b_blkno << dk->dk_bshift; 65330756Skarels #else SECSIZE 65430573Skarels sn = bp->b_blkno; 65530756Skarels #endif SECSIZE 65630519Ssam lp = &dklabel[vi->ui_unit]; 65730519Ssam sn %= lp->d_secpercyl; 65830519Ssam tn = sn / lp->d_nsectors; 65930519Ssam sn %= lp->d_nsectors; 66030519Ssam 66130519Ssam /* 66230519Ssam * Construct dcb for read/write command. 66330519Ssam */ 66430519Ssam vd = &vdsoftc[vm->um_ctlr]; 66530519Ssam vd->vd_dcb.intflg = DCBINT_DONE; 66632211Skarels vd->vd_dcb.devselect = dk->dk_dcb.devselect; 66730519Ssam vd->vd_dcb.operrsta = 0; 66830519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 66930519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin; 67030519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 67130519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 67230574Skarels dk->dk_curcyl = bp->b_cylin; 67330574Skarels bp->b_track = 0; /* init overloaded field */ 67430756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 67534396Skarels if (bp->b_flags & B_FORMAT) 67634396Skarels vd->vd_dcb.opcode = dk->dk_op; 67734396Skarels else if (vd->vd_flags & VD_SCATGATH && 67834396Skarels ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0) 67930756Skarels vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW; 68034396Skarels else 68130756Skarels vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD; 68234396Skarels 68334396Skarels switch (vd->vd_dcb.opcode) { 68434396Skarels case VDOP_FSECT: 68534396Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 68634396Skarels vd->vd_dcb.trail.fmtrail.nsectors = bp->b_bcount / 68734396Skarels lp->d_secsize; 68834396Skarels vd->vd_dcb.trail.fmtrail.hdr = *(dskadr *)&dk->dk_althdr; 68934396Skarels vd->vd_dcb.trail.rwtrail.disk.cylinder |= dk->dk_fmtflags; 69034396Skarels goto setupaddr; 69134396Skarels 69234396Skarels case VDOP_RDRAW: 69334396Skarels case VDOP_RD: 69434396Skarels case VDOP_WD: 69534396Skarels vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1; 69634396Skarels setupaddr: 69730756Skarels vd->vd_dcb.trail.rwtrail.memadr = 69834528Skarels vbasetup(bp, &vd->vd_rbuf, (int)lp->d_secsize); 69934396Skarels break; 70034396Skarels 70134396Skarels case VDOP_RAS: 70234396Skarels case VDOP_GAW: 70334396Skarels vd->vd_dcb.trailcnt += vba_sgsetup(bp, &vd->vd_rbuf, 70434396Skarels &vd->vd_dcb.trail.sgtrail); 70534396Skarels break; 70630756Skarels } 70730574Skarels if (vi->ui_dk >= 0) { 70830574Skarels dk_busy |= 1<<vi->ui_dk; 70930574Skarels dk_xfer[vi->ui_dk]++; 71030574Skarels dk_wds[vi->ui_dk] += bp->b_bcount>>6; 71130574Skarels } 71230519Ssam 71330519Ssam /* 71430519Ssam * Look for any seeks to be performed on other drives on this 71530519Ssam * controller. If overlapped seeks exist, insert seek commands 71630519Ssam * on the controller's command queue before the transfer. 71730519Ssam */ 71830519Ssam dcbp = &vd->vd_mdcb.mdcb_head; 71930519Ssam 72030574Skarels if (dp == vm->um_tab.b_seekf) 72130574Skarels dp = dp->b_forw; 72230574Skarels else 72330574Skarels dp = vm->um_tab.b_seekf; 72430574Skarels for (; dp != NULL; dp = dp->b_forw) { 72530574Skarels if ((bp = dp->b_actf) == NULL) 72630574Skarels continue; 72730574Skarels vi = vddinfo[vdunit(bp->b_dev)]; 72830574Skarels dk = &dksoftc[vi->ui_unit]; 72930519Ssam dk->dk_curcyl = bp->b_cylin; 73030574Skarels if (vi->ui_dk >= 0) 73130574Skarels dk_seek[vi->ui_dk]++; 73230574Skarels dk->dk_dcb.operrsta = 0; 73330574Skarels dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin; 73430574Skarels dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track; 73530574Skarels *dcbp = (struct dcb *)dk->dk_dcbphys; 73630574Skarels dcbp = &dk->dk_dcb.nxtdcb; 73724004Ssam } 73830519Ssam *dcbp = (struct dcb *)vd->vd_dcbphys; 73930574Skarels if (vm->um_tab.b_actf) 74030574Skarels vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf; 74130574Skarels else 74230574Skarels vm->um_tab.b_actf = vm->um_tab.b_seekf; 74330601Skarels if (vm->um_tab.b_seekf) 74430601Skarels vm->um_tab.b_actl = vm->um_tab.b_seekl; 74530574Skarels vm->um_tab.b_seekf = 0; 74624004Ssam 74730519Ssam /* 74830519Ssam * Initiate operation. 74930519Ssam */ 75030519Ssam vd->vd_mdcb.mdcb_status = 0; 75130519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 75224004Ssam } 75324004Ssam 75435082Skarels /* 75535082Skarels * Wait for controller to finish current operation 75635082Skarels * so that direct controller accesses can be done. 75735082Skarels */ 75835082Skarels vdlock(ctlr) 75935082Skarels { 76035082Skarels register struct vba_ctlr *vm = vdminfo[ctlr]; 76135082Skarels register struct vdsoftc *vd = &vdsoftc[ctlr]; 76235082Skarels int s; 76335082Skarels 76435082Skarels s = spl7(); 76535082Skarels while (vm->um_tab.b_active || vd->vd_flags & VD_LOCKED) { 76635082Skarels vd->vd_flags |= VD_WAIT; 76735082Skarels sleep((caddr_t)vd, PRIBIO); 76835082Skarels } 76935082Skarels vd->vd_flags |= VD_LOCKED; 77035082Skarels splx(s); 77135082Skarels } 77235082Skarels 77335082Skarels /* 77435082Skarels * Continue normal operations after pausing for 77535082Skarels * munging the controller directly. 77635082Skarels */ 77735082Skarels vdunlock(ctlr) 77835082Skarels { 77935082Skarels register struct vba_ctlr *vm = vdminfo[ctlr]; 78035082Skarels register struct vdsoftc *vd = &vdsoftc[ctlr]; 78135082Skarels 78235082Skarels vd->vd_flags &= ~VD_LOCKED; 78335082Skarels if (vd->vd_flags & VD_WAIT) { 78435082Skarels vd->vd_flags &= ~VD_WAIT; 78535082Skarels wakeup((caddr_t)vd); 78635082Skarels } else if (vm->um_tab.b_actf || vm->um_tab.b_seekf) 78735082Skarels vdstart(vm); 78835082Skarels } 78935082Skarels 79030519Ssam #define DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE) 79124004Ssam /* 79224004Ssam * Handle a disk interrupt. 79324004Ssam */ 79425675Ssam vdintr(ctlr) 79530519Ssam register ctlr; 79624004Ssam { 79730519Ssam register struct buf *bp, *dp; 79830519Ssam register struct vba_ctlr *vm = vdminfo[ctlr]; 79930519Ssam register struct vba_device *vi; 80030519Ssam register struct vdsoftc *vd = &vdsoftc[ctlr]; 80130519Ssam register status; 80234528Skarels int timedout; 80330573Skarels struct dksoftc *dk; 80424004Ssam 80530519Ssam if (!vm->um_tab.b_active) { 80625675Ssam printf("vd%d: stray interrupt\n", ctlr); 80724004Ssam return; 80824004Ssam } 80925675Ssam /* 81030519Ssam * Get device and block structures, and a pointer 81130519Ssam * to the vba_device for the drive. 81225675Ssam */ 81330519Ssam dp = vm->um_tab.b_actf; 81430519Ssam bp = dp->b_actf; 81530519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 81634528Skarels dk = &dksoftc[vi->ui_unit]; 81730574Skarels if (vi->ui_dk >= 0) 81830574Skarels dk_busy &= ~(1<<vi->ui_dk); 81934396Skarels timedout = (vd->vd_wticks >= VDMAXTIME); 82030519Ssam /* 82130519Ssam * Check for and process errors on 82230519Ssam * either the drive or the controller. 82330519Ssam */ 82430519Ssam uncache(&vd->vd_dcb.operrsta); 82530519Ssam status = vd->vd_dcb.operrsta; 82634396Skarels if (bp->b_flags & B_FORMAT) { 82734396Skarels dk->dk_operrsta = status; 82834396Skarels uncache(&vd->vd_dcb.err_code); 82934396Skarels dk->dk_ecode = vd->vd_dcb.err_code; 83034396Skarels } 83134396Skarels if (status & VDERR_HARD || timedout) { 83234528Skarels if (vd->vd_type == VDTYPE_SMDE) 83330601Skarels uncache(&vd->vd_dcb.err_code); 83430519Ssam if (status & DCBS_WPT) { 83530519Ssam /* 83630519Ssam * Give up on write locked devices immediately. 83730519Ssam */ 83830573Skarels printf("dk%d: write locked\n", vi->ui_unit); 83930519Ssam bp->b_flags |= B_ERROR; 84034396Skarels } else if (status & VDERR_RETRY || timedout) { 84132211Skarels int endline = 1; 84232211Skarels 84334396Skarels if (status & VDERR_CTLR || timedout) { 84434396Skarels vdharderr("controller err", 84534396Skarels vd, bp, &vd->vd_dcb); 84634396Skarels printf("; resetting controller..."); 84734396Skarels vdreset_ctlr(vm); 84834396Skarels } else if (status & VDERR_DRIVE) { 84934396Skarels vdharderr("drive err", vd, bp, &vd->vd_dcb); 85034396Skarels printf("; resetting drive..."); 85130519Ssam if (!vdreset_drive(vi)) 85230519Ssam vi->ui_alive = 0; 85332211Skarels } else 85432211Skarels endline = 0; 85530519Ssam /* 85630519Ssam * Retry transfer once, unless reset failed. 85730519Ssam */ 85834396Skarels if (!vi->ui_alive || dp->b_errcnt++ >= 2 || 85934396Skarels bp->b_flags & B_FORMAT) { 86032211Skarels if (endline) 86132211Skarels printf("\n"); 86230519Ssam goto hard; 86332211Skarels } 86432211Skarels 86532211Skarels if (endline) 86632211Skarels printf(" retrying\n"); 86730519Ssam vm->um_tab.b_active = 0; /* force retry */ 86830519Ssam } else { 86930519Ssam hard: 87030519Ssam bp->b_flags |= B_ERROR; 87134396Skarels vdharderr("hard error", vd, bp, &vd->vd_dcb); 87230519Ssam printf("\n"); 87330519Ssam } 87430519Ssam } else if (status & DCBS_SOFT) 87534528Skarels vdsofterr(bp, &vd->vd_dcb); 87634396Skarels vd->vd_wticks = 0; 87730519Ssam if (vm->um_tab.b_active) { 87830519Ssam vm->um_tab.b_active = 0; 87930519Ssam vm->um_tab.b_actf = dp->b_forw; 88030519Ssam dp->b_active = 0; 88130519Ssam dp->b_errcnt = 0; 88230519Ssam dp->b_actf = bp->av_forw; 88330519Ssam bp->b_resid = 0; 88430601Skarels vbadone(bp, &vd->vd_rbuf); 88530519Ssam biodone(bp); 88630370Skarels /* 88730519Ssam * If this unit has more work to do, 88830519Ssam * then start it up right away. 88930370Skarels */ 89030519Ssam if (dp->b_actf) 89130519Ssam vdustart(vi); 89234528Skarels else if (dk->dk_openpart == 0) 89330573Skarels wakeup((caddr_t)dk); 89424004Ssam } 89525675Ssam /* 89630519Ssam * If there are devices ready to 89730519Ssam * transfer, start the controller. 89825675Ssam */ 89935082Skarels if (vd->vd_flags & VD_WAIT) { 90035082Skarels vd->vd_flags &= ~VD_WAIT; 90135082Skarels wakeup((caddr_t)vd); 90235082Skarels } else if (vm->um_tab.b_actf || vm->um_tab.b_seekf) 90330519Ssam vdstart(vm); 90424004Ssam } 90524004Ssam 90634396Skarels vdharderr(what, vd, bp, dcb) 90734396Skarels char *what; 90834396Skarels struct vdsoftc *vd; 90934396Skarels register struct buf *bp; 91034396Skarels register struct dcb *dcb; 91134396Skarels { 91234396Skarels int unit = vdunit(bp->b_dev), status = dcb->operrsta; 91334396Skarels register struct disklabel *lp = &dklabel[unit]; 91434528Skarels int blkdone; 91534396Skarels 91634396Skarels if (vd->vd_wticks < VDMAXTIME) 91734396Skarels status &= ~DONTCARE; 91834710Skarels blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) * 91934710Skarels lp->d_nsectors + dcb->err_sec - 92034710Skarels lp->d_partitions[vdpart(bp->b_dev)].p_offset) >> 92134710Skarels dksoftc[unit].dk_bshift) - bp->b_blkno; 92234528Skarels diskerr(bp, "dk", what, LOG_PRINTF, blkdone, lp); 92334528Skarels printf(", status %b", status, VDERRBITS); 92434396Skarels if (vd->vd_type == VDTYPE_SMDE) 92534396Skarels printf(" ecode %x", dcb->err_code); 92634396Skarels } 92734396Skarels 92834528Skarels vdsofterr(bp, dcb) 92925675Ssam register struct buf *bp; 93030519Ssam register struct dcb *dcb; 93125675Ssam { 93234562Skarels int unit = vdunit(bp->b_dev); 93334562Skarels struct disklabel *lp = &dklabel[unit]; 93434528Skarels int status = dcb->operrsta; 93534528Skarels int blkdone; 93625675Ssam 93734710Skarels blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) * 93834710Skarels lp->d_nsectors + dcb->err_sec - 93934710Skarels lp->d_partitions[vdpart(bp->b_dev)].p_offset) >> 94034710Skarels dksoftc[unit].dk_bshift) - bp->b_blkno; 94134528Skarels 94234528Skarels if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) { 94334528Skarels diskerr(bp, "dk", "soft error", LOG_WARNING, blkdone, lp); 94434528Skarels addlog(", status %b ecode %x\n", status, VDERRBITS, 94534396Skarels dcb->err_code); 94634528Skarels } else { 94734528Skarels diskerr(bp, "dk", "soft ecc", LOG_WARNING, blkdone, lp); 94834528Skarels addlog("\n"); 94934528Skarels } 95025675Ssam } 95125675Ssam 95230519Ssam vdioctl(dev, cmd, data, flag) 95325675Ssam dev_t dev; 95430519Ssam int cmd; 95530519Ssam caddr_t data; 95630519Ssam int flag; 95724004Ssam { 95832576Skarels register int unit = vdunit(dev); 95930519Ssam register struct disklabel *lp = &dklabel[unit]; 96034076Skarels register struct dksoftc *dk = &dksoftc[unit]; 96134640Skarels int error = 0, vdformat(); 96224004Ssam 96330519Ssam switch (cmd) { 96430519Ssam 96530519Ssam case DIOCGDINFO: 96630519Ssam *(struct disklabel *)data = *lp; 96730519Ssam break; 96830519Ssam 96930573Skarels case DIOCGPART: 97030573Skarels ((struct partinfo *)data)->disklab = lp; 97130573Skarels ((struct partinfo *)data)->part = 97230573Skarels &lp->d_partitions[vdpart(dev)]; 97330519Ssam break; 97430519Ssam 97530519Ssam case DIOCSDINFO: 97630519Ssam if ((flag & FWRITE) == 0) 97730519Ssam error = EBADF; 97830519Ssam else 97932576Skarels error = setdisklabel(lp, (struct disklabel *)data, 98034076Skarels (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart); 98134396Skarels if (error == 0 && dk->dk_state == OPENRAW && 98234396Skarels vdreset_drive(vddinfo[unit])) 98334076Skarels dk->dk_state = OPEN; 98430519Ssam break; 98530519Ssam 98634076Skarels case DIOCWLABEL: 98734076Skarels if ((flag & FWRITE) == 0) 98834076Skarels error = EBADF; 98934076Skarels else 99034076Skarels dk->dk_wlabel = *(int *)data; 99134076Skarels break; 99234076Skarels 99332576Skarels case DIOCWDINFO: 99432576Skarels if ((flag & FWRITE) == 0) 99530519Ssam error = EBADF; 99632576Skarels else if ((error = setdisklabel(lp, (struct disklabel *)data, 99734076Skarels (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) { 99834640Skarels int wlab; 99934640Skarels 1000*35413Skarels if (error == 0 && dk->dk_state == OPENRAW && 1001*35413Skarels vdreset_drive(vddinfo[unit])) 1002*35413Skarels dk->dk_state = OPEN; 100334640Skarels /* simulate opening partition 0 so write succeeds */ 100434640Skarels dk->dk_openpart |= (1 << 0); /* XXX */ 100534640Skarels wlab = dk->dk_wlabel; 100634640Skarels dk->dk_wlabel = 1; 100732576Skarels error = writedisklabel(dev, vdstrategy, lp); 100834640Skarels dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart; 100934640Skarels dk->dk_wlabel = wlab; 101034076Skarels } 101130519Ssam break; 101230519Ssam 101334396Skarels case DIOCWFORMAT: 101434396Skarels { 101534396Skarels register struct format_op *fop; 101634396Skarels struct uio auio; 101734396Skarels struct iovec aiov; 101834396Skarels 101934396Skarels if ((flag & FWRITE) == 0) { 102034396Skarels error = EBADF; 102134396Skarels break; 102234396Skarels } 102334396Skarels fop = (struct format_op *)data; 102434396Skarels aiov.iov_base = fop->df_buf; 102534396Skarels aiov.iov_len = fop->df_count; 102634396Skarels auio.uio_iov = &aiov; 102734396Skarels auio.uio_iovcnt = 1; 102834396Skarels auio.uio_resid = fop->df_count; 102934396Skarels auio.uio_segflg = UIO_USERSPACE; 103034396Skarels auio.uio_offset = fop->df_startblk * lp->d_secsize; 103134396Skarels dk->dk_operrsta = fop->dk_operrsta; 103234396Skarels dk->dk_ecode = fop->dk_ecode; 103334396Skarels /* 103434396Skarels * Don't return errors, as the format op won't get copied 103534396Skarels * out if we return nonzero. Callers must check the returned 103634396Skarels * count. 103734396Skarels */ 103834396Skarels (void) physio(vdformat, (struct buf *)NULL, dev, 103934396Skarels (cmd == DIOCWFORMAT ? B_WRITE : B_READ), minphys, &auio); 104034396Skarels fop->df_count -= auio.uio_resid; 104134396Skarels fop->dk_operrsta = dk->dk_operrsta; 104234396Skarels fop->dk_ecode = dk->dk_ecode; 104334396Skarels break; 104434396Skarels } 104534396Skarels 104630519Ssam default: 104730519Ssam error = ENOTTY; 104830519Ssam break; 104924004Ssam } 105032606Skarels return (error); 105124004Ssam } 105224004Ssam 105334396Skarels vdformat(bp) 105434396Skarels struct buf *bp; 105534396Skarels { 105634396Skarels bp->b_flags |= B_FORMAT; 105734396Skarels vdstrategy(bp); 105834396Skarels } 105934396Skarels 106025675Ssam /* 106130519Ssam * Watch for lost interrupts. 106225675Ssam */ 106330519Ssam vdwatch() 106430519Ssam { 106530519Ssam register struct vdsoftc *vd; 106630519Ssam register struct vba_ctlr *vm; 106734528Skarels register int ctlr; 106834396Skarels int s; 106930519Ssam 107030519Ssam timeout(vdwatch, (caddr_t)0, hz); 107130519Ssam for (ctlr = 0; ctlr < NVD; ctlr++) { 107230519Ssam vm = vdminfo[ctlr]; 107330519Ssam if (vm == 0 || vm->um_alive == 0) 107430519Ssam continue; 107530519Ssam vd = &vdsoftc[ctlr]; 107634396Skarels s = spl7(); 107734396Skarels if (vm->um_tab.b_active && vd->vd_wticks++ >= VDMAXTIME) { 107830519Ssam printf("vd%d: lost interrupt\n", ctlr); 107934396Skarels #ifdef maybe 108034396Skarels VDABORT((struct vddevice *)vm->um_addr, vd->vd_type); 108134396Skarels #endif 108234396Skarels vdintr(ctlr); 108330519Ssam } 108434396Skarels splx(s); 108530519Ssam } 108630519Ssam } 108730519Ssam 108830519Ssam #define DBSIZE 64 /* controller limit with 1K sectors */ 108930519Ssam /* 109030519Ssam * Crash dump. 109130519Ssam */ 109230519Ssam vddump(dev) 109330519Ssam dev_t dev; 109424004Ssam { 109530519Ssam register struct vba_device *vi; 109630519Ssam register struct vba_ctlr *vm; 109730519Ssam register struct disklabel *lp; 109830519Ssam register struct vdsoftc *vd; 109930519Ssam struct dksoftc *dk; 110030519Ssam int part, unit, num; 110130601Skarels u_long start; 110224004Ssam 110330519Ssam start = 0; 110430519Ssam unit = vdunit(dev); 110530519Ssam if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 110630519Ssam return (ENXIO); 110730519Ssam dk = &dksoftc[unit]; 110834076Skarels if (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 110934076Skarels vdinit(vdminor(unit, 0), 0) != 0) 111030519Ssam return (ENXIO); 111130519Ssam lp = &dklabel[unit]; 111230519Ssam part = vdpart(dev); 111330519Ssam if (part >= lp->d_npartitions) 111430519Ssam return (ENXIO); 111532211Skarels vm = vi->ui_mi; 111630519Ssam vdreset_ctlr(vm); 111730519Ssam if (dumplo < 0) 111830519Ssam return (EINVAL); 111930519Ssam /* 112030756Skarels * Maxfree is in pages, dumplo is in DEV_BSIZE units. 112130519Ssam */ 112230519Ssam num = maxfree * (NBPG / lp->d_secsize); 112330756Skarels dumplo *= DEV_BSIZE / lp->d_secsize; 112430519Ssam if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size) 112530519Ssam num = lp->d_partitions[vdpart(dev)].p_size - dumplo; 112630519Ssam vd = &vdsoftc[vm->um_ctlr]; 112730519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 112830519Ssam vd->vd_dcb.opcode = VDOP_WD; 112932211Skarels vd->vd_dcb.devselect = dk->dk_dcb.devselect; 113030756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 113130519Ssam while (num > 0) { 113230519Ssam int nsec, cn, sn, tn; 113330519Ssam 113430519Ssam nsec = MIN(num, DBSIZE); 113530601Skarels sn = dumplo + start / lp->d_secsize; 113630519Ssam cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) / 113730519Ssam lp->d_secpercyl; 113830519Ssam sn %= lp->d_secpercyl; 113930519Ssam tn = sn / lp->d_nsectors; 114030519Ssam sn %= lp->d_nsectors; 114130519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 114230519Ssam vd->vd_dcb.trail.rwtrail.memadr = start; 114330519Ssam vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1; 114430519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = cn; 114530519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 114630519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 114730519Ssam vd->vd_dcb.operrsta = 0; 114830519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 114930519Ssam if (!vdpoll(vm, 5)) { 115030519Ssam printf(" during dump\n"); 115130519Ssam return (EIO); 115230519Ssam } 115330519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 115430519Ssam printf("dk%d: hard error, status=%b\n", unit, 115530519Ssam vd->vd_dcb.operrsta, VDERRBITS); 115630519Ssam return (EIO); 115730519Ssam } 115830519Ssam start += nsec * lp->d_secsize; 115930519Ssam num -= nsec; 116025675Ssam } 116130519Ssam return (0); 116224004Ssam } 116324004Ssam 116424004Ssam vdsize(dev) 116525675Ssam dev_t dev; 116624004Ssam { 116730519Ssam register int unit = vdunit(dev); 116830519Ssam register struct dksoftc *dk; 116930519Ssam struct vba_device *vi; 117030519Ssam struct disklabel *lp; 117124004Ssam 117230519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 || 117330519Ssam (dk = &dksoftc[unit])->dk_state != OPEN) 117425675Ssam return (-1); 117530519Ssam lp = &dklabel[unit]; 117630756Skarels #ifdef SECSIZE 117730573Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size); 117830756Skarels #else SECSIZE 117930756Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift); 118030756Skarels #endif SECSIZE 118124004Ssam } 118224004Ssam 118325675Ssam /* 118425675Ssam * Perform a controller reset. 118525675Ssam */ 118630519Ssam vdreset_ctlr(vm) 118730519Ssam register struct vba_ctlr *vm; 118824004Ssam { 118930519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 119030519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 119130519Ssam register int unit; 119230519Ssam struct vba_device *vi; 119325675Ssam 119430519Ssam VDRESET(vdaddr, vd->vd_type); 119530519Ssam if (vd->vd_type == VDTYPE_SMDE) { 119630519Ssam vdaddr->vdcsr = 0; 119730519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 119830519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 119930519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 120030519Ssam vdaddr->vdtcf_data = AM_ENPDA; 120130519Ssam vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD | 120225675Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 120325675Ssam } 1204*35413Skarels if (!vdcmd(vm, VDOP_INIT, 10, 0) || !vdcmd(vm, VDOP_DIAG, 10, 0)) { 120530519Ssam printf("%s cmd failed\n", 120630519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 120730370Skarels return; 120825675Ssam } 120930519Ssam for (unit = 0; unit < NDK; unit++) 121030519Ssam if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive) 121130519Ssam (void) vdreset_drive(vi); 121230519Ssam } 121330519Ssam 121430519Ssam vdreset_drive(vi) 121530519Ssam register struct vba_device *vi; 121630519Ssam { 121730519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 121830519Ssam struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; 121930519Ssam struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 122032211Skarels register struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 122132211Skarels register struct dksoftc *dk = &dksoftc[vi->ui_unit]; 122230519Ssam 122330519Ssam top: 122430519Ssam vd->vd_dcb.opcode = VDOP_CONFIG; /* command */ 122530519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 122630519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 122730519Ssam vd->vd_dcb.operrsta = 0; 122832211Skarels vd->vd_dcb.devselect = vi->ui_slave | lp->d_devflags; 122930519Ssam vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders; 123030519Ssam vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks; 123130519Ssam if (vd->vd_type == VDTYPE_SMDE) { 123230756Skarels vd->vd_dcb.trailcnt = sizeof (struct treset) / sizeof (long); 123330519Ssam vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors; 123430601Skarels vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack; 123532211Skarels vd->vd_dcb.trail.rstrail.recovery = VDRF_NORMAL; 123630519Ssam } else 123730519Ssam vd->vd_dcb.trailcnt = 2; /* XXX */ 123830519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 123930519Ssam vd->vd_mdcb.mdcb_status = 0; 124030519Ssam VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type); 124130519Ssam if (!vdpoll(vm, 5)) { 124230519Ssam printf(" during config\n"); 124330519Ssam return (0); 124425675Ssam } 1245*35413Skarels /* 1246*35413Skarels uncache(&vd->vd_dcb.err_code); 1247*35413Skarels printf("vdreset_drive %d, error %b, ecode %x, status %x => ", 1248*35413Skarels vi->ui_unit, vd->vd_dcb.operrsta, VDERRBITS, vd->vd_dcb.err_code, 1249*35413Skarels vdaddr->vdstatus[vi->ui_slave]); 1250*35413Skarels uncache(&vdaddr->vdstatus[vi->ui_slave]); 1251*35413Skarels printf("%x =>", vdaddr->vdstatus[vi->ui_slave]); 1252*35413Skarels { int status = vd->vd_dcb.operrsta; 1253*35413Skarels vdcmd(vm, VDOP_STATUS, 5, vi->ui_slave); 1254*35413Skarels vd->vd_dcb.operrsta = status; 1255*35413Skarels } 1256*35413Skarels uncache(&vdaddr->vdstatus[vi->ui_slave]); 1257*35413Skarels printf("%x\n", vdaddr->vdstatus[vi->ui_slave]); 1258*35413Skarels */ 125930519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 126032211Skarels if (vd->vd_type == VDTYPE_SMDE) { 126132211Skarels if (lp->d_devflags == 0) { 126232211Skarels lp->d_devflags = VD_ESDI; 126332211Skarels goto top; 126432211Skarels } 126532211Skarels #ifdef notdef 126632211Skarels /* this doesn't work, STA_US isn't set(?) */ 126732211Skarels if ((vdaddr->vdstatus[vi->ui_slave] & STA_US) == 0) 126832211Skarels return (0); 126932211Skarels #endif 127032211Skarels } 127130519Ssam if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) 127232211Skarels printf("dk%d: config error %b ecode %x\n", vi->ui_unit, 127334396Skarels vd->vd_dcb.operrsta, VDERRBITS, 127434396Skarels (u_char) vd->vd_dcb.err_code); 127532211Skarels else if ((vd->vd_flags & VD_STARTED) == 0) { 127630519Ssam int started; 127730519Ssam 127832211Skarels printf(" starting drives, wait ... "); 127930519Ssam vd->vd_flags |= VD_STARTED; 128030519Ssam started = (vdcmd(vm, VDOP_START, 10) == 1); 128130519Ssam DELAY(62000000); 1282*35413Skarels printf("done\n"); 128332211Skarels lp->d_devflags = 0; 128430519Ssam if (started) 128530519Ssam goto top; 128630519Ssam } 128730519Ssam return (0); 128830519Ssam } 128932211Skarels dk->dk_dcb.devselect |= lp->d_devflags; 129030519Ssam return (1); 129125675Ssam } 129224004Ssam 129325675Ssam /* 129430519Ssam * Perform a command w/o trailer. 129525675Ssam */ 1296*35413Skarels vdcmd(vm, cmd, t, slave) 129730519Ssam register struct vba_ctlr *vm; 129825675Ssam { 129930519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 130025675Ssam 130130519Ssam vd->vd_dcb.opcode = cmd; /* command */ 130230519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 130330519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 130430519Ssam vd->vd_dcb.operrsta = 0; 1305*35413Skarels vd->vd_dcb.devselect = slave; 130630519Ssam vd->vd_dcb.trailcnt = 0; 130730519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 130830519Ssam vd->vd_mdcb.mdcb_status = 0; 130930519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 131030519Ssam if (!vdpoll(vm, t)) { 131130519Ssam printf(" during init\n"); 131230370Skarels return (0); 131330370Skarels } 131430519Ssam return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0); 131525675Ssam } 131625675Ssam 131725925Ssam /* 131830519Ssam * Poll controller until operation 131930519Ssam * completes or timeout expires. 132025925Ssam */ 132130519Ssam vdpoll(vm, t) 132230519Ssam register struct vba_ctlr *vm; 132325925Ssam register int t; 132425925Ssam { 132530519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 132630519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 132725925Ssam 132825925Ssam t *= 1000; 132930370Skarels for (;;) { 133030519Ssam uncache(&vd->vd_dcb.operrsta); 133130519Ssam if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT)) 133230370Skarels break; 133325925Ssam if (--t <= 0) { 133430519Ssam printf("vd%d: controller timeout", vm->um_ctlr); 133530519Ssam VDABORT(vdaddr, vd->vd_type); 133625925Ssam return (0); 133725925Ssam } 133830370Skarels DELAY(1000); 133925925Ssam } 134030519Ssam if (vd->vd_type == VDTYPE_SMDE) { 134130519Ssam do { 134225925Ssam DELAY(50); 134330519Ssam uncache(&vdaddr->vdcsr); 134430519Ssam } while (vdaddr->vdcsr & CS_GO); 134532211Skarels DELAY(300); 134632211Skarels uncache(&vd->vd_dcb.err_code); 134725925Ssam } 134825925Ssam DELAY(200); 134930519Ssam uncache(&vd->vd_dcb.operrsta); 135025925Ssam return (1); 135125925Ssam } 135225925Ssam 135330519Ssam #ifdef COMPAT_42 135430519Ssam struct vdst { 135530519Ssam int nsec; /* sectors/track */ 135630519Ssam int ntrack; /* tracks/cylinder */ 135730519Ssam int ncyl; /* cylinders */ 135832211Skarels int secsize; /* sector size */ 135930519Ssam char *name; /* type name */ 136030519Ssam struct { 136130519Ssam int off; /* partition offset in sectors */ 136230519Ssam int size; /* partition size in sectors */ 136330573Skarels } parts[8]; 136430519Ssam } vdst[] = { 136532211Skarels { 66, 23, 850, 512, "NEC 800", 136632211Skarels {0, 1290300}, /* a cyl 0 - 849 */ 136732211Skarels }, 136834737Sbostic { 64, 20, 842, 512, "2361a", 136934737Sbostic {0, 61440}, /* a cyl 0 - 47 */ 137034737Sbostic {61440, 67840}, /* b cyl 48 - 100 */ 137134737Sbostic {129280, 942080}, /* c cyl 101 - 836 */ 137234737Sbostic {0, 1071360}, /* d cyl 0 - 836 */ 137334737Sbostic {449280, 311040}, /* e cyl 351 - 593 */ 137434737Sbostic {760320, 311040}, /* f cyl 594 - 836 */ 137534737Sbostic {449280, 622080}, /* g cyl 351 - 836 */ 137634737Sbostic {129280, 320000} /* h cyl 101 - 350 */ 137734737Sbostic }, 137832211Skarels { 48, 24, 711, 512, "xsd", 137931039Skarels {0, 61056}, /* a cyl 0 - 52 */ 138031039Skarels {61056, 61056}, /* b cyl 53 - 105 */ 138131039Skarels {122112, 691200}, /* c cyl 106 - 705 */ 138231039Skarels {237312, 576000}, /* d cyl 206 - 705 */ 138331039Skarels {352512, 460800}, /* e cyl 306 - 705 */ 138431039Skarels {467712, 345600}, /* f cyl 406 - 705 */ 138531039Skarels {582912, 230400}, /* g cyl 506 - 705 */ 138631039Skarels {698112, 115200} /* h cyl 606 - 705 */ 138730573Skarels }, 138832211Skarels { 44, 20, 842, 512, "eagle", 138930601Skarels {0, 52800}, /* egl0a cyl 0 - 59 */ 139030601Skarels {52800, 66000}, /* egl0b cyl 60 - 134 */ 139130601Skarels {118800, 617760}, /* egl0c cyl 135 - 836 */ 139230756Skarels {736560, 4400}, /* egl0d cyl 837 - 841 */ 139331039Skarels {0, 736560}, /* egl0e cyl 0 - 836 */ 139431039Skarels {0, 740960}, /* egl0f cyl 0 - 841 */ 139530601Skarels {118800, 310640}, /* egl0g cyl 135 - 487 */ 139630601Skarels {429440, 307120} /* egl0h cyl 488 - 836 */ 139730573Skarels }, 139832211Skarels { 64, 10, 823, 512, "fuj", 139931039Skarels {0, 38400}, /* fuj0a cyl 0 - 59 */ 140031039Skarels {38400, 48000}, /* fuj0b cyl 60 - 134 */ 140131039Skarels {86400, 437120}, /* fuj0c cyl 135 - 817 */ 140231039Skarels {159360, 364160}, /* fuj0d cyl 249 - 817 */ 140331039Skarels {232320, 291200}, /* fuj0e cyl 363 - 817 */ 140431039Skarels {305280, 218240}, /* fuj0f cyl 477 - 817 */ 140531039Skarels {378240, 145280}, /* fuj0g cyl 591 - 817 */ 140631039Skarels {451200, 72320} /* fug0h cyl 705 - 817 */ 140730573Skarels }, 140832211Skarels { 32, 24, 711, 512, "xfd", 140930756Skarels { 0, 40704 }, /* a cyl 0 - 52 */ 141030756Skarels { 40704, 40704 }, /* b cyl 53 - 105 */ 141130756Skarels { 81408, 460800 }, /* c cyl 106 - 705 */ 141230756Skarels { 0, 81408 }, /* d cyl 709 - 710 (a & b) */ 141330756Skarels { 0, 542208 }, /* e cyl 0 - 705 */ 141430756Skarels { 40704, 501504 }, /* f cyl 53 - 705 (b & c) */ 141530756Skarels { 81408, 230400 }, /* g cyl 106 - 405 (1/2 of c) */ 141630756Skarels { 311808,230400 } /* h cyl 406 - 705 (1/2 of c) */ 141730573Skarels }, 141832211Skarels { 32, 19, 823, 512, "smd", 141931039Skarels {0, 40128}, /* a cyl 0-65 */ 142031039Skarels {40128, 27360}, /* b cyl 66-110 */ 142131039Skarels {67488, 429856}, /* c cyl 111-817 */ 142231039Skarels {139232, 358112}, /* d cyl 229 - 817 */ 142331039Skarels {210976, 286368}, /* e cyl 347 - 817 */ 142431039Skarels {282720, 214624}, /* f cyl 465 - 817 */ 142531039Skarels {354464, 142880}, /* g cyl 583 - 817 */ 142631039Skarels {426208, 71136} /* h cyl 701 - 817 */ 142730573Skarels }, 142832211Skarels { 18, 15, 1224, 1024, "mxd", 142932211Skarels {0, 21600}, /* a cyl 0-79 */ 143032211Skarels {21600, 22410}, /* b cyl 80-162 */ 143132211Skarels {44010, 285120}, /* c cyl 163-1217 */ 143232211Skarels #ifdef notyet 143332211Skarels {x, 237600}, /* d cyl y - 1217 */ 143432211Skarels {x, 190080}, /* e cyl y - 1217 */ 143532211Skarels {x, 142560}, /* f cyl y - 1217 */ 143632211Skarels {x, 95040}, /* g cyl y - 1217 */ 143732211Skarels {x, 47520} /* h cyl 701 - 817 */ 143832211Skarels #endif 143932211Skarels }, 144032211Skarels { 32, 10, 823, 512, "fsd", 144130756Skarels {0, 19200}, /* a cyl 0 - 59 */ 144230756Skarels {19200, 24000}, /* b cyl 60 - 134 */ 144330756Skarels {43200, 218560}, /* c cyl 135 - 817 */ 144430573Skarels } 144530519Ssam }; 144630519Ssam #define NVDST (sizeof (vdst) / sizeof (vdst[0])) 144730519Ssam 144825675Ssam /* 144930519Ssam * Construct a label for an unlabeled pack. We 145030519Ssam * deduce the drive type by reading from the last 145130519Ssam * track on successively smaller drives until we 145230519Ssam * don't get an error. 145325675Ssam */ 145430519Ssam vdmaptype(vi, lp) 145530519Ssam register struct vba_device *vi; 145630519Ssam register struct disklabel *lp; 145725675Ssam { 145830519Ssam register struct vdsoftc *vd; 145930519Ssam register struct vdst *p; 146032211Skarels struct vba_ctlr *vm = vi->ui_mi; 146130519Ssam int i; 146225675Ssam 146330519Ssam vd = &vdsoftc[vi->ui_ctlr]; 146430519Ssam for (p = vdst; p < &vdst[NVDST]; p++) { 146530519Ssam if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32) 146630519Ssam continue; 146730519Ssam lp->d_nsectors = p->nsec; 146830519Ssam lp->d_ntracks = p->ntrack; 146930519Ssam lp->d_ncylinders = p->ncyl; 147032211Skarels lp->d_secsize = p->secsize; 1471*35413Skarels DELAY(100000); 147230519Ssam if (!vdreset_drive(vi)) 147330519Ssam return (0); 1474*35413Skarels DELAY(100000); 147530519Ssam vd->vd_dcb.opcode = VDOP_RD; 147630519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 147730519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 147832211Skarels vd->vd_dcb.devselect = dksoftc[vi->ui_unit].dk_dcb.devselect; 147930756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 148030601Skarels vd->vd_dcb.trail.rwtrail.memadr = 148130601Skarels vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf); 148232211Skarels vd->vd_dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof(short); 148330519Ssam vd->vd_dcb.operrsta = 0; 148430519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2; 148530519Ssam vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1; 148630519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1; 148730519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 148830519Ssam vd->vd_mdcb.mdcb_status = 0; 148930519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 149030519Ssam if (!vdpoll(vm, 60)) 149130519Ssam printf(" during probe\n"); 149230519Ssam if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0) 149330519Ssam break; 149424004Ssam } 149532211Skarels if (p >= &vdst[NVDST]) 149630519Ssam return (0); 149732211Skarels 149830573Skarels for (i = 0; i < 8; i++) { 149930519Ssam lp->d_partitions[i].p_offset = p->parts[i].off; 150030519Ssam lp->d_partitions[i].p_size = p->parts[i].size; 150130519Ssam } 150230573Skarels lp->d_npartitions = 8; 150330519Ssam lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 150430519Ssam bcopy(p->name, lp->d_typename, 4); 150530519Ssam return (1); 150624004Ssam } 150730519Ssam #endif COMPAT_42 150824004Ssam #endif 1509