aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/flash
diff options
context:
space:
mode:
authorIan Lepore <ian@FreeBSD.org>2019-02-24 23:08:53 +0000
committerIan Lepore <ian@FreeBSD.org>2019-02-24 23:08:53 +0000
commit4b06839fbfab30c1e432e3500ef2330d93815038 (patch)
tree2283308ad605942a7681bcf4a845a02e9c438a06 /sys/dev/flash
parenta4c69b8bc01256464eb11aaa266c0e72c1f11517 (diff)
Notes
Diffstat (limited to 'sys/dev/flash')
-rw-r--r--sys/dev/flash/at45d.c39
1 files changed, 38 insertions, 1 deletions
diff --git a/sys/dev/flash/at45d.c b/sys/dev/flash/at45d.c
index 678e1d31fe8d..fb6935a22561 100644
--- a/sys/dev/flash/at45d.c
+++ b/sys/dev/flash/at45d.c
@@ -65,11 +65,16 @@ struct at45d_softc
struct proc *p;
struct intr_config_hook config_intrhook;
device_t dev;
+ u_int taskstate;
uint16_t pagecount;
uint16_t pageoffset;
uint16_t pagesize;
};
+#define TSTATE_STOPPED 0
+#define TSTATE_STOPPING 1
+#define TSTATE_RUNNING 2
+
#define AT45D_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define AT45D_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
#define AT45D_LOCK_INIT(_sc) \
@@ -209,8 +214,33 @@ at45d_attach(device_t dev)
static int
at45d_detach(device_t dev)
{
+ struct at45d_softc *sc;
+ int err;
+
+ sc = device_get_softc(dev);
+ err = 0;
- return (EBUSY) /* XXX */;
+ AT45D_LOCK(sc);
+ if (sc->taskstate == TSTATE_RUNNING) {
+ sc->taskstate = TSTATE_STOPPING;
+ wakeup(sc);
+ while (err == 0 && sc->taskstate != TSTATE_STOPPED) {
+ err = msleep(sc, &sc->sc_mtx, 0, "at45dt", hz * 3);
+ if (err != 0) {
+ sc->taskstate = TSTATE_RUNNING;
+ device_printf(sc->dev,
+ "Failed to stop queue task\n");
+ }
+ }
+ }
+ AT45D_UNLOCK(sc);
+
+ if (err == 0 && sc->taskstate == TSTATE_STOPPED) {
+ disk_destroy(sc->disk);
+ bioq_flush(&sc->bio_queue, NULL, ENXIO);
+ AT45D_LOCK_DESTROY(sc);
+ }
+ return (err);
}
static void
@@ -266,6 +296,7 @@ at45d_delayed_attach(void *xsc)
bioq_init(&sc->bio_queue);
kproc_create(&at45d_task, sc, &sc->p, 0, 0,
"task: at45d flash");
+ sc->taskstate = TSTATE_RUNNING;
device_printf(sc->dev, "%s, %d bytes per page, %d pages\n",
ident->name, pagesize, ident->pagecount);
}
@@ -324,6 +355,12 @@ at45d_task(void *arg)
for (;;) {
AT45D_LOCK(sc);
do {
+ if (sc->taskstate == TSTATE_STOPPING) {
+ sc->taskstate = TSTATE_STOPPED;
+ AT45D_UNLOCK(sc);
+ wakeup(sc);
+ kproc_exit(0);
+ }
bp = bioq_takefirst(&sc->bio_queue);
if (bp == NULL)
msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0);