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 
38 static int ataraid_hardsect_size[256];
39 static int ataraid_blksize_size[256];
40 
41 static struct raid_device_operations* ataraid_ops[16];
42 
43 static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
44 static int ataraid_open(struct inode * inode, struct file * filp);
45 static int ataraid_release(struct inode * inode, struct file * filp);
46 static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh);
47 
48 
49 struct gendisk ataraid_gendisk;
50 static int ataraid_gendisk_sizes[256];
51 static int ataraid_readahead[256];
52 
53 static 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 
62 static DECLARE_MUTEX(ataraid_sem);
63 
64 /* Bitmap for the devices currently in use */
65 static unsigned int ataraiduse;
66 
67 
68 /* stub fops functions */
69 
ataraid_ioctl(struct inode * inode,struct file * file,unsigned int cmd,unsigned long arg)70 static 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 
ataraid_open(struct inode * inode,struct file * filp)80 static 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 
ataraid_release(struct inode * inode,struct file * filp)91 static 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 
ataraid_make_request(request_queue_t * q,int rw,struct buffer_head * bh)101 static 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 
ataraid_get_bhead(void)119 struct 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 			__set_current_state(TASK_RUNNING);
126 			yield();
127 		}
128 	}
129 	return ptr;
130 }
131 
132 EXPORT_SYMBOL(ataraid_get_bhead);
133 
ataraid_get_private(void)134 struct ataraid_bh_private *ataraid_get_private(void)
135 {
136 	void *ptr = NULL;
137 	while (!ptr) {
138 		ptr=kmalloc(sizeof(struct ataraid_bh_private),GFP_NOIO);
139 		if (!ptr) {
140 			__set_current_state(TASK_RUNNING);
141 			yield();
142 		}
143 	}
144 	return ptr;
145 }
146 
147 EXPORT_SYMBOL(ataraid_get_private);
148 
ataraid_end_request(struct buffer_head * bh,int uptodate)149 void ataraid_end_request(struct buffer_head *bh, int uptodate)
150 {
151 	struct ataraid_bh_private *private = bh->b_private;
152 
153 	if (private==NULL)
154 		BUG();
155 
156 	if (atomic_dec_and_test(&private->count)) {
157 		private->parent->b_end_io(private->parent,uptodate);
158 		private->parent = NULL;
159 		kfree(private);
160 	}
161 	kfree(bh);
162 }
163 
164 EXPORT_SYMBOL(ataraid_end_request);
165 
ataraid_split_request(request_queue_t * q,int rw,struct buffer_head * bh)166 static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh)
167 {
168 	struct buffer_head *bh1,*bh2;
169 	struct ataraid_bh_private *private;
170 	bh1=ataraid_get_bhead();
171 	bh2=ataraid_get_bhead();
172 
173 	/* If either of those ever fails we're doomed */
174 	if ((!bh1)||(!bh2))
175 		BUG();
176 	private = ataraid_get_private();
177 	if (private==NULL)
178 		BUG();
179 
180 	memcpy(bh1, bh, sizeof(*bh));
181 	memcpy(bh2, bh, sizeof(*bh));
182 
183 	bh1->b_end_io = ataraid_end_request;
184 	bh2->b_end_io = ataraid_end_request;
185 
186 	bh2->b_rsector += bh->b_size >> 10;
187 	bh1->b_size /= 2;
188 	bh2->b_size /= 2;
189 	private->parent = bh;
190 
191 	bh1->b_private = private;
192 	bh2->b_private = private;
193 	atomic_set(&private->count,2);
194 
195 	bh2->b_data +=  bh->b_size/2;
196 
197 	generic_make_request(rw,bh1);
198 	generic_make_request(rw,bh2);
199 }
200 
201 
202 
203 
204 /* device register / release functions */
205 
206 
ataraid_get_device(struct raid_device_operations * fops)207 int ataraid_get_device(struct raid_device_operations *fops)
208 {
209 	int bit;
210 	down(&ataraid_sem);
211 	if (ataraiduse==~0U) {
212 		up(&ataraid_sem);
213 		return -ENODEV;
214 	}
215 	bit=ffz(ataraiduse);
216 	ataraiduse |= 1<<bit;
217 	ataraid_ops[bit] = fops;
218 	up(&ataraid_sem);
219 	return bit;
220 }
221 
ataraid_release_device(int device)222 void ataraid_release_device(int device)
223 {
224 	down(&ataraid_sem);
225 
226 	if ((ataraiduse & (1<<device))==0)
227 		BUG();	/* device wasn't registered at all */
228 
229 	ataraiduse &= ~(1<<device);
230 	ataraid_ops[device] = NULL;
231 	up(&ataraid_sem);
232 }
233 
ataraid_register_disk(int device,long size)234 void ataraid_register_disk(int device,long size)
235 {
236 	register_disk(&ataraid_gendisk, MKDEV(ATAMAJOR,16*device),16,
237 		&ataraid_fops,size);
238 
239 }
240 
ataraid_init(void)241 static __init int ataraid_init(void)
242 {
243 	int i;
244         for(i=0;i<256;i++)
245 	{
246         	ataraid_hardsect_size[i] = 512;
247 		ataraid_blksize_size[i] = 1024;
248 		ataraid_readahead[i] = 1023;
249 	}
250 
251 	if (blksize_size[ATAMAJOR]==NULL)
252 		blksize_size[ATAMAJOR] = ataraid_blksize_size;
253 	if (hardsect_size[ATAMAJOR]==NULL)
254 		hardsect_size[ATAMAJOR] = ataraid_hardsect_size;
255 
256 
257 	/* setup the gendisk structure */
258 	ataraid_gendisk.part = kmalloc(256 * sizeof(struct hd_struct),GFP_KERNEL);
259 	if (ataraid_gendisk.part==NULL) {
260 		printk(KERN_ERR "ataraid: Couldn't allocate memory, aborting \n");
261 		return -1;
262 	}
263 
264 	memset(&ataraid_gendisk.part[0],0,256*sizeof(struct hd_struct));
265 
266 
267 	ataraid_gendisk.major       = ATAMAJOR;
268 	ataraid_gendisk.major_name  = "ataraid";
269 	ataraid_gendisk.minor_shift = 4;
270 	ataraid_gendisk.max_p	    = 15;
271 	ataraid_gendisk.sizes	    = &ataraid_gendisk_sizes[0];
272 	ataraid_gendisk.nr_real	    = 16;
273 	ataraid_gendisk.fops        = &ataraid_fops;
274 
275 
276 	add_gendisk(&ataraid_gendisk);
277 
278 	if (register_blkdev(ATAMAJOR, "ataraid", &ataraid_fops)) {
279 		printk(KERN_ERR "ataraid: Could not get major %d \n",ATAMAJOR);
280 		return -1;
281 	}
282 
283 
284 
285 	blk_queue_make_request(BLK_DEFAULT_QUEUE(ATAMAJOR),ataraid_make_request);
286 
287 	return 0;
288 }
289 
290 
ataraid_exit(void)291 static void __exit ataraid_exit(void)
292 {
293 	unregister_blkdev(ATAMAJOR, "ataraid");
294 	hardsect_size[ATAMAJOR] = NULL;
295 	blk_size[ATAMAJOR] = NULL;
296 	blksize_size[ATAMAJOR] = NULL;
297 	max_readahead[ATAMAJOR] = NULL;
298 
299 	del_gendisk(&ataraid_gendisk);
300 
301 	if (ataraid_gendisk.part) {
302 		kfree(ataraid_gendisk.part);
303 		ataraid_gendisk.part = NULL;
304 	}
305 }
306 
307 module_init(ataraid_init);
308 module_exit(ataraid_exit);
309 
310 
311 
312 EXPORT_SYMBOL(ataraid_get_device);
313 EXPORT_SYMBOL(ataraid_release_device);
314 EXPORT_SYMBOL(ataraid_gendisk);
315 EXPORT_SYMBOL(ataraid_register_disk);
316 MODULE_LICENSE("GPL");
317 
318