HPT370 Raid - SPAN&RAID1 Patch
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
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
drivers/ide/raid/hptraid.c +268 -43
@@ -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
include/linux/pci_ids.h +1 -0
@@ -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