X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/b093933aee94b9e565bd8c76aa206070ff80a961..d6b1355873a0384c5d4cdbe398dc7eb67f4575ce:/usr/src/sys.386bsd/i386/isa/wd.c diff --git a/usr/src/sys.386bsd/i386/isa/wd.c b/usr/src/sys.386bsd/i386/isa/wd.c index 20862605d1..775284a1d7 100644 --- a/usr/src/sys.386bsd/i386/isa/wd.c +++ b/usr/src/sys.386bsd/i386/isa/wd.c @@ -33,11 +33,25 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)wd.c 7.2 (Berkeley) 5/9/91 + * from:@(#)wd.c 7.2 (Berkeley) 5/9/91 + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 4 00072 + * -------------------- ----- ---------------------- + * + * 17 Sep 92 Frank Maclachlan Fixed I/O error reporting on raw device + * 31 Jul 92 Christoph Robitschko Fixed second disk recognition, + * bzero of malloced memory for warm + * boot problem. + * 19 Aug 92 Frank Maclachlan Fixed bug when first sector of a + * multisector read is in bad144 table. + * 17 Jan 93 B. Evans & A.Chernov Fixed bugs from previous patches, + * driver initialization, and cylinder + * boundary conditions. */ -/* TODO:peel out buffer at low ipl, - speed improvement, rewrite to clean code from garbage artifacts */ +/* TODO:peel out buffer at low ipl, speed improvement */ #include "wd.h" @@ -53,147 +67,184 @@ #include "disklabel.h" #include "buf.h" #include "uio.h" +#include "malloc.h" +#include "machine/cpu.h" #include "i386/isa/isa_device.h" #include "i386/isa/icu.h" #include "i386/isa/wdreg.h" #include "syslog.h" #include "vm/vm.h" +#define _NWD (NWD - 1) /* One is for the controller XXX 31 Jul 92*/ + #define RETRIES 5 /* number of retries before giving up */ #define MAXTRANSFER 32 /* max size of transfer in page clusters */ -#define wdctlr(dev) ((minor(dev) & 0x20) >> 5) -#define wdunit(dev) ((minor(dev) & 0x18) >> 3) -#define wdpart(dev) ((minor(dev) & 0x7)) +#define wdnoreloc(dev) (minor(dev) & 0x80) /* ignore partition table */ +#define wddospart(dev) (minor(dev) & 0x40) /* use dos partitions */ +#define wdunit(dev) ((minor(dev) & 0x38) >> 3) +#define wdpart(dev) (minor(dev) & 0x7) +#define makewddev(maj, unit, part) (makedev(maj,((unit<<3)+part))) +#define WDRAW 3 /* 'd' partition isn't a partition! */ #define b_cylin b_resid /* cylinder number for doing IO to */ /* shares an entry in the buf struct */ /* - * Drive states. Used for open and format operations. - * States < OPEN (> 0) are transient, during an open operation. - * OPENRAW is used for unlabeled disks, and for floppies, to inhibit - * bad-sector forwarding. + * Drive states. Used to initialize drive. */ -#define RAWDISK 8 /* raw disk operation, no translation*/ -#define ISRAWSTATE(s) (RAWDISK&(s)) /* are we in a raw state? */ -#define DISKSTATE(s) (~RAWDISK&(s)) /* are we in a given state regardless - of raw or cooked mode? */ #define CLOSED 0 /* disk is closed. */ - /* "cooked" disk states */ #define WANTOPEN 1 /* open requested, not started */ #define RECAL 2 /* doing restore */ -#define RDLABEL 3 /* reading pack label */ -#define RDBADTBL 4 /* reading bad-sector table */ -#define OPEN 5 /* done with open */ - -#define WANTOPENRAW (WANTOPEN|RAWDISK) /* raw WANTOPEN */ -#define RECALRAW (RECAL|RAWDISK) /* raw open, doing restore */ -#define OPENRAW (OPEN|RAWDISK) /* open, but unlabeled disk or floppy */ - +#define OPEN 3 /* done with open */ /* * The structure of a disk drive. */ struct disk { - struct disklabel dk_dd; /* device configuration data */ long dk_bc; /* byte count left */ short dk_skip; /* blocks already transferred */ char dk_unit; /* physical unit number */ char dk_state; /* control state */ u_char dk_status; /* copy of status reg. */ u_char dk_error; /* copy of error reg. */ - short dk_open; /* open/closed refcnt */ + short dk_port; /* i/o port base */ + u_long dk_copenpart; /* character units open on this drive */ u_long dk_bopenpart; /* block units open on this drive */ u_long dk_openpart; /* all units open on this drive */ short dk_wlabel; /* label writable? */ + short dk_flags; /* drive characteistics found */ +#define DKFL_DOSPART 0x00001 /* has DOS partition table */ +#define DKFL_QUIET 0x00002 /* report errors back, but don't complain */ +#define DKFL_SINGLE 0x00004 /* sector at a time mode */ +#define DKFL_ERROR 0x00008 /* processing a disk error */ +#define DKFL_BSDLABEL 0x00010 /* has a BSD disk label */ +#define DKFL_BADSECT 0x00020 /* has a bad144 badsector table */ +#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 */ }; -/* - * This label is used as a default when initializing a new or raw disk. - * It really only lets us access the first track until we know more. - */ -struct disklabel dflt_sizes = { - DISKMAGIC, DTYPE_ST506, 0, "default", "", - 512, /* sector size */ - 17, /* # of sectors per track */ - 8, /* # of tracks per cylinder */ - 766, /* # of cylinders per unit */ - 17*8, /* # of sectors per cylinder */ - 766*8*17, /* # of sectors per unit */ - 0, /* # of spare sectors per track */ - 0, /* # of spare sectors per cylinder */ - 0, /* # of alt. cylinders per unit */ - 3600, /* rotational speed */ - 1, /* hardware sector interleave */ - 0, /* sector 0 skew, per track */ - 0, /* sector 0 skew, per cylinder */ - 0, /* head switch time, usec */ - 0, /* track-to-track seek, usec */ - 0, /* generic flags */ - 0,0,0,0,0, - 0,0,0,0,0, - DISKMAGIC, - 0, - 8, - 8192, - 8192, - - {{21600, 0, 0,0,0,0}, /* A=root filesystem */ - {21600, 21600, 0,0,0,0}, - {660890, 0, 0,0,0,0}, /* C=whole disk */ - {216000, 80, 0,0,0,0}, - {0, 0, 0,0,0,0}, - {0, 0, 0,0,0,0}, - {0, 0, 0,0,0,0}, - {399600, 480, 0,0,0,0}} -}; +struct disk *wddrives[_NWD]; /* table of units */ +struct buf wdtab; +struct buf wdutab[_NWD]; /* head of queue per drive */ +struct buf rwdbuf[_NWD]; /* buffers for raw IO */ +long wdxfer[_NWD]; /* count of transfers */ +#ifdef WDDEBUG +int wddebug; +#endif -static struct dkbad dkbad[NWD]; -struct disk wddrives[NWD] = {0}; /* table of units */ -struct buf wdtab = {0}; -struct buf wdutab[NWD] = {0}; /* head of queue per drive */ -struct buf rwdbuf[NWD] = {0}; /* buffers for raw IO */ -long wdxfer[NWD] = {0}; /* count of transfers */ -int writeprotected[NWD] = { 0 }; -int wdprobe(), wdattach(), wdintr(); struct isa_driver wddriver = { wdprobe, wdattach, "wd", }; - -static wdc; + +void wdustart(struct disk *); +void wdstart(); +int wdcommand(struct disk *, int); +int wdcontrol(struct buf *); +int wdsetctlr(dev_t, struct disk *); +int wdgetctlr(int, struct disk *); + /* - * Probe routine + * Probe for controller. */ -wdprobe(dvp) - struct isa_device *dvp; +int +wdprobe(struct isa_device *dvp) { -wdc = dvp->id_iobase; + int unit = dvp->id_unit; + struct disk *du; + int wdc; -#ifdef lint - wdintr(0); -#endif - /* XXX sorry, needs to be better */ - outb(wdc+wd_error, 0x5a) ; /* error register not writable */ - outb(wdc+wd_cyl_lo, 0xa5) ; /* but all of cyllo are implemented */ - if(inb(wdc+wd_error) != 0x5a && inb(wdc+wd_cyl_lo) == 0xa5) - return(1) ; + if (unit >= _NWD) /* 31 Jul 92*/ + return(0); + + if ((du = wddrives[unit]) == 0) { + du = wddrives[unit] = (struct disk *) + malloc (sizeof(struct disk), M_TEMP, M_NOWAIT); + bzero (du, sizeof(struct disk)); /* 31 Jul 92*/ + du->dk_unit = unit; + } + + wdc = du->dk_port = dvp->id_iobase; + + /* check if we have registers that work */ + outb(wdc+wd_cyl_lo, 0xa5) ; /* wd_cyl_lo is read/write */ + if(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); + + /* 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); + return (1); + +nodevice: + free(du, M_TEMP); + wddrives[unit] = 0; return (0); } /* - * attach each drive if possible. + * Attach each drive if possible. */ -wdattach(dvp) - struct isa_device *dvp; +int +wdattach(struct isa_device *dvp) { - int unit = dvp->id_unit; + int unit; +/* int unit = dvp->id_unit;*/ + + for (unit=0; unit< _NWD; unit++) { + struct disk *du; + if ((du = wddrives[unit]) == 0) { + du = wddrives[unit] = (struct disk *) + malloc (sizeof(struct disk), M_TEMP, M_NOWAIT); + bzero (du, sizeof(struct disk)); + du->dk_unit = unit; + du->dk_port = dvp->id_iobase; + } - outb(wdc+wd_ctlr,12); - DELAY(1000); - outb(wdc+wd_ctlr,8); + /* print out description of drive, suppressing multiple blanks*/ + if(wdgetctlr(unit, du) == 0) { + int i, blank; + char c; + printf(" %d:<", unit); + for (i = blank = 0 ; i < sizeof(du->dk_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(">"); + du->dk_unit = unit; + } + else { + /* old ST506 controller */ + printf(" %d:", + unit); + } + } + return(1); } /* Read/write routine for a buffer. Finds the proper unit, range checks @@ -201,121 +252,90 @@ wdattach(dvp) * to complete. Multi-page transfers are supported. All I/O requests must * be a multiple of a sector in length. */ -wdstrategy(bp) - register struct buf *bp; /* IO operation to perform */ +int +wdstrategy(register struct buf *bp) { register struct buf *dp; - register struct disk *du; /* Disk unit to do the IO. */ + struct disklabel *lp; register struct partition *p; + struct disk *du; /* Disk unit to do the IO. */ long maxsz, sz; int unit = wdunit(bp->b_dev); int s; - if ((unit >= NWD) || (bp->b_blkno < 0)) { - printf("wdstrat: unit = %d, blkno = %d, bcount = %d\n", - unit, bp->b_blkno, bp->b_bcount); - pg("wd:error in wdstrategy"); + /* valid unit, controller, and request? */ + if (unit >= _NWD || bp->b_blkno < 0 || (du = wddrives[unit]) == 0) { + + bp->b_error = EINVAL; bp->b_flags |= B_ERROR; - goto bad; - } - if (writeprotected[unit] && (bp->b_flags & B_READ) == 0) { - printf("wd%d: write protected\n", unit); - goto bad; + goto done; } - du = &wddrives[unit]; - if (DISKSTATE(du->dk_state) != OPEN) - goto q; -#ifdef old - /* - * Convert DEV_BSIZE "blocks" to sectors. - * Note: doing the conversions this way limits the partition size - * to about 8 million sectors (1-8 Gb). - */ - blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.d_secsize; - if (((u_long) bp->b_blkno * DEV_BSIZE % du->dk_dd.d_secsize != 0) || - bp->b_bcount >= MAXTRANSFER * CLBYTES) { + + /* "soft" write protect check */ + if ((du->dk_flags & DKFL_WRITEPROT) && (bp->b_flags & B_READ) == 0) { + bp->b_error = EROFS; bp->b_flags |= B_ERROR; - goto bad; + goto done; } - nblocks = du->dk_dd.d_partitions[part].p_size; - cyloff = du->dk_dd.d_partitions[part].p_offset; - if (blknum + (bp->b_bcount / du->dk_dd.d_secsize) > nblocks) { - if (blknum == nblocks) - bp->b_resid = bp->b_bcount; - else - bp->b_flags |= B_ERROR; - goto bad; + + /* have partitions and want to use them? */ + if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW) { + + /* + * do bounds checking, adjust transfer. if error, process. + * if end of partition, just return + */ + if (bounds_check_with_label(bp, &du->dk_dd, du->dk_wlabel) <= 0) + goto done; + /* otherwise, process transfer request */ } - bp->b_cylin = blknum / du->dk_dd.d_secpercyl + cyloff; -#else - /* - * Determine the size of the transfer, and make sure it is - * within the boundaries of the partition. - */ - p = &du->dk_dd.d_partitions[wdpart(bp->b_dev)]; - maxsz = p->p_size; - sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; - if (bp->b_blkno + p->p_offset <= LABELSECTOR && -#if LABELSECTOR != 0 - bp->b_blkno + p->p_offset + sz > LABELSECTOR && -#endif - (bp->b_flags & B_READ) == 0 && du->dk_wlabel == 0) { - bp->b_error = EROFS; - goto bad; - } - if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) { - /* if exactly at end of disk, return an EOF */ - if (bp->b_blkno == maxsz) { - bp->b_resid = bp->b_bcount; - biodone(bp); - return; - } - /* or truncate if part of it fits */ - sz = maxsz - bp->b_blkno; - if (sz <= 0) - goto bad; - bp->b_bcount = sz << DEV_BSHIFT; - } - bp->b_cylin = (bp->b_blkno + p->p_offset) / du->dk_dd.d_secpercyl; -#endif + q: + /* queue transfer on drive, activate drive and controller if idle */ dp = &wdutab[unit]; - s = splhigh(); + s = splbio(); disksort(dp, bp); if (dp->b_active == 0) - wdustart(du); /* start drive if idle */ + wdustart(du); /* start drive */ if (wdtab.b_active == 0) - wdstart(s); /* start IO if controller idle */ + wdstart(s); /* start controller */ splx(s); return; -bad: - bp->b_error = EINVAL; +done: + /* toss transfer, we're done early */ biodone(bp); } -/* Routine to queue a read or write command to the controller. The request is - * linked into the active list for the controller. If the controller is idle, - * the transfer is started. +/* + * Routine to queue a command to the controller. The unit's + * request is linked into the active list for the controller. + * If the controller is idle, the transfer is started. */ -wdustart(du) - register struct disk *du; +static void +wdustart(register struct disk *du) { - register struct buf *bp, *dp; + register struct buf *bp, *dp = &wdutab[du->dk_unit]; - dp = &wdutab[du->dk_unit]; + /* unit already active? */ if (dp->b_active) return; + + /* anything to start? */ bp = dp->b_actf; if (bp == NULL) return; + + /* link onto controller queue */ dp->b_forw = NULL; - if (wdtab.b_actf == NULL) /* link unit into active list */ + if (wdtab.b_actf == NULL) wdtab.b_actf = dp; else wdtab.b_actl->b_forw = dp; wdtab.b_actl = dp; - dp->b_active = 1; /* mark the drive as busy */ + + /* mark the drive unit as busy */ + dp->b_active = 1; } /* @@ -326,68 +346,73 @@ wdustart(du) * 1. The transfer length must be an exact multiple of the sector size. */ -static wd_sebyse; - +static void wdstart() { register struct disk *du; /* disk unit for IO */ register struct buf *bp; + struct disklabel *lp; struct buf *dp; register struct bt_bad *bt_ptr; long blknum, pagcnt, cylin, head, sector; long secpertrk, secpercyl, addr, i; - int unit, s; + int unit, s, wdc; loop: + /* is there a drive for the controller to do a transfer with? */ dp = wdtab.b_actf; if (dp == NULL) return; + + /* is there a transfer to this drive ? if so, link it on + the controller's queue */ bp = dp->b_actf; if (bp == NULL) { wdtab.b_actf = dp->b_forw; goto loop; } + + /* obtain controller and drive information */ unit = wdunit(bp->b_dev); - du = &wddrives[unit]; - if (DISKSTATE(du->dk_state) <= RDLABEL) { - if (wdcontrol(bp)) { - dp->b_actf = bp->av_forw; - goto loop; /* done */ - } + du = wddrives[unit]; + + /* if not really a transfer, do control operations specially */ + if (du->dk_state < OPEN) { + (void) wdcontrol(bp); return; } - secpertrk = du->dk_dd.d_nsectors; - secpercyl = du->dk_dd.d_secpercyl; - /* - * Convert DEV_BSIZE "blocks" to sectors. - */ - blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.d_secsize - + du->dk_skip; + + /* calculate transfer details */ + blknum = bp->b_blkno + du->dk_skip; +/*if(wddebug)printf("bn%d ", blknum);*/ #ifdef WDDEBUG - if (du->dk_skip == 0) { - dprintf(DDSK,"\nwdstart %d: %s %d@%d; map ", unit, + if (du->dk_skip == 0) + printf("\nwdstart %d: %s %d@%d; map ", unit, (bp->b_flags & B_READ) ? "read" : "write", bp->b_bcount, blknum); - } else { - dprintf(DDSK," %d)%x", du->dk_skip, inb(wdc+wd_altsts)); - } + else + printf(" %d)%x", du->dk_skip, inb(wdc+wd_altsts)); #endif - addr = (int) bp->b_un.b_addr; - if(du->dk_skip==0) du->dk_bc = bp->b_bcount; + if (du->dk_skip == 0) + du->dk_bc = bp->b_bcount; + + lp = &du->dk_dd; + secpertrk = lp->d_nsectors; + secpercyl = lp->d_secpercyl; + if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW) + blknum += lp->d_partitions[wdpart(bp->b_dev)].p_offset; cylin = blknum / secpercyl; head = (blknum % secpercyl) / secpertrk; sector = blknum % secpertrk; - if (DISKSTATE(du->dk_state) == OPEN) - cylin += du->dk_dd.d_partitions[wdpart(bp->b_dev)].p_offset - / secpercyl; /* * See if the current block is in the bad block list. * (If we have one, and not formatting.) */ - if (DISKSTATE(du->dk_state) == OPEN && wd_sebyse) - for (bt_ptr = dkbad[unit].bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) { + if ((du->dk_flags & (DKFL_SINGLE|DKFL_BADSECT)) /* 19 Aug 92*/ + == (DKFL_SINGLE|DKFL_BADSECT)) + for (bt_ptr = du->dk_bad.bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) { if (bt_ptr->bt_cyl > cylin) /* Sorted list, and we passed our cylinder. quit. */ break; @@ -400,145 +425,170 @@ loop: * and works backwards to the front of the disk. */ #ifdef WDDEBUG - dprintf(DDSK,"--- badblock code -> Old = %d; ", + printf("--- badblock code -> Old = %d; ", blknum); #endif - blknum = du->dk_dd.d_secperunit - du->dk_dd.d_nsectors - - (bt_ptr - dkbad[unit].bt_bad) - 1; + blknum = lp->d_secperunit - lp->d_nsectors + - (bt_ptr - du->dk_bad.bt_bad) - 1; cylin = blknum / secpercyl; head = (blknum % secpercyl) / secpertrk; sector = blknum % secpertrk; #ifdef WDDEBUG - dprintf(DDSK, "new = %d\n", blknum); + printf("new = %d\n", blknum); #endif break; } } +/*if(wddebug)pg("c%d h%d s%d ", cylin, head, sector);*/ sector += 1; /* sectors begin with 1, not 0 */ wdtab.b_active = 1; /* mark controller active */ + wdc = du->dk_port; + + /* if starting a multisector transfer, or doing single transfers */ + if (du->dk_skip == 0 || (du->dk_flags & DKFL_SINGLE)) { + if (wdtab.b_errcnt && (bp->b_flags & B_READ) == 0) + du->dk_bc += DEV_BSIZE; + + /* controller idle? */ + while (inb(wdc+wd_status) & WDCS_BUSY) + ; + + /* stuff the task file */ + outb(wdc+wd_precomp, lp->d_precompcyl / 4); +#ifdef B_FORMAT + if (bp->b_flags & B_FORMAT) { + outb(wdc+wd_sector, lp->d_gap3); + outb(wdc+wd_seccnt, lp->d_nsectors); + } else { +#endif + if (du->dk_flags & DKFL_SINGLE) + outb(wdc+wd_seccnt, 1); + else + outb(wdc+wd_seccnt, howmany(du->dk_bc, DEV_BSIZE)); + outb(wdc+wd_sector, sector); - 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); +#ifdef B_FORMAT + } +#endif + + outb(wdc+wd_cyl_lo, cylin); + outb(wdc+wd_cyl_hi, cylin >> 8); - 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)); - /* 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) ; + /* wait for drive to become ready */ + while ((inb(wdc+wd_status) & WDCS_READY) == 0) + ; - /*if (bp->b_flags & B_FORMAT) - wr(wdc+wd_command, WDCC_FORMAT); - else*/ + /* initiate command! */ +#ifdef B_FORMAT + if (bp->b_flags & B_FORMAT) + outb(wdc+wd_command, WDCC_FORMAT); + else +#endif outb(wdc+wd_command, (bp->b_flags & B_READ)? WDCC_READ : WDCC_WRITE); - /*printf("sector %d cylin %d head %d addr %x sts %x\n", - sector, cylin, head, addr, inb(wdc+wd_altsts));*/ -} - - /* If this is a read operation, just go away until it's done. */ +#ifdef WDDEBUG + printf("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); + /* 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; + /* then send it! */ + outsw (wdc+wd_data, addr+du->dk_skip * DEV_BSIZE, + DEV_BSIZE/sizeof(short)); + du->dk_bc -= DEV_BSIZE; } -/* - * 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) +void +wdintr(struct intrframe wdif) { register struct disk *du; register struct buf *bp, *dp; - int status; + int status, wdc; 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) { +#ifdef nyet printf("wd: extra interrupt\n"); +#endif 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) { + du = wddrives[wdunit(bp->b_dev)]; + wdc = du->dk_port; + +#ifdef WDDEBUG + printf("I "); +#endif + + while ((status = inb(wdc+wd_status)) & WDCS_BUSY) ; + + /* is it not a transfer, but a control operation? */ + if (du->dk_state < OPEN) { if (wdcontrol(bp)) - goto done; + wdstart(); return; } + + /* have we an error? */ if (status & (WDCS_ERR | WDCS_ECCCOR)) { - wd_errstat = inb(wdc+wd_error); /* save error status */ + + du->dk_status = status; + du->dk_error = inb(wdc + wd_error); #ifdef WDDEBUG - printf("status %x error %x\n", status, wd_errstat); + printf("status %x error %x\n", status, du->dk_error); #endif - if(wd_sebyse == 0) { - wd_haderror = 1; + if((du->dk_flags & DKFL_SINGLE) == 0) { + du->dk_flags |= DKFL_ERROR; goto outt; } - /*if (bp->b_flags & B_FORMAT) { - du->dk_status = status; - du->dk_error = wdp->wd_error; +#ifdef B_FORMAT + if (bp->b_flags & B_FORMAT) { + bp->b_error = EIO; /* 17 Sep 92*/ bp->b_flags |= B_ERROR; goto done; - }*/ + } +#endif - 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 ; + /* error or error correction? */ 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); + if((du->dk_flags&DKFL_QUIET) == 0) { + diskerr(bp, "wd", "hard error", + LOG_PRINTF, du->dk_skip, + &du->dk_dd); +#ifdef WDDEBUG + printf( "status %b error %b\n", + status, WDCS_BITS, + inb(wdc+wd_error), WDERR_BITS); +#endif + } + bp->b_error = EIO; /* 17 Sep 92*/ 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); + } else if((du->dk_flags&DKFL_QUIET) == 0) { + diskerr(bp, "wd", "soft ecc", 0, + du->dk_skip, &du->dk_dd); + } } outt: @@ -548,48 +598,47 @@ outt: 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) ; + chk = min(DEV_BSIZE / sizeof(short), du->dk_bc / sizeof(short)); + + /* 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); + /* suck in data */ + insw (wdc+wd_data, + (int)bp->b_un.b_addr + du->dk_skip * DEV_BSIZE, chk); + du->dk_bc -= chk * sizeof(short); + + /* for obselete fractional sector reads */ + 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); - } + if (wdtab.b_errcnt && (du->dk_flags & DKFL_QUIET) == 0) + diskerr(bp, "wd", "soft error", 0, + du->dk_skip, &du->dk_dd); 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) { + if (du->dk_bc > 0 && (du->dk_flags & DKFL_ERROR) == 0) { wdstart(); return; /* next chunk is started */ - } else if (wd_haderror && wd_sebyse == 0) { + } else if ((du->dk_flags & (DKFL_SINGLE|DKFL_ERROR)) + == DKFL_ERROR) { du->dk_skip = 0; - wd_haderror = 0; - wd_sebyse = 1; + du->dk_flags &= ~DKFL_ERROR; + du->dk_flags |= DKFL_SINGLE; wdstart(); return; /* redo xfer sector by sector */ } } done: - wd_sebyse = 0; /* done with this transfer, with or without error */ + du->dk_flags &= ~DKFL_SINGLE; wdtab.b_actf = dp->b_forw; wdtab.b_errcnt = 0; du->dk_skip = 0; @@ -599,113 +648,91 @@ done: bp->b_resid = 0; biodone(bp); } + + /* controller idle */ wdtab.b_active = 0; + + /* anything more on drive queue? */ if (dp->b_actf) - wdustart(du); /* requeue disk if more io to do */ + wdustart(du); + /* anything more for controller to do? */ if (wdtab.b_actf) - wdstart(); /* start IO on next drive */ + wdstart(); } /* * Initialize a drive. */ -wdopen(dev, flags, fmt) - dev_t dev; - int flags, fmt; +int +wdopen(dev_t dev, int flags, int fmt, struct proc *p) { 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; + char *msg; 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; + if (unit >= _NWD) return (ENXIO) ; - /* - * 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; + du = wddrives[unit]; + if (du == 0) return (ENXIO) ; + + if ((du->dk_flags & DKFL_BSDLABEL) == 0) { + du->dk_flags |= DKFL_WRITEPROT; + wdutab[unit].b_actf = NULL; + + /* + * Use the default sizes until we've read the label, + * or longer if there isn't one there. + */ + bzero(&du->dk_dd, sizeof(du->dk_dd)); +#undef d_type /* fix goddamn segments.h! XXX */ + du->dk_dd.d_type = DTYPE_ST506; + du->dk_dd.d_ncylinders = 1024; + du->dk_dd.d_secsize = DEV_BSIZE; + du->dk_dd.d_ntracks = 8; + du->dk_dd.d_nsectors = 17; + du->dk_dd.d_secpercyl = 17*8; + du->dk_state = WANTOPEN; + du->dk_unit = unit; + if (part == WDRAW) + du->dk_flags |= DKFL_QUIET; 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;*/ - du->dk_state = OPEN; - } + du->dk_flags &= ~DKFL_QUIET; + + /* read label using "c" partition */ + if (msg = readdisklabel(makewddev(major(dev), wdunit(dev), WDRAW), + wdstrategy, &du->dk_dd, du->dk_dospartitions, + &du->dk_bad, 0)) { + if((du->dk_flags&DKFL_QUIET) == 0) { + log(LOG_WARNING, "wd%d: cannot find label (%s)\n", + unit, msg); + error = EINVAL; /* XXX needs translation */ + } + goto done; + } else { + + wdsetctlr(dev, du); + du->dk_flags |= DKFL_BSDLABEL; + du->dk_flags &= ~DKFL_WRITEPROT; + if (du->dk_dd.d_flags & D_BADSECT) + du->dk_flags |= DKFL_BADSECT; + } + done: - bp->b_flags = B_INVAL | B_AGE; - brelse(bp); - if (error == 0) - du->dk_open = 1; + if (error) + return(error); + } /* * Warn if a partion is opened * that overlaps another partition which is open * unless one is the "raw" partition (whole disk). */ -#define RAWPART 2 /* 'c' partition */ /* XXX */ - if ((du->dk_openpart & mask) == 0 && part != RAWPART) { + if ((du->dk_openpart & mask) == 0 /*&& part != RAWPART*/ && part != WDRAW) { int start, end; pp = &du->dk_dd.d_partitions[part]; @@ -717,7 +744,9 @@ done: if (pp->p_offset + pp->p_size <= start || pp->p_offset >= end) continue; - if (pp - du->dk_dd.d_partitions == RAWPART) + /*if (pp - du->dk_dd.d_partitions == RAWPART) + continue; */ + if (pp - du->dk_dd.d_partitions == WDRAW) continue; if (du->dk_openpart & (1 << (pp - du->dk_dd.d_partitions))) @@ -727,8 +756,10 @@ done: pp - du->dk_dd.d_partitions + 'a'); } } - if (part >= du->dk_dd.d_npartitions) + if (part >= du->dk_dd.d_npartitions && part != WDRAW) return (ENXIO); + + /* insure only one open at a time */ du->dk_openpart |= mask; switch (fmt) { case S_IFCHR: @@ -738,7 +769,7 @@ done: du->dk_bopenpart |= mask; break; } - return (error); + return (0); } /* @@ -747,27 +778,38 @@ done: * 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; +static int +wdcontrol(register struct buf *bp) { register struct disk *du; register unit; unsigned char stat; int s, cnt; - extern int bootdev, cyloffset; + extern int bootdev; + int cyl, trk, sec, i, wdc; + struct wdparams foo; - du = &wddrives[wdunit(bp->b_dev)]; + du = wddrives[wdunit(bp->b_dev)]; unit = du->dk_unit; - switch (DISKSTATE(du->dk_state)) { + wdc = du->dk_port; + + switch (du->dk_state) { tryagainrecal: case WANTOPEN: /* set SDH, step rate, do restore */ #ifdef WDDEBUG - dprintf(DDSK,"wd%d: recal ", unit); + printf("wd%d: recal ", unit); #endif s = splbio(); /* not called from intr level ... */ + wdgetctlr(unit, du); + outb(wdc+wd_sdh, WDSD_IBM | (unit << 4)); wdtab.b_active = 1; + + /* wait for drive and controller to become ready */ + for (i = 1000000; (inb(wdc+wd_status) & (WDCS_READY|WDCS_BUSY)) + != WDCS_READY && i-- != 0; ) + ; outb(wdc+wd_command, WDCC_RESTORE | WD_STEP); du->dk_state++; splx(s); @@ -775,83 +817,25 @@ wdcontrol(bp) case RECAL: if ((stat = inb(wdc+wd_status)) & WDCS_ERR) { - printf("wd%d: recal", du->dk_unit); - if (unit == 0) { + if ((du->dk_flags & DKFL_QUIET) == 0) { + printf("wd%d: recal", du->dk_unit); printf(": status %b error %b\n", - stat, WDCS_BITS, - inb(wdc+wd_error), WDERR_BITS); - if (++wdtab.b_errcnt < RETRIES) - goto tryagainrecal; + stat, WDCS_BITS, inb(wdc+wd_error), + WDERR_BITS); + } + if (++wdtab.b_errcnt < RETRIES) { + du->dk_state = WANTOPEN; + goto tryagainrecal; } + bp->b_error = ENXIO; /* XXX needs translation */ goto badopen; } - /* some compaq controllers require this ... */ + /* some 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 "); -#endif -/*if( cyloffset < 0 || cyloffset > 8192) */cyloffset=0; - /* - * Read in sector LABELSECTOR to get the pack label - * and geometry. - */ - outb(wdc+wd_precomp, 0xff);/* sometimes this is head bit 3 */ - outb(wdc+wd_seccnt, 1); - outb(wdc+wd_sector, LABELSECTOR+1); -/*printf("sec %d ", LABELSECTOR);*/ - /*if (bp->b_dev == bootdev) { - (wdc+wd_cyl_lo = cyloffset & 0xff; - (wdc+wd_cyl_hi = cyloffset >> 8; - } else { - (wdc+wd_cyl_lo = 0; - (wdc+wd_cyl_hi = 0; - }*/ - outb(wdc+wd_cyl_lo, (cyloffset & 0xff)); - outb(wdc+wd_cyl_hi, (cyloffset >> 8)); - outb(wdc+wd_sdh, WDSD_IBM | (unit << 4)); - outb(wdc+wd_command, WDCC_READ); - du->dk_state = RDLABEL; - return(0); - - case RDLABEL: - if ((stat = inb(wdc+wd_status)) & WDCS_ERR) { - if (++wdtab.b_errcnt < RETRIES) - goto retry; - printf("wd%d: read label", unit); - goto badopen; - } - - insw(wdc+wd_data, bp->b_un.b_addr, 256); - - if (((struct disklabel *) - (bp->b_un.b_addr + LABELOFFSET))->d_magic == DISKMAGIC) { - du->dk_dd = - * (struct disklabel *) (bp->b_un.b_addr + LABELOFFSET); - } else { - printf("wd%d: bad disk label (%x)\n", du->dk_unit, - ((struct disklabel *)(bp->b_un.b_addr + LABELOFFSET))->d_magic -); - du->dk_state = OPENRAW; - } - - s = splbio(); /* not called from intr level ... */ - while ((stat = inb(wdc+wd_status)) & WDCS_BUSY); - - wdsetctlr(bp->b_dev, du); - - outb(wdc+wd_seccnt, 0); - splx(s); - - if (du->dk_state == RDLABEL) - du->dk_state = RDBADTBL; + du->dk_state = OPEN; /* * The rest of the initialization can be done * by normal means. @@ -864,54 +848,175 @@ retry: /* NOTREACHED */ badopen: - printf(": status %b error %b\n", - stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS); - du->dk_state = OPENRAW; + if ((du->dk_flags & DKFL_QUIET) == 0) + printf(": status %b error %b\n", + stat, WDCS_BITS, inb(wdc + wd_error), WDERR_BITS); + bp->b_flags |= B_ERROR; return(1); } -wdsetctlr(dev, du) dev_t dev; struct disk *du; { - int stat; +/* + * send a command and wait uninterruptibly until controller is finished. + * return -1 if controller busy for too long, otherwise + * return status. intended for brief controller commands at critical points. + * assumes interrupts are blocked. + */ +static int +wdcommand(struct disk *du, int cmd) { + int timeout = 1000000, stat, wdc; + + /* controller ready for command? */ + wdc = du->dk_port; + while (((stat = inb(wdc + wd_status)) & WDCS_BUSY) && timeout > 0) + timeout--; + if (timeout <= 0) + return(-1); + + /* 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); + 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); + + return (stat); +} + +/* + * issue IDC to drive to tell it just what geometry it is to be. + */ +static int +wdsetctlr(dev_t dev, struct disk *du) { + int stat, x, wdc; + +/*printf("C%dH%dS%d ", du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks, + du->dk_dd.d_nsectors);*/ + x = splbio(); + wdc = du->dk_port; outb(wdc+wd_cyl_lo, du->dk_dd.d_ncylinders+1); outb(wdc+wd_cyl_hi, (du->dk_dd.d_ncylinders+1)>>8); outb(wdc+wd_sdh, WDSD_IBM | (wdunit(dev) << 4) + du->dk_dd.d_ntracks-1); outb(wdc+wd_seccnt, du->dk_dd.d_nsectors); - outb(wdc+wd_command, 0x91); - - while ((stat = inb(wdc+wd_status)) & WDCS_BUSY) ; - stat = inb(wdc+wd_error); + stat = wdcommand(du, WDCC_IDC); + + if (stat < 0) + return(stat); + if (stat & WDCS_ERR) + printf("wdsetctlr: status %b error %b\n", + stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS); + splx(x); return(stat); } +/* + * issue READP to drive to ask it what it is. + */ +static int +wdgetctlr(int u, struct disk *du) { + int stat, x, i, wdc; + char tb[DEV_BSIZE]; + struct wdparams *wp; + + x = splbio(); /* not called from intr level ... */ + wdc = du->dk_port; + outb(wdc+wd_sdh, WDSD_IBM | (u << 4)); + stat = wdcommand(du, WDCC_READP); + + if (stat < 0) + return(stat); + 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); + } +/*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);*/ + + /* 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 */ + (void) inb(wdc+wd_status); + return (0); +} + + /* ARGSUSED */ -wdclose(dev, flags, fmt) - dev_t dev; - int flags, fmt; +int +wdclose(dev_t dev, int flags, int fmt) { register struct disk *du; + int part = wdpart(dev), mask = 1 << part; + + du = wddrives[wdunit(dev)]; - du = &wddrives[wdunit(dev)]; - du->dk_open-- ; - /*if (du->dk_open == 0) du->dk_state = CLOSED ; does not work */ + /* insure only one open at a time */ + du->dk_openpart &= ~mask; + switch (fmt) { + case S_IFCHR: + du->dk_copenpart &= ~mask; + break; + case S_IFBLK: + du->dk_bopenpart &= ~mask; + break; + } return(0); } -wdioctl(dev,cmd,addr,flag) - dev_t dev; - caddr_t addr; +int +wdioctl(dev_t dev, int cmd, caddr_t addr, int flag) { int unit = wdunit(dev); register struct disk *du; int error = 0; struct uio auio; struct iovec aiov; - /*int wdformat();*/ - du = &wddrives[unit]; + du = wddrives[unit]; switch (cmd) { + case DIOCSBAD: + if ((flag & FWRITE) == 0) + error = EBADF; + else + du->dk_bad = *(struct dkbad *)addr; + break; + case DIOCGDINFO: *(struct disklabel *)addr = du->dk_dd; break; @@ -928,14 +1033,16 @@ wdioctl(dev,cmd,addr,flag) else error = setdisklabel(&du->dk_dd, (struct disklabel *)addr, - 0 /*(dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart*/); - /*if (error == 0 && dk->dk_state == OPENRAW && - vdreset_drive(vddinfo[unit])) - dk->dk_state = OPEN;*/ - wdsetctlr(dev, du); + /*(du->dk_flags & DKFL_BSDLABEL) ? du->dk_openpart : */0, + du->dk_dospartitions); + if (error == 0) { + du->dk_flags |= DKFL_BSDLABEL; + wdsetctlr(dev, du); + } break; case DIOCWLABEL: + du->dk_flags &= ~DKFL_WRITEPROT; if ((flag & FWRITE) == 0) error = EBADF; else @@ -943,23 +1050,24 @@ wdioctl(dev,cmd,addr,flag) break; case DIOCWDINFO: + du->dk_flags &= ~DKFL_WRITEPROT; if ((flag & FWRITE) == 0) error = EBADF; else if ((error = setdisklabel(&du->dk_dd, (struct disklabel *)addr, - 0/*(dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart*/)) == 0) { + /*(du->dk_flags & DKFL_BSDLABEL) ? du->dk_openpart :*/ 0, + du->dk_dospartitions)) == 0) { int wlab; - /*if (error == 0 && dk->dk_state == OPENRAW && - vdreset_drive(vddinfo[unit])) - dk->dk_state = OPEN; */ + du->dk_flags |= DKFL_BSDLABEL; wdsetctlr(dev, du); /* simulate opening partition 0 so write succeeds */ - /* dk->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,wdpart(dev)); - /*dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;*/ + error = writedisklabel(dev, wdstrategy, + &du->dk_dd, du->dk_dospartitions); + du->dk_openpart = du->dk_copenpart | du->dk_bopenpart; du->dk_wlabel = wlab; } break; @@ -1000,66 +1108,70 @@ wdioctl(dev,cmd,addr,flag) return (error); } -/*wdformat(bp) - struct buf *bp; +#ifdef B_FORMAT +int +wdformat(struct buf *bp) { bp->b_flags |= B_FORMAT; return (wdstrategy(bp)); -}*/ +} +#endif -wdsize(dev) - dev_t dev; +int +wdsize(dev_t dev) { - register unit = wdunit(dev); - register part = wdpart(dev); - register struct disk *du; - register val ; + int unit = wdunit(dev), part = wdpart(dev), val; + struct disk *du; - if (unit >= NWD) return(-1); - if (wddrives[unit].dk_state == 0) { - val = wdopen (dev, 0); - if (val < 0) - return (-1); - } - du = &wddrives[unit]; - return((int)((u_long)du->dk_dd.d_partitions[part].p_size * - du->dk_dd.d_secsize / 512)); + if (unit >= _NWD) /* 31 Jul 92*/ + return(-1); + + du = wddrives[unit]; + if (du == 0 || du->dk_state == 0) + val = wdopen (makewddev(major(dev), unit, WDRAW), FREAD, S_IFBLK, 0); + if (du == 0 || val != 0 || du->dk_flags & DKFL_WRITEPROT) + return (-1); + + return((int)du->dk_dd.d_partitions[part].p_size); } extern char *vmmap; /* poor name! */ -wddump(dev) /* dump core after a system crash */ - dev_t dev; +int +wddump(dev_t dev) /* dump core after a system crash */ { register struct disk *du; /* disk unit to do the IO */ register struct bt_bad *bt_ptr; long num; /* number of sectors to write */ - int unit, part; - long cyloff, blknum, blkcnt; + int unit, part, wdc; + long blkoff, blknum, blkcnt; long cylin, head, sector, stat; long secpertrk, secpercyl, nblocks, i; char *addr; extern int Maxmem; static wddoingadump = 0 ; - extern CMAP1; - extern char CADDR1[]; + extern caddr_t CADDR1; - -#ifdef ARGO -outb(0x461,0); /* disable failsafe timer */ -#endif addr = (char *) 0; /* starting address */ + + /* toss any characters present prior to dump */ + while (sgetc(1)) + ; + /* size of memory to dump */ num = Maxmem; unit = wdunit(dev); /* eventually support floppies? */ part = wdpart(dev); /* file system */ /* check for acceptable drive number */ - if (unit >= NWD) return(ENXIO); + if (unit >= _NWD) return(ENXIO); /* 31 Jul 92*/ - du = &wddrives[unit]; + du = wddrives[unit]; + if (du == 0) return(ENXIO); /* was it ever initialized ? */ if (du->dk_state < OPEN) return (ENXIO) ; + if (du->dk_flags & DKFL_WRITEPROT) return(ENXIO); + wdc = du->dk_port; /* Convert to disk sectors */ num = (u_long) num * NBPG / du->dk_dd.d_secsize; @@ -1071,7 +1183,7 @@ outb(0x461,0); /* disable failsafe timer */ secpertrk = du->dk_dd.d_nsectors; secpercyl = du->dk_dd.d_secpercyl; nblocks = du->dk_dd.d_partitions[part].p_size; - cyloff = du->dk_dd.d_partitions[part].p_offset / secpercyl; + blkoff = du->dk_dd.d_partitions[part].p_offset; /*pg("xunit %x, nblocks %d, dumplo %d num %d\n", part,nblocks,dumplo,num);*/ /* check transfer bounds against partition size */ @@ -1089,7 +1201,7 @@ outb(0x461,0); /* disable failsafe timer */ /* some compaq controllers require this ... */ wdsetctlr(dev, du); - blknum = dumplo; + blknum = dumplo + blkoff; while (num > 0) { #ifdef notdef if (blkcnt > MAXTRANSFER) blkcnt = MAXTRANSFER; @@ -1097,20 +1209,19 @@ outb(0x461,0); /* disable failsafe timer */ blkcnt = secpercyl - (blknum % secpercyl); /* keep transfer within current cylinder */ #endif - pmap_enter(pmap_kernel(), vmmap, addr, VM_PROT_READ, TRUE); + pmap_enter(kernel_pmap, CADDR1, trunc_page(addr), VM_PROT_READ, TRUE); /* compute disk address */ cylin = blknum / secpercyl; head = (blknum % secpercyl) / secpertrk; sector = blknum % secpertrk; - cylin += cyloff; #ifdef notyet /* * See if the current block is in the bad block list. * (If we have one.) */ - for (bt_ptr = dkbad[unit].bt_bad; + for (bt_ptr = du->dk_bad.bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) { if (bt_ptr->bt_cyl > cylin) /* Sorted list, and we passed our cylinder. @@ -1126,7 +1237,7 @@ outb(0x461,0); /* disable failsafe timer */ */ blknum = (du->dk_dd.d_secperunit) - du->dk_dd.d_nsectors - - (bt_ptr - dkbad[unit].bt_bad) - 1; + - (bt_ptr - du->dk_bad.bt_bad) - 1; cylin = blknum / secpercyl; head = (blknum % secpercyl) / secpertrk; sector = blknum % secpertrk; @@ -1150,12 +1261,6 @@ outb(0x461,0); /* disable failsafe timer */ pg ("sdh 0%o sector %d cyl %d addr 0x%x", inb(wdc+wd_sdh), inb(wdc+wd_sector), inb(wdc+wd_cyl_hi)*256+inb(wdc+wd_cyl_lo), addr) ; -#endif -#ifdef ODYSSEUS -if(cylin < 46 || cylin > 91)pg("oops"); -#endif -#ifdef PRIAM -if(cylin < 40 || cylin > 79)pg("oops"); #endif outb(wdc+wd_command, WDCC_WRITE); @@ -1164,7 +1269,6 @@ if(cylin < 40 || cylin > 79)pg("oops"); if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ; outsw (wdc+wd_data, CADDR1+((int)addr&(NBPG-1)), 256); - (int) addr += 512; if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ; /* Check data request (should be done). */ @@ -1176,10 +1280,16 @@ if(cylin < 40 || cylin > 79)pg("oops"); } /* error check the xfer */ if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ; + + if ((unsigned)addr % (1024*1024) == 0) printf("%d ", num/2048) ; /* update block count */ num--; blknum++ ; -if (num % 100 == 0) printf(".") ; + (int) addr += 512; + + /* operator aborting dump? */ + if (sgetc(1)) + return(EINTR); } return(0); }