qed: Make PF more robust against malicious VF
[cascardo/linux.git] / drivers / net / ethernet / qlogic / qed / qed_sriov.c
index c325ee8..dce81f5 100644 (file)
 #include "qed_vf.h"
 
 /* IOV ramrods */
-static int qed_sp_vf_start(struct qed_hwfn *p_hwfn,
-                          u32 concrete_vfid, u16 opaque_vfid)
+static int qed_sp_vf_start(struct qed_hwfn *p_hwfn, struct qed_vf_info *p_vf)
 {
        struct vf_start_ramrod_data *p_ramrod = NULL;
        struct qed_spq_entry *p_ent = NULL;
        struct qed_sp_init_data init_data;
        int rc = -EINVAL;
+       u8 fp_minor;
 
        /* Get SPQ entry */
        memset(&init_data, 0, sizeof(init_data));
        init_data.cid = qed_spq_get_cid(p_hwfn);
-       init_data.opaque_fid = opaque_vfid;
+       init_data.opaque_fid = p_vf->opaque_fid;
        init_data.comp_mode = QED_SPQ_MODE_EBLOCK;
 
        rc = qed_sp_init_request(p_hwfn, &p_ent,
@@ -43,10 +43,39 @@ static int qed_sp_vf_start(struct qed_hwfn *p_hwfn,
 
        p_ramrod = &p_ent->ramrod.vf_start;
 
-       p_ramrod->vf_id = GET_FIELD(concrete_vfid, PXP_CONCRETE_FID_VFID);
-       p_ramrod->opaque_fid = cpu_to_le16(opaque_vfid);
+       p_ramrod->vf_id = GET_FIELD(p_vf->concrete_fid, PXP_CONCRETE_FID_VFID);
+       p_ramrod->opaque_fid = cpu_to_le16(p_vf->opaque_fid);
+
+       switch (p_hwfn->hw_info.personality) {
+       case QED_PCI_ETH:
+               p_ramrod->personality = PERSONALITY_ETH;
+               break;
+       case QED_PCI_ETH_ROCE:
+               p_ramrod->personality = PERSONALITY_RDMA_AND_ETH;
+               break;
+       default:
+               DP_NOTICE(p_hwfn, "Unknown VF personality %d\n",
+                         p_hwfn->hw_info.personality);
+               return -EINVAL;
+       }
+
+       fp_minor = p_vf->acquire.vfdev_info.eth_fp_hsi_minor;
+       if (fp_minor > ETH_HSI_VER_MINOR) {
+               DP_VERBOSE(p_hwfn,
+                          QED_MSG_IOV,
+                          "VF [%d] - Requested fp hsi %02x.%02x which is slightly newer than PF's %02x.%02x; Configuring PFs version\n",
+                          p_vf->abs_vf_id,
+                          ETH_HSI_VER_MAJOR,
+                          fp_minor, ETH_HSI_VER_MAJOR, ETH_HSI_VER_MINOR);
+               fp_minor = ETH_HSI_VER_MINOR;
+       }
 
-       p_ramrod->personality = PERSONALITY_ETH;
+       p_ramrod->hsi_fp_ver.major_ver_arr[ETH_VER_KEY] = ETH_HSI_VER_MAJOR;
+       p_ramrod->hsi_fp_ver.minor_ver_arr[ETH_VER_KEY] = fp_minor;
+
+       DP_VERBOSE(p_hwfn, QED_MSG_IOV,
+                  "VF[%d] - Starting using HSI %02x.%02x\n",
+                  p_vf->abs_vf_id, ETH_HSI_VER_MAJOR, fp_minor);
 
        return qed_spq_post(p_hwfn, p_ent, NULL);
 }
@@ -117,6 +146,45 @@ static struct qed_vf_info *qed_iov_get_vf_info(struct qed_hwfn *p_hwfn,
        return vf;
 }
 
+static bool qed_iov_validate_rxq(struct qed_hwfn *p_hwfn,
+                                struct qed_vf_info *p_vf, u16 rx_qid)
+{
+       if (rx_qid >= p_vf->num_rxqs)
+               DP_VERBOSE(p_hwfn,
+                          QED_MSG_IOV,
+                          "VF[0x%02x] - can't touch Rx queue[%04x]; Only 0x%04x are allocated\n",
+                          p_vf->abs_vf_id, rx_qid, p_vf->num_rxqs);
+       return rx_qid < p_vf->num_rxqs;
+}
+
+static bool qed_iov_validate_txq(struct qed_hwfn *p_hwfn,
+                                struct qed_vf_info *p_vf, u16 tx_qid)
+{
+       if (tx_qid >= p_vf->num_txqs)
+               DP_VERBOSE(p_hwfn,
+                          QED_MSG_IOV,
+                          "VF[0x%02x] - can't touch Tx queue[%04x]; Only 0x%04x are allocated\n",
+                          p_vf->abs_vf_id, tx_qid, p_vf->num_txqs);
+       return tx_qid < p_vf->num_txqs;
+}
+
+static bool qed_iov_validate_sb(struct qed_hwfn *p_hwfn,
+                               struct qed_vf_info *p_vf, u16 sb_idx)
+{
+       int i;
+
+       for (i = 0; i < p_vf->num_sbs; i++)
+               if (p_vf->igu_sbs[i] == sb_idx)
+                       return true;
+
+       DP_VERBOSE(p_hwfn,
+                  QED_MSG_IOV,
+                  "VF[0%02x] - tried using sb_idx %04x which doesn't exist as one of its 0x%02x SBs\n",
+                  p_vf->abs_vf_id, sb_idx, p_vf->num_sbs);
+
+       return false;
+}
+
 int qed_iov_post_vf_bulletin(struct qed_hwfn *p_hwfn,
                             int vfid, struct qed_ptt *p_ptt)
 {
@@ -293,6 +361,9 @@ static void qed_iov_setup_vfdb(struct qed_hwfn *p_hwfn)
                vf->opaque_fid = (p_hwfn->hw_info.opaque_fid & 0xff) |
                                 (vf->abs_vf_id << 8);
                vf->vport_id = idx + 1;
+
+               vf->num_mac_filters = QED_ETH_VF_NUM_MAC_FILTERS;
+               vf->num_vlan_filters = QED_ETH_VF_NUM_VLAN_FILTERS;
        }
 }
 
@@ -598,17 +669,6 @@ static int qed_iov_enable_vf_access(struct qed_hwfn *p_hwfn,
        /* unpretend */
        qed_fid_pretend(p_hwfn, p_ptt, (u16) p_hwfn->hw_info.concrete_fid);
 
-       if (vf->state != VF_STOPPED) {
-               DP_NOTICE(p_hwfn, "VF[%02x] is already started\n",
-                         vf->abs_vf_id);
-               return -EINVAL;
-       }
-
-       /* Start VF */
-       rc = qed_sp_vf_start(p_hwfn, vf->concrete_fid, vf->opaque_fid);
-       if (rc)
-               DP_NOTICE(p_hwfn, "Failed to start VF[%02x]\n", vf->abs_vf_id);
-
        vf->state = VF_FREE;
 
        return rc;
@@ -852,7 +912,6 @@ static int qed_iov_release_hw_for_vf(struct qed_hwfn *p_hwfn,
        struct qed_mcp_link_params params;
        struct qed_mcp_link_state link;
        struct qed_vf_info *vf = NULL;
-       int rc = 0;
 
        vf = qed_iov_get_vf_info(p_hwfn, rel_vf_id, true);
        if (!vf) {
@@ -874,18 +933,8 @@ static int qed_iov_release_hw_for_vf(struct qed_hwfn *p_hwfn,
        memcpy(&caps, qed_mcp_get_link_capabilities(p_hwfn), sizeof(caps));
        qed_iov_set_link(p_hwfn, rel_vf_id, &params, &link, &caps);
 
-       if (vf->state != VF_STOPPED) {
-               /* Stopping the VF */
-               rc = qed_sp_vf_stop(p_hwfn, vf->concrete_fid, vf->opaque_fid);
-
-               if (rc != 0) {
-                       DP_ERR(p_hwfn, "qed_sp_vf_stop returned error %d\n",
-                              rc);
-                       return rc;
-               }
-
-               vf->state = VF_STOPPED;
-       }
+       /* Forget the VF's acquisition message */
+       memset(&vf->acquire, 0, sizeof(vf->acquire));
 
        /* disablng interrupts and resetting permission table was done during
         * vf-close, however, we could get here without going through vf_close
@@ -1116,8 +1165,6 @@ static void qed_iov_vf_cleanup(struct qed_hwfn *p_hwfn,
 
        p_vf->vf_bulletin = 0;
        p_vf->vport_instance = 0;
-       p_vf->num_mac_filters = 0;
-       p_vf->num_vlan_filters = 0;
        p_vf->configured_features = 0;
 
        /* If VF previously requested less resources, go back to default */
@@ -1130,9 +1177,95 @@ static void qed_iov_vf_cleanup(struct qed_hwfn *p_hwfn,
                p_vf->vf_queues[i].rxq_active = 0;
 
        memset(&p_vf->shadow_config, 0, sizeof(p_vf->shadow_config));
+       memset(&p_vf->acquire, 0, sizeof(p_vf->acquire));
        qed_iov_clean_vf(p_hwfn, p_vf->relative_vf_id);
 }
 
+static u8 qed_iov_vf_mbx_acquire_resc(struct qed_hwfn *p_hwfn,
+                                     struct qed_ptt *p_ptt,
+                                     struct qed_vf_info *p_vf,
+                                     struct vf_pf_resc_request *p_req,
+                                     struct pf_vf_resc *p_resp)
+{
+       int i;
+
+       /* Queue related information */
+       p_resp->num_rxqs = p_vf->num_rxqs;
+       p_resp->num_txqs = p_vf->num_txqs;
+       p_resp->num_sbs = p_vf->num_sbs;
+
+       for (i = 0; i < p_resp->num_sbs; i++) {
+               p_resp->hw_sbs[i].hw_sb_id = p_vf->igu_sbs[i];
+               p_resp->hw_sbs[i].sb_qid = 0;
+       }
+
+       /* These fields are filled for backward compatibility.
+        * Unused by modern vfs.
+        */
+       for (i = 0; i < p_resp->num_rxqs; i++) {
+               qed_fw_l2_queue(p_hwfn, p_vf->vf_queues[i].fw_rx_qid,
+                               (u16 *)&p_resp->hw_qid[i]);
+               p_resp->cid[i] = p_vf->vf_queues[i].fw_cid;
+       }
+
+       /* Filter related information */
+       p_resp->num_mac_filters = min_t(u8, p_vf->num_mac_filters,
+                                       p_req->num_mac_filters);
+       p_resp->num_vlan_filters = min_t(u8, p_vf->num_vlan_filters,
+                                        p_req->num_vlan_filters);
+
+       /* This isn't really needed/enforced, but some legacy VFs might depend
+        * on the correct filling of this field.
+        */
+       p_resp->num_mc_filters = QED_MAX_MC_ADDRS;
+
+       /* Validate sufficient resources for VF */
+       if (p_resp->num_rxqs < p_req->num_rxqs ||
+           p_resp->num_txqs < p_req->num_txqs ||
+           p_resp->num_sbs < p_req->num_sbs ||
+           p_resp->num_mac_filters < p_req->num_mac_filters ||
+           p_resp->num_vlan_filters < p_req->num_vlan_filters ||
+           p_resp->num_mc_filters < p_req->num_mc_filters) {
+               DP_VERBOSE(p_hwfn,
+                          QED_MSG_IOV,
+                          "VF[%d] - Insufficient resources: rxq [%02x/%02x] txq [%02x/%02x] sbs [%02x/%02x] mac [%02x/%02x] vlan [%02x/%02x] mc [%02x/%02x]\n",
+                          p_vf->abs_vf_id,
+                          p_req->num_rxqs,
+                          p_resp->num_rxqs,
+                          p_req->num_rxqs,
+                          p_resp->num_txqs,
+                          p_req->num_sbs,
+                          p_resp->num_sbs,
+                          p_req->num_mac_filters,
+                          p_resp->num_mac_filters,
+                          p_req->num_vlan_filters,
+                          p_resp->num_vlan_filters,
+                          p_req->num_mc_filters, p_resp->num_mc_filters);
+               return PFVF_STATUS_NO_RESOURCE;
+       }
+
+       return PFVF_STATUS_SUCCESS;
+}
+
+static void qed_iov_vf_mbx_acquire_stats(struct qed_hwfn *p_hwfn,
+                                        struct pfvf_stats_info *p_stats)
+{
+       p_stats->mstats.address = PXP_VF_BAR0_START_MSDM_ZONE_B +
+                                 offsetof(struct mstorm_vf_zone,
+                                          non_trigger.eth_queue_stat);
+       p_stats->mstats.len = sizeof(struct eth_mstorm_per_queue_stat);
+       p_stats->ustats.address = PXP_VF_BAR0_START_USDM_ZONE_B +
+                                 offsetof(struct ustorm_vf_zone,
+                                          non_trigger.eth_queue_stat);
+       p_stats->ustats.len = sizeof(struct eth_ustorm_per_queue_stat);
+       p_stats->pstats.address = PXP_VF_BAR0_START_PSDM_ZONE_B +
+                                 offsetof(struct pstorm_vf_zone,
+                                          non_trigger.eth_queue_stat);
+       p_stats->pstats.len = sizeof(struct eth_pstorm_per_queue_stat);
+       p_stats->tstats.address = 0;
+       p_stats->tstats.len = 0;
+}
+
 static void qed_iov_vf_mbx_acquire(struct qed_hwfn *p_hwfn,
                                   struct qed_ptt *p_ptt,
                                   struct qed_vf_info *vf)
@@ -1141,25 +1274,27 @@ static void qed_iov_vf_mbx_acquire(struct qed_hwfn *p_hwfn,
        struct pfvf_acquire_resp_tlv *resp = &mbx->reply_virt->acquire_resp;
        struct pf_vf_pfdev_info *pfdev_info = &resp->pfdev_info;
        struct vfpf_acquire_tlv *req = &mbx->req_virt->acquire;
-       u8 i, vfpf_status = PFVF_STATUS_SUCCESS;
+       u8 vfpf_status = PFVF_STATUS_NOT_SUPPORTED;
        struct pf_vf_resc *resc = &resp->resc;
+       int rc;
+
+       memset(resp, 0, sizeof(*resp));
 
        /* Validate FW compatibility */
-       if (req->vfdev_info.fw_major != FW_MAJOR_VERSION ||
-           req->vfdev_info.fw_minor != FW_MINOR_VERSION ||
-           req->vfdev_info.fw_revision != FW_REVISION_VERSION ||
-           req->vfdev_info.fw_engineering != FW_ENGINEERING_VERSION) {
+       if (req->vfdev_info.eth_fp_hsi_major != ETH_HSI_VER_MAJOR) {
                DP_INFO(p_hwfn,
-                       "VF[%d] is running an incompatible driver [VF needs FW %02x:%02x:%02x:%02x but Hypervisor is using %02x:%02x:%02x:%02x]\n",
+                       "VF[%d] needs fastpath HSI %02x.%02x, which is incompatible with loaded FW's faspath HSI %02x.%02x\n",
                        vf->abs_vf_id,
-                       req->vfdev_info.fw_major,
-                       req->vfdev_info.fw_minor,
-                       req->vfdev_info.fw_revision,
-                       req->vfdev_info.fw_engineering,
-                       FW_MAJOR_VERSION,
-                       FW_MINOR_VERSION,
-                       FW_REVISION_VERSION, FW_ENGINEERING_VERSION);
-               vfpf_status = PFVF_STATUS_NOT_SUPPORTED;
+                       req->vfdev_info.eth_fp_hsi_major,
+                       req->vfdev_info.eth_fp_hsi_minor,
+                       ETH_HSI_VER_MAJOR, ETH_HSI_VER_MINOR);
+
+               /* Write the PF version so that VF would know which version
+                * is supported.
+                */
+               pfdev_info->major_fp_hsi = ETH_HSI_VER_MAJOR;
+               pfdev_info->minor_fp_hsi = ETH_HSI_VER_MINOR;
+
                goto out;
        }
 
@@ -1169,16 +1304,13 @@ static void qed_iov_vf_mbx_acquire(struct qed_hwfn *p_hwfn,
                DP_INFO(p_hwfn,
                        "VF[%d] is running an old driver that doesn't support 100g\n",
                        vf->abs_vf_id);
-               vfpf_status = PFVF_STATUS_NOT_SUPPORTED;
                goto out;
        }
 
-       memset(resp, 0, sizeof(*resp));
+       /* Store the acquire message */
+       memcpy(&vf->acquire, req, sizeof(vf->acquire));
 
-       /* Fill in vf info stuff */
        vf->opaque_fid = req->vfdev_info.opaque_fid;
-       vf->num_mac_filters = 1;
-       vf->num_vlan_filters = QED_ETH_VF_NUM_VLAN_FILTERS;
 
        vf->vf_bulletin = req->bulletin_addr;
        vf->bulletin.size = (vf->bulletin.size < req->bulletin_size) ?
@@ -1194,26 +1326,7 @@ static void qed_iov_vf_mbx_acquire(struct qed_hwfn *p_hwfn,
        if (p_hwfn->cdev->num_hwfns > 1)
                pfdev_info->capabilities |= PFVF_ACQUIRE_CAP_100G;
 
-       pfdev_info->stats_info.mstats.address =
-           PXP_VF_BAR0_START_MSDM_ZONE_B +
-           offsetof(struct mstorm_vf_zone, non_trigger.eth_queue_stat);
-       pfdev_info->stats_info.mstats.len =
-           sizeof(struct eth_mstorm_per_queue_stat);
-
-       pfdev_info->stats_info.ustats.address =
-           PXP_VF_BAR0_START_USDM_ZONE_B +
-           offsetof(struct ustorm_vf_zone, non_trigger.eth_queue_stat);
-       pfdev_info->stats_info.ustats.len =
-           sizeof(struct eth_ustorm_per_queue_stat);
-
-       pfdev_info->stats_info.pstats.address =
-           PXP_VF_BAR0_START_PSDM_ZONE_B +
-           offsetof(struct pstorm_vf_zone, non_trigger.eth_queue_stat);
-       pfdev_info->stats_info.pstats.len =
-           sizeof(struct eth_pstorm_per_queue_stat);
-
-       pfdev_info->stats_info.tstats.address = 0;
-       pfdev_info->stats_info.tstats.len = 0;
+       qed_iov_vf_mbx_acquire_stats(p_hwfn, &pfdev_info->stats_info);
 
        memcpy(pfdev_info->port_mac, p_hwfn->hw_info.hw_mac_addr, ETH_ALEN);
 
@@ -1221,36 +1334,31 @@ static void qed_iov_vf_mbx_acquire(struct qed_hwfn *p_hwfn,
        pfdev_info->fw_minor = FW_MINOR_VERSION;
        pfdev_info->fw_rev = FW_REVISION_VERSION;
        pfdev_info->fw_eng = FW_ENGINEERING_VERSION;
+       pfdev_info->minor_fp_hsi = min_t(u8,
+                                        ETH_HSI_VER_MINOR,
+                                        req->vfdev_info.eth_fp_hsi_minor);
        pfdev_info->os_type = VFPF_ACQUIRE_OS_LINUX;
        qed_mcp_get_mfw_ver(p_hwfn, p_ptt, &pfdev_info->mfw_ver, NULL);
 
        pfdev_info->dev_type = p_hwfn->cdev->type;
        pfdev_info->chip_rev = p_hwfn->cdev->chip_rev;
 
-       resc->num_rxqs = vf->num_rxqs;
-       resc->num_txqs = vf->num_txqs;
-       resc->num_sbs = vf->num_sbs;
-       for (i = 0; i < resc->num_sbs; i++) {
-               resc->hw_sbs[i].hw_sb_id = vf->igu_sbs[i];
-               resc->hw_sbs[i].sb_qid = 0;
-       }
+       /* Fill resources available to VF; Make sure there are enough to
+        * satisfy the VF's request.
+        */
+       vfpf_status = qed_iov_vf_mbx_acquire_resc(p_hwfn, p_ptt, vf,
+                                                 &req->resc_request, resc);
+       if (vfpf_status != PFVF_STATUS_SUCCESS)
+               goto out;
 
-       for (i = 0; i < resc->num_rxqs; i++) {
-               qed_fw_l2_queue(p_hwfn, vf->vf_queues[i].fw_rx_qid,
-                               (u16 *)&resc->hw_qid[i]);
-               resc->cid[i] = vf->vf_queues[i].fw_cid;
+       /* Start the VF in FW */
+       rc = qed_sp_vf_start(p_hwfn, vf);
+       if (rc) {
+               DP_NOTICE(p_hwfn, "Failed to start VF[%02x]\n", vf->abs_vf_id);
+               vfpf_status = PFVF_STATUS_FAILURE;
+               goto out;
        }
 
-       resc->num_mac_filters = min_t(u8, vf->num_mac_filters,
-                                     req->resc_request.num_mac_filters);
-       resc->num_vlan_filters = min_t(u8, vf->num_vlan_filters,
-                                      req->resc_request.num_vlan_filters);
-
-       /* This isn't really required as VF isn't limited, but some VFs might
-        * actually test this value, so need to provide it.
-        */
-       resc->num_mc_filters = req->resc_request.num_mc_filters;
-
        /* Fill agreed size of bulletin board in response */
        resp->bulletin_size = vf->bulletin.size;
        qed_iov_post_vf_bulletin(p_hwfn, vf->relative_vf_id, p_ptt);
@@ -1585,10 +1693,6 @@ static void qed_iov_vf_mbx_stop_vport(struct qed_hwfn *p_hwfn,
                             sizeof(struct pfvf_def_resp_tlv), status);
 }
 
-#define TSTORM_QZONE_START   PXP_VF_BAR0_START_SDM_ZONE_A
-#define MSTORM_QZONE_START(dev)   (TSTORM_QZONE_START +        \
-                                  (TSTORM_QZONE_SIZE * NUM_OF_L2_QUEUES(dev)))
-
 static void qed_iov_vf_mbx_start_rxq_resp(struct qed_hwfn *p_hwfn,
                                          struct qed_ptt *p_ptt,
                                          struct qed_vf_info *vf, u8 status)
@@ -1606,16 +1710,11 @@ static void qed_iov_vf_mbx_start_rxq_resp(struct qed_hwfn *p_hwfn,
 
        /* Update the TLV with the response */
        if (status == PFVF_STATUS_SUCCESS) {
-               u16 hw_qid = 0;
-
                req = &mbx->req_virt->start_rxq;
-               qed_fw_l2_queue(p_hwfn, vf->vf_queues[req->rx_qid].fw_rx_qid,
-                               &hw_qid);
-
-               p_tlv->offset = MSTORM_QZONE_START(p_hwfn->cdev) +
-                               hw_qid * MSTORM_QZONE_SIZE +
-                               offsetof(struct mstorm_eth_queue_zone,
-                                        rx_producers);
+               p_tlv->offset = PXP_VF_BAR0_START_MSDM_ZONE_B +
+                               offsetof(struct mstorm_vf_zone,
+                                        non_trigger.eth_rx_queue_producers) +
+                               sizeof(struct eth_rx_prod_data) * req->rx_qid;
        }
 
        qed_iov_send_response(p_hwfn, p_ptt, vf, sizeof(*p_tlv), status);
@@ -1627,13 +1726,19 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn,
 {
        struct qed_queue_start_common_params params;
        struct qed_iov_vf_mbx *mbx = &vf->vf_mbx;
-       u8 status = PFVF_STATUS_SUCCESS;
+       u8 status = PFVF_STATUS_NO_RESOURCE;
        struct vfpf_start_rxq_tlv *req;
        int rc;
 
        memset(&params, 0, sizeof(params));
        req = &mbx->req_virt->start_rxq;
+
+       if (!qed_iov_validate_rxq(p_hwfn, vf, req->rx_qid) ||
+           !qed_iov_validate_sb(p_hwfn, vf, req->hw_sb))
+               goto out;
+
        params.queue_id =  vf->vf_queues[req->rx_qid].fw_rx_qid;
+       params.vf_qid = req->rx_qid;
        params.vport_id = vf->vport_id;
        params.sb = req->hw_sb;
        params.sb_idx = req->sb_index;
@@ -1649,10 +1754,12 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn,
        if (rc) {
                status = PFVF_STATUS_FAILURE;
        } else {
+               status = PFVF_STATUS_SUCCESS;
                vf->vf_queues[req->rx_qid].rxq_active = true;
                vf->num_active_rxqs++;
        }
 
+out:
        qed_iov_vf_mbx_start_rxq_resp(p_hwfn, p_ptt, vf, status);
 }
 
@@ -1663,8 +1770,8 @@ static void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn,
        u16 length = sizeof(struct pfvf_def_resp_tlv);
        struct qed_queue_start_common_params params;
        struct qed_iov_vf_mbx *mbx = &vf->vf_mbx;
+       u8 status = PFVF_STATUS_NO_RESOURCE;
        union qed_qm_pq_params pq_params;
-       u8 status = PFVF_STATUS_SUCCESS;
        struct vfpf_start_txq_tlv *req;
        int rc;
 
@@ -1675,6 +1782,11 @@ static void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn,
 
        memset(&params, 0, sizeof(params));
        req = &mbx->req_virt->start_txq;
+
+       if (!qed_iov_validate_txq(p_hwfn, vf, req->tx_qid) ||
+           !qed_iov_validate_sb(p_hwfn, vf, req->hw_sb))
+               goto out;
+
        params.queue_id =  vf->vf_queues[req->tx_qid].fw_tx_qid;
        params.vport_id = vf->vport_id;
        params.sb = req->hw_sb;
@@ -1688,11 +1800,14 @@ static void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn,
                                         req->pbl_addr,
                                         req->pbl_size, &pq_params);
 
-       if (rc)
+       if (rc) {
                status = PFVF_STATUS_FAILURE;
-       else
+       } else {
+               status = PFVF_STATUS_SUCCESS;
                vf->vf_queues[req->tx_qid].txq_active = true;
+       }
 
+out:
        qed_iov_prepare_resp(p_hwfn, p_ptt, vf, CHANNEL_TLV_START_TXQ,
                             length, status);
 }
@@ -2119,6 +2234,16 @@ static void qed_iov_vf_mbx_vport_update(struct qed_hwfn *p_hwfn,
        u16 length;
        int rc;
 
+       /* Valiate PF can send such a request */
+       if (!vf->vport_instance) {
+               DP_VERBOSE(p_hwfn,
+                          QED_MSG_IOV,
+                          "No VPORT instance available for VF[%d], failing vport update\n",
+                          vf->abs_vf_id);
+               status = PFVF_STATUS_FAILURE;
+               goto out;
+       }
+
        memset(&params, 0, sizeof(params));
        params.opaque_fid = vf->opaque_fid;
        params.vport_id = vf->vport_id;
@@ -2366,11 +2491,27 @@ static void qed_iov_vf_mbx_release(struct qed_hwfn *p_hwfn,
                                   struct qed_vf_info *p_vf)
 {
        u16 length = sizeof(struct pfvf_def_resp_tlv);
+       u8 status = PFVF_STATUS_SUCCESS;
+       int rc = 0;
 
        qed_iov_vf_cleanup(p_hwfn, p_vf);
 
+       if (p_vf->state != VF_STOPPED && p_vf->state != VF_FREE) {
+               /* Stopping the VF */
+               rc = qed_sp_vf_stop(p_hwfn, p_vf->concrete_fid,
+                                   p_vf->opaque_fid);
+
+               if (rc) {
+                       DP_ERR(p_hwfn, "qed_sp_vf_stop returned error %d\n",
+                              rc);
+                       status = PFVF_STATUS_FAILURE;
+               }
+
+               p_vf->state = VF_STOPPED;
+       }
+
        qed_iov_prepare_resp(p_hwfn, p_ptt, p_vf, CHANNEL_TLV_RELEASE,
-                            length, PFVF_STATUS_SUCCESS);
+                            length, status);
 }
 
 static int