mmcsd.c revision 239607
1163516Simp/*- 2163516Simp * Copyright (c) 2006 Bernd Walter. All rights reserved. 3163516Simp * Copyright (c) 2006 M. Warner Losh. All rights reserved. 4163516Simp * 5163516Simp * Redistribution and use in source and binary forms, with or without 6163516Simp * modification, are permitted provided that the following conditions 7163516Simp * are met: 8163516Simp * 1. Redistributions of source code must retain the above copyright 9163516Simp * notice, this list of conditions and the following disclaimer. 10163516Simp * 2. Redistributions in binary form must reproduce the above copyright 11163516Simp * notice, this list of conditions and the following disclaimer in the 12163516Simp * documentation and/or other materials provided with the distribution. 13163516Simp * 14163516Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15163516Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16163516Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17163516Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18163516Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19163516Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20163516Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21163516Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22163516Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23163516Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24170002Simp * 25170002Simp * Portions of this software may have been developed with reference to 26170002Simp * the SD Simplified Specification. The following disclaimer may apply: 27170002Simp * 28170002Simp * The following conditions apply to the release of the simplified 29170002Simp * specification ("Simplified Specification") by the SD Card Association and 30170002Simp * the SD Group. The Simplified Specification is a subset of the complete SD 31170002Simp * Specification which is owned by the SD Card Association and the SD 32170002Simp * Group. This Simplified Specification is provided on a non-confidential 33170002Simp * basis subject to the disclaimers below. Any implementation of the 34170002Simp * Simplified Specification may require a license from the SD Card 35170002Simp * Association, SD Group, SD-3C LLC or other third parties. 36170002Simp * 37170002Simp * Disclaimers: 38170002Simp * 39170002Simp * The information contained in the Simplified Specification is presented only 40170002Simp * as a standard specification for SD Cards and SD Host/Ancillary products and 41170002Simp * is provided "AS-IS" without any representations or warranties of any 42170002Simp * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD 43170002Simp * Card Association for any damages, any infringements of patents or other 44170002Simp * right of the SD Group, SD-3C LLC, the SD Card Association or any third 45170002Simp * parties, which may result from its use. No license is granted by 46170002Simp * implication, estoppel or otherwise under any patent or other rights of the 47170002Simp * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing 48170002Simp * herein shall be construed as an obligation by the SD Group, the SD-3C LLC 49170002Simp * or the SD Card Association to disclose or distribute any technical 50170002Simp * information, know-how or other confidential information to any third party. 51163516Simp */ 52163516Simp 53163516Simp#include <sys/cdefs.h> 54163516Simp__FBSDID("$FreeBSD: head/sys/dev/mmc/mmcsd.c 239607 2012-08-23 04:35:55Z imp $"); 55163516Simp 56163516Simp#include <sys/param.h> 57163516Simp#include <sys/systm.h> 58163516Simp#include <sys/bio.h> 59163516Simp#include <sys/bus.h> 60163516Simp#include <sys/conf.h> 61163516Simp#include <sys/kernel.h> 62163516Simp#include <sys/kthread.h> 63163516Simp#include <sys/lock.h> 64163516Simp#include <sys/malloc.h> 65163516Simp#include <sys/module.h> 66163516Simp#include <sys/mutex.h> 67163516Simp#include <geom/geom_disk.h> 68163516Simp 69234524Smarius#include <dev/mmc/mmcbrvar.h> 70234524Smarius#include <dev/mmc/mmcreg.h> 71163516Simp#include <dev/mmc/mmcvar.h> 72163516Simp 73163516Simp#include "mmcbus_if.h" 74163516Simp 75234524Smarius#if __FreeBSD_version < 800002 76234524Smarius#define kproc_create kthread_create 77234524Smarius#define kproc_exit kthread_exit 78234524Smarius#endif 79234524Smarius 80163516Simpstruct mmcsd_softc { 81163516Simp device_t dev; 82163516Simp struct mtx sc_mtx; 83163516Simp struct disk *disk; 84163516Simp struct proc *p; 85163516Simp struct bio_queue_head bio_queue; 86184034Smav daddr_t eblock, eend; /* Range remaining after the last erase. */ 87169567Simp int running; 88185721Smav int suspend; 89163516Simp}; 90163516Simp 91239607Simpstatic const char *errmsg[] = 92239607Simp{ 93239607Simp "None", 94239607Simp "Timeout", 95239607Simp "Bad CRC", 96239607Simp "Fifo", 97239607Simp "Failed", 98239607Simp "Invalid", 99239607Simp "NO MEMORY" 100239607Simp}; 101239607Simp 102163516Simp/* bus entry points */ 103163516Simpstatic int mmcsd_attach(device_t dev); 104163516Simpstatic int mmcsd_detach(device_t dev); 105236491Smariusstatic int mmcsd_probe(device_t dev); 106163516Simp 107163516Simp/* disk routines */ 108163516Simpstatic int mmcsd_close(struct disk *dp); 109188725Smavstatic int mmcsd_dump(void *arg, void *virtual, vm_offset_t physical, 110188725Smav off_t offset, size_t length); 111236491Smariusstatic int mmcsd_open(struct disk *dp); 112236491Smariusstatic void mmcsd_strategy(struct bio *bp); 113163516Simpstatic void mmcsd_task(void *arg); 114163516Simp 115183774Simpstatic int mmcsd_bus_bit_width(device_t dev); 116236491Smariusstatic daddr_t mmcsd_delete(struct mmcsd_softc *sc, struct bio *bp); 117236491Smariusstatic daddr_t mmcsd_rw(struct mmcsd_softc *sc, struct bio *bp); 118183774Simp 119163516Simp#define MMCSD_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 120163516Simp#define MMCSD_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 121163516Simp#define MMCSD_LOCK_INIT(_sc) \ 122163516Simp mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ 123163516Simp "mmcsd", MTX_DEF) 124163516Simp#define MMCSD_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); 125163516Simp#define MMCSD_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); 126163516Simp#define MMCSD_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); 127163516Simp 128163516Simpstatic int 129163516Simpmmcsd_probe(device_t dev) 130163516Simp{ 131163516Simp 132183704Smav device_quiet(dev); 133183480Simp device_set_desc(dev, "MMC/SD Memory Card"); 134163516Simp return (0); 135163516Simp} 136163516Simp 137163516Simpstatic int 138163516Simpmmcsd_attach(device_t dev) 139163516Simp{ 140163516Simp struct mmcsd_softc *sc; 141183774Simp struct disk *d; 142183774Simp intmax_t mb; 143234524Smarius uint32_t speed; 144234524Smarius uint32_t maxblocks; 145183774Simp char unit; 146163516Simp 147163516Simp sc = device_get_softc(dev); 148163516Simp sc->dev = dev; 149163516Simp MMCSD_LOCK_INIT(sc); 150163516Simp 151183774Simp d = sc->disk = disk_alloc(); 152183774Simp d->d_open = mmcsd_open; 153183774Simp d->d_close = mmcsd_close; 154183774Simp d->d_strategy = mmcsd_strategy; 155188725Smav d->d_dump = mmcsd_dump; 156183774Simp d->d_name = "mmcsd"; 157183774Simp d->d_drv1 = sc; 158184033Smav d->d_maxsize = 4*1024*1024; /* Maximum defined SD card AU size. */ 159183774Simp d->d_sectorsize = mmc_get_sector_size(dev); 160224868Smav d->d_mediasize = (off_t)mmc_get_media_size(dev) * d->d_sectorsize; 161185202Smav d->d_stripeoffset = 0; 162185202Smav d->d_stripesize = mmc_get_erase_sector(dev) * d->d_sectorsize; 163183774Simp d->d_unit = device_get_unit(dev); 164184033Smav d->d_flags = DISKFLAG_CANDELETE; 165183774Simp /* 166183774Simp * Display in most natural units. There's no cards < 1MB. 167183774Simp * The SD standard goes to 2GiB, but the data format supports 168183774Simp * up to 4GiB and some card makers push it up to this limit. 169183774Simp * The SDHC standard only goes to 32GiB (the data format in 170183774Simp * SDHC is good to 2TiB however, which isn't too ugly at 171183774Simp * 2048GiBm, so we note it in passing here and don't add the 172183774Simp * code to print TiB). 173183774Simp */ 174183774Simp mb = d->d_mediasize >> 20; /* 1MiB == 1 << 20 */ 175183774Simp unit = 'M'; 176183805Smav if (mb >= 10240) { /* 1GiB = 1024 MiB */ 177183774Simp unit = 'G'; 178183774Simp mb /= 1024; 179183774Simp } 180234524Smarius /* 181234524Smarius * Report the clock speed of the underlying hardware, which might be 182234524Smarius * different than what the card reports due to hardware limitations. 183239607Simp * Report how many blocks the hardware transfers at once. 184234524Smarius */ 185234524Smarius speed = mmcbr_get_clock(device_get_parent(dev)); 186234524Smarius maxblocks = mmc_get_max_data(dev); 187234524Smarius device_printf(dev, "%ju%cB <%s>%s at %s %d.%01dMHz/%dbit/%d-block\n", 188234524Smarius mb, unit, mmc_get_card_id_string(dev), 189183774Simp mmc_get_read_only(dev) ? " (read-only)" : "", 190183774Simp device_get_nameunit(device_get_parent(dev)), 191234524Smarius speed / 1000000, (speed / 100000) % 10, 192234524Smarius mmcsd_bus_bit_width(dev), maxblocks); 193183774Simp disk_create(d, DISK_VERSION); 194163516Simp bioq_init(&sc->bio_queue); 195169567Simp 196169567Simp sc->running = 1; 197185721Smav sc->suspend = 0; 198184034Smav sc->eblock = sc->eend = 0; 199172836Sjulian kproc_create(&mmcsd_task, sc, &sc->p, 0, 0, "task: mmc/sd card"); 200163516Simp 201163516Simp return (0); 202163516Simp} 203163516Simp 204163516Simpstatic int 205163516Simpmmcsd_detach(device_t dev) 206163516Simp{ 207169567Simp struct mmcsd_softc *sc = device_get_softc(dev); 208169567Simp 209169567Simp MMCSD_LOCK(sc); 210185721Smav sc->suspend = 0; 211185721Smav if (sc->running > 0) { 212185721Smav /* kill thread */ 213185721Smav sc->running = 0; 214185721Smav wakeup(sc); 215185721Smav /* wait for thread to finish. */ 216185721Smav while (sc->running != -1) 217185721Smav msleep(sc, &sc->sc_mtx, 0, "detach", 0); 218185721Smav } 219169567Simp MMCSD_UNLOCK(sc); 220169567Simp 221185201Smav /* Flush the request queue. */ 222185201Smav bioq_flush(&sc->bio_queue, NULL, ENXIO); 223169567Simp /* kill disk */ 224169567Simp disk_destroy(sc->disk); 225169567Simp 226169567Simp MMCSD_LOCK_DESTROY(sc); 227169567Simp 228183467Simp return (0); 229163516Simp} 230163516Simp 231163516Simpstatic int 232185721Smavmmcsd_suspend(device_t dev) 233185721Smav{ 234185721Smav struct mmcsd_softc *sc = device_get_softc(dev); 235185721Smav 236185721Smav MMCSD_LOCK(sc); 237185721Smav sc->suspend = 1; 238185721Smav if (sc->running > 0) { 239185721Smav /* kill thread */ 240185721Smav sc->running = 0; 241185721Smav wakeup(sc); 242185721Smav /* wait for thread to finish. */ 243185721Smav while (sc->running != -1) 244185721Smav msleep(sc, &sc->sc_mtx, 0, "detach", 0); 245185721Smav } 246185721Smav MMCSD_UNLOCK(sc); 247185721Smav return (0); 248185721Smav} 249185721Smav 250185721Smavstatic int 251185721Smavmmcsd_resume(device_t dev) 252185721Smav{ 253185721Smav struct mmcsd_softc *sc = device_get_softc(dev); 254185721Smav 255185721Smav MMCSD_LOCK(sc); 256185721Smav sc->suspend = 0; 257185721Smav if (sc->running <= 0) { 258185721Smav sc->running = 1; 259185721Smav MMCSD_UNLOCK(sc); 260185721Smav kproc_create(&mmcsd_task, sc, &sc->p, 0, 0, "task: mmc/sd card"); 261185721Smav } else 262185721Smav MMCSD_UNLOCK(sc); 263185721Smav return (0); 264185721Smav} 265185721Smav 266185721Smavstatic int 267163516Simpmmcsd_open(struct disk *dp) 268163516Simp{ 269236491Smarius 270183467Simp return (0); 271163516Simp} 272163516Simp 273163516Simpstatic int 274163516Simpmmcsd_close(struct disk *dp) 275163516Simp{ 276236491Smarius 277183467Simp return (0); 278163516Simp} 279163516Simp 280163516Simpstatic void 281163516Simpmmcsd_strategy(struct bio *bp) 282163516Simp{ 283163516Simp struct mmcsd_softc *sc; 284163516Simp 285163516Simp sc = (struct mmcsd_softc *)bp->bio_disk->d_drv1; 286163516Simp MMCSD_LOCK(sc); 287185721Smav if (sc->running > 0 || sc->suspend > 0) { 288185201Smav bioq_disksort(&sc->bio_queue, bp); 289185721Smav MMCSD_UNLOCK(sc); 290185201Smav wakeup(sc); 291185201Smav } else { 292185201Smav MMCSD_UNLOCK(sc); 293185201Smav biofinish(bp, NULL, ENXIO); 294185201Smav } 295163516Simp} 296163516Simp 297239607Simpstatic const char * 298239607Simpmmcsd_errmsg(int e) 299239607Simp{ 300239607Simp if (e < 0 || e > MMC_ERR_MAX) 301239607Simp return "Bad error code"; 302239607Simp return errmsg[e]; 303239607Simp} 304239607Simp 305184033Smavstatic daddr_t 306184033Smavmmcsd_rw(struct mmcsd_softc *sc, struct bio *bp) 307184033Smav{ 308184033Smav daddr_t block, end; 309184033Smav struct mmc_command cmd; 310184033Smav struct mmc_command stop; 311184033Smav struct mmc_request req; 312184033Smav struct mmc_data data; 313184033Smav device_t dev = sc->dev; 314184033Smav int sz = sc->disk->d_sectorsize; 315184033Smav 316184033Smav block = bp->bio_pblkno; 317184033Smav end = bp->bio_pblkno + (bp->bio_bcount / sz); 318184033Smav while (block < end) { 319184033Smav char *vaddr = bp->bio_data + 320184033Smav (block - bp->bio_pblkno) * sz; 321184452Smav int numblocks = min(end - block, mmc_get_max_data(dev)); 322184033Smav memset(&req, 0, sizeof(req)); 323184033Smav memset(&cmd, 0, sizeof(cmd)); 324184033Smav memset(&stop, 0, sizeof(stop)); 325184033Smav req.cmd = &cmd; 326184033Smav cmd.data = &data; 327184033Smav if (bp->bio_cmd == BIO_READ) { 328184033Smav if (numblocks > 1) 329184033Smav cmd.opcode = MMC_READ_MULTIPLE_BLOCK; 330184033Smav else 331184033Smav cmd.opcode = MMC_READ_SINGLE_BLOCK; 332184033Smav } else { 333184033Smav if (numblocks > 1) 334184033Smav cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK; 335184033Smav else 336184033Smav cmd.opcode = MMC_WRITE_BLOCK; 337184033Smav } 338184033Smav cmd.arg = block; 339184033Smav if (!mmc_get_high_cap(dev)) 340184033Smav cmd.arg <<= 9; 341184033Smav cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; 342184033Smav data.data = vaddr; 343184033Smav data.mrq = &req; 344184033Smav if (bp->bio_cmd == BIO_READ) 345184033Smav data.flags = MMC_DATA_READ; 346184033Smav else 347184033Smav data.flags = MMC_DATA_WRITE; 348184033Smav data.len = numblocks * sz; 349184033Smav if (numblocks > 1) { 350184033Smav data.flags |= MMC_DATA_MULTI; 351184033Smav stop.opcode = MMC_STOP_TRANSMISSION; 352184033Smav stop.arg = 0; 353184033Smav stop.flags = MMC_RSP_R1B | MMC_CMD_AC; 354184033Smav req.stop = &stop; 355184033Smav } 356184033Smav MMCBUS_WAIT_FOR_REQUEST(device_get_parent(dev), dev, 357184033Smav &req); 358239607Simp if (req.cmd->error != MMC_ERR_NONE) { 359239607Simp device_printf(dev, "Error indicated: %d %s\n", 360239607Simp req.cmd->error, mmcsd_errmsg(req.cmd->error)); 361184033Smav break; 362239607Simp } 363184033Smav block += numblocks; 364184033Smav } 365184033Smav return (block); 366184033Smav} 367184033Smav 368184033Smavstatic daddr_t 369184033Smavmmcsd_delete(struct mmcsd_softc *sc, struct bio *bp) 370184033Smav{ 371184033Smav daddr_t block, end, start, stop; 372184033Smav struct mmc_command cmd; 373184033Smav struct mmc_request req; 374184033Smav device_t dev = sc->dev; 375184033Smav int sz = sc->disk->d_sectorsize; 376184033Smav int erase_sector; 377184033Smav 378184033Smav block = bp->bio_pblkno; 379184033Smav end = bp->bio_pblkno + (bp->bio_bcount / sz); 380184034Smav /* Coalesce with part remaining from previous request. */ 381184034Smav if (block > sc->eblock && block <= sc->eend) 382184034Smav block = sc->eblock; 383184034Smav if (end >= sc->eblock && end < sc->eend) 384184034Smav end = sc->eend; 385184033Smav /* Safe round to the erase sector boundaries. */ 386184033Smav erase_sector = mmc_get_erase_sector(dev); 387184033Smav start = block + erase_sector - 1; /* Round up. */ 388184033Smav start -= start % erase_sector; 389184033Smav stop = end; /* Round down. */ 390184033Smav stop -= end % erase_sector; 391184034Smav /* We can't erase area smaller then sector, store it for later. */ 392184034Smav if (start >= stop) { 393184034Smav sc->eblock = block; 394184034Smav sc->eend = end; 395184033Smav return (end); 396184034Smav } 397184033Smav 398184033Smav /* Set erase start position. */ 399184033Smav memset(&req, 0, sizeof(req)); 400184033Smav memset(&cmd, 0, sizeof(cmd)); 401184033Smav req.cmd = &cmd; 402184033Smav if (mmc_get_card_type(dev) == mode_sd) 403184033Smav cmd.opcode = SD_ERASE_WR_BLK_START; 404184033Smav else 405184033Smav cmd.opcode = MMC_ERASE_GROUP_START; 406184033Smav cmd.arg = start; 407184033Smav if (!mmc_get_high_cap(dev)) 408184033Smav cmd.arg <<= 9; 409184033Smav cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; 410184033Smav MMCBUS_WAIT_FOR_REQUEST(device_get_parent(dev), dev, 411184033Smav &req); 412184033Smav if (req.cmd->error != MMC_ERR_NONE) { 413184033Smav printf("erase err1: %d\n", req.cmd->error); 414184033Smav return (block); 415184033Smav } 416184033Smav /* Set erase stop position. */ 417184033Smav memset(&req, 0, sizeof(req)); 418184033Smav memset(&cmd, 0, sizeof(cmd)); 419184033Smav req.cmd = &cmd; 420184033Smav if (mmc_get_card_type(dev) == mode_sd) 421184033Smav cmd.opcode = SD_ERASE_WR_BLK_END; 422184033Smav else 423184033Smav cmd.opcode = MMC_ERASE_GROUP_END; 424184033Smav cmd.arg = stop; 425184033Smav if (!mmc_get_high_cap(dev)) 426184033Smav cmd.arg <<= 9; 427184033Smav cmd.arg--; 428184033Smav cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; 429184033Smav MMCBUS_WAIT_FOR_REQUEST(device_get_parent(dev), dev, 430184033Smav &req); 431184033Smav if (req.cmd->error != MMC_ERR_NONE) { 432184033Smav printf("erase err2: %d\n", req.cmd->error); 433184033Smav return (block); 434184033Smav } 435184033Smav /* Erase range. */ 436184033Smav memset(&req, 0, sizeof(req)); 437184033Smav memset(&cmd, 0, sizeof(cmd)); 438184033Smav req.cmd = &cmd; 439184033Smav cmd.opcode = MMC_ERASE; 440184033Smav cmd.arg = 0; 441184033Smav cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; 442184033Smav MMCBUS_WAIT_FOR_REQUEST(device_get_parent(dev), dev, 443184033Smav &req); 444184033Smav if (req.cmd->error != MMC_ERR_NONE) { 445184033Smav printf("erase err3 %d\n", req.cmd->error); 446184033Smav return (block); 447184033Smav } 448184034Smav /* Store one of remaining parts for the next call. */ 449184034Smav if (bp->bio_pblkno >= sc->eblock || block == start) { 450184034Smav sc->eblock = stop; /* Predict next forward. */ 451184034Smav sc->eend = end; 452184034Smav } else { 453184034Smav sc->eblock = block; /* Predict next backward. */ 454184034Smav sc->eend = start; 455184034Smav } 456184033Smav return (end); 457184033Smav} 458184033Smav 459188725Smavstatic int 460188725Smavmmcsd_dump(void *arg, void *virtual, vm_offset_t physical, 461188725Smav off_t offset, size_t length) 462188725Smav{ 463188725Smav struct disk *disk = arg; 464188725Smav struct mmcsd_softc *sc = (struct mmcsd_softc *)disk->d_drv1; 465188725Smav device_t dev = sc->dev; 466188725Smav struct bio bp; 467188725Smav daddr_t block, end; 468188725Smav 469188725Smav /* length zero is special and really means flush buffers to media */ 470188725Smav if (!length) 471188725Smav return (0); 472188725Smav 473188725Smav bzero(&bp, sizeof(struct bio)); 474188725Smav bp.bio_disk = disk; 475188725Smav bp.bio_pblkno = offset / disk->d_sectorsize; 476188725Smav bp.bio_bcount = length; 477188725Smav bp.bio_data = virtual; 478188725Smav bp.bio_cmd = BIO_WRITE; 479188725Smav end = bp.bio_pblkno + bp.bio_bcount / sc->disk->d_sectorsize; 480188725Smav MMCBUS_ACQUIRE_BUS(device_get_parent(dev), dev); 481188725Smav block = mmcsd_rw(sc, &bp); 482188725Smav MMCBUS_RELEASE_BUS(device_get_parent(dev), dev); 483188725Smav return ((end < block) ? EIO : 0); 484188725Smav} 485188725Smav 486163516Simpstatic void 487163516Simpmmcsd_task(void *arg) 488163516Simp{ 489163516Simp struct mmcsd_softc *sc = (struct mmcsd_softc*)arg; 490163516Simp struct bio *bp; 491163516Simp int sz; 492163516Simp daddr_t block, end; 493163516Simp device_t dev; 494163516Simp 495163516Simp dev = sc->dev; 496185201Smav while (1) { 497163516Simp MMCSD_LOCK(sc); 498163516Simp do { 499185201Smav if (sc->running == 0) 500185201Smav goto out; 501185201Smav bp = bioq_takefirst(&sc->bio_queue); 502163516Simp if (bp == NULL) 503163516Simp msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0); 504185201Smav } while (bp == NULL); 505163516Simp MMCSD_UNLOCK(sc); 506183448Simp if (bp->bio_cmd != BIO_READ && mmc_get_read_only(dev)) { 507183448Simp bp->bio_error = EROFS; 508183448Simp bp->bio_resid = bp->bio_bcount; 509183448Simp bp->bio_flags |= BIO_ERROR; 510183448Simp biodone(bp); 511183448Simp continue; 512183448Simp } 513163516Simp MMCBUS_ACQUIRE_BUS(device_get_parent(dev), dev); 514163516Simp sz = sc->disk->d_sectorsize; 515184033Smav block = bp->bio_pblkno; 516163516Simp end = bp->bio_pblkno + (bp->bio_bcount / sz); 517184033Smav if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) { 518184034Smav /* Access to the remaining erase block obsoletes it. */ 519184034Smav if (block < sc->eend && end > sc->eblock) 520184034Smav sc->eblock = sc->eend = 0; 521184033Smav block = mmcsd_rw(sc, bp); 522184033Smav } else if (bp->bio_cmd == BIO_DELETE) { 523184033Smav block = mmcsd_delete(sc, bp); 524163516Simp } 525163516Simp MMCBUS_RELEASE_BUS(device_get_parent(dev), dev); 526183480Simp if (block < end) { 527183480Simp bp->bio_error = EIO; 528183480Simp bp->bio_resid = (end - block) * sz; 529183480Simp bp->bio_flags |= BIO_ERROR; 530183480Simp } 531163516Simp biodone(bp); 532163516Simp } 533185201Smavout: 534169567Simp /* tell parent we're done */ 535169567Simp sc->running = -1; 536185721Smav MMCSD_UNLOCK(sc); 537169567Simp wakeup(sc); 538169567Simp 539172836Sjulian kproc_exit(0); 540163516Simp} 541163516Simp 542183774Simpstatic int 543183774Simpmmcsd_bus_bit_width(device_t dev) 544183774Simp{ 545236491Smarius 546183774Simp if (mmc_get_bus_width(dev) == bus_width_1) 547183774Simp return (1); 548183774Simp if (mmc_get_bus_width(dev) == bus_width_4) 549183774Simp return (4); 550183774Simp return (8); 551183774Simp} 552183774Simp 553163516Simpstatic device_method_t mmcsd_methods[] = { 554163516Simp DEVMETHOD(device_probe, mmcsd_probe), 555163516Simp DEVMETHOD(device_attach, mmcsd_attach), 556163516Simp DEVMETHOD(device_detach, mmcsd_detach), 557185721Smav DEVMETHOD(device_suspend, mmcsd_suspend), 558185721Smav DEVMETHOD(device_resume, mmcsd_resume), 559234524Smarius DEVMETHOD_END 560163516Simp}; 561163516Simp 562163516Simpstatic driver_t mmcsd_driver = { 563163516Simp "mmcsd", 564163516Simp mmcsd_methods, 565163516Simp sizeof(struct mmcsd_softc), 566163516Simp}; 567163516Simpstatic devclass_t mmcsd_devclass; 568163516Simp 569234524SmariusDRIVER_MODULE(mmcsd, mmc, mmcsd_driver, mmcsd_devclass, NULL, NULL); 570