1/* 2 ataraid.c Copyright (C) 2001 Red Hat, Inc. All rights reserved. 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 2, or (at your option) 7 any later version. 8 9 You should have received a copy of the GNU General Public License 10 (for example /usr/src/linux/COPYING); if not, write to the Free 11 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 12 13 Authors: Arjan van de Ven <arjanv@redhat.com> 14 15 16*/ 17 18#include <linux/module.h> 19#include <linux/init.h> 20#include <linux/kernel.h> 21#include <linux/mm.h> 22#include <asm/semaphore.h> 23#include <linux/sched.h> 24#include <linux/smp_lock.h> 25#include <linux/blkdev.h> 26#include <linux/blkpg.h> 27#include <linux/genhd.h> 28#include <linux/ioctl.h> 29#include <linux/kdev_t.h> 30#include <linux/swap.h> 31 32#include <linux/ide.h> 33#include <asm/uaccess.h> 34 35#include "ataraid.h" 36 37 38static int ataraid_hardsect_size[256]; 39static int ataraid_blksize_size[256]; 40 41static struct raid_device_operations* ataraid_ops[16]; 42 43static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); 44static int ataraid_open(struct inode * inode, struct file * filp); 45static int ataraid_release(struct inode * inode, struct file * filp); 46static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh); 47 48 49struct gendisk ataraid_gendisk; 50static int ataraid_gendisk_sizes[256]; 51static int ataraid_readahead[256]; 52 53static struct block_device_operations ataraid_fops = { 54 owner: THIS_MODULE, 55 open: ataraid_open, 56 release: ataraid_release, 57 ioctl: ataraid_ioctl, 58}; 59 60 61 62static DECLARE_MUTEX(ataraid_sem); 63 64/* Bitmap for the devices currently in use */ 65static unsigned int ataraiduse; 66 67 68/* stub fops functions */ 69 70static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) 71{ 72 int minor; 73 minor = MINOR(inode->i_rdev)>>SHIFT; 74 75 if ((ataraid_ops[minor])&&(ataraid_ops[minor]->ioctl)) 76 return (ataraid_ops[minor]->ioctl)(inode,file,cmd,arg); 77 return -EINVAL; 78} 79 80static int ataraid_open(struct inode * inode, struct file * filp) 81{ 82 int minor; 83 minor = MINOR(inode->i_rdev)>>SHIFT; 84 85 if ((ataraid_ops[minor])&&(ataraid_ops[minor]->open)) 86 return (ataraid_ops[minor]->open)(inode,filp); 87 return -EINVAL; 88} 89 90 91static int ataraid_release(struct inode * inode, struct file * filp) 92{ 93 int minor; 94 minor = MINOR(inode->i_rdev)>>SHIFT; 95 96 if ((ataraid_ops[minor])&&(ataraid_ops[minor]->release)) 97 return (ataraid_ops[minor]->release)(inode,filp); 98 return -EINVAL; 99} 100 101static int ataraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh) 102{ 103 int minor; 104 int retval; 105 minor = MINOR(bh->b_rdev)>>SHIFT; 106 107 if ((ataraid_ops[minor])&&(ataraid_ops[minor]->make_request)) { 108 109 retval= (ataraid_ops[minor]->make_request)(q,rw,bh); 110 if (retval == -1) { 111 ataraid_split_request(q,rw,bh); 112 return 0; 113 } else 114 return retval; 115 } 116 return -EINVAL; 117} 118 119struct buffer_head *ataraid_get_bhead(void) 120{ 121 void *ptr = NULL; 122 while (!ptr) { 123 ptr=kmalloc(sizeof(struct buffer_head),GFP_NOIO); 124 if (!ptr) 125 yield(); 126 } 127 return ptr; 128} 129 130EXPORT_SYMBOL(ataraid_get_bhead); 131 132struct ataraid_bh_private *ataraid_get_private(void) 133{ 134 void *ptr = NULL; 135 while (!ptr) { 136 ptr=kmalloc(sizeof(struct ataraid_bh_private),GFP_NOIO); 137 if (!ptr) 138 yield(); 139 } 140 return ptr; 141} 142 143EXPORT_SYMBOL(ataraid_get_private); 144 145void ataraid_end_request(struct buffer_head *bh, int uptodate) 146{ 147 struct ataraid_bh_private *private = bh->b_private; 148 149 if (private==NULL) 150 BUG(); 151 152 if (atomic_dec_and_test(&private->count)) { 153 private->parent->b_end_io(private->parent,uptodate); 154 private->parent = NULL; 155 kfree(private); 156 } 157 kfree(bh); 158} 159 160EXPORT_SYMBOL(ataraid_end_request); 161 162static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh) 163{ 164 struct buffer_head *bh1,*bh2; 165 struct ataraid_bh_private *private; 166 bh1=ataraid_get_bhead(); 167 bh2=ataraid_get_bhead(); 168 169 /* If either of those ever fails we're doomed */ 170 if ((!bh1)||(!bh2)) 171 BUG(); 172 private = ataraid_get_private(); 173 if (private==NULL) 174 BUG(); 175 176 memcpy(bh1, bh, sizeof(*bh)); 177 memcpy(bh2, bh, sizeof(*bh)); 178 179 bh1->b_end_io = ataraid_end_request; 180 bh2->b_end_io = ataraid_end_request; 181 182 bh2->b_rsector += bh->b_size >> 10; 183 bh1->b_size /= 2; 184 bh2->b_size /= 2; 185 private->parent = bh; 186 187 bh1->b_private = private; 188 bh2->b_private = private; 189 atomic_set(&private->count,2); 190 191 bh2->b_data += bh->b_size/2; 192 193 generic_make_request(rw,bh1); 194 generic_make_request(rw,bh2); 195} 196 197 198 199 200/* device register / release functions */ 201 202 203int ataraid_get_device(struct raid_device_operations *fops) 204{ 205 int bit; 206 down(&ataraid_sem); 207 if (ataraiduse==~0U) { 208 up(&ataraid_sem); 209 return -ENODEV; 210 } 211 bit=ffz(ataraiduse); 212 ataraiduse |= 1<<bit; 213 ataraid_ops[bit] = fops; 214 up(&ataraid_sem); 215 return bit; 216} 217 218void ataraid_release_device(int device) 219{ 220 down(&ataraid_sem); 221 222 if ((ataraiduse & (1<<device))==0) 223 BUG(); /* device wasn't registered at all */ 224 225 ataraiduse &= ~(1<<device); 226 ataraid_ops[device] = NULL; 227 up(&ataraid_sem); 228} 229 230void ataraid_register_disk(int device,long size) 231{ 232 register_disk(&ataraid_gendisk, MKDEV(ATAMAJOR,16*device),16, 233 &ataraid_fops,size); 234 235} 236 237static __init int ataraid_init(void) 238{ 239 int i; 240 for(i=0;i<256;i++) 241 { 242 ataraid_hardsect_size[i] = 512; 243 ataraid_blksize_size[i] = 1024; 244 ataraid_readahead[i] = 1023; 245 } 246 247 if (blksize_size[ATAMAJOR]==NULL) 248 blksize_size[ATAMAJOR] = ataraid_blksize_size; 249 if (hardsect_size[ATAMAJOR]==NULL) 250 hardsect_size[ATAMAJOR] = ataraid_hardsect_size; 251 252 253 /* setup the gendisk structure */ 254 ataraid_gendisk.part = kmalloc(256 * sizeof(struct hd_struct),GFP_KERNEL); 255 if (ataraid_gendisk.part==NULL) { 256 printk(KERN_ERR "ataraid: Couldn't allocate memory, aborting \n"); 257 return -1; 258 } 259 260 memset(&ataraid_gendisk.part[0],0,256*sizeof(struct hd_struct)); 261 262 263 ataraid_gendisk.major = ATAMAJOR; 264 ataraid_gendisk.major_name = "ataraid"; 265 ataraid_gendisk.minor_shift = 4; 266 ataraid_gendisk.max_p = 15; 267 ataraid_gendisk.sizes = &ataraid_gendisk_sizes[0]; 268 ataraid_gendisk.nr_real = 16; 269 ataraid_gendisk.fops = &ataraid_fops; 270 271 272 add_gendisk(&ataraid_gendisk); 273 274 if (register_blkdev(ATAMAJOR, "ataraid", &ataraid_fops)) { 275 printk(KERN_ERR "ataraid: Could not get major %d \n",ATAMAJOR); 276 return -1; 277 } 278 279 280 281 blk_queue_make_request(BLK_DEFAULT_QUEUE(ATAMAJOR),ataraid_make_request); 282 283 return 0; 284} 285 286 287static void __exit ataraid_exit(void) 288{ 289 unregister_blkdev(ATAMAJOR, "ataraid"); 290 hardsect_size[ATAMAJOR] = NULL; 291 blk_size[ATAMAJOR] = NULL; 292 blksize_size[ATAMAJOR] = NULL; 293 max_readahead[ATAMAJOR] = NULL; 294 295 del_gendisk(&ataraid_gendisk); 296 297 if (ataraid_gendisk.part) { 298 kfree(ataraid_gendisk.part); 299 ataraid_gendisk.part = NULL; 300 } 301} 302 303module_init(ataraid_init); 304module_exit(ataraid_exit); 305 306 307 308EXPORT_SYMBOL(ataraid_get_device); 309EXPORT_SYMBOL(ataraid_release_device); 310EXPORT_SYMBOL(ataraid_gendisk); 311EXPORT_SYMBOL(ataraid_register_disk); 312MODULE_LICENSE("GPL"); 313 314