summaryrefslogtreecommitdiff
path: root/sys/dev/aac/aac_disk.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/aac/aac_disk.c')
-rw-r--r--sys/dev/aac/aac_disk.c116
1 files changed, 107 insertions, 9 deletions
diff --git a/sys/dev/aac/aac_disk.c b/sys/dev/aac/aac_disk.c
index d8331ea592c4..931be9d8864a 100644
--- a/sys/dev/aac/aac_disk.c
+++ b/sys/dev/aac/aac_disk.c
@@ -42,6 +42,10 @@
#include <sys/devicestat.h>
#include <sys/disk.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/md_var.h>
#include <machine/bus.h>
#include <sys/rman.h>
@@ -62,6 +66,7 @@ static int aac_disk_detach(device_t dev);
static d_open_t aac_disk_open;
static d_close_t aac_disk_close;
static d_strategy_t aac_disk_strategy;
+static d_dump_t aac_disk_dump;
#define AAC_DISK_CDEV_MAJOR 151
@@ -76,9 +81,12 @@ static struct cdevsw aac_disk_cdevsw = {
/* strategy */ aac_disk_strategy,
/* name */ "aacd",
/* maj */ AAC_DISK_CDEV_MAJOR,
- /* dump */ nodump,
+ /* dump */ aac_disk_dump,
/* psize */ nopsize,
/* flags */ D_DISK,
+#if __FreeBSD_version < 500005
+ /* bmaj */ -1
+#endif
};
devclass_t aac_disk_devclass;
@@ -108,7 +116,9 @@ TUNABLE_INT("hw.aac.iosize_max", &aac_iosize_max);
SYSCTL_DECL(_hw_aac);
SYSCTL_UINT(_hw_aac, OID_AUTO, iosize_max, CTLFLAG_RD, &aac_iosize_max, 0,
- "Max I/O size per transfer to an array");
+ "Max I/O size per transfer to an array");
+
+#define AAC_MAXIO 65536
/******************************************************************************
* Handle open from generic layer.
@@ -181,6 +191,13 @@ aac_disk_strategy(struct bio *bp)
return;
}
+ /* do-nothing operation? */
+ if (bp->bio_bcount == 0) {
+ bp->bio_resid = bp->bio_bcount;
+ biodone(bp);
+ return;
+ }
+
/* perform accounting */
devstat_start_transaction(&sc->ad_stats);
@@ -190,6 +207,82 @@ aac_disk_strategy(struct bio *bp)
}
/******************************************************************************
+ * Dump memory out to an array
+ *
+ * This queues blocks of memory of size AAC_MAXIO to the controller and waits
+ * for the controller to complete the requests.
+ */
+static int
+aac_disk_dump(dev_t dev)
+{
+ struct aac_disk *ad = dev->si_drv1;
+ struct aac_softc *sc;
+ vm_offset_t addr = 0;
+ long blkcnt;
+ unsigned int count, blkno, secsize;
+ int dumppages = AAC_MAXIO / PAGE_SIZE;
+ int i, error;
+
+ if ((error = disk_dumpcheck(dev, &count, &blkno, &secsize)))
+ return (error);
+
+ if (ad == NULL)
+ return (ENXIO);
+
+ sc= ad->ad_controller;
+
+ blkcnt = howmany(PAGE_SIZE, secsize);
+
+ while (count > 0) {
+ caddr_t va = NULL;
+
+ if ((count / blkcnt) < dumppages)
+ dumppages = count / blkcnt;
+
+ for (i = 0; i < dumppages; ++i) {
+ vm_offset_t 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);
+ }
+ }
+
+retry:
+ /*
+ * Queue the block to the controller. If the queue is full, EBUSY
+ * will be returned.
+ */
+ error = aac_dump_enqueue(ad, blkno, va, dumppages);
+ if (error && (error != EBUSY))
+ return (error);
+
+ if (!error) {
+ if (dumpstatus(addr, (long)(count * DEV_BSIZE)) < 0)
+ return (EINTR);
+
+ blkno += blkcnt * dumppages;
+ count -= blkcnt * dumppages;
+ addr += PAGE_SIZE * dumppages;
+ if (count > 0)
+ continue;
+ }
+
+ /*
+ * Either the queue was full on the last attemp, or we have no more
+ * data to dump. Let the queue drain out and retry the block if
+ * the queue was full.
+ */
+ aac_dump_complete(sc);
+
+ if (error == EBUSY)
+ goto retry;
+ }
+
+ return (0);
+}
+
+/******************************************************************************
* Handle completion of an I/O request.
*/
void
@@ -200,8 +293,13 @@ aac_biodone(struct bio *bp)
debug_called(4);
devstat_end_transaction_bio(&sc->ad_stats, bp);
- if (bp->bio_flags & BIO_ERROR)
+ if (bp->bio_flags & BIO_ERROR) {
+#if __FreeBSD_version > 500005
diskerr(bp, (char *)bp->bio_driver1, 0, &sc->ad_label);
+#else
+ diskerr(bp, (char *)bp->bio_driver1, 0, -1, &sc->ad_label);
+#endif
+ }
biodone(bp);
}
@@ -212,7 +310,7 @@ static int
aac_disk_probe(device_t dev)
{
- debug_called(4);
+ debug_called(2);
return (0);
}
@@ -225,7 +323,7 @@ aac_disk_attach(device_t dev)
{
struct aac_disk *sc = (struct aac_disk *)device_get_softc(dev);
- debug_called(4);
+ debug_called(1);
/* initialise our softc */
sc->ad_controller =
@@ -267,6 +365,7 @@ aac_disk_attach(device_t dev)
#endif
sc->ad_dev_t->si_iosize_max = aac_iosize_max;
+ sc->unit = device_get_unit(dev);
return (0);
}
@@ -279,17 +378,16 @@ aac_disk_detach(device_t dev)
{
struct aac_disk *sc = (struct aac_disk *)device_get_softc(dev);
- debug_called(4);
+ debug_called(2);
if (sc->ad_flags & AAC_DISK_OPEN)
return(EBUSY);
devstat_remove_entry(&sc->ad_stats);
+ disk_destroy(sc->ad_dev_t);
#ifdef FREEBSD_4
if (--disks_registered == 0)
- cdevsw_remove(&aac_disk_disk_cdevsw);
-#else
- disk_destroy(sc->ad_dev_t);
+ cdevsw_remove(&aac_disk_cdevsw);
#endif
return(0);