📄 sbp2.c
字号:
/* * 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); return 0;}/* * This function removes an sbp2 device from the sbp2scsi_host_info struct. */static void sbp2_remove_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id){ SBP2_DEBUG("sbp2_remove_device"); /* Complete any pending commands with selection timeout */ sbp2scsi_complete_all_commands(hi, scsi_id, DID_NO_CONNECT); /* Clean up any other structures */ if (scsi_id->sbp2_total_command_orbs) { sbp2util_remove_command_orb_pool(scsi_id, hi); } if (scsi_id->login_response) { pci_free_consistent(hi->host->pdev, sizeof(struct sbp2_login_response), scsi_id->login_response, scsi_id->login_response_dma); SBP2_DMA_FREE("single login FIFO"); } if (scsi_id->login_orb) { pci_free_consistent(hi->host->pdev, sizeof(struct sbp2_login_orb), scsi_id->login_orb, scsi_id->login_orb_dma); SBP2_DMA_FREE("single login ORB"); } if (scsi_id->reconnect_orb) { pci_free_consistent(hi->host->pdev, sizeof(struct sbp2_reconnect_orb), scsi_id->reconnect_orb, scsi_id->reconnect_orb_dma); SBP2_DMA_FREE("single reconnect orb"); } if (scsi_id->logout_orb) { pci_free_consistent(hi->host->pdev, sizeof(struct sbp2_logout_orb), scsi_id->logout_orb, scsi_id->reconnect_orb_dma); SBP2_DMA_FREE("single logout orb"); } SBP2_DEBUG("SBP-2 device removed, SCSI ID = %d", scsi_id->id); hi->scsi_id[scsi_id->id] = NULL; kfree(scsi_id);}/************************************** * SBP-2 protocol related section **************************************//* * This function is called in order to login to a particular SBP-2 device, * after a bus reset. */static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) { quadlet_t data[2]; unsigned long flags; SBP2_DEBUG("sbp2_login_device"); if (!scsi_id->login_orb) { SBP2_DEBUG("sbp2_login_device: login_orb not alloc'd!"); return(-EIO); } /* Set-up login ORB, assume no password */ scsi_id->login_orb->password_hi = 0; scsi_id->login_orb->password_lo = 0; SBP2_DEBUG("sbp2_login_device: password_hi/lo initialized"); scsi_id->login_orb->login_response_lo = scsi_id->login_response_dma; scsi_id->login_orb->login_response_hi = ORB_SET_NODE_ID(hi->host->node_id); SBP2_DEBUG("sbp2_login_device: login_response_hi/lo initialized"); scsi_id->login_orb->lun_misc = ORB_SET_FUNCTION(LOGIN_REQUEST); scsi_id->login_orb->lun_misc |= ORB_SET_RECONNECT(0); /* One second reconnect time */ scsi_id->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(1); /* Exclusive access to device */ scsi_id->login_orb->lun_misc |= ORB_SET_NOTIFY(1); /* Notify us of login complete */ SBP2_DEBUG("sbp2_login_device: lun_misc initialized"); scsi_id->login_orb->passwd_resp_lengths = ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response)); SBP2_DEBUG("sbp2_login_device: passwd_resp_lengths initialized"); scsi_id->login_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO; scsi_id->login_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI); SBP2_DEBUG("sbp2_login_device: status FIFO initialized"); /* * Byte swap ORB if necessary */ sbp2util_cpu_to_be32_buffer(scsi_id->login_orb, sizeof(struct sbp2_login_orb)); SBP2_DEBUG("sbp2_login_device: orb byte-swapped"); /* * Initialize login response and status fifo */ memset(scsi_id->login_response, 0, sizeof(struct sbp2_login_response)); memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block)); SBP2_DEBUG("sbp2_login_device: login_response/status FIFO memset"); /* * Ok, let's write to the target's management agent register */ data[0] = ORB_SET_NODE_ID(hi->host->node_id); data[1] = scsi_id->login_orb_dma; sbp2util_cpu_to_be32_buffer(data, 8); SBP2_DEBUG("sbp2_login_device: prepared to write"); hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_management_agent_addr, data, 8); SBP2_DEBUG("sbp2_login_device: written"); /* * Wait for login status... but, only if the device has not * already logged-in (some devices are fast) */ save_flags(flags); cli(); /* 10 second timeout */ if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma) sleep_on_timeout(&scsi_id->sbp2_login_wait, 10*HZ); restore_flags(flags); SBP2_DEBUG("sbp2_login_device: initial check"); /* * Match status to the login orb. If they do not match, it's * probably because the login timed-out. */ if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma) { SBP2_ERR("Error logging into SBP-2 device - login timed-out"); return(-EIO); } SBP2_DEBUG("sbp2_login_device: second check"); /* * Check status */ if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) || STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) || STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) { SBP2_ERR("Error logging into SBP-2 device - login failed"); return(-EIO); } /* * Byte swap the login response, for use when reconnecting or * logging out. */ sbp2util_cpu_to_be32_buffer(scsi_id->login_response, sizeof(struct sbp2_login_response)); /* * Grab our command block agent address from the login response. */ SBP2_DEBUG("command_block_agent_hi = %x", (unsigned int)scsi_id->login_response->command_block_agent_hi); SBP2_DEBUG("command_block_agent_lo = %x", (unsigned int)scsi_id->login_response->command_block_agent_lo); scsi_id->sbp2_command_block_agent_addr = ((u64)scsi_id->login_response->command_block_agent_hi) << 32; scsi_id->sbp2_command_block_agent_addr |= ((u64)scsi_id->login_response->command_block_agent_lo); scsi_id->sbp2_command_block_agent_addr &= 0x0000ffffffffffffULL; SBP2_INFO("Logged into SBP-2 device"); return(0);}/* * This function is called in order to logout from a particular SBP-2 * device, usually called during driver unload. */static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) { quadlet_t data[2]; SBP2_DEBUG("sbp2_logout_device"); /* * Set-up logout ORB */ scsi_id->logout_orb->reserved1 = 0x0; scsi_id->logout_orb->reserved2 = 0x0; scsi_id->logout_orb->reserved3 = 0x0; scsi_id->logout_orb->reserved4 = 0x0; scsi_id->logout_orb->login_ID_misc = ORB_SET_FUNCTION(LOGOUT_REQUEST); scsi_id->logout_orb->login_ID_misc |= ORB_SET_LOGIN_ID(scsi_id->login_response->length_login_ID); /* Notify us when complete */ scsi_id->logout_orb->login_ID_misc |= ORB_SET_NOTIFY(1); scsi_id->logout_orb->reserved5 = 0x0; scsi_id->logout_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO; scsi_id->logout_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI); /* * Byte swap ORB if necessary */ sbp2util_cpu_to_be32_buffer(scsi_id->logout_orb, sizeof(struct sbp2_logout_orb)); /* * Ok, let's write to the target's management agent register */ data[0] = ORB_SET_NODE_ID(hi->host->node_id); data[1] = scsi_id->logout_orb_dma; sbp2util_cpu_to_be32_buffer(data, 8); hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_management_agent_addr, data, 8); /* Wait for device to logout...1 second. */ sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ); SBP2_INFO("Logged out of SBP-2 device"); return(0);}/* * This function is called in order to reconnect to a particular SBP-2 * device, after a bus reset. */static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) { quadlet_t data[2]; unsigned long flags; SBP2_DEBUG("sbp2_reconnect_device"); /* * Set-up reconnect ORB */ scsi_id->reconnect_orb->reserved1 = 0x0; scsi_id->reconnect_orb->reserved2 = 0x0; scsi_id->reconnect_orb->reserved3 = 0x0; scsi_id->reconnect_orb->reserved4 = 0x0; scsi_id->reconnect_orb->login_ID_misc = ORB_SET_FUNCTION(RECONNECT_REQUEST); scsi_id->reconnect_orb->login_ID_misc |= ORB_SET_LOGIN_ID(scsi_id->login_response->length_login_ID); /* Notify us when complete */ scsi_id->reconnect_orb->login_ID_misc |= ORB_SET_NOTIFY(1); scsi_id->reconnect_orb->reserved5 = 0x0; scsi_id->reconnect_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO; scsi_id->reconnect_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI); /* * Byte swap ORB if necessary */ sbp2util_cpu_to_be32_buffer(scsi_id->reconnect_orb, sizeof(struct sbp2_reconnect_orb)); /* * Initialize status fifo */ memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block)); /* * Ok, let's write to the target's management agent register */ data[0] = ORB_SET_NODE_ID(hi->host->node_id); data[1] = scsi_id->reconnect_orb_dma; sbp2util_cpu_to_be32_buffer(data, 8); hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_management_agent_addr, data, 8); /* * Wait for reconnect status... but, only if the device has not * already reconnected (some devices are fast). */ save_flags(flags); cli(); /* One second timout */ if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma) sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ); restore_flags(flags); /* * Match status to the reconnect orb. If they do not match, it's * probably because the reconnect timed-out. */ if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma) { SBP2_ERR("Error reconnecting to SBP-2 device - reconnect timed-out"); return(-EIO); } /* * Check status */ if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) || STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) || STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) { SBP2_ERR("Error reconnecting to SBP-2 device - reconnect failed"); return(-EIO); } SBP2_INFO("Reconnected to SBP-2 device"); return(0);}/* * This function is called in order to set the busy timeout (number of * retries to attempt) on the sbp2 device. */static int sbp2_set_busy_timeout(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id){ quadlet_t data; SBP2_DEBUG("sbp2_set_busy_timeout"); /* * Ok, let's write to the target's busy timeout register */ data = cpu_to_be32(SBP2_BUSY_TIMEOUT_VALUE); if (hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) { SBP2_ERR("sbp2_set_busy_timeout error"); } return(0);}/* * This function is called to parse sbp2 device's config rom unit * directory. Used to determine things like sbp2 management agent offset, * and command set used (SCSI or RBC). */static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id){ struct unit_directory *ud; int i; SBP2_DEBUG("sbp2_parse_unit_directory"); ud = scsi_id->ud; /* Handle different fields in the unit directory, based on keys */ for (i = 0; i < ud->arb_count; i++) { switch (ud->arb_keys[i]) { case SBP2_CSR_OFFSET_KEY: /* Save off the management agent address */ scsi_id->sbp2_management_agent_addr = CONFIG_ROM_INITIAL_MEMORY_SPACE + (ud->arb_values[i] << 2); SBP2_DEBUG("sbp2_management_agent_addr = %x", (unsigned int) scsi_id->sbp2_management_agent_addr); break; case SBP2_COMMAND_SET_SPEC_ID_KEY: /* Command spec organization */ scsi_id->sbp2_command_set_spec_id = ud->arb_values[i]; SBP2_DEBUG("sbp2_command_set_spec_id = %x", (unsigned int) scsi_id->sbp2_command_set_spec_id); break; case SBP2_COMMAND_SET_KEY: /* Command set used by sbp2 device */ scsi_id->sbp2_command_set = ud->arb_values[i]; SBP2_DEBUG("sbp2_command_set = %x", (unsigned int) scsi_id->sbp2_command_set); break; case SBP2_UNIT_CHARACTERISTICS_KEY: /* * Unit characterisitcs (orb related stuff * that I'm not yet paying attention to) */ scsi_id->sbp2_unit_characteristics = ud->arb_values[i]; SBP2_DEBUG("sbp2_unit_characteristics = %x",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -