📄 cpqarray.c
字号:
if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL) { nr_ctlr = i; if(hba[i]->cmd_pool_bits) kfree(hba[i]->cmd_pool_bits); if(hba[i]->cmd_pool) kfree(hba[i]->cmd_pool); free_irq(hba[i]->intr, hba[i]); unregister_blkdev(MAJOR_NR+i, hba[i]->devname); num_cntlrs_reg--; printk( KERN_ERR "cpqarray: out of memory"); /* If num_cntlrs_reg == 0, no controllers worked. * init_module will fail, so clean up global * memory that clean_module would do. */ if (num_cntlrs_reg == 0) { kfree(ida); kfree(ida_sizes); kfree(ida_hardsizes); kfree(ida_blocksizes); } return(num_cntlrs_reg); } memset(hba[i]->cmd_pool, 0, NR_CMDS * sizeof(cmdlist_t)); memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+31)/32)*sizeof(__u32)); printk(KERN_INFO "cpqarray: Finding drives on %s", hba[i]->devname); getgeometry(i); start_fwbk(i); hba[i]->access.set_intr_mask(hba[i], FIFO_NOT_EMPTY); ida_procinit(i); blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + i), request_fns[i]); blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR + i), 0); blksize_size[MAJOR_NR+i] = ida_blocksizes + (i*256); hardsect_size[MAJOR_NR+i] = ida_hardsizes + (i*256); read_ahead[MAJOR_NR+i] = READ_AHEAD; ida_gendisk[i].major = MAJOR_NR + i; ida_gendisk[i].major_name = "ida"; ida_gendisk[i].minor_shift = NWD_SHIFT; ida_gendisk[i].max_p = 16; ida_gendisk[i].part = ida + (i*256); ida_gendisk[i].sizes = ida_sizes + (i*256); ida_gendisk[i].nr_real = 0; /* Get on the disk list */ ida_gendisk[i].next = gendisk_head; gendisk_head = &ida_gendisk[i]; 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); ida_geninit(i); for(j=0; j<NWD; j++) register_disk(&ida_gendisk[i], MKDEV(MAJOR_NR+i,j<<4), 16, &ida_fops, hba[i]->drv[j].nr_blks); } /* done ! */ return(num_cntlrs_reg);}/* * Find the controller and initialize it * Cannot use the class code to search, because older array controllers use * 0x018000 and new ones use 0x010400. So I might as well search for each * each device IDs, being there are only going to be three of them. */static int cpqarray_pci_detect(void){ struct pci_dev *pdev;#define IDA_BOARD_TYPES 3 static int ida_vendor_id[IDA_BOARD_TYPES] = { PCI_VENDOR_ID_DEC, PCI_VENDOR_ID_NCR, PCI_VENDOR_ID_COMPAQ }; static int ida_device_id[IDA_BOARD_TYPES] = { PCI_DEVICE_ID_COMPAQ_42XX, PCI_DEVICE_ID_NCR_53C1510, PCI_DEVICE_ID_COMPAQ_SMART2P }; int brdtype; /* search for all PCI board types that could be for this driver */ for(brdtype=0; brdtype<IDA_BOARD_TYPES; brdtype++) { pdev = pci_find_device(ida_vendor_id[brdtype], ida_device_id[brdtype], NULL); while (pdev) { printk(KERN_DEBUG "cpqarray: Device %x has been found at %x %x\n", ida_vendor_id[brdtype], pdev->bus->number, pdev->devfn); if (nr_ctlr == 8) { printk(KERN_WARNING "cpqarray: This driver" " supports a maximum of 8 controllers.\n"); break; } /* if it is a PCI_DEVICE_ID_NCR_53C1510, make sure it's the Compaq version of the chip */ if (ida_device_id[brdtype] == PCI_DEVICE_ID_NCR_53C1510) { unsigned short subvendor=pdev->subsystem_vendor; if(subvendor != PCI_VENDOR_ID_COMPAQ) { printk(KERN_DEBUG "cpqarray: not a Compaq integrated array controller\n"); continue; } } hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL); if(hba[nr_ctlr]==NULL) { printk(KERN_ERR "cpqarray: out of memory.\n"); continue; } memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t)); if (cpqarray_pci_init(hba[nr_ctlr], pdev) != 0) { kfree(hba[nr_ctlr]); continue; } sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr); hba[nr_ctlr]->ctlr = nr_ctlr; nr_ctlr++; pdev = pci_find_device(ida_vendor_id[brdtype], ida_device_id[brdtype], pdev); } } return nr_ctlr;}/* * Find the IO address of the controller, its IRQ and so forth. Fill * in some basic stuff into the ctlr_info_t structure. */static int cpqarray_pci_init(ctlr_info_t *c, struct pci_dev *pdev){ ushort vendor_id, device_id, command; unchar cache_line_size, latency_timer; unchar irq, revision; unsigned long addr[6]; __u32 board_id; int i; c->pci_dev = pdev; vendor_id = pdev->vendor; device_id = pdev->device; irq = pdev->irq; for(i=0; i<6; i++) addr[i] = pci_resource_start(pdev, i); if (pci_enable_device(pdev)) return -1; pci_read_config_word(pdev, PCI_COMMAND, &command); pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line_size); pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_timer); pci_read_config_dword(pdev, 0x2c, &board_id);DBGINFO( printk("vendor_id = %x\n", vendor_id); printk("device_id = %x\n", device_id); printk("command = %x\n", command); for(i=0; i<6; i++) printk("addr[%d] = %lx\n", i, addr[i]); printk("revision = %x\n", revision); printk("irq = %x\n", irq); printk("cache_line_size = %x\n", cache_line_size); printk("latency_timer = %x\n", latency_timer); printk("board_id = %x\n", board_id);); c->intr = irq; c->ioaddr = addr[0]; c->paddr = 0; for(i=0; i<6; i++) if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { c->paddr = pci_resource_start (pdev, i); break; } if (!c->paddr) return -1; c->vaddr = remap_pci_mem(c->paddr, 128); if (!c->vaddr) return -1; c->board_id = board_id; for(i=0; i<NR_PRODUCTS; i++) { if (board_id == products[i].board_id) { c->product_name = products[i].product_name; c->access = *(products[i].access); break; } } if (i == NR_PRODUCTS) { printk(KERN_WARNING "cpqarray: Sorry, I don't know how" " to access the SMART Array controller %08lx\n", (unsigned long)board_id); return -1; } return 0;}/* * Map (physical) PCI mem into (virtual) kernel space */static void *remap_pci_mem(ulong base, ulong size){ ulong page_base = ((ulong) base) & PAGE_MASK; ulong page_offs = ((ulong) base) - page_base; void *page_remapped = ioremap(page_base, page_offs+size); return (page_remapped ? (page_remapped + page_offs) : NULL);}#ifndef MODULE#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13)/* * Config string is a comma seperated set of i/o addresses of EISA cards. */static int cpqarray_setup(char *str){ int i, ints[9]; (void)get_options(str, ARRAY_SIZE(ints), ints); for(i=0; i<ints[0] && i<8; i++) eisa[i] = ints[i+1]; return 1;}__setup("smart2=", cpqarray_setup);#else/* * Copy the contents of the ints[] array passed to us by init. */void cpqarray_setup(char *str, int *ints){ int i; for(i=0; i<ints[0] && i<8; i++) eisa[i] = ints[i+1];}#endif#endif/* * Find an EISA controller's signature. Set up an hba if we find it. */static int cpqarray_eisa_detect(void){ int i=0, j; __u32 board_id; int intr; while(i<8 && eisa[i]) { if (nr_ctlr == 8) { printk(KERN_WARNING "cpqarray: This driver supports" " a maximum of 8 controllers.\n"); break; } board_id = inl(eisa[i]+0xC80); for(j=0; j < NR_PRODUCTS; j++) if (board_id == products[j].board_id) break; if (j == NR_PRODUCTS) { printk(KERN_WARNING "cpqarray: Sorry, I don't know how" " to access the SMART Array controller %08lx\n", (unsigned long)board_id); continue; } hba[nr_ctlr] = (ctlr_info_t *) kmalloc(sizeof(ctlr_info_t), GFP_KERNEL); if(hba[nr_ctlr]==NULL) { printk(KERN_ERR "cpqarray: out of memory.\n"); continue; } memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t)); hba[nr_ctlr]->ioaddr = eisa[i]; /* * Read the config register to find our interrupt */ intr = inb(eisa[i]+0xCC0) >> 4; if (intr & 1) intr = 11; else if (intr & 2) intr = 10; else if (intr & 4) intr = 14; else if (intr & 8) intr = 15; hba[nr_ctlr]->intr = intr; sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr); hba[nr_ctlr]->product_name = products[j].product_name; hba[nr_ctlr]->access = *(products[j].access); hba[nr_ctlr]->ctlr = nr_ctlr; hba[nr_ctlr]->board_id = board_id; hba[nr_ctlr]->pci_dev = NULL; /* not PCI */DBGINFO( printk("i = %d, j = %d\n", i, j); printk("irq = %x\n", intr); printk("product name = %s\n", products[j].product_name); printk("board_id = %x\n", board_id);); nr_ctlr++; i++; } return nr_ctlr;}/* * Open. Make sure the device is really there. */static int ida_open(struct inode *inode, struct file *filep){ int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; DBGINFO(printk("ida_open %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) ); if (ctlr > MAX_CTLR || hba[ctlr] == NULL) return -ENXIO; if (!suser() && ida_sizes[(ctlr << CTLR_SHIFT) + MINOR(inode->i_rdev)] == 0) return -ENXIO; /* * Root is allowed to open raw volume zero even if its not configured * so array config can still work. I don't think I really like this, * but I'm already using way to many device nodes to claim another one * for "raw controller". */ if (suser() && ida_sizes[(ctlr << CTLR_SHIFT) + MINOR(inode->i_rdev)] == 0 && MINOR(inode->i_rdev) != 0) return -ENXIO; hba[ctlr]->drv[dsk].usage_count++; hba[ctlr]->usage_count++; MOD_INC_USE_COUNT; return 0;}/* * Close. Sync first. */static int ida_release(struct inode *inode, struct file *filep){ int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; DBGINFO(printk("ida_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) ); hba[ctlr]->drv[dsk].usage_count--; hba[ctlr]->usage_count--; MOD_DEC_USE_COUNT; return 0;}/* * Enqueuing and dequeuing functions for cmdlists. */static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c){ if (*Qptr == NULL) { *Qptr = c; c->next = c->prev = c; } else { c->prev = (*Qptr)->prev; c->next = (*Qptr); (*Qptr)->prev->next = c; (*Qptr)->prev = c; }}static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c){ if (c && c->next != c) { if (*Qptr == c) *Qptr = c->next; c->prev->next = c->next; c->next->prev = c->prev; } else { *Qptr = NULL; } return c;}/* * Get a request and submit it to the controller. * This routine needs to grab all the requests it possibly can from the * req Q and submit them. Interrupts are off (and need to be off) when you * are in here (either via the dummy do_ida_request functions or by being * called from the interrupt handler */static void do_ida_request(int ctlr){ ctlr_info_t *h = hba[ctlr]; cmdlist_t *c; int seg, sect; char *lastdataend; struct list_head * queue_head; struct buffer_head *bh; struct request *creq; queue_head = &blk_dev[MAJOR_NR+ctlr].request_queue.queue_head; if (list_empty(queue_head)) { start_io(h); return; } creq = blkdev_entry_next_request(queue_head); if (creq->rq_status == RQ_INACTIVE) { start_io(h); return; } if (ctlr != MAJOR(creq->rq_dev)-MAJOR_NR || ctlr > nr_ctlr || h == NULL) { printk(KERN_WARNING "doreq cmd for %d, %x at %p\n", ctlr, creq->rq_dev, creq); complete_buffers(creq->bh, 0); start_io(h); return; } if ((c = cmd_alloc(h)) == NULL) { start_io(h); return; } bh = creq->bh; c->ctlr = ctlr; c->hdr.unit = MINOR(creq->rq_dev) >> NWD_SHIFT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -