Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/sdmmc Support retry when error. like wd(4).



details:   https://anonhg.NetBSD.org/src/rev/5bad082909b1
branches:  trunk
changeset: 350187:5bad082909b1
user:      kiyohara <kiyohara%NetBSD.org@localhost>
date:      Sat Jan 07 14:49:53 2017 +0000

description:
Support retry when error.  like wd(4).

diffstat:

 sys/dev/sdmmc/ld_sdmmc.c |  61 ++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 51 insertions(+), 10 deletions(-)

diffs (160 lines):

diff -r 2f5faee71969 -r 5bad082909b1 sys/dev/sdmmc/ld_sdmmc.c
--- a/sys/dev/sdmmc/ld_sdmmc.c  Sat Jan 07 14:44:26 2017 +0000
+++ b/sys/dev/sdmmc/ld_sdmmc.c  Sat Jan 07 14:49:53 2017 +0000
@@ -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 @@
 #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_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 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_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 @@
        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 @@
            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 @@
 {
        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 @@
 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 @@
 }
 
 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 @@
                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);
 }
 



Home | Main Index | Thread Index | Old Index