Messages in this thread Patch in this message | | | Date | Mon, 14 Apr 2003 22:18:34 +0200 | From | Wilfried Weissmann <> | Subject | 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 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 | |