struct work_struct      discov_update;
        struct work_struct      bg_scan_update;
        struct work_struct      scan_update;
+       struct work_struct      connectable_update;
        struct delayed_work     le_scan_disable;
        struct delayed_work     le_scan_restart;
 
                         u16 max_interval, u16 latency, u16 timeout);
 void mgmt_smp_complete(struct hci_conn *conn, bool complete);
 bool mgmt_get_connectable(struct hci_dev *hdev);
+void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status);
 u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev);
 void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev,
                            u8 instance);
 
        hci_req_sync(hdev, update_scan, 0, HCI_CMD_TIMEOUT, NULL);
 }
 
+static int connectable_update(struct hci_request *req, unsigned long opt)
+{
+       struct hci_dev *hdev = req->hdev;
+
+       hci_dev_lock(hdev);
+
+       __hci_req_update_scan(req);
+
+       /* If BR/EDR is not enabled and we disable advertising as a
+        * by-product of disabling connectable, we need to update the
+        * advertising flags.
+        */
+       if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
+               __hci_req_update_adv_data(req, HCI_ADV_CURRENT);
+
+       /* Update the advertising parameters if necessary */
+       if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
+           hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
+               __hci_req_enable_advertising(req);
+
+       __hci_update_background_scan(req);
+
+       hci_dev_unlock(hdev);
+
+       return 0;
+}
+
+static void connectable_update_work(struct work_struct *work)
+{
+       struct hci_dev *hdev = container_of(work, struct hci_dev,
+                                           connectable_update);
+       u8 status;
+
+       hci_req_sync(hdev, connectable_update, 0, HCI_CMD_TIMEOUT, &status);
+       mgmt_set_connectable_complete(hdev, status);
+}
+
 void __hci_abort_conn(struct hci_request *req, struct hci_conn *conn,
                      u8 reason)
 {
        INIT_WORK(&hdev->discov_update, discov_update);
        INIT_WORK(&hdev->bg_scan_update, bg_scan_update);
        INIT_WORK(&hdev->scan_update, scan_update_work);
+       INIT_WORK(&hdev->connectable_update, connectable_update_work);
        INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work);
        INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart_work);
        INIT_DELAYED_WORK(&hdev->adv_instance_expire, adv_timeout_expire);
        cancel_work_sync(&hdev->discov_update);
        cancel_work_sync(&hdev->bg_scan_update);
        cancel_work_sync(&hdev->scan_update);
+       cancel_work_sync(&hdev->connectable_update);
        cancel_delayed_work_sync(&hdev->le_scan_disable);
        cancel_delayed_work_sync(&hdev->le_scan_restart);
 
 
                hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
 }
 
-static void set_connectable_complete(struct hci_dev *hdev, u8 status,
-                                    u16 opcode)
+void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
 {
        struct mgmt_pending_cmd *cmd;
-       struct mgmt_mode *cp;
-       bool conn_changed, discov_changed;
 
        BT_DBG("status 0x%02x", status);
 
                goto remove_cmd;
        }
 
-       cp = cmd->param;
-       if (cp->val) {
-               conn_changed = !hci_dev_test_and_set_flag(hdev,
-                                                         HCI_CONNECTABLE);
-               discov_changed = false;
-       } else {
-               conn_changed = hci_dev_test_and_clear_flag(hdev,
-                                                          HCI_CONNECTABLE);
-               discov_changed = hci_dev_test_and_clear_flag(hdev,
-                                                            HCI_DISCOVERABLE);
-       }
-
        send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
-
-       if (conn_changed || discov_changed) {
-               new_settings(hdev, cmd->sk);
-               hci_req_update_scan(hdev);
-               if (discov_changed)
-                       hci_req_update_adv_data(hdev, HCI_ADV_CURRENT);
-               hci_update_background_scan(hdev);
-       }
+       new_settings(hdev, cmd->sk);
 
 remove_cmd:
        mgmt_pending_remove(cmd);
 {
        struct mgmt_mode *cp = data;
        struct mgmt_pending_cmd *cmd;
-       struct hci_request req;
-       u8 scan;
        int err;
 
        BT_DBG("request for %s", hdev->name);
                goto failed;
        }
 
-       hci_req_init(&req, hdev);
-
-       /* If BR/EDR is not enabled and we disable advertising as a
-        * by-product of disabling connectable, we need to update the
-        * advertising flags.
-        */
-       if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
-               if (!cp->val) {
-                       hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
-                       hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
-               }
-               __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
-       } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
-               if (cp->val) {
-                       scan = SCAN_PAGE;
-               } else {
-                       /* If we don't have any whitelist entries just
-                        * disable all scanning. If there are entries
-                        * and we had both page and inquiry scanning
-                        * enabled then fall back to only page scanning.
-                        * Otherwise no changes are needed.
-                        */
-                       if (list_empty(&hdev->whitelist))
-                               scan = SCAN_DISABLED;
-                       else if (test_bit(HCI_ISCAN, &hdev->flags))
-                               scan = SCAN_PAGE;
-                       else
-                               goto no_scan_update;
-
-                       if (test_bit(HCI_ISCAN, &hdev->flags) &&
-                           hdev->discov_timeout > 0)
-                               cancel_delayed_work(&hdev->discov_off);
-               }
+       if (cp->val) {
+               hci_dev_set_flag(hdev, HCI_CONNECTABLE);
+       } else {
+               if (hdev->discov_timeout > 0)
+                       cancel_delayed_work(&hdev->discov_off);
 
-               hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+               hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
+               hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
+               hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
        }
 
-no_scan_update:
-       /* Update the advertising parameters if necessary */
-       if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
-           hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
-               __hci_req_enable_advertising(&req);
-
-       err = hci_req_run(&req, set_connectable_complete);
-       if (err < 0) {
-               mgmt_pending_remove(cmd);
-               if (err == -ENODATA)
-                       err = set_connectable_update_settings(hdev, sk,
-                                                             cp->val);
-               goto failed;
-       }
+       queue_work(hdev->req_workqueue, &hdev->connectable_update);
+       err = 0;
 
 failed:
        hci_dev_unlock(hdev);