patch-2.4.22 linux-2.4.22/drivers/ide/raid/hptraid.c

Next file: linux-2.4.22/drivers/ide/setup-pci.c
Previous file: linux-2.4.22/drivers/ide/pci/via82cxxx.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.21/drivers/ide/raid/hptraid.c linux-2.4.22/drivers/ide/raid/hptraid.c
@@ -17,7 +17,30 @@
 	Copyright (C) 1994-96 Marc ZYNGIER <zyngier@ufr-info-p7.ibp.fr>
    Based on work done by Søren Schmidt for FreeBSD
 
-   
+   Changelog:
+   15.06.2003 wweissmann@gmx.at
+   	* correct values of raid-1 superbock
+	* re-add check for availability of all disks
+	* fix offset bug in raid-1 (introduced in raid 0+1 implementation)
+
+   14.06.2003 wweissmann@gmx.at
+   	* superblock has wrong "disks" value on raid-1
+   	* fixup for raid-1 disknumbering
+	* do _NOT_ align size to 255*63 boundary
+		I WILL NOT USE FDISK TO DETERMINE THE VOLUME SIZE.
+		I WILL NOT USE FDISK TO DETERMINE THE VOLUME SIZE.
+		I WILL NOT USE FDISK TO DETERMINE THE VOLUME SIZE.
+		I WILL NOT ...
+
+   13.06.2003 wweissmann@gmx.at
+   	* raid 0+1 support
+	* check if all disks of an array are available
+	* bump version number
+
+   29.05.2003 wweissmann@gmx.at
+   	* release no more devices than available on unload
+	* remove static variables in raid-1 read path
+
 */
 
 #include <linux/module.h>
@@ -34,6 +57,8 @@
 #include <asm/uaccess.h>
 
 #include "ataraid.h"
+#include "hptraid.h"
+
 
 static int hptraid_open(struct inode * inode, struct file * filp);
 static int hptraid_release(struct inode * inode, struct file * filp);
@@ -41,26 +66,30 @@
 static int hptraidspan_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
 static int hptraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
 static int hptraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+static int hptraid01_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
 
 
 
 struct hptdisk {
-	kdev_t	device;
+	kdev_t	device;		/* disk-ID/raid 0+1 volume-ID */
 	unsigned long sectors;
 	struct block_device *bdev;
 	unsigned long last_pos;
 };
 
 struct hptraid {
-	unsigned int stride;
-	unsigned int disks;
-	unsigned long sectors;
+	unsigned int stride;	/* stripesize */
+	unsigned int disks;	/* number of disks in array */
+	unsigned long sectors;	/* disksize in sectors */
         u_int32_t magic_0;
+        u_int32_t magic_1;
 	struct geom geom;
 	
+	int previous;		/* most recently accessed disk in mirror */
 	struct hptdisk disk[8];
-	unsigned long cutoff[8];
+	unsigned long cutoff[8];	/* raid 0 cutoff */
 	unsigned int cutoff_disks[8];	
+	struct hptraid * raid01;	/* sub arrays for raid 0+1 */
 };
 
 struct hptraid_dev {
@@ -109,9 +138,30 @@
 	make_request:		hptraid1_make_request
 };
 
+
+static struct raid_device_operations hptraid01_ops = {
+	open:                   hptraid_open,
+	release:                hptraid_release,
+	ioctl:			hptraid_ioctl,
+	make_request:		hptraid01_make_request
+};
+
+static __init struct {
+	struct raid_device_operations *op;
+	u_int8_t type;
+	char label[8];
+} oplist[] = {
+	{&hptraid0_ops, HPT_T_RAID_0, "RAID 0"},
+	{&hptraid1_ops, HPT_T_RAID_1, "RAID 1"},
+	{&hptraidspan_ops, HPT_T_SPAN, "SPAN"},
+	{&hptraid01_ops, HPT_T_RAID_01_RAID_0, "RAID 0+1"},
+	{0, 0}
+};
+
 static struct hptraid raid[14];
 
-static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int hptraid_ioctl(struct inode *inode, struct file *file,
+		unsigned int cmd, unsigned long arg)
 {
 	unsigned int minor;
 	unsigned char val;
@@ -185,7 +235,10 @@
 	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
 	thisraid = &raid[device];
 
-	/* Partitions need adding of the start sector of the partition to the requested sector */
+	/*
+	 * Partitions need adding of the start sector of the partition to the
+	 * requested sector
+	 */
 	
 	rsect += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
 
@@ -216,58 +269,58 @@
 	return 1;
 }
 
-static int hptraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+static int hptraid0_compute_request (struct hptraid *thisraid,
+		request_queue_t *q,
+		int rw, struct buffer_head * bh)
 {
-	unsigned long rsect;
 	unsigned long rsect_left,rsect_accum = 0;
 	unsigned long block;
 	unsigned int disk=0,real_disk=0;
 	int i;
-	int device;
-	struct hptraid *thisraid;
-
-	rsect = bh->b_rsector;
 
-	/* Ok. We need to modify this sector number to a new disk + new sector number. 
+	/* Ok. We need to modify this sector number to a new disk + new sector
+	 * number. 
 	 * If there are disks of different sizes, this gets tricky. 
 	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
 	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
-	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
-	 * and the last 1Gb is disk 3 only.
+	 * Then things get interesting. The next 2Gb (RAID view) are spread
+	 * across disk 2 and 3 and the last 1Gb is disk 3 only.
 	 *
-	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
-	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
-	 * point, we have to divide by one less.
+	 * the way this is solved is like this: We have a list of "cutoff"
+	 * points where everytime a disk falls out of the "higher" count, we
+	 * mark the max sector. So once we pass a cutoff point, we have to
+	 * divide by one less.
 	 */
 	
-	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
-	thisraid = &raid[device];
 	if (thisraid->stride==0)
 		thisraid->stride=1;
 
-	/* Partitions need adding of the start sector of the partition to the requested sector */
-	
-	rsect += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
-
-	/* Woops we need to split the request to avoid crossing a stride barrier */
-	if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
+	/*
+	 * Woops we need to split the request to avoid crossing a stride
+	 * barrier
+	 */
+	if ((bh->b_rsector/thisraid->stride) !=
+			((bh->b_rsector+(bh->b_size/512)-1)/thisraid->stride)) {
 		return -1;
 	}
 			
-	rsect_left = rsect;
+	rsect_left = bh->b_rsector;;
 	
 	for (i=0;i<8;i++) {
 		if (thisraid->cutoff_disks[i]==0)
 			break;
-		if (rsect > thisraid->cutoff[i]) {
+		if (bh->b_rsector > thisraid->cutoff[i]) {
 			/* we're in the wrong area so far */
 			rsect_left -= thisraid->cutoff[i];
-			rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
+			rsect_accum += thisraid->cutoff[i] /
+				thisraid->cutoff_disks[i];
 		} else {
 			block = rsect_left / thisraid->stride;
 			disk = block % thisraid->cutoff_disks[i];
-			block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
-			rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
+			block = (block / thisraid->cutoff_disks[i]) *
+				thisraid->stride;
+			bh->b_rsector = rsect_accum +
+				(rsect_left % thisraid->stride) + block;
 			break;
 		}
 	}
@@ -286,7 +339,7 @@
 	
 	/* All but the first disk have a 10 sector offset */
 	if (i>0)
-		rsect+=10;
+		bh->b_rsector+=10;
 		
 	
 	/*
@@ -295,7 +348,6 @@
 	 */
 	 
 	bh->b_rdev = thisraid->disk[disk].device;
-	bh->b_rsector = rsect;
 
 	/*
 	 * Let the main block layer submit the IO and resolve recursion:
@@ -303,12 +355,39 @@
 	return 1;
 }
 
+static int hptraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	unsigned long rsect;
+	int device;
+
+	/*
+	 * save the sector, it must be restored before a request-split
+	 * is performed
+	 */
+	rsect = bh->b_rsector;
+
+	/*
+	 * Partitions need adding of the start sector of the partition to the
+	 * requested sector
+	 */
+	
+	bh->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
+
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	if( hptraid0_compute_request(raid+device, q, rw, bh) != 1 ) {
+			/* request must be split => restore sector */
+		bh->b_rsector = rsect;
+		return -1;
+	}
+
+	return 1;
+}
+
 static int hptraid1_read_request (request_queue_t *q, int rw, struct buffer_head * bh)
 {
 	int device;
 	int dist;
 	int bestsofar,bestdist,i;
-	static int previous;
 
 	/* Reads are simple in principle. Pick a disk and go. 
 	   Initially I cheat by just picking the one which the last known
@@ -331,11 +410,15 @@
 			dist = -dist;
 		if (dist>4095)
 			dist=4095;
-		
-		if (bestdist==dist) {  /* it's a tie; try to do some read balancing */
-			if ((previous>bestsofar)&&(previous<=i))  
+
+		  /* it's a tie; try to do some read balancing */
+		if (bestdist==dist) {
+			if ( (raid[device].previous>bestsofar) &&
+					(raid[device].previous<=i) )  
 				bestsofar = i;
-			previous = (previous + 1) % raid[device].disks;
+			raid[device].previous =
+				(raid[device].previous + 1) %
+				raid[device].disks;
 		} else if (bestdist>dist) {
 			bestdist = dist;
 			bestsofar = i;
@@ -343,7 +426,6 @@
 	
 	}
 	
-	bh->b_rsector += bestsofar?10:0;
 	bh->b_rdev = raid[device].disk[bestsofar].device; 
 	raid[device].disk[bestsofar].last_pos = bh->b_rsector+(bh->b_size>>9);
 
@@ -377,24 +459,49 @@
 		if (!bh1)
 			BUG();
 	
-		/* dupe the bufferhead and update the parts that need to be different */
+		/*
+		 * dupe the bufferhead and update the parts that need to be
+		 * different
+		 */
 		memcpy(bh1, bh, sizeof(*bh));
 		
 		bh1->b_end_io = ataraid_end_request;
 		bh1->b_private = private;
-		bh1->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect+(i==0?0:10); /* partition offset */
+		bh1->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect; /* partition offset */
 		bh1->b_rdev = raid[device].disk[i].device;
 
 		/* update the last known head position for the drive */
 		raid[device].disk[i].last_pos = bh1->b_rsector+(bh1->b_size>>9);
 
+		if( raid[device].raid01 ) {
+			if( hptraid0_compute_request(
+						raid[device].raid01 +
+							(bh1->b_rdev-1),
+						q, rw, bh1) != 1 ) {
+				/*
+				 * If a split is requested then it is requested
+				 * in the first iteration. This is true because
+				 * of the cutoff is not used in raid 0+1.
+				 */
+				if(unlikely(i)) {
+					BUG();
+				}
+				else {
+					kfree(private);
+					return -1;
+				}
+			}
+		}
 		generic_make_request(rw,bh1);
 	}
 	return 0;
 }
 
 static int hptraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh) {
-	/* Read and Write are totally different cases; split them totally here */
+	/*
+	 * Read and Write are totally different cases; split them totally
+	 * here
+	 */
 	if (rw==READA)
 		rw = READ;
 	
@@ -404,7 +511,43 @@
 		return hptraid1_write_request(q,rw,bh);
 }
 
-#include "hptraid.h"
+static int hptraid01_read_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	int rsector=bh->b_rsector;
+	int rdev=bh->b_rdev;
+
+		/* select mirror volume */
+	hptraid1_read_request(q, rw, bh);
+
+		/* stripe volume is selected by "bh->b_rdev" */
+	if( hptraid0_compute_request(
+				raid[(bh->b_rdev >> SHIFT)&MAJOR_MASK].
+					raid01 + (bh->b_rdev-1) ,
+				q, rw, bh) != 1 ) {
+
+			/* request must be split => restore sector and device */
+		bh->b_rsector = rsector;
+		bh->b_rdev = rdev;
+		return -1;
+
+	}
+
+	return 1;
+}
+
+static int hptraid01_make_request (request_queue_t *q, int rw, struct buffer_head * bh) {
+	/*
+	 * Read and Write are totally different cases; split them totally
+	 * here
+	 */
+	if (rw==READA)
+		rw = READ;
+	
+	if (rw==READ)
+		return hptraid01_read_request(q,rw,bh);
+	else
+		return hptraid1_write_request(q,rw,bh);
+}
 
 static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
 {
@@ -456,77 +599,140 @@
 	return lba;
 }
 
-static void __init probedisk(struct hptraid_dev *disk, int device, u_int8_t type)
+static void writeentry(struct hptraid * raid, struct hptraid_dev * disk,
+		int index, struct highpoint_raid_conf * prom) {
+
+	int j=0;
+	struct gendisk *gd;
+	struct block_device *bdev;
+
+	bdev = bdget(MKDEV(disk->major,disk->minor));
+	if (bdev && blkdev_get(bdev,FMODE_READ|FMODE_WRITE,0,BDEV_RAW) == 0) {
+		raid->disk[index].bdev = 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(disk->major, 0));
+		if (gd!=NULL) {
+ 			if (gd->major==disk->major)
+ 				for (j=1+(disk->minor<<gd->minor_shift);
+					j<((disk->minor+1)<<gd->minor_shift);
+					j++) gd->part[j].nr_sects=0;					
+		}
+        }
+	raid->disk[index].device = MKDEV(disk->major,disk->minor);
+	raid->disk[index].sectors = maxsectors(disk->major,disk->minor);
+	raid->stride = (1<<prom->raid0_shift);
+	raid->disks = prom->raid_disks;
+	raid->sectors = prom->total_secs;
+	raid->sectors += raid->sectors&1?1:0;
+	raid->magic_0=prom->magic_0;
+	raid->magic_1=prom->magic_1;
+
+}
+
+static int probedisk(struct hptraid_dev *disk, int device, u_int8_t type)
 {
-	int i;
+	int i, j;
         struct highpoint_raid_conf *prom;
 	static unsigned char block[4096];
-	struct block_device *bdev;
 	
  	if (disk->device != -1)	/* disk is occupied? */
- 		return;
+ 		return 0;
  
  	if (maxsectors(disk->major,disk->minor)==0)
-		return;
+		return 0;
 	
         if (read_disk_sb(disk->major,disk->minor,(unsigned char*)&block,sizeof(block)))
-        	return;
+        	return 0;
                                                                                                                  
         prom = (struct highpoint_raid_conf*)&block[512];
                 
         if (prom->magic!=  0x5a7816f0)
-        	return;
+        	return 0;
         switch (prom->type) {
 		case HPT_T_SPAN:
 		case HPT_T_RAID_0:
 		case HPT_T_RAID_1:
+		case HPT_T_RAID_01_RAID_0:
 			if(prom->type != type)
-				return;
+				return 0;
 			break;
 		default:
-			printk(KERN_INFO "hptraid: only SPAN, RAID0 and RAID1 is currently supported \n");
-			return;
+			printk(KERN_INFO "hptraid: unknown raid level-id %i\n",
+					prom->type);
+			return 0;
         }
 
  		/* disk from another array? */
- 	if(raid[device].disks && prom->magic_0 != raid[device].magic_0)
- 		return;
+	if (raid[device].disks) {	/* only check if raid is not empty */
+		if (type == HPT_T_RAID_01_RAID_0 ) {
+			if( prom->magic_1 != raid[device].magic_1) {
+				return 0;
+			}
+		}
+		else if (prom->magic_0 != raid[device].magic_0) {
+				return 0;
+		}
+	}
 
 	i = prom->disk_number;
 	if (i<0)
-		return;
+		return 0;
 	if (i>8) 
-		return;
+		return 0;
 
-	bdev = bdget(MKDEV(disk->major,disk->minor));
-	if (bdev && blkdev_get(bdev,FMODE_READ|FMODE_WRITE,0,BDEV_RAW) == 0) {
-        	int j=0;
-        	struct gendisk *gd;
-		raid[device].disk[i].bdev = 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(disk->major, 0));
-		if (gd!=NULL) {
- 			if (gd->major==disk->major)
- 				for (j=1+(disk->minor<<gd->minor_shift);
-					j<((disk->minor+1)<<gd->minor_shift);
-					j++) gd->part[j].nr_sects=0;					
+	if ( type == HPT_T_RAID_01_RAID_0 ) {
+
+			/* allocate helper raid devices for level 0+1 */
+		if (raid[device].raid01 == NULL ) {
+
+			raid[device].raid01=
+				kmalloc(2 * sizeof(struct hptraid),GFP_KERNEL);
+			if ( raid[device].raid01 == NULL ) {
+				printk(KERN_ERR "hptraid: out of memory\n");
+				raid[device].disks=-1;
+				return -ENOMEM;
+			}
+			memset(raid[device].raid01, 0,
+					2 * sizeof(struct hptraid));
 		}
-        }
-	raid[device].disk[i].device = MKDEV(disk->major,disk->minor);
-	raid[device].disk[i].sectors = maxsectors(disk->major,disk->minor);
-	raid[device].stride = (1<<prom->raid0_shift);
-	raid[device].disks = prom->raid_disks;
-	raid[device].sectors = prom->total_secs-(prom->total_secs%(255*63));
-	raid[device].sectors += raid[device].sectors&1?1:0;
-	raid[device].magic_0=prom->magic_0;
+
+			/* find free sub-stucture */
+		for (j=0; j<2; j++) {
+			if ( raid[device].raid01[j].disks == 0 ||
+			     raid[device].raid01[j].magic_0 == prom->magic_0 )
+			{
+				writeentry(raid[device].raid01+j, disk,
+						i, prom);
+				break;
+			}
+		}
+
+			/* no free slot */
+		if(j == 2)
+			return 0;
+
+		raid[device].stride=raid[device].raid01[j].stride;
+		raid[device].disks=j+1;
+		raid[device].sectors=raid[device].raid01[j].sectors;
+		raid[device].disk[j].sectors=raid[device].raid01[j].sectors;
+		raid[device].magic_1=prom->magic_1;
+	}
+	else {
+		writeentry(raid+device, disk, i, prom);
+	}
+
 	disk->device=device;
 			
+	return 1;
 }
 
-static void __init fill_cutoff(int device)
+static void fill_cutoff(struct hptraid * device)
 {
 	int i,j;
 	unsigned long smallest;
@@ -537,111 +743,154 @@
 	for (i=0;i<8;i++) {
 		smallest = ~0;
 		for (j=0;j<8;j++) 
-			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
-				smallest = raid[device].disk[j].sectors;
+			if ((device->disk[j].sectors < smallest) && (device->disk[j].sectors>bar))
+				smallest = device->disk[j].sectors;
 		count = 0;
 		for (j=0;j<8;j++) 
-			if (raid[device].disk[j].sectors >= smallest)
+			if (device->disk[j].sectors >= smallest)
 				count++;
 		
 		smallest = smallest * count;		
 		bar = smallest;
-		raid[device].cutoff[i] = smallest;
-		raid[device].cutoff_disks[i] = count;
+		device->cutoff[i] = smallest;
+		device->cutoff_disks[i] = count;
 		
 	}
 }
 
+static int count_disks(struct hptraid * raid) {
+	int i, count=0;
+	for (i=0;i<8;i++) {
+		if (raid->disk[i].device!=0) {
+			printk(KERN_INFO "Drive %i is %li Mb \n",
+				i,raid->disk[i].sectors/2048);
+			count++;
+		}
+	}
+	return count;
+}
+
+static void raid1_fixup(struct hptraid * raid) {
+	int i, count=0;
+	for (i=0;i<8;i++) {
+			/* disknumbers and total disks values are bogus */
+		if (raid->disk[i].device!=0) {
+			raid->disk[count]=raid->disk[i];
+			if(i > count) {
+				memset(raid->disk+i, 0, sizeof(struct hptdisk));
+			}
+			count++;
+		}
+	}
+	raid->disks=count;
+}
 
-static __init int hptraid_init_one(int device, u_int8_t type)
+static int hptraid_init_one(int device, u_int8_t type, const char * label)
 {
 	int i,count;
-
 	memset(raid+device, 0, sizeof(struct hptraid));
-	for(i=0; i < 14; i++) {
-		probedisk(devlist+i, device, type);
+	for (i=0; i < 14; i++) {
+		if( probedisk(devlist+i, device, type) < 0 )
+			return -EINVAL;
+	}
+
+	/* Initialize raid levels */
+	switch (type) {
+		case HPT_T_RAID_0:
+			fill_cutoff(raid+device);
+			break;
+
+		case HPT_T_RAID_1:
+			raid1_fixup(raid+device);
+			break;
+
+		case HPT_T_RAID_01_RAID_0:
+			for(i=0; i < 2 && raid[device].raid01 && 
+					raid[device].raid01[i].disks; i++) {
+				fill_cutoff(raid[device].raid01+i);
+					/* initialize raid 0+1 volumes */
+				raid[device].disk[i].device=i+1;
+			}
+			break;
 	}
 
-	if(type == HPT_T_RAID_0)
-		fill_cutoff(device);
-	
 	/* Initialize the gendisk structure */
 	
 	ataraid_register_disk(device,raid[device].sectors);
 
-	count=0;
+	/* Verify that we have all disks */
+
+	count=count_disks(raid+device);
 		
-	for (i=0;i<8;i++) {
-		if (raid[device].disk[i].device!=0) {
-			printk(KERN_INFO "Drive %i is %li Mb \n",
-				i,raid[device].disk[i].sectors/2048);
-			count++;
-		}
+	if (count != raid[device].disks) {
+		printk(KERN_INFO "%s consists of %i drives but found %i drives\n",
+				label, raid[device].disks, count);
+		return -ENODEV;
 	}
-	if (count) {
-		printk(KERN_INFO "Raid array consists of %i drives. \n",count);
+	else if (count) {
+		printk(KERN_INFO "%s consists of %i drives.\n",
+				label, count);
+		if (type == HPT_T_RAID_01_RAID_0 ) {
+			for(i=0;i<raid[device].disks;i++) {
+				count=count_disks(raid[device].raid01+i);
+				if(count == raid[device].raid01[i].disks) {
+					printk(KERN_ERR "Sub-Raid %i array consists of %i drives.\n",
+							i, count);
+				}
+				else {
+					printk(KERN_ERR "Sub-Raid %i array consists of %i drives but found %i disk members.\n",
+							i, raid[device].raid01[i].disks,
+							count);
+					return -ENODEV;
+				}
+			}
+		}
 		return 0;
-	} else {
-		printk(KERN_INFO "No raid array found\n");
-		return -ENODEV;
 	}
 	
+	return -ENODEV; /* No more raid volumes */
 }
 
-static __init int hptraid_init(void)
+static int hptraid_init(void)
 {
- 	int retval,device,count=0;
+ 	int retval=-ENODEV;
+	int device,i,count=0;
   	
-	printk(KERN_INFO "Highpoint HPT370 Softwareraid driver for linux version 0.01-ww1\n");
+	printk(KERN_INFO "Highpoint HPT370 Softwareraid driver for linux version 0.02\n");
 
- 	do
- 	{
- 		device=ataraid_get_device(&hptraid0_ops);
- 		if (device<0)
- 			return (count?0:-ENODEV);
- 		retval = hptraid_init_one(device, HPT_T_RAID_0);
- 		if (retval)
- 			ataraid_release_device(device);
- 		else
- 			count++;
- 	} while(!retval);
- 	do
- 	{
- 		device=ataraid_get_device(&hptraid1_ops);
- 		if (device<0)
- 			return (count?0:-ENODEV);
- 		retval = hptraid_init_one(device, HPT_T_RAID_1);
- 		if (retval)
- 			ataraid_release_device(device);
- 		else
- 			count++;
- 	} while(!retval);
- 	do
- 	{
- 		device=ataraid_get_device(&hptraidspan_ops);
- 		if (device<0)
- 			return (count?0:-ENODEV);
- 		retval = hptraid_init_one(device, HPT_T_SPAN);
- 		if (retval)
- 			ataraid_release_device(device);
- 		else
- 			count++;
- 	} while(!retval);
+	for(i=0; oplist[i].op; i++) {
+		do
+		{
+			device=ataraid_get_device(oplist[i].op);
+			if (device<0)
+				return (count?0:-ENODEV);
+			retval = hptraid_init_one(device, oplist[i].type,
+					oplist[i].label);
+			if (retval)
+				ataraid_release_device(device);
+			else
+				count++;
+		} while(!retval);
+	}
  	return (count?0:retval);
 }
 
 static void __exit hptraid_exit (void)
 {
 	int i,device;
-	for (device = 0; device<16; device++) {
+	for (device = 0; device<14; device++) {
 		for (i=0;i<8;i++)  {
 			struct block_device *bdev = raid[device].disk[i].bdev;
 			raid[device].disk[i].bdev = NULL;
 			if (bdev)
 				blkdev_put(bdev, BDEV_RAW);
 		}       
-		if (raid[device].sectors)
+		if (raid[device].sectors) {
 			ataraid_release_device(device);
+			if( raid[device].raid01 ) {
+				kfree(raid[device].raid01);
+			}
+		}
 	}
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)