Module Name:    src
Committed By:   kiyohara
Date:           Sat Jan  7 14:49:53 UTC 2017

Modified Files:
        src/sys/dev/sdmmc: ld_sdmmc.c

Log Message:
Support retry when error.  like wd(4).


To generate a diff of this commit:
cvs rdiff -u -r1.23 -r1.24 src/sys/dev/sdmmc/ld_sdmmc.c

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/sdmmc/ld_sdmmc.c
diff -u src/sys/dev/sdmmc/ld_sdmmc.c:1.23 src/sys/dev/sdmmc/ld_sdmmc.c:1.24
--- src/sys/dev/sdmmc/ld_sdmmc.c:1.23	Tue Sep 27 03:33:33 2016
+++ src/sys/dev/sdmmc/ld_sdmmc.c	Sat Jan  7 14:49:53 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ld_sdmmc.c,v 1.23 2016/09/27 03:33:33 pgoyette Exp $	*/
+/*	$NetBSD: ld_sdmmc.c,v 1.24 2017/01/07 14:49:53 kiyohara Exp $	*/
 
 /*
  * Copyright (c) 2008 KIYOHARA Takashi
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.23 2016/09/27 03:33:33 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.24 2017/01/07 14:49:53 kiyohara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -59,6 +59,9 @@ __KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v
 #define DPRINTF(s)	/**/
 #endif
 
+#define	LD_SDMMC_IORETRIES	5	/* number of retries before giving up */
+#define	RECOVERYTIME		hz/2	/* time to wait before retrying a cmd */
+
 struct ld_sdmmc_softc;
 
 struct ld_sdmmc_task {
@@ -66,6 +69,8 @@ struct ld_sdmmc_task {
 
 	struct ld_sdmmc_softc *task_sc;
 	struct buf *task_bp;
+	int task_retries; /* number of xfer retry */
+	struct callout task_restart_ch;
 };
 
 struct ld_sdmmc_softc {
@@ -75,7 +80,7 @@ struct ld_sdmmc_softc {
 	struct sdmmc_function *sc_sf;
 #define LD_SDMMC_MAXQUEUECNT 4
 	struct ld_sdmmc_task sc_task[LD_SDMMC_MAXQUEUECNT];
-	int sc_nexttask;
+	TAILQ_HEAD(, sdmmc_task) sc_freeq;
 };
 
 static int ld_sdmmc_match(device_t, cfdata_t, void *);
@@ -84,6 +89,7 @@ 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 void ld_sdmmc_doattach(void *);
 static void ld_sdmmc_dobio(void *);
@@ -110,7 +116,9 @@ ld_sdmmc_attach(device_t parent, device_
 	struct ld_sdmmc_softc *sc = device_private(self);
 	struct sdmmc_attach_args *sa = aux;
 	struct ld_softc *ld = &sc->sc_ld;
+	struct ld_sdmmc_task *task;
 	struct lwp *lwp;
+	int i;
 
 	ld->sc_dv = self;
 
@@ -119,7 +127,13 @@ ld_sdmmc_attach(device_t parent, device_
 	    sa->sf->cid.rev, sa->sf->cid.psn, sa->sf->cid.mdt);
 	aprint_naive("\n");
 
-	sc->sc_nexttask = 0;
+	TAILQ_INIT(&sc->sc_freeq);
+	for (i = 0; i < __arraycount(sc->sc_task); i++) {
+		task = &sc->sc_task[i];
+		task->task_sc = sc;
+		callout_init(&task->task_restart_ch, 0);
+		TAILQ_INSERT_TAIL(&sc->sc_freeq, &task->task, next);
+	}
 
 	sc->sc_hwunit = 0;	/* always 0? */
 	sc->sc_sf = sa->sf;
@@ -168,12 +182,15 @@ ld_sdmmc_detach(device_t dev, int flags)
 {
 	struct ld_sdmmc_softc *sc = device_private(dev);
 	struct ld_softc *ld = &sc->sc_ld;
-	int rv;
+	int rv, i;
 
 	if ((rv = ldbegindetach(ld, flags)) != 0)
 		return rv;
 	ldenddetach(ld);
 
+	for (i = 0; i < __arraycount(sc->sc_task); i++)
+		callout_destroy(&sc->sc_task[i].task_restart_ch);
+
 	return 0;
 }
 
@@ -181,12 +198,12 @@ static int
 ld_sdmmc_start(struct ld_softc *ld, struct buf *bp)
 {
 	struct ld_sdmmc_softc *sc = device_private(ld->sc_dv);
-	struct ld_sdmmc_task *task = &sc->sc_task[sc->sc_nexttask];
+	struct ld_sdmmc_task *task = (void *)TAILQ_FIRST(&sc->sc_freeq);
 
-	sc->sc_nexttask = (sc->sc_nexttask + 1) % LD_SDMMC_MAXQUEUECNT;
+	TAILQ_REMOVE(&sc->sc_freeq, &task->task, next);
 
-	task->task_sc = sc;
 	task->task_bp = bp;
+	task->task_retries = 0;
 	sdmmc_init_task(&task->task, ld_sdmmc_dobio, task);
 
 	sdmmc_add_task(sc->sc_sf->sc, &task->task);
@@ -195,6 +212,18 @@ ld_sdmmc_start(struct ld_softc *ld, stru
 }
 
 static void
+ld_sdmmc_restart(void *arg)
+{
+	struct ld_sdmmc_task *task = (struct ld_sdmmc_task *)arg;
+	struct ld_sdmmc_softc *sc = task->task_sc;
+	struct buf *bp = task->task_bp;
+
+	bp->b_resid = bp->b_bcount;
+
+	sdmmc_add_task(sc->sc_sf->sc, &task->task);
+}
+
+static void
 ld_sdmmc_dobio(void *arg)
 {
 	struct ld_sdmmc_task *task = (struct ld_sdmmc_task *)arg;
@@ -228,14 +257,26 @@ ld_sdmmc_dobio(void *arg)
 		error = sdmmc_mem_write_block(sc->sc_sf, bp->b_rawblkno,
 		    bp->b_data, bp->b_bcount);
 	if (error) {
-		DPRINTF(("%s: error %d\n", device_xname(sc->sc_ld.sc_dv),
-		    error));
+		if (task->task_retries < LD_SDMMC_IORETRIES) {
+			struct dk_softc *dksc = &sc->sc_ld.sc_dksc;
+			struct cfdriver *cd = device_cfdriver(dksc->sc_dev);
+
+			diskerr(bp, cd->cd_name, "error", LOG_PRINTF, 0,
+				dksc->sc_dkdev.dk_label);
+			printf(", retrying\n");
+			task->task_retries++;
+			callout_reset(&task->task_restart_ch, RECOVERYTIME,
+			    ld_sdmmc_restart, task);
+			return;
+		}
 		bp->b_error = error;
 		bp->b_resid = bp->b_bcount;
 	} else {
 		bp->b_resid = 0;
 	}
 
+	TAILQ_INSERT_TAIL(&sc->sc_freeq, &task->task, next);
+
 	lddone(&sc->sc_ld, bp);
 }
 

Reply via email to