summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>2003-05-04 12:16:47 +0000
committersos <sos@FreeBSD.org>2003-05-04 12:16:47 +0000
commit0d0a999ff9b8e74341db3f4e92965c0fc21d7a21 (patch)
tree90b5aa25f96a895872efa817bb398b4c71182ddc /sys
parent34cf7a7cc5d0a621a9c8b85e925eba2528c4b6de (diff)
downloadFreeBSD-src-0d0a999ff9b8e74341db3f4e92965c0fc21d7a21.zip
FreeBSD-src-0d0a999ff9b8e74341db3f4e92965c0fc21d7a21.tar.gz
Implement dump function for ATA RAID's. Minor fixes by me...
Submitted by: Tor Egge <Tor.Egge@cvsup.no.freebsd.org>
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ata/ata-raid.c128
1 files changed, 128 insertions, 0 deletions
diff --git a/sys/dev/ata/ata-raid.c b/sys/dev/ata/ata-raid.c
index 417e69b..7269939 100644
--- a/sys/dev/ata/ata-raid.c
+++ b/sys/dev/ata/ata-raid.c
@@ -52,6 +52,7 @@
/* device structures */
static disk_strategy_t arstrategy;
+static dumper_t ardump;
/* prototypes */
static void ar_attach_raid(struct ar_softc *, int);
@@ -169,6 +170,7 @@ ar_attach_raid(struct ar_softc *rdp, int update)
ar_config_changed(rdp, update);
rdp->disk.d_strategy = arstrategy;
+ rdp->disk.d_dump = ardump;
rdp->disk.d_name = "ar";
rdp->disk.d_sectorsize = DEV_BSIZE;
rdp->disk.d_mediasize = (off_t)rdp->total_sectors * DEV_BSIZE;
@@ -505,6 +507,132 @@ ata_raid_rebuild(int array)
"rebuilding ar%d", array);
}
+static int
+ardump(void *arg, void *virtual, vm_offset_t physical,
+ off_t offset, size_t length)
+{
+ struct ar_softc *rdp;
+ struct disk *dp, *ap;
+ vm_offset_t pdata;
+ caddr_t vdata;
+ int blkno, count, chunk, error1, error2, lba, lbs, tmplba;
+ int drv = 0;
+
+ dp = arg;
+ rdp = dp->d_drv1;
+ if (!rdp || !(rdp->flags & AR_F_READY))
+ return ENXIO;
+
+ if (length == 0) {
+ for (drv = 0; drv < rdp->total_disks; drv++) {
+ if (rdp->disks[drv].flags & AR_DF_ONLINE) {
+ ap = &AD_SOFTC(rdp->disks[drv])->disk;
+ (void) ap->d_dump(ap, NULL, 0, 0, 0);
+ }
+ }
+ return 0;
+ }
+
+ blkno = offset / DEV_BSIZE;
+ vdata = virtual;
+ pdata = physical;
+
+ for (count = howmany(length, DEV_BSIZE); count > 0;
+ count -= chunk, blkno += chunk, vdata += (chunk * DEV_BSIZE),
+ pdata += (chunk * DEV_BSIZE)) {
+
+ switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
+ case AR_F_SPAN:
+ lba = blkno;
+ while (lba >= AD_SOFTC(rdp->disks[drv])->total_secs-rdp->reserved)
+ lba -= AD_SOFTC(rdp->disks[drv++])->total_secs-rdp->reserved;
+ chunk = min(AD_SOFTC(rdp->disks[drv])->total_secs-rdp->reserved-lba,
+ count);
+ break;
+
+ case AR_F_RAID0:
+ case AR_F_RAID0 | AR_F_RAID1:
+ tmplba = blkno / rdp->interleave;
+ chunk = blkno % rdp->interleave;
+ if (blkno >= (rdp->total_sectors / (rdp->interleave * rdp->width)) *
+ (rdp->interleave * rdp->width) ) {
+ lbs = (rdp->total_sectors -
+ ((rdp->total_sectors / (rdp->interleave * rdp->width)) *
+ (rdp->interleave * rdp->width))) / rdp->width;
+ drv = (blkno -
+ ((rdp->total_sectors / (rdp->interleave * rdp->width)) *
+ (rdp->interleave * rdp->width))) / lbs;
+ lba = ((tmplba / rdp->width) * rdp->interleave) +
+ (blkno - ((tmplba / rdp->width) * rdp->interleave)) % lbs;
+ chunk = min(count, lbs);
+ }
+ else {
+ drv = tmplba % rdp->width;
+ lba = ((tmplba / rdp->width) * rdp->interleave) + chunk;
+ chunk = min(count, rdp->interleave - chunk);
+ }
+ break;
+
+ case AR_F_RAID1:
+ drv = 0;
+ lba = blkno;
+ chunk = count;
+ break;
+
+ default:
+ printf("ar%d: unknown array type in ardump\n", rdp->lun);
+ return EIO;
+ }
+
+ if (drv > 0)
+ lba += rdp->offset;
+
+ switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
+ case AR_F_SPAN:
+ case AR_F_RAID0:
+ if (rdp->disks[drv].flags & AR_DF_ONLINE) {
+ ap = &AD_SOFTC(rdp->disks[drv])->disk;
+ error1 = ap->d_dump(ap, vdata, pdata,
+ (off_t) lba * DEV_BSIZE,
+ chunk * DEV_BSIZE);
+ } else
+ error1 = EIO;
+ if (error1)
+ return error1;
+ break;
+
+ case AR_F_RAID1:
+ case AR_F_RAID0 | AR_F_RAID1:
+ if ((rdp->disks[drv].flags & AR_DF_ONLINE) ||
+ ((rdp->flags & AR_F_REBUILDING) &&
+ (rdp->disks[drv].flags & AR_DF_SPARE))) {
+ ap = &AD_SOFTC(rdp->disks[drv])->disk;
+ error1 = ap->d_dump(ap, vdata, pdata,
+ (off_t) lba * DEV_BSIZE,
+ chunk * DEV_BSIZE);
+ } else
+ error1 = EIO;
+ if ((rdp->disks[drv + rdp->width].flags & AR_DF_ONLINE) ||
+ ((rdp->flags & AR_F_REBUILDING) &&
+ (rdp->disks[drv + rdp->width].flags & AR_DF_SPARE))) {
+ ap = &AD_SOFTC(rdp->disks[drv + rdp->width])->disk;
+ error2 = ap->d_dump(ap, vdata, pdata,
+ (off_t) lba * DEV_BSIZE,
+ chunk * DEV_BSIZE);
+ } else
+ error2 = EIO;
+ if (error1 && error2)
+ return error1;
+ break;
+
+ default:
+ printf("ar%d: unknown array type in ardump\n", rdp->lun);
+ return EIO;
+ }
+ }
+ return 0;
+}
+
static void
arstrategy(struct bio *bp)
{
OpenPOWER on IntegriCloud