hba_mod.c
来自「6440linuxDriver的源代码」· C语言 代码 · 共 1,621 行 · 第 1/3 页
C
1,621 行
num++; tick_mean = (tick + (num-1)*tick_mean) / num; data_mean = (data_len + (num-1)*data_mean) / num; MV_DBG(DMSG_PROF_FREQ, "_MV_ irq used "YELLOW("%llu (%lu)")" us to trasfer " YELLOW("%u (%lu)")" kbytes.\n", tick*1000/cpu_khz, tick_mean*1000/cpu_khz, data_len/1024, data_mean/1024); spin_unlock_irqrestore(hba->irq_lock, flags);#else /* __AC_PROF__ */ struct hba_extension *hba = (struct hba_extension *) dev_id; spin_lock_irqsave(&hba->irq_lock, flags); retval = hba->desc->child->ops->module_service_isr(hba->desc->child->extension); spin_unlock_irqrestore(&hba->irq_lock, flags);#endif /* __AC_PROF__ */ MV_DBG(DMSG_FREQ, "__MV__ Exit intr handler.\n"); return IRQ_RETVAL(retval);}static int mv_linux_reset (struct scsi_cmnd *cmd){ MV_PRINT("__MV__ reset handler %p.\n", cmd); return FAILED;}static struct scsi_host_template mv_driver_template = { .module = THIS_MODULE, .name = "Marvell Storage Controller", .proc_name = mv_driver_name, .proc_info = mv_linux_proc_info, .queuecommand = mv_linux_queue_command,#if 0 .eh_abort_handler = mv_linux_abort, .eh_device_reset_handler = mv_linux_reset, .eh_bus_reset_handler = mv_linux_reset,#endif /* 0 */ .eh_host_reset_handler = mv_linux_reset,#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 7) && \ LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) .eh_timed_out = mv_linux_timed_out,#endif .can_queue = MV_MAX_REQUEST_DEPTH, .this_id = MV_SHT_THIS_ID, .max_sectors = MV_MAX_TRANSFER_SECTOR, .sg_tablesize = MV_MAX_SG_ENTRY, .cmd_per_lun = MV_MAX_REQUEST_PER_LUN, .use_clustering = MV_SHT_USE_CLUSTERING, .emulated = MV_SHT_EMULATED,};#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)static struct scsi_transport_template mv_transport_template = { .eh_timed_out = mv_linux_timed_out,};#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 16) *//* module management & hba module code */extern struct mv_module_ops *mv_core_register_module(void);extern struct mv_module_ops *mv_hba_register_module(void);#ifdef RAID_DRIVERextern struct mv_module_ops *mv_raid_register_module(void);#elsestatic inline struct mv_module_ops *mv_raid_register_module(void){ return NULL;}#endif /* RAID_DRIVER */#ifdef CACHE_DRIVERextern struct mv_module_ops *mv_cache_register_module(void);#elsestatic inline struct mv_module_ops *mv_cache_register_module(void){ return NULL;}#endif /* CACHE_DRIVER */static LIST_HEAD(mv_online_adapter_list);int __mv_get_adapter_count(void){ struct mv_adp_desc *p; int i = 0; list_for_each_entry(p, &mv_online_adapter_list, hba_entry) i++; return i;}static inline struct mv_adp_desc *__dev_to_desc(struct pci_dev *dev){ struct mv_adp_desc *p; list_for_each_entry(p, &mv_online_adapter_list, hba_entry) if (p->dev == dev) return p; return NULL;}MV_PVOID *mv_get_hba_extension(struct mv_adp_desc *hba_desc){ struct mv_mod_desc *p; list_for_each_entry(p, &hba_desc->online_module_list, mod_entry) if (MODULE_HBA == p->module_id) return p->extension; return NULL;}static inline void __mv_release_hba(struct mv_adp_desc *hba_desc){ struct mv_mod_desc *mod_desc, *p; list_for_each_entry_safe(mod_desc, p, &hba_desc->online_module_list, mod_entry) { list_del(&mod_desc->mod_entry); vfree(mod_desc); } list_del(&hba_desc->hba_entry); vfree(hba_desc);}static struct mv_adp_desc *mv_hba_init_modmm(struct pci_dev *dev){ struct mv_adp_desc *hba_desc; hba_desc = vmalloc(sizeof(struct mv_adp_desc)); if (NULL == hba_desc) { printk("Unable to get memory at hba init.\n"); return NULL; } INIT_LIST_HEAD(&hba_desc->online_module_list); hba_desc->dev = dev; list_add(&hba_desc->hba_entry, &mv_online_adapter_list); return hba_desc;}static void mv_hba_release_modmm(struct pci_dev *dev){ struct mv_adp_desc *hba_desc; hba_desc = __dev_to_desc(dev); if (hba_desc) __mv_release_hba(hba_desc); else printk("Weired! dev %p unassociated with any desc.\n", dev);}static inline struct mv_mod_desc *__alloc_mod_desc(void){ struct mv_mod_desc *desc; desc = vmalloc(sizeof(struct mv_mod_desc)); if (desc) memset(desc, 0, sizeof(struct mv_mod_desc)); return desc;}static int register_online_modules(struct mv_adp_desc *hba_desc){ struct mv_mod_desc *mod_desc, *prev; struct mv_module_ops *ops; /* * iterate through online_module_list manually , from the lowest(CORE) * to the highest layer (HBA) */ hba_desc->running_mod_num = 0; /* CORE */ ops = mv_core_register_module(); if (NULL == ops) { printk("No core no life.\n"); return -1; } mod_desc = __alloc_mod_desc(); if (NULL == mod_desc) goto disaster; mod_desc->hba_desc = hba_desc; mod_desc->ops = ops; mod_desc->status = MV_MOD_REGISTERED; mod_desc->module_id = MODULE_CORE; mod_desc->child = NULL; list_add(&mod_desc->mod_entry, &hba_desc->online_module_list); hba_desc->running_mod_num++; /* RAID */ ops = mv_raid_register_module(); if (ops) { prev = mod_desc; mod_desc = __alloc_mod_desc(); if (NULL == mod_desc) goto disaster; mod_desc->hba_desc = hba_desc; mod_desc->ops = ops; mod_desc->status = MV_MOD_REGISTERED; mod_desc->module_id = MODULE_RAID; mod_desc->child = prev; prev->parent = mod_desc; list_add(&mod_desc->mod_entry, &hba_desc->online_module_list); hba_desc->running_mod_num++; } /* CACHE */ ops = mv_cache_register_module(); if (ops) { prev = mod_desc; mod_desc = __alloc_mod_desc(); if (NULL == mod_desc) goto disaster; mod_desc->hba_desc = hba_desc; mod_desc->ops = ops; mod_desc->status = MV_MOD_REGISTERED; mod_desc->module_id = MODULE_CACHE; mod_desc->child = prev; prev->parent = mod_desc; list_add(&mod_desc->mod_entry, &hba_desc->online_module_list); hba_desc->running_mod_num++; } /* HBA */ prev = mod_desc; mod_desc = __alloc_mod_desc(); if (NULL == mod_desc) goto disaster; mod_desc->ops = mv_hba_register_module(); if (NULL == mod_desc->ops) { printk("No HBA no life.\n"); return -1; } mod_desc->hba_desc = hba_desc; mod_desc->status = MV_MOD_REGISTERED; mod_desc->module_id = MODULE_HBA; mod_desc->child = prev; mod_desc->parent = NULL; prev->parent = mod_desc; list_add(&mod_desc->mod_entry, &hba_desc->online_module_list); hba_desc->running_mod_num++; return 0;disaster: return -1;}static void __release_consistent_mem(struct mv_mod_res *mod_res, struct pci_dev *dev){ dma_addr_t dma_addr; MV_PHYSICAL_ADDR phy_addr; phy_addr = mod_res->bus_addr; dma_addr = (dma_addr_t) (phy_addr.parts.low | ((u64) phy_addr.parts.high << 32)); pci_free_consistent(dev, mod_res->size, mod_res->virt_addr, dma_addr);}static int __alloc_consistent_mem(struct mv_mod_res *mod_res, struct pci_dev *dev){ unsigned long size; dma_addr_t dma_addr; BUS_ADDRESS bus_addr; MV_PHYSICAL_ADDR phy_addr; size = mod_res->size; WARN_ON(size != ROUNDING(size, 8)); mod_res->virt_addr = (MV_PVOID) pci_alloc_consistent(dev, size, &dma_addr); if (NULL == mod_res->virt_addr) { MV_DBG(DMSG_HBA, "unable to alloc %lu consistent mem.\n", size); return -1; } bus_addr = (BUS_ADDRESS) dma_addr; phy_addr.parts.low = LO_BUSADDR(bus_addr); phy_addr.parts.high = HI_BUSADDR(bus_addr); mod_res->bus_addr = phy_addr; return 0;}int HBA_GetResource(struct mv_mod_desc *mod_desc, enum Resource_Type type, MV_U32 size, Assigned_Uncached_Memory *dma_res){ struct mv_mod_res *mod_res; mod_res = vmalloc(sizeof(struct mv_mod_res)); if (NULL == mod_res) { printk("unable to allocate memory for resource management.\n"); return -1; } memset(mod_res, 0, sizeof(struct mv_mod_res)); mod_res->size = size; mod_res->type = type; switch (type) { case RESOURCE_UNCACHED_MEMORY : if (__alloc_consistent_mem(mod_res, mod_desc->hba_desc->dev)) { printk("unable to allocate %d uncached meme.\n", size); vfree(mod_res); return -1; } list_add(&mod_res->res_entry, &mod_desc->res_list); dma_res->Virtual_Address = mod_res->virt_addr; dma_res->Physical_Address = mod_res->bus_addr; dma_res->Byte_Size = size; break; case RESOURCE_CACHED_MEMORY : default: vfree(mod_res); printk("unknown resource type %d.\n", type); return -1; } return 0;}static void __release_resource(struct mv_adp_desc *hba_desc, struct mv_mod_desc *mod_desc){ struct mv_mod_res *mod_res, *tmp; list_for_each_entry_safe(mod_res, tmp, &mod_desc->res_list, res_entry) { switch (mod_res->type) { case RESOURCE_UNCACHED_MEMORY : __release_consistent_mem(mod_res, hba_desc->dev); break; case RESOURCE_CACHED_MEMORY : vfree(mod_res->virt_addr); break; default: MV_DBG(DMSG_HBA, "res type %d unknown.\n", mod_res->type); break; } list_del(&mod_res->res_entry); vfree(mod_res); }}static void __release_module_resource(struct mv_mod_desc *mod_desc){ __release_resource(mod_desc->hba_desc, mod_desc);}static int __alloc_module_resource(struct mv_mod_desc *mod_desc, unsigned int max_io){ struct mv_mod_res *mod_res = NULL; unsigned int size = 0; /* * alloc only cached mem at this stage, uncached mem will be alloc'ed * during mod init. */ INIT_LIST_HEAD(&mod_desc->res_list); mod_res = vmalloc(sizeof(struct mv_mod_res)); if (NULL == mod_res) return -1; memset(mod_res, 0, sizeof(sizeof(struct mv_mod_res))); mod_desc->res_entry = 1; size = mod_desc->ops->get_res_desc(RESOURCE_CACHED_MEMORY, max_io); if (size) { mod_res->virt_addr = vmalloc(size); if (NULL == mod_res->virt_addr) { vfree(mod_res); return -1; } mod_res->type = RESOURCE_CACHED_MEMORY; mod_res->size = size; mod_desc->extension = mod_res->virt_addr; mod_desc->extension_size = size; list_add(&mod_res->res_entry, &mod_desc->res_list); } return 0;}static void mv_release_module_resource(struct mv_adp_desc *hba_desc){ struct mv_mod_desc *mod_desc; list_for_each_entry(mod_desc, &hba_desc->online_module_list, mod_entry) { if (mod_desc->status == MV_MOD_INITED) { __release_module_resource(mod_desc); mod_desc->status = MV_MOD_REGISTERED; } }}static int mv_alloc_module_resource(struct mv_adp_desc *hba_desc){ struct mv_mod_desc *mod_desc; int ret; list_for_each_entry(mod_desc, &hba_desc->online_module_list, mod_entry) { ret = __alloc_module_resource(mod_desc, hba_desc->max_io); if (ret) goto err_out; mod_desc->status = MV_MOD_INITED; } return 0;err_out: MV_DBG(DMSG_HBA, "error %d allocating resource for mod %d.\n", ret, mod_desc->module_id); list_for_each_entry(mod_desc, &hba_desc->online_module_list, mod_entry) { if (mod_desc->status == MV_MOD_INITED) { __release_module_resource(mod_desc); mod_desc->status = MV_MOD_REGISTERED; } } return -1;}static inline struct mv_mod_desc *__get_lowest_module(struct mv_adp_desc *hba_desc){ struct mv_mod_desc *p; /* take a random module, and trace through its child */ p = list_entry(hba_desc->online_module_list.next, struct mv_mod_desc, mod_entry); WARN_ON(NULL == p); while (p) { if (NULL == p->child) break; p = p->child; } return p;}static inline struct mv_mod_desc *__get_highest_module(struct mv_adp_desc *hba_desc){ struct mv_mod_desc *p; /* take a random module, and trace through its parent */ p = list_entry(hba_desc->online_module_list.next, struct mv_mod_desc, mod_entry); WARN_ON(NULL == p); while (p) { if (NULL == p->parent) break; p = p->parent; } return p;}static void __map_pci_addr(struct pci_dev *dev, MV_PVOID *addr_array){ int i; unsigned long addr; unsigned long range; for (i = 0; i < MAX_BASE_ADDRESS; i++) { addr = pci_resource_start(dev, i); range = pci_resource_len(dev, i); if (pci_resource_flags(dev, i) & IORESOURCE_MEM) addr_array[i] =(MV_PVOID) ioremap(addr, range); else addr_array[i] =(MV_PVOID) addr; MV_DBG(DMSG_HBA, "%s : BAR %d : %p.\n", mv_product_name, i, addr_array[i]); }}static void __unmap_pci_addr(struct pci_dev *dev, MV_PVOID *addr_array){ int i; for (i = 0; i < MAX_BASE_ADDRESS; i++) if (pci_resource_flags(dev, i) & IORESOURCE_MEM) iounmap(addr_array[i]);}int __mv_is_mod_all_started(struct mv_adp_desc *adp_desc){ struct mv_mod_desc *mod_desc; mod_desc = __get_lowest_module(adp_desc); while (mod_desc) { if (MV_MOD_STARTED != mod_desc->status) return 0; mod_desc = mod_desc->parent; } return 1;}struct hba_extension *__mv_get_ext_from_adp_id(int id){ struct mv_adp_desc *p; list_for_each_entry(p, &mv_online_adapter_list, hba_entry) if (p->id == id) return __get_highest_module(p)->extension; return NULL;}int mv_hba_start(struct pci_dev *dev){
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?