📄 sbp2.c
字号:
(unsigned int) scsi_id->sbp2_unit_characteristics); break; case SBP2_DEVICE_TYPE_AND_LUN_KEY: /* * Device type and lun (used for * detemining type of sbp2 device) */ scsi_id->sbp2_device_type_and_lun = ud->arb_values[i]; SBP2_DEBUG("sbp2_device_type_and_lun = %x", (unsigned int) scsi_id->sbp2_device_type_and_lun); break; case SBP2_FIRMWARE_REVISION_KEY: /* * Firmware revision (used to find broken * devices). If the vendor id is 0xa0b8 * (Symbios vendor id), then we have a * bridge with 128KB max transfer size * limitation. */ scsi_id->sbp2_firmware_revision = ud->arb_values[i]; if (scsi_id->sbp2_firmware_revision == SBP2_128KB_BROKEN_FIRMWARE) { SBP2_WARN("warning: Bridge chipset supports 128KB max transfer size"); } break; default: break; } }}/* * This function is called in order to determine the max speed and packet * size we can use in our ORBs. Note, that we (the driver and host) only * initiate the transaction. The SBP-2 device actually transfers the data * (by reading from the DMA area we tell it). This means that the SBP-2 * device decides the actual maximum data it can transfer. We just tell it * the speed that it needs to use, and the max_rec the host supports, and * it takes care of the rest. */static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id){ SBP2_DEBUG("sbp2_max_speed_and_size"); /* Initial setting comes from the hosts speed map */ scsi_id->speed_code = hi->host->speed_map[(hi->host->node_id & NODE_MASK) * 64 + (scsi_id->ne->nodeid & NODE_MASK)]; /* Bump down our speed if the user requested it */ if (scsi_id->speed_code > max_speed) { scsi_id->speed_code = max_speed; SBP2_ERR("Forcing SBP-2 max speed down to %s", hpsb_speedto_str[scsi_id->speed_code]); } /* Payload size is the lesser of what our speed supports and what * our host supports. */ scsi_id->max_payload_size = min(sbp2_speedto_maxrec[scsi_id->speed_code], (u8)(((be32_to_cpu(hi->host->csr.rom[2]) >> 12) & 0xf) - 1)); SBP2_ERR("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [%u]", NODE_BUS_ARGS(scsi_id->ne->nodeid), hpsb_speedto_str[scsi_id->speed_code], 1 << ((u32)scsi_id->max_payload_size + 2)); return(0);}/* * This function is called in order to perform a SBP-2 agent reset. */static int sbp2_agent_reset(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 flags) { struct sbp2_request_packet *agent_reset_request_packet; SBP2_DEBUG("sbp2_agent_reset"); /* * Ok, let's write to the target's management agent register */ agent_reset_request_packet = sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_command_block_agent_addr + SBP2_AGENT_RESET_OFFSET, 0, ntohl(SBP2_AGENT_RESET_DATA)); if (!agent_reset_request_packet) { SBP2_ERR("sbp2util_allocate_write_request_packet failed"); return(-EIO); } if (!hpsb_send_packet(agent_reset_request_packet->packet)) { SBP2_ERR("hpsb_send_packet failed"); sbp2util_free_request_packet(agent_reset_request_packet); return(-EIO); } if (!(flags & SBP2_SEND_NO_WAIT)) { down(&agent_reset_request_packet->packet->state_change); down(&agent_reset_request_packet->packet->state_change); } /* * Need to make sure orb pointer is written on next command */ scsi_id->last_orb = NULL; return(0);}/* * This function is called to create the actual command orb and s/g list * out of the scsi command itself. */static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, struct sbp2_command_info *command, unchar *scsi_cmd, unsigned int scsi_use_sg, unsigned int scsi_request_bufflen, void *scsi_request_buffer, int dma_dir){ struct scatterlist *sgpnt = (struct scatterlist *) scsi_request_buffer; struct sbp2_command_orb *command_orb = &command->command_orb; struct sbp2_unrestricted_page_table *scatter_gather_element = &command->scatter_gather_element[0]; u32 sg_count, sg_len; dma_addr_t sg_addr; int i; /* * Set-up our command ORB.. * * NOTE: We're doing unrestricted page tables (s/g), as this is * best performance (at least with the devices I have). This means * that data_size becomes the number of s/g elements, and * page_size should be zero (for unrestricted). */ command_orb->next_ORB_hi = 0xffffffff; command_orb->next_ORB_lo = 0xffffffff; command_orb->misc = ORB_SET_MAX_PAYLOAD(scsi_id->max_payload_size); command_orb->misc |= ORB_SET_SPEED(scsi_id->speed_code); command_orb->misc |= ORB_SET_NOTIFY(1); /* Notify us when complete */ /* * Set-up our pagetable stuff... unfortunately, this has become * messier than I'd like. Need to clean this up a bit. ;-) */ if (sbp2scsi_direction_table[*scsi_cmd] == ORB_DIRECTION_NO_DATA_TRANSFER) { SBP2_DEBUG("No data transfer"); /* * Handle no data transfer */ command_orb->data_descriptor_hi = 0xffffffff; command_orb->data_descriptor_lo = 0xffffffff; command_orb->misc |= ORB_SET_DIRECTION(1); } else if (scsi_use_sg) { SBP2_DEBUG("Use scatter/gather"); /* * Special case if only one element (and less than 64KB in size) */ if ((scsi_use_sg == 1) && (sgpnt[0].length <= SBP2_MAX_SG_ELEMENT_LENGTH)) { SBP2_DEBUG("Only one s/g element"); command->dma_dir = dma_dir; command->dma_size = sgpnt[0].length; command->cmd_dma = pci_map_single (hi->host->pdev, sgpnt[0].address, command->dma_size, command->dma_dir); SBP2_DMA_ALLOC("single scatter element"); command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id); command_orb->data_descriptor_lo = command->cmd_dma; command_orb->misc |= ORB_SET_DATA_SIZE(command->dma_size); command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]); } else { int count = pci_map_sg(hi->host->pdev, sgpnt, scsi_use_sg, dma_dir); SBP2_DMA_ALLOC("scatter list"); command->dma_size = scsi_use_sg; command->dma_dir = dma_dir; command->sge_buffer = sgpnt; /* use page tables (s/g) */ command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1); command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]); command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id); command_orb->data_descriptor_lo = command->sge_dma; /* * Loop through and fill out our sbp-2 page tables * (and split up anything too large) */ for (i = 0, sg_count = 0 ; i < count; i++, sgpnt++) { sg_len = sg_dma_len(sgpnt); sg_addr = sg_dma_address(sgpnt); while (sg_len) { scatter_gather_element[sg_count].segment_base_lo = sg_addr; if (sg_len > SBP2_MAX_SG_ELEMENT_LENGTH) { scatter_gather_element[sg_count].length_segment_base_hi = PAGE_TABLE_SET_SEGMENT_LENGTH(SBP2_MAX_SG_ELEMENT_LENGTH); sg_addr += SBP2_MAX_SG_ELEMENT_LENGTH; sg_len -= SBP2_MAX_SG_ELEMENT_LENGTH; } else { scatter_gather_element[sg_count].length_segment_base_hi = PAGE_TABLE_SET_SEGMENT_LENGTH(sg_len); sg_len = 0; } sg_count++; } } /* Number of page table (s/g) elements */ command_orb->misc |= ORB_SET_DATA_SIZE(sg_count); /* * Byte swap page tables if necessary */ sbp2util_cpu_to_be32_buffer(scatter_gather_element, (sizeof(struct sbp2_unrestricted_page_table)) * sg_count); } } else { SBP2_DEBUG("No scatter/gather"); command->dma_dir = dma_dir; command->dma_size = scsi_request_bufflen; command->cmd_dma = pci_map_single (hi->host->pdev, scsi_request_buffer, command->dma_size, command->dma_dir); SBP2_DMA_ALLOC("single bulk"); /* * Handle case where we get a command w/o s/g enabled (but * check for transfers larger than 64K) */ if (scsi_request_bufflen <= SBP2_MAX_SG_ELEMENT_LENGTH) { command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id); command_orb->data_descriptor_lo = command->cmd_dma; command_orb->misc |= ORB_SET_DATA_SIZE(scsi_request_bufflen); command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]); /* * Sanity, in case our direction table is not * up-to-date */ if (!scsi_request_bufflen) { command_orb->data_descriptor_hi = 0xffffffff; command_orb->data_descriptor_lo = 0xffffffff; command_orb->misc |= ORB_SET_DIRECTION(1); } } else { /* * Need to turn this into page tables, since the * buffer is too large. */ command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id); command_orb->data_descriptor_lo = command->sge_dma; /* Use page tables (s/g) */ command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1); command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]); /* * fill out our sbp-2 page tables (and split up * the large buffer) */ sg_count = 0; sg_len = scsi_request_bufflen; sg_addr = command->cmd_dma; while (sg_len) { scatter_gather_element[sg_count].segment_base_lo = sg_addr; if (sg_len > SBP2_MAX_SG_ELEMENT_LENGTH) { scatter_gather_element[sg_count].length_segment_base_hi = PAGE_TABLE_SET_SEGMENT_LENGTH(SBP2_MAX_SG_ELEMENT_LENGTH); sg_addr += SBP2_MAX_SG_ELEMENT_LENGTH; sg_len -= SBP2_MAX_SG_ELEMENT_LENGTH; } else { scatter_gather_element[sg_count].length_segment_base_hi = PAGE_TABLE_SET_SEGMENT_LENGTH(sg_len); sg_len = 0; } sg_count++; } /* Number of page table (s/g) elements */ command_orb->misc |= ORB_SET_DATA_SIZE(sg_count); /* * Byte swap page tables if necessary */ sbp2util_cpu_to_be32_buffer(scatter_gather_element, (sizeof(struct sbp2_unrestricted_page_table)) * sg_count); } } /* * Byte swap command ORB if necessary */ sbp2util_cpu_to_be32_buffer(command_orb, sizeof(struct sbp2_command_orb)); /* * Put our scsi command in the command ORB */ memset(command_orb->cdb, 0, 12); memcpy(command_orb->cdb, scsi_cmd, COMMAND_SIZE(*scsi_cmd)); return(0);} /* * This function is called in order to begin a regular SBP-2 command. */static int sbp2_link_orb_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, struct sbp2_command_info *command){ struct sbp2_request_packet *command_request_packet; struct sbp2_command_orb *command_orb = &command->command_orb; outstanding_orb_incr; SBP2_ORB_DEBUG("sending command orb %p, linked = %x, total orbs = %x", command_orb, command->linked, global_outstanding_command_orbs); /* * Check to see if there are any previous orbs to use */ if (scsi_id->last_orb == NULL) { /* * Ok, let's write to the target's management agent register */ if (hpsb_node_entry_valid(scsi_id->ne)) { command_request_packet = sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_command_block_agent_addr + SBP2_ORB_POINTER_OFFSET, 8, 0); if (!command_request_packet) { SBP2_ERR("sbp2util_allocate_write_request_packet failed"); return(-EIO); } command_request_packet->packet->data[0] = ORB_SET_NODE_ID(hi->host->node_id); command_request_packet->packet->data[1] = command->command_orb_dma; sbp2util_cpu_to_be32_buffer(command_request_packet->packet->data, 8); SBP2_ORB_DEBUG("write command agent, command orb %p", command_orb); if (!hpsb_send_packet(command_request_packet->packet)) { SBP2_ERR("hpsb_send_packet failed"); sbp2util_free_request_packet(command_request_packet); return(-EIO); } SBP2_ORB_DEBUG("write command agent complete"); } scsi_id->last_orb = command_orb; } else { /* * We have an orb already sent (maybe or maybe not * processed) that we can append this orb to. So do so, * and ring the doorbell. Have to be very careful * modifying these next orb pointers, as they are accessed * both by the sbp2 device and us. */ scsi_id->last_orb->next_ORB_lo = cpu_to_be32(command->command_orb_dma); /* Tells hardware that this pointer is valid */ scsi_id->last_orb->next_ORB_hi = 0x0; /* * Only ring the doorbell if we need to (first parts of * linked orbs don't need this). */ if (!command->linked && hpsb_node_entry_valid(scsi_id->ne)) { command_request_packet = sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_command_block_agent_addr + SBP2_DOORBELL_OFFSET, 0, cpu_to_be32(command->command_orb_dma)); if (!command_request_packet) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -