📄 cpqarray.c
字号:
/* * 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 + -