home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-06-06 | 193.7 KB | 7,081 lines |
- diff --exclude compile -bcrNP src.orig/sys/arch/i386/conf/GENERIC src/sys/arch/i386/conf/GENERIC
- *** src.orig/sys/arch/i386/conf/GENERIC Tue May 21 13:28:55 1996
- --- src/sys/arch/i386/conf/GENERIC Thu Jun 6 16:59:30 1996
- ***************
- *** 158,165 ****
- mcd0 at isa? port 0x300 irq 10 # Mitsumi CD-ROM drives
-
- wdc0 at isa? port 0x1f0 irq 14 # ST506, ESDI, and IDE controllers
- ! #wdc1 at isa? port 0x170 irq ?
- wd* at wdc? drive ?
-
- wt0 at isa? port 0x300 irq 5 drq 1 # Archive and Wangtek QIC tape drives
-
- --- 158,167 ----
- mcd0 at isa? port 0x300 irq 10 # Mitsumi CD-ROM drives
-
- wdc0 at isa? port 0x1f0 irq 14 # ST506, ESDI, and IDE controllers
- ! wdc1 at isa? port 0x170 irq 15
- wd* at wdc? drive ?
- + atapibus* at wdc?
- + acd* at atapibus? drive?
-
- wt0 at isa? port 0x300 irq 5 drq 1 # Archive and Wangtek QIC tape drives
-
- diff --exclude compile -bcrNP src.orig/sys/arch/i386/conf/GENERICADP src/sys/arch/i386/conf/GENERICADP
- *** src.orig/sys/arch/i386/conf/GENERICADP Tue May 21 13:28:55 1996
- --- src/sys/arch/i386/conf/GENERICADP Thu Jun 6 16:59:36 1996
- ***************
- *** 144,151 ****
- mcd0 at isa? port 0x300 irq 10 # Mitsumi CD-ROM drives
-
- wdc0 at isa? port 0x1f0 irq 14 # ST506, ESDI, and IDE controllers
- ! #wdc1 at isa? port 0x170 irq ?
- wd* at wdc? drive ?
-
- wt0 at isa? port 0x300 irq 5 drq 1 # Archive and Wangtek QIC tape drives
-
- --- 144,153 ----
- mcd0 at isa? port 0x300 irq 10 # Mitsumi CD-ROM drives
-
- wdc0 at isa? port 0x1f0 irq 14 # ST506, ESDI, and IDE controllers
- ! wdc1 at isa? port 0x170 irq 15
- wd* at wdc? drive ?
- + atapibus* at wdc?
- + acd* at atapibus? drive?
-
- wt0 at isa? port 0x300 irq 5 drq 1 # Archive and Wangtek QIC tape drives
-
- diff --exclude compile -bcrNP src.orig/sys/arch/i386/conf/GENERICOTHER src/sys/arch/i386/conf/GENERICOTHER
- *** src.orig/sys/arch/i386/conf/GENERICOTHER Tue May 21 13:28:55 1996
- --- src/sys/arch/i386/conf/GENERICOTHER Thu Jun 6 16:59:44 1996
- ***************
- *** 149,156 ****
- mcd0 at isa? port 0x300 irq 10 # Mitsumi CD-ROM drives
-
- wdc0 at isa? port 0x1f0 irq 14 # ST506, ESDI, and IDE controllers
- ! #wdc1 at isa? port 0x170 irq ?
- wd* at wdc? drive ?
-
- wt0 at isa? port 0x300 irq 5 drq 1 # Archive and Wangtek QIC tape drives
-
- --- 149,158 ----
- mcd0 at isa? port 0x300 irq 10 # Mitsumi CD-ROM drives
-
- wdc0 at isa? port 0x1f0 irq 14 # ST506, ESDI, and IDE controllers
- ! wdc1 at isa? port 0x170 irq 15
- wd* at wdc? drive ?
- + atapibus* at wdc?
- + acd* at atapibus? drive?
-
- wt0 at isa? port 0x300 irq 5 drq 1 # Archive and Wangtek QIC tape drives
-
- diff --exclude compile -bcrNP src.orig/sys/arch/i386/conf/files.i386 src/sys/arch/i386/conf/files.i386
- *** src.orig/sys/arch/i386/conf/files.i386 Tue May 7 13:26:13 1996
- --- src/sys/arch/i386/conf/files.i386 Thu Jun 6 12:21:57 1996
- ***************
- *** 47,52 ****
- --- 47,57 ----
- major {rd = 17}
-
- #
- + # Machine-independent ATAPI drivers
- + #
- + include "../../../atapi/files.atapi"
- +
- + #
- # System bus types
- #
-
- diff --exclude compile -bcrNP src.orig/sys/arch/i386/i386/conf.c src/sys/arch/i386/i386/conf.c
- *** src.orig/sys/arch/i386/i386/conf.c Sat May 4 13:47:01 1996
- --- src/sys/arch/i386/i386/conf.c Thu Jun 6 12:24:31 1996
- ***************
- *** 56,61 ****
- --- 56,63 ----
- bdev_decl(st);
- #include "cd.h"
- bdev_decl(cd);
- + #include "acd.h"
- + bdev_decl(acd);
- #include "mcd.h"
- bdev_decl(mcd);
- #include "vnd.h"
- ***************
- *** 88,93 ****
- --- 90,96 ----
- bdev_disk_init(NSCD,scd), /* 15: Sony CD-ROM */
- bdev_disk_init(NCCD,ccd), /* 16: concatenated disk driver */
- bdev_disk_init(NRD,rd), /* 17: ram disk driver */
- + bdev_disk_init(NACD,acd), /* 18: ATAPI CD-ROM */
- };
- int nblkdev = sizeof(bdevsw) / sizeof(bdevsw[0]);
-
- ***************
- *** 145,150 ****
- --- 148,154 ----
- #include "ss.h"
- cdev_decl(ss);
- cdev_decl(cd);
- + cdev_decl(acd);
- #include "lpt.h"
- cdev_decl(lpt);
- #include "ch.h"
- ***************
- *** 202,208 ****
- cdev_disk_init(NCCD,ccd), /* 18: concatenated disk driver */
- cdev_ss_init(NSS,ss), /* 19: SCSI scanner */
- cdev_notdef(), /* 20 */
- ! cdev_notdef(), /* 21 */
- cdev_fd_init(1,filedesc), /* 22: file descriptor pseudo-device */
- cdev_bpftun_init(NBPFILTER,bpf),/* 23: Berkeley packet filter */
- cdev_notdef(), /* 24 */
- --- 206,212 ----
- cdev_disk_init(NCCD,ccd), /* 18: concatenated disk driver */
- cdev_ss_init(NSS,ss), /* 19: SCSI scanner */
- cdev_notdef(), /* 20 */
- ! cdev_disk_init(NACD,acd), /* 21: ATAPI CD-ROM */
- cdev_fd_init(1,filedesc), /* 22: file descriptor pseudo-device */
- cdev_bpftun_init(NBPFILTER,bpf),/* 23: Berkeley packet filter */
- cdev_notdef(), /* 24 */
- diff --exclude compile -bcrNP src.orig/sys/atapi/acd.c src/sys/atapi/acd.c
- *** src.orig/sys/atapi/acd.c Thu Jan 1 01:00:00 1970
- --- src/sys/atapi/acd.c Tue Apr 23 21:11:46 1996
- ***************
- *** 0 ****
- --- 1,1293 ----
- + /*
- + * Copyright (c) 1996 Manuel Bouyer. All rights reserved.
- + *
- + * 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 Manuel Bouyer.
- + * 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 <sys/types.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/errno.h>
- + #include <sys/device.h>
- + #include <sys/disklabel.h>
- + #include <sys/disk.h>
- + #include <sys/cdio.h>
- + #include <sys/proc.h>
- +
- + #include <atapi/atapilink.h>
- + #include <atapi/atapi.h>
- +
- + #define CDUNIT(z) DISKUNIT(z)
- + #define CDPART(z) DISKPART(z)
- + #define MAKECDDEV(maj, unit, part) MAKEDISKDEV(maj, unit, part)
- +
- + struct acd_softc {
- + struct device sc_dev;
- + struct disk sc_dk;
- +
- + int flags;
- + #define CDF_LOCKED 0x01
- + #define CDF_WANTED 0x02
- + #define CDF_WLABEL 0x04 /* label is writable */
- + #define CDF_LABELLING 0x08 /* writing label */
- + struct at_dev_link *ad_link; /* contains our drive number, etc ... */
- + struct cd_parms {
- + int blksize;
- + u_long disksize; /* total number sectors */
- + } params;
- + struct buf buf_queue;
- + };
- +
- + int acdmatch __P((struct device *, void *, void *));
- + void acdattach __P((struct device *, struct device *, void *));
- +
- + struct cfattach acd_ca = {
- + sizeof(struct acd_softc), acdmatch, acdattach
- + };
- +
- + struct cfdriver acd_cd = {
- + NULL, "acd", DV_DISK
- + };
- +
- + void acdgetdisklabel __P((struct acd_softc *));
- + int acd_get_parms __P((struct acd_softc *, int));
- + void acdstrategy __P((struct buf *));
- + void acdstart __P((struct acd_softc *));
- + int acd_pause __P((struct acd_softc *, int));
- + void acdminphys __P((struct buf*));
- + u_long acd_size __P((struct acd_softc*, int));
- + int acddone __P((struct atapi_command_packet *));
- +
- + struct dkdriver acddkdriver = { acdstrategy };
- +
- + int
- + acdmatch(parent, match, aux)
- + struct device *parent;
- + void *match, *aux;
- + {
- + struct cfdata *cf = match;
- + struct at_dev_link *sa = aux;
- + #ifdef ATAPI_DEBUG_PROBE
- + printf("acdmatch: device %d\n",sa->id.config.device_type);
- + #endif
- + if (sa->id.config.device_type == ATAPI_DEVICE_TYPE_CD) return 1;
- + return 0;
- +
- + }
- +
- + /*
- + * The routine called by the low level atapi routine when it discovers
- + * A device suitable for this driver
- + */
- + void
- + acdattach(parent, self, aux)
- + struct device *parent, *self;
- + void *aux;
- + {
- + struct acd_softc *acd = (void *)self;
- + struct at_dev_link *sa = aux;
- + struct mode_sense cmd;
- + struct cappage cap;
- +
- + sa->device_softc = acd;
- + sa->start = acdstart;
- + sa->done = acddone;
- + sa->flags |= ADEV_REMOVABLE;
- + sa->openings = 1;
- + acd->ad_link = sa;
- +
- + /*
- + * Initialize and attach the disk structure.
- + */
- + acd->sc_dk.dk_driver = &acddkdriver;
- + acd->sc_dk.dk_name = acd->sc_dev.dv_xname;
- + disk_attach(&acd->sc_dk);
- +
- + #if !defined(i386) || defined(NEWCONFIG)
- + dk_establish(&acd->sc_dk, &acd->sc_dev);
- + #endif
- +
- + (void)atapi_test_unit_ready(sa, A_POLLED | A_SILENT);
- + delay(1000);
- + (void)atapi_test_unit_ready(sa, A_POLLED | A_SILENT);
- + /* To clear media change, etc ...*/
- + bzero(&cmd, sizeof(cmd));
- + cmd.operation_code = ATAPI_MODE_SENSE;
- + cmd.page_code = CAP_PAGE;
- + cmd.length[0] = sizeof (cap) >> 8;
- + cmd.length[1] = sizeof (cap);
- + if (atapi_exec_cmd(sa, &cmd , sizeof(cmd), &cap, sizeof(cap),
- + B_READ, A_POLLED) != 0) {
- + printf("atapi_exec_cmd failed\n");
- + return;
- + }
- + switch (cap.medium_type) {
- + case MDT_UNKNOWN: printf ("medium type unknown");
- + break;
- + case MDT_DATA_120: printf ("120mm data disc ");
- + break;
- + case MDT_AUDIO_120: printf ("120mm audio disc ");
- + break;
- + case MDT_COMB_120: printf ("120mm data/audio disc ");
- + break;
- + case MDT_PHOTO_120: printf ("120mm photo disc ");
- + break;
- + case MDT_DATA_80: printf ("80mm data disc ");
- + break;
- + case MDT_AUDIO_80: printf ("80mm audio disc ");
- + break;
- + case MDT_COMB_80: printf ("80mm data/audio disc ");
- + break;
- + case MDT_PHOTO_80: printf ("80mm photo disc ");
- + break;
- + case MDT_NO_DISC: printf ("drive empty ");
- + break;
- + case MDT_DOOR_OPEN: printf ("door open");
- + break;
- + case MDT_FMT_ERROR: printf ("medium format error");
- + break;
- + default: printf ("unknown medium type=0x%x", cap.medium_type);
- + break;
- + }
- + printf("\n");
- +
- + }
- +
- + /*
- + * Wait interruptibly for an exclusive lock.
- + *
- + * XXX
- + * Several drivers do this; it should be abstracted and made MP-safe.
- + */
- + int
- + acdlock(acd)
- + struct acd_softc *acd;
- + {
- + int error;
- +
- + while ((acd->flags & CDF_LOCKED) != 0) {
- + acd->flags |= CDF_WANTED;
- + if ((error = tsleep(acd, PRIBIO | PCATCH, "acdlck", 0)) != 0)
- + return error;
- + }
- + acd->flags |= CDF_LOCKED;
- + return 0;
- + }
- +
- + /*
- + * Unlock and wake up any waiters.
- + */
- + void
- + acdunlock(acd)
- + struct acd_softc *acd;
- + {
- +
- + acd->flags &= ~CDF_LOCKED;
- + if ((acd->flags & CDF_WANTED) != 0) {
- + acd->flags &= ~CDF_WANTED;
- + wakeup(acd);
- + }
- + }
- +
- + /*
- + * open the device. Make sure the partition info is a up-to-date as can be.
- + */
- + int
- + acdopen(dev, flag, fmt)
- + dev_t dev;
- + int flag, fmt;
- + {
- + struct acd_softc *acd;
- + struct at_dev_link *ad_link;
- + int unit, part;
- + int error;
- +
- + #ifdef ACD_DEBUG
- + printf("acd: open\n");
- + #endif
- +
- + unit = CDUNIT(dev);
- + if (unit >= acd_cd.cd_ndevs)
- + return ENXIO;
- + acd = acd_cd.cd_devs[unit];
- + if (!acd)
- + return ENXIO;
- +
- + ad_link = acd->ad_link;
- +
- + if ((error = atapi_test_unit_ready(ad_link,0)) != 0) {
- + if (error != UNIT_ATTENTION) return EIO;
- + if ((ad_link->flags & ADEV_OPEN) != 0 ) return EIO;
- + }
- +
- + if (error = acdlock(acd))
- + return error;
- +
- + if (acd->sc_dk.dk_openmask != 0) {
- + /*
- + * If any partition is open, but the disk has been invalidated,
- + * disallow further opens.
- + */
- + if ((ad_link->flags & ADEV_MEDIA_LOADED) == 0) {
- + error = EIO;
- + goto bad3;
- + }
- + } else {
- + ad_link->flags |= ADEV_OPEN;
- +
- + /* Lock the pack in. */
- + if (error = atapi_prevent(ad_link, PR_PREVENT))
- + goto bad;
- +
- + if ((ad_link->flags & ADEV_MEDIA_LOADED) == 0) {
- + ad_link->flags |= ADEV_MEDIA_LOADED;
- +
- + /* Load the physical device parameters. */
- + if (acd_get_parms(acd, 0) != 0) {
- + error = ENXIO;
- + goto bad2;
- + }
- +
- + /* Fabricate a disk label. */
- + acdgetdisklabel(acd);
- + }
- + }
- +
- + part = CDPART(dev);
- +
- + /* Check that the partition exists. */
- + if (part != RAW_PART &&
- + (part >= acd->sc_dk.dk_label->d_npartitions ||
- + acd->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:
- + acd->sc_dk.dk_copenmask |= (1 << part);
- + break;
- + case S_IFBLK:
- + acd->sc_dk.dk_bopenmask |= (1 << part);
- + break;
- + }
- + acd->sc_dk.dk_openmask = acd->sc_dk.dk_copenmask | acd->sc_dk.dk_bopenmask;
- + #ifdef ACD_DEBUG
- + printf("open complete\n");
- + #endif
- + acdunlock(acd);
- + return 0;
- +
- + bad2:
- + ad_link->flags &= ~ADEV_MEDIA_LOADED;
- +
- + bad:
- + if (acd->sc_dk.dk_openmask == 0) {
- + atapi_prevent(ad_link, PR_ALLOW);
- + ad_link->flags &= ~ADEV_OPEN;
- + }
- +
- + bad3:
- + acdunlock(acd);
- + return error;
- + }
- +
- + /*
- + * close the device.. only called if we are the LAST
- + * occurence of an open device
- + */
- + int
- + acdclose(dev, flag, fmt)
- + dev_t dev;
- + int flag, fmt;
- + {
- + struct acd_softc *acd = acd_cd.cd_devs[CDUNIT(dev)];
- + int part = CDPART(dev);
- + int error;
- +
- + if (error = acdlock(acd))
- + return error;
- +
- + switch (fmt) {
- + case S_IFCHR:
- + acd->sc_dk.dk_copenmask &= ~(1 << part);
- + break;
- + case S_IFBLK:
- + acd->sc_dk.dk_bopenmask &= ~(1 << part);
- + break;
- + }
- + acd->sc_dk.dk_openmask = acd->sc_dk.dk_copenmask | acd->sc_dk.dk_bopenmask;
- +
- + if (acd->sc_dk.dk_openmask == 0) {
- + /* XXXX Must wait for I/O to complete! */
- +
- + atapi_prevent(acd->ad_link, PR_ALLOW);
- + acd->ad_link->flags &= ~ADEV_OPEN;
- + }
- +
- + acdunlock(acd);
- + return 0;
- + }
- +
- + /*
- + * Actually translate the requested transfer into one the physical driver can
- + * understand. The transfer is described by a buf and will include only one
- + * physical transfer.
- + */
- + void
- + acdstrategy(bp)
- + struct buf *bp;
- + {
- + struct acd_softc *acd = acd_cd.cd_devs[CDUNIT(bp->b_dev)];
- + int opri;
- +
- + #ifdef ACD_DEBUG
- + printf("acdstrategy\n");
- + #endif
- +
- + /*
- + * The transfer must be a whole number of blocks.
- + */
- + if ((bp->b_bcount % acd->sc_dk.dk_label->d_secsize) != 0) {
- + bp->b_error = EINVAL;
- + goto bad;
- + }
- + if ((bp->b_flags & (B_READ|B_WRITE)) == B_WRITE) {
- + bp->b_error = EROFS;
- + goto bad;
- + }
- + /*
- + * If the device has been made invalid, error out
- + * maybe the media changed
- + */
- + if ((acd->ad_link->flags & ADEV_MEDIA_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 (CDPART(bp->b_dev) != RAW_PART &&
- + bounds_check_with_label(bp, acd->sc_dk.dk_label,
- + (acd->flags & (CDF_WLABEL|CDF_LABELLING)) != 0) <= 0)
- + goto done;
- +
- + opri = splbio();
- +
- + /*
- + * Place it in the queue of disk activities for this disk
- + */
- + disksort(&acd->buf_queue, bp);
- +
- + /*
- + * Tell the device to get going on the transfer if it's
- + * not doing anything, otherwise just wait for completion
- + */
- + acdstart(acd);
- +
- + splx(opri);
- + return;
- +
- + bad:
- + bp->b_flags |= B_ERROR;
- + done:
- + /*
- + * Correctly set the buf to indicate a completed xfer
- + */
- + bp->b_resid = bp->b_bcount;
- + biodone(bp);
- + }
- +
- + /*
- + * acdstart looks to see if there is a buf waiting for the device
- + * and that the device is not already busy. If both are true,
- + * It deques the buf and creates a atapi command to perform the
- + * transfer in the buf. The transfer request will call atapi_done
- + * on completion, which will in turn call this routine again
- + * so that the next queued transfer is performed.
- + * The bufs are queued by the strategy routine (cdstrategy)
- + *
- + * This routine is also called after other non-queued requests
- + * have been made of the atapi driver, to ensure that the queue
- + * continues to be drained.
- + *
- + * must be called at the correct (highish) spl level
- + * cdstart() is called at splbio from cdstrategy and atapi_done
- + */
- + void
- + acdstart(acd)
- + struct acd_softc *acd;
- + {
- + struct at_dev_link *ad_link;
- + struct buf *bp = 0;
- + struct buf *dp;
- + struct read cmd;
- + u_int32_t blkno, nblks;
- + struct partition *p;
- +
- + #ifdef ACD_DEBUG
- + printf("acd: acdstart\n");
- + if (acd == NULL) {
- + printf("acdstart: null acd\n");
- + return;
- + }
- + #endif
- +
- + ad_link = acd->ad_link;
- + #ifdef ACD_DEBUG
- + if (ad_link == NULL) {
- + printf("acdstart: null ad_link\n");
- + return;
- + }
- + #endif
- + /*
- + * Check if the device has room for another command
- + */
- + while (ad_link->openings >0 ) {
- + /*
- + * there is excess capacity, but a special waits
- + * It'll need the adapter as soon as we clear out of the
- + * way and let it run (user level wait).
- + */
- + if (ad_link->flags & ADEV_WAITING) {
- + #ifdef ATAPI_DEBUG
- + printf("acdstart: waking up\n");
- + #endif
- + ad_link->flags &= ~ADEV_WAITING;
- + wakeup((caddr_t)ad_link);
- + return;
- + }
- +
- + /*
- + * See if there is a buf with work for us to do..
- + */
- + dp = &acd->buf_queue;
- + #ifdef ACD_DEBUG
- + if (dp == NULL) {
- + printf("acdstart: null dp\n");
- + return;
- + }
- + #endif
- + if ((bp = dp->b_actf) == NULL) /* yes, an assign */
- + return;
- + #ifdef ACD_DEBUG
- + printf("acdstart: a buf\n");
- + #endif
- + dp->b_actf = bp->b_actf;
- +
- + /*
- + * If the device has become invalid, abort all the
- + * reads and writes until all files have been closed and
- + * re-opened
- + */
- + if ((ad_link->flags & ADEV_MEDIA_LOADED) == 0) {
- + bp->b_error = EIO;
- + bp->b_flags |= B_ERROR;
- + biodone(bp);
- + continue;
- + }
- +
- + /*
- + *
- + * First, translate the block to absolute and put it in terms
- + * of the logical blocksize of the device.
- + */
- + blkno =
- + bp->b_blkno / (acd->sc_dk.dk_label->d_secsize / DEV_BSIZE);
- + if (CDPART(bp->b_dev) != RAW_PART) {
- + p = &acd->sc_dk.dk_label->d_partitions[CDPART(bp->b_dev)];
- + blkno += p->p_offset;
- + }
- + nblks = howmany(bp->b_bcount, acd->sc_dk.dk_label->d_secsize);
- + #ifdef ACD_DEBUG
- + printf("acdstart: blkno %d nblk %d\n",blkno, nblks);
- + #endif
- +
- + /*
- + * Fill out the atapi command
- + */
- + bzero(&cmd, sizeof(cmd));
- + cmd.operation_code = ATAPI_READ;
- + cmd.lba[0] = (blkno >> 24) & 0xff;
- + cmd.lba[1] = (blkno >> 16) & 0xff;
- + cmd.lba[2] = (blkno >> 8) & 0xff;
- + cmd.lba[3] = blkno & 0xff;
- + cmd.length[0] = (nblks >> 8) & 0xff;
- + cmd.length[1] = nblks & 0xff;
- +
- + /* Instrumentation. */
- + disk_busy(&acd->sc_dk);
- +
- + /*
- + * Call the routine that chats with the adapter.
- + * Note: we cannot sleep as we may be an interrupt
- + */
- +
- + if (atapi_exec_io(ad_link, &cmd, sizeof(cmd), bp, A_NOSLEEP))
- + printf("%s: not queued", acd->sc_dev.dv_xname);
- + }
- + }
- +
- + int
- + acdread(dev, uio)
- + dev_t dev;
- + struct uio *uio;
- + {
- +
- + return (physio(acdstrategy, NULL, dev, B_READ,
- + acdminphys, uio));
- + }
- +
- + int
- + acdwrite(dev, uio)
- + dev_t dev;
- + struct uio *uio;
- + {
- +
- + return (physio(acdstrategy, NULL, dev, B_WRITE,
- + acdminphys, uio));
- + }
- +
- + /*
- + * Perform special action on behalf of the user.
- + * Knows about the internals of this device
- + */
- + int
- + acdioctl(dev, cmd, addr, flag, p)
- + dev_t dev;
- + u_long cmd;
- + caddr_t addr;
- + int flag;
- + struct proc *p;
- + {
- + struct acd_softc *acd = acd_cd.cd_devs[CDUNIT(dev)];
- + int error;
- +
- + /*
- + * If the device is not valid.. abandon ship
- + */
- + if ((acd->ad_link->flags & ADEV_MEDIA_LOADED) == 0)
- + return EIO;
- +
- + switch (cmd) {
- + case DIOCGDINFO:
- + *(struct disklabel *)addr = *acd->sc_dk.dk_label;
- + return 0;
- +
- + case DIOCGPART:
- + ((struct partinfo *)addr)->disklab = acd->sc_dk.dk_label;
- + ((struct partinfo *)addr)->part =
- + &acd->sc_dk.dk_label->d_partitions[CDPART(dev)];
- + return 0;
- +
- + case DIOCWDINFO:
- + case DIOCSDINFO:
- + if ((flag & FWRITE) == 0)
- + return EBADF;
- +
- + if (error = acdlock(acd))
- + return error;
- + acd->flags |= CDF_LABELLING;
- +
- + error = setdisklabel(acd->sc_dk.dk_label,
- + (struct disklabel *)addr, /*acd->sc_dk.dk_openmask : */0,
- + acd->sc_dk.dk_cpulabel);
- + if (error == 0) {
- + }
- +
- + acd->flags &= ~CDF_LABELLING;
- + acdunlock(acd);
- + return error;
- +
- + case DIOCWLABEL:
- + return EBADF;
- +
- + case CDIOCPLAYTRACKS:
- + #ifdef notyet
- + {
- + struct ioc_play_track *args = (struct ioc_play_track *)addr;
- + struct acd_mode_data data;
- + if (error = acd_get_mode(acd, &data, AUDIO_PAGE))
- + return error;
- + data.page.audio.flags &= ~CD_PA_SOTC;
- + data.page.audio.flags |= CD_PA_IMMED;
- + if (error = acd_set_mode(acd, &data))
- + return error;
- + return acd_play_tracks(acd, args->start_track, args->start_index,
- + args->end_track, args->end_index);
- + }
- + #else
- + return ENOTTY;
- + #endif
- + case CDIOCPLAYMSF:
- + #ifdef notyet
- + {
- + struct ioc_play_msf *args
- + = (struct ioc_play_msf *)addr;
- + struct cd_mode_data data;
- + if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
- + return error;
- + data.page.audio.flags &= ~CD_PA_SOTC;
- + data.page.audio.flags |= CD_PA_IMMED;
- + if (error = cd_set_mode(cd, &data))
- + return error;
- + return cd_play_msf(cd, args->start_m, args->start_s,
- + args->start_f, args->end_m, args->end_s, args->end_f);
- + }
- + #else
- + return ENOTTY;
- + #endif
- + case CDIOCPLAYBLOCKS:
- + #ifdef notyet
- + {
- + struct ioc_play_blocks *args
- + = (struct ioc_play_blocks *)addr;
- + struct cd_mode_data data;
- + if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
- + return error;
- + data.page.audio.flags &= ~CD_PA_SOTC;
- + data.page.audio.flags |= CD_PA_IMMED;
- + if (error = cd_set_mode(cd, &data))
- + return error;
- + return cd_play(cd, args->blk, args->len);
- + }
- + #else
- + return ENOTTY;
- + #endif
- + case CDIOCREADSUBCHANNEL:
- + #ifdef notyet
- + {
- + struct ioc_read_subchannel *args
- + = (struct ioc_read_subchannel *)addr;
- + struct cd_sub_channel_info data;
- + int len = args->data_len;
- + if (len > sizeof(data) ||
- + len < sizeof(struct cd_sub_channel_header))
- + return EINVAL;
- + if (error = cd_read_subchannel(cd, args->address_format,
- + args->data_format, args->track, &data, len))
- + return error;
- + len = min(len, ((data.header.data_len[0] << 8) +
- + data.header.data_len[1] +
- + sizeof(struct cd_sub_channel_header)));
- + return copyout(&data, args->data, len);
- + }
- + #else
- + return ENOTTY;
- + #endif
- + case CDIOREADTOCHEADER:
- + #ifdef notyet
- + {
- + struct ioc_toc_header th;
- + if (error = cd_read_toc(cd, 0, 0, &th, sizeof(th)))
- + return error;
- + th.len = ntohs(th.len);
- + bcopy(&th, addr, sizeof(th));
- + return 0;
- + }
- + #else
- + return ENOTTY;
- + #endif
- + case CDIOREADTOCENTRYS:
- + #ifdef notyet
- + {
- + struct cd_toc {
- + struct ioc_toc_header header;
- + struct cd_toc_entry entries[65];
- + } data;
- + struct ioc_read_toc_entry *te =
- + (struct ioc_read_toc_entry *)addr;
- + struct ioc_toc_header *th;
- + int len = te->data_len;
- + th = &data.header;
- +
- + if (len > sizeof(data.entries) ||
- + len < sizeof(struct cd_toc_entry))
- + return EINVAL;
- + if (error = cd_read_toc(cd, te->address_format,
- + te->starting_track, (struct cd_toc_entry *)&data,
- + len + sizeof(struct ioc_toc_header)))
- + return error;
- + len = min(len, ntohs(th->len) - (sizeof(th->starting_track) +
- + sizeof(th->ending_track)));
- + return copyout(data.entries, te->data, len);
- + }
- + #else
- + return ENOTTY;
- + #endif
- + case CDIOCSETPATCH:
- + #ifdef notyet
- + {
- + struct ioc_patch *arg = (struct ioc_patch *)addr;
- + struct cd_mode_data data;
- + if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
- + return error;
- + data.page.audio.port[LEFT_PORT].channels = arg->patch[0];
- + data.page.audio.port[RIGHT_PORT].channels = arg->patch[1];
- + data.page.audio.port[2].channels = arg->patch[2];
- + data.page.audio.port[3].channels = arg->patch[3];
- + return cd_set_mode(cd, &data);
- + }
- + #else
- + return ENOTTY;
- + #endif
- + case CDIOCGETVOL:
- + #ifdef notyet
- + {
- + struct ioc_vol *arg = (struct ioc_vol *)addr;
- + struct cd_mode_data data;
- + if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
- + return error;
- + arg->vol[LEFT_PORT] = data.page.audio.port[LEFT_PORT].volume;
- + arg->vol[RIGHT_PORT] = data.page.audio.port[RIGHT_PORT].volume;
- + arg->vol[2] = data.page.audio.port[2].volume;
- + arg->vol[3] = data.page.audio.port[3].volume;
- + return 0;
- + }
- + #else
- + return ENOTTY;
- + #endif
- + case CDIOCSETVOL:
- + #ifdef notyet
- + {
- + struct ioc_vol *arg = (struct ioc_vol *)addr;
- + struct cd_mode_data data;
- + if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
- + return error;
- + data.page.audio.port[LEFT_PORT].channels = CHANNEL_0;
- + data.page.audio.port[LEFT_PORT].volume = arg->vol[LEFT_PORT];
- + data.page.audio.port[RIGHT_PORT].channels = CHANNEL_1;
- + data.page.audio.port[RIGHT_PORT].volume = arg->vol[RIGHT_PORT];
- + data.page.audio.port[2].volume = arg->vol[2];
- + data.page.audio.port[3].volume = arg->vol[3];
- + return cd_set_mode(cd, &data);
- + }
- + #else
- + return ENOTTY;
- + #endif
- + case CDIOCSETMONO:
- + #ifdef notyet
- + {
- + struct ioc_vol *arg = (struct ioc_vol *)addr;
- + struct cd_mode_data data;
- + if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
- + return error;
- + data.page.audio.port[LEFT_PORT].channels =
- + LEFT_CHANNEL | RIGHT_CHANNEL | 4 | 8;
- + data.page.audio.port[RIGHT_PORT].channels =
- + LEFT_CHANNEL | RIGHT_CHANNEL;
- + data.page.audio.port[2].channels = 0;
- + data.page.audio.port[3].channels = 0;
- + return cd_set_mode(cd, &data);
- + }
- + #else
- + return ENOTTY;
- + #endif
- + case CDIOCSETSTEREO:
- + #ifdef notyet
- + {
- + struct ioc_vol *arg = (struct ioc_vol *)addr;
- + struct cd_mode_data data;
- + if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
- + return error;
- + data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL;
- + data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL;
- + data.page.audio.port[2].channels = 0;
- + data.page.audio.port[3].channels = 0;
- + return cd_set_mode(cd, &data);
- + }
- + #else
- + return ENOTTY;
- + #endif
- + case CDIOCSETMUTE:
- + #ifdef notyet
- + {
- + struct ioc_vol *arg = (struct ioc_vol *)addr;
- + struct cd_mode_data data;
- + if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
- + return error;
- + data.page.audio.port[LEFT_PORT].channels = 0;
- + data.page.audio.port[RIGHT_PORT].channels = 0;
- + data.page.audio.port[2].channels = 0;
- + data.page.audio.port[3].channels = 0;
- + return cd_set_mode(cd, &data);
- + }
- + #else
- + return ENOTTY;
- + #endif
- + case CDIOCSETLEFT:
- + #ifdef notyet
- + {
- + struct ioc_vol *arg = (struct ioc_vol *)addr;
- + struct cd_mode_data data;
- + if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
- + return error;
- + data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL;
- + data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL;
- + data.page.audio.port[2].channels = 0;
- + data.page.audio.port[3].channels = 0;
- + return cd_set_mode(cd, &data);
- + }
- + #else
- + return ENOTTY;
- + #endif
- + case CDIOCSETRIGHT:
- + #ifdef notyet
- + {
- + struct ioc_vol *arg = (struct ioc_vol *)addr;
- + struct cd_mode_data data;
- + if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
- + return error;
- + data.page.audio.port[LEFT_PORT].channels = RIGHT_CHANNEL;
- + data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL;
- + data.page.audio.port[2].channels = 0;
- + data.page.audio.port[3].channels = 0;
- + return cd_set_mode(cd, &data);
- + }
- + #else
- + return ENOTTY;
- + #endif
- + case CDIOCRESUME:
- + return acd_pause(acd, 1);
- + case CDIOCPAUSE:
- + return acd_pause(acd, 0);
- + case CDIOCSTART:
- + return atapi_start_stop(acd->ad_link, SSS_START, 0);
- + case CDIOCSTOP:
- + return atapi_start_stop(acd->ad_link, SSS_STOP, 0);
- + case CDIOCEJECT: /* FALLTHROUGH */
- + case DIOCEJECT:
- + return atapi_start_stop(acd->ad_link, SSS_STOP|SSS_LOEJ, 0);
- + case CDIOCALLOW:
- + return atapi_prevent(acd->ad_link, PR_ALLOW);
- + case CDIOCPREVENT:
- + return atapi_prevent(acd->ad_link, PR_PREVENT);
- + case DIOCLOCK:
- + return atapi_prevent(acd->ad_link,
- + (*(int *)addr) ? PR_PREVENT : PR_ALLOW);
- + case CDIOCRESET:
- + return acd_reset(acd);
- + default:
- + return ENOTTY;
- + }
- +
- + #ifdef DIAGNOSTIC
- + panic("cdioctl: impossible");
- + #endif
- + }
- +
- + /*
- + * Load the label information on the named device
- + * Actually fabricate a disklabel
- + *
- + * EVENTUALLY take information about different
- + * data tracks from the TOC and put it in the disklabel
- + */
- + void
- + acdgetdisklabel(acd)
- + struct acd_softc *acd;
- + {
- + struct disklabel *lp = acd->sc_dk.dk_label;
- +
- + bzero(lp, sizeof(struct disklabel));
- + bzero(acd->sc_dk.dk_cpulabel, sizeof(struct cpu_disklabel));
- +
- + /* lp->d_secsize = acd->params.blksize; /* XXX */
- + lp->d_secsize = 2048;
- + lp->d_ntracks = 1;
- + lp->d_nsectors = 100;
- + lp->d_ncylinders = (acd->params.disksize / 100) + 1;
- + lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
- +
- + strncpy(lp->d_typename, "ATAPI CD-ROM", 16);
- + lp->d_type = DTYPE_SCSI; /* XXX */
- + strncpy(lp->d_packname, "fictitious", 16);
- + lp->d_secperunit = acd->params.disksize;
- + lp->d_rpm = 300;
- + lp->d_interleave = 1;
- + lp->d_flags = D_REMOVABLE;
- +
- + lp->d_partitions[0].p_offset = 0;
- + lp->d_partitions[0].p_size =
- + lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
- + lp->d_partitions[0].p_fstype = FS_ISO9660;
- + 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_ISO9660;
- + lp->d_npartitions = RAW_PART + 1;
- +
- + lp->d_magic = DISKMAGIC;
- + lp->d_magic2 = DISKMAGIC;
- + lp->d_checksum = dkcksum(lp);
- + }
- +
- + /*
- + * Find out from the device what it's capacity is
- + */
- + u_long
- + acd_size(cd, flags)
- + struct acd_softc *cd;
- + int flags;
- + {
- + struct read_cd_capacity_data rdcap;
- + struct read_cd_capacity cmd;
- + u_long blksize;
- + u_long size;
- +
- + /*
- + * make up a atapi command and ask the atapi driver to do
- + * it for you.
- + */
- + bzero(&cmd, sizeof(cmd));
- + cmd.operation_code = ATAPI_READ_CD_CAPACITY;
- + cmd.len = sizeof(rdcap);
- +
- + /*
- + * If the command works, interpret the result as a 4 byte
- + * number of blocks and a blocksize
- + */
- + if (atapi_exec_cmd(cd->ad_link, &cmd , sizeof(cmd),
- + &rdcap, sizeof(rdcap), B_READ, 0) != 0) {
- + #ifdef ATAPI_DEBUG
- + printf("ATAPI_READ_CD_CAPACITY failed\n");
- + #endif
- + return 0;
- + }
- +
- + blksize = ntohl(rdcap.blksize);
- + if (blksize < 512)
- + blksize = 2048; /* some drives lie ! */
- + cd->params.blksize = blksize;
- +
- + size = ntohl(size);
- + if (size < 100)
- + size = 400000; /* ditto */
- + cd->params.disksize = size;
- + #ifdef ATAPI_DEBUG
- + printf("acd_size: %ld %ld\n",blksize,size);
- + #endif
- +
- + return size;
- + }
- +
- + #ifdef notyet
- + /*
- + * Get the requested page into the buffer given
- + */
- + int
- + cd_get_mode(cd, data, page)
- + struct acd_softc *cd;
- + struct cd_mode_data *data;
- + int page;
- + {
- + struct scsi_mode_sense scsi_cmd;
- + int error;
- +
- + bzero(&scsi_cmd, sizeof(scsi_cmd));
- + bzero(data, sizeof(*data));
- + scsi_cmd.opcode = MODE_SENSE;
- + scsi_cmd.page = page;
- + scsi_cmd.length = sizeof(*data) & 0xff;
- + return scsi_scsi_cmd(cd->ad_link, (struct scsi_generic *)&scsi_cmd,
- + sizeof(scsi_cmd), (u_char *)data, sizeof(*data), CDRETRIES, 20000,
- + NULL, SCSI_DATA_IN);
- + }
- +
- + /*
- + * Get the requested page into the buffer given
- + */
- + int
- + cd_set_mode(cd, data)
- + struct acd_softc *cd;
- + struct cd_mode_data *data;
- + {
- + struct scsi_mode_select scsi_cmd;
- +
- + bzero(&scsi_cmd, sizeof(scsi_cmd));
- + scsi_cmd.opcode = MODE_SELECT;
- + scsi_cmd.byte2 |= SMS_PF;
- + scsi_cmd.length = sizeof(*data) & 0xff;
- + data->header.data_length = 0;
- + return scsi_scsi_cmd(cd->ad_link, (struct scsi_generic *)&scsi_cmd,
- + sizeof(scsi_cmd), (u_char *)data, sizeof(*data), CDRETRIES, 20000,
- + NULL, SCSI_DATA_OUT);
- + }
- +
- + /*
- + * Get scsi driver to send a "start playing" command
- + */
- + int
- + cd_play(cd, blkno, nblks)
- + struct acd_softc *cd;
- + int blkno, nblks;
- + {
- + struct scsi_play scsi_cmd;
- +
- + bzero(&scsi_cmd, sizeof(scsi_cmd));
- + scsi_cmd.opcode = PLAY;
- + scsi_cmd.blk_addr[0] = (blkno >> 24) & 0xff;
- + scsi_cmd.blk_addr[1] = (blkno >> 16) & 0xff;
- + scsi_cmd.blk_addr[2] = (blkno >> 8) & 0xff;
- + scsi_cmd.blk_addr[3] = blkno & 0xff;
- + scsi_cmd.xfer_len[0] = (nblks >> 8) & 0xff;
- + scsi_cmd.xfer_len[1] = nblks & 0xff;
- + return scsi_scsi_cmd(cd->ad_link, (struct scsi_generic *)&scsi_cmd,
- + sizeof(scsi_cmd), 0, 0, CDRETRIES, 200000, NULL, 0);
- + }
- +
- + /*
- + * Get scsi driver to send a "start playing" command
- + */
- + int
- + cd_play_big(cd, blkno, nblks)
- + struct acd_softc *cd;
- + int blkno, nblks;
- + {
- + struct scsi_play_big scsi_cmd;
- +
- + bzero(&scsi_cmd, sizeof(scsi_cmd));
- + scsi_cmd.opcode = PLAY_BIG;
- + scsi_cmd.blk_addr[0] = (blkno >> 24) & 0xff;
- + scsi_cmd.blk_addr[1] = (blkno >> 16) & 0xff;
- + scsi_cmd.blk_addr[2] = (blkno >> 8) & 0xff;
- + scsi_cmd.blk_addr[3] = blkno & 0xff;
- + scsi_cmd.xfer_len[0] = (nblks >> 24) & 0xff;
- + scsi_cmd.xfer_len[1] = (nblks >> 16) & 0xff;
- + scsi_cmd.xfer_len[2] = (nblks >> 8) & 0xff;
- + scsi_cmd.xfer_len[3] = nblks & 0xff;
- + return scsi_scsi_cmd(cd->ad_link, (struct scsi_generic *)&scsi_cmd,
- + sizeof(scsi_cmd), 0, 0, CDRETRIES, 20000, NULL, 0);
- + }
- +
- + /*
- + * Get scsi driver to send a "start playing" command
- + */
- + int
- + cd_play_tracks(cd, strack, sindex, etrack, eindex)
- + struct acd_softc *cd;
- + int strack, sindex, etrack, eindex;
- + {
- + struct scsi_play_track scsi_cmd;
- +
- + bzero(&scsi_cmd, sizeof(scsi_cmd));
- + scsi_cmd.opcode = PLAY_TRACK;
- + scsi_cmd.start_track = strack;
- + scsi_cmd.start_index = sindex;
- + scsi_cmd.end_track = etrack;
- + scsi_cmd.end_index = eindex;
- + return scsi_scsi_cmd(cd->ad_link, (struct scsi_generic *)&scsi_cmd,
- + sizeof(scsi_cmd), 0, 0, CDRETRIES, 20000, NULL, 0);
- + }
- +
- + /*
- + * Get scsi driver to send a "play msf" command
- + */
- + int
- + cd_play_msf(cd, startm, starts, startf, endm, ends, endf)
- + struct acd_softc *cd;
- + int startm, starts, startf, endm, ends, endf;
- + {
- + struct scsi_play_msf scsi_cmd;
- +
- + bzero(&scsi_cmd, sizeof(scsi_cmd));
- + scsi_cmd.opcode = PLAY_MSF;
- + scsi_cmd.start_m = startm;
- + scsi_cmd.start_s = starts;
- + scsi_cmd.start_f = startf;
- + scsi_cmd.end_m = endm;
- + scsi_cmd.end_s = ends;
- + scsi_cmd.end_f = endf;
- + return scsi_scsi_cmd(cd->ad_link, (struct scsi_generic *)&scsi_cmd,
- + sizeof(scsi_cmd), 0, 0, CDRETRIES, 2000, NULL, 0);
- + }
- +
- + #endif /* notyet */
- +
- + /*
- + * Get atapi driver to send a "start up" command
- + */
- + int
- + acd_pause(acd, go)
- + struct acd_softc *acd;
- + int go;
- + {
- + struct pause_resume cmd;
- +
- + bzero(&cmd, sizeof(cmd));
- + cmd.operation_code = ATAPI_PAUSE_RESUME;
- + cmd.resume = go;
- + return atapi_exec_cmd(acd->ad_link, &cmd , sizeof(cmd), 0, 0, 0, 0);
- + }
- +
- + /*
- + * Get atapi driver to send a "RESET" command
- + */
- + int
- + acd_reset(acd)
- + struct acd_softc *acd;
- + {
- + #ifdef notyet
- + return atapi_soft_reset(acd->ad_link);
- + #else
- + return 0;
- + #endif
- + }
- +
- + #ifdef notyet
- + /*
- + * Read subchannel
- + */
- + int
- + cd_read_subchannel(cd, mode, format, track, data, len)
- + struct acd_softc *cd;
- + int mode, format, len;
- + struct cd_sub_channel_info *data;
- + {
- + struct scsi_read_subchannel scsi_cmd;
- +
- + bzero(&scsi_cmd, sizeof(scsi_cmd));
- + scsi_cmd.opcode = READ_SUBCHANNEL;
- + if (mode == CD_MSF_FORMAT)
- + scsi_cmd.byte2 |= CD_MSF;
- + scsi_cmd.byte3 = SRS_SUBQ;
- + scsi_cmd.subchan_format = format;
- + scsi_cmd.track = track;
- + scsi_cmd.data_len[0] = (len >> 8) & 0xff;
- + scsi_cmd.data_len[1] = len & 0xff;
- + return scsi_scsi_cmd(cd->ad_link, (struct scsi_generic *)&scsi_cmd,
- + sizeof(struct scsi_read_subchannel), (u_char *)data, len,
- + CDRETRIES, 5000, NULL, SCSI_DATA_IN);
- + }
- +
- + /*
- + * Read table of contents
- + */
- + int
- + cd_read_toc(cd, mode, start, data, len)
- + struct acd_softc *cd;
- + int mode, start, len;
- + struct cd_toc_entry *data;
- + {
- + struct scsi_read_toc scsi_cmd;
- + int ntoc;
- +
- + bzero(&scsi_cmd, sizeof(scsi_cmd));
- + /*if (len!=sizeof(struct ioc_toc_header))
- + * ntoc=((len)-sizeof(struct ioc_toc_header))/sizeof(struct cd_toc_entry);
- + * else */
- + ntoc = len;
- + scsi_cmd.opcode = READ_TOC;
- + if (mode == CD_MSF_FORMAT)
- + scsi_cmd.byte2 |= CD_MSF;
- + scsi_cmd.from_track = start;
- + scsi_cmd.data_len[0] = (ntoc >> 8) & 0xff;
- + scsi_cmd.data_len[1] = ntoc & 0xff;
- + return scsi_scsi_cmd(cd->ad_link, (struct scsi_generic *)&scsi_cmd,
- + sizeof(struct scsi_read_toc), (u_char *)data, len, CDRETRIES,
- + 5000, NULL, SCSI_DATA_IN);
- + }
- +
- + #endif /* notyet */
- +
- + /*
- + * Get the atapi driver to send a full inquiry to the device and use the
- + * results to fill out the disk parameter structure.
- + */
- + int
- + acd_get_parms(acd, flags)
- + struct acd_softc *acd;
- + int flags;
- + {
- +
- + /*
- + * give a number of sectors so that sec * trks * cyls
- + * is <= disk_size
- + */
- + if (acd_size(acd, flags) == 0)
- + return ENXIO;
- +
- + return 0;
- + }
- +
- + int
- + acdsize(dev)
- + dev_t dev;
- + {
- +
- + /* CD-ROMs are read-only. */
- + return -1;
- + }
- +
- + void acdminphys(bp)
- + struct buf *bp;
- + {
- + minphys(bp);
- + }
- +
- +
- + int
- + acddump(dev, blkno, va, size)
- + dev_t dev;
- + daddr_t blkno;
- + caddr_t va;
- + size_t size;
- + {
- +
- + /* Not implemented. */
- + return ENXIO;
- + }
- +
- + int
- + acddone(acp)
- + struct atapi_command_packet *acp;
- + {
- + struct at_dev_link *ad_link = acp->ad_link;
- + struct acd_softc *acd = ad_link->device_softc;
- +
- + if (acp->bp != NULL)
- + disk_unbusy(&acd->sc_dk, (acp->bp->b_bcount - acp->bp->b_resid));
- +
- + return (0);
- + }
- +
- diff --exclude compile -bcrNP src.orig/sys/atapi/atapi.h src/sys/atapi/atapi.h
- *** src.orig/sys/atapi/atapi.h Thu Jan 1 01:00:00 1970
- --- src/sys/atapi/atapi.h Thu Jan 11 22:03:56 1996
- ***************
- *** 0 ****
- --- 1,244 ----
- + /*
- + * Copyright (c) 1996 Manuel Bouyer. All rights reserved.
- + *
- + * 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 Manuel Bouyer.
- + * 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.
- + */
- +
- + /* Definition of atapi commands and associated data structures */
- + /*
- + TEST UNIT READY (mandatory)
- + */
- +
- + #define ATAPI_TEST_UNIT_READY 0x00
- +
- + struct test_unit_ready {
- + u_char operation_code;
- + u_char reserved1[15];
- + };
- +
- + /*
- + START/STOP UNIT (mandatory)
- + */
- +
- + #define ATAPI_START_STOP_UNIT 0x1b
- +
- + struct start_stop_unit {
- + u_char operation_code;
- + u_char immed :1;
- + u_char reserved1 :7;
- + u_char reserved2[2];
- + u_char how;
- + #define SSS_STOP 0x00
- + #define SSS_START 0x01
- + #define SSS_LOEJ 0x02
- + u_char reserved4[11];
- + };
- +
- + /*
- + PREVENT/ALLOW MEDIUM REMOVAL (mandatory)
- + */
- +
- + #define ATAPI_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
- +
- + struct prevent_allow_medium_removal {
- + u_char operation_code;
- + u_char reserved1[3];
- + u_char prevent :1;
- + #define PR_PREVENT 0x01
- + #define PR_ALLOW 0x00
- + u_char reserved2 :7;
- + u_char reserved3[11];
- + };
- +
- +
- + /*
- + READ CD CAPACITY (mandatory)
- + */
- +
- + #define ATAPI_READ_CD_CAPACITY 0x25
- +
- + struct read_cd_capacity {
- + u_char operation_code;
- + u_char reserved1[7];
- + u_char len;
- + u_char reserved2[7];
- + };
- +
- + /*
- + * Volume size info.
- + */
- + struct read_cd_capacity_data {
- + u_long size; /* Volume size in blocks */
- + u_long blksize; /* Block size in bytes */
- + };
- +
- +
- + /*
- + READ (10) (mandatory)
- + */
- +
- + #define ATAPI_READ 0x28
- +
- + struct read {
- + u_char operation_code;
- + u_char reserved1;
- + u_char lba[4];
- + u_char reserved2;
- + u_char length[2];
- + u_char reserved3[7];
- + };
- +
- + /*
- + PAUSE/RESUME (optional)
- + */
- +
- + #define ATAPI_PAUSE_RESUME 0x4b
- +
- + struct pause_resume {
- + u_char operation_code;
- + u_char reserved1[7];
- + u_char resume :1;
- + u_char reserved2 :7;
- + u_char reserved3[7];
- + };
- +
- +
- + /*
- + MODE SENSE (mandatory)
- + */
- +
- + #define ATAPI_MODE_SENSE 0x5a
- +
- + struct mode_sense {
- + u_char operation_code;
- + u_char reserved1;
- + u_char page_code :6;
- + u_char page_control :2; /* page control */
- + u_char reserved2[4];
- + u_char length[2];
- + u_char reserved3[7];
- + };
- +
- + struct cappage {
- + /* Mode data header */
- + u_short data_length;
- + u_char medium_type;
- + #define MDT_UNKNOWN 0x00
- + #define MDT_DATA_120 0x01
- + #define MDT_AUDIO_120 0x02
- + #define MDT_COMB_120 0x03
- + #define MDT_PHOTO_120 0x04
- + #define MDT_DATA_80 0x05
- + #define MDT_AUDIO_80 0x06
- + #define MDT_COMB_80 0x07
- + #define MDT_PHOTO_80 0x08
- + #define MDT_NO_DISC 0x70
- + #define MDT_DOOR_OPEN 0x71
- + #define MDT_FMT_ERROR 0x72
- + u_char reserved1[5];
- +
- + /* Capabilities page */
- + u_char page_code;
- + #define CAP_PAGE 0x2a
- + u_char param_len;
- + u_char reserved2[2];
- +
- + u_char audio_play : 1; /* audio play supported */
- + u_char composite : 1; /* composite audio/video supported */
- + u_char dport1 : 1; /* digital audio on port 1 */
- + u_char dport2 : 1; /* digital audio on port 2 */
- + u_char mode2_form1 : 1; /* mode 2 form 1 (XA) read */
- + u_char mode2_form2 : 1; /* mode 2 form 2 format */
- + u_char multisession : 1; /* multi-session photo-CD */
- + u_char : 1;
- + u_char cd_da : 1; /* audio-CD read supported */
- + u_char cd_da_stream : 1; /* CD-DA streaming */
- + u_char rw : 1; /* combined R-W subchannels */
- + u_char rw_corr : 1; /* R-W subchannel data corrected */
- + u_char c2 : 1; /* C2 error pointers supported */
- + u_char isrc : 1; /* can return the ISRC info */
- + u_char upc : 1; /* can return the catalog number UPC */
- + u_char : 1;
- + u_char lock : 1; /* could be locked */
- + u_char locked : 1; /* current lock state */
- + u_char prevent : 1; /* prevent jumper installed */
- + u_char eject : 1; /* can eject */
- + u_char : 1;
- + u_char mech : 3; /* loading mechanism type */
- + #define MECH_CADDY 0
- + #define MECH_TRAY 1
- + #define MECH_POPUP 2
- + #define MECH_CHANGER 4
- + #define MECH_CARTRIDGE 5
- + u_char sep_vol : 1; /* independent volume of channels */
- + u_char sep_mute : 1; /* independent mute of channels */
- + u_char : 6;
- +
- + u_short max_speed; /* max raw data rate in bytes/1000 */
- + u_short max_vol_levels; /* number of discrete volume levels */
- + u_short buf_size; /* internal buffer size in bytes/1024 */
- + u_short cur_speed; /* current data rate in bytes/1000 */
- + /* Digital drive output format description (optional?) */
- + u_char reserved3;
- + u_char bckf : 1; /* data valid on failing edge of BCK */
- + u_char rch : 1; /* high LRCK indicates left channel */
- + u_char lsbf : 1; /* set if LSB first */
- + u_char dlen: 2;
- + #define DLEN_32 0 /* 32 BCKs */
- + #define DLEN_16 1 /* 16 BCKs */
- + #define DLEN_24 2 /* 24 BCKs */
- + #define DLEN_24_I2S 3 /* 24 BCKs (I2S) */
- + u_char : 3;
- + u_char reserved4[2];
- + };
- +
- + /* ATAPI error codes */
- + #define ATAPI_SK_NO_SENSE 0x0
- + #define ATAPI_SK_REC_ERROR 0x1 /* recovered error */
- + #define ATAPI_SK_NOT_READY 0x2
- + #define ATAPI_SK_MEDIUM_ERROR 0x3
- + #define ATAPI_SK_HARDWARE_ERROR 0x4
- + #define ATAPI_SK_ILLEGAL_REQUEST 0x5
- + #define ATAPI_SK_UNIT_ATTENTION 0x6
- + #define ATAPI_SK_DATA_PROTECT 0x7
- + /* 0x8 reserved */
- + /* 0x9-0xa reserved */
- + #define ATAPI_SK_ABORTED_COMMAND 0xb
- + /* 0xc-0xd not referenced */
- + #define ATAPI_SK_MISCOMPARE 0xe
- + /* 0xf reserved */
- +
- + #define ATAPI_MCR 0x08 /* media change requested */
- + #define ATAPI_ABRT 0x04 /* aborted command */
- + #define ATAPI_EOM 0x02 /* end of media */
- + #define ATAPI_ILI 0x01 /* illegal length indication */
- +
- +
- + int atapi_exec_cmd __P((struct at_dev_link *, void*, int, void*, int, long, int));
- + int atapi_exec_io __P((struct at_dev_link *, void *, int, struct buf *, int));
- + int atapi_test_unit_ready __P((struct at_dev_link *, int));
- + int atapi_start_stop __P((struct at_dev_link *, int, int));
- + int atapi_prevent __P((struct at_dev_link *, int));
- diff --exclude compile -bcrNP src.orig/sys/atapi/atapiconf.c src/sys/atapi/atapiconf.c
- *** src.orig/sys/atapi/atapiconf.c Thu Jan 1 01:00:00 1970
- --- src/sys/atapi/atapiconf.c Fri Apr 19 16:17:56 1996
- ***************
- *** 0 ****
- --- 1,588 ----
- + /*
- + * Copyright (c) 1996 Manuel Bouyer. All rights reserved.
- + *
- + * 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 Manuel Bouyer.
- + * 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 <sys/types.h>
- + #include <sys/param.h>
- + #include <sys/systm.h>
- + #include <sys/malloc.h>
- + #include <sys/device.h>
- + #include <sys/buf.h>
- + #include <sys/proc.h>
- +
- + #include <atapi/atapilink.h>
- + #include <atapi/atapi.h>
- + #define SILENT_PRINTF(flags,string) if (!(flags & A_SILENT)) printf string
- +
- + struct atapibus_softc {
- + struct device sc_dev;
- + struct bus_link *b_link;
- + struct atapi_devices *ad_link[2];
- + };
- +
- + LIST_HEAD(pkt_free_list, atapi_command_packet) pkt_free_list;
- +
- + void bswap __P((char*, int));
- + void btrim __P((char*, int));
- +
- + int atapi_error __P((struct atapi_command_packet*));
- + void atapi_sense __P((struct atapi_command_packet*, u_char, u_char));
- + void at_print_addr __P((struct at_dev_link*, u_char));
- +
- + int atapibusmatch __P((struct device *, void *, void *));
- + void atapibusattach __P((struct device *, struct device *, void *));
- +
- + struct cfattach atapibus_ca = {
- + sizeof(struct atapibus_softc), atapibusmatch, atapibusattach,
- + };
- +
- + struct cfdriver atapibus_cd = {
- + NULL, "atapibus", DV_DULL
- + };
- +
- +
- + int
- + atapibusmatch(parent, match, aux)
- + struct device *parent;
- + void *match, *aux;
- + {
- + struct cfdata *cf = match;
- + struct bus_link *ab_link = aux;
- +
- + if (ab_link == NULL ) return 0;
- + if (ab_link-> type != BUS) return 0;
- + return 1;
- + }
- +
- + int
- + atapiprint(aux, bus)
- + void *aux;
- + char *bus;
- + {
- + struct at_dev_link *ad_link = aux;
- +
- + if (!bus)
- + printf(" drive %d: ", ad_link->drive);
- + return QUIET;
- + }
- +
- +
- + void atapibusattach(parent, self, aux)
- + struct device *parent, *self;
- + void *aux;
- + {
- + struct atapibus_softc *ab = (struct atapibus_softc *)self;
- + struct bus_link *ab_link_proto = aux;
- + int drive;
- + struct atapi_identify ids;
- + struct atapi_identify *id = &ids;
- + struct at_dev_link *ad_link;
- +
- + ab_link_proto->atapibus_softc = (caddr_t)ab;
- + ab->b_link = ab_link_proto;
- + printf("\n");
- + for (drive = 0; drive < 2 ; drive++) {
- + if (wdc_atapi_get_params(ab_link_proto, drive, id)) {
- + /*
- + * Shuffle string byte order.
- + * Mitsumi and NEC drives don't need this.
- + */
- + if (! ((id->model[0] == 'N' && id->model[1] == 'E') ||
- + (id->model[0] == 'F' && id->model[1] == 'X')))
- + bswap(id->model, sizeof(id->model));
- + bswap (id->serial_number, sizeof(id->serial_number));
- + bswap (id->firmware_revision, sizeof(id->firmware_revision));
- + /* Clean up the model name, serial and revision numbers. */
- + btrim (id->model, sizeof(id->model));
- + btrim (id->serial_number, sizeof(id->serial_number));
- + btrim (id->firmware_revision, sizeof(id->firmware_revision));
- + printf("atapibus%d drive%d: <%s, %s, %s> ",
- + ab->sc_dev.dv_unit, drive, id->model, id->serial_number, id->firmware_revision);
- + switch (id->config.device_type) {
- + case ATAPI_DEVICE_TYPE_DAD: printf("direct, ");
- + break;
- + case ATAPI_DEVICE_TYPE_CD: printf("cdrom, ");
- + break;
- + case ATAPI_DEVICE_TYPE_OMD: printf(" optical, ");
- + break;
- + default: printf(" unknown type %d, ",id->config.device_type);
- + }
- + printf("%s.\n", id->config.removable?"removable":"fixed");
- + #ifdef ATAPI_DEBUG_PROBE
- + printf("cmdsz %d drqtype %d\n",id->config.packet_size, id->config.drq_type);
- + #endif
- +
- + ad_link = malloc(sizeof(*ad_link), M_DEVBUF, M_NOWAIT);
- + if (ad_link == NULL) {
- + printf("Warning: cannot allocate memory for device\n");
- + continue;
- + }
- + ad_link->drive = drive;
- + if (id->config.packet_size) ad_link->flags |= ACAP_LEN;
- + ad_link->flags |= id->config.drq_type << 8;
- + bcopy(id, &ad_link->id, sizeof(*id));
- + ad_link->bus=ab_link_proto;
- + if (config_found(self,ad_link,atapiprint) == NULL) {
- + printf("atapibus:config not found\n");
- + free(ad_link,M_DEVBUF);
- + }
- + }
- + }
- + }
- +
- + void
- + bswap (buf, len)
- + char *buf;
- + int len;
- + {
- + u_short *p = (u_short*) (buf + len);
- + while (--p >= (u_short*) buf)
- + *p = ntohs (*p);
- + }
- +
- + void
- + btrim (buf, len)
- + char *buf;
- + int len;
- + {
- + char *p;
- +
- + /* Remove the trailing spaces. */
- + for (p=buf; p<buf+len; ++p)
- + if (! *p)
- + *p = ' ';
- + for (p=buf+len-1; p>=buf && *p==' '; --p)
- + *p = 0;
- + }
- +
- + int atapi_exec_cmd(ad_link, cmd, cmd_size, databuf, datalen, rw, flags)
- + struct at_dev_link *ad_link;
- + void *cmd;
- + int cmd_size;
- + void *databuf;
- + int datalen;
- + long rw;
- + int flags;
- + {
- + struct atapi_command_packet *pkt;
- + struct bus_link *b_link = ad_link->bus;
- + int status, s;
- +
- + pkt = atapi_get_pkt(ad_link, flags);
- + if (!pkt) return -1;
- + bcopy(cmd, &pkt->cmd_store, cmd_size);
- + pkt->command = &pkt->cmd_store;
- + pkt->command_size = (ad_link->flags & ACAP_LEN)?16:12;
- + pkt->databuf = databuf;
- + pkt->data_size = datalen;
- + pkt->flags = rw|(flags & 0xff)| (ad_link->flags & 0x0300);
- + pkt->drive = ad_link->drive;
- + wdc_atapi_send_command_packet(b_link, pkt);
- + if ((flags & (A_POLLED|A_NOSLEEP)) == 0 ) {
- + #ifdef ATAPI_DEBUG_CMD
- + printf("atapi_exec_cmd: sleeping\n");
- + #endif
- + s=splbio();
- + while ((pkt->status & ITSDONE) == 0)
- + tsleep(pkt,PRIBIO+1,"atapicmd",0);
- + splx(s);
- + #ifdef ATAPI_DEBUG_CMD
- + printf("atapi_exec_cmd: done sleeping\n");
- + #endif
- + status = pkt->status & STATUS_MASK;
- + atapi_free_pkt(pkt);
- + } else {
- + if ((flags & A_POLLED) != 0) {
- + if ((pkt->status & ERROR) && (pkt->error)) {
- + atapi_error(pkt);
- + SILENT_PRINTF(flags,("\n"));
- + }
- + }
- + status = pkt->status & STATUS_MASK;
- + if ((flags & A_POLLED) != 0)
- + atapi_free_pkt(pkt);
- +
- + }
- + return status;
- + }
- +
- + int atapi_exec_io(ad_link, cmd, cmd_size, bp, flags)
- + struct at_dev_link *ad_link;
- + void *cmd;
- + int cmd_size;
- + struct buf *bp;
- + int flags;
- + {
- + struct atapi_command_packet *pkt;
- + struct bus_link *b_link = ad_link->bus;
- +
- + pkt = atapi_get_pkt(ad_link, flags);
- + if (pkt == NULL) {
- + printf("atapi_exec_io: no pkt\n");
- + return ERROR;
- + }
- + bcopy(cmd, &pkt->cmd_store, cmd_size);
- + pkt->command = &pkt->cmd_store;
- + pkt->command_size = (ad_link->flags & ACAP_LEN)?16:12;
- + pkt->bp = bp;
- + pkt->databuf = bp->b_data;
- + pkt->data_size = bp->b_bcount;
- + pkt->flags = bp->b_flags & (B_READ|B_WRITE)|(flags & 0xff)|
- + (ad_link->flags & 0x0300);
- + pkt->drive = ad_link->drive;
- + wdc_atapi_send_command_packet(b_link, pkt);
- + return (pkt->status & STATUS_MASK);
- + }
- +
- + void atapi_done(acp)
- + struct atapi_command_packet *acp;
- + {
- + struct at_dev_link *ad_link=acp->ad_link;
- + struct buf *bp = acp->bp;
- + int error = 0;
- +
- + #ifdef ATAPI_DEBUG_CMD
- + printf("atapi_done\n");
- + #endif
- +
- + if ((acp->status & ERROR) && (acp->error)) {
- + atapi_error(acp);
- + if (acp->status & RETRY) {
- + if (acp->retries <ATAPI_NRETRIES) {
- + acp->retries++;
- + acp->status = 0;
- + acp->error = 0;
- + SILENT_PRINTF(acp->flags & 0xff,(", retry #%d\n",acp->retries));
- + wdc_atapi_send_command_packet(ad_link->bus, acp);
- + return;
- + } else acp->status = ERROR;
- + }
- + SILENT_PRINTF(acp->flags & 0xff,("\n"));
- + }
- + acp->status |= ITSDONE;
- +
- + if (ad_link->done) {
- + #ifdef ATAPI_DEBUG_CMD
- + printf("calling private done\n");
- + #endif
- + error = (*ad_link->done) (acp);
- + if (error == EJUSTRETURN) return;
- + }
- + if (acp->bp == NULL) {
- + #ifdef ATAPI_DEBUG_CMD
- + printf("atapidone: wakeup acp\n");
- + #endif
- + wakeup(acp);
- + return;
- + }
- + #ifdef ATAPI_DEBUG_CMD
- + printf("atapi_done: status %d\n", acp->status);
- + #endif
- + switch (acp->status&0x0f) {
- + case MEDIA_CHANGE:
- + if (ad_link->flags & ADEV_REMOVABLE) {
- + ad_link->flags &= ~ADEV_MEDIA_LOADED;
- + }
- + error=EIO;
- + break;
- + case NO_ERROR:
- + error=0;
- + break;
- + case ERROR:
- + case END_OF_MEDIA:
- + default:
- + error=EIO;
- + break;
- + }
- + switch (acp->status&0xf0) {
- + case NOT_READY:
- + case UNIT_ATTENTION:
- + if (ad_link->flags & ADEV_REMOVABLE) {
- + ad_link->flags &= ~ADEV_MEDIA_LOADED;
- + }
- + error=EIO;
- + break;
- + default:
- + }
- +
- + if (error) {
- + bp->b_error = error;;
- + bp->b_flags |= B_ERROR;
- + bp->b_resid = bp->b_bcount;
- + } else {
- + bp->b_error = 0;
- + bp->b_resid = acp->data_size;
- + }
- + biodone(bp);
- + atapi_free_pkt(acp);
- + }
- +
- + struct atapi_command_packet *
- + atapi_get_pkt(ad_link, flags)
- + struct at_dev_link *ad_link;
- + int flags;
- + {
- + struct atapi_command_packet *pkt;
- + int s;
- +
- + s = splbio();
- + while (ad_link->openings <= 0) {
- + if (flags & A_NOSLEEP) {
- + splx(s);
- + return 0;
- + }
- + #ifdef ATAPI_DEBUG_CMD
- + printf("atapi_get_pkt: sleeping\n");
- + #endif
- + ad_link->flags |= ADEV_WAITING;
- + (void) tsleep(ad_link, PRIBIO, "getpkt", 0);
- + }
- + ad_link->openings--;
- + if ((pkt = pkt_free_list.lh_first) != 0) {
- + LIST_REMOVE(pkt, free_list);
- + splx(s);
- + } else {
- + splx(s);
- + pkt = malloc(sizeof(struct atapi_command_packet), M_DEVBUF,
- + ((flags & A_NOSLEEP) != 0 ? M_NOWAIT : M_WAITOK));
- + if (!pkt) {
- + printf("atapi_get_pkt: cannot allocate pkt\n");
- + ad_link->openings++;
- + return 0;
- + }
- + }
- + bzero(pkt, sizeof(struct atapi_command_packet));
- + pkt->ad_link = ad_link;
- + return pkt;
- + }
- +
- + void
- + atapi_free_pkt(pkt)
- + struct atapi_command_packet *pkt;
- + {
- + struct at_dev_link *ad_link = pkt->ad_link;
- + int s;
- +
- + s = splbio();
- + LIST_INSERT_HEAD(&pkt_free_list, pkt, free_list);
- +
- + ad_link->openings++;
- + if ((ad_link->flags & ADEV_WAITING) != 0) {
- + ad_link->flags &= ~ADEV_WAITING;
- + wakeup(ad_link);
- + } else {
- + if (ad_link->start) {
- + #ifdef ATAPI_DEBUG_CMD
- + printf("atapi_free_pkt: calling private start\n");
- + #endif
- + (*(ad_link->start)) ((void*)ad_link->device_softc);
- + }
- + }
- + splx(s);
- + }
- +
- + int
- + atapi_test_unit_ready(ad_link, flags)
- + struct at_dev_link *ad_link;
- + int flags;
- + {
- + int ret;
- + struct test_unit_ready cmd;
- + #ifdef ATAPI_DEBUG_FCTN
- + printf("atapi_test_unit_ready: ");
- + #endif
- + bzero(&cmd, sizeof(cmd));
- + cmd.operation_code = ATAPI_TEST_UNIT_READY;
- + ret = atapi_exec_cmd(ad_link, &cmd, sizeof(cmd), 0,0,0,flags);
- + #ifdef ATAPI_DEBUG_FCTN
- + printf("atapi_test_unit_ready: ret %d\n", ret);
- + #endif
- + return ret;
- + }
- +
- + int
- + atapi_start_stop(ad_link, how, flags)
- + struct at_dev_link *ad_link;
- + int how;
- + int flags;
- + {
- + struct start_stop_unit cmd;
- + int ret;
- +
- + #ifdef ATAPI_DEBUG_FCTN
- + printf("atapi_start_stop: ");
- + #endif
- + bzero(&cmd, sizeof(cmd));
- + cmd.operation_code = ATAPI_START_STOP_UNIT;
- + cmd.how = how;
- + ret = atapi_exec_cmd(ad_link, &cmd, sizeof(cmd), 0,0,0,flags);
- + #ifdef ATAPI_DEBUG_FCTN
- + printf("ret %d\n", ret);
- + #endif
- + return ret;
- + }
- +
- + int
- + atapi_prevent(ad_link, how)
- + struct at_dev_link *ad_link;
- + int how;
- + {
- + struct prevent_allow_medium_removal cmd;
- + int ret;
- +
- + #ifdef ATAPI_DEBUG_FCTN
- + printf("atapi_prevent: ");
- + #endif
- + bzero(&cmd, sizeof(cmd));
- + cmd.operation_code = ATAPI_PREVENT_ALLOW_MEDIUM_REMOVAL;
- + cmd.prevent = how;
- + ret = atapi_exec_cmd(ad_link, &cmd, sizeof(cmd), 0,0,0,0);
- + #ifdef ATAPI_DEBUG_FCTN
- + printf("ret %d\n", ret);
- + #endif
- + return ret;
- + }
- +
- + int
- + atapi_error(acp)
- + struct atapi_command_packet* acp;
- + {
- + int flags, error, ret = -1;
- + struct at_dev_link *ad_link = acp->ad_link;
- + flags = acp->flags & 0xff;
- + error = acp->error;
- + at_print_addr(ad_link, acp->flags & 0xff);
- + if (error & ATAPI_MCR) {
- + SILENT_PRINTF(flags,("media change requested"));
- + acp->status = MEDIA_CHANGE;
- + }
- + if (error & ATAPI_ABRT) {
- + SILENT_PRINTF(flags,("command aborted"));
- + acp->status = ERROR;
- + }
- + if (error & ATAPI_EOM) {
- + SILENT_PRINTF(flags,("end of media"));
- + acp->status = END_OF_MEDIA;
- + }
- + if (error & ATAPI_ILI) {
- + SILENT_PRINTF(flags,("illegal length indication"));
- + acp->status = ERROR;
- + }
- + if ((error & 0x0f) == 0) {
- + ret=0;
- + }
- + atapi_sense (acp, error >> 4, flags);
- + if (!(flags & A_SILENT) && (acp->status != NO_ERROR)) {
- + int i;
- + printf(", command:");
- + for (i=0; i< acp->command_size; i++)
- + printf(" %2x", ((u_char*)acp->command)[i]);
- + }
- + return ret;
- + }
- +
- + void
- + atapi_sense(acp, sense_key, flags)
- + struct atapi_command_packet *acp;
- + u_char sense_key;
- + u_char flags;
- + {
- + struct at_dev_link *ad_link = acp->ad_link;
- +
- + switch (sense_key)
- + {
- + case ATAPI_SK_NO_SENSE:
- + break;
- +
- + case ATAPI_SK_REC_ERROR:
- + SILENT_PRINTF(flags,("recovered error"));
- + acp->status = 0;
- + break;
- +
- + case ATAPI_SK_NOT_READY:
- + SILENT_PRINTF(flags,("not ready"));
- + acp->status = NOT_READY;
- + break;
- +
- + case ATAPI_SK_MEDIUM_ERROR:
- + SILENT_PRINTF(flags,("medium error"));
- + acp->status = ERROR;
- + break;
- +
- + case ATAPI_SK_HARDWARE_ERROR:
- + SILENT_PRINTF(flags,("hardware error"));
- + acp->status = ERROR;
- + break;
- +
- + case ATAPI_SK_ILLEGAL_REQUEST:
- + SILENT_PRINTF(flags,("illegal request"));
- + acp->status = ERROR;
- + break;
- +
- + case ATAPI_SK_UNIT_ATTENTION:
- + SILENT_PRINTF(flags,("unit attention"));
- + acp->status = UNIT_ATTENTION;
- + if (ad_link->flags & ADEV_REMOVABLE) {
- + ad_link->flags &= ~ADEV_MEDIA_LOADED;
- + }
- + break;
- +
- + case ATAPI_SK_DATA_PROTECT:
- + SILENT_PRINTF(flags,("data protect"));
- + acp->status = ERROR;
- + break;
- +
- + case ATAPI_SK_ABORTED_COMMAND:
- + SILENT_PRINTF(flags,("aborted command"));
- + acp->status = RETRY;
- + break;
- +
- + case ATAPI_SK_MISCOMPARE:
- + SILENT_PRINTF(flags,("miscompare"));
- + acp->status = ERROR;
- + break;
- +
- + default:
- + SILENT_PRINTF(flags,("unexpected sense key %02x", sense_key));
- + acp->status = ERROR;
- + break;
- + }
- + }
- +
- + void
- + at_print_addr(ad_link, flags)
- + struct at_dev_link *ad_link;
- + u_char flags;
- + {
- + if (flags & A_SILENT) return;
- + printf("%s(%s:%d): ",
- + ad_link->device_softc ?
- + ((struct device *)ad_link->device_softc)->dv_xname : "probe",
- + ((struct device *)ad_link->bus->wdc_softc)->dv_xname,
- + ad_link->drive);
- + }
- diff --exclude compile -bcrNP src.orig/sys/atapi/atapilink.h src/sys/atapi/atapilink.h
- *** src.orig/sys/atapi/atapilink.h Thu Jan 1 01:00:00 1970
- --- src/sys/atapi/atapilink.h Tue Mar 5 21:45:44 1996
- ***************
- *** 0 ****
- --- 1,186 ----
- + /*
- + * Copyright (c) 1996 Manuel Bouyer. All rights reserved.
- + *
- + * 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 Manuel Bouyer.
- + * 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 ATAPI_DEBUG
- + #undef ATAPI_DEBUG_PROBE
- +
- + struct bus_link {
- + u_int8_t type;
- + #define DRIVE 0
- + #define BUS 1
- + caddr_t wdc_softc;
- + caddr_t atapibus_softc;
- + struct wdc_link *ctlr_link;
- + u_int8_t ctrl;
- + };
- +
- + struct atapi_identify {
- + struct config_s {
- + u_int8_t packet_size :2;
- + #define ATAPI_PACKET_SIZE_12 0x0
- + #define ATAPI_PACKET_SIZE_16 0x1
- + /* 1xb reserved */
- + u_int8_t reserved1 :3;
- + u_int8_t drq_type :2;
- + #define ATAPI_MICROPROCESSOR_DRQ 0x0
- + #define ATAPI_INTERRUPT_DRQ 0x1
- + #define ATAPI_ACCELERATED_DRQ 0x2
- + /* 0x3 reserved */
- + u_int8_t removable :1;
- + u_int8_t device_type :5;
- + #define ATAPI_DEVICE_TYPE_DAD 0x0 /* direct access device, eg magnetic di
- + sk */
- + /* 0x1-0x4 reserved */
- + #define ATAPI_DEVICE_TYPE_CD 0x5
- + /* 0x6 reserved */
- + #define ATAPI_DEVICE_TYPE_OMD 0x7 /* optical memory device */
- + /* 0x8-0x1e reserved */
- + #define ATAPI_DEVICE_TYPE_UNKNOWN 0x1f
- + u_int8_t reserved2 :1;
- + u_int8_t protocol_type :2;
- + /* 0x0, 0x1 are ATA */
- + #define ATAPI_GC_PROTO_TYPE_ATAPI 0x2
- + #define ATAPI_GC_PROTO_TYPE_RESERVED 0x3
- + } config; /* general configuration */
- + u_int16_t cylinders;
- + u_int16_t reserved1;
- + u_int16_t heads;
- + u_int16_t unf_bytes_per_track;
- + u_int16_t unf_bytes_per_sector;
- + u_int16_t sectors_per_track;
- + u_int16_t reserved2[3];
- + char serial_number[20];
- + u_int16_t buffer_type;
- + u_int16_t buffer_size;
- + u_int16_t ECC_bytes_available;
- + char firmware_revision[8];
- + char model[40];
- + u_int16_t sector_count;
- + u_int16_t double_word; /* ==0 for CD-ROMs */
- + struct capabilities_s {
- + u_int8_t vendor;
- + u_int8_t dma :1; /* DMA supported */
- + u_int8_t lba :1; /* LBA supported */
- + u_int8_t iordy_disable :1; /* IORDY can be disabled */
- + u_int8_t iordy :1; /* IORDY supported */
- + u_int8_t reserved1 :4;
- + } capabilities;
- + u_int16_t reserved3;
- + u_int16_t PIO_cycle_timing;
- + u_int16_t DMA_cycle_timing;
- + u_int16_t validity; /* of words 54-58, 64-70 in this table */
- +
- + #define ATAPI_VALID_FIRST 0x0 /* == 1 => words 54-58 are valid */
- + #define ATAPI_VALID_SECOND 0x1 /* == 1 => words 64-70 are valid */
- +
- + u_int16_t current_chs[3]; /* cylinder/head/sector */
- + u_int16_t current_capacity[2];
- + u_int16_t reserved4;
- + u_int16_t user_addressable_sectors[2];
- + u_int16_t singleword_DMA_mode;
- +
- + #define ATAPI_SW_DMA_MODE_AVAIL 0x00ff /* bit 0 set => Mode 0 is supported */
- + #define ATAPI_SW_DMA_MODE_ACTIVE 0xff00 /* which mode is active */
- +
- + u_int16_t multiword_DMA_mode;
- +
- + #define ATAPI_MW_DMA_MODE_AVAIL 0x00ff /* bit 0 set => Mode 0 is supported */
- + #define ATAPI_MW_DMA_MODE_ACTIVE 0xff00 /* which mode is active */
- +
- + u_int16_t enhanced_PIO_mode;
- +
- + #define ATAPI_ENHANCED_PIO_AVAIL 0x0001 /* bit 0 set => PIO Mode 3 is support
- + ed */
- +
- + u_int16_t blind_PIO_minimum_cycles;
- + u_int16_t mw_dma_tct; /* multi-word DMA transfer cycle time */
- + u_int16_t min_PIO_tct_no_flow_control;
- + u_int16_t min_PIO_tct_with_flow_control;
- + u_int16_t reserved5[2];
- + u_int16_t reserved6[57];
- + u_int16_t vendor[32]; /* vendor unique */
- + u_int16_t reserved7[96];
- + };
- +
- + struct at_dev_link {
- + void *device_softc;
- + u_int8_t drive;
- + u_int8_t openings;
- + struct atapi_identify id;
- + struct bus_link *bus;
- + u_int16_t flags;
- + #define ADEV_REMOVABLE 0x001 /* media is removable */
- + #define ADEV_MEDIA_LOADED 0x002 /* device figures are still valid */
- + #define ADEV_WAITING 0x004 /* a process is waiting for this */
- + #define ADEV_OPEN 0x008 /* at least 1 open session */
- + #define ACAP_DRQ_MPROC 0x000 /* microprocessor DRQ */
- + #define ACAP_DRQ_INTR 0x100 /* interrupt DRQ */
- + #define ACAP_DRQ_ACCEL 0x200 /* accelerated DRQ */
- + #define ACAP_LEN 0x400 /* 16 bit commands */
- + void (*start)();
- + int (*done)();
- + };
- +
- + struct atapi_command_packet {
- + void *ad_link;
- + void *command;
- + char cmd_store[16];
- + int command_size;
- + struct buf* bp;
- + void *databuf;
- + int data_size;
- + long flags; /* handle B_READ/B_WRITE mask 0x00f00000 */
- + /* controller flags maks 0x0000000f */
- + /* ATAPI flags mask 0x000000f0 */
- + /* Capabilities flags 0x00000f00 */
- + u_int8_t drive;
- + u_int16_t status;
- + #define STATUS_MASK 0xff
- + #define NO_ERROR 0x00
- + #define ERROR 0x01
- + #define MEDIA_CHANGE 0x02
- + #define END_OF_MEDIA 0x03
- + #define NOT_READY 0x10
- + #define UNIT_ATTENTION 0x20
- + #define RETRY 0x40
- + #define ITSDONE 0x100
- + u_int8_t error;
- + u_int8_t retries;
- + #define ATAPI_NRETRIES 5
- + LIST_ENTRY(atapi_command_packet) free_list;
- + };
- +
- + int wdc_atapi_get_params __P((struct bus_link *,u_int8_t, struct atapi_identify *));
- + void wdc_atapi_send_command_packet __P((struct bus_link*, struct atapi_command_packet*));
- + #define A_POLLED 0x10
- + #define A_NOSLEEP 0x20
- + #define A_SILENT 0x40
- + void atapi_done __P((struct atapi_command_packet *));
- + struct atapi_command_packet *atapi_get_pkt __P((struct at_dev_link *, int));
- + void atapi_free_pkt __P((struct atapi_command_packet *));
- diff --exclude compile -bcrNP src.orig/sys/atapi/files.atapi src/sys/atapi/files.atapi
- *** src.orig/sys/atapi/files.atapi Thu Jan 1 01:00:00 1970
- --- src/sys/atapi/files.atapi Fri Apr 19 16:17:58 1996
- ***************
- *** 0 ****
- --- 1,14 ----
- + #
- + # Config.new file and device description for machine-independent ATAPI code.
- + # Included by ports that need it. Ports that usee it must provide
- + # their own "major" declarations for the appropriate devices.
- +
- + define atapi {}
- + file atapi/atapiconf.c atapi
- +
- + device atapibus {drive = -1}
- + attach atapibus at atapi
- +
- + device acd: disk
- + attach acd at atapibus
- + file atapi/acd.c acd needs-flag
- diff --exclude compile -bcrNP src.orig/sys/dev/isa/files.isa src/sys/dev/isa/files.isa
- *** src.orig/sys/dev/isa/files.isa Thu May 16 20:16:36 1996
- --- src/sys/dev/isa/files.isa Thu Jun 6 12:31:55 1996
- ***************
- *** 109,119 ****
- file dev/isa/scd.c scd needs-flag
-
- # ISA "wd" (ESDI/IDE/etc.) controllers
- ! device wdc {drive = -1}
- attach wdc at isa
- ! device wd: disk, isadma
- ! attach wd at wdc
- ! file dev/isa/wd.c wdc needs-flag
-
- # Wangtek- and Archive-compatible tape controller boards
- device wt: tape, isadma
- --- 109,121 ----
- file dev/isa/scd.c scd needs-flag
-
- # ISA "wd" (ESDI/IDE/etc.) controllers
- ! define ata {drive=-1}
- ! device wdc: atapi, isadma, ata
- attach wdc at isa
- ! device wd: disk
- ! attach wd at ata
- ! file dev/isa/wdc.c wdc needs-flag
- ! file dev/isa/wd.c wd needs-flag
-
- # Wangtek- and Archive-compatible tape controller boards
- device wt: tape, isadma
- diff --exclude compile -bcrNP src.orig/sys/dev/isa/wd.c src/sys/dev/isa/wd.c
- *** src.orig/sys/dev/isa/wd.c Mon May 13 13:36:27 1996
- --- src/sys/dev/isa/wd.c Thu Jun 6 17:48:42 1996
- ***************
- *** 1,1775 ****
- - /* $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 <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/cpu.h>
- - #include <machine/intr.h>
- - #include <machine/pio.h>
- -
- - #include <dev/isa/isavar.h>
- - #include <dev/isa/isadmavar.h>
- - #include <dev/isa/wdreg.h>
- -
- - #define WAITTIME (4 * hz) /* time to wait for a completion */
- - #define RECOVERYTIME (hz / 2) /* time to recover from an error */
- -
- - #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 10
- - #endif
- -
- - #define WDIORETRIES 5 /* number of retries before giving up */
- -
- - #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))
- -
- - struct wd_softc {
- - struct device sc_dev;
- - struct disk sc_dk;
- -
- - /* Information about the current transfer: */
- - daddr_t sc_blkno; /* starting block number */
- - int sc_bcount; /* byte count left */
- - int sc_skip; /* bytes already transferred */
- - int sc_nblks; /* number of blocks currently transferring */
- - int sc_nbytes; /* number of bytes currently transferring */
- -
- - /* Long-term state: */
- - 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 OPEN 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 */
- -
- - struct wdparams sc_params; /* ESDI/ATA drive parameters */
- - daddr_t sc_badsect[127]; /* 126 plus trailing -1 marker */
- -
- - TAILQ_ENTRY(wd_softc) sc_drivechain;
- - struct buf sc_q;
- - };
- -
- - struct wdc_softc {
- - struct device sc_dev;
- - void *sc_ih;
- -
- - int sc_iobase; /* I/O port base */
- - int sc_drq; /* DMA channel */
- -
- - TAILQ_HEAD(drivehead, wd_softc) sc_drives;
- - 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() */
- - int sc_errors; /* errors during current transfer */
- - u_char sc_status; /* copy of status register */
- - u_char sc_error; /* copy of error register */
- - };
- -
- - int wdcprobe __P((struct device *, void *, void *));
- - void wdcattach __P((struct device *, struct device *, void *));
- - int wdcintr __P((void *));
- -
- - struct cfattach wdc_ca = {
- - sizeof(struct wdc_softc), wdcprobe, wdcattach
- - };
- -
- - struct cfdriver wdc_cd = {
- - NULL, "wdc", DV_DULL
- - };
- -
- - int wdprobe __P((struct device *, void *, void *));
- - void wdattach __P((struct device *, struct device *, void *));
- - int wdprint __P((void *, char *));
- -
- - struct cfattach wd_ca = {
- - sizeof(struct wd_softc), wdprobe, wdattach
- - };
- -
- - struct cfdriver wd_cd = {
- - NULL, "wd", DV_DISK
- - };
- -
- - void wdgetdisklabel __P((struct wd_softc *));
- - int wd_get_parms __P((struct wd_softc *));
- - void wdstrategy __P((struct buf *));
- - void wdstart __P((struct wd_softc *));
- -
- - struct dkdriver wddkdriver = { wdstrategy };
- -
- - /* XXX: these should go elsewhere */
- - cdev_decl(wd);
- - bdev_decl(wd);
- -
- - void wdfinish __P((struct wd_softc *, struct buf *));
- - int dcintr __P((void *));
- - void wdcstart __P((struct wdc_softc *));
- - int wdcommand __P((struct wd_softc *, int, int, int, int, int));
- - int wdcommandshort __P((struct wdc_softc *, int, int));
- - int wdcontrol __P((struct wd_softc *));
- - int wdsetctlr __P((struct wd_softc *));
- - static void bad144intern __P((struct wd_softc *));
- - int wdcreset __P((struct wdc_softc *));
- - void wdcrestart __P((void *arg));
- - void wdcunwedge __P((struct wdc_softc *));
- - void wdctimeout __P((void *arg));
- - void wderror __P((void *, struct buf *, char *));
- - int wdcwait __P((struct wdc_softc *, int));
- - int wdlock __P((struct wd_softc *));
- - void wdunlock __P((struct wd_softc *));
- -
- - /* 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_ready(d) wdcwait(d, WDCS_DRDY | WDCS_DSC)
- - #define wait_for_unbusy(d) wdcwait(d, 0)
- -
- - int
- - wdcprobe(parent, match, aux)
- - struct device *parent;
- - void *match, *aux;
- - {
- - struct wdc_softc *wdc = match;
- - struct isa_attach_args *ia = aux;
- - int iobase;
- -
- - wdc->sc_iobase = iobase = ia->ia_iobase;
- -
- - /* Check if we have registers that work. */
- - outb(iobase+wd_error, 0x5a); /* Error register not writable, */
- - outb(iobase+wd_cyl_lo, 0xa5); /* but all of cyllo are. */
- - if (inb(iobase+wd_error) == 0x5a || inb(iobase+wd_cyl_lo) != 0xa5)
- - return 0;
- -
- - if (wdcreset(wdc) != 0) {
- - delay(500000);
- - if (wdcreset(wdc) != 0)
- - return 0;
- - }
- -
- - /* Select drive 0. */
- - outb(iobase+wd_sdh, WDSD_IBM | 0);
- -
- - /* Wait for controller to become ready. */
- - if (wait_for_unbusy(wdc) < 0)
- - return 0;
- -
- - /* Start drive diagnostics. */
- - outb(iobase+wd_command, WDCC_DIAGNOSE);
- -
- - /* Wait for command to complete. */
- - if (wait_for_unbusy(wdc) < 0)
- - return 0;
- -
- - ia->ia_iosize = 8;
- - ia->ia_msize = 0;
- - return 1;
- - }
- -
- - struct wdc_attach_args {
- - int wa_drive;
- - };
- -
- - int
- - wdprint(aux, wdc)
- - void *aux;
- - char *wdc;
- - {
- - struct wdc_attach_args *wa = aux;
- -
- - if (!wdc)
- - printf(" drive %d", wa->wa_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;
- - struct wdc_attach_args wa;
- -
- - TAILQ_INIT(&wdc->sc_drives);
- - 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);
- -
- - for (wa.wa_drive = 0; wa.wa_drive < 2; wa.wa_drive++)
- - (void)config_found(self, (void *)&wa, wdprint);
- - }
- -
- - int
- - wdprobe(parent, match, aux)
- - struct device *parent;
- - void *match, *aux;
- - {
- - struct wdc_softc *wdc = (void *)parent;
- - struct cfdata *cf = match;
- - struct wdc_attach_args *wa = aux;
- - int drive = wa->wa_drive;
- -
- - if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != drive)
- - return 0;
- -
- - if (wdcommandshort(wdc, drive, WDCC_RECAL) != 0 ||
- - wait_for_ready(wdc) != 0)
- - return 0;
- -
- - return 1;
- - }
- -
- - void
- - wdattach(parent, self, aux)
- - struct device *parent, *self;
- - void *aux;
- - {
- - struct wd_softc *wd = (void *)self;
- - struct wdc_softc *wdc = (void *)parent;
- - struct wdc_attach_args *wa = aux;
- - int i, blank;
- - char buf[41], c, *p, *q;
- -
- - wd->sc_drive = wa->wa_drive;
- -
- - /*
- - * 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);
- -
- - wd_get_parms(wd);
- - for (blank = 0, p = wd->sc_params.wdp_model, q = buf, i = 0;
- - i < sizeof(wd->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(": %dMB, %d cyl, %d head, %d sec, %d bytes/sec <%s>\n",
- - wd->sc_params.wdp_cylinders *
- - (wd->sc_params.wdp_heads * wd->sc_params.wdp_sectors) /
- - (1048576 / DEV_BSIZE),
- - wd->sc_params.wdp_cylinders,
- - wd->sc_params.wdp_heads,
- - wd->sc_params.wdp_sectors,
- - DEV_BSIZE,
- - buf);
- -
- - if ((wd->sc_params.wdp_capabilities & WD_CAP_DMA) != 0 &&
- - wdc->sc_drq != DRQUNK) {
- - wd->sc_mode = WDM_DMA;
- - } else if (wd->sc_params.wdp_maxmulti > 1) {
- - wd->sc_mode = WDM_PIOMULTI;
- - wd->sc_multiple = min(wd->sc_params.wdp_maxmulti, 16);
- - } else {
- - wd->sc_mode = WDM_PIOSINGLE;
- - wd->sc_multiple = 1;
- - }
- -
- - printf("%s: using", wd->sc_dev.dv_xname);
- - if (wd->sc_mode == WDM_DMA)
- - printf(" dma transfers,");
- - else
- - printf(" %d-sector %d-bit pio transfers,",
- - wd->sc_multiple, (wd->sc_flags & WDF_32BIT) == 0 ? 16 : 32);
- - if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0)
- - printf(" lba addressing\n");
- - else
- - printf(" chs addressing\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)];
- - 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 ((wd->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_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);
- - if (!wd->sc_q.b_active)
- - wdstart(wd);
- - #if 0
- - else {
- - struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
- - if ((wdc->sc_flags & (WDCF_ACTIVE|WDCF_ERROR)) == 0) {
- - printf("wdstrategy: controller inactive\n");
- - wdcstart(wdc);
- - }
- - }
- - #endif
- - 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(wd)
- - struct wd_softc *wd;
- - {
- - struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
- - int active = wdc->sc_drives.tqh_first != 0;
- -
- - /* Link onto controller queue. */
- - wd->sc_q.b_active = 1;
- - TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, sc_drivechain);
- -
- - disk_busy(&wd->sc_dk);
- -
- - /* If controller not already active, start it. */
- - if (!active)
- - wdcstart(wdc);
- - }
- -
- - /*
- - * Finish an I/O operation. Clean up the drive and controller state, set the
- - * residual count, and inform the upper layers that the operation is complete.
- - */
- - void
- - wdfinish(wd, bp)
- - struct wd_softc *wd;
- - struct buf *bp;
- - {
- - struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
- -
- - wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR);
- - wdc->sc_errors = 0;
- - /*
- - * Move this drive to the end of the queue to give others a `fair'
- - * chance.
- - */
- - if (wd->sc_drivechain.tqe_next) {
- - TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain);
- - if (bp->b_actf) {
- - TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, sc_drivechain);
- - } else
- - wd->sc_q.b_active = 0;
- - }
- - bp->b_resid = wd->sc_bcount;
- - wd->sc_skip = 0;
- - wd->sc_q.b_actf = bp->b_actf;
- -
- - disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid));
- -
- - if (!wd->sc_q.b_actf) {
- - TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain);
- - wd->sc_q.b_active = 0;
- - } else
- - disk_busy(&wd->sc_dk);
- -
- - biodone(bp);
- - }
- -
- - int
- - wdread(dev, uio, flags)
- - dev_t dev;
- - struct uio *uio;
- - int flags;
- - {
- -
- - return (physio(wdstrategy, NULL, dev, B_READ, minphys, uio));
- - }
- -
- - int
- - wdwrite(dev, uio, flags)
- - dev_t dev;
- - struct uio *uio;
- - int flags;
- - {
- -
- - return (physio(wdstrategy, NULL, dev, B_WRITE, minphys, uio));
- - }
- -
- - /*
- - * 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 wd_softc *wd;
- - struct buf *bp;
- - struct disklabel *lp;
- - int nblks;
- -
- - #ifdef DIAGNOSTIC
- - if ((wdc->sc_flags & WDCF_ACTIVE) != 0)
- - panic("wdcstart: controller still active");
- - #endif
- -
- - /*
- - * XXX
- - * This is a kluge. See comments in wd_get_parms().
- - */
- - if ((wdc->sc_flags & WDCF_WANTED) != 0) {
- - wdc->sc_flags &= ~WDCF_WANTED;
- - wakeup(wdc);
- - return;
- - }
- -
- - loop:
- - /* Is there a drive for the controller to do a transfer with? */
- - wd = wdc->sc_drives.tqh_first;
- - if (wd == NULL)
- - return;
- -
- - /* Is there a transfer to this drive? If not, deactivate drive. */
- - bp = wd->sc_q.b_actf;
- -
- - if (wdc->sc_errors >= WDIORETRIES) {
- - wderror(wd, bp, "hard error");
- - bp->b_error = EIO;
- - bp->b_flags |= B_ERROR;
- - wdfinish(wd, bp);
- - goto loop;
- - }
- -
- - /* Do control operations specially. */
- - if (wd->sc_state < OPEN) {
- - /*
- - * 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 (wdcontrol(wd) == 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;
- - wd->sc_skip = 0;
- - }
- - }
- -
- - lp = wd->sc_dk.dk_label;
- -
- - /* When starting a transfer... */
- - if (wd->sc_skip == 0) {
- - int part = WDPART(bp->b_dev);
- - daddr_t blkno;
- -
- - #ifdef WDDEBUG
- - printf("\n%s: wdcstart %s %d@%d; map ", wd->sc_dev.dv_xname,
- - (bp->b_flags & B_READ) ? "read" : "write", bp->b_bcount,
- - bp->b_blkno);
- - #endif
- - wd->sc_bcount = bp->b_bcount;
- - blkno = bp->b_blkno;
- - if (part != RAW_PART)
- - blkno += lp->d_partitions[part].p_offset;
- - wd->sc_blkno = blkno / (lp->d_secsize / DEV_BSIZE);
- - } else {
- - #ifdef WDDEBUG
- - printf(" %d)%x", wd->sc_skip, inb(wd->sc_iobase+wd_altsts));
- - #endif
- - }
- -
- - /* When starting a multi-sector transfer, or doing single-sector
- - transfers... */
- - if (wd->sc_skip == 0 || (wdc->sc_flags & WDCF_SINGLE) != 0 ||
- - wd->sc_mode == WDM_DMA) {
- - daddr_t blkno = wd->sc_blkno;
- - long cylin, head, sector;
- - int command;
- -
- - if ((wdc->sc_flags & WDCF_SINGLE) != 0)
- - nblks = 1;
- - else if (wd->sc_mode != WDM_DMA)
- - nblks = wd->sc_bcount / lp->d_secsize;
- - else
- - nblks = min(wd->sc_bcount / lp->d_secsize, 8);
- -
- - /* Check for bad sectors and adjust transfer, if necessary. */
- - if ((lp->d_flags & D_BADSECT) != 0
- - #ifdef B_FORMAT
- - && (bp->b_flags & B_FORMAT) == 0
- - #endif
- - ) {
- - long blkdiff;
- - int i;
- -
- - for (i = 0; (blkdiff = wd->sc_badsect[i]) != -1; i++) {
- - blkdiff -= blkno;
- - if (blkdiff < 0)
- - continue;
- - if (blkdiff == 0) {
- - /* Replace current block of transfer. */
- - blkno =
- - lp->d_secperunit - 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 ((wd->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 % lp->d_nsectors;
- - sector++; /* Sectors begin with 1, not 0. */
- - blkno /= lp->d_nsectors;
- - head = blkno % lp->d_ntracks;
- - blkno /= lp->d_ntracks;
- - cylin = blkno;
- - head |= WDSD_CHS;
- - }
- -
- - if (wd->sc_mode == WDM_PIOSINGLE ||
- - (wdc->sc_flags & WDCF_SINGLE) != 0)
- - wd->sc_nblks = 1;
- - else if (wd->sc_mode == WDM_PIOMULTI)
- - wd->sc_nblks = min(nblks, wd->sc_multiple);
- - else
- - wd->sc_nblks = nblks;
- - wd->sc_nbytes = wd->sc_nblks * lp->d_secsize;
- -
- - #ifdef B_FORMAT
- - if (bp->b_flags & B_FORMAT) {
- - sector = lp->d_gap3;
- - nblks = lp->d_nsectors;
- - command = WDCC_FORMAT;
- - } else
- - #endif
- - switch (wd->sc_mode) {
- - case WDM_DMA:
- - command = (bp->b_flags & B_READ) ?
- - WDCC_READDMA : WDCC_WRITEDMA;
- - /* Start the DMA channel and bounce the buffer if
- - necessary. */
- - isa_dmastart(
- - bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE,
- - bp->b_data + wd->sc_skip,
- - wd->sc_nbytes, wdc->sc_drq);
- - break;
- - case WDM_PIOMULTI:
- - command = (bp->b_flags & B_READ) ?
- - WDCC_READMULTI : WDCC_WRITEMULTI;
- - break;
- - case WDM_PIOSINGLE:
- - command = (bp->b_flags & B_READ) ?
- - WDCC_READ : WDCC_WRITE;
- - break;
- - default:
- - #ifdef DIAGNOSTIC
- - panic("bad wd mode");
- - #endif
- - return;
- - }
- -
- - /* Initiate command! */
- - if (wdcommand(wd, command, cylin, head, sector, nblks) != 0) {
- - wderror(wd, NULL,
- - "wdcstart: timeout waiting for unbusy");
- - wdcunwedge(wdc);
- - return;
- - }
- -
- - #ifdef WDDEBUG
- - printf("sector %d cylin %d head %d addr %x sts %x\n", sector,
- - cylin, head, bp->b_data, inb(wd->sc_iobase+wd_altsts));
- - #endif
- - } else if (wd->sc_nblks > 1) {
- - /* The number of blocks in the last stretch may be smaller. */
- - nblks = wd->sc_bcount / lp->d_secsize;
- - if (wd->sc_nblks > nblks) {
- - wd->sc_nblks = nblks;
- - wd->sc_nbytes = wd->sc_bcount;
- - }
- - }
- -
- - /* If this was a write and not using DMA, push the data. */
- - if (wd->sc_mode != WDM_DMA &&
- - (bp->b_flags & (B_READ|B_WRITE)) == B_WRITE) {
- - if (wait_for_drq(wdc) < 0) {
- - wderror(wd, NULL, "wdcstart: timeout waiting for drq");
- - wdcunwedge(wdc);
- - return;
- - }
- -
- - /* Push out data. */
- - if ((wd->sc_flags & WDF_32BIT) == 0)
- - outsw(wdc->sc_iobase+wd_data, bp->b_data + wd->sc_skip,
- - wd->sc_nbytes >> 1);
- - else
- - outsl(wdc->sc_iobase+wd_data, bp->b_data + wd->sc_skip,
- - wd->sc_nbytes >> 2);
- - }
- -
- - wdc->sc_flags |= WDCF_ACTIVE;
- - timeout(wdctimeout, wdc, WAITTIME);
- - }
- -
- - /*
- - * 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 wd_softc *wd;
- - struct buf *bp;
- -
- - if ((wdc->sc_flags & WDCF_ACTIVE) == 0) {
- - /* Clear the pending interrupt and abort. */
- - (void) inb(wdc->sc_iobase+wd_status);
- - return 0;
- - }
- -
- - wdc->sc_flags &= ~WDCF_ACTIVE;
- - untimeout(wdctimeout, wdc);
- -
- - wd = wdc->sc_drives.tqh_first;
- - bp = wd->sc_q.b_actf;
- -
- - #ifdef WDDEBUG
- - printf("I%d ", ctrlr);
- - #endif
- -
- - if (wait_for_unbusy(wdc) < 0) {
- - wderror(wd, NULL, "wdcintr: timeout waiting for unbusy");
- - wdc->sc_status |= WDCS_ERR; /* XXX */
- - }
- -
- - /* Is it not a transfer, but a control operation? */
- - if (wd->sc_state < OPEN) {
- - if (wdcontrol(wd) == 0) {
- - /* The drive is busy. Wait. */
- - return 1;
- - }
- - wdcstart(wdc);
- - return 1;
- - }
- -
- - /* Turn off the DMA channel and unbounce the buffer. */
- - if (wd->sc_mode == WDM_DMA)
- - isa_dmadone(bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE,
- - bp->b_data + wd->sc_skip, wd->sc_nbytes, wdc->sc_drq);
- -
- - /* Have we an error? */
- - if (wdc->sc_status & WDCS_ERR) {
- - #ifdef WDDEBUG
- - wderror(wd, NULL, "wdcintr");
- - #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 (++wdc->sc_errors < WDIORETRIES)
- - goto restart;
- - wderror(wd, bp, "hard error");
- -
- - #ifdef B_FORMAT
- - bad:
- - #endif
- - bp->b_error = EIO;
- - bp->b_flags |= B_ERROR;
- - goto done;
- - }
- -
- - /* If this was a read and not using DMA, fetch the data. */
- - if (wd->sc_mode != WDM_DMA &&
- - (bp->b_flags & (B_READ|B_WRITE)) == B_READ) {
- - if ((wdc->sc_status & (WDCS_DRDY | WDCS_DSC | WDCS_DRQ))
- - != (WDCS_DRDY | WDCS_DSC | WDCS_DRQ)) {
- - wderror(wd, NULL, "wdcintr: read intr before drq");
- - wdcunwedge(wdc);
- - return 1;
- - }
- -
- - /* Pull in data. */
- - if ((wd->sc_flags & WDF_32BIT) == 0)
- - insw(wdc->sc_iobase+wd_data, bp->b_data + wd->sc_skip,
- - wd->sc_nbytes >> 1);
- - else
- - insl(wdc->sc_iobase+wd_data, bp->b_data + wd->sc_skip,
- - wd->sc_nbytes >> 2);
- - }
- -
- - /* If we encountered any abnormalities, flag it as a soft error. */
- - if (wdc->sc_errors > 0 ||
- - (wdc->sc_status & WDCS_CORR) != 0) {
- - wderror(wd, bp, "soft error (corrected)");
- - wdc->sc_errors = 0;
- - }
- -
- - /* Adjust pointers for the next block, if any. */
- - wd->sc_blkno += wd->sc_nblks;
- - wd->sc_skip += wd->sc_nbytes;
- - wd->sc_bcount -= wd->sc_nbytes;
- -
- - /* See if this transfer is complete. */
- - if (wd->sc_bcount > 0)
- - goto restart;
- -
- - done:
- - /* Done with this transfer, with or without error. */
- - wdfinish(wd, bp);
- -
- - restart:
- - /* Start the next operation, if any. */
- - wdcstart(wdc);
- -
- - return 1;
- - }
- -
- - /*
- - * Wait interruptibly for an exclusive lock.
- - *
- - * XXX
- - * Several drivers do this; it should be abstracted and made MP-safe.
- - */
- - int
- - wdlock(wd)
- - struct wd_softc *wd;
- - {
- - int error;
- -
- - while ((wd->sc_flags & WDF_LOCKED) != 0) {
- - wd->sc_flags |= WDF_WANTED;
- - if ((error = tsleep(wd, PRIBIO | PCATCH, "wdlck", 0)) != 0)
- - return error;
- - }
- - wd->sc_flags |= WDF_LOCKED;
- - return 0;
- - }
- -
- - /*
- - * Unlock and wake up any waiters.
- - */
- - void
- - wdunlock(wd)
- - struct wd_softc *wd;
- - {
- -
- - wd->sc_flags &= ~WDF_LOCKED;
- - if ((wd->sc_flags & WDF_WANTED) != 0) {
- - wd->sc_flags &= ~WDF_WANTED;
- - wakeup(wd);
- - }
- - }
- -
- - int
- - wdopen(dev, flag, fmt, p)
- - dev_t dev;
- - int flag, fmt;
- - struct proc *p;
- - {
- - struct wd_softc *wd;
- - int unit, part;
- - int error;
- -
- - unit = WDUNIT(dev);
- - if (unit >= wd_cd.cd_ndevs)
- - return ENXIO;
- - wd = wd_cd.cd_devs[unit];
- - if (wd == 0)
- - return ENXIO;
- -
- - if ((error = wdlock(wd)) != 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 ((wd->sc_flags & WDF_LOADED) == 0) {
- - error = EIO;
- - goto bad3;
- - }
- - } else {
- - if ((wd->sc_flags & WDF_LOADED) == 0) {
- - wd->sc_flags |= WDF_LOADED;
- -
- - /* Load the physical device parameters. */
- - if (wd_get_parms(wd) != 0) {
- - error = ENXIO;
- - goto bad2;
- - }
- -
- - /* Load the partition info if not already loaded. */
- - wdgetdisklabel(wd);
- - }
- - }
- -
- - 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(wd);
- - return 0;
- -
- - bad2:
- - wd->sc_flags &= ~WDF_LOADED;
- -
- - bad:
- - if (wd->sc_dk.dk_openmask == 0) {
- - }
- -
- - bad3:
- - wdunlock(wd);
- - 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)) != 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);
- - return 0;
- - }
- -
- - /*
- - * Fabricate a default disk label, and try to read the correct one.
- - */
- - void
- - wdgetdisklabel(wd)
- - struct wd_softc *wd;
- - {
- - struct disklabel *lp = wd->sc_dk.dk_label;
- - char *errstring;
- -
- - bzero(lp, sizeof(struct disklabel));
- - bzero(wd->sc_dk.dk_cpulabel, sizeof(struct cpu_disklabel));
- -
- - lp->d_secsize = DEV_BSIZE;
- - lp->d_ntracks = wd->sc_params.wdp_heads;
- - lp->d_nsectors = wd->sc_params.wdp_sectors;
- - lp->d_ncylinders = wd->sc_params.wdp_cylinders;
- - lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
- -
- - #if 0
- - strncpy(lp->d_typename, "ST506 disk", 16);
- - lp->d_type = DTYPE_ST506;
- - #endif
- - strncpy(lp->d_packname, wd->sc_params.wdp_model, 16);
- - lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
- - 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);
- -
- - wd->sc_badsect[0] = -1;
- -
- - if (wd->sc_state > RECAL)
- - wd->sc_state = RECAL;
- - errstring = readdisklabel(MAKEWDDEV(0, wd->sc_dev.dv_unit, RAW_PART),
- - wdstrategy, lp, wd->sc_dk.dk_cpulabel);
- - 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 (wd->sc_state > GEOMETRY)
- - wd->sc_state = GEOMETRY;
- - errstring = readdisklabel(MAKEWDDEV(0, wd->sc_dev.dv_unit, RAW_PART),
- - wdstrategy, lp, wd->sc_dk.dk_cpulabel);
- - }
- - if (errstring) {
- - printf("%s: %s\n", wd->sc_dev.dv_xname, errstring);
- - return;
- - }
- -
- - if (wd->sc_state > GEOMETRY)
- - wd->sc_state = GEOMETRY;
- - if ((lp->d_flags & D_BADSECT) != 0)
- - bad144intern(wd);
- - }
- -
- - /*
- - * Implement operations needed before read/write.
- - * Returns 0 if operation still in progress, 1 if completed.
- - */
- - int
- - wdcontrol(wd)
- - struct wd_softc *wd;
- - {
- - struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
- -
- - switch (wd->sc_state) {
- - case RECAL: /* Set SDH, step rate, do recal. */
- - if (wdcommandshort(wdc, wd->sc_drive, WDCC_RECAL) != 0) {
- - wderror(wd, NULL, "wdcontrol: recal failed (1)");
- - goto bad;
- - }
- - wd->sc_state = RECAL_WAIT;
- - break;
- -
- - case RECAL_WAIT:
- - if (wdc->sc_status & WDCS_ERR) {
- - wderror(wd, NULL, "wdcontrol: recal failed (2)");
- - goto bad;
- - }
- - /* fall through */
- - case GEOMETRY:
- - if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0)
- - goto multimode;
- - if (wdsetctlr(wd) != 0) {
- - /* Already printed a message. */
- - goto bad;
- - }
- - wd->sc_state = GEOMETRY_WAIT;
- - break;
- -
- - case GEOMETRY_WAIT:
- - if (wdc->sc_status & WDCS_ERR) {
- - wderror(wd, NULL, "wdcontrol: geometry failed");
- - goto bad;
- - }
- - /* fall through */
- - case MULTIMODE:
- - multimode:
- - if (wd->sc_mode != WDM_PIOMULTI)
- - goto open;
- - outb(wdc->sc_iobase+wd_seccnt, wd->sc_multiple);
- - if (wdcommandshort(wdc, wd->sc_drive, WDCC_SETMULTI) != 0) {
- - wderror(wd, NULL, "wdcontrol: setmulti failed (1)");
- - goto bad;
- - }
- - wd->sc_state = MULTIMODE_WAIT;
- - break;
- -
- - case MULTIMODE_WAIT:
- - if (wdc->sc_status & WDCS_ERR) {
- - wderror(wd, NULL, "wdcontrol: setmulti failed (2)");
- - goto bad;
- - }
- - /* fall through */
- - case OPEN:
- - open:
- - wdc->sc_errors = 0;
- - wd->sc_state = OPEN;
- - /*
- - * The rest of the initialization can be done by normal means.
- - */
- - return 1;
- -
- - bad:
- - wdcunwedge(wdc);
- - return 0;
- - }
- -
- - wdc->sc_flags |= WDCF_ACTIVE;
- - timeout(wdctimeout, wdc, WAITTIME);
- - return 0;
- - }
- -
- - /*
- - * 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
- - wdcommand(wd, command, cylin, head, sector, count)
- - struct wd_softc *wd;
- - int command;
- - int cylin, head, sector, count;
- - {
- - struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
- - int iobase = wdc->sc_iobase;
- - int stat;
- -
- - /* Select drive, head, and addressing mode. */
- - outb(iobase+wd_sdh, WDSD_IBM | (wd->sc_drive << 4) | head);
- -
- - /* Wait for it to become ready to accept a command. */
- - if (command == WDCC_IDP)
- - stat = wait_for_unbusy(wdc);
- - else
- - stat = wdcwait(wdc, WDCS_DRDY);
- - if (stat < 0)
- - return -1;
- -
- - /* Load parameters. */
- - if (wd->sc_dk.dk_label->d_type == DTYPE_ST506)
- - outb(iobase+wd_precomp, wd->sc_dk.dk_label->d_precompcyl / 4);
- - else
- - outb(iobase+wd_features, 0);
- - outb(iobase+wd_cyl_lo, cylin);
- - outb(iobase+wd_cyl_hi, cylin >> 8);
- - outb(iobase+wd_sector, sector);
- - outb(iobase+wd_seccnt, count);
- -
- - /* Send command. */
- - outb(iobase+wd_command, command);
- -
- - return 0;
- - }
- -
- - /*
- - * Simplified version of wdcommand().
- - */
- - int
- - wdcommandshort(wdc, drive, command)
- - struct wdc_softc *wdc;
- - int drive;
- - int command;
- - {
- - int iobase = wdc->sc_iobase;
- -
- - /* Select drive. */
- - outb(iobase+wd_sdh, WDSD_IBM | (drive << 4));
- -
- - if (wdcwait(wdc, WDCS_DRDY) < 0)
- - return -1;
- -
- - outb(iobase+wd_command, command);
- -
- - return 0;
- - }
- -
- - /*
- - * Tell the drive what geometry to use.
- - */
- - int
- - wdsetctlr(wd)
- - struct wd_softc *wd;
- - {
- -
- - #ifdef WDDEBUG
- - printf("wd(%d,%d) C%dH%dS%d\n", wd->sc_dev.dv_unit, wd->sc_drive,
- - wd->sc_dk.dk_label->d_ncylinders, wd->sc_dk.dk_label->d_ntracks,
- - wd->sc_dk.dk_label->d_nsectors);
- - #endif
- -
- - if (wdcommand(wd, WDCC_IDP, 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(wd, NULL, "wdsetctlr: geometry upload failed");
- - return -1;
- - }
- -
- - return 0;
- - }
- -
- - /*
- - * Get the drive parameters, if ESDI or ATA, or create fake ones for ST506.
- - */
- - int
- - wd_get_parms(wd)
- - struct wd_softc *wd;
- - {
- - struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
- - int i;
- - char tb[DEV_BSIZE];
- - 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;
- - if ((error = tsleep(wdc, PRIBIO | PCATCH, "wdprm", 0)) != 0) {
- - splx(s);
- - return error;
- - }
- - }
- -
- - if (wdcommandshort(wdc, wd->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(wd->sc_dk.dk_label->d_typename, "ST506",
- - sizeof wd->sc_dk.dk_label->d_typename);
- - wd->sc_dk.dk_label->d_type = DTYPE_ST506;
- -
- - strncpy(wd->sc_params.wdp_model, "unknown",
- - sizeof wd->sc_params.wdp_model);
- - wd->sc_params.wdp_config = WD_CFG_FIXED;
- - wd->sc_params.wdp_cylinders = 1024;
- - wd->sc_params.wdp_heads = 8;
- - wd->sc_params.wdp_sectors = 17;
- - wd->sc_params.wdp_maxmulti = 0;
- - wd->sc_params.wdp_usedmovsd = 0;
- - wd->sc_params.wdp_capabilities = 0;
- - } else {
- - strncpy(wd->sc_dk.dk_label->d_typename, "ESDI/IDE",
- - sizeof wd->sc_dk.dk_label->d_typename);
- - wd->sc_dk.dk_label->d_type = DTYPE_ESDI;
- -
- - /* Read in parameter block. */
- - insw(wdc->sc_iobase+wd_data, tb, sizeof(tb) / sizeof(short));
- - bcopy(tb, &wd->sc_params, sizeof(struct wdparams));
- -
- - /* Shuffle string byte order. */
- - for (i = 0; i < sizeof(wd->sc_params.wdp_model); i += 2) {
- - u_short *p;
- - p = (u_short *)(wd->sc_params.wdp_model + i);
- - *p = ntohs(*p);
- - }
- - }
- -
- - /* Clear any leftover interrupt. */
- - (void) inb(wdc->sc_iobase+wd_status);
- -
- - /* Restart the queue. */
- - wdcstart(wdc);
- -
- - splx(s);
- - return 0;
- - }
- -
- - int
- - wdioctl(dev, cmd, addr, flag, p)
- - dev_t dev;
- - u_long cmd;
- - caddr_t addr;
- - int flag;
- - struct proc *p;
- - {
- - struct wd_softc *wd = wd_cd.cd_devs[WDUNIT(dev)];
- - int error;
- -
- - if ((wd->sc_flags & WDF_LOADED) == 0)
- - return EIO;
- -
- - switch (cmd) {
- - case DIOCSBAD:
- - if ((flag & FWRITE) == 0)
- - return EBADF;
- - wd->sc_dk.dk_cpulabel->bad = *(struct dkbad *)addr;
- - wd->sc_dk.dk_label->d_flags |= D_BADSECT;
- - bad144intern(wd);
- - 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)) != 0)
- - return error;
- - wd->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 (wd->sc_state > GEOMETRY)
- - wd->sc_state = GEOMETRY;
- - if (cmd == DIOCWDINFO)
- - error = writedisklabel(WDLABELDEV(dev),
- - wdstrategy, wd->sc_dk.dk_label,
- - wd->sc_dk.dk_cpulabel);
- - }
- -
- - wd->sc_flags &= ~WDF_LABELLING;
- - wdunlock(wd);
- - return error;
- -
- - case DIOCWLABEL:
- - if ((flag & FWRITE) == 0)
- - return EBADF;
- - if (*(int *)addr)
- - wd->sc_flags |= WDF_WLABEL;
- - else
- - wd->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;
- - int size;
- -
- - if (wdopen(dev, 0, S_IFBLK, NULL) != 0)
- - return -1;
- - wd = wd_cd.cd_devs[WDUNIT(dev)];
- - part = WDPART(dev);
- - 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;
- - if (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.
- - */
- - 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 */
- - 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 == 0)
- - return ENXIO;
- -
- - part = WDPART(dev);
- -
- - /* Make sure it was initialized. */
- - if (wd->sc_state < OPEN)
- - 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 (wdcommandshort(wdc, wd->sc_drive, WDCC_RECAL) != 0 ||
- - wait_for_ready(wdc) != 0 || wdsetctlr(wd) != 0 ||
- - wait_for_ready(wdc) != 0) {
- - wderror(wd, NULL, "wddump: recal failed");
- - return EIO;
- - }
- - }
- -
- - while (nblks > 0) {
- - daddr_t xlt_blkno = blkno;
- - long cylin, head, sector;
- -
- - if ((lp->d_flags & D_BADSECT) != 0) {
- - long blkdiff;
- - int i;
- -
- - for (i = 0; (blkdiff = wd->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 ((wd->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 (wdcommand(wd, WDCC_WRITE, cylin, head, sector, 1) != 0 ||
- - wait_for_drq(wdc) != 0) {
- - wderror(wd, NULL, "wddump: write failed");
- - return EIO;
- - }
- -
- - outsw(wdc->sc_iobase+wd_data, va, lp->d_secsize >> 1);
- -
- - /* Check data request (should be done). */
- - if (wait_for_ready(wdc) != 0) {
- - wderror(wd, 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 */
- -
- - /*
- - * Internalize the bad sector table.
- - */
- - void
- - bad144intern(wd)
- - struct wd_softc *wd;
- - {
- - struct dkbad *bt = &wd->sc_dk.dk_cpulabel->bad;
- - struct disklabel *lp = wd->sc_dk.dk_label;
- - int i = 0;
- -
- - for (; i < 126; i++) {
- - if (bt->bt_bad[i].bt_cyl == 0xffff)
- - break;
- - wd->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++)
- - wd->sc_badsect[i] = -1;
- - }
- -
- - int
- - wdcreset(wdc)
- - struct wdc_softc *wdc;
- - {
- - int iobase = wdc->sc_iobase;
- -
- - /* Reset the device. */
- - outb(iobase+wd_ctlr, WDCTL_RST | WDCTL_IDS);
- - delay(1000);
- - outb(iobase+wd_ctlr, WDCTL_IDS);
- - delay(1000);
- - (void) inb(iobase+wd_error);
- - outb(iobase+wd_ctlr, WDCTL_4BIT);
- -
- - if (wait_for_unbusy(wdc) < 0) {
- - 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;
- -
- - untimeout(wdctimeout, wdc);
- - (void) wdcreset(wdc);
- -
- - /* Schedule recalibrate for all drives on this controller. */
- - for (unit = 0; unit < wd_cd.cd_ndevs; unit++) {
- - struct wd_softc *wd = wd_cd.cd_devs[unit];
- - if (!wd || (void *)wd->sc_dev.dv_parent != wdc)
- - continue;
- - if (wd->sc_state > RECAL)
- - wd->sc_state = RECAL;
- - }
- -
- - wdc->sc_flags |= WDCF_ERROR;
- - ++wdc->sc_errors;
- -
- - /* Wake up in a little bit and restart the operation. */
- - timeout(wdcrestart, wdc, RECOVERYTIME);
- - }
- -
- - int
- - wdcwait(wdc, mask)
- - struct wdc_softc *wdc;
- - int mask;
- - {
- - int iobase = wdc->sc_iobase;
- - int timeout = 0;
- - u_char status;
- - #ifdef WDCNDELAY_DEBUG
- - extern int cold;
- - #endif
- -
- - for (;;) {
- - wdc->sc_status = status = inb(iobase+wd_status);
- - if ((status & WDCS_BSY) == 0 && (status & mask) == mask)
- - break;
- - if (++timeout > WDCNDELAY)
- - return -1;
- - delay(WDCDELAY);
- - }
- - if (status & WDCS_ERR) {
- - wdc->sc_error = inb(iobase+wd_error);
- - return WDCS_ERR;
- - }
- - #ifdef WDCNDELAY_DEBUG
- - /* After autoconfig, there should be no long delays. */
- - if (!cold && timeout > WDCNDELAY_DEBUG)
- - printf("%s: warning: busy-wait took %dus\n",
- - wdc->sc_dev.dv_xname, WDCDELAY * timeout);
- - #endif
- - return 0;
- - }
- -
- - void
- - wdctimeout(arg)
- - void *arg;
- - {
- - struct wdc_softc *wdc = (struct wdc_softc *)arg;
- - int s;
- -
- - s = splbio();
- - if ((wdc->sc_flags & WDCF_ACTIVE) != 0) {
- - struct wd_softc *wd = wdc->sc_drives.tqh_first;
- - struct buf *bp = wd->sc_q.b_actf;
- -
- - wdc->sc_flags &= ~WDCF_ACTIVE;
- - wderror(wdc, NULL, "lost interrupt");
- - printf("%s: lost interrupt: %sing %d@%s:%d\n",
- - wdc->sc_dev.dv_xname,
- - (bp->b_flags & B_READ) ? "read" : "writ",
- - wd->sc_nblks, wd->sc_dev.dv_xname, wd->sc_blkno);
- - wdcunwedge(wdc);
- - } else
- - wderror(wdc, NULL, "missing untimeout");
- - splx(s);
- - }
- -
- - void
- - wderror(dev, bp, msg)
- - void *dev;
- - struct buf *bp;
- - char *msg;
- - {
- - struct wd_softc *wd = dev;
- - struct wdc_softc *wdc = dev;
- -
- - if (bp) {
- - diskerr(bp, "wd", msg, LOG_PRINTF, wd->sc_skip / DEV_BSIZE,
- - wd->sc_dk.dk_label);
- - printf("\n");
- - } else
- - printf("%s: %s: status %b error %b\n", wdc->sc_dev.dv_xname,
- - msg, wdc->sc_status, WDCS_BITS, wdc->sc_error, WDERR_BITS);
- - }
- --- 0 ----
- diff --exclude compile -bcrNP src.orig/sys/dev/isa/wd.c src/sys/dev/isa/wd.c
- *** src.orig/sys/dev/isa/wd.c Thu Jan 1 01:00:00 1970
- --- src/sys/dev/isa/wd.c Thu Jun 6 12:21:06 1996
- ***************
- *** 0 ****
- --- 1,852 ----
- + /* $NetBSD: wd.c,v 1.142 1995/08/05 23:50:23 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 <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/cpu.h>
- + #include <machine/pio.h>
- +
- + #include <dev/isa/isavar.h>
- + #include <dev/isa/wdreg.h>
- + #include <dev/isa/wdlink.h>
- +
- + #define WAITTIME (4 * hz) /* time to wait for a completion */
- +
- + #define WDIORETRIES 5 /* number of retries before giving up */
- +
- + #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))
- +
- + 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 *));
- +
- + struct cfdriver wd_cd = {
- + NULL, "wd", DV_DISK
- + };
- +
- + struct cfattach wd_ca = {
- + sizeof(struct wd_softc), wdprobe, wdattach
- + };
- +
- +
- + void wdgetdisklabel __P((struct wd_softc *));
- + void wdstrategy __P((struct buf *));
- + void wdstart __P((struct wd_softc *));
- +
- + struct dkdriver wddkdriver = { wdstrategy };
- +
- + int wdlock __P((struct wd_link *));
- + void wdunlock __P((struct wd_link *));
- +
- + int wdsetctlr __P((struct wd_link *));
- + static void bad144intern __P((struct wd_softc *));
- +
- + int
- + wdprobe(parent, match, aux)
- + struct device *parent;
- + void *match, *aux;
- + {
- + caddr_t *wdc = (void *)parent;
- + 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 caddr_t *wdc = (void *)parent;
- + 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);
- +
- + 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(": %dMB, %d cyl, %d head, %d sec, %d bytes/sec <%s>\n",
- + 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,
- + buf);
- +
- + if ((d_link->sc_params.wdp_capabilities & WD_CAP_DMA) != 0 &&
- + d_link->sc_mode == WDM_DMA) {
- + d_link->sc_mode = WDM_DMA;
- + } else 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 (d_link->sc_mode == WDM_DMA)
- + printf(" dma transfers,");
- + else
- + 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\n");
- + else
- + printf(" chs addressing\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,
- + (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(wd)
- + struct wd_softc *wd;
- + {
- + 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;
- + int blkno, nblks;
- + u_long 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_bcount = bp->b_bcount;
- + xfer->c_flags |= bp->b_flags & (B_READ|B_WRITE);
- + xfer->c_blkno = bp->b_blkno;
- +
- + /* 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;
- + {
- + #ifdef WDDEBUG
- + printf("wdread\n");
- + #endif
- + return (physio(wdstrategy, NULL, dev, B_READ, minphys, uio));
- + }
- +
- + int
- + wdwrite(dev, uio, flags)
- + dev_t dev;
- + struct uio *uio;
- + int flags;
- + {
- + #ifdef WDDEBUG
- + printf("wdwrite\n");
- + #endif
- +
- + 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;
- +
- + #ifdef WDDEBUG
- + printf("wdlock\n");
- + #endif
- + 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;
- + {
- + #ifdef WDDEBUG
- + printf("wdunlock\n");
- + #endif
- +
- + 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;
- +
- + #ifdef WDDEBUG
- + printf("wdopen\n");
- + #endif
- +
- +
- + 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(wd);
- + }
- + }
- +
- + 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(wd)
- + struct wd_softc *wd;
- + {
- + struct disklabel *lp = wd->sc_dk.dk_label;
- + struct wd_link *d_link = wd->d_link;
- + char *errstring;
- +
- + #ifdef WDDEBUG
- + printf("wdgetdisklabel\n");
- + #endif
- +
- + bzero(lp, sizeof(struct disklabel));
- + bzero(wd->sc_dk.dk_cpulabel, 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;
- +
- + #if 0
- + strncpy(lp->d_typename, "ST506 disk", 16);
- + lp->d_type = DTYPE_ST506;
- + #endif
- + strncpy(lp->d_packname, d_link->sc_params.wdp_model, 16);
- + lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
- + 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;
- + errstring = readdisklabel(MAKEWDDEV(0, wd->sc_dev.dv_unit, RAW_PART),
- + wdstrategy, lp, wd->sc_dk.dk_cpulabel);
- + 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(MAKEWDDEV(0, wd->sc_dev.dv_unit, RAW_PART),
- + wdstrategy, lp, wd->sc_dk.dk_cpulabel);
- + }
- + if (errstring) {
- + printf("%s: %s\n", wd->sc_dev.dv_xname, errstring);
- + return;
- + }
- +
- + if (d_link->sc_state > GEOMETRY)
- + d_link->sc_state = GEOMETRY;
- + if ((lp->d_flags & D_BADSECT) != 0)
- + bad144intern(wd);
- + }
- +
- +
- + /*
- + * 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;
- +
- + #ifdef WDDEBUG
- + printf("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);
- + #endif
- +
- + 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;
- + #ifdef WDDEBUG
- + printf("wdioctl\n");
- + #endif
- +
- + if ((d_link->sc_flags & WDF_LOADED) == 0)
- + return EIO;
- +
- + switch (xfer) {
- + case DIOCSBAD:
- + if ((flag & FWRITE) == 0)
- + return EBADF;
- + wd->sc_dk.dk_cpulabel->bad = *(struct dkbad *)addr;
- + wd->sc_dk.dk_label->d_flags |= D_BADSECT;
- + bad144intern(wd);
- + 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;
- + int size;
- + #ifdef WDDEBUG
- + printf("wdsize\n");
- + #endif
- +
- + if (wdopen(dev, 0, S_IFBLK, NULL) != 0)
- + return -1;
- + wd = wd_cd.cd_devs[WDUNIT(dev)];
- + part = WDPART(dev);
- + 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;
- + if (wdclose(dev, 0, S_IFBLK, NULL) != 0)
- + return -1;
- + return size;
- + }
- +
- +
- + #ifndef __BDEVSW_DUMP_OLD_TYPE
- + static int wddoingadump;
- + static int wddumprecalibrated;
- +
- + /*
- + * Dump core after a system crash.
- + */
- + 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 wd_link *d_link; /* link struct for this disk */
- + struct disklabel *lp; /* disk's disklabel */
- + int unit, part;
- + int nblks; /* total number of sectors left to write */
- + int err;
- +
- + /* 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];
- + d_link = wd->d_link;
- + if (wd == 0)
- + return ENXIO;
- +
- + part = WDPART(dev);
- +
- + /* Make sure it was initialized. */
- + if (d_link->sc_state < OPEN)
- + return ENXIO;
- +
- + /* 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;
- +
- + err = wdcdump(d_link, blkno, nblks, va);
- + if (err == 0) {
- + wddoingadump = 0;
- + }
- + return err;
- + }
- + #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 */
- +
- + /*
- + * Internalize the bad sector table.
- + */
- + void
- + bad144intern(wd)
- + struct wd_softc *wd;
- + {
- + struct dkbad *bt = &wd->sc_dk.dk_cpulabel->bad;
- + struct disklabel *lp = wd->sc_dk.dk_label;
- + struct wd_link *d_link = wd->d_link;
- + int i = 0;
- +
- + #ifdef WDDEBUG
- + printf("bad144intern\n");
- + #endif
- +
- + 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;
- + }
- +
- + 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 --exclude compile -bcrNP src.orig/sys/dev/isa/wdc.c src/sys/dev/isa/wdc.c
- *** src.orig/sys/dev/isa/wdc.c Thu Jan 1 01:00:00 1970
- --- src/sys/dev/isa/wdc.c Thu Jun 6 12:21:06 1996
- ***************
- *** 0 ****
- --- 1,1733 ----
- + /* $NetBSD: wd.c,v 1.142 1995/08/05 23:50:23 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.
- + */
- +
- + #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/cpu.h>
- + #include <machine/intr.h>
- + #include <machine/pio.h>
- +
- + #include <dev/isa/isavar.h>
- + #include <dev/isa/isadmavar.h>
- + #include <dev/isa/wdreg.h>
- + #include <dev/isa/wdlink.h>
- + #include <atapi/atapilink.h>
- +
- + #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 5 /* number of retries before giving up */
- +
- + #define WDPART(dev) DISKPART(dev)
- +
- + LIST_HEAD(xfer_free_list, wdc_xfer) xfer_free_list;
- +
- + 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;
- + int sc_iobase; /* I/O port base */
- + 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 */
- + int sc_errors; /* errors during current transfer */
- + u_char sc_status; /* copy of status register */
- + u_char sc_error; /* copy of error register */
- + };
- +
- + int wdcprobe __P((struct device *, void *, void *));
- + void wdcattach __P((struct device *, struct device *, void *));
- +
- + struct cfattach wdc_ca = {
- + sizeof(struct wdc_softc), wdcprobe, wdcattach
- + };
- +
- + struct cfdriver wdc_cd = {
- + NULL, "wdc", DV_DULL
- + };
- +
- +
- + int wdcintr __P((void *));
- + int wdc_ata_intr __P((struct wdc_softc *,struct wdc_xfer *));
- + void wdcstart __P((struct wdc_softc *));
- + void wdc_ata_start __P((struct wdc_softc *,struct wdc_xfer *));
- + void wdc_atapi_start __P((struct wdc_softc *,struct wdc_xfer *));
- + int wdcreset __P((struct wdc_softc *));
- + void wdcrestart __P((void *arg));
- + void wdcunwedge __P((struct wdc_softc *));
- + void wdctimeout __P((void *arg));
- + int wdcwait __P((struct wdc_softc *, int));
- + int wdccontrol __P((struct wd_link *));
- + void wdc_ata_done __P((struct wdc_softc *, struct wdc_xfer *));
- + void wdc_free_xfer __P((struct wdc_xfer *));
- + void wdcerror __P((struct wdc_softc*, char *));
- + int wdccommandshort __P((struct wdc_softc *, int, int));
- + void wdcbit_bucket __P(( struct wdc_softc *, int));
- + int wdc_atapi_intr __P((struct wdc_softc *, struct wdc_xfer *));
- + void wdc_atapi_done __P((struct wdc_softc *, struct wdc_xfer *));
- +
- + /* 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)
- +
- + #ifdef ATAPI_DEBUG
- + static int wdc_nxfer;
- + #endif
- +
- + int
- + wdcprobe(parent, match, aux)
- + struct device *parent;
- + void *match, *aux;
- + {
- + struct wdc_softc *wdc = match;
- + struct isa_attach_args *ia = aux;
- + int iobase;
- +
- + wdc->sc_iobase = iobase = ia->ia_iobase;
- +
- + /* Check if we have registers that work. */
- + outb(iobase+wd_error, 0x5a); /* Error register not writable, */
- + outb(iobase+wd_cyl_lo, 0xa5); /* but all of cyllo are. */
- + if (inb(iobase+wd_error) == 0x5a || inb(iobase+wd_cyl_lo) != 0xa5) {
- + /*
- + * Test for a controller with no IDE master, just one
- + * ATAPI device. Select drive 1, and try again.
- + */
- + outb(iobase+wd_sdh, WDSD_IBM | 0x10);
- + outb(iobase+wd_error, 0x5a);
- + outb(iobase+wd_cyl_lo, 0xa5);
- + if (inb(iobase+wd_error) == 0x5a || inb(iobase+wd_cyl_lo)
- + != 0xa5)
- + return 0;
- + wdc->sc_flags |= WDCF_ONESLAVE;
- + }
- +
- + if (wdcreset(wdc) != 0) {
- + delay(500000);
- + if (wdcreset(wdc) != 0)
- + return 0;
- + }
- +
- + /* Select drive 0 or ATAPI slave device */
- + if (wdc->sc_flags & WDCF_ONESLAVE)
- + outb(iobase+wd_sdh, WDSD_IBM | 0x10);
- + else
- + outb(iobase+wd_sdh, WDSD_IBM);
- +
- + /* Wait for controller to become ready. */
- + if (wait_for_unbusy(wdc) < 0)
- + return 0;
- +
- + /* Start drive diagnostics. */
- + outb(iobase+wd_command, WDCC_DIAGNOSE);
- +
- + /* Wait for command to complete. */
- + if (wait_for_unbusy(wdc) < 0)
- + return 0;
- +
- + ia->ia_iosize = 8;
- + ia->ia_msize = 0;
- + return 1;
- + }
- +
- + int
- + wdprint(aux, wdc)
- + void *aux;
- + 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;
- + int drive;
- +
- + 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->ctlr_link.flags = 0;
- + #ifdef ATAPI_DEBUG
- + wdc_nxfer = 0;
- + #endif
- +
- + for (drive = 0; drive < 2; drive++) {
- + wdc->sc_flags |= WDCF_ACTIVE; /* controller active while autoconf */
- + 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);
- + 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 (wdc->sc_drq != DRQUNK)
- + wdc->d_link[drive]->sc_mode = WDM_DMA;
- + else wdc->d_link[drive]->sc_mode = 0;
- +
- + (void)config_found(self, (void *)wdc->d_link[drive], wdprint);
- + }
- + }
- +
- + wdc->ab_link = malloc(sizeof(struct bus_link), M_DEVBUF, M_NOWAIT);
- + 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);
- + }
- +
- + /*
- + * 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 ) {
- + #ifdef WDDEBUG
- + printf("wdcstart: already active\n");
- + #endif
- + return; /* controller aleady active */
- + }
- + #ifdef DIAGNOSTIC
- + if ((wdc->sc_flags & WDCF_IRQ_WAIT) != 0)
- + panic("wdcstart: controller waiting for irq\n");
- + #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 (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);
- + }
- + }
- +
- +
- + void wdc_ata_start(wdc, xfer)
- + struct wdc_softc *wdc;
- + struct wdc_xfer *xfer;
- + {
- + struct wd_link *d_link;
- + struct buf *bp = xfer->c_bp;
- + int nblks;
- +
- + d_link=xfer->d_link;
- +
- + loop:
- +
- + if (wdc->sc_errors >= WDIORETRIES) {
- + wderror(d_link, bp, "hard error");
- + xfer->c_flags |= C_ERROR;
- + wdc_ata_done(wdc, xfer);
- + return;
- + }
- +
- + /* Do control operations specially. */
- + if (d_link->sc_state < OPEN) {
- + /*
- + * 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) {
- + daddr_t blkno;
- +
- + #ifdef WDDEBUG
- + printf("\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);
- + #endif
- + blkno = xfer->c_blkno+xfer->c_p_offset;
- + xfer->c_blkno = blkno / (d_link->sc_lp->d_secsize / DEV_BSIZE);
- + } else {
- + #ifdef WDDEBUG
- + printf(" %d)%x", xfer->c_skip, inb(wdc->sc_iobase+wd_altsts));
- + #endif
- + }
- +
- + /* 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;
- + long cylin, head, sector;
- + int command;
- +
- + if ((wdc->sc_flags & WDCF_SINGLE) != 0)
- + nblks = 1;
- + 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);
- +
- + /* 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
- + ) {
- + long 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 transfer. */
- + 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) {
- + case WDM_DMA:
- + command = (xfer->c_flags & B_READ) ?
- + WDCC_READDMA : WDCC_WRITEDMA;
- + /* Start the DMA channel and bounce the buffer if
- + necessary. */
- + isa_dmastart(xfer->c_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE,
- + xfer->databuf + xfer->c_skip,
- + xfer->c_nbytes, wdc->sc_drq);
- + break;
- + 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;
- + }
- +
- + #ifdef WDDEBUG
- + printf("sector %d cylin %d head %d addr %x sts %x\n", sector,
- + cylin, head, xfer->databuf, inb(wdc->sc_iobase+wd_altsts));
- + #endif
- + } 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)
- + outsw(wdc->sc_iobase+wd_data, xfer->databuf + xfer->c_skip,
- + xfer->c_nbytes >> 1);
- + else
- + outsl(wdc->sc_iobase+wd_data, xfer->databuf + xfer->c_skip,
- + xfer->c_nbytes >> 2);
- + }
- +
- + wdc->sc_flags |= WDCF_IRQ_WAIT;
- + #ifdef WDDEBUG
- + printf("wdc_ata_start: timeout ");
- + #endif
- + timeout(wdctimeout, wdc, WAITTIME);
- + #ifdef WDDEBUG
- + printf("done\n");
- + #endif
- + }
- +
- + void
- + wdc_atapi_start (wdc, xfer)
- + struct wdc_softc *wdc;
- + struct wdc_xfer *xfer;
- + {
- + struct atapi_command_packet *acp = xfer->atapi_cmd;
- + #ifdef ATAPI_DEBUG_WDC
- + printf("wdc_atapi_start, acp flags %lx\n",acp->flags);
- + #endif
- + if (wdc->sc_errors >= WDIORETRIES) {
- + acp->status |= ERROR;
- + acp->error = inb (wdc->sc_iobase + wd_error);
- + wdc_atapi_done(wdc, xfer);
- + return;
- + }
- + if (wait_for_unbusy (wdc) != 0)
- + if (!(wdc->sc_status & WDCS_ERR)) {
- + 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 & 0x0300) != ACAP_DRQ_INTR) {
- + int i, phase;
- + for (i=20000; i>0; --i) {
- + phase = (inb(wdc->sc_iobase + wd_ireason) & (WDCI_CMD | WDCI_IN)) |
- + (inb(wdc->sc_iobase + wd_status) & WDCS_DRQ);
- + if (phase == PHASE_CMDOUT)
- + break;
- + delay(10);
- + }
- + if (phase != PHASE_CMDOUT ) {
- + printf("wdc_atapi_start: timout waiting PHASE_CMDOUT");
- + acp->status = ERROR;
- + wdc_atapi_done(wdc, xfer);
- + return;
- + }
- + outsw (wdc->sc_iobase + wd_data, acp->command,
- + acp->command_size/ sizeof (short));
- + }
- + wdc->sc_flags |= WDCF_IRQ_WAIT;
- +
- +
- + #ifdef ATAPI_DEBUG2
- + printf("wdc_atapi_start: timeout\n");
- + #endif
- + timeout(wdctimeout, wdc, WAITTIME);
- + return;
- + }
- +
- +
- + /*
- + * 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;
- +
- + if ((wdc->sc_flags & WDCF_IRQ_WAIT) == 0) {
- + /* Clear the pending interrupt and abort. */
- + u_char s = inb(wdc->sc_iobase+wd_status);
- + u_char e = inb(wdc->sc_iobase+wd_error);
- + u_char i = inb(wdc->sc_iobase+wd_seccnt);
- + #ifdef ATAPI_DEBUG_WDC
- + printf ("wdcintr: inactive controller, punting st=%02x er=%02x irr=%02x\n", s, e, i);
- + #endif /* ATAPI_DEBUG */
- + if (s & WDCS_DRQ) {
- + int len = inb (wdc->sc_iobase + wd_cyl_lo) +
- + 256 * inb (wdc->sc_iobase + wd_cyl_hi);
- + #ifdef ATAPI_DEBUG_WDC
- + printf ("wdcintr: clearing up %d bytes\n", len);
- + #endif /* ATAPI_DEBUG */
- + wdcbit_bucket (wdc, len);
- + }
- + return 0;
- + }
- +
- + #ifdef WDDEBUG
- + printf("wdcintr\n");
- + #endif
- + wdc->sc_flags &= ~WDCF_IRQ_WAIT;
- + xfer = wdc->sc_xfer.tqh_first;
- + if (xfer->c_flags & C_ATAPI) {
- + (void) wdc_atapi_intr(wdc,xfer);
- + return 0;
- + } else {
- + return wdc_ata_intr(wdc,xfer);
- + }
- + }
- +
- +
- + int
- + wdc_ata_intr(wdc,xfer)
- + struct wdc_softc *wdc;
- + struct wdc_xfer *xfer;
- + {
- + struct wd_link *d_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 < OPEN) {
- + if (wdccontrol(d_link) == 0) {
- + /* The drive is busy. Wait. */
- + return 1;
- + }
- + #ifdef WDDEBUG
- + printf("wdc_ata_start from wdc_ata_intr(open) flags %d\n",
- + dc->sc_flags);
- + #endif
- + wdc_ata_start(wdc,xfer);
- + return 1;
- + }
- +
- + /* Turn off the DMA channel and unbounce the buffer. */
- + if (d_link->sc_mode == WDM_DMA)
- + isa_dmadone(xfer->c_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE,
- + xfer->databuf + xfer->c_skip, xfer->c_nbytes, wdc->sc_drq);
- +
- + /* Have we an error? */
- + if (wdc->sc_status & WDCS_ERR) {
- + #ifdef WDDEBUG
- + wderror(d_link, NULL, "wdc_ata_start");
- + #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 (++wdc->sc_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)
- + insw(wdc->sc_iobase+wd_data, xfer->databuf + xfer->c_skip,
- + xfer->c_nbytes >> 1);
- + else
- + insl(wdc->sc_iobase+wd_data, xfer->databuf + xfer->c_skip,
- + xfer->c_nbytes >> 2);
- + }
- +
- + /* If we encountered any abnormalities, flag it as a soft error. */
- + if (wdc->sc_errors > 0 ||
- + (wdc->sc_status & WDCS_CORR) != 0) {
- + wderror(d_link, xfer->c_bp, "soft error (corrected)");
- + wdc->sc_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 */
- + #ifdef WDDEBUG
- + printf("wdc_ata_start from wdcintr flags %d\n",wdc->sc_flags);
- + #endif
- + wdc_ata_start(wdc, xfer);
- +
- + return 1;
- + }
- +
- + int
- + wdcreset(wdc)
- + struct wdc_softc *wdc;
- + {
- + int iobase = wdc->sc_iobase;
- +
- + /* Reset the device. */
- + outb(iobase+wd_ctlr, WDCTL_RST | WDCTL_IDS);
- + delay(1000);
- + outb(iobase+wd_ctlr, WDCTL_IDS);
- + delay(1000);
- + (void) inb(iobase+wd_error);
- + outb(iobase+wd_ctlr, WDCTL_4BIT);
- +
- + if (wait_for_unbusy(wdc) < 0) {
- + 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);
- +
- + /* 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;
- + ++wdc->sc_errors;
- +
- + /* Wake up in a little bit and restart the operation. */
- + #ifdef WDDEBUG
- + printf("wdcrestart from wdcunwedge\n");
- + #endif
- + wdc->sc_flags &= ~WDCF_ACTIVE;
- + timeout(wdcrestart, wdc, RECOVERYTIME);
- + }
- +
- + int
- + wdcwait(wdc, mask)
- + struct wdc_softc *wdc;
- + int mask;
- + {
- + int iobase = wdc->sc_iobase;
- + int timeout = 0;
- + u_char status;
- + #ifdef WDCNDELAY_DEBUG
- + extern int cold;
- + #endif
- + #ifdef WDDEBUG
- + printf("wdcwait\n");
- + #endif
- +
- + for (;;) {
- + wdc->sc_status = status = inb(iobase+wd_status);
- + /*
- + * XXX
- + * 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) {
- + outb(iobase+wd_sdh, WDSD_IBM | 0x10);
- + wdc->sc_status = status = inb(iobase+wd_status);
- + }
- + if ((status & WDCS_BSY) == 0 && (status & mask) == mask)
- + break;
- + if (++timeout > WDCNDELAY) {
- + #ifdef ATAPI_DEBUG2
- + printf("wdcwait: timeout, status %x\n", status);
- + #endif
- + return -1;
- + }
- + delay(WDCDELAY);
- + }
- + if (status & WDCS_ERR) {
- + wdc->sc_error = inb(iobase+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;
- + #ifdef WDDEBUG
- + printf("wdctimeout\n");
- + #endif
- +
- + 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;
- + int iobase = wdc->sc_iobase;
- + int stat;
- + #ifdef WDDEBUG
- + printf("wdccommand drive %d\n",drive);
- + #endif
- + #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. */
- + outb(iobase+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)
- + outb(iobase+wd_precomp, d_link->sc_lp->d_precompcyl / 4);
- + else
- + outb(iobase+wd_features, 0);
- + outb(iobase+wd_cyl_lo, cylin);
- + outb(iobase+wd_cyl_hi, cylin >> 8);
- + outb(iobase+wd_sector, sector);
- + outb(iobase+wd_seccnt, count);
- +
- + /* Send command. */
- + outb(iobase+wd_command, command);
- +
- + return 0;
- + }
- +
- + /*
- + * Simplified version of wdccommand().
- + */
- + int
- + wdccommandshort(wdc, drive, command)
- + struct wdc_softc *wdc;
- + int drive;
- + int command;
- + {
- + int iobase = wdc->sc_iobase;
- + #ifdef WDDEBUG
- + printf("wdccommandshort\n");
- + #endif
- + #if defined(DIAGNOSTIC) && defined(WDCDEBUG)
- + if ((wdc->sc_flags & WDCF_ACTIVE) == 0 )
- + printf("wdccommandshort: controler not active (drive %d)\n", drive);
- + #endif
- +
- + /* Select drive. */
- + outb(iobase+wd_sdh, WDSD_IBM | (drive << 4));
- +
- + if (wdcwait(wdc, WDCS_DRDY) < 0)
- + return -1;
- +
- + outb(iobase+wd_command, command);
- +
- + return 0;
- + }
- +
- + #ifndef __BDEVSW_DUMP_OLD_TYPE
- + /* #define WD_DUMP_NOT_TRUSTED /* if you just want to watch */
- + static int wddumprecalibrated;
- +
- + int
- + wdcdump(d_link, blkno, nblks, va)
- + struct wd_link *d_link;
- + daddr_t blkno;
- + int nblks;
- + caddr_t va;
- + {
- + struct wdc_softc *wdc = (void*)d_link->wdc_softc;
- + struct disklabel *lp = d_link->sc_lp;
- + /* Recalibrate, if first dump transfer. */
- + wdc->sc_flags |= WDCF_ACTIVE;
- + if (wddumprecalibrated == 0) {
- + if (wdccommandshort(wdc, d_link->sc_drive, WDCC_RECAL) != 0 ||
- + wait_for_ready(wdc) != 0 ||
- + wdsetctlr(d_link) != 0 || wait_for_ready(wdc) != 0) {
- + wdcerror(wdc, "wdcdump: recal failed");
- + return EIO;
- + }
- + }
- + while (nblks > 0) {
- + daddr_t xlt_blkno = blkno;
- + long cylin, head, sector;
- +
- + if ((lp->d_flags & D_BADSECT) != 0) {
- + long 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) {
- + wdcerror(wdc, "wddump: write failed");
- + return EIO;
- + }
- +
- + outsw(wdc->sc_iobase+wd_data, va, lp->d_secsize >> 1);
- +
- + /* Check data request (should be done). */
- + if (wait_for_ready(wdc) != 0) {
- + wdcerror(wdc, "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",
- + d_link->sc_drive, va, cylin, head, sector);
- + delay(500 * 1000); /* half a second */
- + #endif
- + /* update block count */
- + nblks -= 1;
- + blkno += 1;
- + va += lp->d_secsize;
- + }
- + wdc->sc_flags &= ~WDCF_ACTIVE;
- + return 0;
- + }
- + #endif
- +
- + void wdc_ata_done(wdc, xfer)
- + struct wdc_softc *wdc;
- + struct wdc_xfer *xfer;
- + {
- + int s;
- + struct buf *bp = xfer->c_bp;
- + struct wd_link *d_link = xfer->d_link;
- + #ifdef WDDEBUG
- + printf("wdc_ata_done\n");
- + #endif
- + /* 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);
- + wdc->sc_errors = 0;
- + 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);
- + #ifdef WDDEBUG
- + printf("wdcstart from wdc_ata_done, flags %d\n",wdc->sc_flags);
- + #endif
- + wdcstart(wdc);
- + splx(s);
- + }
- +
- + 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;
- +
- + #ifdef WDDEBUG
- + printf("wdc_exec_xfer\n");
- + #endif
- + s = splbio();
- + /* insert at the end of command list */
- + TAILQ_INSERT_TAIL(&wdc->sc_xfer,xfer , c_xferchain)
- + #ifdef WDDEBUG
- + printf("wdcstart from wdc_exec_xfer, flags %d\n",wdc->sc_flags);
- + #endif
- + 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) {
- + LIST_REMOVE(xfer, free_list);
- + splx(s);
- + #ifdef DIAGNOSTIC
- + if ((xfer->c_flags & C_INUSE) != 0) panic("xfer already in use\n");
- + #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) {
- + 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("xfer already in use\n");
- + #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);
- + }
- +
- + /*
- + * 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;
- + #ifdef WDDEBUG
- + printf("wdccontrol\n");
- + #endif
- +
- + 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 open;
- + outb(wdc->sc_iobase+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 OPEN:
- + open:
- + wdc->sc_errors = 0;
- + d_link->sc_state = OPEN;
- + /*
- + * 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;
- + }
- +
- + /*
- + * 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;
- + int i;
- + char tb[DEV_BSIZE];
- + 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;
- + if ((error = tsleep(wdc, PRIBIO | PCATCH, "wdprm", 0)) != 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, "unknown",
- + 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. */
- + insw(wdc->sc_iobase+wd_data, tb, sizeof(tb) / sizeof(short));
- + bcopy(tb, &d_link->sc_params, sizeof(struct wdparams));
- +
- + /* Shuffle string byte order. */
- + for (i = 0; i < sizeof(d_link->sc_params.wdp_model); i += 2) {
- + u_short *p;
- + p = (u_short *)(d_link->sc_params.wdp_model + i);
- + *p = ntohs(*p);
- + }
- + }
- +
- + /* Clear any leftover interrupt. */
- + (void) inb(wdc->sc_iobase+wd_status);
- +
- + /* Restart the queue. */
- + #ifdef WDDEBUG
- + printf("wdcstart from wdc_get_parms flags %d\n",wdc->sc_flags);
- + #endif
- + wdc->sc_flags &= ~WDCF_ACTIVE;
- + wdcstart(wdc);
- +
- + splx(s);
- + return 0;
- + }
- + 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);
- + }
- +
- + 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;
- + 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 ion 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);
- + 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 = inb(wdc->sc_iobase + wd_cyl_lo) +
- + 256 * inb(wdc->sc_iobase + wd_cyl_hi);
- + if (len != sizeof(struct atapi_identify)) {
- + printf("Warning drive %d returned %d/%d of indentify device data\n",
- + drive, len, sizeof(struct atapi_identify));
- + excess = len - sizeof(struct atapi_identify);
- + if (excess < 0) excess = 0;
- + }
- + insw(wdc->sc_iobase + wd_data, id,
- + sizeof(struct atapi_identify)/sizeof(short));
- + wdcbit_bucket(wdc, excess);
- +
- + end: /* Restart the queue. */
- + #ifdef WDDEBUG
- + printf("wdcstart from wdc_atapi_get_parms flags %d\n",wdc->sc_flags);
- + #endif
- + 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;
- + struct wdc_xfer *xfer;
- + int s;
- + 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;
- + #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)) {
- + printf ("wdc_atapi_send_command: not ready, st = %02x\n",wdc->sc_status);
- + acp->status = ERROR;
- + return;
- + }
- +
- + 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. */
- + for (i=20000; i>0; --i) {
- + int phase;
- + phase = (inb(wdc->sc_iobase + wd_ireason) & (WDCI_CMD | WDCI_IN)) |
- + (inb(wdc->sc_iobase + wd_status) & WDCS_DRQ);
- + if (phase == PHASE_CMDOUT)
- + break;
- + delay(10);
- + }
- + #ifdef ATAPI_DEBUG_WDC
- + printf("Wait for cmd i/o phase: i= %d\n", i);
- + #endif
- +
- + outsw (wdc->sc_iobase + wd_data, acp->command,
- + acp->command_size/ sizeof (short));
- + /* Wait for data i/o phase. */
- +
- + for (i=20000; i>0; --i) {
- + int phase;
- + phase = (inb(wdc->sc_iobase + wd_ireason) & (WDCI_CMD | WDCI_IN)) |
- + (inb(wdc->sc_iobase + wd_status) & WDCS_DRQ);
- + if (phase != PHASE_CMDOUT) {
- + break;
- + }
- + delay(10);
- + }
- +
- + #ifdef ATAPI_DEBUG_WDC
- + printf("Wait for data i/o phase: i= %d\n", i);
- + #endif
- + while (wdc_atapi_intr(wdc, xfer)) {
- + for (i=2000; i>0; --i)
- + if (! (inb (wdc->sc_iobase + wd_status) & WDCS_DRQ))
- + break;
- + #ifdef ATAPI_DEBUG_WDC
- + printf("wdc_atapi_intr: i=%d\n", i);
- + #endif
- + }
- + wdc->sc_flags &= ~(WDCF_IRQ_WAIT | WDCF_SINGLE | WDCF_ERROR);
- + wdc->sc_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;
- + }
- + }
- +
- +
- + /*
- + the bit bucket
- + */
- + void wdcbit_bucket (wdc, size)
- + struct wdc_softc *wdc;
- + int size;
- + {
- + int iobase = wdc->sc_iobase;
- + int i;
- +
- + for (i = 0 ; i < size / 2 ; i++) {
- + short null;
- + (void) insw (iobase + wd_data, &null, 1);
- + }
- +
- + if (size % 2)
- + (void) inb (iobase + wd_data);
- +
- + }
- +
- + int wdc_atapi_intr(wdc, xfer)
- + struct wdc_softc *wdc;
- + struct wdc_xfer *xfer;
- + {
- + int len, phase, i;
- + int err, st, ire;
- + struct atapi_command_packet *acp = xfer->atapi_cmd;
- + if (wait_for_unbusy(wdc)<0) {
- + printf("wdc_atapi_intr: controller busy\n");
- + acp->status = ERROR;
- + acp->error = inb (wdc->sc_iobase + wd_error);
- + return 0;
- + }
- + #ifdef ATAPI_DEBUG2
- + printf("wdc_atapi_intr: %s\n", wdc->sc_dev.dv_xname);
- + #endif
- +
- + len = inb (wdc->sc_iobase + wd_cyl_lo) +
- + 256 * inb (wdc->sc_iobase + wd_cyl_hi);
- +
- + st = inb(wdc->sc_iobase + wd_status);
- + err = inb(wdc->sc_iobase + wd_error);
- + ire = inb(wdc->sc_iobase + 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("%x ",c[i]);
- + printf("\n");
- + }
- + #endif
- +
- + wdc->sc_flags |= WDCF_IRQ_WAIT;
- + outsw (wdc->sc_iobase + wd_data, acp->command,
- + acp->command_size/ sizeof (short));
- + 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);
- + outsw (wdc->sc_iobase + wd_data, xfer->databuf+xfer->c_skip,
- + xfer->c_bcount/sizeof (short));
- + for(i = xfer->c_bcount; i<len; i+=sizeof(short))
- + outw(wdc->sc_iobase + wd_data, 0);
- + xfer->c_bcount = 0;
- + return 1;
- + } else {
- + outsw (wdc->sc_iobase + wd_data, xfer->databuf+xfer->c_skip,
- + len/sizeof (short));
- + 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);
- + insw(wdc->sc_iobase + wd_data, xfer->databuf+xfer->c_skip,
- + xfer->c_bcount/sizeof(short));
- + wdcbit_bucket(wdc, len - xfer->c_bcount);
- + xfer->c_bcount = 0;
- + return 1;
- + } else {
- + insw(wdc->sc_iobase + wd_data, xfer->databuf+xfer->c_skip,
- + len/sizeof(short));
- + 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 = inb (wdc->sc_iobase + 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:
- + 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 */
- + wdc->sc_errors = 0;
- + 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_DEBU
- + 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);
- + }
- diff --exclude compile -bcrNP src.orig/sys/dev/isa/wdlink.h src/sys/dev/isa/wdlink.h
- *** src.orig/sys/dev/isa/wdlink.h Thu Jan 1 01:00:00 1970
- --- src/sys/dev/isa/wdlink.h Thu Jun 6 12:21:06 1996
- ***************
- *** 0 ****
- --- 1,112 ----
- + /*
- + * 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 */
- +
- + struct wdc_link {
- + int flags;
- + int openings;
- + };
- +
- + 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 OPEN 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 long 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_long c_p_offset; /* offset of the partition */
- + 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 *));
- + void wderror __P((struct wd_link* , struct buf *, char *));
- + void wddone __P((struct wd_link*, struct buf*));
- + int wdccommand __P((struct wd_link *, int, int, int, int, int, int));
- + int wdcdumpprecalibrated __P((struct wd_link *));
- +
- + #define IDE_NOSLEEP 0x01
- diff --exclude compile -bcrNP src.orig/sys/dev/isa/wdreg.h src/sys/dev/isa/wdreg.h
- *** src.orig/sys/dev/isa/wdreg.h Sat Oct 14 03:39:23 1995
- --- src/sys/dev/isa/wdreg.h Thu Jun 6 12:27:04 1996
- ***************
- *** 46,51 ****
- --- 46,52 ----
- #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) */
- ***************
- *** 118,123 ****
- --- 119,146 ----
- #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
-
- #ifdef _KERNEL
- /*
- diff --exclude compile -bcrNP src.orig/usr.bin/eject/eject.c src/usr.bin/eject/eject.c
- *** src.orig/usr.bin/eject/eject.c Thu Feb 1 13:27:47 1996
- --- src/usr.bin/eject/eject.c Thu Jun 6 16:54:06 1996
- ***************
- *** 88,93 ****
- --- 88,96 ----
- { "mcd", "/dev/mcd0", 'a', DISK },
- { "mcd0", "/dev/mcd0", 'a', DISK },
- { "mcd1", "/dev/mcd1", 'a', DISK },
- + { "acd", "/dev/acd0", 'a', DISK },
- + { "acd0", "/dev/acd0", 'a', DISK },
- + { "acd1", "/dev/acd1", 'a', DISK },
- { "tape", "/dev/rst0", '\0', TAPE },
- { "tape0", "/dev/rst0", '\0', TAPE },
- { "tape1", "/dev/rst1", '\0', TAPE },
-