1803 lines · 46.7 KB · C
RawDownload
/* *    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/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/seq_file.h>#include <linux/init.h>#include <linux/hdreg.h>#include <linux/spinlock.h>#include <linux/blkdev.h>#include <linux/genhd.h>#include <linux/scatterlist.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 ARRAY_SIZE(products) /*  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 block_device *bdev, fmode_t mode);static int ida_release(struct gendisk *disk, fmode_t mode);static int ida_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg);static int ida_getgeo(struct block_device *bdev, struct hd_geometry *geo);static int ida_ctlr_ioctl(ctlr_info_t *h, int dsk, ida_ioctl_t *io); static void do_ida_request(struct request_queue *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_command(cmdlist_t *cmd, int timeout); static irqreturn_t do_ida_intr(int irq, void *dev_id);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);#elsestatic void ida_procinit(int i) {}#endif static 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 const struct block_device_operations ida_fops  = {	.owner		= THIS_MODULE,	.open		= ida_open,	.release	= ida_release,	.locked_ioctl	= ida_ioctl,	.getgeo		= ida_getgeo,	.revalidate_disk= ida_revalidate,};  #ifdef CONFIG_PROC_FS static struct proc_dir_entry *proc_array;static const struct file_operations ida_proc_fops; /* * 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/cpqarray", NULL);		if (!proc_array) return;	} 	proc_create_data(hba[i]->devname, 0, proc_array, &ida_proc_fops, hba[i]);} /* * Report information about this controller. */static int ida_proc_show(struct seq_file *m, void *v){	int i, ctlr;	ctlr_info_t *h = (ctlr_info_t*)m->private;	drv_info_t *drv;#ifdef CPQ_PROC_PRINT_QUEUES	cmdlist_t *c;	unsigned long flags;#endif 	ctlr = h->ctlr;	seq_printf(m, "%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); 	seq_puts(m, "Logical Drive Info:\n"); 	for(i=0; i<h->log_drives; i++) {		drv = &h->drv[i];		seq_printf(m, "ida/c%dd%d: blksz=%d nr_blks=%d\n",				ctlr, i, drv->blk_size, drv->nr_blks);	} #ifdef CPQ_PROC_PRINT_QUEUES	spin_lock_irqsave(IDA_LOCK(h->ctlr), flags); 	seq_puts(m, "\nCurrent Queues:\n"); 	c = h->reqQ;	seq_printf(m, "reqQ = %p", c);	if (c) c=c->next;	while(c && c != h->reqQ) {		seq_printf(m, "->%p", c);		c=c->next;	} 	c = h->cmpQ;	seq_printf(m, "\ncmpQ = %p", c);	if (c) c=c->next;	while(c && c != h->cmpQ) {		seq_printf(m, "->%p", c);		c=c->next;	} 	seq_putc(m, '\n');	spin_unlock_irqrestore(IDA_LOCK(h->ctlr), flags); #endif	seq_printf(m, "nr_allocs = %d\nnr_frees = %d\n",			h->nr_allocs, h->nr_frees);	return 0;} static int ida_proc_open(struct inode *inode, struct file *file){	return single_open(file, ida_proc_show, PDE(inode)->data);} static const struct file_operations ida_proc_fops = {	.owner		= THIS_MODULE,	.open		= ida_proc_open,	.read		= seq_read,	.llseek		= seq_lseek,	.release	= single_release,};#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]);		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 __init cpqarray_register_ctlr( int i, struct pci_dev *pdev){	struct request_queue *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,		IRQF_DISABLED|IRQF_SHARED, 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 = pci_alloc_consistent(		hba[i]->pci_dev, NR_CMDS * sizeof(cmdlist_t),		&(hba[i]->cmd_pool_dhandle));	hba[i]->cmd_pool_bits = kcalloc(		DIV_ROUND_UP(NR_CMDS, 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));	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_segments(q, SG_MAX); 	init_timer(&hba[i]->timer);	hba[i]->timer.expires = jiffies + IDA_TIMER;	hba[i]->timer.data = (unsigned long)hba[i];	hba[i]->timer.function = ida_timer;	add_timer(&hba[i]->timer); 	/* Enable IRQ now that spinlock and rate limit timer are set up */	hba[i]->access.set_intr_mask(hba[i], FIFO_NOT_EMPTY); 	for(j=0; j<NWD; j++) {		struct gendisk *disk = ida_gendisk[i][j];		drv_info_t *drv = &hba[i]->drv[j];		sprintf(disk->disk_name, "ida/c%dd%d", i, j);		disk->major = COMPAQ_SMART2_MAJOR + i;		disk->first_minor = j<<NWD_SHIFT;		disk->fops = &ida_fops;		if (j && !drv->nr_blks)			continue;		blk_queue_logical_block_size(hba[i]->queue, drv->blk_size);		set_capacity(disk, drv->nr_blks);		disk->queue = hba[i]->queue;		disk->private_data = drv;		add_disk(disk);	} 	/* done ! */	return(i); Enomem1:	nr_ctlr = i; 	kfree(hba[i]->cmd_pool_bits);	if (hba[i]->cmd_pool)		pci_free_consistent(hba[i]->pci_dev, NR_CMDS*sizeof(cmdlist_t), 				    hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);Enomem2:	while (j--) {		put_disk(ida_gendisk[i][j]);		ida_gendisk[i][j] = NULL;	}	free_irq(hba[i]->intr, hba[i]);Enomem3:	unregister_blkdev(COMPAQ_SMART2_MAJOR+i, hba[i]->devname);Enomem4:	if (pdev)		pci_set_drvdata(pdev, NULL);	release_io_mem(hba[i]);	free_hba(i); 

Lines 1–500 of 1803.