📄 cciss.c
字号:
addr[i] = pdev->resource[i].start; if (pci_enable_device(pdev)) return( -1); (void) pci_read_config_word(pdev, PCI_COMMAND,&command); (void) pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); (void) pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line_size); (void) pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_timer); (void) pci_read_config_dword(pdev, PCI_SUBSYSTEM_VENDOR_ID, &board_id);#ifdef CCISS_DEBUG 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] = %x\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);#endif /* CCISS_DEBUG */ c->intr = irq; /* * Memory base addr is first addr , the second points to the config * table */ c->paddr = pci_resource_start(pdev, 0); c->vaddr = remap_pci_mem(c->paddr, 128); c->cfgtable = (CfgTable_struct *) remap_pci_mem(addr[1], sizeof(CfgTable_struct)); c->board_id = board_id;#ifdef CCISS_DEBUG print_cfg_table(c->cfgtable); #endif /* CCISS_DEBUG */ 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 "cciss: Sorry, I don't know how" " to access the Smart Array controller %08lx\n", (unsigned long)board_id); return -1; }#ifdef CCISS_DEBUG printk("Trying to put board into Simple mode\n");#endif /* CCISS_DEBUG */ c->max_commands = readl(&(c->cfgtable->CmdsOutMax)); /* Update the field, and then ring the doorbell */ writel( CFGTBL_Trans_Simple, &(c->cfgtable->HostWrite.TransportRequest)); writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL); for(i=0;i<MAX_CONFIG_WAIT;i++) { if (!(readl(c->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq)) break; /* delay and try again */ udelay(1000); } #ifdef CCISS_DEBUG printk(KERN_DEBUG "I counter got to %d %x\n", i, readl(c->vaddr + SA5_DOORBELL));#endif /* CCISS_DEBUG */#ifdef CCISS_DEBUG print_cfg_table(c->cfgtable); #endif /* CCISS_DEBUG */ if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) { printk(KERN_WARNING "cciss: unable to get board into" " simple mode\n"); return -1; } return 0;}/* * Scans PCI space for any controllers that this driver can control. */static int cciss_pci_detect(void){ int index; unchar bus=0, dev_fn=0; for(index=0; ; index++) { if (pcibios_find_device(PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISS, index, &bus, &dev_fn)) break; printk(KERN_DEBUG "cciss: Device %x has been found at %x %x\n", PCI_DEVICE_ID_COMPAQ_CISS, bus, dev_fn); if (index == 1000000) break; if (nr_ctlr == 8) { printk(KERN_WARNING "cciss: This driver" " supports a maximum of 8 controllers.\n"); break; } hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL); if(hba[nr_ctlr]==NULL) { printk(KERN_ERR "cciss: out of memory.\n"); continue; } memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t)); if (cciss_pci_init(hba[nr_ctlr], bus, dev_fn) != 0) { kfree(hba[nr_ctlr]); continue; } sprintf(hba[nr_ctlr]->devname, "cciss%d", nr_ctlr); hba[nr_ctlr]->ctlr = nr_ctlr; hba[nr_ctlr]->pci_bus = bus; hba[nr_ctlr]->pci_dev_fn = dev_fn; nr_ctlr++; } return nr_ctlr;}/* * Gets information about the local volumes attached to the controller. */ static void cciss_getgeometry(int cntl_num){ ReportLunData_struct *ld_buff; ReadCapdata_struct *size_buff; InquiryData_struct *inq_buff; int return_code; int i; int listlength = 0; int lunid = 0; int block_size; int total_size; ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL); if (ld_buff == NULL) { printk(KERN_ERR "cciss: out of memory\n"); return; } memset(ld_buff, 0, sizeof(ReportLunData_struct)); size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL); if (size_buff == NULL) { printk(KERN_ERR "cciss: out of memory\n"); kfree(ld_buff); return; } inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL); if (inq_buff == NULL) { printk(KERN_ERR "cciss: out of memory\n"); kfree(ld_buff); kfree(size_buff); return; } /* Get the firmware version */ return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, sizeof(InquiryData_struct), 0, 0 ,0 ); if (return_code == IO_OK) { hba[cntl_num]->firm_ver[0] = inq_buff->data_byte[32]; hba[cntl_num]->firm_ver[1] = inq_buff->data_byte[33]; hba[cntl_num]->firm_ver[2] = inq_buff->data_byte[34]; hba[cntl_num]->firm_ver[3] = inq_buff->data_byte[35]; } else /* send command failed */ { printk(KERN_WARNING "cciss: unable to determine firmware" " version of controller\n"); } /* Get the number of logical volumes */ return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff, sizeof(ReportLunData_struct), 0, 0, 0 ); if( return_code == IO_OK) {#ifdef CCISS_DEBUG printk("LUN Data\n--------------------------\n");#endif /* CCISS_DEBUG */ listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24; listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16; listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8; listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]); } else /* reading number of logical volumes failed */ { printk(KERN_WARNING "cciss: report logical volume" " command failed\n"); listlength = 0; } hba[cntl_num]->num_luns = listlength / 8; // 8 bytes pre entry if (hba[cntl_num]->num_luns > CISS_MAX_LUN) { printk(KERN_ERR "ciss: only %d number of logical volumes supported\n", CISS_MAX_LUN); hba[cntl_num]->num_luns = CISS_MAX_LUN; }#ifdef CCISS_DEBUG printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0], ld_buff->LUNListLength[1], ld_buff->LUNListLength[2], ld_buff->LUNListLength[3], hba[cntl_num]->num_luns);#endif /* CCISS_DEBUG */ for(i=0; i< hba[cntl_num]->num_luns ; i++) { lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24; lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16; lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8; lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]); hba[cntl_num]->drv[i].LunID = lunid;#ifdef CCISS_DEBUG printk(KERN_DEBUG "LUN[%d]: %x %x %x %x = %x\n", i, ld_buff->LUN[i][0], ld_buff->LUN[i][1],ld_buff->LUN[i][2], ld_buff->LUN[i][3], hba[cntl_num]->drv[i].LunID);#endif /* CCISS_DEBUG */ memset(size_buff, 0, sizeof(ReadCapdata_struct)); return_code = sendcmd(CCISS_READ_CAPACITY, cntl_num, size_buff, sizeof( ReadCapdata_struct), 1, i, 0 ); if (return_code == IO_OK) { total_size = (0xff & (unsigned int)(size_buff->total_size[0])) << 24; total_size |= (0xff & (unsigned int)(size_buff->total_size[1])) << 16; total_size |= (0xff & (unsigned int)(size_buff->total_size[2])) << 8; total_size |= (0xff & (unsigned int) (size_buff->total_size[3])); total_size++; // command returns highest block address block_size = (0xff & (unsigned int)(size_buff->block_size[0])) << 24; block_size |= (0xff & (unsigned int)(size_buff->block_size[1])) << 16; block_size |= (0xff & (unsigned int)(size_buff->block_size[2])) << 8; block_size |= (0xff & (unsigned int)(size_buff->block_size[3])); } else /* read capacity command failed */ { printk(KERN_WARNING "cciss: read capacity failed\n"); total_size = block_size = 0; } printk(" blocks= %d block_size= %d\n", total_size, block_size); /* Execute the command to read the disk geometry */ memset(inq_buff, 0, sizeof(InquiryData_struct)); return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, sizeof(InquiryData_struct), 1, i ,0xC1 ); if (return_code == IO_OK) { if(inq_buff->data_byte[8] == 0xFF) { printk(KERN_WARNING "cciss: reading geometry failed, volume does not support reading geometry\n"); hba[cntl_num]->drv[i].block_size = block_size; hba[cntl_num]->drv[i].nr_blocks = total_size; hba[cntl_num]->drv[i].heads = 255; hba[cntl_num]->drv[i].sectors = 32; // Sectors per track hba[cntl_num]->drv[i].cylinders = total_size / 255 / 32; } else { hba[cntl_num]->drv[i].block_size = block_size; hba[cntl_num]->drv[i].nr_blocks = total_size; hba[cntl_num]->drv[i].heads = inq_buff->data_byte[6]; hba[cntl_num]->drv[i].sectors = inq_buff->data_byte[7]; hba[cntl_num]->drv[i].cylinders = (inq_buff->data_byte[4] & 0xff) << 8; hba[cntl_num]->drv[i].cylinders += inq_buff->data_byte[5]; } } else /* Get geometry failed */ { printk(KERN_WARNING "cciss: reading geometry failed, continuing with default geometry\n"); hba[cntl_num]->drv[i].block_size = block_size; hba[cntl_num]->drv[i].nr_blocks = total_size; hba[cntl_num]->drv[i].heads = 255; hba[cntl_num]->drv[i].sectors = 32; // Sectors per track hba[cntl_num]->drv[i].cylinders = total_size / 255 / 32; } printk(KERN_INFO " heads= %d, sectors= %d, cylinders= %d\n\n", hba[cntl_num]->drv[i].heads, hba[cntl_num]->drv[i].sectors, hba[cntl_num]->drv[i].cylinders); } kfree(ld_buff); kfree(size_buff);} /* * 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 cciss_init(void){ int num_cntlrs_reg = 0; int i,j; void (*request_fns[MAX_CTLR])(request_queue_t *) = { do_cciss_request0, do_cciss_request1, do_cciss_request2, do_cciss_request3, do_cciss_request4, do_cciss_request5, do_cciss_request6, do_cciss_request7, }; /* detect controllers */ cciss_pci_detect(); if (nr_ctlr == 0) return(num_cntlrs_reg); printk(KERN_INFO DRIVER_NAME "\n"); printk(KERN_INFO "Found %d controller(s)\n", nr_ctlr); for(i=0;i<nr_ctlr;i++) { if( register_blkdev(MAJOR_NR+i, hba[i]->devname, &cciss_fops)) { printk(KERN_ERR "cciss: Unable to get major number " "%d for %s\n", MAJOR_NR+i, hba[i]->devname); continue; } /* make sure the board interrupts are off */ hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); if( request_irq(hba[i]->intr, do_cciss_intr, SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i])) { printk(KERN_ERR "ciss: 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_bits = (__u32*)kmalloc( ((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL); hba[i]->cmd_pool = (CommandList_struct *)kmalloc( NR_CMDS * sizeof(CommandList_struct), GFP_KERNEL); hba[i]->errinfo_pool = (ErrorInfo_struct *)kmalloc( NR_CMDS * sizeof( ErrorInfo_struct), GFP_KERNEL); if((hba[i]->cmd_pool_bits == NULL) || (hba[i]->cmd_pool == NULL) || (hba[i]->errinfo_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); if(hba[i]->errinfo_pool) kfree(hba[i]->errinfo_pool); free_irq(hba[i]->intr, hba[i]); unregister_blkdev(MAJOR_NR+i, hba[i]->devname); num_cntlrs_reg--; printk( KERN_ERR "cciss: out of memory"); return(num_cntlrs_reg); } /* command and error info recs zeroed out before they are used */ memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+31)/32)*sizeof(__u32));#ifdef CCISS_DEBUG printk(KERN_DEBUG "Scanning for drives on controller cciss%d\n",i);#endif /* CCISS_DEBUG */ cciss_getgeometry(i); /* Turn the interrupts on so we can service requests */ hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_ON); cciss_procinit(i); blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR+i), request_fns[i]); blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR+i), 0); /* fill in the other Kernel structs */ blksize_size[MAJOR_NR+i] = hba[i]->blocksizes; hardsect_size[MAJOR_NR+i] = hba[i]->hardsizes; read_ahead[MAJOR_NR+i] = READ_AHEAD; /* Fill in the gendisk data */ hba[i]->gendisk.major = MAJOR_NR + i; hba[i]->gendisk.major_name = "cciss"; hba[i]->gendisk.minor_shift = NWD_SHIFT; hba[i]->gendisk.max_p = MAX_PART; hba[i]->gendisk.part = hba[i]->hd; hba[i]->gendisk.sizes = hba[i]->sizes; hba[i]->gendisk.nr_real = hba[i]->num_luns; /* Get on the disk list */ hba[i]->gendisk.next = gendisk_head; gendisk_head = &(hba[i]->gendisk); cciss_geninit(i); for(j=0; j<NWD; j++) register_disk(&(hba[i]->gendisk), MKDEV(MAJOR_NR+i, j <<4), MAX_PART, &cciss_fops, hba[i]->drv[j].nr_blocks); } return(nr_ctlr);}EXPORT_NO_SYMBOLS;/* This is a bit of a hack... */static int __init init_cciss_module(void){ if (cciss_init() == 0) /* all the block dev numbers already used */ return -EIO; /* or no controllers were found */ return 0;}static void __exit cleanup_cciss_module(void){ int i; struct gendisk *g; for(i=0; i<nr_ctlr; i++) { /* Turn board interrupts off */ hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); free_irq(hba[i]->intr, hba[i]); iounmap((void*)hba[i]->vaddr); unregister_blkdev(MAJOR_NR+i, hba[i]->devname); remove_proc_entry(hba[i]->devname, proc_cciss); /* remove it from the disk list */ if (gendisk_head == &(hba[i]->gendisk)) { gendisk_head = hba[i]->gendisk.next; } else { for(g=gendisk_head; g ; g=g->next) { if(g->next == &(hba[i]->gendisk)) { g->next = hba[i]->gendisk.next; } } } remove_proc_entry("driver/cciss", &proc_root); kfree(hba[i]->cmd_pool); kfree(hba[i]->errinfo_pool); kfree(hba[i]->cmd_pool_bits); kfree(hba[i]); }}module_init(init_cciss_module);module_exit(cleanup_cciss_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -