📄 wd.c
字号:
dprintf(DDSK,"--- badblock code -> Old = %d; ", blknum);#endif blknum = du->dk_dd.d_secperunit - du->dk_dd.d_nsectors - (bt_ptr - dkbad[unit].bt_bad) - 1; cylin = blknum / secpercyl; head = (blknum % secpercyl) / secpertrk; sector = blknum % secpertrk;#ifdef WDDEBUG dprintf(DDSK, "new = %d\n", blknum);#endif break; } } sector += 1; /* sectors begin with 1, not 0 */ wdtab.b_active = 1; /* mark controller active */ if(du->dk_skip==0 || wd_sebyse) { if(wdtab.b_errcnt && (bp->b_flags & B_READ) == 0) du->dk_bc += 512; while ((inb(wdc+wd_status) & WDCS_BUSY) != 0) ; /*while ((inb(wdc+wd_status) & WDCS_DRQ)) inb(wdc+wd_data);*/ outb(wdc+wd_precomp, 0xff); /*wr(wdc+wd_precomp, du->dk_dd.dk_precompcyl / 4);*/ /*if (bp->b_flags & B_FORMAT) { wr(wdc+wd_sector, du->dk_dd.dk_gap3); wr(wdc+wd_seccnt, du->dk_dd.dk_nsectors); } else {*/ if(wd_sebyse) outb(wdc+wd_seccnt, 1); else outb(wdc+wd_seccnt, ((du->dk_bc +511) / 512)); outb(wdc+wd_sector, sector); outb(wdc+wd_cyl_lo, cylin); outb(wdc+wd_cyl_hi, cylin >> 8); /* Set up the SDH register (select drive). */ outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf)); while ((inb(wdc+wd_status) & WDCS_READY) == 0) ; /*if (bp->b_flags & B_FORMAT) wr(wdc+wd_command, WDCC_FORMAT); else*/ outb(wdc+wd_command, (bp->b_flags & B_READ)? WDCC_READ : WDCC_WRITE);#ifdef WDDEBUG dprintf(DDSK,"sector %d cylin %d head %d addr %x sts %x\n", sector, cylin, head, addr, inb(wdc+wd_altsts));#endif} /* If this is a read operation, just go away until it's done. */ if (bp->b_flags & B_READ) return; /* Ready to send data? */ while ((inb(wdc+wd_status) & WDCS_DRQ) == 0); /* ASSUMES CONTIGUOUS MEMORY */ outsw (wdc+wd_data, addr+du->dk_skip*512, 256); du->dk_bc -= 512;}/* * these are globally defined so they can be found * by the debugger easily in the case of a system crash */daddr_t wd_errsector;daddr_t wd_errbn;unsigned char wd_errstat;/* Interrupt routine for the controller. Acknowledge the interrupt, check for * errors on the current operation, mark it done if necessary, and start * the next request. Also check for a partially done transfer, and * continue with the next chunk if so. */wdintr(unit){ register struct disk *du; register struct buf *bp, *dp; int status; char partch ; static wd_haderror; /* Shouldn't need this, but it may be a slow controller. */ while ((status = inb(wdc+wd_status)) & WDCS_BUSY) ; if (!wdtab.b_active) { printf("wd: extra interrupt\n"); return; }#ifdef WDDEBUG dprintf(DDSK,"I ");#endif dp = wdtab.b_actf; bp = dp->b_actf; du = &wddrives[wdunit(bp->b_dev)]; partch = wdpart(bp->b_dev) + 'a'; if (DISKSTATE(du->dk_state) <= RDLABEL) { if (wdcontrol(bp)) goto done; return; } if (status & (WDCS_ERR | WDCS_ECCCOR)) { wd_errstat = inb(wdc+wd_error); /* save error status */#ifdef WDDEBUG printf("status %x error %x\n", status, wd_errstat);#endif if(wd_sebyse == 0) { wd_haderror = 1; goto outt; } /*if (bp->b_flags & B_FORMAT) { du->dk_status = status; du->dk_error = wdp->wd_error; bp->b_flags |= B_ERROR; goto done; }*/ wd_errsector = (bp->b_cylin * du->dk_dd.d_secpercyl) + (((unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.d_secsize) % du->dk_dd.d_secpercyl) + du->dk_skip; wd_errbn = bp->b_blkno + du->dk_skip * du->dk_dd.d_secsize / DEV_BSIZE ; if (status & WDCS_ERR) { if (++wdtab.b_errcnt < RETRIES) { wdtab.b_active = 0; } else { printf("wd%d%c: ", du->dk_unit, partch); printf( "hard %s error, sn %d bn %d status %b error %b\n", (bp->b_flags & B_READ)? "read":"write", wd_errsector, wd_errbn, status, WDCS_BITS, wd_errstat, WDERR_BITS); bp->b_flags |= B_ERROR; /* flag the error */ } } else log(LOG_WARNING,"wd%d%c: soft ecc sn %d bn %d\n", du->dk_unit, partch, wd_errsector, wd_errbn); }outt: /* * If this was a successful read operation, fetch the data. */ if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && wdtab.b_active) { int chk, dummy; chk = min(256,du->dk_bc/2); /* Ready to receive data? */ while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;/*dprintf(DDSK,"addr %x\n", (int)bp->b_un.b_addr + du->dk_skip * 512);*/ insw(wdc+wd_data,(int)bp->b_un.b_addr + du->dk_skip * 512 ,chk); du->dk_bc -= 2*chk; while (chk++ < 256) insw (wdc+wd_data,&dummy,1); } wdxfer[du->dk_unit]++; if (wdtab.b_active) { if ((bp->b_flags & B_ERROR) == 0) { du->dk_skip++; /* Add to successful sectors. */ if (wdtab.b_errcnt) { log(LOG_WARNING, "wd%d%c: ", du->dk_unit, partch); log(LOG_WARNING, "soft %s error, sn %d bn %d error %b retries %d\n", (bp->b_flags & B_READ) ? "read" : "write", wd_errsector, wd_errbn, wd_errstat, WDERR_BITS, wdtab.b_errcnt); } wdtab.b_errcnt = 0; /* see if more to transfer */ /*if (du->dk_skip < (bp->b_bcount + 511) / 512) {*/ if (du->dk_bc > 0 && wd_haderror == 0) { wdstart(); return; /* next chunk is started */ } else if (wd_haderror && wd_sebyse == 0) { du->dk_skip = 0; wd_haderror = 0; wd_sebyse = 1; wdstart(); return; /* redo xfer sector by sector */ } }done: wd_sebyse = 0; /* done with this transfer, with or without error */ wdtab.b_actf = dp->b_forw; wdtab.b_errcnt = 0; du->dk_skip = 0; dp->b_active = 0; dp->b_actf = bp->av_forw; dp->b_errcnt = 0; bp->b_resid = 0; biodone(bp); } wdtab.b_active = 0; if (dp->b_actf) wdustart(du); /* requeue disk if more io to do */ if (wdtab.b_actf) wdstart(); /* start IO on next drive */}/* * Initialize a drive. */wdopen(dev, flags, fmt) dev_t dev; int flags, fmt;{ register unsigned int unit; register struct buf *bp; register struct disk *du; int part = wdpart(dev), mask = 1 << part; struct partition *pp; struct dkbad *db; int i, error = 0; unit = wdunit(dev); if (unit >= NWD) return (ENXIO) ; du = &wddrives[unit];#ifdef notdef if (du->dk_open){ du->dk_open++ ; return(0); /* already is open, don't mess with it */ }#endif du->dk_unit = unit; wdutab[unit].b_actf = NULL; /*if (flags & O_NDELAY) du->dk_state = WANTOPENRAW; else*/ du->dk_state = WANTOPEN; /* * Use the default sizes until we've read the label, * or longer if there isn't one there. */ du->dk_dd = dflt_sizes; /* * Recal, read of disk label will be done in wdcontrol * during first read operation. */ bp = geteblk(512); bp->b_dev = dev & 0xff00; bp->b_bcount = 0; bp->b_blkno = LABELSECTOR; bp->b_flags = B_READ; wdstrategy(bp); biowait(bp); if (bp->b_flags & B_ERROR) { error = ENXIO; du->dk_state = CLOSED; goto done; } if (du->dk_state == OPENRAW) { du->dk_state = OPENRAW; goto done; } /* * Read bad sector table into memory. */ i = 0; do { bp->b_flags = B_BUSY | B_READ; bp->b_blkno = du->dk_dd.d_secperunit - du->dk_dd.d_nsectors + i; if (du->dk_dd.d_secsize > DEV_BSIZE) bp->b_blkno *= du->dk_dd.d_secsize / DEV_BSIZE; else bp->b_blkno /= DEV_BSIZE / du->dk_dd.d_secsize; bp->b_bcount = du->dk_dd.d_secsize; bp->b_cylin = du->dk_dd.d_ncylinders - 1; wdstrategy(bp); biowait(bp); } while ((bp->b_flags & B_ERROR) && (i += 2) < 10 && i < du->dk_dd.d_nsectors); db = (struct dkbad *)(bp->b_un.b_addr);#define DKBAD_MAGIC 0x4321 if ((bp->b_flags & B_ERROR) == 0 && db->bt_mbz == 0 && db->bt_flag == DKBAD_MAGIC) { dkbad[unit] = *db; du->dk_state = OPEN; } else { printf("wd%d: %s bad-sector file\n", unit, (bp->b_flags & B_ERROR) ? "can't read" : "format error in"); error = ENXIO ; du->dk_state = OPENRAW; }done: bp->b_flags = B_INVAL | B_AGE; brelse(bp); if (error == 0) du->dk_open = 1; /* * 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 ((du->dk_openpart & mask) == 0 && part != RAWPART) { int start, end; pp = &du->dk_dd.d_partitions[part]; start = pp->p_offset; end = pp->p_offset + pp->p_size; for (pp = du->dk_dd.d_partitions; pp < &du->dk_dd.d_partitions[du->dk_dd.d_npartitions]; pp++) { if (pp->p_offset + pp->p_size <= start || pp->p_offset >= end) continue; if (pp - du->dk_dd.d_partitions == RAWPART) continue; if (du->dk_openpart & (1 << (pp - du->dk_dd.d_partitions))) log(LOG_WARNING, "wd%d%c: overlaps open partition (%c)\n", unit, part + 'a', pp - du->dk_dd.d_partitions + 'a'); } } if (part >= du->dk_dd.d_npartitions) return (ENXIO); du->dk_openpart |= mask; switch (fmt) { case S_IFCHR: du->dk_copenpart |= mask; break; case S_IFBLK: du->dk_bopenpart |= mask; break; } return (error);}/* * Implement operations other than read/write. * Called from wdstart or wdintr during opens and formats. * Uses finite-state-machine to track progress of operation in progress. * Returns 0 if operation still in progress, 1 if completed. */wdcontrol(bp) register struct buf *bp;{ register struct disk *du; register unit; unsigned char stat; int s, cnt; extern int bootdev, cyloffset; du = &wddrives[wdunit(bp->b_dev)]; unit = du->dk_unit; switch (DISKSTATE(du->dk_state)) { tryagainrecal: case WANTOPEN: /* set SDH, step rate, do restore */#ifdef WDDEBUG dprintf(DDSK,"wd%d: recal ", unit);#endif s = splbio(); /* not called from intr level ... */ outb(wdc+wd_sdh, WDSD_IBM | (unit << 4)); wdtab.b_active = 1; outb(wdc+wd_command, WDCC_RESTORE | WD_STEP); du->dk_state++; splx(s); return(0); case RECAL: if ((stat = inb(wdc+wd_status)) & WDCS_ERR) { printf("wd%d: recal", du->dk_unit); if (unit == 0) { printf(": status %b error %b\n", stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS); if (++wdtab.b_errcnt < RETRIES) goto tryagainrecal; } goto badopen; } /* some compaq controllers require this ... */ wdsetctlr(bp->b_dev, du); wdtab.b_errcnt = 0; if (ISRAWSTATE(du->dk_state)) { du->dk_state = OPENRAW; return(1); }retry:#ifdef WDDEBUG dprintf(DDSK,"rdlabel ");#endifif( cyloffset < 0 || cyloffset > 8192) cyloffset=0; /* * Read in sector LABELSECTOR to get the pack label * and geometry.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -