📄 cpqarray.c
字号:
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_hardsect_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); printk( KERN_ERR "cpqarray: out of memory"); return -1;}static int __init cpqarray_init_one( struct pci_dev *pdev, const struct pci_device_id *ent){ int i; printk(KERN_DEBUG "cpqarray: Device 0x%x has been found at" " bus %d dev %d func %d\n", pdev->device, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); i = alloc_cpqarray_hba(); if( i < 0 ) return (-1); memset(hba[i], 0, sizeof(ctlr_info_t)); sprintf(hba[i]->devname, "ida%d", i); hba[i]->ctlr = i; /* Initialize the pdev driver private data */ pci_set_drvdata(pdev, hba[i]); if (cpqarray_pci_init(hba[i], pdev) != 0) { pci_set_drvdata(pdev, NULL); release_io_mem(hba[i]); free_hba(i); return -1; } return (cpqarray_register_ctlr(i, pdev));}static struct pci_driver cpqarray_pci_driver = { .name = "cpqarray", .probe = cpqarray_init_one, .remove = __devexit_p(cpqarray_remove_one_pci), .id_table = cpqarray_pci_device_id,};/* * This is it. Find all the controllers and register them. * returns the number of block devices registered. */static int __init cpqarray_init(void){ int num_cntlrs_reg = 0; int i; int rc = 0; /* detect controllers */ printk(DRIVER_NAME "\n"); rc = pci_register_driver(&cpqarray_pci_driver); if (rc) return rc; cpqarray_eisa_detect(); for (i=0; i < MAX_CTLR; i++) { if (hba[i] != NULL) num_cntlrs_reg++; } return(num_cntlrs_reg);}/* Function to find the first free pointer into our hba[] array *//* Returns -1 if no free entries are left. */static int alloc_cpqarray_hba(void){ int i; for(i=0; i< MAX_CTLR; i++) { if (hba[i] == NULL) { hba[i] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL); if(hba[i]==NULL) { printk(KERN_ERR "cpqarray: out of memory.\n"); return (-1); } return (i); } } printk(KERN_WARNING "cpqarray: This driver supports a maximum" " of 8 controllers.\n"); return(-1);}static void free_hba(int i){ kfree(hba[i]); hba[i]=NULL;}/* * 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; if (pci_enable_device(pdev)) { printk(KERN_ERR "cpqarray: Unable to Enable PCI device\n"); return -1; } 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_set_dma_mask(pdev, CPQARRAY_DMA_MASK) != 0) { printk(KERN_ERR "cpqarray: Unable to set DMA mask\n"); 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); /* check to see if controller has been disabled */ if(!(command & 0x02)) { printk(KERN_WARNING "cpqarray: controller appears to be disabled\n"); return(-1); }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; for(i=0; i<6; i++) { if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO) { /* IO space */ c->io_mem_addr = addr[i]; c->io_mem_length = pci_resource_end(pdev, i) - pci_resource_start(pdev, i) + 1; if(!request_region( c->io_mem_addr, c->io_mem_length, "cpqarray")) { printk( KERN_WARNING "cpqarray I/O memory range already in use addr %lx length = %ld\n", c->io_mem_addr, c->io_mem_length); c->io_mem_addr = 0; c->io_mem_length = 0; } break; } } c->paddr = 0; for(i=0; i<6; i++) if (!(pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO)) { 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 __iomem *remap_pci_mem(ulong base, ulong size){ ulong page_base = ((ulong) base) & PAGE_MASK; ulong page_offs = ((ulong) base) - page_base; void __iomem *page_remapped = ioremap(page_base, page_offs+size); return (page_remapped ? (page_remapped + page_offs) : NULL);}#ifndef MODULE/* * Config string is a comma separated 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);#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; int ctlr; int num_ctlr = 0; while(i<8 && eisa[i]) { ctlr = alloc_cpqarray_hba(); if(ctlr == -1) 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; } memset(hba[ctlr], 0, sizeof(ctlr_info_t)); hba[ctlr]->io_mem_addr = eisa[i]; hba[ctlr]->io_mem_length = 0x7FF; if(!request_region(hba[ctlr]->io_mem_addr, hba[ctlr]->io_mem_length, "cpqarray")) { printk(KERN_WARNING "cpqarray: I/O range already in " "use addr = %lx length = %ld\n", hba[ctlr]->io_mem_addr, hba[ctlr]->io_mem_length); free_hba(ctlr); continue; } /* * 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[ctlr]->intr = intr; sprintf(hba[ctlr]->devname, "ida%d", nr_ctlr); hba[ctlr]->product_name = products[j].product_name; hba[ctlr]->access = *(products[j].access); hba[ctlr]->ctlr = ctlr; hba[ctlr]->board_id = board_id; hba[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);); num_ctlr++; i++; if (cpqarray_register_ctlr(ctlr, NULL) == -1) printk(KERN_WARNING "cpqarray: Can't register EISA controller %d\n", ctlr); } return num_ctlr;}/* * Open. Make sure the device is really there. */static int ida_open(struct inode *inode, struct file *filep){ drv_info_t *drv = get_drv(inode->i_bdev->bd_disk); ctlr_info_t *host = get_host(inode->i_bdev->bd_disk); DBGINFO(printk("ida_open %s\n", inode->i_bdev->bd_disk->disk_name)); /* * Root is allowed to open raw volume zero even if it's 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 (!drv->nr_blks) { if (!capable(CAP_SYS_RAWIO)) return -ENXIO; if (!capable(CAP_SYS_ADMIN) && drv != host->drv) return -ENXIO; } host->usage_count++; return 0;}/* * Close. Sync first. */static int ida_release(struct inode *inode, struct file *filep){ ctlr_info_t *host = get_host(inode->i_bdev->bd_disk); host->usage_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(request_queue_t *q){ ctlr_info_t *h = q->queuedata; cmdlist_t *c; struct request *creq; struct scatterlist tmp_sg[SG_MAX]; int i, dir, seg; if (blk_queue_plugged(q)) goto startio;queue_next: creq = elv_next_request(q); if (!creq) goto startio; if (creq->nr_phys_segments > SG_MAX) BUG(); if ((c = cmd_alloc(h,1)) == NULL) goto startio; blkdev_dequeue_request(creq); c->ctlr = h->ctlr; c->hdr.unit = (drv_info_t *)(creq->rq_disk->private_data) - h->drv; c->hdr.size = sizeof(rblk_t) >> 2; c->size += sizeof(rblk_t); c->req.hdr.blk = creq->sector; c->rq = creq;DBGPX( printk("sector=%d, nr_sectors=%d\n", creq->sector, creq->nr_sectors);); seg = blk_rq_map_sg(q, creq, tmp_sg);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -