📄 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 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 + -