s32 retry = 0;
        int ret;
 
+       if (sdiodev->bus_if->state == BRCMF_BUS_NOMEDIUM)
+               return -ENOMEDIUM;
+
        /*
         * figure out how to read the register based on address range
         * 0x00 ~ 0x7FF: function 0 CCCR and FBR
                        usleep_range(1000, 2000);
                ret = brcmf_sdiod_request_data(sdiodev, func_num, addr, regsz,
                                               data, write);
-       } while (ret != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
+       } while (ret != 0 && ret != -ENOMEDIUM &&
+                retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
 
-       if (ret != 0)
+       if (ret == -ENOMEDIUM)
+               brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_NOMEDIUM);
+       else if (ret != 0)
                brcmf_err("failed with %d\n", ret);
 
        return ret;
        int err = 0, i;
        u8 addr[3];
 
+       if (sdiodev->bus_if->state == BRCMF_BUS_NOMEDIUM)
+               return -ENOMEDIUM;
+
        addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK;
        addr[1] = (address >> 16) & SBSDIO_SBADDRMID_MASK;
        addr[2] = (address >> 24) & SBSDIO_SBADDRHIGH_MASK;
                             bool write, u32 addr, struct sk_buff *pkt)
 {
        unsigned int req_sz;
+       int err;
 
        brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
        if (brcmf_sdiod_pm_resume_error(sdiodev))
        req_sz &= (uint)~3;
 
        if (write)
-               return sdio_memcpy_toio(sdiodev->func[fn], addr,
-                                       ((u8 *)(pkt->data)),
-                                       req_sz);
+               err = sdio_memcpy_toio(sdiodev->func[fn], addr,
+                                      ((u8 *)(pkt->data)), req_sz);
        else if (fn == 1)
-               return sdio_memcpy_fromio(sdiodev->func[fn],
-                                         ((u8 *)(pkt->data)),
-                                         addr, req_sz);
+               err = sdio_memcpy_fromio(sdiodev->func[fn], ((u8 *)(pkt->data)),
+                                        addr, req_sz);
        else
                /* function 2 read is FIFO operation */
-               return sdio_readsb(sdiodev->func[fn],
-                                  ((u8 *)(pkt->data)), addr,
-                                  req_sz);
+               err = sdio_readsb(sdiodev->func[fn], ((u8 *)(pkt->data)), addr,
+                                 req_sz);
+       if (err == -ENOMEDIUM)
+               brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_NOMEDIUM);
+       return err;
 }
 
 /**
                mmc_wait_for_req(sdiodev->func[fn]->card->host, &mmc_req);
 
                ret = mmc_cmd.error ? mmc_cmd.error : mmc_dat.error;
-               if (ret != 0) {
+               if (ret == -ENOMEDIUM) {
+                       brcmf_bus_change_state(sdiodev->bus_if,
+                                              BRCMF_BUS_NOMEDIUM);
+                       break;
+               } else if (ret != 0) {
                        brcmf_err("CMD53 sg block %s failed %d\n",
                                  write ? "write" : "read", ret);
                        ret = -EIO;
 
 static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
 {
-       sdiodev->bus_if->state = BRCMF_BUS_DOWN;
-
        if (sdiodev->bus) {
                brcmf_sdio_remove(sdiodev->bus);
                sdiodev->bus = NULL;
 
 
        /* Clear partial in any case */
        bus->cur_read.len = 0;
-
-       /* If we can't reach the device, signal failure */
-       if (err)
-               bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
 }
 
 /* return total length of buffer chain */
        bus->rxpending = true;
 
        for (rd->seq_num = bus->rx_seq, rxleft = maxframes;
-            !bus->rxskip && rxleft &&
-            bus->sdiodev->bus_if->state != BRCMF_BUS_DOWN;
+            !bus->rxskip && rxleft && brcmf_bus_ready(bus->sdiodev->bus_if);
             rd->seq_num++, rxleft--) {
 
                /* Handle glomming separately */
                bus->watchdog_tsk = NULL;
        }
 
-       sdio_claim_host(bus->sdiodev->func[1]);
-
-       /* Enable clock for device interrupts */
-       brcmf_sdio_bus_sleep(bus, false, false);
+       if (bus_if->state == BRCMF_BUS_DOWN) {
+               sdio_claim_host(sdiodev->func[1]);
+
+               /* Enable clock for device interrupts */
+               brcmf_sdio_bus_sleep(bus, false, false);
+
+               /* Disable and clear interrupts at the chip level also */
+               w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask));
+               local_hostintmask = bus->hostintmask;
+               bus->hostintmask = 0;
+
+               /* Force backplane clocks to assure F2 interrupt propagates */
+               saveclk = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+                                           &err);
+               if (!err)
+                       brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+                                         (saveclk | SBSDIO_FORCE_HT), &err);
+               if (err)
+                       brcmf_err("Failed to force clock for F2: err %d\n",
+                                 err);
 
-       /* Disable and clear interrupts at the chip level also */
-       w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask));
-       local_hostintmask = bus->hostintmask;
-       bus->hostintmask = 0;
+               /* Turn off the bus (F2), free any pending packets */
+               brcmf_dbg(INTR, "disable SDIO interrupts\n");
+               sdio_disable_func(sdiodev->func[SDIO_FUNC_2]);
 
-       /* Change our idea of bus state */
-       bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
+               /* Clear any pending interrupts now that F2 is disabled */
+               w_sdreg32(bus, local_hostintmask,
+                         offsetof(struct sdpcmd_regs, intstatus));
 
-       /* Force clocks on backplane to be sure F2 interrupt propagates */
-       saveclk = brcmf_sdiod_regrb(bus->sdiodev,
-                                   SBSDIO_FUNC1_CHIPCLKCSR, &err);
-       if (!err) {
-               brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
-                                 (saveclk | SBSDIO_FORCE_HT), &err);
+               sdio_release_host(sdiodev->func[1]);
        }
-       if (err)
-               brcmf_err("Failed to force clock for F2: err %d\n", err);
-
-       /* Turn off the bus (F2), free any pending packets */
-       brcmf_dbg(INTR, "disable SDIO interrupts\n");
-       sdio_disable_func(bus->sdiodev->func[SDIO_FUNC_2]);
-
-       /* Clear any pending interrupts now that F2 is disabled */
-       w_sdreg32(bus, local_hostintmask,
-                 offsetof(struct sdpcmd_regs, intstatus));
-
-       sdio_release_host(bus->sdiodev->func[1]);
-
        /* Clear the data packet queues */
        brcmu_pktq_flush(&bus->txq, true, NULL, NULL);
 
                /* Check for inconsistent device control */
                devctl = brcmf_sdiod_regrb(bus->sdiodev,
                                           SBSDIO_DEVICE_CTL, &err);
-               if (err) {
-                       brcmf_err("error reading DEVCTL: %d\n", err);
-                       bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
-               }
 #endif                         /* DEBUG */
 
                /* Read CSR, if clock on switch to AVAIL, else ignore */
                clkctl = brcmf_sdiod_regrb(bus->sdiodev,
                                           SBSDIO_FUNC1_CHIPCLKCSR, &err);
-               if (err) {
-                       brcmf_err("error reading CSR: %d\n",
-                                 err);
-                       bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
-               }
 
                brcmf_dbg(SDIO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n",
                          devctl, clkctl);
                if (SBSDIO_HTAV(clkctl)) {
                        devctl = brcmf_sdiod_regrb(bus->sdiodev,
                                                   SBSDIO_DEVICE_CTL, &err);
-                       if (err) {
-                               brcmf_err("error reading DEVCTL: %d\n",
-                                         err);
-                               bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
-                       }
                        devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
                        brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
                                          devctl, &err);
-                       if (err) {
-                               brcmf_err("error writing DEVCTL: %d\n",
-                                         err);
-                               bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
-                       }
                        bus->clkstate = CLK_AVAIL;
                }
        }
                txlimit -= framecnt;
        }
 
-       if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) || (err != 0)) {
+       if (!brcmf_bus_ready(bus->sdiodev->bus_if) || (err != 0)) {
                brcmf_err("failed backplane access over SDIO, halting operation\n");
-               bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
                atomic_set(&bus->intstatus, 0);
        } else if (atomic_read(&bus->intstatus) ||
                   atomic_read(&bus->ipend) > 0 ||
        }
 
        /* Allow HT Clock now that the ARM is running. */
-       bus->sdiodev->bus_if->state = BRCMF_BUS_LOAD;
+       brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_LOAD);
        bcmerror = 0;
 
 err:
                return;
        }
 
-       if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) {
+       if (!brcmf_bus_ready(bus->sdiodev->bus_if)) {
                brcmf_err("bus is down. we have nothing to do\n");
                return;
        }
        else
                if (brcmf_sdio_intr_rstatus(bus)) {
                        brcmf_err("failed backplane access\n");
-                       bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
                }
 
        /* Disable additional interrupts (is this needed now)? */
                goto fail;
        }
 
+       /* SDIO register access works so moving
+        * state from UNKNOWN to DOWN.
+        */
+       brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_DOWN);
+
        if (brcmf_sdio_chip_attach(bus->sdiodev, &bus->ci)) {
                brcmf_err("brcmf_sdio_chip_attach failed!\n");
                goto fail;
        /* Disable F2 to clear any intermediate frame state on the dongle */
        sdio_disable_func(bus->sdiodev->func[SDIO_FUNC_2]);
 
-       bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
        bus->rxflow = false;
 
        /* Done with backplane-dependent accesses, can drop clock... */
                }
 
                if (bus->ci) {
-                       sdio_claim_host(bus->sdiodev->func[1]);
-                       brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
-                       /* Leave the device in state where it is 'quiet'. This
-                        * is done by putting it in download_state which
-                        * essentially resets all necessary cores
-                        */
-                       msleep(20);
-                       brcmf_sdio_chip_enter_download(bus->sdiodev, bus->ci);
-                       brcmf_sdio_clkctl(bus, CLK_NONE, false);
-                       sdio_release_host(bus->sdiodev->func[1]);
+                       if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) {
+                               sdio_claim_host(bus->sdiodev->func[1]);
+                               brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
+                               /* Leave the device in state where it is
+                                * 'quiet'. This is done by putting it in
+                                * download_state which essentially resets
+                                * all necessary cores.
+                                */
+                               msleep(20);
+                               brcmf_sdio_chip_enter_download(bus->sdiodev,
+                                                              bus->ci);
+                               brcmf_sdio_clkctl(bus, CLK_NONE, false);
+                               sdio_release_host(bus->sdiodev->func[1]);
+                       }
                        brcmf_sdio_chip_detach(&bus->ci);
                }