📄 aic94xx_init.c
字号:
struct kmem_cache *asd_dma_token_cache;struct kmem_cache *asd_ascb_cache;static int asd_create_global_caches(void){ if (!asd_dma_token_cache) { asd_dma_token_cache = kmem_cache_create(ASD_DRIVER_NAME "_dma_token", sizeof(struct asd_dma_tok), 0, SLAB_HWCACHE_ALIGN, NULL); if (!asd_dma_token_cache) { asd_printk("couldn't create dma token cache\n"); return -ENOMEM; } } if (!asd_ascb_cache) { asd_ascb_cache = kmem_cache_create(ASD_DRIVER_NAME "_ascb", sizeof(struct asd_ascb), 0, SLAB_HWCACHE_ALIGN, NULL); if (!asd_ascb_cache) { asd_printk("couldn't create ascb cache\n"); goto Err; } } return 0;Err: kmem_cache_destroy(asd_dma_token_cache); asd_dma_token_cache = NULL; return -ENOMEM;}static void asd_destroy_global_caches(void){ if (asd_dma_token_cache) kmem_cache_destroy(asd_dma_token_cache); asd_dma_token_cache = NULL; if (asd_ascb_cache) kmem_cache_destroy(asd_ascb_cache); asd_ascb_cache = NULL;}static int asd_register_sas_ha(struct asd_ha_struct *asd_ha){ int i; struct asd_sas_phy **sas_phys = kmalloc(ASD_MAX_PHYS * sizeof(struct asd_sas_phy), GFP_KERNEL); struct asd_sas_port **sas_ports = kmalloc(ASD_MAX_PHYS * sizeof(struct asd_sas_port), GFP_KERNEL); if (!sas_phys || !sas_ports) { kfree(sas_phys); kfree(sas_ports); return -ENOMEM; } asd_ha->sas_ha.sas_ha_name = (char *) asd_ha->name; asd_ha->sas_ha.lldd_module = THIS_MODULE; asd_ha->sas_ha.sas_addr = &asd_ha->hw_prof.sas_addr[0]; for (i = 0; i < ASD_MAX_PHYS; i++) { sas_phys[i] = &asd_ha->phys[i].sas_phy; sas_ports[i] = &asd_ha->ports[i]; } asd_ha->sas_ha.sas_phy = sas_phys; asd_ha->sas_ha.sas_port= sas_ports; asd_ha->sas_ha.num_phys= ASD_MAX_PHYS; asd_ha->sas_ha.lldd_queue_size = asd_ha->seq.can_queue; asd_ha->sas_ha.lldd_max_execute_num = lldd_max_execute_num; return sas_register_ha(&asd_ha->sas_ha);}static int asd_unregister_sas_ha(struct asd_ha_struct *asd_ha){ int err; err = sas_unregister_ha(&asd_ha->sas_ha); sas_remove_host(asd_ha->sas_ha.core.shost); scsi_remove_host(asd_ha->sas_ha.core.shost); scsi_host_put(asd_ha->sas_ha.core.shost); kfree(asd_ha->sas_ha.sas_phy); kfree(asd_ha->sas_ha.sas_port); return err;}static int __devinit asd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id){ struct asd_pcidev_struct *asd_dev; unsigned asd_id = (unsigned) id->driver_data; struct asd_ha_struct *asd_ha; struct Scsi_Host *shost; int err; if (asd_id >= ARRAY_SIZE(asd_pcidev_data)) { asd_printk("wrong driver_data in PCI table\n"); return -ENODEV; } if ((err = pci_enable_device(dev))) { asd_printk("couldn't enable device %s\n", pci_name(dev)); return err; } pci_set_master(dev); err = -ENOMEM; shost = scsi_host_alloc(&aic94xx_sht, sizeof(void *)); if (!shost) goto Err; asd_dev = &asd_pcidev_data[asd_id]; asd_ha = kzalloc(sizeof(*asd_ha), GFP_KERNEL); if (!asd_ha) { asd_printk("out of memory\n"); goto Err_put; } asd_ha->pcidev = dev; asd_ha->sas_ha.dev = &asd_ha->pcidev->dev; asd_ha->sas_ha.lldd_ha = asd_ha; asd_ha->name = asd_dev->name; asd_printk("found %s, device %s\n", asd_ha->name, pci_name(dev)); SHOST_TO_SAS_HA(shost) = &asd_ha->sas_ha; asd_ha->sas_ha.core.shost = shost; shost->transportt = aic94xx_transport_template; shost->max_id = ~0; shost->max_lun = ~0; shost->max_cmd_len = 16; err = scsi_add_host(shost, &dev->dev); if (err) goto Err_free; err = asd_dev->setup(asd_ha); if (err) goto Err_remove; err = -ENODEV; if (!pci_set_dma_mask(dev, DMA_64BIT_MASK) && !pci_set_consistent_dma_mask(dev, DMA_64BIT_MASK)) ; else if (!pci_set_dma_mask(dev, DMA_32BIT_MASK) && !pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK)) ; else { asd_printk("no suitable DMA mask for %s\n", pci_name(dev)); goto Err_remove; } pci_set_drvdata(dev, asd_ha); err = asd_map_ha(asd_ha); if (err) goto Err_remove; err = asd_create_ha_caches(asd_ha); if (err) goto Err_unmap; err = asd_init_hw(asd_ha); if (err) goto Err_free_cache; asd_printk("device %s: SAS addr %llx, PCBA SN %s, %d phys, %d enabled " "phys, flash %s, BIOS %s%d\n", pci_name(dev), SAS_ADDR(asd_ha->hw_prof.sas_addr), asd_ha->hw_prof.pcba_sn, asd_ha->hw_prof.max_phys, asd_ha->hw_prof.num_phys, asd_ha->hw_prof.flash.present ? "present" : "not present", asd_ha->hw_prof.bios.present ? "build " : "not present", asd_ha->hw_prof.bios.bld); shost->can_queue = asd_ha->seq.can_queue; if (use_msi) pci_enable_msi(asd_ha->pcidev); err = request_irq(asd_ha->pcidev->irq, asd_hw_isr, IRQF_SHARED, ASD_DRIVER_NAME, asd_ha); if (err) { asd_printk("couldn't get irq %d for %s\n", asd_ha->pcidev->irq, pci_name(asd_ha->pcidev)); goto Err_irq; } asd_enable_ints(asd_ha); err = asd_init_post_escbs(asd_ha); if (err) { asd_printk("couldn't post escbs for %s\n", pci_name(asd_ha->pcidev)); goto Err_escbs; } ASD_DPRINTK("escbs posted\n"); err = asd_create_dev_attrs(asd_ha); if (err) goto Err_dev_attrs; err = asd_register_sas_ha(asd_ha); if (err) goto Err_reg_sas; scsi_scan_host(shost); return 0;Err_reg_sas: asd_remove_dev_attrs(asd_ha);Err_dev_attrs:Err_escbs: asd_disable_ints(asd_ha); free_irq(dev->irq, asd_ha);Err_irq: if (use_msi) pci_disable_msi(dev); asd_chip_hardrst(asd_ha);Err_free_cache: asd_destroy_ha_caches(asd_ha);Err_unmap: asd_unmap_ha(asd_ha);Err_remove: scsi_remove_host(shost);Err_free: kfree(asd_ha);Err_put: scsi_host_put(shost);Err: pci_disable_device(dev); return err;}static void asd_free_queues(struct asd_ha_struct *asd_ha){ unsigned long flags; LIST_HEAD(pending); struct list_head *n, *pos; spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags); asd_ha->seq.pending = 0; list_splice_init(&asd_ha->seq.pend_q, &pending); spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags); if (!list_empty(&pending)) ASD_DPRINTK("Uh-oh! Pending is not empty!\n"); list_for_each_safe(pos, n, &pending) { struct asd_ascb *ascb = list_entry(pos, struct asd_ascb, list); /* * Delete unexpired ascb timers. This may happen if we issue * a CONTROL PHY scb to an adapter and rmmod before the scb * times out. Apparently we don't wait for the CONTROL PHY * to complete, so it doesn't matter if we kill the timer. */ del_timer_sync(&ascb->timer); WARN_ON(ascb->scb->header.opcode != CONTROL_PHY); list_del_init(pos); ASD_DPRINTK("freeing from pending\n"); asd_ascb_free(ascb); }}static void asd_turn_off_leds(struct asd_ha_struct *asd_ha){ u8 phy_mask = asd_ha->hw_prof.enabled_phys; u8 i; for_each_phy(phy_mask, phy_mask, i) { asd_turn_led(asd_ha, i, 0); asd_control_led(asd_ha, i, 0); }}static void __devexit asd_pci_remove(struct pci_dev *dev){ struct asd_ha_struct *asd_ha = pci_get_drvdata(dev); if (!asd_ha) return; asd_unregister_sas_ha(asd_ha); asd_disable_ints(asd_ha); asd_remove_dev_attrs(asd_ha); /* XXX more here as needed */ free_irq(dev->irq, asd_ha); if (use_msi) pci_disable_msi(asd_ha->pcidev); asd_turn_off_leds(asd_ha); asd_chip_hardrst(asd_ha); asd_free_queues(asd_ha); asd_destroy_ha_caches(asd_ha); asd_unmap_ha(asd_ha); kfree(asd_ha); pci_disable_device(dev); return;}static void asd_scan_start(struct Scsi_Host *shost){ struct asd_ha_struct *asd_ha; int err; asd_ha = SHOST_TO_SAS_HA(shost)->lldd_ha; err = asd_enable_phys(asd_ha, asd_ha->hw_prof.enabled_phys); if (err) asd_printk("Couldn't enable phys, err:%d\n", err);}static int asd_scan_finished(struct Scsi_Host *shost, unsigned long time){ /* give the phy enabling interrupt event time to come in (1s * is empirically about all it takes) */ if (time < HZ) return 0; /* Wait for discovery to finish */ scsi_flush_work(shost); return 1;}static ssize_t asd_version_show(struct device_driver *driver, char *buf){ return snprintf(buf, PAGE_SIZE, "%s\n", ASD_DRIVER_VERSION);}static DRIVER_ATTR(version, S_IRUGO, asd_version_show, NULL);static int asd_create_driver_attrs(struct device_driver *driver){ return driver_create_file(driver, &driver_attr_version);}static void asd_remove_driver_attrs(struct device_driver *driver){ driver_remove_file(driver, &driver_attr_version);}static struct sas_domain_function_template aic94xx_transport_functions = { .lldd_dev_found = asd_dev_found, .lldd_dev_gone = asd_dev_gone, .lldd_execute_task = asd_execute_task, .lldd_abort_task = asd_abort_task, .lldd_abort_task_set = asd_abort_task_set, .lldd_clear_aca = asd_clear_aca, .lldd_clear_task_set = asd_clear_task_set, .lldd_I_T_nexus_reset = NULL, .lldd_lu_reset = asd_lu_reset, .lldd_query_task = asd_query_task, .lldd_clear_nexus_port = asd_clear_nexus_port, .lldd_clear_nexus_ha = asd_clear_nexus_ha, .lldd_control_phy = asd_control_phy,};static const struct pci_device_id aic94xx_pci_table[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x410),0, 0, 1}, {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x412),0, 0, 1}, {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x416),0, 0, 1}, {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x41E),0, 0, 1}, {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x41F),0, 0, 1}, {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x430),0, 0, 2}, {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x432),0, 0, 2}, {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x43E),0, 0, 2}, {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x43F),0, 0, 2}, {}};MODULE_DEVICE_TABLE(pci, aic94xx_pci_table);static struct pci_driver aic94xx_pci_driver = { .name = ASD_DRIVER_NAME, .id_table = aic94xx_pci_table, .probe = asd_pci_probe, .remove = __devexit_p(asd_pci_remove),};static int __init aic94xx_init(void){ int err; asd_printk("%s version %s loaded\n", ASD_DRIVER_DESCRIPTION, ASD_DRIVER_VERSION); err = asd_create_global_caches(); if (err) return err; aic94xx_transport_template = sas_domain_attach_transport(&aic94xx_transport_functions); if (!aic94xx_transport_template) goto out_destroy_caches; err = pci_register_driver(&aic94xx_pci_driver); if (err) goto out_release_transport; err = asd_create_driver_attrs(&aic94xx_pci_driver.driver); if (err) goto out_unregister_pcidrv; return err; out_unregister_pcidrv: pci_unregister_driver(&aic94xx_pci_driver); out_release_transport: sas_release_transport(aic94xx_transport_template); out_destroy_caches: asd_destroy_global_caches(); return err;}static void __exit aic94xx_exit(void){ asd_remove_driver_attrs(&aic94xx_pci_driver.driver); pci_unregister_driver(&aic94xx_pci_driver); sas_release_transport(aic94xx_transport_template); asd_release_firmware(); asd_destroy_global_caches(); asd_printk("%s version %s unloaded\n", ASD_DRIVER_DESCRIPTION, ASD_DRIVER_VERSION);}module_init(aic94xx_init);module_exit(aic94xx_exit);MODULE_AUTHOR("Luben Tuikov <luben_tuikov@adaptec.com>");MODULE_DESCRIPTION(ASD_DRIVER_DESCRIPTION);MODULE_LICENSE("GPL v2");MODULE_VERSION(ASD_DRIVER_VERSION);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -