|  | /* | 
|  | * 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 version 2 of the GNU General Public License as published | 
|  | * by the Free Software Foundation. | 
|  | * | 
|  | * 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@broadcom.com | 
|  | * | 
|  | */ | 
|  |  | 
|  | #include <linux/bsg-lib.h> | 
|  | #include <scsi/scsi_transport_iscsi.h> | 
|  | #include <scsi/scsi_bsg_iscsi.h> | 
|  | #include "be_mgmt.h" | 
|  | #include "be_iscsi.h" | 
|  | #include "be_main.h" | 
|  |  | 
|  | 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_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; | 
|  | unsigned short region, sector_size, sector, offset; | 
|  |  | 
|  | nonemb_cmd->size = job->request_payload.payload_len; | 
|  | memset(nonemb_cmd->va, 0, nonemb_cmd->size); | 
|  | 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]; | 
|  | offset =  bsg_req->rqst_data.h_vendor.vendor_cmd[4]; | 
|  | req->region = region; | 
|  | req->sector = sector; | 
|  | req->offset = offset; | 
|  |  | 
|  | 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; | 
|  | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, | 
|  | OPCODE_COMMON_WRITE_FLASH, sizeof(*req)); | 
|  | sg_copy_to_buffer(job->request_payload.sg_list, | 
|  | job->request_payload.sg_cnt, | 
|  | nonemb_cmd->va + offset, job->request_len); | 
|  | break; | 
|  | case BEISCSI_READ_FLASH: | 
|  | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, | 
|  | OPCODE_COMMON_READ_FLASH, sizeof(*req)); | 
|  | break; | 
|  | default: | 
|  | beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, | 
|  | "BG_%d : Unsupported cmd = 0x%x\n\n", | 
|  | bsg_req->rqst_data.h_vendor.vendor_cmd[0]); | 
|  |  | 
|  | mutex_unlock(&ctrl->mbox_lock); | 
|  | return -EPERM; | 
|  | } | 
|  |  | 
|  | 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); | 
|  |  | 
|  | be_mcc_notify(phba, tag); | 
|  |  | 
|  | 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, | 
|  | struct be_dma_mem *nonemb_cmd) | 
|  | { | 
|  | struct hwi_controller *phwi_ctrlr; | 
|  | struct hwi_context_memory *phwi_context; | 
|  | struct sockaddr_in *daddr_in = (struct sockaddr_in *)dst_addr; | 
|  | 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_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, 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; | 
|  |  | 
|  | 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); | 
|  | if (mutex_lock_interruptible(&ctrl->mbox_lock)) | 
|  | return 0; | 
|  | wrb = alloc_mcc_wrb(phba, &tag); | 
|  | if (!wrb) { | 
|  | mutex_unlock(&ctrl->mbox_lock); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | sge = nonembedded_sgl(wrb); | 
|  | req = nonemb_cmd->va; | 
|  | memset(req, 0, sizeof(*req)); | 
|  |  | 
|  | 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, | 
|  | nonemb_cmd->size); | 
|  | if (dst_addr->sa_family == PF_INET) { | 
|  | __be32 s_addr = daddr_in->sin_addr.s_addr; | 
|  | 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; | 
|  | req->ip_address.addr[3] = (s_addr & 0xff000000) >> 24; | 
|  | 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 = 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 = BEISCSI_IP_TYPE_V6; | 
|  | } | 
|  | req->cid = cid; | 
|  | i = phba->nxt_cqid++; | 
|  | if (phba->nxt_cqid == phba->num_cpus) | 
|  | phba->nxt_cqid = 0; | 
|  | req->cq_id = phwi_context->be_cq[i].id; | 
|  | beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, | 
|  | "BG_%d : i=%d cq_id=%d\n", i, req->cq_id); | 
|  | req->defq_id = def_hdr_id; | 
|  | req->hdr_ring_id = def_hdr_id; | 
|  | req->data_ring_id = def_data_id; | 
|  | req->do_offload = 1; | 
|  | req->dataout_template_pa.lo = ptemplate_address->lo; | 
|  | req->dataout_template_pa.hi = ptemplate_address->hi; | 
|  | 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); | 
|  |  | 
|  | if (!is_chip_be2_be3r(phba)) { | 
|  | req->hdr.version = MBX_CMD_VER1; | 
|  | req->tcp_window_size = 0x8000; | 
|  | req->tcp_window_scale_count = 2; | 
|  | } | 
|  |  | 
|  | be_mcc_notify(phba, tag); | 
|  | mutex_unlock(&ctrl->mbox_lock); | 
|  | return tag; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * 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 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; | 
|  | struct be_sge *sge; | 
|  | unsigned int tag; | 
|  | int rc = 0; | 
|  |  | 
|  | mutex_lock(&ctrl->mbox_lock); | 
|  | wrb = alloc_mcc_wrb(phba, &tag); | 
|  | if (!wrb) { | 
|  | mutex_unlock(&ctrl->mbox_lock); | 
|  | return -ENOMEM; | 
|  | } | 
|  |  | 
|  | 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); | 
|  |  | 
|  | if (cbfn) { | 
|  | struct be_dma_mem *tag_mem; | 
|  |  | 
|  | 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; | 
|  |  | 
|  | /* 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); | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | static int beiscsi_prep_nemb_cmd(struct beiscsi_hba *phba, | 
|  | struct be_dma_mem *cmd, | 
|  | u8 subsystem, u8 opcode, u32 size) | 
|  | { | 
|  | 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; | 
|  | } | 
|  | cmd->size = 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 void beiscsi_free_nemb_cmd(struct beiscsi_hba *phba, | 
|  | struct be_dma_mem *cmd, int rc) | 
|  | { | 
|  | /* | 
|  | * If FW is busy the DMA buffer is saved with the tag. When the cmd | 
|  | * completes this buffer is freed. | 
|  | */ | 
|  | if (rc == -EBUSY) | 
|  | return; | 
|  |  | 
|  | dma_free_coherent(&phba->ctrl.pdev->dev, cmd->size, cmd->va, cmd->dma); | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  | } | 
|  |  | 
|  | int beiscsi_modify_eq_delay(struct beiscsi_hba *phba, | 
|  | struct be_set_eqd *set_eqd, int num) | 
|  | { | 
|  | struct be_cmd_req_modify_eq_delay *req; | 
|  | struct be_dma_mem nonemb_cmd; | 
|  | int i, rc; | 
|  |  | 
|  | 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->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); | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * 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_dma_mem nonemb_cmd; | 
|  | struct be_cmd_hba_name resp; | 
|  | struct be_cmd_hba_name *req; | 
|  | int rc; | 
|  |  | 
|  | 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; | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | 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; | 
|  |  | 
|  | if (mutex_lock_interruptible(&ctrl->mbox_lock)) | 
|  | return -EINTR; | 
|  | wrb = alloc_mcc_wrb(phba, &tag); | 
|  | if (!wrb) { | 
|  | mutex_unlock(&ctrl->mbox_lock); | 
|  | return -ENOMEM; | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | pbe_allid = embedded_payload(wrb); | 
|  | /* we now support only one interface per function */ | 
|  | phba->interface_handle = pbe_allid->if_hndl_list[0]; | 
|  |  | 
|  | return status; | 
|  | } | 
|  |  | 
|  | static inline bool beiscsi_if_zero_ip(u8 *ip, u32 ip_type) | 
|  | { | 
|  | u32 len; | 
|  |  | 
|  | len = (ip_type < BEISCSI_IP_TYPE_V6) ? IP_V4_LEN : IP_V6_LEN; | 
|  | while (len && !ip[len - 1]) | 
|  | len--; | 
|  | return (len == 0); | 
|  | } | 
|  |  | 
|  | 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; | 
|  |  | 
|  | 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; | 
|  |  | 
|  | 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 beiscsi_if_set_gw(struct beiscsi_hba *phba, u32 ip_type, u8 *gw) | 
|  | { | 
|  | struct be_cmd_get_def_gateway_resp gw_resp; | 
|  | int rt_val; | 
|  |  | 
|  | 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 (!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"); | 
|  | return rt_val; | 
|  | } | 
|  | } | 
|  |  | 
|  | 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"); | 
|  |  | 
|  | return rt_val; | 
|  | } | 
|  |  | 
|  | 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 = 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; | 
|  |  | 
|  | rc = beiscsi_exec_nemb_cmd(phba, &nonemb_cmd, NULL, resp, | 
|  | sizeof(*resp)); | 
|  | beiscsi_free_nemb_cmd(phba, &nonemb_cmd, rc); | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | static int | 
|  | beiscsi_if_clr_ip(struct beiscsi_hba *phba, | 
|  | struct be_cmd_get_if_info_resp *if_info) | 
|  | { | 
|  | struct be_cmd_set_ip_addr_req *req; | 
|  | struct be_dma_mem nonemb_cmd; | 
|  | 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->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; | 
|  | } | 
|  |  | 
|  | 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->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; | 
|  | } | 
|  |  | 
|  | /* 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, | 
|  | struct be_cmd_get_nic_conf_resp *nic) | 
|  | { | 
|  | struct be_dma_mem nonemb_cmd; | 
|  | int rc; | 
|  |  | 
|  | rc = beiscsi_prep_nemb_cmd(phba, &nonemb_cmd, CMD_SUBSYSTEM_ISCSI, | 
|  | OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG, | 
|  | sizeof(*nic)); | 
|  | if (rc) | 
|  | return rc; | 
|  |  | 
|  | 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); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * 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) | 
|  | { | 
|  | struct be_ctrl_info *ctrl = &phba->ctrl; | 
|  | struct be_mcc_wrb *wrb; | 
|  | struct be_cmd_req_logout_fw_sess *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(*req), true, 0); | 
|  | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, | 
|  | 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); | 
|  |  | 
|  | return tag; | 
|  | } | 
|  | /** | 
|  | * 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) | 
|  | { | 
|  | struct be_ctrl_info *ctrl = &phba->ctrl; | 
|  | struct be_mcc_wrb *wrb; | 
|  | struct be_cmd_reopen_session_req *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(*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)); | 
|  | 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, tag); | 
|  | mutex_unlock(&ctrl->mbox_lock); | 
|  | return tag; | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * beiscsi_boot_get_sinfo()- Get boot session info | 
|  | * @phba: device priv structure instance | 
|  | * | 
|  | * Fetches the boot_struct.s_handle info from FW. | 
|  | * return | 
|  | *	the TAG used for MBOX Command | 
|  | * | 
|  | **/ | 
|  | unsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba) | 
|  | { | 
|  | 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; | 
|  |  | 
|  | mutex_lock(&ctrl->mbox_lock); | 
|  | wrb = alloc_mcc_wrb(phba, &tag); | 
|  | if (!wrb) { | 
|  | mutex_unlock(&ctrl->mbox_lock); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | 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); | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | 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; | 
|  |  | 
|  | 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(*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; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * beiscsi_boot_get_shandle()- Get boot session handle | 
|  | * @phba: device priv structure instance | 
|  | * @s_handle: session handle returned for boot session. | 
|  | * | 
|  | * return | 
|  | *	Success: 1 | 
|  | *	Failure: negative | 
|  | * | 
|  | **/ | 
|  | int beiscsi_boot_get_shandle(struct beiscsi_hba *phba, unsigned int *s_handle) | 
|  | { | 
|  | struct be_cmd_get_boot_target_resp *boot_resp; | 
|  | struct be_mcc_wrb *wrb; | 
|  | unsigned int tag; | 
|  | int rc; | 
|  |  | 
|  | *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_INIT, | 
|  | "BG_%d : Getting Boot Target Info Failed\n"); | 
|  | return -EAGAIN; | 
|  | } | 
|  |  | 
|  | rc = beiscsi_mccq_compl_wait(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; | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * beiscsi_drvr_ver_disp()- Display the driver Name and Version | 
|  | * @dev: ptr to device not used. | 
|  | * @attr: device attribute, not used. | 
|  | * @buf: contains formatted text driver name and version | 
|  | * | 
|  | * return | 
|  | * size of the formatted string | 
|  | **/ | 
|  | ssize_t | 
|  | beiscsi_drvr_ver_disp(struct device *dev, struct device_attribute *attr, | 
|  | char *buf) | 
|  | { | 
|  | return snprintf(buf, PAGE_SIZE, BE_NAME "\n"); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * beiscsi_fw_ver_disp()- Display Firmware Version | 
|  | * @dev: ptr to device not used. | 
|  | * @attr: device attribute, not used. | 
|  | * @buf: contains formatted text Firmware version | 
|  | * | 
|  | * return | 
|  | * size of the formatted string | 
|  | **/ | 
|  | ssize_t | 
|  | beiscsi_fw_ver_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, "%s\n", phba->fw_ver_str); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * beiscsi_active_session_disp()- Display Sessions Active | 
|  | * @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_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 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; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * beiscsi_adap_family_disp()- Display adapter family. | 
|  | * @dev: ptr to device to get priv structure | 
|  | * @attr: device attribute, not used. | 
|  | * @buf: contains formatted text driver name and version | 
|  | * | 
|  | * return | 
|  | * size of the formatted string | 
|  | **/ | 
|  | ssize_t | 
|  | beiscsi_adap_family_disp(struct device *dev, struct device_attribute *attr, | 
|  | char *buf) | 
|  | { | 
|  | uint16_t dev_id = 0; | 
|  | struct Scsi_Host *shost = class_to_shost(dev); | 
|  | struct beiscsi_hba *phba = iscsi_host_priv(shost); | 
|  |  | 
|  | dev_id = phba->pcidev->device; | 
|  | switch (dev_id) { | 
|  | case BE_DEVICE_ID1: | 
|  | case OC_DEVICE_ID1: | 
|  | case OC_DEVICE_ID2: | 
|  | 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"); | 
|  | case OC_SKH_ID1: | 
|  | return snprintf(buf, PAGE_SIZE, "Skyhawk-R Adapter Family\n"); | 
|  | default: | 
|  | return snprintf(buf, PAGE_SIZE, | 
|  | "Unknown Adapter Family: 0x%x\n", dev_id); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * 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 hwi_wrb_context *pwrb_context) | 
|  | { | 
|  | struct iscsi_wrb *pwrb = pwrb_handle->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, | 
|  | max_send_data_segment_length) / 32]); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, type, pwrb, | 
|  | BE_TGT_CTX_UPDT_CMD); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, | 
|  | first_burst_length, | 
|  | pwrb, | 
|  | params->dw[offsetof(struct amap_beiscsi_offload_params, | 
|  | first_burst_length) / 32]); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, erl, pwrb, | 
|  | (params->dw[offsetof(struct amap_beiscsi_offload_params, | 
|  | erl) / 32] & OFFLD_PARAMS_ERL)); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, dde, pwrb, | 
|  | (params->dw[offsetof(struct amap_beiscsi_offload_params, | 
|  | dde) / 32] & OFFLD_PARAMS_DDE) >> 2); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, hde, pwrb, | 
|  | (params->dw[offsetof(struct amap_beiscsi_offload_params, | 
|  | hde) / 32] & OFFLD_PARAMS_HDE) >> 3); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ir2t, pwrb, | 
|  | (params->dw[offsetof(struct amap_beiscsi_offload_params, | 
|  | ir2t) / 32] & OFFLD_PARAMS_IR2T) >> 4); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, imd, pwrb, | 
|  | (params->dw[offsetof(struct amap_beiscsi_offload_params, | 
|  | imd) / 32] & OFFLD_PARAMS_IMD) >> 5); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, stat_sn, | 
|  | pwrb, | 
|  | (params->dw[offsetof(struct amap_beiscsi_offload_params, | 
|  | exp_statsn) / 32] + 1)); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, wrb_idx, | 
|  | pwrb, pwrb_handle->wrb_index); | 
|  |  | 
|  | 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, ptr2nextwrb, | 
|  | 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, | 
|  | pwrb, 1); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, notpredblq, | 
|  | pwrb, 0); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, mode, pwrb, | 
|  | 0); | 
|  |  | 
|  | mem_descr += ISCSI_MEM_GLOBAL_HEADER; | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, | 
|  | pad_buffer_addr_hi, pwrb, | 
|  | mem_descr->mem_array[0].bus_address.u.a32.address_hi); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, | 
|  | pad_buffer_addr_lo, pwrb, | 
|  | mem_descr->mem_array[0].bus_address.u.a32.address_lo); | 
|  | } | 
|  |  | 
|  | void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params, | 
|  | struct wrb_handle *pwrb_handle, | 
|  | struct hwi_wrb_context *pwrb_context) | 
|  | { | 
|  | struct iscsi_wrb *pwrb = pwrb_handle->pwrb; | 
|  |  | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, | 
|  | 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, | 
|  | type, pwrb, | 
|  | BE_TGT_CTX_UPDT_CMD); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, | 
|  | ptr2nextwrb, | 
|  | 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, | 
|  | max_send_data_segment_length, pwrb, | 
|  | params->dw[offsetof(struct amap_beiscsi_offload_params, | 
|  | max_send_data_segment_length) / 32]); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, | 
|  | first_burst_length, pwrb, | 
|  | 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, | 
|  | 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, | 
|  | (params->dw[offsetof(struct amap_beiscsi_offload_params, | 
|  | erl) / 32] & OFFLD_PARAMS_ERL)); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, dde, pwrb, | 
|  | (params->dw[offsetof(struct amap_beiscsi_offload_params, | 
|  | dde) / 32] & OFFLD_PARAMS_DDE) >> 2); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, hde, pwrb, | 
|  | (params->dw[offsetof(struct amap_beiscsi_offload_params, | 
|  | hde) / 32] & OFFLD_PARAMS_HDE) >> 3); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, | 
|  | ir2t, pwrb, | 
|  | (params->dw[offsetof(struct amap_beiscsi_offload_params, | 
|  | ir2t) / 32] & OFFLD_PARAMS_IR2T) >> 4); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, imd, pwrb, | 
|  | (params->dw[offsetof(struct amap_beiscsi_offload_params, | 
|  | imd) / 32] & OFFLD_PARAMS_IMD) >> 5); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, | 
|  | data_seq_inorder, | 
|  | pwrb, | 
|  | (params->dw[offsetof(struct amap_beiscsi_offload_params, | 
|  | data_seq_inorder) / 32] & | 
|  | OFFLD_PARAMS_DATA_SEQ_INORDER) >> 6); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, | 
|  | pdu_seq_inorder, | 
|  | pwrb, | 
|  | (params->dw[offsetof(struct amap_beiscsi_offload_params, | 
|  | pdu_seq_inorder) / 32] & | 
|  | OFFLD_PARAMS_PDU_SEQ_INORDER) >> 7); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, max_r2t, | 
|  | pwrb, | 
|  | (params->dw[offsetof(struct amap_beiscsi_offload_params, | 
|  | max_r2t) / 32] & | 
|  | OFFLD_PARAMS_MAX_R2T) >> 8); | 
|  | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, stat_sn, | 
|  | pwrb, | 
|  | (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; | 
|  | } |