diff options
Diffstat (limited to 'drivers/scsi/be2iscsi/be_mgmt.c')
| -rw-r--r-- | drivers/scsi/be2iscsi/be_mgmt.c | 1974 |
1 files changed, 1027 insertions, 947 deletions
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 245a9595a93a..4e899ec1477d 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -1,20 +1,26 @@ -/** - * Copyright (C) 2005 - 2013 Emulex - * All rights reserved. +/* + * This file is part of the Emulex Linux Device Driver for Enterprise iSCSI + * Host Bus Adapters. Refer to the README file included with this package + * for driver version and adapter compatibility. + * + * Copyright (c) 2018 Broadcom. All Rights Reserved. + * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General - * Public License is included in this distribution in the file called COPYING. + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as published + * by the Free Software Foundation. * - * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com) + * This program is distributed in the hope that it will be useful. ALL EXPRESS + * OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY + * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, + * OR NON-INFRINGEMENT, ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH + * DISCLAIMERS ARE HELD TO BE LEGALLY INVALID. + * See the GNU General Public License for more details, a copy of which + * can be found in the file COPYING included with this package. * * Contact Information: - * linux-drivers@emulex.com + * linux-drivers@broadcom.com * - * Emulex - * 3333 Susan Street - * Costa Mesa, CA 92626 */ #include <linux/bsg-lib.h> @@ -24,371 +30,13 @@ #include "be_iscsi.h" #include "be_main.h" -/* UE Status Low CSR */ -static const char * const desc_ue_status_low[] = { - "CEV", - "CTX", - "DBUF", - "ERX", - "Host", - "MPU", - "NDMA", - "PTC ", - "RDMA ", - "RXF ", - "RXIPS ", - "RXULP0 ", - "RXULP1 ", - "RXULP2 ", - "TIM ", - "TPOST ", - "TPRE ", - "TXIPS ", - "TXULP0 ", - "TXULP1 ", - "UC ", - "WDMA ", - "TXULP2 ", - "HOST1 ", - "P0_OB_LINK ", - "P1_OB_LINK ", - "HOST_GPIO ", - "MBOX ", - "AXGMAC0", - "AXGMAC1", - "JTAG", - "MPU_INTPEND" -}; - -/* UE Status High CSR */ -static const char * const desc_ue_status_hi[] = { - "LPCMEMHOST", - "MGMT_MAC", - "PCS0ONLINE", - "MPU_IRAM", - "PCS1ONLINE", - "PCTL0", - "PCTL1", - "PMEM", - "RR", - "TXPB", - "RXPP", - "XAUI", - "TXP", - "ARM", - "IPC", - "HOST2", - "HOST3", - "HOST4", - "HOST5", - "HOST6", - "HOST7", - "HOST8", - "HOST9", - "NETC", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown" -}; - -/* - * beiscsi_ue_detec()- Detect Unrecoverable Error on adapter - * @phba: Driver priv structure - * - * Read registers linked to UE and check for the UE status - **/ -void beiscsi_ue_detect(struct beiscsi_hba *phba) -{ - uint32_t ue_hi = 0, ue_lo = 0; - uint32_t ue_mask_hi = 0, ue_mask_lo = 0; - uint8_t i = 0; - - if (phba->ue_detected) - return; - - pci_read_config_dword(phba->pcidev, - PCICFG_UE_STATUS_LOW, &ue_lo); - pci_read_config_dword(phba->pcidev, - PCICFG_UE_STATUS_MASK_LOW, - &ue_mask_lo); - pci_read_config_dword(phba->pcidev, - PCICFG_UE_STATUS_HIGH, - &ue_hi); - pci_read_config_dword(phba->pcidev, - PCICFG_UE_STATUS_MASK_HI, - &ue_mask_hi); - - ue_lo = (ue_lo & ~ue_mask_lo); - ue_hi = (ue_hi & ~ue_mask_hi); - - - if (ue_lo || ue_hi) { - phba->ue_detected = true; - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, - "BG_%d : Error detected on the adapter\n"); - } - - if (ue_lo) { - for (i = 0; ue_lo; ue_lo >>= 1, i++) { - if (ue_lo & 1) - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_CONFIG, - "BG_%d : UE_LOW %s bit set\n", - desc_ue_status_low[i]); - } - } - - if (ue_hi) { - for (i = 0; ue_hi; ue_hi >>= 1, i++) { - if (ue_hi & 1) - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_CONFIG, - "BG_%d : UE_HIGH %s bit set\n", - desc_ue_status_hi[i]); - } - } -} - -/** - * 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, - unsigned int sess_handle) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct be_cmd_reopen_session_req *req; - unsigned int tag = 0; - - beiscsi_log(phba, KERN_INFO, - BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, - "BG_%d : In bescsi_get_boot_target\n"); - - spin_lock(&ctrl->mbox_lock); - tag = alloc_mcc_tag(phba); - if (!tag) { - spin_unlock(&ctrl->mbox_lock); - return tag; - } - - wrb = wrb_from_mccq(phba); - req = embedded_payload(wrb); - wrb->tag0 |= tag; - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, - OPCODE_ISCSI_INI_DRIVER_REOPEN_ALL_SESSIONS, - sizeof(struct be_cmd_reopen_session_resp)); - - /* set the reopen_type,sess_handle */ - req->reopen_type = reopen_type; - req->session_handle = sess_handle; - - be_mcc_notify(phba); - spin_unlock(&ctrl->mbox_lock); - return tag; -} - -unsigned int mgmt_get_boot_target(struct beiscsi_hba *phba) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct be_cmd_get_boot_target_req *req; - unsigned int tag = 0; - - beiscsi_log(phba, KERN_INFO, - BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, - "BG_%d : In bescsi_get_boot_target\n"); - - spin_lock(&ctrl->mbox_lock); - tag = alloc_mcc_tag(phba); - if (!tag) { - spin_unlock(&ctrl->mbox_lock); - return tag; - } - - wrb = wrb_from_mccq(phba); - req = embedded_payload(wrb); - wrb->tag0 |= tag; - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, - OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET, - sizeof(struct be_cmd_get_boot_target_resp)); - - be_mcc_notify(phba); - spin_unlock(&ctrl->mbox_lock); - return tag; -} - -unsigned int mgmt_get_session_info(struct beiscsi_hba *phba, - u32 boot_session_handle, - struct be_dma_mem *nonemb_cmd) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - unsigned int tag = 0; - struct be_cmd_get_session_req *req; - struct be_cmd_get_session_resp *resp; - struct be_sge *sge; - - beiscsi_log(phba, KERN_INFO, - BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, - "BG_%d : In beiscsi_get_session_info\n"); - - spin_lock(&ctrl->mbox_lock); - tag = alloc_mcc_tag(phba); - if (!tag) { - spin_unlock(&ctrl->mbox_lock); - return tag; - } - - nonemb_cmd->size = sizeof(*resp); - req = nonemb_cmd->va; - memset(req, 0, sizeof(*req)); - wrb = wrb_from_mccq(phba); - sge = nonembedded_sgl(wrb); - wrb->tag0 |= tag; - - - wrb->tag0 |= tag; - be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, - OPCODE_ISCSI_INI_SESSION_GET_A_SESSION, - sizeof(*resp)); - req->session_handle = boot_session_handle; - sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); - sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); - sge->len = cpu_to_le32(nonemb_cmd->size); - - be_mcc_notify(phba); - spin_unlock(&ctrl->mbox_lock); - return tag; -} - -int mgmt_get_fw_config(struct be_ctrl_info *ctrl, - struct beiscsi_hba *phba) -{ - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct be_fw_cfg *req = embedded_payload(wrb); - int status = 0; - - spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); - - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, sizeof(*req)); - status = be_mbox_notify(ctrl); - if (!status) { - struct be_fw_cfg *pfw_cfg; - pfw_cfg = req; - phba->fw_config.phys_port = pfw_cfg->phys_port; - phba->fw_config.iscsi_icd_start = - pfw_cfg->ulp[0].icd_base; - phba->fw_config.iscsi_icd_count = - pfw_cfg->ulp[0].icd_count; - phba->fw_config.iscsi_cid_start = - pfw_cfg->ulp[0].sq_base; - phba->fw_config.iscsi_cid_count = - pfw_cfg->ulp[0].sq_count; - if (phba->fw_config.iscsi_cid_count > (BE2_MAX_SESSIONS / 2)) { - beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, - "BG_%d : FW reported MAX CXNS as %d\t" - "Max Supported = %d.\n", - phba->fw_config.iscsi_cid_count, - BE2_MAX_SESSIONS); - phba->fw_config.iscsi_cid_count = BE2_MAX_SESSIONS / 2; - } - } else { - beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_INIT, - "BG_%d : Failed in mgmt_get_fw_config\n"); - } - - spin_unlock(&ctrl->mbox_lock); - return status; -} - -int mgmt_check_supported_fw(struct be_ctrl_info *ctrl, - struct beiscsi_hba *phba) -{ - struct be_dma_mem nonemb_cmd; - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct be_mgmt_controller_attributes *req; - struct be_sge *sge = nonembedded_sgl(wrb); - int status = 0; - - nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev, - sizeof(struct be_mgmt_controller_attributes), - &nonemb_cmd.dma); - if (nonemb_cmd.va == NULL) { - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BG_%d : Failed to allocate memory for " - "mgmt_check_supported_fw\n"); - return -ENOMEM; - } - nonemb_cmd.size = sizeof(struct be_mgmt_controller_attributes); - req = nonemb_cmd.va; - memset(req, 0, sizeof(*req)); - spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); - be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_GET_CNTL_ATTRIBUTES, sizeof(*req)); - sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma)); - sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF); - sge->len = cpu_to_le32(nonemb_cmd.size); - status = be_mbox_notify(ctrl); - if (!status) { - struct be_mgmt_controller_attributes_resp *resp = nonemb_cmd.va; - beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, - "BG_%d : Firmware Version of CMD : %s\n" - "Firmware Version is : %s\n" - "Developer Build, not performing version check...\n", - resp->params.hba_attribs - .flashrom_version_string, - resp->params.hba_attribs. - firmware_version_string); - - phba->fw_config.iscsi_features = - resp->params.hba_attribs.iscsi_features; - beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, - "BM_%d : phba->fw_config.iscsi_features = %d\n", - phba->fw_config.iscsi_features); - memcpy(phba->fw_ver_str, resp->params.hba_attribs. - firmware_version_string, BEISCSI_VER_STRLEN); - } else - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BG_%d : Failed in mgmt_check_supported_fw\n"); - spin_unlock(&ctrl->mbox_lock); - if (nonemb_cmd.va) - pci_free_consistent(ctrl->pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - - return status; -} - unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba, struct bsg_job *job, struct be_dma_mem *nonemb_cmd) { - struct be_cmd_resp_hdr *resp; - struct be_mcc_wrb *wrb = wrb_from_mccq(phba); - struct be_sge *mcc_sge = nonembedded_sgl(wrb); + struct be_mcc_wrb *wrb; + struct be_sge *mcc_sge; unsigned int tag = 0; struct iscsi_bsg_request *bsg_req = job->request; struct be_bsg_vendor_cmd *req = nonemb_cmd->va; @@ -396,7 +44,6 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, nonemb_cmd->size = job->request_payload.payload_len; memset(nonemb_cmd->va, 0, nonemb_cmd->size); - resp = nonemb_cmd->va; region = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; sector_size = bsg_req->rqst_data.h_vendor.vendor_cmd[2]; sector = bsg_req->rqst_data.h_vendor.vendor_cmd[3]; @@ -404,9 +51,9 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, req->region = region; req->sector = sector; req->offset = offset; - spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); + if (mutex_lock_interruptible(&ctrl->mbox_lock)) + return 0; switch (bsg_req->rqst_data.h_vendor.vendor_cmd[0]) { case BEISCSI_WRITE_FLASH: offset = sector * sector_size + offset; @@ -425,166 +72,40 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, "BG_%d : Unsupported cmd = 0x%x\n\n", bsg_req->rqst_data.h_vendor.vendor_cmd[0]); - spin_unlock(&ctrl->mbox_lock); - return -ENOSYS; + mutex_unlock(&ctrl->mbox_lock); + return -EPERM; } - tag = alloc_mcc_tag(phba); - if (!tag) { - spin_unlock(&ctrl->mbox_lock); - return tag; + wrb = alloc_mcc_wrb(phba, &tag); + if (!wrb) { + mutex_unlock(&ctrl->mbox_lock); + return 0; } + mcc_sge = nonembedded_sgl(wrb); be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, job->request_payload.sg_cnt); mcc_sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); mcc_sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); mcc_sge->len = cpu_to_le32(nonemb_cmd->size); - wrb->tag0 |= tag; - be_mcc_notify(phba); + be_mcc_notify(phba, tag); - spin_unlock(&ctrl->mbox_lock); - return tag; -} - -int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mccq(phba); - struct iscsi_cleanup_req *req = embedded_payload(wrb); - int status = 0; - - spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); - - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, - OPCODE_COMMON_ISCSI_CLEANUP, sizeof(*req)); - - req->chute = chute; - req->hdr_ring_id = cpu_to_le16(HWI_GET_DEF_HDRQ_ID(phba)); - req->data_ring_id = cpu_to_le16(HWI_GET_DEF_BUFQ_ID(phba)); - - status = be_mcc_notify_wait(phba); - if (status) - beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_INIT, - "BG_%d : mgmt_epfw_cleanup , FAILED\n"); - spin_unlock(&ctrl->mbox_lock); - return status; -} - -unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, - struct invalidate_command_table *inv_tbl, - unsigned int num_invalidate, unsigned int cid, - struct be_dma_mem *nonemb_cmd) - -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct be_sge *sge; - struct invalidate_commands_params_in *req; - unsigned int i, tag = 0; - - spin_lock(&ctrl->mbox_lock); - tag = alloc_mcc_tag(phba); - if (!tag) { - spin_unlock(&ctrl->mbox_lock); - return tag; - } - - req = nonemb_cmd->va; - memset(req, 0, sizeof(*req)); - wrb = wrb_from_mccq(phba); - sge = nonembedded_sgl(wrb); - wrb->tag0 |= tag; - - be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, - OPCODE_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS, - sizeof(*req)); - req->ref_handle = 0; - req->cleanup_type = CMD_ISCSI_COMMAND_INVALIDATE; - for (i = 0; i < num_invalidate; i++) { - req->table[i].icd = inv_tbl->icd; - req->table[i].cid = inv_tbl->cid; - req->icd_count++; - inv_tbl++; - } - sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); - sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); - sge->len = cpu_to_le32(nonemb_cmd->size); - - be_mcc_notify(phba); - spin_unlock(&ctrl->mbox_lock); - return tag; -} - -unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba, - struct beiscsi_endpoint *beiscsi_ep, - unsigned short cid, - unsigned short issue_reset, - unsigned short savecfg_flag) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct iscsi_invalidate_connection_params_in *req; - unsigned int tag = 0; - - spin_lock(&ctrl->mbox_lock); - tag = alloc_mcc_tag(phba); - if (!tag) { - spin_unlock(&ctrl->mbox_lock); - return tag; - } - wrb = wrb_from_mccq(phba); - wrb->tag0 |= tag; - req = embedded_payload(wrb); - - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, - OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION, - sizeof(*req)); - req->session_handle = beiscsi_ep->fw_handle; - req->cid = cid; - if (issue_reset) - req->cleanup_type = CMD_ISCSI_CONNECTION_ISSUE_TCP_RST; - else - req->cleanup_type = CMD_ISCSI_CONNECTION_INVALIDATE; - req->save_cfg = savecfg_flag; - be_mcc_notify(phba); - spin_unlock(&ctrl->mbox_lock); - return tag; -} - -unsigned int mgmt_upload_connection(struct beiscsi_hba *phba, - unsigned short cid, unsigned int upload_flag) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct tcp_upload_params_in *req; - unsigned int tag = 0; - - spin_lock(&ctrl->mbox_lock); - tag = alloc_mcc_tag(phba); - if (!tag) { - spin_unlock(&ctrl->mbox_lock); - return tag; - } - wrb = wrb_from_mccq(phba); - req = embedded_payload(wrb); - wrb->tag0 |= tag; - - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_COMMON_TCP_UPLOAD, - OPCODE_COMMON_TCP_UPLOAD, sizeof(*req)); - req->id = (unsigned short)cid; - req->upload_type = (unsigned char)upload_flag; - be_mcc_notify(phba); - spin_unlock(&ctrl->mbox_lock); + mutex_unlock(&ctrl->mbox_lock); return tag; } +/** + * mgmt_open_connection()- Establish a TCP CXN + * @phba: driver priv structure + * @dst_addr: Destination Address + * @beiscsi_ep: ptr to device endpoint struct + * @nonemb_cmd: ptr to memory allocated for command + * + * return + * Success: Tag number of the MBX Command issued + * Failure: Error code + **/ int mgmt_open_connection(struct beiscsi_hba *phba, struct sockaddr *dst_addr, struct beiscsi_endpoint *beiscsi_ep, @@ -596,44 +117,52 @@ int mgmt_open_connection(struct beiscsi_hba *phba, struct sockaddr_in6 *daddr_in6 = (struct sockaddr_in6 *)dst_addr; struct be_ctrl_info *ctrl = &phba->ctrl; struct be_mcc_wrb *wrb; - struct tcp_connect_and_offload_in *req; + struct tcp_connect_and_offload_in_v1 *req; unsigned short def_hdr_id; unsigned short def_data_id; struct phys_addr template_address = { 0, 0 }; struct phys_addr *ptemplate_address; unsigned int tag = 0; - unsigned int i; + unsigned int i, ulp_num; unsigned short cid = beiscsi_ep->ep_cid; struct be_sge *sge; + if (dst_addr->sa_family != PF_INET && dst_addr->sa_family != PF_INET6) { + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, + "BG_%d : unknown addr family %d\n", + dst_addr->sa_family); + return 0; + } + phwi_ctrlr = phba->phwi_ctrlr; phwi_context = phwi_ctrlr->phwi_ctxt; - def_hdr_id = (unsigned short)HWI_GET_DEF_HDRQ_ID(phba); - def_data_id = (unsigned short)HWI_GET_DEF_BUFQ_ID(phba); + + ulp_num = phwi_ctrlr->wrb_context[BE_GET_CRI_FROM_CID(cid)].ulp_num; + + def_hdr_id = (unsigned short)HWI_GET_DEF_HDRQ_ID(phba, ulp_num); + def_data_id = (unsigned short)HWI_GET_DEF_BUFQ_ID(phba, ulp_num); ptemplate_address = &template_address; ISCSI_GET_PDU_TEMPLATE_ADDRESS(phba, ptemplate_address); - spin_lock(&ctrl->mbox_lock); - tag = alloc_mcc_tag(phba); - if (!tag) { - spin_unlock(&ctrl->mbox_lock); - return tag; + if (mutex_lock_interruptible(&ctrl->mbox_lock)) + return 0; + wrb = alloc_mcc_wrb(phba, &tag); + if (!wrb) { + mutex_unlock(&ctrl->mbox_lock); + return 0; } - wrb = wrb_from_mccq(phba); - memset(wrb, 0, sizeof(*wrb)); - sge = nonembedded_sgl(wrb); + sge = nonembedded_sgl(wrb); req = nonemb_cmd->va; memset(req, 0, sizeof(*req)); - wrb->tag0 |= tag; - be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); + be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, OPCODE_COMMON_ISCSI_TCP_CONNECT_AND_OFFLOAD, - sizeof(*req)); + nonemb_cmd->size); if (dst_addr->sa_family == PF_INET) { __be32 s_addr = daddr_in->sin_addr.s_addr; - req->ip_address.ip_type = BE2_IPV4; + req->ip_address.ip_type = BEISCSI_IP_TYPE_V4; req->ip_address.addr[0] = s_addr & 0x000000ff; req->ip_address.addr[1] = (s_addr & 0x0000ff00) >> 8; req->ip_address.addr[2] = (s_addr & 0x00ff0000) >> 16; @@ -641,24 +170,17 @@ int mgmt_open_connection(struct beiscsi_hba *phba, req->tcp_port = ntohs(daddr_in->sin_port); beiscsi_ep->dst_addr = daddr_in->sin_addr.s_addr; beiscsi_ep->dst_tcpport = ntohs(daddr_in->sin_port); - beiscsi_ep->ip_type = BE2_IPV4; - } else if (dst_addr->sa_family == PF_INET6) { - req->ip_address.ip_type = BE2_IPV6; + beiscsi_ep->ip_type = BEISCSI_IP_TYPE_V4; + } else { + /* else its PF_INET6 family */ + req->ip_address.ip_type = BEISCSI_IP_TYPE_V6; memcpy(&req->ip_address.addr, &daddr_in6->sin6_addr.in6_u.u6_addr8, 16); req->tcp_port = ntohs(daddr_in6->sin6_port); beiscsi_ep->dst_tcpport = ntohs(daddr_in6->sin6_port); memcpy(&beiscsi_ep->dst6_addr, &daddr_in6->sin6_addr.in6_u.u6_addr8, 16); - beiscsi_ep->ip_type = BE2_IPV6; - } else{ - beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, - "BG_%d : unknown addr family %d\n", - dst_addr->sa_family); - spin_unlock(&ctrl->mbox_lock); - free_mcc_tag(&phba->ctrl, tag); - return -EINVAL; - + beiscsi_ep->ip_type = BEISCSI_IP_TYPE_V6; } req->cid = cid; i = phba->nxt_cqid++; @@ -676,322 +198,281 @@ int mgmt_open_connection(struct beiscsi_hba *phba, sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); sge->len = cpu_to_le32(nonemb_cmd->size); - be_mcc_notify(phba); - spin_unlock(&ctrl->mbox_lock); - return tag; -} -unsigned int mgmt_get_all_if_id(struct beiscsi_hba *phba) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct be_cmd_get_all_if_id_req *req = embedded_payload(wrb); - struct be_cmd_get_all_if_id_req *pbe_allid = req; - int status = 0; - - memset(wrb, 0, sizeof(*wrb)); - - spin_lock(&ctrl->mbox_lock); - - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, - OPCODE_COMMON_ISCSI_NTWK_GET_ALL_IF_ID, - sizeof(*req)); - status = be_mbox_notify(ctrl); - if (!status) - phba->interface_handle = pbe_allid->if_hndl_list[0]; - else { - beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, - "BG_%d : Failed in mgmt_get_all_if_id\n"); + if (!is_chip_be2_be3r(phba)) { + req->hdr.version = MBX_CMD_VER1; + req->tcp_window_size = 0x8000; + req->tcp_window_scale_count = 2; } - spin_unlock(&ctrl->mbox_lock); - return status; + be_mcc_notify(phba, tag); + mutex_unlock(&ctrl->mbox_lock); + return tag; } -/* - * mgmt_exec_nonemb_cmd()- Execute Non Embedded MBX Cmd - * @phba: Driver priv structure - * @nonemb_cmd: Address of the MBX command issued - * @resp_buf: Buffer to copy the MBX cmd response - * @resp_buf_len: respone lenght to be copied +/** + * beiscsi_exec_nemb_cmd()- execute non-embedded MBX cmd + * @phba: driver priv structure + * @nonemb_cmd: DMA address of the MBX command to be issued + * @cbfn: callback func on MCC completion + * @resp_buf: buffer to copy the MBX cmd response + * @resp_buf_len: response length to be copied * **/ -static int mgmt_exec_nonemb_cmd(struct beiscsi_hba *phba, - struct be_dma_mem *nonemb_cmd, void *resp_buf, - int resp_buf_len) +static int beiscsi_exec_nemb_cmd(struct beiscsi_hba *phba, + struct be_dma_mem *nonemb_cmd, + void (*cbfn)(struct beiscsi_hba *, + unsigned int), + void *resp_buf, u32 resp_buf_len) { struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mccq(phba); + struct be_mcc_wrb *wrb; struct be_sge *sge; unsigned int tag; int rc = 0; - spin_lock(&ctrl->mbox_lock); - tag = alloc_mcc_tag(phba); - if (!tag) { - spin_unlock(&ctrl->mbox_lock); - rc = -ENOMEM; - goto free_cmd; + mutex_lock(&ctrl->mbox_lock); + wrb = alloc_mcc_wrb(phba, &tag); + if (!wrb) { + mutex_unlock(&ctrl->mbox_lock); + return -ENOMEM; } - memset(wrb, 0, sizeof(*wrb)); - wrb->tag0 |= tag; - sge = nonembedded_sgl(wrb); + sge = nonembedded_sgl(wrb); be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1); sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); sge->pa_lo = cpu_to_le32(lower_32_bits(nonemb_cmd->dma)); sge->len = cpu_to_le32(nonemb_cmd->size); - be_mcc_notify(phba); - spin_unlock(&ctrl->mbox_lock); + if (cbfn) { + struct be_dma_mem *tag_mem; - rc = beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd->va); - if (rc) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, - "BG_%d : mgmt_exec_nonemb_cmd Failed status\n"); + set_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state); + ctrl->ptag_state[tag].cbfn = cbfn; + tag_mem = &phba->ctrl.ptag_state[tag].tag_mem_state; - rc = -EIO; - goto free_cmd; + /* store DMA mem to be freed in callback */ + tag_mem->size = nonemb_cmd->size; + tag_mem->va = nonemb_cmd->va; + tag_mem->dma = nonemb_cmd->dma; } + be_mcc_notify(phba, tag); + mutex_unlock(&ctrl->mbox_lock); + + /* with cbfn set, its async cmd, don't wait */ + if (cbfn) + return 0; + rc = beiscsi_mccq_compl_wait(phba, tag, NULL, nonemb_cmd); + + /* copy the response, if any */ if (resp_buf) memcpy(resp_buf, nonemb_cmd->va, resp_buf_len); - -free_cmd: - pci_free_consistent(ctrl->pdev, nonemb_cmd->size, - nonemb_cmd->va, nonemb_cmd->dma); return rc; } -static int mgmt_alloc_cmd_data(struct beiscsi_hba *phba, struct be_dma_mem *cmd, - int iscsi_cmd, int size) +static int beiscsi_prep_nemb_cmd(struct beiscsi_hba *phba, + struct be_dma_mem *cmd, + u8 subsystem, u8 opcode, u32 size) { - cmd->va = pci_alloc_consistent(phba->ctrl.pdev, size, &cmd->dma); + cmd->va = dma_alloc_coherent(&phba->ctrl.pdev->dev, size, &cmd->dma, + GFP_KERNEL); if (!cmd->va) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BG_%d : Failed to allocate memory for if info\n"); return -ENOMEM; } - memset(cmd->va, 0, size); cmd->size = size; - be_cmd_hdr_prepare(cmd->va, CMD_SUBSYSTEM_ISCSI, iscsi_cmd, size); + be_cmd_hdr_prepare(cmd->va, subsystem, opcode, size); + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, + "BG_%d : subsystem %u cmd %u size %u\n", + subsystem, opcode, size); return 0; } -static int -mgmt_static_ip_modify(struct beiscsi_hba *phba, - struct be_cmd_get_if_info_resp *if_info, - struct iscsi_iface_param_info *ip_param, - struct iscsi_iface_param_info *subnet_param, - uint32_t ip_action) +static void beiscsi_free_nemb_cmd(struct beiscsi_hba *phba, + struct be_dma_mem *cmd, int rc) { - struct be_cmd_set_ip_addr_req *req; - struct be_dma_mem nonemb_cmd; - uint32_t ip_type; - int rc; - - rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, - OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR, - sizeof(*req)); - if (rc) - return rc; - - ip_type = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ? - BE2_IPV6 : BE2_IPV4 ; - - req = nonemb_cmd.va; - req->ip_params.record_entry_count = 1; - req->ip_params.ip_record.action = ip_action; - req->ip_params.ip_record.interface_hndl = - phba->interface_handle; - req->ip_params.ip_record.ip_addr.size_of_structure = - sizeof(struct be_ip_addr_subnet_format); - req->ip_params.ip_record.ip_addr.ip_type = ip_type; - - if (ip_action == IP_ACTION_ADD) { - memcpy(req->ip_params.ip_record.ip_addr.addr, ip_param->value, - ip_param->len); + /* + * If FW is busy the DMA buffer is saved with the tag. When the cmd + * completes this buffer is freed. + */ + if (rc == -EBUSY) + return; - if (subnet_param) - memcpy(req->ip_params.ip_record.ip_addr.subnet_mask, - subnet_param->value, subnet_param->len); - } else { - memcpy(req->ip_params.ip_record.ip_addr.addr, - if_info->ip_addr.addr, ip_param->len); + dma_free_coherent(&phba->ctrl.pdev->dev, cmd->size, cmd->va, cmd->dma); +} - memcpy(req->ip_params.ip_record.ip_addr.subnet_mask, - if_info->ip_addr.subnet_mask, ip_param->len); +static void __beiscsi_eq_delay_compl(struct beiscsi_hba *phba, unsigned int tag) +{ + struct be_dma_mem *tag_mem; + + /* status is ignored */ + __beiscsi_mcc_compl_status(phba, tag, NULL, NULL); + tag_mem = &phba->ctrl.ptag_state[tag].tag_mem_state; + if (tag_mem->size) { + dma_free_coherent(&phba->pcidev->dev, tag_mem->size, + tag_mem->va, tag_mem->dma); + tag_mem->size = 0; } - - rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); - if (rc < 0) - beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, - "BG_%d : Failed to Modify existing IP Address\n"); - return rc; } -static int mgmt_modify_gateway(struct beiscsi_hba *phba, uint8_t *gt_addr, - uint32_t gtway_action, uint32_t param_len) +int beiscsi_modify_eq_delay(struct beiscsi_hba *phba, + struct be_set_eqd *set_eqd, int num) { - struct be_cmd_set_def_gateway_req *req; + struct be_cmd_req_modify_eq_delay *req; struct be_dma_mem nonemb_cmd; - int rt_val; + int i, rc; - - rt_val = mgmt_alloc_cmd_data(phba, &nonemb_cmd, - OPCODE_COMMON_ISCSI_NTWK_MODIFY_DEFAULT_GATEWAY, - sizeof(*req)); - if (rt_val) - return rt_val; + rc = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_MODIFY_EQ_DELAY, sizeof(*req)); + if (rc) + return rc; req = nonemb_cmd.va; - req->action = gtway_action; - req->ip_addr.ip_type = BE2_IPV4; - - memcpy(req->ip_addr.addr, gt_addr, param_len); + req->num_eq = cpu_to_le32(num); + for (i = 0; i < num; i++) { + req->delay[i].eq_id = cpu_to_le32(set_eqd[i].eq_id); + req->delay[i].phase = 0; + req->delay[i].delay_multiplier = + cpu_to_le32(set_eqd[i].delay_multiplier); + } - return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); + rc = beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, __beiscsi_eq_delay_compl, + NULL, 0); + if (rc) { + /* + * Only free on failure. Async cmds are handled like -EBUSY + * where it's handled for us. + */ + beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc); + } + return rc; } -int mgmt_set_ip(struct beiscsi_hba *phba, - struct iscsi_iface_param_info *ip_param, - struct iscsi_iface_param_info *subnet_param, - uint32_t boot_proto) +/** + * beiscsi_get_initiator_name - read initiator name from flash + * @phba: device priv structure + * @name: buffer pointer + * @cfg: fetch user configured + * + */ +int beiscsi_get_initiator_name(struct beiscsi_hba *phba, char *name, bool cfg) { - struct be_cmd_get_def_gateway_resp gtway_addr_set; - struct be_cmd_get_if_info_resp if_info; - struct be_cmd_set_dhcp_req *dhcpreq; - struct be_cmd_rel_dhcp_req *reldhcp; struct be_dma_mem nonemb_cmd; - uint8_t *gtway_addr; - uint32_t ip_type; + struct be_cmd_hba_name resp; + struct be_cmd_hba_name *req; int rc; - if (mgmt_get_all_if_id(phba)) - return -EIO; - - memset(&if_info, 0, sizeof(if_info)); - ip_type = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ? - BE2_IPV6 : BE2_IPV4 ; - - rc = mgmt_get_if_info(phba, ip_type, &if_info); + rc = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd, CMD_SUBSYSTEM_ISCSI_INI, + OPCODE_ISCSI_INI_CFG_GET_HBA_NAME, sizeof(resp)); if (rc) return rc; - if (boot_proto == ISCSI_BOOTPROTO_DHCP) { - if (if_info.dhcp_state) { - beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, - "BG_%d : DHCP Already Enabled\n"); - return 0; - } - /* The ip_param->len is 1 in DHCP case. Setting - proper IP len as this it is used while - freeing the Static IP. - */ - ip_param->len = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ? - IP_V6_LEN : IP_V4_LEN; - - } else { - if (if_info.dhcp_state) { - - memset(&if_info, 0, sizeof(if_info)); - rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, - OPCODE_COMMON_ISCSI_NTWK_REL_STATELESS_IP_ADDR, - sizeof(*reldhcp)); - - if (rc) - return rc; + req = nonemb_cmd.va; + if (cfg) + req->hdr.version = 1; + rc = beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, NULL, + &resp, sizeof(resp)); + beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc); + if (rc) { + beiscsi_log(phba, KERN_ERR, + BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, + "BS_%d : Initiator Name MBX Failed\n"); + return rc; + } + rc = sprintf(name, "%s\n", resp.initiator_name); + return rc; +} - reldhcp = nonemb_cmd.va; - reldhcp->interface_hndl = phba->interface_handle; - reldhcp->ip_type = ip_type; +unsigned int beiscsi_if_get_handle(struct beiscsi_hba *phba) +{ + struct be_ctrl_info *ctrl = &phba->ctrl; + struct be_mcc_wrb *wrb; + struct be_cmd_get_all_if_id_req *req; + struct be_cmd_get_all_if_id_req *pbe_allid; + unsigned int tag; + int status = 0; - rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); - if (rc < 0) { - beiscsi_log(phba, KERN_WARNING, - BEISCSI_LOG_CONFIG, - "BG_%d : Failed to Delete existing dhcp\n"); - return rc; - } - } + if (mutex_lock_interruptible(&ctrl->mbox_lock)) + return -EINTR; + wrb = alloc_mcc_wrb(phba, &tag); + if (!wrb) { + mutex_unlock(&ctrl->mbox_lock); + return -ENOMEM; } - /* Delete the Static IP Set */ - if (if_info.ip_addr.addr[0]) { - rc = mgmt_static_ip_modify(phba, &if_info, ip_param, NULL, - IP_ACTION_DEL); - if (rc) - return rc; + req = embedded_payload(wrb); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_ISCSI_NTWK_GET_ALL_IF_ID, + sizeof(*req)); + be_mcc_notify(phba, tag); + mutex_unlock(&ctrl->mbox_lock); + + status = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL); + if (status) { + beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, + "BG_%d : %s failed: %d\n", __func__, status); + return -EBUSY; } - /* Delete the Gateway settings if mode change is to DHCP */ - if (boot_proto == ISCSI_BOOTPROTO_DHCP) { - memset(>way_addr_set, 0, sizeof(gtway_addr_set)); - rc = mgmt_get_gateway(phba, BE2_IPV4, >way_addr_set); - if (rc) { - beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, - "BG_%d : Failed to Get Gateway Addr\n"); - return rc; - } + pbe_allid = embedded_payload(wrb); + /* we now support only one interface per function */ + phba->interface_handle = pbe_allid->if_hndl_list[0]; - if (gtway_addr_set.ip_addr.addr[0]) { - gtway_addr = (uint8_t *)>way_addr_set.ip_addr.addr; - rc = mgmt_modify_gateway(phba, gtway_addr, - IP_ACTION_DEL, IP_V4_LEN); + return status; +} - if (rc) { - beiscsi_log(phba, KERN_WARNING, - BEISCSI_LOG_CONFIG, - "BG_%d : Failed to clear Gateway Addr Set\n"); - return rc; - } - } - } +static inline bool beiscsi_if_zero_ip(u8 *ip, u32 ip_type) +{ + u32 len; - /* Set Adapter to DHCP/Static Mode */ - if (boot_proto == ISCSI_BOOTPROTO_DHCP) { - rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, - OPCODE_COMMON_ISCSI_NTWK_CONFIG_STATELESS_IP_ADDR, - sizeof(*dhcpreq)); - if (rc) - return rc; + len = (ip_type < BEISCSI_IP_TYPE_V6) ? IP_V4_LEN : IP_V6_LEN; + while (len && !ip[len - 1]) + len--; + return (len == 0); +} - dhcpreq = nonemb_cmd.va; - dhcpreq->flags = BLOCKING; - dhcpreq->retry_count = 1; - dhcpreq->interface_hndl = phba->interface_handle; - dhcpreq->ip_type = BE2_DHCP_V4; +static int beiscsi_if_mod_gw(struct beiscsi_hba *phba, + u32 action, u32 ip_type, u8 *gw) +{ + struct be_cmd_set_def_gateway_req *req; + struct be_dma_mem nonemb_cmd; + int rt_val; - return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); - } else { - return mgmt_static_ip_modify(phba, &if_info, ip_param, - subnet_param, IP_ACTION_ADD); - } + rt_val = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd, CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_ISCSI_NTWK_MODIFY_DEFAULT_GATEWAY, + sizeof(*req)); + if (rt_val) + return rt_val; - return rc; + req = nonemb_cmd.va; + req->action = action; + req->ip_addr.ip_type = ip_type; + memcpy(req->ip_addr.addr, gw, + (ip_type < BEISCSI_IP_TYPE_V6) ? IP_V4_LEN : IP_V6_LEN); + rt_val = beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, NULL, NULL, 0); + beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rt_val); + return rt_val; } -int mgmt_set_gateway(struct beiscsi_hba *phba, - struct iscsi_iface_param_info *gateway_param) +int beiscsi_if_set_gw(struct beiscsi_hba *phba, u32 ip_type, u8 *gw) { - struct be_cmd_get_def_gateway_resp gtway_addr_set; - uint8_t *gtway_addr; + struct be_cmd_get_def_gateway_resp gw_resp; int rt_val; - memset(>way_addr_set, 0, sizeof(gtway_addr_set)); - rt_val = mgmt_get_gateway(phba, BE2_IPV4, >way_addr_set); + memset(&gw_resp, 0, sizeof(gw_resp)); + rt_val = beiscsi_if_get_gw(phba, ip_type, &gw_resp); if (rt_val) { beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, "BG_%d : Failed to Get Gateway Addr\n"); return rt_val; } - if (gtway_addr_set.ip_addr.addr[0]) { - gtway_addr = (uint8_t *)>way_addr_set.ip_addr.addr; - rt_val = mgmt_modify_gateway(phba, gtway_addr, IP_ACTION_DEL, - gateway_param->len); + if (!beiscsi_if_zero_ip(gw_resp.ip_addr.addr, ip_type)) { + rt_val = beiscsi_if_mod_gw(phba, IP_ACTION_DEL, ip_type, + gw_resp.ip_addr.addr); if (rt_val) { beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, "BG_%d : Failed to clear Gateway Addr Set\n"); @@ -999,10 +480,7 @@ int mgmt_set_gateway(struct beiscsi_hba *phba, } } - gtway_addr = (uint8_t *)&gateway_param->value; - rt_val = mgmt_modify_gateway(phba, gtway_addr, IP_ACTION_ADD, - gateway_param->len); - + rt_val = beiscsi_if_mod_gw(phba, IP_ACTION_ADD, ip_type, gw); if (rt_val) beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, "BG_%d : Failed to Set Gateway Addr\n"); @@ -1010,48 +488,315 @@ int mgmt_set_gateway(struct beiscsi_hba *phba, return rt_val; } -int mgmt_get_gateway(struct beiscsi_hba *phba, int ip_type, - struct be_cmd_get_def_gateway_resp *gateway) +int beiscsi_if_get_gw(struct beiscsi_hba *phba, u32 ip_type, + struct be_cmd_get_def_gateway_resp *resp) { struct be_cmd_get_def_gateway_req *req; struct be_dma_mem nonemb_cmd; int rc; - rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, - OPCODE_COMMON_ISCSI_NTWK_GET_DEFAULT_GATEWAY, - sizeof(*gateway)); + rc = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd, CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_ISCSI_NTWK_GET_DEFAULT_GATEWAY, + sizeof(*resp)); if (rc) return rc; req = nonemb_cmd.va; req->ip_type = ip_type; - return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, gateway, - sizeof(*gateway)); + rc = beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, NULL, resp, + sizeof(*resp)); + beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc); + return rc; } -int mgmt_get_if_info(struct beiscsi_hba *phba, int ip_type, - struct be_cmd_get_if_info_resp *if_info) +static int +beiscsi_if_clr_ip(struct beiscsi_hba *phba, + struct be_cmd_get_if_info_resp *if_info) { - struct be_cmd_get_if_info_req *req; + struct be_cmd_set_ip_addr_req *req; struct be_dma_mem nonemb_cmd; int rc; - if (mgmt_get_all_if_id(phba)) - return -EIO; + rc = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd, CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR, + sizeof(*req)); + if (rc) + return rc; + + req = nonemb_cmd.va; + req->ip_params.record_entry_count = 1; + req->ip_params.ip_record.action = IP_ACTION_DEL; + req->ip_params.ip_record.interface_hndl = + phba->interface_handle; + req->ip_params.ip_record.ip_addr.size_of_structure = + sizeof(struct be_ip_addr_subnet_format); + req->ip_params.ip_record.ip_addr.ip_type = if_info->ip_addr.ip_type; + memcpy(req->ip_params.ip_record.ip_addr.addr, + if_info->ip_addr.addr, + sizeof(if_info->ip_addr.addr)); + memcpy(req->ip_params.ip_record.ip_addr.subnet_mask, + if_info->ip_addr.subnet_mask, + sizeof(if_info->ip_addr.subnet_mask)); + rc = beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, NULL, NULL, 0); + if (rc < 0 || req->ip_params.ip_record.status) { + beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, + "BG_%d : failed to clear IP: rc %d status %d\n", + rc, req->ip_params.ip_record.status); + } + beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc); + return rc; +} - rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, - OPCODE_COMMON_ISCSI_NTWK_GET_IF_INFO, - sizeof(*if_info)); +static int +beiscsi_if_set_ip(struct beiscsi_hba *phba, u8 *ip, + u8 *subnet, u32 ip_type) +{ + struct be_cmd_set_ip_addr_req *req; + struct be_dma_mem nonemb_cmd; + uint32_t ip_len; + int rc; + + rc = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd, CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR, + sizeof(*req)); if (rc) return rc; req = nonemb_cmd.va; - req->interface_hndl = phba->interface_handle; - req->ip_type = ip_type; + req->ip_params.record_entry_count = 1; + req->ip_params.ip_record.action = IP_ACTION_ADD; + req->ip_params.ip_record.interface_hndl = + phba->interface_handle; + req->ip_params.ip_record.ip_addr.size_of_structure = + sizeof(struct be_ip_addr_subnet_format); + req->ip_params.ip_record.ip_addr.ip_type = ip_type; + ip_len = (ip_type < BEISCSI_IP_TYPE_V6) ? IP_V4_LEN : IP_V6_LEN; + memcpy(req->ip_params.ip_record.ip_addr.addr, ip, ip_len); + if (subnet) + memcpy(req->ip_params.ip_record.ip_addr.subnet_mask, + subnet, ip_len); + + rc = beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, NULL, NULL, 0); + /** + * In some cases, host needs to look into individual record status + * even though FW reported success for that IOCTL. + */ + if (rc < 0 || req->ip_params.ip_record.status) { + __beiscsi_log(phba, KERN_ERR, + "BG_%d : failed to set IP: rc %d status %d\n", + rc, req->ip_params.ip_record.status); + if (req->ip_params.ip_record.status) + rc = -EINVAL; + } + beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc); + return rc; +} + +int beiscsi_if_en_static(struct beiscsi_hba *phba, u32 ip_type, + u8 *ip, u8 *subnet) +{ + struct be_cmd_get_if_info_resp *if_info; + struct be_cmd_rel_dhcp_req *reldhcp; + struct be_dma_mem nonemb_cmd; + int rc; + + rc = beiscsi_if_get_info(phba, ip_type, &if_info); + if (rc) + return rc; + + if (if_info->dhcp_state) { + rc = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd, + CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_ISCSI_NTWK_REL_STATELESS_IP_ADDR, + sizeof(*reldhcp)); + if (rc) + goto exit; + + reldhcp = nonemb_cmd.va; + reldhcp->interface_hndl = phba->interface_handle; + reldhcp->ip_type = ip_type; + rc = beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, NULL, NULL, 0); + beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc); + if (rc < 0) { + beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, + "BG_%d : failed to release existing DHCP: %d\n", + rc); + goto exit; + } + } + + /* first delete any IP set */ + if (!beiscsi_if_zero_ip(if_info->ip_addr.addr, ip_type)) { + rc = beiscsi_if_clr_ip(phba, if_info); + if (rc) + goto exit; + } - return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, if_info, - sizeof(*if_info)); + /* if ip == NULL then this is called just to release DHCP IP */ + if (ip) + rc = beiscsi_if_set_ip(phba, ip, subnet, ip_type); +exit: + kfree(if_info); + return rc; +} + +int beiscsi_if_en_dhcp(struct beiscsi_hba *phba, u32 ip_type) +{ + struct be_cmd_get_def_gateway_resp gw_resp; + struct be_cmd_get_if_info_resp *if_info; + struct be_cmd_set_dhcp_req *dhcpreq; + struct be_dma_mem nonemb_cmd; + u8 *gw; + int rc; + + rc = beiscsi_if_get_info(phba, ip_type, &if_info); + if (rc) + return rc; + + if (if_info->dhcp_state) { + beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, + "BG_%d : DHCP Already Enabled\n"); + goto exit; + } + + /* first delete any IP set */ + if (!beiscsi_if_zero_ip(if_info->ip_addr.addr, ip_type)) { + rc = beiscsi_if_clr_ip(phba, if_info); + if (rc) + goto exit; + } + + /* delete gateway settings if mode change is to DHCP */ + memset(&gw_resp, 0, sizeof(gw_resp)); + /* use ip_type provided in if_info */ + rc = beiscsi_if_get_gw(phba, if_info->ip_addr.ip_type, &gw_resp); + if (rc) { + beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, + "BG_%d : Failed to Get Gateway Addr\n"); + goto exit; + } + gw = (u8 *)&gw_resp.ip_addr.addr; + if (!beiscsi_if_zero_ip(gw, if_info->ip_addr.ip_type)) { + rc = beiscsi_if_mod_gw(phba, IP_ACTION_DEL, + if_info->ip_addr.ip_type, gw); + if (rc) { + beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, + "BG_%d : Failed to clear Gateway Addr Set\n"); + goto exit; + } + } + + rc = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd, CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_ISCSI_NTWK_CONFIG_STATELESS_IP_ADDR, + sizeof(*dhcpreq)); + if (rc) + goto exit; + + dhcpreq = nonemb_cmd.va; + dhcpreq->flags = 1; /* 1 - blocking; 0 - non-blocking */ + dhcpreq->retry_count = 1; + dhcpreq->interface_hndl = phba->interface_handle; + dhcpreq->ip_type = ip_type; + rc = beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, NULL, NULL, 0); + beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc); +exit: + kfree(if_info); + return rc; +} + +/** + * beiscsi_if_set_vlan()- Issue and wait for CMD completion + * @phba: device private structure instance + * @vlan_tag: VLAN tag + * + * Issue the MBX Cmd and wait for the completion of the + * command. + * + * returns + * Success: 0 + * Failure: Non-Xero Value + **/ +int beiscsi_if_set_vlan(struct beiscsi_hba *phba, uint16_t vlan_tag) +{ + int rc; + unsigned int tag; + + tag = be_cmd_set_vlan(phba, vlan_tag); + if (!tag) { + beiscsi_log(phba, KERN_ERR, + (BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX), + "BG_%d : VLAN Setting Failed\n"); + return -EBUSY; + } + + rc = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL); + if (rc) { + beiscsi_log(phba, KERN_ERR, + (BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX), + "BS_%d : VLAN MBX Cmd Failed\n"); + return rc; + } + return rc; +} + + +int beiscsi_if_get_info(struct beiscsi_hba *phba, int ip_type, + struct be_cmd_get_if_info_resp **if_info) +{ + struct be_cmd_get_if_info_req *req; + struct be_dma_mem nonemb_cmd; + uint32_t ioctl_size = sizeof(struct be_cmd_get_if_info_resp); + int rc; + + rc = beiscsi_if_get_handle(phba); + if (rc) + return rc; + + do { + rc = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd, + CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_ISCSI_NTWK_GET_IF_INFO, + ioctl_size); + if (rc) + return rc; + + req = nonemb_cmd.va; + req->interface_hndl = phba->interface_handle; + req->ip_type = ip_type; + + /* Allocate memory for if_info */ + *if_info = kzalloc(ioctl_size, GFP_KERNEL); + if (!*if_info) { + beiscsi_log(phba, KERN_ERR, + BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, + "BG_%d : Memory Allocation Failure\n"); + + beiscsi_free_nemb_cmd(phba, &nonemb_cmd, + -ENOMEM); + return -ENOMEM; + } + + rc = beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, NULL, *if_info, + ioctl_size); + + /* Check if the error is because of Insufficent_Buffer */ + if (rc == -EAGAIN) { + + /* Get the new memory size */ + ioctl_size = ((struct be_cmd_resp_hdr *) + nonemb_cmd.va)->actual_resp_len; + ioctl_size += sizeof(struct be_cmd_req_hdr); + + beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc); + /* Free the virtual memory */ + kfree(*if_info); + } else { + beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc); + break; + } + } while (true); + return rc; } int mgmt_get_nic_conf(struct beiscsi_hba *phba, @@ -1060,189 +805,328 @@ int mgmt_get_nic_conf(struct beiscsi_hba *phba, struct be_dma_mem nonemb_cmd; int rc; - rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, - OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG, - sizeof(*nic)); + rc = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd, CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG, + sizeof(*nic)); if (rc) return rc; - return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, nic, sizeof(*nic)); + rc = beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, NULL, nic, sizeof(*nic)); + beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc); + return rc; } +static void beiscsi_boot_process_compl(struct beiscsi_hba *phba, + unsigned int tag) +{ + struct be_cmd_get_boot_target_resp *boot_resp; + struct be_cmd_resp_logout_fw_sess *logo_resp; + struct be_cmd_get_session_resp *sess_resp; + struct be_mcc_wrb *wrb; + struct boot_struct *bs; + int boot_work, status; + + if (!test_bit(BEISCSI_HBA_BOOT_WORK, &phba->state)) { + __beiscsi_log(phba, KERN_ERR, + "BG_%d : %s no boot work %lx\n", + __func__, phba->state); + return; + } + + if (phba->boot_struct.tag != tag) { + __beiscsi_log(phba, KERN_ERR, + "BG_%d : %s tag mismatch %d:%d\n", + __func__, tag, phba->boot_struct.tag); + return; + } + bs = &phba->boot_struct; + boot_work = 1; + status = 0; + switch (bs->action) { + case BEISCSI_BOOT_REOPEN_SESS: + status = __beiscsi_mcc_compl_status(phba, tag, NULL, NULL); + if (!status) + bs->action = BEISCSI_BOOT_GET_SHANDLE; + else + bs->retry--; + break; + case BEISCSI_BOOT_GET_SHANDLE: + status = __beiscsi_mcc_compl_status(phba, tag, &wrb, NULL); + if (!status) { + boot_resp = embedded_payload(wrb); + bs->s_handle = boot_resp->boot_session_handle; + } + if (bs->s_handle == BE_BOOT_INVALID_SHANDLE) { + bs->action = BEISCSI_BOOT_REOPEN_SESS; + bs->retry--; + } else { + bs->action = BEISCSI_BOOT_GET_SINFO; + } + break; + case BEISCSI_BOOT_GET_SINFO: + status = __beiscsi_mcc_compl_status(phba, tag, NULL, + &bs->nonemb_cmd); + if (!status) { + sess_resp = bs->nonemb_cmd.va; + memcpy(&bs->boot_sess, &sess_resp->session_info, + sizeof(struct mgmt_session_info)); + bs->action = BEISCSI_BOOT_LOGOUT_SESS; + } else { + __beiscsi_log(phba, KERN_ERR, + "BG_%d : get boot session info error : 0x%x\n", + status); + boot_work = 0; + } + dma_free_coherent(&phba->ctrl.pdev->dev, bs->nonemb_cmd.size, + bs->nonemb_cmd.va, bs->nonemb_cmd.dma); + bs->nonemb_cmd.va = NULL; + break; + case BEISCSI_BOOT_LOGOUT_SESS: + status = __beiscsi_mcc_compl_status(phba, tag, &wrb, NULL); + if (!status) { + logo_resp = embedded_payload(wrb); + if (logo_resp->session_status != BE_SESS_STATUS_CLOSE) { + __beiscsi_log(phba, KERN_ERR, + "BG_%d : FW boot session logout error : 0x%x\n", + logo_resp->session_status); + } + } + /* continue to create boot_kset even if logout failed? */ + bs->action = BEISCSI_BOOT_CREATE_KSET; + break; + default: + break; + } + /* clear the tag so no other completion matches this tag */ + bs->tag = 0; + if (!bs->retry) { + boot_work = 0; + __beiscsi_log(phba, KERN_ERR, + "BG_%d : failed to setup boot target: status %d action %d\n", + status, bs->action); + } + if (!boot_work) { + /* wait for next event to start boot_work */ + clear_bit(BEISCSI_HBA_BOOT_WORK, &phba->state); + return; + } + schedule_work(&phba->boot_work); +} -unsigned int be_cmd_get_initname(struct beiscsi_hba *phba) +/** + * beiscsi_boot_logout_sess()- Logout from boot FW session + * @phba: Device priv structure instance + * + * return + * the TAG used for MBOX Command + * + */ +unsigned int beiscsi_boot_logout_sess(struct beiscsi_hba *phba) { - unsigned int tag = 0; - struct be_mcc_wrb *wrb; - struct be_cmd_hba_name *req; struct be_ctrl_info *ctrl = &phba->ctrl; + struct be_mcc_wrb *wrb; + struct be_cmd_req_logout_fw_sess *req; + unsigned int tag; - spin_lock(&ctrl->mbox_lock); - tag = alloc_mcc_tag(phba); - if (!tag) { - spin_unlock(&ctrl->mbox_lock); - return tag; + mutex_lock(&ctrl->mbox_lock); + wrb = alloc_mcc_wrb(phba, &tag); + if (!wrb) { + mutex_unlock(&ctrl->mbox_lock); + return 0; } - wrb = wrb_from_mccq(phba); req = embedded_payload(wrb); - wrb->tag0 |= tag; be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, - OPCODE_ISCSI_INI_CFG_GET_HBA_NAME, - sizeof(*req)); + OPCODE_ISCSI_INI_SESSION_LOGOUT_TARGET, + sizeof(struct be_cmd_req_logout_fw_sess)); + /* Use the session handle copied into boot_sess */ + req->session_handle = phba->boot_struct.boot_sess.session_handle; + + phba->boot_struct.tag = tag; + set_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state); + ctrl->ptag_state[tag].cbfn = beiscsi_boot_process_compl; + + be_mcc_notify(phba, tag); + mutex_unlock(&ctrl->mbox_lock); - be_mcc_notify(phba); - spin_unlock(&ctrl->mbox_lock); return tag; } - -unsigned int be_cmd_get_port_speed(struct beiscsi_hba *phba) +/** + * beiscsi_boot_reopen_sess()- Reopen boot session + * @phba: Device priv structure instance + * + * return + * the TAG used for MBOX Command + * + **/ +unsigned int beiscsi_boot_reopen_sess(struct beiscsi_hba *phba) { - unsigned int tag = 0; - struct be_mcc_wrb *wrb; - struct be_cmd_ntwk_link_status_req *req; struct be_ctrl_info *ctrl = &phba->ctrl; + struct be_mcc_wrb *wrb; + struct be_cmd_reopen_session_req *req; + unsigned int tag; - spin_lock(&ctrl->mbox_lock); - tag = alloc_mcc_tag(phba); - if (!tag) { - spin_unlock(&ctrl->mbox_lock); - return tag; + mutex_lock(&ctrl->mbox_lock); + wrb = alloc_mcc_wrb(phba, &tag); + if (!wrb) { + mutex_unlock(&ctrl->mbox_lock); + return 0; } - wrb = wrb_from_mccq(phba); req = embedded_payload(wrb); - wrb->tag0 |= tag; be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, - sizeof(*req)); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, + OPCODE_ISCSI_INI_DRIVER_REOPEN_ALL_SESSIONS, + sizeof(struct be_cmd_reopen_session_resp)); + req->reopen_type = BE_REOPEN_BOOT_SESSIONS; + req->session_handle = BE_BOOT_INVALID_SHANDLE; + + phba->boot_struct.tag = tag; + set_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state); + ctrl->ptag_state[tag].cbfn = beiscsi_boot_process_compl; - be_mcc_notify(phba); - spin_unlock(&ctrl->mbox_lock); + be_mcc_notify(phba, tag); + mutex_unlock(&ctrl->mbox_lock); return tag; } + /** - * be_mgmt_get_boot_shandle()- Get the session handle + * beiscsi_boot_get_sinfo()- Get boot session info * @phba: device priv structure instance - * @s_handle: session handle returned for boot session. - * - * Get the boot target session handle. In case of - * crashdump mode driver has to issue and MBX Cmd - * for FW to login to boot target * + * Fetches the boot_struct.s_handle info from FW. * return - * Success: 0 - * Failure: Non-Zero value + * the TAG used for MBOX Command * **/ -int be_mgmt_get_boot_shandle(struct beiscsi_hba *phba, - unsigned int *s_handle) +unsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba) { - struct be_cmd_get_boot_target_resp *boot_resp; + struct be_ctrl_info *ctrl = &phba->ctrl; + struct be_cmd_get_session_req *req; + struct be_dma_mem *nonemb_cmd; struct be_mcc_wrb *wrb; + struct be_sge *sge; unsigned int tag; - uint8_t boot_retry = 3; - int rc; - do { - /* Get the Boot Target Session Handle and Count*/ - tag = mgmt_get_boot_target(phba); - if (!tag) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_CONFIG | BEISCSI_LOG_INIT, - "BG_%d : Getting Boot Target Info Failed\n"); - return -EAGAIN; - } + mutex_lock(&ctrl->mbox_lock); + wrb = alloc_mcc_wrb(phba, &tag); + if (!wrb) { + mutex_unlock(&ctrl->mbox_lock); + return 0; + } - rc = beiscsi_mccq_compl(phba, tag, &wrb, NULL); - if (rc) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, - "BG_%d : MBX CMD get_boot_target Failed\n"); - return -EBUSY; - } + nonemb_cmd = &phba->boot_struct.nonemb_cmd; + nonemb_cmd->size = sizeof(struct be_cmd_get_session_resp); + nonemb_cmd->va = dma_alloc_coherent(&phba->ctrl.pdev->dev, + nonemb_cmd->size, + &nonemb_cmd->dma, + GFP_KERNEL); + if (!nonemb_cmd->va) { + mutex_unlock(&ctrl->mbox_lock); + return 0; + } - boot_resp = embedded_payload(wrb); + req = nonemb_cmd->va; + memset(req, 0, sizeof(*req)); + sge = nonembedded_sgl(wrb); + be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, + OPCODE_ISCSI_INI_SESSION_GET_A_SESSION, + sizeof(struct be_cmd_get_session_resp)); + req->session_handle = phba->boot_struct.s_handle; + sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); + sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(nonemb_cmd->size); - /* Check if the there are any Boot targets configured */ - if (!boot_resp->boot_session_count) { - beiscsi_log(phba, KERN_INFO, - BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, - "BG_%d ;No boot targets configured\n"); - return -ENXIO; - } + phba->boot_struct.tag = tag; + set_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state); + ctrl->ptag_state[tag].cbfn = beiscsi_boot_process_compl; - /* FW returns the session handle of the boot session */ - if (boot_resp->boot_session_handle != INVALID_SESS_HANDLE) { - *s_handle = boot_resp->boot_session_handle; - return 0; - } + be_mcc_notify(phba, tag); + mutex_unlock(&ctrl->mbox_lock); + return tag; +} - /* Issue MBX Cmd to FW to login to the boot target */ - tag = mgmt_reopen_session(phba, BE_REOPEN_BOOT_SESSIONS, - INVALID_SESS_HANDLE); - if (!tag) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, - "BG_%d : mgmt_reopen_session Failed\n"); - return -EAGAIN; - } +unsigned int __beiscsi_boot_get_shandle(struct beiscsi_hba *phba, int async) +{ + struct be_ctrl_info *ctrl = &phba->ctrl; + struct be_mcc_wrb *wrb; + struct be_cmd_get_boot_target_req *req; + unsigned int tag; - rc = beiscsi_mccq_compl(phba, tag, NULL, NULL); - if (rc) { - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, - "BG_%d : mgmt_reopen_session Failed"); - return rc; - } - } while (--boot_retry); + mutex_lock(&ctrl->mbox_lock); + wrb = alloc_mcc_wrb(phba, &tag); + if (!wrb) { + mutex_unlock(&ctrl->mbox_lock); + return 0; + } - /* Couldn't log into the boot target */ - beiscsi_log(phba, KERN_ERR, - BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, - "BG_%d : Login to Boot Target Failed\n"); - return -ENXIO; + req = embedded_payload(wrb); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, + OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET, + sizeof(struct be_cmd_get_boot_target_resp)); + + if (async) { + phba->boot_struct.tag = tag; + set_bit(MCC_TAG_STATE_ASYNC, &ctrl->ptag_state[tag].tag_state); + ctrl->ptag_state[tag].cbfn = beiscsi_boot_process_compl; + } + + be_mcc_notify(phba, tag); + mutex_unlock(&ctrl->mbox_lock); + return tag; } /** - * mgmt_set_vlan()- Issue and wait for CMD completion - * @phba: device private structure instance - * @vlan_tag: VLAN tag + * beiscsi_boot_get_shandle()- Get boot session handle + * @phba: device priv structure instance + * @s_handle: session handle returned for boot session. * - * Issue the MBX Cmd and wait for the completion of the - * command. + * return + * Success: 1 + * Failure: negative * - * returns - * Success: 0 - * Failure: Non-Xero Value **/ -int mgmt_set_vlan(struct beiscsi_hba *phba, - uint16_t vlan_tag) +int beiscsi_boot_get_shandle(struct beiscsi_hba *phba, unsigned int *s_handle) { - int rc; + struct be_cmd_get_boot_target_resp *boot_resp; + struct be_mcc_wrb *wrb; unsigned int tag; - struct be_mcc_wrb *wrb = NULL; + int rc; - tag = be_cmd_set_vlan(phba, vlan_tag); + *s_handle = BE_BOOT_INVALID_SHANDLE; + /* get configured boot session count and handle */ + tag = __beiscsi_boot_get_shandle(phba, 0); if (!tag) { beiscsi_log(phba, KERN_ERR, - (BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX), - "BG_%d : VLAN Setting Failed\n"); - return -EBUSY; + BEISCSI_LOG_CONFIG | BEISCSI_LOG_INIT, + "BG_%d : Getting Boot Target Info Failed\n"); + return -EAGAIN; } - rc = beiscsi_mccq_compl(phba, tag, &wrb, NULL); + rc = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL); if (rc) { beiscsi_log(phba, KERN_ERR, - (BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX), - "BS_%d : VLAN MBX Cmd Failed\n"); - return rc; + BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, + "BG_%d : MBX CMD get_boot_target Failed\n"); + return -EBUSY; } - return rc; + + boot_resp = embedded_payload(wrb); + /* check if there are any boot targets configured */ + if (!boot_resp->boot_session_count) { + __beiscsi_log(phba, KERN_INFO, + "BG_%d : No boot targets configured\n"); + return -ENXIO; + } + + /* only if FW has logged in to the boot target, s_handle is valid */ + *s_handle = boot_resp->boot_session_handle; + return 1; } /** @@ -1281,7 +1165,7 @@ beiscsi_fw_ver_disp(struct device *dev, struct device_attribute *attr, } /** - * beiscsi_active_cid_disp()- Display Sessions Active + * beiscsi_active_session_disp()- Display Sessions Active * @dev: ptr to device not used. * @attr: device attribute, not used. * @buf: contains formatted text Session Count @@ -1290,14 +1174,56 @@ beiscsi_fw_ver_disp(struct device *dev, struct device_attribute *attr, * size of the formatted string **/ ssize_t -beiscsi_active_cid_disp(struct device *dev, struct device_attribute *attr, +beiscsi_active_session_disp(struct device *dev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(dev); struct beiscsi_hba *phba = iscsi_host_priv(shost); + uint16_t avlbl_cids = 0, ulp_num, len = 0, total_cids = 0; + + for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { + if (test_bit(ulp_num, (void *)&phba->fw_config.ulp_supported)) { + avlbl_cids = BEISCSI_ULP_AVLBL_CID(phba, ulp_num); + total_cids = BEISCSI_GET_CID_COUNT(phba, ulp_num); + len += scnprintf(buf+len, PAGE_SIZE - len, + "ULP%d : %d\n", ulp_num, + (total_cids - avlbl_cids)); + } else + len += scnprintf(buf+len, PAGE_SIZE - len, + "ULP%d : %d\n", ulp_num, 0); + } - return snprintf(buf, PAGE_SIZE, "%d\n", - (phba->params.cxns_per_ctrl - phba->avlbl_cids)); + return len; +} + +/** + * beiscsi_free_session_disp()- Display Avaliable Session + * @dev: ptr to device not used. + * @attr: device attribute, not used. + * @buf: contains formatted text Session Count + * + * return + * size of the formatted string + **/ +ssize_t +beiscsi_free_session_disp(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct beiscsi_hba *phba = iscsi_host_priv(shost); + uint16_t ulp_num, len = 0; + + for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { + if (test_bit(ulp_num, (void *)&phba->fw_config.ulp_supported)) + len += scnprintf(buf+len, PAGE_SIZE - len, + "ULP%d : %d\n", ulp_num, + BEISCSI_ULP_AVLBL_CID(phba, ulp_num)); + else + len += scnprintf(buf+len, PAGE_SIZE - len, + "ULP%d : %d\n", ulp_num, 0); + } + + return len; } /** @@ -1322,30 +1248,46 @@ beiscsi_adap_family_disp(struct device *dev, struct device_attribute *attr, case BE_DEVICE_ID1: case OC_DEVICE_ID1: case OC_DEVICE_ID2: - return snprintf(buf, PAGE_SIZE, "BE2 Adapter Family\n"); - break; + return snprintf(buf, PAGE_SIZE, + "Obsolete/Unsupported BE2 Adapter Family\n"); case BE_DEVICE_ID2: case OC_DEVICE_ID3: return snprintf(buf, PAGE_SIZE, "BE3-R Adapter Family\n"); - break; case OC_SKH_ID1: return snprintf(buf, PAGE_SIZE, "Skyhawk-R Adapter Family\n"); - break; default: return snprintf(buf, PAGE_SIZE, "Unknown Adapter Family: 0x%x\n", dev_id); - break; } } +/** + * beiscsi_phys_port_disp()- Display Physical Port Identifier + * @dev: ptr to device not used. + * @attr: device attribute, not used. + * @buf: contains formatted text port identifier + * + * return + * size of the formatted string + **/ +ssize_t +beiscsi_phys_port_disp(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct beiscsi_hba *phba = iscsi_host_priv(shost); + + return snprintf(buf, PAGE_SIZE, "Port Identifier : %u\n", + phba->fw_config.phys_port); +} void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params, struct wrb_handle *pwrb_handle, - struct be_mem_descriptor *mem_descr) + struct be_mem_descriptor *mem_descr, + struct hwi_wrb_context *pwrb_context) { struct iscsi_wrb *pwrb = pwrb_handle->pwrb; - memset(pwrb, 0, sizeof(*pwrb)); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, max_send_data_segment_length, pwrb, params->dw[offsetof(struct amap_beiscsi_offload_params, @@ -1385,7 +1327,14 @@ void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params, max_burst_length) / 32]); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ptr2nextwrb, - pwrb, pwrb_handle->nxt_wrb_index); + pwrb, pwrb_handle->wrb_index); + if (pwrb_context->plast_wrb) + AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, + ptr2nextwrb, + pwrb_context->plast_wrb, + pwrb_handle->wrb_index); + pwrb_context->plast_wrb = pwrb; + AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, session_state, pwrb, 0); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, compltonack, @@ -1405,16 +1354,11 @@ void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params, } void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params, - struct wrb_handle *pwrb_handle) + struct wrb_handle *pwrb_handle, + struct hwi_wrb_context *pwrb_context) { struct iscsi_wrb *pwrb = pwrb_handle->pwrb; - memset(pwrb, 0, sizeof(*pwrb)); - - AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, - max_burst_length, pwrb, params->dw[offsetof - (struct amap_beiscsi_offload_params, - max_burst_length) / 32]); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, max_burst_length, pwrb, params->dw[offsetof (struct amap_beiscsi_offload_params, @@ -1424,7 +1368,14 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params, BE_TGT_CTX_UPDT_CMD); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, ptr2nextwrb, - pwrb, pwrb_handle->nxt_wrb_index); + pwrb, pwrb_handle->wrb_index); + if (pwrb_context->plast_wrb) + AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, + ptr2nextwrb, + pwrb_context->plast_wrb, + pwrb_handle->wrb_index); + pwrb_context->plast_wrb = pwrb; + AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, wrb_idx, pwrb, pwrb_handle->wrb_index); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, @@ -1436,7 +1387,9 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params, params->dw[offsetof(struct amap_beiscsi_offload_params, first_burst_length) / 32]); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, - max_recv_dataseg_len, pwrb, BEISCSI_MAX_RECV_DATASEG_LEN); + max_recv_dataseg_len, pwrb, + params->dw[offsetof(struct amap_beiscsi_offload_params, + max_recv_data_segment_length) / 32]); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, max_cxns, pwrb, BEISCSI_MAX_CXNS); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, erl, pwrb, @@ -1477,3 +1430,130 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params, (params->dw[offsetof(struct amap_beiscsi_offload_params, exp_statsn) / 32] + 1)); } + +unsigned int beiscsi_invalidate_cxn(struct beiscsi_hba *phba, + struct beiscsi_endpoint *beiscsi_ep) +{ + struct be_invalidate_connection_params_in *req; + struct be_ctrl_info *ctrl = &phba->ctrl; + struct be_mcc_wrb *wrb; + unsigned int tag = 0; + + mutex_lock(&ctrl->mbox_lock); + wrb = alloc_mcc_wrb(phba, &tag); + if (!wrb) { + mutex_unlock(&ctrl->mbox_lock); + return 0; + } + + req = embedded_payload(wrb); + be_wrb_hdr_prepare(wrb, sizeof(union be_invalidate_connection_params), + true, 0); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, + OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION, + sizeof(*req)); + req->session_handle = beiscsi_ep->fw_handle; + req->cid = beiscsi_ep->ep_cid; + if (beiscsi_ep->conn) + req->cleanup_type = BE_CLEANUP_TYPE_INVALIDATE; + else + req->cleanup_type = BE_CLEANUP_TYPE_ISSUE_TCP_RST; + /** + * 0 - non-persistent targets + * 1 - save session info on flash + */ + req->save_cfg = 0; + be_mcc_notify(phba, tag); + mutex_unlock(&ctrl->mbox_lock); + return tag; +} + +unsigned int beiscsi_upload_cxn(struct beiscsi_hba *phba, + struct beiscsi_endpoint *beiscsi_ep) +{ + struct be_ctrl_info *ctrl = &phba->ctrl; + struct be_mcc_wrb *wrb; + struct be_tcp_upload_params_in *req; + unsigned int tag; + + mutex_lock(&ctrl->mbox_lock); + wrb = alloc_mcc_wrb(phba, &tag); + if (!wrb) { + mutex_unlock(&ctrl->mbox_lock); + return 0; + } + + req = embedded_payload(wrb); + be_wrb_hdr_prepare(wrb, sizeof(union be_tcp_upload_params), true, 0); + be_cmd_hdr_prepare(&req->hdr, CMD_COMMON_TCP_UPLOAD, + OPCODE_COMMON_TCP_UPLOAD, sizeof(*req)); + req->id = beiscsi_ep->ep_cid; + if (beiscsi_ep->conn) + req->upload_type = BE_UPLOAD_TYPE_GRACEFUL; + else + req->upload_type = BE_UPLOAD_TYPE_ABORT; + be_mcc_notify(phba, tag); + mutex_unlock(&ctrl->mbox_lock); + return tag; +} + +int beiscsi_mgmt_invalidate_icds(struct beiscsi_hba *phba, + struct invldt_cmd_tbl *inv_tbl, + unsigned int nents) +{ + struct be_ctrl_info *ctrl = &phba->ctrl; + struct invldt_cmds_params_in *req; + struct be_dma_mem nonemb_cmd; + struct be_mcc_wrb *wrb; + unsigned int i, tag; + struct be_sge *sge; + int rc; + + if (!nents || nents > BE_INVLDT_CMD_TBL_SZ) + return -EINVAL; + + nonemb_cmd.size = sizeof(union be_invldt_cmds_params); + nonemb_cmd.va = dma_alloc_coherent(&phba->ctrl.pdev->dev, + nonemb_cmd.size, &nonemb_cmd.dma, + GFP_KERNEL); + if (!nonemb_cmd.va) { + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH, + "BM_%d : invldt_cmds_params alloc failed\n"); + return -ENOMEM; + } + + mutex_lock(&ctrl->mbox_lock); + wrb = alloc_mcc_wrb(phba, &tag); + if (!wrb) { + mutex_unlock(&ctrl->mbox_lock); + dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); + return -ENOMEM; + } + + req = nonemb_cmd.va; + be_wrb_hdr_prepare(wrb, nonemb_cmd.size, false, 1); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS, + sizeof(*req)); + req->ref_handle = 0; + req->cleanup_type = CMD_ISCSI_COMMAND_INVALIDATE; + for (i = 0; i < nents; i++) { + req->table[i].icd = inv_tbl[i].icd; + req->table[i].cid = inv_tbl[i].cid; + req->icd_count++; + } + sge = nonembedded_sgl(wrb); + sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma)); + sge->pa_lo = cpu_to_le32(lower_32_bits(nonemb_cmd.dma)); + sge->len = cpu_to_le32(nonemb_cmd.size); + + be_mcc_notify(phba, tag); + mutex_unlock(&ctrl->mbox_lock); + + rc = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd); + if (rc != -EBUSY) + dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); + return rc; +} |
