📄 sbp2.c
字号:
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)) { SBP2_ERR("sbp2util_create_command_orb_pool failed!"); sbp2_remove_device(lu); return -ENOMEM; } /* 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"); return -EIO; } if (STATUS_TEST_RDS(lu->status_block.ORB_offset_hi_misc)) { SBP2_ERR("Error reconnecting to SBP-2 device - failed"); return -EIO; } SBP2_INFO("Reconnected to SBP-2 device"); return 0;}/* * Set the target node's Single Phase Retry limit. Affects the target's retry * behaviour if our node is too busy to accept requests. */static int sbp2_set_busy_timeout(struct sbp2_lu *lu){ quadlet_t data; data = cpu_to_be32(SBP2_BUSY_TIMEOUT_VALUE); if (hpsb_node_write(lu->ne, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) SBP2_ERR("%s error", __FUNCTION__); return 0;}static void sbp2_parse_unit_directory(struct sbp2_lu *lu, struct unit_directory *ud){ struct csr1212_keyval *kv; struct csr1212_dentry *dentry; u64 management_agent_addr; u32 unit_characteristics, firmware_revision; unsigned workarounds; int i; management_agent_addr = 0; unit_characteristics = 0; firmware_revision = 0; 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) management_agent_addr = CSR1212_REGISTER_SPACE_BASE + (kv->value.csr_offset << 2); else if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) lu->lun = ORB_SET_LUN(kv->value.immediate); break; case SBP2_UNIT_CHARACTERISTICS_KEY: /* FIXME: This is ignored so far. * See SBP-2 clause 7.4.8. */ unit_characteristics = kv->value.immediate; break; case SBP2_FIRMWARE_REVISION_KEY: firmware_revision = kv->value.immediate; break; default:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -