📄 sbp2.c
字号:
}static void sbp2util_notify_fetch_agent(struct sbp2_lu *lu, u64 offset, quadlet_t *data, size_t len){ /* There is a small window after a bus reset within which the node * entry's generation is current but the reconnect wasn't completed. */ if (unlikely(atomic_read(&lu->state) == SBP2LU_STATE_IN_RESET)) return; if (hpsb_node_write(lu->ne, lu->command_block_agent_addr + offset, data, len)) SBP2_ERR("sbp2util_notify_fetch_agent failed."); /* Now accept new SCSI commands, unless a bus reset happended during * hpsb_node_write. */ if (likely(atomic_read(&lu->state) != SBP2LU_STATE_IN_RESET)) scsi_unblock_requests(lu->shost);}static void sbp2util_write_orb_pointer(struct work_struct *work){ struct sbp2_lu *lu = container_of(work, struct sbp2_lu, protocol_work); quadlet_t data[2]; data[0] = ORB_SET_NODE_ID(lu->hi->host->node_id); data[1] = lu->last_orb_dma; sbp2util_cpu_to_be32_buffer(data, 8); sbp2util_notify_fetch_agent(lu, SBP2_ORB_POINTER_OFFSET, data, 8);}static void sbp2util_write_doorbell(struct work_struct *work){ struct sbp2_lu *lu = container_of(work, struct sbp2_lu, protocol_work); sbp2util_notify_fetch_agent(lu, SBP2_DOORBELL_OFFSET, NULL, 4);}static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu){ struct sbp2_fwhost_info *hi = lu->hi; int i; unsigned long flags, orbs; struct sbp2_command_info *cmd; orbs = sbp2_serialize_io ? 2 : SBP2_MAX_CMDS; spin_lock_irqsave(&lu->cmd_orb_lock, flags); for (i = 0; i < orbs; i++) { cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); if (!cmd) { spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); return -ENOMEM; } cmd->command_orb_dma = dma_map_single(hi->host->device.parent, &cmd->command_orb, sizeof(struct sbp2_command_orb), DMA_TO_DEVICE); cmd->sge_dma = dma_map_single(hi->host->device.parent, &cmd->scatter_gather_element, sizeof(cmd->scatter_gather_element), DMA_BIDIRECTIONAL); INIT_LIST_HEAD(&cmd->list); list_add_tail(&cmd->list, &lu->cmd_orb_completed); } spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); return 0;}static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu){ struct hpsb_host *host = lu->hi->host; struct list_head *lh, *next; struct sbp2_command_info *cmd; unsigned long flags; spin_lock_irqsave(&lu->cmd_orb_lock, flags); if (!list_empty(&lu->cmd_orb_completed)) list_for_each_safe(lh, next, &lu->cmd_orb_completed) { cmd = list_entry(lh, struct sbp2_command_info, list); dma_unmap_single(host->device.parent, cmd->command_orb_dma, sizeof(struct sbp2_command_orb), DMA_TO_DEVICE); dma_unmap_single(host->device.parent, cmd->sge_dma, sizeof(cmd->scatter_gather_element), DMA_BIDIRECTIONAL); kfree(cmd); } spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); return;}/* * Finds the sbp2_command for a given outstanding command ORB. * Only looks at the in-use list. */static struct sbp2_command_info *sbp2util_find_command_for_orb( struct sbp2_lu *lu, dma_addr_t orb){ struct sbp2_command_info *cmd; unsigned long flags; spin_lock_irqsave(&lu->cmd_orb_lock, flags); if (!list_empty(&lu->cmd_orb_inuse)) list_for_each_entry(cmd, &lu->cmd_orb_inuse, list) if (cmd->command_orb_dma == orb) { spin_unlock_irqrestore( &lu->cmd_orb_lock, flags); return cmd; } spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); return NULL;}/* * Finds the sbp2_command for a given outstanding SCpnt. * Only looks at the in-use list. * Must be called with lu->cmd_orb_lock held. */static struct sbp2_command_info *sbp2util_find_command_for_SCpnt( struct sbp2_lu *lu, void *SCpnt){ struct sbp2_command_info *cmd; if (!list_empty(&lu->cmd_orb_inuse)) list_for_each_entry(cmd, &lu->cmd_orb_inuse, list) if (cmd->Current_SCpnt == SCpnt) return cmd; return NULL;}static struct sbp2_command_info *sbp2util_allocate_command_orb( struct sbp2_lu *lu, struct scsi_cmnd *Current_SCpnt, void (*Current_done)(struct scsi_cmnd *)){ struct list_head *lh; struct sbp2_command_info *cmd = NULL; unsigned long flags; spin_lock_irqsave(&lu->cmd_orb_lock, flags); if (!list_empty(&lu->cmd_orb_completed)) { lh = lu->cmd_orb_completed.next; list_del(lh); cmd = list_entry(lh, struct sbp2_command_info, list); cmd->Current_done = Current_done; cmd->Current_SCpnt = Current_SCpnt; list_add_tail(&cmd->list, &lu->cmd_orb_inuse); } else SBP2_ERR("%s: no orbs available", __FUNCTION__); spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); return cmd;}/* * Unmaps the DMAs of a command and moves the command to the completed ORB list. * Must be called with lu->cmd_orb_lock held. */static void sbp2util_mark_command_completed(struct sbp2_lu *lu, struct sbp2_command_info *cmd){ struct hpsb_host *host = lu->ud->ne->host; if (cmd->cmd_dma) { if (cmd->dma_type == CMD_DMA_SINGLE) dma_unmap_single(host->device.parent, cmd->cmd_dma, cmd->dma_size, cmd->dma_dir); else if (cmd->dma_type == CMD_DMA_PAGE) dma_unmap_page(host->device.parent, cmd->cmd_dma, cmd->dma_size, cmd->dma_dir); /* XXX: Check for CMD_DMA_NONE bug */ cmd->dma_type = CMD_DMA_NONE; cmd->cmd_dma = 0; } if (cmd->sge_buffer) { dma_unmap_sg(host->device.parent, cmd->sge_buffer, cmd->dma_size, cmd->dma_dir); cmd->sge_buffer = NULL; } list_move_tail(&cmd->list, &lu->cmd_orb_completed);}/* * Is lu valid? Is the 1394 node still present? */static inline int sbp2util_node_is_available(struct sbp2_lu *lu){ return lu && lu->ne && !lu->ne->in_limbo;}/********************************************* * IEEE-1394 core driver stack related section *********************************************/static int sbp2_probe(struct device *dev){ struct unit_directory *ud; struct sbp2_lu *lu; 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; lu = sbp2_alloc_device(ud); if (!lu) return -ENOMEM; sbp2_parse_unit_directory(lu, ud); return sbp2_start_device(lu);}static int sbp2_remove(struct device *dev){ struct unit_directory *ud; struct sbp2_lu *lu; struct scsi_device *sdev; ud = container_of(dev, struct unit_directory, device); lu = ud->device.driver_data; if (!lu) return 0; if (lu->shost) { /* Get rid of enqueued commands if there is no chance to * send them. */ if (!sbp2util_node_is_available(lu)) sbp2scsi_complete_all_commands(lu, DID_NO_CONNECT); /* scsi_remove_device() may trigger shutdown functions of SCSI * highlevel drivers which would deadlock if blocked. */ atomic_set(&lu->state, SBP2LU_STATE_IN_SHUTDOWN); scsi_unblock_requests(lu->shost); } sdev = lu->sdev; if (sdev) { lu->sdev = NULL; scsi_remove_device(sdev); } sbp2_logout_device(lu); sbp2_remove_device(lu); return 0;}static int sbp2_update(struct unit_directory *ud){ struct sbp2_lu *lu = ud->device.driver_data; if (sbp2_reconnect_device(lu)) { /* Reconnect has failed. Perhaps we didn't reconnect fast * enough. Try a regular login, but first log out just in * case of any weirdness. */ sbp2_logout_device(lu); if (sbp2_login_device(lu)) { /* 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; } } sbp2_set_busy_timeout(lu); sbp2_agent_reset(lu, 1); sbp2_max_speed_and_size(lu); /* Complete any pending commands with busy (so they get retried) * and remove them from our queue. */ sbp2scsi_complete_all_commands(lu, DID_BUS_BUSY); /* Accept new commands unless there was another bus reset in the * meantime. */ if (hpsb_node_entry_valid(lu->ne)) { atomic_set(&lu->state, SBP2LU_STATE_RUNNING); scsi_unblock_requests(lu->shost); } return 0;}static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *ud){ struct sbp2_fwhost_info *hi; struct Scsi_Host *shost = NULL; struct sbp2_lu *lu = NULL; lu = kzalloc(sizeof(*lu), GFP_KERNEL); if (!lu) { SBP2_ERR("failed to create lu"); goto failed_alloc; } lu->ne = ud->ne; lu->ud = ud; lu->speed_code = IEEE1394_SPEED_100; lu->max_payload_size = sbp2_speedto_max_payload[IEEE1394_SPEED_100]; lu->status_fifo_addr = CSR1212_INVALID_ADDR_SPACE; INIT_LIST_HEAD(&lu->cmd_orb_inuse); INIT_LIST_HEAD(&lu->cmd_orb_completed); INIT_LIST_HEAD(&lu->lu_list); spin_lock_init(&lu->cmd_orb_lock); atomic_set(&lu->state, SBP2LU_STATE_RUNNING); INIT_WORK(&lu->protocol_work, NULL); ud->device.driver_data = lu; 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; } hi->host = ud->ne->host; INIT_LIST_HEAD(&hi->logical_units);#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; } lu->hi = hi; list_add_tail(&lu->lu_list, &hi->logical_units); /* 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. */ lu->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 (lu->status_fifo_addr == CSR1212_INVALID_ADDR_SPACE) { SBP2_ERR("failed to allocate status FIFO address range"); goto failed_alloc; } shost = scsi_host_alloc(&sbp2_shost_template, sizeof(unsigned long)); if (!shost) { SBP2_ERR("failed to register scsi host"); goto failed_alloc; } shost->hostdata[0] = (unsigned long)lu; if (!scsi_add_host(shost, &ud->device)) { lu->shost = shost; return lu; } SBP2_ERR("failed to add scsi host"); scsi_host_put(shost);failed_alloc: sbp2_remove_device(lu); return NULL;}static void sbp2_host_reset(struct hpsb_host *host){ struct sbp2_fwhost_info *hi; struct sbp2_lu *lu; hi = hpsb_get_hostinfo(&sbp2_highlevel, host); if (!hi) return; list_for_each_entry(lu, &hi->logical_units, lu_list) if (likely(atomic_read(&lu->state) != SBP2LU_STATE_IN_SHUTDOWN)) { atomic_set(&lu->state, SBP2LU_STATE_IN_RESET); scsi_block_requests(lu->shost); }}static int sbp2_start_device(struct sbp2_lu *lu){ struct sbp2_fwhost_info *hi = lu->hi; int error; lu->login_response = dma_alloc_coherent(hi->host->device.parent, sizeof(struct sbp2_login_response), &lu->login_response_dma, GFP_KERNEL); if (!lu->login_response) goto alloc_fail; lu->query_logins_orb = dma_alloc_coherent(hi->host->device.parent, sizeof(struct sbp2_query_logins_orb), &lu->query_logins_orb_dma, GFP_KERNEL); if (!lu->query_logins_orb) goto alloc_fail; lu->query_logins_response = dma_alloc_coherent(hi->host->device.parent, sizeof(struct sbp2_query_logins_response), &lu->query_logins_response_dma, GFP_KERNEL); if (!lu->query_logins_response) goto alloc_fail; lu->reconnect_orb = dma_alloc_coherent(hi->host->device.parent, sizeof(struct sbp2_reconnect_orb), &lu->reconnect_orb_dma, GFP_KERNEL); if (!lu->reconnect_orb) goto alloc_fail; lu->logout_orb = dma_alloc_coherent(hi->host->device.parent, sizeof(struct sbp2_logout_orb), &lu->logout_orb_dma, GFP_KERNEL); if (!lu->logout_orb) goto alloc_fail;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -