134528Skarels /* 234528Skarels * Copyright (c) 1988 Regents of the University of California. 334528Skarels * All rights reserved. 434528Skarels * 5*35056Skarels * This code is derived from software contributed to Berkeley by 6*35056Skarels * Computer Consoles Inc. 7*35056Skarels * 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*35056Skarels * @(#)vd.c 7.6 (Berkeley) 07/09/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) */ 7930519Ssam u_short vd_type; /* controller type */ 8030519Ssam u_short vd_wticks; /* timeout */ 8130519Ssam struct mdcb vd_mdcb; /* master command block */ 8230519Ssam u_long vd_mdcbphys; /* physical address of vd_mdcb */ 8330519Ssam struct dcb vd_dcb; /* i/o command block */ 8430519Ssam u_long vd_dcbphys; /* physical address of vd_dcb */ 8530601Skarels struct vb_buf vd_rbuf; /* vba resources */ 8630519Ssam } vdsoftc[NVD]; 8730519Ssam 8834396Skarels #define VDMAXTIME 20 /* max time for operation, sec. */ 8934396Skarels 9030519Ssam /* 9125675Ssam * Per-drive state. 9225675Ssam */ 9330519Ssam struct dksoftc { 9434076Skarels int dk_state; /* open fsm */ 9530756Skarels #ifndef SECSIZE 9630756Skarels u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */ 9730756Skarels #endif SECSIZE 9834076Skarels int dk_wlabel; /* label sector is currently writable */ 9932576Skarels u_long dk_copenpart; /* character units open on this drive */ 10032576Skarels u_long dk_bopenpart; /* block units open on this drive */ 10132576Skarels u_long dk_openpart; /* all units open on this drive */ 10230519Ssam u_int dk_curcyl; /* last selected cylinder */ 10330756Skarels struct skdcb dk_dcb; /* seek command block */ 10430519Ssam u_long dk_dcbphys; /* physical address of dk_dcb */ 10534396Skarels int df_reg[3]; /* for formatting, in-out parameters */ 10630519Ssam } dksoftc[NDK]; 10724004Ssam 10824004Ssam /* 10930519Ssam * Drive states. Used during steps of open/initialization. 11030519Ssam * States < OPEN (> 0) are transient, during an open operation. 11134076Skarels * OPENRAW is used for unlabeled disks, to allow format operations. 11225675Ssam */ 11330519Ssam #define CLOSED 0 /* disk is closed */ 11430519Ssam #define WANTOPEN 1 /* open requested, not started */ 11530519Ssam #define WANTOPENRAW 2 /* open requested, no label */ 11630519Ssam #define RDLABEL 3 /* reading pack label */ 11730519Ssam #define OPEN 4 /* intialized and ready */ 11830519Ssam #define OPENRAW 5 /* open, no label */ 11924004Ssam 12030519Ssam struct buf dkutab[NDK]; /* i/o queue headers */ 12130519Ssam struct disklabel dklabel[NDK]; /* pack labels */ 12224004Ssam 12330519Ssam #define b_cylin b_resid 12430574Skarels #define b_track b_error /* used for seek commands */ 12530574Skarels #define b_seekf b_forw /* second queue on um_tab */ 12630574Skarels #define b_seekl b_back /* second queue on um_tab */ 12730519Ssam 12830519Ssam int vdwstart, vdwatch(); 12930519Ssam 13024004Ssam /* 13125675Ssam * See if the controller is really there; if so, initialize it. 13225675Ssam */ 13325857Ssam vdprobe(reg, vm) 13425857Ssam caddr_t reg; 13525857Ssam struct vba_ctlr *vm; 13625675Ssam { 13725857Ssam register br, cvec; /* must be r12, r11 */ 13830519Ssam register struct vddevice *vdaddr = (struct vddevice *)reg; 13930519Ssam struct vdsoftc *vd; 14030573Skarels int s; 14125857Ssam 14230370Skarels #ifdef lint 14330370Skarels br = 0; cvec = br; br = cvec; 14430370Skarels vdintr(0); 14530370Skarels #endif 14625857Ssam if (badaddr((caddr_t)reg, 2)) 14725675Ssam return (0); 14830519Ssam vd = &vdsoftc[vm->um_ctlr]; 14930519Ssam vdaddr->vdreset = 0xffffffff; 15025675Ssam DELAY(1000000); 15130519Ssam if (vdaddr->vdreset != (unsigned)0xffffffff) { 15230519Ssam vd->vd_type = VDTYPE_VDDC; 15330519Ssam vd->vd_flags &= ~VD_DOSEEKS; 15425675Ssam DELAY(1000000); 15525675Ssam } else { 15630519Ssam vd->vd_type = VDTYPE_SMDE; 15730519Ssam vd->vd_flags |= VD_DOSEEKS; 15830519Ssam vdaddr->vdrstclr = 0; 15925675Ssam DELAY(3000000); 16030519Ssam vdaddr->vdcsr = 0; 16130519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 16230519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 16330519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 16430519Ssam vdaddr->vdtcf_data = AM_ENPDA; 16530519Ssam vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS | 16629921Skarels XMD_32BIT | BSZ_16WRD | 16725925Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 16825675Ssam } 16930519Ssam vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb); 17030519Ssam vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb); 17130519Ssam vm->um_addr = reg; /* XXX */ 17230573Skarels s = spl7(); 17330519Ssam if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { 17430519Ssam printf("vd%d: %s cmd failed\n", vm->um_ctlr, 17530519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 17630573Skarels splx(s); 17730519Ssam return (0); 17830519Ssam } 17930756Skarels if (vd->vd_type == VDTYPE_SMDE) { 18030756Skarels vd->vd_dcb.trail.idtrail.date = 0; 18130756Skarels if (vdcmd(vm, VDOP_IDENT, 10)) { 18230756Skarels uncache(&vd->vd_dcb.trail.idtrail.date); 18330756Skarels if (vd->vd_dcb.trail.idtrail.date != 0) 18430756Skarels vd->vd_flags |= VD_SCATGATH; 18530756Skarels } 18630756Skarels } 18730573Skarels splx(s); 18825925Ssam /* 18925950Ssam * Allocate page tables and i/o buffer. 19025925Ssam */ 19132211Skarels if (vbainit(&vd->vd_rbuf, MAXPHYS, 19232211Skarels vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT) == 0) { 19332211Skarels printf("vd%d: vbainit failed\n", vm->um_ctlr); 19432211Skarels return (0); 19532211Skarels } 19625857Ssam br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */ 19730519Ssam return (sizeof (struct vddevice)); 19825675Ssam } 19924004Ssam 20024004Ssam /* 20130519Ssam * See if a drive is really there. 20230519Ssam * 20330519Ssam * Can't read pack label here as various data structures 20430519Ssam * aren't setup for doing a read in a straightforward 20530519Ssam * manner. Instead just probe for the drive and leave 20630519Ssam * the pack label stuff to the attach routine. 20725675Ssam */ 20834076Skarels /* ARGSUSED */ 20934076Skarels vdslave(vi, vdaddr) 21025675Ssam register struct vba_device *vi; 21130519Ssam struct vddevice *vdaddr; 21225675Ssam { 21330519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 21432211Skarels register struct dksoftc *dk = &dksoftc[vi->ui_unit]; 21530519Ssam struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 21624004Ssam 21730519Ssam if ((vd->vd_flags&VD_INIT) == 0) { 21830756Skarels printf("vd%d: %s controller%s\n", vi->ui_ctlr, 21930756Skarels vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE", 22030756Skarels (vd->vd_flags & VD_SCATGATH) ? " with scatter-gather" : ""); 22130519Ssam vd->vd_flags |= VD_INIT; 22225675Ssam } 22330519Ssam 22425675Ssam /* 22530519Ssam * Initialize label enough to do a reset on 22630519Ssam * the drive. The remainder of the default 22730519Ssam * label values will be filled in in vdinit 22830519Ssam * at attach time. 22925675Ssam */ 23032211Skarels if (vd->vd_type == VDTYPE_SMDE) 23132211Skarels lp->d_secsize = VD_MAXSECSIZE; 23232211Skarels else 23332211Skarels lp->d_secsize = VDDC_SECSIZE; 23434396Skarels lp->d_nsectors = 66; /* only used on smd-e */ 23534076Skarels lp->d_ntracks = 23; 23634396Skarels lp->d_ncylinders = 850; 23734396Skarels lp->d_secpercyl = 66*23; 23834592Skarels lp->d_npartitions = 1; 23934592Skarels lp->d_partitions[0].p_offset = 0; 24034592Skarels lp->d_partitions[0].p_size = LABELSECTOR + 1; 24124004Ssam 24230519Ssam /* 24330519Ssam * Initialize invariant portion of 24430519Ssam * dcb used for overlapped seeks. 24530519Ssam */ 24630519Ssam dk->dk_dcb.opcode = VDOP_SEEK; 24730519Ssam dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA; 24830519Ssam dk->dk_dcb.devselect = vi->ui_slave; 24930756Skarels dk->dk_dcb.trailcnt = sizeof (struct trseek) / sizeof (long); 25030519Ssam dk->dk_dcb.trail.sktrail.skaddr.sector = 0; 25130519Ssam dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb); 25232211Skarels #ifndef SECSIZE 25332211Skarels vd_setsecsize(dk, lp); 25432211Skarels #endif 25532211Skarels return (vdreset_drive(vi)); 25632211Skarels } 25732211Skarels 25832211Skarels vdattach(vi) 25932211Skarels register struct vba_device *vi; 26032211Skarels { 26132211Skarels register int unit = vi->ui_unit; 26232211Skarels register struct disklabel *lp = &dklabel[unit]; 26332211Skarels 26430601Skarels /* 26530601Skarels * Try to initialize device and read pack label. 26630601Skarels */ 26730601Skarels if (vdinit(vdminor(unit, 0), 0) != 0) { 26830601Skarels printf(": unknown drive type"); 26930601Skarels return; 27030601Skarels } 27132211Skarels if (dksoftc[unit].dk_state == OPEN) 27232211Skarels printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>", 27332211Skarels lp->d_typename, lp->d_secsize, 27432211Skarels lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors); 27530519Ssam /* 27630519Ssam * (60 / rpm) / (sectors per track * (bytes per sector / 2)) 27730519Ssam */ 27830519Ssam if (vi->ui_dk >= 0) 27930519Ssam dk_mspw[vi->ui_dk] = 120.0 / 28030519Ssam (lp->d_rpm * lp->d_nsectors * lp->d_secsize); 28130519Ssam #ifdef notyet 28230573Skarels addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp); 28330519Ssam #endif 28424004Ssam } 28524004Ssam 28630756Skarels vdopen(dev, flags, fmt) 28730519Ssam dev_t dev; 28830756Skarels int flags, fmt; 28924004Ssam { 29030519Ssam register unit = vdunit(dev); 29130519Ssam register struct disklabel *lp; 29230519Ssam register struct dksoftc *dk; 29330519Ssam register struct partition *pp; 29430519Ssam struct vba_device *vi; 29530756Skarels int s, error, part = vdpart(dev), mask = 1 << part; 29630519Ssam daddr_t start, end; 29724004Ssam 29830519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 29930519Ssam return (ENXIO); 30030519Ssam lp = &dklabel[unit]; 30130519Ssam dk = &dksoftc[unit]; 30230519Ssam 30330519Ssam s = spl7(); 30430519Ssam while (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 30530519Ssam dk->dk_state != CLOSED) 30630519Ssam sleep((caddr_t)dk, PZERO+1); 30730519Ssam splx(s); 30830519Ssam if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 30930519Ssam if (error = vdinit(dev, flags)) 31030519Ssam return (error); 31130573Skarels 31230573Skarels if (vdwstart == 0) { 31330573Skarels timeout(vdwatch, (caddr_t)0, hz); 31430573Skarels vdwstart++; 31530573Skarels } 31630519Ssam /* 31730519Ssam * Warn if a partion is opened 31830519Ssam * that overlaps another partition which is open 31930519Ssam * unless one is the "raw" partition (whole disk). 32030519Ssam */ 32132211Skarels #define RAWPART 8 /* 'x' partition */ /* XXX */ 32232576Skarels if ((dk->dk_openpart & mask) == 0 && part != RAWPART) { 32330519Ssam pp = &lp->d_partitions[part]; 32430519Ssam start = pp->p_offset; 32530519Ssam end = pp->p_offset + pp->p_size; 32630519Ssam for (pp = lp->d_partitions; 32730519Ssam pp < &lp->d_partitions[lp->d_npartitions]; pp++) { 32830519Ssam if (pp->p_offset + pp->p_size <= start || 32930519Ssam pp->p_offset >= end) 33030519Ssam continue; 33130519Ssam if (pp - lp->d_partitions == RAWPART) 33230519Ssam continue; 33330519Ssam if (dk->dk_openpart & (1 << (pp - lp->d_partitions))) 33430519Ssam log(LOG_WARNING, 33530519Ssam "dk%d%c: overlaps open partition (%c)\n", 33630519Ssam unit, part + 'a', 33730519Ssam pp - lp->d_partitions + 'a'); 33830519Ssam } 33924004Ssam } 34030519Ssam if (part >= lp->d_npartitions) 34130519Ssam return (ENXIO); 34230756Skarels dk->dk_openpart |= mask; 34330756Skarels switch (fmt) { 34430756Skarels case S_IFCHR: 34530756Skarels dk->dk_copenpart |= mask; 34630756Skarels break; 34730756Skarels case S_IFBLK: 34830756Skarels dk->dk_bopenpart |= mask; 34930756Skarels break; 35030756Skarels } 35130519Ssam return (0); 35225675Ssam } 35324004Ssam 35434528Skarels /* ARGSUSED */ 35530756Skarels vdclose(dev, flags, fmt) 35630519Ssam dev_t dev; 35730756Skarels int flags, fmt; 35824004Ssam { 35930519Ssam register int unit = vdunit(dev); 36030519Ssam register struct dksoftc *dk = &dksoftc[unit]; 36130756Skarels int part = vdpart(dev), mask = 1 << part; 36224004Ssam 36330756Skarels switch (fmt) { 36430756Skarels case S_IFCHR: 36530756Skarels dk->dk_copenpart &= ~mask; 36630756Skarels break; 36730756Skarels case S_IFBLK: 36830756Skarels dk->dk_bopenpart &= ~mask; 36930756Skarels break; 37030756Skarels } 37130756Skarels if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0) 37230756Skarels dk->dk_openpart &= ~mask; 37330519Ssam /* 37430519Ssam * Should wait for i/o to complete on this partition 37530519Ssam * even if others are open, but wait for work on blkflush(). 37630519Ssam */ 37730519Ssam if (dk->dk_openpart == 0) { 37830573Skarels int s = spl7(); 37930573Skarels while (dkutab[unit].b_actf) 38030573Skarels sleep((caddr_t)dk, PZERO-1); 38130519Ssam splx(s); 38230519Ssam dk->dk_state = CLOSED; 38334076Skarels dk->dk_wlabel = 0; 38424004Ssam } 38530756Skarels return (0); 38625675Ssam } 38724004Ssam 38830519Ssam vdinit(dev, flags) 38930519Ssam dev_t dev; 39030519Ssam int flags; 39125675Ssam { 39230519Ssam register struct disklabel *lp; 39330519Ssam register struct dksoftc *dk; 39430519Ssam struct vba_device *vi; 39530519Ssam int unit = vdunit(dev), error = 0; 39630756Skarels char *msg, *readdisklabel(); 39730519Ssam extern int cold; 39825675Ssam 39930519Ssam dk = &dksoftc[unit]; 40030519Ssam if (flags & O_NDELAY) { 40130519Ssam dk->dk_state = OPENRAW; 40234528Skarels return (0); 40330519Ssam } 40430519Ssam dk->dk_state = RDLABEL; 40530519Ssam lp = &dklabel[unit]; 40630519Ssam vi = vddinfo[unit]; 40730756Skarels if (msg = readdisklabel(dev, vdstrategy, lp)) { 40834076Skarels if (cold) { 40930601Skarels printf(": %s", msg); 41034076Skarels dk->dk_state = CLOSED; 41134076Skarels } else { 41232211Skarels log(LOG_ERR, "dk%d: %s\n", unit, msg); 41334076Skarels dk->dk_state = OPENRAW; 41434076Skarels } 41530519Ssam #ifdef COMPAT_42 41634076Skarels if (vdmaptype(vi, lp)) 41730519Ssam dk->dk_state = OPEN; 41830519Ssam #endif 41930756Skarels } else { 42030756Skarels /* 42130756Skarels * Now that we have the label, configure 42230756Skarels * the correct drive parameters. 42330756Skarels */ 42432211Skarels if (vdreset_drive(vi)) 42532211Skarels dk->dk_state = OPEN; 42632211Skarels else { 42730756Skarels dk->dk_state = CLOSED; 42830756Skarels error = ENXIO; 42932211Skarels } 43025675Ssam } 43130756Skarels #ifndef SECSIZE 43232211Skarels vd_setsecsize(dk, lp); 43332211Skarels #endif 43430519Ssam wakeup((caddr_t)dk); 43530519Ssam return (error); 43624004Ssam } 43724004Ssam 43832211Skarels #ifndef SECSIZE 43932211Skarels vd_setsecsize(dk, lp) 44032211Skarels register struct dksoftc *dk; 44132211Skarels register struct disklabel *lp; 44232211Skarels { 44332211Skarels int mul; 44432211Skarels 44532211Skarels /* 44632211Skarels * Calculate scaling shift for mapping 44732211Skarels * DEV_BSIZE blocks to drive sectors. 44832211Skarels */ 44932211Skarels mul = DEV_BSIZE / lp->d_secsize; 45032211Skarels dk->dk_bshift = 0; 45132211Skarels while ((mul >>= 1) > 0) 45232211Skarels dk->dk_bshift++; 45332211Skarels } 45432211Skarels #endif SECSIZE 45532211Skarels 45625675Ssam /*ARGSUSED*/ 45730519Ssam vddgo(vm) 45830519Ssam struct vba_device *vm; 45924004Ssam { 46024004Ssam 46124004Ssam } 46224004Ssam 46324004Ssam vdstrategy(bp) 46425675Ssam register struct buf *bp; 46524004Ssam { 46630519Ssam register struct vba_device *vi; 46730519Ssam register struct disklabel *lp; 46830519Ssam register struct dksoftc *dk; 46930519Ssam register int unit; 47030573Skarels register daddr_t sn; 47130519Ssam struct buf *dp; 47230573Skarels daddr_t sz, maxsz; 47330519Ssam int part, s; 47424004Ssam 47530519Ssam unit = vdunit(bp->b_dev); 47632211Skarels if (unit >= NDK) { 47729954Skarels bp->b_error = ENXIO; 47825675Ssam goto bad; 47929954Skarels } 48030519Ssam vi = vddinfo[unit]; 48130519Ssam lp = &dklabel[unit]; 48230519Ssam if (vi == 0 || vi->ui_alive == 0) { 48330519Ssam bp->b_error = ENXIO; 48430519Ssam goto bad; 48530519Ssam } 48630519Ssam dk = &dksoftc[unit]; 48730519Ssam if (dk->dk_state < OPEN) 48830519Ssam goto q; 48934076Skarels if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) { 49034076Skarels bp->b_error = EROFS; 49134076Skarels goto bad; 49234076Skarels } 49330519Ssam part = vdpart(bp->b_dev); 49430519Ssam if ((dk->dk_openpart & (1 << part)) == 0) { 49530519Ssam bp->b_error = ENODEV; 49630519Ssam goto bad; 49730519Ssam } 49832211Skarels sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize; 49930519Ssam maxsz = lp->d_partitions[part].p_size; 50030756Skarels #ifndef SECSIZE 50130756Skarels sn = bp->b_blkno << dk->dk_bshift; 50230756Skarels #else SECSIZE 50330573Skarels sn = bp->b_blkno; 50430756Skarels #endif SECSIZE 50534076Skarels if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR && 50634076Skarels #if LABELSECTOR != 0 50734076Skarels sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR && 50834076Skarels #endif 50934076Skarels (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) { 51034076Skarels bp->b_error = EROFS; 51134076Skarels goto bad; 51234076Skarels } 51330519Ssam if (sn < 0 || sn + sz > maxsz) { 51430519Ssam if (sn == maxsz) { 51529954Skarels bp->b_resid = bp->b_bcount; 51629954Skarels goto done; 51729954Skarels } 51830756Skarels sz = maxsz - sn; 51930573Skarels if (sz <= 0) { 52030573Skarels bp->b_error = EINVAL; 52130573Skarels goto bad; 52230573Skarels } 52330573Skarels bp->b_bcount = sz * lp->d_secsize; 52425675Ssam } 52530519Ssam bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl; 52630756Skarels #ifdef SECSIZE 52730756Skarels if (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0) 52830756Skarels panic("vdstrat blksize"); 52930756Skarels #endif SECSIZE 53030519Ssam q: 53125675Ssam s = spl7(); 53230519Ssam dp = &dkutab[vi->ui_unit]; 53330519Ssam disksort(dp, bp); 53430519Ssam if (!dp->b_active) { 53530519Ssam (void) vdustart(vi); 53630573Skarels if (!vi->ui_mi->um_tab.b_active) 53730519Ssam vdstart(vi->ui_mi); 53824004Ssam } 53930519Ssam splx(s); 54024004Ssam return; 54125675Ssam bad: 54229954Skarels bp->b_flags |= B_ERROR; 54329954Skarels done: 54430519Ssam biodone(bp); 54530519Ssam return; 54624004Ssam } 54724004Ssam 54830519Ssam vdustart(vi) 54930519Ssam register struct vba_device *vi; 55024004Ssam { 55130519Ssam register struct buf *bp, *dp; 55230519Ssam register struct vba_ctlr *vm; 55330519Ssam register int unit = vi->ui_unit; 55430519Ssam register struct dksoftc *dk; 55530519Ssam register struct vdsoftc *vd; 55630519Ssam struct disklabel *lp; 55724004Ssam 55830519Ssam dp = &dkutab[unit]; 55930519Ssam /* 56030519Ssam * If queue empty, nothing to do. 56130519Ssam */ 56230519Ssam if ((bp = dp->b_actf) == NULL) 56330519Ssam return; 56430519Ssam /* 56530574Skarels * If drive is off-cylinder and controller supports seeks, 56630574Skarels * place drive on seek queue for controller. 56730574Skarels * Otherwise, place on transfer queue. 56830519Ssam */ 56930519Ssam vd = &vdsoftc[vi->ui_ctlr]; 57030519Ssam dk = &dksoftc[unit]; 57130574Skarels vm = vi->ui_mi; 57230519Ssam if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) { 57330519Ssam lp = &dklabel[unit]; 57430574Skarels bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors; 57530574Skarels if (vm->um_tab.b_seekf == NULL) 57630574Skarels vm->um_tab.b_seekf = dp; 57730574Skarels else 57830574Skarels vm->um_tab.b_seekl->b_forw = dp; 57930574Skarels vm->um_tab.b_seekl = dp; 58030574Skarels } else { 58130574Skarels if (vm->um_tab.b_actf == NULL) 58230574Skarels vm->um_tab.b_actf = dp; 58330574Skarels else 58430574Skarels vm->um_tab.b_actl->b_forw = dp; 58530574Skarels vm->um_tab.b_actl = dp; 58630519Ssam } 58730573Skarels dp->b_forw = NULL; 58830573Skarels dp->b_active++; 58925675Ssam } 59025675Ssam 59125675Ssam /* 59230519Ssam * Start next transfer on a controller. 59330574Skarels * There are two queues of drives, the first on-cylinder 59430574Skarels * and the second off-cylinder from their next transfers. 59530574Skarels * Perform the first transfer for the first drive on the on-cylinder 59630574Skarels * queue, if any, otherwise the first transfer for the first drive 59730574Skarels * on the second queue. Initiate seeks on remaining drives on the 59830574Skarels * off-cylinder queue, then move them all to the on-cylinder queue. 59925675Ssam */ 60030519Ssam vdstart(vm) 60130519Ssam register struct vba_ctlr *vm; 60225675Ssam { 60325675Ssam register struct buf *bp; 60430519Ssam register struct vba_device *vi; 60530519Ssam register struct vdsoftc *vd; 60630519Ssam register struct dksoftc *dk; 60730519Ssam register struct disklabel *lp; 60830519Ssam register struct dcb **dcbp; 60930519Ssam struct buf *dp; 61030519Ssam int sn, tn; 61125675Ssam 61230519Ssam loop: 61330519Ssam /* 61430519Ssam * Pull a request off the controller queue. 61530519Ssam */ 61630574Skarels if ((dp = vm->um_tab.b_actf) == NULL && 61730574Skarels (dp = vm->um_tab.b_seekf) == NULL) 61830519Ssam return; 61930519Ssam if ((bp = dp->b_actf) == NULL) { 62030601Skarels if (dp == vm->um_tab.b_actf) 62130601Skarels vm->um_tab.b_actf = dp->b_forw; 62230601Skarels else 62330601Skarels vm->um_tab.b_seekf = dp->b_forw; 62430519Ssam goto loop; 62530519Ssam } 62625675Ssam 62724004Ssam /* 62830519Ssam * Mark controller busy, and determine 62930519Ssam * destination of this request. 63024004Ssam */ 63130519Ssam vm->um_tab.b_active++; 63230519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 63330519Ssam dk = &dksoftc[vi->ui_unit]; 63430756Skarels #ifndef SECSIZE 63530756Skarels sn = bp->b_blkno << dk->dk_bshift; 63630756Skarels #else SECSIZE 63730573Skarels sn = bp->b_blkno; 63830756Skarels #endif SECSIZE 63930519Ssam lp = &dklabel[vi->ui_unit]; 64030519Ssam sn %= lp->d_secpercyl; 64130519Ssam tn = sn / lp->d_nsectors; 64230519Ssam sn %= lp->d_nsectors; 64330519Ssam 64430519Ssam /* 64530519Ssam * Construct dcb for read/write command. 64630519Ssam */ 64730519Ssam vd = &vdsoftc[vm->um_ctlr]; 64830519Ssam vd->vd_dcb.intflg = DCBINT_DONE; 64932211Skarels vd->vd_dcb.devselect = dk->dk_dcb.devselect; 65030519Ssam vd->vd_dcb.operrsta = 0; 65130519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 65230519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin; 65330519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 65430519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 65530574Skarels dk->dk_curcyl = bp->b_cylin; 65630574Skarels bp->b_track = 0; /* init overloaded field */ 65730756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 65834396Skarels if (bp->b_flags & B_FORMAT) 65934396Skarels vd->vd_dcb.opcode = dk->dk_op; 66034396Skarels else if (vd->vd_flags & VD_SCATGATH && 66134396Skarels ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0) 66230756Skarels vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW; 66334396Skarels else 66430756Skarels vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD; 66534396Skarels 66634396Skarels switch (vd->vd_dcb.opcode) { 66734396Skarels case VDOP_FSECT: 66834396Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 66934396Skarels vd->vd_dcb.trail.fmtrail.nsectors = bp->b_bcount / 67034396Skarels lp->d_secsize; 67134396Skarels vd->vd_dcb.trail.fmtrail.hdr = *(dskadr *)&dk->dk_althdr; 67234396Skarels vd->vd_dcb.trail.rwtrail.disk.cylinder |= dk->dk_fmtflags; 67334396Skarels goto setupaddr; 67434396Skarels 67534396Skarels case VDOP_RDRAW: 67634396Skarels case VDOP_RD: 67734396Skarels case VDOP_WD: 67834396Skarels vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1; 67934396Skarels setupaddr: 68030756Skarels vd->vd_dcb.trail.rwtrail.memadr = 68134528Skarels vbasetup(bp, &vd->vd_rbuf, (int)lp->d_secsize); 68234396Skarels break; 68334396Skarels 68434396Skarels case VDOP_RAS: 68534396Skarels case VDOP_GAW: 68634396Skarels vd->vd_dcb.trailcnt += vba_sgsetup(bp, &vd->vd_rbuf, 68734396Skarels &vd->vd_dcb.trail.sgtrail); 68834396Skarels break; 68930756Skarels } 69030574Skarels if (vi->ui_dk >= 0) { 69130574Skarels dk_busy |= 1<<vi->ui_dk; 69230574Skarels dk_xfer[vi->ui_dk]++; 69330574Skarels dk_wds[vi->ui_dk] += bp->b_bcount>>6; 69430574Skarels } 69530519Ssam 69630519Ssam /* 69730519Ssam * Look for any seeks to be performed on other drives on this 69830519Ssam * controller. If overlapped seeks exist, insert seek commands 69930519Ssam * on the controller's command queue before the transfer. 70030519Ssam */ 70130519Ssam dcbp = &vd->vd_mdcb.mdcb_head; 70230519Ssam 70330574Skarels if (dp == vm->um_tab.b_seekf) 70430574Skarels dp = dp->b_forw; 70530574Skarels else 70630574Skarels dp = vm->um_tab.b_seekf; 70730574Skarels for (; dp != NULL; dp = dp->b_forw) { 70830574Skarels if ((bp = dp->b_actf) == NULL) 70930574Skarels continue; 71030574Skarels vi = vddinfo[vdunit(bp->b_dev)]; 71130574Skarels dk = &dksoftc[vi->ui_unit]; 71230519Ssam dk->dk_curcyl = bp->b_cylin; 71330574Skarels if (vi->ui_dk >= 0) 71430574Skarels dk_seek[vi->ui_dk]++; 71530574Skarels dk->dk_dcb.operrsta = 0; 71630574Skarels dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin; 71730574Skarels dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track; 71830574Skarels *dcbp = (struct dcb *)dk->dk_dcbphys; 71930574Skarels dcbp = &dk->dk_dcb.nxtdcb; 72024004Ssam } 72130519Ssam *dcbp = (struct dcb *)vd->vd_dcbphys; 72230574Skarels if (vm->um_tab.b_actf) 72330574Skarels vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf; 72430574Skarels else 72530574Skarels vm->um_tab.b_actf = vm->um_tab.b_seekf; 72630601Skarels if (vm->um_tab.b_seekf) 72730601Skarels vm->um_tab.b_actl = vm->um_tab.b_seekl; 72830574Skarels vm->um_tab.b_seekf = 0; 72924004Ssam 73030519Ssam /* 73130519Ssam * Initiate operation. 73230519Ssam */ 73330519Ssam vd->vd_mdcb.mdcb_status = 0; 73430519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 73524004Ssam } 73624004Ssam 73730519Ssam #define DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE) 73824004Ssam /* 73924004Ssam * Handle a disk interrupt. 74024004Ssam */ 74125675Ssam vdintr(ctlr) 74230519Ssam register ctlr; 74324004Ssam { 74430519Ssam register struct buf *bp, *dp; 74530519Ssam register struct vba_ctlr *vm = vdminfo[ctlr]; 74630519Ssam register struct vba_device *vi; 74730519Ssam register struct vdsoftc *vd = &vdsoftc[ctlr]; 74830519Ssam register status; 74934528Skarels int timedout; 75030573Skarels struct dksoftc *dk; 75124004Ssam 75230519Ssam if (!vm->um_tab.b_active) { 75325675Ssam printf("vd%d: stray interrupt\n", ctlr); 75424004Ssam return; 75524004Ssam } 75625675Ssam /* 75730519Ssam * Get device and block structures, and a pointer 75830519Ssam * to the vba_device for the drive. 75925675Ssam */ 76030519Ssam dp = vm->um_tab.b_actf; 76130519Ssam bp = dp->b_actf; 76230519Ssam vi = vddinfo[vdunit(bp->b_dev)]; 76334528Skarels dk = &dksoftc[vi->ui_unit]; 76430574Skarels if (vi->ui_dk >= 0) 76530574Skarels dk_busy &= ~(1<<vi->ui_dk); 76634396Skarels timedout = (vd->vd_wticks >= VDMAXTIME); 76730519Ssam /* 76830519Ssam * Check for and process errors on 76930519Ssam * either the drive or the controller. 77030519Ssam */ 77130519Ssam uncache(&vd->vd_dcb.operrsta); 77230519Ssam status = vd->vd_dcb.operrsta; 77334396Skarels if (bp->b_flags & B_FORMAT) { 77434396Skarels dk->dk_operrsta = status; 77534396Skarels uncache(&vd->vd_dcb.err_code); 77634396Skarels dk->dk_ecode = vd->vd_dcb.err_code; 77734396Skarels } 77834396Skarels if (status & VDERR_HARD || timedout) { 77934528Skarels if (vd->vd_type == VDTYPE_SMDE) 78030601Skarels uncache(&vd->vd_dcb.err_code); 78130519Ssam if (status & DCBS_WPT) { 78230519Ssam /* 78330519Ssam * Give up on write locked devices immediately. 78430519Ssam */ 78530573Skarels printf("dk%d: write locked\n", vi->ui_unit); 78630519Ssam bp->b_flags |= B_ERROR; 78734396Skarels } else if (status & VDERR_RETRY || timedout) { 78832211Skarels int endline = 1; 78932211Skarels 79034396Skarels if (status & VDERR_CTLR || timedout) { 79134396Skarels vdharderr("controller err", 79234396Skarels vd, bp, &vd->vd_dcb); 79334396Skarels printf("; resetting controller..."); 79434396Skarels vdreset_ctlr(vm); 79534396Skarels } else if (status & VDERR_DRIVE) { 79634396Skarels vdharderr("drive err", vd, bp, &vd->vd_dcb); 79734396Skarels printf("; resetting drive..."); 79830519Ssam if (!vdreset_drive(vi)) 79930519Ssam vi->ui_alive = 0; 80032211Skarels } else 80132211Skarels endline = 0; 80230519Ssam /* 80330519Ssam * Retry transfer once, unless reset failed. 80430519Ssam */ 80534396Skarels if (!vi->ui_alive || dp->b_errcnt++ >= 2 || 80634396Skarels bp->b_flags & B_FORMAT) { 80732211Skarels if (endline) 80832211Skarels printf("\n"); 80930519Ssam goto hard; 81032211Skarels } 81132211Skarels 81232211Skarels if (endline) 81332211Skarels printf(" retrying\n"); 81430519Ssam vm->um_tab.b_active = 0; /* force retry */ 81530519Ssam } else { 81630519Ssam hard: 81730519Ssam bp->b_flags |= B_ERROR; 81834396Skarels vdharderr("hard error", vd, bp, &vd->vd_dcb); 81930519Ssam printf("\n"); 82030519Ssam } 82130519Ssam } else if (status & DCBS_SOFT) 82234528Skarels vdsofterr(bp, &vd->vd_dcb); 82334396Skarels vd->vd_wticks = 0; 82430519Ssam if (vm->um_tab.b_active) { 82530519Ssam vm->um_tab.b_active = 0; 82630519Ssam vm->um_tab.b_actf = dp->b_forw; 82730519Ssam dp->b_active = 0; 82830519Ssam dp->b_errcnt = 0; 82930519Ssam dp->b_actf = bp->av_forw; 83030519Ssam bp->b_resid = 0; 83130601Skarels vbadone(bp, &vd->vd_rbuf); 83230519Ssam biodone(bp); 83330370Skarels /* 83430519Ssam * If this unit has more work to do, 83530519Ssam * then start it up right away. 83630370Skarels */ 83730519Ssam if (dp->b_actf) 83830519Ssam vdustart(vi); 83934528Skarels else if (dk->dk_openpart == 0) 84030573Skarels wakeup((caddr_t)dk); 84124004Ssam } 84225675Ssam /* 84330519Ssam * If there are devices ready to 84430519Ssam * transfer, start the controller. 84525675Ssam */ 84630601Skarels if (vm->um_tab.b_actf || vm->um_tab.b_seekf) 84730519Ssam vdstart(vm); 84824004Ssam } 84924004Ssam 85034396Skarels vdharderr(what, vd, bp, dcb) 85134396Skarels char *what; 85234396Skarels struct vdsoftc *vd; 85334396Skarels register struct buf *bp; 85434396Skarels register struct dcb *dcb; 85534396Skarels { 85634396Skarels int unit = vdunit(bp->b_dev), status = dcb->operrsta; 85734396Skarels register struct disklabel *lp = &dklabel[unit]; 85834528Skarels int blkdone; 85934396Skarels 86034396Skarels if (vd->vd_wticks < VDMAXTIME) 86134396Skarels status &= ~DONTCARE; 86234710Skarels blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) * 86334710Skarels lp->d_nsectors + dcb->err_sec - 86434710Skarels lp->d_partitions[vdpart(bp->b_dev)].p_offset) >> 86534710Skarels dksoftc[unit].dk_bshift) - bp->b_blkno; 86634528Skarels diskerr(bp, "dk", what, LOG_PRINTF, blkdone, lp); 86734528Skarels printf(", status %b", status, VDERRBITS); 86834396Skarels if (vd->vd_type == VDTYPE_SMDE) 86934396Skarels printf(" ecode %x", dcb->err_code); 87034396Skarels } 87134396Skarels 87234528Skarels vdsofterr(bp, dcb) 87325675Ssam register struct buf *bp; 87430519Ssam register struct dcb *dcb; 87525675Ssam { 87634562Skarels int unit = vdunit(bp->b_dev); 87734562Skarels struct disklabel *lp = &dklabel[unit]; 87834528Skarels int status = dcb->operrsta; 87934528Skarels int blkdone; 88025675Ssam 88134710Skarels blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) * 88234710Skarels lp->d_nsectors + dcb->err_sec - 88334710Skarels lp->d_partitions[vdpart(bp->b_dev)].p_offset) >> 88434710Skarels dksoftc[unit].dk_bshift) - bp->b_blkno; 88534528Skarels 88634528Skarels if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) { 88734528Skarels diskerr(bp, "dk", "soft error", LOG_WARNING, blkdone, lp); 88834528Skarels addlog(", status %b ecode %x\n", status, VDERRBITS, 88934396Skarels dcb->err_code); 89034528Skarels } else { 89134528Skarels diskerr(bp, "dk", "soft ecc", LOG_WARNING, blkdone, lp); 89234528Skarels addlog("\n"); 89334528Skarels } 89425675Ssam } 89525675Ssam 89630519Ssam vdioctl(dev, cmd, data, flag) 89725675Ssam dev_t dev; 89830519Ssam int cmd; 89930519Ssam caddr_t data; 90030519Ssam int flag; 90124004Ssam { 90232576Skarels register int unit = vdunit(dev); 90330519Ssam register struct disklabel *lp = &dklabel[unit]; 90434076Skarels register struct dksoftc *dk = &dksoftc[unit]; 90534640Skarels int error = 0, vdformat(); 90624004Ssam 90730519Ssam switch (cmd) { 90830519Ssam 90930519Ssam case DIOCGDINFO: 91030519Ssam *(struct disklabel *)data = *lp; 91130519Ssam break; 91230519Ssam 91330573Skarels case DIOCGPART: 91430573Skarels ((struct partinfo *)data)->disklab = lp; 91530573Skarels ((struct partinfo *)data)->part = 91630573Skarels &lp->d_partitions[vdpart(dev)]; 91730519Ssam break; 91830519Ssam 91930519Ssam case DIOCSDINFO: 92030519Ssam if ((flag & FWRITE) == 0) 92130519Ssam error = EBADF; 92230519Ssam else 92332576Skarels error = setdisklabel(lp, (struct disklabel *)data, 92434076Skarels (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart); 92534396Skarels if (error == 0 && dk->dk_state == OPENRAW && 92634396Skarels vdreset_drive(vddinfo[unit])) 92734076Skarels dk->dk_state = OPEN; 92830519Ssam break; 92930519Ssam 93034076Skarels case DIOCWLABEL: 93134076Skarels if ((flag & FWRITE) == 0) 93234076Skarels error = EBADF; 93334076Skarels else 93434076Skarels dk->dk_wlabel = *(int *)data; 93534076Skarels break; 93634076Skarels 93732576Skarels case DIOCWDINFO: 93832576Skarels if ((flag & FWRITE) == 0) 93930519Ssam error = EBADF; 94032576Skarels else if ((error = setdisklabel(lp, (struct disklabel *)data, 94134076Skarels (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) { 94234640Skarels int wlab; 94334640Skarels 94434076Skarels dk->dk_state = OPEN; 94534640Skarels /* simulate opening partition 0 so write succeeds */ 94634640Skarels dk->dk_openpart |= (1 << 0); /* XXX */ 94734640Skarels wlab = dk->dk_wlabel; 94834640Skarels dk->dk_wlabel = 1; 94932576Skarels error = writedisklabel(dev, vdstrategy, lp); 95034640Skarels dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart; 95134640Skarels dk->dk_wlabel = wlab; 95234076Skarels } 95330519Ssam break; 95430519Ssam 95534396Skarels case DIOCWFORMAT: 95634396Skarels { 95734396Skarels register struct format_op *fop; 95834396Skarels struct uio auio; 95934396Skarels struct iovec aiov; 96034396Skarels 96134396Skarels if ((flag & FWRITE) == 0) { 96234396Skarels error = EBADF; 96334396Skarels break; 96434396Skarels } 96534396Skarels fop = (struct format_op *)data; 96634396Skarels aiov.iov_base = fop->df_buf; 96734396Skarels aiov.iov_len = fop->df_count; 96834396Skarels auio.uio_iov = &aiov; 96934396Skarels auio.uio_iovcnt = 1; 97034396Skarels auio.uio_resid = fop->df_count; 97134396Skarels auio.uio_segflg = UIO_USERSPACE; 97234396Skarels auio.uio_offset = fop->df_startblk * lp->d_secsize; 97334396Skarels dk->dk_operrsta = fop->dk_operrsta; 97434396Skarels dk->dk_ecode = fop->dk_ecode; 97534396Skarels /* 97634396Skarels * Don't return errors, as the format op won't get copied 97734396Skarels * out if we return nonzero. Callers must check the returned 97834396Skarels * count. 97934396Skarels */ 98034396Skarels (void) physio(vdformat, (struct buf *)NULL, dev, 98134396Skarels (cmd == DIOCWFORMAT ? B_WRITE : B_READ), minphys, &auio); 98234396Skarels fop->df_count -= auio.uio_resid; 98334396Skarels fop->dk_operrsta = dk->dk_operrsta; 98434396Skarels fop->dk_ecode = dk->dk_ecode; 98534396Skarels break; 98634396Skarels } 98734396Skarels 98830519Ssam default: 98930519Ssam error = ENOTTY; 99030519Ssam break; 99124004Ssam } 99232606Skarels return (error); 99324004Ssam } 99424004Ssam 99534396Skarels vdformat(bp) 99634396Skarels struct buf *bp; 99734396Skarels { 99834396Skarels bp->b_flags |= B_FORMAT; 99934396Skarels vdstrategy(bp); 100034396Skarels } 100134396Skarels 100225675Ssam /* 100330519Ssam * Watch for lost interrupts. 100425675Ssam */ 100530519Ssam vdwatch() 100630519Ssam { 100730519Ssam register struct vdsoftc *vd; 100830519Ssam register struct vba_ctlr *vm; 100934528Skarels register int ctlr; 101034396Skarels int s; 101130519Ssam 101230519Ssam timeout(vdwatch, (caddr_t)0, hz); 101330519Ssam for (ctlr = 0; ctlr < NVD; ctlr++) { 101430519Ssam vm = vdminfo[ctlr]; 101530519Ssam if (vm == 0 || vm->um_alive == 0) 101630519Ssam continue; 101730519Ssam vd = &vdsoftc[ctlr]; 101834396Skarels s = spl7(); 101934396Skarels if (vm->um_tab.b_active && vd->vd_wticks++ >= VDMAXTIME) { 102030519Ssam printf("vd%d: lost interrupt\n", ctlr); 102134396Skarels #ifdef maybe 102234396Skarels VDABORT((struct vddevice *)vm->um_addr, vd->vd_type); 102334396Skarels #endif 102434396Skarels vdintr(ctlr); 102530519Ssam } 102634396Skarels splx(s); 102730519Ssam } 102830519Ssam } 102930519Ssam 103030519Ssam #define DBSIZE 64 /* controller limit with 1K sectors */ 103130519Ssam /* 103230519Ssam * Crash dump. 103330519Ssam */ 103430519Ssam vddump(dev) 103530519Ssam dev_t dev; 103624004Ssam { 103730519Ssam register struct vba_device *vi; 103830519Ssam register struct vba_ctlr *vm; 103930519Ssam register struct disklabel *lp; 104030519Ssam register struct vdsoftc *vd; 104130519Ssam struct dksoftc *dk; 104230519Ssam int part, unit, num; 104330601Skarels u_long start; 104424004Ssam 104530519Ssam start = 0; 104630519Ssam unit = vdunit(dev); 104730519Ssam if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 104830519Ssam return (ENXIO); 104930519Ssam dk = &dksoftc[unit]; 105034076Skarels if (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 105134076Skarels vdinit(vdminor(unit, 0), 0) != 0) 105230519Ssam return (ENXIO); 105330519Ssam lp = &dklabel[unit]; 105430519Ssam part = vdpart(dev); 105530519Ssam if (part >= lp->d_npartitions) 105630519Ssam return (ENXIO); 105732211Skarels vm = vi->ui_mi; 105830519Ssam vdreset_ctlr(vm); 105930519Ssam if (dumplo < 0) 106030519Ssam return (EINVAL); 106130519Ssam /* 106230756Skarels * Maxfree is in pages, dumplo is in DEV_BSIZE units. 106330519Ssam */ 106430519Ssam num = maxfree * (NBPG / lp->d_secsize); 106530756Skarels dumplo *= DEV_BSIZE / lp->d_secsize; 106630519Ssam if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size) 106730519Ssam num = lp->d_partitions[vdpart(dev)].p_size - dumplo; 106830519Ssam vd = &vdsoftc[vm->um_ctlr]; 106930519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 107030519Ssam vd->vd_dcb.opcode = VDOP_WD; 107132211Skarels vd->vd_dcb.devselect = dk->dk_dcb.devselect; 107230756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 107330519Ssam while (num > 0) { 107430519Ssam int nsec, cn, sn, tn; 107530519Ssam 107630519Ssam nsec = MIN(num, DBSIZE); 107730601Skarels sn = dumplo + start / lp->d_secsize; 107830519Ssam cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) / 107930519Ssam lp->d_secpercyl; 108030519Ssam sn %= lp->d_secpercyl; 108130519Ssam tn = sn / lp->d_nsectors; 108230519Ssam sn %= lp->d_nsectors; 108330519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 108430519Ssam vd->vd_dcb.trail.rwtrail.memadr = start; 108530519Ssam vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1; 108630519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = cn; 108730519Ssam vd->vd_dcb.trail.rwtrail.disk.track = tn; 108830519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = sn; 108930519Ssam vd->vd_dcb.operrsta = 0; 109030519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 109130519Ssam if (!vdpoll(vm, 5)) { 109230519Ssam printf(" during dump\n"); 109330519Ssam return (EIO); 109430519Ssam } 109530519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 109630519Ssam printf("dk%d: hard error, status=%b\n", unit, 109730519Ssam vd->vd_dcb.operrsta, VDERRBITS); 109830519Ssam return (EIO); 109930519Ssam } 110030519Ssam start += nsec * lp->d_secsize; 110130519Ssam num -= nsec; 110225675Ssam } 110330519Ssam return (0); 110424004Ssam } 110524004Ssam 110624004Ssam vdsize(dev) 110725675Ssam dev_t dev; 110824004Ssam { 110930519Ssam register int unit = vdunit(dev); 111030519Ssam register struct dksoftc *dk; 111130519Ssam struct vba_device *vi; 111230519Ssam struct disklabel *lp; 111324004Ssam 111430519Ssam if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 || 111530519Ssam (dk = &dksoftc[unit])->dk_state != OPEN) 111625675Ssam return (-1); 111730519Ssam lp = &dklabel[unit]; 111830756Skarels #ifdef SECSIZE 111930573Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size); 112030756Skarels #else SECSIZE 112130756Skarels return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift); 112230756Skarels #endif SECSIZE 112324004Ssam } 112424004Ssam 112525675Ssam /* 112625675Ssam * Perform a controller reset. 112725675Ssam */ 112830519Ssam vdreset_ctlr(vm) 112930519Ssam register struct vba_ctlr *vm; 113024004Ssam { 113130519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 113230519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 113330519Ssam register int unit; 113430519Ssam struct vba_device *vi; 113525675Ssam 113630519Ssam VDRESET(vdaddr, vd->vd_type); 113730519Ssam if (vd->vd_type == VDTYPE_SMDE) { 113830519Ssam vdaddr->vdcsr = 0; 113930519Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 114030519Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 114130519Ssam vdaddr->vdtcf_trail = AM_ENPDA; 114230519Ssam vdaddr->vdtcf_data = AM_ENPDA; 114330519Ssam vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD | 114425675Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 114525675Ssam } 114630519Ssam if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { 114730519Ssam printf("%s cmd failed\n", 114830519Ssam vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 114930370Skarels return; 115025675Ssam } 115130519Ssam for (unit = 0; unit < NDK; unit++) 115230519Ssam if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive) 115330519Ssam (void) vdreset_drive(vi); 115430519Ssam } 115530519Ssam 115630519Ssam vdreset_drive(vi) 115730519Ssam register struct vba_device *vi; 115830519Ssam { 115930519Ssam register struct disklabel *lp = &dklabel[vi->ui_unit]; 116030519Ssam struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; 116130519Ssam struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 116232211Skarels register struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 116332211Skarels register struct dksoftc *dk = &dksoftc[vi->ui_unit]; 116430519Ssam 116530519Ssam top: 116630519Ssam vd->vd_dcb.opcode = VDOP_CONFIG; /* command */ 116730519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 116830519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 116930519Ssam vd->vd_dcb.operrsta = 0; 117032211Skarels vd->vd_dcb.devselect = vi->ui_slave | lp->d_devflags; 117130519Ssam vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders; 117230519Ssam vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks; 117330519Ssam if (vd->vd_type == VDTYPE_SMDE) { 117430756Skarels vd->vd_dcb.trailcnt = sizeof (struct treset) / sizeof (long); 117530519Ssam vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors; 117630601Skarels vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack; 117732211Skarels vd->vd_dcb.trail.rstrail.recovery = VDRF_NORMAL; 117830519Ssam } else 117930519Ssam vd->vd_dcb.trailcnt = 2; /* XXX */ 118030519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 118130519Ssam vd->vd_mdcb.mdcb_status = 0; 118230519Ssam VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type); 118330519Ssam if (!vdpoll(vm, 5)) { 118430519Ssam printf(" during config\n"); 118530519Ssam return (0); 118625675Ssam } 118730519Ssam if (vd->vd_dcb.operrsta & VDERR_HARD) { 118832211Skarels if (vd->vd_type == VDTYPE_SMDE) { 118932211Skarels if (lp->d_devflags == 0) { 119032211Skarels lp->d_devflags = VD_ESDI; 119132211Skarels goto top; 119232211Skarels } 119332211Skarels #ifdef notdef 119432211Skarels /* this doesn't work, STA_US isn't set(?) */ 119532211Skarels if ((vdaddr->vdstatus[vi->ui_slave] & STA_US) == 0) 119632211Skarels return (0); 119732211Skarels #endif 119832211Skarels } 119930519Ssam if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) 120032211Skarels printf("dk%d: config error %b ecode %x\n", vi->ui_unit, 120134396Skarels vd->vd_dcb.operrsta, VDERRBITS, 120234396Skarels (u_char) vd->vd_dcb.err_code); 120332211Skarels else if ((vd->vd_flags & VD_STARTED) == 0) { 120430519Ssam int started; 120530519Ssam 120632211Skarels printf(" starting drives, wait ... "); 120730519Ssam vd->vd_flags |= VD_STARTED; 120830519Ssam started = (vdcmd(vm, VDOP_START, 10) == 1); 120930519Ssam DELAY(62000000); 121032211Skarels printf("done"); 121132211Skarels lp->d_devflags = 0; 121230519Ssam if (started) 121330519Ssam goto top; 121430519Ssam } 121530519Ssam return (0); 121630519Ssam } 121732211Skarels dk->dk_dcb.devselect |= lp->d_devflags; 121830519Ssam return (1); 121925675Ssam } 122024004Ssam 122125675Ssam /* 122230519Ssam * Perform a command w/o trailer. 122325675Ssam */ 122430519Ssam vdcmd(vm, cmd, t) 122530519Ssam register struct vba_ctlr *vm; 122625675Ssam { 122730519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 122825675Ssam 122930519Ssam vd->vd_dcb.opcode = cmd; /* command */ 123030519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 123130519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 123230519Ssam vd->vd_dcb.operrsta = 0; 123330519Ssam vd->vd_dcb.devselect = 0; 123430519Ssam vd->vd_dcb.trailcnt = 0; 123530519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 123630519Ssam vd->vd_mdcb.mdcb_status = 0; 123730519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 123830519Ssam if (!vdpoll(vm, t)) { 123930519Ssam printf(" during init\n"); 124030370Skarels return (0); 124130370Skarels } 124230519Ssam return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0); 124325675Ssam } 124425675Ssam 124525925Ssam /* 124630519Ssam * Poll controller until operation 124730519Ssam * completes or timeout expires. 124825925Ssam */ 124930519Ssam vdpoll(vm, t) 125030519Ssam register struct vba_ctlr *vm; 125125925Ssam register int t; 125225925Ssam { 125330519Ssam register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 125430519Ssam register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 125525925Ssam 125625925Ssam t *= 1000; 125730370Skarels for (;;) { 125830519Ssam uncache(&vd->vd_dcb.operrsta); 125930519Ssam if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT)) 126030370Skarels break; 126125925Ssam if (--t <= 0) { 126230519Ssam printf("vd%d: controller timeout", vm->um_ctlr); 126330519Ssam VDABORT(vdaddr, vd->vd_type); 126425925Ssam return (0); 126525925Ssam } 126630370Skarels DELAY(1000); 126725925Ssam } 126830519Ssam if (vd->vd_type == VDTYPE_SMDE) { 126930519Ssam do { 127025925Ssam DELAY(50); 127130519Ssam uncache(&vdaddr->vdcsr); 127230519Ssam } while (vdaddr->vdcsr & CS_GO); 127332211Skarels DELAY(300); 127432211Skarels uncache(&vd->vd_dcb.err_code); 127525925Ssam } 127625925Ssam DELAY(200); 127730519Ssam uncache(&vd->vd_dcb.operrsta); 127825925Ssam return (1); 127925925Ssam } 128025925Ssam 128130519Ssam #ifdef COMPAT_42 128230519Ssam struct vdst { 128330519Ssam int nsec; /* sectors/track */ 128430519Ssam int ntrack; /* tracks/cylinder */ 128530519Ssam int ncyl; /* cylinders */ 128632211Skarels int secsize; /* sector size */ 128730519Ssam char *name; /* type name */ 128830519Ssam struct { 128930519Ssam int off; /* partition offset in sectors */ 129030519Ssam int size; /* partition size in sectors */ 129130573Skarels } parts[8]; 129230519Ssam } vdst[] = { 129332211Skarels { 66, 23, 850, 512, "NEC 800", 129432211Skarels {0, 1290300}, /* a cyl 0 - 849 */ 129532211Skarels }, 129634737Sbostic { 64, 20, 842, 512, "2361a", 129734737Sbostic {0, 61440}, /* a cyl 0 - 47 */ 129834737Sbostic {61440, 67840}, /* b cyl 48 - 100 */ 129934737Sbostic {129280, 942080}, /* c cyl 101 - 836 */ 130034737Sbostic {0, 1071360}, /* d cyl 0 - 836 */ 130134737Sbostic {449280, 311040}, /* e cyl 351 - 593 */ 130234737Sbostic {760320, 311040}, /* f cyl 594 - 836 */ 130334737Sbostic {449280, 622080}, /* g cyl 351 - 836 */ 130434737Sbostic {129280, 320000} /* h cyl 101 - 350 */ 130534737Sbostic }, 130632211Skarels { 48, 24, 711, 512, "xsd", 130731039Skarels {0, 61056}, /* a cyl 0 - 52 */ 130831039Skarels {61056, 61056}, /* b cyl 53 - 105 */ 130931039Skarels {122112, 691200}, /* c cyl 106 - 705 */ 131031039Skarels {237312, 576000}, /* d cyl 206 - 705 */ 131131039Skarels {352512, 460800}, /* e cyl 306 - 705 */ 131231039Skarels {467712, 345600}, /* f cyl 406 - 705 */ 131331039Skarels {582912, 230400}, /* g cyl 506 - 705 */ 131431039Skarels {698112, 115200} /* h cyl 606 - 705 */ 131530573Skarels }, 131632211Skarels { 44, 20, 842, 512, "eagle", 131730601Skarels {0, 52800}, /* egl0a cyl 0 - 59 */ 131830601Skarels {52800, 66000}, /* egl0b cyl 60 - 134 */ 131930601Skarels {118800, 617760}, /* egl0c cyl 135 - 836 */ 132030756Skarels {736560, 4400}, /* egl0d cyl 837 - 841 */ 132131039Skarels {0, 736560}, /* egl0e cyl 0 - 836 */ 132231039Skarels {0, 740960}, /* egl0f cyl 0 - 841 */ 132330601Skarels {118800, 310640}, /* egl0g cyl 135 - 487 */ 132430601Skarels {429440, 307120} /* egl0h cyl 488 - 836 */ 132530573Skarels }, 132632211Skarels { 64, 10, 823, 512, "fuj", 132731039Skarels {0, 38400}, /* fuj0a cyl 0 - 59 */ 132831039Skarels {38400, 48000}, /* fuj0b cyl 60 - 134 */ 132931039Skarels {86400, 437120}, /* fuj0c cyl 135 - 817 */ 133031039Skarels {159360, 364160}, /* fuj0d cyl 249 - 817 */ 133131039Skarels {232320, 291200}, /* fuj0e cyl 363 - 817 */ 133231039Skarels {305280, 218240}, /* fuj0f cyl 477 - 817 */ 133331039Skarels {378240, 145280}, /* fuj0g cyl 591 - 817 */ 133431039Skarels {451200, 72320} /* fug0h cyl 705 - 817 */ 133530573Skarels }, 133632211Skarels { 32, 24, 711, 512, "xfd", 133730756Skarels { 0, 40704 }, /* a cyl 0 - 52 */ 133830756Skarels { 40704, 40704 }, /* b cyl 53 - 105 */ 133930756Skarels { 81408, 460800 }, /* c cyl 106 - 705 */ 134030756Skarels { 0, 81408 }, /* d cyl 709 - 710 (a & b) */ 134130756Skarels { 0, 542208 }, /* e cyl 0 - 705 */ 134230756Skarels { 40704, 501504 }, /* f cyl 53 - 705 (b & c) */ 134330756Skarels { 81408, 230400 }, /* g cyl 106 - 405 (1/2 of c) */ 134430756Skarels { 311808,230400 } /* h cyl 406 - 705 (1/2 of c) */ 134530573Skarels }, 134632211Skarels { 32, 19, 823, 512, "smd", 134731039Skarels {0, 40128}, /* a cyl 0-65 */ 134831039Skarels {40128, 27360}, /* b cyl 66-110 */ 134931039Skarels {67488, 429856}, /* c cyl 111-817 */ 135031039Skarels {139232, 358112}, /* d cyl 229 - 817 */ 135131039Skarels {210976, 286368}, /* e cyl 347 - 817 */ 135231039Skarels {282720, 214624}, /* f cyl 465 - 817 */ 135331039Skarels {354464, 142880}, /* g cyl 583 - 817 */ 135431039Skarels {426208, 71136} /* h cyl 701 - 817 */ 135530573Skarels }, 135632211Skarels { 18, 15, 1224, 1024, "mxd", 135732211Skarels {0, 21600}, /* a cyl 0-79 */ 135832211Skarels {21600, 22410}, /* b cyl 80-162 */ 135932211Skarels {44010, 285120}, /* c cyl 163-1217 */ 136032211Skarels #ifdef notyet 136132211Skarels {x, 237600}, /* d cyl y - 1217 */ 136232211Skarels {x, 190080}, /* e cyl y - 1217 */ 136332211Skarels {x, 142560}, /* f cyl y - 1217 */ 136432211Skarels {x, 95040}, /* g cyl y - 1217 */ 136532211Skarels {x, 47520} /* h cyl 701 - 817 */ 136632211Skarels #endif 136732211Skarels }, 136832211Skarels { 32, 10, 823, 512, "fsd", 136930756Skarels {0, 19200}, /* a cyl 0 - 59 */ 137030756Skarels {19200, 24000}, /* b cyl 60 - 134 */ 137130756Skarels {43200, 218560}, /* c cyl 135 - 817 */ 137230573Skarels } 137330519Ssam }; 137430519Ssam #define NVDST (sizeof (vdst) / sizeof (vdst[0])) 137530519Ssam 137625675Ssam /* 137730519Ssam * Construct a label for an unlabeled pack. We 137830519Ssam * deduce the drive type by reading from the last 137930519Ssam * track on successively smaller drives until we 138030519Ssam * don't get an error. 138125675Ssam */ 138230519Ssam vdmaptype(vi, lp) 138330519Ssam register struct vba_device *vi; 138430519Ssam register struct disklabel *lp; 138525675Ssam { 138630519Ssam register struct vdsoftc *vd; 138730519Ssam register struct vdst *p; 138832211Skarels struct vba_ctlr *vm = vi->ui_mi; 138930519Ssam int i; 139025675Ssam 139130519Ssam vd = &vdsoftc[vi->ui_ctlr]; 139230519Ssam for (p = vdst; p < &vdst[NVDST]; p++) { 139330519Ssam if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32) 139430519Ssam continue; 139530519Ssam lp->d_nsectors = p->nsec; 139630519Ssam lp->d_ntracks = p->ntrack; 139730519Ssam lp->d_ncylinders = p->ncyl; 139832211Skarels lp->d_secsize = p->secsize; 139930519Ssam if (!vdreset_drive(vi)) 140030519Ssam return (0); 140130519Ssam vd->vd_dcb.opcode = VDOP_RD; 140230519Ssam vd->vd_dcb.intflg = DCBINT_NONE; 140330519Ssam vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 140432211Skarels vd->vd_dcb.devselect = dksoftc[vi->ui_unit].dk_dcb.devselect; 140530756Skarels vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 140630601Skarels vd->vd_dcb.trail.rwtrail.memadr = 140730601Skarels vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf); 140832211Skarels vd->vd_dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof(short); 140930519Ssam vd->vd_dcb.operrsta = 0; 141030519Ssam vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2; 141130519Ssam vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1; 141230519Ssam vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1; 141330519Ssam vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 141430519Ssam vd->vd_mdcb.mdcb_status = 0; 141530519Ssam VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 141630519Ssam if (!vdpoll(vm, 60)) 141730519Ssam printf(" during probe\n"); 141830519Ssam if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0) 141930519Ssam break; 142024004Ssam } 142132211Skarels if (p >= &vdst[NVDST]) 142230519Ssam return (0); 142332211Skarels 142430573Skarels for (i = 0; i < 8; i++) { 142530519Ssam lp->d_partitions[i].p_offset = p->parts[i].off; 142630519Ssam lp->d_partitions[i].p_size = p->parts[i].size; 142730519Ssam } 142830573Skarels lp->d_npartitions = 8; 142930519Ssam lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 143030519Ssam lp->d_rpm = 3600; 143130519Ssam bcopy(p->name, lp->d_typename, 4); 143230519Ssam return (1); 143324004Ssam } 143430519Ssam #endif COMPAT_42 143524004Ssam #endif 1436