1163516Simp/*-
2163516Simp * Copyright (c) 2006 Bernd Walter.  All rights reserved.
3163516Simp * Copyright (c) 2006 M. Warner Losh.  All rights reserved.
4318198Smarius * Copyright (c) 2017 Marius Strobl <marius@FreeBSD.org>
5163516Simp *
6163516Simp * Redistribution and use in source and binary forms, with or without
7163516Simp * modification, are permitted provided that the following conditions
8163516Simp * are met:
9163516Simp * 1. Redistributions of source code must retain the above copyright
10163516Simp *    notice, this list of conditions and the following disclaimer.
11163516Simp * 2. Redistributions in binary form must reproduce the above copyright
12163516Simp *    notice, this list of conditions and the following disclaimer in the
13163516Simp *    documentation and/or other materials provided with the distribution.
14163516Simp *
15163516Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16163516Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17163516Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18163516Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19163516Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20163516Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21163516Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22163516Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23163516Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24163516Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25170002Simp *
26170002Simp * Portions of this software may have been developed with reference to
27170002Simp * the SD Simplified Specification.  The following disclaimer may apply:
28170002Simp *
29170002Simp * The following conditions apply to the release of the simplified
30170002Simp * specification ("Simplified Specification") by the SD Card Association and
31170002Simp * the SD Group. The Simplified Specification is a subset of the complete SD
32170002Simp * Specification which is owned by the SD Card Association and the SD
33170002Simp * Group. This Simplified Specification is provided on a non-confidential
34170002Simp * basis subject to the disclaimers below. Any implementation of the
35170002Simp * Simplified Specification may require a license from the SD Card
36170002Simp * Association, SD Group, SD-3C LLC or other third parties.
37170002Simp *
38170002Simp * Disclaimers:
39170002Simp *
40170002Simp * The information contained in the Simplified Specification is presented only
41170002Simp * as a standard specification for SD Cards and SD Host/Ancillary products and
42170002Simp * is provided "AS-IS" without any representations or warranties of any
43170002Simp * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
44170002Simp * Card Association for any damages, any infringements of patents or other
45170002Simp * right of the SD Group, SD-3C LLC, the SD Card Association or any third
46170002Simp * parties, which may result from its use. No license is granted by
47170002Simp * implication, estoppel or otherwise under any patent or other rights of the
48170002Simp * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
49170002Simp * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
50170002Simp * or the SD Card Association to disclose or distribute any technical
51170002Simp * information, know-how or other confidential information to any third party.
52163516Simp */
53163516Simp
54163516Simp#include <sys/cdefs.h>
55163516Simp__FBSDID("$FreeBSD: stable/10/sys/dev/mmc/mmcsd.c 338638 2018-09-13 10:18:50Z marius $");
56163516Simp
57163516Simp#include <sys/param.h>
58163516Simp#include <sys/systm.h>
59163516Simp#include <sys/bio.h>
60163516Simp#include <sys/bus.h>
61163516Simp#include <sys/conf.h>
62338638Smarius#include <sys/endian.h>
63318198Smarius#include <sys/fcntl.h>
64318198Smarius#include <sys/ioccom.h>
65163516Simp#include <sys/kernel.h>
66163516Simp#include <sys/kthread.h>
67163516Simp#include <sys/lock.h>
68163516Simp#include <sys/malloc.h>
69163516Simp#include <sys/module.h>
70163516Simp#include <sys/mutex.h>
71338638Smarius#include <sys/priv.h>
72318198Smarius#include <sys/slicer.h>
73338638Smarius#include <sys/sysctl.h>
74278687Sian#include <sys/time.h>
75318198Smarius
76318198Smarius#include <geom/geom.h>
77163516Simp#include <geom/geom_disk.h>
78163516Simp
79318198Smarius#include <dev/mmc/bridge.h>
80318198Smarius#include <dev/mmc/mmc_ioctl.h>
81318198Smarius#include <dev/mmc/mmc_subr.h>
82234524Smarius#include <dev/mmc/mmcbrvar.h>
83234524Smarius#include <dev/mmc/mmcreg.h>
84163516Simp#include <dev/mmc/mmcvar.h>
85163516Simp
86163516Simp#include "mmcbus_if.h"
87163516Simp
88234524Smarius#if __FreeBSD_version < 800002
89234524Smarius#define	kproc_create	kthread_create
90234524Smarius#define	kproc_exit	kthread_exit
91234524Smarius#endif
92234524Smarius
93318198Smarius#define	MMCSD_CMD_RETRIES	5
94318198Smarius
95318198Smarius#define	MMCSD_FMT_BOOT		"mmcsd%dboot"
96318198Smarius#define	MMCSD_FMT_GP		"mmcsd%dgp"
97318198Smarius#define	MMCSD_FMT_RPMB		"mmcsd%drpmb"
98318198Smarius#define	MMCSD_LABEL_ENH		"enh"
99318198Smarius
100318198Smarius#define	MMCSD_PART_NAMELEN	(16 + 1)
101318198Smarius
102318198Smariusstruct mmcsd_softc;
103318198Smarius
104318198Smariusstruct mmcsd_part {
105322120Smarius	struct mtx disk_mtx;
106322120Smarius	struct mtx ioctl_mtx;
107318198Smarius	struct mmcsd_softc *sc;
108163516Simp	struct disk *disk;
109163516Simp	struct proc *p;
110163516Simp	struct bio_queue_head bio_queue;
111184034Smav	daddr_t eblock, eend;	/* Range remaining after the last erase. */
112318198Smarius	u_int cnt;
113318198Smarius	u_int type;
114169567Simp	int running;
115185721Smav	int suspend;
116322120Smarius	int ioctl;
117318198Smarius	bool ro;
118318198Smarius	char name[MMCSD_PART_NAMELEN];
119318198Smarius};
120318198Smarius
121318198Smariusstruct mmcsd_softc {
122318198Smarius	device_t dev;
123322120Smarius	device_t mmcbus;
124318198Smarius	struct mmcsd_part *part[MMC_PART_MAX];
125318198Smarius	enum mmc_card_mode mode;
126322120Smarius	u_int max_data;		/* Maximum data size [blocks] */
127322120Smarius	u_int erase_sector;	/* Device native erase sector size [blocks] */
128322120Smarius	uint8_t	high_cap;	/* High Capacity device (block addressed) */
129318198Smarius	uint8_t part_curr;	/* Partition currently switched to */
130318198Smarius	uint8_t ext_csd[MMC_EXTCSD_SIZE];
131318198Smarius	uint16_t rca;
132322389Smarius	uint32_t flags;
133322389Smarius#define	MMCSD_INAND_CMD38	0x0001
134322389Smarius#define	MMCSD_USE_TRIM		0x0002
135338638Smarius#define	MMCSD_FLUSH_CACHE	0x0004
136338638Smarius#define	MMCSD_DIRTY		0x0008
137322389Smarius	uint32_t cmd6_time;	/* Generic switch timeout [us] */
138318198Smarius	uint32_t part_time;	/* Partition switch timeout [us] */
139318198Smarius	off_t enh_base;		/* Enhanced user data area slice base ... */
140318198Smarius	off_t enh_size;		/* ... and size [bytes] */
141278687Sian	int log_count;
142278687Sian	struct timeval log_time;
143318198Smarius	struct cdev *rpmb_dev;
144163516Simp};
145163516Simp
146239607Simpstatic const char *errmsg[] =
147239607Simp{
148239607Simp	"None",
149239607Simp	"Timeout",
150239607Simp	"Bad CRC",
151239607Simp	"Fifo",
152239607Simp	"Failed",
153239607Simp	"Invalid",
154239607Simp	"NO MEMORY"
155239607Simp};
156239607Simp
157338638Smariusstatic SYSCTL_NODE(_hw, OID_AUTO, mmcsd, CTLFLAG_RD, NULL, "mmcsd driver");
158338638Smarius
159338638Smariusstatic int mmcsd_cache = 1;
160338638SmariusTUNABLE_INT("hw.mmcsd.cache", &mmcsd_cache);
161338638SmariusSYSCTL_INT(_hw_mmcsd, OID_AUTO, cache, CTLFLAG_RDTUN, &mmcsd_cache, 0,
162338638Smarius    "Device R/W cache enabled if present");
163338638Smarius
164278687Sian#define	LOG_PPS		5 /* Log no more than 5 errors per second. */
165278687Sian
166163516Simp/* bus entry points */
167163516Simpstatic int mmcsd_attach(device_t dev);
168163516Simpstatic int mmcsd_detach(device_t dev);
169236491Smariusstatic int mmcsd_probe(device_t dev);
170338638Smariusstatic int mmcsd_shutdown(device_t dev);
171163516Simp
172163516Simp/* disk routines */
173163516Simpstatic int mmcsd_close(struct disk *dp);
174188725Smavstatic int mmcsd_dump(void *arg, void *virtual, vm_offset_t physical,
175318198Smarius    off_t offset, size_t length);
176318198Smariusstatic int mmcsd_getattr(struct bio *);
177318198Smariusstatic int mmcsd_ioctl_disk(struct disk *disk, u_long cmd, void *data,
178318198Smarius    int fflag, struct thread *td);
179236491Smariusstatic void mmcsd_strategy(struct bio *bp);
180163516Simpstatic void mmcsd_task(void *arg);
181163516Simp
182318198Smarius/* RMPB cdev interface */
183318198Smariusstatic int mmcsd_ioctl_rpmb(struct cdev *dev, u_long cmd, caddr_t data,
184318198Smarius    int fflag, struct thread *td);
185318198Smarius
186318198Smariusstatic void mmcsd_add_part(struct mmcsd_softc *sc, u_int type,
187322389Smarius    const char *name, u_int cnt, off_t media_size, bool ro);
188183774Simpstatic int mmcsd_bus_bit_width(device_t dev);
189318198Smariusstatic daddr_t mmcsd_delete(struct mmcsd_part *part, struct bio *bp);
190322389Smariusstatic const char *mmcsd_errmsg(int e);
191338638Smariusstatic int mmcsd_flush_cache(struct mmcsd_softc *sc);
192318198Smariusstatic int mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data,
193338638Smarius    int fflag, struct thread *td);
194318198Smariusstatic int mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic,
195318198Smarius    int fflag);
196318198Smariusstatic uintmax_t mmcsd_pretty_size(off_t size, char *unit);
197318198Smariusstatic daddr_t mmcsd_rw(struct mmcsd_part *part, struct bio *bp);
198318198Smariusstatic int mmcsd_set_blockcount(struct mmcsd_softc *sc, u_int count, bool rel);
199318198Smariusstatic int mmcsd_slicer(device_t dev, const char *provider,
200318198Smarius    struct flash_slice *slices, int *nslices);
201318198Smariusstatic int mmcsd_switch_part(device_t bus, device_t dev, uint16_t rca,
202318198Smarius    u_int part);
203183774Simp
204322120Smarius#define	MMCSD_DISK_LOCK(_part)		mtx_lock(&(_part)->disk_mtx)
205322120Smarius#define	MMCSD_DISK_UNLOCK(_part)	mtx_unlock(&(_part)->disk_mtx)
206322120Smarius#define	MMCSD_DISK_LOCK_INIT(_part)					\
207322120Smarius	mtx_init(&(_part)->disk_mtx, (_part)->name, "mmcsd disk", MTX_DEF)
208322120Smarius#define	MMCSD_DISK_LOCK_DESTROY(_part)	mtx_destroy(&(_part)->disk_mtx);
209322120Smarius#define	MMCSD_DISK_ASSERT_LOCKED(_part)					\
210322120Smarius	mtx_assert(&(_part)->disk_mtx, MA_OWNED);
211322120Smarius#define	MMCSD_DISK_ASSERT_UNLOCKED(_part)				\
212322120Smarius	mtx_assert(&(_part)->disk_mtx, MA_NOTOWNED);
213163516Simp
214322120Smarius#define	MMCSD_IOCTL_LOCK(_part)		mtx_lock(&(_part)->ioctl_mtx)
215322120Smarius#define	MMCSD_IOCTL_UNLOCK(_part)	mtx_unlock(&(_part)->ioctl_mtx)
216322120Smarius#define	MMCSD_IOCTL_LOCK_INIT(_part)					\
217322120Smarius	mtx_init(&(_part)->ioctl_mtx, (_part)->name, "mmcsd IOCTL", MTX_DEF)
218322120Smarius#define	MMCSD_IOCTL_LOCK_DESTROY(_part)	mtx_destroy(&(_part)->ioctl_mtx);
219322120Smarius#define	MMCSD_IOCTL_ASSERT_LOCKED(_part)				\
220322120Smarius	mtx_assert(&(_part)->ioctl_mtx, MA_OWNED);
221322120Smarius#define	MMCSD_IOCLT_ASSERT_UNLOCKED(_part)				\
222322120Smarius	mtx_assert(&(_part)->ioctl_mtx, MA_NOTOWNED);
223322120Smarius
224163516Simpstatic int
225163516Simpmmcsd_probe(device_t dev)
226163516Simp{
227163516Simp
228183704Smav	device_quiet(dev);
229183480Simp	device_set_desc(dev, "MMC/SD Memory Card");
230163516Simp	return (0);
231163516Simp}
232163516Simp
233163516Simpstatic int
234163516Simpmmcsd_attach(device_t dev)
235163516Simp{
236322120Smarius	device_t mmcbus;
237163516Simp	struct mmcsd_softc *sc;
238318198Smarius	const uint8_t *ext_csd;
239318198Smarius	off_t erase_size, sector_size, size, wp_size;
240318198Smarius	uintmax_t bytes;
241318198Smarius	int err, i;
242322389Smarius	uint32_t quirks;
243318198Smarius	uint8_t rev;
244318198Smarius	bool comp, ro;
245318198Smarius	char unit[2];
246163516Simp
247163516Simp	sc = device_get_softc(dev);
248163516Simp	sc->dev = dev;
249322120Smarius	sc->mmcbus = mmcbus = device_get_parent(dev);
250338638Smarius	sc->mode = mmc_get_card_type(dev);
251322120Smarius	/*
252322120Smarius	 * Note that in principle with an SDHCI-like re-tuning implementation,
253322120Smarius	 * the maximum data size can change at runtime due to a device removal/
254322120Smarius	 * insertion that results in switches to/from a transfer mode involving
255322120Smarius	 * re-tuning, iff there are multiple devices on a given bus.  Until now
256322120Smarius	 * mmc(4) lacks support for rescanning already attached buses, however,
257322120Smarius	 * and sdhci(4) to date has no support for shared buses in the first
258322120Smarius	 * place either.
259322120Smarius	 */
260322120Smarius	sc->max_data = mmc_get_max_data(dev);
261322120Smarius	sc->high_cap = mmc_get_high_cap(dev);
262318198Smarius	sc->rca = mmc_get_rca(dev);
263322389Smarius	sc->cmd6_time = mmc_get_cmd6_timeout(dev);
264322389Smarius	quirks = mmc_get_quirks(dev);
265163516Simp
266318198Smarius	/* Only MMC >= 4.x devices support EXT_CSD. */
267318198Smarius	if (mmc_get_spec_vers(dev) >= 4) {
268322120Smarius		MMCBUS_ACQUIRE_BUS(mmcbus, dev);
269322120Smarius		err = mmc_send_ext_csd(mmcbus, dev, sc->ext_csd);
270322120Smarius		MMCBUS_RELEASE_BUS(mmcbus, dev);
271322389Smarius		if (err != MMC_ERR_NONE) {
272322389Smarius			device_printf(dev, "Error reading EXT_CSD %s\n",
273322389Smarius			    mmcsd_errmsg(err));
274322389Smarius			return (ENXIO);
275322389Smarius		}
276318198Smarius	}
277318198Smarius	ext_csd = sc->ext_csd;
278269795Sian
279322389Smarius	if ((quirks & MMC_QUIRK_INAND_CMD38) != 0) {
280322389Smarius		if (mmc_get_spec_vers(dev) < 4) {
281322389Smarius			device_printf(dev,
282322389Smarius			    "MMC_QUIRK_INAND_CMD38 set but no EXT_CSD\n");
283322389Smarius			return (EINVAL);
284322389Smarius		}
285322389Smarius		sc->flags |= MMCSD_INAND_CMD38;
286322389Smarius	}
287322389Smarius
288183774Simp	/*
289322389Smarius	 * EXT_CSD_SEC_FEATURE_SUPPORT_GB_CL_EN denotes support for both
290322389Smarius	 * insecure and secure TRIM.
291322389Smarius	 */
292322389Smarius	if ((ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] &
293322389Smarius	    EXT_CSD_SEC_FEATURE_SUPPORT_GB_CL_EN) != 0 &&
294322389Smarius	    (quirks & MMC_QUIRK_BROKEN_TRIM) == 0) {
295322389Smarius		if (bootverbose)
296322389Smarius			device_printf(dev, "taking advantage of TRIM\n");
297322389Smarius		sc->flags |= MMCSD_USE_TRIM;
298322389Smarius		sc->erase_sector = 1;
299322389Smarius	} else
300322389Smarius		sc->erase_sector = mmc_get_erase_sector(dev);
301322389Smarius
302322389Smarius	/*
303318198Smarius	 * Enhanced user data area and general purpose partitions are only
304318198Smarius	 * supported in revision 1.4 (EXT_CSD_REV == 4) and later, the RPMB
305318198Smarius	 * partition in revision 1.5 (MMC v4.41, EXT_CSD_REV == 5) and later.
306183774Simp	 */
307318198Smarius	rev = ext_csd[EXT_CSD_REV];
308318198Smarius
309318198Smarius	/*
310338638Smarius	 * With revision 1.5 (MMC v4.5, EXT_CSD_REV == 6) and later, take
311338638Smarius	 * advantage of the device R/W cache if present and useage is not
312338638Smarius	 * disabled.
313338638Smarius	 */
314338638Smarius	if (rev >= 6 && mmcsd_cache != 0) {
315338638Smarius		size = le32dec(&ext_csd[EXT_CSD_CACHE_SIZE]);
316338638Smarius		if (bootverbose)
317338638Smarius			device_printf(dev, "cache size %juKB\n", size);
318338638Smarius		if (size > 0) {
319338638Smarius			MMCBUS_ACQUIRE_BUS(mmcbus, dev);
320338638Smarius			err = mmc_switch(mmcbus, dev, sc->rca,
321338638Smarius			    EXT_CSD_CMD_SET_NORMAL, EXT_CSD_CACHE_CTRL,
322338638Smarius			    EXT_CSD_CACHE_CTRL_CACHE_EN, sc->cmd6_time, true);
323338638Smarius			MMCBUS_RELEASE_BUS(mmcbus, dev);
324338638Smarius			if (err != MMC_ERR_NONE)
325338638Smarius				device_printf(dev, "failed to enable cache\n");
326338638Smarius			else
327338638Smarius				sc->flags |= MMCSD_FLUSH_CACHE;
328338638Smarius		}
329338638Smarius	}
330338638Smarius
331338638Smarius	/*
332318198Smarius	 * Ignore user-creatable enhanced user data area and general purpose
333318198Smarius	 * partitions partitions as long as partitioning hasn't been finished.
334318198Smarius	 */
335318198Smarius	comp = (ext_csd[EXT_CSD_PART_SET] & EXT_CSD_PART_SET_COMPLETED) != 0;
336318198Smarius
337318198Smarius	/*
338318198Smarius	 * Add enhanced user data area slice, unless it spans the entirety of
339318198Smarius	 * the user data area.  The enhanced area is of a multiple of high
340318198Smarius	 * capacity write protect groups ((ERASE_GRP_SIZE + HC_WP_GRP_SIZE) *
341318198Smarius	 * 512 KB) and its offset given in either sectors or bytes, depending
342318198Smarius	 * on whether it's a high capacity device or not.
343318198Smarius	 * NB: The slicer and its slices need to be registered before adding
344318198Smarius	 *     the disk for the corresponding user data area as re-tasting is
345318198Smarius	 *     racy.
346318198Smarius	 */
347318198Smarius	sector_size = mmc_get_sector_size(dev);
348318198Smarius	size = ext_csd[EXT_CSD_ENH_SIZE_MULT] +
349318198Smarius	    (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
350318198Smarius	    (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16);
351318198Smarius	if (rev >= 4 && comp == TRUE && size > 0 &&
352318198Smarius	    (ext_csd[EXT_CSD_PART_SUPPORT] &
353318198Smarius	    EXT_CSD_PART_SUPPORT_ENH_ATTR_EN) != 0 &&
354318198Smarius	    (ext_csd[EXT_CSD_PART_ATTR] & (EXT_CSD_PART_ATTR_ENH_USR)) != 0) {
355318198Smarius		erase_size = ext_csd[EXT_CSD_ERASE_GRP_SIZE] * 1024 *
356318198Smarius		    MMC_SECTOR_SIZE;
357318198Smarius		wp_size = ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
358318198Smarius		size *= erase_size * wp_size;
359318198Smarius		if (size != mmc_get_media_size(dev) * sector_size) {
360318198Smarius			sc->enh_size = size;
361338638Smarius			sc->enh_base =
362338638Smarius			    le32dec(&ext_csd[EXT_CSD_ENH_START_ADDR]) *
363322120Smarius			    (sc->high_cap != 0 ? MMC_SECTOR_SIZE : 1);
364318198Smarius		} else if (bootverbose)
365318198Smarius			device_printf(dev,
366318198Smarius			    "enhanced user data area spans entire device\n");
367183774Simp	}
368318198Smarius
369234524Smarius	/*
370318198Smarius	 * Add default partition.  This may be the only one or the user
371318198Smarius	 * data area in case partitions are supported.
372234524Smarius	 */
373318198Smarius	ro = mmc_get_read_only(dev);
374318198Smarius	mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_DEFAULT, "mmcsd",
375322389Smarius	    device_get_unit(dev), mmc_get_media_size(dev) * sector_size, ro);
376169567Simp
377318198Smarius	if (mmc_get_spec_vers(dev) < 3)
378318198Smarius		return (0);
379163516Simp
380318198Smarius	/* Belatedly announce enhanced user data slice. */
381318198Smarius	if (sc->enh_size != 0) {
382318198Smarius		bytes = mmcsd_pretty_size(size, unit);
383318198Smarius		printf(FLASH_SLICES_FMT ": %ju%sB enhanced user data area "
384318198Smarius		    "slice offset 0x%jx at %s\n", device_get_nameunit(dev),
385318198Smarius		    MMCSD_LABEL_ENH, bytes, unit, (uintmax_t)sc->enh_base,
386318198Smarius		    device_get_nameunit(dev));
387318198Smarius	}
388318198Smarius
389318198Smarius	/*
390318198Smarius	 * Determine partition switch timeout (provided in units of 10 ms)
391318198Smarius	 * and ensure it's at least 300 ms as some eMMC chips lie.
392318198Smarius	 */
393318198Smarius	sc->part_time = max(ext_csd[EXT_CSD_PART_SWITCH_TO] * 10 * 1000,
394318198Smarius	    300 * 1000);
395318198Smarius
396318198Smarius	/* Add boot partitions, which are of a fixed multiple of 128 KB. */
397318198Smarius	size = ext_csd[EXT_CSD_BOOT_SIZE_MULT] * MMC_BOOT_RPMB_BLOCK_SIZE;
398322120Smarius	if (size > 0 && (mmcbr_get_caps(mmcbus) & MMC_CAP_BOOT_NOACC) == 0) {
399318198Smarius		mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_BOOT0,
400322389Smarius		    MMCSD_FMT_BOOT, 0, size,
401318198Smarius		    ro | ((ext_csd[EXT_CSD_BOOT_WP_STATUS] &
402318198Smarius		    EXT_CSD_BOOT_WP_STATUS_BOOT0_MASK) != 0));
403318198Smarius		mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_BOOT1,
404322389Smarius		    MMCSD_FMT_BOOT, 1, size,
405318198Smarius		    ro | ((ext_csd[EXT_CSD_BOOT_WP_STATUS] &
406318198Smarius		    EXT_CSD_BOOT_WP_STATUS_BOOT1_MASK) != 0));
407318198Smarius	}
408318198Smarius
409318198Smarius	/* Add RPMB partition, which also is of a fixed multiple of 128 KB. */
410318198Smarius	size = ext_csd[EXT_CSD_RPMB_MULT] * MMC_BOOT_RPMB_BLOCK_SIZE;
411318198Smarius	if (rev >= 5 && size > 0)
412318198Smarius		mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_RPMB,
413322389Smarius		    MMCSD_FMT_RPMB, 0, size, ro);
414318198Smarius
415318198Smarius	if (rev <= 3 || comp == FALSE)
416318198Smarius		return (0);
417318198Smarius
418318198Smarius	/*
419318198Smarius	 * Add general purpose partitions, which are of a multiple of high
420318198Smarius	 * capacity write protect groups, too.
421318198Smarius	 */
422318198Smarius	if ((ext_csd[EXT_CSD_PART_SUPPORT] & EXT_CSD_PART_SUPPORT_EN) != 0) {
423318198Smarius		erase_size = ext_csd[EXT_CSD_ERASE_GRP_SIZE] * 1024 *
424318198Smarius		    MMC_SECTOR_SIZE;
425318198Smarius		wp_size = ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
426318198Smarius		for (i = 0; i < MMC_PART_GP_MAX; i++) {
427318198Smarius			size = ext_csd[EXT_CSD_GP_SIZE_MULT + i * 3] +
428318198Smarius			    (ext_csd[EXT_CSD_GP_SIZE_MULT + i * 3 + 1] << 8) +
429318198Smarius			    (ext_csd[EXT_CSD_GP_SIZE_MULT + i * 3 + 2] << 16);
430318198Smarius			if (size == 0)
431318198Smarius				continue;
432318198Smarius			mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_GP0 + i,
433322389Smarius			    MMCSD_FMT_GP, i, size * erase_size * wp_size, ro);
434318198Smarius		}
435318198Smarius	}
436163516Simp	return (0);
437163516Simp}
438163516Simp
439318198Smariusstatic uintmax_t
440318198Smariusmmcsd_pretty_size(off_t size, char *unit)
441318198Smarius{
442318198Smarius	uintmax_t bytes;
443318198Smarius	int i;
444318198Smarius
445318198Smarius	/*
446318198Smarius	 * Display in most natural units.  There's no card < 1MB.  However,
447318198Smarius	 * RPMB partitions occasionally are smaller than that, though.  The
448318198Smarius	 * SD standard goes to 2 GiB due to its reliance on FAT, but the data
449318198Smarius	 * format supports up to 4 GiB and some card makers push it up to this
450318198Smarius	 * limit.  The SDHC standard only goes to 32 GiB due to FAT32, but the
451318198Smarius	 * data format supports up to 2 TiB however.  2048 GB isn't too ugly,
452318198Smarius	 * so we note it in passing here and don't add the code to print TB).
453318198Smarius	 * Since these cards are sold in terms of MB and GB not MiB and GiB,
454318198Smarius	 * report them like that.  We also round to the nearest unit, since
455318198Smarius	 * many cards are a few percent short, even of the power of 10 size.
456318198Smarius	 */
457318198Smarius	bytes = size;
458318198Smarius	unit[0] = unit[1] = '\0';
459318198Smarius	for (i = 0; i <= 2 && bytes >= 1000; i++) {
460318198Smarius		bytes = (bytes + 1000 / 2 - 1) / 1000;
461318198Smarius		switch (i) {
462318198Smarius		case 0:
463318198Smarius			unit[0] = 'k';
464318198Smarius			break;
465318198Smarius		case 1:
466318198Smarius			unit[0] = 'M';
467318198Smarius			break;
468318198Smarius		case 2:
469318198Smarius			unit[0] = 'G';
470318198Smarius			break;
471318198Smarius		default:
472318198Smarius			break;
473318198Smarius		}
474318198Smarius	}
475318198Smarius	return (bytes);
476318198Smarius}
477318198Smarius
478318198Smariusstatic struct cdevsw mmcsd_rpmb_cdevsw = {
479318198Smarius	.d_version	= D_VERSION,
480318198Smarius	.d_name		= "mmcsdrpmb",
481318198Smarius	.d_ioctl	= mmcsd_ioctl_rpmb
482318198Smarius};
483318198Smarius
484318198Smariusstatic void
485318198Smariusmmcsd_add_part(struct mmcsd_softc *sc, u_int type, const char *name, u_int cnt,
486322389Smarius    off_t media_size, bool ro)
487318198Smarius{
488318198Smarius	struct make_dev_args args;
489322120Smarius	device_t dev, mmcbus;
490318198Smarius	const char *ext;
491318198Smarius	const uint8_t *ext_csd;
492318198Smarius	struct mmcsd_part *part;
493318198Smarius	struct disk *d;
494318198Smarius	uintmax_t bytes;
495318198Smarius	u_int gp;
496318198Smarius	uint32_t speed;
497318198Smarius	uint8_t extattr;
498318198Smarius	bool enh;
499318198Smarius	char unit[2];
500318198Smarius
501318198Smarius	dev = sc->dev;
502322120Smarius	mmcbus = sc->mmcbus;
503318198Smarius	part = sc->part[type] = malloc(sizeof(*part), M_DEVBUF,
504318198Smarius	    M_WAITOK | M_ZERO);
505318198Smarius	part->sc = sc;
506318198Smarius	part->cnt = cnt;
507318198Smarius	part->type = type;
508318198Smarius	part->ro = ro;
509318198Smarius	snprintf(part->name, sizeof(part->name), name, device_get_unit(dev));
510318198Smarius
511322120Smarius	MMCSD_IOCTL_LOCK_INIT(part);
512322120Smarius
513322120Smarius	/*
514322120Smarius	 * For the RPMB partition, allow IOCTL access only.
515322120Smarius	 * NB: If ever attaching RPMB partitions to disk(9), the re-tuning
516322120Smarius	 *     implementation and especially its pausing need to be revisited,
517322120Smarius	 *     because then re-tuning requests may be issued by the IOCTL half
518322120Smarius	 *     of this driver while re-tuning is already paused by the disk(9)
519322120Smarius	 *     one and vice versa.
520322120Smarius	 */
521318198Smarius	if (type == EXT_CSD_PART_CONFIG_ACC_RPMB) {
522318198Smarius		make_dev_args_init(&args);
523318198Smarius		args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK;
524318198Smarius		args.mda_devsw = &mmcsd_rpmb_cdevsw;
525318198Smarius		args.mda_uid = UID_ROOT;
526318198Smarius		args.mda_gid = GID_OPERATOR;
527318198Smarius		args.mda_mode = 0640;
528318198Smarius		args.mda_si_drv1 = part;
529318198Smarius		if (make_dev_s(&args, &sc->rpmb_dev, "%s", part->name) != 0) {
530318198Smarius			device_printf(dev, "Failed to make RPMB device\n");
531318198Smarius			free(part, M_DEVBUF);
532318198Smarius			return;
533318198Smarius		}
534318198Smarius	} else {
535322120Smarius		MMCSD_DISK_LOCK_INIT(part);
536318198Smarius
537318198Smarius		d = part->disk = disk_alloc();
538318198Smarius		d->d_close = mmcsd_close;
539318198Smarius		d->d_strategy = mmcsd_strategy;
540318198Smarius		d->d_ioctl = mmcsd_ioctl_disk;
541318198Smarius		d->d_dump = mmcsd_dump;
542318198Smarius		d->d_getattr = mmcsd_getattr;
543318198Smarius		d->d_name = part->name;
544318198Smarius		d->d_drv1 = part;
545318198Smarius		d->d_sectorsize = mmc_get_sector_size(dev);
546322120Smarius		d->d_maxsize = sc->max_data * d->d_sectorsize;
547318198Smarius		d->d_mediasize = media_size;
548322389Smarius		d->d_stripesize = sc->erase_sector * d->d_sectorsize;
549318198Smarius		d->d_unit = cnt;
550318198Smarius		d->d_flags = DISKFLAG_CANDELETE;
551338638Smarius		if ((sc->flags & MMCSD_FLUSH_CACHE) != 0)
552338638Smarius			d->d_flags |= DISKFLAG_CANFLUSHCACHE;
553322389Smarius		d->d_delmaxsize = mmc_get_erase_sector(dev) * d->d_sectorsize;
554318198Smarius		strlcpy(d->d_ident, mmc_get_card_sn_string(dev),
555318198Smarius		    sizeof(d->d_ident));
556318198Smarius		strlcpy(d->d_descr, mmc_get_card_id_string(dev),
557318198Smarius		    sizeof(d->d_descr));
558318198Smarius		d->d_rotation_rate = DISK_RR_NON_ROTATING;
559318198Smarius
560318198Smarius		disk_create(d, DISK_VERSION);
561318198Smarius		bioq_init(&part->bio_queue);
562318198Smarius
563318198Smarius		part->running = 1;
564318198Smarius		kproc_create(&mmcsd_task, part, &part->p, 0, 0,
565318198Smarius		    "%s%d: mmc/sd card", part->name, cnt);
566318198Smarius	}
567318198Smarius
568318198Smarius	bytes = mmcsd_pretty_size(media_size, unit);
569318198Smarius	if (type == EXT_CSD_PART_CONFIG_ACC_DEFAULT) {
570322120Smarius		speed = mmcbr_get_clock(mmcbus);
571318198Smarius		printf("%s%d: %ju%sB <%s>%s at %s %d.%01dMHz/%dbit/%d-block\n",
572318198Smarius		    part->name, cnt, bytes, unit, mmc_get_card_id_string(dev),
573322120Smarius		    ro ? " (read-only)" : "", device_get_nameunit(mmcbus),
574318198Smarius		    speed / 1000000, (speed / 100000) % 10,
575322120Smarius		    mmcsd_bus_bit_width(dev), sc->max_data);
576318198Smarius	} else if (type == EXT_CSD_PART_CONFIG_ACC_RPMB) {
577318198Smarius		printf("%s: %ju%sB partion %d%s at %s\n", part->name, bytes,
578318198Smarius		    unit, type, ro ? " (read-only)" : "",
579318198Smarius		    device_get_nameunit(dev));
580318198Smarius	} else {
581318198Smarius		enh = false;
582318198Smarius		ext = NULL;
583318198Smarius		extattr = 0;
584318198Smarius		if (type >= EXT_CSD_PART_CONFIG_ACC_GP0 &&
585318198Smarius		    type <= EXT_CSD_PART_CONFIG_ACC_GP3) {
586318198Smarius			ext_csd = sc->ext_csd;
587318198Smarius			gp = type - EXT_CSD_PART_CONFIG_ACC_GP0;
588318198Smarius			if ((ext_csd[EXT_CSD_PART_SUPPORT] &
589318198Smarius			    EXT_CSD_PART_SUPPORT_ENH_ATTR_EN) != 0 &&
590318198Smarius			    (ext_csd[EXT_CSD_PART_ATTR] &
591318198Smarius			    (EXT_CSD_PART_ATTR_ENH_GP0 << gp)) != 0)
592318198Smarius				enh = true;
593318198Smarius			else if ((ext_csd[EXT_CSD_PART_SUPPORT] &
594318198Smarius			    EXT_CSD_PART_SUPPORT_EXT_ATTR_EN) != 0) {
595318198Smarius				extattr = (ext_csd[EXT_CSD_EXT_PART_ATTR +
596318198Smarius				    (gp / 2)] >> (4 * (gp % 2))) & 0xF;
597318198Smarius				switch (extattr) {
598318198Smarius					case EXT_CSD_EXT_PART_ATTR_DEFAULT:
599318198Smarius						break;
600318198Smarius					case EXT_CSD_EXT_PART_ATTR_SYSTEMCODE:
601318198Smarius						ext = "system code";
602318198Smarius						break;
603318198Smarius					case EXT_CSD_EXT_PART_ATTR_NPERSISTENT:
604318198Smarius						ext = "non-persistent";
605318198Smarius						break;
606318198Smarius					default:
607318198Smarius						ext = "reserved";
608318198Smarius						break;
609318198Smarius				}
610318198Smarius			}
611318198Smarius		}
612318198Smarius		if (ext == NULL)
613318198Smarius			printf("%s%d: %ju%sB partion %d%s%s at %s\n",
614318198Smarius			    part->name, cnt, bytes, unit, type, enh ?
615318198Smarius			    " enhanced" : "", ro ? " (read-only)" : "",
616318198Smarius			    device_get_nameunit(dev));
617318198Smarius		else
618318198Smarius			printf("%s%d: %ju%sB partion %d extended 0x%x "
619318198Smarius			    "(%s)%s at %s\n", part->name, cnt, bytes, unit,
620318198Smarius			    type, extattr, ext, ro ? " (read-only)" : "",
621318198Smarius			    device_get_nameunit(dev));
622318198Smarius	}
623318198Smarius}
624318198Smarius
625163516Simpstatic int
626318198Smariusmmcsd_slicer(device_t dev, const char *provider,
627318198Smarius    struct flash_slice *slices, int *nslices)
628318198Smarius{
629318198Smarius	char name[MMCSD_PART_NAMELEN];
630318198Smarius	struct mmcsd_softc *sc;
631318198Smarius	struct mmcsd_part *part;
632318198Smarius
633318198Smarius	*nslices = 0;
634318198Smarius	if (slices == NULL)
635318198Smarius		return (ENOMEM);
636318198Smarius
637318198Smarius	sc = device_get_softc(dev);
638318198Smarius	if (sc->enh_size == 0)
639318198Smarius		return (ENXIO);
640318198Smarius
641318198Smarius	part = sc->part[EXT_CSD_PART_CONFIG_ACC_DEFAULT];
642318198Smarius	snprintf(name, sizeof(name), "%s%d", part->disk->d_name,
643318198Smarius	    part->disk->d_unit);
644318198Smarius	if (strcmp(name, provider) != 0)
645318198Smarius		return (ENXIO);
646318198Smarius
647318198Smarius	*nslices = 1;
648318198Smarius	slices[0].base = sc->enh_base;
649318198Smarius	slices[0].size = sc->enh_size;
650318198Smarius	slices[0].label = MMCSD_LABEL_ENH;
651318198Smarius	return (0);
652318198Smarius}
653318198Smarius
654318198Smariusstatic int
655163516Simpmmcsd_detach(device_t dev)
656163516Simp{
657169567Simp	struct mmcsd_softc *sc = device_get_softc(dev);
658318198Smarius	struct mmcsd_part *part;
659318198Smarius	int i;
660169567Simp
661318198Smarius	for (i = 0; i < MMC_PART_MAX; i++) {
662318198Smarius		part = sc->part[i];
663322120Smarius		if (part != NULL) {
664322120Smarius			if (part->disk != NULL) {
665322120Smarius				MMCSD_DISK_LOCK(part);
666322120Smarius				part->suspend = 0;
667322120Smarius				if (part->running > 0) {
668322120Smarius					/* kill thread */
669322120Smarius					part->running = 0;
670322120Smarius					wakeup(part);
671322120Smarius					/* wait for thread to finish. */
672322120Smarius					while (part->running != -1)
673322120Smarius						msleep(part, &part->disk_mtx, 0,
674322120Smarius						    "mmcsd disk detach", 0);
675322120Smarius				}
676322120Smarius				MMCSD_DISK_UNLOCK(part);
677318198Smarius			}
678322120Smarius			MMCSD_IOCTL_LOCK(part);
679322120Smarius			while (part->ioctl > 0)
680322120Smarius				msleep(part, &part->ioctl_mtx, 0,
681322120Smarius				    "mmcsd IOCTL detach", 0);
682322120Smarius			part->ioctl = -1;
683322120Smarius			MMCSD_IOCTL_UNLOCK(part);
684318198Smarius		}
685185721Smav	}
686169567Simp
687318198Smarius	if (sc->rpmb_dev != NULL)
688318198Smarius		destroy_dev(sc->rpmb_dev);
689169567Simp
690318198Smarius	for (i = 0; i < MMC_PART_MAX; i++) {
691318198Smarius		part = sc->part[i];
692318198Smarius		if (part != NULL) {
693318198Smarius			if (part->disk != NULL) {
694318198Smarius				/* Flush the request queue. */
695318198Smarius				bioq_flush(&part->bio_queue, NULL, ENXIO);
696318198Smarius				/* kill disk */
697318198Smarius				disk_destroy(part->disk);
698169567Simp
699322120Smarius				MMCSD_DISK_LOCK_DESTROY(part);
700318198Smarius			}
701322120Smarius			MMCSD_IOCTL_LOCK_DESTROY(part);
702318198Smarius			free(part, M_DEVBUF);
703318198Smarius		}
704318198Smarius	}
705338638Smarius	if (mmcsd_flush_cache(sc) != MMC_ERR_NONE)
706338638Smarius		device_printf(dev, "failed to flush cache\n");
707183467Simp	return (0);
708163516Simp}
709163516Simp
710163516Simpstatic int
711338638Smariusmmcsd_shutdown(device_t dev)
712338638Smarius{
713338638Smarius	struct mmcsd_softc *sc = device_get_softc(dev);
714338638Smarius
715338638Smarius	if (mmcsd_flush_cache(sc) != MMC_ERR_NONE)
716338638Smarius		device_printf(dev, "failed to flush cache\n");
717338638Smarius	return (0);
718338638Smarius}
719338638Smarius
720338638Smariusstatic int
721185721Smavmmcsd_suspend(device_t dev)
722185721Smav{
723185721Smav	struct mmcsd_softc *sc = device_get_softc(dev);
724318198Smarius	struct mmcsd_part *part;
725318198Smarius	int i;
726185721Smav
727318198Smarius	for (i = 0; i < MMC_PART_MAX; i++) {
728318198Smarius		part = sc->part[i];
729322120Smarius		if (part != NULL) {
730322120Smarius			if (part->disk != NULL) {
731322120Smarius				MMCSD_DISK_LOCK(part);
732322120Smarius				part->suspend = 1;
733322120Smarius				if (part->running > 0) {
734322120Smarius					/* kill thread */
735322120Smarius					part->running = 0;
736322120Smarius					wakeup(part);
737322120Smarius					/* wait for thread to finish. */
738322120Smarius					while (part->running != -1)
739322120Smarius						msleep(part, &part->disk_mtx, 0,
740322120Smarius						    "mmcsd disk suspension", 0);
741322120Smarius				}
742322120Smarius				MMCSD_DISK_UNLOCK(part);
743318198Smarius			}
744322120Smarius			MMCSD_IOCTL_LOCK(part);
745322120Smarius			while (part->ioctl > 0)
746322120Smarius				msleep(part, &part->ioctl_mtx, 0,
747322120Smarius				    "mmcsd IOCTL suspension", 0);
748322120Smarius			part->ioctl = -1;
749322120Smarius			MMCSD_IOCTL_UNLOCK(part);
750318198Smarius		}
751185721Smav	}
752338638Smarius	if (mmcsd_flush_cache(sc) != MMC_ERR_NONE)
753338638Smarius		device_printf(dev, "failed to flush cache\n");
754185721Smav	return (0);
755185721Smav}
756185721Smav
757185721Smavstatic int
758185721Smavmmcsd_resume(device_t dev)
759185721Smav{
760185721Smav	struct mmcsd_softc *sc = device_get_softc(dev);
761318198Smarius	struct mmcsd_part *part;
762318198Smarius	int i;
763185721Smav
764318198Smarius	for (i = 0; i < MMC_PART_MAX; i++) {
765318198Smarius		part = sc->part[i];
766322120Smarius		if (part != NULL) {
767322120Smarius			if (part->disk != NULL) {
768322120Smarius				MMCSD_DISK_LOCK(part);
769322120Smarius				part->suspend = 0;
770322120Smarius				if (part->running <= 0) {
771322120Smarius					part->running = 1;
772322120Smarius					MMCSD_DISK_UNLOCK(part);
773322120Smarius					kproc_create(&mmcsd_task, part,
774322120Smarius					    &part->p, 0, 0, "%s%d: mmc/sd card",
775322120Smarius					    part->name, part->cnt);
776322120Smarius				} else
777322120Smarius					MMCSD_DISK_UNLOCK(part);
778322120Smarius			}
779322120Smarius			MMCSD_IOCTL_LOCK(part);
780322120Smarius			part->ioctl = 0;
781322120Smarius			MMCSD_IOCTL_UNLOCK(part);
782318198Smarius		}
783318198Smarius	}
784185721Smav	return (0);
785185721Smav}
786185721Smav
787185721Smavstatic int
788338638Smariusmmcsd_close(struct disk *dp)
789163516Simp{
790338638Smarius	struct mmcsd_softc *sc;
791236491Smarius
792338638Smarius	if ((dp->d_flags & DISKFLAG_OPEN) != 0) {
793338638Smarius		sc = ((struct mmcsd_part *)dp->d_drv1)->sc;
794338638Smarius		if (mmcsd_flush_cache(sc) != MMC_ERR_NONE)
795338638Smarius			device_printf(sc->dev, "failed to flush cache\n");
796338638Smarius	}
797183467Simp	return (0);
798163516Simp}
799163516Simp
800163516Simpstatic void
801163516Simpmmcsd_strategy(struct bio *bp)
802163516Simp{
803163516Simp	struct mmcsd_softc *sc;
804318198Smarius	struct mmcsd_part *part;
805163516Simp
806318198Smarius	part = bp->bio_disk->d_drv1;
807318198Smarius	sc = part->sc;
808322120Smarius	MMCSD_DISK_LOCK(part);
809318198Smarius	if (part->running > 0 || part->suspend > 0) {
810318198Smarius		bioq_disksort(&part->bio_queue, bp);
811322120Smarius		MMCSD_DISK_UNLOCK(part);
812318198Smarius		wakeup(part);
813185201Smav	} else {
814322120Smarius		MMCSD_DISK_UNLOCK(part);
815185201Smav		biofinish(bp, NULL, ENXIO);
816185201Smav	}
817163516Simp}
818163516Simp
819318198Smariusstatic int
820318198Smariusmmcsd_ioctl_rpmb(struct cdev *dev, u_long cmd, caddr_t data,
821338638Smarius    int fflag, struct thread *td)
822318198Smarius{
823318198Smarius
824338638Smarius	return (mmcsd_ioctl(dev->si_drv1, cmd, data, fflag, td));
825318198Smarius}
826318198Smarius
827318198Smariusstatic int
828318198Smariusmmcsd_ioctl_disk(struct disk *disk, u_long cmd, void *data, int fflag,
829338638Smarius    struct thread *td)
830318198Smarius{
831318198Smarius
832338638Smarius	return (mmcsd_ioctl(disk->d_drv1, cmd, data, fflag, td));
833318198Smarius}
834318198Smarius
835318198Smariusstatic int
836338638Smariusmmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, int fflag,
837338638Smarius    struct thread *td)
838318198Smarius{
839318198Smarius	struct mmc_ioc_cmd *mic;
840318198Smarius	struct mmc_ioc_multi_cmd *mimc;
841318198Smarius	int i, err;
842318198Smarius	u_long cnt, size;
843318198Smarius
844318198Smarius	if ((fflag & FREAD) == 0)
845318198Smarius		return (EBADF);
846318198Smarius
847338638Smarius	err = priv_check(td, PRIV_DRIVER);
848338638Smarius	if (err != 0)
849338638Smarius		return (err);
850338638Smarius
851318198Smarius	err = 0;
852318198Smarius	switch (cmd) {
853318198Smarius	case MMC_IOC_CMD:
854318198Smarius		mic = data;
855322120Smarius		err = mmcsd_ioctl_cmd(part, mic, fflag);
856318198Smarius		break;
857322120Smarius	case MMC_IOC_MULTI_CMD:
858318198Smarius		mimc = data;
859318198Smarius		if (mimc->num_of_cmds == 0)
860318198Smarius			break;
861318198Smarius		if (mimc->num_of_cmds > MMC_IOC_MAX_CMDS)
862318198Smarius			return (EINVAL);
863318198Smarius		cnt = mimc->num_of_cmds;
864318198Smarius		size = sizeof(*mic) * cnt;
865318198Smarius		mic = malloc(size, M_TEMP, M_WAITOK);
866318198Smarius		err = copyin((const void *)mimc->cmds, mic, size);
867322120Smarius		if (err == 0) {
868322120Smarius			for (i = 0; i < cnt; i++) {
869322120Smarius				err = mmcsd_ioctl_cmd(part, &mic[i], fflag);
870322120Smarius				if (err != 0)
871322120Smarius					break;
872322120Smarius			}
873318198Smarius		}
874318198Smarius		free(mic, M_TEMP);
875318198Smarius		break;
876318198Smarius	default:
877318198Smarius		return (ENOIOCTL);
878318198Smarius	}
879318198Smarius	return (err);
880318198Smarius}
881318198Smarius
882318198Smariusstatic int
883318198Smariusmmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic, int fflag)
884318198Smarius{
885318198Smarius	struct mmc_command cmd;
886318198Smarius	struct mmc_data data;
887318198Smarius	struct mmcsd_softc *sc;
888322120Smarius	device_t dev, mmcbus;
889318198Smarius	void *dp;
890318198Smarius	u_long len;
891318198Smarius	int err, retries;
892318198Smarius	uint32_t status;
893318198Smarius	uint16_t rca;
894318198Smarius
895318198Smarius	if ((fflag & FWRITE) == 0 && mic->write_flag != 0)
896318198Smarius		return (EBADF);
897318198Smarius
898318198Smarius	if (part->ro == TRUE && mic->write_flag != 0)
899318198Smarius		return (EROFS);
900318198Smarius
901322120Smarius	/*
902322120Smarius	 * We don't need to explicitly lock against the disk(9) half of this
903322120Smarius	 * driver as MMCBUS_ACQUIRE_BUS() will serialize us.  However, it's
904322120Smarius	 * necessary to protect against races with detachment and suspension,
905322120Smarius	 * especially since it's required to switch away from RPMB partitions
906322120Smarius	 * again after an access (see mmcsd_switch_part()).
907322120Smarius	 */
908322120Smarius	MMCSD_IOCTL_LOCK(part);
909322120Smarius	while (part->ioctl != 0) {
910322120Smarius		if (part->ioctl < 0) {
911322120Smarius			MMCSD_IOCTL_UNLOCK(part);
912322120Smarius			return (ENXIO);
913322120Smarius		}
914322120Smarius		msleep(part, &part->ioctl_mtx, 0, "mmcsd IOCTL", 0);
915322120Smarius	}
916322120Smarius	part->ioctl = 1;
917322120Smarius	MMCSD_IOCTL_UNLOCK(part);
918322120Smarius
919318198Smarius	err = 0;
920318198Smarius	dp = NULL;
921318198Smarius	len = mic->blksz * mic->blocks;
922322120Smarius	if (len > MMC_IOC_MAX_BYTES) {
923322120Smarius		err = EOVERFLOW;
924322120Smarius		goto out;
925322120Smarius	}
926318198Smarius	if (len != 0) {
927318198Smarius		dp = malloc(len, M_TEMP, M_WAITOK);
928318198Smarius		err = copyin((void *)(uintptr_t)mic->data_ptr, dp, len);
929318198Smarius		if (err != 0)
930318198Smarius			goto out;
931318198Smarius	}
932318198Smarius	memset(&cmd, 0, sizeof(cmd));
933318198Smarius	memset(&data, 0, sizeof(data));
934318198Smarius	cmd.opcode = mic->opcode;
935318198Smarius	cmd.arg = mic->arg;
936318198Smarius	cmd.flags = mic->flags;
937318198Smarius	if (len != 0) {
938318198Smarius		data.len = len;
939318198Smarius		data.data = dp;
940318198Smarius		data.flags = mic->write_flag != 0 ? MMC_DATA_WRITE :
941318198Smarius		    MMC_DATA_READ;
942318198Smarius		cmd.data = &data;
943318198Smarius	}
944318198Smarius	sc = part->sc;
945318198Smarius	rca = sc->rca;
946318198Smarius	if (mic->is_acmd == 0) {
947318198Smarius		/* Enforce/patch/restrict RCA-based commands */
948318198Smarius		switch (cmd.opcode) {
949318198Smarius		case MMC_SET_RELATIVE_ADDR:
950318198Smarius		case MMC_SELECT_CARD:
951318198Smarius			err = EPERM;
952318198Smarius			goto out;
953318198Smarius		case MMC_STOP_TRANSMISSION:
954318198Smarius			if ((cmd.arg & 0x1) == 0)
955318198Smarius				break;
956318198Smarius			/* FALLTHROUGH */
957318198Smarius		case MMC_SLEEP_AWAKE:
958318198Smarius		case MMC_SEND_CSD:
959318198Smarius		case MMC_SEND_CID:
960318198Smarius		case MMC_SEND_STATUS:
961318198Smarius		case MMC_GO_INACTIVE_STATE:
962318198Smarius		case MMC_FAST_IO:
963318198Smarius		case MMC_APP_CMD:
964318198Smarius			cmd.arg = (cmd.arg & 0x0000FFFF) | (rca << 16);
965318198Smarius			break;
966318198Smarius		default:
967318198Smarius			break;
968318198Smarius		}
969331037Smarius		/*
970331037Smarius		 * No partition switching in userland; it's almost impossible
971331037Smarius		 * to recover from that, especially if things go wrong.
972331037Smarius		 */
973331037Smarius		if (cmd.opcode == MMC_SWITCH_FUNC && dp != NULL &&
974331037Smarius		    (((uint8_t *)dp)[EXT_CSD_PART_CONFIG] &
975331037Smarius		    EXT_CSD_PART_CONFIG_ACC_MASK) != part->type) {
976331037Smarius			err = EINVAL;
977331037Smarius			goto out;
978331037Smarius		}
979318198Smarius	}
980318198Smarius	dev = sc->dev;
981322120Smarius	mmcbus = sc->mmcbus;
982322120Smarius	MMCBUS_ACQUIRE_BUS(mmcbus, dev);
983322120Smarius	err = mmcsd_switch_part(mmcbus, dev, rca, part->type);
984318198Smarius	if (err != MMC_ERR_NONE)
985318198Smarius		goto release;
986318198Smarius	if (part->type == EXT_CSD_PART_CONFIG_ACC_RPMB) {
987318198Smarius		err = mmcsd_set_blockcount(sc, mic->blocks,
988318198Smarius		    mic->write_flag & (1 << 31));
989318198Smarius		if (err != MMC_ERR_NONE)
990322120Smarius			goto switch_back;
991318198Smarius	}
992338638Smarius	if (mic->write_flag != 0)
993338638Smarius		sc->flags |= MMCSD_DIRTY;
994318198Smarius	if (mic->is_acmd != 0)
995322120Smarius		(void)mmc_wait_for_app_cmd(mmcbus, dev, rca, &cmd, 0);
996318198Smarius	else
997322120Smarius		(void)mmc_wait_for_cmd(mmcbus, dev, &cmd, 0);
998318198Smarius	if (part->type == EXT_CSD_PART_CONFIG_ACC_RPMB) {
999318198Smarius		/*
1000318198Smarius		 * If the request went to the RPMB partition, try to ensure
1001331037Smarius		 * that the command actually has completed.
1002318198Smarius		 */
1003318198Smarius		retries = MMCSD_CMD_RETRIES;
1004318198Smarius		do {
1005322120Smarius			err = mmc_send_status(mmcbus, dev, rca, &status);
1006318198Smarius			if (err != MMC_ERR_NONE)
1007318198Smarius				break;
1008318198Smarius			if (R1_STATUS(status) == 0 &&
1009318198Smarius			    R1_CURRENT_STATE(status) != R1_STATE_PRG)
1010318198Smarius				break;
1011318198Smarius			DELAY(1000);
1012318198Smarius		} while (retries-- > 0);
1013318198Smarius	}
1014318198Smarius	/*
1015318198Smarius	 * If EXT_CSD was changed, our copy is outdated now.  Specifically,
1016318198Smarius	 * the upper bits of EXT_CSD_PART_CONFIG used in mmcsd_switch_part(),
1017318198Smarius	 * so retrieve EXT_CSD again.
1018318198Smarius	 */
1019318198Smarius	if (cmd.opcode == MMC_SWITCH_FUNC) {
1020322120Smarius		err = mmc_send_ext_csd(mmcbus, dev, sc->ext_csd);
1021318198Smarius		if (err != MMC_ERR_NONE)
1022318198Smarius			goto release;
1023318198Smarius	}
1024331037Smariusswitch_back:
1025331037Smarius	if (part->type == EXT_CSD_PART_CONFIG_ACC_RPMB) {
1026331037Smarius		/*
1027331037Smarius		 * If the request went to the RPMB partition, always switch
1028331037Smarius		 * back to the default partition (see mmcsd_switch_part()).
1029331037Smarius		 */
1030331037Smarius		err = mmcsd_switch_part(mmcbus, dev, rca,
1031331037Smarius		    EXT_CSD_PART_CONFIG_ACC_DEFAULT);
1032331037Smarius		if (err != MMC_ERR_NONE)
1033331037Smarius			goto release;
1034331037Smarius	}
1035322120Smarius	MMCBUS_RELEASE_BUS(mmcbus, dev);
1036318198Smarius	if (cmd.error != MMC_ERR_NONE) {
1037318198Smarius		switch (cmd.error) {
1038318198Smarius		case MMC_ERR_TIMEOUT:
1039318198Smarius			err = ETIMEDOUT;
1040318198Smarius			break;
1041318198Smarius		case MMC_ERR_BADCRC:
1042318198Smarius			err = EILSEQ;
1043318198Smarius			break;
1044318198Smarius		case MMC_ERR_INVALID:
1045318198Smarius			err = EINVAL;
1046318198Smarius			break;
1047318198Smarius		case MMC_ERR_NO_MEMORY:
1048318198Smarius			err = ENOMEM;
1049318198Smarius			break;
1050318198Smarius		default:
1051318198Smarius			err = EIO;
1052318198Smarius			break;
1053318198Smarius		}
1054318198Smarius		goto out;
1055318198Smarius	}
1056318198Smarius	memcpy(mic->response, cmd.resp, 4 * sizeof(uint32_t));
1057318198Smarius	if (mic->write_flag == 0 && len != 0) {
1058318198Smarius		err = copyout(dp, (void *)(uintptr_t)mic->data_ptr, len);
1059318198Smarius		if (err != 0)
1060318198Smarius			goto out;
1061318198Smarius	}
1062318198Smarius	goto out;
1063318198Smarius
1064318198Smariusrelease:
1065322120Smarius	MMCBUS_RELEASE_BUS(mmcbus, dev);
1066318198Smarius	err = EIO;
1067318198Smarius
1068318198Smariusout:
1069322120Smarius	MMCSD_IOCTL_LOCK(part);
1070322120Smarius	part->ioctl = 0;
1071322120Smarius	MMCSD_IOCTL_UNLOCK(part);
1072322120Smarius	wakeup(part);
1073318198Smarius	if (dp != NULL)
1074318198Smarius		free(dp, M_TEMP);
1075318198Smarius	return (err);
1076318198Smarius}
1077318198Smarius
1078318198Smariusstatic int
1079318198Smariusmmcsd_getattr(struct bio *bp)
1080318198Smarius{
1081318198Smarius	struct mmcsd_part *part;
1082318198Smarius	device_t dev;
1083318198Smarius
1084318198Smarius	if (strcmp(bp->bio_attribute, "MMC::device") == 0) {
1085318198Smarius		if (bp->bio_length != sizeof(dev))
1086318198Smarius			return (EFAULT);
1087318198Smarius		part = bp->bio_disk->d_drv1;
1088318198Smarius		dev = part->sc->dev;
1089318198Smarius		bcopy(&dev, bp->bio_data, sizeof(dev));
1090318198Smarius		bp->bio_completed = bp->bio_length;
1091318198Smarius		return (0);
1092318198Smarius	}
1093318198Smarius	return (-1);
1094318198Smarius}
1095318198Smarius
1096318198Smariusstatic int
1097318198Smariusmmcsd_set_blockcount(struct mmcsd_softc *sc, u_int count, bool reliable)
1098318198Smarius{
1099318198Smarius	struct mmc_command cmd;
1100318198Smarius	struct mmc_request req;
1101318198Smarius
1102318198Smarius	memset(&req, 0, sizeof(req));
1103318198Smarius	memset(&cmd, 0, sizeof(cmd));
1104318198Smarius	cmd.mrq = &req;
1105318198Smarius	req.cmd = &cmd;
1106318198Smarius	cmd.opcode = MMC_SET_BLOCK_COUNT;
1107318198Smarius	cmd.arg = count & 0x0000FFFF;
1108318198Smarius	if (reliable)
1109318198Smarius		cmd.arg |= 1 << 31;
1110318198Smarius	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
1111322120Smarius	MMCBUS_WAIT_FOR_REQUEST(sc->mmcbus, sc->dev, &req);
1112318198Smarius	return (cmd.error);
1113318198Smarius}
1114318198Smarius
1115318198Smariusstatic int
1116318198Smariusmmcsd_switch_part(device_t bus, device_t dev, uint16_t rca, u_int part)
1117318198Smarius{
1118318198Smarius	struct mmcsd_softc *sc;
1119318198Smarius	int err;
1120318198Smarius	uint8_t	value;
1121318198Smarius
1122318198Smarius	sc = device_get_softc(dev);
1123318198Smarius
1124322120Smarius	if (sc->mode == mode_sd)
1125318198Smarius		return (MMC_ERR_NONE);
1126318198Smarius
1127322120Smarius	/*
1128322120Smarius	 * According to section "6.2.2 Command restrictions" of the eMMC
1129322120Smarius	 * specification v5.1, CMD19/CMD21 aren't allowed to be used with
1130322120Smarius	 * RPMB partitions.  So we pause re-tuning along with triggering
1131322120Smarius	 * it up-front to decrease the likelihood of re-tuning becoming
1132322120Smarius	 * necessary while accessing an RPMB partition.  Consequently, an
1133322120Smarius	 * RPMB partition should immediately be switched away from again
1134322120Smarius	 * after an access in order to allow for re-tuning to take place
1135322120Smarius	 * anew.
1136322120Smarius	 */
1137322120Smarius	if (part == EXT_CSD_PART_CONFIG_ACC_RPMB)
1138322120Smarius		MMCBUS_RETUNE_PAUSE(sc->mmcbus, sc->dev, true);
1139322120Smarius
1140322120Smarius	if (sc->part_curr == part)
1141318198Smarius		return (MMC_ERR_NONE);
1142318198Smarius
1143318198Smarius	value = (sc->ext_csd[EXT_CSD_PART_CONFIG] &
1144318198Smarius	    ~EXT_CSD_PART_CONFIG_ACC_MASK) | part;
1145318198Smarius	/* Jump! */
1146318198Smarius	err = mmc_switch(bus, dev, rca, EXT_CSD_CMD_SET_NORMAL,
1147318198Smarius	    EXT_CSD_PART_CONFIG, value, sc->part_time, true);
1148322120Smarius	if (err != MMC_ERR_NONE) {
1149322120Smarius		if (part == EXT_CSD_PART_CONFIG_ACC_RPMB)
1150322120Smarius			MMCBUS_RETUNE_UNPAUSE(sc->mmcbus, sc->dev);
1151318198Smarius		return (err);
1152322120Smarius	}
1153318198Smarius
1154318198Smarius	sc->ext_csd[EXT_CSD_PART_CONFIG] = value;
1155322120Smarius	if (sc->part_curr == EXT_CSD_PART_CONFIG_ACC_RPMB)
1156322120Smarius		MMCBUS_RETUNE_UNPAUSE(sc->mmcbus, sc->dev);
1157318198Smarius	sc->part_curr = part;
1158318198Smarius	return (MMC_ERR_NONE);
1159318198Smarius}
1160318198Smarius
1161239607Simpstatic const char *
1162239607Simpmmcsd_errmsg(int e)
1163239607Simp{
1164318198Smarius
1165239607Simp	if (e < 0 || e > MMC_ERR_MAX)
1166239607Simp		return "Bad error code";
1167322120Smarius	return (errmsg[e]);
1168239607Simp}
1169239607Simp
1170184033Smavstatic daddr_t
1171318198Smariusmmcsd_rw(struct mmcsd_part *part, struct bio *bp)
1172184033Smav{
1173184033Smav	daddr_t block, end;
1174184033Smav	struct mmc_command cmd;
1175184033Smav	struct mmc_command stop;
1176184033Smav	struct mmc_request req;
1177184033Smav	struct mmc_data data;
1178318198Smarius	struct mmcsd_softc *sc;
1179322120Smarius	device_t dev, mmcbus;
1180322120Smarius	u_int numblocks, sz;
1181318198Smarius	char *vaddr;
1182184033Smav
1183318198Smarius	sc = part->sc;
1184318198Smarius	dev = sc->dev;
1185322120Smarius	mmcbus = sc->mmcbus;
1186318198Smarius
1187184033Smav	block = bp->bio_pblkno;
1188318198Smarius	sz = part->disk->d_sectorsize;
1189184033Smav	end = bp->bio_pblkno + (bp->bio_bcount / sz);
1190184033Smav	while (block < end) {
1191318198Smarius		vaddr = bp->bio_data + (block - bp->bio_pblkno) * sz;
1192322120Smarius		numblocks = min(end - block, sc->max_data);
1193184033Smav		memset(&req, 0, sizeof(req));
1194318198Smarius		memset(&cmd, 0, sizeof(cmd));
1195184033Smav		memset(&stop, 0, sizeof(stop));
1196254432Sian		memset(&data, 0, sizeof(data));
1197248689Sian		cmd.mrq = &req;
1198184033Smav		req.cmd = &cmd;
1199184033Smav		cmd.data = &data;
1200184033Smav		if (bp->bio_cmd == BIO_READ) {
1201184033Smav			if (numblocks > 1)
1202184033Smav				cmd.opcode = MMC_READ_MULTIPLE_BLOCK;
1203184033Smav			else
1204184033Smav				cmd.opcode = MMC_READ_SINGLE_BLOCK;
1205184033Smav		} else {
1206338638Smarius			sc->flags |= MMCSD_DIRTY;
1207184033Smav			if (numblocks > 1)
1208184033Smav				cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK;
1209184033Smav			else
1210184033Smav				cmd.opcode = MMC_WRITE_BLOCK;
1211184033Smav		}
1212184033Smav		cmd.arg = block;
1213322120Smarius		if (sc->high_cap == 0)
1214184033Smav			cmd.arg <<= 9;
1215184033Smav		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
1216184033Smav		data.data = vaddr;
1217184033Smav		data.mrq = &req;
1218184033Smav		if (bp->bio_cmd == BIO_READ)
1219184033Smav			data.flags = MMC_DATA_READ;
1220184033Smav		else
1221184033Smav			data.flags = MMC_DATA_WRITE;
1222184033Smav		data.len = numblocks * sz;
1223184033Smav		if (numblocks > 1) {
1224184033Smav			data.flags |= MMC_DATA_MULTI;
1225184033Smav			stop.opcode = MMC_STOP_TRANSMISSION;
1226184033Smav			stop.arg = 0;
1227184033Smav			stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
1228248689Sian			stop.mrq = &req;
1229184033Smav			req.stop = &stop;
1230184033Smav		}
1231322120Smarius		MMCBUS_WAIT_FOR_REQUEST(mmcbus, dev, &req);
1232239607Simp		if (req.cmd->error != MMC_ERR_NONE) {
1233318198Smarius			if (ppsratecheck(&sc->log_time, &sc->log_count,
1234318198Smarius			    LOG_PPS))
1235278687Sian				device_printf(dev, "Error indicated: %d %s\n",
1236318198Smarius				    req.cmd->error,
1237318198Smarius				    mmcsd_errmsg(req.cmd->error));
1238184033Smav			break;
1239239607Simp		}
1240184033Smav		block += numblocks;
1241184033Smav	}
1242184033Smav	return (block);
1243184033Smav}
1244184033Smav
1245184033Smavstatic daddr_t
1246318198Smariusmmcsd_delete(struct mmcsd_part *part, struct bio *bp)
1247184033Smav{
1248184033Smav	daddr_t block, end, start, stop;
1249184033Smav	struct mmc_command cmd;
1250184033Smav	struct mmc_request req;
1251318198Smarius	struct mmcsd_softc *sc;
1252322120Smarius	device_t dev, mmcbus;
1253322120Smarius	u_int erase_sector, sz;
1254322389Smarius	int err;
1255322389Smarius	bool use_trim;
1256184033Smav
1257318198Smarius	sc = part->sc;
1258318198Smarius	dev = sc->dev;
1259322120Smarius	mmcbus = sc->mmcbus;
1260318198Smarius
1261184033Smav	block = bp->bio_pblkno;
1262318198Smarius	sz = part->disk->d_sectorsize;
1263184033Smav	end = bp->bio_pblkno + (bp->bio_bcount / sz);
1264322389Smarius	use_trim = sc->flags & MMCSD_USE_TRIM;
1265322389Smarius	if (use_trim == true) {
1266322389Smarius		start = block;
1267322389Smarius		stop = end;
1268322389Smarius	} else {
1269322389Smarius		/* Coalesce with the remainder of the previous request. */
1270322389Smarius		if (block > part->eblock && block <= part->eend)
1271322389Smarius			block = part->eblock;
1272322389Smarius		if (end >= part->eblock && end < part->eend)
1273322389Smarius			end = part->eend;
1274322389Smarius		/* Safely round to the erase sector boundaries. */
1275322389Smarius		erase_sector = sc->erase_sector;
1276322389Smarius		start = block + erase_sector - 1;	 /* Round up. */
1277322389Smarius		start -= start % erase_sector;
1278322389Smarius		stop = end;				/* Round down. */
1279322389Smarius		stop -= end % erase_sector;
1280322389Smarius		/*
1281322389Smarius		 * We can't erase an area smaller than an erase sector, so
1282322389Smarius		 * store it for later.
1283322389Smarius		 */
1284322389Smarius		if (start >= stop) {
1285322389Smarius			part->eblock = block;
1286322389Smarius			part->eend = end;
1287322389Smarius			return (end);
1288322389Smarius		}
1289184034Smav	}
1290184033Smav
1291322389Smarius	if ((sc->flags & MMCSD_INAND_CMD38) != 0) {
1292322389Smarius		err = mmc_switch(mmcbus, dev, sc->rca, EXT_CSD_CMD_SET_NORMAL,
1293322389Smarius		    EXT_CSD_INAND_CMD38, use_trim == true ?
1294322389Smarius		    EXT_CSD_INAND_CMD38_TRIM : EXT_CSD_INAND_CMD38_ERASE,
1295322389Smarius		    sc->cmd6_time, true);
1296322389Smarius		if (err != MMC_ERR_NONE) {
1297322389Smarius			device_printf(dev,
1298322389Smarius			    "Setting iNAND erase command failed %s\n",
1299322389Smarius			    mmcsd_errmsg(err));
1300322389Smarius			return (block);
1301322389Smarius		}
1302322389Smarius	}
1303322389Smarius
1304322120Smarius	/*
1305322120Smarius	 * Pause re-tuning so it won't interfere with the order of erase
1306322120Smarius	 * commands.  Note that these latter don't use the data lines, so
1307322120Smarius	 * re-tuning shouldn't actually become necessary during erase.
1308322120Smarius	 */
1309322120Smarius	MMCBUS_RETUNE_PAUSE(mmcbus, dev, false);
1310184033Smav	/* Set erase start position. */
1311184033Smav	memset(&req, 0, sizeof(req));
1312184033Smav	memset(&cmd, 0, sizeof(cmd));
1313248689Sian	cmd.mrq = &req;
1314184033Smav	req.cmd = &cmd;
1315338638Smarius	if (sc->mode == mode_sd)
1316184033Smav		cmd.opcode = SD_ERASE_WR_BLK_START;
1317184033Smav	else
1318184033Smav		cmd.opcode = MMC_ERASE_GROUP_START;
1319184033Smav	cmd.arg = start;
1320322120Smarius	if (sc->high_cap == 0)
1321184033Smav		cmd.arg <<= 9;
1322184033Smav	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
1323322120Smarius	MMCBUS_WAIT_FOR_REQUEST(mmcbus, dev, &req);
1324184033Smav	if (req.cmd->error != MMC_ERR_NONE) {
1325322389Smarius		device_printf(dev, "Setting erase start position failed %s\n",
1326322389Smarius		    mmcsd_errmsg(req.cmd->error));
1327322120Smarius		block = bp->bio_pblkno;
1328322120Smarius		goto unpause;
1329184033Smav	}
1330184033Smav	/* Set erase stop position. */
1331184033Smav	memset(&req, 0, sizeof(req));
1332184033Smav	memset(&cmd, 0, sizeof(cmd));
1333184033Smav	req.cmd = &cmd;
1334338638Smarius	if (sc->mode == mode_sd)
1335184033Smav		cmd.opcode = SD_ERASE_WR_BLK_END;
1336184033Smav	else
1337184033Smav		cmd.opcode = MMC_ERASE_GROUP_END;
1338184033Smav	cmd.arg = stop;
1339322120Smarius	if (sc->high_cap == 0)
1340184033Smav		cmd.arg <<= 9;
1341184033Smav	cmd.arg--;
1342184033Smav	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
1343322120Smarius	MMCBUS_WAIT_FOR_REQUEST(mmcbus, dev, &req);
1344184033Smav	if (req.cmd->error != MMC_ERR_NONE) {
1345322389Smarius		device_printf(dev, "Setting erase stop position failed %s\n",
1346322389Smarius		    mmcsd_errmsg(req.cmd->error));
1347322120Smarius		block = bp->bio_pblkno;
1348322120Smarius		goto unpause;
1349184033Smav	}
1350184033Smav	/* Erase range. */
1351184033Smav	memset(&req, 0, sizeof(req));
1352184033Smav	memset(&cmd, 0, sizeof(cmd));
1353184033Smav	req.cmd = &cmd;
1354184033Smav	cmd.opcode = MMC_ERASE;
1355322389Smarius	cmd.arg = use_trim == true ? MMC_ERASE_TRIM : MMC_ERASE_ERASE;
1356184033Smav	cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
1357322120Smarius	MMCBUS_WAIT_FOR_REQUEST(mmcbus, dev, &req);
1358184033Smav	if (req.cmd->error != MMC_ERR_NONE) {
1359322389Smarius		device_printf(dev, "Issuing erase command failed %s\n",
1360322389Smarius		    mmcsd_errmsg(req.cmd->error));
1361322120Smarius		block = bp->bio_pblkno;
1362322120Smarius		goto unpause;
1363184033Smav	}
1364322389Smarius	if (use_trim == false) {
1365322389Smarius		/* Store one of the remaining parts for the next call. */
1366322389Smarius		if (bp->bio_pblkno >= part->eblock || block == start) {
1367322389Smarius			part->eblock = stop;	/* Predict next forward. */
1368322389Smarius			part->eend = end;
1369322389Smarius		} else {
1370322389Smarius			part->eblock = block;	/* Predict next backward. */
1371322389Smarius			part->eend = start;
1372322389Smarius		}
1373184034Smav	}
1374322120Smarius	block = end;
1375322120Smariusunpause:
1376322120Smarius	MMCBUS_RETUNE_UNPAUSE(mmcbus, dev);
1377322120Smarius	return (block);
1378184033Smav}
1379184033Smav
1380188725Smavstatic int
1381318198Smariusmmcsd_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset,
1382318198Smarius    size_t length)
1383188725Smav{
1384188725Smav	struct bio bp;
1385188725Smav	daddr_t block, end;
1386318198Smarius	struct disk *disk;
1387318198Smarius	struct mmcsd_softc *sc;
1388318198Smarius	struct mmcsd_part *part;
1389322120Smarius	device_t dev, mmcbus;
1390318198Smarius	int err;
1391188725Smav
1392338638Smarius	disk = arg;
1393338638Smarius	part = disk->d_drv1;
1394338638Smarius	sc = part->sc;
1395338638Smarius
1396188725Smav	/* length zero is special and really means flush buffers to media */
1397338638Smarius	if (length == 0) {
1398338638Smarius		err = mmcsd_flush_cache(sc);
1399338638Smarius		if (err != MMC_ERR_NONE)
1400338638Smarius			return (EIO);
1401188725Smav		return (0);
1402338638Smarius	}
1403188725Smav
1404318198Smarius	dev = sc->dev;
1405322120Smarius	mmcbus = sc->mmcbus;
1406318198Smarius
1407188725Smav	bzero(&bp, sizeof(struct bio));
1408188725Smav	bp.bio_disk = disk;
1409188725Smav	bp.bio_pblkno = offset / disk->d_sectorsize;
1410188725Smav	bp.bio_bcount = length;
1411188725Smav	bp.bio_data = virtual;
1412188725Smav	bp.bio_cmd = BIO_WRITE;
1413318198Smarius	end = bp.bio_pblkno + bp.bio_bcount / disk->d_sectorsize;
1414322120Smarius	MMCBUS_ACQUIRE_BUS(mmcbus, dev);
1415322120Smarius	err = mmcsd_switch_part(mmcbus, dev, sc->rca, part->type);
1416318198Smarius	if (err != MMC_ERR_NONE) {
1417318198Smarius		if (ppsratecheck(&sc->log_time, &sc->log_count, LOG_PPS))
1418318198Smarius			device_printf(dev, "Partition switch error\n");
1419322120Smarius		MMCBUS_RELEASE_BUS(mmcbus, dev);
1420318198Smarius		return (EIO);
1421318198Smarius	}
1422318198Smarius	block = mmcsd_rw(part, &bp);
1423322120Smarius	MMCBUS_RELEASE_BUS(mmcbus, dev);
1424188725Smav	return ((end < block) ? EIO : 0);
1425188725Smav}
1426188725Smav
1427163516Simpstatic void
1428163516Simpmmcsd_task(void *arg)
1429163516Simp{
1430318198Smarius	daddr_t block, end;
1431318198Smarius	struct mmcsd_part *part;
1432318198Smarius	struct mmcsd_softc *sc;
1433163516Simp	struct bio *bp;
1434322120Smarius	device_t dev, mmcbus;
1435318198Smarius	int err, sz;
1436163516Simp
1437318198Smarius	part = arg;
1438318198Smarius	sc = part->sc;
1439318198Smarius	dev = sc->dev;
1440322120Smarius	mmcbus = sc->mmcbus;
1441318198Smarius
1442185201Smav	while (1) {
1443322120Smarius		MMCSD_DISK_LOCK(part);
1444163516Simp		do {
1445318198Smarius			if (part->running == 0)
1446185201Smav				goto out;
1447318198Smarius			bp = bioq_takefirst(&part->bio_queue);
1448163516Simp			if (bp == NULL)
1449322120Smarius				msleep(part, &part->disk_mtx, PRIBIO,
1450322120Smarius				    "mmcsd disk jobqueue", 0);
1451185201Smav		} while (bp == NULL);
1452322120Smarius		MMCSD_DISK_UNLOCK(part);
1453338638Smarius		if (__predict_false(bp->bio_cmd == BIO_FLUSH)) {
1454338638Smarius			if (mmcsd_flush_cache(sc) != MMC_ERR_NONE) {
1455338638Smarius				bp->bio_error = EIO;
1456338638Smarius				bp->bio_flags |= BIO_ERROR;
1457338638Smarius			}
1458338638Smarius			biodone(bp);
1459338638Smarius			continue;
1460338638Smarius		}
1461318198Smarius		if (bp->bio_cmd != BIO_READ && part->ro) {
1462183448Simp			bp->bio_error = EROFS;
1463183448Simp			bp->bio_resid = bp->bio_bcount;
1464183448Simp			bp->bio_flags |= BIO_ERROR;
1465183448Simp			biodone(bp);
1466183448Simp			continue;
1467183448Simp		}
1468322120Smarius		MMCBUS_ACQUIRE_BUS(mmcbus, dev);
1469318198Smarius		sz = part->disk->d_sectorsize;
1470184033Smav		block = bp->bio_pblkno;
1471163516Simp		end = bp->bio_pblkno + (bp->bio_bcount / sz);
1472322120Smarius		err = mmcsd_switch_part(mmcbus, dev, sc->rca, part->type);
1473318198Smarius		if (err != MMC_ERR_NONE) {
1474318198Smarius			if (ppsratecheck(&sc->log_time, &sc->log_count,
1475318198Smarius			    LOG_PPS))
1476318198Smarius				device_printf(dev, "Partition switch error\n");
1477318198Smarius			goto release;
1478318198Smarius		}
1479184033Smav		if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) {
1480184034Smav			/* Access to the remaining erase block obsoletes it. */
1481318198Smarius			if (block < part->eend && end > part->eblock)
1482318198Smarius				part->eblock = part->eend = 0;
1483318198Smarius			block = mmcsd_rw(part, bp);
1484184033Smav		} else if (bp->bio_cmd == BIO_DELETE) {
1485318198Smarius			block = mmcsd_delete(part, bp);
1486163516Simp		}
1487318198Smariusrelease:
1488322120Smarius		MMCBUS_RELEASE_BUS(mmcbus, dev);
1489183480Simp		if (block < end) {
1490183480Simp			bp->bio_error = EIO;
1491183480Simp			bp->bio_resid = (end - block) * sz;
1492183480Simp			bp->bio_flags |= BIO_ERROR;
1493312400Smarius		} else {
1494312400Smarius			bp->bio_resid = 0;
1495183480Simp		}
1496163516Simp		biodone(bp);
1497163516Simp	}
1498185201Smavout:
1499169567Simp	/* tell parent we're done */
1500318198Smarius	part->running = -1;
1501322120Smarius	MMCSD_DISK_UNLOCK(part);
1502318198Smarius	wakeup(part);
1503169567Simp
1504172836Sjulian	kproc_exit(0);
1505163516Simp}
1506163516Simp
1507183774Simpstatic int
1508183774Simpmmcsd_bus_bit_width(device_t dev)
1509183774Simp{
1510236491Smarius
1511183774Simp	if (mmc_get_bus_width(dev) == bus_width_1)
1512183774Simp		return (1);
1513183774Simp	if (mmc_get_bus_width(dev) == bus_width_4)
1514183774Simp		return (4);
1515183774Simp	return (8);
1516183774Simp}
1517183774Simp
1518338638Smariusstatic int
1519338638Smariusmmcsd_flush_cache(struct mmcsd_softc *sc)
1520338638Smarius{
1521338638Smarius	device_t dev, mmcbus;
1522338638Smarius	int err;
1523338638Smarius
1524338638Smarius	if ((sc->flags & MMCSD_FLUSH_CACHE) == 0)
1525338638Smarius		return (MMC_ERR_NONE);
1526338638Smarius
1527338638Smarius	dev = sc->dev;
1528338638Smarius	mmcbus = sc->mmcbus;
1529338638Smarius	MMCBUS_ACQUIRE_BUS(mmcbus, dev);
1530338638Smarius	if ((sc->flags & MMCSD_DIRTY) == 0) {
1531338638Smarius		MMCBUS_RELEASE_BUS(mmcbus, dev);
1532338638Smarius		return (MMC_ERR_NONE);
1533338638Smarius	}
1534338638Smarius	err = mmc_switch(mmcbus, dev, sc->rca, EXT_CSD_CMD_SET_NORMAL,
1535338638Smarius	    EXT_CSD_FLUSH_CACHE, EXT_CSD_FLUSH_CACHE_FLUSH, 60 * 1000, true);
1536338638Smarius	if (err == MMC_ERR_NONE)
1537338638Smarius		sc->flags &= ~MMCSD_DIRTY;
1538338638Smarius	MMCBUS_RELEASE_BUS(mmcbus, dev);
1539338638Smarius	return (err);
1540338638Smarius}
1541338638Smarius
1542163516Simpstatic device_method_t mmcsd_methods[] = {
1543163516Simp	DEVMETHOD(device_probe, mmcsd_probe),
1544163516Simp	DEVMETHOD(device_attach, mmcsd_attach),
1545163516Simp	DEVMETHOD(device_detach, mmcsd_detach),
1546338638Smarius	DEVMETHOD(device_shutdown, mmcsd_shutdown),
1547185721Smav	DEVMETHOD(device_suspend, mmcsd_suspend),
1548185721Smav	DEVMETHOD(device_resume, mmcsd_resume),
1549234524Smarius	DEVMETHOD_END
1550163516Simp};
1551163516Simp
1552163516Simpstatic driver_t mmcsd_driver = {
1553163516Simp	"mmcsd",
1554163516Simp	mmcsd_methods,
1555163516Simp	sizeof(struct mmcsd_softc),
1556163516Simp};
1557163516Simpstatic devclass_t mmcsd_devclass;
1558163516Simp
1559318198Smariusstatic int
1560318198Smariusmmcsd_handler(module_t mod __unused, int what, void *arg __unused)
1561318198Smarius{
1562318198Smarius
1563318198Smarius	switch (what) {
1564318198Smarius	case MOD_LOAD:
1565318198Smarius		flash_register_slicer(mmcsd_slicer, FLASH_SLICES_TYPE_MMC,
1566318198Smarius		    TRUE);
1567318198Smarius		return (0);
1568318198Smarius	case MOD_UNLOAD:
1569318198Smarius		flash_register_slicer(NULL, FLASH_SLICES_TYPE_MMC, TRUE);
1570318198Smarius		return (0);
1571318198Smarius	}
1572318198Smarius	return (0);
1573318198Smarius}
1574318198Smarius
1575318198SmariusDRIVER_MODULE(mmcsd, mmc, mmcsd_driver, mmcsd_devclass, mmcsd_handler, NULL);
1576318198SmariusMODULE_DEPEND(mmcsd, g_flashmap, 0, 0, 0);
1577318198SmariusMMC_DEPEND(mmcsd);
1578