diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/be2iscsi/be.h | 2 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_cmds.c | 161 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_cmds.h | 18 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_main.c | 608 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_main.h | 33 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_mgmt.c | 537 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_mgmt.h | 23 |
7 files changed, 725 insertions, 657 deletions
diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h index 621291ab0214..454002d98bcd 100644 --- a/drivers/scsi/be2iscsi/be.h +++ b/drivers/scsi/be2iscsi/be.h @@ -113,6 +113,8 @@ struct beiscsi_mcc_tag_state { unsigned long tag_state; #define MCC_TAG_STATE_RUNNING 1 #define MCC_TAG_STATE_TIMEOUT 2 +#define MCC_TAG_STATE_ASYNC 3 + void (*cbfn)(struct beiscsi_hba *, unsigned int); struct be_dma_mem tag_mem_state; }; diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index f16de6cf2678..27d10cee0c40 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -84,6 +84,7 @@ struct be_mcc_wrb *alloc_mcc_wrb(struct beiscsi_hba *phba, phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index] = 0; phba->ctrl.mcc_tag_status[tag] = 0; phba->ctrl.ptag_state[tag].tag_state = 0; + phba->ctrl.ptag_state[tag].cbfn = NULL; phba->ctrl.mcc_tag_available--; if (phba->ctrl.mcc_alloc_index == (MAX_MCC_CMD - 1)) phba->ctrl.mcc_alloc_index = 0; @@ -128,6 +129,70 @@ void beiscsi_fail_session(struct iscsi_cls_session *cls_session) } /* + * beiscsi_mcc_compl_status - Return the status of MCC completion + * @phba: Driver private structure + * @tag: Tag for the MBX Command + * @wrb: the WRB used for the MBX Command + * @mbx_cmd_mem: ptr to memory allocated for MBX Cmd + * + * return + * Success: 0 + * Failure: Non-Zero + */ +int __beiscsi_mcc_compl_status(struct beiscsi_hba *phba, + unsigned int tag, + struct be_mcc_wrb **wrb, + struct be_dma_mem *mbx_cmd_mem) +{ + struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; + uint16_t status = 0, addl_status = 0, wrb_num = 0; + struct be_cmd_resp_hdr *mbx_resp_hdr; + struct be_cmd_req_hdr *mbx_hdr; + struct be_mcc_wrb *temp_wrb; + uint32_t mcc_tag_status; + int rc = 0; + + mcc_tag_status = phba->ctrl.mcc_tag_status[tag]; + status = (mcc_tag_status & CQE_STATUS_MASK); + addl_status = ((mcc_tag_status & CQE_STATUS_ADDL_MASK) >> + CQE_STATUS_ADDL_SHIFT); + + if (mbx_cmd_mem) { + mbx_hdr = (struct be_cmd_req_hdr *)mbx_cmd_mem->va; + } else { + wrb_num = (mcc_tag_status & CQE_STATUS_WRB_MASK) >> + CQE_STATUS_WRB_SHIFT; + temp_wrb = (struct be_mcc_wrb *)queue_get_wrb(mccq, wrb_num); + mbx_hdr = embedded_payload(temp_wrb); + + if (wrb) + *wrb = temp_wrb; + } + + if (status || addl_status) { + beiscsi_log(phba, KERN_WARNING, + BEISCSI_LOG_INIT | BEISCSI_LOG_EH | + BEISCSI_LOG_CONFIG, + "BC_%d : MBX Cmd Failed for Subsys : %d Opcode : %d with Status : %d and Extd_Status : %d\n", + mbx_hdr->subsystem, mbx_hdr->opcode, + status, addl_status); + rc = -EIO; + if (status == MCC_STATUS_INSUFFICIENT_BUFFER) { + mbx_resp_hdr = (struct be_cmd_resp_hdr *)mbx_hdr; + beiscsi_log(phba, KERN_WARNING, + BEISCSI_LOG_INIT | BEISCSI_LOG_EH | + BEISCSI_LOG_CONFIG, + "BC_%d : Insufficient Buffer Error Resp_Len : %d Actual_Resp_Len : %d\n", + mbx_resp_hdr->response_length, + mbx_resp_hdr->actual_resp_len); + rc = -EAGAIN; + } + } + + return rc; +} + +/* * beiscsi_mccq_compl_wait()- Process completion in MCC CQ * @phba: Driver private structure * @tag: Tag for the MBX Command @@ -141,16 +206,11 @@ void beiscsi_fail_session(struct iscsi_cls_session *cls_session) * Failure: Non-Zero **/ int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba, - uint32_t tag, struct be_mcc_wrb **wrb, + unsigned int tag, + struct be_mcc_wrb **wrb, struct be_dma_mem *mbx_cmd_mem) { int rc = 0; - uint32_t mcc_tag_status; - uint16_t status = 0, addl_status = 0, wrb_num = 0; - struct be_mcc_wrb *temp_wrb; - struct be_cmd_req_hdr *mbx_hdr; - struct be_cmd_resp_hdr *mbx_resp_hdr; - struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; if (beiscsi_hba_in_error(phba)) { clear_bit(MCC_TAG_STATE_RUNNING, @@ -159,11 +219,11 @@ int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba, } /* wait for the mccq completion */ - rc = wait_event_interruptible_timeout( - phba->ctrl.mcc_wait[tag], - phba->ctrl.mcc_tag_status[tag], - msecs_to_jiffies( - BEISCSI_HOST_MBX_TIMEOUT)); + rc = wait_event_interruptible_timeout(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_tag_status[tag], + msecs_to_jiffies( + BEISCSI_HOST_MBX_TIMEOUT)); + /** * If MBOX cmd timeout expired, tag and resource allocated * for cmd is not freed until FW returns completion. @@ -197,47 +257,7 @@ int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba, return -EBUSY; } - rc = 0; - mcc_tag_status = phba->ctrl.mcc_tag_status[tag]; - status = (mcc_tag_status & CQE_STATUS_MASK); - addl_status = ((mcc_tag_status & CQE_STATUS_ADDL_MASK) >> - CQE_STATUS_ADDL_SHIFT); - - if (mbx_cmd_mem) { - mbx_hdr = (struct be_cmd_req_hdr *)mbx_cmd_mem->va; - } else { - wrb_num = (mcc_tag_status & CQE_STATUS_WRB_MASK) >> - CQE_STATUS_WRB_SHIFT; - temp_wrb = (struct be_mcc_wrb *)queue_get_wrb(mccq, wrb_num); - mbx_hdr = embedded_payload(temp_wrb); - - if (wrb) - *wrb = temp_wrb; - } - - if (status || addl_status) { - beiscsi_log(phba, KERN_WARNING, - BEISCSI_LOG_INIT | BEISCSI_LOG_EH | - BEISCSI_LOG_CONFIG, - "BC_%d : MBX Cmd Failed for " - "Subsys : %d Opcode : %d with " - "Status : %d and Extd_Status : %d\n", - mbx_hdr->subsystem, - mbx_hdr->opcode, - status, addl_status); - rc = -EIO; - if (status == MCC_STATUS_INSUFFICIENT_BUFFER) { - mbx_resp_hdr = (struct be_cmd_resp_hdr *) mbx_hdr; - beiscsi_log(phba, KERN_WARNING, - BEISCSI_LOG_INIT | BEISCSI_LOG_EH | - BEISCSI_LOG_CONFIG, - "BC_%d : Insufficient Buffer Error " - "Resp_Len : %d Actual_Resp_Len : %d\n", - mbx_resp_hdr->response_length, - mbx_resp_hdr->actual_resp_len); - rc = -EAGAIN; - } - } + rc = __beiscsi_mcc_compl_status(phba, tag, wrb, mbx_cmd_mem); free_mcc_wrb(&phba->ctrl, tag); return rc; @@ -318,11 +338,9 @@ static void beiscsi_process_async_link(struct beiscsi_hba *phba, * This has been newly introduced in SKH-R Firmware 10.0.338.45. **/ if (evt->port_link_status & BE_ASYNC_LINK_UP_MASK) { - phba->get_boot = BE_GET_BOOT_RETRIES; - /* first this needs to be visible to worker thread */ - wmb(); - set_bit(BEISCSI_HBA_LINK_UP | BEISCSI_HBA_BOOT_FOUND, - &phba->state); + set_bit(BEISCSI_HBA_LINK_UP, &phba->state); + if (test_bit(BEISCSI_HBA_BOOT_FOUND, &phba->state)) + beiscsi_start_boot_work(phba, BE_BOOT_INVALID_SHANDLE); __beiscsi_log(phba, KERN_ERR, "BC_%d : Link Up on Port %d tag 0x%x\n", evt->physical_port, evt->event_tag); @@ -412,10 +430,8 @@ void beiscsi_process_async_event(struct beiscsi_hba *phba, beiscsi_process_async_link(phba, compl); break; case ASYNC_EVENT_CODE_ISCSI: - phba->get_boot = BE_GET_BOOT_RETRIES; - /* first this needs to be visible to worker thread */ - wmb(); - set_bit(BEISCSI_HBA_BOOT_FOUND, &phba->state); + if (test_bit(BEISCSI_HBA_BOOT_FOUND, &phba->state)) + beiscsi_start_boot_work(phba, BE_BOOT_INVALID_SHANDLE); sev = KERN_ERR; break; case ASYNC_EVENT_CODE_SLI: @@ -451,6 +467,9 @@ int beiscsi_process_mcc_compl(struct be_ctrl_info *ctrl, return 0; } + /* end MCC with this tag */ + clear_bit(MCC_TAG_STATE_RUNNING, &ctrl->ptag_state[tag].tag_state); + if (test_bit(MCC_TAG_STATE_TIMEOUT, &ctrl->ptag_state[tag].tag_state)) { beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_MBOX | BEISCSI_LOG_INIT | @@ -461,9 +480,11 @@ int beiscsi_process_mcc_compl(struct be_ctrl_info *ctrl, * Only for non-embedded cmd, PCI resource is allocated. **/ tag_mem = &ctrl->ptag_state[tag].tag_mem_state; - if (tag_mem->size) + if (tag_mem->size) { pci_free_consistent(ctrl->pdev, tag_mem->size, tag_mem->va, tag_mem->dma); + tag_mem->size = 0; + } free_mcc_wrb(ctrl, tag); return 0; } @@ -482,8 +503,18 @@ int beiscsi_process_mcc_compl(struct be_ctrl_info *ctrl, CQE_STATUS_ADDL_MASK; ctrl->mcc_tag_status[tag] |= (compl_status & CQE_STATUS_MASK); - /* write ordering forced in wake_up_interruptible */ - clear_bit(MCC_TAG_STATE_RUNNING, &ctrl->ptag_state[tag].tag_state); + if (test_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state)) { + if (ctrl->ptag_state[tag].cbfn) + ctrl->ptag_state[tag].cbfn(phba, tag); + else + beiscsi_log(phba, KERN_ERR, + BEISCSI_LOG_MBOX | BEISCSI_LOG_INIT | + BEISCSI_LOG_CONFIG, + "BC_%d : MBX ASYNC command with no callback\n"); + free_mcc_wrb(ctrl, tag); + return 0; + } + wake_up_interruptible(&ctrl->mcc_wait[tag]); return 0; } diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index c50b74afd00a..0510b6767341 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -345,8 +345,8 @@ struct be_cmd_req_logout_fw_sess { struct be_cmd_resp_logout_fw_sess { struct be_cmd_resp_hdr hdr; /* dw[4] */ -#define BEISCSI_MGMT_SESSION_CLOSE 0x20 uint32_t session_status; +#define BE_SESS_STATUS_CLOSE 0x20 } __packed; struct mgmt_conn_login_options { @@ -438,8 +438,13 @@ struct be_cmd_get_boot_target_req { struct be_cmd_get_boot_target_resp { struct be_cmd_resp_hdr hdr; - u32 boot_session_count; - int boot_session_handle; + u32 boot_session_count; + u32 boot_session_handle; +/** + * FW returns 0xffffffff if it couldn't establish connection with + * configured boot target. + */ +#define BE_BOOT_INVALID_SHANDLE 0xffffffff }; struct be_cmd_reopen_session_req { @@ -741,8 +746,13 @@ void free_mcc_wrb(struct be_ctrl_info *ctrl, unsigned int tag); int be_cmd_modify_eq_delay(struct beiscsi_hba *phba, struct be_set_eqd *, int num); int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba, - uint32_t tag, struct be_mcc_wrb **wrb, + unsigned int tag, + struct be_mcc_wrb **wrb, struct be_dma_mem *mbx_cmd_mem); +int __beiscsi_mcc_compl_status(struct beiscsi_hba *phba, + unsigned int tag, + struct be_mcc_wrb **wrb, + struct be_dma_mem *mbx_cmd_mem); /*ISCSI Functuions */ int be_cmd_fw_initialize(struct be_ctrl_info *ctrl); int be_cmd_fw_uninit(struct be_ctrl_info *ctrl); diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 22fcbea6894d..eb4ce17a683d 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -374,152 +374,6 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) return iscsi_eh_device_reset(sc); } -static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf) -{ - struct beiscsi_hba *phba = data; - struct mgmt_session_info *boot_sess = &phba->boot_sess; - struct mgmt_conn_info *boot_conn = &boot_sess->conn_list[0]; - char *str = buf; - int rc = -EPERM; - - switch (type) { - case ISCSI_BOOT_TGT_NAME: - rc = sprintf(buf, "%.*s\n", - (int)strlen(boot_sess->target_name), - (char *)&boot_sess->target_name); - break; - case ISCSI_BOOT_TGT_IP_ADDR: - if (boot_conn->dest_ipaddr.ip_type == BEISCSI_IP_TYPE_V4) - rc = sprintf(buf, "%pI4\n", - (char *)&boot_conn->dest_ipaddr.addr); - else - rc = sprintf(str, "%pI6\n", - (char *)&boot_conn->dest_ipaddr.addr); - break; - case ISCSI_BOOT_TGT_PORT: - rc = sprintf(str, "%d\n", boot_conn->dest_port); - break; - - case ISCSI_BOOT_TGT_CHAP_NAME: - rc = sprintf(str, "%.*s\n", - boot_conn->negotiated_login_options.auth_data.chap. - target_chap_name_length, - (char *)&boot_conn->negotiated_login_options. - auth_data.chap.target_chap_name); - break; - case ISCSI_BOOT_TGT_CHAP_SECRET: - rc = sprintf(str, "%.*s\n", - boot_conn->negotiated_login_options.auth_data.chap. - target_secret_length, - (char *)&boot_conn->negotiated_login_options. - auth_data.chap.target_secret); - break; - case ISCSI_BOOT_TGT_REV_CHAP_NAME: - rc = sprintf(str, "%.*s\n", - boot_conn->negotiated_login_options.auth_data.chap. - intr_chap_name_length, - (char *)&boot_conn->negotiated_login_options. - auth_data.chap.intr_chap_name); - break; - case ISCSI_BOOT_TGT_REV_CHAP_SECRET: - rc = sprintf(str, "%.*s\n", - boot_conn->negotiated_login_options.auth_data.chap. - intr_secret_length, - (char *)&boot_conn->negotiated_login_options. - auth_data.chap.intr_secret); - break; - case ISCSI_BOOT_TGT_FLAGS: - rc = sprintf(str, "2\n"); - break; - case ISCSI_BOOT_TGT_NIC_ASSOC: - rc = sprintf(str, "0\n"); - break; - } - return rc; -} - -static ssize_t beiscsi_show_boot_ini_info(void *data, int type, char *buf) -{ - struct beiscsi_hba *phba = data; - char *str = buf; - int rc = -EPERM; - - switch (type) { - case ISCSI_BOOT_INI_INITIATOR_NAME: - rc = sprintf(str, "%s\n", phba->boot_sess.initiator_iscsiname); - break; - } - return rc; -} - -static ssize_t beiscsi_show_boot_eth_info(void *data, int type, char *buf) -{ - struct beiscsi_hba *phba = data; - char *str = buf; - int rc = -EPERM; - - switch (type) { - case ISCSI_BOOT_ETH_FLAGS: - rc = sprintf(str, "2\n"); - break; - case ISCSI_BOOT_ETH_INDEX: - rc = sprintf(str, "0\n"); - break; - case ISCSI_BOOT_ETH_MAC: - rc = beiscsi_get_macaddr(str, phba); - break; - } - return rc; -} - - -static umode_t beiscsi_tgt_get_attr_visibility(void *data, int type) -{ - umode_t rc = 0; - - switch (type) { - case ISCSI_BOOT_TGT_NAME: - case ISCSI_BOOT_TGT_IP_ADDR: - case ISCSI_BOOT_TGT_PORT: - case ISCSI_BOOT_TGT_CHAP_NAME: - case ISCSI_BOOT_TGT_CHAP_SECRET: - case ISCSI_BOOT_TGT_REV_CHAP_NAME: - case ISCSI_BOOT_TGT_REV_CHAP_SECRET: - case ISCSI_BOOT_TGT_NIC_ASSOC: - case ISCSI_BOOT_TGT_FLAGS: - rc = S_IRUGO; - break; - } - return rc; -} - -static umode_t beiscsi_ini_get_attr_visibility(void *data, int type) -{ - umode_t rc = 0; - - switch (type) { - case ISCSI_BOOT_INI_INITIATOR_NAME: - rc = S_IRUGO; - break; - } - return rc; -} - - -static umode_t beiscsi_eth_get_attr_visibility(void *data, int type) -{ - umode_t rc = 0; - - switch (type) { - case ISCSI_BOOT_ETH_FLAGS: - case ISCSI_BOOT_ETH_MAC: - case ISCSI_BOOT_ETH_INDEX: - rc = S_IRUGO; - break; - } - return rc; -} - /*------------------- PCI Driver operations and data ----------------- */ static const struct pci_device_id beiscsi_pci_id_table[] = { { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) }, @@ -4312,149 +4166,6 @@ static void hwi_disable_intr(struct beiscsi_hba *phba) "BM_%d : In hwi_disable_intr, Already Disabled\n"); } -/** - * beiscsi_get_boot_info()- Get the boot session info - * @phba: The device priv structure instance - * - * Get the boot target info and store in driver priv structure - * - * return values - * Success: 0 - * Failure: Non-Zero Value - **/ -static int beiscsi_get_boot_info(struct beiscsi_hba *phba) -{ - struct be_cmd_get_session_resp *session_resp; - struct be_dma_mem nonemb_cmd; - unsigned int tag; - unsigned int s_handle; - int ret = -ENOMEM; - - /* Get the session handle of the boot target */ - ret = be_mgmt_get_boot_shandle(phba, &s_handle); - if (ret) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, - "BM_%d : No boot session\n"); - - if (ret == -ENXIO) - phba->get_boot = 0; - - - return ret; - } - phba->get_boot = 0; - nonemb_cmd.va = pci_zalloc_consistent(phba->ctrl.pdev, - sizeof(*session_resp), - &nonemb_cmd.dma); - if (nonemb_cmd.va == NULL) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, - "BM_%d : Failed to allocate memory for" - "beiscsi_get_session_info\n"); - - return -ENOMEM; - } - - tag = mgmt_get_session_info(phba, s_handle, - &nonemb_cmd); - if (!tag) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, - "BM_%d : beiscsi_get_session_info" - " Failed\n"); - - goto boot_freemem; - } - - ret = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd); - if (ret) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, - "BM_%d : beiscsi_get_session_info Failed"); - - if (ret != -EBUSY) - goto boot_freemem; - else - return ret; - } - - session_resp = nonemb_cmd.va ; - - memcpy(&phba->boot_sess, &session_resp->session_info, - sizeof(struct mgmt_session_info)); - - beiscsi_logout_fw_sess(phba, - phba->boot_sess.session_handle); - ret = 0; - -boot_freemem: - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - return ret; -} - -static void beiscsi_boot_release(void *data) -{ - struct beiscsi_hba *phba = data; - - scsi_host_put(phba->shost); -} - -static int beiscsi_setup_boot_info(struct beiscsi_hba *phba) -{ - struct iscsi_boot_kobj *boot_kobj; - - /* it has been created previously */ - if (phba->boot_kset) - return 0; - - /* get boot info using mgmt cmd */ - if (beiscsi_get_boot_info(phba)) - /* Try to see if we can carry on without this */ - return 0; - - phba->boot_kset = iscsi_boot_create_host_kset(phba->shost->host_no); - if (!phba->boot_kset) - return -ENOMEM; - - /* get a ref because the show function will ref the phba */ - if (!scsi_host_get(phba->shost)) - goto free_kset; - boot_kobj = iscsi_boot_create_target(phba->boot_kset, 0, phba, - beiscsi_show_boot_tgt_info, - beiscsi_tgt_get_attr_visibility, - beiscsi_boot_release); - if (!boot_kobj) - goto put_shost; - - if (!scsi_host_get(phba->shost)) - goto free_kset; - boot_kobj = iscsi_boot_create_initiator(phba->boot_kset, 0, phba, - beiscsi_show_boot_ini_info, - beiscsi_ini_get_attr_visibility, - beiscsi_boot_release); - if (!boot_kobj) - goto put_shost; - - if (!scsi_host_get(phba->shost)) - goto free_kset; - boot_kobj = iscsi_boot_create_ethernet(phba->boot_kset, 0, phba, - beiscsi_show_boot_eth_info, - beiscsi_eth_get_attr_visibility, - beiscsi_boot_release); - if (!boot_kobj) - goto put_shost; - return 0; - -put_shost: - scsi_host_put(phba->shost); -free_kset: - iscsi_boot_destroy_kset(phba->boot_kset); - phba->boot_kset = NULL; - return -ENOMEM; -} - static int beiscsi_init_port(struct beiscsi_hba *phba) { int ret; @@ -5289,6 +5000,7 @@ static void beiscsi_quiesce(struct beiscsi_hba *phba) free_irq(phba->pcidev->irq, phba); pci_disable_msix(phba->pcidev); cancel_delayed_work_sync(&phba->beiscsi_hw_check_task); + cancel_work_sync(&phba->boot_work); for (i = 0; i < phba->num_cpus; i++) { pbe_eq = &phwi_context->be_eq[i]; @@ -5325,9 +5037,10 @@ static void beiscsi_remove(struct pci_dev *pcidev) clear_bit(BEISCSI_HBA_RUNNING, &phba->state); beiscsi_iface_destroy_default(phba); - iscsi_boot_destroy_kset(phba->boot_kset); iscsi_host_remove(phba->shost); beiscsi_quiesce(phba); + /* after cancelling boot_work */ + iscsi_boot_destroy_kset(phba->boot_struct.boot_kset); pci_dev_put(phba->pcidev); iscsi_host_free(phba->shost); pci_disable_pcie_error_reporting(pcidev); @@ -5351,6 +5064,281 @@ static void beiscsi_msix_enable(struct beiscsi_hba *phba) return; } +void beiscsi_start_boot_work(struct beiscsi_hba *phba, unsigned int s_handle) +{ + if (phba->boot_struct.boot_kset) + return; + + /* skip if boot work is already in progress */ + if (test_and_set_bit(BEISCSI_HBA_BOOT_WORK, &phba->state)) + return; + + phba->boot_struct.retry = 3; + phba->boot_struct.tag = 0; + phba->boot_struct.s_handle = s_handle; + phba->boot_struct.action = BEISCSI_BOOT_GET_SHANDLE; + schedule_work(&phba->boot_work); +} + +static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf) +{ + struct beiscsi_hba *phba = data; + struct mgmt_session_info *boot_sess = &phba->boot_struct.boot_sess; + struct mgmt_conn_info *boot_conn = &boot_sess->conn_list[0]; + char *str = buf; + int rc = -EPERM; + + switch (type) { + case ISCSI_BOOT_TGT_NAME: + rc = sprintf(buf, "%.*s\n", + (int)strlen(boot_sess->target_name), + (char *)&boot_sess->target_name); + break; + case ISCSI_BOOT_TGT_IP_ADDR: + if (boot_conn->dest_ipaddr.ip_type == BEISCSI_IP_TYPE_V4) + rc = sprintf(buf, "%pI4\n", + (char *)&boot_conn->dest_ipaddr.addr); + else + rc = sprintf(str, "%pI6\n", + (char *)&boot_conn->dest_ipaddr.addr); + break; + case ISCSI_BOOT_TGT_PORT: + rc = sprintf(str, "%d\n", boot_conn->dest_port); + break; + + case ISCSI_BOOT_TGT_CHAP_NAME: + rc = sprintf(str, "%.*s\n", + boot_conn->negotiated_login_options.auth_data.chap. + target_chap_name_length, + (char *)&boot_conn->negotiated_login_options. + auth_data.chap.target_chap_name); + break; + case ISCSI_BOOT_TGT_CHAP_SECRET: + rc = sprintf(str, "%.*s\n", + boot_conn->negotiated_login_options.auth_data.chap. + target_secret_length, + (char *)&boot_conn->negotiated_login_options. + auth_data.chap.target_secret); + break; + case ISCSI_BOOT_TGT_REV_CHAP_NAME: + rc = sprintf(str, "%.*s\n", + boot_conn->negotiated_login_options.auth_data.chap. + intr_chap_name_length, + (char *)&boot_conn->negotiated_login_options. + auth_data.chap.intr_chap_name); + break; + case ISCSI_BOOT_TGT_REV_CHAP_SECRET: + rc = sprintf(str, "%.*s\n", + boot_conn->negotiated_login_options.auth_data.chap. + intr_secret_length, + (char *)&boot_conn->negotiated_login_options. + auth_data.chap.intr_secret); + break; + case ISCSI_BOOT_TGT_FLAGS: + rc = sprintf(str, "2\n"); + break; + case ISCSI_BOOT_TGT_NIC_ASSOC: + rc = sprintf(str, "0\n"); + break; + } + return rc; +} + +static ssize_t beiscsi_show_boot_ini_info(void *data, int type, char *buf) +{ + struct beiscsi_hba *phba = data; + char *str = buf; + int rc = -EPERM; + + switch (type) { + case ISCSI_BOOT_INI_INITIATOR_NAME: + rc = sprintf(str, "%s\n", + phba->boot_struct.boot_sess.initiator_iscsiname); + break; + } + return rc; +} + +static ssize_t beiscsi_show_boot_eth_info(void *data, int type, char *buf) +{ + struct beiscsi_hba *phba = data; + char *str = buf; + int rc = -EPERM; + + switch (type) { + case ISCSI_BOOT_ETH_FLAGS: + rc = sprintf(str, "2\n"); + break; + case ISCSI_BOOT_ETH_INDEX: + rc = sprintf(str, "0\n"); + break; + case ISCSI_BOOT_ETH_MAC: + rc = beiscsi_get_macaddr(str, phba); + break; + } + return rc; +} + + +static umode_t beiscsi_tgt_get_attr_visibility(void *data, int type) +{ + umode_t rc = 0; + + switch (type) { + case ISCSI_BOOT_TGT_NAME: + case ISCSI_BOOT_TGT_IP_ADDR: + case ISCSI_BOOT_TGT_PORT: + case ISCSI_BOOT_TGT_CHAP_NAME: + case ISCSI_BOOT_TGT_CHAP_SECRET: + case ISCSI_BOOT_TGT_REV_CHAP_NAME: + case ISCSI_BOOT_TGT_REV_CHAP_SECRET: + case ISCSI_BOOT_TGT_NIC_ASSOC: + case ISCSI_BOOT_TGT_FLAGS: + rc = S_IRUGO; + break; + } + return rc; +} + +static umode_t beiscsi_ini_get_attr_visibility(void *data, int type) +{ + umode_t rc = 0; + + switch (type) { + case ISCSI_BOOT_INI_INITIATOR_NAME: + rc = S_IRUGO; + break; + } + return rc; +} + + +static umode_t beiscsi_eth_get_attr_visibility(void *data, int type) +{ + umode_t rc = 0; + + switch (type) { + case ISCSI_BOOT_ETH_FLAGS: + case ISCSI_BOOT_ETH_MAC: + case ISCSI_BOOT_ETH_INDEX: + rc = S_IRUGO; + break; + } + return rc; +} + +static void beiscsi_boot_kobj_release(void *data) +{ + struct beiscsi_hba *phba = data; + + scsi_host_put(phba->shost); +} + +static int beiscsi_boot_create_kset(struct beiscsi_hba *phba) +{ + struct boot_struct *bs = &phba->boot_struct; + struct iscsi_boot_kobj *boot_kobj; + + if (bs->boot_kset) { + __beiscsi_log(phba, KERN_ERR, + "BM_%d: boot_kset already created\n"); + return 0; + } + + bs->boot_kset = iscsi_boot_create_host_kset(phba->shost->host_no); + if (!bs->boot_kset) { + __beiscsi_log(phba, KERN_ERR, + "BM_%d: boot_kset alloc failed\n"); + return -ENOMEM; + } + + /* get shost ref because the show function will refer phba */ + if (!scsi_host_get(phba->shost)) + goto free_kset; + + boot_kobj = iscsi_boot_create_target(bs->boot_kset, 0, phba, + beiscsi_show_boot_tgt_info, + beiscsi_tgt_get_attr_visibility, + beiscsi_boot_kobj_release); + if (!boot_kobj) + goto put_shost; + + if (!scsi_host_get(phba->shost)) + goto free_kset; + + boot_kobj = iscsi_boot_create_initiator(bs->boot_kset, 0, phba, + beiscsi_show_boot_ini_info, + beiscsi_ini_get_attr_visibility, + beiscsi_boot_kobj_release); + if (!boot_kobj) + goto put_shost; + + if (!scsi_host_get(phba->shost)) + goto free_kset; + + boot_kobj = iscsi_boot_create_ethernet(bs->boot_kset, 0, phba, + beiscsi_show_boot_eth_info, + beiscsi_eth_get_attr_visibility, + beiscsi_boot_kobj_release); + if (!boot_kobj) + goto put_shost; + + return 0; + +put_shost: + scsi_host_put(phba->shost); +free_kset: + iscsi_boot_destroy_kset(bs->boot_kset); + bs->boot_kset = NULL; + return -ENOMEM; +} + +static void beiscsi_boot_work(struct work_struct *work) +{ + struct beiscsi_hba *phba = + container_of(work, struct beiscsi_hba, boot_work); + struct boot_struct *bs = &phba->boot_struct; + unsigned int tag = 0; + + if (beiscsi_hba_in_error(phba)) + return; + + beiscsi_log(phba, KERN_INFO, + BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, + "BM_%d : %s action %d\n", + __func__, phba->boot_struct.action); + + switch (phba->boot_struct.action) { + case BEISCSI_BOOT_REOPEN_SESS: + tag = beiscsi_boot_reopen_sess(phba); + break; + case BEISCSI_BOOT_GET_SHANDLE: + tag = __beiscsi_boot_get_shandle(phba, 1); + break; + case BEISCSI_BOOT_GET_SINFO: + tag = beiscsi_boot_get_sinfo(phba); + break; + case BEISCSI_BOOT_LOGOUT_SESS: + tag = beiscsi_boot_logout_sess(phba); + break; + case BEISCSI_BOOT_CREATE_KSET: + beiscsi_boot_create_kset(phba); + /** + * updated boot_kset is made visible to all before + * ending the boot work. + */ + mb(); + clear_bit(BEISCSI_HBA_BOOT_WORK, &phba->state); + return; + } + if (!tag) { + if (bs->retry--) + schedule_work(&phba->boot_work); + else + clear_bit(BEISCSI_HBA_BOOT_WORK, &phba->state); + } +} + static void be_eqd_update(struct beiscsi_hba *phba) { struct be_set_eqd set_eqd[MAX_CPUS]; @@ -5405,17 +5393,6 @@ static void be_eqd_update(struct beiscsi_hba *phba) } } -static void be_check_boot_session(struct beiscsi_hba *phba) -{ - if (beiscsi_hba_in_error(phba)) - return; - - if (beiscsi_setup_boot_info(phba)) - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : Could not set up " - "iSCSI boot info on async event.\n"); -} - /* * beiscsi_hw_health_check()- Check adapter health * @work: work item to check HW health @@ -5431,17 +5408,6 @@ beiscsi_hw_health_check(struct work_struct *work) be_eqd_update(phba); - if (test_bit(BEISCSI_HBA_BOOT_FOUND, &phba->state)) { - if ((phba->get_boot > 0) && (!phba->boot_kset)) { - phba->get_boot--; - if (!(phba->get_boot % BE_GET_BOOT_TO)) - be_check_boot_session(phba); - } else { - clear_bit(BEISCSI_HBA_BOOT_FOUND, &phba->state); - phba->get_boot = 0; - } - } - beiscsi_ue_detect(phba); schedule_delayed_work(&phba->beiscsi_hw_check_task, @@ -5607,6 +5573,7 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev, struct hwi_controller *phwi_ctrlr; struct hwi_context_memory *phwi_context; struct be_eq_obj *pbe_eq; + unsigned int s_handle; int ret = 0, i; ret = beiscsi_enable_pci(pcidev); @@ -5769,14 +5736,17 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev, if (iscsi_host_add(phba->shost, &phba->pcidev->dev)) goto free_blkenbld; - if (beiscsi_setup_boot_info(phba)) - /* - * log error but continue, because we may not be using - * iscsi boot. + INIT_WORK(&phba->boot_work, beiscsi_boot_work); + ret = beiscsi_boot_get_shandle(phba, &s_handle); + if (ret > 0) { + beiscsi_start_boot_work(phba, s_handle); + /** + * Set this bit after starting the work to let + * probe handle it first. + * ASYNC event can too schedule this work. */ - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BM_%d : Could not set up " - "iSCSI boot info.\n"); + set_bit(BEISCSI_HBA_BOOT_FOUND, &phba->state); + } beiscsi_iface_create_default(phba); schedule_delayed_work(&phba->beiscsi_hw_check_task, diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 8ab16516ae9a..780c3fc16ec6 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -96,11 +96,6 @@ #define MAX_CMD_SZ 65536 #define IIOC_SCSI_DATA 0x05 /* Write Operation */ -#define INVALID_SESS_HANDLE 0xFFFFFFFF - -#define BE_GET_BOOT_RETRIES 45 -#define BE_GET_BOOT_TO 20 - /** * hardware needs the async PDU buffers to be posted in multiples of 8 * So have atleast 8 of them by default @@ -378,7 +373,6 @@ struct beiscsi_hba { struct ulp_cid_info *cid_array_info[BEISCSI_ULP_COUNT]; struct iscsi_endpoint **ep_array; struct beiscsi_conn **conn_table; - struct iscsi_boot_kset *boot_kset; struct Scsi_Host *shost; struct iscsi_iface *ipv4_iface; struct iscsi_iface *ipv6_iface; @@ -410,16 +404,16 @@ struct beiscsi_hba { #define BEISCSI_HBA_RUNNING 0 #define BEISCSI_HBA_LINK_UP 1 #define BEISCSI_HBA_BOOT_FOUND 2 -#define BEISCSI_HBA_PCI_ERR 3 -#define BEISCSI_HBA_FW_TIMEOUT 4 -#define BEISCSI_HBA_IN_UE 5 +#define BEISCSI_HBA_BOOT_WORK 3 +#define BEISCSI_HBA_PCI_ERR 4 +#define BEISCSI_HBA_FW_TIMEOUT 5 +#define BEISCSI_HBA_IN_UE 6 /* error bits */ #define BEISCSI_HBA_IN_ERR ((1 << BEISCSI_HBA_PCI_ERR) | \ (1 << BEISCSI_HBA_FW_TIMEOUT) | \ (1 << BEISCSI_HBA_IN_UE)) u8 optic_state; - int get_boot; struct delayed_work beiscsi_hw_check_task; bool mac_addr_set; @@ -432,7 +426,6 @@ struct beiscsi_hba { struct be_ctrl_info ctrl; unsigned int generation; unsigned int interface_handle; - struct mgmt_session_info boot_sess; struct invalidate_command_table inv_tbl[128]; struct be_aic_obj aic_obj[MAX_CPUS]; @@ -441,6 +434,22 @@ struct beiscsi_hba { struct scatterlist *sg, uint32_t num_sg, uint32_t xferlen, uint32_t writedir); + struct boot_struct { + int retry; + unsigned int tag; + unsigned int s_handle; + struct be_dma_mem nonemb_cmd; + enum { + BEISCSI_BOOT_REOPEN_SESS = 1, + BEISCSI_BOOT_GET_SHANDLE, + BEISCSI_BOOT_GET_SINFO, + BEISCSI_BOOT_LOGOUT_SESS, + BEISCSI_BOOT_CREATE_KSET, + } action; + struct mgmt_session_info boot_sess; + struct iscsi_boot_kset *boot_kset; + } boot_struct; + struct work_struct boot_work; }; #define beiscsi_hba_in_error(phba) ((phba)->state & BEISCSI_HBA_IN_ERR) @@ -1066,6 +1075,8 @@ struct hwi_context_memory { struct hwi_async_pdu_context *pasync_ctx[BEISCSI_ULP_COUNT]; }; +void beiscsi_start_boot_work(struct beiscsi_hba *phba, unsigned int s_handle); + /* Logging related definitions */ #define BEISCSI_LOG_INIT 0x0001 /* Initialization events */ #define BEISCSI_LOG_MBOX 0x0002 /* Mailbox Events */ diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 4f2194e324ae..756e7ae33e2c 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -187,120 +187,6 @@ int be_cmd_modify_eq_delay(struct beiscsi_hba *phba, } /** - * mgmt_reopen_session()- Reopen a session based on reopen_type - * @phba: Device priv structure instance - * @reopen_type: Type of reopen_session FW should do. - * @sess_handle: Session Handle of the session to be re-opened - * - * return - * the TAG used for MBOX Command - * - **/ -unsigned int mgmt_reopen_session(struct beiscsi_hba *phba, - unsigned int reopen_type, - unsigne |