/** * beiscsi_set_vlan_tag()- Set the VLAN TAG * @shost: Scsi Host for the driver instance * @iface_param: Interface paramters * * Set the VLAN TAG for the adapter or disable * the VLAN config * * returns * Success: 0 * Failure: Non-Zero Value **/ static int beiscsi_set_vlan_tag(struct Scsi_Host *shost, struct iscsi_iface_param_info *iface_param) { struct beiscsi_hba *phba = iscsi_host_priv(shost); int ret = 0; /* Get the Interface Handle */ if (mgmt_get_all_if_id(phba)) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : Getting Interface Handle Failed\n"); return -EIO; } switch (iface_param->param) { case ISCSI_NET_PARAM_VLAN_ENABLED: if (iface_param->value[0] != ISCSI_VLAN_ENABLE) ret = mgmt_set_vlan(phba, BEISCSI_VLAN_DISABLE); break; case ISCSI_NET_PARAM_VLAN_TAG: ret = mgmt_set_vlan(phba, *((uint16_t *)iface_param->value)); break; default: beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, "BS_%d : Unknown Param Type : %d\n", iface_param->param); return -ENOSYS; } return ret; }
/** * beiscsi_conn_bind - Binds iscsi session/connection with TCP connection * @cls_session: pointer to iscsi cls session * @cls_conn: pointer to iscsi cls conn * @transport_fd: EP handle(64 bit) * * This function binds the TCP Conn with iSCSI Connection and Session. */ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session, struct iscsi_cls_conn *cls_conn, u64 transport_fd, int is_leading) { struct iscsi_conn *conn = cls_conn->dd_data; struct beiscsi_conn *beiscsi_conn = conn->dd_data; struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); struct beiscsi_hba *phba = iscsi_host_priv(shost); struct hwi_controller *phwi_ctrlr = phba->phwi_ctrlr; struct hwi_wrb_context *pwrb_context; struct beiscsi_endpoint *beiscsi_ep; struct iscsi_endpoint *ep; uint16_t cri_index; ep = iscsi_lookup_endpoint(transport_fd); if (!ep) return -EINVAL; beiscsi_ep = ep->dd_data; if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) return -EINVAL; if (beiscsi_ep->phba != phba) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : beiscsi_ep->hba=%p not equal to phba=%p\n", beiscsi_ep->phba, phba); return -EEXIST; } cri_index = BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid); if (phba->conn_table[cri_index]) { if (beiscsi_conn != phba->conn_table[cri_index] || beiscsi_ep != phba->conn_table[cri_index]->ep) { __beiscsi_log(phba, KERN_ERR, "BS_%d : conn_table not empty at %u: cid %u conn %p:%p\n", cri_index, beiscsi_ep->ep_cid, beiscsi_conn, phba->conn_table[cri_index]); return -EINVAL; } } beiscsi_conn->beiscsi_conn_cid = beiscsi_ep->ep_cid; beiscsi_conn->ep = beiscsi_ep; beiscsi_ep->conn = beiscsi_conn; /** * Each connection is associated with a WRBQ kept in wrb_context. * Store doorbell offset for transmit path. */ pwrb_context = &phwi_ctrlr->wrb_context[cri_index]; beiscsi_conn->doorbell_offset = pwrb_context->doorbell_offset; beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, "BS_%d : cid %d phba->conn_table[%u]=%p\n", beiscsi_ep->ep_cid, cri_index, beiscsi_conn); phba->conn_table[cri_index] = beiscsi_conn; return 0; }
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; }
/* * 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]); } } }
int be2iscsi_iface_set_param(struct Scsi_Host *shost, void *data, uint32_t dt_len) { struct iscsi_iface_param_info *iface_param = NULL; struct beiscsi_hba *phba = iscsi_host_priv(shost); struct nlattr *attrib; uint32_t rm_len = dt_len; int ret = 0 ; if (phba->state & BE_ADAPTER_PCI_ERR) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : In PCI_ERROR Recovery\n"); return -EBUSY; } nla_for_each_attr(attrib, data, dt_len, rm_len) { iface_param = nla_data(attrib); if (iface_param->param_type != ISCSI_NET_PARAM) continue; /* * BE2ISCSI only supports 1 interface */ if (iface_param->iface_num) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : Invalid iface_num %d." "Only iface_num 0 is supported.\n", iface_param->iface_num); return -EINVAL; } switch (iface_param->iface_type) { case ISCSI_IFACE_TYPE_IPV4: ret = beiscsi_set_ipv4(shost, iface_param, data, dt_len); break; case ISCSI_IFACE_TYPE_IPV6: ret = beiscsi_set_ipv6(shost, iface_param, data, dt_len); break; default: beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : Invalid iface type :%d passed\n", iface_param->iface_type); break; } if (ret) return ret; }
static int beiscsi_set_static_ip(struct Scsi_Host *shost, struct iscsi_iface_param_info *iface_param, void *data, uint32_t dt_len) { struct beiscsi_hba *phba = iscsi_host_priv(shost); struct iscsi_iface_param_info *iface_ip = NULL; struct iscsi_iface_param_info *iface_subnet = NULL; struct nlattr *nla; int ret; switch (iface_param->param) { case ISCSI_NET_PARAM_IPV4_BOOTPROTO: nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_ADDR); if (nla) iface_ip = nla_data(nla); nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_SUBNET); if (nla) iface_subnet = nla_data(nla); break; case ISCSI_NET_PARAM_IPV4_ADDR: iface_ip = iface_param; nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_SUBNET); if (nla) iface_subnet = nla_data(nla); break; case ISCSI_NET_PARAM_IPV4_SUBNET: iface_subnet = iface_param; nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_ADDR); if (nla) iface_ip = nla_data(nla); break; default: beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : Unsupported param %d\n", iface_param->param); } if (!iface_ip || !iface_subnet) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : IP and Subnet Mask required\n"); return -EINVAL; } ret = mgmt_set_ip(phba, iface_ip, iface_subnet, ISCSI_BOOTPROTO_STATIC); return ret; }
static int beiscsi_set_ipv4(struct Scsi_Host *shost, struct iscsi_iface_param_info *iface_param, void *data, uint32_t dt_len) { struct beiscsi_hba *phba = iscsi_host_priv(shost); int ret = 0; /* Check the param */ switch (iface_param->param) { case ISCSI_NET_PARAM_IPV4_GW: ret = mgmt_set_gateway(phba, iface_param); break; case ISCSI_NET_PARAM_IPV4_BOOTPROTO: if (iface_param->value[0] == ISCSI_BOOTPROTO_DHCP) ret = mgmt_set_ip(phba, iface_param, NULL, ISCSI_BOOTPROTO_DHCP); else if (iface_param->value[0] == ISCSI_BOOTPROTO_STATIC) ret = beiscsi_set_static_ip(shost, iface_param, data, dt_len); else beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : Invalid BOOTPROTO: %d\n", iface_param->value[0]); break; case ISCSI_NET_PARAM_IFACE_ENABLE: if (iface_param->value[0] == ISCSI_IFACE_ENABLE) ret = beiscsi_create_ipv4_iface(phba); else iscsi_destroy_iface(phba->ipv4_iface); break; case ISCSI_NET_PARAM_IPV4_SUBNET: case ISCSI_NET_PARAM_IPV4_ADDR: ret = beiscsi_set_static_ip(shost, iface_param, data, dt_len); break; case ISCSI_NET_PARAM_VLAN_ENABLED: case ISCSI_NET_PARAM_VLAN_TAG: ret = beiscsi_set_vlan_tag(shost, iface_param); break; default: beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : Param %d not supported\n", iface_param->param); } return ret; }
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; }
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; }
static int beiscsi_set_ipv6(struct Scsi_Host *shost, struct iscsi_iface_param_info *iface_param, void *data, uint32_t dt_len) { struct beiscsi_hba *phba = iscsi_host_priv(shost); int ret = 0; switch (iface_param->param) { case ISCSI_NET_PARAM_IFACE_ENABLE: if (iface_param->value[0] == ISCSI_IFACE_ENABLE) ret = beiscsi_create_ipv6_iface(phba); else { iscsi_destroy_iface(phba->ipv6_iface); ret = 0; } break; case ISCSI_NET_PARAM_IPV6_ADDR: ret = mgmt_set_ip(phba, iface_param, NULL, ISCSI_BOOTPROTO_STATIC); break; default: beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : Param %d not supported\n", iface_param->param); } return ret; }
/** * beiscsi_conn_create - create an instance of iscsi connection * @cls_session: ptr to iscsi_cls_session * @cid: iscsi cid */ struct iscsi_cls_conn * beiscsi_conn_create(struct iscsi_cls_session *cls_session, u32 cid) { struct beiscsi_hba *phba; struct Scsi_Host *shost; struct iscsi_cls_conn *cls_conn; struct beiscsi_conn *beiscsi_conn; struct iscsi_conn *conn; struct iscsi_session *sess; struct beiscsi_session *beiscsi_sess; shost = iscsi_session_to_shost(cls_session); phba = iscsi_host_priv(shost); beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, "BS_%d : In beiscsi_conn_create ,cid" "from iscsi layer=%d\n", cid); cls_conn = iscsi_conn_setup(cls_session, sizeof(*beiscsi_conn), cid); if (!cls_conn) return NULL; conn = cls_conn->dd_data; beiscsi_conn = conn->dd_data; beiscsi_conn->ep = NULL; beiscsi_conn->phba = phba; beiscsi_conn->conn = conn; sess = cls_session->dd_data; beiscsi_sess = sess->dd_data; beiscsi_conn->beiscsi_sess = beiscsi_sess; return cls_conn; }
/** * beiscsi_conn_bind - Binds iscsi session/connection with TCP connection * @cls_session: pointer to iscsi cls session * @cls_conn: pointer to iscsi cls conn * @transport_fd: EP handle(64 bit) * * This function binds the TCP Conn with iSCSI Connection and Session. */ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session, struct iscsi_cls_conn *cls_conn, u64 transport_fd, int is_leading) { struct iscsi_conn *conn = cls_conn->dd_data; struct beiscsi_conn *beiscsi_conn = conn->dd_data; struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); struct beiscsi_hba *phba = iscsi_host_priv(shost); struct hwi_controller *phwi_ctrlr = phba->phwi_ctrlr; struct hwi_wrb_context *pwrb_context; struct beiscsi_endpoint *beiscsi_ep; struct iscsi_endpoint *ep; ep = iscsi_lookup_endpoint(transport_fd); if (!ep) return -EINVAL; beiscsi_ep = ep->dd_data; if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) return -EINVAL; if (beiscsi_ep->phba != phba) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : beiscsi_ep->hba=%p not equal to phba=%p\n", beiscsi_ep->phba, phba); return -EEXIST; } pwrb_context = &phwi_ctrlr->wrb_context[BE_GET_CRI_FROM_CID( beiscsi_ep->ep_cid)]; beiscsi_conn->beiscsi_conn_cid = beiscsi_ep->ep_cid; beiscsi_conn->ep = beiscsi_ep; beiscsi_ep->conn = beiscsi_conn; beiscsi_conn->doorbell_offset = pwrb_context->doorbell_offset; beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, "BS_%d : beiscsi_conn=%p conn=%p ep_cid=%d\n", beiscsi_conn, conn, beiscsi_ep->ep_cid); return beiscsi_bindconn_cid(phba, beiscsi_conn, beiscsi_ep->ep_cid); }
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; }
/** * beiscsi_bindconn_cid - Bind the beiscsi_conn with phba connection table * @beiscsi_conn: The pointer to beiscsi_conn structure * @phba: The phba instance * @cid: The cid to free */ static int beiscsi_bindconn_cid(struct beiscsi_hba *phba, struct beiscsi_conn *beiscsi_conn, unsigned int cid) { uint16_t cri_index = BE_GET_CRI_FROM_CID(cid); if (phba->conn_table[cri_index]) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : Connection table already occupied. Detected clash\n"); return -EINVAL; } else { beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, "BS_%d : phba->conn_table[%d]=%p(beiscsi_conn)\n", cri_index, beiscsi_conn); phba->conn_table[cri_index] = beiscsi_conn; } return 0; }
static int beiscsi_create_ipv6_iface(struct beiscsi_hba *phba) { if (phba->ipv6_iface) return 0; phba->ipv6_iface = iscsi_create_iface(phba->shost, &beiscsi_iscsi_transport, ISCSI_IFACE_TYPE_IPV6, 0, 0); if (!phba->ipv6_iface) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : Could not " "create default IPv6 address.\n"); return -ENODEV; } return 0; }
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; }
/** * 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; }
/** * mgmt_get_fw_config()- Get the FW config for the function * @ctrl: ptr to Ctrl Info * @phba: ptr to the dev priv structure * * Get the FW config and resources available for the function. * The resources are created based on the count received here. * * return * Success: 0 * Failure: Non-Zero Value **/ 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, EMBED_MBX_MAX_PAYLOAD_SIZE); status = be_mbox_notify(ctrl); if (!status) { uint8_t ulp_num = 0; struct be_fw_cfg *pfw_cfg; pfw_cfg = req; if (!is_chip_be2_be3r(phba)) { phba->fw_config.eqid_count = pfw_cfg->eqid_count; phba->fw_config.cqid_count = pfw_cfg->cqid_count; beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, "BG_%d : EQ_Count : %d CQ_Count : %d\n", phba->fw_config.eqid_count, phba->fw_config.cqid_count); } for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) if (pfw_cfg->ulp[ulp_num].ulp_mode & BEISCSI_ULP_ISCSI_INI_MODE) set_bit(ulp_num, &phba->fw_config.ulp_supported); phba->fw_config.phys_port = pfw_cfg->phys_port; for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) { phba->fw_config.iscsi_cid_start[ulp_num] = pfw_cfg->ulp[ulp_num].sq_base; phba->fw_config.iscsi_cid_count[ulp_num] = pfw_cfg->ulp[ulp_num].sq_count; phba->fw_config.iscsi_icd_start[ulp_num] = pfw_cfg->ulp[ulp_num].icd_base; phba->fw_config.iscsi_icd_count[ulp_num] = pfw_cfg->ulp[ulp_num].icd_count; phba->fw_config.iscsi_chain_start[ulp_num] = pfw_cfg->chain_icd[ulp_num].chain_base; phba->fw_config.iscsi_chain_count[ulp_num] = pfw_cfg->chain_icd[ulp_num].chain_count; beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, "BG_%d : Function loaded on ULP : %d\n" "\tiscsi_cid_count : %d\n" "\tiscsi_cid_start : %d\n" "\t iscsi_icd_count : %d\n" "\t iscsi_icd_start : %d\n", ulp_num, phba->fw_config. iscsi_cid_count[ulp_num], phba->fw_config. iscsi_cid_start[ulp_num], phba->fw_config. iscsi_icd_count[ulp_num], phba->fw_config. iscsi_icd_start[ulp_num]); } } phba->fw_config.dual_ulp_aware = (pfw_cfg->function_mode & BEISCSI_FUNC_DUA_MODE); beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, "BG_%d : DUA Mode : 0x%x\n", phba->fw_config.dual_ulp_aware); } else { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BG_%d : Failed in mgmt_get_fw_config\n"); status = -EINVAL; } spin_unlock(&ctrl->mbox_lock); return status; }
static int beiscsi_iface_config_ipv4(struct Scsi_Host *shost, struct iscsi_iface_param_info *info, void *data, uint32_t dt_len) { struct beiscsi_hba *phba = iscsi_host_priv(shost); u8 *ip = NULL, *subnet = NULL, *gw; struct nlattr *nla; int ret = -EPERM; /* Check the param */ switch (info->param) { case ISCSI_NET_PARAM_IFACE_ENABLE: if (info->value[0] == ISCSI_IFACE_ENABLE) ret = beiscsi_iface_create_ipv4(phba); else { iscsi_destroy_iface(phba->ipv4_iface); phba->ipv4_iface = NULL; } break; case ISCSI_NET_PARAM_IPV4_GW: gw = info->value; ret = beiscsi_if_set_gw(phba, BEISCSI_IP_TYPE_V4, gw); break; case ISCSI_NET_PARAM_IPV4_BOOTPROTO: if (info->value[0] == ISCSI_BOOTPROTO_DHCP) ret = beiscsi_if_en_dhcp(phba, BEISCSI_IP_TYPE_V4); else if (info->value[0] == ISCSI_BOOTPROTO_STATIC) /* release DHCP IP address */ ret = beiscsi_if_en_static(phba, BEISCSI_IP_TYPE_V4, NULL, NULL); else beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : Invalid BOOTPROTO: %d\n", info->value[0]); break; case ISCSI_NET_PARAM_IPV4_ADDR: ip = info->value; nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_SUBNET); if (nla) { info = nla_data(nla); subnet = info->value; } ret = beiscsi_if_en_static(phba, BEISCSI_IP_TYPE_V4, ip, subnet); break; case ISCSI_NET_PARAM_IPV4_SUBNET: /* * OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR ioctl needs IP * and subnet both. Find IP to be applied for this subnet. */ subnet = info->value; nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_ADDR); if (nla) { info = nla_data(nla); ip = info->value; } ret = beiscsi_if_en_static(phba, BEISCSI_IP_TYPE_V4, ip, subnet); break; } return ret; }
/** * beiscsi_session_create - creates a new iscsi session * @cmds_max: max commands supported * @qdepth: max queue depth supported * @initial_cmdsn: initial iscsi CMDSN */ struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep, u16 cmds_max, u16 qdepth, u32 initial_cmdsn) { struct Scsi_Host *shost; struct beiscsi_endpoint *beiscsi_ep; struct iscsi_cls_session *cls_session; struct beiscsi_hba *phba; struct iscsi_session *sess; struct beiscsi_session *beiscsi_sess; struct beiscsi_io_task *io_task; if (!ep) { printk(KERN_ERR "beiscsi_session_create: invalid ep\n"); return NULL; } beiscsi_ep = ep->dd_data; phba = beiscsi_ep->phba; if (phba->state & BE_ADAPTER_PCI_ERR) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : PCI_ERROR Recovery\n"); return NULL; } else { beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, "BS_%d : In beiscsi_session_create\n"); } if (cmds_max > beiscsi_ep->phba->params.wrbs_per_cxn) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : Cannot handle %d cmds." "Max cmds per session supported is %d. Using %d." "\n", cmds_max, beiscsi_ep->phba->params.wrbs_per_cxn, beiscsi_ep->phba->params.wrbs_per_cxn); cmds_max = beiscsi_ep->phba->params.wrbs_per_cxn; } shost = phba->shost; cls_session = iscsi_session_setup(&beiscsi_iscsi_transport, shost, cmds_max, sizeof(*beiscsi_sess), sizeof(*io_task), initial_cmdsn, ISCSI_MAX_TARGET); if (!cls_session) return NULL; sess = cls_session->dd_data; beiscsi_sess = sess->dd_data; beiscsi_sess->bhs_pool = pci_pool_create("beiscsi_bhs_pool", phba->pcidev, sizeof(struct be_cmd_bhs), 64, 0); if (!beiscsi_sess->bhs_pool) goto destroy_sess; return cls_session; destroy_sess: iscsi_session_teardown(cls_session); return NULL; }
int beiscsi_iface_set_param(struct Scsi_Host *shost, void *data, uint32_t dt_len) { struct iscsi_iface_param_info *iface_param = NULL; struct beiscsi_hba *phba = iscsi_host_priv(shost); struct nlattr *attrib; uint32_t rm_len = dt_len; int ret; if (!beiscsi_hba_is_online(phba)) { beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, "BS_%d : HBA in error 0x%lx\n", phba->state); return -EBUSY; } /* update interface_handle */ ret = beiscsi_if_get_handle(phba); if (ret) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : Getting Interface Handle Failed\n"); return ret; } nla_for_each_attr(attrib, data, dt_len, rm_len) { iface_param = nla_data(attrib); if (iface_param->param_type != ISCSI_NET_PARAM) continue; /* * BE2ISCSI only supports 1 interface */ if (iface_param->iface_num) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : Invalid iface_num %d." "Only iface_num 0 is supported.\n", iface_param->iface_num); return -EINVAL; } beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, "BS_%d : %s.0 set param %d", (iface_param->iface_type == ISCSI_IFACE_TYPE_IPV4) ? "ipv4" : "ipv6", iface_param->param); ret = -EPERM; switch (iface_param->param) { case ISCSI_NET_PARAM_VLAN_ENABLED: case ISCSI_NET_PARAM_VLAN_TAG: ret = beiscsi_iface_config_vlan(shost, iface_param); break; default: switch (iface_param->iface_type) { case ISCSI_IFACE_TYPE_IPV4: ret = beiscsi_iface_config_ipv4(shost, iface_param, data, dt_len); break; case ISCSI_IFACE_TYPE_IPV6: ret = beiscsi_iface_config_ipv6(shost, iface_param, data, dt_len); break; } } if (ret == -EPERM) { __beiscsi_log(phba, KERN_ERR, "BS_%d : %s.0 set param %d not permitted", (iface_param->iface_type == ISCSI_IFACE_TYPE_IPV4) ? "ipv4" : "ipv6", iface_param->param); ret = 0; } if (ret) break; }
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); 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); 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]; offset = bsg_req->rqst_data.h_vendor.vendor_cmd[4]; req->region = region; req->sector = sector; req->offset = offset; spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); 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]); spin_unlock(&ctrl->mbox_lock); return -ENOSYS; } tag = alloc_mcc_tag(phba); if (!tag) { spin_unlock(&ctrl->mbox_lock); return tag; } 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); spin_unlock(&ctrl->mbox_lock); return tag; }