lkml.org 
[lkml]   [2003]   [Oct]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectRe: [PATCH] [2.4.23-pre7] Updated Medley Software RAID driver

Thomas,

I can not touch this because I have the SPECs (several versions), however,
adding to the kernel is fine with me. The level of detail you have is a
bit surprizing; however, I will forward this to the folks at SiI. This
will allow me to press the point to release their version or assist you in
yours and Arjan's efforts.

Cheers,

Andre Hedrick
LAD Storage Consulting Group

On Sun, 12 Oct 2003, Thomas Horsten wrote:

> Hi Andre and all,
>
> Here's a new version of my Medley RAID patch. I would like it included in the
> kernel (it is an improvement to the driver already there which fails to
> detect arrays in the correct way and thus misses many), and also for it to be
> tested more widely.
>
> Changes:
>
> - Added support for BLKRRPART ioctl to re-read partition table.
> - Added code from hptraid.c to remove original drive partitions from /proc/
> partitions (so scripts don't try to mount them) and use blkdev_get/blkdev_put
> to prevent losing the underlying block device
> - Fix to work with 2.4.23 (get_info_ptr renamed to ide_info_ptr)
>
> The patch can also be downloaded from my Linux page where you'll also find a
> compatibility list and some precompiled modules etc. This is at
> http://www.infowares.com/linux/
>
> Also, I've started to look at a better way of implementing IDE software
> RAID's, that will work in 2.6. My thought is to use the existing MD framework
> and add extra personalities for these software RAID's. The problem is that
> the BIOS software RAID's are based on whole disks.
>
> I've thought about adding an extra major to the MD framework and use this for
> software RAID's in "whole disk" mode, using the partition table support in
> gendisk. This would add config options "Support whole disk software RAIDs"
> and "Support foreign RAID formats", and during boot the partition table
> handler would call the RAID detection for each of the devices, this would
> give the driver a chance to scan for a software RAID superblock. The devices
> would use the existing RAID0/RAID1 code where possible (this would work for
> Medley RAID, but not Highpoint and others due to the way they handle
> different disk sizes in one array). The MD code would then handle the
> requests and the partition table reckognition would pretend an empty
> partition table for the underlying disks. Unlike the current MD devices there
> would be a /disc device for each of these (it would look much like the
> ataraid driver does in 2.4).
>
> Any comments, ideas and discussion is welcome since I'm ready to start working
> on this.
>
> Thanks in advance :)
>
> And the patch:
>
> diff -u --recursive --new-file linux-2.4.23-pre7/Documentation/Configure.help
> linux-2.4.23-pre7-medley/Documentation/Configure.help
> --- linux-2.4.23-pre7/Documentation/Configure.help 2003-10-12
> 21:30:11.000000000 +0100
> +++ linux-2.4.23-pre7-medley/Documentation/Configure.help 2003-10-12
> 21:31:35.000000000 +0100
> @@ -2074,6 +2074,37 @@
> If you choose to compile this as a module, the module will be called
> hptraid.o.
>
> +CMD/Silicon Image Medley Software RAID
> +CONFIG_BLK_DEV_ATARAID_MEDLEY
> + Say Y or M if you have a Silicon Image 3112 SATA RAID controller, a
> + CMD680 based controller, or another IDE RAID controller that uses
> + CMD's Medley software RAID, and want Linux to use the software RAID
> + feature of this card. This driver uses /dev/ataraid/dXpY (X and Y
> + numbers) as device names. It has been reported to work on a number
> + of systems using the Medley RAID.
> +
> + This driver only supports RAID0 (striped) mode, so if you are using
> + mirroring this will not work for you.
> +
> + You may want to try the Silicon Image Medley Software RAID driver if
> + this does not work for you.
> +
> + If you choose to compile this as a module, the module will be called
> + medley.o.
> +
> +Silicon Image Medley Software RAID
> +CONFIG_BLK_DEV_ATARAID_SII
> + Say Y or M if you have a Silicon Image SATARaid controller
> + and want linux to use the softwareraid feature of this card.
> + This driver uses /dev/ataraid/dXpY (X and Y numbers) as device
> + names.
> +
> + This driver is not working on all systems. Please try the Medley
> + RAID driver instead, which is based on the specifications from CMD.
> +
> + If you choose to compile this as a module, the module will be called
> + silraid.o.
> +
> Support for Acer PICA 1 chipset
> CONFIG_ACER_PICA_61
> This is a machine with a R4400 133/150 MHz CPU. To compile a Linux
> diff -u --recursive --new-file linux-2.4.23-pre7/drivers/ide/Config.in
> linux-2.4.23-pre7-medley/drivers/ide/Config.in
> --- linux-2.4.23-pre7/drivers/ide/Config.in 2003-10-12 21:30:12.000000000
> +0100
> +++ linux-2.4.23-pre7-medley/drivers/ide/Config.in 2003-10-12
> 21:28:28.000000000 +0100
> @@ -222,6 +222,7 @@
> dep_tristate 'Support for IDE Raid controllers (EXPERIMENTAL)'
> CONFIG_BLK_DEV_ATARAID $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL
> dep_tristate ' Support Promise software RAID (Fasttrak(tm)) (EXPERIMENTAL)'
> CONFIG_BLK_DEV_ATARAID_PDC $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL
> $CONFIG_BLK_DEV_ATARAID
> dep_tristate ' Highpoint 370 software RAID (EXPERIMENTAL)'
> CONFIG_BLK_DEV_ATARAID_HPT $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL
> $CONFIG_BLK_DEV_ATARAID
> +dep_tristate ' CMD/Silicon Image Medley Software RAID (EXPERIMENTAL)'
> CONFIG_BLK_DEV_ATARAID_MEDLEY $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL
> $CONFIG_BLK_DEV_ATARAID
> dep_tristate ' Silicon Image Medley software RAID (EXPERIMENTAL)'
> CONFIG_BLK_DEV_ATARAID_SII $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL
> $CONFIG_BLK_DEV_ATARAID
>
> endmenu
> diff -u --recursive --new-file linux-2.4.23-pre7/drivers/ide/raid/Makefile
> linux-2.4.23-pre7-medley/drivers/ide/raid/Makefile
> --- linux-2.4.23-pre7/drivers/ide/raid/Makefile 2003-06-13 15:51:34.000000000
> +0100
> +++ linux-2.4.23-pre7-medley/drivers/ide/raid/Makefile 2003-10-12
> 21:28:28.000000000 +0100
> @@ -12,6 +12,7 @@
> obj-$(CONFIG_BLK_DEV_ATARAID) += ataraid.o
> obj-$(CONFIG_BLK_DEV_ATARAID_PDC) += pdcraid.o
> obj-$(CONFIG_BLK_DEV_ATARAID_HPT) += hptraid.o
> +obj-$(CONFIG_BLK_DEV_ATARAID_MEDLEY) += medley.o
> obj-$(CONFIG_BLK_DEV_ATARAID_SII) += silraid.o
>
> EXTRA_CFLAGS := -I../
> diff -u --recursive --new-file linux-2.4.23-pre7/drivers/ide/raid/medley.c
> linux-2.4.23-pre7-medley/drivers/ide/raid/medley.c
> --- linux-2.4.23-pre7/drivers/ide/raid/medley.c 1970-01-01 01:00:00.000000000
> +0100
> +++ linux-2.4.23-pre7-medley/drivers/ide/raid/medley.c 2003-10-12
> 21:28:51.000000000 +0100
> @@ -0,0 +1,702 @@
> +/*
> + * MEDLEY SOFTWARE RAID DRIVER (Silicon Image 3112 and others)
> + *
> + * Copyright (C) 2003 Thomas Horsten <thomas@horsten.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + * Copyright (C) 2003 Thomas Horsten <thomas@horsten.com>
> + * All Rights Reserved.
> + *
> + * This driver uses the ATA RAID driver framework and is based on
> + * code from Arjan van de Ven's silraid.c and hptraid.c.
> + *
> + * It is a driver for the Medley software RAID, which is used by
> + * some IDE controllers, including the Silicon Image 3112 SATA
> + * controller found onboard many modern motherboards, and the
> + * CMD680 stand-alone PCI RAID controller.
> + *
> + * The author has only tested this on the Silicon Image SiI3112.
> + * If you have any luck using more than 2 drives, and/or more
> + * than one RAID set, and/or any other chip than the SiI3112,
> + * please let me know by sending me mail at the above address.
> + *
> + * Currently, only striped mode is supported for these RAIDs.
> + *
> + * You are welcome to contact me if you have any questions or
> + * suggestions for improvement.
> + *
> + * Change history:
> + *
> + * 20031012 - thomas@horsten.com
> + * Added support for BLKRRPART ioctl to re-read partition table
> + * 20030801 - thomas@horsten.com
> + * First test release
> + *
> + */
> +
> +#include <linux/version.h>
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/sched.h>
> +#include <linux/smp_lock.h>
> +#include <linux/blkdev.h>
> +#include <linux/blkpg.h>
> +#include <linux/genhd.h>
> +#include <linux/ioctl.h>
> +
> +#include <linux/ide.h>
> +#include <asm/uaccess.h>
> +
> +#include "ataraid.h"
> +
> +/*
> + * These options can be tuned if the need should occur.
> + *
> + * Even better, this driver could be changed to allocate the structures
> + * dynamically.
> + */
> +#define MAX_DRIVES_PER_SET 8
> +#define MAX_MEDLEY_ARRAYS 4
> +
> +/*
> + * Define this only if you are debugging the driver.
> + */
> +#define DEBUGGING_MEDLEY 0
> +
> +#if DEBUGGING_MEDLEY
> +#define dprintk(fmt, args...) printk(fmt, ##args)
> +#else
> +#define dprintk(fmt, args...)
> +#endif
> +
> +/*
> + * Medley RAID metadata structure.
> + *
> + * The metadata structure is based on the ATA drive ID from the drive itself,
> + * with the RAID information in the vendor specific regions.
> + *
> + * We do not use all the fields, since we only support Striped Sets.
> + */
> +struct medley_metadata {
> + u8 driveid0[46];
> + u8 ascii_version[8];
> + u8 driveid1[52];
> + u32 total_sectors_low;
> + u32 total_sectors_high;
> + u16 reserved0;
> + u8 driveid2[142];
> + u16 product_id;
> + u16 vendor_id;
> + u16 minor_ver;
> + u16 major_ver;
> + u16 creation_timestamp[3];
> + u16 chunk_size;
> + u16 reserved1;
> + u8 drive_number;
> + u8 raid_type;
> + u8 drives_per_striped_set;
> + u8 striped_set_number;
> + u8 drives_per_mirrored_set;
> + u8 mirrored_set_number;
> + u32 rebuild_ptr_low;
> + u32 rebuild_ptr_high;
> + u32 incarnation_no;
> + u8 member_status;
> + u8 mirrored_set_state;
> + u8 reported_device_location;
> + u8 member_location;
> + u8 auto_rebuild;
> + u8 reserved3[17];
> + u16 checksum;
> +};
> +
> +/*
> + * This struct holds the information about a Medley array
> + */
> +struct medley_array {
> + u8 drives;
> + u16 chunk_size;
> + u32 sectors_per_row;
> + u8 chunk_size_log;
> + u16 present;
> + u16 timestamp[3];
> + u32 sectors;
> + int registered;
> + atomic_t valid;
> + int access;
> +
> + kdev_t members[MAX_DRIVES_PER_SET];
> + struct block_device *bdev[MAX_DRIVES_PER_SET];
> +
> +};
> +static struct medley_array raid[MAX_MEDLEY_ARRAYS];
> +
> +/*
> + * Here we keep the offset of the ATARAID device ID's compared to our
> + * own (this will normally be 0, unless another ATARAID driver has
> + * registered some arrays before us).
> + */
> +static int medley_devid_offset=0;
> +
> +/*
> + * This holds the number of detected arrays.
> + */
> +static int medley_arrays=0;
> +
> +/*
> + * Wait queue for opening device (used when re-reading partition table)
> + */
> +static DECLARE_WAIT_QUEUE_HEAD(medley_wait_open);
> +
> +/*
> + * The interface functions used by the ataraid framework.
> + */
> +static int medley_open(struct inode * inode, struct file * filp);
> +static int medley_release(struct inode * inode, struct file * filp);
> +static int medley_ioctl(struct inode *inode, struct file *file, unsigned int
> cmd, unsigned long arg);
> +static int medley_make_request (request_queue_t *q, int rw, struct
> buffer_head * bh);
> +
> +static struct raid_device_operations medley_ops = {
> + open: medley_open,
> + release: medley_release,
> + ioctl: medley_ioctl,
> + make_request: medley_make_request
> +};
> +
> +/*
> + * This is the list of devices to probe.
> + */
> +static const kdev_t probelist[]= {
> + MKDEV(IDE0_MAJOR, 0),
> + MKDEV(IDE0_MAJOR, 64),
> + MKDEV(IDE1_MAJOR, 0),
> + MKDEV(IDE1_MAJOR, 64),
> + MKDEV(IDE2_MAJOR, 0),
> + MKDEV(IDE2_MAJOR, 64),
> + MKDEV(IDE3_MAJOR, 0),
> + MKDEV(IDE3_MAJOR, 64),
> + MKDEV(IDE4_MAJOR, 0),
> + MKDEV(IDE4_MAJOR, 64),
> + MKDEV(IDE5_MAJOR, 0),
> + MKDEV(IDE5_MAJOR, 64),
> + MKDEV(IDE6_MAJOR, 0),
> + MKDEV(IDE6_MAJOR, 64),
> + MKDEV(0,0)
> +};
> +
> +/*
> + * Handler for ioctl calls to the virtual device
> + */
> +static int medley_ioctl(struct inode *inode, struct file *file, unsigned int
> cmd, unsigned long arg)
> +{
> + unsigned int minor;
> + unsigned long sectors;
> + int devminor = (inode->i_rdev >> SHIFT)&MAJOR_MASK;
> + int device = devminor-medley_devid_offset;
> +
> + dprintk("medley_ioctl\n");
> +
> + if (!inode || !inode->i_rdev)
> + {
> + return -EINVAL;
> + }
> +
> + minor = MINOR(inode->i_rdev)>>SHIFT;
> +
> + switch (cmd) {
> +
> + case BLKGETSIZE: /* Return device size */
> + if (!arg) return -EINVAL;
> + sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
> + dprintk("medley_ioctl: BLKGETSIZE\n");
> + if (MINOR(inode->i_rdev)&15)
> + return put_user(sectors, (unsigned long *) arg);
> + return put_user(raid[minor-medley_devid_offset].sectors, (unsigned long *)
> arg);
> + break;
> +
> + case HDIO_GETGEO:
> + {
> + struct hd_geometry *loc = (struct hd_geometry *) arg;
> + unsigned short bios_cyl = (unsigned short)(raid[minor].sectors/255/63); /*
> truncate */
> +
> + dprintk("medley_ioctl: HDIO_GETGEO\n");
> + if (!loc) return -EINVAL;
> + if (put_user(255, (byte *) &loc->heads)) return -EFAULT;
> + if (put_user(63, (byte *) &loc->sectors)) return -EFAULT;
> + if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
> + if
> (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
> + (unsigned long *) &loc->start)) return -EFAULT;
> + return 0;
> + }
> +
> + case HDIO_GETGEO_BIG:
> + {
> + struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
> +
> + dprintk("medley_ioctl: HDIO_GETGEO_BIG\n");
> + if (!loc) return -EINVAL;
> + if (put_user(255, (byte *) &loc->heads)) return -EFAULT;
> + if (put_user(63, (byte *) &loc->sectors)) return -EFAULT;
> + if (put_user(raid[minor-medley_devid_offset].sectors/255/63, (unsigned int
> *) &loc->cylinders)) return -EFAULT;
> + if
> (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
> + (unsigned long *) &loc->start)) return -EFAULT;
> + return 0;
> + }
> +
> + case BLKROSET:
> + case BLKROGET:
> + case BLKSSZGET:
> + dprintk("medley_ioctl: BLK*\n");
> + return blk_ioctl(inode->i_rdev, cmd, arg);
> +
> + case BLKRRPART: /* Re-read partition tables */
> + if (!capable(CAP_SYS_ADMIN)) return -EACCES;
> + if (minor!=0) return -EINVAL;
> + if (atomic_read(&(raid[device].valid))==0) return -EINVAL;
> +
> + atomic_set(&(raid[device].valid),0);
> + if (raid[device].access != 1)
> + {
> + atomic_set(&(raid[device].valid),1);
> + return -EBUSY;
> + }
> +
> + int partition;
> + for (partition = 15; partition >= 0; partition--) {
> + invalidate_device(MKDEV(ATARAID_MAJOR, partition+devminor), 1);
> + ataraid_gendisk.part[partition+devminor].start_sect = 0;
> + ataraid_gendisk.part[partition+devminor].nr_sects = 0;
> + }
> + ataraid_register_disk(device,raid[device].sectors);
> + atomic_set(&(raid[device].valid),1);
> + wake_up(&medley_wait_open);
> + return 0;
> +
> + default:
> + return -EINVAL;
> + };
> +
> + return 0;
> +}
> +
> +/*
> + * Handler to map a request to the real device.
> + * If the request cannot be made because it spans multiple disks,
> + * we return -1, otherwise we modify the request and return 1.
> + */
> +static int medley_make_request(request_queue_t *q, int rw, struct buffer_head
> * bh)
> +{
> + u8 disk;
> + u32 rsect = bh->b_rsector;
> + int device = ((bh->b_rdev >> SHIFT)&MAJOR_MASK) - medley_devid_offset;
> + struct medley_array *r = raid+device;
> +
> + /* Add the partition offset */
> + rsect = rsect + ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
> +
> + dprintk("medley_make_request, rsect=%ul\n",rsect);
> +
> + /* Detect if the request crosses a chunk barrier */
> + if (r->chunk_size_log)
> + {
> + if ( ((rsect & (r->chunk_size-1)) + (bh->b_size/512)) >
> (1<<r->chunk_size_log))
> + {
> + return -1;
> + }
> + } else {
> + if ((rsect/r->chunk_size) != ((rsect+(bh->b_size/512)-1)/r->chunk_size))
> + {
> + return -1;
> + }
> + }
> +
> + /*
> + * Medley arrays are simple enough, since the smallest disk decides the
> + * number of sectors used per disk. So there is no need for the cutoff
> + * magic found in other drivers like hptraid.
> + */
> + if (r->chunk_size_log)
> + {
> + /* We save some expensive operations (1 div, 1 mul, 1 mod), if the chunk
> + * size is a power of 2, which is the normal case.
> + */
> + disk = (rsect >> r->chunk_size_log) % r->drives;
> + rsect = ((rsect / r->sectors_per_row) << r->chunk_size_log) + (rsect &
> (r->chunk_size-1));
> + }
> + else
> + {
> + disk = (rsect / r->chunk_size) % r->drives;
> + rsect = rsect / r->sectors_per_row * r->chunk_size + rsect % r->chunk_size;
> + }
> +
> + dprintk("medley_make_request :-), disk=%d, rsect=%ul\n",disk,rsect);
> + bh->b_rdev = r->members[disk];
> + bh->b_rsector = rsect;
> + return 1;
> +}
> +
> +/*
> + * Find out which array a drive belongs to, and add it to that array.
> + * If it is not a member of a detected array, add a new array for it.
> + */
> +void medley_add_raiddrive(kdev_t dev, struct medley_metadata *md)
> +{
> + dprintk("Candidate drive %02x:%02x - drive %d of %d, stride %d, sectors %ul
> (%d MB)\n",
> +
> MAJOR(dev),MINOR(dev),md->drive_number,md->drives_per_striped_set,md->chunk_size,md->total_sectors_low,md->total_sectors_low/1024/1024/2);
> +
> + int c;
> + for (c=0; c<medley_arrays; c++)
> + {
> + if ( (raid[c].timestamp[0]==md->creation_timestamp[0]) &&
> + (raid[c].timestamp[1]==md->creation_timestamp[1]) &&
> + (raid[c].timestamp[2]==md->creation_timestamp[2]) &&
> + (raid[c].drives==md->drives_per_striped_set) &&
> + (raid[c].chunk_size==md->chunk_size) &&
> + ((raid[c].present & (1<<md->drive_number)) == 0) )
> + {
> + dprintk("Existing array %d\n", c);
> + raid[c].present |= (1 << md->drive_number);
> + raid[c].members[md->drive_number]=dev;
> + break;
> + }
> + }
> + if (c==medley_arrays)
> + {
> + dprintk("New array %d\n",medley_arrays);
> + if (medley_arrays==MAX_MEDLEY_ARRAYS)
> + {
> + printk(KERN_ERR "Medley RAID: Too many RAID sets detected - you can change
> the max in the driver.\n");
> + }
> + else
> + {
> + raid[c].timestamp[0]=md->creation_timestamp[0];
> + raid[c].timestamp[1]=md->creation_timestamp[1];
> + raid[c].timestamp[2]=md->creation_timestamp[2];
> + raid[c].drives=md->drives_per_striped_set;
> + raid[c].chunk_size=md->chunk_size;
> + raid[c].sectors_per_row=md->chunk_size*md->drives_per_striped_set;
> +
> + /* Speedup if chunk size is a power of 2 */
> + if ( ((raid[c].chunk_size-1) & (raid[c].chunk_size)) == 0)
> + {
> + raid[c].chunk_size_log = ffs(raid[c].chunk_size)-1;
> + }
> + else
> + {
> + raid[c].chunk_size_log = 0;
> + }
> + raid[c].present=(1<<md->drive_number);
> + raid[c].members[md->drive_number]=dev;
> + if (md->major_ver == 1)
> + {
> + raid[c].sectors=((u32 *)(md))[27];
> + }
> + else
> + {
> + raid[c].sectors=md->total_sectors_low;
> + }
> + medley_arrays++;
> + }
> + }
> +}
> +
> +/*
> + * Read the Medley metadata from a drive.
> + * Returns the bh if it was found, otherwise NULL.
> + */
> +struct buffer_head *medley_get_metadata(kdev_t dev)
> +{
> + struct buffer_head *bh = NULL;
> +
> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,23)
> + ide_drive_t *drvinfo = ide_info_ptr(dev, 0);
> +#else
> + ide_drive_t *drvinfo = get_info_ptr(dev, 0);
> +#endif
> + if ((drvinfo==NULL) || drvinfo->capacity<1)
> + {
> + return NULL;
> + }
> +
> + dprintk("Probing %02x:%02x\n",MAJOR(dev),MINOR(dev));
> + /* If this drive is not on a PCI controller, it is not Medley RAID.
> + * Medley matches the PCI device ID with the metadata to check if it is
> valid. */
> + struct pci_dev *pcidev = drvinfo->hwif?drvinfo->hwif->pci_dev:NULL;
> + if (!pcidev)
> + {
> + return NULL;
> + }
> +
> + /*
> + * 4 copies of the metadata exist, in the following 4 sectors:
> + * last, last-0x200, last-0x400, last-0x600.
> + *
> + * We must try each of these in order, until we find the metadata.
> + * FIXME: This does not take into account drives with 48/64-bit LBA
> addressing,
> + * even though the Medley RAID version 2 supports these.
> + */
> + u32 lba=drvinfo->capacity-1;
> + int pos;
> + for (pos=0; pos<4; pos++,lba-=0x200)
> + {
> + bh = bread(dev, lba, 512);
> + if (!bh)
> + {
> + printk(KERN_ERR "Medley RAID (%02x:%02x): Error reading metadata (lba=%d)
> \n", MAJOR(dev),MINOR(dev),lba);
> + break;
> + }
> +
> + /* A valid Medley RAID has the PCI vendor/device ID of its IDE controller,
> + * and the correct checksum. */
> + struct medley_metadata *md = (void *)(bh->b_data);
> +
> + if (pcidev->vendor == md->vendor_id && pcidev->device == md->product_id)
> + {
> + u16 checksum=0;
> + u16 *p = (void *)(bh->b_data);
> + int c;
> + for (c=0; c<160; c++)
> + {
> + checksum += *p++;
> + }
> + dprintk("Probing %02x:%02x csum=%d, major_ver=%d
> \n",MAJOR(dev),MINOR(dev),checksum,md->major_ver);
> + if (((checksum == 0xffff) && (md->major_ver == 1)) || (checksum == 0))
> + {
> + dprintk("Probing %02x:%02x VALID\n",MAJOR(dev),MINOR(dev));
> + /* Found a valid block */
> + break;
> + }
> + }
> + /* Was not a valid superblock */
> + if (bh)
> + {
> + brelse(bh);
> + bh=NULL;
> + }
> + }
> + return bh;
> +}
> +
> +/*
> + * Determine if this drive belongs to a Medley array.
> + */
> +static void medley_probe_drive(int major, int minor)
> +{
> + struct buffer_head *bh;
> + kdev_t dev = MKDEV(major,minor);
> +
> + bh=medley_get_metadata(dev);
> + if (!bh)
> + return;
> +
> + struct medley_metadata *md = (void *)(bh->b_data);
> +
> + if (md->raid_type != 0x0)
> + {
> + printk(KERN_INFO "Medley RAID (%02x:%02x): Sorry, this driver currently
> only supports striped sets (RAID level 0).\n",
> + major,minor);
> + }
> + else if (md->major_ver == 2 && md->total_sectors_high != 0)
> + {
> + printk(KERN_ERR "Medley RAID (%02x:%02x): Sorry, the driver only supports
> 32 bit LBA disks (disk too big).\n",
> + major,minor);
> + }
> + else if (md->major_ver > 0 && md->major_ver > 2)
> + {
> + printk(KERN_INFO "Medley RAID (%02x:%02x): Unsupported version (%d.%d) -
> this driver supports version 1.x and 2.x\n",
> + major,minor,md->major_ver,md->minor_ver);
> + }
> + else if (md->drives_per_striped_set > MAX_DRIVES_PER_SET)
> + {
> + printk(KERN_ERR "Medley RAID (%02x:%02x): Striped set too large (%d drives)
> - please report this and change max in driver.\n",
> + major,minor,md->drives_per_striped_set);
> + }
> + else if ((md->drive_number > md->drives_per_striped_set) ||
> + (md->drives_per_striped_set<1) ||
> + (md->chunk_size < 1))
> + {
> + printk(KERN_ERR "Medley RAID (%02x:%02x): Metadata appears to be corrupt.
> \n",
> + major,minor);
> + }
> + else
> + {
> + /* We have a good candidate, put it in the correct array */
> + medley_add_raiddrive(dev,md);
> + }
> +
> + if (bh)
> + {
> + brelse(bh);
> + }
> +}
> +
> +/*
> + * Initialise the driver.
> + */
> +static __init int medley_init(void)
> +{
> + int c;
> +
> + memset(raid, 0, MAX_MEDLEY_ARRAYS*sizeof(struct medley_array));
> +
> + /* Probe each of the drives on our list */
> + for (c=0; probelist[c] != MKDEV(0,0); c++)
> + {
> + medley_probe_drive(MAJOR(probelist[c]),MINOR(probelist[c]));
> + }
> +
> + /* Check if the detected sets are complete */
> + for (c=0; c<medley_arrays; c++)
> + {
> + if (raid[c].present != (1<<raid[c].drives)-1)
> + {
> + printk(KERN_ERR "Medley RAID: Incomplete RAID set deleted - disks:");
> + int d;
> + for (d=0; c<raid[c].drives; c++)
> + {
> + if (raid[c].present & (1<<d))
> + {
> + printk(" %02x:%02x", MAJOR(raid[c].members[d]),
> MINOR(raid[c].members[d]));
> + }
> + }
> + printk("\n");
> + /* Delete it */
> + if (c+1<medley_arrays) {
> + memmove(raid+c+1,raid+c,(medley_arrays-c-1)*sizeof(struct medley_array));
> + }
> + medley_arrays--;
> + }
> + }
> +
> + /* Register any remaining array(s) */
> + for (c=0; c<medley_arrays; c++)
> + {
> + int device=ataraid_get_device(&medley_ops);
> + if (device<0) {
> + printk(KERN_ERR "Medley RAID: Could not get ATARAID device.\n");
> + break;
> + }
> + if (c==0)
> + {
> + /* First array, compute offset to our device ID's */
> + medley_devid_offset=device;
> + dprintk("Medley_devid_offset: %d\n",medley_devid_offset);
> + }
> + else if (device-medley_devid_offset != medley_arrays)
> + {
> + printk(KERN_ERR "Medley RAID: ATARAID gave us an illegal device ID.\n");
> + ataraid_release_device(device);
> + break;
> + }
> +
> + printk(KERN_INFO "Medley RAID: Striped set %d consists of %d disks, total %
> dMB - disks:",
> + c, raid[c].drives,raid[c].sectors/1024/1024/2);
> + int d;
> + for (d=0; d<raid[c].drives; d++)
> + {
> + printk(" %02x:%02x", MAJOR(raid[c].members[d]),
> MINOR(raid[c].members[d]));
> +
> + /* Taken from hptraid.c, this is supposed
> + * to prevent the device from disappearing
> + * from under us */
> + struct block_device *bdev;
> + struct gendisk *gd;
> + bdev = bdget(raid[c].members[d]);
> + if (bdev && blkdev_get(bdev,FMODE_READ|FMODE_WRITE,0,BDEV_RAW) == 0) {
> + raid[c].bdev[d] = bdev;
> + /*
> + * This is supposed to prevent others from stealing our
> + * underlying disks now blank the /proc/partitions table for
> + * the wrong partition table, so that scripts don't
> + * accidentally mount it and crash the kernel
> + */
> + /* XXX: the 0 is an utter hack --hch */
> + gd=get_gendisk(MKDEV(MAJOR(raid[c].members[d]), 0));
> + if (gd!=NULL) {
> + if (gd->major==MAJOR(raid[c].members[d])) {
> + int minor=MINOR(raid[c].members[d]);
> + int j;
> + for (j=1+(minor<<gd->minor_shift);
> + j<((minor+1)<<gd->minor_shift);
> + j++) gd->part[j].nr_sects=0;
> + }
> + }
> + }
> + raid[c].bdev[d] = bdev;
> + }
> + printk("\n");
> + raid[c].registered=1;
> + atomic_set(&(raid[c].valid),1);
> + ataraid_register_disk(c,raid[c].sectors);
> + }
> +
> + if (medley_arrays > 0)
> + {
> + printk(KERN_INFO "Medley RAID: %d active RAID set%s
> \n",medley_arrays,medley_arrays==1?"":"s");
> + return 0;
> + }
> +
> + printk(KERN_INFO "Medley RAID: No usable RAID sets found\n");
> + return -ENODEV;
> +}
> +
> +static void __exit medley_exit (void)
> +{
> + int device,d;
> + for (device = 0; device<medley_arrays; device++) {
> + for (d=0; d<raid[device].drives; d++)
> + {
> + if (raid[device].bdev[d]) {
> + blkdev_put(raid[device].bdev[d], BDEV_RAW);
> + raid[device].bdev[d]=NULL;
> + }
> + }
> + if (raid[device].registered) {
> + ataraid_release_device(device+medley_devid_offset);
> + raid[device].registered=0;
> + }
> + }
> +}
> +
> +static int medley_open(struct inode * inode, struct file * filp)
> +{
> + dprintk("medley_open\n");
> +
> + int device = ((inode->i_rdev >> SHIFT)&MAJOR_MASK) - medley_devid_offset;
> +
> + if (device < medley_arrays)
> + {
> + while (!atomic_read(&(raid[device].valid)))
> + sleep_on(&medley_wait_open);
> + raid[device].access++;
> + MOD_INC_USE_COUNT;
> + return (0);
> + }
> + return -ENODEV;
> +}
> +
> +static int medley_release(struct inode * inode, struct file * filp)
> +{
> + int device = ((inode->i_rdev >> SHIFT)&MAJOR_MASK) - medley_devid_offset;
> + dprintk("medley_release\n");
> + raid[device].access--;
> + MOD_DEC_USE_COUNT;
> + return 0;
> +}
> +
> +module_init(medley_init);
> +module_exit(medley_exit);
> +MODULE_LICENSE("GPL");
>

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:49    [W:0.125 / U:0.140 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site