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

📄 sbp2.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
	 */	switch (scsi_dir) {		case SCSI_DATA_NONE:			orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER;			break;		case SCSI_DATA_WRITE:			orb_direction = ORB_DIRECTION_WRITE_TO_MEDIA;			break;		case SCSI_DATA_READ:			orb_direction = ORB_DIRECTION_READ_FROM_MEDIA;			break;		case SCSI_DATA_UNKNOWN:		default:			SBP2_ERR("SCSI data transfer direction not specified. "				 "Update the SBP2 direction table in sbp2.h if "				 "necessary for your application");			print_command (scsi_cmd);			orb_direction = sbp2scsi_direction_table[*scsi_cmd];			break;	}	/*	 * Set-up our pagetable stuff... unfortunately, this has become	 * messier than I'd like. Need to clean this up a bit.   ;-)	 */	if (orb_direction == ORB_DIRECTION_NO_DATA_TRANSFER) {		SBP2_DEBUG("No data transfer");		/*		 * Handle no data transfer		 */		command_orb->data_descriptor_hi = 0x0;		command_orb->data_descriptor_lo = 0x0;		command_orb->misc |= ORB_SET_DIRECTION(1);	} else if (scsi_use_sg) {		SBP2_DEBUG("Use scatter/gather");		/*		 * Special case if only one element (and less than 64KB in size)		 */		if ((scsi_use_sg == 1) && (sgpnt[0].length <= SBP2_MAX_SG_ELEMENT_LENGTH)) {			SBP2_DEBUG("Only one s/g element");			command->dma_dir = dma_dir;			command->dma_size = sgpnt[0].length;			command->dma_type = CMD_DMA_PAGE;			command->cmd_dma = pci_map_page(hi->host->pdev,							sgpnt[0].page,							sgpnt[0].offset,							command->dma_size,							command->dma_dir);			SBP2_DMA_ALLOC("single page scatter element");			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);			command_orb->data_descriptor_lo = command->cmd_dma;			command_orb->misc |= ORB_SET_DATA_SIZE(command->dma_size);			command_orb->misc |= ORB_SET_DIRECTION(orb_direction);		} else {			int count = pci_map_sg(hi->host->pdev, sgpnt, scsi_use_sg, dma_dir);			SBP2_DMA_ALLOC("scatter list");			command->dma_size = scsi_use_sg;			command->dma_dir = dma_dir;			command->sge_buffer = sgpnt;			/* use page tables (s/g) */			command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1);			command_orb->misc |= ORB_SET_DIRECTION(orb_direction);			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);			command_orb->data_descriptor_lo = command->sge_dma;			/*			 * Loop through and fill out our sbp-2 page tables			 * (and split up anything too large)			 */			for (i = 0, sg_count = 0 ; i < count; i++, sgpnt++) {				sg_len = sg_dma_len(sgpnt);				sg_addr = sg_dma_address(sgpnt);				while (sg_len) {					scatter_gather_element[sg_count].segment_base_lo = sg_addr;					if (sg_len > SBP2_MAX_SG_ELEMENT_LENGTH) {						scatter_gather_element[sg_count].length_segment_base_hi =							PAGE_TABLE_SET_SEGMENT_LENGTH(SBP2_MAX_SG_ELEMENT_LENGTH);						sg_addr += SBP2_MAX_SG_ELEMENT_LENGTH;						sg_len -= SBP2_MAX_SG_ELEMENT_LENGTH;					} else {						scatter_gather_element[sg_count].length_segment_base_hi =							PAGE_TABLE_SET_SEGMENT_LENGTH(sg_len);						sg_len = 0;					}					sg_count++;				}			}			/* Number of page table (s/g) elements */			command_orb->misc |= ORB_SET_DATA_SIZE(sg_count);			sbp2util_packet_dump(scatter_gather_element,					     (sizeof(struct sbp2_unrestricted_page_table)) * sg_count,					     "sbp2 s/g list", command->sge_dma);			/*			 * Byte swap page tables if necessary			 */			sbp2util_cpu_to_be32_buffer(scatter_gather_element,						    (sizeof(struct sbp2_unrestricted_page_table)) *						    sg_count);		}	} else {		SBP2_DEBUG("No scatter/gather");		command->dma_dir = dma_dir;		command->dma_size = scsi_request_bufflen;		command->dma_type = CMD_DMA_SINGLE;		command->cmd_dma = pci_map_single (hi->host->pdev, scsi_request_buffer,						   command->dma_size,						   command->dma_dir);		SBP2_DMA_ALLOC("single bulk");		/*		 * Handle case where we get a command w/o s/g enabled (but		 * check for transfers larger than 64K)		 */		if (scsi_request_bufflen <= SBP2_MAX_SG_ELEMENT_LENGTH) {			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);			command_orb->data_descriptor_lo = command->cmd_dma;			command_orb->misc |= ORB_SET_DATA_SIZE(scsi_request_bufflen);			command_orb->misc |= ORB_SET_DIRECTION(orb_direction);			/*			 * Sanity, in case our direction table is not			 * up-to-date			 */			if (!scsi_request_bufflen) {				command_orb->data_descriptor_hi = 0x0;				command_orb->data_descriptor_lo = 0x0;				command_orb->misc |= ORB_SET_DIRECTION(1);			}		} else {			/*			 * Need to turn this into page tables, since the			 * buffer is too large.			 */			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);			command_orb->data_descriptor_lo = command->sge_dma;			/* Use page tables (s/g) */			command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1);			command_orb->misc |= ORB_SET_DIRECTION(orb_direction);			/*			 * fill out our sbp-2 page tables (and split up			 * the large buffer)			 */			sg_count = 0;			sg_len = scsi_request_bufflen;			sg_addr = command->cmd_dma;			while (sg_len) {				scatter_gather_element[sg_count].segment_base_lo = sg_addr;				if (sg_len > SBP2_MAX_SG_ELEMENT_LENGTH) {					scatter_gather_element[sg_count].length_segment_base_hi =						PAGE_TABLE_SET_SEGMENT_LENGTH(SBP2_MAX_SG_ELEMENT_LENGTH);					sg_addr += SBP2_MAX_SG_ELEMENT_LENGTH;					sg_len -= SBP2_MAX_SG_ELEMENT_LENGTH;				} else {					scatter_gather_element[sg_count].length_segment_base_hi =						PAGE_TABLE_SET_SEGMENT_LENGTH(sg_len);					sg_len = 0;				}				sg_count++;			}			/* Number of page table (s/g) elements */			command_orb->misc |= ORB_SET_DATA_SIZE(sg_count);			sbp2util_packet_dump(scatter_gather_element,					     (sizeof(struct sbp2_unrestricted_page_table)) * sg_count,					     "sbp2 s/g list", command->sge_dma);			/*			 * Byte swap page tables if necessary			 */			sbp2util_cpu_to_be32_buffer(scatter_gather_element,						    (sizeof(struct sbp2_unrestricted_page_table)) *						     sg_count);		}	}	/*	 * Byte swap command ORB if necessary	 */	sbp2util_cpu_to_be32_buffer(command_orb, sizeof(struct sbp2_command_orb));	/*	 * Put our scsi command in the command ORB	 */	memset(command_orb->cdb, 0, 12);	memcpy(command_orb->cdb, scsi_cmd, COMMAND_SIZE(*scsi_cmd));	return(0);}/* * This function is called in order to begin a regular SBP-2 command. */static int sbp2_link_orb_command(struct scsi_id_instance_data *scsi_id,				 struct sbp2_command_info *command){	struct sbp2scsi_host_info *hi = scsi_id->hi;	struct sbp2_command_orb *command_orb = &command->command_orb;	struct node_entry *ne = scsi_id->ne;	u64 addr;	outstanding_orb_incr;	SBP2_ORB_DEBUG("sending command orb %p, total orbs = %x",			command_orb, global_outstanding_command_orbs);	pci_dma_sync_single_for_device(hi->host->pdev, command->command_orb_dma,				       sizeof(struct sbp2_command_orb),				       PCI_DMA_BIDIRECTIONAL);	pci_dma_sync_single_for_device(hi->host->pdev, command->sge_dma,				       sizeof(command->scatter_gather_element),				       PCI_DMA_BIDIRECTIONAL);	/*	 * Check to see if there are any previous orbs to use	 */	if (scsi_id->last_orb == NULL) {		quadlet_t data[2];		/*		 * Ok, let's write to the target's management agent register		 */		addr = scsi_id->sbp2_command_block_agent_addr + SBP2_ORB_POINTER_OFFSET;		data[0] = ORB_SET_NODE_ID(hi->host->node_id);		data[1] = command->command_orb_dma;		sbp2util_cpu_to_be32_buffer(data, 8);		SBP2_ORB_DEBUG("write command agent, command orb %p", command_orb);		if (sbp2util_node_write_no_wait(ne, addr, data, 8) < 0) {			SBP2_ERR("sbp2util_node_write_no_wait failed.\n");			return -EIO;		}		SBP2_ORB_DEBUG("write command agent complete");		scsi_id->last_orb = command_orb;		scsi_id->last_orb_dma = command->command_orb_dma;	} else {		quadlet_t data;		/*		 * We have an orb already sent (maybe or maybe not		 * processed) that we can append this orb to. So do so,		 * and ring the doorbell. Have to be very careful		 * modifying these next orb pointers, as they are accessed		 * both by the sbp2 device and us.		 */		scsi_id->last_orb->next_ORB_lo =			cpu_to_be32(command->command_orb_dma);		/* Tells hardware that this pointer is valid */		scsi_id->last_orb->next_ORB_hi = 0x0;		pci_dma_sync_single_for_device(hi->host->pdev, scsi_id->last_orb_dma,					       sizeof(struct sbp2_command_orb),					       PCI_DMA_BIDIRECTIONAL);		/*		 * Ring the doorbell		 */		data = cpu_to_be32(command->command_orb_dma);		addr = scsi_id->sbp2_command_block_agent_addr + SBP2_DOORBELL_OFFSET;		SBP2_ORB_DEBUG("ring doorbell, command orb %p", command_orb);		if (sbp2util_node_write_no_wait(ne, addr, &data, 4) < 0) {			SBP2_ERR("sbp2util_node_write_no_wait failed");			return(-EIO);		}		scsi_id->last_orb = command_orb;		scsi_id->last_orb_dma = command->command_orb_dma;	}       	return(0);}/* * This function is called in order to begin a regular SBP-2 command. */static int sbp2_send_command(struct scsi_id_instance_data *scsi_id,			     Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)){	unchar *cmd = (unchar *) SCpnt->cmnd;	unsigned int request_bufflen = SCpnt->request_bufflen;	struct sbp2_command_info *command;	SBP2_DEBUG("sbp2_send_command");#if (CONFIG_IEEE1394_SBP2_DEBUG >= 2) || defined(CONFIG_IEEE1394_SBP2_PACKET_DUMP)	printk("[scsi command]\n   ");	print_command (cmd);#endif	SBP2_DEBUG("SCSI transfer size = %x", request_bufflen);	SBP2_DEBUG("SCSI s/g elements = %x", (unsigned int)SCpnt->use_sg);	/*	 * Allocate a command orb and s/g structure	 */	command = sbp2util_allocate_command_orb(scsi_id, SCpnt, done);	if (!command) {		return(-EIO);	}	/*	 * The scsi stack sends down a request_bufflen which does not match the	 * length field in the scsi cdb. This causes some sbp2 devices to	 * reject this inquiry command. Fix the request_bufflen.	 */	if (*cmd == INQUIRY) {		if (force_inquiry_hack || scsi_id->workarounds & SBP2_BREAKAGE_INQUIRY_HACK)			request_bufflen = cmd[4] = 0x24;		else			request_bufflen = cmd[4];	}	/*	 * Now actually fill in the comamnd orb and sbp2 s/g list	 */	sbp2_create_command_orb(scsi_id, command, cmd, SCpnt->use_sg,				request_bufflen, SCpnt->request_buffer,				SCpnt->sc_data_direction);	/*	 * Update our cdb if necessary (to handle sbp2 RBC command set	 * differences). This is where the command set hacks go!   =)	 */	sbp2_check_sbp2_command(scsi_id, command->command_orb.cdb);	sbp2util_packet_dump(&command->command_orb, sizeof(struct sbp2_command_orb),			     "sbp2 command orb", command->command_orb_dma);	/*	 * Initialize status fifo	 */	memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));	/*	 * Link up the orb, and ring the doorbell if needed	 */	sbp2_link_orb_command(scsi_id, command);	return(0);}/* * This function deals with command set differences between Linux scsi * command set and sbp2 RBC command set. */static void sbp2_check_sbp2_command(struct scsi_id_instance_data *scsi_id, unchar *cmd){	unchar new_cmd[16];	u8 device_type = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun);	SBP2_DEBUG("sbp2_check_sbp2_command");	switch (*cmd) {		case READ_6:			if (sbp2_command_conversion_device_type(device_type)) {				SBP2_DEBUG("Convert READ_6 to READ_10");				/*				 * Need to turn read_6 into read_10				 */				new_cmd[0] = 0x28;				new_cmd[1] = (cmd[1] & 0xe0);				new_cmd[2] = 0x0;				new_cmd[3] = (cmd[1] & 0x1f);				new_cmd[4] = cmd[2];				new_cmd[5] = cmd[3];				new_cmd[6] = 0x0;				new_cmd[7] = 0x0;				new_cmd[8] = cmd[4];				new_cmd[9] = cmd[5];				memcpy(cmd, new_cmd, 10);			}			break;		case WRITE_6:			if (sbp2_command_conversion_device_type(device_type)) {				SBP2_DEBUG("Convert WRITE_6 to WRITE_10");				/*				 * Need to turn write_6 into write_10				 */				new_cmd[0] = 0x2a;				new_cmd[1] = (cmd[1] & 0xe0);				new_cmd[2] = 0x0;				new_cmd[3] = (cmd[1] & 0x1f);				new_cmd[4] = cmd[2];				new_cmd[5] = cmd[3];				new_cmd[6] = 0x0;				new_cmd[7] = 0x0;				new_cmd[8] = cmd[4];				new_cmd[9] = cmd[5];				memcpy(cmd, new_cmd, 10);			}			break;		case MODE_SENSE:		

⌨️ 快捷键说明

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