📄 sbp2.c
字号:
/* Login FIFO DMA */ scsi_id->login_response = pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_login_response), &scsi_id->login_response_dma); if (!scsi_id->login_response) goto alloc_fail; SBP2_DMA_ALLOC("consistent DMA region for login FIFO"); /* Query logins ORB DMA */ scsi_id->query_logins_orb = pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_query_logins_orb), &scsi_id->query_logins_orb_dma); if (!scsi_id->query_logins_orb) goto alloc_fail; SBP2_DMA_ALLOC("consistent DMA region for query logins ORB"); /* Query logins response DMA */ scsi_id->query_logins_response = pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_query_logins_response), &scsi_id->query_logins_response_dma); if (!scsi_id->query_logins_response) goto alloc_fail; SBP2_DMA_ALLOC("consistent DMA region for query logins response"); /* Reconnect ORB DMA */ scsi_id->reconnect_orb = pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_reconnect_orb), &scsi_id->reconnect_orb_dma); if (!scsi_id->reconnect_orb) goto alloc_fail; SBP2_DMA_ALLOC("consistent DMA region for reconnect ORB"); /* Logout ORB DMA */ scsi_id->logout_orb = pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_logout_orb), &scsi_id->logout_orb_dma); if (!scsi_id->logout_orb) goto alloc_fail; SBP2_DMA_ALLOC("consistent DMA region for logout ORB"); /* Login ORB DMA */ scsi_id->login_orb = pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_login_orb), &scsi_id->login_orb_dma); if (!scsi_id->login_orb) {alloc_fail: if (scsi_id->query_logins_response) { pci_free_consistent(hi->host->pdev, sizeof(struct sbp2_query_logins_response), scsi_id->query_logins_response, scsi_id->query_logins_response_dma); SBP2_DMA_FREE("query logins response DMA"); } if (scsi_id->query_logins_orb) { pci_free_consistent(hi->host->pdev, sizeof(struct sbp2_query_logins_orb), scsi_id->query_logins_orb, scsi_id->query_logins_orb_dma); SBP2_DMA_FREE("query logins ORB DMA"); } if (scsi_id->logout_orb) { pci_free_consistent(hi->host->pdev, sizeof(struct sbp2_logout_orb), scsi_id->logout_orb, scsi_id->logout_orb_dma); SBP2_DMA_FREE("logout ORB DMA"); } if (scsi_id->reconnect_orb) { pci_free_consistent(hi->host->pdev, sizeof(struct sbp2_reconnect_orb), scsi_id->reconnect_orb, scsi_id->reconnect_orb_dma); SBP2_DMA_FREE("reconnect ORB DMA"); } if (scsi_id->login_response) { pci_free_consistent(hi->host->pdev, sizeof(struct sbp2_login_response), scsi_id->login_response, scsi_id->login_response_dma); SBP2_DMA_FREE("login FIFO DMA"); } kfree(scsi_id); list_del(&scsi_id->list); SBP2_ERR ("Could not allocate memory for scsi_id"); return -ENOMEM; } SBP2_DMA_ALLOC("consistent DMA region for login ORB"); /* * Find an empty spot to stick our scsi id instance data. */ for (i = 0; i < hi->scsi_host->max_id; i++) { if (!hi->scsi_id[i]) { hi->scsi_id[i] = scsi_id; scsi_id->id = i; SBP2_DEBUG("New SBP-2 device inserted, SCSI ID = %x", (unsigned int) i); break; } } /* * Create our command orb pool */ if (sbp2util_create_command_orb_pool(scsi_id)) { SBP2_ERR("sbp2util_create_command_orb_pool failed!"); sbp2_remove_device(scsi_id); return -ENOMEM; } /* * Make sure we are not out of space */ if (i == hi->scsi_host->max_id) { SBP2_ERR("No slots left for SBP-2 device"); sbp2_remove_device(scsi_id); return -EBUSY; } /* Schedule a timeout here. The reason is that we may be so close * to a bus reset, that the device is not available for logins. * This can happen when the bus reset is caused by the host * connected to the sbp2 device being removed. That host would * have a certain amount of time to relogin before the sbp2 device * allows someone else to login instead. One second makes sense. */ set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); /* * Login to the sbp-2 device */ if (sbp2_login_device(scsi_id)) { /* Login failed, just remove the device. */ sbp2_remove_device(scsi_id); return -EBUSY; } /* * Set max retries to something large on the device */ sbp2_set_busy_timeout(scsi_id); /* * Do a SBP-2 fetch agent reset */ sbp2_agent_reset(scsi_id, 1); /* * Get the max speed and packet size that we can use */ sbp2_max_speed_and_size(scsi_id);#ifdef SBP2_USE_SCSI_ADDREM_HACK /* Try to hook ourselves into the SCSI subsystem */ if (scsi_add_single_device(hi->scsi_host, 0, scsi_id->id, 0)) SBP2_INFO("Unable to connect SBP-2 device into the SCSI subsystem");#endif return 0;}/* * This function removes an sbp2 device from the sbp2scsi_host_info struct. */static void sbp2_remove_device(struct scsi_id_instance_data *scsi_id){ struct sbp2scsi_host_info *hi = scsi_id->hi; SBP2_DEBUG("sbp2_remove_device"); /* Complete any pending commands with selection timeout */ sbp2scsi_complete_all_commands(scsi_id, DID_NO_CONNECT); /* Clean up any other structures */ sbp2util_remove_command_orb_pool(scsi_id); hi->scsi_id[scsi_id->id] = NULL; if (scsi_id->login_response) { pci_free_consistent(hi->host->pdev, sizeof(struct sbp2_login_response), scsi_id->login_response, scsi_id->login_response_dma); SBP2_DMA_FREE("single login FIFO"); } if (scsi_id->login_orb) { pci_free_consistent(hi->host->pdev, sizeof(struct sbp2_login_orb), scsi_id->login_orb, scsi_id->login_orb_dma); SBP2_DMA_FREE("single login ORB"); } if (scsi_id->reconnect_orb) { pci_free_consistent(hi->host->pdev, sizeof(struct sbp2_reconnect_orb), scsi_id->reconnect_orb, scsi_id->reconnect_orb_dma); SBP2_DMA_FREE("single reconnect orb"); } if (scsi_id->logout_orb) { pci_free_consistent(hi->host->pdev, sizeof(struct sbp2_logout_orb), scsi_id->logout_orb, scsi_id->logout_orb_dma); SBP2_DMA_FREE("single logout orb"); } if (scsi_id->query_logins_orb) { pci_free_consistent(hi->host->pdev, sizeof(struct sbp2_query_logins_orb), scsi_id->query_logins_orb, scsi_id->query_logins_orb_dma); SBP2_DMA_FREE("single query logins orb"); } if (scsi_id->query_logins_response) { pci_free_consistent(hi->host->pdev, sizeof(struct sbp2_query_logins_response), scsi_id->query_logins_response, scsi_id->query_logins_response_dma); SBP2_DMA_FREE("single query logins data"); } SBP2_DEBUG("SBP-2 device removed, SCSI ID = %d", scsi_id->id); list_del(&scsi_id->list); kfree(scsi_id);}#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA/* * This function deals with physical dma write requests (for adapters that do not support * physical dma in hardware). Mostly just here for debugging... */static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, int destid, quadlet_t *data, u64 addr, size_t length, u16 flags){ /* * Manually put the data in the right place. */ memcpy(bus_to_virt((u32)addr), data, length); sbp2util_packet_dump(data, length, "sbp2 phys dma write by device", (u32)addr); return(RCODE_COMPLETE);}/* * This function deals with physical dma read requests (for adapters that do not support * physical dma in hardware). Mostly just here for debugging... */static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data, u64 addr, size_t length, u16 flags){ /* * Grab data from memory and send a read response. */ memcpy(data, bus_to_virt((u32)addr), length); sbp2util_packet_dump(data, length, "sbp2 phys dma read by device", (u32)addr); return(RCODE_COMPLETE);}#endif/************************************** * SBP-2 protocol related section **************************************//* * This function determines if we should convert scsi commands for a particular sbp2 device type */static __inline__ int sbp2_command_conversion_device_type(u8 device_type){ return (((device_type == TYPE_DISK) || (device_type == TYPE_SDAD) || (device_type == TYPE_ROM)) ? 1:0);}/* * This function queries the device for the maximum concurrent logins it * supports. */static int sbp2_query_logins(struct scsi_id_instance_data *scsi_id){ struct sbp2scsi_host_info *hi = scsi_id->hi; quadlet_t data[2]; int max_logins; int active_logins; SBP2_DEBUG("sbp2_query_logins"); scsi_id->query_logins_orb->reserved1 = 0x0; scsi_id->query_logins_orb->reserved2 = 0x0; scsi_id->query_logins_orb->query_response_lo = scsi_id->query_logins_response_dma; scsi_id->query_logins_orb->query_response_hi = ORB_SET_NODE_ID(hi->host->node_id); SBP2_DEBUG("sbp2_query_logins: query_response_hi/lo initialized"); scsi_id->query_logins_orb->lun_misc = ORB_SET_FUNCTION(QUERY_LOGINS_REQUEST); scsi_id->query_logins_orb->lun_misc |= ORB_SET_NOTIFY(1); if (scsi_id->sbp2_device_type_and_lun != SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) { scsi_id->query_logins_orb->lun_misc |= ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun); SBP2_DEBUG("sbp2_query_logins: set lun to %d", ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun)); } SBP2_DEBUG("sbp2_query_logins: lun_misc initialized"); scsi_id->query_logins_orb->reserved_resp_length = ORB_SET_QUERY_LOGINS_RESP_LENGTH(sizeof(struct sbp2_query_logins_response)); SBP2_DEBUG("sbp2_query_logins: reserved_resp_length initialized"); scsi_id->query_logins_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO + SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->id); scsi_id->query_logins_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI); SBP2_DEBUG("sbp2_query_logins: status FIFO initialized"); sbp2util_cpu_to_be32_buffer(scsi_id->query_logins_orb, sizeof(struct sbp2_query_logins_orb)); SBP2_DEBUG("sbp2_query_logins: orb byte-swapped"); sbp2util_packet_dump(scsi_id->query_logins_orb, sizeof(struct sbp2_query_logins_orb), "sbp2 query logins orb", scsi_id->query_logins_orb_dma); memset(scsi_id->query_logins_response, 0, sizeof(struct sbp2_query_logins_response)); memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block)); SBP2_DEBUG("sbp2_query_logins: query_logins_response/status FIFO memset"); data[0] = ORB_SET_NODE_ID(hi->host->node_id); data[1] = scsi_id->query_logins_orb_dma; sbp2util_cpu_to_be32_buffer(data, 8); atomic_set(&scsi_id->sbp2_login_complete, 0); SBP2_DEBUG("sbp2_query_logins: prepared to write"); hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8); SBP2_DEBUG("sbp2_query_logins: written"); if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, 2*HZ)) { SBP2_ERR("Error querying logins to SBP-2 device - timed out"); return(-EIO); } if (scsi_id->status_block.ORB_offset_lo != scsi_id->query_logins_orb_dma) { SBP2_ERR("Error querying logins to SBP-2 device - timed out"); return(-EIO); } 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 querying logins to SBP-2 device - timed out"); return(-EIO); } sbp2util_cpu_to_be32_buffer(scsi_id->query_logins_response, sizeof(struct sbp2_query_logins_response)); SBP2_DEBUG("length_max_logins = %x", (unsigned int)scsi_id->query_logins_response->length_max_logins); SBP2_INFO("Query logins to SBP-2 device successful"); max_logins = RESPONSE_GET_MAX_LOGINS(scsi_id->query_logins_response->length_max_logins); SBP2_INFO("Maximum concurrent logins supported: %d", max_logins); active_logins = RESPONSE_GET_ACTIVE_LOGINS(scsi_id->query_logins_response->length_max_logins); SBP2_INFO("Number of active logins: %d", active_logins); if (active_logins >= max_logins) { return(-EIO); } return 0;}/* * This function is called in order to login to a particular SBP-2 device, * after a bus reset. */static int sbp2_login_device(struct scsi_id_instance_data *scsi_id) { struct sbp2scsi_host_info *hi = scsi_id->hi; quadlet_t data[2]; SBP2_DEBUG("sbp2_login_device"); if (!scsi_id->login_orb) { SBP2_DEBUG("sbp2_login_device: login_orb not alloc'd!"); return(-EIO); } if (!sbp2_exclusive_login) { if (sbp2_query_logins(scsi_id)) { SBP2_ERR("Device does not support any more concurrent logins"); return(-EIO); } } /* Set-up login ORB, assume no password */ scsi_id->login_orb->password_hi = 0; scsi_id->login_orb->password_lo = 0; SBP2_DEBUG("sbp2_login_device: password_hi/lo initialized"); scsi_id->login_orb->login_response_lo = scsi_id->login_response_dma; scsi_id->login_orb->login_response_hi = ORB_SET_NODE_ID(hi->host->node_id); SBP2_DEBUG("sbp2_login_device: login_response_hi/lo initialized"); scsi_id->login_orb->lun_misc = ORB_SET_FUNCTION(LOGIN_REQUEST); scsi_id->login_orb->lun_misc |= ORB_SET_RECONNECT(0); /* One second reconnect time */ scsi_id->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(sbp2_exclusive_login); /* Exclusive access to device */ scsi_id->login_orb->lun_misc |= ORB_SET_NOTIFY(1); /* Notify us of login complete */ /* Set the lun if we were able to pull it from the device's unit directory */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -