Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[safe/jmp/linux-2.6] / drivers / net / wireless / iwlwifi / iwl-scan.c
index c2ed7c1..107e173 100644 (file)
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
  * in the file called LICENSE.GPL.
  *
  * Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *****************************************************************************/
-#include <net/mac80211.h>
+#include <linux/slab.h>
+#include <linux/types.h>
 #include <linux/etherdevice.h>
+#include <net/mac80211.h>
 
 #include "iwl-eeprom.h"
 #include "iwl-dev.h"
 /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
  * sending probe req.  This should be set long enough to hear probe responses
  * from more than one AP.  */
-#define IWL_ACTIVE_DWELL_TIME_24    (20)       /* all times in msec */
-#define IWL_ACTIVE_DWELL_TIME_52    (10)
-
-/* For faster active scanning, scan will move to the next channel if fewer than
- * PLCP_QUIET_THRESH packets are heard on this channel within
- * ACTIVE_QUIET_TIME after sending probe request.  This shortens the dwell
- * time if it's a quiet channel (nothing responded to our probe, and there's
- * no other traffic).
- * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
-#define IWL_PLCP_QUIET_THRESH       __constant_cpu_to_le16(1)  /* packets */
-#define IWL_ACTIVE_QUIET_TIME       __constant_cpu_to_le16(5)  /* msec */
+#define IWL_ACTIVE_DWELL_TIME_24    (30)       /* all times in msec */
+#define IWL_ACTIVE_DWELL_TIME_52    (20)
+
+#define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3)
+#define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2)
 
 /* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
  * Must be set longer than active dwell time.
 
 
 
-static int iwl_is_empty_essid(const char *essid, int essid_len)
-{
-       /* Single white space is for Linksys APs */
-       if (essid_len == 1 && essid[0] == ' ')
-               return 1;
-
-       /* Otherwise, if the entire essid is 0, we assume it is hidden */
-       while (essid_len) {
-               essid_len--;
-               if (essid[essid_len] != '\0')
-                       return 0;
-       }
-
-       return 1;
-}
-
-
-
-const char *iwl_escape_essid(const char *essid, u8 essid_len)
-{
-       static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
-       const char *s = essid;
-       char *d = escaped;
-
-       if (iwl_is_empty_essid(essid, essid_len)) {
-               memcpy(escaped, "<hidden>", sizeof("<hidden>"));
-               return escaped;
-       }
-
-       essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
-       while (essid_len--) {
-               if (*s == '\0') {
-                       *d++ = '\\';
-                       *d++ = '0';
-                       s++;
-               } else
-                       *d++ = *s++;
-       }
-       *d = '\0';
-       return escaped;
-}
-EXPORT_SYMBOL(iwl_escape_essid);
-
 /**
  * iwl_scan_cancel - Cancel any currently executing HW scan
  *
@@ -116,13 +69,12 @@ int iwl_scan_cancel(struct iwl_priv *priv)
        }
 
        if (test_bit(STATUS_SCANNING, &priv->status)) {
-               if (!test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
-                       IWL_DEBUG_SCAN("Queuing scan abort.\n");
-                       set_bit(STATUS_SCAN_ABORTING, &priv->status);
+               if (!test_and_set_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+                       IWL_DEBUG_SCAN(priv, "Queuing scan abort.\n");
                        queue_work(priv->workqueue, &priv->abort_scan);
 
                } else
-                       IWL_DEBUG_SCAN("Scan abort already in progress.\n");
+                       IWL_DEBUG_SCAN(priv, "Scan abort already in progress.\n");
 
                return test_bit(STATUS_SCANNING, &priv->status);
        }
@@ -159,10 +111,10 @@ EXPORT_SYMBOL(iwl_scan_cancel_timeout);
 static int iwl_send_scan_abort(struct iwl_priv *priv)
 {
        int ret = 0;
-       struct iwl_rx_packet *res;
+       struct iwl_rx_packet *pkt;
        struct iwl_host_cmd cmd = {
                .id = REPLY_SCAN_ABORT_CMD,
-               .meta.flags = CMD_WANT_SKB,
+               .flags = CMD_WANT_SKB,
        };
 
        /* If there isn't a scan actively going on in the hardware
@@ -179,35 +131,34 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
                return ret;
        }
 
-       res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
-       if (res->u.status != CAN_ABORT_STATUS) {
+       pkt = (struct iwl_rx_packet *)cmd.reply_page;
+       if (pkt->u.status != CAN_ABORT_STATUS) {
                /* The scan abort will return 1 for success or
                 * 2 for "failure".  A failure condition can be
                 * due to simply not being in an active scan which
                 * can occur if we send the scan abort before we
                 * the microcode has notified us that a scan is
                 * completed. */
-               IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status);
+               IWL_DEBUG_INFO(priv, "SCAN_ABORT returned %d.\n", pkt->u.status);
                clear_bit(STATUS_SCAN_ABORTING, &priv->status);
                clear_bit(STATUS_SCAN_HW, &priv->status);
        }
 
-       dev_kfree_skb_any(cmd.meta.u.skb);
+       iwl_free_pages(priv, cmd.reply_page);
 
        return ret;
 }
 
-
 /* Service response to REPLY_SCAN_CMD (0x80) */
 static void iwl_rx_reply_scan(struct iwl_priv *priv,
                              struct iwl_rx_mem_buffer *rxb)
 {
 #ifdef CONFIG_IWLWIFI_DEBUG
-       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_scanreq_notification *notif =
            (struct iwl_scanreq_notification *)pkt->u.raw;
 
-       IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status);
+       IWL_DEBUG_RX(priv, "Scan request status = 0x%x\n", notif->status);
 #endif
 }
 
@@ -215,17 +166,18 @@ static void iwl_rx_reply_scan(struct iwl_priv *priv,
 static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
                                    struct iwl_rx_mem_buffer *rxb)
 {
-       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_scanstart_notification *notif =
            (struct iwl_scanstart_notification *)pkt->u.raw;
        priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
-       IWL_DEBUG_SCAN("Scan start: "
+       IWL_DEBUG_SCAN(priv, "Scan start: "
                       "%d [802.11%s] "
                       "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
                       notif->channel,
                       notif->band ? "bg" : "a",
-                      notif->tsf_high,
-                      notif->tsf_low, notif->status, notif->beacon_timer);
+                      le32_to_cpu(notif->tsf_high),
+                      le32_to_cpu(notif->tsf_low),
+                      notif->status, notif->beacon_timer);
 }
 
 /* Service SCAN_RESULTS_NOTIFICATION (0x83) */
@@ -233,83 +185,58 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
                                      struct iwl_rx_mem_buffer *rxb)
 {
 #ifdef CONFIG_IWLWIFI_DEBUG
-       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_scanresults_notification *notif =
            (struct iwl_scanresults_notification *)pkt->u.raw;
 
-       IWL_DEBUG_SCAN("Scan ch.res: "
+       IWL_DEBUG_SCAN(priv, "Scan ch.res: "
                       "%d [802.11%s] "
                       "(TSF: 0x%08X:%08X) - %d "
-                      "elapsed=%lu usec (%dms since last)\n",
+                      "elapsed=%lu usec\n",
                       notif->channel,
                       notif->band ? "bg" : "a",
                       le32_to_cpu(notif->tsf_high),
                       le32_to_cpu(notif->tsf_low),
                       le32_to_cpu(notif->statistics[0]),
-                      le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf,
-                      jiffies_to_msecs(elapsed_jiffies
-                                       (priv->last_scan_jiffies, jiffies)));
+                      le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf);
 #endif
-
-       priv->last_scan_jiffies = jiffies;
-       priv->next_scan_jiffies = 0;
 }
 
 /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
 static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
                                       struct iwl_rx_mem_buffer *rxb)
 {
-       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+#ifdef CONFIG_IWLWIFI_DEBUG
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
 
-       IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
+       IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
                       scan_notif->scanned_channels,
                       scan_notif->tsf_low,
                       scan_notif->tsf_high, scan_notif->status);
+#endif
 
        /* The HW is no longer scanning */
        clear_bit(STATUS_SCAN_HW, &priv->status);
 
-       /* The scan completion notification came in, so kill that timer... */
-       cancel_delayed_work(&priv->scan_check);
-
-       IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n",
-                      (priv->scan_bands == 2) ? "2.4" : "5.2",
+       IWL_DEBUG_INFO(priv, "Scan on %sGHz took %dms\n",
+                      (priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2",
                       jiffies_to_msecs(elapsed_jiffies
-                                       (priv->scan_pass_start, jiffies)));
-
-       /* Remove this scanned band from the list
-        * of pending bands to scan */
-       priv->scan_bands--;
+                                       (priv->scan_start, jiffies)));
 
-       /* If a request to abort was given, or the scan did not succeed
+       /*
+        * If a request to abort was given, or the scan did not succeed
         * then we reset the scan state machine and terminate,
-        * re-queuing another scan if one has been requested */
-       if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
-               IWL_DEBUG_INFO("Aborted scan completed.\n");
-               clear_bit(STATUS_SCAN_ABORTING, &priv->status);
-       } else {
-               /* If there are more bands on this scan pass reschedule */
-               if (priv->scan_bands > 0)
-                       goto reschedule;
-       }
+        * re-queuing another scan if one has been requested
+        */
+       if (test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status))
+               IWL_DEBUG_INFO(priv, "Aborted scan completed.\n");
 
-       priv->last_scan_jiffies = jiffies;
-       priv->next_scan_jiffies = 0;
-       IWL_DEBUG_INFO("Setting scan to off\n");
+       IWL_DEBUG_INFO(priv, "Setting scan to off\n");
 
        clear_bit(STATUS_SCANNING, &priv->status);
 
-       IWL_DEBUG_INFO("Scan took %dms\n",
-               jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies)));
-
        queue_work(priv->workqueue, &priv->scan_completed);
-
-       return;
-
-reschedule:
-       priv->scan_pass_start = jiffies;
-       queue_work(priv->workqueue, &priv->request_scan);
 }
 
 void iwl_setup_rx_scan_handlers(struct iwl_priv *priv)
@@ -324,20 +251,24 @@ void iwl_setup_rx_scan_handlers(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_setup_rx_scan_handlers);
 
-static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
-                                               enum ieee80211_band band)
+inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
+                                    enum ieee80211_band band,
+                                    u8 n_probes)
 {
        if (band == IEEE80211_BAND_5GHZ)
-               return IWL_ACTIVE_DWELL_TIME_52;
+               return IWL_ACTIVE_DWELL_TIME_52 +
+                       IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1);
        else
-               return IWL_ACTIVE_DWELL_TIME_24;
+               return IWL_ACTIVE_DWELL_TIME_24 +
+                       IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1);
 }
+EXPORT_SYMBOL(iwl_get_active_dwell_time);
 
-static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
-                                         enum ieee80211_band band)
+u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
+                              enum ieee80211_band band,
+                              struct ieee80211_vif *vif)
 {
-       u16 active = iwl_get_active_dwell_time(priv, band);
-       u16 passive = (band != IEEE80211_BAND_5GHZ) ?
+       u16 passive = (band == IEEE80211_BAND_2GHZ) ?
            IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
            IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
 
@@ -345,133 +276,137 @@ static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
                /* If we're associated, we clamp the maximum passive
                 * dwell time to be 98% of the beacon interval (minus
                 * 2 * channel tune time) */
-               passive = priv->beacon_int;
+               passive = vif ? vif->bss_conf.beacon_int : 0;
                if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive)
                        passive = IWL_PASSIVE_DWELL_BASE;
                passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
        }
 
-       if (passive <= active)
-               passive = active + 1;
-
        return passive;
 }
+EXPORT_SYMBOL(iwl_get_passive_dwell_time);
 
-static int iwl_get_channels_for_scan(struct iwl_priv *priv,
-                                    enum ieee80211_band band,
-                                    u8 is_active, u8 direct_mask,
-                                    struct iwl_scan_channel *scan_ch)
+void iwl_init_scan_params(struct iwl_priv *priv)
 {
-       const struct ieee80211_channel *channels = NULL;
-       const struct ieee80211_supported_band *sband;
-       const struct iwl_channel_info *ch_info;
-       u16 passive_dwell = 0;
-       u16 active_dwell = 0;
-       int added, i;
-
-       sband = iwl_get_hw_mode(priv, band);
-       if (!sband)
-               return 0;
+       u8 ant_idx = fls(priv->hw_params.valid_tx_ant) - 1;
+       if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ])
+               priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx;
+       if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ])
+               priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx;
+}
+EXPORT_SYMBOL(iwl_init_scan_params);
 
-       channels = sband->channels;
-
-       active_dwell = iwl_get_active_dwell_time(priv, band);
-       passive_dwell = iwl_get_passive_dwell_time(priv, band);
-
-       for (i = 0, added = 0; i < sband->n_channels; i++) {
-               if (channels[i].flags & IEEE80211_CHAN_DISABLED)
-                       continue;
-
-               scan_ch->channel =
-                       ieee80211_frequency_to_channel(channels[i].center_freq);
-
-               ch_info = iwl_get_channel_info(priv, band,
-                                        scan_ch->channel);
-               if (!is_channel_valid(ch_info)) {
-                       IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
-                                      scan_ch->channel);
-                       continue;
-               }
-
-               if (!is_active || is_channel_passive(ch_info) ||
-                   (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
-                       scan_ch->type = 0;      /* passive */
-               else
-                       scan_ch->type = 1;      /* active */
-
-               if (scan_ch->type & 1)
-                       scan_ch->type |= (direct_mask << 1);
-
-               scan_ch->active_dwell = cpu_to_le16(active_dwell);
-               scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
-
-               /* Set txpower levels to defaults */
-               scan_ch->tpc.dsp_atten = 110;
-               /* scan_pwr_info->tpc.dsp_atten; */
-
-               /*scan_pwr_info->tpc.tx_gain; */
-               if (band == IEEE80211_BAND_5GHZ)
-                       scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3;
-               else {
-                       scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
-                       /* NOTE: if we were doing 6Mb OFDM for scans we'd use
-                        * power level:
-                        * scan_ch->tpc.tx_gain = ((1 << 5) | (2 << 3)) | 3;
-                        */
-               }
-
-               IWL_DEBUG_SCAN("Scanning %d [%s %d]\n",
-                              scan_ch->channel,
-                              (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE",
-                              (scan_ch->type & 1) ?
-                              active_dwell : passive_dwell);
-
-               scan_ch++;
-               added++;
-       }
+static int iwl_scan_initiate(struct iwl_priv *priv, struct ieee80211_vif *vif)
+{
+       WARN_ON(!mutex_is_locked(&priv->mutex));
+
+       IWL_DEBUG_INFO(priv, "Starting scan...\n");
+       set_bit(STATUS_SCANNING, &priv->status);
+       priv->is_internal_short_scan = false;
+       priv->scan_start = jiffies;
+
+       if (WARN_ON(!priv->cfg->ops->utils->request_scan))
+               return -EOPNOTSUPP;
+
+       priv->cfg->ops->utils->request_scan(priv, vif);
 
-       IWL_DEBUG_SCAN("total channels to scan %d \n", added);
-       return added;
+       return 0;
 }
 
-int iwl_scan_initiate(struct iwl_priv *priv)
+int iwl_mac_hw_scan(struct ieee80211_hw *hw,
+                   struct ieee80211_vif *vif,
+                   struct cfg80211_scan_request *req)
 {
-       if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
-               IWL_ERROR("APs don't scan.\n");
-               return 0;
+       struct iwl_priv *priv = hw->priv;
+       int ret;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (req->n_channels == 0)
+               return -EINVAL;
+
+       mutex_lock(&priv->mutex);
+
+       if (!iwl_is_ready_rf(priv)) {
+               ret = -EIO;
+               IWL_DEBUG_MAC80211(priv, "leave - not ready or exit pending\n");
+               goto out_unlock;
        }
 
+       if (test_bit(STATUS_SCANNING, &priv->status)) {
+               IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
+               ret = -EAGAIN;
+               goto out_unlock;
+       }
+
+       if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+               IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n");
+               ret = -EAGAIN;
+               goto out_unlock;
+       }
+
+       /* mac80211 will only ask for one band at a time */
+       priv->scan_band = req->channels[0]->band;
+       priv->scan_request = req;
+
+       ret = iwl_scan_initiate(priv, vif);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+out_unlock:
+       mutex_unlock(&priv->mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL(iwl_mac_hw_scan);
+
+/*
+ * internal short scan, this function should only been called while associated.
+ * It will reset and tune the radio to prevent possible RF related problem
+ */
+void iwl_internal_short_hw_scan(struct iwl_priv *priv)
+{
+       queue_work(priv->workqueue, &priv->start_internal_scan);
+}
+
+void iwl_bg_start_internal_scan(struct work_struct *work)
+{
+       struct iwl_priv *priv =
+               container_of(work, struct iwl_priv, start_internal_scan);
+
+       mutex_lock(&priv->mutex);
+
        if (!iwl_is_ready_rf(priv)) {
-               IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
-               return -EIO;
+               IWL_DEBUG_SCAN(priv, "not ready or exit pending\n");
+               goto unlock;
        }
 
        if (test_bit(STATUS_SCANNING, &priv->status)) {
-               IWL_DEBUG_SCAN("Scan already in progress.\n");
-               return -EAGAIN;
+               IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
+               goto unlock;
        }
 
        if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
-               IWL_DEBUG_SCAN("Scan request while abort pending.  "
-                              "Queuing.\n");
-               return -EAGAIN;
+               IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n");
+               goto unlock;
        }
 
-       IWL_DEBUG_INFO("Starting scan...\n");
-       priv->scan_bands = 2;
+       priv->scan_band = priv->band;
+
+       IWL_DEBUG_SCAN(priv, "Start internal short scan...\n");
        set_bit(STATUS_SCANNING, &priv->status);
-       priv->scan_start = jiffies;
-       priv->scan_pass_start = priv->scan_start;
+       priv->is_internal_short_scan = true;
 
-       queue_work(priv->workqueue, &priv->request_scan);
+       if (WARN_ON(!priv->cfg->ops->utils->request_scan))
+               goto unlock;
 
-       return 0;
+       priv->cfg->ops->utils->request_scan(priv, NULL);
+ unlock:
+       mutex_unlock(&priv->mutex);
 }
-EXPORT_SYMBOL(iwl_scan_initiate);
+EXPORT_SYMBOL(iwl_bg_start_internal_scan);
 
-#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
-
-static void iwl_bg_scan_check(struct work_struct *data)
+void iwl_bg_scan_check(struct work_struct *data)
 {
        struct iwl_priv *priv =
            container_of(data, struct iwl_priv, scan_check.work);
@@ -482,7 +417,7 @@ static void iwl_bg_scan_check(struct work_struct *data)
        mutex_lock(&priv->mutex);
        if (test_bit(STATUS_SCANNING, &priv->status) ||
            test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
-               IWL_DEBUG(IWL_DL_SCAN, "Scan completion watchdog resetting "
+               IWL_DEBUG_SCAN(priv, "Scan completion watchdog resetting "
                        "adapter (%dms)\n",
                        jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
 
@@ -491,79 +426,23 @@ static void iwl_bg_scan_check(struct work_struct *data)
        }
        mutex_unlock(&priv->mutex);
 }
-/**
- * iwl_supported_rate_to_ie - fill in the supported rate in IE field
- *
- * return : set the bit for each supported rate insert in ie
- */
-static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
-                                   u16 basic_rate, int *left)
-{
-       u16 ret_rates = 0, bit;
-       int i;
-       u8 *cnt = ie;
-       u8 *rates = ie + 1;
-
-       for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) {
-               if (bit & supported_rate) {
-                       ret_rates |= bit;
-                       rates[*cnt] = iwl_rates[i].ieee |
-                               ((bit & basic_rate) ? 0x80 : 0x00);
-                       (*cnt)++;
-                       (*left)--;
-                       if ((*left <= 0) ||
-                           (*cnt >= IWL_SUPPORTED_RATES_IE_LEN))
-                               break;
-               }
-       }
-
-       return ret_rates;
-}
-
-
-static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband,
-                       u8 *pos, int *left)
-{
-       struct ieee80211_ht_cap *ht_cap;
-
-       if (!sband || !sband->ht_info.ht_supported)
-               return;
-
-       if (*left < sizeof(struct ieee80211_ht_cap))
-               return;
-
-       *pos++ = sizeof(struct ieee80211_ht_cap);
-       ht_cap = (struct ieee80211_ht_cap *) pos;
-
-       ht_cap->cap_info = cpu_to_le16(sband->ht_info.cap);
-       memcpy(ht_cap->supp_mcs_set, sband->ht_info.supp_mcs_set, 16);
-       ht_cap->ampdu_params_info =
-               (sband->ht_info.ampdu_factor & IEEE80211_HT_CAP_AMPDU_FACTOR) |
-               ((sband->ht_info.ampdu_density << 2) &
-                       IEEE80211_HT_CAP_AMPDU_DENSITY);
-       *left -= sizeof(struct ieee80211_ht_cap);
-}
+EXPORT_SYMBOL(iwl_bg_scan_check);
 
 /**
  * iwl_fill_probe_req - fill in all required fields and IE for probe request
  */
-static u16 iwl_fill_probe_req(struct iwl_priv *priv,
-                                 enum ieee80211_band band,
-                                 struct ieee80211_mgmt *frame,
-                                 int left, int is_direct)
+
+u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
+                      const u8 *ies, int ie_len, int left)
 {
        int len = 0;
        u8 *pos = NULL;
-       u16 active_rates, ret_rates, cck_rates, active_rate_basic;
-       const struct ieee80211_supported_band *sband =
-                                               iwl_get_hw_mode(priv, band);
 
        /* Make sure there is enough space for the probe request,
         * two mandatory IEs and the data */
        left -= 24;
        if (left < 0)
                return 0;
-       len += 24;
 
        frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
        memcpy(frame->da, iwl_bcast_addr, ETH_ALEN);
@@ -571,325 +450,81 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
        memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN);
        frame->seq_ctrl = 0;
 
-       /* fill in our indirect SSID IE */
+       len += 24;
+
        /* ...next IE... */
+       pos = &frame->u.probe_req.variable[0];
 
+       /* fill in our indirect SSID IE */
        left -= 2;
        if (left < 0)
                return 0;
-       len += 2;
-       pos = &(frame->u.probe_req.variable[0]);
        *pos++ = WLAN_EID_SSID;
        *pos++ = 0;
 
-       /* fill in our direct SSID IE... */
-       if (is_direct) {
-               /* ...next IE... */
-               left -= 2 + priv->essid_len;
-               if (left < 0)
-                       return 0;
-               /* ... fill it in... */
-               *pos++ = WLAN_EID_SSID;
-               *pos++ = priv->essid_len;
-               memcpy(pos, priv->essid, priv->essid_len);
-               pos += priv->essid_len;
-               len += 2 + priv->essid_len;
-       }
-
-       /* fill in supported rate */
-       /* ...next IE... */
-       left -= 2;
-       if (left < 0)
-               return 0;
-
-       /* ... fill it in... */
-       *pos++ = WLAN_EID_SUPP_RATES;
-       *pos = 0;
-
-       /* exclude 60M rate */
-       active_rates = priv->rates_mask;
-       active_rates &= ~IWL_RATE_60M_MASK;
-
-       active_rate_basic = active_rates & IWL_BASIC_RATES_MASK;
-
-       cck_rates = IWL_CCK_RATES_MASK & active_rates;
-       ret_rates = iwl_supported_rate_to_ie(pos, cck_rates,
-                       active_rate_basic, &left);
-       active_rates &= ~ret_rates;
-
-       ret_rates = iwl_supported_rate_to_ie(pos, active_rates,
-                                active_rate_basic, &left);
-       active_rates &= ~ret_rates;
-
-       len += 2 + *pos;
-       pos += (*pos) + 1;
-       if (active_rates == 0)
-               goto fill_end;
-
-       /* fill in supported extended rate */
-       /* ...next IE... */
-       left -= 2;
-       if (left < 0)
-               return 0;
-       /* ... fill it in... */
-       *pos++ = WLAN_EID_EXT_SUPP_RATES;
-       *pos = 0;
-       iwl_supported_rate_to_ie(pos, active_rates,
-                                active_rate_basic, &left);
-       if (*pos > 0)
-               len += 2 + *pos;
-
- fill_end:
-       /* fill in HT IE */
-       left -= 2;
-       if (left < 0)
-               return 0;
+       len += 2;
 
-       *pos++ = WLAN_EID_HT_CAPABILITY;
-       *pos = 0;
+       if (WARN_ON(left < ie_len))
+               return len;
 
-       iwl_ht_cap_to_ie(sband, pos, &left);
+       if (ies && ie_len) {
+               memcpy(pos, ies, ie_len);
+               len += ie_len;
+       }
 
-       if (*pos > 0)
-               len += 2 + *pos;
        return (u16)len;
 }
+EXPORT_SYMBOL(iwl_fill_probe_req);
 
-static void iwl_bg_request_scan(struct work_struct *data)
+void iwl_bg_abort_scan(struct work_struct *work)
 {
-       struct iwl_priv *priv =
-           container_of(data, struct iwl_priv, request_scan);
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_SCAN_CMD,
-               .len = sizeof(struct iwl_scan_cmd),
-               .meta.flags = CMD_SIZE_HUGE,
-       };
-       struct iwl_scan_cmd *scan;
-       struct ieee80211_conf *conf = NULL;
-       u16 cmd_len;
-       enum ieee80211_band band;
-       u8 direct_mask;
-       int ret = 0;
+       struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);
 
-       conf = ieee80211_get_hw_conf(priv->hw);
+       if (!test_bit(STATUS_READY, &priv->status) ||
+           !test_bit(STATUS_GEO_CONFIGURED, &priv->status))
+               return;
 
        mutex_lock(&priv->mutex);
 
-       if (!iwl_is_ready(priv)) {
-               IWL_WARNING("request scan called when driver not ready.\n");
-               goto done;
-       }
-
-       /* Make sure the scan wasn't cancelled before this queued work
-        * was given the chance to run... */
-       if (!test_bit(STATUS_SCANNING, &priv->status))
-               goto done;
-
-       /* This should never be called or scheduled if there is currently
-        * a scan active in the hardware. */
-       if (test_bit(STATUS_SCAN_HW, &priv->status)) {
-               IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. "
-                              "Ignoring second request.\n");
-               ret = -EIO;
-               goto done;
-       }
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
-               IWL_DEBUG_SCAN("Aborting scan due to device shutdown\n");
-               goto done;
-       }
-
-       if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
-               IWL_DEBUG_HC("Scan request while abort pending.  Queuing.\n");
-               goto done;
-       }
-
-       if (iwl_is_rfkill(priv)) {
-               IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n");
-               goto done;
-       }
-
-       if (!test_bit(STATUS_READY, &priv->status)) {
-               IWL_DEBUG_HC("Scan request while uninitialized.  Queuing.\n");
-               goto done;
-       }
+       set_bit(STATUS_SCAN_ABORTING, &priv->status);
+       iwl_send_scan_abort(priv);
 
-       if (!priv->scan_bands) {
-               IWL_DEBUG_HC("Aborting scan due to no requested bands\n");
-               goto done;
-       }
+       mutex_unlock(&priv->mutex);
+}
+EXPORT_SYMBOL(iwl_bg_abort_scan);
 
-       if (!priv->scan) {
-               priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) +
-                                    IWL_MAX_SCAN_SIZE, GFP_KERNEL);
-               if (!priv->scan) {
-                       ret = -ENOMEM;
-                       goto done;
-               }
-       }
-       scan = priv->scan;
-       memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE);
+void iwl_bg_scan_completed(struct work_struct *work)
+{
+       struct iwl_priv *priv =
+           container_of(work, struct iwl_priv, scan_completed);
 
-       scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
-       scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
+       IWL_DEBUG_SCAN(priv, "SCAN complete scan\n");
 
-       if (iwl_is_associated(priv)) {
-               u16 interval = 0;
-               u32 extra;
-               u32 suspend_time = 100;
-               u32 scan_suspend_time = 100;
-               unsigned long flags;
-
-               IWL_DEBUG_INFO("Scanning while associated...\n");
-
-               spin_lock_irqsave(&priv->lock, flags);
-               interval = priv->beacon_int;
-               spin_unlock_irqrestore(&priv->lock, flags);
-
-               scan->suspend_time = 0;
-               scan->max_out_time = cpu_to_le32(200 * 1024);
-               if (!interval)
-                       interval = suspend_time;
-
-               extra = (suspend_time / interval) << 22;
-               scan_suspend_time = (extra |
-                   ((suspend_time % interval) * 1024));
-               scan->suspend_time = cpu_to_le32(scan_suspend_time);
-               IWL_DEBUG_SCAN("suspend_time 0x%X beacon interval %d\n",
-                              scan_suspend_time, interval);
-       }
-
-       /* We should add the ability for user to lock to PASSIVE ONLY */
-       if (priv->one_direct_scan) {
-               IWL_DEBUG_SCAN
-                   ("Kicking off one direct scan for '%s'\n",
-                    iwl_escape_essid(priv->direct_ssid,
-                                     priv->direct_ssid_len));
-               scan->direct_scan[0].id = WLAN_EID_SSID;
-               scan->direct_scan[0].len = priv->direct_ssid_len;
-               memcpy(scan->direct_scan[0].ssid,
-                      priv->direct_ssid, priv->direct_ssid_len);
-               direct_mask = 1;
-       } else if (!iwl_is_associated(priv) && priv->essid_len) {
-               IWL_DEBUG_SCAN
-                 ("Kicking off one direct scan for '%s' when not associated\n",
-                  iwl_escape_essid(priv->essid, priv->essid_len));
-               scan->direct_scan[0].id = WLAN_EID_SSID;
-               scan->direct_scan[0].len = priv->essid_len;
-               memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
-               direct_mask = 1;
-       } else {
-               IWL_DEBUG_SCAN("Kicking off one indirect scan.\n");
-               direct_mask = 0;
-       }
+       cancel_delayed_work(&priv->scan_check);
 
-       scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
-       scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id;
-       scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
-
-
-       switch (priv->scan_bands) {
-       case 2:
-               scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
-               scan->tx_cmd.rate_n_flags =
-                               iwl4965_hw_set_rate_n_flags(IWL_RATE_1M_PLCP,
-                               RATE_MCS_ANT_B_MSK|RATE_MCS_CCK_MSK);
-
-               scan->good_CRC_th = 0;
-               band = IEEE80211_BAND_2GHZ;
-               break;
-
-       case 1:
-               scan->tx_cmd.rate_n_flags =
-                               iwl4965_hw_set_rate_n_flags(IWL_RATE_6M_PLCP,
-                               RATE_MCS_ANT_B_MSK);
-               scan->good_CRC_th = IWL_GOOD_CRC_TH;
-               band = IEEE80211_BAND_5GHZ;
-               break;
-
-       default:
-               IWL_WARNING("Invalid scan band count\n");
-               goto done;
+       if (!priv->is_internal_short_scan)
+               ieee80211_scan_completed(priv->hw, false);
+       else {
+               priv->is_internal_short_scan = false;
+               IWL_DEBUG_SCAN(priv, "internal short scan completed\n");
        }
 
-       /* We don't build a direct scan probe request; the uCode will do
-        * that based on the direct_mask added to each channel entry */
-       cmd_len = iwl_fill_probe_req(priv, band,
-                                       (struct ieee80211_mgmt *)scan->data,
-                                       IWL_MAX_SCAN_SIZE - sizeof(*scan), 0);
-
-       scan->tx_cmd.len = cpu_to_le16(cmd_len);
-       /* select Rx chains */
-
-       /* Force use of chains B and C (0x6) for scan Rx.
-        * Avoid A (0x1) because of its off-channel reception on A-band.
-        * MIMO is not used here, but value is required to make uCode happy. */
-       scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK |
-                       cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) |
-                       (0x6 << RXON_RX_CHAIN_FORCE_SEL_POS) |
-                       (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
-
-       if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR)
-               scan->filter_flags = RXON_FILTER_PROMISC_MSK;
-
-       if (direct_mask)
-               scan->channel_count =
-                       iwl_get_channels_for_scan(
-                               priv, band, 1, /* active */
-                               direct_mask,
-                               (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
-       else
-               scan->channel_count =
-                       iwl_get_channels_for_scan(
-                               priv, band, 0, /* passive */
-                               direct_mask,
-                               (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
-
-       scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
-                              RXON_FILTER_BCON_AWARE_MSK);
-       cmd.len += le16_to_cpu(scan->tx_cmd.len) +
-           scan->channel_count * sizeof(struct iwl_scan_channel);
-       cmd.data = scan;
-       scan->len = cpu_to_le16(cmd.len);
-
-       set_bit(STATUS_SCAN_HW, &priv->status);
-       ret = iwl_send_cmd_sync(priv, &cmd);
-       if (ret)
-               goto done;
-
-       queue_delayed_work(priv->workqueue, &priv->scan_check,
-                          IWL_SCAN_CHECK_WATCHDOG);
-
-       mutex_unlock(&priv->mutex);
-       return;
-
- done:
-       /* inform mac80211 scan aborted */
-       queue_work(priv->workqueue, &priv->scan_completed);
-       mutex_unlock(&priv->mutex);
-}
-
-static void iwl_bg_abort_scan(struct work_struct *work)
-{
-       struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);
-
-       if (!iwl_is_ready(priv))
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
+       /* Since setting the TXPOWER may have been deferred while
+        * performing the scan, fire one off */
        mutex_lock(&priv->mutex);
-
-       set_bit(STATUS_SCAN_ABORTING, &priv->status);
-       iwl_send_scan_abort(priv);
-
+       iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
        mutex_unlock(&priv->mutex);
 }
+EXPORT_SYMBOL(iwl_bg_scan_completed);
 
 void iwl_setup_scan_deferred_work(struct iwl_priv *priv)
 {
-       /*  FIXME: move here when resolved PENDING
-        *  INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); */
-       INIT_WORK(&priv->request_scan, iwl_bg_request_scan);
+       INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
        INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
+       INIT_WORK(&priv->start_internal_scan, iwl_bg_start_internal_scan);
        INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
 }
 EXPORT_SYMBOL(iwl_setup_scan_deferred_work);