summaryrefslogtreecommitdiffstats
path: root/sys/dev/aac
diff options
context:
space:
mode:
authoremaste <emaste@FreeBSD.org>2008-04-03 23:29:31 +0000
committeremaste <emaste@FreeBSD.org>2008-04-03 23:29:31 +0000
commit3e2864c15bf1d092f3a98e55d5b99b3a25e5d895 (patch)
treeb92ea2d59d5dfe789bd414f773157d3d6427dcbb /sys/dev/aac
parentbb6c26f00ef1c89fbaf62df080b26622eb6ec2e8 (diff)
downloadFreeBSD-src-3e2864c15bf1d092f3a98e55d5b99b3a25e5d895.zip
FreeBSD-src-3e2864c15bf1d092f3a98e55d5b99b3a25e5d895.tar.gz
Allow crashdumps on machines with >4GB of RAM as long as the adapter can
do 64-bit S/G. Submitted by: Alex Bencz Reviewed by: scottl
Diffstat (limited to 'sys/dev/aac')
-rw-r--r--sys/dev/aac/aac_disk.c67
1 files changed, 54 insertions, 13 deletions
diff --git a/sys/dev/aac/aac_disk.c b/sys/dev/aac/aac_disk.c
index 6568a0d..2e7dbac 100644
--- a/sys/dev/aac/aac_disk.c
+++ b/sys/dev/aac/aac_disk.c
@@ -183,9 +183,6 @@ aac_disk_strategy(struct bio *bp)
/*
* Map the S/G elements for doing a dump.
- *
- * XXX This does not handle >4GB of RAM. Fixing it is possible except on
- * adapters that cannot do 64bit s/g lists.
*/
static void
aac_dump_map_sg(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
@@ -212,6 +209,31 @@ aac_dump_map_sg(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
}
/*
+ * Map the S/G elements for doing a dump on 64-bit capable devices.
+ */
+static void
+aac_dump_map_sg64(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+ struct aac_fib *fib;
+ struct aac_blockwrite64 *bw;
+ struct aac_sg_table64 *sg;
+ int i;
+
+ fib = (struct aac_fib *)arg;
+ bw = (struct aac_blockwrite64 *)&fib->data[0];
+ sg = &bw->SgMap64;
+
+ if (sg != NULL) {
+ sg->SgCount = nsegs;
+ for (i = 0; i < nsegs; i++) {
+ sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
+ sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
+ }
+ fib->Header.Size = nsegs * sizeof(struct aac_sg_entry64);
+ }
+}
+
+/*
* Dump memory out to an array
*
* Send out one command at a time with up to AAC_MAXIO of data.
@@ -222,12 +244,13 @@ aac_disk_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size
struct aac_disk *ad;
struct aac_softc *sc;
struct aac_fib *fib;
- struct aac_blockwrite *bw;
size_t len;
int size;
static bus_dmamap_t dump_datamap;
static int first = 0;
struct disk *dp;
+ bus_dmamap_callback_t *callback;
+ u_int32_t command;
dp = arg;
ad = dp->d_drv1;
@@ -247,15 +270,33 @@ aac_disk_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size
/* Skip aac_alloc_sync_fib(). We don't want to mess with sleep locks */
fib = &sc->aac_common->ac_sync_fib;
- bw = (struct aac_blockwrite *)&fib->data[0];
while (length > 0) {
len = (length > AAC_MAXIO) ? AAC_MAXIO : length;
- bw->Command = VM_CtBlockWrite;
- bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
- bw->BlockNumber = offset / AAC_BLOCK_SIZE;
- bw->ByteCount = len;
- bw->Stable = CUNSTABLE;
+ if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
+ struct aac_blockwrite *bw;
+ bw = (struct aac_blockwrite *)&fib->data[0];
+ bw->Command = VM_CtBlockWrite;
+ bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
+ bw->BlockNumber = offset / AAC_BLOCK_SIZE;
+ bw->ByteCount = len;
+ bw->Stable = CUNSTABLE;
+ command = ContainerCommand;
+ callback = aac_dump_map_sg;
+ size = sizeof(struct aac_blockwrite);
+ } else {
+ struct aac_blockwrite64 *bw;
+ bw = (struct aac_blockwrite64 *)&fib->data[0];
+ bw->Command = VM_CtHostWrite64;
+ bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
+ bw->BlockNumber = offset / AAC_BLOCK_SIZE;
+ bw->SectorCount = len / AAC_BLOCK_SIZE;
+ bw->Pad = 0;
+ bw->Flags = 0;
+ command = ContainerCommand64;
+ callback = aac_dump_map_sg64;
+ size = sizeof(struct aac_blockwrite64);
+ }
/*
* There really isn't any way to recover from errors or
@@ -264,16 +305,16 @@ aac_disk_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size
* is too much required context.
*/
if (bus_dmamap_load(sc->aac_buffer_dmat, dump_datamap, virtual,
- len, aac_dump_map_sg, fib, BUS_DMA_NOWAIT) != 0)
+ len, callback, fib, BUS_DMA_NOWAIT) != 0)
return (ENOMEM);
bus_dmamap_sync(sc->aac_buffer_dmat, dump_datamap,
BUS_DMASYNC_PREWRITE);
/* fib->Header.Size is set in aac_dump_map_sg */
- size = fib->Header.Size + sizeof(struct aac_blockwrite);
+ size += fib->Header.Size;
- if (aac_sync_fib(sc, ContainerCommand, 0, fib, size)) {
+ if (aac_sync_fib(sc, command, 0, fib, size)) {
printf("Error dumping block 0x%jx\n",
(uintmax_t)physical);
return (EIO);
OpenPOWER on IntegriCloud