⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cpqarray.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *    Disk Array driver for Compaq SMART2 Controllers *    Copyright 1998 Compaq Computer Corporation * *    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 of the License, or *    (at your option) any later version. * *    This program is distributed in the hope that it will be useful, *    but WITHOUT ANY WARRANTY; without even the implied warranty of *    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or *    NON INFRINGEMENT.  See the GNU General Public License for more details. * *    You should have received a copy of the GNU General Public License *    along with this program; if not, write to the Free Software *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *    Questions/Comments/Bugfixes to arrays@compaq.com * *    If you want to make changes, improve or add functionality to this *    driver, you'll probably need the Compaq Array Controller Interface *    Specificiation (Document number ECG086/1198) */#include <linux/config.h>	/* CONFIG_PROC_FS */#include <linux/module.h>#include <linux/version.h>#include <linux/types.h>#include <linux/pci.h>#include <linux/kernel.h>#include <linux/malloc.h>#include <linux/delay.h>#include <linux/major.h>#include <linux/fs.h>#include <linux/blkpg.h>#include <linux/timer.h>#include <linux/proc_fs.h>#include <linux/init.h>#include <linux/hdreg.h>#include <linux/spinlock.h>#include <asm/uaccess.h>#include <asm/io.h>#define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.1)"#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,1)/* Embedded module documentation macros - see modules.h *//* Original author Chris Frantz - Compaq Computer Corporation */MODULE_AUTHOR("Compaq Computer Corporation");MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers");#define MAJOR_NR COMPAQ_SMART2_MAJOR#include <linux/blk.h>#include <linux/blkdev.h>#include <linux/genhd.h>#include "cpqarray.h"#include "ida_cmd.h"#include "smart1,2.h"#include "ida_ioctl.h"#define READ_AHEAD	128#define NR_CMDS		128 /* This could probably go as high as ~400 */#define MAX_CTLR	8#define CTLR_SHIFT	8static int nr_ctlr;static ctlr_info_t *hba[MAX_CTLR];static int eisa[8];#define NR_PRODUCTS (sizeof(products)/sizeof(struct board_type))/*  board_id = Subsystem Device ID & Vendor ID *  product = Marketing Name for the board *  access = Address of the struct of function pointers  */static struct board_type products[] = {	{ 0x0040110E, "IDA",			&smart1_access },	{ 0x0140110E, "IDA-2",			&smart1_access },	{ 0x1040110E, "IAES",			&smart1_access },	{ 0x2040110E, "SMART",			&smart1_access },	{ 0x3040110E, "SMART-2/E",		&smart2e_access },	{ 0x40300E11, "SMART-2/P",		&smart2_access },	{ 0x40310E11, "SMART-2SL",		&smart2_access },	{ 0x40320E11, "Smart Array 3200",	&smart2_access },	{ 0x40330E11, "Smart Array 3100ES",	&smart2_access },	{ 0x40340E11, "Smart Array 221",	&smart2_access },	{ 0x40400E11, "Integrated Array",	&smart4_access },	{ 0x40480E11, "Compaq Raid LC2",        &smart4_access },	{ 0x40500E11, "Smart Array 4200",	&smart4_access },	{ 0x40510E11, "Smart Array 4250ES",	&smart4_access },	{ 0x40580E11, "Smart Array 431",	&smart4_access },};static struct hd_struct * ida;static int * ida_sizes;static int * ida_blocksizes;static int * ida_hardsizes;static struct gendisk ida_gendisk[MAX_CTLR];static struct proc_dir_entry *proc_array;/* Debug... */#define DBG(s)	do { s } while(0)/* Debug (general info)... */#define DBGINFO(s) do { } while(0)/* Debug Paranoid... */#define DBGP(s)  do { } while(0)/* Debug Extra Paranoid... */#define DBGPX(s) do { } while(0)int cpqarray_init(void);static int cpqarray_pci_detect(void);static int cpqarray_pci_init(ctlr_info_t *c, struct pci_dev *pdev);static void *remap_pci_mem(ulong base, ulong size);static int cpqarray_eisa_detect(void);static int pollcomplete(int ctlr);static void getgeometry(int ctlr);static void start_fwbk(int ctlr);static cmdlist_t * cmd_alloc(ctlr_info_t *h);static void cmd_free(ctlr_info_t *h, cmdlist_t *c);static int sendcmd(	__u8	cmd,	int	ctlr,	void	*buff,	size_t	size,	unsigned int blk,	unsigned int blkcnt,	unsigned int log_unit );static int ida_open(struct inode *inode, struct file *filep);static int ida_release(struct inode *inode, struct file *filep);static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg);static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io);static void do_ida_request(int i);/* * This is a hack.  This driver eats a major number for each controller, and * sets blkdev[xxx].request_fn to each one of these so the real request * function knows what controller its working with. */#define DO_IDA_REQUEST(x) { do_ida_request(x); }static void do_ida_request0(request_queue_t * q) DO_IDA_REQUEST(0);static void do_ida_request1(request_queue_t * q) DO_IDA_REQUEST(1);static void do_ida_request2(request_queue_t * q) DO_IDA_REQUEST(2);static void do_ida_request3(request_queue_t * q) DO_IDA_REQUEST(3);static void do_ida_request4(request_queue_t * q) DO_IDA_REQUEST(4);static void do_ida_request5(request_queue_t * q) DO_IDA_REQUEST(5);static void do_ida_request6(request_queue_t * q) DO_IDA_REQUEST(6);static void do_ida_request7(request_queue_t * q) DO_IDA_REQUEST(7);static void start_io(ctlr_info_t *h);static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c);static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c);static inline void complete_buffers(struct buffer_head *bh, int ok);static inline void complete_command(cmdlist_t *cmd, int timeout);static void do_ida_intr(int irq, void *dev_id, struct pt_regs * regs);static void ida_timer(unsigned long tdata);static int frevalidate_logvol(kdev_t dev);static int revalidate_logvol(kdev_t dev, int maxusage);static int revalidate_allvol(kdev_t dev);#ifdef CONFIG_PROC_FSstatic void ida_procinit(int i);static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data);#elsestatic void ida_procinit(int i) {}static int ida_proc_get_info(char *buffer, char **start, off_t offset,			     int length, int *eof, void *data) { return 0;}#endifstatic void ida_geninit(int ctlr){	int i,j;	drv_info_t *drv;	for(i=0; i<NWD; i++) {		drv = &hba[ctlr]->drv[i];		if (!drv->nr_blks)			continue;		ida[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)].nr_sects =		ida_sizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)] =				drv->nr_blks;		for(j=0; j<16; j++) {			ida_blocksizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)+j] =				1024;			ida_hardsizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)+j] =				drv->blk_size;		}		ida_gendisk[ctlr].nr_real++;	}}static struct block_device_operations ida_fops  = {	open:		ida_open,	release:	ida_release,	ioctl:		ida_ioctl,	revalidate:	frevalidate_logvol,};#ifdef CONFIG_PROC_FS/* * Get us a file in /proc/array that says something about each controller. * Create /proc/array if it doesn't exist yet. */static void __init ida_procinit(int i){	if (proc_array == NULL) {		proc_array = proc_mkdir("driver/array", NULL);		if (!proc_array) return;	}	create_proc_read_entry(hba[i]->devname, 0, proc_array,			       ida_proc_get_info, hba[i]);}/* * Report information about this controller. */static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data){	off_t pos = 0;	off_t len = 0;	int size, i, ctlr;	ctlr_info_t *h = (ctlr_info_t*)data;	drv_info_t *drv;#ifdef CPQ_PROC_PRINT_QUEUES	cmdlist_t *c;#endif	ctlr = h->ctlr;	size = sprintf(buffer, "%s:  Compaq %s Controller\n"		"       Board ID: %08lx\n"		"       Firmware Revision: %c%c%c%c\n"		"       Controller Sig: %08lx\n"		"       Memory Address: %08lx\n"		"       I/O Port: %04x\n"		"       IRQ: %x\n"		"       Logical drives: %d\n"		"       Physical drives: %d\n\n"		"       Current Q depth: %d\n"		"       Max Q depth since init: %d\n\n",		h->devname, 		h->product_name,		(unsigned long)h->board_id,		h->firm_rev[0], h->firm_rev[1], h->firm_rev[2], h->firm_rev[3],		(unsigned long)h->ctlr_sig, (unsigned long)h->vaddr,		(unsigned int) h->ioaddr, (unsigned int)h->intr,		h->log_drives, h->phys_drives,		h->Qdepth, h->maxQsinceinit);	pos += size; len += size;		size = sprintf(buffer+len, "Logical Drive Info:\n");	pos += size; len += size;	for(i=0; i<h->log_drives; i++) {		drv = &h->drv[i];		size = sprintf(buffer+len, "ida/c%dd%d: blksz=%d nr_blks=%d\n",				ctlr, i, drv->blk_size, drv->nr_blks);		pos += size; len += size;	}#ifdef CPQ_PROC_PRINT_QUEUES	size = sprintf(buffer+len, "\nCurrent Queues:\n");	pos += size; len += size;	c = h->reqQ;	size = sprintf(buffer+len, "reqQ = %p", c); pos += size; len += size;	if (c) c=c->next;	while(c && c != h->reqQ) {		size = sprintf(buffer+len, "->%p", c);		pos += size; len += size;		c=c->next;	}	c = h->cmpQ;	size = sprintf(buffer+len, "\ncmpQ = %p", c); pos += size; len += size;	if (c) c=c->next;	while(c && c != h->cmpQ) {		size = sprintf(buffer+len, "->%p", c);		pos += size; len += size;		c=c->next;	}	size = sprintf(buffer+len, "\n"); pos += size; len += size;#endif	size = sprintf(buffer+len, "nr_allocs = %d\nnr_frees = %d\n",			h->nr_allocs, h->nr_frees);	pos += size; len += size;	*eof = 1;	*start = buffer+offset;	len -= offset;	if (len>length)		len = length;	return len;}#endif /* CONFIG_PROC_FS */#ifdef MODULEMODULE_PARM(eisa, "1-8i");EXPORT_NO_SYMBOLS;/* This is a bit of a hack... */int __init init_module(void){	if (cpqarray_init() == 0) /* all the block dev numbers already used */		return -EIO;	  /* or no controllers were found */	return 0;}void cleanup_module(void){	int i;	struct gendisk *g;	remove_proc_entry("driver/array", NULL);	for(i=0; i<nr_ctlr; i++) {		hba[i]->access.set_intr_mask(hba[i], 0);		free_irq(hba[i]->intr, hba[i]);		iounmap(hba[i]->vaddr);		unregister_blkdev(MAJOR_NR+i, hba[i]->devname);		del_timer(&hba[i]->timer);		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + i));		remove_proc_entry(hba[i]->devname, proc_array);		kfree(hba[i]->cmd_pool);		kfree(hba[i]->cmd_pool_bits);		if (gendisk_head == &ida_gendisk[i]) {			gendisk_head = ida_gendisk[i].next;		} else {			for(g=gendisk_head; g; g=g->next) {				if (g->next == &ida_gendisk[i]) {					g->next = ida_gendisk[i].next;					break;				}			}		}	}	kfree(ida);	kfree(ida_sizes);	kfree(ida_hardsizes);	kfree(ida_blocksizes);}#endif /* MODULE *//* *  This is it.  Find all the controllers and register them.  I really hate *  stealing all these major device numbers. *  returns the number of block devices registered. */int __init cpqarray_init(void){	void (*request_fns[MAX_CTLR])(request_queue_t *) = {		do_ida_request0, do_ida_request1,		do_ida_request2, do_ida_request3,		do_ida_request4, do_ida_request5,		do_ida_request6, do_ida_request7,	};	int i,j;	int num_cntlrs_reg = 0;	/* detect controllers */	cpqarray_pci_detect();	cpqarray_eisa_detect();		if (nr_ctlr == 0)		return(num_cntlrs_reg);	printk(DRIVER_NAME "\n");	printk("Found %d controller(s)\n", nr_ctlr);	/* allocate space for disk structs */	ida = kmalloc(sizeof(struct hd_struct)*nr_ctlr*NWD*16, GFP_KERNEL);	if(ida==NULL)	{		printk( KERN_ERR "cpqarray: out of memory");		return(num_cntlrs_reg);	}		ida_sizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);	if(ida_sizes==NULL)	{		kfree(ida); 		printk( KERN_ERR "cpqarray: out of memory");		return(num_cntlrs_reg);	}	ida_blocksizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);	if(ida_blocksizes==NULL)	{		kfree(ida);		kfree(ida_sizes); 		printk( KERN_ERR "cpqarray: out of memory");		return(num_cntlrs_reg);	}	ida_hardsizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);	if(ida_hardsizes==NULL)	{		kfree(ida);		kfree(ida_sizes); 		kfree(ida_blocksizes);		printk( KERN_ERR "cpqarray: out of memory");		return(num_cntlrs_reg);	}	memset(ida, 0, sizeof(struct hd_struct)*nr_ctlr*NWD*16);	memset(ida_sizes, 0, sizeof(int)*nr_ctlr*NWD*16);	memset(ida_blocksizes, 0, sizeof(int)*nr_ctlr*NWD*16);	memset(ida_hardsizes, 0, sizeof(int)*nr_ctlr*NWD*16);	memset(ida_gendisk, 0, sizeof(struct gendisk)*MAX_CTLR);		/* 	 * register block devices	 * Find disks and fill in structs	 * Get an interrupt, set the Q depth and get into /proc	 */	for(i=0; i< nr_ctlr; i++) {	  	/* If this successful it should insure that we are the only */		/* instance of the driver */			if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) {                        printk(KERN_ERR "cpqarray: Unable to get major number %d for ida\n",                                MAJOR_NR+i);                        continue;                }			hba[i]->access.set_intr_mask(hba[i], 0);		if (request_irq(hba[i]->intr, do_ida_intr,			SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i])) {			printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n", 				hba[i]->intr, hba[i]->devname);			unregister_blkdev(MAJOR_NR+i, hba[i]->devname);			continue;		}		num_cntlrs_reg++;		hba[i]->cmd_pool = (cmdlist_t *)kmalloc(				NR_CMDS * sizeof(cmdlist_t), GFP_KERNEL);		hba[i]->cmd_pool_bits = (__u32*)kmalloc(				((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -