📄 rd.c
字号:
/* * Copyright (c) 1988 University of Utah. * Copyright (c) 1982, 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * the Systems Programming Group of the University of Utah Computer * Science Department. * * 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. * * from: Utah $Hdr: rd.c 1.44 92/12/26$ * * @(#)rd.c 8.1 (Berkeley) 6/10/93 *//* * CS80/SS80 disk driver */#include "rd.h"#if NRD > 0#include <sys/param.h>#include <sys/systm.h>#include <sys/buf.h>#include <sys/stat.h>#include <sys/dkstat.h>#include <sys/disklabel.h>#include <sys/ioctl.h>#include <sys/fcntl.h>#include <hp/dev/device.h>#include <hp300/dev/rdreg.h>#include <hp300/dev/rdvar.h>#ifdef USELEDS#include <hp300/hp300/led.h>#endif#include <vm/vm_param.h>#include <vm/lock.h>#include <vm/vm_prot.h>#include <vm/pmap.h>int rdinit(), rdstart(), rdgo(), rdintr();void rdstrategy();struct driver rddriver = { rdinit, "rd", rdstart, rdgo, rdintr,};struct rd_softc rd_softc[NRD];struct buf rdtab[NRD];int rderrthresh = RDRETRY-1; /* when to start reporting errors */#ifdef DEBUG/* error message tables */char *err_reject[] = { 0, 0, "channel parity error", /* 0x2000 */ 0, 0, "illegal opcode", /* 0x0400 */ "module addressing", /* 0x0200 */ "address bounds", /* 0x0100 */ "parameter bounds", /* 0x0080 */ "illegal parameter", /* 0x0040 */ "message sequence", /* 0x0020 */ 0, "message length", /* 0x0008 */ 0, 0, 0};char *err_fault[] = { 0, "cross unit", /* 0x4000 */ 0, "controller fault", /* 0x1000 */ 0, 0, "unit fault", /* 0x0200 */ 0, "diagnostic result", /* 0x0080 */ 0, "operator release request", /* 0x0020 */ "diagnostic release request", /* 0x0010 */ "internal maintenance release request", /* 0x0008 */ 0, "power fail", /* 0x0002 */ "retransmit" /* 0x0001 */};char *err_access[] = { "illegal parallel operation", /* 0x8000 */ "uninitialized media", /* 0x4000 */ "no spares available", /* 0x2000 */ "not ready", /* 0x1000 */ "write protect", /* 0x0800 */ "no data found", /* 0x0400 */ 0, 0, "unrecoverable data overflow", /* 0x0080 */ "unrecoverable data", /* 0x0040 */ 0, "end of file", /* 0x0010 */ "end of volume", /* 0x0008 */ 0, 0, 0};char *err_info[] = { "operator release request", /* 0x8000 */ "diagnostic release request", /* 0x4000 */ "internal maintenance release request", /* 0x2000 */ "media wear", /* 0x1000 */ "latency induced", /* 0x0800 */ 0, 0, "auto sparing invoked", /* 0x0100 */ 0, "recoverable data overflow", /* 0x0040 */ "marginal data", /* 0x0020 */ "recoverable data", /* 0x0010 */ 0, "maintenance track overflow", /* 0x0004 */ 0, 0};struct rdstats rdstats[NRD];int rddebug = 0x80;#define RDB_FOLLOW 0x01#define RDB_STATUS 0x02#define RDB_IDENT 0x04#define RDB_IO 0x08#define RDB_ASYNC 0x10#define RDB_ERROR 0x80#endif/* * Misc. HW description, indexed by sc_type. * Nothing really critical here, could do without it. */struct rdidentinfo rdidentinfo[] = { { RD7946AID, 0, "7945A", 108416 }, { RD9134DID, 1, "9134D", 29088 }, { RD9134LID, 1, "9122S", 1232 }, { RD7912PID, 0, "7912P", 128128 }, { RD7914PID, 0, "7914P", 258048 }, { RD7958AID, 0, "7958A", 255276 }, { RD7957AID, 0, "7957A", 159544 }, { RD7933HID, 0, "7933H", 789958 }, { RD9134LID, 1, "9134L", 77840 }, { RD7936HID, 0, "7936H", 600978 }, { RD7937HID, 0, "7937H", 1116102 }, { RD7914CTID, 0, "7914CT", 258048 }, { RD7946AID, 0, "7946A", 108416 }, { RD9134LID, 1, "9122D", 1232 }, { RD7957BID, 0, "7957B", 159894 }, { RD7958BID, 0, "7958B", 297108 }, { RD7959BID, 0, "7959B", 594216 }, { RD2200AID, 0, "2200A", 654948 }, { RD2203AID, 0, "2203A", 1309896 }};int numrdidentinfo = sizeof(rdidentinfo) / sizeof(rdidentinfo[0]);rdinit(hd) register struct hp_device *hd;{ register struct rd_softc *rs = &rd_softc[hd->hp_unit]; rs->sc_hd = hd; rs->sc_punit = rdpunit(hd->hp_flags); rs->sc_type = rdident(rs, hd); if (rs->sc_type < 0) return(0); rs->sc_dq.dq_ctlr = hd->hp_ctlr; rs->sc_dq.dq_unit = hd->hp_unit; rs->sc_dq.dq_slave = hd->hp_slave; rs->sc_dq.dq_driver = &rddriver; rs->sc_flags = RDF_ALIVE;#ifdef DEBUG /* always report errors */ if (rddebug & RDB_ERROR) rderrthresh = 0;#endif return(1);}rdident(rs, hd) struct rd_softc *rs; struct hp_device *hd;{ struct rd_describe desc; u_char stat, cmd[3]; int unit, lunit; char name[7]; register int ctlr, slave, id, i; ctlr = hd->hp_ctlr; slave = hd->hp_slave; unit = rs->sc_punit; lunit = hd->hp_unit; /* * Grab device id and make sure: * 1. It is a CS80 device. * 2. It is one of the types we support. * 3. If it is a 7946, we are accessing the disk unit (0) */ id = hpibid(ctlr, slave);#ifdef DEBUG if (rddebug & RDB_IDENT) printf("hpibid(%d, %d) -> %x\n", ctlr, slave, id);#endif if ((id & 0x200) == 0) return(-1); for (i = 0; i < numrdidentinfo; i++) if (id == rdidentinfo[i].ri_hwid) break; if (i == numrdidentinfo || unit > rdidentinfo[i].ri_maxunum) return(-1); id = i; /* * Reset drive and collect device description. * Don't really use the description info right now but * might come in handy in the future (for disk labels). */ rdreset(rs, hd); cmd[0] = C_SUNIT(unit); cmd[1] = C_SVOL(0); cmd[2] = C_DESC; hpibsend(ctlr, slave, C_CMD, cmd, sizeof(cmd)); hpibrecv(ctlr, slave, C_EXEC, &desc, 37); hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat)); bzero(name, sizeof(name)); if (!stat) { register int n = desc.d_name; for (i = 5; i >= 0; i--) { name[i] = (n & 0xf) + '0'; n >>= 4; } /* use drive characteristics to calculate xfer rate */ rs->sc_wpms = 1000000 * (desc.d_sectsize/2) / desc.d_blocktime; }#ifdef DEBUG if (rddebug & RDB_IDENT) { printf("rd%d: name: %x ('%s')\n", lunit, desc.d_name, name); printf(" iuw %x, maxxfr %d, ctype %d\n", desc.d_iuw, desc.d_cmaxxfr, desc.d_ctype); printf(" utype %d, bps %d, blkbuf %d, burst %d, blktime %d\n", desc.d_utype, desc.d_sectsize, desc.d_blkbuf, desc.d_burstsize, desc.d_blocktime); printf(" avxfr %d, ort %d, atp %d, maxint %d, fv %x, rv %x\n", desc.d_uavexfr, desc.d_retry, desc.d_access, desc.d_maxint, desc.d_fvbyte, desc.d_rvbyte); printf(" maxcyl/head/sect %d/%d/%d, maxvsect %d, inter %d\n", desc.d_maxcyl, desc.d_maxhead, desc.d_maxsect, desc.d_maxvsectl, desc.d_interleave); }#endif /* * Take care of a couple of anomolies: * 1. 7945A and 7946A both return same HW id * 2. 9122S and 9134D both return same HW id * 3. 9122D and 9134L both return same HW id */ switch (rdidentinfo[id].ri_hwid) { case RD7946AID: if (bcmp(name, "079450", 6) == 0) id = RD7945A; else id = RD7946A; break; case RD9134LID: if (bcmp(name, "091340", 6) == 0) id = RD9134L; else id = RD9122D; break; case RD9134DID: if (bcmp(name, "091220", 6) == 0) id = RD9122S; else id = RD9134D; break; } printf("rd%d: %s\n", lunit, rdidentinfo[id].ri_desc); return(id);}rdreset(rs, hd) register struct rd_softc *rs; register struct hp_device *hd;{ u_char stat; rs->sc_clear.c_unit = C_SUNIT(rs->sc_punit); rs->sc_clear.c_cmd = C_CLEAR; hpibsend(hd->hp_ctlr, hd->hp_slave, C_TCMD, &rs->sc_clear, sizeof(rs->sc_clear)); hpibswait(hd->hp_ctlr, hd->hp_slave); hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat)); rs->sc_src.c_unit = C_SUNIT(RDCTLR); rs->sc_src.c_nop = C_NOP; rs->sc_src.c_cmd = C_SREL; rs->sc_src.c_param = C_REL; hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, &rs->sc_src, sizeof(rs->sc_src)); hpibswait(hd->hp_ctlr, hd->hp_slave); hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat)); rs->sc_ssmc.c_unit = C_SUNIT(rs->sc_punit); rs->sc_ssmc.c_cmd = C_SSM; rs->sc_ssmc.c_refm = REF_MASK; rs->sc_ssmc.c_fefm = FEF_MASK; rs->sc_ssmc.c_aefm = AEF_MASK; rs->sc_ssmc.c_iefm = IEF_MASK; hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, &rs->sc_ssmc, sizeof(rs->sc_ssmc)); hpibswait(hd->hp_ctlr, hd->hp_slave); hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat));#ifdef DEBUG rdstats[hd->hp_unit].rdresets++;#endif}/* * Read or constuct a disklabel */intrdgetinfo(dev) dev_t dev;{ int unit = rdunit(dev); register struct rd_softc *rs = &rd_softc[unit]; register struct disklabel *lp = &rs->sc_info.ri_label; register struct partition *pi; char *msg, *readdisklabel(); /* * Set some default values to use while reading the label * or to use if there isn't a label. */ bzero((caddr_t)lp, sizeof *lp); lp->d_type = DTYPE_HPIB; lp->d_secsize = DEV_BSIZE; lp->d_nsectors = 32; lp->d_ntracks = 20; lp->d_ncylinders = 1; lp->d_secpercyl = 32*20; lp->d_npartitions = 3; lp->d_partitions[2].p_offset = 0; lp->d_partitions[2].p_size = LABELSECTOR+1; /* * Now try to read the disklabel */ msg = readdisklabel(rdlabdev(dev), rdstrategy, lp); if (msg == NULL) return(0); pi = lp->d_partitions; printf("rd%d: WARNING: %s, ", unit, msg);#ifdef COMPAT_NOLABEL printf("using old default partitioning\n"); rdmakedisklabel(unit, lp);#else printf("defining `c' partition as entire disk\n"); pi[2].p_size = rdidentinfo[rs->sc_type].ri_nblocks;#endif return(0);}intrdopen(dev, flags, mode, p) dev_t dev; int flags, mode; struct proc *p;{ register int unit = rdunit(dev); register struct rd_softc *rs = &rd_softc[unit]; int error, mask; if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0) return(ENXIO); /* * Wait for any pending opens/closes to complete */ while (rs->sc_flags & (RDF_OPENING|RDF_CLOSING)) sleep((caddr_t)rs, PRIBIO); /* * On first open, get label and partition info. * We may block reading the label, so be careful * to stop any other opens. */ if (rs->sc_info.ri_open == 0) { rs->sc_flags |= RDF_OPENING; error = rdgetinfo(dev); rs->sc_flags &= ~RDF_OPENING; wakeup((caddr_t)rs); if (error) return(error); } if (rs->sc_hd->hp_dk >= 0) { /* guess at xfer rate based on 3600 rpm (60 rps) */ if (rs->sc_wpms == 0) rs->sc_wpms = 60 * rs->sc_info.ri_label.d_nsectors * DEV_BSIZE / 2; dk_wpms[rs->sc_hd->hp_dk] = rs->sc_wpms; } mask = 1 << rdpart(dev); if (mode == S_IFCHR) rs->sc_info.ri_copen |= mask; else rs->sc_info.ri_bopen |= mask; rs->sc_info.ri_open |= mask; return(0);}intrdclose(dev, flag, mode, p) dev_t dev; int flag, mode; struct proc *p;{ int unit = rdunit(dev); register struct rd_softc *rs = &rd_softc[unit]; register struct rdinfo *ri = &rs->sc_info; int mask, s; mask = 1 << rdpart(dev); if (mode == S_IFCHR) ri->ri_copen &= ~mask; else ri->ri_bopen &= ~mask; ri->ri_open = ri->ri_bopen | ri->ri_copen; /* * On last close, we wait for all activity to cease since * the label/parition info will become invalid. Since we * might sleep, we must block any opens while we are here. * Note we don't have to about other closes since we know * we are the last one. */ if (ri->ri_open == 0) { rs->sc_flags |= RDF_CLOSING; s = splbio(); while (rdtab[unit].b_active) { rs->sc_flags |= RDF_WANTED; sleep((caddr_t)&rdtab[unit], PRIBIO); } splx(s); rs->sc_flags &= ~(RDF_CLOSING|RDF_WLABEL); wakeup((caddr_t)rs); } return(0);}voidrdstrategy(bp) register struct buf *bp;{ int unit = rdunit(bp->b_dev); register struct rd_softc *rs = &rd_softc[unit]; register struct buf *dp = &rdtab[unit]; register struct partition *pinfo; register daddr_t bn; register int sz, s;#ifdef DEBUG if (rddebug & RDB_FOLLOW) printf("rdstrategy(%x): dev %x, bn %x, bcount %x, %c\n", bp, bp->b_dev, bp->b_blkno, bp->b_bcount, (bp->b_flags & B_READ) ? 'R' : 'W');#endif bn = bp->b_blkno; sz = howmany(bp->b_bcount, DEV_BSIZE); pinfo = &rs->sc_info.ri_label.d_partitions[rdpart(bp->b_dev)]; if (bn < 0 || bn + sz > pinfo->p_size) { sz = pinfo->p_size - bn; if (sz == 0) { bp->b_resid = bp->b_bcount; goto done; } if (sz < 0) { bp->b_error = EINVAL; goto bad; } bp->b_bcount = dbtob(sz); } /* * Check for write to write protected label */ if (bn + pinfo->p_offset <= LABELSECTOR &&#if LABELSECTOR != 0 bn + pinfo->p_offset + sz > LABELSECTOR &&#endif !(bp->b_flags & B_READ) && !(rs->sc_flags & RDF_WLABEL)) { bp->b_error = EROFS; goto bad; } bp->b_cylin = bn + pinfo->p_offset; s = splbio(); disksort(dp, bp); if (dp->b_active == 0) { dp->b_active = 1; rdustart(unit); } splx(s); return;bad: bp->b_flags |= B_ERROR;done: biodone(bp);}/* * Called from timeout() when handling maintenance releases */voidrdrestart(arg) void *arg;{ int s = splbio(); rdustart((int)arg); splx(s);}rdustart(unit)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -