Module Name:    src
Committed By:   martin
Date:           Fri Sep  1 09:59:11 UTC 2017

Modified Files:
        src/sys/dev [netbsd-8]: dksubr.c ld.c ldvar.h
        src/sys/dev/i2o [netbsd-8]: ld_iop.c
        src/sys/dev/ic [netbsd-8]: ld_cac.c ld_nvme.c
        src/sys/dev/pci [netbsd-8]: ld_virtio.c
        src/sys/dev/sdmmc [netbsd-8]: ld_sdmmc.c sdmmc_mem.c sdmmcvar.h

Log Message:
Pull up following revision(s) (requested by mlelstv in ticket #261):
        sys/dev/sdmmc/ld_sdmmc.c: revision 1.32
        sys/dev/sdmmc/ld_sdmmc.c: revision 1.33
        sys/dev/sdmmc/ld_sdmmc.c: revision 1.34
        sys/dev/sdmmc/sdmmc_mem.c: revision 1.62
        sys/dev/i2o/ld_iop.c: revision 1.39
        sys/dev/ld.c: revision 1.102
        sys/dev/ld.c: revision 1.103
        sys/dev/dksubr.c: revision 1.98
        sys/dev/dksubr.c: revision 1.99
        sys/dev/sdmmc/sdmmcvar.h: revision 1.29
        sys/dev/ic/ld_nvme.c: revision 1.17
        sys/dev/ldvar.h: revision 1.31
        sys/dev/ldvar.h: revision 1.32
        sys/dev/ic/ld_cac.c: revision 1.31
        sys/dev/pci/ld_virtio.c: revision 1.16
While ld(4) is MP safe, many backends are not.
Add a flag for backends that are MP safe. Take KERNEL_LOCK when calling
into a backend that doesn't have the flag set. Do the same for the
discard routine.
Fixes PR 52462.
Defer sdmmc discard operations to the sdmmc task queue. Fixes a panic
introduced by ld.c r1.102.
validate length for discard operation and split operation when byte length
doesn't fit into 'int'.
make the sc_discard interface for the ld backend asynchronous and
signal completion through new callback lddiscardend. Use a standard
struct buf to pass disk address and range instead of two off_t values.
make lddiscard synchronous again. This is a requirement of the current
ffs discard code.
Initialize error also in the case where len=0, which just succeeds.
while here, assert that the len is indeed non-negative. this is already
confirmed by sys_fdiscard, but let's be sure.
reported by: GCC, but with different compile flags


To generate a diff of this commit:
cvs rdiff -u -r1.97 -r1.97.2.1 src/sys/dev/dksubr.c
cvs rdiff -u -r1.101 -r1.101.2.1 src/sys/dev/ld.c
cvs rdiff -u -r1.30 -r1.30.2.1 src/sys/dev/ldvar.h
cvs rdiff -u -r1.37 -r1.37.6.1 src/sys/dev/i2o/ld_iop.c
cvs rdiff -u -r1.30 -r1.30.8.1 src/sys/dev/ic/ld_cac.c
cvs rdiff -u -r1.16 -r1.16.2.1 src/sys/dev/ic/ld_nvme.c
cvs rdiff -u -r1.15 -r1.15.6.1 src/sys/dev/pci/ld_virtio.c
cvs rdiff -u -r1.26.4.4 -r1.26.4.5 src/sys/dev/sdmmc/ld_sdmmc.c
cvs rdiff -u -r1.56.4.3 -r1.56.4.4 src/sys/dev/sdmmc/sdmmc_mem.c
cvs rdiff -u -r1.23.6.3 -r1.23.6.4 src/sys/dev/sdmmc/sdmmcvar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/dksubr.c
diff -u src/sys/dev/dksubr.c:1.97 src/sys/dev/dksubr.c:1.97.2.1
--- src/sys/dev/dksubr.c:1.97	Thu Apr 27 17:07:22 2017
+++ src/sys/dev/dksubr.c	Fri Sep  1 09:59:10 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: dksubr.c,v 1.97 2017/04/27 17:07:22 jdolecek Exp $ */
+/* $NetBSD: dksubr.c,v 1.97.2.1 2017/09/01 09:59:10 martin Exp $ */
 
 /*-
  * Copyright (c) 1996, 1997, 1998, 1999, 2002, 2008 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dksubr.c,v 1.97 2017/04/27 17:07:22 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dksubr.c,v 1.97.2.1 2017/09/01 09:59:10 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -497,7 +497,10 @@ dk_discard(struct dk_softc *dksc, dev_t 
 	const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver;
 	unsigned secsize = dksc->sc_dkdev.dk_geom.dg_secsize;
 	struct buf tmp, *bp = &tmp;
-	int error;
+	int maxsz;
+	int error = 0;
+
+	KASSERT(len >= 0);
 
 	DPRINTF_FOLLOW(("%s(%s, %p, 0x"PRIx64", %jd, %jd)\n", __func__,
 	    dksc->sc_xname, dksc, (intmax_t)pos, (intmax_t)len));
@@ -507,22 +510,32 @@ dk_discard(struct dk_softc *dksc, dev_t 
 		return ENXIO;
 	}
 
-	if (secsize == 0 || (pos % secsize) != 0)
+	if (secsize == 0 || (pos % secsize) != 0 || (len % secsize) != 0)
 		return EINVAL;
 
-	/* enough data to please the bounds checking code */
-	bp->b_dev = dev;
-	bp->b_blkno = (daddr_t)(pos / secsize);
-	bp->b_bcount = len;
-	bp->b_flags = B_WRITE;
+	/* largest value that b_bcount can store */
+	maxsz = rounddown(INT_MAX, secsize);
 
-	error = dk_translate(dksc, bp);
-	if (error >= 0)
-		return error;
+	while (len > 0) {
+		/* enough data to please the bounds checking code */
+		bp->b_dev = dev;
+		bp->b_blkno = (daddr_t)(pos / secsize);
+		bp->b_bcount = min(len, maxsz);
+		bp->b_flags = B_WRITE;
+
+		error = dk_translate(dksc, bp);
+		if (error >= 0)
+			break;
+
+		error = dkd->d_discard(dksc->sc_dev,
+			(off_t)bp->b_rawblkno * secsize,
+			(off_t)bp->b_bcount);
+		if (error)
+			break;
 
-	error = dkd->d_discard(dksc->sc_dev,
-		(off_t)bp->b_rawblkno * secsize,
-		(off_t)bp->b_bcount);
+		pos += bp->b_bcount;
+		len -= bp->b_bcount;
+	}
 
 	return error;
 }

Index: src/sys/dev/ld.c
diff -u src/sys/dev/ld.c:1.101 src/sys/dev/ld.c:1.101.2.1
--- src/sys/dev/ld.c:1.101	Thu Apr 27 17:07:22 2017
+++ src/sys/dev/ld.c	Fri Sep  1 09:59:10 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ld.c,v 1.101 2017/04/27 17:07:22 jdolecek Exp $	*/
+/*	$NetBSD: ld.c,v 1.101.2.1 2017/09/01 09:59:10 martin Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.101 2017/04/27 17:07:22 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.101.2.1 2017/09/01 09:59:10 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -419,6 +419,9 @@ ld_diskstart(device_t dev, struct buf *b
 	if (sc->sc_queuecnt >= sc->sc_maxqueuecnt)
 		return EAGAIN;
 
+	if ((sc->sc_flags & LDF_MPSAFE) == 0)
+		KERNEL_LOCK(1, curlwp);
+
 	mutex_enter(&sc->sc_mutex);
 
 	if (sc->sc_queuecnt >= sc->sc_maxqueuecnt)
@@ -431,6 +434,9 @@ ld_diskstart(device_t dev, struct buf *b
 
 	mutex_exit(&sc->sc_mutex);
 
+	if ((sc->sc_flags & LDF_MPSAFE) == 0)
+		KERNEL_UNLOCK_ONE(curlwp);
+
 	return error;
 }
 
@@ -589,11 +595,45 @@ static int
 ld_discard(device_t dev, off_t pos, off_t len)
 {
 	struct ld_softc *sc = device_private(dev);
+	struct buf dbuf, *bp = &dbuf;
+	int error = 0;
+
+	KASSERT(len <= INT_MAX);
 
 	if (sc->sc_discard == NULL)
 		return (ENODEV);
 
-	return (*sc->sc_discard)(sc, pos, len);
+	if ((sc->sc_flags & LDF_MPSAFE) == 0)
+		KERNEL_LOCK(1, curlwp);
+
+	buf_init(bp);
+	bp->b_vp = NULL;
+	bp->b_data = NULL;
+	bp->b_bufsize = 0;
+	bp->b_rawblkno = pos / sc->sc_secsize;
+	bp->b_bcount = len;
+	bp->b_flags = B_WRITE;
+	bp->b_cflags = BC_BUSY;
+
+	error = (*sc->sc_discard)(sc, bp);
+	if (error == 0)
+		error = biowait(bp);
+
+	buf_destroy(bp);
+
+	if ((sc->sc_flags & LDF_MPSAFE) == 0)
+		KERNEL_UNLOCK_ONE(curlwp);
+
+	return error;
+}
+
+void
+lddiscardend(struct ld_softc *sc, struct buf *bp)
+{
+
+	if (bp->b_error)
+		bp->b_resid = bp->b_bcount;
+	biodone(bp);
 }
 
 static int

Index: src/sys/dev/ldvar.h
diff -u src/sys/dev/ldvar.h:1.30 src/sys/dev/ldvar.h:1.30.2.1
--- src/sys/dev/ldvar.h:1.30	Thu Apr 27 17:07:22 2017
+++ src/sys/dev/ldvar.h	Fri Sep  1 09:59:10 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ldvar.h,v 1.30 2017/04/27 17:07:22 jdolecek Exp $	*/
+/*	$NetBSD: ldvar.h,v 1.30.2.1 2017/09/01 09:59:10 martin Exp $	*/
 
 /*-
  * Copyright (c) 2000 The NetBSD Foundation, Inc.
@@ -61,18 +61,20 @@ struct ld_softc {
 	int		(*sc_dump)(struct ld_softc *, void *, int, int);
 	int		(*sc_ioctl)(struct ld_softc *, u_long, void *, int32_t, bool);
 	int		(*sc_start)(struct ld_softc *, struct buf *);
-	int		(*sc_discard)(struct ld_softc *, off_t, off_t);
+	int		(*sc_discard)(struct ld_softc *, struct buf *);
 };
 
 /* sc_flags */
 #define	LDF_ENABLED	0x001		/* device enabled */
 #define	LDF_DRAIN	0x020		/* maxqueuecnt has changed; drain */
 #define	LDF_NO_RND	0x040		/* do not attach rnd source */
+#define	LDF_MPSAFE	0x080		/* backend is MPSAFE */
 
 int	ldadjqparam(struct ld_softc *, int);
 void	ldattach(struct ld_softc *, const char *);
 int	ldbegindetach(struct ld_softc *, int);
 void	ldenddetach(struct ld_softc *);
 void	lddone(struct ld_softc *, struct buf *);
+void	lddiscardend(struct ld_softc *, struct buf *);
 
 #endif	/* !_DEV_LDVAR_H_ */

Index: src/sys/dev/i2o/ld_iop.c
diff -u src/sys/dev/i2o/ld_iop.c:1.37 src/sys/dev/i2o/ld_iop.c:1.37.6.1
--- src/sys/dev/i2o/ld_iop.c:1.37	Mon Feb 27 21:32:33 2017
+++ src/sys/dev/i2o/ld_iop.c	Fri Sep  1 09:59:10 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ld_iop.c,v 1.37 2017/02/27 21:32:33 jdolecek Exp $	*/
+/*	$NetBSD: ld_iop.c,v 1.37.6.1 2017/09/01 09:59:10 martin Exp $	*/
 
 /*-
  * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld_iop.c,v 1.37 2017/02/27 21:32:33 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld_iop.c,v 1.37.6.1 2017/09/01 09:59:10 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -171,6 +171,7 @@ ld_iop_attach(device_t parent, device_t 
 	ld->sc_dump = ld_iop_dump;
 	ld->sc_ioctl = ld_iop_ioctl;
 	ld->sc_start = ld_iop_start;
+	ld->sc_flags = LDF_MPSAFE;
 
 	/* Say what the device is. */
 	printf(":");
@@ -221,7 +222,7 @@ ld_iop_attach(device_t parent, device_t 
 
 	if ((le32toh(param.p.bdi.capabilities) & I2O_RBS_CAP_REMOVABLE_MEDIA)
 	    != 0) {
-		/* ld->sc_flags = LDF_REMOVABLE; */
+		/* ld->sc_flags |= LDF_REMOVABLE; */
 		fixedstr = "removable";
 		enable = 0;
 	} else

Index: src/sys/dev/ic/ld_cac.c
diff -u src/sys/dev/ic/ld_cac.c:1.30 src/sys/dev/ic/ld_cac.c:1.30.8.1
--- src/sys/dev/ic/ld_cac.c:1.30	Tue Sep 27 03:33:32 2016
+++ src/sys/dev/ic/ld_cac.c	Fri Sep  1 09:59:11 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ld_cac.c,v 1.30 2016/09/27 03:33:32 pgoyette Exp $	*/
+/*	$NetBSD: ld_cac.c,v 1.30.8.1 2017/09/01 09:59:11 martin Exp $	*/
 
 /*-
  * Copyright (c) 2000, 2006 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld_cac.c,v 1.30 2016/09/27 03:33:32 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld_cac.c,v 1.30.8.1 2017/09/01 09:59:11 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -131,7 +131,7 @@ ld_cac_attach(device_t parent, device_t 
 	aprint_normal(": %s array\n", type);
 
 	/* XXX We should verify this... */
-	ld->sc_flags = LDF_ENABLED;
+	ld->sc_flags = LDF_ENABLED | LDF_MPSAFE;
 	ldattach(ld, BUFQ_DISK_DEFAULT_STRAT);
 }
 

Index: src/sys/dev/ic/ld_nvme.c
diff -u src/sys/dev/ic/ld_nvme.c:1.16 src/sys/dev/ic/ld_nvme.c:1.16.2.1
--- src/sys/dev/ic/ld_nvme.c:1.16	Thu Apr 27 17:07:22 2017
+++ src/sys/dev/ic/ld_nvme.c	Fri Sep  1 09:59:11 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ld_nvme.c,v 1.16 2017/04/27 17:07:22 jdolecek Exp $	*/
+/*	$NetBSD: ld_nvme.c,v 1.16.2.1 2017/09/01 09:59:11 martin Exp $	*/
 
 /*-
  * Copyright (C) 2016 NONAKA Kimihiro <non...@netbsd.org>
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld_nvme.c,v 1.16 2017/04/27 17:07:22 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld_nvme.c,v 1.16.2.1 2017/09/01 09:59:11 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -128,7 +128,7 @@ ld_nvme_attach(device_t parent, device_t
 	ld->sc_start = ld_nvme_start;
 	ld->sc_dump = ld_nvme_dump;
 	ld->sc_ioctl = ld_nvme_ioctl;
-	ld->sc_flags = LDF_ENABLED | LDF_NO_RND;
+	ld->sc_flags = LDF_ENABLED | LDF_NO_RND | LDF_MPSAFE;
 	ldattach(ld, "fcfs");
 }
 

Index: src/sys/dev/pci/ld_virtio.c
diff -u src/sys/dev/pci/ld_virtio.c:1.15 src/sys/dev/pci/ld_virtio.c:1.15.6.1
--- src/sys/dev/pci/ld_virtio.c:1.15	Sat Mar 25 18:02:06 2017
+++ src/sys/dev/pci/ld_virtio.c	Fri Sep  1 09:59:11 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ld_virtio.c,v 1.15 2017/03/25 18:02:06 jdolecek Exp $	*/
+/*	$NetBSD: ld_virtio.c,v 1.15.6.1 2017/09/01 09:59:11 martin Exp $	*/
 
 /*
  * Copyright (c) 2010 Minoura Makoto.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld_virtio.c,v 1.15 2017/03/25 18:02:06 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld_virtio.c,v 1.15.6.1 2017/09/01 09:59:11 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -345,7 +345,7 @@ ld_virtio_attach(device_t parent, device
 	ld->sc_dump = ld_virtio_dump;
 	ld->sc_start = ld_virtio_start;
 
-	ld->sc_flags = LDF_ENABLED;
+	ld->sc_flags = LDF_ENABLED | LDF_MPSAFE;
 	ldattach(ld, BUFQ_DISK_DEFAULT_STRAT);
 
 	return;

Index: src/sys/dev/sdmmc/ld_sdmmc.c
diff -u src/sys/dev/sdmmc/ld_sdmmc.c:1.26.4.4 src/sys/dev/sdmmc/ld_sdmmc.c:1.26.4.5
--- src/sys/dev/sdmmc/ld_sdmmc.c:1.26.4.4	Tue Jul 25 01:49:13 2017
+++ src/sys/dev/sdmmc/ld_sdmmc.c	Fri Sep  1 09:59:10 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ld_sdmmc.c,v 1.26.4.4 2017/07/25 01:49:13 snj Exp $	*/
+/*	$NetBSD: ld_sdmmc.c,v 1.26.4.5 2017/09/01 09:59:10 martin Exp $	*/
 
 /*
  * Copyright (c) 2008 KIYOHARA Takashi
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.26.4.4 2017/07/25 01:49:13 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.26.4.5 2017/09/01 09:59:10 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -65,12 +65,16 @@ __KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v
 #define	LD_SDMMC_IORETRIES	5	/* number of retries before giving up */
 #define	RECOVERYTIME		hz/2	/* time to wait before retrying a cmd */
 
+#define	LD_SDMMC_MAXQUEUECNT	4	/* number of queued bio requests */
+#define	LD_SDMMC_MAXTASKCNT	8	/* number of tasks in task pool */
+
 struct ld_sdmmc_softc;
 
 struct ld_sdmmc_task {
 	struct sdmmc_task task;
 
 	struct ld_sdmmc_softc *task_sc;
+
 	struct buf *task_bp;
 	int task_retries; /* number of xfer retry */
 	struct callout task_restart_ch;
@@ -81,9 +85,12 @@ struct ld_sdmmc_softc {
 	int sc_hwunit;
 
 	struct sdmmc_function *sc_sf;
-#define LD_SDMMC_MAXQUEUECNT 4
-	struct ld_sdmmc_task sc_task[LD_SDMMC_MAXQUEUECNT];
+	struct ld_sdmmc_task sc_task[LD_SDMMC_MAXTASKCNT];
 	pcq_t *sc_freeq;
+
+	struct evcnt sc_ev_discard;	/* discard counter */
+	struct evcnt sc_ev_discarderr;	/* discard error counter */
+	struct evcnt sc_ev_discardbusy;	/* discard busy counter */
 };
 
 static int ld_sdmmc_match(device_t, cfdata_t, void *);
@@ -93,11 +100,12 @@ static int ld_sdmmc_detach(device_t, int
 static int ld_sdmmc_dump(struct ld_softc *, void *, int, int);
 static int ld_sdmmc_start(struct ld_softc *, struct buf *);
 static void ld_sdmmc_restart(void *);
-static int ld_sdmmc_discard(struct ld_softc *, off_t, off_t);
+static int ld_sdmmc_discard(struct ld_softc *, struct buf *);
 static int ld_sdmmc_ioctl(struct ld_softc *, u_long, void *, int32_t, bool);
 
 static void ld_sdmmc_doattach(void *);
 static void ld_sdmmc_dobio(void *);
+static void ld_sdmmc_dodiscard(void *);
 
 CFATTACH_DECL_NEW(ld_sdmmc, sizeof(struct ld_sdmmc_softc),
     ld_sdmmc_match, ld_sdmmc_attach, ld_sdmmc_detach, NULL);
@@ -132,6 +140,13 @@ ld_sdmmc_attach(device_t parent, device_
 	    sa->sf->cid.rev, sa->sf->cid.psn, sa->sf->cid.mdt);
 	aprint_naive("\n");
 
+	evcnt_attach_dynamic(&sc->sc_ev_discard, EVCNT_TYPE_MISC,
+	    NULL, device_xname(self), "sdmmc discard count");
+	evcnt_attach_dynamic(&sc->sc_ev_discarderr, EVCNT_TYPE_MISC,
+	    NULL, device_xname(self), "sdmmc discard errors");
+	evcnt_attach_dynamic(&sc->sc_ev_discardbusy, EVCNT_TYPE_MISC,
+	    NULL, device_xname(self), "sdmmc discard busy");
+
 	const int ntask = __arraycount(sc->sc_task);
 	sc->sc_freeq = pcq_create(ntask, KM_SLEEP);
 	for (i = 0; i < ntask; i++) {
@@ -144,7 +159,7 @@ ld_sdmmc_attach(device_t parent, device_
 	sc->sc_hwunit = 0;	/* always 0? */
 	sc->sc_sf = sa->sf;
 
-	ld->sc_flags = LDF_ENABLED;
+	ld->sc_flags = LDF_ENABLED | LDF_MPSAFE;
 	ld->sc_secperunit = sc->sc_sf->csd.capacity;
 	ld->sc_secsize = SDMMC_SECTOR_SIZE;
 	ld->sc_maxxfer = MAXPHYS;
@@ -208,6 +223,9 @@ ld_sdmmc_detach(device_t dev, int flags)
 		callout_destroy(&sc->sc_task[i].task_restart_ch);
 
 	pcq_destroy(sc->sc_freeq);
+	evcnt_detach(&sc->sc_ev_discard);
+	evcnt_detach(&sc->sc_ev_discarderr);
+	evcnt_detach(&sc->sc_ev_discardbusy);
 
 	return 0;
 }
@@ -309,12 +327,51 @@ ld_sdmmc_dump(struct ld_softc *ld, void 
 	    blkcnt * ld->sc_secsize);
 }
 
+static void
+ld_sdmmc_dodiscard(void *arg)
+{
+	struct ld_sdmmc_task *task = arg;
+	struct ld_sdmmc_softc *sc = task->task_sc;
+	struct buf *bp = task->task_bp;
+	uint32_t sblkno, nblks;
+	int error;
+
+	/* first and last block to erase */
+	sblkno = bp->b_rawblkno;
+	nblks  = howmany(bp->b_bcount, sc->sc_ld.sc_secsize);
+
+	/* An error from discard is non-fatal */
+	error = sdmmc_mem_discard(sc->sc_sf, sblkno, sblkno + nblks - 1);
+	if (error != 0)
+		sc->sc_ev_discarderr.ev_count++;
+	else
+		sc->sc_ev_discard.ev_count++;
+	pcq_put(sc->sc_freeq, task);
+
+	if (error)
+		bp->b_error = error;
+
+	lddiscardend(&sc->sc_ld, bp);
+}
+
 static int
-ld_sdmmc_discard(struct ld_softc *ld, off_t pos, off_t len)
+ld_sdmmc_discard(struct ld_softc *ld, struct buf *bp)
 {
 	struct ld_sdmmc_softc *sc = device_private(ld->sc_dv);
+	struct ld_sdmmc_task *task = pcq_get(sc->sc_freeq);
+
+	if (task == NULL) {
+		sc->sc_ev_discardbusy.ev_count++;
+		return 0;
+	}
 
-	return sdmmc_mem_discard(sc->sc_sf, pos, len);
+	task->task_bp = bp;
+
+	sdmmc_init_task(&task->task, ld_sdmmc_dodiscard, task);
+
+	sdmmc_add_task(sc->sc_sf->sc, &task->task);
+
+	return 0;
 }
 
 static int

Index: src/sys/dev/sdmmc/sdmmc_mem.c
diff -u src/sys/dev/sdmmc/sdmmc_mem.c:1.56.4.3 src/sys/dev/sdmmc/sdmmc_mem.c:1.56.4.4
--- src/sys/dev/sdmmc/sdmmc_mem.c:1.56.4.3	Tue Jul 25 01:49:13 2017
+++ src/sys/dev/sdmmc/sdmmc_mem.c	Fri Sep  1 09:59:10 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmc_mem.c,v 1.56.4.3 2017/07/25 01:49:13 snj Exp $	*/
+/*	$NetBSD: sdmmc_mem.c,v 1.56.4.4 2017/09/01 09:59:10 martin Exp $	*/
 /*	$OpenBSD: sdmmc_mem.c,v 1.10 2009/01/09 10:55:22 jsg Exp $	*/
 
 /*
@@ -45,7 +45,7 @@
 /* Routines for SD/MMC memory cards. */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.56.4.3 2017/07/25 01:49:13 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.56.4.4 2017/09/01 09:59:10 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -2152,7 +2152,7 @@ out:
 }
 
 int
-sdmmc_mem_discard(struct sdmmc_function *sf, off_t pos, off_t len)
+sdmmc_mem_discard(struct sdmmc_function *sf, uint32_t sblkno, uint32_t eblkno)
 {
 	struct sdmmc_softc *sc = sf->sc;
 	struct sdmmc_command cmd;
@@ -2161,13 +2161,8 @@ sdmmc_mem_discard(struct sdmmc_function 
 	if (ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE))
 		return ENODEV;	/* XXX not tested */
 
-	/* Erase what we can in the specified range. */
-	const off_t start = roundup(pos, SDMMC_SECTOR_SIZE);
-	const off_t end = rounddown(pos + len, SDMMC_SECTOR_SIZE) - 1;
-	if (end < start)
+	if (eblkno < sblkno)
 		return EINVAL;
-	const uint32_t sblkno = start / SDMMC_SECTOR_SIZE;
-	const uint32_t eblkno = end / SDMMC_SECTOR_SIZE;
 
 	SDMMC_LOCK(sc);
 	mutex_enter(&sc->sc_mtx);

Index: src/sys/dev/sdmmc/sdmmcvar.h
diff -u src/sys/dev/sdmmc/sdmmcvar.h:1.23.6.3 src/sys/dev/sdmmc/sdmmcvar.h:1.23.6.4
--- src/sys/dev/sdmmc/sdmmcvar.h:1.23.6.3	Tue Jul 25 01:49:13 2017
+++ src/sys/dev/sdmmc/sdmmcvar.h	Fri Sep  1 09:59:10 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmcvar.h,v 1.23.6.3 2017/07/25 01:49:13 snj Exp $	*/
+/*	$NetBSD: sdmmcvar.h,v 1.23.6.4 2017/09/01 09:59:10 martin Exp $	*/
 /*	$OpenBSD: sdmmcvar.h,v 1.13 2009/01/09 10:55:22 jsg Exp $	*/
 
 /*
@@ -381,7 +381,7 @@ int	sdmmc_mem_read_block(struct sdmmc_fu
 	    size_t);
 int	sdmmc_mem_write_block(struct sdmmc_function *, uint32_t, u_char *,
 	    size_t);
-int	sdmmc_mem_discard(struct sdmmc_function *, off_t, off_t);
+int	sdmmc_mem_discard(struct sdmmc_function *, uint32_t, uint32_t);
 int	sdmmc_mem_flush_cache(struct sdmmc_function *, bool);
 
 #endif	/* _SDMMCVAR_H_ */

Reply via email to