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

📄 sbp2.c

📁 Ieee1394驱动实现
💻 C
📖 第 1 页 / 共 5 页
字号:

static void sbp2_host_reset(struct hpsb_host *host)
{
	struct sbp2_fwhost_info *hi;
	struct sbp2_lu *lu;

	hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
	if (!hi)
		return;
	list_for_each_entry(lu, &hi->logical_units, lu_list)
		if (likely(atomic_read(&lu->state) !=
			   SBP2LU_STATE_IN_SHUTDOWN)) {
			atomic_set(&lu->state, SBP2LU_STATE_IN_RESET);
			scsi_block_requests(lu->shost);
		}
}

static int sbp2_start_device(struct sbp2_lu *lu)
{
	struct sbp2_fwhost_info *hi = lu->hi;
	int error;

	lu->login_response = dma_alloc_coherent(hi->host->device.parent,
				     sizeof(struct sbp2_login_response),
				     &lu->login_response_dma, GFP_KERNEL);
	if (!lu->login_response)
		goto alloc_fail;

	lu->query_logins_orb = dma_alloc_coherent(hi->host->device.parent,
				     sizeof(struct sbp2_query_logins_orb),
				     &lu->query_logins_orb_dma, GFP_KERNEL);
	if (!lu->query_logins_orb)
		goto alloc_fail;

	lu->query_logins_response = dma_alloc_coherent(hi->host->device.parent,
				     sizeof(struct sbp2_query_logins_response),
				     &lu->query_logins_response_dma, GFP_KERNEL);
	if (!lu->query_logins_response)
		goto alloc_fail;

	lu->reconnect_orb = dma_alloc_coherent(hi->host->device.parent,
				     sizeof(struct sbp2_reconnect_orb),
				     &lu->reconnect_orb_dma, GFP_KERNEL);
	if (!lu->reconnect_orb)
		goto alloc_fail;

	lu->logout_orb = dma_alloc_coherent(hi->host->device.parent,
				     sizeof(struct sbp2_logout_orb),
				     &lu->logout_orb_dma, GFP_KERNEL);
	if (!lu->logout_orb)
		goto alloc_fail;

	lu->login_orb = dma_alloc_coherent(hi->host->device.parent,
				     sizeof(struct sbp2_login_orb),
				     &lu->login_orb_dma, GFP_KERNEL);
	if (!lu->login_orb)
		goto alloc_fail;

	if (sbp2util_create_command_orb_pool(lu))
		goto alloc_fail;

	/* Wait a second before trying to log in. Previously logged in
	 * initiators need a chance to reconnect. */
	if (msleep_interruptible(1000)) {
		sbp2_remove_device(lu);
		return -EINTR;
	}

	if (sbp2_login_device(lu)) {
		sbp2_remove_device(lu);
		return -EBUSY;
	}

	sbp2_set_busy_timeout(lu);
	sbp2_agent_reset(lu, 1);
	sbp2_max_speed_and_size(lu);

	error = scsi_add_device(lu->shost, 0, lu->ud->id, 0);
	if (error) {
		SBP2_ERR("scsi_add_device failed");
		sbp2_logout_device(lu);
		sbp2_remove_device(lu);
		return error;
	}

	return 0;

alloc_fail:
	SBP2_ERR("Could not allocate memory for lu");
	sbp2_remove_device(lu);
	return -ENOMEM;
}

static void sbp2_remove_device(struct sbp2_lu *lu)
{
	struct sbp2_fwhost_info *hi;

	if (!lu)
		return;

	hi = lu->hi;

	if (lu->shost) {
		scsi_remove_host(lu->shost);
		scsi_host_put(lu->shost);
	}
	flush_scheduled_work();
	sbp2util_remove_command_orb_pool(lu);

	list_del(&lu->lu_list);

	if (lu->login_response)
		dma_free_coherent(hi->host->device.parent,
				    sizeof(struct sbp2_login_response),
				    lu->login_response,
				    lu->login_response_dma);
	if (lu->login_orb)
		dma_free_coherent(hi->host->device.parent,
				    sizeof(struct sbp2_login_orb),
				    lu->login_orb,
				    lu->login_orb_dma);
	if (lu->reconnect_orb)
		dma_free_coherent(hi->host->device.parent,
				    sizeof(struct sbp2_reconnect_orb),
				    lu->reconnect_orb,
				    lu->reconnect_orb_dma);
	if (lu->logout_orb)
		dma_free_coherent(hi->host->device.parent,
				    sizeof(struct sbp2_logout_orb),
				    lu->logout_orb,
				    lu->logout_orb_dma);
	if (lu->query_logins_orb)
		dma_free_coherent(hi->host->device.parent,
				    sizeof(struct sbp2_query_logins_orb),
				    lu->query_logins_orb,
				    lu->query_logins_orb_dma);
	if (lu->query_logins_response)
		dma_free_coherent(hi->host->device.parent,
				    sizeof(struct sbp2_query_logins_response),
				    lu->query_logins_response,
				    lu->query_logins_response_dma);

	if (lu->status_fifo_addr != CSR1212_INVALID_ADDR_SPACE)
		hpsb_unregister_addrspace(&sbp2_highlevel, hi->host,
					  lu->status_fifo_addr);

	lu->ud->device.driver_data = NULL;

	if (hi)
		module_put(hi->host->driver->owner);

	kfree(lu);
}

#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
/*
 * Deal with write requests on adapters which do not support physical DMA or
 * have it switched off.
 */
static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid,
				     int destid, quadlet_t *data, u64 addr,
				     size_t length, u16 flags)
{
	memcpy(bus_to_virt((u32) addr), data, length);
	return RCODE_COMPLETE;
}

/*
 * Deal with read requests on adapters which do not support physical DMA or
 * have it switched off.
 */
static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid,
				    quadlet_t *data, u64 addr, size_t length,
				    u16 flags)
{
	memcpy(data, bus_to_virt((u32) addr), length);
	return RCODE_COMPLETE;
}
#endif

/**************************************
 * SBP-2 protocol related section
 **************************************/

static int sbp2_query_logins(struct sbp2_lu *lu)
{
	struct sbp2_fwhost_info *hi = lu->hi;
	quadlet_t data[2];
	int max_logins;
	int active_logins;

	lu->query_logins_orb->reserved1 = 0x0;
	lu->query_logins_orb->reserved2 = 0x0;

	lu->query_logins_orb->query_response_lo = lu->query_logins_response_dma;
	lu->query_logins_orb->query_response_hi =
			ORB_SET_NODE_ID(hi->host->node_id);
	lu->query_logins_orb->lun_misc =
			ORB_SET_FUNCTION(SBP2_QUERY_LOGINS_REQUEST);
	lu->query_logins_orb->lun_misc |= ORB_SET_NOTIFY(1);
	lu->query_logins_orb->lun_misc |= ORB_SET_LUN(lu->lun);

	lu->query_logins_orb->reserved_resp_length =
		ORB_SET_QUERY_LOGINS_RESP_LENGTH(
			sizeof(struct sbp2_query_logins_response));

	lu->query_logins_orb->status_fifo_hi =
		ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id);
	lu->query_logins_orb->status_fifo_lo =
		ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr);

	sbp2util_cpu_to_be32_buffer(lu->query_logins_orb,
				    sizeof(struct sbp2_query_logins_orb));

	memset(lu->query_logins_response, 0,
	       sizeof(struct sbp2_query_logins_response));

	data[0] = ORB_SET_NODE_ID(hi->host->node_id);
	data[1] = lu->query_logins_orb_dma;
	sbp2util_cpu_to_be32_buffer(data, 8);

	hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8);

	if (sbp2util_access_timeout(lu, 2*HZ)) {
		SBP2_INFO("Error querying logins to SBP-2 device - timed out");
		return -EIO;
	}

	if (lu->status_block.ORB_offset_lo != lu->query_logins_orb_dma) {
		SBP2_INFO("Error querying logins to SBP-2 device - timed out");
		return -EIO;
	}

	if (STATUS_TEST_RDS(lu->status_block.ORB_offset_hi_misc)) {
		SBP2_INFO("Error querying logins to SBP-2 device - failed");
		return -EIO;
	}

	sbp2util_cpu_to_be32_buffer(lu->query_logins_response,
				    sizeof(struct sbp2_query_logins_response));

	max_logins = RESPONSE_GET_MAX_LOGINS(
			lu->query_logins_response->length_max_logins);
	SBP2_INFO("Maximum concurrent logins supported: %d", max_logins);

	active_logins = RESPONSE_GET_ACTIVE_LOGINS(
			lu->query_logins_response->length_max_logins);
	SBP2_INFO("Number of active logins: %d", active_logins);

	if (active_logins >= max_logins) {
		return -EIO;
	}

	return 0;
}

static int sbp2_login_device(struct sbp2_lu *lu)
{
	struct sbp2_fwhost_info *hi = lu->hi;
	quadlet_t data[2];

	if (!lu->login_orb)
		return -EIO;

	if (!sbp2_exclusive_login && sbp2_query_logins(lu)) {
		SBP2_INFO("Device does not support any more concurrent logins");
		return -EIO;
	}

	/* assume no password */
	lu->login_orb->password_hi = 0;
	lu->login_orb->password_lo = 0;

	lu->login_orb->login_response_lo = lu->login_response_dma;
	lu->login_orb->login_response_hi = ORB_SET_NODE_ID(hi->host->node_id);
	lu->login_orb->lun_misc = ORB_SET_FUNCTION(SBP2_LOGIN_REQUEST);

	/* one second reconnect time */
	lu->login_orb->lun_misc |= ORB_SET_RECONNECT(0);
	lu->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(sbp2_exclusive_login);
	lu->login_orb->lun_misc |= ORB_SET_NOTIFY(1);
	lu->login_orb->lun_misc |= ORB_SET_LUN(lu->lun);

	lu->login_orb->passwd_resp_lengths =
		ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response));

	lu->login_orb->status_fifo_hi =
		ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id);
	lu->login_orb->status_fifo_lo =
		ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr);

	sbp2util_cpu_to_be32_buffer(lu->login_orb,
				    sizeof(struct sbp2_login_orb));

	memset(lu->login_response, 0, sizeof(struct sbp2_login_response));

	data[0] = ORB_SET_NODE_ID(hi->host->node_id);
	data[1] = lu->login_orb_dma;
	sbp2util_cpu_to_be32_buffer(data, 8);

	hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8);

	/* wait up to 20 seconds for login status */
	if (sbp2util_access_timeout(lu, 20*HZ)) {
		SBP2_ERR("Error logging into SBP-2 device - timed out");
		return -EIO;
	}

	/* make sure that the returned status matches the login ORB */
	if (lu->status_block.ORB_offset_lo != lu->login_orb_dma) {
		SBP2_ERR("Error logging into SBP-2 device - timed out");
		return -EIO;
	}

	if (STATUS_TEST_RDS(lu->status_block.ORB_offset_hi_misc)) {
		SBP2_ERR("Error logging into SBP-2 device - failed");
		return -EIO;
	}

	sbp2util_cpu_to_be32_buffer(lu->login_response,
				    sizeof(struct sbp2_login_response));
	lu->command_block_agent_addr =
			((u64)lu->login_response->command_block_agent_hi) << 32;
	lu->command_block_agent_addr |=
			((u64)lu->login_response->command_block_agent_lo);
	lu->command_block_agent_addr &= 0x0000ffffffffffffULL;

	SBP2_INFO("Logged into SBP-2 device");
	return 0;
}

static int sbp2_logout_device(struct sbp2_lu *lu)
{
	struct sbp2_fwhost_info *hi = lu->hi;
	quadlet_t data[2];
	int error;

	lu->logout_orb->reserved1 = 0x0;
	lu->logout_orb->reserved2 = 0x0;
	lu->logout_orb->reserved3 = 0x0;
	lu->logout_orb->reserved4 = 0x0;

	lu->logout_orb->login_ID_misc = ORB_SET_FUNCTION(SBP2_LOGOUT_REQUEST);
	lu->logout_orb->login_ID_misc |=
			ORB_SET_LOGIN_ID(lu->login_response->length_login_ID);
	lu->logout_orb->login_ID_misc |= ORB_SET_NOTIFY(1);

	lu->logout_orb->reserved5 = 0x0;
	lu->logout_orb->status_fifo_hi =
		ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id);
	lu->logout_orb->status_fifo_lo =
		ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr);

	sbp2util_cpu_to_be32_buffer(lu->logout_orb,
				    sizeof(struct sbp2_logout_orb));

	data[0] = ORB_SET_NODE_ID(hi->host->node_id);
	data[1] = lu->logout_orb_dma;
	sbp2util_cpu_to_be32_buffer(data, 8);

	error = hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8);
	if (error)
		return error;

	/* wait up to 1 second for the device to complete logout */
	if (sbp2util_access_timeout(lu, HZ))
		return -EIO;

	SBP2_INFO("Logged out of SBP-2 device");
	return 0;
}

static int sbp2_reconnect_device(struct sbp2_lu *lu)
{
	struct sbp2_fwhost_info *hi = lu->hi;
	quadlet_t data[2];
	int error;

	lu->reconnect_orb->reserved1 = 0x0;
	lu->reconnect_orb->reserved2 = 0x0;
	lu->reconnect_orb->reserved3 = 0x0;
	lu->reconnect_orb->reserved4 = 0x0;

	lu->reconnect_orb->login_ID_misc =
			ORB_SET_FUNCTION(SBP2_RECONNECT_REQUEST);
	lu->reconnect_orb->login_ID_misc |=
			ORB_SET_LOGIN_ID(lu->login_response->length_login_ID);
	lu->reconnect_orb->login_ID_misc |= ORB_SET_NOTIFY(1);

	lu->reconnect_orb->reserved5 = 0x0;
	lu->reconnect_orb->status_fifo_hi =
		ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id);
	lu->reconnect_orb->status_fifo_lo =
		ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr);

	sbp2util_cpu_to_be32_buffer(lu->reconnect_orb,
				    sizeof(struct sbp2_reconnect_orb));

	data[0] = ORB_SET_NODE_ID(hi->host->node_id);
	data[1] = lu->reconnect_orb_dma;
	sbp2util_cpu_to_be32_buffer(data, 8);

	error = hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8);
	if (error)
		return error;

	/* wait up to 1 second for reconnect status */
	if (sbp2util_access_timeout(lu, HZ)) {
		SBP2_ERR("Error reconnecting to SBP-2 device - timed out");
		return -EIO;
	}

	/* make sure that the returned status matches the reconnect ORB */
	if (lu->status_block.ORB_offset_lo != lu->reconnect_orb_dma) {
		SBP2_ERR("Error reconnecting to SBP-2 device - timed out");

⌨️ 快捷键说明

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