1 /*-
2  * Copyright (c) 2012 Robert N. M. Watson
3  * All rights reserved.
4  *
5  * This software was developed by SRI International and the University of
6  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7  * ("CTSRD"), as part of the DARPA CRASH research programme.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD: stable/10/sys/dev/altera/sdcard/altera_sdcard.c 257445 2013-10-31 13:47:39Z brooks $");
33 
34 #include "opt_altera_sdcard.h"
35 
36 #include <sys/param.h>
37 #include <sys/bus.h>
38 #include <sys/condvar.h>
39 #include <sys/conf.h>
40 #include <sys/bio.h>
41 #include <sys/kernel.h>
42 #include <sys/lock.h>
43 #include <sys/malloc.h>
44 #include <sys/module.h>
45 #include <sys/mutex.h>
46 #include <sys/rman.h>
47 #include <sys/systm.h>
48 #include <sys/taskqueue.h>
49 
50 #include <machine/bus.h>
51 #include <machine/resource.h>
52 
53 #include <geom/geom_disk.h>
54 
55 #include <dev/altera/sdcard/altera_sdcard.h>
56 
57 /*
58  * Device driver for the Altera University Program Secure Data Card IP Core,
59  * as described in the similarly named SOPC Builder IP Core specification.
60  * This soft core is not a full SD host controller interface (SDHCI) but
61  * instead provides a set of memory mapped registers and memory buffer that
62  * mildly abstract the SD Card protocol, but without providing DMA or
63  * interrupts.  However, it does hide the details of voltage and
64  * communications negotiation.  This driver implements disk(9), but due to the
65  * lack of interrupt support, must rely on timer-driven polling to determine
66  * when I/Os have completed.
67  *
68  * TODO:
69  *
70  * 1. Implement DISKFLAG_CANDELETE / SD Card sector erase support.
71  * 2. Implement d_ident from SD Card CID serial number field.
72  * 3. Handle read-only SD Cards.
73  * 4. Tune timeouts based on real-world SD Card speeds.
74  */
75 devclass_t	altera_sdcard_devclass;
76 
77 void
altera_sdcard_attach(struct altera_sdcard_softc * sc)78 altera_sdcard_attach(struct altera_sdcard_softc *sc)
79 {
80 
81 	ALTERA_SDCARD_LOCK_INIT(sc);
82 	ALTERA_SDCARD_CONDVAR_INIT(sc);
83 	sc->as_disk = NULL;
84 	bioq_init(&sc->as_bioq);
85 	sc->as_currentbio = NULL;
86 	sc->as_state = ALTERA_SDCARD_STATE_NOCARD;
87 	sc->as_taskqueue = taskqueue_create("altera_sdcardc taskq", M_WAITOK,
88 	    taskqueue_thread_enqueue, &sc->as_taskqueue);
89 	taskqueue_start_threads(&sc->as_taskqueue, 1, PI_DISK,
90 	    "altera_sdcardc%d taskqueue", sc->as_unit);
91 	TIMEOUT_TASK_INIT(sc->as_taskqueue, &sc->as_task, 0,
92 	    altera_sdcard_task, sc);
93 
94 	/*
95 	 * Kick off timer-driven processing with a manual poll so that we
96 	 * synchronously detect an already-inserted SD Card during the boot or
97 	 * other driver attach point.
98 	 */
99 	altera_sdcard_task(sc, 1);
100 }
101 
102 void
altera_sdcard_detach(struct altera_sdcard_softc * sc)103 altera_sdcard_detach(struct altera_sdcard_softc *sc)
104 {
105 
106 	KASSERT(sc->as_taskqueue != NULL, ("%s: taskqueue not present",
107 	    __func__));
108 
109 	/*
110 	 * Winding down the driver on detach is a bit complex.  Update the
111 	 * flags to indicate that a detach has been requested, and then wait
112 	 * for in-progress I/O to wind down before continuing.
113 	 */
114 	ALTERA_SDCARD_LOCK(sc);
115 	sc->as_flags |= ALTERA_SDCARD_FLAG_DETACHREQ;
116 	while (sc->as_state != ALTERA_SDCARD_STATE_DETACHED)
117 		ALTERA_SDCARD_CONDVAR_WAIT(sc);
118 	ALTERA_SDCARD_UNLOCK(sc);
119 
120 	/*
121 	 * Now wait for the possibly still executing taskqueue to drain.  In
122 	 * principle no more events will be scheduled as we've transitioned to
123 	 * a detached state, but there might still be a request in execution.
124 	 */
125 	while (taskqueue_cancel_timeout(sc->as_taskqueue, &sc->as_task, NULL))
126 		taskqueue_drain_timeout(sc->as_taskqueue, &sc->as_task);
127 
128 	/*
129 	 * Simulate a disk removal if one is present to deal with any pending
130 	 * or queued I/O.
131 	 */
132 	if (sc->as_disk != NULL)
133 		altera_sdcard_disk_remove(sc);
134 	KASSERT(bioq_first(&sc->as_bioq) == NULL,
135 	    ("%s: non-empty bioq", __func__));
136 
137 	/*
138 	 * Free any remaining allocated resources.
139 	 */
140 	taskqueue_free(sc->as_taskqueue);
141 	sc->as_taskqueue = NULL;
142 	ALTERA_SDCARD_CONDVAR_DESTROY(sc);
143 	ALTERA_SDCARD_LOCK_DESTROY(sc);
144 }
145 
146 /*
147  * Set up and start the next I/O.  Transition to the I/O state, but allow the
148  * caller to schedule the next timeout, as this may be called either from an
149  * initial attach context, or from the task queue, which requires different
150  * behaviour.
151  */
152 static void
altera_sdcard_nextio(struct altera_sdcard_softc * sc)153 altera_sdcard_nextio(struct altera_sdcard_softc *sc)
154 {
155 	struct bio *bp;
156 
157 	ALTERA_SDCARD_LOCK_ASSERT(sc);
158 	KASSERT(sc->as_currentbio == NULL,
159 	    ("%s: bio already active", __func__));
160 
161 	bp = bioq_takefirst(&sc->as_bioq);
162 	if (bp == NULL)
163 		panic("%s: bioq empty", __func__);
164 	altera_sdcard_io_start(sc, bp);
165 	sc->as_state = ALTERA_SDCARD_STATE_IO;
166 }
167 
168 static void
altera_sdcard_task_nocard(struct altera_sdcard_softc * sc)169 altera_sdcard_task_nocard(struct altera_sdcard_softc *sc)
170 {
171 
172 	ALTERA_SDCARD_LOCK_ASSERT(sc);
173 
174 	/*
175 	 * Handle device driver detach.
176 	 */
177 	if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) {
178 		sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
179 		return;
180 	}
181 
182 	/*
183 	 * If there is no card insertion, remain in NOCARD.
184 	 */
185 	if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT))
186 		return;
187 
188 	/*
189 	 * Read the CSD -- it may contain values that the driver can't handle,
190 	 * either because of an unsupported version/feature, or because the
191 	 * card is misbehaving.  This triggers a transition to
192 	 * ALTERA_SDCARD_STATE_BADCARD.  We rely on the CSD read to print a
193 	 * banner about how the card is problematic, since it has more
194 	 * information.  The bad card state allows us to print that banner
195 	 * once rather than each time we notice the card is there, and still
196 	 * bad.
197 	 */
198 	if (altera_sdcard_read_csd(sc) != 0) {
199 		sc->as_state = ALTERA_SDCARD_STATE_BADCARD;
200 		return;
201 	}
202 
203 	/*
204 	 * Process card insertion and upgrade to the IDLE state.
205 	 */
206 	altera_sdcard_disk_insert(sc);
207 	sc->as_state = ALTERA_SDCARD_STATE_IDLE;
208 }
209 
210 static void
altera_sdcard_task_badcard(struct altera_sdcard_softc * sc)211 altera_sdcard_task_badcard(struct altera_sdcard_softc *sc)
212 {
213 
214 	ALTERA_SDCARD_LOCK_ASSERT(sc);
215 
216 	/*
217 	 * Handle device driver detach.
218 	 */
219 	if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) {
220 		sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
221 		return;
222 	}
223 
224 	/*
225 	 * Handle safe card removal -- no teardown is required, just a state
226 	 * transition.
227 	 */
228 	if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT))
229 		sc->as_state = ALTERA_SDCARD_STATE_NOCARD;
230 }
231 
232 static void
altera_sdcard_task_idle(struct altera_sdcard_softc * sc)233 altera_sdcard_task_idle(struct altera_sdcard_softc *sc)
234 {
235 
236 	ALTERA_SDCARD_LOCK_ASSERT(sc);
237 
238 	/*
239 	 * Handle device driver detach.
240 	 */
241 	if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) {
242 		sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
243 		return;
244 	}
245 
246 	/*
247 	 * Handle safe card removal.
248 	 */
249 	if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT)) {
250 		altera_sdcard_disk_remove(sc);
251 		sc->as_state = ALTERA_SDCARD_STATE_NOCARD;
252 	}
253 }
254 
255 static void
altera_sdcard_task_io(struct altera_sdcard_softc * sc)256 altera_sdcard_task_io(struct altera_sdcard_softc *sc)
257 {
258 	uint16_t asr;
259 
260 	ALTERA_SDCARD_LOCK_ASSERT(sc);
261 	KASSERT(sc->as_currentbio != NULL, ("%s: no current I/O", __func__));
262 
263 #ifdef ALTERA_SDCARD_FAST_SIM
264 recheck:
265 #endif
266 	asr = altera_sdcard_read_asr(sc);
267 
268 	/*
269 	 * Check for unexpected card removal during an I/O.
270 	 */
271 	if (!(asr & ALTERA_SDCARD_ASR_CARDPRESENT)) {
272 		altera_sdcard_disk_remove(sc);
273 		if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ)
274 			sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
275 		else
276 			sc->as_state = ALTERA_SDCARD_STATE_NOCARD;
277 		return;
278 	}
279 
280 	/*
281 	 * If the I/O isn't complete, remain in the IO state without further
282 	 * action, even if DETACHREQ is in flight.
283 	 */
284 	if (asr & ALTERA_SDCARD_ASR_CMDINPROGRESS)
285 		return;
286 
287 	/*
288 	 * Handle various forms of I/O completion, successful and otherwise.
289 	 * The I/O layer may restart the transaction if an error occurred, in
290 	 * which case remain in the IO state and reschedule.
291 	 */
292 	if (!altera_sdcard_io_complete(sc, asr))
293 		return;
294 
295 	/*
296 	 * Now that I/O is complete, process detach requests in preference to
297 	 * starting new I/O.
298 	 */
299 	if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) {
300 		sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
301 		return;
302 	}
303 
304 	/*
305 	 * Finally, either start the next I/O or transition to the IDLE state.
306 	 */
307 	if (bioq_first(&sc->as_bioq) != NULL) {
308 		altera_sdcard_nextio(sc);
309 #ifdef ALTERA_SDCARD_FAST_SIM
310 		goto recheck;
311 #endif
312 	} else
313 		sc->as_state = ALTERA_SDCARD_STATE_IDLE;
314 }
315 
316 static void
altera_sdcard_task_rechedule(struct altera_sdcard_softc * sc)317 altera_sdcard_task_rechedule(struct altera_sdcard_softc *sc)
318 {
319 	int interval;
320 
321 	/*
322 	 * Reschedule based on new state.  Or not, if detaching the device
323 	 * driver.  Treat a bad card as though it were no card at all.
324 	 */
325 	switch (sc->as_state) {
326 	case ALTERA_SDCARD_STATE_NOCARD:
327 	case ALTERA_SDCARD_STATE_BADCARD:
328 		interval = ALTERA_SDCARD_TIMEOUT_NOCARD;
329 		break;
330 
331 	case ALTERA_SDCARD_STATE_IDLE:
332 		interval = ALTERA_SDCARD_TIMEOUT_IDLE;
333 		break;
334 
335 	case ALTERA_SDCARD_STATE_IO:
336 		if (sc->as_flags & ALTERA_SDCARD_FLAG_IOERROR)
337 			interval = ALTERA_SDCARD_TIMEOUT_IOERROR;
338 		else
339 			interval = ALTERA_SDCARD_TIMEOUT_IO;
340 		break;
341 
342 	default:
343 		panic("%s: invalid exit state %d", __func__, sc->as_state);
344 	}
345 	taskqueue_enqueue_timeout(sc->as_taskqueue, &sc->as_task, interval);
346 }
347 
348 /*
349  * Because the Altera SD Card IP Core doesn't support interrupts, we do all
350  * asynchronous work from a timeout.  Poll at two different rates -- an
351  * infrequent check for card insertion status changes, and a frequent one for
352  * I/O completion.  The task should never start in DETACHED, as that would
353  * imply that a previous instance failed to cancel rather than reschedule.
354  */
355 void
altera_sdcard_task(void * arg,int pending)356 altera_sdcard_task(void *arg, int pending)
357 {
358 	struct altera_sdcard_softc *sc;
359 
360 	sc = arg;
361 	KASSERT(sc->as_state != ALTERA_SDCARD_STATE_DETACHED,
362 	    ("%s: already in detached", __func__));
363 
364 	ALTERA_SDCARD_LOCK(sc);
365 	switch (sc->as_state) {
366 	case ALTERA_SDCARD_STATE_NOCARD:
367 		altera_sdcard_task_nocard(sc);
368 		break;
369 
370 	case ALTERA_SDCARD_STATE_BADCARD:
371 		altera_sdcard_task_badcard(sc);
372 		break;
373 
374 	case ALTERA_SDCARD_STATE_IDLE:
375 		altera_sdcard_task_idle(sc);
376 		break;
377 
378 	case ALTERA_SDCARD_STATE_IO:
379 		altera_sdcard_task_io(sc);
380 		break;
381 
382 	default:
383 		panic("%s: invalid enter state %d", __func__, sc->as_state);
384 	}
385 
386 	/*
387 	 * If we have transitioned to DETACHED, signal the detach thread and
388 	 * cancel the timeout-driven task.  Otherwise reschedule on an
389 	 * appropriate timeout.
390 	 */
391 	if (sc->as_state == ALTERA_SDCARD_STATE_DETACHED)
392 		ALTERA_SDCARD_CONDVAR_SIGNAL(sc);
393 	else
394 		altera_sdcard_task_rechedule(sc);
395 	ALTERA_SDCARD_UNLOCK(sc);
396 }
397 
398 void
altera_sdcard_start(struct altera_sdcard_softc * sc)399 altera_sdcard_start(struct altera_sdcard_softc *sc)
400 {
401 
402 	ALTERA_SDCARD_LOCK_ASSERT(sc);
403 
404 	KASSERT(sc->as_state == ALTERA_SDCARD_STATE_IDLE,
405 	    ("%s: starting when not IDLE", __func__));
406 
407 	taskqueue_cancel_timeout(sc->as_taskqueue, &sc->as_task, NULL);
408 	altera_sdcard_nextio(sc);
409 #ifdef ALTERA_SDCARD_FAST_SIM
410 	altera_sdcard_task_io(sc);
411 #endif
412 	altera_sdcard_task_rechedule(sc);
413 }
414