OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [ide/] [raid/] [ataraid.c] - Rev 1765

Compare with Previous | Blame | View Log

/*
   ataraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.
 
   You should have received a copy of the GNU General Public License
   (for example /usr/src/linux/COPYING); if not, write to the Free
   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
 
   Authors: 	Arjan van de Ven <arjanv@redhat.com>
 
 
*/
 
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/semaphore.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/blkdev.h>
#include <linux/blkpg.h>
#include <linux/genhd.h>
#include <linux/ioctl.h>
#include <linux/kdev_t.h>
#include <linux/swap.h>
 
#include <linux/ide.h>
#include <asm/uaccess.h>
 
#include "ataraid.h"
 
 
static int ataraid_hardsect_size[256];
static int ataraid_blksize_size[256];
 
static struct raid_device_operations* ataraid_ops[16];
 
static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
static int ataraid_open(struct inode * inode, struct file * filp);
static int ataraid_release(struct inode * inode, struct file * filp);
static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh);
 
 
struct gendisk ataraid_gendisk;
static int ataraid_gendisk_sizes[256];
static int ataraid_readahead[256];
 
static struct block_device_operations ataraid_fops = {
	owner:			THIS_MODULE,
	open:                   ataraid_open,
	release:                ataraid_release,
	ioctl:                  ataraid_ioctl,
};
 
 
 
static DECLARE_MUTEX(ataraid_sem);
 
/* Bitmap for the devices currently in use */
static unsigned int ataraiduse;
 
 
/* stub fops functions */
 
static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)  
{
	int minor;
	minor = MINOR(inode->i_rdev)>>SHIFT;
 
	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->ioctl))
		return (ataraid_ops[minor]->ioctl)(inode,file,cmd,arg);
	return -EINVAL;
}
 
static int ataraid_open(struct inode * inode, struct file * filp)
{
	int minor;
	minor = MINOR(inode->i_rdev)>>SHIFT;
 
	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->open))
		return (ataraid_ops[minor]->open)(inode,filp);
	return -EINVAL;
}
 
 
static int ataraid_release(struct inode * inode, struct file * filp)
{
	int minor;
	minor = MINOR(inode->i_rdev)>>SHIFT;
 
	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->release))
		return (ataraid_ops[minor]->release)(inode,filp);
	return -EINVAL;
}
 
static int ataraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
{
	int minor;
	int retval;
	minor = MINOR(bh->b_rdev)>>SHIFT;
 
	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->make_request)) {
 
		retval= (ataraid_ops[minor]->make_request)(q,rw,bh);
		if (retval == -1) {
			ataraid_split_request(q,rw,bh);		
			return 0;
		} else
			return retval;
	}
	return -EINVAL;
}
 
struct buffer_head *ataraid_get_bhead(void)
{
	void *ptr = NULL;
	while (!ptr) {
		ptr=kmalloc(sizeof(struct buffer_head),GFP_NOIO);
		if (!ptr) {
			__set_current_state(TASK_RUNNING);
			yield();
		}
	}
	return ptr;
}
 
EXPORT_SYMBOL(ataraid_get_bhead);
 
struct ataraid_bh_private *ataraid_get_private(void)
{
	void *ptr = NULL;
	while (!ptr) {
		ptr=kmalloc(sizeof(struct ataraid_bh_private),GFP_NOIO);
		if (!ptr) {
			__set_current_state(TASK_RUNNING);
			yield();
		}
	}
	return ptr;
}
 
EXPORT_SYMBOL(ataraid_get_private);
 
void ataraid_end_request(struct buffer_head *bh, int uptodate)
{
	struct ataraid_bh_private *private = bh->b_private;
 
	if (private==NULL)
		BUG();
 
	if (atomic_dec_and_test(&private->count)) {
		private->parent->b_end_io(private->parent,uptodate);
		private->parent = NULL;
		kfree(private);
	}
	kfree(bh);
}
 
EXPORT_SYMBOL(ataraid_end_request);
 
