📄 sbp2.c
字号:
for (i = 0; i < orbs; i++) { command = (struct sbp2_command_info *) kmalloc(sizeof(struct sbp2_command_info), GFP_ATOMIC); if (!command) { spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); return(-ENOMEM); } memset(command, '\0', sizeof(struct sbp2_command_info)); command->command_orb_dma = pci_map_single (hi->host->pdev, &command->command_orb, sizeof(struct sbp2_command_orb), PCI_DMA_BIDIRECTIONAL); SBP2_DMA_ALLOC("single command orb DMA"); command->sge_dma = pci_map_single (hi->host->pdev, &command->scatter_gather_element, sizeof(command->scatter_gather_element), PCI_DMA_BIDIRECTIONAL); SBP2_DMA_ALLOC("scatter_gather_element"); INIT_LIST_HEAD(&command->list); list_add_tail(&command->list, &scsi_id->sbp2_command_orb_completed); } 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 list_head *lh; 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(lh, &scsi_id->sbp2_command_orb_inuse) { command = list_entry(lh, struct sbp2_command_info, 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 list_head *lh; 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(lh, &scsi_id->sbp2_command_orb_inuse) { command = list_entry(lh, struct sbp2_command_info, 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 hpsb_host *host; host = hpsb_get_host_bykey(&sbp2_highlevel, (unsigned long)command->Current_SCpnt->device->host->hostt); if (!host) { printk(KERN_ERR "%s: host == NULL\n", __FUNCTION__); return; } 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 *********************************************//* * This function is called at SCSI init in order to register our driver * with the IEEE-1394 stack. */static int sbp2scsi_detect(Scsi_Host_Template *tpnt){ struct Scsi_Host *scsi_host; struct hpsb_host *host = hpsb_get_host_bykey(&sbp2_highlevel, (unsigned long)tpnt); SBP2_DEBUG("sbp2scsi_detect"); /* Register our host with the SCSI stack. */ if (!(scsi_host = scsi_register(tpnt, 0))) return 0; scsi_set_pci_device(scsi_host, host->pdev); tpnt->present = 1; return tpnt->present;}static int sbp2_probe(struct unit_directory *ud){ struct sbp2scsi_host_info *hi; SBP2_DEBUG(__FUNCTION__); /* 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 -1; /* This will only add it if it doesn't exist */ hi = sbp2_add_host(ud->ne->host); if (!hi) return -1; return sbp2_start_ud(hi, ud);}static void sbp2_disconnect(struct unit_directory *ud){ struct scsi_id_group *scsi_group = ud->driver_data; struct list_head *lh, *next; struct scsi_id_instance_data *scsi_id; SBP2_DEBUG("sbp2_disconnect"); list_for_each_safe (lh, next, &scsi_group->scsi_id_list) { scsi_id = list_entry(lh, struct scsi_id_instance_data, list); if (scsi_id) { sbp2_logout_device(scsi_id); sbp2_remove_device(scsi_id); } } kfree(scsi_group);}static void sbp2_update(struct unit_directory *ud){ struct sbp2scsi_host_info *hi; struct scsi_id_group *scsi_group = ud->driver_data; struct list_head *lh, *next; struct scsi_id_instance_data *scsi_id; unsigned long flags; SBP2_DEBUG("sbp2_update"); hi = hpsb_get_hostinfo(&sbp2_highlevel, ud->ne->host); list_for_each_safe (lh, next, &scsi_group->scsi_id_list) { scsi_id = list_entry(lh, struct scsi_id_instance_data, list); if (sbp2_reconnect_device(scsi_id)) { /* * Ok, reconnect has failed. Perhaps we didn't * reconnect fast enough. Try doing a regular login. */ if (sbp2_login_device(scsi_id)) { /* Login failed too, just remove the device. */ SBP2_ERR("sbp2_reconnect_device failed!"); sbp2_remove_device(scsi_id); continue; } } /* 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, 0); /* 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 */ spin_lock_irqsave(&hi->sbp2_command_lock, flags); sbp2scsi_complete_all_commands(scsi_id, DID_BUS_BUSY); spin_unlock_irqrestore(&hi->sbp2_command_lock, flags); } if (list_empty(&scsi_group->scsi_id_list)) { hpsb_release_unit_directory(ud); kfree(scsi_group); }}/* * We go ahead and allocate some memory for our host info structure, and * init some structures. */static struct sbp2scsi_host_info *sbp2_add_host(struct hpsb_host *host){ struct sbp2scsi_host_info *hi; SBP2_DEBUG("sbp2_add_host"); /* Check for existing hostinfo */ hi = hpsb_get_hostinfo(&sbp2_highlevel, host); if (hi) return hi; /* Allocate some memory for our host info structure */ hi = hpsb_create_hostinfo(&sbp2_highlevel, host, sizeof(*hi)); if (hi == NULL) { SBP2_ERR("out of memory in sbp2_add_host"); return NULL; } /* Initialize some host stuff */ hi->host = host; hi->sbp2_command_lock = SPIN_LOCK_UNLOCKED; memcpy(&hi->sht, &scsi_driver_template, sizeof hi->sht); sprintf(hi->proc_name, "%s_%d", SBP2_DEVICE_NAME, host->id); hi->sht.proc_name = hi->proc_name; hpsb_set_hostinfo_key(&sbp2_highlevel, host, (unsigned long)&hi->sht); if (SCSI_REGISTER_HOST(&hi->sht)) { SBP2_ERR("Failed to register scsi template for ieee1394 host"); hpsb_destroy_hostinfo(&sbp2_highlevel, host); return NULL; } for (hi->scsi_host = scsi_hostlist; hi->scsi_host; hi->scsi_host = hi->scsi_host->next) if (hi->scsi_host->hostt == &hi->sht) break; if (!hi->scsi_host) { SBP2_ERR("Failed to register scsi host for ieee1394 host"); SCSI_UNREGISTER_HOST(&hi->sht); hpsb_destroy_hostinfo(&sbp2_highlevel, host); return NULL; } hi->scsi_host->max_id = SBP2SCSI_MAX_SCSI_IDS; return hi;}/* * This function is called when a host is removed. */static void sbp2_remove_host(struct hpsb_host *host){ struct sbp2scsi_host_info *hi; SBP2_DEBUG("sbp2_remove_host"); hi = hpsb_get_hostinfo(&sbp2_highlevel, host); if (hi) SCSI_UNREGISTER_HOST(&hi->sht);}static int sbp2_start_ud(struct sbp2scsi_host_info *hi, struct unit_directory *ud){ struct scsi_id_instance_data *scsi_id; struct scsi_id_group *scsi_group; struct list_head *lh, *next; SBP2_DEBUG("sbp2_start_ud"); scsi_group = kmalloc(sizeof(*scsi_group), GFP_KERNEL); if (!scsi_group) { SBP2_ERR ("Could not allocate memory for scsi_group"); return -ENOMEM; } INIT_LIST_HEAD(&scsi_group->scsi_id_list); ud->driver_data = scsi_group; sbp2_parse_unit_directory(scsi_group, ud); list_for_each_safe (lh, next, &scsi_group->scsi_id_list) { scsi_id = list_entry(lh, struct scsi_id_instance_data, list); scsi_id->ne = ud->ne; scsi_id->hi = hi; 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); scsi_id->sbp2_command_orb_lock = SPIN_LOCK_UNLOCKED; sbp2_start_device(scsi_id); } /* Check to see if any of our devices survived the ordeal */ if (list_empty(&scsi_group->scsi_id_list)) { kfree(scsi_group); return -ENODEV; } return 0;}/* * 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 i; SBP2_DEBUG("sbp2_start_device");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -