public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* HPT370 Raid - SPAN&RAID1 Patch
@ 2003-04-14 20:18 Wilfried Weissmann
  0 siblings, 0 replies; only message in thread
From: Wilfried Weissmann @ 2003-04-14 20:18 UTC (permalink / raw)
  To: Kernel Mailing List; +Cc: Arjan van de Ven

[-- Attachment #1: Type: text/plain, Size: 471 bytes --]

Greetings HPT370 owners,

After I messed up my harddisk I had no more reasons for not doing some 
work on the raid implementation. So here is an update that does the 
disk-spanning and raid1 (sorry, no real redundancy implemented yet, just 
clone of pdcraid1). It also correct the total sector length (round down 
to 1k blocks). The patch applies against linux-2.4.21-pre7. The PCI-ID 
of HPT372N is also added so that HPT[67]X supports compiles. Enjoy...

bye,
Wilfried

[-- Attachment #2: linux-2.4.21-pre7-hptraid-0.1-ww1.patch --]
[-- Type: text/plain, Size: 12821 bytes --]

Index: linux/drivers/ide/raid/hptraid.c
===================================================================
RCS file: /home/rayn/src/cvsroot/linux/drivers/ide/raid/Attic/hptraid.c,v
retrieving revision 1.1.2.1
retrieving revision 1.1.2.1.6.2
diff -a -u -r1.1.2.1 -r1.1.2.1.6.2
--- linux/drivers/ide/raid/hptraid.c	12 Apr 2003 21:57:31 -0000	1.1.2.1
+++ linux/drivers/ide/raid/hptraid.c	14 Apr 2003 19:37:52 -0000	1.1.2.1.6.2
@@ -38,7 +38,9 @@
 static int hptraid_open(struct inode * inode, struct file * filp);
 static int hptraid_release(struct inode * inode, struct file * filp);
 static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int hptraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+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);
 
 
 
@@ -46,28 +48,68 @@
 	kdev_t	device;
 	unsigned long sectors;
 	struct block_device *bdev;
+	unsigned long last_pos;
 };
 
 struct hptraid {
 	unsigned int stride;
 	unsigned int disks;
 	unsigned long sectors;
+        u_int32_t magic_0;
 	struct geom geom;
 	
 	struct hptdisk disk[8];
-	
 	unsigned long cutoff[8];
 	unsigned int cutoff_disks[8];	
 };
 
-static struct raid_device_operations hptraid_ops = {
+struct hptraid_dev {
+	int major;
+	int minor;
+	int device;
+};
+
+static struct hptraid_dev devlist[]=
+{
+
+	{IDE0_MAJOR,  0, -1},
+	{IDE0_MAJOR, 64, -1},
+	{IDE1_MAJOR,  0, -1},
+	{IDE1_MAJOR, 64, -1},
+	{IDE2_MAJOR,  0, -1},
+	{IDE2_MAJOR, 64, -1},
+	{IDE3_MAJOR,  0, -1},
+	{IDE3_MAJOR, 64, -1},
+	{IDE4_MAJOR,  0, -1},
+	{IDE4_MAJOR, 64, -1},
+	{IDE5_MAJOR,  0, -1},
+	{IDE5_MAJOR, 64, -1},
+	{IDE6_MAJOR,  0, -1},
+	{IDE6_MAJOR, 64, -1}
+};
+
+static struct raid_device_operations hptraidspan_ops = {
+	open:                   hptraid_open,
+	release:                hptraid_release,
+	ioctl:			hptraid_ioctl,
+	make_request:		hptraidspan_make_request
+};
+
+static struct raid_device_operations hptraid0_ops = {
+	open:                   hptraid_open,
+	release:                hptraid_release,
+	ioctl:			hptraid_ioctl,
+	make_request:		hptraid0_make_request
+};
+
+static struct raid_device_operations hptraid1_ops = {
 	open:                   hptraid_open,
 	release:                hptraid_release,
 	ioctl:			hptraid_ioctl,
-	make_request:		hptraid_make_request
+	make_request:		hptraid1_make_request
 };
 
-static struct hptraid raid[16];
+static struct hptraid raid[14];
 
 static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
@@ -131,7 +173,50 @@
 }
 
 
-static int hptraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+static int hptraidspan_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	unsigned long rsect;
+	unsigned int disk;
+	int device;
+	struct hptraid *thisraid;
+
+	rsect = bh->b_rsector;
+
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	thisraid = &raid[device];
+
+	/* Partitions need adding of the start sector of the partition to the requested sector */
+	
+	rsect += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
+
+	for (disk=0;disk<thisraid->disks;disk++) {
+		if (disk==1)
+			rsect+=10;
+			// the "on next disk" contition check is a bit odd
+		if (thisraid->disk[disk].sectors > rsect+1)
+			break;
+		rsect-=thisraid->disk[disk].sectors-(disk?11:1);
+	}
+
+		// request spans over 2 disks => request must be split
+	if(rsect+bh->b_size/512 >= thisraid->disk[disk].sectors)
+		return -1;
+	
+	/*
+	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
+	 * is the only IO operation happening on this bh.
+	 */
+	 
+	bh->b_rdev = thisraid->disk[disk].device;
+	bh->b_rsector = rsect;
+
+	/*
+	 * Let the main block layer submit the IO and resolve recursion:
+	 */
+	return 1;
+}
+
+static int hptraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
 {
 	unsigned long rsect;
 	unsigned long rsect_left,rsect_accum = 0;
@@ -218,6 +303,106 @@
 	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
+	   head position is closest by.
+	   Later on, online/offline checking and performance needs adding */
+	
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	bh->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
+
+	bestsofar = 0; 
+	bestdist = raid[device].disk[0].last_pos - bh->b_rsector;
+	if (bestdist<0) 
+		bestdist=-bestdist;
+	if (bestdist>4095)
+		bestdist=4095;
+
+	for (i=1 ; i<raid[device].disks; i++) {
+		dist = raid[device].disk[i].last_pos - bh->b_rsector;
+		if (dist<0) 
+			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))  
+				bestsofar = i;
+			previous = (previous + 1) % raid[device].disks;
+		} else if (bestdist>dist) {
+			bestdist = dist;
+			bestsofar = i;
+		}
+	
+	}
+	
+	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);
+
+	/*
+	 * Let the main block layer submit the IO and resolve recursion:
+	 */
+                          	
+	return 1;
+}
+
+static int hptraid1_write_request(request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	struct buffer_head *bh1;
+	struct ataraid_bh_private *private;
+	int device;
+	int i;
+
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	private = ataraid_get_private();
+	if (private==NULL)
+		BUG();
+
+	private->parent = bh;
+	
+	atomic_set(&private->count,raid[device].disks);
+
+
+	for (i = 0; i< raid[device].disks; i++) { 
+		bh1=ataraid_get_bhead();
+		/* If this ever fails we're doomed */
+		if (!bh1)
+			BUG();
+	
+		/* 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_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);
+
+		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 */
+	if (rw==READA)
+		rw = READ;
+	
+	if (rw==READ)
+		return hptraid1_read_request(q,rw,bh);
+	else
+		return hptraid1_write_request(q,rw,bh);
+}
 
 #include "hptraid.h"
 
@@ -271,35 +456,49 @@
 	return lba;
 }
 
