diff options
author | 1999-12-11 21:25:07 +0000 | |
---|---|---|
committer | 1999-12-11 21:25:07 +0000 | |
commit | 212751fd09da558cc0e542be8be01a117381df2a (patch) | |
tree | 1c3ee0f84f61c6b73acb24927be6dbc92c8cb9b5 | |
parent | Remove old atapi driver (diff) | |
download | wireguard-openbsd-212751fd09da558cc0e542be8be01a117381df2a.tar.xz wireguard-openbsd-212751fd09da558cc0e542be8be01a117381df2a.zip |
Remove old IDE driver
-rw-r--r-- | sys/dev/isa/wd.c | 1010 | ||||
-rw-r--r-- | sys/dev/isa/wdc.c | 1972 | ||||
-rw-r--r-- | sys/dev/isa/wdlink.h | 160 | ||||
-rw-r--r-- | sys/dev/isa/wdreg.h | 211 |
4 files changed, 0 insertions, 3353 deletions
diff --git a/sys/dev/isa/wd.c b/sys/dev/isa/wd.c deleted file mode 100644 index 149a668a832..00000000000 --- a/sys/dev/isa/wd.c +++ /dev/null @@ -1,1010 +0,0 @@ -/* $OpenBSD: wd.c,v 1.41 1999/08/10 23:09:49 deraadt Exp $ */ -/* $NetBSD: wd.c,v 1.150 1996/05/12 23:54:03 mycroft Exp $ */ - -/* - * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. - * - * DMA and multi-sector PIO handling are derived from code contributed by - * Onno van der Linden. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Charles M. Hannum. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "isadma.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/conf.h> -#include <sys/file.h> -#include <sys/stat.h> -#include <sys/ioctl.h> -#include <sys/buf.h> -#include <sys/uio.h> -#include <sys/malloc.h> -#include <sys/device.h> -#include <sys/disklabel.h> -#include <sys/disk.h> -#include <sys/syslog.h> -#include <sys/proc.h> - -#include <vm/vm.h> - -#include <machine/bus.h> -#include <machine/cpu.h> -#include <machine/intr.h> - -#include <dev/isa/isavar.h> -#include <dev/isa/wdreg.h> -#include <dev/isa/wdlink.h> - -#define WDUNIT(dev) DISKUNIT(dev) -#define WDPART(dev) DISKPART(dev) -#define MAKEWDDEV(maj, unit, part) MAKEDISKDEV(maj, unit, part) - -#define WDLABELDEV(dev) (MAKEWDDEV(major(dev), WDUNIT(dev), RAW_PART)) - -#ifdef WDDEBUG -#define WDDEBUG_PRINT(args) printf args -#else -#define WDDEBUG_PRINT(args) -#endif - -struct wd_softc { - struct device sc_dev; - struct disk sc_dk; - struct wd_link *d_link; - struct buf sc_q; -}; - -int wdprobe __P((struct device *, void *, void *)); -void wdattach __P((struct device *, struct device *, void *)); -int wdprint __P((void *, const char *)); - -struct cfattach wd_ca = { - sizeof(struct wd_softc), wdprobe, wdattach -}; - -struct cfdriver wd_cd = { - NULL, "wd", DV_DISK -}; - -void wdgetdisklabel __P((dev_t, struct wd_softc *, struct disklabel *, - struct cpu_disklabel *, int)); -int wd_get_parms __P((struct wd_softc *)); -void wdstrategy __P((struct buf *)); - -struct dkdriver wddkdriver = { wdstrategy }; - -/* XXX: these should go elsewhere */ -cdev_decl(wd); -bdev_decl(wd); - -void wdfinish __P((struct wd_softc *, struct buf *)); -int wdsetctlr __P((struct wd_link *)); -#ifdef DKBAD -static void bad144intern __P((struct wd_softc *)); -#endif -int wdlock __P((struct wd_link *)); -void wdunlock __P((struct wd_link *)); - -int -wdprobe(parent, match, aux) - struct device *parent; - void *match, *aux; -{ - struct cfdata *cf = match; - struct wd_link *d_link = aux; - int drive; - - if (d_link == NULL) - return 0; - if (d_link->type != DRIVE) - return 0; - - drive = d_link->sc_drive; - if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != drive) - return 0; - - return 1; -} - -void -wdattach(parent, self, aux) - struct device *parent, *self; - void *aux; -{ - struct wd_softc *wd = (void *)self; - struct wd_link *d_link= aux; - int i, blank; - char buf[41], c, *p, *q; - - wd->d_link = d_link; - d_link->openings = 1; - d_link->wd_softc = (caddr_t)wd; - - /* - * Initialize and attach the disk structure. - */ - wd->sc_dk.dk_driver = &wddkdriver; - wd->sc_dk.dk_name = wd->sc_dev.dv_xname; - disk_attach(&wd->sc_dk); - - dk_establish(&wd->sc_dk, &wd->sc_dev); - - d_link->sc_lp = wd->sc_dk.dk_label; - - wdc_get_parms(d_link); - for (blank = 0, p = d_link->sc_params.wdp_model, q = buf, i = 0; - i < sizeof(d_link->sc_params.wdp_model); i++) { - c = *p++; - if (c == '\0') - break; - if (c != ' ') { - if (blank) { - *q++ = ' '; - blank = 0; - } - *q++ = c; - } else - blank = 1; - } - *q++ = '\0'; - - printf(": <%s>\n", buf); - if (d_link->sc_lp->d_type != DTYPE_ST506) { - if ((d_link->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) { - printf("%s: %dMB, %d cyl, %d head, %d sec, %d bytes/sec, %d sec total\n", - self->dv_xname, - d_link->sc_params.wdp_lbacapacity / 2048, - d_link->sc_params.wdp_cylinders, - d_link->sc_params.wdp_heads, - d_link->sc_params.wdp_sectors, - DEV_BSIZE, /* XXX */ - d_link->sc_params.wdp_lbacapacity); - } else { - printf("%s: %dMB, %d cyl, %d head, %d sec, %d bytes/sec, %d sec total\n", - self->dv_xname, - d_link->sc_params.wdp_cylinders * - (d_link->sc_params.wdp_heads * - d_link->sc_params.wdp_sectors) / (1048576 / DEV_BSIZE), - d_link->sc_params.wdp_cylinders, - d_link->sc_params.wdp_heads, - d_link->sc_params.wdp_sectors, - DEV_BSIZE, /* XXX */ - d_link->sc_params.wdp_cylinders * - (d_link->sc_params.wdp_heads * - d_link->sc_params.wdp_sectors)); - } - } - -#if NISADMA > 0 - if ((d_link->sc_params.wdp_capabilities & WD_CAP_DMA) != 0 && - d_link->sc_mode == WDM_DMA) { - d_link->sc_mode = WDM_DMA; - } else -#endif - if (d_link->sc_params.wdp_maxmulti > 1) { - d_link->sc_mode = WDM_PIOMULTI; - d_link->sc_multiple = min(d_link->sc_params.wdp_maxmulti, 16); - } else { - d_link->sc_mode = WDM_PIOSINGLE; - d_link->sc_multiple = 1; - } - - printf("%s: using", wd->sc_dev.dv_xname); -#if NISADMA > 0 - if (d_link->sc_mode == WDM_DMA) - printf(" dma transfers,"); - else -#endif - printf(" %d-sector %d-bit pio transfers,", - d_link->sc_multiple, - (d_link->sc_flags & WDF_32BIT) == 0 ? 16 : 32); - if ((d_link->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) - printf(" lba addressing"); - else - printf(" chs addressing"); - if (d_link->sc_params.wdp_bufsize > 0) - printf(" (%dKB cache)", d_link->sc_params.wdp_bufsize / 2); - printf("\n"); -} - -/* - * Read/write routine for a buffer. Validates the arguments and schedules the - * transfer. Does not wait for the transfer to complete. - */ -void -wdstrategy(bp) - struct buf *bp; -{ - struct wd_softc *wd = wd_cd.cd_devs[WDUNIT(bp->b_dev)]; - struct wd_link *d_link= wd->d_link; - int s; - - /* Valid request? */ - if (bp->b_blkno < 0 || - (bp->b_bcount % wd->sc_dk.dk_label->d_secsize) != 0 || - (bp->b_bcount / wd->sc_dk.dk_label->d_secsize) >= (1 << NBBY)) { - bp->b_error = EINVAL; - goto bad; - } - - /* If device invalidated (e.g. media change, door open), error. */ - if ((d_link->sc_flags & WDF_LOADED) == 0) { - bp->b_error = EIO; - goto bad; - } - - /* If it's a null transfer, return immediately. */ - if (bp->b_bcount == 0) - goto done; - - /* - * Do bounds checking, adjust transfer. if error, process. - * If end of partition, just return. - */ - if (WDPART(bp->b_dev) != RAW_PART && - bounds_check_with_label(bp, wd->sc_dk.dk_label, - wd->sc_dk.dk_cpulabel, - (d_link->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0) - goto done; - - /* Queue transfer on drive, activate drive and controller if idle. */ - s = splbio(); - disksort(&wd->sc_q, bp); - wdstart(wd); - splx(s); - return; - -bad: - bp->b_flags |= B_ERROR; -done: - /* Toss transfer; we're done early. */ - bp->b_resid = bp->b_bcount; - biodone(bp); -} - -/* - * Queue a drive for I/O. - */ -void -wdstart(vp) - void *vp; -{ - struct wd_softc *wd = vp; - struct buf *dp, *bp=0; - struct wd_link *d_link = wd->d_link; - struct wdc_link *ctlr_link = d_link->ctlr_link; - struct wdc_xfer *xfer; - u_int32_t p_offset; - - while (d_link->openings > 0) { - - /* Is there a buf for us ? */ - dp = &wd->sc_q; - if ((bp = dp->b_actf) == NULL) /* yes, an assign */ - return; - dp->b_actf = bp->b_actf; - - /* - * Make the command. First lock the device - */ - d_link->openings--; - if (WDPART(bp->b_dev) != RAW_PART) - p_offset = - wd->sc_dk.dk_label->d_partitions[WDPART(bp->b_dev)].p_offset; - else - p_offset = 0; - - xfer = wdc_get_xfer(ctlr_link, 0); - if (xfer == NULL) - panic("wdc_xfer"); - - xfer->d_link = d_link; - xfer->c_bp = bp; - xfer->c_p_offset = p_offset; - xfer->databuf = bp->b_data; - xfer->c_flags |= bp->b_flags & (B_READ|B_WRITE); - xfer->c_skip = 0; - xfer->c_errors = 0; - /* count and blkno are filled in by wdcstart */ - - /* Instrumentation. */ - disk_busy(&wd->sc_dk); - wdc_exec_xfer(wd->d_link,xfer); - } -} - -int -wdread(dev, uio, flags) - dev_t dev; - struct uio *uio; - int flags; -{ - - WDDEBUG_PRINT(("wdread\n")); - return (physio(wdstrategy, NULL, dev, B_READ, minphys, uio)); -} - -int -wdwrite(dev, uio, flags) - dev_t dev; - struct uio *uio; - int flags; -{ - - WDDEBUG_PRINT(("wdwrite\n")); - return (physio(wdstrategy, NULL, dev, B_WRITE, minphys, uio)); -} - -/* - * Wait interruptibly for an exclusive lock. - * - * XXX - * Several drivers do this; it should be abstracted and made MP-safe. - */ -int -wdlock(d_link) - struct wd_link *d_link; -{ - int error; - int s; - - WDDEBUG_PRINT(("wdlock\n")); - - s = splbio(); - - while ((d_link->sc_flags & WDF_LOCKED) != 0) { - d_link->sc_flags |= WDF_WANTED; - if ((error = tsleep(d_link, PRIBIO | PCATCH, - "wdlck", 0)) != 0) { - splx(s); - return error; - } - } - d_link->sc_flags |= WDF_LOCKED; - splx(s); - return 0; -} - -/* - * Unlock and wake up any waiters. - */ -void -wdunlock(d_link) - struct wd_link *d_link; -{ - - WDDEBUG_PRINT(("wdunlock")); - - d_link->sc_flags &= ~WDF_LOCKED; - if ((d_link->sc_flags & WDF_WANTED) != 0) { - d_link->sc_flags &= ~WDF_WANTED; - wakeup(d_link); - } -} - -int -wdopen(dev, flag, fmt, p) - dev_t dev; - int flag, fmt; - struct proc *p; -{ - struct wd_softc *wd; - struct wd_link *d_link; - int unit, part; - int error; - - WDDEBUG_PRINT(("wdopen\n")); - - unit = WDUNIT(dev); - if (unit >= wd_cd.cd_ndevs) - return ENXIO; - wd = wd_cd.cd_devs[unit]; - if (wd == 0) - return ENXIO; - - d_link = wd->d_link; - if ((error = wdlock(d_link)) != 0) - return error; - - if (wd->sc_dk.dk_openmask != 0) { - /* - * If any partition is open, but the disk has been invalidated, - * disallow further opens. - */ - if ((d_link->sc_flags & WDF_LOADED) == 0) { - error = EIO; - goto bad3; - } - } else { - if ((d_link->sc_flags & WDF_LOADED) == 0) { - d_link->sc_flags |= WDF_LOADED; - - /* Load the physical device parameters. */ - if (wdc_get_parms(d_link) != 0) { - error = ENXIO; - goto bad2; - } - - /* Load the partition info if not already loaded. */ - wdgetdisklabel(dev, wd, wd->sc_dk.dk_label, - wd->sc_dk.dk_cpulabel, 0); - } - } - - part = WDPART(dev); - - /* Check that the partition exists. */ - if (part != RAW_PART && - (part >= wd->sc_dk.dk_label->d_npartitions || - wd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { - error = ENXIO; - goto bad; - } - - /* Insure only one open at a time. */ - switch (fmt) { - case S_IFCHR: - wd->sc_dk.dk_copenmask |= (1 << part); - break; - case S_IFBLK: - wd->sc_dk.dk_bopenmask |= (1 << part); - break; - } - wd->sc_dk.dk_openmask = wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; - - wdunlock(d_link); - return 0; - -bad2: - d_link->sc_flags &= ~WDF_LOADED; - -bad: - if (wd->sc_dk.dk_openmask == 0) { - } - -bad3: - wdunlock(d_link); - return error; -} - -int -wdclose(dev, flag, fmt, p) - dev_t dev; - int flag, fmt; - struct proc *p; -{ - struct wd_softc *wd = wd_cd.cd_devs[WDUNIT(dev)]; - int part = WDPART(dev); - int error; - - if ((error = wdlock(wd->d_link)) != 0) - return error; - - switch (fmt) { - case S_IFCHR: - wd->sc_dk.dk_copenmask &= ~(1 << part); - break; - case S_IFBLK: - wd->sc_dk.dk_bopenmask &= ~(1 << part); - break; - } - wd->sc_dk.dk_openmask = wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; - - if (wd->sc_dk.dk_openmask == 0) { - /* XXXX Must wait for I/O to complete! */ - } - - wdunlock(wd->d_link); - return 0; -} - -/* - * Fabricate a default disk label, and try to read the correct one. - */ -void -wdgetdisklabel(dev, wd, lp, clp, spoofonly) - dev_t dev; - struct wd_softc *wd; - struct disklabel *lp; - struct cpu_disklabel *clp; - int spoofonly; -{ - struct wd_link *d_link = wd->d_link; - char *errstring; - - WDDEBUG_PRINT(("wdgetdisklabel\n")); - - bzero(lp, sizeof(struct disklabel)); - bzero(clp, sizeof(struct cpu_disklabel)); - - lp->d_secsize = DEV_BSIZE; - lp->d_ntracks = d_link->sc_params.wdp_heads; - lp->d_nsectors = d_link->sc_params.wdp_sectors; - lp->d_ncylinders = d_link->sc_params.wdp_cylinders; - lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; - - strncpy(lp->d_packname, d_link->sc_params.wdp_model, 16); - if ((d_link->sc_params.wdp_capabilities & WD_CAP_LBA)) { - lp->d_secperunit = d_link->sc_params.wdp_lbacapacity; - strncpy(lp->d_typename, "ESDI/IDE disk", 16); - lp->d_type = DTYPE_ESDI; - } else { - lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; - strncpy(lp->d_typename, "ST506/MFM/RLL", 16); - lp->d_type = DTYPE_ST506; - } - - lp->d_rpm = 3600; - lp->d_interleave = 1; - lp->d_flags = 0; - - lp->d_partitions[RAW_PART].p_offset = 0; - lp->d_partitions[RAW_PART].p_size = - lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); - lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; - lp->d_npartitions = RAW_PART + 1; - - lp->d_magic = DISKMAGIC; - lp->d_magic2 = DISKMAGIC; - lp->d_checksum = dkcksum(lp); - - d_link->sc_badsect[0] = -1; - - if (d_link->sc_state > RECAL) - d_link->sc_state = RECAL; - - /* - * Call the generic disklabel extraction routine - */ - errstring = readdisklabel(WDLABELDEV(dev), wdstrategy, lp, clp, - spoofonly); - if (errstring) { - /* - * This probably happened because the drive's default - * geometry doesn't match the DOS geometry. We - * assume the DOS geometry is now in the label and try - * again. XXX This is a kluge. - */ - if (d_link->sc_state > GEOMETRY) - d_link->sc_state = GEOMETRY; - errstring = readdisklabel(WDLABELDEV(dev), wdstrategy, lp, clp, - spoofonly); - } - if (errstring) { - /*printf("%s: %s\n", wd->sc_dev.dv_xname, errstring);*/ - return; - } - - if (d_link->sc_state > GEOMETRY) - d_link->sc_state = GEOMETRY; -#ifdef DKBAD - if ((lp->d_flags & D_BADSECT) != 0) - bad144intern(wd); -#endif -} - -/* - * Tell the drive what geometry to use. - */ -int -wdsetctlr(d_link) - struct wd_link *d_link; -{ - struct wd_softc *wd=(struct wd_softc *)d_link->wd_softc; - - WDDEBUG_PRINT(("wd(%d,%d) C%dH%dS%d\n", wd->sc_dev.dv_unit, - d_link->sc_drive, wd->sc_dk.dk_label->d_ncylinders, - wd->sc_dk.dk_label->d_ntracks, wd->sc_dk.dk_label->d_nsectors)); - - if (wdccommand(d_link, WDCC_IDP, d_link->sc_drive, - wd->sc_dk.dk_label->d_ncylinders, - wd->sc_dk.dk_label->d_ntracks - 1, 0, - wd->sc_dk.dk_label->d_nsectors) != 0) { - wderror(d_link, NULL, "wdsetctlr: geometry upload failed"); - return -1; - } - - return 0; -} - -int -wdioctl(dev, xfer, addr, flag, p) - dev_t dev; - u_long xfer; - caddr_t addr; - int flag; - struct proc *p; -{ - struct wd_softc *wd = wd_cd.cd_devs[WDUNIT(dev)]; - struct wd_link *d_link = wd->d_link; - int error; - - WDDEBUG_PRINT(("wdioctl\n")); - - if ((d_link->sc_flags & WDF_LOADED) == 0) - return EIO; - - switch (xfer) { -#ifdef DKBAD - case DIOCSBAD: - if ((flag & FWRITE) == 0) - return EBADF; - DKBAD(wd->sc_dk.dk_cpulabel) = *(struct dkbad *)addr; - wd->sc_dk.dk_label->d_flags |= D_BADSECT; - bad144intern(wd); - return 0; -#endif - - case DIOCRLDINFO: - wdgetdisklabel(dev, wd, wd->sc_dk.dk_label, - wd->sc_dk.dk_cpulabel, 0); - return 0; - case DIOCGPDINFO: { - struct cpu_disklabel osdep; - - wdgetdisklabel(dev, wd, (struct disklabel *)addr, - &osdep, 1); - return 0; - } - case DIOCGDINFO: - *(struct disklabel *)addr = *(wd->sc_dk.dk_label); - return 0; - - case DIOCGPART: - ((struct partinfo *)addr)->disklab = wd->sc_dk.dk_label; - ((struct partinfo *)addr)->part = - &wd->sc_dk.dk_label->d_partitions[WDPART(dev)]; - return 0; - - case DIOCWDINFO: - case DIOCSDINFO: - if ((flag & FWRITE) == 0) - return EBADF; - - if ((error = wdlock(wd->d_link)) != 0) - return error; - d_link->sc_flags |= WDF_LABELLING; - - error = setdisklabel(wd->sc_dk.dk_label, - (struct disklabel *)addr, /*wd->sc_dk.dk_openmask : */0, - wd->sc_dk.dk_cpulabel); - if (error == 0) { - if (d_link->sc_state > GEOMETRY) - d_link->sc_state = GEOMETRY; - if (xfer == DIOCWDINFO) - error = writedisklabel(WDLABELDEV(dev), - wdstrategy, wd->sc_dk.dk_label, - wd->sc_dk.dk_cpulabel); - } - - d_link->sc_flags &= ~WDF_LABELLING; - wdunlock(d_link); - return error; - - case DIOCWLABEL: - if ((flag & FWRITE) == 0) - return EBADF; - if (*(int *)addr) - d_link->sc_flags |= WDF_WLABEL; - else - d_link->sc_flags &= ~WDF_WLABEL; - return 0; - -#ifdef notyet - case DIOCWFORMAT: - if ((flag & FWRITE) == 0) - return EBADF; - { - register struct format_op *fop; - struct iovec aiov; - struct uio auio; - - fop = (struct format_op *)addr; - aiov.iov_base = fop->df_buf; - aiov.iov_len = fop->df_count; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_resid = fop->df_count; - auio.uio_segflg = 0; - auio.uio_offset = - fop->df_startblk * wd->sc_dk.dk_label->d_secsize; - auio.uio_procp = p; - error = physio(wdformat, NULL, dev, B_WRITE, minphys, - &auio); - fop->df_count -= auio.uio_resid; - fop->df_reg[0] = wdc->sc_status; - fop->df_reg[1] = wdc->sc_error; - return error; - } -#endif - - default: - return ENOTTY; - } - -#ifdef DIAGNOSTIC - panic("wdioctl: impossible"); -#endif -} - -#ifdef B_FORMAT -int -wdformat(struct buf *bp) -{ - - bp->b_flags |= B_FORMAT; - return wdstrategy(bp); -} -#endif - -int -wdsize(dev) - dev_t dev; -{ - struct wd_softc *wd; - int part, unit, omask; - int size; - - WDDEBUG_PRINT(("wdsize\n")); - - unit = WDUNIT(dev); - if (unit >= wd_cd.cd_ndevs) - return -1; - wd = wd_cd.cd_devs[unit]; - if (wd == NULL) - return -1; - - part = WDPART(dev); - omask = wd->sc_dk.dk_openmask & (1 << part); - - if (omask == 0 && wdopen(dev, 0, S_IFBLK, NULL) != 0) - return -1; - else if (wd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) - size = -1; - else - size = wd->sc_dk.dk_label->d_partitions[part].p_size * - (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE); - - if (omask == 0 && wdclose(dev, 0, S_IFBLK, NULL) != 0) - return -1; - return size; -} - - -#ifndef __BDEVSW_DUMP_OLD_TYPE -/* #define WD_DUMP_NOT_TRUSTED if you just want to watch */ -static int wddoingadump; -static int wddumprecalibrated; - -/* - * Dump core after a system crash. - * - * XXX: This needs work! Currently, it's a major hack: the - * use of wdc_softc is very bad and should go away. - */ -int -wddump(dev, blkno, va, size) - dev_t dev; - daddr_t blkno; - caddr_t va; - size_t size; -{ - struct wd_softc *wd; /* disk unit to do the I/O */ - struct wdc_softc *wdc; /* disk controller to do the I/O */ - struct disklabel *lp; /* disk's disklabel */ - struct wd_link *d_link; - int unit, part; - int nblks; /* total number of sectors left to write */ - - /* Check if recursive dump; if so, punt. */ - if (wddoingadump) - return EFAULT; - wddoingadump = 1; - - unit = WDUNIT(dev); - if (unit >= wd_cd.cd_ndevs) - return ENXIO; - wd = wd_cd.cd_devs[unit]; - if (wd == (struct wd_softc *)0) - return ENXIO; - d_link = wd->d_link; - - part = WDPART(dev); - - /* Make sure it was initialized. */ - if (d_link->sc_state < READY) - return ENXIO; - - wdc = (void *)wd->sc_dev.dv_parent; - - /* Convert to disk sectors. Request must be a multiple of size. */ - lp = wd->sc_dk.dk_label; - if ((size % lp->d_secsize) != 0) - return EFAULT; - nblks = size / lp->d_secsize; - blkno = blkno / (lp->d_secsize / DEV_BSIZE); - - /* Check transfer bounds against partition size. */ - if ((blkno < 0) || ((blkno + nblks) > lp->d_partitions[part].p_size)) - return EINVAL; - - /* Offset block number to start of partition. */ - blkno += lp->d_partitions[part].p_offset; - - /* Recalibrate, if first dump transfer. */ - if (wddumprecalibrated == 0) { - wddumprecalibrated = 1; - if (wdccommandshort(wdc, d_link->sc_drive, WDCC_RECAL) != 0 || - wait_for_ready(wdc) != 0 || wdsetctlr(d_link) != 0 || - wait_for_ready(wdc) != 0) { - wderror(d_link, NULL, "wddump: recal failed"); - return EIO; - } - } - - while (nblks > 0) { - daddr_t xlt_blkno = blkno; - int cylin, head, sector; - - if ((lp->d_flags & D_BADSECT) != 0) { - int blkdiff; - int i; - - for (i = 0; (blkdiff = d_link->sc_badsect[i]) != -1; i++) { - blkdiff -= xlt_blkno; - if (blkdiff < 0) - continue; - if (blkdiff == 0) { - /* Replace current block of transfer. */ - xlt_blkno = lp->d_secperunit - - lp->d_nsectors - i - 1; - } - break; - } - /* Tranfer is okay now. */ - } - - if ((d_link->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) { - sector = (xlt_blkno >> 0) & 0xff; - cylin = (xlt_blkno >> 8) & 0xffff; - head = (xlt_blkno >> 24) & 0xf; - head |= WDSD_LBA; - } else { - sector = xlt_blkno % lp->d_nsectors; - sector++; /* Sectors begin with 1, not 0. */ - xlt_blkno /= lp->d_nsectors; - head = xlt_blkno % lp->d_ntracks; - xlt_blkno /= lp->d_ntracks; - cylin = xlt_blkno; - head |= WDSD_CHS; - } - -#ifndef WD_DUMP_NOT_TRUSTED - if (wdccommand(d_link, WDCC_WRITE, d_link->sc_drive, cylin, - head, sector, 1) != 0 || - wait_for_drq(wdc) != 0) { - wderror(d_link, NULL, "wddump: write failed"); - return EIO; - } - - /* XXX XXX XXX */ - bus_space_write_multi_2(wdc->sc_iot, wdc->sc_ioh, wd_data, - (u_int16_t *)va, lp->d_secsize >> 1); - - /* Check data request (should be done). */ - if (wait_for_ready(wdc) != 0) { - wderror(d_link, NULL, - "wddump: timeout waiting for ready"); - return EIO; - } -#else /* WD_DUMP_NOT_TRUSTED */ - /* Let's just talk about this first... */ - printf("wd%d: dump addr 0x%x, cylin %d, head %d, sector %d\n", - unit, va, cylin, head, sector); - delay(500 * 1000); /* half a second */ -#endif - - /* update block count */ - nblks -= 1; - blkno += 1; - va += lp->d_secsize; - } - - wddoingadump = 0; - return 0; -} -#else /* __BDEVSW_DUMP_NEW_TYPE */ - - -int -wddump(dev, blkno, va, size) - dev_t dev; - daddr_t blkno; - caddr_t va; - size_t size; -{ - - /* Not implemented. */ - return ENXIO; -} -#endif /* __BDEVSW_DUMP_NEW_TYPE */ - -#ifdef DKBAD -/* - * Internalize the bad sector table. - */ -void -bad144intern(wd) - struct wd_softc *wd; -{ - struct dkbad *bt = &DKBAD(wd->sc_dk.dk_cpulabel); - struct disklabel *lp = wd->sc_dk.dk_label; - struct wd_link *d_link = wd->d_link; - int i = 0; - - WDDEBUG_PRINT(("bad144intern\n")); - - for (; i < 126; i++) { - if (bt->bt_bad[i].bt_cyl == 0xffff) - break; - d_link->sc_badsect[i] = - bt->bt_bad[i].bt_cyl * lp->d_secpercyl + - (bt->bt_bad[i].bt_trksec >> 8) * lp->d_nsectors + - (bt->bt_bad[i].bt_trksec & 0xff); - } - for (; i < 127; i++) - d_link->sc_badsect[i] = -1; -} -#endif - -void -wderror(d_link, bp, msg) - struct wd_link *d_link; - struct buf *bp; - char *msg; -{ - struct wd_softc *wd = (struct wd_softc *)d_link->wd_softc; - - if (bp) { - diskerr(bp, "wd", msg, LOG_PRINTF, bp->b_bcount, - wd->sc_dk.dk_label); - printf("\n"); - } else - printf("%s: %s\n", wd->sc_dev.dv_xname, msg); -} - -void -wddone(d_link, bp) - struct wd_link *d_link; - struct buf *bp; -{ - struct wd_softc *wd = (void *)d_link->wd_softc; - - disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid)); -} diff --git a/sys/dev/isa/wdc.c b/sys/dev/isa/wdc.c deleted file mode 100644 index 6ec61f5c157..00000000000 --- a/sys/dev/isa/wdc.c +++ /dev/null @@ -1,1972 +0,0 @@ -/* $OpenBSD: wdc.c,v 1.37 1999/06/28 22:35:24 ho Exp $ */ -/* $NetBSD: wd.c,v 1.150 1996/05/12 23:54:03 mycroft Exp $ */ - -/* - * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. - * - * DMA and multi-sector PIO handling are derived from code contributed by - * Onno van der Linden. - * - * Atapi support added by Manuel Bouyer. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Charles M. Hannum. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "isadma.h" - -/* #undef ATAPI_DEBUG_WDC */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/conf.h> -#include <sys/file.h> -#include <sys/stat.h> -#include <sys/ioctl.h> -#include <sys/buf.h> -#include <sys/uio.h> -#include <sys/malloc.h> -#include <sys/device.h> -#include <sys/disklabel.h> -#include <sys/disk.h> -#include <sys/syslog.h> -#include <sys/proc.h> - -#include <vm/vm.h> - -#include <machine/bus.h> -#include <machine/cpu.h> -#include <machine/intr.h> - -#include <dev/isa/isavar.h> -#if NISADMA > 0 -#include <dev/isa/isadmavar.h> -#endif /* NISADMA > 0 */ -#include <dev/isa/wdreg.h> -#include <dev/isa/wdlink.h> - -#include "wdc.h" - -#include "atapibus.h" -#if NATAPIBUS > 0 -#include <dev/atapi/atapilink.h> -#endif /* NATAPIBUS */ - -#define WAITTIME (10 * hz) /* time to wait for a completion */ - /* this is a lot for hard drives, but not for cdroms */ -#define RECOVERYTIME hz/2 -#define WDCDELAY 100 -#define WDCNDELAY 100000 /* delay = 100us; so 10s for a controller state change */ -#if 0 -/* If you enable this, it will report any delays more than 100us * N long. */ -#define WDCNDELAY_DEBUG 50 -#endif - -#define WDIORETRIES 3 /* number of retries before giving up */ - -#define WDPART(dev) DISKPART(dev) - -LIST_HEAD(xfer_free_list, wdc_xfer) xfer_free_list; - -int wdcprobe __P((struct device *, void *, void *)); -int wdcprint __P((void *, const char *)); -void wdcattach __P((struct device *, struct device *, void *)); -int wdcintr __P((void *)); - -#if NWDC_ISA -struct cfattach wdc_isa_ca = { - sizeof(struct wdc_softc), wdcprobe, wdcattach -}; -#endif - -#if NWDC_ISAPNP -struct cfattach wdc_isapnp_ca = { - sizeof(struct wdc_softc), wdcprobe, wdcattach -}; -#endif - -struct cfdriver wdc_cd = { - NULL, "wdc", DV_DULL -}; - -enum wdcreset_mode { WDCRESET_VERBOSE, WDCRESET_SILENT }; - -#if NWD > 0 -int wdc_ata_intr __P((struct wdc_softc *, struct wdc_xfer *)); -void wdc_ata_start __P((struct wdc_softc *, struct wdc_xfer *)); -void wdc_ata_done __P((struct wdc_softc *, struct wdc_xfer *)); -__inline static void u_int16_to_string __P((u_int16_t *, char *, size_t)); -#endif /* NWD */ -int wait_for_phase __P((struct wdc_softc *, int)); -int wait_for_unphase __P((struct wdc_softc *, int)); -void wdcstart __P((struct wdc_softc *)); -int wdcreset __P((struct wdc_softc *, enum wdcreset_mode)); -void wdcrestart __P((void *arg)); -void wdcunwedge __P((struct wdc_softc *)); -void wdctimeout __P((void *arg)); -int wdccontrol __P((struct wd_link *)); -void wdc_free_xfer __P((struct wdc_xfer *)); -void wdcerror __P((struct wdc_softc*, char *)); -void wdcbit_bucket __P(( struct wdc_softc *, int)); -#if NATAPIBUS > 0 -void wdc_atapi_start __P((struct wdc_softc *,struct wdc_xfer *)); -int wdc_atapi_intr __P((struct wdc_softc *, struct wdc_xfer *)); -void wdc_atapi_done __P((struct wdc_softc *, struct wdc_xfer *)); -#endif /* NATAPIBUS */ - -#ifdef ATAPI_DEBUG -static int wdc_nxfer; -#endif - -#ifdef WDDEBUG -#define WDDEBUG_PRINT(args) printf args -#else -#define WDDEBUG_PRINT(args) -#endif - -/* Macro for determining bus type. */ -#if NWDC_ISAPNP -#define IS_ISAPNP(parent) \ - !strcmp((parent)->dv_cfdata->cf_driver->cd_name, "isapnp") -#else -#define IS_ISAPNP(parent) 0 -#endif - -int -wdcprobe(parent, match, aux) - struct device *parent; - void *match, *aux; -{ - bus_space_tag_t iot; - bus_space_handle_t ioh; - bus_space_handle_t ioh_ctl; - struct wdc_softc *wdc = match; - struct isa_attach_args *ia = aux; -#ifdef notyet - int err; -#endif - -#if NISADMA == 0 - if (ia->ia_drq != DRQUNK) { - printf("cannot support dma wdc devices\n"); - return 0; - } -#endif - - wdc->sc_iot = iot = ia->ia_iot; - if (IS_ISAPNP(parent)) { - ioh = ia->ipa_io[0].h; - ioh_ctl = ia->ipa_io[1].h; - } else { - if (bus_space_map(iot, ia->ia_iobase, 8, 0, &ioh)) - return 0; - if (bus_space_map(iot, ia->ia_iobase + WDCTL_OFFSET, - 1, 0, &ioh_ctl)) - return 0; - } - wdc->sc_ioh = ioh; - wdc->sc_ioh_ctl = ioh_ctl; - - /* Check if we have registers that work. */ - /* Error register not writable, */ - bus_space_write_1(iot, ioh, wd_error, 0x5a); - /* but all of cyl_lo are. */ - bus_space_write_1(iot, ioh, wd_cyl_lo, 0xa5); - if (bus_space_read_1(iot, ioh, wd_error) == 0x5a || - bus_space_read_1(iot, ioh, wd_cyl_lo) != 0xa5) { - /* - * Test for a controller with no IDE master, just one - * ATAPI device. Select drive 1, and try again. - */ - bus_space_write_1(iot, ioh, wd_sdh, WDSD_IBM | 0x10); - bus_space_write_1(iot, ioh, wd_error, 0x5a); - bus_space_write_1(iot, ioh, wd_cyl_lo, 0xa5); - if (bus_space_read_1(iot, ioh, wd_error) == 0x5a || - bus_space_read_1(iot, ioh, wd_cyl_lo) != 0xa5) - goto nomatch; - wdc->sc_flags |= WDCF_ONESLAVE; - } - - if (wdcreset(wdc, WDCRESET_SILENT) != 0) { - /* - * If the reset failed, there is no master. test for ATAPI - * signature on the slave device. If no ATAPI slave, wait 5s - * and retry a reset. - */ - bus_space_write_1(iot, ioh, wd_sdh, WDSD_IBM | 0x10); /* slave */ - if (bus_space_read_1(iot, ioh, wd_cyl_lo) != 0x14 || - bus_space_read_1(iot, ioh, wd_cyl_hi) != 0xeb) { - delay(500000); - if (wdcreset(wdc, WDCRESET_SILENT) != 0) - goto nomatch; - } - wdc->sc_flags |= WDCF_ONESLAVE; - } - - /* Select drive 0 or ATAPI slave device */ - if (wdc->sc_flags & WDCF_ONESLAVE) - bus_space_write_1(iot, ioh, wd_sdh, WDSD_IBM | 0x10); - else - bus_space_write_1(iot, ioh, wd_sdh, WDSD_IBM); - - /* Wait for controller to become ready. */ - if (wait_for_unbusy(wdc) < 0) - goto nomatch; - - /* Start drive diagnostics. */ - bus_space_write_1(iot, ioh, wd_command, WDCC_DIAGNOSE); - - /* Wait for command to complete. */ - if (wait_for_unbusy(wdc) < 0) - goto nomatch; - -#ifdef notyet - /* See if the drive(s) are alive. */ - err = bus_space_read_1(iot, ioh, wd_error); - if (err && (err != 0x01)) { - if (err & 0x80) { - /* Select drive 1. */ - bus_space_write_1(iot, ioh, wd_sdh, WDSD_IBM | 0x10); - (void) wait_for_unbusy(wdc); - - err = bus_space_read_1(iot, ioh, wd_error); - if ((err != 0x01) && (err != 0x81)) - goto nomatch; - } else - goto nomatch; - } -#endif - - ia->ia_iosize = 8; - ia->ia_msize = 0; - return 1; - -nomatch: - if (!IS_ISAPNP(parent)) { - bus_space_unmap(iot, ioh, 8); - bus_space_unmap(iot, ioh_ctl, 1); - } - return 0; -} - -int -wdcprint(aux, wdc) - void *aux; - const char *wdc; -{ - struct wd_link *d_link = aux; - - if (!wdc) - printf(" drive %d", d_link->sc_drive); - return QUIET; -} - -void -wdcattach(parent, self, aux) - struct device *parent, *self; - void *aux; -{ - struct wdc_softc *wdc = (void *)self; - struct isa_attach_args *ia = aux; -#if NWD > 0 - int drive; - bus_space_tag_t iot = wdc->sc_iot; - bus_space_handle_t ioh = wdc->sc_ioh; -#endif /* NWD */ - - TAILQ_INIT(&wdc->sc_xfer); - wdc->sc_drq = ia->ia_drq; - - printf("\n"); - - wdc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, - IPL_BIO, wdcintr, wdc, wdc->sc_dev.dv_xname); - - wdc->ctlr_link.flags = 0; -#ifdef ATAPI_DEBUG - wdc_nxfer = 0; -#endif - -#if NATAPIBUS > 0 - /* - * Attach an ATAPI bus, if configured. - */ - wdc->ab_link = malloc(sizeof(struct bus_link), M_DEVBUF, M_NOWAIT); - if (wdc->ab_link == NULL) { - printf("%s: can't allocate ATAPI link\n", self->dv_xname); - return; - } - bzero(wdc->ab_link,sizeof(struct bus_link)); - wdc->ab_link->type = BUS; - wdc->ab_link->wdc_softc = (caddr_t)wdc; - wdc->ab_link->ctlr_link = &(wdc->ctlr_link); - wdc->ab_link->ctrl = self->dv_unit; - (void)config_found(self, (void *)wdc->ab_link, NULL); -#endif /* NATAPIBUS */ -#if NWD > 0 - /* - * Attach standard IDE/ESDI/etc. disks to the controller. - */ - for (drive = 0; drive < 2; drive++) { - /* test for ATAPI signature on this drive */ - bus_space_write_1(iot, ioh, wd_sdh, WDSD_IBM | (drive << 4)); - if (bus_space_read_1(iot, ioh, wd_cyl_lo) == 0x14 && - bus_space_read_1(iot, ioh, wd_cyl_hi) == 0xeb) { - continue; - } - /* controller active while autoconf */ - wdc->sc_flags |= WDCF_ACTIVE; - - if (wdccommandshort(wdc, drive, WDCC_RECAL) != 0 || - wait_for_ready(wdc) != 0) { - wdc->d_link[drive] = NULL; - wdc->sc_flags &= ~WDCF_ACTIVE; - } else { - wdc->sc_flags &= ~WDCF_ACTIVE; - wdc->d_link[drive] = malloc(sizeof(struct wd_link), - M_DEVBUF, M_NOWAIT); - if (wdc->d_link[drive] == NULL) { - printf("%s: can't allocate link for drive %d\n", - self->dv_xname, drive); - continue; - } - bzero(wdc->d_link[drive],sizeof(struct wd_link)); - wdc->d_link[drive]->type = DRIVE; - wdc->d_link[drive]->wdc_softc =(caddr_t) wdc; - wdc->d_link[drive]->ctlr_link = &(wdc->ctlr_link); - wdc->d_link[drive]->sc_drive = drive; -#if NISADMA > 0 - if (wdc->sc_drq != DRQUNK) - wdc->d_link[drive]->sc_mode = WDM_DMA; - else -#endif /* NISADMA */ - wdc->d_link[drive]->sc_mode = 0; - - (void)config_found(self, (void *)wdc->d_link[drive], - wdcprint); - } - } -#endif /* NWD */ -} - -/* - * Start I/O on a controller. This does the calculation, and starts a read or - * write operation. Called to from wdstart() to start a transfer, from - * wdcintr() to continue a multi-sector transfer or start the next transfer, or - * wdcrestart() after recovering from an error. - */ -void -wdcstart(wdc) - struct wdc_softc *wdc; -{ - struct wdc_xfer *xfer; - - if ((wdc->sc_flags & WDCF_ACTIVE) != 0 ) { - WDDEBUG_PRINT(("wdcstart: already active\n")); - return; /* controller aleady active */ - } -#ifdef DIAGNOSTIC - if ((wdc->sc_flags & WDCF_IRQ_WAIT) != 0) - panic("wdcstart: controller waiting for irq"); -#endif - /* - * XXX - * This is a kluge. See comments in wd_get_parms(). - */ - if ((wdc->sc_flags & WDCF_WANTED) != 0) { -#ifdef ATAPI_DEBUG_WDC - printf("WDCF_WANTED\n"); -#endif - wdc->sc_flags &= ~WDCF_WANTED; - wakeup(wdc); - return; - } - /* is there a xfer ? */ - xfer = wdc->sc_xfer.tqh_first; - if (xfer == NULL) { -#ifdef ATAPI_DEBUG2 - printf("wdcstart: null xfer\n"); -#endif - return; - } - wdc->sc_flags |= WDCF_ACTIVE; -#if NATAPIBUS > 0 && NWD > 0 - if (xfer->c_flags & C_ATAPI) { -#ifdef ATAPI_DEBUG_WDC - printf("wdcstart: atapi\n"); -#endif - wdc_atapi_start(wdc, xfer); - } else - wdc_ata_start(wdc, xfer); -#else -#if NATAPIBUS > 0 -#ifdef ATAPI_DEBUG_WDC - printf("wdcstart: atapi\n"); -#endif - wdc_atapi_start(wdc, xfer); -#endif /* NATAPIBUS */ -#if NWD > 0 - wdc_ata_start(wdc, xfer); -#endif /* NWD */ -#endif /* NATAPIBUS && NWD */ -} - -#if NWD > 0 -void -wdc_ata_start(wdc, xfer) - struct wdc_softc *wdc; - struct wdc_xfer *xfer; -{ - bus_space_tag_t iot = wdc->sc_iot; - bus_space_handle_t ioh = wdc->sc_ioh; -#ifdef WDDEBUG - bus_space_handle_t ioh_ctl = wdc->sc_ioh_ctl; -#endif - struct wd_link *d_link = xfer->d_link; - struct buf *bp = xfer->c_bp; - int nblks; - - if (xfer->c_errors >= WDIORETRIES) { - wderror(d_link, bp, "wdcstart hard error"); - xfer->c_flags |= C_ERROR; - wdc_ata_done(wdc, xfer); - return; - } - - /* Do control operations specially. */ - if (d_link->sc_state < READY) { - /* - * Actually, we want to be careful not to mess with the control - * state if the device is currently busy, but we can assume - * that we never get to this point if that's the case. - */ - if (wdccontrol(d_link) == 0) { - /* The drive is busy. Wait. */ - return; - } - } - - /* - * WDCF_ERROR is set by wdcunwedge() and wdcintr() when an error is - * encountered. If we are in multi-sector mode, then we switch to - * single-sector mode and retry the operation from the start. - */ - if (wdc->sc_flags & WDCF_ERROR) { - wdc->sc_flags &= ~WDCF_ERROR; - if ((wdc->sc_flags & WDCF_SINGLE) == 0) { - wdc->sc_flags |= WDCF_SINGLE; - xfer->c_skip = 0; - } - } - - - /* When starting a transfer... */ - if (xfer->c_skip == 0) { - struct buf *bp = xfer->c_bp; - - xfer->c_bcount = bp->b_bcount; - xfer->c_blkno = (bp->b_blkno + xfer->c_p_offset) / (d_link->sc_lp->d_secsize / DEV_BSIZE); - WDDEBUG_PRINT(("\n%s: wdc_ata_start %s %d@%d; map ", - wdc->sc_dev.dv_xname, - (xfer->c_flags & B_READ) ? "read" : "write", - xfer->c_bcount, xfer->c_blkno)); - } else { - WDDEBUG_PRINT((" %d)0x%x", xfer->c_skip, - bus_space_read_1(iot, ioh_ctl, wd_altsts))); - } - - /* - * When starting a multi-sector transfer, or doing single-sector - * transfers... - */ - if (xfer->c_skip == 0 || (wdc->sc_flags & WDCF_SINGLE) != 0 || - d_link->sc_mode == WDM_DMA) { - daddr_t blkno = xfer->c_blkno; - int cylin, head, sector; - int command; - - if ((wdc->sc_flags & WDCF_SINGLE) != 0) - nblks = 1; -#if NISADMA > 0 - else if (d_link->sc_mode != WDM_DMA) - nblks = xfer->c_bcount / d_link->sc_lp->d_secsize; - else - nblks = - min(xfer->c_bcount / d_link->sc_lp->d_secsize, 8); -#else - else - nblks = xfer->c_bcount / d_link->sc_lp->d_secsize; -#endif - - /* Check for bad sectors and adjust transfer, if necessary. */ - if ((d_link->sc_lp->d_flags & D_BADSECT) != 0 -#ifdef B_FORMAT - && (bp->b_flags & B_FORMAT) == 0 -#endif - ) { - int blkdiff; - int i; - - for (i = 0; - (blkdiff = d_link->sc_badsect[i]) != -1; i++) { - blkdiff -= blkno; - if (blkdiff < 0) - continue; - if (blkdiff == 0) { - /* Replace current block of xfer. */ - blkno = d_link->sc_lp->d_secperunit - - d_link->sc_lp->d_nsectors - i - 1; - } - if (blkdiff < nblks) { - /* Bad block inside transfer. */ - wdc->sc_flags |= WDCF_SINGLE; - nblks = 1; - } - break; - } - /* Tranfer is okay now. */ - } - - if ((d_link->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) { - sector = (blkno >> 0) & 0xff; - cylin = (blkno >> 8) & 0xffff; - head = (blkno >> 24) & 0xf; - head |= WDSD_LBA; - } else { - sector = blkno % d_link->sc_lp->d_nsectors; - sector++; /* Sectors begin with 1, not 0. */ - blkno /= d_link->sc_lp->d_nsectors; - head = blkno % d_link->sc_lp->d_ntracks; - blkno /= d_link->sc_lp->d_ntracks; - cylin = blkno; - head |= WDSD_CHS; - } - - if (d_link->sc_mode == WDM_PIOSINGLE || - (wdc->sc_flags & WDCF_SINGLE) != 0) - xfer->c_nblks = 1; - else if (d_link->sc_mode == WDM_PIOMULTI) - xfer->c_nblks = min(nblks, d_link->sc_multiple); - else - xfer->c_nblks = nblks; - xfer->c_nbytes = xfer->c_nblks * d_link->sc_lp->d_secsize; - -#ifdef B_FORMAT - if (bp->b_flags & B_FORMAT) { - sector = d_link->sc_lp->d_gap3; - nblks = d_link->sc_lp->d_nsectors; - command = WDCC_FORMAT; - } else -#endif - switch (d_link->sc_mode) { -#if NISADMA > 0 - case WDM_DMA: - command = (xfer->c_flags & B_READ) ? - WDCC_READDMA : WDCC_WRITEDMA; - /* - * Start the DMA channel and bounce the buffer if - * necessary. - */ - isadma_start(xfer->databuf + xfer->c_skip, - xfer->c_nbytes, wdc->sc_drq, - xfer->c_flags & B_READ ? - DMAMODE_READ : DMAMODE_WRITE); - break; -#endif - - case WDM_PIOMULTI: - command = (xfer->c_flags & B_READ) ? - WDCC_READMULTI : WDCC_WRITEMULTI; - break; - - case WDM_PIOSINGLE: - command = (xfer->c_flags & B_READ) ? - WDCC_READ : WDCC_WRITE; - break; - - default: -#ifdef DIAGNOSTIC - panic("bad wd mode"); -#endif - return; - } - - /* Initiate command! */ - if (wdccommand(d_link, command, d_link->sc_drive, - cylin, head, sector, nblks) != 0) { - wderror(d_link, NULL, - "wdc_ata_start: timeout waiting for unbusy"); - wdcunwedge(wdc); - return; - } - - WDDEBUG_PRINT(("sector %d cylin %d head %d addr %x sts %x\n", - sector, cylin, head, xfer->databuf, - bus_space_read_1(iot, ioh_ctl, wd_altsts))); - - } else if (xfer->c_nblks > 1) { - /* The number of blocks in the last stretch may be smaller. */ - nblks = xfer->c_bcount / d_link->sc_lp->d_secsize; - if (xfer->c_nblks > nblks) { - xfer->c_nblks = nblks; - xfer->c_nbytes = xfer->c_bcount; - } - } - - /* If this was a write and not using DMA, push the data. */ - if (d_link->sc_mode != WDM_DMA && - (xfer->c_flags & (B_READ|B_WRITE)) == B_WRITE) { - if (wait_for_drq(wdc) < 0) { - wderror(d_link, NULL, - "wdc_ata_start: timeout waiting for drq"); - wdcunwedge(wdc); - return; - } - - /* Push out data. */ - if ((d_link->sc_flags & WDF_32BIT) == 0) - bus_space_write_raw_multi_2(iot, ioh, wd_data, - xfer->databuf + xfer->c_skip, xfer->c_nbytes); - else - bus_space_write_raw_multi_4(iot, ioh, wd_data, - xfer->databuf + xfer->c_skip, xfer->c_nbytes); - } - - wdc->sc_flags |= WDCF_IRQ_WAIT; - WDDEBUG_PRINT(("wdc_ata_start: timeout ")); - timeout(wdctimeout, wdc, WAITTIME); - WDDEBUG_PRINT(("done\n")); -} - -int -wdc_ata_intr(wdc, xfer) - struct wdc_softc *wdc; - struct wdc_xfer *xfer; -{ - bus_space_tag_t iot = wdc->sc_iot; - bus_space_handle_t ioh = wdc->sc_ioh; - struct wd_link *d_link = xfer->d_link; - - if (wait_for_unbusy(wdc) < 0) { - wdcerror(wdc, "wdcintr: timeout waiting for unbusy"); - wdc->sc_status |= WDCS_ERR; /* XXX */ - } - - untimeout(wdctimeout, wdc); - - /* Is it not a transfer, but a control operation? */ - if (d_link->sc_state < READY) { - if (wdccontrol(d_link) == 0) { - /* The drive is busy. Wait. */ - return 1; - } - WDDEBUG_PRINT( - ("wdc_ata_start from wdc_ata_intr(open) flags %d\n", - wdc->sc_flags)); - wdc_ata_start(wdc,xfer); - return 1; - } - -#if NISADMA > 0 - /* Turn off the DMA channel and unbounce the buffer. */ - if (d_link->sc_mode == WDM_DMA) - isadma_done(wdc->sc_drq); -#endif - - /* Have we an error? */ - if (wdc->sc_status & WDCS_ERR) { -#ifdef WDDEBUG - wderror(d_link, NULL, "wdc_ata_intr"); -#endif - if ((wdc->sc_flags & WDCF_SINGLE) == 0) { - wdc->sc_flags |= WDCF_ERROR; - goto restart; - } - -#ifdef B_FORMAT - if (bp->b_flags & B_FORMAT) - goto bad; -#endif - - if (++xfer->c_errors == (WDIORETRIES + 1) / 2) { - wdcunwedge(wdc); - return 1; - } - if (xfer->c_errors < WDIORETRIES) - goto restart; - - wderror(d_link, xfer->c_bp, "hard error"); - -#ifdef B_FORMAT - bad: -#endif - xfer->c_flags |= C_ERROR; - goto done; - } - - /* If this was a read and not using DMA, fetch the data. */ - if (d_link->sc_mode != WDM_DMA && - (xfer->c_flags & (B_READ|B_WRITE)) == B_READ) { - if ((wdc->sc_status & (WDCS_DRDY | WDCS_DSC | WDCS_DRQ)) - != (WDCS_DRDY | WDCS_DSC | WDCS_DRQ)) { - wderror(d_link, NULL, "wdcintr: read intr before drq"); - wdcunwedge(wdc); - return 1; - } - - /* Pull in data. */ - if ((d_link->sc_flags & WDF_32BIT) == 0) - bus_space_read_raw_multi_2(iot, ioh, wd_data, - xfer->databuf + xfer->c_skip, xfer->c_nbytes); - else - bus_space_read_raw_multi_4(iot, ioh, wd_data, - xfer->databuf + xfer->c_skip, xfer->c_nbytes); - } - - /* If we encountered any abnormalities, flag it as a soft error. */ - if (xfer->c_errors > 0 || - (wdc->sc_status & WDCS_CORR) != 0) { - wderror(d_link, xfer->c_bp, "soft error (corrected)"); - xfer->c_errors = 0; - } - - /* Adjust pointers for the next block, if any. */ - xfer->c_blkno += xfer->c_nblks; - xfer->c_skip += xfer->c_nbytes; - xfer->c_bcount -= xfer->c_nbytes; - - /* See if this transfer is complete. */ - if (xfer->c_bcount > 0) - goto restart; - -done: - /* Done with this transfer, with or without error. */ - wdc_ata_done(wdc, xfer); - return 0; - -restart: - /* Start the next operation */ - WDDEBUG_PRINT(("wdc_ata_start from wdcintr flags %d\n", - wdc->sc_flags)); - wdc_ata_start(wdc, xfer); - - return 1; -} - -void -wdc_ata_done(wdc, xfer) - struct wdc_softc *wdc; - struct wdc_xfer *xfer; -{ - struct buf *bp = xfer->c_bp; - struct wd_link *d_link = xfer->d_link; - int s; - - WDDEBUG_PRINT(("wdc_ata_done\n")); - - /* remove this command from xfer queue */ - s = splbio(); - TAILQ_REMOVE(&wdc->sc_xfer, xfer, c_xferchain); - wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR | WDCF_ACTIVE); - if (bp) { - if (xfer->c_flags & C_ERROR) { - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - } - bp->b_resid = xfer->c_bcount; - wddone(d_link, bp); - biodone(bp); - } else { - wakeup(xfer->databuf); - } - xfer->c_skip = 0; - wdc_free_xfer(xfer); - d_link->openings++; - wdstart((void *)d_link->wd_softc); - WDDEBUG_PRINT(("wdcstart from wdc_ata_done, flags %d\n", - wdc->sc_flags)); - wdcstart(wdc); - splx(s); -} - -/* decode IDE strings, stored as if the words are big-endian. */ -__inline static void -u_int16_to_string(from, to, cnt) - u_int16_t *from; - char *to; - size_t cnt; -{ - size_t i; - - for (i = 0; i < cnt; i += 2) { - *to++ = (char)(*from >> 8 & 0xff); - *to++ = (char)(*from++ & 0xff); - } -} - -/* - * Get the drive parameters, if ESDI or ATA, or create fake ones for ST506. - */ -int -wdc_get_parms(d_link) - struct wd_link *d_link; -{ - struct wdc_softc *wdc = (struct wdc_softc *)d_link->wdc_softc; - bus_space_tag_t iot = wdc->sc_iot; - bus_space_handle_t ioh = wdc->sc_ioh; - u_int16_t tb[DEV_BSIZE / sizeof(u_int16_t)]; - int s, error; - - /* - * XXX - * The locking done here, and the length of time this may keep the rest - * of the system suspended, is a kluge. This should be rewritten to - * set up a transfer and queue it through wdstart(), but it's called - * infrequently enough that this isn't a pressing matter. - */ - - s = splbio(); - - while ((wdc->sc_flags & WDCF_ACTIVE) != 0) { - wdc->sc_flags |= WDCF_WANTED; - error = tsleep(wdc, PRIBIO | PCATCH, "wdprm", 0); - if (error != 0) { - splx(s); - return error; - } - } - - wdc->sc_flags |= WDCF_ACTIVE; - - if (wdccommandshort(wdc, d_link->sc_drive, WDCC_IDENTIFY) != 0 || - wait_for_drq(wdc) != 0) { - /* - * We `know' there's a drive here; just assume it's old. - * This geometry is only used to read the MBR and print a - * (false) attach message. - */ - strncpy(d_link->sc_lp->d_typename, "ST506", - sizeof d_link->sc_lp->d_typename); - d_link->sc_lp->d_type = DTYPE_ST506; - - strncpy(d_link->sc_params.wdp_model, "ST506/MFM/RLL", - sizeof d_link->sc_params.wdp_model); - d_link->sc_params.wdp_config = WD_CFG_FIXED; - d_link->sc_params.wdp_cylinders = 1024; - d_link->sc_params.wdp_heads = 8; - d_link->sc_params.wdp_sectors = 17; - d_link->sc_params.wdp_maxmulti = 0; - d_link->sc_params.wdp_usedmovsd = 0; - d_link->sc_params.wdp_capabilities = 0; - } else { - strncpy(d_link->sc_lp->d_typename, "ESDI/IDE", - sizeof d_link->sc_lp->d_typename); - d_link->sc_lp->d_type = DTYPE_ESDI; - - /* Read in parameter block. */ - bus_space_read_multi_2(iot, ioh, wd_data, tb, - sizeof(tb) / sizeof(u_int16_t)); - d_link->sc_params.wdp_config = (u_int16_t)tb[0]; - d_link->sc_params.wdp_cylinders = (u_int16_t)tb[1]; - d_link->sc_params.wdp_heads = (u_int16_t)tb[3]; - d_link->sc_params.wdp_unfbytespertrk = (u_int16_t)tb[4]; - d_link->sc_params.wdp_unfbytespersec = (u_int16_t)tb[5]; - d_link->sc_params.wdp_sectors = (u_int16_t)tb[6]; - u_int16_to_string (tb + 7, d_link->sc_params.wdp_vendor1, 6); - u_int16_to_string (tb + 10, d_link->sc_params.wdp_serial, 20); - d_link->sc_params.wdp_buftype = (u_int16_t)tb[20]; - d_link->sc_params.wdp_bufsize = (u_int16_t)tb[21]; - d_link->sc_params.wdp_eccbytes = (u_int16_t)tb[22]; - u_int16_to_string (tb + 23, d_link->sc_params.wdp_revision, 8); - u_int16_to_string (tb + 27, d_link->sc_params.wdp_model, 40); - d_link->sc_params.wdp_maxmulti = (u_int8_t)(tb[47] & 0xff); - d_link->sc_params.wdp_vendor2[0] = (u_int8_t)(tb[47] >> 8 & - 0xff); - d_link->sc_params.wdp_usedmovsd = (u_int16_t)tb[48]; - d_link->sc_params.wdp_vendor3[0] = (u_int8_t)(tb[49] & 0xff); - d_link->sc_params.wdp_capabilities = (u_int8_t)(tb[49] >> 8 & - 0xff); - d_link->sc_params.wdp_vendor4[0] = (u_int8_t)(tb[50] & 0xff); - d_link->sc_params.wdp_piotiming = (u_int8_t)(tb[50] >> 8 & - 0xff); - d_link->sc_params.wdp_vendor5[0] = (u_int8_t)(tb[51] & 0xff); - d_link->sc_params.wdp_dmatiming = (u_int8_t)(tb[51] >> 8 & - 0xff); - d_link->sc_params.wdp_capvalid = (u_int16_t)tb[53]; - d_link->sc_params.wdp_curcyls = (u_int16_t)tb[54]; - d_link->sc_params.wdp_curheads = (u_int16_t)tb[55]; - d_link->sc_params.wdp_cursectors = (u_int16_t)tb[56]; - d_link->sc_params.wdp_curcapacity = ((u_int32_t)tb[58] << 16) + tb[57]; - d_link->sc_params.wdp_curmulti = (u_int8_t)(tb[59] & 0xff); - d_link->sc_params.wdp_valmulti = (u_int8_t)(tb[59] >> 8 & 0xff); - d_link->sc_params.wdp_lbacapacity = ((u_int32_t)tb[61] << 16) + tb[60]; - d_link->sc_params.wdp_dma1word = (u_int16_t)tb[62]; - d_link->sc_params.wdp_dmamword = (u_int16_t)tb[63]; - d_link->sc_params.wdp_eidepiomode = (u_int16_t)tb[64]; - d_link->sc_params.wdp_eidedmamin = (u_int16_t)tb[65]; - d_link->sc_params.wdp_eidedmatime = (u_int16_t)tb[66]; - d_link->sc_params.wdp_eidepiotime = (u_int16_t)tb[67]; - d_link->sc_params.wdp_eidepioiordy = (u_int16_t)tb[68]; - } - - /* Clear any leftover interrupt. */ - (void) bus_space_read_1(iot, ioh, wd_status); - - /* Restart the queue. */ - WDDEBUG_PRINT(("wdcstart from wdc_get_parms flags %d\n", - wdc->sc_flags)); - wdc->sc_flags &= ~WDCF_ACTIVE; - wdcstart(wdc); - - splx(s); - return 0; -} - -/* - * Implement operations needed before read/write. - * Returns 0 if operation still in progress, 1 if completed. - */ -int -wdccontrol(d_link) - struct wd_link *d_link; -{ - struct wdc_softc *wdc = (void *)d_link->wdc_softc; - bus_space_tag_t iot = wdc->sc_iot; - bus_space_handle_t ioh = wdc->sc_ioh; - - WDDEBUG_PRINT(("wdccontrol\n")); - - switch (d_link->sc_state) { - case RECAL: /* Set SDH, step rate, do recal. */ - if (wdccommandshort(wdc, d_link->sc_drive, WDCC_RECAL) != 0) { - wderror(d_link, NULL, "wdccontrol: recal failed (1)"); - goto bad; - } - d_link->sc_state = RECAL_WAIT; - break; - - case RECAL_WAIT: - if (wdc->sc_status & WDCS_ERR) { - wderror(d_link, NULL, "wdccontrol: recal failed (2)"); - goto bad; - } - /* fall through */ - - case GEOMETRY: - if ((d_link->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) - goto multimode; - if (wdsetctlr(d_link) != 0) { - /* Already printed a message. */ - goto bad; - } - d_link->sc_state = GEOMETRY_WAIT; - break; - - case GEOMETRY_WAIT: - if (wdc->sc_status & WDCS_ERR) { - wderror(d_link, NULL, "wdccontrol: geometry failed"); - goto bad; - } - /* fall through */ - - case MULTIMODE: - multimode: - if (d_link->sc_mode != WDM_PIOMULTI) - goto ready; - bus_space_write_1(iot, ioh, wd_seccnt, d_link->sc_multiple); - if (wdccommandshort(wdc, d_link->sc_drive, - WDCC_SETMULTI) != 0) { - wderror(d_link, NULL, - "wdccontrol: setmulti failed (1)"); - goto bad; - } - d_link->sc_state = MULTIMODE_WAIT; - break; - - case MULTIMODE_WAIT: - if (wdc->sc_status & WDCS_ERR) { - wderror(d_link, NULL, - "wdccontrol: setmulti failed (2)"); - goto bad; - } - /* fall through */ - - case READY: - ready: - d_link->sc_state = READY; - /* - * The rest of the initialization can be done by normal means. - */ - return 1; - - bad: - wdcunwedge(wdc); - return 0; - } - - wdc->sc_flags |= WDCF_IRQ_WAIT; - timeout(wdctimeout, wdc, WAITTIME); - return 0; -} -#endif /* NWD */ - -int -wait_for_phase(wdc, wphase) - struct wdc_softc *wdc; - int wphase; -{ - bus_space_tag_t iot = wdc->sc_iot; - bus_space_handle_t ioh = wdc->sc_ioh; - int i, phase; - - for (i = 20000; i; i--) { - phase = (bus_space_read_1(iot, ioh, wd_ireason) & - (WDCI_CMD | WDCI_IN)) | - (bus_space_read_1(iot, ioh, wd_status) - & WDCS_DRQ); - if (phase == wphase) - break; - delay(10); - } - return (phase); -} - -int -wait_for_unphase(wdc, wphase) - struct wdc_softc *wdc; - int wphase; -{ - bus_space_tag_t iot = wdc->sc_iot; - bus_space_handle_t ioh = wdc->sc_ioh; - int i, phase; - - for (i = 20000; i; i--) { - phase = (bus_space_read_1(iot, ioh, wd_ireason) & - (WDCI_CMD | WDCI_IN)) | - (bus_space_read_1(iot, ioh, wd_status) - & WDCS_DRQ); - if (phase != wphase) - break; - delay(10); - } - return (phase); -} - -#if NATAPIBUS > 0 -void -wdc_atapi_start(wdc, xfer) - struct wdc_softc *wdc; - struct wdc_xfer *xfer; -{ - bus_space_tag_t iot = wdc->sc_iot; - bus_space_handle_t ioh = wdc->sc_ioh; - struct atapi_command_packet *acp = xfer->atapi_cmd; - -#ifdef ATAPI_DEBUG_WDC - printf("wdc_atapi_start, acp flags %lx\n",acp->flags); -#endif - if (xfer->c_errors >= WDIORETRIES) { - acp->status |= ERROR; - acp->error = bus_space_read_1(iot, ioh, wd_error); - wdc_atapi_done(wdc, xfer); - return; - } - if (wait_for_unbusy(wdc) != 0) { - if ((wdc->sc_status & WDCS_ERR) == 0) { - printf("wdc_atapi_start: not ready, st = %02x\n", - wdc->sc_status); - acp->status = ERROR; - return; - } - } - - if (wdccommand((struct wd_link*)xfer->d_link, ATAPI_PACKET_COMMAND, - acp->drive, acp->data_size, 0, 0, 0) != 0) { - printf("wdc_atapi_start: can't send atapi paket command\n"); - acp->status = ERROR; - wdc->sc_flags |= WDCF_IRQ_WAIT; - return; - } - if ((acp->flags & (ACAP_DRQ_INTR|ACAP_DRQ_ACCEL)) != ACAP_DRQ_INTR) { - if (!(wdc->sc_flags & WDCF_BROKENPOLL)) { - int phase = wait_for_phase(wdc, PHASE_CMDOUT); - - if (phase != PHASE_CMDOUT) { - printf("wdc_atapi_start: timeout waiting " - "PHASE_CMDOUT, got 0x%x\n", phase); - - /* NEC SUCKS. */ - wdc->sc_flags |= WDCF_BROKENPOLL; - } - } else - DELAY(10); /* Simply pray for the data. */ - - bus_space_write_raw_multi_2(iot, ioh, wd_data, acp->command, - acp->command_size); - } - wdc->sc_flags |= WDCF_IRQ_WAIT; - -#ifdef ATAPI_DEBUG2 - printf("wdc_atapi_start: timeout\n"); -#endif - timeout(wdctimeout, wdc, WAITTIME); - return; -} - -int -wdc_atapi_get_params(ab_link, drive, id) - struct bus_link *ab_link; - u_int8_t drive; - struct atapi_identify *id; -{ - struct wdc_softc *wdc = (void*)ab_link->wdc_softc; - bus_space_tag_t iot = wdc->sc_iot; - bus_space_handle_t ioh = wdc->sc_ioh; - int status, len, excess = 0; - int s, error; - - if (wdc->d_link[drive] != 0) { -#ifdef ATAPI_DEBUG_PROBE - printf("wdc_atapi_get_params: WD drive %d\n", drive); - -#endif - return 0; - } - - /* - * If there is only one ATAPI slave on the bus, don't probe - * drive 0 (master) - */ - - if ((wdc->sc_flags & WDCF_ONESLAVE) && (drive != 1)) - return 0; - -#ifdef ATAPI_DEBUG_PROBE - printf("wdc_atapi_get_params: probing drive %d\n", drive); -#endif - - /* - * XXX - * The locking done here, and the length of time this may keep the rest - * of the system suspended, is a kluge. This should be rewritten to - * set up a transfer and queue it through wdstart(), but it's called - * infrequently enough that this isn't a pressing matter. - */ - - s = splbio(); - - while ((wdc->sc_flags & WDCF_ACTIVE) != 0) { - wdc->sc_flags |= WDCF_WANTED; - if ((error = tsleep(wdc, PRIBIO | PCATCH, "atprm", 0)) != 0) { - splx(s); - return error; - } - } - - wdc->sc_flags |= WDCF_ACTIVE; - error = 1; - (void)wdcreset(wdc, WDCRESET_VERBOSE); - if ((status = wdccommand((struct wd_link*)ab_link, - ATAPI_SOFT_RESET, drive, 0, 0, 0, 0)) != 0) { -#ifdef ATAPI_DEBUG - printf("wdc_atapi_get_params: ATAPI_SOFT_RESET" - "failed for drive %d: status %d error %d\n", - drive, status, wdc->sc_error); -#endif - error = 0; - goto end; - } - if ((status = wait_for_unbusy(wdc)) != 0) { -#ifdef ATAPI_DEBUG - printf("wdc_atapi_get_params: wait_for_unbusy failed " - "for drive %d: status %d error %d\n", - drive, status, wdc->sc_error); -#endif - error = 0; - goto end; - } - - if (wdccommand((struct wd_link*)ab_link, ATAPI_IDENTIFY_DEVICE, - drive, sizeof(struct atapi_identify), 0, 0, 0) != 0 || - atapi_ready(wdc) != 0) { -#ifdef ATAPI_DEBUG_PROBE - printf("ATAPI_IDENTIFY_DEVICE failed for drive %d\n", drive); -#endif - error = 0; - goto end; - } - len = bus_space_read_1(iot, ioh, wd_cyl_lo) + 256 * - bus_space_read_1(iot, ioh, wd_cyl_hi); - if (len != sizeof(struct atapi_identify)) { - if (len < 142) { /* XXX */ - printf("%s: drive %d returned %d/%d of identify device data, device unusuable\n", - wdc->sc_dev.dv_xname, drive, len, - sizeof(struct atapi_identify)); - - error = 0; - goto end; - } - - excess = (len - sizeof(struct atapi_identify)); - if (excess < 0) - excess = 0; - } - bus_space_read_raw_multi_2(iot, ioh, wd_data, (u_int8_t *)id, - sizeof(struct atapi_identify)); - wdcbit_bucket(wdc, excess); - - end: /* Restart the queue. */ - WDDEBUG_PRINT(("wdcstart from wdc_atapi_get_params flags %d\n", - wdc->sc_flags)); - wdc->sc_flags &= ~WDCF_ACTIVE; - wdcstart(wdc); - splx(s); - return error; -} - -void -wdc_atapi_send_command_packet(ab_link, acp) - struct bus_link *ab_link; - struct atapi_command_packet *acp; -{ - struct wdc_softc *wdc = (void*)ab_link->wdc_softc; - bus_space_tag_t iot = wdc->sc_iot; - bus_space_handle_t ioh = wdc->sc_ioh; - bus_space_handle_t ioh_ctl = wdc->sc_ioh_ctl; - struct wdc_xfer *xfer; - u_int8_t flags = acp->flags & 0xff; - - if (flags & A_POLLED) { /* Must use the queue and wdc_atapi_start */ - struct wdc_xfer xfer_s; - int i, phase; - -#ifdef ATAPI_DEBUG_WDC - printf("wdc_atapi_send_cmd: " - "flags %ld drive %d cmdlen %d datalen %d", - acp->flags, acp->drive, acp->command_size, acp->data_size); -#endif - xfer = &xfer_s; - bzero(xfer, sizeof(xfer_s)); - xfer->c_flags = C_INUSE|C_ATAPI|acp->flags; - xfer->d_link = (struct wd_link *)ab_link; - xfer->c_link = ab_link->ctlr_link; - xfer->c_bp = acp->bp; - xfer->atapi_cmd = acp; - xfer->c_blkno = 0; - xfer->databuf = acp->databuf; - xfer->c_bcount = acp->data_size; - if (wait_for_unbusy (wdc) != 0) { - if ((wdc->sc_status & WDCS_ERR) == 0) { - printf("wdc_atapi_send_command: not ready, " - "st = %02x\n", wdc->sc_status); - acp->status = ERROR; - return; - } - } - - /* Turn off interrupts. */ - bus_space_write_1(iot, ioh_ctl, wd_ctlr, WDCTL_4BIT|WDCTL_IDS); - delay(1000); - - if (wdccommand((struct wd_link*)ab_link, - ATAPI_PACKET_COMMAND, acp->drive, acp->data_size, - 0, 0, 0) != 0) { - printf("can't send atapi paket command\n"); - acp->status = ERROR; - return; - } - - /* Wait for cmd i/o phase. */ - phase = wait_for_phase(wdc, PHASE_CMDOUT); - if (phase != PHASE_CMDOUT) - printf("wdc_atapi_send_command_packet: " - "got wrong phase (0x%x) wanted cmd I/O\n", - phase); - - bus_space_write_raw_multi_2(iot, ioh, wd_data, acp->command, - acp->command_size); - - /* Wait for data i/o phase. */ - phase = wait_for_unphase(wdc, PHASE_CMDOUT); - if (phase == PHASE_CMDOUT) - printf("wdc_atapi_send_command_packet: " - "got wrong phase (0x%x) wanted data I/O\n", - phase); - - while (wdc_atapi_intr(wdc, xfer)) { - for (i = 2000; i > 0; --i) { - if ((bus_space_read_1(iot, ioh, wd_status) & - WDCS_DRQ) == 0) - break; - delay(10); - } -#ifdef ATAPI_DEBUG_WDC - printf("wdc_atapi_send_command_packet: i = %d\n", i); -#endif - } - - /* Turn on interrupts again. */ - bus_space_write_1(iot, ioh_ctl, wd_ctlr, WDCTL_4BIT); - delay(1000); - - wdc->sc_flags &= ~(WDCF_IRQ_WAIT | WDCF_SINGLE | WDCF_ERROR); - xfer->c_errors = 0; - xfer->c_skip = 0; - return; - } else { /* POLLED */ - xfer = wdc_get_xfer(ab_link->ctlr_link, - flags & A_NOSLEEP ? IDE_NOSLEEP : 0); - if (xfer == NULL) { - acp->status = ERROR; - return; - } - xfer->c_flags |= C_ATAPI|acp->flags; - xfer->d_link = (struct wd_link*) ab_link; - xfer->c_link = ab_link->ctlr_link; - xfer->c_bp = acp->bp; - xfer->atapi_cmd = acp; - xfer->c_blkno = 0; - xfer->databuf = acp->databuf; - xfer->c_bcount = acp->data_size; - wdc_exec_xfer((struct wd_link*)ab_link,xfer); - return; - } -} - -int -wdc_atapi_intr(wdc, xfer) - struct wdc_softc *wdc; - struct wdc_xfer *xfer; -{ - bus_space_tag_t iot = wdc->sc_iot; - bus_space_handle_t ioh = wdc->sc_ioh; - struct atapi_command_packet *acp = xfer->atapi_cmd; - int len, phase, i, retries = 0; - int err, st, ire; - - if (wait_for_unbusy(wdc) < 0) { - printf("wdc_atapi_intr: controller busy\n"); - acp->status = ERROR; - acp->error = bus_space_read_1(iot, ioh, wd_error); - return 0; - } - -#ifdef ATAPI_DEBUG2 - printf("wdc_atapi_intr: %s\n", wdc->sc_dev.dv_xname); -#endif - -again: - len = bus_space_read_1(iot, ioh, wd_cyl_lo) + - 256 * bus_space_read_1(iot, ioh, wd_cyl_hi); - - st = bus_space_read_1(iot, ioh, wd_status); - err = bus_space_read_1(iot, ioh, wd_error); - ire = bus_space_read_1(iot, ioh, wd_ireason); - - phase = (ire & (WDCI_CMD | WDCI_IN)) | (st & WDCS_DRQ); -#ifdef ATAPI_DEBUG_WDC - printf("wdc_atapi_intr: len %d st %d err %d ire %d :", - len, st, err, ire); -#endif - switch (phase) { - case PHASE_CMDOUT: - /* send packet command */ -#ifdef ATAPI_DEBUG_WDC - printf("PHASE_CMDOUT\n"); -#endif - -#ifdef ATAPI_DEBUG_WDC - { - int i; - char *c = (char *)acp->command; - - printf("wdc_atapi_intr: cmd "); - for (i = 0; i < acp->command_size; i++) - printf("0x%x ", c[i]); - printf("\n"); - } -#endif - - wdc->sc_flags |= WDCF_IRQ_WAIT; - bus_space_write_raw_multi_2(iot, ioh, wd_data, acp->command, - acp->command_size); - return 1; - - case PHASE_DATAOUT: - /* write data */ -#ifdef ATAPI_DEBUG_WDC - printf("PHASE_DATAOUT\n"); -#endif - if ((acp->flags & (B_READ|B_WRITE)) != B_WRITE) { - printf("wdc_atapi_intr: bad data phase\n"); - acp->status = ERROR; - return 1; - } - wdc->sc_flags |= WDCF_IRQ_WAIT; - if (xfer->c_bcount < len) { - printf("wdc_atapi_intr: warning: write only " - "%d of %d requested bytes\n", xfer->c_bcount, len); - bus_space_write_raw_multi_2(iot, ioh, wd_data, - xfer->databuf + xfer->c_skip, xfer->c_bcount); - for (i = xfer->c_bcount; i < len; - i += sizeof(u_int16_t)) - bus_space_write_2(iot, ioh, wd_data, 0); - xfer->c_bcount = 0; - return 1; - } else { - bus_space_write_raw_multi_2(iot, ioh, wd_data, - xfer->databuf + xfer->c_skip, len); - xfer->c_skip += len; - xfer->c_bcount -= len; - return 1; - } - - case PHASE_DATAIN: - /* Read data */ -#ifdef ATAPI_DEBUG_WDC - printf("PHASE_DATAIN\n"); -#endif - if ((acp->flags & (B_READ|B_WRITE)) != B_READ) { - printf("wdc_atapi_intr: bad data phase\n"); - acp->status = ERROR; - return 1; - } - wdc->sc_flags |= WDCF_IRQ_WAIT; - if (xfer->c_bcount < len) { - printf("wdc_atapi_intr: warning: reading only " - "%d of %d bytes\n", xfer->c_bcount, len); - bus_space_read_raw_multi_2(iot, ioh, wd_data, - xfer->databuf + xfer->c_skip, xfer->c_bcount); - wdcbit_bucket(wdc, len - xfer->c_bcount); - xfer->c_bcount = 0; - return 1; - } else { - bus_space_read_raw_multi_2(iot, ioh, wd_data, - xfer->databuf + xfer->c_skip, len); - xfer->c_skip += len; - xfer->c_bcount -=len; - return 1; - } - - case PHASE_ABORTED: - case PHASE_COMPLETED: -#ifdef ATAPI_DEBUG_WDC - printf("PHASE_COMPLETED\n"); -#endif - if (st & WDCS_ERR) { - acp->error = bus_space_read_1(iot, ioh, wd_error); - acp->status = ERROR; - } -#ifdef ATAPI_DEBUG_WDC - if (xfer->c_bcount != 0) { - printf("wdc_atapi_intr warning: bcount value " - "is %d after io\n", xfer->c_bcount); - } -#endif - break; - - default: - if (++retries < 500) { - DELAY(100); - goto again; - } - printf("wdc_atapi_intr: unknown phase %d\n", phase); - acp->status = ERROR; - } - - wdc_atapi_done(wdc, xfer); - return (0); -} - - -void -wdc_atapi_done(wdc, xfer) - struct wdc_softc *wdc; - struct wdc_xfer *xfer; -{ - struct atapi_command_packet *acp = xfer->atapi_cmd; - int s; - - acp->data_size = xfer->c_bcount; - - s = splbio(); - - /* remove this command from xfer queue */ - xfer->c_skip = 0; - if ((xfer->c_flags & A_POLLED) == 0) { - untimeout(wdctimeout, wdc); - TAILQ_REMOVE(&wdc->sc_xfer, xfer, c_xferchain); - wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR | WDCF_ACTIVE); - wdc_free_xfer(xfer); -#ifdef ATAPI_DEBUG - printf("wdc_atapi_done: atapi_done\n"); -#endif - atapi_done(acp); -#ifdef WDDEBUG - printf("wdcstart from wdc_atapi_intr, flags %d\n", - wdc->sc_flags); -#endif - wdcstart(wdc); - } else - wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR | WDCF_ACTIVE); - - splx(s); -} -#endif /* NATAPIBUS */ - -/* - * 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. - */ -int -wdcintr(arg) - void *arg; -{ - struct wdc_softc *wdc = arg; - struct wdc_xfer *xfer; - - /* - * It appears that some drives are causing the controller to - * interrupt too quickly. It also appears that such drives do not - * conform to the MMC2 specifications. This needs to be fixed - * correctly and the extra check for NULL removed from the following - * if(). - */ - if (((wdc->sc_flags & WDCF_IRQ_WAIT) == 0) - || (wdc->sc_xfer.tqh_first == NULL)) { - bus_space_tag_t iot = wdc->sc_iot; - bus_space_handle_t ioh = wdc->sc_ioh; - u_char s; -#ifdef ATAPI_DEBUG_WDC - u_char e, i; -#endif - DELAY(100); - - /* Clear the pending interrupt and abort. */ - s = bus_space_read_1(iot, ioh, wd_status); - if (s != (WDCS_DRDY|WDCS_DSC)) { -#ifdef ATAPI_DEBUG_WDC - e = bus_space_read_1(iot, ioh, wd_error); - i = bus_space_read_1(iot, ioh, wd_seccnt); - - printf("wdcintr: inactive controller, " - "punting st=%02x er=%02x irr=%02x\n", s, e, i); -#else - bus_space_read_1(iot, ioh, wd_error); - bus_space_read_1(iot, ioh, wd_seccnt); -#endif - - if (s & WDCS_DRQ) { - int len = 256 * bus_space_read_1(iot, ioh, - wd_cyl_hi) + - bus_space_read_1(iot, ioh, wd_cyl_lo); -#ifdef ATAPI_DEBUG_WDC - printf("wdcintr: clearing up %d bytes\n", len); -#endif - wdcbit_bucket(wdc, len); - } - } - return 0; - } - - WDDEBUG_PRINT(("wdcintr\n")); - - wdc->sc_flags &= ~WDCF_IRQ_WAIT; - xfer = wdc->sc_xfer.tqh_first; - if (xfer == NULL) { -#ifdef ATAPI_DEBUG - printf("wdcintr: null xfer\n"); -#endif - return 0; - } -#if NATAPIBUS > 0 && NWD > 0 - if (xfer->c_flags & C_ATAPI) { - (void)wdc_atapi_intr(wdc, xfer); - return 0; - } else - return wdc_ata_intr(wdc, xfer); -#else -#if NATAPIBUS > 0 - (void)wdc_atapi_intr(wdc, xfer); - return 0; -#endif /* NATAPIBUS */ -#if NWD > 0 - return wdc_ata_intr(wdc, xfer); -#endif /* NWD */ -#endif /* NATAPIBUS && NWD */ -} - -int -wdcreset(wdc, mode) - struct wdc_softc *wdc; - enum wdcreset_mode mode; -{ - bus_space_tag_t iot = wdc->sc_iot; - bus_space_handle_t ioh = wdc->sc_ioh; - bus_space_handle_t ioh_ctl = wdc->sc_ioh_ctl; - - /* Reset the device. */ - bus_space_write_1(iot, ioh_ctl, wd_ctlr, WDCTL_RST|WDCTL_IDS); - delay(1000); - bus_space_write_1(iot, ioh_ctl, wd_ctlr, WDCTL_IDS); - delay(1000); - (void) bus_space_read_1(iot, ioh, wd_error); - bus_space_write_1(iot, ioh_ctl, wd_ctlr, WDCTL_4BIT); - - if (wait_for_unbusy(wdc) < 0) { - if (mode != WDCRESET_SILENT) - printf("%s: reset failed\n", wdc->sc_dev.dv_xname); - return 1; - } - - return 0; -} - -void -wdcrestart(arg) - void *arg; -{ - struct wdc_softc *wdc = arg; - int s; - - s = splbio(); - wdcstart(wdc); - splx(s); -} - -/* - * Unwedge the controller after an unexpected error. We do this by resetting - * it, marking all drives for recalibration, and stalling the queue for a short - * period to give the reset time to finish. - * NOTE: We use a timeout here, so this routine must not be called during - * autoconfig or dump. - */ -void -wdcunwedge(wdc) - struct wdc_softc *wdc; -{ - int unit; - -#ifdef ATAPI_DEBUG - printf("wdcunwedge\n"); -#endif - - untimeout(wdctimeout, wdc); - wdc->sc_flags &= ~WDCF_IRQ_WAIT; - (void) wdcreset(wdc, WDCRESET_VERBOSE); - - /* Schedule recalibrate for all drives on this controller. */ - for (unit = 0; unit < 2; unit++) { - if (!wdc->d_link[unit]) continue; - if (wdc->d_link[unit]->sc_state > RECAL) - wdc->d_link[unit]->sc_state = RECAL; - } - - wdc->sc_flags |= WDCF_ERROR; - - /* Wake up in a little bit and restart the operation. */ - WDDEBUG_PRINT(("wdcrestart from wdcunwedge\n")); - wdc->sc_flags &= ~WDCF_ACTIVE; - timeout(wdcrestart, wdc, RECOVERYTIME); -} - -int -wdcwait(wdc, mask) - struct wdc_softc *wdc; - int mask; -{ - bus_space_tag_t iot = wdc->sc_iot; - bus_space_handle_t ioh = wdc->sc_ioh; - int timeout = 0; - u_char status; -#ifdef WDCNDELAY_DEBUG - extern int cold; -#endif - - WDDEBUG_PRINT(("wdcwait\n")); - - for (;;) { - wdc->sc_status = status = bus_space_read_1(iot, ioh, - wd_status); - /* - * If a single slave ATAPI device is attached, it may - * have released the bus. Select it and try again. - */ - if (status == 0xff && wdc->sc_flags & WDCF_ONESLAVE) { - bus_space_write_1(iot, ioh, wd_sdh, - WDSD_IBM | 0x10); - wdc->sc_status = status = bus_space_read_1(iot, ioh, - wd_status); - } - if ((status & WDCS_BSY) == 0 && (status & mask) == mask) - break; - if (++timeout > WDCNDELAY) { -#ifdef ATAPI_DEBUG2 - printf("wdcwait: timeout, status 0x%x\n", status); -#endif - return -1; - } - delay(WDCDELAY); - } - if (status & WDCS_ERR) { - wdc->sc_error = bus_space_read_1(iot, ioh, wd_error); - return WDCS_ERR; - } -#ifdef WDCNDELAY_DEBUG - /* After autoconfig, there should be no long delays. */ - if (!cold && timeout > WDCNDELAY_DEBUG) { - struct wdc_xfer *xfer = wdc->sc_xfer.tqh_first; - if (xfer == NULL) - printf("%s: warning: busy-wait took %dus\n", - wdc->sc_dev.dv_xname, WDCDELAY * timeout); - else - printf("%s(%s): warning: busy-wait took %dus\n", - wdc->sc_dev.dv_xname, - ((struct device*)xfer->d_link->wd_softc)->dv_xname, - WDCDELAY * timeout); - } -#endif - return 0; -} - -void -wdctimeout(arg) - void *arg; -{ - struct wdc_softc *wdc = (struct wdc_softc *)arg; - int s; - - WDDEBUG_PRINT(("wdctimeout\n")); - - s = splbio(); - if ((wdc->sc_flags & WDCF_IRQ_WAIT) != 0) { - wdc->sc_flags &= ~WDCF_IRQ_WAIT; - wdcerror(wdc, "lost interrupt"); - wdcunwedge(wdc); - } else - wdcerror(wdc, "missing untimeout"); - splx(s); -} - -/* - * Wait for the drive to become ready and send a command. - * Return -1 if busy for too long or 0 otherwise. - * Assumes interrupts are blocked. - */ -int -wdccommand(d_link, command, drive, cylin, head, sector, count) - struct wd_link *d_link; - int command; - int drive, cylin, head, sector, count; -{ - struct wdc_softc *wdc = (void*)d_link->wdc_softc; - bus_space_tag_t iot = wdc->sc_iot; - bus_space_handle_t ioh = wdc->sc_ioh; - int stat; - - WDDEBUG_PRINT(("wdccommand drive %d\n", drive)); - -#if defined(DIAGNOSTIC) && defined(WDCDEBUG) - if ((wdc->sc_flags & WDCF_ACTIVE) == 0) - printf("wdccommand: controler not active (drive %d)\n", drive); -#endif - - /* Select drive, head, and addressing mode. */ - bus_space_write_1(iot, ioh, wd_sdh, WDSD_IBM | (drive << 4) | head); - - /* Wait for it to become ready to accept a command. */ - if (command == WDCC_IDP || d_link->type == BUS) - stat = wait_for_unbusy(wdc); - else - stat = wdcwait(wdc, WDCS_DRDY); - - if (stat < 0) { -#ifdef ATAPI_DEBUG - printf("wdcommand: xfer failed (wait_for_unbusy) status %d\n", - stat); -#endif - return -1; - } - - /* Load parameters. */ - if (d_link->type == DRIVE && d_link->sc_lp->d_type == DTYPE_ST506) - bus_space_write_1(iot, ioh, wd_precomp, - d_link->sc_lp->d_precompcyl / 4); - else - bus_space_write_1(iot, ioh, wd_features, 0); - bus_space_write_1(iot, ioh, wd_cyl_lo, cylin); - bus_space_write_1(iot, ioh, wd_cyl_hi, cylin >> 8); - bus_space_write_1(iot, ioh, wd_sector, sector); - bus_space_write_1(iot, ioh, wd_seccnt, count); - - /* Send command. */ - bus_space_write_1(iot, ioh, wd_command, command); - - return 0; -} - -/* - * Simplified version of wdccommand(). - */ -int -wdccommandshort(wdc, drive, command) - struct wdc_softc *wdc; - int drive; - int command; -{ - bus_space_tag_t iot = wdc->sc_iot; - bus_space_handle_t ioh = wdc->sc_ioh; - - WDDEBUG_PRINT(("wdccommandshort\n")); - -#if defined(DIAGNOSTIC) && defined(WDCDEBUG) - if ((wdc->sc_flags & WDCF_ACTIVE) == 0) - printf("wdccommandshort: controller not active (drive %d)\n", - drive); -#endif - - /* Select drive. */ - bus_space_write_1(iot, ioh, wd_sdh, WDSD_IBM|(drive << 4)); - - if (wdcwait(wdc, WDCS_DRDY) < 0) - return -1; - - bus_space_write_1(iot, ioh, wd_command, command); - - return 0; -} - -void -wdc_exec_xfer(d_link, xfer) - struct wd_link *d_link; - struct wdc_xfer *xfer; -{ - struct wdc_softc *wdc = (struct wdc_softc *)d_link->wdc_softc; - int s; - - WDDEBUG_PRINT(("wdc_exec_xfer\n")); - - s = splbio(); - - /* insert at the end of command list */ - TAILQ_INSERT_TAIL(&wdc->sc_xfer,xfer , c_xferchain); - WDDEBUG_PRINT(("wdcstart from wdc_exec_xfer, flags %d\n", - wdc->sc_flags)); - wdcstart(wdc); - splx(s); -} - -struct wdc_xfer * -wdc_get_xfer(c_link,flags) - struct wdc_link *c_link; - int flags; -{ - struct wdc_xfer *xfer; - int s; - - s = splbio(); - if ((xfer = xfer_free_list.lh_first) != NULL) { - LIST_REMOVE(xfer, free_list); - splx(s); -#ifdef DIAGNOSTIC - if ((xfer->c_flags & C_INUSE) != 0) - panic("wdc_get_xfer: xfer already in use"); -#endif - } else { - splx(s); -#ifdef ATAPI_DEBUG - printf("wdc:making xfer %d\n",wdc_nxfer); -#endif - xfer = malloc(sizeof(*xfer), M_DEVBUF, - ((flags & IDE_NOSLEEP) != 0 ? M_NOWAIT : M_WAITOK)); - if (xfer == NULL) - return 0; - -#ifdef DIAGNOSTIC - xfer->c_flags &= ~C_INUSE; -#endif -#ifdef ATAPI_DEBUG - wdc_nxfer++; -#endif - } -#ifdef DIAGNOSTIC - if ((xfer->c_flags & C_INUSE) != 0) - panic("wdc_get_xfer: xfer already in use"); -#endif - bzero(xfer, sizeof(struct wdc_xfer)); - xfer->c_flags = C_INUSE; - xfer->c_link = c_link; - return xfer; -} - -void -wdc_free_xfer(xfer) - struct wdc_xfer *xfer; -{ - int s; - - s = splbio(); - xfer->c_flags &= ~C_INUSE; - LIST_INSERT_HEAD(&xfer_free_list, xfer, free_list); - splx(s); -} - -void -wdcerror(wdc, msg) - struct wdc_softc *wdc; - char *msg; -{ - struct wdc_xfer *xfer = wdc->sc_xfer.tqh_first; - if (xfer == NULL) - printf("%s: %s\n", wdc->sc_dev.dv_xname, msg); - else - printf("%s(%s): %s\n", wdc->sc_dev.dv_xname, - ((struct device*)xfer->d_link->wd_softc)->dv_xname, msg); -} - -/* - * the bit bucket - */ -void -wdcbit_bucket(wdc, size) - struct wdc_softc *wdc; - int size; -{ - bus_space_tag_t iot = wdc->sc_iot; - bus_space_handle_t ioh = wdc->sc_ioh; - int i; - - for (i = 0 ; i < size / 2 ; i++) { - u_int16_t null; - - bus_space_read_multi_2(iot, ioh, wd_data, &null, 1); - } - - if (size % 2) - bus_space_read_1(iot, ioh, wd_data); -} diff --git a/sys/dev/isa/wdlink.h b/sys/dev/isa/wdlink.h deleted file mode 100644 index 7f69a2d5cf9..00000000000 --- a/sys/dev/isa/wdlink.h +++ /dev/null @@ -1,160 +0,0 @@ -/* $OpenBSD: wdlink.h,v 1.10 1998/08/08 23:01:11 downsj Exp $ */ - -/* - * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. - * - * DMA and multi-sector PIO handling are derived from code contributed by - * Onno van der Linden. - * - * Atapi support added by Manuel Bouyer. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Charles M. Hannum. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* #undef WDDEBUG */ -/* #undef DIAGNOSTIC */ - -#include "wd.h" - -struct wdc_link { - int flags; - int openings; -}; - -struct wdc_softc { - struct device sc_dev; - void *sc_ih; - struct wd_link *d_link[2]; - struct bus_link *ab_link; - struct wdc_link ctlr_link; - bus_space_tag_t sc_iot; - bus_space_handle_t sc_ioh; - bus_space_handle_t sc_ioh_ctl; - int sc_drq; /* DMA channel */ - - TAILQ_HEAD(xferhead, wdc_xfer) sc_xfer; - int sc_flags; -#define WDCF_ACTIVE 0x01 /* controller is active */ -#define WDCF_SINGLE 0x02 /* sector at a time mode */ -#define WDCF_ERROR 0x04 /* processing a disk error */ -#define WDCF_WANTED 0x08 /* XXX locking for wd_get_parms() */ -#define WDCF_IRQ_WAIT 0x10 /* controller is waiting for irq */ -#define WDCF_ONESLAVE 0x20 /* ctrl. has one ATAPI slave attached */ -#define WDCF_BROKENPOLL 0x40 /* or, generally fucked up */ - u_char sc_status; /* copy of status register */ - u_char sc_error; /* copy of error register */ -}; - -struct wd_link { - u_char type; -#define DRIVE 0 -#define BUS 1 - caddr_t wdc_softc; - caddr_t wd_softc; - struct wdc_link *ctlr_link; - struct wdparams sc_params; - - /* Long-term state: */ - u_int8_t openings; - int sc_drive; /* physical unit number */ - int sc_state; /* control state */ -#define RECAL 0 /* recalibrate */ -#define RECAL_WAIT 1 /* done recalibrating */ -#define GEOMETRY 2 /* upload geometry */ -#define GEOMETRY_WAIT 3 /* done uploading geometry */ -#define MULTIMODE 4 /* set multiple mode */ -#define MULTIMODE_WAIT 5 /* done setting multiple mode */ -#define READY 6 /* done with open */ - int sc_mode; /* transfer mode */ -#define WDM_PIOSINGLE 0 /* single-sector PIO */ -#define WDM_PIOMULTI 1 /* multi-sector PIO */ -#define WDM_DMA 2 /* DMA */ - int sc_multiple; /* multiple for WDM_PIOMULTI */ - int sc_flags; /* drive characteistics found */ -#define WDF_LOCKED 0x01 -#define WDF_WANTED 0x02 -#define WDF_WLABEL 0x04 /* label is writable */ -#define WDF_LABELLING 0x08 /* writing label */ - -/* - * XXX Nothing resets this yet, but disk change sensing will when ATAPI is - * implemented. - */ -#define WDF_LOADED 0x10 /* parameters loaded */ -#define WDF_32BIT 0x20 /* can do 32-bit transfer */ -#define WDF_WAIT 0x40 /* waiting for resourses */ - - daddr_t sc_badsect[127]; /* 126 plus trailing -1 marker */ - struct disklabel *sc_lp; /* label info for this disk */ -}; - -struct wdc_xfer { - struct wdc_link *c_link; /* controller structure info */ - struct wd_link *d_link; /* drive/bus structure info */ - volatile int c_flags; /* handle also B_READ and B_WRITE */ -#define C_INUSE 0x01 -#define C_ATAPI 0x02 -#define C_ERROR 0x04 - - /* Information about the current transfer */ - struct buf *c_bp; - void *atapi_cmd; - void *databuf; - daddr_t c_blkno; /* starting block number */ - int c_bcount; /* byte count left */ - int c_skip; /* bytes already transferred */ - int c_nblks; /* number of blocks currently transferring */ - int c_nbytes; /* number of bytes currently transferring */ - u_int32_t c_p_offset; /* offset of the partition */ - int c_errors; /* errors during current transfer */ - TAILQ_ENTRY(wdc_xfer) c_xferchain; - LIST_ENTRY(wdc_xfer) free_list; -}; - -void wdc_exec_xfer __P((struct wd_link *, struct wdc_xfer *)); -struct wdc_xfer *wdc_get_xfer __P((struct wdc_link *, int)); -int wdc_get_parms __P((struct wd_link *)); -int wdccommandshort __P((struct wdc_softc *, int, int)); -int wdcwait __P((struct wdc_softc *, int)); -int wdccommand __P((struct wd_link *, int, int, int, int, int, int)); - -#if NWD > 0 -void wderror __P((struct wd_link* , struct buf *, char *)); -int wdsetctlr __P((struct wd_link *)); -void wdstart __P((void *)); -void wddone __P((struct wd_link*, struct buf*)); -#endif /* NWD */ - -/* - * ST506 spec says that if READY or SEEKCMPLT go off, then the read or write - * command is aborted. - */ -#define wait_for_drq(d) wdcwait(d, WDCS_DRDY | WDCS_DSC | WDCS_DRQ) -#define wait_for_unbusy(d) wdcwait(d, 0) -#define wait_for_ready(d) wdcwait(d, WDCS_DRDY | WDCS_DSC) -#define atapi_ready(d) wdcwait(d, WDCS_DRQ) - -#define IDE_NOSLEEP 0x01 diff --git a/sys/dev/isa/wdreg.h b/sys/dev/isa/wdreg.h deleted file mode 100644 index 9def532b136..00000000000 --- a/sys/dev/isa/wdreg.h +++ /dev/null @@ -1,211 +0,0 @@ -/* $OpenBSD: wdreg.h,v 1.8 1998/08/08 23:01:12 downsj Exp $ */ -/* $NetBSD: wdreg.h,v 1.13 1995/03/29 21:56:46 briggs Exp $ */ - -/*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * William Jolitz. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)wdreg.h 7.1 (Berkeley) 5/9/91 - */ - -/* - * Disk Controller register definitions. - */ -#define wd_data 0x000 /* data register (R/W - 16 bits) */ -#define wd_error 0x001 /* error register (R) */ -#define wd_precomp 0x001 /* write precompensation (W) */ -#define wd_features 0x001 /* features (W) */ -#define wd_seccnt 0x002 /* sector count (R/W) */ -#define wd_ireason 0x002 /* interrupt reason (R/W) (for atapi) */ -#define wd_sector 0x003 /* first sector number (R/W) */ -#define wd_cyl_lo 0x004 /* cylinder address, low byte (R/W) */ -#define wd_cyl_hi 0x005 /* cylinder address, high byte (R/W) */ -#define wd_sdh 0x006 /* sector size/drive/head (R/W) */ -#define wd_command 0x007 /* command register (W) */ -#define wd_status 0x007 /* immediate status (R) */ - -/* - * Control register definiations. - */ -#define WDCTL_OFFSET 0x206 /* offset from the first set. */ - -#define wd_altsts 0x000 /* alternate fixed disk status (via 1015) (R) */ -#define wd_ctlr 0x000 /* fixed disk controller control (via 1015) (W) */ -#define WDCTL_4BIT 0x08 /* use four head bits (wd1003) */ -#define WDCTL_RST 0x04 /* reset the controller */ -#define WDCTL_IDS 0x02 /* disable controller interrupts */ -#if 0 -#define wd_digin 0x001 /* disk controller input (via 1015) (R) */ -#endif - -/* - * Status bits. - */ -#define WDCS_BSY 0x80 /* busy */ -#define WDCS_DRDY 0x40 /* drive ready */ -#define WDCS_DWF 0x20 /* drive write fault */ -#define WDCS_DSC 0x10 /* drive seek complete */ -#define WDCS_DRQ 0x08 /* data request */ -#define WDCS_CORR 0x04 /* corrected data */ -#define WDCS_IDX 0x02 /* index */ -#define WDCS_ERR 0x01 /* error */ -#define WDCS_BITS "\020\010bsy\007drdy\006dwf\005dsc\004drq\003corr\002idx\001err" - -/* - * Error bits. - */ -#define WDCE_BBK 0x80 /* bad block detected */ -#define WDCE_UNC 0x40 /* uncorrectable data error */ -#define WDCE_MC 0x20 /* media changed */ -#define WDCE_IDNF 0x10 /* id not found */ -#define WDCE_ABRT 0x08 /* aborted command */ -#define WDCE_MCR 0x04 /* media change requested */ -#define WDCE_TK0NF 0x02 /* track 0 not found */ -#define WDCE_AMNF 0x01 /* address mark not found */ -#define WDERR_BITS "\020\010bbk\007unc\006mc\005idnf\004mcr\003abrt\002tk0nf\001amnf" - -/* - * Commands for Disk Controller. - */ -#define WDCC_RECAL 0x10 /* disk restore code -- resets cntlr */ - -#define WDCC_READ 0x20 /* disk read code */ -#define WDCC_WRITE 0x30 /* disk write code */ -#define WDCC__LONG 0x02 /* modifier -- access ecc bytes */ -#define WDCC__NORETRY 0x01 /* modifier -- no retrys */ - -#define WDCC_FORMAT 0x50 /* disk format code */ -#define WDCC_DIAGNOSE 0x90 /* controller diagnostic */ -#define WDCC_IDP 0x91 /* initialize drive parameters */ - -#define WDCC_READMULTI 0xc4 /* read multiple */ -#define WDCC_WRITEMULTI 0xc5 /* write multiple */ -#define WDCC_SETMULTI 0xc6 /* set multiple mode */ - -#define WDCC_READDMA 0xc8 /* read with DMA */ -#define WDCC_WRITEDMA 0xca /* write with DMA */ - -#define WDCC_ACKMC 0xdb /* acknowledge media change */ -#define WDCC_LOCK 0xde /* lock drawer */ -#define WDCC_UNLOCK 0xdf /* unlock drawer */ - -#define WDCC_IDENTIFY 0xec /* read parameters from controller */ -#define WDCC_CACHEC 0xef /* cache control */ - -#define WDSD_IBM 0xa0 /* forced to 512 byte sector, ecc */ -#define WDSD_CHS 0x00 /* cylinder/head/sector addressing */ -#define WDSD_LBA 0x40 /* logical block addressing */ - -/* Commands for ATAPI devices */ -#define ATAPI_CHECK_POWER_MODE 0xe5 -#define ATAPI_EXEC_DRIVE_DIAGS 0x90 -#define ATAPI_IDLE_IMMEDIATE 0xe1 -#define ATAPI_NOP 0x00 -#define ATAPI_PACKET_COMMAND 0xa0 -#define ATAPI_IDENTIFY_DEVICE 0xa1 -#define ATAPI_SOFT_RESET 0x08 -#define ATAPI_SET_FEATURES 0xef -#define ATAPI_SLEEP 0xe6 -#define ATAPI_STANDBY_IMMEDIATE 0xe0 - -/* ireason */ -#define WDCI_CMD 0x01 /* command(1) or data(0) */ -#define WDCI_IN 0x02 /* transfer to(1) or from(0) the host */ -#define WDCI_RELEASE 0x04 /* bus released until completion */ - -#define PHASE_CMDOUT (WDCS_DRQ | WDCI_CMD) -#define PHASE_DATAIN (WDCS_DRQ | WDCI_IN) -#define PHASE_DATAOUT WDCS_DRQ -#define PHASE_COMPLETED (WDCI_IN | WDCI_CMD) -#define PHASE_ABORTED 0 - - -#if defined(_KERNEL) && !defined(_LOCORE) -/* - * read parameters command returns this: - */ -struct wdparams { - u_int16_t wdp_config; /* general configuration */ -#define WD_CFG_REMOVABLE 0x0080 -#define WD_CFG_FIXED 0x0040 - u_int16_t wdp_cylinders; /* number of non-removable cylinders */ - u_int8_t __reserved1[2]; - u_int16_t wdp_heads; /* number of heads */ - u_int16_t wdp_unfbytespertrk; /* number of unformatted bytes/track */ - u_int16_t wdp_unfbytespersec; /* number of unformatted bytes/sector */ - u_int16_t wdp_sectors; /* number of sectors */ - u_int8_t wdp_vendor1[6]; - u_int8_t wdp_serial[20]; /* serial number */ - u_int16_t wdp_buftype; /* buffer type */ -#define WD_BUF_SINGLEPORTSECTOR 1 /* single port, single sector buffer */ -#define WD_BUF_DUALPORTMULTI 2 /* dual port, multiple sector buffer */ -#define WD_BUF_DUALPORTMULTICACHE 3 /* above plus track cache */ - u_int16_t wdp_bufsize; /* buffer size, in 512-byte units */ - u_int16_t wdp_eccbytes; /* ecc bytes appended */ - u_int8_t wdp_revision[8]; /* firmware revision */ - u_int8_t wdp_model[40]; /* model name */ - u_int8_t wdp_maxmulti; /* maximum sectors per interrupt */ - u_int8_t wdp_vendor2[1]; - u_int16_t wdp_usedmovsd; /* can use double word read/write? */ - u_int8_t wdp_vendor3[1]; - u_int8_t wdp_capabilities; /* capability flags */ -#define WD_CAP_DMA 0x01 -#define WD_CAP_LBA 0x02 -#define WD_CAP_IORDYSW 0x04 -#define WD_CAP_IODRYSUP 0x08 - u_int8_t __reserved2[2]; - u_int8_t wdp_vendor4[1]; - u_int8_t wdp_piotiming; /* PIO timing mode */ - u_int8_t wdp_vendor5[1]; - u_int8_t wdp_dmatiming; /* DMA timing mode */ - u_int16_t wdp_capvalid; /* valid capabilities */ - u_int16_t wdp_curcyls; /* logical cylinders */ - u_int16_t wdp_curheads; /* logical heads */ - u_int16_t wdp_cursectors; /* logical sectors per track */ - u_int32_t wdp_curcapacity; /* logical total sectors on drive */ - u_int8_t wdp_curmulti; /* current multiple sector count */ - u_int8_t wdp_valmulti; /* multiple sector is valid */ -#define WD_CAP_MULTI 0x01 - u_int32_t wdp_lbacapacity; /* total number of sectors */ - u_int16_t wdp_dma1word; /* single-word dma info */ - u_int16_t wdp_dmamword; /* multiple-word dma info */ - u_int16_t wdp_eidepiomode; /* EIDE PIO mode */ -#define WD_CAP_PIO3 0x01 -#define WD_CAP_PIO4 0x02 - u_int16_t wdp_eidedmamin; /* min mword dma cycle time (ns) */ - u_int16_t wdp_eidedmatime; /* rec'd mword dma cycle time (ns) */ - u_int16_t wdp_eidepiotime; /* min cycle time (ns), no IORDY */ - u_int16_t wdp_eidepioiordy; /* min cycle time (ns), with IORDY */ -}; -#endif /* _KERNEL && !_LOCORE*/ |