static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh)
{
	struct buffer_head *bh1,*bh2;
	struct ataraid_bh_private *private;
	bh1=ataraid_get_bhead();
	bh2=ataraid_get_bhead();
 
	/* If either of those ever fails we're doomed */
	if ((!bh1)||(!bh2))
		BUG();
	private = ataraid_get_private();
	if (private==NULL)
		BUG();
 
	memcpy(bh1, bh, sizeof(*bh));
	memcpy(bh2, bh, sizeof(*bh));
 
	bh1->b_end_io = ataraid_end_request;
	bh2->b_end_io = ataraid_end_request;
 
	bh2->b_rsector += bh->b_size >> 10;
	bh1->b_size /= 2;
	bh2->b_size /= 2;
	private->parent = bh;
 
	bh1->b_private = private;
	bh2->b_private = private;
	atomic_set(&private->count,2);
 
	bh2->b_data +=  bh->b_size/2;
 
	generic_make_request(rw,bh1);
	generic_make_request(rw,bh2);
}
 
 
 
 
/* device register / release functions */
 
 
int ataraid_get_device(struct raid_device_operations *fops)
{
	int bit;
	down(&ataraid_sem);
	if (ataraiduse==~0U) {
		up(&ataraid_sem);
		return -ENODEV;
	}
	bit=ffz(ataraiduse); 
	ataraiduse |= 1<<bit;
	ataraid_ops[bit] = fops;
	up(&ataraid_sem);
	return bit;
}
 
void ataraid_release_device(int device)
{
	down(&ataraid_sem);
 
	if ((ataraiduse & (1<<device))==0)
		BUG();	/* device wasn't registered at all */
 
	ataraiduse &= ~(1<<device);
	ataraid_ops[device] = NULL;
	up(&ataraid_sem);
}
 
void ataraid_register_disk(int device,long size)
{
	register_disk(&ataraid_gendisk, MKDEV(ATAMAJOR,16*device),16,
		&ataraid_fops,size);
 
}
 
static __init int ataraid_init(void) 
{
	int i;
        for(i=0;i<256;i++)
	{
        	ataraid_hardsect_size[i] = 512;
		ataraid_blksize_size[i] = 1024;  
		ataraid_readahead[i] = 1023;
	}
 
	if (blksize_size[ATAMAJOR]==NULL)
		blksize_size[ATAMAJOR] = ataraid_blksize_size;
	if (hardsect_size[ATAMAJOR]==NULL)
		hardsect_size[ATAMAJOR] = ataraid_hardsect_size;
 
 
	/* setup the gendisk structure */	
	ataraid_gendisk.part = kmalloc(256 * sizeof(struct hd_struct),GFP_KERNEL);
	if (ataraid_gendisk.part==NULL) {
		printk(KERN_ERR "ataraid: Couldn't allocate memory, aborting \n");
		return -1;
	}
 
	memset(&ataraid_gendisk.part[0],0,256*sizeof(struct hd_struct));
 
 
	ataraid_gendisk.major       = ATAMAJOR;
	ataraid_gendisk.major_name  = "ataraid";
	ataraid_gendisk.minor_shift = 4;
	ataraid_gendisk.max_p	    = 15;
	ataraid_gendisk.sizes	    = &ataraid_gendisk_sizes[0];
	ataraid_gendisk.nr_real	    = 16;
	ataraid_gendisk.fops        = &ataraid_fops;
 
 
	add_gendisk(&ataraid_gendisk);
 
	if (register_blkdev(ATAMAJOR, "ataraid", &ataraid_fops)) {
		printk(KERN_ERR "ataraid: Could not get major %d \n",ATAMAJOR);
		return -1;
	}
 
 
 
	blk_queue_make_request(BLK_DEFAULT_QUEUE(ATAMAJOR),ataraid_make_request);
 
	return 0;                                                        	
}
 
 
static void __exit ataraid_exit(void)
{
	unregister_blkdev(ATAMAJOR, "ataraid");
	hardsect_size[ATAMAJOR] = NULL;
	blk_size[ATAMAJOR] = NULL;
	blksize_size[ATAMAJOR] = NULL;                       
	max_readahead[ATAMAJOR] = NULL;
 
	del_gendisk(&ataraid_gendisk);
 
	if (ataraid_gendisk.part) {
		kfree(ataraid_gendisk.part);
		ataraid_gendisk.part = NULL;
	}
}
 
module_init(ataraid_init);
module_exit(ataraid_exit);
 
 
 
EXPORT_SYMBOL(ataraid_get_device);
EXPORT_SYMBOL(ataraid_release_device);
EXPORT_SYMBOL(ataraid_gendisk);
EXPORT_SYMBOL(ataraid_register_disk);
MODULE_LICENSE("GPL");
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.