📄 sbp2.c
字号:
#define sbp2_spin_unlock(lock, flags) do {restore_flags(flags);} while (0)#endif/* * Globals */static Scsi_Host_Template scsi_driver_template;static u8 sbp2_speedto_maxrec[] = { 0x7, 0x8, 0x9 };static LIST_HEAD(sbp2_host_info_list);static int sbp2_host_count = 0;static struct hpsb_highlevel *sbp2_hl_handle = NULL;static struct hpsb_highlevel_ops sbp2_hl_ops = { add_host: sbp2_add_host, remove_host: sbp2_remove_host,};static struct hpsb_address_ops sbp2_ops = { write: sbp2_handle_status_write};static struct hpsb_protocol_driver sbp2_driver = { name: "SBP2 Driver", id_table: sbp2_id_table, probe: sbp2_probe, disconnect: sbp2_disconnect, update: sbp2_update};/************************************** * General utility functions **************************************/#ifndef __BIG_ENDIAN/* * Converts a buffer from be32 to cpu byte ordering. Length is in bytes. */static __inline__ void sbp2util_be32_to_cpu_buffer(void *buffer, int length){ u32 *temp = buffer; for (length = (length >> 2); length--; ) temp[length] = be32_to_cpu(temp[length]); return;}/* * Converts a buffer from cpu to be32 byte ordering. Length is in bytes. */static __inline__ void sbp2util_cpu_to_be32_buffer(void *buffer, int length){ u32 *temp = buffer; for (length = (length >> 2); length--; ) temp[length] = cpu_to_be32(temp[length]); return;}#else /* BIG_ENDIAN *//* Why waste the cpu cycles? */#define sbp2util_be32_to_cpu_buffer(x,y)#define sbp2util_cpu_to_be32_buffer(x,y)#endif/* * This function is called to initially create a packet pool for use in * sbp2 I/O requests. This packet pool is used when sending out sbp2 * command and agent reset requests, and allows us to remove all * kmallocs/kfrees from the critical I/O paths. */static int sbp2util_create_request_packet_pool(struct sbp2scsi_host_info *hi){ struct hpsb_packet *packet; int i; /* Create SBP2_MAX_REQUEST_PACKETS number of request packets. */ for (i=0; i<SBP2_MAX_REQUEST_PACKETS; i++) { /* * Max payload of 8 bytes since the sbp2 command request * uses a payload of 8 bytes, and agent reset is a quadlet * write request. Bump this up if we plan on using this * pool for other stuff. */ packet = alloc_hpsb_packet(8); if (!packet) { SBP2_ERR("sbp2util_create_request_packet_pool - packet allocation failed!"); return(-ENOMEM); } /* * Put these request packets into a free list */ INIT_LIST_HEAD(&hi->request_packet[i].list); hi->request_packet[i].packet = packet; list_add_tail(&hi->request_packet[i].list, &hi->sbp2_req_free); } return(0);}/* * This function is called to remove the packet pool. It is called when * the sbp2 driver is unloaded. */static void sbp2util_remove_request_packet_pool(struct sbp2scsi_host_info *hi){ struct list_head *lh; struct sbp2_request_packet *request_packet; unsigned long flags; /* * Go through free list releasing packets */ sbp2_spin_lock(&hi->sbp2_request_packet_lock, flags); while (!list_empty(&hi->sbp2_req_free)) { lh = hi->sbp2_req_free.next; list_del(lh); request_packet = list_entry(lh, struct sbp2_request_packet, list); /* * Free the hpsb packets that we allocated for the pool */ if (request_packet) { free_hpsb_packet(request_packet->packet); } } sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags); return;}/* * This function is called to retrieve a block write packet from our * packet pool. This function is used in place of calling * alloc_hpsb_packet (which costs us three kmallocs). Instead we just pull * out a free request packet and re-initialize values in it. I'm sure this * can still stand some more optimization. */static struct sbp2_request_packet *sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi, nodeid_t node, u64 addr, size_t data_size, quadlet_t data) { struct list_head *lh; struct sbp2_request_packet *request_packet = NULL; struct hpsb_packet *packet; unsigned long flags; sbp2_spin_lock(&hi->sbp2_request_packet_lock, flags); if (!list_empty(&hi->sbp2_req_free)) { /* * Pull out a free request packet */ lh = hi->sbp2_req_free.next; list_del(lh); request_packet = list_entry(lh, struct sbp2_request_packet, list); packet = request_packet->packet; /* * Initialize the packet (this is really initialization * the core 1394 stack should do, but I'm doing it myself * to avoid the overhead). */ packet->data_size = data_size; INIT_LIST_HEAD(&packet->list); sema_init(&packet->state_change, 0); packet->state = hpsb_unused; packet->generation = get_hpsb_generation(hi->host); packet->data_be = 1; packet->host = hi->host; packet->tlabel = get_tlabel(hi->host, node, 1); packet->node_id = node; 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; queue_task(&request_packet->tq, &packet->complete_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 functions 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 functions 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; command->linked = 0; 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 __FUNCTION__": hi == NULL\n"); return; } if (command->cmd_dma) { pci_unmap_single(hi->host->pdev, command->cmd_dma, command->dma_size, command->dma_dir); SBP2_DMA_FREE("single bulk"); command->cmd_dma = 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -