📄 sbp2.c
字号:
packet->data_size = data_size; INIT_LIST_HEAD(&packet->list); sema_init(&packet->state_change, 0); packet->state = hpsb_unused; packet->data_be = 1; hpsb_node_fill_packet(ne, packet); packet->tlabel = get_tlabel(hi->host, packet->node_id, 0); if (!data_size) { fill_async_writequad(packet, addr, data); } else { fill_async_writeblock(packet, addr, data_size); } /* * Set up a task queue completion routine, which returns * the packet to the free list and releases the tlabel. */ request_packet->tq.routine = (void (*)(void*))sbp2util_free_request_packet; request_packet->tq.data = request_packet; request_packet->hi_context = hi; hpsb_add_packet_complete_task(packet, &request_packet->tq); /* * Now, put the packet on the in-use list. */ list_add_tail(&request_packet->list, &hi->sbp2_req_inuse); } else { SBP2_ERR("sbp2util_allocate_request_packet - no packets available!"); } sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags); return(request_packet);}/* * This function is called to return a packet to our packet pool. It is * also called as a completion routine when a request packet is completed. */static void sbp2util_free_request_packet(struct sbp2_request_packet *request_packet){ unsigned long flags; struct sbp2scsi_host_info *hi = request_packet->hi_context; /* * Free the tlabel, and return the packet to the free pool. */ sbp2_spin_lock(&hi->sbp2_request_packet_lock, flags); free_tlabel(hi->host, LOCAL_BUS | request_packet->packet->node_id, request_packet->packet->tlabel); list_del(&request_packet->list); list_add_tail(&request_packet->list, &hi->sbp2_req_free); sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags); return;}/* * This function is called to create a pool of command orbs used for * command processing. It is called when a new sbp2 device is detected. */static int sbp2util_create_command_orb_pool(struct scsi_id_instance_data *scsi_id, struct sbp2scsi_host_info *hi){ int i; unsigned long flags; struct sbp2_command_info *command; sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags); for (i = 0; i < scsi_id->sbp2_total_command_orbs; i++) { command = (struct sbp2_command_info *) kmalloc(sizeof(struct sbp2_command_info), GFP_KERNEL); if (!command) { sbp2_spin_unlock(&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); } sbp2_spin_unlock(&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 sbp2scsi_host_info *hi){ struct list_head *lh, *next; struct sbp2_command_info *command; unsigned long flags; sbp2_spin_lock(&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(hi->host->pdev, command->command_orb_dma, sizeof(struct sbp2_command_orb), PCI_DMA_BIDIRECTIONAL); SBP2_DMA_FREE("single command orb DMA"); pci_unmap_single(hi->host->pdev, command->sge_dma, sizeof(command->scatter_gather_element), PCI_DMA_BIDIRECTIONAL); SBP2_DMA_FREE("scatter_gather_element"); kfree(command); } } sbp2_spin_unlock(&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; sbp2_spin_lock(&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) { sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags); return (command); } } } sbp2_spin_unlock(&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; sbp2_spin_lock(&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) { sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags); return (command); } } } sbp2_spin_unlock(&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 sbp2scsi_host_info *hi){ struct list_head *lh; struct sbp2_command_info *command = NULL; unsigned long flags; sbp2_spin_lock(&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!"); } sbp2_spin_unlock(&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 sbp2scsi_host_info *hi; hi = (struct sbp2scsi_host_info *) command->Current_SCpnt->host->hostdata[0]; if (hi == NULL) { printk(KERN_ERR "%s: hi == NULL\n", __FUNCTION__); return; } if (command->cmd_dma) { if (command->dma_type == CMD_DMA_SINGLE) { pci_unmap_single(hi->host->pdev, command->cmd_dma, command->dma_size, command->dma_dir); SBP2_DMA_FREE("single bulk"); } else if (command->dma_type == CMD_DMA_PAGE) {#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13) pci_unmap_single(hi->host->pdev, command->cmd_dma, command->dma_size, command->dma_dir);#else pci_unmap_page(hi->host->pdev, command->cmd_dma, command->dma_size, command->dma_dir);#endif /* Linux version < 2.4.13 */ 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(hi->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; sbp2_spin_lock(&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); sbp2_spin_unlock(&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. */int sbp2_init(void){ SBP2_DEBUG("sbp2_init"); /* * Register our high level driver with 1394 stack */ sbp2_hl_handle = hpsb_register_highlevel(SBP2_DEVICE_NAME, &sbp2_hl_ops); if (sbp2_hl_handle == NULL) { SBP2_ERR("sbp2 failed to register with ieee1394 highlevel"); return(-ENOMEM); } /* * Register our sbp2 status address space... */ hpsb_register_addrspace(sbp2_hl_handle, &sbp2_ops, SBP2_STATUS_FIFO_ADDRESS, SBP2_STATUS_FIFO_ADDRESS + SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(SBP2SCSI_MAX_SCSI_IDS+1)); /* * Handle data movement if physical dma is not enabled/supported on host controller */#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA hpsb_register_addrspace(sbp2_hl_handle, &sbp2_physdma_ops, 0x0ULL, 0xfffffffcULL);#endif hpsb_register_protocol(&sbp2_driver); return 0;}/* * This function is called from cleanup module, or during shut-down, in * order to unregister our driver. */void sbp2_cleanup(void){ SBP2_DEBUG("sbp2_cleanup"); hpsb_unregister_protocol(&sbp2_driver); if (sbp2_hl_handle) { hpsb_unregister_highlevel(sbp2_hl_handle); sbp2_hl_handle = NULL; }}static int sbp2_probe(struct unit_directory *ud){ struct sbp2scsi_host_info *hi; SBP2_DEBUG("sbp2_probe"); hi = sbp2_find_host_info(ud->ne->host); return sbp2_start_device(hi, ud);}static void sbp2_disconnect(struct unit_directory *ud){ struct sbp2scsi_host_info *hi; struct scsi_id_instance_data *scsi_id = ud->driver_data; SBP2_DEBUG("sbp2_disconnect"); hi = sbp2_find_host_info(ud->ne->host); if (hi != NULL) { sbp2_logout_device(hi, scsi_id); sbp2_remove_device(hi, scsi_id); }}static void sbp2_update(struct unit_directory *ud){ struct sbp2scsi_host_info *hi; struct scsi_id_instance_data *scsi_id = ud->driver_data; unsigned long flags; SBP2_DEBUG("sbp2_update"); hi = sbp2_find_host_info(ud->ne->host); if (sbp2_reconnect_device(hi, scsi_id)) { /* * Ok, reconnect has failed. Perhaps we didn't * reconnect fast enough. Try doing a regular login. */ if (sbp2_login_device(hi, scsi_id)) { /* Login failed too, just remove the device. */ SBP2_ERR("sbp2_reconnect_device failed!"); sbp2_remove_device(hi, scsi_id); hpsb_release_unit_directory(ud); return; } } /* Set max retries to something large on the device. */ sbp2_set_busy_timeout(hi, scsi_id); /* Do a SBP-2 fetch agent reset. */ sbp2_agent_reset(hi, scsi_id, 0); /* Get the max speed and packet size that we can use. */ sbp2_max_speed_and_size(hi, scsi_id); /* Complete any pending commands with busy (so they get * retried) and remove them from our queue */ sbp2_spin_lock(&hi->sbp2_command_lock, flags); sbp2scsi_complete_all_commands(hi, scsi_id, DID_BUS_BUSY); sbp2_spin_unlock(&hi->sbp2_command_lock, flags);}/* * This function is called after registering our operations in sbp2_init. * We go ahead and allocate some memory for our host info structure, and * init some structures.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -