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