📄 up.c
字号:
#ifndef lintstatic char *sccsid = "@(#)up.c 4.1 ULTRIX 7/2/90";#endif lint/************************************************************************ * * * Copyright (c) 1985,86 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. * * * ************************************************************************//************************************************************************ * * Modification History * * 26-July-89 - Alan Frechette * Conditionalize out the dump code. * * 13-Jun-86 -- jaw fix to uba reset and drivers. * * 22-May-86 Paul Shaughnessy * Added saving of the u_area to the partial dump code. * * 09-Apr-86 Paul Shaughnessy * Added partial dump code support, and removed common dump code. * * 18-mar-86 -- jaw br/cvec changed to NOT use registers. * * 24-Sep-85 Stephen Reilly * 002- Added new ioctl request that returns the default partition table * * 30-Nov-84 Stephen Reilly * 001 - Fixed up an error message * * 14-Nov-84 Stephen Reilly * 001 - Modifed driver to now handle the disk partitioning scheme * * up.c 6.1 83/07/29 ***********************************************************************/#include "up.h"#if NSC > 0 || defined(BINARY)/* * UNIBUS disk driver with: * overlapped seeks, * ECC recovery, and * bad sector forwarding. * * TODO: * Check that offset recovery code works */#include "../h/dump.h"#include "../data/up_data.c"int upprobe(), upslave(), upattach(), updgo(), upintr();u_short upstd[] = { 0776700 };struct uba_driver scdriver = { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo };struct upst { short nsect; /* # sectors/track */ short ntrak; /* # tracks/cylinder */ short nspc; /* # sectors/cylinder */ short ncyl; /* # cylinders */ struct size *sizes; /* partition tables */ short sdist; /* seek distance metric */ short rdist; /* rotational distance metric */} upst[] = { { 32, 19, 32*19, 815, up9300_sizes, 3, 4 }, /* 9300 */ { 32, 19, 32*19, 823, up9766_sizes, 3, 4 }, /* 9766 */ { 32, 10, 32*10, 823, up160_sizes, 3, 4 }, /* fuji 160m */ { 32, 16, 32*16, 1024, upam_sizes, 7, 8 }, /* Capricorn */ { 32, 5, 32*5, 823, up980_sizes, 3, 4 }, /* DM980 */ { 0, 0, 0, 0, 0, 0, 0 }};u_char up_offset[16] = { UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, 0, 0, 0, 0};#define b_cylin b_resid#ifdef INTRLVEdaddr_t dkblock();#endifint upwstart, upwatch(); /* Have started guardian */int upseek;int upwaitdry;/*ARGSUSED*/upprobe(reg) caddr_t reg;{#ifdef lint upintr(0);#endif ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; DELAY(10); ((struct updevice *)reg)->upcs1 = 0; return (sizeof (struct updevice));}upslave(ui, reg) struct uba_device *ui; caddr_t reg;{ register struct updevice *upaddr = (struct updevice *)reg; upaddr->upcs1 = 0; /* conservative */ upaddr->upcs2 = ui->ui_slave; upaddr->upcs1 = UP_NOP|UP_GO; if (upaddr->upcs2&UPCS2_NED) { upaddr->upcs1 = UP_DCLR|UP_GO; return (0); } return (1);}upattach(ui) register struct uba_device *ui;{ if (upwstart == 0) { timeout(upwatch, (caddr_t)0, hz); upwstart++; } if (ui->ui_dk >= 0) dk_mspw[ui->ui_dk] = .0000020345; upip[ui->ui_ctlr][ui->ui_slave] = ui; up_softc[ui->ui_ctlr].sc_ndrive++; ui->ui_type = upmaptype(ui);}upmaptype(ui) register struct uba_device *ui;{ register struct updevice *upaddr = (struct updevice *)ui->ui_addr; int type = ui->ui_type; register struct upst *st; upaddr->upcs1 = 0; upaddr->upcs2 = ui->ui_slave; upaddr->uphr = UPHR_MAXTRAK; for (st = upst; st->nsect != 0; st++) if (upaddr->uphr == st->ntrak - 1) { type = st - upst; break; } if (st->nsect == 0) printf("up%d: uphr=%x\n", ui->ui_slave, upaddr->uphr); if (type == 0) { upaddr->uphr = UPHR_MAXCYL; if (upaddr->uphr == 822) type++; } upaddr->upcs2 = UPCS2_CLR; return (type);} upopen(dev) dev_t dev;{ register int unit = minor(dev) >> 3; register struct uba_device *ui; register int nspc; /* 001 */ register int i; /* 001 */ struct uba_ctlr *um; /* 001 */ struct updevice *upaddr; /* 001 */ int upstrategy(); /* 001 */ if (unit >= nNUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0) return (ENXIO); /* * Get address for up device in question */ ui = updinfo[unit] ; um = ui->ui_mi; upaddr = ( struct updevice *)um->um_addr; /* * See if we need to read in the partition table from the disk. * The conditions we will have to read from the disk is if the * partition table valid bit has not been set for the volume * is invalid. */ if (((upaddr->upds & UPDS_VV) == 0 )|| ( up_part[unit].pt_valid ==0)) { /* * Assume that the default values before trying to * see if the partition tables are on the pack. The * reason that we do this is that the strategy routine * is used to read in the superblock but uses the * partition info. So we must first assume the * default values. */ int nspc = upst[ui->ui_type].nspc; for( i = 0; i <= 7; i++ ) { up_part[unit].pt_part[i].pi_nblocks = upst[ui->ui_type].sizes[i].nblocks; up_part[unit].pt_part[i].pi_blkoff = upst[ui->ui_type].sizes[i].cyloff * nspc; } up_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( upstrategy, dev, &up_part[unit] ); } return (0);}upstrategy(bp) register struct buf *bp;{ register struct uba_device *ui; register struct upst *st; register int unit; register struct buf *dp; register struct pt *pt; /* 001 */ int xunit = minor(bp->b_dev) & 07; long bn, sz; sz = (bp->b_bcount+511) >> 9; unit = dkunit(bp); if (unit >= nNUP) goto bad; ui = updinfo[unit]; if (ui == 0 || ui->ui_alive == 0) goto bad; st = &upst[ui->ui_type]; /* * Get partition table for the pack */ pt = &up_part[unit]; if ( up_part[unit].pt_valid != PT_VALID ) panic("upstrategy: invalid partition table "); if (bp->b_blkno < 0 || (bn = dkblock(bp))+sz > pt->pt_part[xunit].pi_nblocks) /* 001 */ goto bad; bp->b_cylin = bn/st->nspc + pt->pt_part[xunit].pi_blkoff / st->nspc; (void) spl5(); dp = &uputab[ui->ui_unit]; disksort(dp, bp); if (dp->b_active == 0) { (void) upustart(ui); bp = &ui->ui_mi->um_tab; if (bp->b_actf && bp->b_active == 0) (void) upstart(ui->ui_mi); } (void) spl0(); return;bad: bp->b_flags |= B_ERROR; 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. * If there is only one drive on the controller, * or we are very close to the data, don't * bother with the search. If called after * searching once, don't bother to look where * we are, just queue for transfer (to avoid * positioning forever without transferrring.) */upustart(ui) register struct uba_device *ui;{ register struct buf *bp, *dp; register struct uba_ctlr *um; register struct updevice *upaddr; register struct upst *st; daddr_t bn; int sn, csn; /* * The SC21 cancels commands if you just say * cs1 = UP_IE * so we are cautious about handling of cs1. * Also don't bother to clear as bits other than in upintr(). */ int didie = 0; if (ui == 0) return (0); um = ui->ui_mi; dk_busy &= ~(1<<ui->ui_dk); dp = &uputab[ui->ui_unit]; if ((bp = dp->b_actf) == NULL) goto out; /* * If the controller is active, just remember * that this device would like to be positioned... * if we tried to position now we would confuse the SC21. */ if (um->um_tab.b_active) { up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; return (0); } /* * 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; upaddr = (struct updevice *)um->um_addr; upaddr->upcs2 = ui->ui_slave; /* * If drive has just come up, * setup the pack. */ if ((upaddr->upds & UPDS_VV) == 0 || upinit[ui->ui_unit] == 0) { struct buf *bbp = &bupbuf[ui->ui_unit]; /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ upinit[ui->ui_unit] = 1; upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; upaddr->upof = UPOF_FMT22; didie = 1; st = &upst[ui->ui_type]; bbp->b_flags = B_READ|B_BUSY; bbp->b_dev = bp->b_dev; bbp->b_bcount = 512; bbp->b_un.b_addr = (caddr_t)&upbad[ui->ui_unit]; bbp->b_blkno = st->ncyl * st->nspc - st->nsect; bbp->b_cylin = st->ncyl - 1; dp->b_actf = bbp; bbp->av_forw = bp; bp = bbp; } /* * If drive is offline, forget about positioning. */ if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) goto done; /* * If there is only one drive, * dont bother searching. */ if (up_softc[um->um_ctlr].sc_ndrive == 1) goto done; /* * Figure out where this transfer is going to * and see if we are close enough to justify not searching. */ st = &upst[ui->ui_type]; bn = dkblock(bp); sn = bn%st->nspc; sn = (sn + st->nsect - st->sdist) % st->nsect; if (bp->b_cylin - upaddr->updc) goto search; /* Not on-cylinder */ else if (upseek) goto done; /* Ok just to be on-cylinder */ csn = (upaddr->upla>>6) - sn - 1; if (csn < 0) csn += st->nsect; if (csn > st->nsect - st->rdist) goto done;search: upaddr->updc = bp->b_cylin; /* * Not on cylinder at correct position, * seek/search. */ if (upseek) upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; else { upaddr->upda = sn; upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; } didie = 1; /* * Mark unit busy for iostat. */ if (ui->ui_dk >= 0) { dk_busy |= 1<<ui->ui_dk; dk_seek[ui->ui_dk]++; } goto out;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; }out: return (didie);}/* * Start up a transfer on a drive. */upstart(um) register struct uba_ctlr *um;{ register struct buf *bp, *dp; register struct uba_device *ui; register struct updevice *upaddr; struct upst *st; daddr_t bn; int dn, sn, tn, cmd, waitdry;loop: /* * Pull a request off the controller queue */ if ((dp = um->um_tab.b_actf) == NULL) return (0); if ((bp = dp->b_actf) == NULL) { um->um_tab.b_actf = dp->b_forw; goto loop; } /* * Mark controller busy, and * determine destination of this request. */ um->um_tab.b_active++; ui = updinfo[dkunit(bp)]; bn = dkblock(bp); dn = ui->ui_slave; st = &upst[ui->ui_type]; sn = bn%st->nspc; tn = sn/st->nsect; sn %= st->nsect; upaddr = (struct updevice *)ui->ui_addr; /* * Select drive if not selected already. */ if ((upaddr->upcs2&07) != dn) upaddr->upcs2 = dn; /* * Check that it is ready and online */ waitdry = 0; while ((upaddr->upds&UPDS_DRY) == 0) { printf("up%d: ds wait ds=%o\n",dkunit(bp),upaddr->upds); if (++waitdry > 512) break; upwaitdry++; } if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { printf("up%d: not ready", dkunit(bp)); if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { printf("\n"); um->um_tab.b_active = 0; um->um_tab.b_errcnt = 0; dp->b_actf = bp->av_forw; dp->b_active = 0; bp->b_flags |= B_ERROR; iodone(bp); goto loop; } /* * Oh, well, sometimes this * happens, for reasons unknown. */ printf(" (flakey)\n"); } /* * Setup for the transfer, and get in the * UNIBUS adaptor queue. */ upaddr->updc = bp->b_cylin; upaddr->upda = (tn << 8) + sn; upaddr->upwc = -bp->b_bcount / sizeof (short); if (bp->b_flags & B_READ) cmd = UP_IE|UP_RCOM|UP_GO; else cmd = UP_IE|UP_WCOM|UP_GO; um->um_cmd = cmd; (void) ubago(ui); return (1);}/* * Now all ready to go, stuff the registers. */updgo(um) struct uba_ctlr *um;{ register struct updevice *upaddr = (struct updevice *)um->um_addr; um->um_tab.b_active = 2; /* should now be 2 */ upaddr->upba = um->um_ubinfo; upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300);}/* * Handle a disk interrupt. */upintr(sc21) register sc21;{ register struct buf *bp, *dp; register struct uba_ctlr *um = upminfo[sc21]; register struct uba_device *ui; register struct updevice *upaddr = (struct updevice *)um->um_addr; register unit; struct up_softc *sc = &up_softc[um->um_ctlr]; int as = (upaddr->upas & 0377) | sc->sc_softas; int needie = 1, waitdry; sc->sc_wticks = 0; sc->sc_softas = 0; /* * If controller wasn't transferring, then this is an * interrupt for attention status on seeking drives. * Just service them. */ if (um->um_tab.b_active != 2 && !sc->sc_recal) { if (upaddr->upcs1 & UP_TRE) upaddr->upcs1 = UP_TRE; goto doattn; } um->um_tab.b_active = 1; /* * Get device and block structures, and a pointer * to the uba_device for the drive. Select the drive. */ dp = um->um_tab.b_actf; bp = dp->b_actf; ui = updinfo[dkunit(bp)]; dk_busy &= ~(1 << ui->ui_dk); if ((upaddr->upcs2&07) != ui->ui_slave) upaddr->upcs2 = ui->ui_slave; if (bp->b_flags&B_BAD) { if (upecc(ui, CONT)) return; } /* * Check for and process errors on * either the drive or the controller. */ if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) { waitdry = 0; while ((upaddr->upds & UPDS_DRY) == 0) { if (++waitdry > 512) break; upwaitdry++; } if (upaddr->uper1&UPER1_WLE) { /* * Give up on write locked devices * immediately. */ printf("up%d: write locked\n", dkunit(bp)); bp->b_flags |= B_ERROR; } else if (++um->um_tab.b_errcnt > 27) { /* * After 28 retries (16 without offset, and * 12 with offset positioning) give up. * If the error was header CRC, the header is * screwed up, and the sector may in fact exist * in the bad sector table, better check... */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -