[SCSI] be2iscsi: Fix Insufficient Buffer Error returned in MBX Completion
authorJayamohan Kallickal <jayamohank@gmail.com>
Sat, 28 Sep 2013 22:35:56 +0000 (15:35 -0700)
committerJames Bottomley <JBottomley@Parallels.com>
Fri, 25 Oct 2013 08:58:09 +0000 (09:58 +0100)
When MBX_Cmd completion happens with error code Insufficient Buffer,
the MBX_Cmd is posted again with the new buffer size posted by FW.

Signed-off-by: John Soni Jose <sony.john-n@emulex.com>
Signed-off-by: Jayamohan Kallickal <jayamohan.kallickal@emulex.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/be2iscsi/be_cmds.c
drivers/scsi/be2iscsi/be_iscsi.c
drivers/scsi/be2iscsi/be_mgmt.c
drivers/scsi/be2iscsi/be_mgmt.h

index cc37a4e5ce45fb504698b1072d326e66a427c3a7..fce298ba4b41dcfd2d448da49939f67a9e72d85a 100644 (file)
@@ -158,8 +158,10 @@ int beiscsi_mccq_compl(struct beiscsi_hba *phba,
        struct be_cmd_resp_hdr *ioctl_resp_hdr;
        struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
 
-       if (beiscsi_error(phba))
+       if (beiscsi_error(phba)) {
+               free_mcc_tag(&phba->ctrl, tag);
                return -EIO;
+       }
 
        /* wait for the mccq completion */
        rc = wait_event_interruptible_timeout(
@@ -173,7 +175,7 @@ int beiscsi_mccq_compl(struct beiscsi_hba *phba,
                            BEISCSI_LOG_INIT | BEISCSI_LOG_EH |
                            BEISCSI_LOG_CONFIG,
                            "BC_%d : MBX Cmd Completion timed out\n");
-               rc = -EAGAIN;
+               rc = -EBUSY;
 
                /* decrement the mccq used count */
                atomic_dec(&phba->ctrl.mcc_obj.q.used);
@@ -212,10 +214,18 @@ int beiscsi_mccq_compl(struct beiscsi_hba *phba,
 
                if (status == MCC_STATUS_INSUFFICIENT_BUFFER) {
                        ioctl_resp_hdr = (struct be_cmd_resp_hdr *) ioctl_hdr;
-                       if (ioctl_resp_hdr->response_length)
-                               goto release_mcc_tag;
+                       beiscsi_log(phba, KERN_WARNING,
+                                   BEISCSI_LOG_INIT | BEISCSI_LOG_EH |
+                                   BEISCSI_LOG_CONFIG,
+                                   "BC_%d : Insufficent Buffer Error "
+                                   "Resp_Len : %d Actual_Resp_Len : %d\n",
+                                   ioctl_resp_hdr->response_length,
+                                   ioctl_resp_hdr->actual_resp_len);
+
+                       rc = -EAGAIN;
+                       goto release_mcc_tag;
                }
-               rc = -EAGAIN;
+               rc = -EIO;
        }
 
 release_mcc_tag:
index a7cd92c3c383add421a0dc280ed96d68f12d546e..e82ab812495846632a4a0d6528367605c893811b 100644 (file)
@@ -271,13 +271,17 @@ static int beiscsi_create_ipv6_iface(struct beiscsi_hba *phba)
 
 void beiscsi_create_def_ifaces(struct beiscsi_hba *phba)
 {
-       struct be_cmd_get_if_info_resp if_info;
+       struct be_cmd_get_if_info_resp *if_info;
 
-       if (!mgmt_get_if_info(phba, BE2_IPV4, &if_info))
+       if (!mgmt_get_if_info(phba, BE2_IPV4, &if_info)) {
                beiscsi_create_ipv4_iface(phba);
+               kfree(if_info);
+       }
 
-       if (!mgmt_get_if_info(phba, BE2_IPV6, &if_info))
+       if (!mgmt_get_if_info(phba, BE2_IPV6, &if_info)) {
                beiscsi_create_ipv6_iface(phba);
+               kfree(if_info);
+       }
 }
 
 void beiscsi_destroy_def_ifaces(struct beiscsi_hba *phba)
@@ -518,59 +522,60 @@ static int be2iscsi_get_if_param(struct beiscsi_hba *phba,
                struct iscsi_iface *iface, int param,
                char *buf)
 {
-       struct be_cmd_get_if_info_resp if_info;
+       struct be_cmd_get_if_info_resp *if_info;
        int len, ip_type = BE2_IPV4;
 
-       memset(&if_info, 0, sizeof(if_info));
-
        if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6)
                ip_type = BE2_IPV6;
 
        len = mgmt_get_if_info(phba, ip_type, &if_info);
-       if (len)
+       if (len) {
+               kfree(if_info);
                return len;
+       }
 
        switch (param) {
        case ISCSI_NET_PARAM_IPV4_ADDR:
-               len = sprintf(buf, "%pI4\n", &if_info.ip_addr.addr);
+               len = sprintf(buf, "%pI4\n", if_info->ip_addr.addr);
                break;
        case ISCSI_NET_PARAM_IPV6_ADDR:
-               len = sprintf(buf, "%pI6\n", &if_info.ip_addr.addr);
+               len = sprintf(buf, "%pI6\n", if_info->ip_addr.addr);
                break;
        case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
-               if (!if_info.dhcp_state)
+               if (!if_info->dhcp_state)
                        len = sprintf(buf, "static\n");
                else
                        len = sprintf(buf, "dhcp\n");
                break;
        case ISCSI_NET_PARAM_IPV4_SUBNET:
-               len = sprintf(buf, "%pI4\n", &if_info.ip_addr.subnet_mask);
+               len = sprintf(buf, "%pI4\n", if_info->ip_addr.subnet_mask);
                break;
        case ISCSI_NET_PARAM_VLAN_ENABLED:
                len = sprintf(buf, "%s\n",
-                            (if_info.vlan_priority == BEISCSI_VLAN_DISABLE)
+                            (if_info->vlan_priority == BEISCSI_VLAN_DISABLE)
                             ? "Disabled\n" : "Enabled\n");
                break;
        case ISCSI_NET_PARAM_VLAN_ID:
-               if (if_info.vlan_priority == BEISCSI_VLAN_DISABLE)
+               if (if_info->vlan_priority == BEISCSI_VLAN_DISABLE)
                        return -EINVAL;
                else
                        len = sprintf(buf, "%d\n",
-                                    (if_info.vlan_priority &
+                                    (if_info->vlan_priority &
                                     ISCSI_MAX_VLAN_ID));
                break;
        case ISCSI_NET_PARAM_VLAN_PRIORITY:
-               if (if_info.vlan_priority == BEISCSI_VLAN_DISABLE)
+               if (if_info->vlan_priority == BEISCSI_VLAN_DISABLE)
                        return -EINVAL;
                else
                        len = sprintf(buf, "%d\n",
-                                    ((if_info.vlan_priority >> 13) &
+                                    ((if_info->vlan_priority >> 13) &
                                     ISCSI_MAX_VLAN_PRIORITY));
                break;
        default:
                WARN_ON(1);
        }
 
+       kfree(if_info);
        return len;
 }
 
index befeace182579f008f9eb8f37efe7a5165090310..1f2b546a3fc4467213b91065b6529b28c4ada86e 100644 (file)
@@ -824,11 +824,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;
        }
 
@@ -937,7 +940,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;
@@ -948,16 +951,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;
@@ -970,9 +974,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));
@@ -995,8 +999,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;
@@ -1042,7 +1046,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);
        }
 
@@ -1107,27 +1111,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;
+               }
 
-       return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, if_info,
-                                   sizeof(*if_info));
+               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);
+
+                       /* 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,
index 645e144622c98c7087aff92b6c26b6d595e80502..01b8c97284c0653753f6bc8085c47f799ce09f79 100644 (file)
@@ -294,7 +294,7 @@ int mgmt_get_nic_conf(struct beiscsi_hba *phba,
                      struct be_cmd_get_nic_conf_resp *mac);
 
 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);
 
 int mgmt_get_gateway(struct beiscsi_hba *phba, int ip_type,
                     struct be_cmd_get_def_gateway_resp *gateway);