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 + -
显示快捷键?