summaryrefslogtreecommitdiff
path: root/sys/dev/mca
diff options
context:
space:
mode:
authorjdolecek <jdolecek@NetBSD.org>2001-11-23 22:53:09 +0000
committerjdolecek <jdolecek@NetBSD.org>2001-11-23 22:53:09 +0000
commit07312f0fbbc7fe070866fd36999bfb352234ef4d (patch)
tree63109b887f70d1bfe7138e9137e74c2005b11aec /sys/dev/mca
parent90fac765dadfa371fbf728224e46a7911f4970a0 (diff)
Convert over to use the new MCA DMA facilities, which encapsulate
the MCA DMA controller access. This also means we gain >16MB RAM support. While here, overhaul the driver to saner state, especially: * simplify and clean the attach code a lot, and support the 'drive' locator * pass proper dev_t to readdisklabel() - formerly, the passed value was completely broken (used incorrect major and wrong minor), but worked by accident * worker thread is now spawned per controller, rather than per-drive; i/o cannot be done concurrently by different drivers, only one i/o can be pending at any time * simplify the command queue code, just sleep appropriately when !poll case, g/c 'async' code formerly needed, move the bio code from ed_mca.c to edc_mca.c:edc_bio() * put all string arrays used by edc_dump_status_block() within #ifdef EDC_DEBUG, and use numbers instead if it's not defined; this cuts object size by 5KB * other misc cleanups
Diffstat (limited to 'sys/dev/mca')
-rw-r--r--sys/dev/mca/ed_mca.c562
-rw-r--r--sys/dev/mca/edc_mca.c501
2 files changed, 395 insertions, 668 deletions
diff --git a/sys/dev/mca/ed_mca.c b/sys/dev/mca/ed_mca.c
index e40ad166589..befe720b66e 100644
--- a/sys/dev/mca/ed_mca.c
+++ b/sys/dev/mca/ed_mca.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ed_mca.c,v 1.9 2001/11/13 07:46:25 lukem Exp $ */
+/* $NetBSD: ed_mca.c,v 1.10 2001/11/23 22:53:10 jdolecek Exp $ */
/*
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -34,13 +34,14 @@
*/
/*
- * Disk goo for MCA ESDI controller driver.
+ * Disk drive goo for MCA ESDI controller driver.
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ed_mca.c,v 1.9 2001/11/13 07:46:25 lukem Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ed_mca.c,v 1.10 2001/11/23 22:53:10 jdolecek Exp $");
#include "rnd.h"
+#include "locators.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -58,7 +59,6 @@ __KERNEL_RCSID(0, "$NetBSD: ed_mca.c,v 1.9 2001/11/13 07:46:25 lukem Exp $");
#include <sys/syslog.h>
#include <sys/proc.h>
#include <sys/vnode.h>
-#include <sys/kthread.h>
#if NRND > 0
#include <sys/rnd.h>
#endif
@@ -95,19 +95,11 @@ struct cfattach ed_mca_ca = {
extern struct cfdriver ed_cd;
-static int ed_get_params __P((struct ed_softc *));
+static int ed_get_params __P((struct ed_softc *, int *));
static int ed_lock __P((struct ed_softc *));
static void ed_unlock __P((struct ed_softc *));
-static void edgetdisklabel __P((struct ed_softc *));
+static void edgetdisklabel __P((dev_t, struct ed_softc *));
static void edgetdefaultlabel __P((struct ed_softc *, struct disklabel *));
-static void ed_shutdown __P((void*));
-static void __edstart __P((struct ed_softc*, struct buf *));
-static void bad144intern __P((struct ed_softc *));
-static void edworker __P((void *));
-static void ed_spawn_worker __P((void *));
-static void edmcadone __P((struct ed_softc *, struct buf *));
-static void ed_bio __P((struct ed_softc *, int, int));
-static void ed_bio_done __P((struct ed_softc *));
static struct dkdriver eddkdriver = { edmcastrategy };
@@ -115,22 +107,29 @@ static struct dkdriver eddkdriver = { edmcastrategy };
* Just check if it's possible to identify the disk.
*/
static int
-ed_mca_probe(parent, match, aux)
+ed_mca_probe(parent, cf, aux)
struct device *parent;
- struct cfdata *match;
+ struct cfdata *cf;
void *aux;
{
u_int16_t cmd_args[2];
struct edc_mca_softc *sc = (void *) parent;
- struct ed_attach_args *eda = (void *) aux;
+ struct ed_attach_args *eda = (struct ed_attach_args *) aux;
int found = 1;
/*
+ * Check we match hardwired config.
+ */
+ if (cf->edccf_unit != EDCCF_DRIVE_DEFAULT &&
+ cf->edccf_unit != eda->edc_drive)
+ return (0);
+
+ /*
* Get Device Configuration (09).
*/
cmd_args[0] = 14; /* Options: 00s110, s: 0=Physical 1=Pseudo */
cmd_args[1] = 0;
- if (edc_run_cmd(sc, CMD_GET_DEV_CONF, eda->sc_devno, cmd_args, 2, 0, 1))
+ if (edc_run_cmd(sc, CMD_GET_DEV_CONF, eda->edc_drive, cmd_args, 2, 1))
found = 0;
return (found);
@@ -143,20 +142,20 @@ ed_mca_attach(parent, self, aux)
{
struct ed_softc *ed = (void *) self;
struct edc_mca_softc *sc = (void *) parent;
- struct ed_attach_args *eda = (void *) aux;
- char pbuf[8];
- int error, nsegs;
+ struct ed_attach_args *eda = (struct ed_attach_args *) aux;
+ char pbuf[8], lckname[10];
+ int drv_flags;
ed->edc_softc = sc;
- ed->sc_dmat = eda->sc_dmat;
- ed->sc_devno = eda->sc_devno;
- edc_add_disk(sc, ed, eda->sc_devno);
+ ed->sc_devno = eda->edc_drive;
+ edc_add_disk(sc, ed);
BUFQ_INIT(&ed->sc_q);
simple_lock_init(&ed->sc_q_lock);
- lockinit(&ed->sc_lock, PRIBIO | PCATCH, "edlck", 0, 0);
+ snprintf(lckname, sizeof(lckname), "%slck", ed->sc_dev.dv_xname);
+ lockinit(&ed->sc_lock, PRIBIO | PCATCH, lckname, 0, 0);
- if (ed_get_params(ed)) {
+ if (ed_get_params(ed, &drv_flags)) {
printf(": IDENTIFY failed, no disk found\n");
return;
}
@@ -170,88 +169,27 @@ ed_mca_attach(parent, self, aux)
printf("%s: %u spares/cyl, %s, %s, %s, %s, %s\n",
ed->sc_dev.dv_xname, ed->spares,
- (ed->drv_flags & (1 << 0)) ? "NoRetries" : "Retries",
- (ed->drv_flags & (1 << 1)) ? "Removable" : "Fixed",
- (ed->drv_flags & (1 << 2)) ? "SkewedFormat" : "NoSkew",
- (ed->drv_flags & (1 << 3)) ? "ZeroDefect" : "Defects",
- (ed->drv_flags & (1 << 4)) ? "InvalidSecondary" : "SecondaryOK"
+ (drv_flags & (1 << 0)) ? "NoRetries" : "Retries",
+ (drv_flags & (1 << 1)) ? "Removable" : "Fixed",
+ (drv_flags & (1 << 2)) ? "SkewedFormat" : "NoSkew",
+ (drv_flags & (1 << 3)) ? "ZeroDefect" : "Defects",
+ (drv_flags & (1 << 4)) ? "InvalidSecondary" : "SecondaryOK"
);
- /* Create a DMA map for mapping individual transfer bufs */
- if ((error = bus_dmamap_create(ed->sc_dmat, 65536, 1,
- 65536, 65536, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW,
- &ed->dmamap_xfer)) != 0) {
- printf("%s: unable to create xfer DMA map, error=%d\n",
- ed->sc_dev.dv_xname, error);
- return;
- }
-
- /*
- * Allocate DMA memory used in case where passed buf isn't
- * physically contiguous.
- */
- ed->sc_dmam_sz = MAXPHYS;
- if ((error = bus_dmamem_alloc(ed->sc_dmat, ed->sc_dmam_sz,
- ed->sc_dmam_sz, 65536, ed->sc_dmam, 1, &nsegs,
- BUS_DMA_WAITOK|BUS_DMA_STREAMING)) != 0) {
- printf("%s: unable to allocate DMA memory for xfer, errno=%d\n",
- ed->sc_dev.dv_xname, error);
- bus_dmamap_destroy(ed->sc_dmat, ed->dmamap_xfer);
- return;
- }
- /*
- * Map the memory.
- */
- if ((error = bus_dmamem_map(ed->sc_dmat, ed->sc_dmam, 1,
- ed->sc_dmam_sz, &ed->sc_dmamkva, BUS_DMA_WAITOK)) != 0) {
- printf("%s: unable to map DMA memory, error=%d\n",
- ed->sc_dev.dv_xname, error);
- bus_dmamem_free(ed->sc_dmat, ed->sc_dmam, 1);
- bus_dmamap_destroy(ed->sc_dmat, ed->dmamap_xfer);
- return;
- }
-
-
/*
* Initialize and attach the disk structure.
*/
ed->sc_dk.dk_driver = &eddkdriver;
ed->sc_dk.dk_name = ed->sc_dev.dv_xname;
disk_attach(&ed->sc_dk);
-#if 0
- wd->sc_wdc_bio.lp = wd->sc_dk.dk_label;
-#endif
- ed->sc_sdhook = shutdownhook_establish(ed_shutdown, ed);
- if (ed->sc_sdhook == NULL)
- printf("%s: WARNING: unable to establish shutdown hook\n",
- ed->sc_dev.dv_xname);
#if NRND > 0
rnd_attach_source(&ed->rnd_source, ed->sc_dev.dv_xname,
RND_TYPE_DISK, 0);
#endif
- config_pending_incr();
- kthread_create(ed_spawn_worker, (void *) ed);
-
ed->sc_flags |= EDF_INIT;
}
-void
-ed_spawn_worker(arg)
- void *arg;
-{
- struct ed_softc *ed = (struct ed_softc *) arg;
- int error;
-
- /* Now, everything is ready, start a kthread */
- if ((error = kthread_create1(edworker, ed, &ed->sc_worker,
- "%s", ed->sc_dev.dv_xname))) {
- printf("%s: cannot spawn worker thread: errno=%d\n",
- ed->sc_dev.dv_xname, error);
- panic("ed_spawn_worker");
- }
-}
-
/*
* Read/write routine for a buffer. Validates the arguments and schedules the
* transfer. Does not wait for the transfer to complete.
@@ -260,12 +198,12 @@ void
edmcastrategy(bp)
struct buf *bp;
{
- struct ed_softc *wd = device_lookup(&ed_cd, DISKUNIT(bp->b_dev));
- struct disklabel *lp = wd->sc_dk.dk_label;
+ struct ed_softc *ed = device_lookup(&ed_cd, DISKUNIT(bp->b_dev));
+ struct disklabel *lp = ed->sc_dk.dk_label;
daddr_t blkno;
int s;
- WDCDEBUG_PRINT(("edmcastrategy (%s)\n", wd->sc_dev.dv_xname),
+ WDCDEBUG_PRINT(("edmcastrategy (%s)\n", ed->sc_dev.dv_xname),
DEBUG_XFERS);
/* Valid request? */
@@ -277,7 +215,7 @@ edmcastrategy(bp)
}
/* If device invalidated (e.g. media change, door open), error. */
- if ((wd->sc_flags & WDF_LOADED) == 0) {
+ if ((ed->sc_flags & WDF_LOADED) == 0) {
bp->b_error = EIO;
goto bad;
}
@@ -291,8 +229,8 @@ edmcastrategy(bp)
* If end of partition, just return.
*/
if (DISKPART(bp->b_dev) != RAW_PART &&
- bounds_check_with_label(bp, wd->sc_dk.dk_label,
- (wd->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0)
+ bounds_check_with_label(bp, ed->sc_dk.dk_label,
+ (ed->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0)
goto done;
/*
@@ -311,13 +249,12 @@ edmcastrategy(bp)
/* Queue transfer on drive, activate drive and controller if idle. */
s = splbio();
- simple_lock(&wd->sc_q_lock);
- disksort_blkno(&wd->sc_q, bp);
- simple_unlock(&wd->sc_q_lock);
+ simple_lock(&ed->sc_q_lock);
+ disksort_blkno(&ed->sc_q, bp);
+ simple_unlock(&ed->sc_q_lock);
/* Ring the worker thread */
- wd->sc_flags |= EDF_PROCESS_QUEUE;
- wakeup_one(&wd->sc_q);
+ wakeup_one(ed->edc_softc);
splx(s);
return;
@@ -329,141 +266,6 @@ done:
biodone(bp);
}
-static void
-ed_bio(struct ed_softc *ed, int async, int poll)
-{
- u_int16_t cmd_args[4];
- int error=0;
- u_int16_t track;
- u_int16_t cyl;
- u_int8_t head;
- u_int8_t sector;
-
- /* Get physical bus mapping for buf. */
- if (bus_dmamap_load(ed->sc_dmat, ed->dmamap_xfer,
- ed->sc_data, ed->sc_bcount, NULL,
- BUS_DMA_WAITOK|BUS_DMA_STREAMING) != 0) {
-
- /*
- * Use our DMA safe memory to get data to/from device.
- */
- if ((error = bus_dmamap_load(ed->sc_dmat, ed->dmamap_xfer,
- ed->sc_dmamkva, ed->sc_bcount, NULL,
- BUS_DMA_WAITOK|BUS_DMA_STREAMING)) != 0) {
- printf("%s: unable to load raw data for xfer, errno=%d\n",
- ed->sc_dev.dv_xname, error);
- goto out;
- }
- ed->sc_flags |= EDF_BOUNCEBUF;
-
- /* If data write, copy the data to our bounce buffer. */
- if (!ed->sc_read)
- memcpy(ed->sc_dmamkva, ed->sc_data, ed->sc_bcount);
- }
-
- ed->sc_flags |= EDF_DMAMAP_LOADED;
-
- track = ed->sc_rawblkno / ed->sectors;
- head = track % ed->heads;
- cyl = track / ed->heads;
- sector = ed->sc_rawblkno % ed->sectors;
-
- WDCDEBUG_PRINT(("__edstart %s: map: %u %u %u\n", ed->sc_dev.dv_xname,
- cyl, sector, head),
- DEBUG_XFERS);
-
- mca_disk_busy();
-
- /* Read or Write Data command */
- cmd_args[0] = 2; /* Options 0000010 */
- cmd_args[1] = ed->sc_bcount / DEV_BSIZE;
- cmd_args[2] = ((cyl & 0x1f) << 11) | (head << 5) | sector;
- cmd_args[3] = ((cyl & 0x3E0) >> 5);
- if (edc_run_cmd(ed->edc_softc,
- (ed->sc_read) ? CMD_READ_DATA : CMD_WRITE_DATA,
- ed->sc_devno, cmd_args, 4, async, poll)) {
- printf("%s: data i/o command failed\n", ed->sc_dev.dv_xname);
- mca_disk_unbusy();
- error = EIO;
- }
-
- out:
- if (error)
- ed->sc_error = error;
-}
-
-static void
-__edstart(ed, bp)
- struct ed_softc *ed;
- struct buf *bp;
-{
- WDCDEBUG_PRINT(("__edstart %s (%s): %lu %lu %u\n", ed->sc_dev.dv_xname,
- (bp->b_flags & B_READ) ? "read" : "write",
- bp->b_bcount, bp->b_resid, bp->b_rawblkno),
- DEBUG_XFERS);
-
- /* Instrumentation. */
- disk_busy(&ed->sc_dk);
- ed->sc_flags |= EDF_DK_BUSY;
-
- ed->sc_data = bp->b_data;
- ed->sc_rawblkno = bp->b_rawblkno;
- ed->sc_bcount = bp->b_bcount;
- ed->sc_read = bp->b_flags & B_READ;
- ed_bio(ed, 1, 0);
-}
-
-static void
-ed_bio_done(ed)
- struct ed_softc *ed;
-{
- /*
- * If read transfer finished without error and using a bounce
- * buffer, copy the data to buf.
- */
- if (ed->sc_error == 0 && (ed->sc_flags & EDF_BOUNCEBUF) && ed->sc_read)
- memcpy(ed->sc_data, ed->sc_dmamkva, ed->sc_bcount);
- ed->sc_flags &= ~EDF_BOUNCEBUF;
-
- /* Unload buf from DMA map */
- if (ed->sc_flags & EDF_DMAMAP_LOADED) {
- bus_dmamap_unload(ed->sc_dmat, ed->dmamap_xfer);
- ed->sc_flags &= ~EDF_DMAMAP_LOADED;
- }
-
- mca_disk_unbusy();
-}
-
-static void
-edmcadone(ed, bp)
- struct ed_softc *ed;
- struct buf *bp;
-{
- WDCDEBUG_PRINT(("eddone %s\n", ed->sc_dev.dv_xname),
- DEBUG_XFERS);
-
- if (ed->sc_error) {
- bp->b_error = ed->sc_error;
- bp->b_flags |= B_ERROR;
- } else {
- /* Set resid, most commonly to zero. */
- bp->b_resid = ed->sc_status_block[SB_RESBLKCNT_IDX] * DEV_BSIZE;
- }
-
- ed_bio_done(ed);
-
- /* If disk was busied, unbusy it now */
- if (ed->sc_flags & EDF_DK_BUSY) {
- disk_unbusy(&ed->sc_dk, (bp->b_bcount - bp->b_resid));
- ed->sc_flags &= ~EDF_DK_BUSY;
- }
-
-#if NRND > 0
- rnd_add_uint32(&ed->rnd_source, bp->b_blkno);
-#endif
- biodone(bp);
-}
-
int
edmcaread(dev, uio, flags)
dev_t dev;
@@ -543,13 +345,17 @@ edmcaopen(dev, flag, fmt, p)
}
} else {
if ((wd->sc_flags & WDF_LOADED) == 0) {
+ int s;
+
wd->sc_flags |= WDF_LOADED;
/* Load the physical device parameters. */
- ed_get_params(wd);
+ s = splbio();
+ ed_get_params(wd, NULL);
+ splx(s);
/* Load the partition info if not already loaded. */
- edgetdisklabel(wd);
+ edgetdisklabel(dev, wd);
}
}
@@ -629,24 +435,24 @@ edmcaclose(dev, flag, fmt, p)
}
static void
-edgetdefaultlabel(wd, lp)
- struct ed_softc *wd;
+edgetdefaultlabel(ed, lp)
+ struct ed_softc *ed;
struct disklabel *lp;
{
WDCDEBUG_PRINT(("edgetdefaultlabel\n"), DEBUG_FUNCS);
memset(lp, 0, sizeof(struct disklabel));
lp->d_secsize = DEV_BSIZE;
- lp->d_ntracks = wd->heads;
- lp->d_nsectors = wd->sectors;
- lp->d_ncylinders = wd->cyl;
+ lp->d_ntracks = ed->heads;
+ lp->d_nsectors = ed->sectors;
+ lp->d_ncylinders = ed->cyl;
lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
lp->d_type = DTYPE_ESDI;
strncpy(lp->d_typename, "ESDI", 16);
strncpy(lp->d_packname, "fictitious", 16);
- lp->d_secperunit = wd->sc_capacity;
+ lp->d_secperunit = ed->sc_capacity;
lp->d_rpm = 3600;
lp->d_interleave = 1;
lp->d_flags = 0;
@@ -666,26 +472,21 @@ edgetdefaultlabel(wd, lp)
* Fabricate a default disk label, and try to read the correct one.
*/
static void
-edgetdisklabel(wd)
- struct ed_softc *wd;
+edgetdisklabel(dev, ed)
+ dev_t dev;
+ struct ed_softc *ed;
{
- struct disklabel *lp = wd->sc_dk.dk_label;
+ struct disklabel *lp = ed->sc_dk.dk_label;
char *errstring;
WDCDEBUG_PRINT(("edgetdisklabel\n"), DEBUG_FUNCS);
- memset(wd->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel));
-
- edgetdefaultlabel(wd, lp);
+ memset(ed->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel));
-#if 0
- wd->sc_badsect[0] = -1;
+ edgetdefaultlabel(ed, lp);
- if (wd->drvp->state > RECAL)
- wd->drvp->drive_flags |= DRIVE_RESET;
-#endif
- errstring = readdisklabel(MAKEDISKDEV(0, wd->sc_dev.dv_unit, RAW_PART),
- edmcastrategy, lp, wd->sc_dk.dk_cpulabel);
+ errstring = readdisklabel(
+ EDLABELDEV(dev), edmcastrategy, lp, ed->sc_dk.dk_cpulabel);
if (errstring) {
/*
* This probably happened because the drive's default
@@ -697,22 +498,13 @@ edgetdisklabel(wd)
if (wd->drvp->state > RECAL)
wd->drvp->drive_flags |= DRIVE_RESET;
#endif
- errstring = readdisklabel(MAKEDISKDEV(0, wd->sc_dev.dv_unit,
- RAW_PART), edmcastrategy, lp, wd->sc_dk.dk_cpulabel);
+ errstring = readdisklabel(EDLABELDEV(dev),
+ edmcastrategy, lp, ed->sc_dk.dk_cpulabel);
}
if (errstring) {
- printf("%s: %s\n", wd->sc_dev.dv_xname, errstring);
+ printf("%s: %s\n", ed->sc_dev.dv_xname, errstring);
return;
}
-
-#if 0
- if (wd->drvp->state > RECAL)
- wd->drvp->drive_flags |= DRIVE_RESET;
-#endif
-#ifdef HAS_BAD144_HANDLING
- if ((lp->d_flags & D_BADSECT) != 0)
- bad144intern(wd);
-#endif
}
int
@@ -723,123 +515,79 @@ edmcaioctl(dev, xfer, addr, flag, p)
int flag;
struct proc *p;
{
- struct ed_softc *wd = device_lookup(&ed_cd, DISKUNIT(dev));
+ struct ed_softc *ed = device_lookup(&ed_cd, DISKUNIT(dev));
int error;
-#ifdef __HAVE_OLD_DISKLABEL
- struct disklabel newlabel;
-#endif
WDCDEBUG_PRINT(("edioctl\n"), DEBUG_FUNCS);
- if ((wd->sc_flags & WDF_LOADED) == 0)
+ if ((ed->sc_flags & WDF_LOADED) == 0)
return EIO;
switch (xfer) {
-#ifdef HAS_BAD144_HANDLING
- 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;
-#endif
-
case DIOCGDINFO:
- *(struct disklabel *)addr = *(wd->sc_dk.dk_label);
+ *(struct disklabel *)addr = *(ed->sc_dk.dk_label);
return 0;
-#ifdef __HAVE_OLD_DISKLABEL
- case ODIOCGDINFO:
- newlabel = *(wd->sc_dk.dk_label);
- if (newlabel.d_npartitions > OLDMAXPARTITIONS)
- return ENOTTY;
- memcpy(addr, &newlabel, sizeof (struct olddisklabel));
- return 0;
-#endif
case DIOCGPART:
- ((struct partinfo *)addr)->disklab = wd->sc_dk.dk_label;
+ ((struct partinfo *)addr)->disklab = ed->sc_dk.dk_label;
((struct partinfo *)addr)->part =
- &wd->sc_dk.dk_label->d_partitions[DISKPART(dev)];
+ &ed->sc_dk.dk_label->d_partitions[DISKPART(dev)];
return 0;
case DIOCWDINFO:
case DIOCSDINFO:
-#ifdef __HAVE_OLD_DISKLABEL
- case ODIOCWDINFO:
- case ODIOCSDINFO:
-#endif
{
struct disklabel *lp;
-#ifdef __HAVE_OLD_DISKLABEL
- if (xfer == ODIOCSDINFO || xfer == ODIOCWDINFO) {
- memset(&newlabel, 0, sizeof newlabel);
- memcpy(&newlabel, addr, sizeof (struct olddisklabel));
- lp = &newlabel;
- } else
-#endif
lp = (struct disklabel *)addr;
if ((flag & FWRITE) == 0)
return EBADF;
- if ((error = ed_lock(wd)) != 0)
+ if ((error = ed_lock(ed)) != 0)
return error;
- wd->sc_flags |= WDF_LABELLING;
+ ed->sc_flags |= WDF_LABELLING;
- error = setdisklabel(wd->sc_dk.dk_label,
+ error = setdisklabel(ed->sc_dk.dk_label,
lp, /*wd->sc_dk.dk_openmask : */0,
- wd->sc_dk.dk_cpulabel);
+ ed->sc_dk.dk_cpulabel);
if (error == 0) {
#if 0
if (wd->drvp->state > RECAL)
wd->drvp->drive_flags |= DRIVE_RESET;
#endif
- if (xfer == DIOCWDINFO
-#ifdef __HAVE_OLD_DISKLABEL
- || xfer == ODIOCWDINFO
-#endif
- )
+ if (xfer == DIOCWDINFO)
error = writedisklabel(EDLABELDEV(dev),
- edmcastrategy, wd->sc_dk.dk_label,
- wd->sc_dk.dk_cpulabel);
+ edmcastrategy, ed->sc_dk.dk_label,
+ ed->sc_dk.dk_cpulabel);
}
- wd->sc_flags &= ~WDF_LABELLING;
- ed_unlock(wd);
- return error;
+ ed->sc_flags &= ~WDF_LABELLING;
+ ed_unlock(ed);
+ return (error);
}
case DIOCKLABEL:
if (*(int *)addr)
- wd->sc_flags |= WDF_KLABEL;
+ ed->sc_flags |= WDF_KLABEL;
else
- wd->sc_flags &= ~WDF_KLABEL;
+ ed->sc_flags &= ~WDF_KLABEL;
return 0;
case DIOCWLABEL:
if ((flag & FWRITE) == 0)
return EBADF;
if (*(int *)addr)
- wd->sc_flags |= WDF_WLABEL;
+ ed->sc_flags |= WDF_WLABEL;
else
- wd->sc_flags &= ~WDF_WLABEL;
+ ed->sc_flags &= ~WDF_WLABEL;
return 0;
case DIOCGDEFLABEL:
- edgetdefaultlabel(wd, (struct disklabel *)addr);
- return 0;
-#ifdef __HAVE_OLD_DISKLABEL
- case ODIOCGDEFLABEL:
- edgetdefaultlabel(wd, &newlabel);
- if (newlabel.d_npartitions > OLDMAXPARTITIONS)
- return ENOTTY;
- memcpy(addr, &newlabel, sizeof (struct olddisklabel));
+ edgetdefaultlabel(ed, (struct disklabel *)addr);
return 0;
-#endif
-#ifdef notyet
+#if 0
case DIOCWFORMAT:
if ((flag & FWRITE) == 0)
return EBADF;
@@ -876,18 +624,6 @@ edmcaioctl(dev, xfer, addr, flag, p)
#endif
}
-#if 0
-#ifdef B_FORMAT
-int
-edmcaformat(struct buf *bp)
-{
-
- bp->b_flags |= B_FORMAT;
- return edmcastrategy(bp);
-}
-#endif
-#endif
-
int
edmcasize(dev)
dev_t dev;
@@ -936,6 +672,7 @@ edmcadump(dev, blkno, va, size)
struct disklabel *lp; /* disk's disklabel */
int part;
int nblks; /* total number of sectors left to write */
+ int error;
/* Check if recursive dump; if so, punt. */
if (eddoingadump)
@@ -976,16 +713,10 @@ edmcadump(dev, blkno, va, size)
}
while (nblks > 0) {
- ed->sc_data = va;
- ed->sc_rawblkno = blkno;
- ed->sc_bcount = min(nblks, eddumpmulti) * lp->d_secsize;
- ed->sc_read = 0;
-
- ed_bio(ed, 0, 1);
- if (ed->sc_error)
- return (ed->sc_error);
-
- ed_bio_done(ed);
+ error = edc_bio(ed->edc_softc, ed, va, blkno,
+ min(nblks, eddumpmulti) * lp->d_secsize, 0, 1);
+ if (error)
+ return (error);
/* update block count */
nblks -= min(nblks, eddumpmulti);
@@ -997,36 +728,10 @@ edmcadump(dev, blkno, va, size)
return (0);
}
-#ifdef HAS_BAD144_HANDLING
-/*
- * Internalize the bad sector table.
- */
-static void
-bad144intern(wd)
- struct ed_softc *wd;
-{
- struct dkbad *bt = &wd->sc_dk.dk_cpulabel->bad;
- struct disklabel *lp = wd->sc_dk.dk_label;
- int i = 0;
-
- WDCDEBUG_PRINT(("bad144intern\n"), DEBUG_XFERS);
-
- for (; i < NBT_BAD; 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 < NBT_BAD+1; i++)
- wd->sc_badsect[i] = -1;
-}
-#endif
-
static int
-ed_get_params(ed)
+ed_get_params(ed, drv_flags)
struct ed_softc *ed;
+ int *drv_flags;
{
u_int16_t cmd_args[2];
@@ -1036,17 +741,17 @@ ed_get_params(ed)
cmd_args[0] = 14; /* Options: 00s110, s: 0=Physical 1=Pseudo */
cmd_args[1] = 0;
if (edc_run_cmd(ed->edc_softc, CMD_GET_DEV_CONF, ed->sc_devno,
- cmd_args, 2, 0, 1))
+ cmd_args, 2, 1))
return (1);
- ed->spares = ed->sc_status_block[1] >> 8;
- ed->drv_flags = ed->sc_status_block[1] & 0x1f;
- ed->rba = ed->sc_status_block[2] |
- (ed->sc_status_block[3] << 16);
+ ed->spares = ed->sense_data[1] >> 8;
+ if (drv_flags)
+ *drv_flags = ed->sense_data[1] & 0x1f;
+ ed->rba = ed->sense_data[2] | (ed->sense_data[3] << 16);
/* Instead of using:
- ed->cyl = ed->sc_status_block[4];
- ed->heads = ed->sc_status_block[5] & 0xff;
- ed->sectors = ed->sc_status_block[5] >> 8;
+ ed->cyl = ed->sense_data[4];
+ ed->heads = ed->sense_data[5] & 0xff;
+ ed->sectors = ed->sense_data[5] >> 8;
* we fabricate the numbers from RBA count, so that
* number of sectors is 32 and heads 64. This seems
* to be necessary for integrated ESDI controller.
@@ -1058,72 +763,3 @@ ed_get_params(ed)
return (0);
}
-
-/*
- * Our shutdown hook. We attempt to park disk's head only.
- */
-void
-ed_shutdown(arg)
- void *arg;
-{
-#if 0
- struct ed_softc *ed = arg;
- u_int16_t cmd_args[2];
-
- /* Issue Park Head command */
- cmd_args[0] = 6; /* Options: 000110 */
- cmd_args[1] = 0;
- (void) edc_run_cmd(ed->edc_softc, CMD_PARK_HEAD, ed->sc_devno,
- cmd_args, 2, 0);
-#endif
-}
-
-/*
- * Main worker thread function.
- */
-void
-edworker(arg)
- void *arg;
-{
- struct ed_softc *ed = (struct ed_softc *) arg;
- struct buf *bp;
- int s;
-
- config_pending_decr();
-
- for(;;) {
- /* Wait until awakened */
- (void) tsleep(&ed->sc_q, PRIBIO, "edidle", 0);
-
- if ((ed->sc_flags & EDF_PROCESS_QUEUE) == 0)
- panic("edworker: expecting process queue");
- ed->sc_flags &= ~EDF_PROCESS_QUEUE;
-
- for(;;) {
- /* Is there a buf for us ? */
- simple_lock(&ed->sc_q_lock);
- if ((bp = BUFQ_FIRST(&ed->sc_q)) == NULL) {
- simple_unlock(&ed->sc_q_lock);
- break;
- }
- BUFQ_REMOVE(&ed->sc_q, bp);
- simple_unlock(&ed->sc_q_lock);
-
- /* Schedule i/o operation */
- ed->sc_error = 0;
- s = splbio();
- __edstart(ed, bp);
-
- /*
- * Wait until the command executes; edc_intr() wakes
- * us up.
- */
- if (ed->sc_error == 0)
- (void)tsleep(&ed->edc_softc, PRIBIO, "edwrk",0);
-
- /* Handle i/o results */
- edmcadone(ed, bp);
- splx(s);
- }
- }
-}
diff --git a/sys/dev/mca/edc_mca.c b/sys/dev/mca/edc_mca.c
index c8f15f430b7..647600de49d 100644
--- a/sys/dev/mca/edc_mca.c
+++ b/sys/dev/mca/edc_mca.c
@@ -1,4 +1,4 @@
-/* $NetBSD: edc_mca.c,v 1.10 2001/11/13 07:46:25 lukem Exp $ */
+/* $NetBSD: edc_mca.c,v 1.11 2001/11/23 22:53:09 jdolecek Exp $ */
/*
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -41,19 +41,16 @@
* for MCA rev. 2.2 in hands, thanks to Scott Telford <st@epcc.ed.ac.uk>.
*
* TODO:
- * - move the MCA DMA controller (edc_setup_dma()) goo to device driver
- * independant location
* - improve error recovery
- * add any soft resets when anything gets stuck?
- * - test with > 1 disk (this is supported by some controllers), eliminate
- * any remaining devno=0 assumptions if there are any still
+ * Issue soft reset on error or timeout?
+ * - test with > 1 disk (this is supported by some controllers)
* - test with > 1 ESDI controller in machine; shared interrupts
* necessary for this to work should be supported - edc_intr() specifically
* checks if the interrupt is for this controller
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: edc_mca.c,v 1.10 2001/11/13 07:46:25 lukem Exp $");
+__KERNEL_RCSID(0, "$NetBSD: edc_mca.c,v 1.11 2001/11/23 22:53:09 jdolecek Exp $");
#include "rnd.h"
@@ -69,6 +66,7 @@ __KERNEL_RCSID(0, "$NetBSD: edc_mca.c,v 1.10 2001/11/13 07:46:25 lukem Exp $");
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/kernel.h>
+#include <sys/kthread.h>
#if NRND > 0
#include <sys/rnd.h>
#endif
@@ -85,6 +83,7 @@ __KERNEL_RCSID(0, "$NetBSD: edc_mca.c,v 1.10 2001/11/13 07:46:25 lukem Exp $");
#include <dev/mca/edcvar.h>
#define EDC_ATTN_MAXTRIES 10000 /* How many times check for unbusy */
+#define EDC_MAX_CMD_RES_LEN 8
struct edc_mca_softc {
struct device sc_dev;
@@ -92,19 +91,23 @@ struct edc_mca_softc {
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
+ /* DMA related stuff */
bus_dma_tag_t sc_dmat; /* DMA tag as passed by parent */
- bus_space_handle_t sc_dmaextcmdh;
- bus_space_handle_t sc_dmaexech;
+ bus_dmamap_t sc_dmamap_xfer; /* transfer dma map */
void *sc_ih; /* interrupt handle */
- int sc_drq; /* DRQ number */
- int sc_cmd_async; /* asynchronous cmd pending */
int sc_flags;
#define DASD_QUIET 0x01 /* don't dump cmd error info */
+
#define DASD_MAXDEVS 8
struct ed_softc *sc_ed[DASD_MAXDEVS];
- struct ed_softc sc_controller;
+ int sc_maxdevs; /* max number of disks attached to this
+ * controller */
+
+ /* I/O results variables */
+ volatile int sc_error;
+ volatile int sc_resblk; /* residual block count */
};
int edc_mca_probe __P((struct device *, struct cfdata *, void *));
@@ -114,15 +117,13 @@ struct cfattach edc_mca_ca = {
sizeof(struct edc_mca_softc), edc_mca_probe, edc_mca_attach
};
-#define DMA_EXTCMD 0x18
-#define DMA_EXEC 0x1A
-
static int edc_intr __P((void *));
-static void edc_dump_status_block __P((struct edc_mca_softc *, int, int));
-static int edc_setup_dma __P((struct edc_mca_softc *, int,
- bus_addr_t, bus_size_t));
+static void edc_dump_status_block __P((struct edc_mca_softc *,
+ u_int16_t *, int));
static int edc_do_attn __P((struct edc_mca_softc *, int, int, int));
-static int edc_cmd_wait __P((struct edc_mca_softc *, int, int, int));
+static int edc_cmd_wait __P((struct edc_mca_softc *, int, int));
+static void edcworker __P((void *));
+static void edc_spawn_worker __P((void *));
int
edc_mca_probe(parent, match, aux)
@@ -148,12 +149,11 @@ edc_mca_attach(parent, self, aux)
{
struct edc_mca_softc *sc = (void *) self;
struct mca_attach_args *ma = aux;
+ struct ed_attach_args eda;
int pos2, pos3, pos4;
int irq, drq, iobase;
const char *typestr;
- struct ed_softc *ed;
- struct ed_attach_args eda;
- int devno, maxdevs;
+ int devno, error;
pos2 = mca_conf_read(ma->ma_mc, ma->ma_slot, 2);
pos3 = mca_conf_read(ma->ma_mc, ma->ma_slot, 3);
@@ -231,7 +231,6 @@ edc_mca_attach(parent, self, aux)
printf("DMA pacing control disabled\n");
sc->sc_iot = ma->ma_iot;
- sc->sc_drq = drq;
if (bus_space_map(sc->sc_iot, iobase,
ESDIC_REG_NPORTS, 0, &sc->sc_ioh)) {
@@ -240,19 +239,6 @@ edc_mca_attach(parent, self, aux)
return;
}
- if (bus_space_map(sc->sc_iot, DMA_EXTCMD, 1, 0, &sc->sc_dmaextcmdh)) {
- printf("%s: couldn't map registers\n",
- sc->sc_dev.dv_xname);
- return;
- }
- if (bus_space_map(sc->sc_iot, DMA_EXEC, 1, 0, &sc->sc_dmaexech)) {
- printf("%s: couldn't map registers\n",
- sc->sc_dev.dv_xname);
- return;
- }
-
- sc->sc_dmat = ma->ma_dmat;
-
sc->sc_ih = mca_intr_establish(ma->ma_mc, irq, IPL_BIO, edc_intr, sc);
if (sc->sc_ih == NULL) {
printf("%s: couldn't establish interrupt handler\n",
@@ -260,22 +246,23 @@ edc_mca_attach(parent, self, aux)
return;
}
+ /* Create a MCA DMA map, used for data transfer */
+ sc->sc_dmat = ma->ma_dmat;
+ if ((error = mca_dmamap_create(sc->sc_dmat, MAXPHYS,
+ BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &sc->sc_dmamap_xfer, drq)) != 0){
+ printf("%s: couldn't create DMA map - error %d\n",
+ sc->sc_dev.dv_xname, error);
+ return;
+ }
+
/*
* Integrated ESDI controller supports only one disk, other
* controllers support two disks.
*/
if (ma->ma_id == MCA_PRODUCT_IBM_ESDIC_IG)
- maxdevs = 1;
+ sc->sc_maxdevs = 1;
else
- maxdevs = 2;
-
- /*
- * Initialize the controller ed softc. We could do without this,
- * but absence of checks for controller devno simplifies code logic
- * somewhat.
- */
- sc->sc_ed[DASD_DEVNO_CONTROLLER] = &sc->sc_controller;
- strcpy(sc->sc_controller.sc_dev.dv_xname, sc->sc_dev.dv_xname);/*safe*/
+ sc->sc_maxdevs = 2;
/*
* Reset controller and attach individual disks. ed attach routine
@@ -306,53 +293,53 @@ edc_mca_attach(parent, self, aux)
delay(100);
}
- /*
- * Get dummy ed_softc to be used during probe. Once a disk is
- * found, ed_mca_attach() calls edc_add_disk() to insert the
- * right pointer into sc->sc_ed[] array.
- */
- MALLOC(ed, struct ed_softc *, sizeof(struct ed_softc),
- M_TEMP, M_WAITOK);
-
- /* be quiet duting probes */
+ /* be quiet during probes */
sc->sc_flags |= DASD_QUIET;
/* check for attached disks */
- for(devno=0; devno < maxdevs; devno++) {
- eda.sc_devno = devno;
- eda.sc_dmat = sc->sc_dmat;
- sc->sc_ed[devno] = ed;
- (void *) config_found_sm(self, &eda, NULL, NULL);
+ for(devno=0; devno < sc->sc_maxdevs; devno++) {
+ eda.edc_drive = devno;
+ sc->sc_ed[devno] =
+ (void *) config_found_sm(self, &eda, NULL, NULL);
+
+ /* If initialization did not succeed, NULL the pointer. */
+ if (sc->sc_ed[devno]
+ && (sc->sc_ed[devno]->sc_flags & EDF_INIT) == 0)
+ sc->sc_ed[devno] = NULL;
}
/* enable full error dumps again */
sc->sc_flags &= ~DASD_QUIET;
- /* cleanup */
- FREE(ed, M_TEMP);
-
/*
* Check if there are any disks attached. If not, disestablish
* the interrupt.
*/
- for(devno=0; devno < maxdevs; devno++) {
- if (sc->sc_ed[devno] && (sc->sc_ed[devno]->sc_flags & EDF_INIT))
+ for(devno=0; devno < sc->sc_maxdevs; devno++) {
+ if (sc->sc_ed[devno])
break;
}
- if (devno == maxdevs) {
+
+ if (devno == sc->sc_maxdevs) {
printf("%s: disabling controller (no drives attached)\n",
sc->sc_dev.dv_xname);
mca_intr_disestablish(ma->ma_mc, sc->sc_ih);
+ return;
}
+
+ /*
+ * Run the worker thread.
+ */
+ config_pending_incr();
+ kthread_create(edc_spawn_worker, (void *) sc);
}
void
-edc_add_disk(sc, ed, devno)
+edc_add_disk(sc, ed)
struct edc_mca_softc *sc;
struct ed_softc *ed;
- int devno;
{
- sc->sc_ed[devno] = ed;
+ sc->sc_ed[ed->sc_devno] = ed;
}
static int
@@ -362,8 +349,8 @@ edc_intr(arg)
struct edc_mca_softc *sc = arg;
u_int8_t isr, intr_id;
u_int16_t sifr;
- int cmd=-1, devno, bioerror=0;
- struct ed_softc *ed=NULL;
+ int cmd=-1, devno, error=0;
+ u_int16_t status_block[EDC_MAX_CMD_RES_LEN]; /* CMD status block */
/*
* Check if the interrupt was for us.
@@ -413,14 +400,14 @@ edc_intr(arg)
cmd = sifr & SIFR_CMD_MASK;
/* Read whole status block */
- ed = sc->sc_ed[devno];
- ed->sc_status_block[0] = sifr;
+ memset(status_block, 0, sizeof(status_block)); /* zero first */
+ status_block[0] = sifr;
for(i=1; i < len; i++) {
while((bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR)
& BSR_SIFR_FULL) == 0)
delay(1);
- ed->sc_status_block[i] = le16toh(
+ status_block[i] = le16toh(
bus_space_read_2(sc->sc_iot, sc->sc_ioh, SIFR));
}
}
@@ -428,29 +415,27 @@ edc_intr(arg)
switch (intr_id) {
case ISR_DATA_TRANSFER_RDY:
/*
- * Ready to do DMA, setup DMA controller and kick DASD
- * controller to do the transfer.
+ * Ready to do DMA. The DMA controller has already been
+ * setup, now just kick disk controller to do the transfer.
*/
- ed = sc->sc_ed[devno];
- if (!edc_setup_dma(sc, ed->sc_read,
- ed->dmamap_xfer->dm_segs[0].ds_addr,
- ed->dmamap_xfer->dm_segs[0].ds_len)) {
- /* XXX bail out? */
- printf("%s: edc_setup_dma() failed\n",
- ed->sc_dev.dv_xname);
- bus_space_write_1(sc->sc_iot, sc->sc_ioh, BCR,
- BCR_INT_ENABLE);
- } else {
- /* OK, proceed with DMA */
- bus_space_write_1(sc->sc_iot, sc->sc_ioh, BCR,
- BCR_INT_ENABLE|BCR_DMA_ENABLE);
- }
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, BCR,
+ BCR_INT_ENABLE|BCR_DMA_ENABLE);
break;
case ISR_COMPLETED:
case ISR_COMPLETED_WITH_ECC:
case ISR_COMPLETED_RETRIES:
case ISR_COMPLETED_WARNING:
- bioerror = 0;
+ error = 0;
+
+ /*
+ * Copy device config data if appropriate. sc->sc_ed[]
+ * entry might be NULL during probe.
+ */
+ if (cmd == CMD_GET_DEV_CONF && sc->sc_ed[devno]) {
+ memcpy(sc->sc_ed[devno]->sense_data, status_block,
+ sizeof(sc->sc_ed[devno]->sense_data));
+ }
+
break;
case ISR_RESET_COMPLETED:
case ISR_ABORT_COMPLETED:
@@ -458,9 +443,9 @@ edc_intr(arg)
break;
default:
if ((sc->sc_flags & DASD_QUIET) == 0)
- edc_dump_status_block(sc, devno, intr_id);
+ edc_dump_status_block(sc, status_block, intr_id);
- bioerror = EIO;
+ error = EIO;
break;
}
@@ -476,8 +461,9 @@ edc_intr(arg)
/* If Read or Write Data, wakeup worker thread to finish it */
if (intr_id != ISR_DATA_TRANSFER_RDY
&& (cmd == CMD_READ_DATA || cmd == CMD_WRITE_DATA)) {
- sc->sc_ed[devno]->sc_error = bioerror;
- wakeup_one(&sc->sc_ed[devno]->edc_softc);
+ if ((sc->sc_error = error) == 0)
+ sc->sc_resblk = status_block[SB_RESBLKCNT_IDX];
+ wakeup_one(sc);
}
return (1);
@@ -541,22 +527,32 @@ edc_do_attn(sc, attn_type, devno, intr_id)
* interval.
*/
static int
-edc_cmd_wait(sc, devno, secs, poll)
+edc_cmd_wait(sc, secs, poll)
struct edc_mca_softc *sc;
- int devno, secs, poll;
+ int secs, poll;
{
int val, delayed;
+ if (!poll) {
+ int error;
+
+ /* Not polling, can sleep. Sleep until we are awakened,
+ * but maximum secs seconds.
+ */
+ error = tsleep(sc, PRIBIO, "edcwcmd", secs * hz);
+ if (error)
+ goto err;
+ return (0);
+ }
+
+ /* Poll the controller until command finishes */
delayed = 0;
do {
val = bus_space_read_1(sc->sc_iot,sc->sc_ioh, BSR);
if ((val & BSR_CMD_INPROGRESS) == 0)
break;
- if (poll && (val & BSR_INTR))
- goto out;
-
- if (secs == 0)
+ if (val & BSR_INTR)
break;
delay(1);
@@ -570,44 +566,33 @@ edc_cmd_wait(sc, devno, secs, poll)
delayed = 0;
secs--;
}
-#if 0
- if (delayed % 1000)
- printf("looping ...");
-#endif
- } while(1);
+ } while(secs > 0);
if (secs == 0 &&
bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR) & BSR_CMD_INPROGRESS){
- printf("%s: timed out waiting for previous cmd to finish\n",
- sc->sc_ed[devno]->sc_dev.dv_xname);
+ err:
+ printf("%s: timed out waiting for cmd to finish\n",
+ sc->sc_dev.dv_xname);
return (EAGAIN);
}
- out:
return (0);
}
int
-edc_run_cmd(sc, cmd, devno, cmd_args, cmd_len, async, poll)
+edc_run_cmd(sc, cmd, devno, cmd_args, cmd_len, poll)
struct edc_mca_softc *sc;
int cmd;
int devno;
u_int16_t cmd_args[];
- int cmd_len, async, poll;
+ int cmd_len, poll;
{
int i, error, tries;
u_int16_t cmd0;
- /*
- * If there has been an asynchronous command executed, first wait for it
- * to finish.
- */
- if (sc->sc_cmd_async) {
- /* Wait maximum 15s */
- if (edc_cmd_wait(sc, devno, 15, 0))
- return (EAGAIN); /* Busy */
-
- sc->sc_cmd_async = 0;
+ if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR) & BSR_BUSY) {
+ printf("%s: device busy?\n", sc->sc_dev.dv_xname);
+ return (EAGAIN);
}
/* Do Attention Request for Command Request. */
@@ -635,7 +620,8 @@ edc_run_cmd(sc, cmd, devno, cmd_args, cmd_len, async, poll)
/*
* Write word of CMD to the CIFR. This sets "Command
* Interface Register Full (CMD IN)" in BSR. Once the attachment
- * detects it, it reads the word and clears CMD IN.
+ * detects it, it reads the word and clears CMD IN. This all should
+ * be quite fast, so don't bother with sleeps for !poll case.
*/
for(i=0; i < cmd_len; i++) {
bus_space_write_2(sc->sc_iot, sc->sc_ioh, CIFR,
@@ -647,22 +633,20 @@ edc_run_cmd(sc, cmd, devno, cmd_args, cmd_len, async, poll)
* soon. Quirky hw ?
*/
tries = 0;
- while(bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR) & BSR_CIFR_FULL)
+ for(; (bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR)
+ & BSR_CIFR_FULL) && tries < 1000 ; tries++)
delay(poll ? 1000 : 1);
- }
- /*
- * Attachment is now executing the command. Unless we are executing
- * command asynchronously, wait until it finishes.
- */
- if (async) {
- sc->sc_cmd_async = 1;
- return (0);
+ if (tries == 10000) {
+ printf("%s: device too slow to accept command %d\n",
+ sc->sc_dev.dv_xname, cmd);
+ return (EAGAIN);
+ }
}
/* Wait for command to complete, but maximum 15 seconds. */
- if (edc_cmd_wait(sc, devno, 15, poll))
- return (EAGAIN);
+ if ((error = edc_cmd_wait(sc, 15, poll)))
+ return (error);
/* If polling, call edc_intr() explicitly */
if (poll) {
@@ -672,70 +656,21 @@ edc_run_cmd(sc, cmd, devno, cmd_args, cmd_len, async, poll)
* If got attention id DATA TRANSFER READY, wait for
* the transfer to finish.
*/
- if (sc->sc_ed[devno]->sc_error == 0
- && (cmd == CMD_READ_DATA || cmd == CMD_WRITE_DATA)) {
- if (edc_cmd_wait(sc, devno, 15, 1))
- return (EAGAIN);
+ if ((cmd == CMD_READ_DATA || cmd == CMD_WRITE_DATA)
+ && sc->sc_error == 0) {
+ if ((error = edc_cmd_wait(sc, 15, poll)))
+ return (error);
edc_intr(sc);
}
- if (edc_cmd_wait(sc, devno, 15, 0))
- return (EAGAIN);
- }
-
- /* Check if the command completed successfully; if not, return error */
- switch(SB_GET_CMD_STATUS(sc->sc_ed[devno]->sc_status_block)) {
- case ISR_COMPLETED:
- case ISR_COMPLETED_WITH_ECC:
- case ISR_COMPLETED_RETRIES:
- case ISR_COMPLETED_WARNING:
- return (0);
- default:
- return (EIO);
+ if ((error = edc_cmd_wait(sc, 15, poll)))
+ return (error);
}
-}
-
-static int
-edc_setup_dma(sc, isread, phys, cnt)
- struct edc_mca_softc *sc;
- int isread;
- bus_addr_t phys;
- bus_size_t cnt;
-{
- /* XXX magic constants, should be moved to device-independant location*/
- /* The exact sequence to setup MCA DMA controller is taken from Minix */
-
- bus_space_write_1(sc->sc_iot, sc->sc_dmaextcmdh, 0,
- 0x90 + sc->sc_drq);
- /* Disable access to dma channel */
- bus_space_write_1(sc->sc_iot, sc->sc_dmaextcmdh, 0,
- 0x20 + sc->sc_drq);
- /* Clear the address byte pointer */
- bus_space_write_1(sc->sc_iot, sc->sc_dmaexech, 0,
- (phys >> 0) & 0xff); /* address bits 0..7 */
- bus_space_write_1(sc->sc_iot, sc->sc_dmaexech, 0,
- (phys >> 8) & 0xff); /* address bits 8..15 */
- bus_space_write_1(sc->sc_iot, sc->sc_dmaexech, 0,
- (phys >> 16) & 0xff); /* address bits 16..23 */
- bus_space_write_1(sc->sc_iot, sc->sc_dmaextcmdh, 0,
- 0x40 + sc->sc_drq);
- /* Clear the count byte pointer */
- bus_space_write_1(sc->sc_iot, sc->sc_dmaexech, 0,
- ((cnt - 1) >> 0) & 0xff); /* count bits 0..7 */
- bus_space_write_1(sc->sc_iot, sc->sc_dmaexech, 0,
- ((cnt - 1) >> 8) & 0xff); /* count bits 8..15 */
- bus_space_write_1(sc->sc_iot, sc->sc_dmaextcmdh, 0,
- 0x70 + sc->sc_drq);
- /* Set the transfer mode */
- bus_space_write_1(sc->sc_iot, sc->sc_dmaexech, 0,
- (isread) ? 0x4C : 0x44);
- bus_space_write_1(sc->sc_iot, sc->sc_dmaextcmdh, 0,
- 0xA0 + sc->sc_drq);
- /* Enable access to dma channel */
- return (1);
+ return (sc->sc_error);
}
+#ifdef EDC_DEBUG
static const char * const edc_commands[] = {
"Invalid Command",
"Read Data",
@@ -832,36 +767,51 @@ static const char * const edc_dev_errors[] = {
"No ID found on track (ID search)",
/* 0x19 - 0xff reserved */
};
+#endif /* EDC_DEBUG */
static void
-edc_dump_status_block(sc, devno, intr_id)
+edc_dump_status_block(sc, status_block, intr_id)
struct edc_mca_softc *sc;
- int devno, intr_id;
+ u_int16_t *status_block;
+ int intr_id;
{
- struct ed_softc *ed = sc->sc_ed[devno];
+#ifdef EDC_DEBUG
printf("%s: Command: %s, Status: %s\n",
- ed->sc_dev.dv_xname,
- edc_commands[ed->sc_status_block[0] & 0x1f],
- edc_cmd_status[SB_GET_CMD_STATUS(ed->sc_status_block)]
+ sc->sc_dev.dv_xname,
+ edc_commands[status_block[0] & 0x1f],
+ edc_cmd_status[SB_GET_CMD_STATUS(status_block)]
);
+#else
+ printf("%s: Command: %d, Status: %d\n",
+ sc->sc_dev.dv_xname,
+ status_block[0] & 0x1f,
+ SB_GET_CMD_STATUS(status_block));
+#endif
printf("%s: # left blocks: %u, last processed RBA: %u\n",
- ed->sc_dev.dv_xname,
- ed->sc_status_block[SB_RESBLKCNT_IDX],
- (ed->sc_status_block[5] << 16) | ed->sc_status_block[4]);
+ sc->sc_dev.dv_xname,
+ status_block[SB_RESBLKCNT_IDX],
+ (status_block[5] << 16) | status_block[4]);
if (intr_id == ISR_COMPLETED_WARNING) {
+#ifdef EDC_DEBUG
printf("%s: Command Error Code: %s\n",
- ed->sc_dev.dv_xname,
- edc_cmd_error[ed->sc_status_block[1] & 0xff]);
+ sc->sc_dev.dv_xname,
+ edc_cmd_error[status_block[1] & 0xff]);
+#else
+ printf("%s: Command Error Code: %d\n",
+ sc->sc_dev.dv_xname,
+ status_block[1] & 0xff);
+#endif
}
if (intr_id == ISR_CMD_FAILED) {
+#ifdef EDC_DEBUG
char buf[100];
printf("%s: Device Error Code: %s\n",
- ed->sc_dev.dv_xname,
- edc_dev_errors[ed->sc_status_block[2] & 0xff]);
- bitmask_snprintf((ed->sc_status_block[2] & 0xff00) >> 8,
+ sc->sc_dev.dv_xname,
+ edc_dev_errors[status_block[2] & 0xff]);
+ bitmask_snprintf((status_block[2] & 0xff00) >> 8,
"\20"
"\01SeekOrCmdComplete"
"\02Track0Flag"
@@ -873,6 +823,147 @@ edc_dump_status_block(sc, devno, intr_id)
"\010Reserved0",
buf, sizeof(buf));
printf("%s: Device Status: %s\n",
- ed->sc_dev.dv_xname, buf);
+ sc->sc_dev.dv_xname, buf);
+#else
+ printf("%s: Device Error Code: %d, Device Status: %d\n",
+ sc->sc_dev.dv_xname,
+ status_block[2] & 0xff,
+ (status_block[2] & 0xff00) >> 8);
+#endif
+ }
+}
+
+static void
+edc_spawn_worker(arg)
+ void *arg;
+{
+ struct edc_mca_softc *sc = (struct edc_mca_softc *) arg;
+ int error;
+ struct proc *wrk;
+
+ /* Now, everything is ready, start a kthread */
+ if ((error = kthread_create1(edcworker, sc, &wrk,
+ "%s", sc->sc_dev.dv_xname))) {
+ printf("%s: cannot spawn worker thread: errno=%d\n",
+ sc->sc_dev.dv_xname, error);
+ panic("edc_spawn_worker");
}
}
+
+/*
+ * Main worker thread function.
+ */
+void
+edcworker(arg)
+ void *arg;
+{
+ struct edc_mca_softc *sc = (struct edc_mca_softc *) arg;
+ struct ed_softc *ed;
+ struct buf *bp;
+ int s, i, error;
+
+ config_pending_decr();
+
+ s = splbio();
+
+ for(;;) {
+ /* Wait until awakened */
+ (void) tsleep(sc, PRIBIO, "edcidle", 0);
+
+ for(i=0; i<sc->sc_maxdevs; ) {
+ if ((ed = sc->sc_ed[i]) == NULL) {
+ i++;
+ continue;
+ }
+
+ /* Is there a buf for us ? */
+ simple_lock(&ed->sc_q_lock);
+ if ((bp = BUFQ_FIRST(&ed->sc_q)) == NULL) {
+ simple_unlock(&ed->sc_q_lock);
+ i++;
+ continue;
+ }
+ BUFQ_REMOVE(&ed->sc_q, bp);
+ simple_unlock(&ed->sc_q_lock);
+
+ /* Instrumentation. */
+ disk_busy(&ed->sc_dk);
+
+ error = edc_bio(sc, ed, bp->b_data, bp->b_bcount,
+ bp->b_rawblkno, (bp->b_flags & B_READ), 0);
+
+ if (error) {
+ bp->b_error = error;
+ bp->b_flags |= B_ERROR;
+ } else {
+ /* Set resid, most commonly to zero. */
+ bp->b_resid = sc->sc_resblk * DEV_BSIZE;
+ }
+
+ disk_unbusy(&ed->sc_dk, (bp->b_bcount - bp->b_resid));
+#if NRND > 0
+ rnd_add_uint32(&ed->rnd_source, bp->b_blkno);
+#endif
+ biodone(bp);
+ }
+ }
+
+ splx(s);
+}
+
+int
+edc_bio(struct edc_mca_softc *sc, struct ed_softc *ed, void *data,
+ size_t bcount, daddr_t rawblkno, int isread, int poll)
+{
+ u_int16_t cmd_args[4];
+ int error=0, fl;
+ u_int16_t track;
+ u_int16_t cyl;
+ u_int8_t head;
+ u_int8_t sector;
+
+ mca_disk_busy();
+
+ /* set WAIT and R/W flag appropriately for the DMA transfer */
+ fl = ((poll) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK)
+ | ((isread) ? BUS_DMA_READ : BUS_DMA_WRITE);
+
+ /* Load the buffer for DMA transfer. */
+ if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap_xfer, data,
+ bcount, NULL, BUS_DMA_STREAMING|fl))) {
+ printf("%s: ed_bio: unable to load DMA buffer - error %d\n",
+ ed->sc_dev.dv_xname, error);
+ goto out;
+ }
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_xfer, 0,
+ bcount, (isread) ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
+
+ track = rawblkno / ed->sectors;
+ head = track % ed->heads;
+ cyl = track / ed->heads;
+ sector = rawblkno % ed->sectors;
+
+ /* Read or Write Data command */
+ cmd_args[0] = 2; /* Options 0000010 */
+ cmd_args[1] = bcount / DEV_BSIZE;
+ cmd_args[2] = ((cyl & 0x1f) << 11) | (head << 5) | sector;
+ cmd_args[3] = ((cyl & 0x3E0) >> 5);
+ error = edc_run_cmd(sc,
+ (isread) ? CMD_READ_DATA : CMD_WRITE_DATA,
+ ed->sc_devno, cmd_args, 4, poll);
+
+ /* Sync the DMA memory */
+ if (!error) {
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_xfer, 0, bcount,
+ (isread)? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
+ }
+
+ /* We are done, unload buffer from DMA map */
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap_xfer);
+
+ out:
+ mca_disk_unbusy();
+
+ return (error);
+}