📄 vd.c
字号:
/* * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Computer Consoles Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)vd.c 7.15 (Berkeley) 7/23/92 */#include "dk.h"#if NVD > 0/* * Versabus VDDC/SMDE driver. */#include "sys/param.h"#include "sys/buf.h"#include "sys/cmap.h"#include "sys/conf.h"#include "sys/dkstat.h"#include "sys/disklabel.h"#include "sys/map.h"#include "sys/file.h"#include "sys/systm.h"#include "sys/user.h"#include "sys/vmmac.h"#include "sys/proc.h"#include "sys/syslog.h"#include "sys/kernel.h"#include "sys/ioctl.h"#include "sys/stat.h"#include "../include/cpu.h"#include "../include/mtpr.h"#include "../include/pte.h"#include "../vba/vbavar.h"#include "../vba/vdreg.h"#ifndef COMPAT_42#define COMPAT_42#endif#define B_FORMAT B_XXX /* XXX */#define vdunit(dev) (minor(dev) >> 3)#define vdpart(dev) (minor(dev) & 0x07)#define vdminor(unit,part) (((unit) << 3) | (part))struct vba_ctlr *vdminfo[NVD];struct vba_device *vddinfo[NDK];int vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy();long vdstd[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 };struct vba_driver vddriver = { vdprobe, vdslave, vdattach, vddgo, vdstd, "dk", vddinfo, "vd", vdminfo };/* * Per-controller state. */struct vdsoftc { u_short vd_flags;#define VD_PRINT 0x1 /* controller info printed */#define VD_STARTED 0x2 /* start command issued */#define VD_DOSEEKS 0x4 /* should overlap seeks */#define VD_SCATGATH 0x8 /* can do scatter-gather commands (correctly) */#define VD_LOCKED 0x10 /* locked for direct controller access */#define VD_WAIT 0x20 /* someone needs direct controller access */ u_short vd_type; /* controller type */ u_short vd_wticks; /* timeout */ u_short vd_secsize; /* sector size for controller */ struct mdcb vd_mdcb; /* master command block */ u_long vd_mdcbphys; /* physical address of vd_mdcb */ struct dcb vd_dcb; /* i/o command block */ u_long vd_dcbphys; /* physical address of vd_dcb */ struct vb_buf vd_rbuf; /* vba resources */} vdsoftc[NVD];#define VDMAXTIME 20 /* max time for operation, sec. *//* * Per-drive state. */struct dksoftc { int dk_state; /* open fsm */#ifndef SECSIZE u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */#endif SECSIZE int dk_wlabel; /* label sector is currently writable */ u_long dk_copenpart; /* character units open on this drive */ u_long dk_bopenpart; /* block units open on this drive */ u_long dk_openpart; /* all units open on this drive */ u_int dk_curcyl; /* last selected cylinder */ struct skdcb dk_dcb; /* seek command block */ u_long dk_dcbphys; /* physical address of dk_dcb */ int df_reg[3]; /* for formatting, in-out parameters */} dksoftc[NDK];/* * Drive states. Used during steps of open/initialization. * States < OPEN (> 0) are transient, during an open operation. * OPENRAW is used for unlabeled disks, to allow format operations. */#define CLOSED 0 /* disk is closed */#define WANTOPEN 1 /* open requested, not started */#define WANTOPENRAW 2 /* open requested, no label */#define RDLABEL 3 /* reading pack label */#define OPEN 4 /* intialized and ready */#define OPENRAW 5 /* open, no label */struct buf dkutab[NDK]; /* i/o queue headers */struct disklabel dklabel[NDK]; /* pack labels */#define b_cylin b_resid#define b_track b_error /* used for seek commands */#define b_seekf b_forw /* second queue on um_tab */#define b_seekl b_back /* second queue on um_tab */int vdwstart, vdwatch();/* * See if the controller is really there; if so, initialize it. */vdprobe(reg, vm) caddr_t reg; struct vba_ctlr *vm;{ register br, cvec; /* must be r12, r11 */ register struct vddevice *vdaddr = (struct vddevice *)reg; struct vdsoftc *vd; int s;#ifdef lint br = 0; cvec = br; br = cvec; vdintr(0);#endif if (badaddr((caddr_t)reg, 2)) return (0); vd = &vdsoftc[vm->um_ctlr]; vdaddr->vdreset = 0xffffffff; DELAY(1000000); if (vdaddr->vdreset != (unsigned)0xffffffff) { vd->vd_type = VDTYPE_VDDC; vd->vd_flags &= ~VD_DOSEEKS; DELAY(1000000); } else { vd->vd_type = VDTYPE_SMDE; vd->vd_flags |= VD_DOSEEKS; vdaddr->vdrstclr = 0; DELAY(3000000); } vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb); vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb); vm->um_addr = reg; /* XXX */ s = spl7(); if (vdinit_ctlr(vm, vd) == 0) { splx(s); return (0); } if (vd->vd_type == VDTYPE_SMDE) {#ifdef notdef /* * Attempt PROBE to get all drive status; * we take advantage of this in vdreset_drive * to try to avoid guessing games. */ (void) vdcmd(vm, VDOP_PROBE, 5, 0);#endif /* * Check for scatter-gather by checking firmware date * with IDENT command. The date is printed when * vdslave is first called, thus this must be * the last controller operation in vdprobe. */ vd->vd_dcb.trail.idtrail.date = 0; if (vdcmd(vm, VDOP_IDENT, 10, 0)) { uncache(&vd->vd_dcb.trail.idtrail.date); if (vd->vd_dcb.trail.idtrail.date != 0) vd->vd_flags |= VD_SCATGATH; } } splx(s); /* * Allocate page tables and i/o buffer. */ if (vbainit(&vd->vd_rbuf, MAXPHYS, vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT) == 0) { printf("vd%d: vbainit failed\n", vm->um_ctlr); return (0); } br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */ return (sizeof (struct vddevice));}/* * See if a drive is really there. * * Can't read pack label here as various data structures * aren't setup for doing a read in a straightforward * manner. Instead just probe for the drive and leave * the pack label stuff to the attach routine. *//* ARGSUSED */vdslave(vi, vdaddr) register struct vba_device *vi; struct vddevice *vdaddr;{ register struct disklabel *lp = &dklabel[vi->ui_unit]; register struct dksoftc *dk = &dksoftc[vi->ui_unit]; struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; int bcd(); if ((vd->vd_flags&VD_PRINT) == 0) { printf("vd%d: %s controller", vi->ui_ctlr, vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE"); if (vd->vd_flags & VD_SCATGATH) { char rev[5]; bcopy((caddr_t)&vd->vd_dcb.trail.idtrail.rev, rev, sizeof(vd->vd_dcb.trail.idtrail.rev)); printf(" firmware rev %s (%d-%d-%d)", rev, bcd((vd->vd_dcb.trail.idtrail.date >> 8) & 0xff), bcd(vd->vd_dcb.trail.idtrail.date & 0xff), bcd((vd->vd_dcb.trail.idtrail.date >> 16)&0xffff)); } printf("\n"); vd->vd_flags |= VD_PRINT; } /* * Initialize label enough to do a reset on * the drive. The remainder of the default * label values will be filled in in vdinit * at attach time. */ if (vd->vd_type == VDTYPE_SMDE) lp->d_secsize = VD_MAXSECSIZE; else lp->d_secsize = VDDC_SECSIZE; lp->d_nsectors = 66; /* only used on smd-e */ lp->d_ntracks = 23; lp->d_ncylinders = 850; lp->d_secpercyl = 66*23; lp->d_rpm = 3600; lp->d_npartitions = 1; lp->d_partitions[0].p_offset = 0; lp->d_partitions[0].p_size = LABELSECTOR + 1; /* * Initialize invariant portion of * dcb used for overlapped seeks. */ dk->dk_dcb.opcode = VDOP_SEEK; dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA; dk->dk_dcb.devselect = vi->ui_slave; dk->dk_dcb.trailcnt = sizeof (struct trseek) / sizeof (long); dk->dk_dcb.trail.sktrail.skaddr.sector = 0; dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb);#ifndef SECSIZE vd_setsecsize(dk, lp);#endif return (vdreset_drive(vi));}static intbcd(n) register u_int n;{ register int bin = 0; register int mul = 1; while (n) { bin += (n & 0xf) * mul; n >>= 4; mul *= 10; } return (bin);}vdattach(vi) register struct vba_device *vi;{ register int unit = vi->ui_unit; register struct disklabel *lp = &dklabel[unit]; /* * Try to initialize device and read pack label. */ if (vdinit(vdminor(unit, 0), 0) != 0) { printf(": unknown drive type"); return; } if (dksoftc[unit].dk_state == OPEN) printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>", lp->d_typename, lp->d_secsize, lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors); /* * (60 / rpm) / (sectors per track * (bytes per sector / 2)) */ if (vi->ui_dk >= 0) dk_wpms[vi->ui_dk] = (lp->d_rpm * lp->d_nsectors * lp->d_secsize) / 120;#ifdef notyet addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp);#endif}vdopen(dev, flags, fmt) dev_t dev; int flags, fmt;{ register unit = vdunit(dev); register struct disklabel *lp; register struct dksoftc *dk; register struct partition *pp; struct vba_device *vi; int s, error = 0, part = vdpart(dev), mask = 1 << part; daddr_t start, end; if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) return (ENXIO); lp = &dklabel[unit]; dk = &dksoftc[unit]; s = spl7(); while (dk->dk_state != OPEN && dk->dk_state != OPENRAW && dk->dk_state != CLOSED) if (error = tsleep((caddr_t)dk, (PZERO+1) | PCATCH, devopn, 0)) break; splx(s); if (error) return (error); if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) if (error = vdinit(dev, flags)) return (error); if (vdwstart == 0) { timeout(vdwatch, (caddr_t)0, hz); vdwstart++; } /* * Warn if a partion is opened * that overlaps another partition which is open * unless one is the "raw" partition (whole disk). */#define RAWPART 8 /* 'x' partition */ /* XXX */ if ((dk->dk_openpart & mask) == 0 && part != RAWPART) { pp = &lp->d_partitions[part]; start = pp->p_offset; end = pp->p_offset + pp->p_size; for (pp = lp->d_partitions; pp < &lp->d_partitions[lp->d_npartitions]; pp++) { if (pp->p_offset + pp->p_size <= start || pp->p_offset >= end) continue; if (pp - lp->d_partitions == RAWPART) continue; if (dk->dk_openpart & (1 << (pp - lp->d_partitions))) log(LOG_WARNING, "dk%d%c: overlaps open partition (%c)\n", unit, part + 'a', pp - lp->d_partitions + 'a'); } } if (part >= lp->d_npartitions) return (ENXIO); dk->dk_openpart |= mask; switch (fmt) { case S_IFCHR: dk->dk_copenpart |= mask; break; case S_IFBLK: dk->dk_bopenpart |= mask; break; } return (0);}/* ARGSUSED */vdclose(dev, flags, fmt) dev_t dev; int flags, fmt;{ register int unit = vdunit(dev); register struct dksoftc *dk = &dksoftc[unit]; int part = vdpart(dev), mask = 1 << part; switch (fmt) { case S_IFCHR: dk->dk_copenpart &= ~mask; break; case S_IFBLK: dk->dk_bopenpart &= ~mask; break; } if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0) dk->dk_openpart &= ~mask; /* * Should wait for i/o to complete on this partition * even if others are open, but wait for work on blkflush(). */ if (dk->dk_openpart == 0) { int s = spl7(); while (dkutab[unit].b_actf) sleep((caddr_t)dk, PZERO-1); splx(s); dk->dk_state = CLOSED; dk->dk_wlabel = 0; } return (0);}vdinit(dev, flags) dev_t dev; int flags;{ register struct disklabel *lp; register struct dksoftc *dk; struct vba_device *vi; int unit = vdunit(dev), error = 0; char *msg, *readdisklabel(); extern int cold; dk = &dksoftc[unit]; if (flags & O_NDELAY) { dk->dk_state = OPENRAW; return (0); } dk->dk_state = RDLABEL; lp = &dklabel[unit]; vi = vddinfo[unit]; if (msg = readdisklabel(dev, vdstrategy, lp)) { if (cold) { printf(": %s", msg); dk->dk_state = CLOSED; } else { log(LOG_ERR, "dk%d: %s\n", unit, msg); dk->dk_state = OPENRAW; }#ifdef COMPAT_42 vdlock(vi->ui_ctlr); if (vdmaptype(vi, lp)) dk->dk_state = OPEN; vdunlock(vi->ui_ctlr);#endif } else { /* * Now that we have the label, configure * the correct drive parameters. */ vdlock(vi->ui_ctlr); if (vdreset_drive(vi)) dk->dk_state = OPEN; else { dk->dk_state = CLOSED; error = ENXIO; } vdunlock(vi->ui_ctlr); }#ifndef SECSIZE vd_setsecsize(dk, lp);#endif wakeup((caddr_t)dk); return (error);}#ifndef SECSIZEvd_setsecsize(dk, lp) register struct dksoftc *dk; register struct disklabel *lp;{ int mul; /* * Calculate scaling shift for mapping * DEV_BSIZE blocks to drive sectors. */ mul = DEV_BSIZE / lp->d_secsize; dk->dk_bshift = 0; while ((mul >>= 1) > 0) dk->dk_bshift++;}#endif SECSIZE/*ARGSUSED*/vddgo(vm) struct vba_device *vm;{}vdstrategy(bp) register struct buf *bp;{ register struct vba_device *vi; register struct disklabel *lp; register struct dksoftc *dk; register int unit; register daddr_t sn; struct buf *dp; daddr_t sz, maxsz; int part, s; unit = vdunit(bp->b_dev); if (unit >= NDK) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -