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); }