📄 rl.c
字号:
#ifndef lintstatic char *sccsid = "@(#)rl.c 4.1 ULTRIX 7/2/90";#endif lint/************************************************************************ * * * Copyright (c) 1985, 1986, 1988, 1989 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//* * rl.c 6.1 07/29/83 * * Modification history * * RLU211/RLV211/RL02 disk driver * * 26-Oct-84 - Stephen Reilly * * Derived from 4.2BSD labeled: rl.c 6.1 83/07/29. * Modified driver to handle the disk partition scheme. -001 * * 24-Sep-85 - Stephen Reilly * * Added new ioctl request that will return the default * partition table. -002 * * 18-Mar-86 - jaw * * br/cvec changed to NOT use registers. * * 16-Apr-86 - ricky palmer * * Added new DEVIOCGET ioctl request code along with * soft and hard error counters. V2.0 * * 13-Jun-86 - jaw * * Fix to uba reset and drivers. * * 11-Jul-86 - ricky palmer * * Added adpt and nexus fields to DEVIOCGET code. * * 26-Aug-86 - rsp (Ricky Palmer) * * Cleaned up devioctl code to (1) zero out devget structure * upon entry and (2) use strlen instead of fixed storage * for bcopy's. * * 04-Dec-86 - pmk * Changed mprintf's to log just one entry. * * 24-Jul-88 - dallas * changed rlintr to fix the drive hanging problem. We would * forget about the attention summary if we needed to do another * seek to finish off this transfer. * * 13-Aug-89 - Tim Burke * Prevent driver hangs by putting timeouts in the wait routines. * This is needed to prevent the driver from spinning forever waiting * for a bit which will never clear. * * Modified the open routine to correctly determine the drive's status * so that it doesn't try to perform operations on an offline drive * which was hanging the system when calling the wait routines which * previously did not have any timeouts. The wait routines would spin * forever because the drive was not online so it would never become ready. */#include "rl.h"#if NRL > 0 || defined(BINARY)#include "../data/rl_data.c"int rlprobe(), rlslave(), rlattach(), rldgo(), rlintr();/* RL02 driver structure */u_short rlstd[] = { 0174400 };struct uba_driver hldriver = { rlprobe, rlslave, rlattach, rldgo, rlstd, "rl", rldinfo, "hl", rlminfo };/* RL02 drive structure */struct RL02 { short nbpt; /* Number of 512 byte blocks/track */ short ntrak; short nbpc; /* Number of 512 byte blocks/cylinder */ short ncyl; short btrak; /* Number of bytes/track */ struct size *sizes;} rl02 = { 20, 2, 40, 512, 20*512, rl02_sizes /* rl02/DEC*/};int rldebug = 0; /* Print out debug messages */#define b_cylin b_resid /* Last seek as CYL<<1 | HD */#ifdef INTRLVEdaddr_t dkblock();#endif INTRLVEint rlwstart, rlwatch(); /* Have started guardian *//* Check that controller exists *//*ARGSUSED*/rlprobe(reg) caddr_t reg;{#ifdef lint rlintr(0);#endif ((struct rldevice *)reg)->rlcs = RL_IE | RL_NOOP; DELAY(100000); ((struct rldevice *)reg)->rlcs &= ~RL_IE; return (sizeof (struct rldevice));}rlslave(ui, reg) struct uba_device *ui; caddr_t reg;{ register struct rldevice *rladdr = (struct rldevice *)reg; short ctr = 0; /* * DEC reports that: * For some unknown reason the RL02 (seems to be only drive 1) * does not return a valid drive status the first time that a * GET STATUS request is issued for the drive, in fact it can * take up to three or more GET STATUS requests to obtain the * correct status. * In order to overcome this, the driver has been modified to * issue a GET STATUS request and validate the drive status * returned. If a valid status is not returned after eight * attempts, then an error message is printed. */ /* s.p. miller 11/83 * change test of "ok" status such that only care if we get * a composite error (MSB) and return in CSR. So, for * autoconfigure, device is * considered ok even if spun down, as long as it is there. */ do { rladdr->rlda.getstat = RL_RESET; rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/ rlwait(rladdr); } while ((rladdr->rlcs&RLCS_STATUS) != RLCS_STATOK && ++ctr<8); if ((rladdr->rlcs & RL_DE) || (ctr >= 8)) { return (0); } if ((rladdr->rlmp.getstat & RLMP_DT) == 0 ) { printf("rl%d: rl01's not supported\n", ui->ui_slave); return(0); } return (1);}rlattach(ui) register struct uba_device *ui;{ register struct rldevice *rladdr; register struct rl_softc *sc = &rl_softc[ui->ui_ctlr]; if (rlwstart == 0) { timeout(rlwatch, (caddr_t)0, hz); rlwstart++; } /* Initialize iostat values */ if (ui->ui_dk >= 0) { dk_mspw[ui->ui_dk] = .000003906; /* 16bit transfer time? */ bcopy(DEV_RL02,sc->sc_device[ui->ui_unit], strlen(DEV_RL02)); sc->sc_softcnt[ui->ui_unit] = 0; sc->sc_hardcnt[ui->ui_unit] = 0; } rlip[ui->ui_ctlr][ui->ui_slave] = ui; sc->rl_ndrive++; rladdr = (struct rldevice *)ui->ui_addr; /* reset controller */ rladdr->rlda.getstat = RL_RESET; /* SHOULD BE REPEATED? */ rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT; /* Reset DE bit */ rlwait(rladdr); /* determine disk posistion */ rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR; rlwait(rladdr); /* save disk drive posistion */ rl_stat[ui->ui_ctlr].rl_cyl[ui->ui_slave] = (rladdr->rlmp.readhdr & 0177700) >> 6; rl_stat[ui->ui_ctlr].rl_dn = -1;}rlopen(dev, flag) dev_t dev; int flag;{ register int unit = minor(dev) >> 3; register struct uba_device *ui; register struct rl_softc *sc; struct uba_ctlr *um; register struct rldevice *rladdr; register int i = 0; /* 001 */ int rlstrategy(); /* 001 */ if (unit >= nNRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0) { return (ENXIO); } um = ui->ui_mi; rladdr = (struct rldevice *)um->um_addr; sc = &rl_softc[ui->ui_ctlr]; sc->sc_flags[ui->ui_unit] = 0; sc->sc_category_flags[ui->ui_unit] = 0; do { rladdr->rlda.getstat = RL_GSTAT; rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; rlwait(rladdr); } while ((rladdr->rlcs&RLCS_STATUS) != RLCS_STATOK && ++i<8) ; i = rladdr->rlmp.getstat; switch( i & RLMP_STATMASK ) { case RLMP_SPINDOWN: sc->sc_flags[ui->ui_unit] |= DEV_OFFLINE; if (rldebug > 1) printf("rlopen: unit %d spun down.\n", ui->ui_unit); break; case RLMP_UNLOADED: sc->sc_flags[ui->ui_unit] |= DEV_OFFLINE; if (rldebug > 1) printf("rlopen: unit %d unloaded.\n", ui->ui_unit); break; default: sc->sc_flags[ui->ui_unit] &= ~DEV_OFFLINE; } ; if (i & RLMP_WL) { sc->sc_flags[ui->ui_unit] |= DEV_WRTLCK; } /* * We must check to see if the pack on the drive has a * partition table on it, but first set the default * partition tables becuase the strategy routine need them. * * Only attempt disk activity to an online drive. */ if(((sc->sc_flags[ui->ui_unit] & DEV_OFFLINE) == 0) && (rl_part[unit].pt_valid == 0)) { int nbpc = rl02.nbpc; /* * Set default partition tables */ for( i = 0; i <= 7; i++ ) { rl_part[unit].pt_part[i].pi_nblocks = rl02_sizes[i].nblocks; rl_part[unit].pt_part[i].pi_blkoff = rl02_sizes[i].cyloff * nbpc; } rl_part[unit].pt_valid = PT_VALID; /*001 Validate the pt*/ /* * Default partition are now set. Call rsblk to set * the driver's partition tables, if any exists, from * the "a" partition superblock */ rsblk( rlstrategy, dev, &rl_part[unit] ); } return (0);}rlstrategy(bp) register struct buf *bp;{ register int unit = dkunit(bp); register struct uba_device *ui = rldinfo[unit]; register struct pt *pt; /* 001 */ register struct buf *dp; register struct rl_softc *sc = &rl_softc[ui->ui_ctlr]; int xunit = minor(bp->b_dev) & 07; long bn, sz; int s; sz = (bp->b_bcount+511) >> 9; if (unit >= nNRL) goto bad; if ((ui == 0) || (ui->ui_alive == 0) || (sc->sc_flags[ui->ui_unit] & DEV_OFFLINE)) goto bad; pt = &rl_part[unit]; if ( pt->pt_valid != PT_VALID ) /* 001 */ panic("rlstrategy: invalid partition table "); /* 001 */ if (bp->b_blkno < 0 || ((bn = dkblock(bp))+sz > pt->pt_part[xunit].pi_nblocks /* 001*/ && pt->pt_part[xunit].pi_nblocks >= 0)) { sc->sc_flags[ui->ui_unit] |= DEV_EOM; goto bad; } /* 001 bn is in 512 byte block size */ bp->b_cylin = bn/rl02.nbpc + pt->pt_part[xunit].pi_blkoff / rl02.nbpc; s = spl5(); dp = &rlutab[ui->ui_unit]; disksort(dp, bp); if (dp->b_active == 0) { rlustart(ui); bp = &ui->ui_mi->um_tab; if (bp->b_actf && bp->b_active == 0) rlstart(ui->ui_mi); } splx(s); return;bad: bp->b_flags |= B_ERROR; if (sc->sc_flags[ui->ui_unit] & DEV_EOM) { bp->b_error = ENOSPC; } iodone(bp); return;}/* * Unit start routine. * Seek the drive to be where the data is * and then generate another interrupt * to actually start the transfer. */rlustart(ui) register struct uba_device *ui;{ register struct buf *bp, *dp; register struct uba_ctlr *um; register struct rldevice *rladdr; register struct rl_softc *sc; daddr_t bn; short hd, diff; if (ui == 0) return; um = ui->ui_mi; sc = &rl_softc[um->um_ctlr]; dk_busy &= ~(1 << ui->ui_dk); dp = &rlutab[ui->ui_unit]; if ((bp = dp->b_actf) == NULL) return; /* * If the controller is active, just remember * that this device has to be positioned... */ if (um->um_tab.b_active) { sc->rl_softas |= (1<<ui->ui_slave); return; } /* * If we have already positioned this drive, * then just put it on the ready queue. */ if (dp->b_active) goto done; dp->b_active = 1; /* positioning drive */ rladdr = (struct rldevice *)um->um_addr; /* * Figure out where this transfer is going to * and see if we are seeked correctly. */ bn = dkblock(bp); /* Block # desired */ /* * Map 512 byte logical disk blocks * to 256 byte sectors (rl02's are stupid). */ hd = (bn / rl02.nbpt) & 1; /* Get head required */ diff = (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] >> 1) - bp->b_cylin; if ( diff == 0 && (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] & 1) == hd) goto done; /* on cylinder and head */ /* * Not at correct position. */ rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] = (bp->b_cylin << 1) | hd; if (diff < 0) rladdr->rlda.seek = -diff << 7 | RLDA_HGH | hd << 4; else rladdr->rlda.seek = diff << 7 | RLDA_LOW | hd << 4; rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK; /* * Mark unit busy for iostat. */ if (ui->ui_dk >= 0) { dk_busy |= 1<<ui->ui_dk; dk_seek[ui->ui_dk]++; } rlwait(rladdr);done: /* * Device is ready to go. * Put it on the ready queue for the controller * (unless its already there.) */ if (dp->b_active != 2) { dp->b_forw = NULL; if (um->um_tab.b_actf == NULL) um->um_tab.b_actf = dp; else um->um_tab.b_actl->b_forw = dp; um->um_tab.b_actl = dp; dp->b_active = 2; /* Request on ready queue */ }}/* * Start up a transfer on a drive. */rlstart(um) register struct uba_ctlr *um;{ register struct buf *bp, *dp; register struct uba_device *ui; register struct rldevice *rladdr; register struct rl_stat *st = &rl_stat[um->um_ctlr]; daddr_t bn; short sn, cyl, cmd;loop: if ((dp = um->um_tab.b_actf) == NULL) { st->rl_dn = -1; st->rl_cylnhd = 0; st->rl_bleft = 0; st->rl_bpart = 0; return; } if ((bp = dp->b_actf) == NULL) { um->um_tab.b_actf = dp->b_forw; goto loop; } /* * Mark controller busy, and * determine destination. */ um->um_tab.b_active++; ui = rldinfo[dkunit(bp)]; /* Controller */ bn = dkblock(bp); /* 512 byte Block number */ cyl = bp->b_cylin << 1; /* Cylinder */ cyl |= (bn / rl02.nbpt) & 1; /* Get head required */ sn = (bn % rl02.nbpt) << 1; /* Sector number */ rladdr = (struct rldevice *)ui->ui_addr; rlwait(rladdr); rladdr->rlda.rw = cyl<<6 | sn; /* save away current transfers drive status */ st->rl_dn = ui->ui_slave; st->rl_cylnhd = cyl; st->rl_bleft = bp->b_bcount; st->rl_bpart = rl02.btrak - (sn * NRLBPSC); /* * RL02 must seek between cylinders and between tracks, * determine maximum data transfer at this time. */ if (st->rl_bleft < st->rl_bpart) st->rl_bpart = st->rl_bleft; rladdr->rlmp.rw = -(st->rl_bpart >> 1); if (bp->b_flags & B_READ) cmd = RL_IE | RL_READ | (ui->ui_slave << 8); else cmd = RL_IE | RL_WRITE | (ui->ui_slave << 8); um->um_cmd = cmd; (void) ubago(ui);}rldgo(um) register struct uba_ctlr *um;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -