}
 }
 
+static void brcmf_scan_params_v2_to_v1(struct brcmf_scan_params_v2_le *params_v2_le,
+                                      struct brcmf_scan_params_le *params_le)
+{
+       size_t params_size;
+       u32 ch;
+       int n_channels, n_ssids;
+
+       memcpy(¶ms_le->ssid_le, ¶ms_v2_le->ssid_le,
+              sizeof(params_le->ssid_le));
+       memcpy(¶ms_le->bssid, ¶ms_v2_le->bssid,
+              sizeof(params_le->bssid));
+
+       params_le->bss_type = params_v2_le->bss_type;
+       params_le->scan_type = le32_to_cpu(params_v2_le->scan_type);
+       params_le->nprobes = params_v2_le->nprobes;
+       params_le->active_time = params_v2_le->active_time;
+       params_le->passive_time = params_v2_le->passive_time;
+       params_le->home_time = params_v2_le->home_time;
+       params_le->channel_num = params_v2_le->channel_num;
+
+       ch = le32_to_cpu(params_v2_le->channel_num);
+       n_channels = ch & BRCMF_SCAN_PARAMS_COUNT_MASK;
+       n_ssids = ch >> BRCMF_SCAN_PARAMS_NSSID_SHIFT;
+
+       params_size = sizeof(u16) * n_channels;
+       if (n_ssids > 0) {
+               params_size = roundup(params_size, sizeof(u32));
+               params_size += sizeof(struct brcmf_ssid_le) * n_ssids;
+       }
+
+       memcpy(¶ms_le->channel_list[0],
+              ¶ms_v2_le->channel_list[0], params_size);
+}
+
+static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
+                            struct brcmf_scan_params_v2_le *params_le,
+                            struct cfg80211_scan_request *request)
+{
+       u32 n_ssids;
+       u32 n_channels;
+       s32 i;
+       s32 offset;
+       u16 chanspec;
+       char *ptr;
+       int length;
+       struct brcmf_ssid_le ssid_le;
+
+       eth_broadcast_addr(params_le->bssid);
+
+       length = BRCMF_SCAN_PARAMS_V2_FIXED_SIZE;
+
+       params_le->version = cpu_to_le16(BRCMF_SCAN_PARAMS_VERSION_V2);
+       params_le->bss_type = DOT11_BSSTYPE_ANY;
+       params_le->scan_type = cpu_to_le32(BRCMF_SCANTYPE_ACTIVE);
+       params_le->channel_num = 0;
+       params_le->nprobes = cpu_to_le32(-1);
+       params_le->active_time = cpu_to_le32(-1);
+       params_le->passive_time = cpu_to_le32(-1);
+       params_le->home_time = cpu_to_le32(-1);
+       memset(¶ms_le->ssid_le, 0, sizeof(params_le->ssid_le));
+
+       /* Scan abort */
+       if (!request) {
+               length += sizeof(u16);
+               params_le->channel_num = cpu_to_le32(1);
+               params_le->channel_list[0] = cpu_to_le16(-1);
+               params_le->length = cpu_to_le16(length);
+               return;
+       }
+
+       n_ssids = request->n_ssids;
+       n_channels = request->n_channels;
+
+       /* Copy channel array if applicable */
+       brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
+                 n_channels);
+       if (n_channels > 0) {
+               length += roundup(sizeof(u16) * n_channels, sizeof(u32));
+               for (i = 0; i < n_channels; i++) {
+                       chanspec = channel_to_chanspec(&cfg->d11inf,
+                                                      request->channels[i]);
+                       brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
+                                 request->channels[i]->hw_value, chanspec);
+                       params_le->channel_list[i] = cpu_to_le16(chanspec);
+               }
+       } else {
+               brcmf_dbg(SCAN, "Scanning all channels\n");
+       }
+
+       /* Copy ssid array if applicable */
+       brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
+       if (n_ssids > 0) {
+               offset = offsetof(struct brcmf_scan_params_v2_le, channel_list) +
+                               n_channels * sizeof(u16);
+               offset = roundup(offset, sizeof(u32));
+               length += sizeof(ssid_le) * n_ssids,
+               ptr = (char *)params_le + offset;
+               for (i = 0; i < n_ssids; i++) {
+                       memset(&ssid_le, 0, sizeof(ssid_le));
+                       ssid_le.SSID_len =
+                                       cpu_to_le32(request->ssids[i].ssid_len);
+                       memcpy(ssid_le.SSID, request->ssids[i].ssid,
+                              request->ssids[i].ssid_len);
+                       if (!ssid_le.SSID_len)
+                               brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
+                       else
+                               brcmf_dbg(SCAN, "%d: scan for  %.32s size=%d\n",
+                                         i, ssid_le.SSID, ssid_le.SSID_len);
+                       memcpy(ptr, &ssid_le, sizeof(ssid_le));
+                       ptr += sizeof(ssid_le);
+               }
+       } else {
+               brcmf_dbg(SCAN, "Performing passive scan\n");
+               params_le->scan_type = cpu_to_le32(BRCMF_SCANTYPE_PASSIVE);
+       }
+       params_le->length = cpu_to_le16(length);
+       /* Adding mask to channel numbers */
+       params_le->channel_num =
+               cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
+                       (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
+}
+
 s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
                                struct brcmf_if *ifp, bool aborted,
                                bool fw_abort)
 {
        struct brcmf_pub *drvr = cfg->pub;
-       struct brcmf_scan_params_le params_le;
+       struct brcmf_scan_params_v2_le params_v2_le;
        struct cfg80211_scan_request *scan_request;
        u64 reqid;
        u32 bucket;
        if (fw_abort) {
                /* Do a scan abort to stop the driver's scan engine */
                brcmf_dbg(SCAN, "ABORT scan in firmware\n");
-               memset(¶ms_le, 0, sizeof(params_le));
-               eth_broadcast_addr(params_le.bssid);
-               params_le.bss_type = DOT11_BSSTYPE_ANY;
-               params_le.scan_type = 0;
-               params_le.channel_num = cpu_to_le32(1);
-               params_le.nprobes = cpu_to_le32(1);
-               params_le.active_time = cpu_to_le32(-1);
-               params_le.passive_time = cpu_to_le32(-1);
-               params_le.home_time = cpu_to_le32(-1);
-               /* Scan is aborted by setting channel_list[0] to -1 */
-               params_le.channel_list[0] = cpu_to_le16(-1);
+
+               brcmf_escan_prep(cfg, ¶ms_v2_le, NULL);
+
                /* E-Scan (or anyother type) can be aborted by SCAN */
-               err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
-                                            ¶ms_le, sizeof(params_le));
+               if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_V2)) {
+                       err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
+                                                    ¶ms_v2_le,
+                                                    sizeof(params_v2_le));
+               } else {
+                       struct brcmf_scan_params_le params_le;
+
+                       brcmf_scan_params_v2_to_v1(¶ms_v2_le, ¶ms_le);
+                       err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
+                                                    ¶ms_le,
+                                                    sizeof(params_le));
+               }
+
                if (err)
                        bphy_err(drvr, "Scan abort failed\n");
        }
        return err;
 }
 
-static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
-                            struct brcmf_scan_params_le *params_le,
-                            struct cfg80211_scan_request *request)
-{
-       u32 n_ssids;
-       u32 n_channels;
-       s32 i;
-       s32 offset;
-       u16 chanspec;
-       char *ptr;
-       struct brcmf_ssid_le ssid_le;
-
-       eth_broadcast_addr(params_le->bssid);
-       params_le->bss_type = DOT11_BSSTYPE_ANY;
-       params_le->scan_type = BRCMF_SCANTYPE_ACTIVE;
-       params_le->channel_num = 0;
-       params_le->nprobes = cpu_to_le32(-1);
-       params_le->active_time = cpu_to_le32(-1);
-       params_le->passive_time = cpu_to_le32(-1);
-       params_le->home_time = cpu_to_le32(-1);
-       memset(¶ms_le->ssid_le, 0, sizeof(params_le->ssid_le));
-
-       n_ssids = request->n_ssids;
-       n_channels = request->n_channels;
-
-       /* Copy channel array if applicable */
-       brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
-                 n_channels);
-       if (n_channels > 0) {
-               for (i = 0; i < n_channels; i++) {
-                       chanspec = channel_to_chanspec(&cfg->d11inf,
-                                                      request->channels[i]);
-                       brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
-                                 request->channels[i]->hw_value, chanspec);
-                       params_le->channel_list[i] = cpu_to_le16(chanspec);
-               }
-       } else {
-               brcmf_dbg(SCAN, "Scanning all channels\n");
-       }
-       /* Copy ssid array if applicable */
-       brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
-       if (n_ssids > 0) {
-               offset = offsetof(struct brcmf_scan_params_le, channel_list) +
-                               n_channels * sizeof(u16);
-               offset = roundup(offset, sizeof(u32));
-               ptr = (char *)params_le + offset;
-               for (i = 0; i < n_ssids; i++) {
-                       memset(&ssid_le, 0, sizeof(ssid_le));
-                       ssid_le.SSID_len =
-                                       cpu_to_le32(request->ssids[i].ssid_len);
-                       memcpy(ssid_le.SSID, request->ssids[i].ssid,
-                              request->ssids[i].ssid_len);
-                       if (!ssid_le.SSID_len)
-                               brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
-                       else
-                               brcmf_dbg(SCAN, "%d: scan for  %.32s size=%d\n",
-                                         i, ssid_le.SSID, ssid_le.SSID_len);
-                       memcpy(ptr, &ssid_le, sizeof(ssid_le));
-                       ptr += sizeof(ssid_le);
-               }
-       } else {
-               brcmf_dbg(SCAN, "Performing passive scan\n");
-               params_le->scan_type = BRCMF_SCANTYPE_PASSIVE;
-       }
-       /* Adding mask to channel numbers */
-       params_le->channel_num =
-               cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
-                       (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
-}
-
 static s32
 brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
                struct cfg80211_scan_request *request)
 {
        struct brcmf_pub *drvr = cfg->pub;
-       s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
-                         offsetof(struct brcmf_escan_params_le, params_le);
+       s32 params_size = BRCMF_SCAN_PARAMS_V2_FIXED_SIZE +
+                         offsetof(struct brcmf_escan_params_le, params_v2_le);
        struct brcmf_escan_params_le *params;
        s32 err = 0;
 
                goto exit;
        }
        BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
-       brcmf_escan_prep(cfg, ¶ms->params_le, request);
-       params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
+       brcmf_escan_prep(cfg, ¶ms->params_v2_le, request);
+
+       params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION_V2);
+
+       if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_V2)) {
+               struct brcmf_escan_params_le *params_v1;
+
+               params_size -= BRCMF_SCAN_PARAMS_V2_FIXED_SIZE;
+               params_size += BRCMF_SCAN_PARAMS_FIXED_SIZE;
+               params_v1 = kzalloc(params_size, GFP_KERNEL);
+               params_v1->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
+               brcmf_scan_params_v2_to_v1(¶ms->params_v2_le, ¶ms_v1->params_le);
+               kfree(params);
+               params = params_v1;
+       }
+
        params->action = cpu_to_le16(WL_ESCAN_ACTION_START);
        params->sync_id = cpu_to_le16(0x1234);
 
 
 
 /* size of brcmf_scan_params not including variable length array */
 #define BRCMF_SCAN_PARAMS_FIXED_SIZE   64
+#define BRCMF_SCAN_PARAMS_V2_FIXED_SIZE        72
+
+/* version of brcmf_scan_params structure */
+#define BRCMF_SCAN_PARAMS_VERSION_V2   2
 
 /* masks for channel and ssid count */
 #define BRCMF_SCAN_PARAMS_COUNT_MASK   0x0000ffff
 #define BRCMF_PRIMARY_KEY              (1 << 1)
 #define DOT11_BSSTYPE_ANY              2
 #define BRCMF_ESCAN_REQ_VERSION                1
+#define BRCMF_ESCAN_REQ_VERSION_V2     2
 
 #define BRCMF_MAXRATES_IN_SET          16      /* max # of rates in rateset */
 
        __le16 channel_list[1]; /* list of chanspecs */
 };
 
+struct brcmf_scan_params_v2_le {
+       __le16 version;         /* structure version */
+       __le16 length;          /* structure length */
+       struct brcmf_ssid_le ssid_le;   /* default: {0, ""} */
+       u8 bssid[ETH_ALEN];     /* default: bcast */
+       s8 bss_type;            /* default: any,
+                                * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT
+                                */
+       u8 pad;
+       __le32 scan_type;       /* flags, 0 use default */
+       __le32 nprobes;         /* -1 use default, number of probes per channel */
+       __le32 active_time;     /* -1 use default, dwell time per channel for
+                                * active scanning
+                                */
+       __le32 passive_time;    /* -1 use default, dwell time per channel
+                                * for passive scanning
+                                */
+       __le32 home_time;       /* -1 use default, dwell time for the
+                                * home channel between channel scans
+                                */
+       __le32 channel_num;     /* count of channels and ssids that follow
+                                *
+                                * low half is count of channels in
+                                * channel_list, 0 means default (use all
+                                * available channels)
+                                *
+                                * high half is entries in struct brcmf_ssid
+                                * array that follows channel_list, aligned for
+                                * s32 (4 bytes) meaning an odd channel count
+                                * implies a 2-byte pad between end of
+                                * channel_list and first ssid
+                                *
+                                * if ssid count is zero, single ssid in the
+                                * fixed parameter portion is assumed, otherwise
+                                * ssid in the fixed portion is ignored
+                                */
+       __le16 channel_list[1]; /* list of chanspecs */
+};
+
 struct brcmf_scan_results {
        u32 buflen;
        u32 version;
        __le32 version;
        __le16 action;
        __le16 sync_id;
-       struct brcmf_scan_params_le params_le;
+       union {
+               struct brcmf_scan_params_le params_le;
+               struct brcmf_scan_params_v2_le params_v2_le;
+       };
 };
 
 struct brcmf_escan_result_le {