diff options
author | jlemon <jlemon@FreeBSD.org> | 2001-02-26 22:25:30 +0000 |
---|---|---|
committer | jlemon <jlemon@FreeBSD.org> | 2001-02-26 22:25:30 +0000 |
commit | 88383c1fc469dc0031b59f9f8ce8c41a8bb37d96 (patch) | |
tree | 7fba17c04c03de1fcf71fd22fad55071f5eee5dd /sys/dev/ida | |
parent | 95dbcd4c3875ca99c450dd5b8a7f6fc938d67c64 (diff) | |
download | FreeBSD-src-88383c1fc469dc0031b59f9f8ce8c41a8bb37d96.zip FreeBSD-src-88383c1fc469dc0031b59f9f8ce8c41a8bb37d96.tar.gz |
Add crashdump support.
Tested by: ps
Diffstat (limited to 'sys/dev/ida')
-rw-r--r-- | sys/dev/ida/ida.c | 42 | ||||
-rw-r--r-- | sys/dev/ida/ida_disk.c | 66 | ||||
-rw-r--r-- | sys/dev/ida/ida_eisa.c | 8 | ||||
-rw-r--r-- | sys/dev/ida/ida_pci.c | 10 | ||||
-rw-r--r-- | sys/dev/ida/idavar.h | 5 |
5 files changed, 106 insertions, 25 deletions
diff --git a/sys/dev/ida/ida.c b/sys/dev/ida/ida.c index 83396ae..e5494c0 100644 --- a/sys/dev/ida/ida.c +++ b/sys/dev/ida/ida.c @@ -41,6 +41,7 @@ #include <pci.h> #include <sys/param.h> +#include <sys/kernel.h> #include <sys/systm.h> #include <sys/malloc.h> @@ -64,7 +65,7 @@ static void ida_alloc_qcb(struct ida_softc *ida); static void ida_construct_qcb(struct ida_softc *ida); static void ida_start(struct ida_softc *ida); static void ida_done(struct ida_softc *ida, struct ida_qcb *qcb); -static void ida_wait(struct ida_softc *ida, struct ida_qcb *qcb, int delay); +static int ida_wait(struct ida_softc *ida, struct ida_qcb *qcb); void ida_free(struct ida_softc *ida) @@ -249,7 +250,7 @@ ida_attach(struct ida_softc *ida) ida->cmd.int_enable(ida, 0); error = ida_command(ida, CMD_GET_CTRL_INFO, &cinfo, sizeof(cinfo), - IDA_CONTROLLER, DMA_DATA_IN); + IDA_CONTROLLER, 0, DMA_DATA_IN); if (error) { device_printf(ida->dev, "CMD_GET_CTRL_INFO failed.\n"); return; @@ -263,7 +264,7 @@ ida_attach(struct ida_softc *ida) int data; error = ida_command(ida, CMD_START_FIRMWARE, - &data, sizeof(data), IDA_CONTROLLER, DMA_DATA_IN); + &data, sizeof(data), IDA_CONTROLLER, 0, DMA_DATA_IN); if (error) { device_printf(ida->dev, "CMD_START_FIRMWARE failed.\n"); return; @@ -322,12 +323,12 @@ ida_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error) int ida_command(struct ida_softc *ida, int command, void *data, int datasize, - int drive, int flags) + int drive, u_int32_t pblkno, int flags) { struct ida_hardware_qcb *hwqcb; struct ida_qcb *qcb; bus_dmasync_op_t op; - int s; + int s, error; s = splbio(); qcb = ida_get_qcb(ida); @@ -335,7 +336,7 @@ ida_command(struct ida_softc *ida, int command, void *data, int datasize, if (qcb == NULL) { printf("ida_command: out of QCBs"); - return (1); + return (EAGAIN); } hwqcb = qcb->hwqcb; @@ -348,6 +349,7 @@ ida_command(struct ida_softc *ida, int command, void *data, int datasize, bus_dmamap_sync(ida->buffer_dmat, qcb->dmamap, op); hwqcb->hdr.drive = drive; + hwqcb->req.blkno = pblkno; hwqcb->req.bcount = howmany(datasize, DEV_BSIZE); hwqcb->req.command = command; @@ -356,13 +358,13 @@ ida_command(struct ida_softc *ida, int command, void *data, int datasize, s = splbio(); STAILQ_INSERT_TAIL(&ida->qcb_queue, qcb, link.stqe); ida_start(ida); - ida_wait(ida, qcb, 500); + error = ida_wait(ida, qcb); splx(s); /* XXX should have status returned here? */ /* XXX have "status pointer" area in QCB? */ - return (0); + return (error); } void @@ -437,30 +439,32 @@ ida_start(struct ida_softc *ida) } } -static -void -ida_wait(struct ida_softc *ida, struct ida_qcb *qcb, int delay) +static int +ida_wait(struct ida_softc *ida, struct ida_qcb *qcb) { struct ida_qcb *qcb_done = NULL; bus_addr_t completed; + int delay; - if (ida->flags & IDA_ATTACHED) { - if (tsleep((caddr_t)qcb, PRIBIO, "idacmd", delay)) - panic("ida_command: timeout waiting for interrupt"); - return; + if (ida->flags & IDA_INTERRUPTS) { + if (tsleep((caddr_t)qcb, PRIBIO, "idacmd", 5 * hz)) + return (ETIMEDOUT); + return (0); } +again: + delay = 5 * 1000 * 100; /* 5 sec delay */ while ((completed = ida->cmd.done(ida)) == 0) { if (delay-- == 0) - panic("ida_wait: timeout waiting for completion"); + return (ETIMEDOUT); DELAY(10); } qcb_done = idahwqcbptov(ida, completed & ~3); if (qcb_done != qcb) - panic("ida_wait: incorrect qcb returned"); + goto again; ida_done(ida, qcb); - return; + return (0); } void @@ -520,7 +524,7 @@ ida_done(struct ida_softc *ida, struct ida_qcb *qcb) } if (qcb->flags & IDA_COMMAND) { - if (ida->flags & IDA_ATTACHED) + if (ida->flags & IDA_INTERRUPTS) wakeup(qcb); } else { if (error) diff --git a/sys/dev/ida/ida_disk.c b/sys/dev/ida/ida_disk.c index 8863adc..257cc30 100644 --- a/sys/dev/ida/ida_disk.c +++ b/sys/dev/ida/ida_disk.c @@ -37,6 +37,7 @@ #include <sys/bio.h> #include <sys/bus.h> #include <sys/conf.h> +#include <sys/cons.h> #include <sys/devicestat.h> #include <sys/disk.h> @@ -47,6 +48,10 @@ #include <machine/bus.h> #include <sys/rman.h> +#include <vm/vm.h> +#include <vm/pmap.h> +#include <machine/md_var.h> + #include <dev/ida/idareg.h> #include <dev/ida/idavar.h> @@ -58,6 +63,7 @@ static int idad_detach(device_t dev); static d_open_t idad_open; static d_close_t idad_close; static d_strategy_t idad_strategy; +static d_dump_t idad_dump; #define IDAD_BDEV_MAJOR 29 #define IDAD_CDEV_MAJOR 109 @@ -73,7 +79,7 @@ static struct cdevsw id_cdevsw = { /* strategy */ idad_strategy, /* name */ "idad", /* maj */ IDAD_CDEV_MAJOR, - /* dump */ nodump, + /* dump */ idad_dump, /* psize */ nopsize, /* flags */ D_DISK, /* bmaj */ IDAD_BDEV_MAJOR @@ -190,6 +196,62 @@ done: return; } +static int +idad_dump(dev_t dev) +{ + struct idad_softc *drv; + u_int count, blkno, secsize; + long blkcnt; + int i, error, dumppages; + caddr_t va; + vm_offset_t addr, a; + + if ((error = disk_dumpcheck(dev, &count, &blkno, &secsize))) + return (error); + + drv = idad_getsoftc(dev); + if (drv == NULL) + return (ENXIO); + + addr = 0; + blkcnt = howmany(PAGE_SIZE, secsize); + + while (count > 0) { + va = NULL; + + dumppages = imin(count / blkcnt, MAXDUMPPGS); + + for (i = 0; i < dumppages; i++) { + a = addr + (i * PAGE_SIZE); + if (is_physical_memory(a)) + va = pmap_kenter_temporary(trunc_page(a), i); + else + va = pmap_kenter_temporary(trunc_page(0), i); + } + + error = ida_command(drv->controller, CMD_WRITE, va, + PAGE_SIZE * dumppages, drv->drive, blkno, DMA_DATA_OUT); + if (error) + return (error); + + if (addr % (1024 * 1024) == 0) { +#ifdef HW_WDOG + if (wdog_tickler) + (*wdog_tickler)(); +#endif + printf("%ld ", (long)(count * DEV_BSIZE)/(1024 * 1024)); + } + + blkno += blkcnt * dumppages; + count -= blkcnt * dumppages; + addr += PAGE_SIZE * dumppages; + + if (cncheckc() != -1) + return (EINTR); + } + return (0); +} + void idad_intr(struct bio *bp) { @@ -229,7 +291,7 @@ idad_attach(device_t dev) drv->controller->num_drives++; error = ida_command(drv->controller, CMD_GET_LOG_DRV_INFO, - &dinfo, sizeof(dinfo), drv->drive, DMA_DATA_IN); + &dinfo, sizeof(dinfo), drv->drive, 0, DMA_DATA_IN); if (error) { device_printf(dev, "CMD_GET_LOG_DRV_INFO failed\n"); return (ENXIO); diff --git a/sys/dev/ida/ida_eisa.c b/sys/dev/ida/ida_eisa.c index 7c54e13..41d4096 100644 --- a/sys/dev/ida/ida_eisa.c +++ b/sys/dev/ida/ida_eisa.c @@ -122,8 +122,10 @@ ida_v1_int_enable(struct ida_softc *ida, int enable) ida_outb(ida, R_EISA_LOCAL_DOORBELL, EISA_CHANNEL_BUSY); ida_outb(ida, R_EISA_INT_MASK, INT_ENABLE); ida_outb(ida, R_EISA_SYSTEM_MASK, INT_ENABLE); + ida->flags |= IDA_INTERRUPTS; } else { ida_outb(ida, R_EISA_SYSTEM_MASK, INT_DISABLE); + ida->flags &= ~IDA_INTERRUPTS; } } @@ -154,6 +156,10 @@ ida_v2_int_pending(struct ida_softc *ida) static void ida_v2_int_enable(struct ida_softc *ida, int enable) { + if (enable) + ida->flags |= IDA_INTERRUPTS; + else + ida->flags &= ~IDA_INTERRUPTS; ida_outl(ida, R_INT_MASK, enable ? INT_ENABLE : INT_DISABLE); } @@ -328,7 +334,7 @@ ida_eisa_attach(device_t dev) } ida_attach(ida); - ida->flags |= IDA_ATTACHED; + ida->flags |= IDA_ATTACHED; return (0); } diff --git a/sys/dev/ida/ida_pci.c b/sys/dev/ida/ida_pci.c index 19930b3..cf1f2d5 100644 --- a/sys/dev/ida/ida_pci.c +++ b/sys/dev/ida/ida_pci.c @@ -83,6 +83,10 @@ ida_v3_int_pending(struct ida_softc *ida) static void ida_v3_int_enable(struct ida_softc *ida, int enable) { + if (enable) + ida->flags |= IDA_INTERRUPTS; + else + ida->flags &= ~IDA_INTERRUPTS; ida_outl(ida, R_INT_MASK, enable ? INT_ENABLE : INT_DISABLE); } @@ -119,6 +123,10 @@ ida_v4_int_pending(struct ida_softc *ida) static void ida_v4_int_enable(struct ida_softc *ida, int enable) { + if (enable) + ida->flags |= IDA_INTERRUPTS; + else + ida->flags &= ~IDA_INTERRUPTS; ida_outl(ida, R_42XX_INT_MASK, enable ? INT_ENABLE_42XX : INT_DISABLE_42XX); } @@ -287,7 +295,7 @@ ida_pci_attach(device_t dev) return (error); } ida_attach(ida); - ida->flags |= IDA_ATTACHED; + ida->flags |= IDA_ATTACHED; return (0); } diff --git a/sys/dev/ida/idavar.h b/sys/dev/ida/idavar.h index 2540f30..c11438e 100644 --- a/sys/dev/ida/idavar.h +++ b/sys/dev/ida/idavar.h @@ -119,8 +119,9 @@ struct ida_access { /* * flags for the controller */ -#define IDA_ATTACHED 0x01 /* attached, interrupts okay */ +#define IDA_ATTACHED 0x01 /* attached */ #define IDA_FIRMWARE 0x02 /* firmware must be started */ +#define IDA_INTERRUPTS 0x04 /* interrupts enabled */ struct ida_softc { device_t dev; @@ -194,7 +195,7 @@ extern void ida_free(struct ida_softc *ida); extern int ida_init(struct ida_softc *ida); extern void ida_attach(struct ida_softc *ida); extern int ida_command(struct ida_softc *ida, int command, void *data, - int datasize, int drive, int flags); + int datasize, int drive, u_int32_t pblkno, int flags); extern void ida_submit_buf(struct ida_softc *ida, struct bio *bp); extern void ida_intr(void *data); |