--- Net2/arch/i386/isa/wd.c 2018/04/24 18:11:55 1.1.1.4 +++ Net2/arch/i386/isa/wd.c 2018/04/24 18:19:54 1.1.1.5 @@ -1,4 +1,4 @@ -/*- +/* * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * @@ -33,18 +33,18 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * from:@(#)wd.c 7.2 (Berkeley) 5/9/91 + * from: @(#)wd.c 7.2 (Berkeley) 5/9/91 + * wd.c,v 1.24.2.3 1993/07/28 00:11:28 deraadt Exp */ /* Note: This code heavily modified by tih@barsoom.nhh.no; use at own risk! */ /* The following defines represent only a very small part of the mods, most */ -/* of them are not marked in any way. -tih */ +/* of them are not marked in any way. -tih */ -#undef WDOPENLOCK /* Prevent reentrancy in wdopen() for testing */ #define TIHMODS /* wdopen() workaround, some splx() calls */ -#define TIHBAD144 /* new bad144 bad sector handling */ #define QUIETWORKS /* define this when wdopen() can actually set DKFL_QUIET */ #define INSTRUMENT /* Add instrumentation stuff by Brad Parker */ +#define TIPCAT /* theo says: whatever it is, it looks important! */ /* TODO: peel out buffer at low ipl, speed improvement */ /* TODO: find and fix the timing bugs apparent on some controllers */ @@ -74,7 +74,15 @@ #include "syslog.h" #include "vm/vm.h" -#define RETRIES 5 /* number of retries before giving up */ +#ifndef WDCNDELAY +#define WDCNDELAY 400000 /* delay = 25us; so 10s for a controller state change */ +#endif +#define WDCDELAY 25 + +/* if you enable this, it will report any delays more than 25us * N long */ +/*#define WDCNDELAY_DEBUG 6 */ + +#define WDIORETRIES 5 /* number of retries before giving up */ #define wdnoreloc(dev) (minor(dev) & 0x80) /* ignore partition table */ #define wddospart(dev) (minor(dev) & 0x40) /* use dos partitions */ @@ -125,29 +133,24 @@ struct disk { #define DKFL_WRITEPROT 0x00040 /* manual unit write protect */ struct wdparams dk_params; /* ESDI/IDE drive/controller parameters */ struct disklabel dk_dd; /* device configuration data */ - struct dos_partition - dk_dospartitions[NDOSPART]; /* DOS view of disk */ - struct dkbad dk_bad; /* bad sector table */ -#ifdef TIHBAD144 + struct cpu_disklabel dk_cpd; long dk_badsect[127]; /* 126 plus trailing -1 marker */ -#endif }; -#ifdef TIHBAD144 +struct board { + short dkc_port; +}; + void bad144intern(struct disk *); -#endif void wddisksort(); +struct board wdcontroller[NWDC]; struct disk *wddrives[NWD]; /* table of units */ struct buf wdtab[NWDC]; /* various per-controller info */ struct buf wdutab[NWD]; /* head of queue per drive */ struct buf rwdbuf[NWD]; /* buffers for raw IO */ long wdxfer[NWD]; /* count of transfers */ -#ifdef WDOPENLOCK -int wdopenbusy = 0; -#endif - int wdprobe(), wdattach(); struct isa_driver wdcdriver = { @@ -170,10 +173,6 @@ wdprobe(struct isa_device *dvp) struct disk *du; int wdc; -#ifdef WDOPENLOCK - wdopenbusy = 0; -#endif - if (dvp->id_unit >= NWDC) return(0); @@ -183,6 +182,7 @@ wdprobe(struct isa_device *dvp) du->dk_ctrlr = dvp->id_unit; du->dk_unit = 0; du->dk_lunit = 0; + wdcontroller[dvp->id_unit].dkc_port = dvp->id_iobase; wdc = du->dk_port = dvp->id_iobase; @@ -192,20 +192,12 @@ wdprobe(struct isa_device *dvp) if(inb(wdc+wd_error) == 0x5a || inb(wdc+wd_cyl_lo) != 0xa5) goto nodevice; - /* reset the device */ - outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS)); - DELAY(1000); - outb(wdc+wd_ctlr, WDCTL_IDS); - DELAY(1000); + wdreset(dvp->id_unit, wdc, 0); /* execute a controller only command */ if (wdcommand(du, WDCC_DIAGNOSE) < 0) goto nodevice; - (void) inb(wdc+wd_error); /* XXX! */ - outb(wdc+wd_ctlr, WDCTL_4BIT); - DELAY(1000); - bzero(&wdtab[du->dk_ctrlr], sizeof(struct buf)); free(du, M_TEMP); @@ -217,71 +209,78 @@ nodevice: } /* + * Called for the controller too * Attach each drive if possible. */ int wdattach(struct isa_device *dvp) { int unit, lunit; - extern struct isa_device isa_biotab_wdc[]; - struct isa_device *wdup; struct disk *du; - int first = 0; - if (dvp->id_unit >= NWDC) + if (dvp->id_masunit == -1) + return(0); + if (dvp->id_masunit >= NWDC) return(0); - for (wdup = isa_biotab_wdc; wdup->id_driver != 0; wdup++) { - if (wdup->id_iobase != dvp->id_iobase) - continue; - lunit = wdup->id_unit; - if (lunit >= NWD) - continue; - unit = wdup->id_physid; + lunit = dvp->id_unit; + if (lunit == -1) { + printf("wdc%d: cannot support unit ?\n", dvp->id_masunit); + return 0; + } + if (lunit >= NWD) + return(0); + unit = dvp->id_physid; - du = wddrives[lunit] = (struct disk *) - malloc(sizeof(struct disk), M_TEMP, M_NOWAIT); - bzero(du, sizeof(struct disk)); - bzero(&wdutab[lunit], sizeof(struct buf)); - bzero(&rwdbuf[lunit], sizeof(struct buf)); - wdxfer[lunit] = 0; - - du->dk_ctrlr = dvp->id_unit; - du->dk_unit = unit; - du->dk_lunit = lunit; - du->dk_port = dvp->id_iobase; - - if(wdgetctlr(unit, du) == 0) { - int i, blank; - if(first==0) { - first = 1; - printf("wdc%d: <", dvp->id_unit); - - for (i=blank=0; idk_params.wdp_model); i++) { - char c = du->dk_params.wdp_model[i]; - if (blank && c == ' ') - continue; - if (blank && c != ' ') { - printf(" %c", c); - blank = 0; - continue; - } - if (c == ' ') - blank = 1; - else - printf("%c", c); - } - printf(">\n"); - } - printf("wd%d at wdc%d slave %d\n", lunit, dvp->id_unit, unit); - } else { - /*printf("wd%d at wdc%d slave %d -- error\n", - lunit, dvp->id_unit, unit);*/ - wddrives[lunit] = 0; - free(du, M_TEMP); + du = wddrives[lunit] = (struct disk *) + malloc(sizeof(struct disk), M_TEMP, M_NOWAIT); + bzero(du, sizeof(struct disk)); + bzero(&wdutab[lunit], sizeof(struct buf)); + bzero(&rwdbuf[lunit], sizeof(struct buf)); + wdxfer[lunit] = 0; + + du->dk_ctrlr = dvp->id_masunit; + du->dk_unit = unit; + du->dk_lunit = lunit; + du->dk_port = wdcontroller[dvp->id_masunit].dkc_port; + + if(wdgetctlr(unit, du) == 0) { + int i, blank; + + printf("wd%d at wdc%d targ %d: ", + dvp->id_unit, dvp->id_masunit, dvp->id_physid); + if(du->dk_params.wdp_heads==0) + printf("(unknown size) <"); + else + printf("%dMB %d cyl, %d head, %d sec <", + du->dk_dd.d_ncylinders * du->dk_dd.d_secpercyl / 2048, + du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks, + du->dk_dd.d_nsectors); + for (i=blank=0; idk_params.wdp_model); i++) { + char c = du->dk_params.wdp_model[i]; + if (!c) + break; + if (blank && c == ' ') + continue; + if (blank && c != ' ') { + printf(" %c", c); + blank = 0; + continue; + } + if (c == ' ') + blank = 1; + else + printf("%c", c); } + printf(">\n"); + } else { + /*printf("wd%d at wdc%d slave %d -- error\n", + lunit, dvp->id_masunit, unit);*/ + wddrives[lunit] = 0; + free(du, M_TEMP); + return 0; } - return(1); + return 1; } /* Read/write routine for a buffer. Finds the proper unit, range checks @@ -388,7 +387,7 @@ wdstart(int ctrlr) struct disklabel *lp; struct buf *dp; long blknum, cylin, head, sector; - long secpertrk, secpercyl, addr; + long secpertrk, secpercyl, addr, timeout; int lunit, wdc; int xfrblknum; unsigned char status; @@ -461,7 +460,6 @@ loop: head = (blknum % secpercyl) / secpertrk; sector = blknum % secpertrk; -#ifdef TIHBAD144 /* Check for bad sectors if we have them, and not formatting */ /* Only do this in single-sector mode, or when starting a */ /* multiple-sector transfer. */ @@ -494,7 +492,6 @@ loop: } } } -#endif if( du->dk_flags & DKFL_SINGLE) { du->dk_bct = du->dk_bc; du->dk_skipm = du->dk_skip; @@ -521,6 +518,7 @@ loop: } #endif +retry: /* if starting a multisector transfer, or doing single transfers */ if (du->dk_skipm == 0 || (du->dk_flags & DKFL_SINGLE)) { if (wdtab[ctrlr].b_errcnt && (bp->b_flags & B_READ) == 0) { @@ -529,8 +527,17 @@ loop: } /* controller idle? */ - while (inb(wdc+wd_status) & WDCS_BUSY) - ; + for (timeout=0; inb(wdc+wd_status) & WDCS_BUSY; ) { + DELAY(WDCDELAY); + if (++timeout < WDCNDELAY) + continue; + wdreset(ctrlr, wdc, 1); + break; + } +#ifdef WDCNDELAY_DEBUG + if(timeout>WDCNDELAY_DEBUG) + printf("wdc%d: timeout took %dus\n", ctrlr, WDCDELAY * timeout); +#endif /* stuff the task file */ outb(wdc+wd_precomp, lp->d_precompcyl / 4); @@ -559,8 +566,17 @@ loop: outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit<<4) | (head & 0xf)); /* wait for drive to become ready */ - while ((inb(wdc+wd_status) & WDCS_READY) == 0) - ; + for (timeout=0; (inb(wdc+wd_status) & WDCS_READY) == 0; ) { + DELAY(WDCDELAY); + if (++timeout < WDCNDELAY) + continue; + wdreset(ctrlr, wdc, 1); + goto retry; + } +#ifdef WDCNDELAY_DEBUG + if(timeout>WDCNDELAY_DEBUG) + printf("wdc%d: timeout took %dus\n", ctrlr, WDCDELAY * timeout); +#endif /* initiate command! */ #ifdef B_FORMAT @@ -583,8 +599,17 @@ loop: return; /* ready to send data? */ - while ((inb(wdc+wd_altsts) & WDCS_DRQ) == 0) - ; + for (timeout=0; (inb(wdc+wd_altsts) & WDCS_DRQ) == 0; ) { + DELAY(WDCDELAY); + if (++timeout < WDCNDELAY) + continue; + wdreset(ctrlr, wdc, 1); + goto retry; + } +#ifdef WDCNDELAY_DEBUG + if(timeout>WDCNDELAY_DEBUG) + printf("wdc%d: timeout took %dus\n", ctrlr, WDCDELAY * timeout); +#endif /* then send it! */ outagain: @@ -621,7 +646,7 @@ wdintr(struct intrframe wdif) #ifdef WDDEBUG printf("I%d ", ctrlr); #endif - + while ((status = inb(wdc+wd_status)) & WDCS_BUSY) ; @@ -652,7 +677,7 @@ wdintr(struct intrframe wdif) /* error or error correction? */ if (status & WDCS_ERR) { - if (++wdtab[ctrlr].b_errcnt < RETRIES) { + if (++wdtab[ctrlr].b_errcnt < WDIORETRIES) { wdtab[ctrlr].b_active = 0; } else { if((du->dk_flags & DKFL_QUIET) == 0) { @@ -714,9 +739,10 @@ outt: /* see if more to transfer */ if (du->dk_bc > 0 && (du->dk_flags & DKFL_ERROR) == 0) { if( (du->dk_flags & DKFL_SINGLE) - || (du->dk_flags & B_READ) == 0) + || (du->dk_flags & B_READ) == 0) { wdstart(ctrlr); return; /* next chunk is started */ + } } else if ((du->dk_flags & (DKFL_SINGLE|DKFL_ERROR)) == DKFL_ERROR) { du->dk_skip = 0; du->dk_skipm = 0; @@ -778,17 +804,6 @@ wdopen(dev_t dev, int flags, int fmt, st if (du == 0) return (ENXIO); -#ifdef WDOPENLOCK - printf("[Enter wd%d%c]\n", lunit, part+'a'); - if (wdopenbusy) { - printf("[Sleep wd%d%c]\n", lunit, part+'a'); - while (wdopenbusy) - ; - } - printf("[Lock wd%d%c]\n", lunit, part+'a'); - wdopenbusy = 1; -#endif - #ifdef QUIETWORKS if (part == WDRAW) du->dk_flags |= DKFL_QUIET; @@ -800,9 +815,6 @@ wdopen(dev_t dev, int flags, int fmt, st if ((du->dk_flags & DKFL_BSDLABEL) == 0) { du->dk_flags |= DKFL_WRITEPROT; -#ifdef WDOPENLOCK - printf("[Init wd%d%c]\n", lunit, part+'a'); -#endif wdutab[lunit].b_actf = NULL; /* @@ -824,12 +836,10 @@ wdopen(dev_t dev, int flags, int fmt, st #if defined(TIHMODS) && defined(garbage) /* wdsetctlr(dev, du); */ /* Maybe do this TIH */ msg = readdisklabel(makewddev(major(dev), wdunit(dev), WDRAW), - wdstrategy, &du->dk_dd, du->dk_dospartitions, - 0, 0); + wdstrategy, &du->dk_dd, &du->dk_cpd); wdsetctlr(dev, du); msg = readdisklabel(makewddev(major(dev), wdunit(dev), WDRAW), - wdstrategy, &du->dk_dd, du->dk_dospartitions, - &du->dk_bad, 0); + wdstrategy, &du->dk_dd, &du->dk_cpd); if (msg) { #ifdef QUIETWORKS if((du->dk_flags & DKFL_QUIET) == 0) { @@ -853,8 +863,7 @@ wdopen(dev_t dev, int flags, int fmt, st } #else if (msg = readdisklabel(makewddev(major(dev), wdunit(dev), WDRAW), - wdstrategy, &du->dk_dd, du->dk_dospartitions, - &du->dk_bad, 0)) { + wdstrategy, &du->dk_dd, &du->dk_cpd) ) { if((du->dk_flags & DKFL_QUIET) == 0) { log(LOG_WARNING, "wd%d: cannot find label (%s)\n", lunit, msg); @@ -872,18 +881,12 @@ wdopen(dev_t dev, int flags, int fmt, st done: if (error) { -#ifdef WDOPENLOCK - printf("[Error wd%d%c]\n", lunit, part+'a'); - wdopenbusy = 0; -#endif return(error); } } -#ifdef TIHBAD144 if (du->dk_flags & DKFL_BADSECT) bad144intern(du); -#endif /* * Warn if a partion is opened @@ -913,10 +916,6 @@ done: } if (part >= du->dk_dd.d_npartitions && part != WDRAW) { -#ifdef WDOPENLOCK - printf("[ENXIO wd%d%c]\n", lunit, part+'a'); - wdopenbusy = 0; -#endif return (ENXIO); } @@ -930,10 +929,6 @@ done: du->dk_bopenpart |= mask; break; } -#ifdef WDOPENLOCK - printf("[Done wd%d%c]\n", lunit, part+'a'); - wdopenbusy = 0; -#endif return (0); } @@ -949,7 +944,7 @@ wdcontrol(register struct buf *bp) register struct disk *du; register unit, lunit; unsigned char stat; - int s, ctrlr; + int s, ctrlr, timeout; int wdc; du = wddrives[wdunit(bp->b_dev)]; @@ -967,15 +962,34 @@ tryagainrecal: s = splbio(); /* not called from intr level ... */ wdgetctlr(unit, du); #ifdef TIPCAT - while ((inb(wdc+wd_status) & WDCS_READY) == 0) - ; + + for (timeout=0; (inb(wdc+wd_status) & WDCS_READY) == 0; ) { + DELAY(WDCDELAY); + if (++timeout < WDCNDELAY) + continue; + wdreset(ctrlr, wdc, 1); + goto tryagainrecal; + } +#ifdef WDCNDELAY_DEBUG + if(timeout>WDCNDELAY_DEBUG) + printf("wdc%d: timeout took %dus\n", ctrlr, WDCDELAY * timeout); +#endif #endif outb(wdc+wd_sdh, WDSD_IBM | (unit << 4)); wdtab[ctrlr].b_active = 1; outb(wdc+wd_command, WDCC_RESTORE | WD_STEP); #ifdef TIPCAT - while ((inb(wdc+wd_status) & WDCS_READY) == 0) - ; + for (timeout=0; (inb(wdc+wd_status) & WDCS_READY) == 0; ) { + DELAY(WDCDELAY); + if (++timeout < WDCNDELAY) + continue; + wdreset(ctrlr, wdc, 1); + goto tryagainrecal; + } +#ifdef WDCNDELAY_DEBUG + if(timeout>WDCNDELAY_DEBUG) + printf("wdc%d: timeout took %dus\n", ctrlr, WDCDELAY * timeout); +#endif #endif du->dk_state = RECAL; splx(s); @@ -988,7 +1002,7 @@ tryagainrecal: stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS); } - if (++wdtab[ctrlr].b_errcnt < RETRIES) + if (++wdtab[ctrlr].b_errcnt < WDIORETRIES) goto tryagainrecal; bp->b_error = ENXIO; /* XXX needs translation */ goto badopen; @@ -1026,31 +1040,46 @@ badopen: static int wdcommand(struct disk *du, int cmd) { - int timeout = 5000000, stat, wdc; + int timeout, stat, wdc; - DELAY(2000); - /* controller ready for command? */ + /*DELAY(2000);*/ wdc = du->dk_port; - while (((stat = inb(wdc + wd_status)) & WDCS_BUSY) && timeout > 0) - timeout--; - if (timeout <= 0) - return(-1); + + /* controller ready for command? */ + for (timeout=0; (stat=inb(wdc+wd_status)) & WDCS_BUSY; ) { + DELAY(WDCDELAY); + if(++timeout > WDCNDELAY) + return -1; + } +#ifdef WDCNDELAY_DEBUG + if(timeout>WDCNDELAY_DEBUG) + printf("wdc%d: timeout took %dus\n", du->dk_ctrlr, WDCDELAY * timeout); +#endif /* send command, await results */ outb(wdc+wd_command, cmd); - while (((stat = inb(wdc+wd_status)) & WDCS_BUSY) && timeout > 0) - timeout--; - if (timeout <= 0) - return(-1); + for (timeout=0; (stat=inb(wdc+wd_status)) & WDCS_BUSY; ) { + DELAY(WDCDELAY); + if(++timeout > WDCNDELAY) + return -1; + } +#ifdef WDCNDELAY_DEBUG + if(timeout>WDCNDELAY_DEBUG) + printf("wdc%d: timeout took %dus\n", du->dk_ctrlr, WDCDELAY * timeout); +#endif if (cmd != WDCC_READP) return (stat); /* is controller ready to return data? */ - while (((stat = inb(wdc+wd_status)) & (WDCS_ERR|WDCS_DRQ)) == 0 && - timeout > 0) - timeout--; - if (timeout <= 0) - return(-1); + for (timeout=0; ((stat=inb(wdc+wd_status)) & (WDCS_ERR|WDCS_DRQ)) == 0; ) { + DELAY(WDCDELAY); + if(++timeout > WDCNDELAY) + return -1; + } +#ifdef WDCNDELAY_DEBUG + if(timeout>WDCNDELAY_DEBUG) + printf("wdc%d: timeout took %dus\n", du->dk_ctrlr, WDCDELAY * timeout); +#endif return (stat); } @@ -1067,9 +1096,11 @@ wdsetctlr(dev_t dev, struct disk *du) du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks, du->dk_dd.d_nsectors); */ - DELAY(2000); - x = splbio(); wdc = du->dk_port; + + /*DELAY(2000);*/ + + x = splbio(); outb(wdc+wd_cyl_lo, du->dk_dd.d_ncylinders); /* TIH: was ...ders+1 */ outb(wdc+wd_cyl_hi, (du->dk_dd.d_ncylinders)>>8); /* TIH: was ...ders+1 */ outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4) + du->dk_dd.d_ntracks-1); @@ -1096,27 +1127,50 @@ wdgetctlr(int u, struct disk *du) int stat, x, i, wdc; char tb[DEV_BSIZE]; struct wdparams *wp; - long timeout = 5000000; + int timeout; x = splbio(); /* not called from intr level ... */ wdc = du->dk_port; #ifdef TIPCAT - while ((inb(wdc+wd_status) & WDCS_READY) == 0 && timeout > 0) - timeout--; - if (timeout <= 0) { - splx(x); - return (-1); + for (timeout=0; (inb(wdc+wd_status) & WDCS_BUSY); ) { + DELAY(WDCDELAY); + if(++timeout > WDCNDELAY) { + splx(x); + return -1; + } } +#ifdef WDCNDELAY_DEBUG + if(timeout>WDCNDELAY_DEBUG) + printf("wdc%d: timeout took %dus\n", du->dk_ctrlr, WDCDELAY * timeout); +#endif #endif outb(wdc+wd_sdh, WDSD_IBM | (u << 4)); +#ifdef TIPCAT + for (timeout=0; (inb(wdc+wd_status) & WDCS_READY) == 0; ) { + DELAY(WDCDELAY); + if(++timeout > WDCNDELAY) { + splx(x); + return -1; + } + } +#ifdef WDCNDELAY_DEBUG + if(timeout>WDCNDELAY_DEBUG) + printf("wdc%d: timeout took %dus\n", du->dk_ctrlr, WDCDELAY * timeout); +#endif +#endif stat = wdcommand(du, WDCC_READP); #ifdef TIPCAT - while ((inb(wdc+wd_status) & WDCS_READY) == 0 && timeout > 0) - timeout--; - if (timeout <= 0) { - splx(x); - return (-1); + for (timeout=0; (inb(wdc+wd_status) & WDCS_READY) == 0; ) { + DELAY(WDCDELAY); + if(++timeout > WDCNDELAY) { + splx(x); + return -1; + } } +#ifdef WDCNDELAY_DEBUG + if(timeout>WDCNDELAY_DEBUG) + printf("wdc%d: timeout took %dus\n", du->dk_ctrlr, WDCDELAY * timeout); +#endif #endif #ifndef TIHMODS @@ -1128,41 +1182,57 @@ wdgetctlr(int u, struct disk *du) return(stat); } #endif - if (stat & WDCS_ERR) { - splx(x); - return(inb(wdc+wd_error)); - } - - /* obtain parameters */ - wp = &du->dk_params; - insw(wdc+wd_data, tb, sizeof(tb)/sizeof(short)); - bcopy(tb, wp, sizeof(struct wdparams)); - - /* shuffle string byte order */ - for (i=0; i < sizeof(wp->wdp_model); i+=2) { - u_short *p; - p = (u_short *) (wp->wdp_model + i); - *p = ntohs(*p); + + if( (stat & WDCS_ERR) == 0) { + /* obtain parameters */ + wp = &du->dk_params; + insw(wdc+wd_data, tb, sizeof(tb)/sizeof(short)); + bcopy(tb, wp, sizeof(struct wdparams)); + + /* shuffle string byte order */ + for (i=0; i < sizeof(wp->wdp_model); i+=2) { + u_short *p; + p = (u_short *) (wp->wdp_model + i); + *p = ntohs(*p); + } + + strncpy(du->dk_dd.d_typename, "ESDI/IDE", sizeof du->dk_dd.d_typename); + du->dk_dd.d_type = DTYPE_ESDI; + bcopy(wp->wdp_model+20, du->dk_dd.d_packname, 14-1); + + /* update disklabel given drive information */ + du->dk_dd.d_ncylinders = wp->wdp_fixedcyl + wp->wdp_removcyl /*+- 1*/; + du->dk_dd.d_ntracks = wp->wdp_heads; + du->dk_dd.d_nsectors = wp->wdp_sectors; + du->dk_dd.d_secpercyl = du->dk_dd.d_ntracks * du->dk_dd.d_nsectors; + du->dk_dd.d_partitions[1].p_size = du->dk_dd.d_secpercyl * + wp->wdp_sectors; + du->dk_dd.d_partitions[1].p_offset = 0; + } else { + /* + * If WDCC_READP fails then we might have an old drive + * so we try a seek to 0; if that passes then the + * drive is there but it's OLD AND KRUSTY. + */ + stat = wdcommand(du, WDCC_RESTORE | WD_STEP); + if(stat & WDCS_ERR) { + splx(x); + return(inb(wdc+wd_error)); + } + + strncpy(du->dk_dd.d_typename, "ST506", sizeof du->dk_dd.d_typename); + strncpy(du->dk_params.wdp_model, "Unknown Type", + sizeof du->dk_params.wdp_model); + du->dk_dd.d_type = DTYPE_ST506; } -/* + +#if 0 printf("gc %x cyl %d trk %d sec %d type %d sz %d model %s\n", wp->wdp_config, wp->wdp_fixedcyl+wp->wdp_removcyl, wp->wdp_heads, wp->wdp_sectors, wp->wdp_cntype, wp->wdp_cnsbsz, wp->wdp_model); -*/ +#endif - /* update disklabel given drive information */ - du->dk_dd.d_ncylinders = wp->wdp_fixedcyl + wp->wdp_removcyl /*+- 1*/; - du->dk_dd.d_ntracks = wp->wdp_heads; - du->dk_dd.d_nsectors = wp->wdp_sectors; - du->dk_dd.d_secpercyl = du->dk_dd.d_ntracks * du->dk_dd.d_nsectors; - du->dk_dd.d_partitions[1].p_size = du->dk_dd.d_secpercyl * wp->wdp_sectors; - du->dk_dd.d_partitions[1].p_offset = 0; - - /* dubious ... */ - bcopy("ESDI/IDE", du->dk_dd.d_typename, 9); - bcopy(wp->wdp_model+20, du->dk_dd.d_packname, 14-1); /* better ... */ - du->dk_dd.d_type = DTYPE_ESDI; du->dk_dd.d_subtype |= DSTYPE_GEOMETRY; /* XXX sometimes possibly needed */ @@ -1212,10 +1282,8 @@ wdioctl(dev_t dev, int cmd, caddr_t addr if ((flag & FWRITE) == 0) error = EBADF; else { - du->dk_bad = *(struct dkbad *)addr; -#ifdef TIHBAD144 + du->dk_cpd.bad = *(struct dkbad *)addr; bad144intern(du); -#endif } break; @@ -1232,10 +1300,11 @@ wdioctl(dev_t dev, int cmd, caddr_t addr case DIOCSDINFO: if ((flag & FWRITE) == 0) error = EBADF; - else + else { error = setdisklabel(&du->dk_dd, (struct disklabel *)addr, /*(du->dk_flags&DKFL_BSDLABEL) ? du->dk_openpart : */0, - du->dk_dospartitions); + &du->dk_cpd); + } if (error == 0) { du->dk_flags |= DKFL_BSDLABEL; wdsetctlr(dev, du); @@ -1256,18 +1325,17 @@ wdioctl(dev_t dev, int cmd, caddr_t addr error = EBADF; else if ((error = setdisklabel(&du->dk_dd, (struct disklabel *)addr, /*(du->dk_flags & DKFL_BSDLABEL) ? du->dk_openpart :*/ 0, - du->dk_dospartitions)) == 0) { + &du->dk_cpd)) == 0) { int wlab; du->dk_flags |= DKFL_BSDLABEL; wdsetctlr(dev, du); /* simulate opening partition 0 so write succeeds */ - du->dk_openpart |= (1 << 0); /* XXX */ + du->dk_openpart |= (1 << 0); /* XXX */ wlab = du->dk_wlabel; du->dk_wlabel = 1; - error = writedisklabel(dev, wdstrategy, - &du->dk_dd, du->dk_dospartitions); + error = writedisklabel(dev, wdstrategy, &du->dk_dd, &du->dk_cpd); du->dk_openpart = du->dk_copenpart | du->dk_bopenpart; du->dk_wlabel = wlab; } @@ -1342,7 +1410,7 @@ wdsize(dev_t dev) return((int)du->dk_dd.d_partitions[part].p_size); } -extern char *vmmap; /* poor name! */ +extern char *vmmap; /* poor name! */ /* dump core after a system crash */ int @@ -1361,9 +1429,11 @@ wddump(dev_t dev) addr = (char *) 0; /* starting address */ - /* toss any characters present prior to dump */ - while (sgetc(1)) +#if DO_NOT_KNOW_HOW + /* toss any characters present prior to dump, ie. non-blocking getc */ + while (cngetc()) ; +#endif /* size of memory to dump */ num = Maxmem; @@ -1426,7 +1496,6 @@ wddump(dev_t dev) head = (blknum % secpercyl) / secpertrk; sector = blknum % secpertrk; -#ifdef TIHBAD144 if (du->dk_flags & DKFL_BADSECT) { long newblk; int i; @@ -1445,7 +1514,6 @@ wddump(dev_t dev) } } } -#endif sector++; /* origin 1 */ /* select drive. */ @@ -1476,7 +1544,7 @@ wddump(dev_t dev) if (inb(wdc+wd_status) & WDCS_ERR) return(EIO); - /* Check data request (should be done). */ + /* Check data request (should be done). */ if (inb(wdc+wd_status) & WDCS_DRQ) return(EIO); @@ -1498,15 +1566,16 @@ wddump(dev_t dev) blknum++; (int) addr += 512; - /* operator aborting dump? */ - if (sgetc(1)) +#if DO_NOT_KNOW_HOW + /* operator aborting dump? non-blocking getc() */ + if (cngetc()) return(EINTR); +#endif } return(0); } #endif -#ifdef TIHBAD144 /* * Internalize the bad sector table. */ @@ -1520,21 +1589,19 @@ bad144intern(struct disk *du) } for (i = 0; i < 126; i++) { - if (du->dk_bad.bt_bad[i].bt_cyl == 0xffff) { + if (du->dk_cpd.bad.bt_bad[i].bt_cyl == 0xffff) { break; } else { du->dk_badsect[i] = - du->dk_bad.bt_bad[i].bt_cyl * du->dk_dd.d_secpercyl + - (du->dk_bad.bt_bad[i].bt_trksec >> 8) * du->dk_dd.d_nsectors + - (du->dk_bad.bt_bad[i].bt_trksec & 0x00ff); + du->dk_cpd.bad.bt_bad[i].bt_cyl * + du->dk_dd.d_secpercyl + + (du->dk_cpd.bad.bt_bad[i].bt_trksec >> 8) * + du->dk_dd.d_nsectors + + (du->dk_cpd.bad.bt_bad[i].bt_trksec & 0x00ff); } } } } -#endif - -wdprint() {} - /* this routine was adopted from the kernel sources */ /* more efficient because b_cylin is not really as useful at this level */ @@ -1623,3 +1690,28 @@ insert: dp->b_actl = bp; } +wdreset(ctrlr, wdc, err) +int ctrlr; +{ + int stat, timeout; + + if(err) + printf("wdc%d: busy too long, resetting\n", ctrlr); + + /* reset the device */ + outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS)); + DELAY(1000); + outb(wdc+wd_ctlr, WDCTL_4BIT); + + for (timeout=0; (stat=inb(wdc+wd_status)) & WDCS_BUSY; ) { + DELAY(WDCDELAY); + if(++timeout > WDCNDELAY) { + printf("wdc%d: failed to reset controller\n", ctrlr); + break; + } + } +#ifdef WDCNDELAY_DEBUG + if(timeout>WDCNDELAY_DEBUG) + printf("wdc%d: timeout took %dus\n", ctrlr, WDCDELAY * timeout); +#endif +}