drm/nv4c/bios: disallow retrieving from prom on nv4x igp's
[cascardo/linux.git] / drivers / scsi / be2iscsi / be_mgmt.c
index 245a959..b2fcac7 100644 (file)
@@ -278,6 +278,18 @@ unsigned int mgmt_get_session_info(struct beiscsi_hba *phba,
        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)
 {
@@ -291,31 +303,79 @@ int mgmt_get_fw_config(struct be_ctrl_info *ctrl,
        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));
+                          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;
-               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;
+               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_WARNING, BEISCSI_LOG_INIT,
+               beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
                            "BG_%d : Failed in mgmt_get_fw_config\n");
+               status = -EINVAL;
        }
 
        spin_unlock(&ctrl->mbox_lock);
@@ -448,7 +508,16 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
        return tag;
 }
 
-int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute)
+/**
+ * mgmt_epfw_cleanup()- Inform FW to cleanup data structures.
+ * @phba: pointer to dev priv structure
+ * @ulp_num: ULP number.
+ *
+ * return
+ *     Success: 0
+ *     Failure: Non-Zero Value
+ **/
+int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short ulp_num)
 {
        struct be_ctrl_info *ctrl = &phba->ctrl;
        struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
@@ -462,9 +531,9 @@ int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute)
        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));
+       req->chute = (1 << ulp_num);
+       req->hdr_ring_id = cpu_to_le16(HWI_GET_DEF_HDRQ_ID(phba, ulp_num));
+       req->data_ring_id = cpu_to_le16(HWI_GET_DEF_BUFQ_ID(phba, ulp_num));
 
        status =  be_mcc_notify_wait(phba);
        if (status)
@@ -585,6 +654,16 @@ unsigned int mgmt_upload_connection(struct beiscsi_hba *phba,
        return tag;
 }
 
+/**
+ * mgmt_open_connection()- Establish a TCP CXN
+ * @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,
@@ -602,14 +681,17 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
        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;
 
        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);
@@ -748,11 +830,14 @@ static int mgmt_exec_nonemb_cmd(struct beiscsi_hba *phba,
 
        rc = beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd->va);
        if (rc) {
+               /* Check if the IOCTL needs to be re-issued */
+               if (rc == -EAGAIN)
+                       return rc;
+
                beiscsi_log(phba, KERN_ERR,
                            BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
                            "BG_%d : mgmt_exec_nonemb_cmd Failed status\n");
 
-               rc = -EIO;
                goto free_cmd;
        }
 
@@ -861,7 +946,7 @@ int mgmt_set_ip(struct beiscsi_hba *phba,
                uint32_t boot_proto)
 {
        struct be_cmd_get_def_gateway_resp gtway_addr_set;
-       struct be_cmd_get_if_info_resp if_info;
+       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;
@@ -872,16 +957,17 @@ int mgmt_set_ip(struct beiscsi_hba *phba,
        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);
-       if (rc)
+       if (rc) {
+               kfree(if_info);
                return rc;
+       }
 
        if (boot_proto == ISCSI_BOOTPROTO_DHCP) {
-               if (if_info.dhcp_state) {
+               if (if_info->dhcp_state) {
                        beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
                                    "BG_%d : DHCP Already Enabled\n");
                        return 0;
@@ -894,9 +980,9 @@ int mgmt_set_ip(struct beiscsi_hba *phba,
                                IP_V6_LEN : IP_V4_LEN;
 
        } else {
-               if (if_info.dhcp_state) {
+               if (if_info->dhcp_state) {
 
-                       memset(&if_info, 0, sizeof(if_info));
+                       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));
@@ -919,8 +1005,8 @@ int mgmt_set_ip(struct beiscsi_hba *phba,
        }
 
        /* Delete the Static IP Set */
-       if (if_info.ip_addr.addr[0]) {
-               rc = mgmt_static_ip_modify(phba, &if_info, ip_param, NULL,
+       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;
@@ -966,7 +1052,7 @@ int mgmt_set_ip(struct beiscsi_hba *phba,
 
                return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0);
        } else {
-               return mgmt_static_ip_modify(phba, &if_info, ip_param,
+               return mgmt_static_ip_modify(phba, if_info, ip_param,
                                             subnet_param, IP_ACTION_ADD);
        }
 
@@ -1031,27 +1117,64 @@ int mgmt_get_gateway(struct beiscsi_hba *phba, int ip_type,
 }
 
 int mgmt_get_if_info(struct beiscsi_hba *phba, int ip_type,
-                    struct be_cmd_get_if_info_resp *if_info)
+                    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;
 
        if (mgmt_get_all_if_id(phba))
                return -EIO;
 
-       rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
-                                OPCODE_COMMON_ISCSI_NTWK_GET_IF_INFO,
-                                sizeof(*if_info));
-       if (rc)
-               return rc;
+       do {
+               rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
+                                        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;
+               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");
+
+                               /* Free the DMA memory for the IOCTL issuing */
+                               pci_free_consistent(phba->ctrl.pdev,
+                                                   nonemb_cmd.size,
+                                                   nonemb_cmd.va,
+                                                   nonemb_cmd.dma);
+                               return -ENOMEM;
+               }
+
+               rc =  mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, *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);
 
-       return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, if_info,
-                                   sizeof(*if_info));
+                       /* Free the previous allocated DMA memory */
+                       pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+                                           nonemb_cmd.va,
+                                           nonemb_cmd.dma);
+
+                       /* Free the virtual memory */
+                       kfree(*if_info);
+               } else
+                       break;
+       } while (true);
+       return rc;
 }
 
 int mgmt_get_nic_conf(struct beiscsi_hba *phba,
@@ -1281,7 +1404,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 +1413,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 += snprintf(buf+len, PAGE_SIZE - len,
+                                       "ULP%d : %d\n", ulp_num,
+                                       (total_cids - avlbl_cids));
+               } else
+                       len += snprintf(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 += snprintf(buf+len, PAGE_SIZE - len,
+                                       "ULP%d : %d\n", ulp_num,
+                                       BEISCSI_ULP_AVLBL_CID(phba, ulp_num));
+               else
+                       len += snprintf(buf+len, PAGE_SIZE - len,
+                                       "ULP%d : %d\n", ulp_num, 0);
+       }
+
+       return len;
 }
 
 /**
@@ -1338,6 +1503,25 @@ beiscsi_adap_family_disp(struct device *dev, struct device_attribute *attr,
        }
 }
 
+/**
+ * beiscsi_phys_port()- 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 : %d\n",
+                       phba->fw_config.phys_port);
+}
 
 void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params,
                             struct wrb_handle *pwrb_handle,
@@ -1411,10 +1595,6 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params,
 
        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,
@@ -1436,7 +1616,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,