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

📄 sbp2.c

📁 Armlinux ieee1394接口驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
				   (unsigned int) scsi_id->sbp2_unit_characteristics);			break;		case SBP2_DEVICE_TYPE_AND_LUN_KEY:			/*			 * Device type and lun (used for			 * detemining type of sbp2 device)			 */			scsi_id->sbp2_device_type_and_lun = ud->arb_values[i];			SBP2_DEBUG("sbp2_device_type_and_lun = %x",				   (unsigned int) scsi_id->sbp2_device_type_and_lun);			break;		case SBP2_FIRMWARE_REVISION_KEY:			/*			 * Firmware revision (used to find broken			 * devices). If the vendor id is 0xa0b8			 * (Symbios vendor id), then we have a			 * bridge with 128KB max transfer size			 * limitation.			 */			scsi_id->sbp2_firmware_revision = ud->arb_values[i];			if (scsi_id->sbp2_firmware_revision ==			    SBP2_128KB_BROKEN_FIRMWARE) {				SBP2_WARN("warning: Bridge chipset supports 128KB max transfer size");			}			break;		default:			break;		}	}}/* * This function is called in order to determine the max speed and packet * size we can use in our ORBs. Note, that we (the driver and host) only * initiate the transaction. The SBP-2 device actually transfers the data * (by reading from the DMA area we tell it). This means that the SBP-2 * device decides the actual maximum data it can transfer. We just tell it * the speed that it needs to use, and the max_rec the host supports, and * it takes care of the rest. */static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id){	SBP2_DEBUG("sbp2_max_speed_and_size");	/* Initial setting comes from the hosts speed map */	scsi_id->speed_code = hi->host->speed_map[(hi->host->node_id & NODE_MASK) * 64						  + (scsi_id->ne->nodeid & NODE_MASK)];	/* Bump down our speed if the user requested it */	if (scsi_id->speed_code > max_speed) {		scsi_id->speed_code = max_speed;		SBP2_ERR("Forcing SBP-2 max speed down to %s",			 hpsb_speedto_str[scsi_id->speed_code]);	}	/* Payload size is the lesser of what our speed supports and what	 * our host supports.  */	scsi_id->max_payload_size = min(sbp2_speedto_maxrec[scsi_id->speed_code],					(u8)(((be32_to_cpu(hi->host->csr.rom[2]) >> 12) & 0xf) - 1));	SBP2_ERR("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [%u]",		 NODE_BUS_ARGS(scsi_id->ne->nodeid), hpsb_speedto_str[scsi_id->speed_code],		 1 << ((u32)scsi_id->max_payload_size + 2));	return(0);}/* * This function is called in order to perform a SBP-2 agent reset.  */static int sbp2_agent_reset(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 flags) {	struct sbp2_request_packet *agent_reset_request_packet;	SBP2_DEBUG("sbp2_agent_reset");	/*	 * Ok, let's write to the target's management agent register	 */	agent_reset_request_packet =		sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->ne->nodeid,						       scsi_id->sbp2_command_block_agent_addr +						       SBP2_AGENT_RESET_OFFSET,						       0, ntohl(SBP2_AGENT_RESET_DATA));	if (!agent_reset_request_packet) {		SBP2_ERR("sbp2util_allocate_write_request_packet failed");		return(-EIO);	}	if (!hpsb_send_packet(agent_reset_request_packet->packet)) {		SBP2_ERR("hpsb_send_packet failed");		sbp2util_free_request_packet(agent_reset_request_packet); 		return(-EIO);	}	if (!(flags & SBP2_SEND_NO_WAIT)) {		down(&agent_reset_request_packet->packet->state_change);		down(&agent_reset_request_packet->packet->state_change);	}	/*	 * Need to make sure orb pointer is written on next command	 */	scsi_id->last_orb = NULL;	return(0);}/* * This function is called to create the actual command orb and s/g list * out of the scsi command itself. */static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, 				   struct scsi_id_instance_data *scsi_id,				   struct sbp2_command_info *command,				   unchar *scsi_cmd,				   unsigned int scsi_use_sg,				   unsigned int scsi_request_bufflen,				   void *scsi_request_buffer, int dma_dir){	struct scatterlist *sgpnt = (struct scatterlist *) scsi_request_buffer;	struct sbp2_command_orb *command_orb = &command->command_orb;	struct sbp2_unrestricted_page_table *scatter_gather_element =		&command->scatter_gather_element[0];	u32 sg_count, sg_len;	dma_addr_t sg_addr;	int i;	/*	 * Set-up our command ORB..	 *	 * NOTE: We're doing unrestricted page tables (s/g), as this is	 * best performance (at least with the devices I have). This means	 * that data_size becomes the number of s/g elements, and	 * page_size should be zero (for unrestricted).	 */	command_orb->next_ORB_hi = 0xffffffff;	command_orb->next_ORB_lo = 0xffffffff;	command_orb->misc = ORB_SET_MAX_PAYLOAD(scsi_id->max_payload_size);	command_orb->misc |= ORB_SET_SPEED(scsi_id->speed_code);	command_orb->misc |= ORB_SET_NOTIFY(1);		/* Notify us when complete */	/*	 * Set-up our pagetable stuff... unfortunately, this has become	 * messier than I'd like. Need to clean this up a bit.   ;-)	 */	if (sbp2scsi_direction_table[*scsi_cmd] == ORB_DIRECTION_NO_DATA_TRANSFER) {		SBP2_DEBUG("No data transfer");		/*		 * Handle no data transfer		 */		command_orb->data_descriptor_hi = 0xffffffff;		command_orb->data_descriptor_lo = 0xffffffff;		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->cmd_dma = pci_map_single (hi->host->pdev, sgpnt[0].address,							   command->dma_size,							   command->dma_dir);			SBP2_DMA_ALLOC("single 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(sbp2scsi_direction_table[*scsi_cmd]);		} 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(sbp2scsi_direction_table[*scsi_cmd]);			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);			/*			 * 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->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(sbp2scsi_direction_table[*scsi_cmd]);			/*			 * Sanity, in case our direction table is not			 * up-to-date			 */			if (!scsi_request_bufflen) {				command_orb->data_descriptor_hi = 0xffffffff;				command_orb->data_descriptor_lo = 0xffffffff;				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(sbp2scsi_direction_table[*scsi_cmd]);			/*			 * 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);			/*			 * 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 sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,				 struct sbp2_command_info *command){        struct sbp2_request_packet *command_request_packet;	struct sbp2_command_orb *command_orb = &command->command_orb;	outstanding_orb_incr;	SBP2_ORB_DEBUG("sending command orb %p, linked = %x, total orbs = %x",			command_orb, command->linked, global_outstanding_command_orbs);	/*	 * Check to see if there are any previous orbs to use	 */	if (scsi_id->last_orb == NULL) {			/*		 * Ok, let's write to the target's management agent register		 */		if (hpsb_node_entry_valid(scsi_id->ne)) {			command_request_packet =				sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->ne->nodeid,								scsi_id->sbp2_command_block_agent_addr +								SBP2_ORB_POINTER_OFFSET, 8, 0);					if (!command_request_packet) {				SBP2_ERR("sbp2util_allocate_write_request_packet failed");				return(-EIO);			}					command_request_packet->packet->data[0] = ORB_SET_NODE_ID(hi->host->node_id);			command_request_packet->packet->data[1] = command->command_orb_dma;			sbp2util_cpu_to_be32_buffer(command_request_packet->packet->data, 8);					SBP2_ORB_DEBUG("write command agent, command orb %p", command_orb);			if (!hpsb_send_packet(command_request_packet->packet)) {				SBP2_ERR("hpsb_send_packet failed");				sbp2util_free_request_packet(command_request_packet); 				return(-EIO);			}			SBP2_ORB_DEBUG("write command agent complete");		}		scsi_id->last_orb = command_orb;	} else {		/*		 * 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;		/*		 * Only ring the doorbell if we need to (first parts of		 * linked orbs don't need this).		 */		if (!command->linked && hpsb_node_entry_valid(scsi_id->ne)) {			command_request_packet = sbp2util_allocate_write_request_packet(hi,				LOCAL_BUS | scsi_id->ne->nodeid,				scsi_id->sbp2_command_block_agent_addr + SBP2_DOORBELL_OFFSET,				0, cpu_to_be32(command->command_orb_dma));				if (!command_request_packet) {			

⌨️ 快捷键说明

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