diff -crN ../linux-2.4.3.virgin/drivers/md/Makefile linux-2.4.3.md/drivers/md/Makefile *** ../linux-2.4.3.virgin/drivers/md/Makefile Fri Dec 29 15:07:22 2000 --- linux-2.4.3.md/drivers/md/Makefile Mon May 7 13:12:34 2001 *************** *** 3,8 **** --- 3,9 ---- # O_TARGET := mddev.o + EXTRA_CFLAGS := -g export-objs := md.o xor.o list-multi := lvm-mod.o *************** *** 17,23 **** obj-$(CONFIG_MD_RAID0) += raid0.o obj-$(CONFIG_MD_RAID1) += raid1.o obj-$(CONFIG_MD_RAID5) += raid5.o xor.o ! obj-$(CONFIG_BLK_DEV_MD) += md.o obj-$(CONFIG_BLK_DEV_LVM) += lvm-mod.o include $(TOPDIR)/Rules.make --- 18,24 ---- obj-$(CONFIG_MD_RAID0) += raid0.o obj-$(CONFIG_MD_RAID1) += raid1.o obj-$(CONFIG_MD_RAID5) += raid5.o xor.o ! obj-$(CONFIG_BLK_DEV_MD) += adaptec_md.o md.o obj-$(CONFIG_BLK_DEV_LVM) += lvm-mod.o include $(TOPDIR)/Rules.make diff -crN ../linux-2.4.3.virgin/drivers/md/adaptec_md.c linux-2.4.3.md/drivers/md/adaptec_md.c *** ../linux-2.4.3.virgin/drivers/md/adaptec_md.c Wed Dec 31 17:00:00 1969 --- linux-2.4.3.md/drivers/md/adaptec_md.c Mon Jun 25 15:32:33 2001 *************** *** 0 **** --- 1,998 ---- + /* + * Copyright (c) 2001 Adaptec, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + #include + #include + #include + /* #include */ + #include "adaptec_md.h" + + /* + * DPT RAID table is 8K, and the reserved block is 512 bytes. These two + * blocks are at the very end of the disk -- they take up the last 17 512 + * byte sectors of the disk. The reserved block is the last block of the + * disk, and contains a pointer to the start of the raid table, which + * generally takes up the 8KB before the reserved block. + */ + #define ADAPTEC_ASR_RT_SIZE 8192 + #define ADAPTEC_ASR_RB_SIZE 512 + + extern int md_ffs(int i); + extern uint8_t *md_read_blocks(kdev_t dev, int sector_offset, int num_sectors, + uint8_t *dest_buf); + extern int md_write_blocks(kdev_t dev, int sector_offset, int num_sectors, + uint8_t *src_buf); + extern unsigned int calc_sb_csum (mdp_super_t * sb); + extern int uuid_equal(mdk_rdev_t *rdev1, mdk_rdev_t *rdev2); + extern struct list_head pending_raid_disks; + + unsigned int + md_get_sb_size_adaptec(void) + { + return(ADAPTEC_ASR_RB_SIZE); + } + + unsigned int + md_get_sb_offset_adaptec(mdk_rdev_t *rdev) + { + struct gendisk *gd; + long nr_sects; + + gd = find_gendisk(rdev->dev); + + if (gd == NULL) + return(0); + + if (gd->part == NULL) + return(0); + + /* + * The reserved block, if it is around, will be on the last sector + * of the disk. + */ + nr_sects = gd->part[MINOR(rdev->dev)].nr_sects - 1; + + return(nr_sects); + } + + unsigned int + md_get_dev_size_adaptec(mdk_rdev_t *rdev) + { + struct asr_reservedblock *asr_rb; + struct asr_raidtable *asr_rt; + struct asr_raid_configline *asr_cl; + int i, found; + + asr_rb = (struct asr_reservedblock *)rdev->primary_native_sb; + asr_rt = (struct asr_raidtable *)rdev->secondary_native_sb; + asr_cl = NULL; + found = 0; + + if ((asr_rb == NULL) || (asr_rt == NULL)) { + printk("md%d: adaptec_md: primary sb %p, secondary sb %p\n", + mdidx(rdev->mddev), asr_rb, asr_rt); + return(0); + } + + for (i = 0; i < ntohs(asr_rt->elmcnt); i++) { + if (asr_rt->ent[i].raidmagic == asr_rb->drivemagic){ + found = 1; + asr_cl = &asr_rt->ent[i]; + break; + } + } + if (found == 0) + return(0); + + return(ntohl(asr_cl->lcapcty) >> 1); + } + + int + md_validate_sb_adaptec(mdk_rdev_t *rdev, void *sb) + { + struct asr_reservedblock *asr_rb; + + asr_rb = (struct asr_reservedblock *)sb; + + if ((ntohl(asr_rb->b0idcode) == B0RESRVD) + && (ntohl(asr_rb->smagic) == SVALID)) + return(0); + else + return(1); + } + + /* + * To figure out which drive in the table we're actually looking at, + * compare the drivemagic field in the reserved block with the raidmagic + * field in the raid table. + */ + int + md_translate_sb_adaptec(mdk_rdev_t *rdev, void *adaptec_sb, mdp_super_t *md_sb) + { + struct asr_raidtable *asr_rt; + struct asr_reservedblock *asr_rb; + struct asr_raid_configline *asr_cl; + unsigned int rt_cksum; + uint8_t *rclptr; + int i, found; + int rt_index; + + found = 0; + rt_index = 0; + rt_cksum = 0; + asr_cl = NULL; + asr_rb = (struct asr_reservedblock *)adaptec_sb; + + asr_rt = (struct asr_raidtable *)kmalloc(sizeof(*asr_rt), GFP_KERNEL); + + if (asr_rt == NULL) { + printk("md: adaptec_md: can't malloc raidtable structure\n"); + return(-ENOMEM); + } + + if (md_read_blocks(rdev->dev, ntohl(asr_rb->raidtbl), + ADAPTEC_ASR_RT_SIZE / 512, + (uint8_t *)asr_rt) == NULL) { + printk("md: adaptec_md: can't read ASR raidtable at %#x\n", + ntohl(asr_rb->raidtbl)); + kfree(asr_rt); + return(-ENOENT); + } + + if (ntohl(asr_rt->ridcode) != RVALID2) { + printk("md: adaptec_md: RAID table signature %#x invalid\n", + ntohl(asr_rt->ridcode)); + return(-EINVAL); + } + + rclptr = (uint8_t *)asr_rt->ent; + /* + * The checksum isn't calculated over the entire RAID table, only + * over the filled-in config line elements. + */ + for (i = 0; i < (sizeof(asr_rt->ent[0]) * ntohs(asr_rt->elmcnt)); i++) + rt_cksum += rclptr[i]; + /* 16-bit checksum */ + rt_cksum &= 0xffff; + + if (ntohs(asr_rt->rchksum) != rt_cksum) { + printk("md: adaptec_md: RAID table checksum %#x doesn't match " + "calculated checksum %#x\n", + ntohs(asr_rt->rchksum), rt_cksum); + return(-EINVAL); + } + + for (i = 0; i < ntohs(asr_rt->elmcnt); i++) { + if (asr_rt->ent[i].raidmagic == asr_rb->drivemagic) { + found = 1; + asr_cl = &asr_rt->ent[i]; + rt_index = i; + break; + } + } + + if (found == 0) + return(-ENOENT); + + md_sb->md_magic = MD_SB_MAGIC; + md_sb->major_version = MD_MAJOR_VERSION; + md_sb->minor_version = MD_MINOR_VERSION; + md_sb->patch_version = MD_PATCHLEVEL_VERSION; + md_sb->ctime = CURRENT_TIME; + /* We have persistent metadata */ + md_sb->not_persistent = 0; + + md_sb->nr_disks = ntohs(asr_rt->elmcnt) - 1; + + md_sb->utime = CURRENT_TIME; + + /* This doesn't seem to be set for regular md superblocks */ + md_sb->layout = 0; + + /* + * Use the first element, since that will hopefully be the RAID + * type of the whole array. + * XXX KDM test this by creating an array with a spare disk. + */ + md_sb->level = asr_rt->ent[0].raidtype; + + /* + * If we've got a RAID-1 array, just set the chunk size to 64K. + * Stripe size doesn't matter on RAID-1, so raidselect Alpha 5 seems + * to set the stripe size to 0. This causes md to barf, even though + * it doesn't use the strip size for RAID-1. + */ + if (asr_rt->ent[0].raidtype == ASR_RAID1) + md_sb->chunk_size = 65536; + else { + /* + * md's chunk size is in bytes, DPT metadata stripe size is in + * 512 byte blocks + */ + md_sb->chunk_size = ntohs(asr_cl->strpsize) * 512; + } + + /* + * Use the sequence number from the RAID table as the md event + * number. The sequence number is only updated in element 0, which + * is the overall meta-element. + */ + md_sb->events_lo = ntohs(asr_rt->ent[0].raidseq); + + /* + * For spare disks, we use the magic number of the array they are a + * part of, not the magic number for the spare array. This will + * allow md to figure out that this spare belongs with the rest + * of the array. + */ + if (asr_rt->ent[0].raidtype == ASR_RAIDSPR) { + md_sb->set_uuid0 = md_sb->set_uuid1 = md_sb->set_uuid2 = + md_sb->set_uuid3 = ntohl(asr_rt->raidmagic); + } else { + /* + * Use the magic value from element 0 of the RAID table as + * the uuid for the md superblock. + */ + md_sb->set_uuid0 = md_sb->set_uuid1 = md_sb->set_uuid2 = + md_sb->set_uuid3 = ntohl(asr_rt->ent[0].raidmagic); + } + + /* + * md's size is in 1K chunks, DPT metadata gives the capacity in + * 512 byte blocks. + */ + md_sb->size = ntohl(asr_cl->lcapcty) >> 1; + md_sb->this_disk.major = MAJOR(rdev->dev); + md_sb->this_disk.minor = MINOR(rdev->dev); + md_sb->this_disk.number = rt_index - 1; + md_sb->this_disk.raid_disk = rt_index - 1; + + switch(asr_cl->raidstate & MAIN_STATE) { + case LSU_COMPONENT_STATE_OPTIMAL: + mark_disk_active(&md_sb->this_disk); + mark_disk_sync(&md_sb->this_disk); + md_sb->state = (1 << MD_SB_CLEAN); + break; + case LSU_COMPONENT_STATE_DEGRADED: + case LSU_COMPONENT_STATE_UNCONFIGURED: + case LSU_COMPONENT_STATE_FAILED: + mark_disk_faulty(&md_sb->this_disk); + break; + case LSU_COMPONENT_STATE_REPLACED: + case LSU_COMPONENT_STATE_UNINITIALIZED: + mark_disk_active(&md_sb->this_disk); + mark_disk_sync(&md_sb->this_disk); + break; + } + + /* + * XXX What do we do for a redirected disk, and what exactly is a + * redirected disk (ASR_RAIDRED)? + */ + if (asr_rt->ent[0].raidtype == ASR_RAIDSPR) + mark_disk_spare(&md_sb->this_disk); + + /* + * We don't know the major and minor numbers of the rest of the + * disks in this array, so once all disks are known, we should + * propagate the majors and minors to all the superblocks of the + * individual devices. + */ + rdev->flags |= MDK_RDEV_NEED_MAJORS; + + for (i = 0; i < (ntohs(asr_rt->elmcnt) - 1); i++) { + switch(asr_rt->ent[i+1].raidstate & MAIN_STATE) { + case LSU_COMPONENT_STATE_OPTIMAL: + mark_disk_active(&md_sb->disks[i]); + mark_disk_sync(&md_sb->disks[i]); + md_sb->working_disks++; + break; + case LSU_COMPONENT_STATE_DEGRADED: + case LSU_COMPONENT_STATE_UNCONFIGURED: + case LSU_COMPONENT_STATE_FAILED: + mark_disk_faulty(&md_sb->disks[i]); + md_sb->failed_disks++; + break; + case LSU_COMPONENT_STATE_REPLACED: + case LSU_COMPONENT_STATE_UNINITIALIZED: + mark_disk_active(&md_sb->disks[i]); + mark_disk_sync(&md_sb->disks[i]); + md_sb->working_disks++; + break; + } + if (asr_rt->ent[i+1].raidtype == ASR_RAIDSPR) { + mark_disk_spare(&md_sb->disks[i]); + md_sb->spare_disks++; + } + } + + /* + * Total number of disks in the array, not including spares. + */ + md_sb->raid_disks = ntohs(asr_rt->ent[0].raidcnt) - md_sb->spare_disks; + + md_sb->sb_csum = calc_sb_csum(md_sb); + + rdev->desc_nr = rt_index - 1; + printk("md: adaptec_md: rdev->desc_nr = %d\n", rdev->desc_nr); + printk("md: adaptec_md: raidstate = %#x\n", asr_cl->raidstate); + printk("md: adaptec_md: raidtype = %#x\n", asr_rt->ent[0].raidtype); + printk("md: adaptec_md: element raidtype = %#x\n", asr_cl->raidtype); + + if (rdev->secondary_native_sb != NULL) + kfree(rdev->secondary_native_sb); + + rdev->secondary_native_sb = asr_rt; + rdev->secondary_native_sb_offset = ntohl(asr_rb->raidtbl); + rdev->secondary_native_sb_size = ADAPTEC_ASR_RT_SIZE; + + return(0); + } + + /* + * Translate md metadata to Adaptec ASR format metadata. At the moment + * we're making the assumption that we're dealing with a pre-existing + * array, so we're just updating some of the fields that might have changed + * in the md superblock. + * + * If this changes and we make the assumption that we're writing out a + * whole new superblock, we'll need to put in a fair bit more code to + * set the proper fields in the raid table. + */ + int + md_translate_sb_to_adaptec(mdk_rdev_t *rdev) + { + struct asr_raidtable *asr_rt; + unsigned int rt_cksum; + uint8_t *rclptr; + int num_optimal, num_failed, num_rebuilding; + mdk_rdev_t *rdevtmp, *this_rdev; + struct md_list_head *listtmp; + int found; + int i, j; + + if ((rdev->primary_native_sb == NULL) + || (rdev->secondary_native_sb == NULL)) + return(-EINVAL); + + asr_rt = (struct asr_raidtable *)rdev->secondary_native_sb; + + rt_cksum = 0; + num_optimal = 0; + num_failed = 0; + num_rebuilding = 0; + + /* + * md uses a 64 bit event counter, ASR metadata has a 16-bit event + * counter. So we just use the bottom 16 bits. + */ + asr_rt->ent[0].raidseq = htons(rdev->sb->events_lo & 0xffff); + + for (i = 0; i < rdev->sb->nr_disks; i++) { + struct asr_reservedblock *asr_rb; + + asr_rb = NULL; + this_rdev = NULL; + + ITERATE_RDEV(rdev->mddev, rdevtmp, listtmp) { + if ((rdev->sb->disks[i].major == MAJOR(rdevtmp->dev)) + && (rdev->sb->disks[i].minor == MINOR(rdevtmp->dev))) { + this_rdev = rdevtmp; + asr_rb = rdevtmp->primary_native_sb; + break; + } + } + + if (this_rdev == NULL) { + printk("md: adaptec_md: rdev not found\n"); + continue; + } else if (asr_rb == NULL) { + printk("md: adaptec_md: primary superblock is NULL\n"); + continue; + } + + found = 0; + for (j = 1; j < ntohs(asr_rt->elmcnt); j++) { + if (asr_rb->drivemagic == asr_rt->ent[j].raidmagic) { + found = 1; + break; + } + } + + /* + * XXX KDM remove these printks. + */ + if (found == 0) { + printk("md: adaptec_md: matching metadata entry not " + "found for %s\n",partition_name(this_rdev->dev)); + continue; + } else { + printk("md: adaptec_md: matching metadata entry " + "found for %s\n",partition_name(this_rdev->dev)); + } + + /* + * If a disk is a spare, it isn't active, in sync or + * faulty. + */ + if (disk_spare(&rdev->sb->disks[i])) { + asr_rt->ent[j].raidtype = ASR_RAIDSPR; + asr_rt->ent[j].raidstate = + LSU_COMPONENT_STATE_OPTIMAL; + continue; + } + + /* + * If the disk is faulty, don't bother checking to see + * whether it is active or in sync, since as far as the ASR + * metadata goes, those states map to "optimal" and are + * mutually exclusive with "failed". + */ + if (disk_faulty(&rdev->sb->disks[i])) { + asr_rt->ent[j].raidtype = rdev->sb->level; + asr_rt->ent[j].raidstate = + LSU_COMPONENT_STATE_FAILED; + num_failed++; + continue; + } + + /* + * We've got a bit of an issue here mapping states back + * into the ASR metadata. Unfortunately it appears that at + * least the md RAID-1 code uses the MD_SB_CLEAN superblock + * flag to determine whether or not the array needs to be + * resynced instead of using the MD_DISK_SYNC disk flag to + * determine whether an individual disk should be resynced. + * The problem with this is that it isn't a per-disk flag, + * but rather a per-superblock flag. It can't be turned + * into a per-disk flag (at least not easily) because + * analyze_sbs() looks for the "freshest" superblock and + * then uses that one. + * + * I changed analyze_sbs() so that it will consider any + * superblock with the same event number but without the + * MD_SB_CLEAN flag set to be the freshest. This way, + * we get an array resync/rebuild when necessary. (Usually + * when it has first been created and you're copying from + * one disk to another.) Unfortunately these semantics don't + * allow us to specify which direction the build should go. + * + * The RAID-1 code uses its own per-disk "operational" bit + * to determine whether a disk is operational. In order to + * be operational, a disk has to be active (MD_DISK_ACTIVE) + * and in sync (MD_DISK_SYNC). Then the RAID-1 code goes + * through and for every disk that isn't operational, marks + * it not in sync. This appears to be a no-op. + * + * So...if a disk is active and in sync, we'll obviously + * mark it optimal. If a disk is either not active or not + * in sync (and not a spare and not failed), I suppose we + * can just mark it replaced and rebuilding. I'm not sure + * we'll see a disk that isn't either active and in sync + * or not active and not in sync. But, just in case, + * replaced/rebuilding is my best guess for the equivalent + * ASR state. When the metadata is read off the array on + * boot, and we're dealing with a RAID-1 array, this will + * result in the RAID-1 code rebuilding onto this disk. + */ + if (disk_active(&rdev->sb->disks[i]) + && disk_sync(&rdev->sb->disks[i])) { + asr_rt->ent[j].raidtype = rdev->sb->level; + /* + * XXX KDM unifdefing these next two blocks is + * probably the way to get md to recognize, on a + * reboot, that we didn't shut down cleanly. What + * it will do, I don't know. This will also likely + * wreak havoc with the BIOS or ASR firmware if + * they see all disks in the replaced/rebuilding + * state. Need to figure out how to make this + * work. + */ + #if 0 + if (rdev->sb->state & (1 << MD_SB_CLEAN)) { + #endif + asr_rt->ent[j].raidstate = + LSU_COMPONENT_STATE_OPTIMAL; + #if 0 + else { + asr_rt->ent[j].raidstate = + LSU_COMPONENT_STATE_REPLACED | + LSU_COMPONENT_SUBSTATE_REBUILDING; + } + #endif + num_optimal++; + } else { + asr_rt->ent[j].raidtype = rdev->sb->level; + asr_rt->ent[j].raidstate = + LSU_COMPONENT_STATE_REPLACED | + LSU_COMPONENT_SUBSTATE_REBUILDING; + num_rebuilding++; + } + } + + /* + * Here we attempt to figure out the overall state of the array, + * but if we can't make a determination (only possible if there are + * no disks), we don't change the overall state. + */ + switch (rdev->sb->level) { + case 0: + /* + * With a RAID-0 array, any failures result in a dead + * array. I'm not sure if it's possible to rebuild on a + * RAID-1, but the state is there anyway. + */ + if (num_failed > 0) + asr_rt->ent[0].raidstate = LS_DEAD_M; + else if (num_rebuilding > 0) + asr_rt->ent[0].raidstate = LS_REBUILDING_M; + else if (num_optimal > 0) + asr_rt->ent[0].raidstate = LS_OPTIMAL_M; + break; + case 1: + if (num_failed > 0) { + if (num_optimal > 0) + if (num_rebuilding > 0) + asr_rt->ent[0].raidstate = + LS_REBUILDING_M; + else + asr_rt->ent[0].raidstate = + LS_DEGRADED_M; + else + asr_rt->ent[0].raidstate = LS_DEAD_M; + } else if (num_rebuilding > 0) + asr_rt->ent[0].raidstate = LS_REBUILDING_M; + else if (num_optimal > 0) + asr_rt->ent[0].raidstate = LS_OPTIMAL_M; + break; + default: + break; + } + + /* + * Re-calculate the RAID table checksum, in case we changed any + * values in the RAID table. + */ + + rclptr = (uint8_t *)asr_rt->ent; + /* + * The checksum isn't calculated over the entire RAID table, only + * over the filled-in config line elements. + */ + for (i = 0; i < (sizeof(asr_rt->ent[0]) * ntohs(asr_rt->elmcnt)); i++) + rt_cksum += rclptr[i]; + rt_cksum &= 0xffff; + + asr_rt->rchksum = ntohs(rt_cksum); + + return(0); + } + + int + md_write_sb_adaptec(mdk_rdev_t *rdev) + { + uint32_t rt_offset; + struct asr_reservedblock *asr_rb; + int retval; + + /* + * Don't bother writing the superblock out if the secondary native + * superblock isn't available. + */ + if ((rdev->primary_native_sb == NULL) + || (rdev->secondary_native_sb == NULL)) + return(0); + + asr_rb = (struct asr_reservedblock *)rdev->primary_native_sb; + rt_offset = ntohl(asr_rb->raidtbl); + + retval = md_write_blocks(rdev->dev, rt_offset, + ADAPTEC_ASR_RT_SIZE / 512, + rdev->secondary_native_sb); + + return(retval); + } + + int + md_configure_array_adaptec(mdk_rdev_t *rdev0) + { + struct md_list_head *tmp, *tmp1; + mdk_rdev_t *rdev, *rdev1; + struct md_list_head devlist; + + MD_INIT_LIST_HEAD(&devlist); + + /* + * First run through the devices and see if we can find devices + * whose uuids are the same and whose types are the same. + */ + ITERATE_RDEV_PENDING(rdev, tmp) { + if (uuid_equal(rdev0, rdev) + && (rdev0->sb_type == rdev->sb_type)) + md_list_add(&rdev->tmplist, &devlist); + } + + /* + * Now we run through the list of devices we found and attempt + * to graft in any dedicated spares. + * + * This is necessary due to the way dedicated spares are + * implemented in iROC. DPT metadata really only has the concept + * of pool spares, which sit by themselves in a separate array. + * So in order to be forward compatible with the DPT metadata + * format, iROC spares must at least appear to be pool spares as + * well. + * + * For various reasons, the marketing and engineering folks at + * Adaptec decided that dedicated spares were the way to go for + * iROC. So there are now additional fields in the RAID table in + * what used to be a reserved area. The 'sparedrivemagic' field + * in a RAID-1 or RAID-10 array points to the spare drive for that + * array. And the 'raidmagic' field in the overall RAID table in a + * spare array points to the RAID-1 or RAID-10 array that contains + * that spare. + * + * So because the actual array table is separate from the spare + * table, we have to integrate the two so md knows what's going on. + * If md had the concept of pool spares, it's possible we could + * just get away with leaving the spares as pool spares, but the + * pool spare semantics probably aren't what many users are looking + * for. + */ + ITERATE_RDEV_GENERIC(devlist, tmplist, rdev, tmp) { + struct asr_reservedblock *asr_rb; + struct asr_raidtable *asr_rt; + + asr_rb = (struct asr_reservedblock *)rdev->primary_native_sb; + asr_rt = (struct asr_raidtable *)rdev->secondary_native_sb; + + /* + * This shouldn't happen. + */ + if ((asr_rb == NULL) + || (asr_rt == NULL)) + continue; + + /* + * We're only interested in finding spares at the moment. + */ + if (asr_rt->ent[0].raidtype != ASR_RAIDSPR) + continue; + + /* + * Run through the rest of the devices and make sure their + * information on the spare disk is correct. + */ + ITERATE_RDEV_GENERIC(devlist, tmplist, rdev1, tmp1) { + struct asr_raidtable *asr_rt1; + + asr_rt1 = (struct asr_raidtable *) + rdev1->secondary_native_sb; + + if (asr_rt1 == NULL) + continue; + + /* + * We're not changing the spare entry at the + * moment. + */ + if (asr_rt1->ent[0].raidtype == ASR_RAIDSPR) + continue; + /* + * Increment the number of disks in the table. + */ + rdev1->sb->nr_disks++; + + /* + * Set the size of the disk number for the spare. + * This might get set multiple times, but that's + * okay. + */ + rdev->sb->this_disk.number = rdev1->sb->nr_disks - 1; + rdev->sb->this_disk.raid_disk = rdev1->sb->nr_disks - 1; + rdev->desc_nr = rdev1->sb->nr_disks - 1; + + /* Increment the number of working and spare disks */ + rdev1->sb->working_disks++; + rdev1->sb->spare_disks++; + + /* Recalculate the checksum */ + rdev1->sb->sb_csum = calc_sb_csum(rdev1->sb); + } + } + + /* + * Now that we've filled in the information in the regular RAID + * array on any dedicated spares, we need to fill in the + * information in the superblocks of any spare disks about the + * rest of the array. + */ + ITERATE_RDEV_GENERIC(devlist, tmplist, rdev, tmp) { + struct asr_reservedblock *asr_rb; + struct asr_raidtable *asr_rt; + + asr_rb = (struct asr_reservedblock *)rdev->primary_native_sb; + asr_rt = (struct asr_raidtable *)rdev->secondary_native_sb; + + /* + * This shouldn't happen. + */ + if ((asr_rb == NULL) + || (asr_rt == NULL)) + continue; + + /* + * We're only interested in finding non-spare drives at + * the moment. + */ + if (asr_rt->ent[0].raidtype == ASR_RAIDSPR) + continue; + + /* + * If this array doesn't have a spare, we don't need to + * continue. + */ + if (asr_rt->sparedrivemagic == 0) + break; + + ITERATE_RDEV_GENERIC(devlist, tmplist, rdev1, tmp1) { + struct asr_raidtable *asr_rt1; + mdp_disk_t this_disk; + uint32_t state, size; + + asr_rt1 = (struct asr_raidtable *) + rdev1->secondary_native_sb; + + if (asr_rt1 == NULL) + continue; + + /* + * We're only changing spare entries now, we've + * already changed the non-spare drives. + */ + if (asr_rt1->ent[0].raidtype != ASR_RAIDSPR) + continue; + + /* + * First copy off some of the state from the spare. + */ + this_disk = rdev1->sb->this_disk; + state = rdev1->sb->state; + size = rdev1->sb->size; + + /* + * Now pull over the entire superblock, so the + * spare disk gets information on the rest of the + * disks. + */ + *rdev1->sb = *rdev->sb; + + /* + * Replace some of the disk-specific information. + */ + rdev1->sb->this_disk = this_disk; + rdev1->sb->state = state; + rdev1->sb_size = size; + + /* Recalculate the checksum */ + rdev1->sb->sb_csum = calc_sb_csum(rdev1->sb); + } + } + + /* + * Adaptec metadata doesn't natively have Linux major and minor + * numbers, so we need to propagate them out to all the superblocks + * in the RAID set. + */ + ITERATE_RDEV_GENERIC(devlist, tmplist, rdev1, tmp1) { + /* XXX KDM remove */ + printk("md: adaptec_md: updating majors for %s\n", + partition_name(rdev1->dev)); + ITERATE_RDEV_GENERIC(devlist, tmplist, rdev, tmp) { + int disknum; + disknum = rdev->sb->this_disk.number; + + rdev1->sb->disks[disknum].major = + rdev->sb->this_disk.major; + rdev1->sb->disks[disknum].minor = + rdev->sb->this_disk.minor; + rdev1->sb->disks[disknum].number = + rdev->sb->this_disk.number; + rdev1->sb->disks[disknum].raid_disk= + rdev->sb->this_disk.raid_disk; + } + rdev1->sb->sb_csum = calc_sb_csum(rdev1->sb); + } + + /* + * Now remove all the items from the list so the tmplist field + * can be used later. + */ + ITERATE_RDEV_GENERIC(devlist, tmplist, rdev, tmp) + md_list_del(&rdev->tmplist); + + return(0); + } + + /* + * Since we're using the hybrid pool/dedicated spare scheme, the spare + * disk is actually in a separate RAID table. So we need to move its RAID + * table entry to the main array RAID table and update all the disks in the + * array with the new information. + * + * Note that this *will* work if the spare is not the only spare in the + * pool, but the RAID table for the rest of the spares will not be + * correctly updated, since we don't really have a good pointer to those + * devices at this point. + */ + int + md_activate_spare_adaptec(mddev_t *mddev, int failed_disk, int spare_disk) + { + mdk_rdev_t *rdev, *failed_rdev, *spare_rdev; + struct md_list_head *listtmp; + struct asr_raidtable *failed_rt, *spare_rt; + struct asr_reservedblock *failed_rb, *spare_rb; + int failed_index, spare_index; + unsigned int rt_cksum; + uint8_t *rclptr; + int i; + + spare_rdev = NULL; + failed_rdev = NULL; + spare_index = -1; + failed_index = -1; + rt_cksum = 0; + + printk("md_activate_spare_adaptec called\n"); + ITERATE_RDEV(mddev, rdev, listtmp) { + if ((mddev->sb->disks[spare_disk].major == MAJOR(rdev->dev)) + && (mddev->sb->disks[spare_disk].minor == MINOR(rdev->dev))) { + spare_rdev = rdev; + } else if ((mddev->sb->disks[failed_disk].major == + MAJOR(rdev->dev)) + && (mddev->sb->disks[failed_disk].minor == + MINOR(rdev->dev))) { + failed_rdev = rdev; + } + if ((spare_rdev != NULL) + && (failed_rdev != NULL)) + break; + } + + if ((spare_rdev == NULL) + || (failed_rdev == NULL)) { + printk("md%d: adaptec_md: couldn't find at least one of " + "disk %d or %d\n", mdidx(mddev), spare_disk, + failed_disk); + return(-ENXIO); + } + + if ((spare_rdev->primary_native_sb == NULL) + || (spare_rdev->secondary_native_sb == NULL) + || (failed_rdev->primary_native_sb == NULL) + || (failed_rdev->secondary_native_sb == NULL)) + return(-EINVAL); + + failed_rb = (struct asr_reservedblock *)failed_rdev->primary_native_sb; + spare_rb = (struct asr_reservedblock *)spare_rdev->primary_native_sb; + + failed_rt = (struct asr_raidtable *)failed_rdev->secondary_native_sb; + spare_rt = (struct asr_raidtable *)spare_rdev->secondary_native_sb; + + for (i = 1; i < ntohs(spare_rt->elmcnt); i++) { + if (spare_rt->ent[i].raidmagic == failed_rt->sparedrivemagic) { + spare_index = i; + break; + } + } + + for (i = 1; i < ntohs(failed_rt->elmcnt); i++) { + if (failed_rt->ent[i].raidmagic == failed_rb->drivemagic) { + failed_index = i; + break; + } + } + + if ((failed_index == -1) + || (spare_index == -1)) { + printk("md%d: adaptec_md: can't find index for at least one" + "of failed %s or spare %s\n", mdidx(mddev), + partition_name(failed_rdev->dev), + partition_name(spare_rdev->dev)); + return(-ENXIO); + } + + /* Change the RAID type from spare to whatever the failed disk was */ + spare_rt->ent[spare_index].raidtype = + failed_rt->ent[failed_index].raidtype; + + /* + * Spare disk capacity is listed as the full capacity of the disk, + * minus 17 sectors for the metadata. Spare capacity for disks + * involved in a regular array is generally listed as something + * less. (The exact calculation should be (x - 17) & 0xFFFFF800 + * for RAID-1 and RAID-0.) In this situation, the spare's capacity + * should end up being the same as the rest of the disks in the + * array. + */ + if (ntohl(spare_rt->ent[spare_index].lcapcty) > + ntohl(failed_rt->ent[failed_index].lcapcty)) + spare_rt->ent[spare_index].lcapcty = + failed_rt->ent[failed_index].lcapcty; + + /* + * We need to set the size in the rdev as well, otherwise we'll + * trigger the size check in write_disk_sb(). This is a known + * change in size, so it's okay to change it here. + */ + spare_rdev->size = ntohl(spare_rt->ent[spare_index].lcapcty) >> 1; + + /* Now copy the spare's table entry over the failed drive entry */ + failed_rt->ent[failed_index] = spare_rt->ent[spare_index]; + + /* + * Re-generate the checksum + */ + rclptr = (uint8_t *)failed_rt->ent; + + /* + * The checksum isn't calculated over the entire RAID table, only + * over the filled-in config line elements. + */ + for (i = 0; i < (sizeof(failed_rt->ent[0]) * ntohs(failed_rt->elmcnt)); + i++) + rt_cksum += rclptr[i]; + /* 16-bit checksum */ + rt_cksum &= 0xffff; + + failed_rt->rchksum = ntohs(rt_cksum); + + /* Copy the new RAID table to all drives in the array */ + ITERATE_RDEV(mddev, rdev, listtmp) { + printk("md%d: copying superblock to %s\n", + mdidx(rdev->mddev), partition_name(rdev->dev)); + memcpy(rdev->secondary_native_sb, + failed_rdev->secondary_native_sb, + min(rdev->secondary_native_sb_size, + failed_rdev->secondary_native_sb_size)); + } + + memcpy(mddev->secondary_native_sb, failed_rdev->secondary_native_sb, + min(mddev->secondary_native_sb_size, + failed_rdev->secondary_native_sb_size)); + + /* Zero out the failed drive's RAID table, just in case */ + memset(failed_rdev->secondary_native_sb, 0, + failed_rdev->secondary_native_sb_size); + + printk("md_activate_spare_adaptec finished\n"); + + return(0); + } diff -crN ../linux-2.4.3.virgin/drivers/md/adaptec_md.h linux-2.4.3.md/drivers/md/adaptec_md.h *** ../linux-2.4.3.virgin/drivers/md/adaptec_md.h Wed Dec 31 17:00:00 1969 --- linux-2.4.3.md/drivers/md/adaptec_md.h Wed Jun 20 10:53:08 2001 *************** *** 0 **** --- 1,389 ---- + /* + * Copyright (c) 2001 Adaptec, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + #ifndef _ADAPTEC_MD_H + #define _ADAPTEC_MD_H + + #define FW_RESERVED_BLOCKS 0x800 + + #define MAX_SLEEPRATE_ENTRIES 10 + + /* define lsu levels */ + #define LSU_LEVEL_PHYSICAL 1 /* Firmware Physical */ + #define LSU_LEVEL_LOGICAL 2 /* Firmware Logical */ + + /* define RAID drive substates */ + #define FWP 0 /* Firmware Physical */ + #define FWL 1 /* Firmware Logical */ + #define OSI 2 /* Operating System Intermediate */ + #define FWL_2 3 /* Dual Level */ + + #define ASR_RAID0 0 + #define ASR_RAID1 1 + #define ASR_RAID4 4 + #define ASR_RAID5 5 + #define ASR_RAIDRED 0xFF + #define ASR_RAIDSPR 0xFE + + /*** RAID CONFIGURATION TABLE STRUCTURE ***/ + + #define RVALID2 0x900765C4 /* Version 2+ RAID table ID code + signature */ + #define RCTBL_MAX_ENTRIES 127 + #define HBA_RCTBL_MAX_ENTRIES 255 + #define RTBLBLOCKS 16 /* Size of drive's raid table + in blocks */ + + /* flag bits */ + #define RCTBLCHNG 0x80 /* Set on comp OR log (NOT AND) if tbl updates needed */ + #define COPYDIR 0x40 + #define MIRCOPY 0x20 + #define INITIAL_BUILD_COMPLETED 0x10 + #define SMART_DISABLED 0x08 + #define WRITEBACK 0x04 + #define PREDICTIVE_ENABLE 0x02 + #define RAID_ENTRY_FLAGS_ALARM_OFF_M 0x01 + + struct asr_raid_configline + { + uint16_t raidcnt; /* Component count of an OSL/FWL array */ + uint16_t raidseq; /* Sequence # of component to look for */ + uint32_t raidmagic; /* Magic # of component to look for */ + uint8_t raidlevel; /* Array level = OSL/FWL/OSI/FWP */ + uint8_t raidtype; /* Array type = RAID0/1/3/5, RAIDRED, + RAIDSPR */ + uint8_t raidstate; /* State of logical or physical drive */ + + uint8_t flags; /* misc flags set bit positions above */ + + uint8_t refcnt; /* Number of references to this log entry */ + uint8_t raidhba; /* -- not used -- Host bus adapter number + or RAIDID */ + uint8_t raidchnl; /* Channel number */ + uint8_t raidlun; /* SCSI LUN of log/phys drv */ + uint32_t raidid; /* SCSI ID of log/phys drv */ + uint32_t loffset; /* Offset of data for this comp in the + array */ + uint32_t lcapcty; /* Capacity of log drv or space used on + phys */ + uint16_t strpsize; /* Stripe size in blocks of this drive */ + uint16_t biosInfo; /* bios info - set by + I2O_EXEC_BIOS_INFO_SET */ + uint32_t lsu; /* Pointer to phys/log lun of this entry */ + uint8_t addedDrives; + uint8_t appSleepRate; + uint16_t blockStorageTid; + uint32_t curAppBlock; + uint32_t appBurstCount; + uint8_t name[16]; /* Full name of the array. */ + }; + + #if 0 + typedef struct HBARCTBL_S + { + /* raid Flag defines 32 bits 0 - FFFFFFFF */ + #define RAID_FLAGS_ALARM_OFF_M 0x00000001 + uint32_t ridcode; /* RAID table signature - 0x900765C4 */ + uint32_t rversion; /* Version of the RAID config table */ + uint16_t maxelm; /* Maximum number of elements */ + uint16_t elmcnt; /* Element Count (number used) */ + uint16_t elmsize; /* Size of an individual raidCLine */ + uint16_t rchksum; /* RAID table check sum + (no rconfTblV2) */ + uint32_t res1; /* Reserved */ + uint16_t res2; /* was bldRate - Time in 1/10s + between idle build bursts */ + uint16_t res3; /* was bldAmount - Block to build + during a build burst */ + uint32_t raidFlags; + uint32_t timestamp; /* used for iROC. A stamp to find + which is latest */ + uint8_t activity; /* Stores activity during checkpoint + (Zero/Verify/Rebuild) */ + uint8_t dirty; /* Stores ARRAY_STATE_DIRTY for iROC */ + uint8_t actionPriority; + uint8_t spareid; /* Stored in member disk meta data + to declare the ID of dedicated + spare to show up. */ + uint32_t sparedrivemagic;/* drivemagic (in RB) of the spare + at above ID. */ + uint32_t raidmagic; /* used to identify spare drive with + its mirror set. */ + uint32_t verifyDate; /* used by iomgr */ + uint32_t recreateDate; /* used by iomgr */ + uint8_t res4[12]; /* Reserved */ + struct asr_raid_configline ent[HBA_RCTBL_MAX_ENTRIES]; + } HBARCTBL_T; + + #endif + + struct asr_raidtable + { + /* raid Flag defines 32 bits 0 - FFFFFFFF */ + #define RAID_FLAGS_ALARM_OFF_M 0x00000001 + uint32_t ridcode; /* RAID table signature - 0x900765C4 */ + uint32_t rversion; /* Version of the RAID config table */ + uint16_t maxelm; /* Maximum number of elements */ + uint16_t elmcnt; /* Element Count (number used) */ + uint16_t elmsize; /* Size of an individual raidCLine */ + uint16_t rchksum; /* RAID table check sum + (no rconfTblV2)*/ + uint32_t res1; /* Reserved */ + uint16_t res2; /* was bldRate - Time in 1/10s + between idle build bursts */ + uint16_t res3; /* was bldAmount - Block to build + during a build burst */ + uint32_t raidFlags; + uint32_t timestamp; /* used for iROC. A stamp to find + which is latest */ + uint8_t activity; /* Stores activity during checkpoint + (Zero/Verify/Rebuild) */ + uint8_t dirty; /* Stores ARRAY_STATE_DIRTY for iROC */ + uint8_t actionPriority; + uint8_t spareid; /* Stored in member disk meta data + to declare the ID of dedicated + spare to show up. */ + uint32_t sparedrivemagic;/* drivemagic (in RB) of the spare + at above ID. */ + uint32_t raidmagic; /* used to identify spare drive with + its mirror set. */ + uint32_t verifyDate; /* used by iomgr */ + uint32_t recreateDate; /* used by iomgr */ + uint8_t res4[12]; /* Reserved */ + struct asr_raid_configline ent[RCTBL_MAX_ENTRIES]; + }; + + + #define RBLOCK_VER 8 /* Version of the reserved block */ + #define B0RESRVD 0x37FC4D1E /* Signature of the reserved block */ + #define SVALID 0x4450544D /* ASCII code for "DPTM" DPT Mirror */ + + struct asr_reservedblock + { + uint32_t b0idcode; /* 0x00 - ID code signifying block 0 + reserved */ + uint8_t lunsave[8]; /* 0x04 - NOT USED - LUN mappings for + all drives */ + uint16_t sdtype; /* 0x0C - NOT USED - drive type in + boot prom */ + uint16_t ssavecyl; /* 0x0E - NOT USED - Set Parameters + cylinders */ + uint8_t ssavehed; /* 0x10 - NOT USED - Set Parameters + heads */ + uint8_t ssavesec; /* 0x11 - NOT USED - Set Parameters + sectors */ + uint8_t sb0flags; /* 0x12 - flags saved in reserved + block */ + uint8_t jbodEnable; /* 0x13 - jbod enable -- DEC drive + hiding */ + uint8_t lundsave; /* 0x14 - NOT USED - LUNMAP disable + flags */ + uint8_t svpdirty; /* 0x15 - NOT USED - saved percentage + dirty */ + uint16_t biosInfo; /* 0x16 - bios info - set by + I2O_EXEC_BIOS_INFO_SET */ + uint16_t svwbskip; /* 0x18 - NOT USED - saved write-back + skip value */ + uint16_t svwbcln; /* 0x1A - NOT USED - saved maximum + clean blocks in write-back */ + uint16_t svwbmax; /* 0x1C - NOT USED - saved maximum + write-back length */ + uint16_t res3; /* 0x1E - unused (was write-back burst + block count) */ + uint16_t svwbmin; /* 0x20 - NOT USED - saved minimum + block count to write */ + uint16_t res4; /* 0x22 - unused (was minimum + look-ahead length) */ + uint16_t svrcacth; /* 0x24 - NOT USED - saved read cache + threshold */ + uint16_t svwcacth; /* 0x26 - NOT USED - saved write + cache threshold */ + uint16_t svwbdly; /* 0x28 - NOT USED - saved write-back + delay */ + uint8_t svsdtime; /* 0x2A - NOT USED - saved spin down + time */ + uint8_t res5; /* 0x2B - unused */ + uint16_t firmval; /* 0x2C - NOT USED - firmware on + drive (dw) */ + uint16_t firmbln; /* 0x2E - NOT USED - length in blocks + for firmware */ + uint32_t firmblk; /* 0x30 - NOT USED - starting block + for firmware */ + uint32_t fstrsvrb; /* 0x34 - 1st block reserved by + Storage Manager */ + uint16_t svBlockStorageTid; /* 0x38 - */ + uint16_t svtid; /* 0x3A - */ + uint8_t svseccfl; /* 0x3C - NOT USED - reserved block + scsi bus ecc flags */ + uint8_t res6; /* 0x3D - unused */ + uint8_t svhbanum; /* 0x3E - NOT USED - HBA's unique + RAID number */ + uint8_t resver; /* 0x3F - reserved block version + number */ + uint32_t drivemagic; /* 0x40 - Magic number of this drive - + used w/ RCTBLs */ + uint8_t reserved[20]; /* 0x44 - unused */ + uint8_t testnum; /* 0x58 - NOT USED - diagnostic test + number */ + uint8_t testflags; /* 0x59 - NOT USED - diagnostic test + flags */ + uint16_t maxErrorCount; /* 0x5A - NOT USED - diagnostic test + maximum error count */ + uint32_t count; /* 0x5C - NOT USED - diagnostic test + cycles - # of iterations */ + uint32_t startTime; /* 0x60 - NOT USED - diagnostic test + absolute test start time in + seconds */ + uint32_t interval; /* 0x64 - NOT USED - diagnostic test + interval in seconds */ + uint8_t tstxt0; /* 0x68 - not used - originally + diagnostic test exclusion period + start hour */ + uint8_t tstxt1; /* 0x69 - not used - originally + diagnostic test exclusion period + end hour */ + uint8_t serNum[32]; /* 0x6A - reserved */ + uint8_t res8[102]; /* 0x8A - reserved */ + uint32_t fwTestMagic; /* 0xF0 - test magic number - used by + FW Test for automated tests */ + uint32_t fwTestSeqNum; /* 0xF4 - test sequence number - used + by FW Test for automated tests */ + uint8_t fwTestRes[8]; /* 0xF6 - reserved by FW Test for + automated tests */ + uint32_t smagic; /* 0x100 - magic value saying software + half is valid */ + uint32_t raidtbl; /* 0x104 - pointer to first block of + raid table */ + uint16_t raidline; /* 0x108 - line number of this raid + table entry - only if version <7 */ + uint8_t res9[0xF6]; /* 0x10A - reserved for software stuff*/ + }; + + + + #define ARRAY_NEW 0x00 + #define ARRAY_EQUAL 0x01 + #define ARRAY_SEQ_LESS 0x02 + #define ARRAY_SEQ_GREAT 0x03 + + #define LOCK_PRIORITY 10 /* Uses 10, 11, 12 - For all three channels */ + + + /* B0FLAGS flag bits: */ + + #define SMARTENA 7 /* SMART emulation enabled */ + #define CLRERROR 4 /* Clear stage of Interpret Format + not completed */ + #define FMTERROR 3 /* Format stage of Interpret Format + not completed */ + #define WRTTHRU 2 /* write throughs */ + #define CACHEDIS 0 /* cache disable bit */ + #define PREDICTIVE_ENABLE 0x02 + + #define ID_MAP_PHYSICAL_M 1 /* Logical Map Physical */ + #define ID_MAP_LOGICAL_M 2 /* Either Dual Level or Single Level + Logical*/ + + #define MAX_LSU_COUNT 256 + + #define MAX_LSU_COMPONENTS 64 + #define MAX_LSU_INQUIRY_DATA 64 + #define MAX_LSU_SERIAL_NUMBER 8 + #define STD_INQUIRY_SIZE 48 + + #define MAX_LSU_BAD_BLOCKS 8 + + /* lsuType definitions */ + #define LT_UNCONFIGURED_M 0x00 + #define LT_RAID0_M 0x01 + #define LT_RAID1_M 0x02 + #define LT_RAID3_M 0x08 + #define LT_RAID4_M 0x10 + #define LT_RAID5_M 0x20 + #define LT_REDIR_M 0x40 + #define LT_SPARE_M 0x80 + + #define LSU_RAID_LEVEL_0 LT_RAID0_M + #define LSU_RAID_LEVEL_1 LT_RAID1_M + #define LSU_RAID_LEVEL_3 LT_RAID3_M + #define LSU_RAID_LEVEL_4 LT_RAID4_M + #define LSU_RAID_LEVEL_5 LT_RAID5_M + #define LSU_RAID_REDIRECT LT_REDIR_M + #define LSU_RAID_SPARE LT_SPARE_M + + /* raidState definitions */ + #define LS_OPTIMAL_M 0x00 + #define LS_DEGRADED_M 0x01 + #define LS_REBUILDING_M 0x02 + #define LS_MORPHING_M 0x03 + #define LS_DEAD_M 0x04 + #define LS_WARNING_M 0x05 + + #define LS_VERIFYING_M 0x0A + #define LSU_ARRAY_SUBSTATE_WITH_FIX 0x10 + + #define LS_BUILDING_M 0x0B + #define LS_CREATED_M 0x54 + #define LS_DIAGNOSING_M 0xFD + + + /* arrayState definitions */ + #define LSU_ARRAY_STATE_OPTIMAL 0x00 + #define LSU_ARRAY_STATE_DEGRADED 0x01 + /* etc. */ + + /* component raidState definitions */ + #define MAIN_STATE 0x0F + #define LSU_COMPONENT_STATE_OPTIMAL 0x00 + #define LSU_COMPONENT_STATE_DEGRADED 0x01 + #define LSU_COMPONENT_STATE_UNCONFIGURED 0x02 + #define LSU_COMPONENT_STATE_FAILED 0x03 + #define LSU_COMPONENT_STATE_REPLACED 0x04 + #define LSU_COMPONENT_STATE_UNINITIALIZED 0x0A + + #define LSU_COMPONENT_SUBSTATE_BUILDING 0x10 /* drive is being built + for first time */ + #define LSU_COMPONENT_SUBSTATE_REBUILDING 0x20 /* drive is being + rebuilt */ + #define LSU_ARRAY_SUBSTATE_AWAIT_FORMAT 0x50 + /* etc. */ + + unsigned int md_get_sb_size_adaptec(void); + unsigned int md_get_sb_offset_adaptec(mdk_rdev_t *rdev); + unsigned int md_get_dev_size_adaptec(mdk_rdev_t *rdev); + int md_validate_sb_adaptec(mdk_rdev_t *rdev, void *sb); + int md_translate_sb_adaptec(mdk_rdev_t *rdev, void *adaptec_sb, + mdp_super_t *md_sb); + int md_translate_sb_to_adaptec(mdk_rdev_t *rdev); + int md_write_sb_adaptec(mdk_rdev_t *rdev); + int md_configure_array_adaptec(mdk_rdev_t *rdev); + int md_activate_spare_adaptec(mddev_t *mddev, int failed_disk, int spare_disk); + + #endif /* _ADAPTEC_MD_H */ diff -crN ../linux-2.4.3.virgin/drivers/md/linear.c linux-2.4.3.md/drivers/md/linear.c *** ../linux-2.4.3.virgin/drivers/md/linear.c Fri Feb 9 12:30:23 2001 --- linux-2.4.3.md/drivers/md/linear.c Tue Jun 26 10:38:40 2001 *************** *** 66,73 **** } nb_zone = conf->nr_zones = ! md_size[mdidx(mddev)] / conf->smallest->size + ! ((md_size[mdidx(mddev)] % conf->smallest->size) ? 1 : 0); conf->hash_table = kmalloc (sizeof (struct linear_hash) * nb_zone, GFP_KERNEL); --- 66,73 ---- } nb_zone = conf->nr_zones = ! md_size[mdminor(mddev)] / conf->smallest->size + ! ((md_size[mdminor(mddev)] % conf->smallest->size) ? 1 : 0); conf->hash_table = kmalloc (sizeof (struct linear_hash) * nb_zone, GFP_KERNEL); diff -crN ../linux-2.4.3.virgin/drivers/md/md.c linux-2.4.3.md/drivers/md/md.c *** ../linux-2.4.3.virgin/drivers/md/md.c Mon Mar 12 19:13:28 2001 --- linux-2.4.3.md/drivers/md/md.c Tue Jun 26 16:31:16 2001 *************** *** 53,58 **** --- 53,59 ---- #define MD_DRIVER #include + #include "adaptec_md.h" #define DEBUG 0 #if DEBUG *************** *** 102,107 **** --- 103,130 ---- {0} }; + static int check_disk_sb (mdk_rdev_t *rdev, mdp_super_t *sb); + unsigned int md_get_sb_offset (mdk_rdev_t * rdev); + unsigned int md_get_sb_size (void); + unsigned int md_get_dev_size (mdk_rdev_t *rdev); + int md_validate_sb (mdk_rdev_t *rdev, void *sb); + int md_translate_sb (mdk_rdev_t *rdev, void *sb, mdp_super_t *md_sb); + int md_translate_sb_to_native(mdk_rdev_t *rdev); + int md_write_sb (mdk_rdev_t *rdev); + int md_configure_array (mdk_rdev_t *rdev); + int md_activate_spare (mddev_t *mddev, int failed_disk, int spare_disk); + + struct mdk_superblock_desc_s md_sb_types[] = { + {MD_SB_MD, &md_get_sb_offset, &md_get_sb_size, &md_get_dev_size, + &md_validate_sb, &md_translate_sb, &md_translate_sb_to_native, + &md_write_sb, &md_configure_array, &md_activate_spare}, + {MD_SB_ADAPTEC_ASR, &md_get_sb_offset_adaptec, + &md_get_sb_size_adaptec, &md_get_dev_size_adaptec, + &md_validate_sb_adaptec, &md_translate_sb_adaptec, + &md_translate_sb_to_adaptec, &md_write_sb_adaptec, + &md_configure_array_adaptec, &md_activate_spare_adaptec}, + }; + /* * these have to be allocated separately because external * subsystems want to have a pre-defined structure *************** *** 110,118 **** static int md_blocksizes[MAX_MD_DEVS]; static int md_hardsect_sizes[MAX_MD_DEVS]; static int md_maxreadahead[MAX_MD_DEVS]; static mdk_thread_t *md_recovery_thread; ! int md_size[MAX_MD_DEVS]; extern struct block_device_operations md_fops; static devfs_handle_t devfs_handle; --- 133,149 ---- static int md_blocksizes[MAX_MD_DEVS]; static int md_hardsect_sizes[MAX_MD_DEVS]; static int md_maxreadahead[MAX_MD_DEVS]; + int md_size[MAX_MD_DEVS]; + + struct hd_struct mdp_hd_struct[MAX_MDP_DEVS<b_rdev); ! if (mddev && mddev->pers) return mddev->pers->make_request(mddev, rw, bh); ! else { buffer_IO_error(bh); return 0; } } ! static mddev_t * alloc_mddev (kdev_t dev) { mddev_t *mddev; - if (MAJOR(dev) != MD_MAJOR) { - MD_BUG(); - return 0; - } mddev = (mddev_t *) kmalloc(sizeof(*mddev), GFP_KERNEL); if (!mddev) return NULL; memset(mddev, 0, sizeof(*mddev)); ! mddev->__minor = MINOR(dev); init_MUTEX(&mddev->reconfig_sem); init_MUTEX(&mddev->recovery_sem); init_MUTEX(&mddev->resync_sem); --- 181,330 ---- static MD_LIST_HEAD(all_mddevs); /* + * The standard assembly version of ffs() on i386 causes the assembler to + * choke: + * {standard input}: Assembler messages: + * {standard input}:1116: Error: suffix or operands invalid for `bsf' + */ + int + md_ffs(int i) + { + int x; + + for (x = 0; x < (sizeof(int) * 8); x++) + if (i & (1 << x)) + return(x + 1); + + return(0); + } + + /* + * Read num_sectors 512 byte sectors from the given device, starting at + * the given sector offset. Copy the result into the buffer supplied by + * the user. Return NULL if there is a failure, otherwise return the + * user-supplied buffer. + * + * Hopefully there is a better way to do this. + */ + uint8_t * + md_read_blocks(kdev_t dev, int sector_offset, int num_sectors, + uint8_t *dest_buf) + { + struct buffer_head *bh = NULL; + int i; + + fsync_dev(dev); + + for (i = 0; i < num_sectors; i++) { + bh = bread(dev, sector_offset + i, 512); + if (bh == NULL) { + brelse(bh); + return(NULL); + } + memcpy(dest_buf + (i * 512), bh->b_data, 512); + brelse(bh); + } + + return(dest_buf); + } + + #define GETBLK_FAILED KERN_ERR \ + "md: getblk failed for device %s\n" + + /* + * Write num_sectors 512 byte sectors from a user-supplied buffer to a + * disk, starting at the given sector offset. Return 0 for success, + * non-zero for failure. + * + * Hopefully there is a better way to do this. + */ + int + md_write_blocks(kdev_t dev, int sector_offset, int num_sectors, + uint8_t *src_buf) + { + struct buffer_head *bh; + int i; + + set_blocksize(dev, 512); + fsync_dev(dev); + + for (i = 0; i < num_sectors; i++) { + bh = getblk(dev, sector_offset + i, 512); + if (bh == NULL) { + printk(GETBLK_FAILED, partition_name(dev)); + return(1); + } + memcpy(bh->b_data, src_buf + (i * 512), 512); + mark_buffer_uptodate(bh, 1); + mark_buffer_dirty(bh); + ll_rw_block(WRITE, 1, &bh); + wait_on_buffer(bh); + brelse(bh); + } + + fsync_dev(dev); + + set_blocksize(dev, MD_SB_BYTES); + + return(0); + } + + #undef GETBLK_FAILED + + /* * The mapping between kdev and mddev is not necessary a simple * one! Eg. HSM uses several sub-devices to implement Logical * Volumes. All these sub-devices map to the same mddev. */ dev_mapping_t mddev_map[MAX_MD_DEVS]; ! void add_mddev_mapping (mddev_t * mddev, int unit, void *data) { ! if (mddev_map[unit].mddev != NULL) { MD_BUG(); return; } ! mddev_map[unit].mddev = mddev; ! mddev_map[unit].data = data; } ! void del_mddev_mapping (mddev_t * mddev, int unit) { ! if (mddev_map[unit].mddev != mddev) { MD_BUG(); return; } ! mddev_map[unit].mddev = NULL; ! mddev_map[unit].data = NULL; } static int md_make_request (request_queue_t *q, int rw, struct buffer_head * bh) { + unsigned int minor = MINOR(bh->b_rdev); mddev_t *mddev = kdev_to_mddev(bh->b_rdev); ! if (mddev && mddev->pers) { ! if (MAJOR(bh->b_rdev) == MDP_MAJOR) ! /* map the sector for partitions */ ! bh->b_rsector += mdp_hd_struct[minor].start_sect; return mddev->pers->make_request(mddev, rw, bh); ! } else { buffer_IO_error(bh); return 0; } } ! static mddev_t * alloc_mddev (int unit) { mddev_t *mddev; mddev = (mddev_t *) kmalloc(sizeof(*mddev), GFP_KERNEL); if (!mddev) return NULL; memset(mddev, 0, sizeof(*mddev)); ! mddev->__unit = unit; init_MUTEX(&mddev->reconfig_sem); init_MUTEX(&mddev->recovery_sem); init_MUTEX(&mddev->resync_sem); *************** *** 214,220 **** * personalities can create additional mddevs * if necessary. */ ! add_mddev_mapping(mddev, dev, 0); md_list_add(&mddev->all_mddevs, &all_mddevs); MOD_INC_USE_COUNT; --- 337,343 ---- * personalities can create additional mddevs * if necessary. */ ! add_mddev_mapping(mddev, unit, 0); md_list_add(&mddev->all_mddevs, &all_mddevs); MOD_INC_USE_COUNT; *************** *** 340,346 **** ITERATE_RDEV(mddev,rdev,tmp) { rdev->size &= mask; ! md_size[mdidx(mddev)] += rdev->size; } return 0; } --- 463,469 ---- ITERATE_RDEV(mddev,rdev,tmp) { rdev->size &= mask; ! md_size[mdminor(mddev)] += rdev->size; } return 0; } *************** *** 493,538 **** rdev->faulty = 1; } static int read_disk_sb (mdk_rdev_t * rdev) { int ret = -EINVAL; - struct buffer_head *bh = NULL; kdev_t dev = rdev->dev; ! mdp_super_t *sb; ! unsigned long sb_offset; if (!rdev->sb) { MD_BUG(); goto abort; } /* ! * Calculate the position of the superblock, ! * it's at the end of the disk */ ! sb_offset = calc_dev_sboffset(rdev->dev, rdev->mddev, 1); rdev->sb_offset = sb_offset; ! printk("(read) %s's sb offset: %ld", partition_name(dev), sb_offset); ! fsync_dev(dev); set_blocksize (dev, MD_SB_BYTES); bh = bread (dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); - if (bh) { - sb = (mdp_super_t *) bh->b_data; - memcpy (rdev->sb, sb, MD_SB_BYTES); - } else { - printk (NO_SB,partition_name(rdev->dev)); - goto abort; - } printk(" [events: %08lx]\n", (unsigned long)rdev->sb->events_lo); ret = 0; abort: - if (bh) - brelse (bh); return ret; } ! static unsigned int calc_sb_csum (mdp_super_t * sb) { unsigned int disk_csum, csum; --- 616,798 ---- rdev->faulty = 1; } + /* + * Return superblock offset in 512 byte sectors. + */ + unsigned int md_get_sb_offset (mdk_rdev_t * rdev) + { + unsigned int size; + + /* Translate the blocksize to 512 byte sectors */ + size = calc_dev_sboffset(rdev->dev, rdev->mddev, + !rdev->sb->not_persistent); + size *= BLOCK_SIZE / 512; + return(size); + } + + /* + * Return superblock size in bytes. + */ + unsigned int md_get_sb_size (void) + { + return(MD_SB_BYTES); + } + + int md_validate_sb (mdk_rdev_t *rdev, void *sb) + { + return(check_disk_sb(rdev, (mdp_super_t *)sb)); + } + + int md_translate_sb (mdk_rdev_t *rdev, void *sb, mdp_super_t *md_sb) + { + memcpy(md_sb, sb, sizeof(*md_sb)); + return(0); + } + + int md_translate_sb_to_native(mdk_rdev_t *rdev) + { + return(0); + } + + int md_write_sb (mdk_rdev_t *rdev) + { + int retval; + + retval = md_write_blocks(rdev->dev, rdev->sb_offset, + rdev->sb_size / 512, (uint8_t *)rdev->sb); + + return(retval); + } + + int md_configure_array (mdk_rdev_t *rdev) + { + return(0); + } + int md_activate_spare (mddev_t *mddev, int failed_disk, int spare_disk) + { + printk("md%d: md_activate_spare called\n", mdidx(mddev)); + return(0); + } + + /* + * Return device size in 1K blocks. + */ + unsigned int md_get_dev_size (mdk_rdev_t *rdev) + { + unsigned int size; + + size = calc_dev_size(rdev->dev, rdev->mddev, + !rdev->mddev->sb->not_persistent); + return(size); + } + static int read_disk_sb (mdk_rdev_t * rdev) { int ret = -EINVAL; kdev_t dev = rdev->dev; ! uint8_t *sb; ! unsigned int sb_offset; ! unsigned int sb_size; ! int i, valid_sb_found; if (!rdev->sb) { MD_BUG(); goto abort; } + valid_sb_found = 0; + #if 0 + set_blocksize(dev, MD_SB_BYTES); + #endif + /* + * At least initially, set the blocksize to 512 bytes. We don't + * know what sort of offset we may need to fetch the superblock for + * a given RAID implementation, so we can't assume that it's going + * to be at an offset that's a 4K multiple. + */ + set_blocksize(dev, 512); + /* ! * Run through the different superblock types and see if we can ! * find a valid superblock for one of the types we know about. */ ! for (i = 0; i < (sizeof(md_sb_types)/sizeof(md_sb_types[0])); i++) { ! /* ! * Calculate the position of the superblock. The position ! * depends on which type of superblock we're looking for. ! */ ! sb_offset = md_sb_types[i].get_sb_offset(rdev); ! sb_size = md_sb_types[i].get_sb_size(); ! ! printk("looking for type %d metadata at offset %d size %d " ! "on %s\n", i, sb_offset, sb_size, partition_name(dev)); ! ! sb = (uint8_t *)kmalloc(sb_size, GFP_KERNEL); ! ! if (sb == NULL) { ! printk("md: can't kmalloc superblock\n"); ! goto abort; ! } ! ! /* ! * If we can't even read the blocks where the superblock is ! * located, bail. ! */ ! if (md_read_blocks(dev, sb_offset, sb_size / 512, sb) == NULL) { ! kfree(sb); ! printk (NO_SB,partition_name(rdev->dev)); ! goto abort; ! } ! ! /* ! * If we found a valid superblock, set the valid flag and ! * translate this superblock into the standard md ! * superblock format. We only declare the superblock valid ! * if it can also be translated into an md-style superblock. ! */ ! if (md_sb_types[i].validate_sb(rdev, sb) == 0) { ! if (md_sb_types[i].translate_sb(rdev, sb, ! rdev->sb) != 0) { ! kfree(sb); ! continue; ! } else { ! rdev->primary_native_sb = sb; ! rdev->primary_native_sb_size = sb_size; ! rdev->primary_native_sb_offset = sb_offset; ! rdev->sb_type = md_sb_types[i].type; ! valid_sb_found = 1; ! break; ! } ! } else ! kfree(sb); ! } ! if (valid_sb_found == 0) { ! printk("md: no valid superblock found for %s\n", ! partition_name(rdev->dev)); ! goto abort; ! } ! rdev->sb_offset = sb_offset; ! rdev->sb_size = sb_size; ! printk("(read) %s's sb offset: %d, size: %d", partition_name(dev), ! sb_offset, sb_size); ! ! /* ! * Now that we've read off the superblock, set the blocksize to ! * the standard size for md. ! */ set_blocksize (dev, MD_SB_BYTES); + #if 0 bh = bread (dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); + #endif printk(" [events: %08lx]\n", (unsigned long)rdev->sb->events_lo); ret = 0; abort: return ret; } ! unsigned int calc_sb_csum (mdp_super_t * sb) { unsigned int disk_csum, csum; *************** *** 547,558 **** * Check one RAID superblock for generic plausibility */ ! static int check_disk_sb (mdk_rdev_t * rdev) { - mdp_super_t *sb; int ret = -EINVAL; - sb = rdev->sb; if (!sb) { MD_BUG(); goto abort; --- 807,816 ---- * Check one RAID superblock for generic plausibility */ ! static int check_disk_sb (mdk_rdev_t *rdev, mdp_super_t *sb) { int ret = -EINVAL; if (!sb) { MD_BUG(); goto abort; *************** *** 613,619 **** } static MD_LIST_HEAD(all_raid_disks); ! static MD_LIST_HEAD(pending_raid_disks); static void bind_rdev_to_array (mdk_rdev_t * rdev, mddev_t * mddev) { --- 871,877 ---- } static MD_LIST_HEAD(all_raid_disks); ! MD_LIST_HEAD(pending_raid_disks); static void bind_rdev_to_array (mdk_rdev_t * rdev, mddev_t * mddev) { *************** *** 736,749 **** static void free_mddev (mddev_t *mddev) { if (!mddev) { MD_BUG(); return; } export_array(mddev); ! md_size[mdidx(mddev)] = 0; ! md_hd_struct[mdidx(mddev)].nr_sects = 0; /* * Make sure nobody else is using this mddev --- 994,1012 ---- static void free_mddev (mddev_t *mddev) { + int part; if (!mddev) { MD_BUG(); return; } export_array(mddev); ! md_size[mdminor(mddev)] = 0; ! md_hd_struct[mdminor(mddev)].nr_sects = 0; ! foreach_part(part, mddev) { ! mdp_size[part] = 0; ! mdp_hd_struct[part].nr_sects = 0; ! } /* * Make sure nobody else is using this mddev *************** *** 754,760 **** while (md_atomic_read(&mddev->recovery_sem.count) != 1) schedule(); ! del_mddev_mapping(mddev, MKDEV(MD_MAJOR, mdidx(mddev))); md_list_del(&mddev->all_mddevs); MD_INIT_LIST_HEAD(&mddev->all_mddevs); kfree(mddev); --- 1017,1023 ---- while (md_atomic_read(&mddev->recovery_sem.count) != 1) schedule(); ! del_mddev_mapping(mddev, mdidx(mddev)); md_list_del(&mddev->all_mddevs); MD_INIT_LIST_HEAD(&mddev->all_mddevs); kfree(mddev); *************** *** 878,884 **** return ret; } ! static int uuid_equal(mdk_rdev_t *rdev1, mdk_rdev_t *rdev2) { if ( (rdev1->sb->set_uuid0 == rdev2->sb->set_uuid0) && (rdev1->sb->set_uuid1 == rdev2->sb->set_uuid1) && --- 1141,1147 ---- return ret; } ! int uuid_equal(mdk_rdev_t *rdev1, mdk_rdev_t *rdev2) { if ( (rdev1->sb->set_uuid0 == rdev2->sb->set_uuid0) && (rdev1->sb->set_uuid1 == rdev2->sb->set_uuid1) && *************** *** 905,919 **** return NULL; } - #define GETBLK_FAILED KERN_ERR \ - "md: getblk failed for device %s\n" - static int write_disk_sb(mdk_rdev_t * rdev) { - struct buffer_head *bh; kdev_t dev; unsigned long sb_offset, size; ! mdp_super_t *sb; if (!rdev->sb) { MD_BUG(); --- 1168,1179 ---- return NULL; } static int write_disk_sb(mdk_rdev_t * rdev) { kdev_t dev; unsigned long sb_offset, size; ! md_superblock_type sb_type; ! int retval; if (!rdev->sb) { MD_BUG(); *************** *** 929,937 **** } dev = rdev->dev; ! sb_offset = calc_dev_sboffset(dev, rdev->mddev, 1); if (rdev->sb_offset != sb_offset) { ! printk("%s's sb offset has changed from %ld to %ld, skipping\n", partition_name(dev), rdev->sb_offset, sb_offset); goto skip; } /* --- 1189,1202 ---- } dev = rdev->dev; ! sb_type = rdev->sb_type; ! ! sb_offset = md_sb_types[sb_type].get_sb_offset(rdev); ! if (rdev->sb_offset != sb_offset) { ! printk("md%d: %s's sb offset has changed from %ld to %ld, " ! "skipping\n", mdidx(rdev->mddev), partition_name(dev), ! rdev->sb_offset, sb_offset); goto skip; } /* *************** *** 939,972 **** * it's size has changed to zero silently, and the MD code does * not yet know that it's faulty. */ ! size = calc_dev_size(dev, rdev->mddev, 1); if (size != rdev->size) { ! printk("%s's size has changed from %ld to %ld since import, skipping\n", partition_name(dev), rdev->size, size); goto skip; } printk("(write) %s's sb offset: %ld\n", partition_name(dev), sb_offset); ! fsync_dev(dev); ! set_blocksize(dev, MD_SB_BYTES); ! bh = getblk(dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); ! if (!bh) { ! printk(GETBLK_FAILED, partition_name(dev)); ! return 1; } ! memset(bh->b_data,0,bh->b_size); ! sb = (mdp_super_t *) bh->b_data; ! memcpy(sb, rdev->sb, MD_SB_BYTES); ! ! mark_buffer_uptodate(bh, 1); ! mark_buffer_dirty(bh); ! ll_rw_block(WRITE, 1, &bh); ! wait_on_buffer(bh); ! brelse(bh); ! fsync_dev(dev); skip: return 0; } - #undef GETBLK_FAILED static void set_this_disk(mddev_t *mddev, mdk_rdev_t *rdev) { --- 1204,1233 ---- * it's size has changed to zero silently, and the MD code does * not yet know that it's faulty. */ ! size = md_sb_types[sb_type].get_dev_size(rdev); if (size != rdev->size) { ! printk("md%d: %s's size has changed from %ld to %ld since " ! "import, skipping\n", mdidx(rdev->mddev), ! partition_name(dev), rdev->size, size); goto skip; } + if ((retval = md_sb_types[sb_type].translate_sb_to_native(rdev)) != 0){ + printk("md%d: unable to translate %s superblock to native " + "format\n", mdidx(rdev->mddev), partition_name(dev)); + goto skip; + } printk("(write) %s's sb offset: %ld\n", partition_name(dev), sb_offset); ! ! if ((retval = md_sb_types[sb_type].write_sb(rdev)) != 0) { ! printk("md%d: superblock write failed for %s\n", ! mdidx(rdev->mddev), partition_name(dev)); ! return(retval); } ! skip: return 0; } static void set_this_disk(mddev_t *mddev, mdk_rdev_t *rdev) { *************** *** 1090,1095 **** --- 1351,1360 ---- if (find_rdev_all(newdev)) return -EEXIST; + #if 0 + printk("md_import_device: importing %s\n", partition_name(newdev)); + #endif + rdev = (mdk_rdev_t *) kmalloc(sizeof(*rdev), GFP_KERNEL); if (!rdev) { printk("could not alloc mem for %s!\n", partition_name(newdev)); *************** *** 1128,1142 **** } if (on_disk) { if ((err = read_disk_sb(rdev))) { ! printk("md: could not read %s's sb, not importing!\n", ! partition_name(newdev)); ! goto abort_free; ! } ! if ((err = check_disk_sb(rdev))) { ! printk("md: %s has invalid sb, not importing!\n", ! partition_name(newdev)); ! goto abort_free; } rdev->old_dev = MKDEV(rdev->sb->this_disk.major, --- 1393,1403 ---- } if (on_disk) { + if ((err = read_disk_sb(rdev))) { ! printk("md: could not read %s's sb, not " ! "importing!\n", partition_name(newdev)); ! goto abort_free; } rdev->old_dev = MKDEV(rdev->sb->this_disk.major, *************** *** 1198,1204 **** MD_BUG(); goto abort; } ! if (check_disk_sb(rdev)) goto abort; } --- 1459,1465 ---- MD_BUG(); goto abort; } ! if (check_disk_sb(rdev, rdev->sb)) goto abort; } *************** *** 1251,1257 **** continue; } /* ! * Find the newest superblock version */ ev1 = md_event(rdev->sb); ev2 = md_event(freshest->sb); --- 1512,1521 ---- continue; } /* ! * Find the newest superblock version. If one of the ! * superblocks is equal, but not clean, use that one ! * so that we can force a rebuild. ! * XXX KDM this might not be a good idea. */ ev1 = md_event(rdev->sb); ev2 = md_event(freshest->sb); *************** *** 1259,1264 **** --- 1523,1530 ---- out_of_date = 1; if (ev1 > ev2) freshest = rdev; + } else if ((rdev->sb->state & (1 << MD_SB_CLEAN)) == 0) { + freshest = rdev; } } if (out_of_date) { *************** *** 1266,1271 **** --- 1532,1545 ---- printk("freshest: %s\n", partition_name(freshest->dev)); } memcpy (sb, freshest->sb, sizeof(*sb)); + mddev->sb_type = freshest->sb_type; + mddev->primary_native_sb = freshest->primary_native_sb; + mddev->primary_native_sb_size = freshest->primary_native_sb_size; + mddev->primary_native_sb_offset = freshest->primary_native_sb_offset; + mddev->secondary_native_sb = freshest->secondary_native_sb; + mddev->secondary_native_sb_size = freshest->secondary_native_sb_size; + mddev->secondary_native_sb_offset = + freshest->secondary_native_sb_offset; /* * at this point we have picked the 'best' superblock *************** *** 1424,1429 **** --- 1698,1709 ---- ITERATE_RDEV(mddev,rdev2,tmp2) { if ((rdev2 != rdev) && (rdev2->desc_nr == rdev->desc_nr)) { + /* XXX KDM remove */ + printk("%s desc_nr (%d) == %s desc_nr(%d)\n", + partition_name(rdev->dev), + rdev->desc_nr, + partition_name(rdev2->dev), + rdev2->desc_nr); MD_BUG(); goto abort; } *************** *** 1486,1492 **** MD_BUG(); continue; } ! rdev->size = calc_dev_size(rdev->dev, mddev, persistent); if (rdev->size < sb->chunk_size / 1024) { printk (KERN_WARNING "Dev %s smaller than chunk_size: %ldk < %dk\n", --- 1766,1773 ---- MD_BUG(); continue; } ! rdev->size = md_sb_types[rdev->sb_type].get_dev_size(rdev); ! if (rdev->size < sb->chunk_size / 1024) { printk (KERN_WARNING "Dev %s smaller than chunk_size: %ldk < %dk\n", *************** *** 1522,1530 **** printk (UNKNOWN_LEVEL, mdidx(mddev), sb->level); goto abort; } ! if (!md_size[mdidx(mddev)]) ! md_size[mdidx(mddev)] = sb->size * data_disks; ! readahead = MD_READAHEAD; if ((sb->level == 0) || (sb->level == 4) || (sb->level == 5)) { readahead = (mddev->sb->chunk_size>>PAGE_SHIFT) * 4 * data_disks; --- 1803,1812 ---- printk (UNKNOWN_LEVEL, mdidx(mddev), sb->level); goto abort; } ! if (!md_size[mdminor(mddev)]) ! md_size[mdminor(mddev)] = sb->size * data_disks; ! mdp_size[mdpminor(mddev)] = md_size[mdminor(mddev)]; ! readahead = MD_READAHEAD; if ((sb->level == 0) || (sb->level == 4) || (sb->level == 5)) { readahead = (mddev->sb->chunk_size>>PAGE_SHIFT) * 4 * data_disks; *************** *** 1534,1540 **** if (sb->level == -3) readahead = 0; } ! md_maxreadahead[mdidx(mddev)] = readahead; printk(KERN_INFO "md%d: max total readahead window set to %ldk\n", mdidx(mddev), readahead*(PAGE_SIZE/1024)); --- 1816,1823 ---- if (sb->level == -3) readahead = 0; } ! md_maxreadahead[mdminor(mddev)] = readahead; ! mdp_maxreadahead[mdpminor(mddev)] = readahead; printk(KERN_INFO "md%d: max total readahead window set to %ldk\n", mdidx(mddev), readahead*(PAGE_SIZE/1024)); *************** *** 1563,1568 **** --- 1846,1852 ---- int chunk_size; struct md_list_head *tmp; mdk_rdev_t *rdev; + int part,minor,pminor; if (!mddev->nb_dev) { *************** *** 1577,1583 **** * Resize disks to align partitions size on a given * chunk size. */ ! md_size[mdidx(mddev)] = 0; /* * Analyze all RAID superblock(s) --- 1861,1869 ---- * Resize disks to align partitions size on a given * chunk size. */ ! minor = mdminor(mddev); ! pminor = mdpminor(mddev); ! md_size[minor] = 0; /* * Analyze all RAID superblock(s) *************** *** 1645,1666 **** * device. * Also find largest hardsector size */ ! md_hardsect_sizes[mdidx(mddev)] = 512; ITERATE_RDEV(mddev,rdev,tmp) { if (rdev->faulty) continue; fsync_dev(rdev->dev); invalidate_buffers(rdev->dev); if (get_hardsect_size(rdev->dev) ! > md_hardsect_sizes[mdidx(mddev)]) ! md_hardsect_sizes[mdidx(mddev)] = get_hardsect_size(rdev->dev); } ! md_blocksizes[mdidx(mddev)] = 1024; ! if (md_blocksizes[mdidx(mddev)] < md_hardsect_sizes[mdidx(mddev)]) ! md_blocksizes[mdidx(mddev)] = md_hardsect_sizes[mdidx(mddev)]; mddev->pers = pers[pnum]; err = mddev->pers->run(mddev); if (err) { printk("pers->run() failed ...\n"); --- 1931,1957 ---- * device. * Also find largest hardsector size */ ! md_hardsect_sizes[minor] = 512; ITERATE_RDEV(mddev,rdev,tmp) { if (rdev->faulty) continue; fsync_dev(rdev->dev); invalidate_buffers(rdev->dev); if (get_hardsect_size(rdev->dev) ! > md_hardsect_sizes[minor]) ! md_hardsect_sizes[minor] = get_hardsect_size(rdev->dev); } ! md_blocksizes[minor] = 1024; ! if (md_blocksizes[minor] < md_hardsect_sizes[minor]) ! md_blocksizes[minor] = md_hardsect_sizes[minor]; mddev->pers = pers[pnum]; + foreach_part(part, mddev) { + mdp_blocksizes[part] = md_blocksizes[minor]; + mdp_hardsect_sizes[part] = md_hardsect_sizes[minor]; + } + err = mddev->pers->run(mddev); if (err) { printk("pers->run() failed ...\n"); *************** *** 1675,1684 **** * md_size has units of 1K blocks, which are * twice as large as sectors. */ ! md_hd_struct[mdidx(mddev)].start_sect = 0; ! md_hd_struct[mdidx(mddev)].nr_sects = md_size[mdidx(mddev)] << 1; read_ahead[MD_MAJOR] = 1024; return (0); } --- 1966,1986 ---- * md_size has units of 1K blocks, which are * twice as large as sectors. */ ! md_hd_struct[minor].start_sect = 0; ! md_hd_struct[minor].nr_sects = md_size[minor] << 1; read_ahead[MD_MAJOR] = 1024; + read_ahead[MDP_MAJOR] = 1024; + + register_disk(&md_gendisk, md_kdev(mddev), + 1, &md_fops, + md_size[minor] << 1); + + if (mdidx(mddev) < MAX_MDP_DEVS) + register_disk(&mdp_gendisk, mdp_kdev(mddev,0), + 1 << MDP_MINOR_SHIFT, &md_fops, + mdp_size[minor] << 1); + return (0); } *************** *** 1690,1695 **** --- 1992,1998 ---- static int restart_array (mddev_t *mddev) { int err = 0; + int part; /* * Complain if it has no devices *************** *** 1702,1708 **** OUT(-EBUSY); mddev->ro = 0; ! set_device_ro(mddev_to_kdev(mddev), 0); printk (KERN_INFO "md%d switched to read-write mode.\n", mdidx(mddev)); --- 2005,2013 ---- OUT(-EBUSY); mddev->ro = 0; ! set_device_ro(md_kdev(mddev), 0); ! foreach_part(part, mddev) ! set_device_ro(MKDEV(MDP_MAJOR,part), 0); printk (KERN_INFO "md%d switched to read-write mode.\n", mdidx(mddev)); *************** *** 1727,1745 **** static int do_md_stop (mddev_t * mddev, int ro) { int err = 0, resync_interrupted = 0; ! kdev_t dev = mddev_to_kdev(mddev); if (atomic_read(&mddev->active)>1) { printk(STILL_IN_USE, mdidx(mddev)); OUT(-EBUSY); } - /* this shouldn't be needed as above would have fired */ - if (!ro && get_super(dev)) { - printk (STILL_MOUNTED, mdidx(mddev)); - OUT(-EBUSY); - } - if (mddev->pers) { /* * It is safe to call stop here, it only frees private --- 2032,2044 ---- static int do_md_stop (mddev_t * mddev, int ro) { int err = 0, resync_interrupted = 0; ! int part; if (atomic_read(&mddev->active)>1) { printk(STILL_IN_USE, mdidx(mddev)); OUT(-EBUSY); } if (mddev->pers) { /* * It is safe to call stop here, it only frees private *************** *** 1768,1787 **** * the kernel lock protects us from new requests being * added after invalidate_buffers(). */ ! fsync_dev (mddev_to_kdev(mddev)); ! fsync_dev (dev); ! invalidate_buffers (dev); ! if (ro) { if (mddev->ro) OUT(-ENXIO); mddev->ro = 1; } else { ! if (mddev->ro) ! set_device_ro(dev, 0); if (mddev->pers->stop(mddev)) { ! if (mddev->ro) ! set_device_ro(dev, 1); OUT(-EBUSY); } if (mddev->ro) --- 2067,2096 ---- * the kernel lock protects us from new requests being * added after invalidate_buffers(). */ ! fsync_dev (md_kdev(mddev)); ! invalidate_buffers(md_kdev(mddev)); ! foreach_part(part, mddev) { ! kdev_t dev = MKDEV(MDP_MAJOR, part); ! ! fsync_dev (dev); ! invalidate_buffers (dev); ! } if (ro) { if (mddev->ro) OUT(-ENXIO); mddev->ro = 1; } else { ! if (mddev->ro) { ! set_device_ro(md_kdev(mddev),0); ! foreach_part(part, mddev) ! set_device_ro(MKDEV(MDP_MAJOR,part), 0); ! } if (mddev->pers->stop(mddev)) { ! if (mddev->ro) { ! set_device_ro(md_kdev(mddev),1); ! foreach_part(part, mddev) ! set_device_ro(MKDEV(MDP_MAJOR,part), 1); ! } OUT(-EBUSY); } if (mddev->ro) *************** *** 1798,1805 **** } md_update_sb(mddev); } ! if (ro) ! set_device_ro(dev, 1); } /* --- 2107,2117 ---- } md_update_sb(mddev); } ! if (ro) { ! set_device_ro(md_kdev(mddev),1); ! foreach_part(part, mddev) ! set_device_ro(MKDEV(MDP_MAJOR,part), 1); ! } } /* *************** *** 1879,1893 **** struct md_list_head *tmp; mdk_rdev_t *rdev0, *rdev; mddev_t *mddev; ! kdev_t md_kdev; ! printk("autorun ...\n"); while (pending_raid_disks.next != &pending_raid_disks) { rdev0 = md_list_entry(pending_raid_disks.next, mdk_rdev_t, pending); printk("considering %s ...\n", partition_name(rdev0->dev)); MD_INIT_LIST_HEAD(&candidates); ITERATE_RDEV_PENDING(rdev,tmp) { if (uuid_equal(rdev0, rdev)) { --- 2191,2214 ---- struct md_list_head *tmp; mdk_rdev_t *rdev0, *rdev; mddev_t *mddev; ! int unit; printk("autorun ...\n"); while (pending_raid_disks.next != &pending_raid_disks) { + int retval; + + retval = 0; + rdev0 = md_list_entry(pending_raid_disks.next, mdk_rdev_t, pending); printk("considering %s ...\n", partition_name(rdev0->dev)); + if ((retval = md_sb_types[rdev0->sb_type].configure_array( + rdev0)) != 0) { + printk("md: array configuration failed, error " + "code %d\n", retval); + break; + } MD_INIT_LIST_HEAD(&candidates); ITERATE_RDEV_PENDING(rdev,tmp) { if (uuid_equal(rdev0, rdev)) { *************** *** 1905,1912 **** * mostly sane superblocks. It's time to allocate the * mddev. */ ! md_kdev = MKDEV(MD_MAJOR, rdev0->sb->md_minor); ! mddev = kdev_to_mddev(md_kdev); if (mddev) { printk("md%d already running, cannot run %s\n", mdidx(mddev), partition_name(rdev0->dev)); --- 2226,2233 ---- * mostly sane superblocks. It's time to allocate the * mddev. */ ! unit = rdev0->sb->md_minor; ! mddev = mddev_map[unit].mddev; if (mddev) { printk("md%d already running, cannot run %s\n", mdidx(mddev), partition_name(rdev0->dev)); *************** *** 1914,1927 **** export_rdev(rdev); continue; } ! mddev = alloc_mddev(md_kdev); if (mddev == NULL) { printk("md: cannot allocate memory for md drive.\n"); break; } ! if (md_kdev == countdev) atomic_inc(&mddev->active); printk("created md%d\n", mdidx(mddev)); ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) { bind_rdev_to_array(rdev, mddev); md_list_del(&rdev->pending); --- 2235,2249 ---- export_rdev(rdev); continue; } ! mddev = alloc_mddev(unit); if (mddev == NULL) { printk("md: cannot allocate memory for md drive.\n"); break; } ! if (unit == countdev) atomic_inc(&mddev->active); printk("created md%d\n", mdidx(mddev)); + ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) { bind_rdev_to_array(rdev, mddev); md_list_del(&rdev->pending); *************** *** 2404,2409 **** --- 2726,2736 ---- SET_SB(nr_disks); SET_SB(raid_disks); SET_SB(md_minor); + /* I want to trust the unit number of mddev more than + * md_minorfrom info - neilb + */ + mddev->sb->md_minor = mdidx(mddev); + SET_SB(not_persistent); SET_SB(state); *************** *** 2463,2473 **** { int ret; ! fsync_dev(mddev_to_kdev(mddev)); ! ret = md_error(mddev_to_kdev(mddev), dev); return ret; } static int md_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { --- 2790,2847 ---- { int ret; ! ret = md_error(mddev, dev); return ret; } + static int md_reread_partition(mddev_t *mddev) + { + /* copied from ide_revalidate_disk */ + int minor = mdpminor(mddev); + int part; + if (mdidx(mddev) >= MAX_MDP_DEVS) + return 0; + foreach_part(part, mddev) { + if (mdp_hd_struct[part].nr_sects > 0) { + kdev_t dev = MKDEV(MDP_MAJOR, part); + struct super_block *sb = get_super(dev); + fsync_dev(dev); + if (sb) + invalidate_inodes(sb); + invalidate_buffers(dev); + set_blocksize(dev, 1024); + } + mdp_hd_struct[part].start_sect= 0; + mdp_hd_struct[part].nr_sects = 0; + } + /* and from revalidate_scsidisk.. */ + grok_partitions(&mdp_gendisk, minor >> MDP_MINOR_SHIFT, 1<i_rdev; minor = MINOR(dev); ! if (minor >= MAX_MD_DEVS) return -EINVAL; /* * Commands dealing with the RAID driver but not any * particular array: --- 2850,2875 ---- struct hd_geometry *loc = (struct hd_geometry *) arg; mddev_t *mddev = NULL; kdev_t dev; + int unit=0; + struct hd_struct *hdp = NULL; if (!md_capable_admin()) return -EACCES; dev = inode->i_rdev; minor = MINOR(dev); ! if (( MAJOR(dev) == MD_MAJOR && minor >= MAX_MD_DEVS) || ! ( MAJOR(dev) == MDP_MAJOR && minor >= (MAX_MDP_DEVS<> MDP_MINOR_SHIFT; + hdp = &mdp_hd_struct[minor]; + } else + BUG(); /* * Commands dealing with the RAID driver but not any * particular array: *************** *** 2512,2519 **** err = -EINVAL; goto abort; } ! err = md_put_user(md_hd_struct[minor].nr_sects, ! (long *) arg); goto done; case BLKFLSBUF: --- 2897,2905 ---- err = -EINVAL; goto abort; } ! err = md_put_user(hdp->nr_sects, ! (long *) arg); ! goto done; case BLKFLSBUF: *************** *** 2561,2567 **** switch (cmd) { case SET_ARRAY_INFO: ! mddev = alloc_mddev(dev); if (!mddev) { err = -ENOMEM; goto abort; --- 2947,2953 ---- switch (cmd) { case SET_ARRAY_INFO: ! mddev = alloc_mddev(unit); if (!mddev) { err = -ENOMEM; goto abort; *************** *** 2601,2606 **** --- 2987,2998 ---- /* * possibly make it lock the array ... */ + /* XXX KDM remove */ + printk("START_ARRAY ioctl called, calling " + "autostart_array()\n"); + printk("start_dev = %s, count_dev = %s\n", + partition_name((kdev_t)arg), + partition_name(dev)); err = autostart_array((kdev_t)arg, dev); if (err) { printk("autostart %s failed!\n", *************** *** 2657,2686 **** err = do_md_stop (mddev, 1); goto done_unlock; ! /* ! * We have a problem here : there is no easy way to give a CHS ! * virtual geometry. We currently pretend that we have a 2 heads ! * 4 sectors (with a BIG number of cylinders...). This drives ! * dosfs just mad... ;-) ! */ case HDIO_GETGEO: if (!loc) { err = -EINVAL; goto abort_unlock; } ! err = md_put_user (2, (char *) &loc->heads); if (err) goto abort_unlock; ! err = md_put_user (4, (char *) &loc->sectors); if (err) goto abort_unlock; ! err = md_put_user (md_hd_struct[mdidx(mddev)].nr_sects/8, (short *) &loc->cylinders); if (err) goto abort_unlock; ! err = md_put_user (md_hd_struct[minor].start_sect, (long *) &loc->start); goto done_unlock; } /* --- 3049,3144 ---- err = do_md_stop (mddev, 1); goto done_unlock; ! /* ! * The geometry of a raid array is not necessarily well ! * defined. There aren't always heads, sectors, and cylinders. ! * For raid1 and linear we take the head and sector counts ! * for the first drive, or 2 and 4 if the ioctl fails. ! * For raid0 and raid5 we set sectors to sectors-per-chunk, ! * and heads to number-of-data-disks. ! * Then we calculate the number of cylinders to account for ! * the full size of the device. ! * ! */ case HDIO_GETGEO: + { + int sectors, heads; if (!loc) { err = -EINVAL; goto abort_unlock; } ! switch (mddev->sb->level) { ! case 4: ! case 5: ! sectors = mddev->sb->chunk_size>>9; ! heads = mddev->sb->raid_disks-1; ! break; ! case 0: ! sectors = mddev->sb->chunk_size>>9; ! heads = mddev->sb->raid_disks; ! break; ! default: ! /* raid1 or linear.. */ ! { ! struct md_list_head *tmp; ! mdk_rdev_t *rdev, *found_rdev = NULL; ! int rd = -1; ! ! ITERATE_RDEV(mddev,rdev,tmp) { ! mdp_disk_t *d; ! d = &mddev->sb->disks[rdev->desc_nr]; ! if (disk_active(d) && ! (rd == -1 || d->raid_disk < rd)) { ! rd = d->raid_disk; ! found_rdev = rdev; ! } ! } ! if (!found_rdev || ! get_geo(found_rdev->dev, &heads, §ors)!=0) { ! heads = 2; ! sectors = 4; ! } ! } ! ! } ! /* fdisk gets doesn't like sectors > 63 or head > 255 ... */ ! while (sectors > 63) { sectors >>= 1; heads <<= 1; } ! while (heads > 255) heads >>= 1; ! err = md_put_user ((char)heads, (char *) &loc->heads); if (err) goto abort_unlock; ! err = md_put_user ((char)sectors, (char *) &loc->sectors); if (err) goto abort_unlock; ! err = md_put_user (hdp->nr_sects/((int)heads*(int)sectors), (short *) &loc->cylinders); if (err) goto abort_unlock; ! err = md_put_user (hdp->start_sect, (long *) &loc->start); goto done_unlock; + } + + case BLKPG: + if (MAJOR(dev) == MD_MAJOR || mddev->pers == pers[RAID5]) { + printk(KERN_WARNING "%s(pid %d) used ioctl to change partitions on RAID5 array - this is illegal.\n", + current->comm, current->pid); + err = -EINVAL; + } + else + err = blk_ioctl(dev, cmd, arg); + goto done_unlock; + + case BLKRRPART: /* Re-read partition tables */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + if (MAJOR(dev) == MD_MAJOR || mddev->pers == pers[RAID5]) { + printk(KERN_WARNING "%s(pid %d) used ioctl to change partitions on RAID5 array - this is illegal.\n", + current->comm, current->pid); + err = -EINVAL; + } + else + err = md_reread_partition(mddev); + goto done_unlock; } /* *************** *** 2938,2950 **** } ! int md_error (kdev_t dev, kdev_t rdev) { - mddev_t *mddev; mdk_rdev_t * rrdev; int rc; - mddev = kdev_to_mddev(dev); /* printk("md_error dev:(%d:%d), rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",MAJOR(dev),MINOR(dev),MAJOR(rdev),MINOR(rdev), __builtin_return_address(0),__builtin_return_address(1),__builtin_return_address(2),__builtin_return_address(3)); */ if (!mddev) { --- 3396,3406 ---- } ! int md_error (mddev_t *mddev, kdev_t rdev) { mdk_rdev_t * rrdev; int rc; /* printk("md_error dev:(%d:%d), rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",MAJOR(dev),MINOR(dev),MAJOR(rdev),MINOR(rdev), __builtin_return_address(0),__builtin_return_address(1),__builtin_return_address(2),__builtin_return_address(3)); */ if (!mddev) { *************** *** 3099,3105 **** if (mddev->nb_dev) { if (mddev->pers) sz += sprintf(page + sz, "\n %d blocks", ! md_size[mdidx(mddev)]); else sz += sprintf(page + sz, "\n %d blocks", size); } --- 3555,3561 ---- if (mddev->nb_dev) { if (mddev->pers) sz += sprintf(page + sz, "\n %d blocks", ! md_size[mdminor(mddev)]); else sz += sprintf(page + sz, "\n %d blocks", size); } *************** *** 3234,3240 **** mddev_t *mddev2; unsigned int max_blocks, currspeed, j, window, err, serialize; - kdev_t read_disk = mddev_to_kdev(mddev); unsigned long mark[SYNC_MARKS]; unsigned long mark_cnt[SYNC_MARKS]; int last_mark,m; --- 3690,3695 ---- *************** *** 3367,3373 **** } else current->nice = -20; } - fsync_dev(read_disk); printk(KERN_INFO "md: md%d: sync done.\n",mdidx(mddev)); err = 0; /* --- 3822,3827 ---- *************** *** 3501,3507 **** struct notifier_block md_notifier = { md_notify_reboot, NULL, ! 0 }; static void md_geninit (void) --- 3955,3961 ---- struct notifier_block md_notifier = { md_notify_reboot, NULL, ! INT_MAX /* max priority */ }; static void md_geninit (void) *************** *** 3513,3524 **** md_size[i] = 0; md_hardsect_sizes[i] = 512; md_maxreadahead[i] = MD_READAHEAD; - register_disk(&md_gendisk, MKDEV(MAJOR_NR,i), 1, &md_fops, 0); } ! blksize_size[MAJOR_NR] = md_blocksizes; ! blk_size[MAJOR_NR] = md_size; ! max_readahead[MAJOR_NR] = md_maxreadahead; ! hardsect_size[MAJOR_NR] = md_hardsect_sizes; printk("md.c: sizeof(mdp_super_t) = %d\n", (int)sizeof(mdp_super_t)); --- 3967,3988 ---- md_size[i] = 0; md_hardsect_sizes[i] = 512; md_maxreadahead[i] = MD_READAHEAD; } ! for(i = 0; i < MAX_MDP_DEVS<= 0 && dev_cnt < 127) detected_devices[dev_cnt++] = dev; + /* XXX KDM remove */ + printk("md_autodetect_dev: dev_cnt = %d, device = %s\n", + dev_cnt, partition_name(dev)); } *************** *** 3740,3769 **** void md__init md_setup_drive(void) { ! int minor, i; kdev_t dev; mddev_t*mddev; ! for (minor = 0; minor < MAX_MD_DEVS; minor++) { mdu_disk_info_t dinfo; int err = 0; ! if (!md_setup_args.device_set[minor]) continue; ! printk("md: Loading md%d.\n", minor); ! if (mddev_map[minor].mddev) { ! printk(".. md%d already autodetected - use raid=noautodetect\n", minor); continue; } ! mddev = alloc_mddev(MKDEV(MD_MAJOR,minor)); ! if (md_setup_args.pers[minor]) { /* non-persistent */ mdu_array_info_t ainfo; ! ainfo.level = pers_to_level(md_setup_args.pers[minor]); ainfo.size = 0; ainfo.nr_disks =0; ainfo.raid_disks =0; ! ainfo.md_minor =minor; ainfo.not_persistent = 1; ainfo.state = MD_SB_CLEAN; --- 4218,4247 ---- void md__init md_setup_drive(void) { ! int unit, i; kdev_t dev; mddev_t*mddev; ! for (unit = 0; unit < MAX_MD_DEVS; unit++) { mdu_disk_info_t dinfo; int err = 0; ! if (!md_setup_args.device_set[unit]) continue; ! printk("md: Loading md%d.\n", unit); ! if (mddev_map[unit].mddev) { ! printk(".. md%d already autodetected - use raid=noautodetect\n", unit); continue; } ! mddev = alloc_mddev(unit); ! if (md_setup_args.pers[unit]) { /* non-persistent */ mdu_array_info_t ainfo; ! ainfo.level = pers_to_level(md_setup_args.pers[unit]); ainfo.size = 0; ainfo.nr_disks =0; ainfo.raid_disks =0; ! ainfo.md_minor = unit; ainfo.not_persistent = 1; ainfo.state = MD_SB_CLEAN; *************** *** 3772,3780 **** ainfo.failed_disks = 0; ainfo.spare_disks = 0; ainfo.layout = 0; ! ainfo.chunk_size = md_setup_args.chunk[minor]; err = set_array_info(mddev, &ainfo); ! for (i = 0; !err && (dev = md_setup_args.devices[minor][i]); i++) { dinfo.number = i; dinfo.raid_disk = i; dinfo.state = (1<sb_dirty = 0; do_md_stop(mddev, 0); ! printk("md: starting md%d failed\n", minor); } } } --- 4277,4283 ---- if (err) { mddev->sb_dirty = 0; do_md_stop(mddev, 0); ! printk("md: starting md%d failed\n", unit); } } } *************** *** 3866,3872 **** md_unregister_thread(md_recovery_thread); devfs_unregister(devfs_handle); ! devfs_unregister_blkdev(MAJOR_NR,"md"); unregister_reboot_notifier(&md_notifier); unregister_sysctl_table(raid_table_header); #ifdef CONFIG_PROC_FS --- 4344,4351 ---- md_unregister_thread(md_recovery_thread); devfs_unregister(devfs_handle); ! devfs_unregister_blkdev(MD_MAJOR,"md"); ! devfs_unregister_blkdev(MDP_MAJOR,"md"); unregister_reboot_notifier(&md_notifier); unregister_sysctl_table(raid_table_header); #ifdef CONFIG_PROC_FS *************** *** 3881,3891 **** } gendisk_ptr = & (*gendisk_ptr)->next; } ! blk_dev[MAJOR_NR].queue = NULL; ! blksize_size[MAJOR_NR] = NULL; ! blk_size[MAJOR_NR] = NULL; ! max_readahead[MAJOR_NR] = NULL; ! hardsect_size[MAJOR_NR] = NULL; free_device_names(); --- 4360,4384 ---- } gendisk_ptr = & (*gendisk_ptr)->next; } ! gendisk_ptr = &gendisk_head; ! while (*gendisk_ptr) { ! if (*gendisk_ptr == &mdp_gendisk) { ! *gendisk_ptr = mdp_gendisk.next; ! break; ! } ! gendisk_ptr = & (*gendisk_ptr)->next; ! } ! blk_dev[MD_MAJOR].queue = NULL; ! blksize_size[MD_MAJOR] = NULL; ! blk_size[MD_MAJOR] = NULL; ! max_readahead[MD_MAJOR] = NULL; ! hardsect_size[MD_MAJOR] = NULL; ! ! blk_dev[MDP_MAJOR].queue = NULL; ! blksize_size[MDP_MAJOR] = NULL; ! blk_size[MDP_MAJOR] = NULL; ! max_readahead[MDP_MAJOR] = NULL; ! hardsect_size[MDP_MAJOR] = NULL; free_device_names(); diff -crN ../linux-2.4.3.virgin/drivers/md/raid0.c linux-2.4.3.md/drivers/md/raid0.c *** ../linux-2.4.3.virgin/drivers/md/raid0.c Mon Dec 11 14:19:35 2000 --- linux-2.4.3.md/drivers/md/raid0.c Tue Jun 26 10:38:53 2001 *************** *** 138,147 **** if (create_strip_zones (mddev)) goto out_free_conf; ! printk("raid0 : md_size is %d blocks.\n", md_size[mdidx(mddev)]); printk("raid0 : conf->smallest->size is %ld blocks.\n", conf->smallest->size); ! nb_zone = md_size[mdidx(mddev)]/conf->smallest->size + ! (md_size[mdidx(mddev)] % conf->smallest->size ? 1 : 0); printk("raid0 : nb_zone is %ld.\n", nb_zone); conf->nr_zones = nb_zone; --- 138,147 ---- if (create_strip_zones (mddev)) goto out_free_conf; ! printk("raid0 : md_size is %d blocks.\n", md_size[mdminor(mddev)]); printk("raid0 : conf->smallest->size is %ld blocks.\n", conf->smallest->size); ! nb_zone = md_size[mdminor(mddev)]/conf->smallest->size + ! (md_size[mdminor(mddev)] % conf->smallest->size ? 1 : 0); printk("raid0 : nb_zone is %ld.\n", nb_zone); conf->nr_zones = nb_zone; diff -crN ../linux-2.4.3.virgin/drivers/md/raid1.c linux-2.4.3.md/drivers/md/raid1.c *** ../linux-2.4.3.virgin/drivers/md/raid1.c Fri Feb 9 12:30:23 2001 --- linux-2.4.3.md/drivers/md/raid1.c Tue Jun 26 12:53:01 2001 *************** *** 47,52 **** --- 47,54 ---- #endif + extern struct mdk_superblock_desc_s md_sb_types[]; + static mdk_personality_t raid1_personality; static md_spinlock_t retry_list_lock = MD_SPIN_LOCK_UNLOCKED; struct raid1_bh *raid1_retry_list = NULL, **raid1_retry_tail; *************** *** 388,394 **** * this branch is our 'one mirror IO has finished' event handler: */ if (!uptodate) ! md_error (mddev_to_kdev(r1_bh->mddev), bh->b_dev); else /* * Set R1BH_Uptodate in our master buffer_head, so that --- 390,396 ---- * this branch is our 'one mirror IO has finished' event handler: */ if (!uptodate) ! md_error (r1_bh->mddev, bh->b_dev); else /* * Set R1BH_Uptodate in our master buffer_head, so that *************** *** 986,991 **** --- 988,999 ---- goto abort; } + if ((err = md_sb_types[mddev->sb_type].activate_spare(mddev, + fdisk->number, sdisk->number)) != 0) { + MD_BUG(); + goto abort; + } + /* * do the switch finally */ *************** *** 1415,1421 **** * We don't do much here, just schedule handling by raid1d */ if (!uptodate) ! md_error (mddev_to_kdev(r1_bh->mddev), bh->b_dev); else set_bit(R1BH_Uptodate, &r1_bh->state); raid1_reschedule_retry(r1_bh); --- 1423,1429 ---- * We don't do much here, just schedule handling by raid1d */ if (!uptodate) ! md_error (r1_bh->mddev, bh->b_dev); else set_bit(R1BH_Uptodate, &r1_bh->state); raid1_reschedule_retry(r1_bh); *************** *** 1426,1432 **** struct raid1_bh * r1_bh = (struct raid1_bh *)(bh->b_private); if (!uptodate) ! md_error (mddev_to_kdev(r1_bh->mddev), bh->b_dev); if (atomic_dec_and_test(&r1_bh->remaining)) { mddev_t *mddev = r1_bh->mddev; unsigned long sect = bh->b_blocknr * (bh->b_size>>9); --- 1434,1440 ---- struct raid1_bh * r1_bh = (struct raid1_bh *)(bh->b_private); if (!uptodate) ! md_error (r1_bh->mddev, bh->b_dev); if (atomic_dec_and_test(&r1_bh->remaining)) { mddev_t *mddev = r1_bh->mddev; unsigned long sect = bh->b_blocknr * (bh->b_size>>9); diff -crN ../linux-2.4.3.virgin/drivers/md/raid5.c linux-2.4.3.md/drivers/md/raid5.c *** ../linux-2.4.3.virgin/drivers/md/raid5.c Fri Feb 9 12:30:23 2001 --- linux-2.4.3.md/drivers/md/raid5.c Tue Jun 26 13:27:46 2001 *************** *** 24,29 **** --- 24,30 ---- #include #include + extern struct mdk_superblock_desc_s md_sb_types[]; static mdk_personality_t raid5_personality; /* *************** *** 412,418 **** spin_lock_irqsave(&conf->device_lock, flags); } } else { ! md_error(mddev_to_kdev(conf->mddev), bh->b_dev); clear_bit(BH_Uptodate, &bh->b_state); } clear_bit(BH_Lock, &bh->b_state); --- 413,419 ---- spin_lock_irqsave(&conf->device_lock, flags); } } else { ! md_error(conf->mddev, bh->b_dev); clear_bit(BH_Uptodate, &bh->b_state); } clear_bit(BH_Lock, &bh->b_state); *************** *** 440,446 **** md_spin_lock_irqsave(&conf->device_lock, flags); if (!uptodate) ! md_error(mddev_to_kdev(conf->mddev), bh->b_dev); clear_bit(BH_Lock, &bh->b_state); set_bit(STRIPE_HANDLE, &sh->state); __release_stripe(conf, sh); --- 441,447 ---- md_spin_lock_irqsave(&conf->device_lock, flags); if (!uptodate) ! md_error(conf->mddev, bh->b_dev); clear_bit(BH_Lock, &bh->b_state); set_bit(STRIPE_HANDLE, &sh->state); __release_stripe(conf, sh); *************** *** 1869,1874 **** --- 1870,1881 ---- if (fdisk->raid_disk != failed_disk) { MD_BUG(); err = 1; + goto abort; + } + + if ((err = md_sb_types[mddev->sb_type].activate_spare(mddev, + fdisk->number, sdisk->number)) != 0) { + MD_BUG(); goto abort; } diff -crN ../linux-2.4.3.virgin/fs/partitions/check.c linux-2.4.3.md/fs/partitions/check.c *** ../linux-2.4.3.virgin/fs/partitions/check.c Fri Feb 16 17:02:37 2001 --- linux-2.4.3.md/fs/partitions/check.c Wed May 2 13:55:45 2001 *************** *** 33,38 **** --- 33,42 ---- #include "ibm.h" #include "ultrix.h" + #if CONFIG_BLK_DEV_MD + extern void md_autodetect_dev(kdev_t dev); + #endif + extern void device_init(void); extern int *blk_size[]; extern void rd_load(void); *************** *** 408,413 **** --- 412,420 ---- { if (!gdev) return; + #if CONFIG_BLK_DEV_MD + md_autodetect_dev(dev); + #endif grok_partitions(gdev, MINOR(dev)>>gdev->minor_shift, minors, size); } diff -crN ../linux-2.4.3.virgin/include/linux/raid/md.h linux-2.4.3.md/include/linux/raid/md.h *** ../linux-2.4.3.virgin/include/linux/raid/md.h Mon Mar 26 16:48:46 2001 --- linux-2.4.3.md/include/linux/raid/md.h Tue Jun 26 13:28:13 2001 *************** *** 61,68 **** extern int md_size[MAX_MD_DEVS]; extern struct hd_struct md_hd_struct[MAX_MD_DEVS]; ! extern void add_mddev_mapping (mddev_t *mddev, kdev_t dev, void *data); ! extern void del_mddev_mapping (mddev_t *mddev, kdev_t dev); extern char * partition_name (kdev_t dev); extern int register_md_personality (int p_num, mdk_personality_t *p); extern int unregister_md_personality (int p_num); --- 61,71 ---- extern int md_size[MAX_MD_DEVS]; extern struct hd_struct md_hd_struct[MAX_MD_DEVS]; ! extern int mdp_size[MAX_MDP_DEVS<> MDP_MINOR_SHIFT; ! else BUG(); ! return mddev_map[unit].mddev; } /* *************** *** 150,155 **** --- 161,172 ---- d->state &= ~(1 << MD_DISK_SYNC); } + typedef enum { + MD_SB_MD, + MD_SB_ADAPTEC_ASR, + MD_SB_NUMENTRIES + } md_superblock_type; + /* * MD's 'extended' device */ *************** *** 158,163 **** --- 175,181 ---- struct md_list_head same_set; /* RAID devices within the same set */ struct md_list_head all; /* all RAID devices */ struct md_list_head pending; /* undetected RAID devices */ + struct md_list_head tmplist; /* scratch list */ kdev_t dev; /* Device number */ kdev_t old_dev; /* "" when it was last imported */ *************** *** 169,177 **** --- 187,207 ---- mdp_super_t *sb; unsigned long sb_offset; + unsigned long sb_size; int faulty; /* if faulty do not issue IO requests */ int desc_nr; /* descriptor index in the superblock */ + + md_superblock_type sb_type; + void *primary_native_sb; + unsigned int primary_native_sb_size; + unsigned int primary_native_sb_offset; + void *secondary_native_sb; + unsigned int secondary_native_sb_size; + unsigned int secondary_native_sb_offset; + #define MDK_RDEV_NONE 0x00 + #define MDK_RDEV_NEED_MAJORS 0x01 + uint32_t flags; }; *************** *** 190,196 **** { void *private; mdk_personality_t *pers; ! int __minor; mdp_super_t *sb; int nb_dev; struct md_list_head disks; --- 220,226 ---- { void *private; mdk_personality_t *pers; ! int __unit; mdp_super_t *sb; int nb_dev; struct md_list_head disks; *************** *** 211,216 **** --- 241,253 ---- md_wait_queue_head_t recovery_wait; struct md_list_head all_mddevs; + md_superblock_type sb_type; + void *primary_native_sb; + int primary_native_sb_size; + int primary_native_sb_offset; + void *secondary_native_sb; + int secondary_native_sb_size; + int secondary_native_sb_offset; }; struct mdk_personality_s *************** *** 239,244 **** --- 276,296 ---- int (*sync_request)(mddev_t *mddev, unsigned long block_nr); }; + struct mdk_superblock_desc_s { + md_superblock_type type; + unsigned int (*get_sb_offset)(mdk_rdev_t *); + unsigned int (*get_sb_size)(void); + unsigned int (*get_dev_size)(mdk_rdev_t *); + int (*validate_sb)(mdk_rdev_t *rdev, void *sb); + int (*translate_sb)(mdk_rdev_t *rdev, void *sb, + mdp_super_t *md_sb); + int (*translate_sb_to_native)(mdk_rdev_t *rdev); + int (*write_sb)(mdk_rdev_t *rdev); + int (*configure_array)(mdk_rdev_t *rdev); + int (*activate_spare)(mddev_t *mddev, + int failed_disk, + int spare_disk); + }; /* * Currently we index md_array directly, based on the minor *************** *** 247,259 **** */ extern inline int mdidx (mddev_t * mddev) { ! return mddev->__minor; } ! extern inline kdev_t mddev_to_kdev(mddev_t * mddev) { ! return MKDEV(MD_MAJOR, mdidx(mddev)); } extern mdk_rdev_t * find_rdev(mddev_t * mddev, kdev_t dev); extern mdk_rdev_t * find_rdev_nr(mddev_t *mddev, int nr); --- 299,333 ---- */ extern inline int mdidx (mddev_t * mddev) { ! return mddev->__unit; ! } ! ! ! static inline int mdminor (mddev_t *mddev) ! { ! return mdidx(mddev); ! } ! ! static inline int mdpminor (mddev_t *mddev) ! { ! return mdidx(mddev)<< MDP_MINOR_SHIFT; } ! static inline kdev_t md_kdev (mddev_t *mddev) { ! return MKDEV(MD_MAJOR, mdminor(mddev)); } + + static inline kdev_t mdp_kdev (mddev_t *mddev, int part) + { + return MKDEV(MDP_MAJOR, mdpminor(mddev)+part); + } + + #define foreach_part(tmp,mddev) \ + if (mdidx(mddev)