public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] 2.4.x Linux Medley RAID Version 7
@ 2004-03-10 13:07 Thomas Horsten
  2004-03-10 14:39 ` Bartlomiej Zolnierkiewicz
  0 siblings, 1 reply; 10+ messages in thread
From: Thomas Horsten @ 2004-03-10 13:07 UTC (permalink / raw)
  To: andre, arjanv, linux-kernel

[-- Attachment #1: Type: TEXT/PLAIN, Size: 813 bytes --]

I'll submit this again in the hope that it will be included.

This patch adds generic support for Medley RAID0 ataraid. It has been
used over the last 7 months by a large number of people, without any
reports of problems that could be traced back to this patch.

This latest version fixes a problem when compiling with pre-3.0 gcc.

The patch supports the BIOS-assisted software RAID used, among others, by
Silicon Image and CMD680 RAID PCI-cards and on-chip controllers.

The patch has also been included in a number of custom kernels, including
Debian's kernel-source-2.4.25.

History and comments are available here: http://www.infowares.com/linux/

I am working on a RAID-detect utility for 2.6, that will run from
initramfs or initrd and use the dm framework. More information on the
above site.

// Thomas


[-- Attachment #2: Type: TEXT/PLAIN, Size: 24741 bytes --]

diff -urN linux-2.4.25/Documentation/Configure.help linux-2.4.25.th-medley/Documentation/Configure.help
--- linux-2.4.25/Documentation/Configure.help	Wed Feb 18 13:36:30 2004
+++ linux-2.4.25.th-medley/Documentation/Configure.help	Wed Mar 10 11:06:06 2004
@@ -2085,6 +2085,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 -urN linux-2.4.25/drivers/ide/Config.in linux-2.4.25.th-medley/drivers/ide/Config.in
--- linux-2.4.25/drivers/ide/Config.in	Wed Feb 18 13:36:31 2004
+++ linux-2.4.25.th-medley/drivers/ide/Config.in	Wed Mar 10 11:06:07 2004
@@ -190,6 +190,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 -urN linux-2.4.25/drivers/ide/raid/Makefile linux-2.4.25.th-medley/drivers/ide/raid/Makefile
--- linux-2.4.25/drivers/ide/raid/Makefile	Fri Jun 13 15:51:34 2003
+++ linux-2.4.25.th-medley/drivers/ide/raid/Makefile	Wed Mar 10 11:06:07 2004
@@ -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 -urN linux-2.4.25/drivers/ide/raid/medley.c linux-2.4.25.th-medley/drivers/ide/raid/medley.c
--- linux-2.4.25/drivers/ide/raid/medley.c	Thu Jan  1 01:00:00 1970
+++ linux-2.4.25.th-medley/drivers/ide/raid/medley.c	Wed Mar 10 11:21:50 2004
@@ -0,0 +1,704 @@
+/*
+ * 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;
+	int partition;
+
+	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;
+		}
+
+		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)
+{
+	int c;
+
+	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);
+
+	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;
+	struct pci_dev *pcidev;
+	u32 lba;
+	int pos;
+	struct medley_metadata *md;
+
+#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);
+#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. */
+	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.
+	 */
+	lba=drvinfo->capacity-1;
+	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. */
+		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);
+	struct medley_metadata *md;
+
+	bh=medley_get_metadata(dev);
+	if (!bh)
+		return;
+
+	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,d;
+	struct block_device *bdev;
+	struct gendisk *gd;
+	
+	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:");
+			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);
+		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 */
+			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) 
+{
+	int device = ((inode->i_rdev >> SHIFT)&MAJOR_MASK) - medley_devid_offset;
+	dprintk("medley_open\n");
+
+	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");

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2004-03-10 22:08 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-03-10 13:07 [PATCH] 2.4.x Linux Medley RAID Version 7 Thomas Horsten
2004-03-10 14:39 ` Bartlomiej Zolnierkiewicz
2004-03-10 15:19   ` Thomas Horsten
2004-03-10 16:07     ` Bartlomiej Zolnierkiewicz
2004-03-10 16:29       ` Thomas Horsten
2004-03-10 16:46       ` Christoph Hellwig
2004-03-10 20:11       ` Thomas Horsten
2004-03-10 20:49         ` Miquel van Smoorenburg
2004-03-10 20:56           ` Jeff Garzik
2004-03-10 22:14         ` Bartlomiej Zolnierkiewicz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox