📄 sbp2.c
字号:
} spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); return 0;}/* * This function is called to delete a pool of command orbs. */static void sbp2util_remove_command_orb_pool(struct scsi_id_instance_data *scsi_id){ struct hpsb_host *host = scsi_id->hi->host; struct list_head *lh, *next; struct sbp2_command_info *command; unsigned long flags; spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags); if (!list_empty(&scsi_id->sbp2_command_orb_completed)) { list_for_each_safe(lh, next, &scsi_id->sbp2_command_orb_completed) { command = list_entry(lh, struct sbp2_command_info, list); /* Release our generic DMA's */ pci_unmap_single(host->pdev, command->command_orb_dma, sizeof(struct sbp2_command_orb), PCI_DMA_BIDIRECTIONAL); SBP2_DMA_FREE("single command orb DMA"); pci_unmap_single(host->pdev, command->sge_dma, sizeof(command->scatter_gather_element), PCI_DMA_BIDIRECTIONAL); SBP2_DMA_FREE("scatter_gather_element"); kfree(command); } } spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); return;}/* * This function finds the sbp2_command for a given outstanding command * orb.Only looks at the inuse list. */static struct sbp2_command_info *sbp2util_find_command_for_orb( struct scsi_id_instance_data *scsi_id, dma_addr_t orb){ struct sbp2_command_info *command; unsigned long flags; spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags); if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) { list_for_each_entry(command, &scsi_id->sbp2_command_orb_inuse, list) { if (command->command_orb_dma == orb) { spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); return (command); } } } spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); SBP2_ORB_DEBUG("could not match command orb %x", (unsigned int)orb); return(NULL);}/* * This function finds the sbp2_command for a given outstanding SCpnt. * Only looks at the inuse list. */static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_instance_data *scsi_id, void *SCpnt){ struct sbp2_command_info *command; unsigned long flags; spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags); if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) { list_for_each_entry(command, &scsi_id->sbp2_command_orb_inuse, list) { if (command->Current_SCpnt == SCpnt) { spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); return (command); } } } spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); return(NULL);}/* * This function allocates a command orb used to send a scsi command. */static struct sbp2_command_info *sbp2util_allocate_command_orb( struct scsi_id_instance_data *scsi_id, Scsi_Cmnd *Current_SCpnt, void (*Current_done)(Scsi_Cmnd *)){ struct list_head *lh; struct sbp2_command_info *command = NULL; unsigned long flags; spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags); if (!list_empty(&scsi_id->sbp2_command_orb_completed)) { lh = scsi_id->sbp2_command_orb_completed.next; list_del(lh); command = list_entry(lh, struct sbp2_command_info, list); command->Current_done = Current_done; command->Current_SCpnt = Current_SCpnt; list_add_tail(&command->list, &scsi_id->sbp2_command_orb_inuse); } else { SBP2_ERR("sbp2util_allocate_command_orb - No orbs available!"); } spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); return (command);}/* Free our DMA's */static void sbp2util_free_command_dma(struct sbp2_command_info *command){ struct scsi_id_instance_data *scsi_id = (struct scsi_id_instance_data *)command->Current_SCpnt->device->host->hostdata[0]; struct hpsb_host *host; if (!scsi_id) { printk(KERN_ERR "%s: scsi_id == NULL\n", __FUNCTION__); return; } host = scsi_id->ud->ne->host; if (command->cmd_dma) { if (command->dma_type == CMD_DMA_SINGLE) { pci_unmap_single(host->pdev, command->cmd_dma, command->dma_size, command->dma_dir); SBP2_DMA_FREE("single bulk"); } else if (command->dma_type == CMD_DMA_PAGE) { pci_unmap_page(host->pdev, command->cmd_dma, command->dma_size, command->dma_dir); SBP2_DMA_FREE("single page"); } /* XXX: Check for CMD_DMA_NONE bug */ command->dma_type = CMD_DMA_NONE; command->cmd_dma = 0; } if (command->sge_buffer) { pci_unmap_sg(host->pdev, command->sge_buffer, command->dma_size, command->dma_dir); SBP2_DMA_FREE("scatter list"); command->sge_buffer = NULL; }}/* * This function moves a command to the completed orb list. */static void sbp2util_mark_command_completed(struct scsi_id_instance_data *scsi_id, struct sbp2_command_info *command){ unsigned long flags; spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags); list_del(&command->list); sbp2util_free_command_dma(command); list_add_tail(&command->list, &scsi_id->sbp2_command_orb_completed); spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);}/********************************************* * IEEE-1394 core driver stack related section *********************************************/static struct scsi_id_instance_data *sbp2_alloc_device(struct unit_directory *ud);static int sbp2_probe(struct device *dev){ struct unit_directory *ud; struct scsi_id_instance_data *scsi_id; SBP2_DEBUG("sbp2_probe"); ud = container_of(dev, struct unit_directory, device); /* Don't probe UD's that have the LUN flag. We'll probe the LUN(s) * instead. */ if (ud->flags & UNIT_DIRECTORY_HAS_LUN_DIRECTORY) return -ENODEV; scsi_id = sbp2_alloc_device(ud); if (!scsi_id) return -ENOMEM; sbp2_parse_unit_directory(scsi_id, ud); return sbp2_start_device(scsi_id);}static int sbp2_remove(struct device *dev){ struct unit_directory *ud; struct scsi_id_instance_data *scsi_id; SBP2_DEBUG("sbp2_remove"); ud = container_of(dev, struct unit_directory, device); scsi_id = ud->device.driver_data; sbp2_logout_device(scsi_id); sbp2_remove_device(scsi_id); return 0;}static int sbp2_update(struct unit_directory *ud){ struct scsi_id_instance_data *scsi_id = ud->device.driver_data; SBP2_DEBUG("sbp2_update"); if (sbp2_reconnect_device(scsi_id)) { /* * Ok, reconnect has failed. Perhaps we didn't * reconnect fast enough. Try doing a regular login, but * first do a logout just in case of any weirdness. */ sbp2_logout_device(scsi_id); if (sbp2_login_device(scsi_id)) { /* Login failed too, just fail, and the backend * will call our sbp2_remove for us */ SBP2_ERR("Failed to reconnect to sbp2 device!"); 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); /* Complete any pending commands with busy (so they get * retried) and remove them from our queue */ sbp2scsi_complete_all_commands(scsi_id, DID_BUS_BUSY); /* Make sure we unblock requests (since this is likely after a bus * reset). */ scsi_unblock_requests(scsi_id->scsi_host); return 0;}/* This functions is called by the sbp2_probe, for each new device. We now * allocate one scsi host for each scsi_id (unit directory). */static struct scsi_id_instance_data *sbp2_alloc_device(struct unit_directory *ud){ struct sbp2scsi_host_info *hi; struct Scsi_Host *scsi_host = NULL; struct scsi_id_instance_data *scsi_id = NULL; SBP2_DEBUG("sbp2_alloc_device"); scsi_id = kmalloc(sizeof(*scsi_id), GFP_KERNEL); if (!scsi_id) { SBP2_ERR("failed to create scsi_id"); goto failed_alloc; } memset(scsi_id, 0, sizeof(*scsi_id)); scsi_id->ne = ud->ne; scsi_id->ud = ud; scsi_id->speed_code = IEEE1394_SPEED_100; scsi_id->max_payload_size = sbp2_speedto_max_payload[IEEE1394_SPEED_100]; atomic_set(&scsi_id->sbp2_login_complete, 0); INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse); INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed); INIT_LIST_HEAD(&scsi_id->scsi_list); scsi_id->sbp2_command_orb_lock = SPIN_LOCK_UNLOCKED; scsi_id->sbp2_device_type_and_lun = SBP2_DEVICE_TYPE_LUN_UNINITIALIZED; ud->device.driver_data = scsi_id; hi = hpsb_get_hostinfo(&sbp2_highlevel, ud->ne->host); if (!hi) { hi = hpsb_create_hostinfo(&sbp2_highlevel, ud->ne->host, sizeof(*hi)); if (!hi) { SBP2_ERR("failed to allocate hostinfo"); goto failed_alloc; } SBP2_DEBUG("sbp2_alloc_device: allocated hostinfo"); hi->host = ud->ne->host; INIT_LIST_HEAD(&hi->scsi_ids); /* Register our sbp2 status address space... */ hpsb_register_addrspace(&sbp2_highlevel, ud->ne->host, &sbp2_ops, SBP2_STATUS_FIFO_ADDRESS, SBP2_STATUS_FIFO_ADDRESS + SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(SBP2_MAX_UDS_PER_NODE+1));#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA /* Handle data movement if physical dma is not * enabled/supportedon host controller */ hpsb_register_addrspace(&sbp2_highlevel, ud->ne->host, &sbp2_physdma_ops, 0x0ULL, 0xfffffffcULL);#endif } scsi_id->hi = hi; list_add_tail(&scsi_id->scsi_list, &hi->scsi_ids); /* Register our host with the SCSI stack. */ scsi_host = scsi_host_alloc(&scsi_driver_template, 0); 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) { list_for_each_entry(scsi_id, &hi->scsi_ids, scsi_list) 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; struct scsi_device *sdev; SBP2_DEBUG("sbp2_start_device"); /* 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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -