📄 sbp2.c
字号:
goto failed_alloc; } SBP2_DEBUG("sbp2_alloc_device: allocated hostinfo"); hi->host = ud->ne->host; INIT_LIST_HEAD(&hi->scsi_ids);#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA /* Handle data movement if physical dma is not * enabled or not supported on host controller */ if (!hpsb_register_addrspace(&sbp2_highlevel, ud->ne->host, &sbp2_physdma_ops, 0x0ULL, 0xfffffffcULL)) { SBP2_ERR("failed to register lower 4GB address range"); goto failed_alloc; }#endif } /* Prevent unloading of the 1394 host */ if (!try_module_get(hi->host->driver->owner)) { SBP2_ERR("failed to get a reference on 1394 host driver"); goto failed_alloc; } scsi_id->hi = hi; list_add_tail(&scsi_id->scsi_list, &hi->scsi_ids); /* Register the status FIFO address range. We could use the same FIFO * for targets at different nodes. However we need different FIFOs per * target in order to support multi-unit devices. * The FIFO is located out of the local host controller's physical range * but, if possible, within the posted write area. Status writes will * then be performed as unified transactions. This slightly reduces * bandwidth usage, and some Prolific based devices seem to require it. */ scsi_id->status_fifo_addr = hpsb_allocate_and_register_addrspace( &sbp2_highlevel, ud->ne->host, &sbp2_ops, sizeof(struct sbp2_status_block), sizeof(quadlet_t), ud->ne->host->low_addr_space, CSR1212_ALL_SPACE_END); if (scsi_id->status_fifo_addr == CSR1212_INVALID_ADDR_SPACE) { SBP2_ERR("failed to allocate status FIFO address range"); goto failed_alloc; } /* Register our host with the SCSI stack. */ scsi_host = scsi_host_alloc(&scsi_driver_template, sizeof(unsigned long)); if (!scsi_host) { SBP2_ERR("failed to register scsi host"); goto failed_alloc; } scsi_host->hostdata[0] = (unsigned long)scsi_id; if (!scsi_add_host(scsi_host, &ud->device)) { scsi_id->scsi_host = scsi_host; return scsi_id; } SBP2_ERR("failed to add scsi host"); scsi_host_put(scsi_host);failed_alloc: sbp2_remove_device(scsi_id); return NULL;}static void sbp2_host_reset(struct hpsb_host *host){ struct sbp2scsi_host_info *hi; struct scsi_id_instance_data *scsi_id; hi = hpsb_get_hostinfo(&sbp2_highlevel, host); if (!hi) return; list_for_each_entry(scsi_id, &hi->scsi_ids, scsi_list) if (likely(atomic_read(&scsi_id->state) != SBP2LU_STATE_IN_SHUTDOWN)) { atomic_set(&scsi_id->state, SBP2LU_STATE_IN_RESET); scsi_block_requests(scsi_id->scsi_host); }}/* * This function is where we first pull the node unique ids, and then * allocate memory and register a SBP-2 device. */static int sbp2_start_device(struct scsi_id_instance_data *scsi_id){ struct sbp2scsi_host_info *hi = scsi_id->hi; int error; SBP2_DEBUG_ENTER(); /* 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) goto alloc_fail; SBP2_DMA_ALLOC("consistent DMA region for login ORB"); SBP2_DEBUG("New SBP-2 device inserted, SCSI ID = %x", scsi_id->ud->id); /* * 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; } /* 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. */ if (msleep_interruptible(1000)) { sbp2_remove_device(scsi_id); return -EINTR; } /* * 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); /* Add this device to the scsi layer now */ error = scsi_add_device(scsi_id->scsi_host, 0, scsi_id->ud->id, 0); if (error) { SBP2_ERR("scsi_add_device failed"); sbp2_logout_device(scsi_id); sbp2_remove_device(scsi_id); return error; } return 0;alloc_fail: SBP2_ERR("Could not allocate memory for scsi_id"); sbp2_remove_device(scsi_id); return -ENOMEM;}/* * 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; SBP2_DEBUG_ENTER(); if (!scsi_id) return; hi = scsi_id->hi; /* This will remove our scsi device aswell */ if (scsi_id->scsi_host) { scsi_remove_host(scsi_id->scsi_host); scsi_host_put(scsi_id->scsi_host); } flush_scheduled_work(); sbp2util_remove_command_orb_pool(scsi_id); list_del(&scsi_id->scsi_list); 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"); } if (scsi_id->status_fifo_addr != CSR1212_INVALID_ADDR_SPACE) hpsb_unregister_addrspace(&sbp2_highlevel, hi->host, scsi_id->status_fifo_addr); scsi_id->ud->device.driver_data = NULL; if (hi) module_put(hi->host->driver->owner); SBP2_DEBUG("SBP-2 device removed, SCSI ID = %d", scsi_id->ud->id); 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 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_ENTER(); 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); scsi_id->query_logins_orb->lun_misc = ORB_SET_FUNCTION(SBP2_QUERY_LOGINS_REQUEST); scsi_id->query_logins_orb->lun_misc |= ORB_SET_NOTIFY(1); scsi_id->query_logins_orb->lun_misc |= ORB_SET_LUN(scsi_id->sbp2_lun); scsi_id->query_logins_orb->reserved_resp_length = ORB_SET_QUERY_LOGINS_RESP_LENGTH(sizeof(struct sbp2_query_logins_response)); scsi_id->query_logins_orb->status_fifo_hi = ORB_SET_STATUS_FIFO_HI(scsi_id->status_fifo_addr, hi->host->node_id); scsi_id->query_logins_orb->status_fifo_lo = ORB_SET_STATUS_FIFO_LO(scsi_id->status_fifo_addr); sbp2util_cpu_to_be32_buffer(scsi_id->query_logins_orb, sizeof(struct sbp2_query_logins_orb)); 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)); 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); hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8); if (sbp2util_access_timeout(scsi_id, 2*HZ)) { SBP2_INFO("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_INFO("Error querying logins to SBP-2 device - timed out"); return -EIO; } if (STATUS_TEST_RDS(scsi_id->status_block.ORB_offset_hi_misc)) { SBP2_INFO("Error querying logins to SBP-2 device - failed"); 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); 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_ENTER();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -