Hi tech@ Here is a diff to allow the sdmmc SMC_CAPS_SINGLE_ONLY caps to do something. The bits I take are from NetBSD and it works well with ommmc(4) on my Beagle Bone Black.
This capability force the sdmmc stack to only issue single blocks transfers. It is usefull for debug purpose and/or for broken sdmmmc controller. Any OK/Comments ? Cheers, Index: sdmmc_mem.c =================================================================== RCS file: /cvs/src/sys/dev/sdmmc/sdmmc_mem.c,v retrieving revision 1.17 diff -u -p -u -p -r1.17 sdmmc_mem.c --- sdmmc_mem.c 12 Sep 2013 11:54:04 -0000 1.17 +++ sdmmc_mem.c 18 Oct 2013 09:31:15 -0000 @@ -42,6 +42,14 @@ int sdmmc_mem_mmc_switch(struct sdmmc_fu int sdmmc_mem_sd_init(struct sdmmc_softc *, struct sdmmc_function *); int sdmmc_mem_mmc_init(struct sdmmc_softc *, struct sdmmc_function *); +int sdmmc_mem_single_read_block(struct sdmmc_function *, int, u_char *, + size_t); +int sdmmc_mem_read_block_subr(struct sdmmc_function *, int, u_char *, + size_t); +int sdmmc_mem_single_write_block(struct sdmmc_function *, int, u_char *, + size_t); +int sdmmc_mem_write_block_subr(struct sdmmc_function *, int, u_char *, + size_t); #ifdef SDMMC_DEBUG #define DPRINTF(s) printf s @@ -551,14 +559,13 @@ sdmmc_mem_set_blocklen(struct sdmmc_soft } int -sdmmc_mem_read_block(struct sdmmc_function *sf, int blkno, u_char *data, +sdmmc_mem_read_block_subr(struct sdmmc_function *sf, int blkno, u_char *data, size_t datalen) { struct sdmmc_softc *sc = sf->sc; struct sdmmc_command cmd; int error; - rw_enter_write(&sc->sc_lock); if ((error = sdmmc_select_card(sc, sf)) != 0) goto err; @@ -602,20 +609,53 @@ sdmmc_mem_read_block(struct sdmmc_functi } while (!ISSET(MMC_R1(cmd.c_resp), MMC_R1_READY_FOR_DATA)); err: - rw_exit(&sc->sc_lock); - return error; + return (error); } int -sdmmc_mem_write_block(struct sdmmc_function *sf, int blkno, u_char *data, +sdmmc_mem_single_read_block(struct sdmmc_function *sf, int blkno, u_char *data, + size_t datalen) +{ + int error; + int i; + + for (i = 0; i < datalen / sf->csd.sector_size; i++) { + error = sdmmc_mem_read_block_subr(sf, blkno + i, data + i * + sf->csd.sector_size, sf->csd.sector_size); + if (error) + break; + } + + return (error); +} + +int +sdmmc_mem_read_block(struct sdmmc_function *sf, int blkno, u_char *data, size_t datalen) { struct sdmmc_softc *sc = sf->sc; - struct sdmmc_command cmd; int error; rw_enter_write(&sc->sc_lock); + if (ISSET(sc->sc_caps, SMC_CAPS_SINGLE_ONLY)) { + error = sdmmc_mem_single_read_block(sf, blkno, data, datalen); + } else { + error = sdmmc_mem_read_block_subr(sf, blkno, data, datalen); + } + + rw_exit(&sc->sc_lock); + return (error); +} + +int +sdmmc_mem_write_block_subr(struct sdmmc_function *sf, int blkno, u_char *data, + size_t datalen) +{ + struct sdmmc_softc *sc = sf->sc; + struct sdmmc_command cmd; + int error; + if ((error = sdmmc_select_card(sc, sf)) != 0) goto err; @@ -657,6 +697,41 @@ sdmmc_mem_write_block(struct sdmmc_funct } while (!ISSET(MMC_R1(cmd.c_resp), MMC_R1_READY_FOR_DATA)); err: + return (error); +} + +int +sdmmc_mem_single_write_block(struct sdmmc_function *sf, int blkno, u_char *data, + size_t datalen) +{ + int error; + int i; + + for (i = 0; i < datalen / sf->csd.sector_size; i++) { + error = sdmmc_mem_write_block_subr(sf, blkno + i, data + i * + sf->csd.sector_size, sf->csd.sector_size); + if (error) + break; + } + + return (error); +} + +int +sdmmc_mem_write_block(struct sdmmc_function *sf, int blkno, u_char *data, + size_t datalen) +{ + struct sdmmc_softc *sc = sf->sc; + int error; + + rw_enter_write(&sc->sc_lock); + + if (ISSET(sc->sc_caps, SMC_CAPS_SINGLE_ONLY)) { + error = sdmmc_mem_single_write_block(sf, blkno, data, datalen); + } else { + error = sdmmc_mem_write_block_subr(sf, blkno, data, datalen); + } + rw_exit(&sc->sc_lock); - return error; + return (error); }