-static void __init probedisk(int major, int minor,int device)
+static void __init probedisk(struct hptraid_dev *disk, int device, u_int8_t type)
 {
 	int i;
         struct highpoint_raid_conf *prom;
 	static unsigned char block[4096];
 	struct block_device *bdev;
 	
-	if (maxsectors(major,minor)==0)
+ 	if (disk->device != -1)	/* disk is occupied? */
+ 		return;
+ 
+ 	if (maxsectors(disk->major,disk->minor)==0)
 		return;
 	
-        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
+        if (read_disk_sb(disk->major,disk->minor,(unsigned char*)&block,sizeof(block)))
         	return;
                                                                                                                  
         prom = (struct highpoint_raid_conf*)&block[512];
                 
         if (prom->magic!=  0x5a7816f0)
         	return;
-        if (prom->type) {
-        	printk(KERN_INFO "hptraid: only RAID0 is supported currently\n");
-        	return;
+        switch (prom->type) {
+		case HPT_T_SPAN:
+		case HPT_T_RAID_0:
+		case HPT_T_RAID_1:
+			if(prom->type != type)
+				return;
+			break;
+		default:
+			printk(KERN_INFO "hptraid: only SPAN, RAID0 and RAID1 is currently supported \n");
+			return;
         }
 
+ 		/* disk from another array? */
+ 	if(raid[device].disks && prom->magic_0 != raid[device].magic_0)
+ 		return;
+
 	i = prom->disk_number;
 	if (i<0)
 		return;
 	if (i>8) 
 		return;
 
-	bdev = bdget(MKDEV(major,minor));
+	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;
@@ -308,17 +507,22 @@
 		/* 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, 0));
+		gd=get_gendisk(MKDEV(disk->major, 0));
 		if (gd!=NULL) {
-			for (j=1+(minor<<gd->minor_shift);j<((minor+1)<<gd->minor_shift);j++) 
-				gd->part[j].nr_sects=0;					
+ 			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[device].disk[i].device = MKDEV(major,minor);
-	raid[device].disk[i].sectors = maxsectors(major,minor);
+	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;
+	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;
+	disk->device=device;
 			
 }
 
@@ -349,31 +553,23 @@
 }
 
 
-static __init int hptraid_init_one(int device)
+static __init int hptraid_init_one(int device, u_int8_t type)
 {
 	int i,count;
 
-	probedisk(IDE0_MAJOR,  0, device);
-	probedisk(IDE0_MAJOR, 64, device);
-	probedisk(IDE1_MAJOR,  0, device);
-	probedisk(IDE1_MAJOR, 64, device);
-	probedisk(IDE2_MAJOR,  0, device);
-	probedisk(IDE2_MAJOR, 64, device);
-	probedisk(IDE3_MAJOR,  0, device);
-	probedisk(IDE3_MAJOR, 64, device);
-	probedisk(IDE4_MAJOR,  0, device);
-	probedisk(IDE4_MAJOR, 64, device);
-	probedisk(IDE5_MAJOR,  0, device);
-	probedisk(IDE5_MAJOR, 64, device);
+	memset(raid+device, 0, sizeof(struct hptraid));
+	for(i=0; i < 14; i++) {
+		probedisk(devlist+i, device, type);
+	}
 
-	fill_cutoff(device);
+	if(type == HPT_T_RAID_0)
+		fill_cutoff(device);
 	
 	/* Initialize the gendisk structure */
 	
 	ataraid_register_disk(device,raid[device].sectors);
 
 	count=0;
-	printk(KERN_INFO "Highpoint HPT370 Softwareraid driver for linux version 0.01\n");
 		
 	for (i=0;i<8;i++) {
 		if (raid[device].disk[i].device!=0) {
@@ -394,15 +590,44 @@
 
 static __init int hptraid_init(void)
 {
-	int retval,device;
-	
-	device=ataraid_get_device(&hptraid_ops);
-	if (device<0)
-		return -ENODEV;
-	retval = hptraid_init_one(device);
-	if (retval)
-		ataraid_release_device(device);
-	return retval;
+ 	int retval,device,count=0;
+  	
+	printk(KERN_INFO "Highpoint HPT370 Softwareraid driver for linux version 0.01-ww1\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);
+ 	return (count?0:retval);
 }
 
 static void __exit hptraid_exit (void)
Index: linux/include/linux/pci_ids.h
===================================================================
RCS file: /home/rayn/src/cvsroot/linux/include/linux/pci_ids.h,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -a -u -r1.1.1.3 -r1.1.1.3.2.1
--- linux/include/linux/pci_ids.h	12 Apr 2003 21:58:17 -0000	1.1.1.3
+++ linux/include/linux/pci_ids.h	13 Apr 2003 20:55:02 -0000	1.1.1.3.2.1
@@ -983,6 +983,7 @@
 #define PCI_DEVICE_ID_TTI_HPT302	0x0006
 #define PCI_DEVICE_ID_TTI_HPT371	0x0007
 #define PCI_DEVICE_ID_TTI_HPT374	0x0008
+#define PCI_DEVICE_ID_TTI_HPT372N	0x0009
 
 #define PCI_VENDOR_ID_VIA		0x1106
 #define PCI_DEVICE_ID_VIA_8363_0	0x0305

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2003-04-14 20:07 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-04-14 20:18 HPT370 Raid - SPAN&RAID1 Patch Wilfried Weissmann

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