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

📄 cpqarray.c

📁 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 iss_storagedev@hp.com * */#include <linux/config.h>	/* CONFIG_PROC_FS */#include <linux/module.h>#include <linux/types.h>#include <linux/pci.h>#include <linux/bio.h>#include <linux/interrupt.h>#include <linux/kernel.h>#include <linux/slab.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/devfs_fs_kernel.h>#include <linux/init.h>#include <linux/hdreg.h>#include <linux/spinlock.h>#include <linux/blkdev.h>#include <linux/genhd.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.6.0)"#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,6,0)/* 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 version 2.6.0");MODULE_LICENSE("GPL");#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	8#define CPQARRAY_DMA_MASK	0xFFFFFFFF	/* 32 bit DMA */static 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 },};/* define the PCI info for the PCI cards this driver can control */static const struct pci_device_id cpqarray_pci_device_id[] ={	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_COMPAQ_42XX,		0x0E11, 0x4058, 0, 0, 0},       /* SA431 */	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_COMPAQ_42XX,		0x0E11, 0x4051, 0, 0, 0},      /* SA4250ES */	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_COMPAQ_42XX,		0x0E11, 0x4050, 0, 0, 0},      /* SA4200 */	{ PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C1510,		0x0E11, 0x4048, 0, 0, 0},       /* LC2 */	{ PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C1510,		0x0E11, 0x4040, 0, 0, 0},      /* Integrated Array */	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_SMART2P,		0x0E11, 0x4034, 0, 0, 0},       /* SA 221 */	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_SMART2P,		0x0E11, 0x4033, 0, 0, 0},       /* SA 3100ES*/	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_SMART2P,		0x0E11, 0x4032, 0, 0, 0},       /* SA 3200*/	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_SMART2P,		0x0E11, 0x4031, 0, 0, 0},       /* SA 2SL*/	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_SMART2P,		0x0E11, 0x4030, 0, 0, 0},       /* SA 2P */	{ 0 }};MODULE_DEVICE_TABLE(pci, cpqarray_pci_device_id);static struct gendisk *ida_gendisk[MAX_CTLR][NWD];/* 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)static int cpqarray_pci_init(ctlr_info_t *c, struct pci_dev *pdev);static void __iomem *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, int get_from_pool);static void cmd_free(ctlr_info_t *h, cmdlist_t *c, int got_from_pool);static void free_hba(int i);static int alloc_cpqarray_hba(void);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(ctlr_info_t *h, int dsk, ida_ioctl_t *io);static void do_ida_request(request_queue_t *q);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 bio *bio, int ok);static inline void complete_command(cmdlist_t *cmd, int timeout);static irqreturn_t do_ida_intr(int irq, void *dev_id, struct pt_regs * regs);static void ida_timer(unsigned long tdata);static int ida_revalidate(struct gendisk *disk);static int revalidate_allvol(ctlr_info_t *host);static int cpqarray_register_ctlr(int ctlr, struct pci_dev *pdev);#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) {}#endifstatic inline drv_info_t *get_drv(struct gendisk *disk){	return disk->private_data;}static inline ctlr_info_t *get_host(struct gendisk *disk){	return disk->queue->queuedata;}static struct block_device_operations ida_fops  = {	.owner		= THIS_MODULE,	.open		= ida_open,	.release	= ida_release,	.ioctl		= ida_ioctl,	.revalidate_disk= ida_revalidate,};#ifdef CONFIG_PROC_FSstatic struct proc_dir_entry *proc_array;/* * 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("cpqarray", proc_root_driver);		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;	unsigned long flags;#endif	ctlr = h->ctlr;	size = sprintf(buffer, "%s:  Compaq %s Controller\n"		"       Board ID: 0x%08lx\n"		"       Firmware Revision: %c%c%c%c\n"		"       Controller Sig: 0x%08lx\n"		"       Memory Address: 0x%08lx\n"		"       I/O Port: 0x%04x\n"		"       IRQ: %d\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->io_mem_addr, (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	spin_lock_irqsave(IDA_LOCK(h->ctlr), flags); 	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;	spin_unlock_irqrestore(IDA_LOCK(h->ctlr), flags); #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 */module_param_array(eisa, int, NULL, 0);static void release_io_mem(ctlr_info_t *c){	/* if IO mem was not protected do nothing */	if( c->io_mem_addr == 0)		return;	release_region(c->io_mem_addr, c->io_mem_length);	c->io_mem_addr = 0;	c->io_mem_length = 0;}static void __devexit cpqarray_remove_one(int i){	int j;	char buff[4];	/* sendcmd will turn off interrupt, and send the flush...	 * To write all data in the battery backed cache to disks	 * no data returned, but don't want to send NULL to sendcmd */	if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0))	{		printk(KERN_WARNING "Unable to flush cache on controller %d\n",				i);	}	free_irq(hba[i]->intr, hba[i]);	iounmap(hba[i]->vaddr);	unregister_blkdev(COMPAQ_SMART2_MAJOR+i, hba[i]->devname);	del_timer(&hba[i]->timer);	remove_proc_entry(hba[i]->devname, proc_array);	pci_free_consistent(hba[i]->pci_dev,			NR_CMDS * sizeof(cmdlist_t), (hba[i]->cmd_pool),			hba[i]->cmd_pool_dhandle);	kfree(hba[i]->cmd_pool_bits);	for(j = 0; j < NWD; j++) {		if (ida_gendisk[i][j]->flags & GENHD_FL_UP)			del_gendisk(ida_gendisk[i][j]);		devfs_remove("ida/c%dd%d",i,j);		put_disk(ida_gendisk[i][j]);	}	blk_cleanup_queue(hba[i]->queue);	release_io_mem(hba[i]);	free_hba(i);}static void __devexit cpqarray_remove_one_pci (struct pci_dev *pdev){	int i;	ctlr_info_t *tmp_ptr;	if (pci_get_drvdata(pdev) == NULL) {		printk( KERN_ERR "cpqarray: Unable to remove device \n");		return;	}	tmp_ptr = pci_get_drvdata(pdev);	i = tmp_ptr->ctlr;	if (hba[i] == NULL) {		printk(KERN_ERR "cpqarray: controller %d appears to have"			"already been removed \n", i);		return;        }	pci_set_drvdata(pdev, NULL);	cpqarray_remove_one(i);}/* removing an instance that was not removed automatically.. * must be an eisa card. */static void __devexit cpqarray_remove_one_eisa (int i){	if (hba[i] == NULL) {		printk(KERN_ERR "cpqarray: controller %d appears to have"			"already been removed \n", i);		return;        }	cpqarray_remove_one(i);}/* pdev is NULL for eisa */static int cpqarray_register_ctlr( int i, struct pci_dev *pdev){	request_queue_t *q;	int j;	/* 	 * register block devices	 * Find disks and fill in structs	 * Get an interrupt, set the Q depth and get into /proc	 */	/* If this successful it should insure that we are the only */	/* instance of the driver */	if (register_blkdev(COMPAQ_SMART2_MAJOR+i, hba[i]->devname)) {		goto Enomem4;	}	hba[i]->access.set_intr_mask(hba[i], 0);	if (request_irq(hba[i]->intr, do_ida_intr,		SA_INTERRUPT|SA_SHIRQ|SA_SAMPLE_RANDOM,		hba[i]->devname, hba[i]))	{		printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n",				hba[i]->intr, hba[i]->devname);		goto Enomem3;	}			for (j=0; j<NWD; j++) {		ida_gendisk[i][j] = alloc_disk(1 << NWD_SHIFT);		if (!ida_gendisk[i][j])			goto Enomem2;	}	hba[i]->cmd_pool = (cmdlist_t *)pci_alloc_consistent(		hba[i]->pci_dev, NR_CMDS * sizeof(cmdlist_t),		&(hba[i]->cmd_pool_dhandle));	hba[i]->cmd_pool_bits = kmalloc(		((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long),		GFP_KERNEL);	if (!hba[i]->cmd_pool_bits || !hba[i]->cmd_pool)			goto Enomem1;	memset(hba[i]->cmd_pool, 0, NR_CMDS * sizeof(cmdlist_t));	memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long));	printk(KERN_INFO "cpqarray: Finding drives on %s",		hba[i]->devname);	spin_lock_init(&hba[i]->lock);	q = blk_init_queue(do_ida_request, &hba[i]->lock);	if (!q)		goto Enomem1;	hba[i]->queue = q;	q->queuedata = hba[i];	getgeometry(i);	start_fwbk(i);	ida_procinit(i);	if (pdev)		blk_queue_bounce_limit(q, hba[i]->pci_dev->dma_mask);	/* This is a hardware imposed limit. */	blk_queue_max_hw_segments(q, SG_MAX);	/* This is a driver limit and could be eliminated. */	blk_queue_max_phys_segments(q, SG_MAX);		init_timer(&hba[i]->timer);	hba[i]->timer.expires = jiffies + IDA_TIMER;

⌨️ 快捷键说明

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