📄 sbp2.c
字号:
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 + -