⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sbp2.c

📁 Armlinux ieee1394接口驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
#define sbp2_spin_unlock(lock, flags)	do {restore_flags(flags);} while (0)#endif/* * Globals */static Scsi_Host_Template scsi_driver_template;static u8 sbp2_speedto_maxrec[] = { 0x7, 0x8, 0x9 };static LIST_HEAD(sbp2_host_info_list);static int sbp2_host_count = 0;static struct hpsb_highlevel *sbp2_hl_handle = NULL;static struct hpsb_highlevel_ops sbp2_hl_ops = {	add_host:	sbp2_add_host,	remove_host:	sbp2_remove_host,};static struct hpsb_address_ops sbp2_ops = {	write: sbp2_handle_status_write};static struct hpsb_protocol_driver sbp2_driver = {	name:		"SBP2 Driver",	id_table: 	sbp2_id_table,	probe: 		sbp2_probe,	disconnect: 	sbp2_disconnect,	update: 	sbp2_update};/************************************** * General utility functions **************************************/#ifndef __BIG_ENDIAN/* * Converts a buffer from be32 to cpu byte ordering. Length is in bytes. */static __inline__ void sbp2util_be32_to_cpu_buffer(void *buffer, int length){	u32 *temp = buffer;	for (length = (length >> 2); length--; )		temp[length] = be32_to_cpu(temp[length]);	return;}/* * Converts a buffer from cpu to be32 byte ordering. Length is in bytes. */static __inline__ void sbp2util_cpu_to_be32_buffer(void *buffer, int length){	u32 *temp = buffer;	for (length = (length >> 2); length--; )		temp[length] = cpu_to_be32(temp[length]);	return;}#else /* BIG_ENDIAN *//* Why waste the cpu cycles? */#define sbp2util_be32_to_cpu_buffer(x,y)#define sbp2util_cpu_to_be32_buffer(x,y)#endif/* * This function is called to initially create a packet pool for use in * sbp2 I/O requests. This packet pool is used when sending out sbp2 * command and agent reset requests, and allows us to remove all * kmallocs/kfrees from the critical I/O paths. */static int sbp2util_create_request_packet_pool(struct sbp2scsi_host_info *hi){	struct hpsb_packet *packet;	int i;	/* Create SBP2_MAX_REQUEST_PACKETS number of request packets. */	for (i=0; i<SBP2_MAX_REQUEST_PACKETS; i++) {		/*		 * Max payload of 8 bytes since the sbp2 command request		 * uses a payload of 8 bytes, and agent reset is a quadlet		 * write request. Bump this up if we plan on using this		 * pool for other stuff.		 */		packet = alloc_hpsb_packet(8);		if (!packet) {			SBP2_ERR("sbp2util_create_request_packet_pool - packet allocation failed!");			return(-ENOMEM);		}		/* 		 * Put these request packets into a free list		 */		INIT_LIST_HEAD(&hi->request_packet[i].list);		hi->request_packet[i].packet = packet;		list_add_tail(&hi->request_packet[i].list, &hi->sbp2_req_free);	}	return(0);}/* * This function is called to remove the packet pool. It is called when * the sbp2 driver is unloaded. */static void sbp2util_remove_request_packet_pool(struct sbp2scsi_host_info *hi){	struct list_head *lh;	struct sbp2_request_packet *request_packet;	unsigned long flags;	/* 	 * Go through free list releasing packets	 */	sbp2_spin_lock(&hi->sbp2_request_packet_lock, flags);	while (!list_empty(&hi->sbp2_req_free)) {		lh = hi->sbp2_req_free.next;		list_del(lh);		request_packet = list_entry(lh, struct sbp2_request_packet, list);		/*		 * Free the hpsb packets that we allocated for the pool		 */		if (request_packet) {			free_hpsb_packet(request_packet->packet);		}	}	sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags);	return;}/* * This function is called to retrieve a block write packet from our * packet pool. This function is used in place of calling * alloc_hpsb_packet (which costs us three kmallocs). Instead we just pull * out a free request packet and re-initialize values in it. I'm sure this * can still stand some more optimization. */static struct sbp2_request_packet *sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi,				       nodeid_t node, u64 addr,				       size_t data_size,				       quadlet_t data) {	struct list_head *lh;	struct sbp2_request_packet *request_packet = NULL;	struct hpsb_packet *packet;	unsigned long flags;	sbp2_spin_lock(&hi->sbp2_request_packet_lock, flags);	if (!list_empty(&hi->sbp2_req_free)) {		/*		 * Pull out a free request packet		 */		lh = hi->sbp2_req_free.next;		list_del(lh);		request_packet = list_entry(lh, struct sbp2_request_packet, list);		packet = request_packet->packet;		/*		 * Initialize the packet (this is really initialization		 * the core 1394 stack should do, but I'm doing it myself		 * to avoid the overhead).		 */		packet->data_size = data_size;		INIT_LIST_HEAD(&packet->list);		sema_init(&packet->state_change, 0);		packet->state = hpsb_unused;		packet->generation = get_hpsb_generation(hi->host);		packet->data_be = 1;		packet->host = hi->host;		packet->tlabel = get_tlabel(hi->host, node, 1);		packet->node_id = node;		if (!data_size) {			fill_async_writequad(packet, addr, data);		} else {			fill_async_writeblock(packet, addr, data_size);         		}		/*		 * Set up a task queue completion routine, which returns		 * the packet to the free list and releases the tlabel.		 */		request_packet->tq.routine = (void (*)(void*))sbp2util_free_request_packet;		request_packet->tq.data = request_packet;		request_packet->hi_context = hi;		queue_task(&request_packet->tq, &packet->complete_tq);		/*		 * Now, put the packet on the in-use list.		 */		list_add_tail(&request_packet->list, &hi->sbp2_req_inuse);	} else {		SBP2_ERR("sbp2util_allocate_request_packet - no packets available!");	}	sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags);	return(request_packet);}/* * This function is called to return a packet to our packet pool. It is * also called as a completion routine when a request packet is completed. */static void sbp2util_free_request_packet(struct sbp2_request_packet *request_packet){	unsigned long flags;	struct sbp2scsi_host_info *hi = request_packet->hi_context;	/*	 * Free the tlabel, and return the packet to the free pool.	 */	sbp2_spin_lock(&hi->sbp2_request_packet_lock, flags);	free_tlabel(hi->host, LOCAL_BUS | request_packet->packet->node_id,		    request_packet->packet->tlabel);	list_del(&request_packet->list);	list_add_tail(&request_packet->list, &hi->sbp2_req_free);	sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags);	return;}/* * This function is called to create a pool of command orbs used for * command processing. It is called when a new sbp2 device is detected. */static int sbp2util_create_command_orb_pool(struct scsi_id_instance_data *scsi_id,					    struct sbp2scsi_host_info *hi){	int i;	unsigned long flags;	struct sbp2_command_info *command;        	sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags);	for (i = 0; i < scsi_id->sbp2_total_command_orbs; i++) {		command = (struct sbp2_command_info *)		    kmalloc(sizeof(struct sbp2_command_info), GFP_KERNEL);		if (!command) {			sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);			return(-ENOMEM);		}		memset(command, '\0', sizeof(struct sbp2_command_info));		command->command_orb_dma =			pci_map_single (hi->host->pdev, &command->command_orb,					sizeof(struct sbp2_command_orb),					PCI_DMA_BIDIRECTIONAL);		SBP2_DMA_ALLOC("single command orb DMA");		command->sge_dma =			pci_map_single (hi->host->pdev, &command->scatter_gather_element,					sizeof(command->scatter_gather_element),					PCI_DMA_BIDIRECTIONAL);		SBP2_DMA_ALLOC("scatter_gather_element");		INIT_LIST_HEAD(&command->list);		list_add_tail(&command->list, &scsi_id->sbp2_command_orb_completed);	}	sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);	return 0;}/* * This function is called to delete a pool of command orbs. */static void sbp2util_remove_command_orb_pool(struct scsi_id_instance_data *scsi_id,					     struct sbp2scsi_host_info *hi){	struct list_head *lh, *next;	struct sbp2_command_info *command;	unsigned long flags;        	sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags);	if (!list_empty(&scsi_id->sbp2_command_orb_completed)) {		list_for_each_safe(lh, next, &scsi_id->sbp2_command_orb_completed) {			command = list_entry(lh, struct sbp2_command_info, list);			/* Release our generic DMA's */			pci_unmap_single(hi->host->pdev, command->command_orb_dma,					 sizeof(struct sbp2_command_orb),					 PCI_DMA_BIDIRECTIONAL);			SBP2_DMA_FREE("single command orb DMA");			pci_unmap_single(hi->host->pdev, command->sge_dma,					 sizeof(command->scatter_gather_element),					 PCI_DMA_BIDIRECTIONAL);			SBP2_DMA_FREE("scatter_gather_element");			kfree(command);		}	}	sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);	return;}/*  * This functions finds the sbp2_command for a given outstanding command * orb. Only looks at the inuse list. */static struct sbp2_command_info *sbp2util_find_command_for_orb(		struct scsi_id_instance_data *scsi_id, dma_addr_t orb){	struct list_head *lh;	struct sbp2_command_info *command;	unsigned long flags;	sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags);	if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) {		list_for_each(lh, &scsi_id->sbp2_command_orb_inuse) {			command = list_entry(lh, struct sbp2_command_info, list);			if (command->command_orb_dma == orb) {				sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);				return (command);			}		}	}	sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);	SBP2_ORB_DEBUG("could not match command orb %x", (unsigned int)orb);	return(NULL);}/*  * This functions finds the sbp2_command for a given outstanding SCpnt. * Only looks at the inuse list. */static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_instance_data *scsi_id, void *SCpnt){	struct list_head *lh;	struct sbp2_command_info *command;	unsigned long flags;	sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags);	if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) {		list_for_each(lh, &scsi_id->sbp2_command_orb_inuse) {			command = list_entry(lh, struct sbp2_command_info, list);			if (command->Current_SCpnt == SCpnt) {				sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);				return (command);			}		}	}	sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);	return(NULL);}/* * This function allocates a command orb used to send a scsi command. */static struct sbp2_command_info *sbp2util_allocate_command_orb(		struct scsi_id_instance_data *scsi_id, 		Scsi_Cmnd *Current_SCpnt, 		void (*Current_done)(Scsi_Cmnd *),		struct sbp2scsi_host_info *hi){	struct list_head *lh;	struct sbp2_command_info *command = NULL;	unsigned long flags;	sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags);	if (!list_empty(&scsi_id->sbp2_command_orb_completed)) {		lh = scsi_id->sbp2_command_orb_completed.next;		list_del(lh);		command = list_entry(lh, struct sbp2_command_info, list);		command->Current_done = Current_done;		command->Current_SCpnt = Current_SCpnt;		command->linked = 0;		list_add_tail(&command->list, &scsi_id->sbp2_command_orb_inuse);	} else {		SBP2_ERR("sbp2util_allocate_command_orb - No orbs available!");	}	sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);	return (command);}/* Free our DMA's */static void sbp2util_free_command_dma(struct sbp2_command_info *command){	struct sbp2scsi_host_info *hi;		hi = (struct sbp2scsi_host_info *) command->Current_SCpnt->host->hostdata[0];	if (hi == NULL) {		printk(KERN_ERR __FUNCTION__": hi == NULL\n");		return;	}	if (command->cmd_dma) {		pci_unmap_single(hi->host->pdev, command->cmd_dma,				 command->dma_size, command->dma_dir);		SBP2_DMA_FREE("single bulk");		command->cmd_dma = 0;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -