diff options
author | Søren Schmidt <sos@FreeBSD.org> | 2003-05-04 12:16:47 +0000 |
---|---|---|
committer | Søren Schmidt <sos@FreeBSD.org> | 2003-05-04 12:16:47 +0000 |
commit | cf764e45ae4e81a5cbb14e1fe68cec4646719145 (patch) | |
tree | 90b5aa25f96a895872efa817bb398b4c71182ddc /sys/dev/ata/ata-raid.c | |
parent | 08b25cc04597696a884d39fff417bd3ece37edda (diff) | |
download | src-cf764e45ae4e81a5cbb14e1fe68cec4646719145.tar.gz src-cf764e45ae4e81a5cbb14e1fe68cec4646719145.zip |
Implement dump function for ATA RAID's. Minor fixes by me...
Submitted by: Tor Egge <Tor.Egge@cvsup.no.freebsd.org>
Notes
Notes:
svn path=/head/; revision=114662
Diffstat (limited to 'sys/dev/ata/ata-raid.c')
-rw-r--r-- | sys/dev/ata/ata-raid.c | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/sys/dev/ata/ata-raid.c b/sys/dev/ata/ata-raid.c index 417e69ba31c6..72699393788a 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) { |