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