📄 hd.c
字号:
/* * Copyright (c) 1988 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Harris Corp. * * 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. * * @(#)hd.c 7.12 (Berkeley) 12/16/90 */#include "hd.h"#if NHD > 0#include "sys/param.h"#include "sys/buf.h"#include "sys/conf.h"#include "sys/dkstat.h"#include "sys/disklabel.h"#include "sys/file.h"#include "sys/systm.h"#include "sys/vmmac.h"#include "sys/time.h"#include "sys/proc.h"#include "sys/uio.h"#include "sys/syslog.h"#include "sys/kernel.h"#include "sys/ioctl.h"#include "sys/stat.h"#include "sys/errno.h"#include "../include/cpu.h"#include "../include/mtpr.h"#include "../vba/vbavar.h"#include "../vba/hdreg.h"#define b_cylin b_resid#define hdunit(dev) (minor(dev)>>3)#define hdpart(dev) (minor(dev)&0x07)#define hdminor(unit, part) (((unit)<<3)|(part))struct vba_ctlr *hdcminfo[NHDC];struct vba_device *hddinfo[NHD];int hdcprobe(), hdslave(), hdattach(), hddgo(), hdstrategy();long hdstd[] = { 0 };struct vba_driver hdcdriver = { hdcprobe, hdslave, hdattach, hddgo, hdstd, "hd", hddinfo, "hdc", hdcminfo };/* * Per-controller state. */struct hdcsoftc { u_short hdc_flags;#define HDC_INIT 0x01 /* controller initialized */#define HDC_STARTED 0x02 /* start command issued */#define HDC_LOCKED 0x04 /* locked for direct controller access */#define HDC_WAIT 0x08 /* someone needs direct controller access */ u_short hdc_wticks; /* timeout */ struct master_mcb *hdc_mcbp; /* address of controller mcb */ struct registers *hdc_reg; /* base address of i/o regs */ struct vb_buf hdc_rbuf; /* vba resources */ struct master_mcb hdc_mcb; /* controller mcb */} hdcsoftc[NHDC];#define HDCMAXTIME 20 /* max time for operation, sec. */#define HDCINTERRUPT 0xf0 /* interrupt vector *//* * Per-drive state; probably everything should be "hd_", not "dk_", * but it's not worth it, and dk is a better mnemonic for disk anyway. */struct dksoftc {#ifdef COMPAT_42 u_short dk_def_cyl; /* definition track cylinder address */#endif int dk_state; /* open fsm */ u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */ int dk_wlabel; /* if label sector is writeable */ 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 */ int dk_unit; /* unit# */ int dk_ctlr; /* controller# */ int dk_format; /* if format program is using disk */ struct buf dk_utab; /* i/o queue header */ struct disklabel dk_label; /* disklabel for this disk */ struct mcb dk_mcb; /* disk mcb */} dksoftc[NHD];/* * 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 */int hdcwstart, hdcwatch();/* see if the controller is really there, if so, init it. *//* ARGSUSED */hdcprobe(reg, vm) caddr_t reg; /* register */ struct vba_ctlr *vm;{ register int br, cvec; /* must be r12, r11 */ register struct hdcsoftc *hdc; static struct module_id id; struct pte *dummypte; caddr_t putl; /* initialize the hdc controller structure. */ hdc = &hdcsoftc[vm->um_ctlr]; if (!vbmemalloc(1, reg, &dummypte, &putl)) { printf("hdc%d: vbmemalloc failed.\n", vm->um_ctlr); return(0); } hdc->hdc_reg = (struct registers *)putl; /* * try and ping the MID register; side effect of wbadaddr is to read * the module id; the controller is bad if it's not an hdc, the hdc's * writeable control store is not loaded, or the hdc failed the * functional integrity test; */ if (wbadaddr(&hdc->hdc_reg->module_id, 4, vtoph((struct process *)NULL, &id))) return(0); DELAY(10000); mtpr(PADC, 0); if (id.module_id != (u_char)HDC_MID) { printf("hdc%d: bad module id; id = %x.\n", vm->um_ctlr, id.module_id); return(0); } if (id.code_rev == (u_char)0xff) { printf("hdc%d: micro-code not loaded.\n", vm->um_ctlr); return(0); } if (id.fit != (u_char)0xff) { printf("hdc%d: FIT test failed.\n", vm->um_ctlr); return(0); } /* reset that pup; flag as inited */ hdc->hdc_reg->soft_reset = 0; DELAY(1000000); hdc->hdc_flags |= HDC_INIT; /* allocate page tables and i/o buffer. */ if (!vbainit(&hdc->hdc_rbuf, MAXPHYS, VB_32BIT|VB_SCATTER)) { printf("hdc%d: vbainit failed\n", vm->um_ctlr); return (0); } /* set pointer to master control block */ hdc->hdc_mcbp = (struct master_mcb *)vtoph((struct proc *)NULL, &hdc->hdc_mcb); br = 0x17, cvec = HDCINTERRUPT + vm->um_ctlr; /* XXX */ return(sizeof(struct registers));}/* ARGSUSED */hdslave(vi, vdaddr) struct vba_device *vi; struct vddevice *vdaddr;{ register struct mcb *mcb; register struct disklabel *lp; register struct dksoftc *dk; static struct status status; dk = &dksoftc[vi->ui_unit]; dk->dk_unit = vi->ui_unit; dk->dk_ctlr = vi->ui_ctlr; mcb = &dk->dk_mcb; mcb->command = HCMD_STATUS; mcb->chain[0].wcount = sizeof(struct status) / sizeof(long); mcb->chain[0].memadr = (u_long)vtoph((struct process *)0, &status); if (hdimcb(dk)) { printf(" (no status)\n"); return(0); } /* * Report the drive down if anything in the drive status looks bad. * If the drive is offline and it is not on cylinder, then the drive * is not there. If there is a fault condition, the hdc will try to * clear it when we read the disklabel information. */ if (!(status.drs&DRS_ONLINE)) { if (status.drs&DRS_ON_CYLINDER) printf(" (not online)\n"); return(0); } if (status.drs&DRS_FAULT) printf(" (clearing fault)"); lp = &dk->dk_label;#ifdef RAW_SIZE lp->d_secsize = status.bytes_per_sec;#else lp->d_secsize = 512;#endif lp->d_nsectors = status.max_sector + 1; lp->d_ntracks = status.max_head + 1; lp->d_ncylinders = status.max_cyl + 1; lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; lp->d_npartitions = 1; lp->d_partitions[0].p_offset = 0; lp->d_partitions[0].p_size = LABELSECTOR + 1; lp->d_rpm = status.rpm; lp->d_typename[0] = 'h'; lp->d_typename[1] = 'd'; lp->d_typename[2] = '\0';#ifdef COMPAT_42 dk->dk_def_cyl = status.def_cyl;#endif return(1);}hdattach(vi) register struct vba_device *vi;{ register struct dksoftc *dk; register struct disklabel *lp; register int unit; unit = vi->ui_unit; if (hdinit(hdminor(unit, 0), 0)) { printf(": unknown drive type"); return; } dk = &dksoftc[unit]; lp = &dk->dk_label; hd_setsecsize(dk, lp); if (dk->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(HDMAJOR, hdminor(unit, 0)), lp);#endif}hdopen(dev, flags, fmt) dev_t dev; int flags, fmt;{ register struct disklabel *lp; register struct dksoftc *dk; register struct partition *pp; register int unit; struct vba_device *vi; int s, error, part = hdpart(dev), mask = 1 << part; daddr_t start, end; unit = hdunit(dev); if (unit >= NHD || (vi = hddinfo[unit]) == 0 || vi->ui_alive == 0) return(ENXIO); dk = &dksoftc[unit]; lp = &dk->dk_label; 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)) { splx(s); return (error); } splx(s); if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) if (error = hdinit(dev, flags)) return(error); if (hdcwstart == 0) { timeout(hdcwatch, (caddr_t)0, hz); hdcwstart++; } /* * 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, "hd%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 */hdclose(dev, flags, fmt) dev_t dev; int flags, fmt;{ register struct dksoftc *dk; int mask; dk = &dksoftc[hdunit(dev)]; mask = 1 << hdpart(dev); 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 (dk->dk_utab.b_actf) sleep((caddr_t)dk, PZERO-1); splx(s); dk->dk_state = CLOSED; dk->dk_wlabel = 0; } return(0);}hdinit(dev, flags) dev_t dev; int flags;{ register struct dksoftc *dk; register struct disklabel *lp; struct vba_device *vi; int error, unit; char *msg, *readdisklabel(); extern int cold; vi = hddinfo[unit = hdunit(dev)]; dk = &dksoftc[unit]; dk->dk_unit = vi->ui_slave; dk->dk_ctlr = vi->ui_ctlr; if (flags & O_NDELAY) { dk->dk_state = OPENRAW; return(0); } error = 0; lp = &dk->dk_label; dk->dk_state = RDLABEL; if (msg = readdisklabel(dev, hdstrategy, lp)) { if (cold) { printf(": %s\n", msg); dk->dk_state = CLOSED; } else { log(LOG_ERR, "hd%d: %s\n", unit, msg); dk->dk_state = OPENRAW; }#ifdef COMPAT_42 hdclock(vi->ui_ctlr); if (!(error = hdreadgeometry(dk))) dk->dk_state = OPEN; hdcunlock(vi->ui_ctlr);#endif } else dk->dk_state = OPEN; wakeup((caddr_t)dk); return(error);}hd_setsecsize(dk, lp) register struct dksoftc *dk; struct disklabel *lp;{ register 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++;}/* ARGSUSED */hddgo(vm) struct vba_device *vm;{}extern int name_ext;hdstrategy(bp) register struct buf *bp;{ register struct vba_device *vi; register struct disklabel *lp; register struct dksoftc *dk; struct buf *dp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -