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

📄 sbp2.c

📁 这是关于ieee1394的最新源码,上面包含了所有更新的部分!
💻 C
📖 第 1 页 / 共 5 页
字号:
 * Returns nonzero if timed out or prematurely interrupted. */static int sbp2util_access_timeout(struct scsi_id_instance_data *scsi_id,				   int timeout){	long leftover = wait_event_interruptible_timeout(				access_wq, scsi_id->access_complete, timeout);	scsi_id->access_complete = 0;	return leftover <= 0;}/* Frees an allocated packet */static void sbp2_free_packet(struct hpsb_packet *packet){	hpsb_free_tlabel(packet);	hpsb_free_packet(packet);}/* This is much like hpsb_node_write(), except it ignores the response * subaction and returns immediately. Can be used from interrupts. */static int sbp2util_node_write_no_wait(struct node_entry *ne, u64 addr,				       quadlet_t *buffer, size_t length){	struct hpsb_packet *packet;	packet = hpsb_make_writepacket(ne->host, ne->nodeid,				       addr, buffer, length);	if (!packet)		return -ENOMEM;	hpsb_set_packet_complete_task(packet,				      (void (*)(void *))sbp2_free_packet,				      packet);	hpsb_node_fill_packet(ne, packet);	if (hpsb_send_packet(packet) < 0) {		sbp2_free_packet(packet);		return -EIO;	}	return 0;}static void sbp2util_notify_fetch_agent(struct scsi_id_instance_data *scsi_id,					u64 offset, quadlet_t *data, size_t len){	/*	 * There is a small window after a bus reset within which the node	 * entry's generation is current but the reconnect wasn't completed.	 */	if (unlikely(atomic_read(&scsi_id->state) == SBP2LU_STATE_IN_RESET))		return;	if (hpsb_node_write(scsi_id->ne,			    scsi_id->sbp2_command_block_agent_addr + offset,			    data, len))		SBP2_ERR("sbp2util_notify_fetch_agent failed.");	/*	 * Now accept new SCSI commands, unless a bus reset happended during	 * hpsb_node_write.	 */	if (likely(atomic_read(&scsi_id->state) != SBP2LU_STATE_IN_RESET))		scsi_unblock_requests(scsi_id->scsi_host);}static void sbp2util_write_orb_pointer(void *p){	quadlet_t data[2];	data[0] = ORB_SET_NODE_ID(			((struct scsi_id_instance_data *)p)->hi->host->node_id);	data[1] = ((struct scsi_id_instance_data *)p)->last_orb_dma;	sbp2util_cpu_to_be32_buffer(data, 8);	sbp2util_notify_fetch_agent(p, SBP2_ORB_POINTER_OFFSET, data, 8);}static void sbp2util_write_doorbell(void *p){	sbp2util_notify_fetch_agent(p, SBP2_DOORBELL_OFFSET, NULL, 4);}/* * 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 = scsi_id->hi;	int i;	unsigned long flags, orbs;	struct sbp2_command_info *command;	orbs = serialize_io ? 2 : SBP2_MAX_CMDS;	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);	for (i = 0; i < orbs; i++) {		command = kzalloc(sizeof(*command), GFP_ATOMIC);		if (!command) {			spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock,					       flags);			return -ENOMEM;		}		command->command_orb_dma =		    pci_map_single(hi->host->pdev, &command->command_orb,				   sizeof(struct sbp2_command_orb),				   PCI_DMA_TODEVICE);		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);	}	spin_unlock_irqrestore(&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 hpsb_host *host = scsi_id->hi->host;	struct list_head *lh, *next;	struct sbp2_command_info *command;	unsigned long flags;	spin_lock_irqsave(&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(host->pdev, command->command_orb_dma,					 sizeof(struct sbp2_command_orb),					 PCI_DMA_TODEVICE);			SBP2_DMA_FREE("single command orb DMA");			pci_unmap_single(host->pdev, command->sge_dma,					 sizeof(command->scatter_gather_element),					 PCI_DMA_BIDIRECTIONAL);			SBP2_DMA_FREE("scatter_gather_element");			kfree(command);		}	}	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);	return;}/* * This function 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 sbp2_command_info *command;	unsigned long flags;	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);	if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) {		list_for_each_entry(command, &scsi_id->sbp2_command_orb_inuse, list) {			if (command->command_orb_dma == orb) {				spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);				return command;			}		}	}	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);	SBP2_ORB_DEBUG("could not match command orb %x", (unsigned int)orb);	return NULL;}/* * This function finds the sbp2_command for a given outstanding SCpnt. * Only looks at the inuse list. * Must be called with scsi_id->sbp2_command_orb_lock held. */static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(		struct scsi_id_instance_data *scsi_id, void *SCpnt){	struct sbp2_command_info *command;	if (!list_empty(&scsi_id->sbp2_command_orb_inuse))		list_for_each_entry(command, &scsi_id->sbp2_command_orb_inuse, list)			if (command->Current_SCpnt == SCpnt)				return command;	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,		struct scsi_cmnd *Current_SCpnt,		void (*Current_done)(struct scsi_cmnd *)){	struct list_head *lh;	struct sbp2_command_info *command = NULL;	unsigned long flags;	spin_lock_irqsave(&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;		list_add_tail(&command->list, &scsi_id->sbp2_command_orb_inuse);	} else {		SBP2_ERR("%s: no orbs available", __FUNCTION__);	}	spin_unlock_irqrestore(&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 scsi_id_instance_data *scsi_id =		(struct scsi_id_instance_data *)command->Current_SCpnt->device->host->hostdata[0];	struct hpsb_host *host;	if (!scsi_id) {		SBP2_ERR("%s: scsi_id == NULL", __FUNCTION__);		return;	}	host = scsi_id->ud->ne->host;	if (command->cmd_dma) {		if (command->dma_type == CMD_DMA_SINGLE) {			pci_unmap_single(host->pdev, command->cmd_dma,					 command->dma_size, command->dma_dir);			SBP2_DMA_FREE("single bulk");		} else if (command->dma_type == CMD_DMA_PAGE) {			pci_unmap_page(host->pdev, command->cmd_dma,				       command->dma_size, command->dma_dir);			SBP2_DMA_FREE("single page");		} /* XXX: Check for CMD_DMA_NONE bug */		command->dma_type = CMD_DMA_NONE;		command->cmd_dma = 0;	}	if (command->sge_buffer) {		pci_unmap_sg(host->pdev, command->sge_buffer,			     command->dma_size, command->dma_dir);		SBP2_DMA_FREE("scatter list");		command->sge_buffer = NULL;	}}/* * This function moves a command to the completed orb list. * Must be called with scsi_id->sbp2_command_orb_lock held. */static void sbp2util_mark_command_completed(		struct scsi_id_instance_data *scsi_id,		struct sbp2_command_info *command){	list_del(&command->list);	sbp2util_free_command_dma(command);	list_add_tail(&command->list, &scsi_id->sbp2_command_orb_completed);}/* * Is scsi_id valid? Is the 1394 node still present? */static inline int sbp2util_node_is_available(struct scsi_id_instance_data *scsi_id){	return scsi_id && scsi_id->ne && !scsi_id->ne->in_limbo;}/********************************************* * IEEE-1394 core driver stack related section *********************************************/static struct scsi_id_instance_data *sbp2_alloc_device(struct unit_directory *ud);static int sbp2_probe(struct device *dev){	struct unit_directory *ud;	struct scsi_id_instance_data *scsi_id;	SBP2_DEBUG_ENTER();	ud = container_of(dev, struct unit_directory, device);	/* Don't probe UD's that have the LUN flag. We'll probe the LUN(s)	 * instead. */	if (ud->flags & UNIT_DIRECTORY_HAS_LUN_DIRECTORY)		return -ENODEV;	scsi_id = sbp2_alloc_device(ud);	if (!scsi_id)		return -ENOMEM;	sbp2_parse_unit_directory(scsi_id, ud);	return sbp2_start_device(scsi_id);}static int sbp2_remove(struct device *dev){	struct unit_directory *ud;	struct scsi_id_instance_data *scsi_id;	struct scsi_device *sdev;	SBP2_DEBUG_ENTER();	ud = container_of(dev, struct unit_directory, device);	scsi_id = ud->device.driver_data;	if (!scsi_id)		return 0;	if (scsi_id->scsi_host) {		/* Get rid of enqueued commands if there is no chance to		 * send them. */		if (!sbp2util_node_is_available(scsi_id))			sbp2scsi_complete_all_commands(scsi_id, DID_NO_CONNECT);		/* scsi_remove_device() will trigger shutdown functions of SCSI		 * highlevel drivers which would deadlock if blocked. */		atomic_set(&scsi_id->state, SBP2LU_STATE_IN_SHUTDOWN);		scsi_unblock_requests(scsi_id->scsi_host);	}	sdev = scsi_id->sdev;	if (sdev) {		scsi_id->sdev = NULL;		scsi_remove_device(sdev);	}	sbp2_logout_device(scsi_id);	sbp2_remove_device(scsi_id);	return 0;}static int sbp2_update(struct unit_directory *ud){	struct scsi_id_instance_data *scsi_id = ud->device.driver_data;	SBP2_DEBUG_ENTER();	if (sbp2_reconnect_device(scsi_id)) {		/*		 * Ok, reconnect has failed. Perhaps we didn't		 * reconnect fast enough. Try doing a regular login, but		 * first do a logout just in case of any weirdness.		 */		sbp2_logout_device(scsi_id);		if (sbp2_login_device(scsi_id)) {			/* Login failed too, just fail, and the backend			 * will call our sbp2_remove for us */			SBP2_ERR("Failed to reconnect to sbp2 device!");			return -EBUSY;		}	}	/* Set max retries to something large on the device. */	sbp2_set_busy_timeout(scsi_id);	/* Do a SBP-2 fetch agent reset. */	sbp2_agent_reset(scsi_id, 1);	/* Get the max speed and packet size that we can use. */	sbp2_max_speed_and_size(scsi_id);	/* Complete any pending commands with busy (so they get	 * retried) and remove them from our queue	 */	sbp2scsi_complete_all_commands(scsi_id, DID_BUS_BUSY);	/* Accept new commands unless there was another bus reset in the	 * meantime. */	if (hpsb_node_entry_valid(scsi_id->ne)) {		atomic_set(&scsi_id->state, SBP2LU_STATE_RUNNING);		scsi_unblock_requests(scsi_id->scsi_host);	}	return 0;}/* This functions is called by the sbp2_probe, for each new device. We now * allocate one scsi host for each scsi_id (unit directory). */static struct scsi_id_instance_data *sbp2_alloc_device(struct unit_directory *ud){	struct sbp2scsi_host_info *hi;	struct Scsi_Host *scsi_host = NULL;	struct scsi_id_instance_data *scsi_id = NULL;	SBP2_DEBUG_ENTER();	scsi_id = kzalloc(sizeof(*scsi_id), GFP_KERNEL);	if (!scsi_id) {		SBP2_ERR("failed to create scsi_id");		goto failed_alloc;	}	scsi_id->ne = ud->ne;	scsi_id->ud = ud;	scsi_id->speed_code = IEEE1394_SPEED_100;	scsi_id->max_payload_size = sbp2_speedto_max_payload[IEEE1394_SPEED_100];	scsi_id->status_fifo_addr = CSR1212_INVALID_ADDR_SPACE;	INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse);	INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed);	INIT_LIST_HEAD(&scsi_id->scsi_list);	spin_lock_init(&scsi_id->sbp2_command_orb_lock);	atomic_set(&scsi_id->state, SBP2LU_STATE_RUNNING);	INIT_WORK(&scsi_id->protocol_work, NULL, NULL);	ud->device.driver_data = scsi_id;	hi = hpsb_get_hostinfo(&sbp2_highlevel, ud->ne->host);	if (!hi) {		hi = hpsb_create_hostinfo(&sbp2_highlevel, ud->ne->host, sizeof(*hi));		if (!hi) {			SBP2_ERR("failed to allocate hostinfo");

⌨️ 快捷键说明

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