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

📄 sbp2.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
	scsi_id->sbp2_command_block_agent_addr &= 0x0000ffffffffffffULL;	SBP2_INFO("Logged into SBP-2 device");	return(0);}/* * This function is called in order to logout from a particular SBP-2 * device, usually called during driver unload. */static int sbp2_logout_device(struct scsi_id_instance_data *scsi_id){	struct sbp2scsi_host_info *hi = scsi_id->hi;	quadlet_t data[2];	int error;	SBP2_DEBUG("sbp2_logout_device");	/*	 * Set-up logout ORB	 */	scsi_id->logout_orb->reserved1 = 0x0;	scsi_id->logout_orb->reserved2 = 0x0;	scsi_id->logout_orb->reserved3 = 0x0;	scsi_id->logout_orb->reserved4 = 0x0;	scsi_id->logout_orb->login_ID_misc = ORB_SET_FUNCTION(LOGOUT_REQUEST);	scsi_id->logout_orb->login_ID_misc |= ORB_SET_LOGIN_ID(scsi_id->login_response->length_login_ID);	/* Notify us when complete */	scsi_id->logout_orb->login_ID_misc |= ORB_SET_NOTIFY(1);	scsi_id->logout_orb->reserved5 = 0x0;	scsi_id->logout_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO +					      SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->ud->id);	scsi_id->logout_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) |					       SBP2_STATUS_FIFO_ADDRESS_HI);	/*	 * Byte swap ORB if necessary	 */	sbp2util_cpu_to_be32_buffer(scsi_id->logout_orb, sizeof(struct sbp2_logout_orb));	sbp2util_packet_dump(scsi_id->logout_orb, sizeof(struct sbp2_logout_orb),			     "sbp2 logout orb", scsi_id->logout_orb_dma);	/*	 * Ok, let's write to the target's management agent register	 */	data[0] = ORB_SET_NODE_ID(hi->host->node_id);	data[1] = scsi_id->logout_orb_dma;	sbp2util_cpu_to_be32_buffer(data, 8);	atomic_set(&scsi_id->sbp2_login_complete, 0);	error = hpsb_node_write(scsi_id->ne,	                            scsi_id->sbp2_management_agent_addr,	                            data, 8);	if (error)		return error;	/* Wait for device to logout...1 second. */	if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, HZ))		return -EIO;	SBP2_INFO("Logged out of SBP-2 device");	return(0);}/* * This function is called in order to reconnect to a particular SBP-2 * device, after a bus reset. */static int sbp2_reconnect_device(struct scsi_id_instance_data *scsi_id){	struct sbp2scsi_host_info *hi = scsi_id->hi;	quadlet_t data[2];	int error;	SBP2_DEBUG("sbp2_reconnect_device");	/*	 * Set-up reconnect ORB	 */	scsi_id->reconnect_orb->reserved1 = 0x0;	scsi_id->reconnect_orb->reserved2 = 0x0;	scsi_id->reconnect_orb->reserved3 = 0x0;	scsi_id->reconnect_orb->reserved4 = 0x0;	scsi_id->reconnect_orb->login_ID_misc = ORB_SET_FUNCTION(RECONNECT_REQUEST);	scsi_id->reconnect_orb->login_ID_misc |=		ORB_SET_LOGIN_ID(scsi_id->login_response->length_login_ID);	/* Notify us when complete */	scsi_id->reconnect_orb->login_ID_misc |= ORB_SET_NOTIFY(1);	scsi_id->reconnect_orb->reserved5 = 0x0;	scsi_id->reconnect_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO +						 SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->ud->id);	scsi_id->reconnect_orb->status_FIFO_hi =		(ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI);	/*	 * Byte swap ORB if necessary	 */	sbp2util_cpu_to_be32_buffer(scsi_id->reconnect_orb, sizeof(struct sbp2_reconnect_orb));	sbp2util_packet_dump(scsi_id->reconnect_orb, sizeof(struct sbp2_reconnect_orb),			     "sbp2 reconnect orb", scsi_id->reconnect_orb_dma);	/*	 * Initialize status fifo	 */	memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));	/*	 * Ok, let's write to the target's management agent register	 */	data[0] = ORB_SET_NODE_ID(hi->host->node_id);	data[1] = scsi_id->reconnect_orb_dma;	sbp2util_cpu_to_be32_buffer(data, 8);	atomic_set(&scsi_id->sbp2_login_complete, 0);	error = hpsb_node_write(scsi_id->ne,	                            scsi_id->sbp2_management_agent_addr,	                            data, 8);	if (error)		return error;	/*	 * Wait for reconnect status (up to 1 second)...	 */	if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, HZ)) {		SBP2_ERR("Error reconnecting to SBP-2 device - reconnect timed-out");		return(-EIO);	}	/*	 * Sanity. Make sure status returned matches reconnect orb.	 */	if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma) {		SBP2_ERR("Error reconnecting to SBP-2 device - reconnect timed-out");		return(-EIO);	}	/*	 * Check status	 */	if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) ||	    STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) ||	    STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {		SBP2_ERR("Error reconnecting to SBP-2 device - reconnect failed");		return(-EIO);	}	HPSB_DEBUG("Reconnected to SBP-2 device");	return(0);}/* * This function is called in order to set the busy timeout (number of * retries to attempt) on the sbp2 device. */static int sbp2_set_busy_timeout(struct scsi_id_instance_data *scsi_id){	quadlet_t data;	SBP2_DEBUG("sbp2_set_busy_timeout");	/*	 * Ok, let's write to the target's busy timeout register	 */	data = cpu_to_be32(SBP2_BUSY_TIMEOUT_VALUE);	if (hpsb_node_write(scsi_id->ne, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) {		SBP2_ERR("sbp2_set_busy_timeout error");	}	return(0);}/* * This function is called to parse sbp2 device's config rom unit * directory. Used to determine things like sbp2 management agent offset, * and command set used (SCSI or RBC). */static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id,				      struct unit_directory *ud){	struct csr1212_keyval *kv;	struct csr1212_dentry *dentry;	u64 management_agent_addr;	u32 command_set_spec_id, command_set, unit_characteristics,		firmware_revision, workarounds;	int i;	SBP2_DEBUG("sbp2_parse_unit_directory");	management_agent_addr = 0x0;	command_set_spec_id = 0x0;	command_set = 0x0;	unit_characteristics = 0x0;	firmware_revision = 0x0;	/* Handle different fields in the unit directory, based on keys */	csr1212_for_each_dir_entry(ud->ne->csr, kv, ud->ud_kv, dentry) {		switch (kv->key.id) {		case CSR1212_KV_ID_DEPENDENT_INFO:			if (kv->key.type == CSR1212_KV_TYPE_CSR_OFFSET) {				/* Save off the management agent address */				management_agent_addr =					CSR1212_REGISTER_SPACE_BASE +					(kv->value.csr_offset << 2);				SBP2_DEBUG("sbp2_management_agent_addr = %x",					   (unsigned int) management_agent_addr);			} else				scsi_id->sbp2_device_type_and_lun = kv->value.immediate;			break;		case SBP2_COMMAND_SET_SPEC_ID_KEY:			/* Command spec organization */			command_set_spec_id = kv->value.immediate;			SBP2_DEBUG("sbp2_command_set_spec_id = %x",				   (unsigned int) command_set_spec_id);			break;		case SBP2_COMMAND_SET_KEY:			/* Command set used by sbp2 device */			command_set = kv->value.immediate;			SBP2_DEBUG("sbp2_command_set = %x",				   (unsigned int) command_set);			break;		case SBP2_UNIT_CHARACTERISTICS_KEY:			/*			 * Unit characterisitcs (orb related stuff			 * that I'm not yet paying attention to)			 */			unit_characteristics = kv->value.immediate;			SBP2_DEBUG("sbp2_unit_characteristics = %x",				   (unsigned int) unit_characteristics);			break;		case SBP2_FIRMWARE_REVISION_KEY:			/* Firmware revision */			firmware_revision = kv->value.immediate;			if (force_inquiry_hack)				SBP2_INFO("sbp2_firmware_revision = %x",				   (unsigned int) firmware_revision);			else	SBP2_DEBUG("sbp2_firmware_revision = %x",				   (unsigned int) firmware_revision);			break;		default:			break;		}	}	/* This is the start of our broken device checking. We try to hack	 * around oddities and known defects.  */	workarounds = 0x0;	/* If the vendor id is 0xa0b8 (Symbios vendor id), then we have a	 * bridge with 128KB max transfer size limitation. For sanity, we	 * only voice this when the current max_sectors setting	 * exceeds the 128k limit. By default, that is not the case.	 *	 * It would be really nice if we could detect this before the scsi	 * host gets initialized. That way we can down-force the	 * max_sectors to account for it. That is not currently	 * possible.  */	if ((firmware_revision & 0xffff00) ==			SBP2_128KB_BROKEN_FIRMWARE &&			(max_sectors * 512) > (128*1024)) {		SBP2_WARN("Node " NODE_BUS_FMT ": Bridge only supports 128KB max transfer size.",				NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid));		SBP2_WARN("WARNING: Current max_sectors setting is larger than 128KB (%d sectors)!",				max_sectors);		workarounds |= SBP2_BREAKAGE_128K_MAX_TRANSFER;	}	/* Check for a blacklisted set of devices that require us to force	 * a 36 byte host inquiry. This can be overriden as a module param	 * (to force all hosts).  */	for (i = 0; i < NUM_BROKEN_INQUIRY_DEVS; i++) {		if ((firmware_revision & 0xffff00) ==				sbp2_broken_inquiry_list[i]) {			SBP2_WARN("Node " NODE_BUS_FMT ": Using 36byte inquiry workaround",					NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid));			workarounds |= SBP2_BREAKAGE_INQUIRY_HACK;			break; /* No need to continue. */		}	}	/* If this is a logical unit directory entry, process the parent	 * to get the values. */	if (ud->flags & UNIT_DIRECTORY_LUN_DIRECTORY) {		struct unit_directory *parent_ud =			container_of(ud->device.parent, struct unit_directory, device);		sbp2_parse_unit_directory(scsi_id, parent_ud);	} else {		scsi_id->sbp2_management_agent_addr = management_agent_addr;		scsi_id->sbp2_command_set_spec_id = command_set_spec_id;		scsi_id->sbp2_command_set = command_set;		scsi_id->sbp2_unit_characteristics = unit_characteristics;		scsi_id->sbp2_firmware_revision = firmware_revision;		scsi_id->workarounds = workarounds;	}}/* * 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 scsi_id_instance_data *scsi_id){	struct sbp2scsi_host_info *hi = scsi_id->hi;	SBP2_DEBUG("sbp2_max_speed_and_size");	/* Initial setting comes from the hosts speed map */	scsi_id->speed_code = hi->host->speed_map[NODEID_TO_NODE(hi->host->node_id) * 64						  + NODEID_TO_NODE(scsi_id->ne->nodeid)];	/* 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_max_payload[scsi_id->speed_code],					(u8)(hi->host->csr.max_rec - 1));	HPSB_DEBUG("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [%u]",		   NODE_BUS_ARGS(hi->host, 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 scsi_id_instance_data *scsi_id, int wait){	quadlet_t data;	u64 addr;	int retval;	SBP2_DEBUG("sbp2_agent_reset");	/*	 * Ok, let's write to the target's management agent register	 */	data = ntohl(SBP2_AGENT_RESET_DATA);	addr = scsi_id->sbp2_command_block_agent_addr + SBP2_AGENT_RESET_OFFSET;	if (wait)		retval = hpsb_node_write(scsi_id->ne, addr, &data, 4);	else		retval = sbp2util_node_write_no_wait(scsi_id->ne, addr, &data, 4);	if (retval < 0) {		SBP2_ERR("hpsb_node_write failed.\n");		return -EIO;	}	/*	 * 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 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,				   unsigned char scsi_dir){	struct sbp2scsi_host_info *hi = scsi_id->hi;	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];	int dma_dir = scsi_to_pci_dma_dir (scsi_dir);	u32 sg_count, sg_len, orb_direction;	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 = ORB_SET_NULL_PTR(1);	command_orb->next_ORB_lo = 0x0;	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 */	/*	 * Get the direction of the transfer. If the direction is unknown, then use our	 * goofy table as a back-up.

⌨️ 快捷键说明

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