1239675Srwatson/*-
2239675Srwatson * Copyright (c) 2012 Robert N. M. Watson
3239675Srwatson * All rights reserved.
4239675Srwatson *
5239675Srwatson * This software was developed by SRI International and the University of
6239675Srwatson * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7239675Srwatson * ("CTSRD"), as part of the DARPA CRASH research programme.
8239675Srwatson *
9239675Srwatson * Redistribution and use in source and binary forms, with or without
10239675Srwatson * modification, are permitted provided that the following conditions
11239675Srwatson * are met:
12239675Srwatson * 1. Redistributions of source code must retain the above copyright
13239675Srwatson *    notice, this list of conditions and the following disclaimer.
14239675Srwatson * 2. Redistributions in binary form must reproduce the above copyright
15239675Srwatson *    notice, this list of conditions and the following disclaimer in the
16239675Srwatson *    documentation and/or other materials provided with the distribution.
17239675Srwatson *
18239675Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19239675Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20239675Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21239675Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22239675Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23239675Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24239675Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25239675Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26239675Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27239675Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28239675Srwatson * SUCH DAMAGE.
29239675Srwatson */
30239675Srwatson
31239675Srwatson#include <sys/cdefs.h>
32239675Srwatson__FBSDID("$FreeBSD$");
33239675Srwatson
34239675Srwatson#include <sys/param.h>
35239675Srwatson#include <sys/bus.h>
36239675Srwatson#include <sys/condvar.h>
37239675Srwatson#include <sys/conf.h>
38239675Srwatson#include <sys/bio.h>
39239675Srwatson#include <sys/endian.h>
40239675Srwatson#include <sys/kernel.h>
41239675Srwatson#include <sys/lock.h>
42239675Srwatson#include <sys/malloc.h>
43239675Srwatson#include <sys/module.h>
44239675Srwatson#include <sys/mutex.h>
45239675Srwatson#include <sys/rman.h>
46239675Srwatson#include <sys/systm.h>
47239675Srwatson#include <sys/taskqueue.h>
48239675Srwatson
49239675Srwatson#include <machine/bus.h>
50239675Srwatson#include <machine/resource.h>
51239675Srwatson
52239675Srwatson#include <geom/geom_disk.h>
53239675Srwatson
54239675Srwatson#include <dev/altera/sdcard/altera_sdcard.h>
55239675Srwatson
56239675Srwatsonint altera_sdcard_ignore_crc_errors = 1;
57239675Srwatsonint altera_sdcard_verify_rxtx_writes = 1;
58239675Srwatson
59239675Srwatson/*
60239675Srwatson * Low-level I/O routines for the Altera SD Card University IP Core driver.
61239675Srwatson *
62239675Srwatson * XXXRW: Throughout, it is assumed that the IP Core handles multibyte
63239675Srwatson * registers as little endian, as is the case for other Altera IP cores.
64239675Srwatson * However, the specification makes no reference to endianness, so this
65239675Srwatson * assumption might not always be correct.
66239675Srwatson */
67239675Srwatsonuint16_t
68239675Srwatsonaltera_sdcard_read_asr(struct altera_sdcard_softc *sc)
69239675Srwatson{
70239675Srwatson
71239675Srwatson	return (le16toh(bus_read_2(sc->as_res, ALTERA_SDCARD_OFF_ASR)));
72239675Srwatson}
73239675Srwatson
74239675Srwatsonstatic int
75239675Srwatsonaltera_sdcard_process_csd0(struct altera_sdcard_softc *sc)
76239675Srwatson{
77239675Srwatson	uint64_t c_size, c_size_mult, read_bl_len;
78239675Srwatson	uint8_t byte0, byte1, byte2;
79239675Srwatson
80239675Srwatson	ALTERA_SDCARD_LOCK_ASSERT(sc);
81239675Srwatson
82239675Srwatson	/*-
83239675Srwatson	 * Compute card capacity per SD Card interface description as follows:
84239675Srwatson	 *
85239675Srwatson	 *   Memory capacity = BLOCKNR * BLOCK_LEN
86239675Srwatson	 *
87239675Srwatson	 * Where:
88239675Srwatson	 *
89239675Srwatson	 *   BLOCKNR = (C_SIZE + 1) * MULT
90239675Srwatson	 *   MULT = 2^(C_SIZE_MULT+2)
91239675Srwatson	 *   BLOCK_LEN = 2^READ_BL_LEN
92239675Srwatson	 */
93239675Srwatson	read_bl_len = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_READ_BL_LEN_BYTE];
94239675Srwatson	read_bl_len &= ALTERA_SDCARD_CSD_READ_BL_LEN_MASK;
95239675Srwatson
96239675Srwatson	byte0 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_BYTE0];
97239675Srwatson	byte0 &= ALTERA_SDCARD_CSD_C_SIZE_MASK0;
98239675Srwatson	byte1 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_BYTE1];
99239675Srwatson	byte2 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_BYTE2];
100239675Srwatson	byte2 &= ALTERA_SDCARD_CSD_C_SIZE_MASK2;
101239675Srwatson	c_size = (byte0 >> ALTERA_SDCARD_CSD_C_SIZE_RSHIFT0) |
102239675Srwatson	    (byte1 << ALTERA_SDCARD_CSD_C_SIZE_LSHIFT1) |
103239675Srwatson	    (byte2 << ALTERA_SDCARD_CSD_C_SIZE_LSHIFT2);
104239675Srwatson
105239675Srwatson	byte0 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE0];
106239675Srwatson	byte0 &= ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK0;
107239675Srwatson	byte1 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE1];
108239675Srwatson	byte1 &= ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK1;
109239675Srwatson	c_size_mult = (byte0 >> ALTERA_SDCARD_CSD_C_SIZE_MULT_RSHIFT0) |
110239675Srwatson	    (byte1 << ALTERA_SDCARD_CSD_C_SIZE_MULT_LSHIFT1);
111239675Srwatson
112239675Srwatson	/*
113239675Srwatson	 * If we're just getting back zero's, mark the card as bad, even
114239675Srwatson	 * though it could just mean a Very Small Disk Indeed.
115239675Srwatson	 */
116239675Srwatson	if (c_size == 0 && c_size_mult == 0 && read_bl_len == 0) {
117239675Srwatson		device_printf(sc->as_dev, "Ignored zero-size card\n");
118239675Srwatson		return (ENXIO);
119239675Srwatson	}
120239675Srwatson	sc->as_mediasize = (c_size + 1) * (1 << (c_size_mult + 2)) *
121239675Srwatson	    (1 << read_bl_len);
122239675Srwatson	return (0);
123239675Srwatson}
124239675Srwatson
125239675Srwatsonint
126239675Srwatsonaltera_sdcard_read_csd(struct altera_sdcard_softc *sc)
127239675Srwatson{
128239675Srwatson	uint8_t csd_structure;
129239675Srwatson	int error;
130239675Srwatson
131239675Srwatson	ALTERA_SDCARD_LOCK_ASSERT(sc);
132239675Srwatson
133239675Srwatson	/*
134239675Srwatson	 * XXXRW: Assume for now that when the SD Card IP Core negotiates
135239675Srwatson	 * voltage/speed/etc, it must use the CSD register, and therefore
136239675Srwatson	 * populates the SD Card IP Core's cache of the register value.  This
137239675Srwatson	 * means that we can read it without issuing further SD Card commands.
138239675Srwatson	 * If this assumption proves false, we will (a) get back garbage and
139239675Srwatson	 * (b) need to add additional states in the driver state machine in
140239675Srwatson	 * order to query card properties before I/O can start.
141239675Srwatson	 *
142239675Srwatson	 * XXXRW: Treating this as an array of bytes, so no byte swapping --
143239675Srwatson	 * is that a safe assumption?
144239675Srwatson	 */
145239675Srwatson	KASSERT(((uintptr_t)&sc->as_csd.csd_data) % 2 == 0,
146239675Srwatson	    ("%s: CSD buffer unaligned", __func__));
147239675Srwatson	bus_read_region_2(sc->as_res, ALTERA_SDCARD_OFF_CSD,
148239675Srwatson	    (uint16_t *)sc->as_csd.csd_data, sizeof(sc->as_csd) / 2);
149239675Srwatson
150239675Srwatson	/*
151239675Srwatson	 * Interpret the loaded CSD, extracting certain fields and copying
152239675Srwatson	 * them into the softc for easy software access.
153239675Srwatson	 *
154239675Srwatson	 * Currently, we support only CSD Version 1.0.  If we detect a newer
155239675Srwatson	 * version, suppress card detection.
156239675Srwatson	 */
157239675Srwatson	csd_structure = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_STRUCTURE_BYTE];
158239675Srwatson	csd_structure &= ALTERA_SDCARD_CSD_STRUCTURE_MASK;
159239675Srwatson	csd_structure >>= ALTERA_SDCARD_CSD_STRUCTURE_RSHIFT;
160239675Srwatson	sc->as_csd_structure = csd_structure;
161239675Srwatson
162239675Srwatson	/*
163239675Srwatson	 * Interpret the CSD field based on its version.  Extract fields,
164239675Srwatson	 * especially mediasize.
165239675Srwatson	 *
166239675Srwatson	 * XXXRW: Desirable to support further CSD versions here.
167239675Srwatson	 */
168239675Srwatson	switch (sc->as_csd_structure) {
169239675Srwatson	case 0:
170239675Srwatson		error = altera_sdcard_process_csd0(sc);
171239675Srwatson		if (error)
172239675Srwatson			return (error);
173239675Srwatson		break;
174239675Srwatson
175239675Srwatson	default:
176239675Srwatson		device_printf(sc->as_dev,
177239675Srwatson		    "Ignored disk with unsupported CSD structure (%d)\n",
178239675Srwatson		    sc->as_csd_structure);
179239675Srwatson		return (ENXIO);
180239675Srwatson	}
181239675Srwatson	return (0);
182239675Srwatson}
183239675Srwatson
184239675Srwatson/*
185239675Srwatson * XXXRW: The Altera IP Core specification indicates that RR1 is a 16-bit
186239675Srwatson * register, but all bits it identifies are >16 bit.  Most likely, RR1 is a
187239675Srwatson * 32-bit register?
188239675Srwatson */
189239675Srwatsonstatic uint16_t
190239675Srwatsonaltera_sdcard_read_rr1(struct altera_sdcard_softc *sc)
191239675Srwatson{
192239675Srwatson
193239675Srwatson	return (le16toh(bus_read_2(sc->as_res, ALTERA_SDCARD_OFF_RR1)));
194239675Srwatson}
195239675Srwatson
196239675Srwatsonstatic void
197239675Srwatsonaltera_sdcard_write_cmd_arg(struct altera_sdcard_softc *sc, uint32_t cmd_arg)
198239675Srwatson{
199239675Srwatson
200239675Srwatson	bus_write_4(sc->as_res, ALTERA_SDCARD_OFF_CMD_ARG, htole32(cmd_arg));
201239675Srwatson}
202239675Srwatson
203239675Srwatsonstatic void
204239675Srwatsonaltera_sdcard_write_cmd(struct altera_sdcard_softc *sc, uint16_t cmd)
205239675Srwatson{
206239675Srwatson
207239675Srwatson	bus_write_2(sc->as_res, ALTERA_SDCARD_OFF_CMD, htole16(cmd));
208239675Srwatson}
209239675Srwatson
210239675Srwatsonstatic void
211239675Srwatsonaltera_sdcard_read_rxtx_buffer(struct altera_sdcard_softc *sc, void *data,
212239675Srwatson    size_t len)
213239675Srwatson{
214239675Srwatson
215239675Srwatson	KASSERT((uintptr_t)data % 2 == 0,
216239675Srwatson	    ("%s: unaligned data %p", __func__, data));
217239675Srwatson	KASSERT((len <= ALTERA_SDCARD_SECTORSIZE) && (len % 2 == 0),
218239675Srwatson	    ("%s: invalid length %ju", __func__, len));
219239675Srwatson
220239675Srwatson	bus_read_region_2(sc->as_res, ALTERA_SDCARD_OFF_RXTX_BUFFER,
221239675Srwatson	    (uint16_t *)data, len / 2);
222239675Srwatson}
223239675Srwatson
224239675Srwatsonstatic void
225239675Srwatsonaltera_sdcard_write_rxtx_buffer(struct altera_sdcard_softc *sc, void *data,
226239675Srwatson    size_t len)
227239675Srwatson{
228239675Srwatson	u_int corrections, differences, i, retry_counter;
229239675Srwatson	uint16_t d, v;
230239675Srwatson
231239675Srwatson	KASSERT((uintptr_t)data % 2 == 0,
232239675Srwatson	    ("%s: unaligned data %p", __func__, data));
233239675Srwatson	KASSERT((len <= ALTERA_SDCARD_SECTORSIZE) && (len % 2 == 0),
234239675Srwatson	    ("%s: invalid length %ju", __func__, len));
235239675Srwatson
236239675Srwatson	retry_counter = 0;
237239675Srwatson	do {
238239675Srwatson		bus_write_region_2(sc->as_res, ALTERA_SDCARD_OFF_RXTX_BUFFER,
239239675Srwatson		    (uint16_t *)data, len / 2);
240239675Srwatson
241239675Srwatson		/*
242239675Srwatson		 * XXXRW: Due to a possible hardware bug, the above call to
243239675Srwatson		 * bus_write_region_2() might not succeed.  If the workaround
244239675Srwatson		 * is enabled, verify each write and retry until it succeeds.
245239675Srwatson		 *
246239675Srwatson		 * XXXRW: Do we want a limit counter for retries here?
247239675Srwatson		 */
248239675Srwatsonrecheck:
249239675Srwatson		corrections = 0;
250239675Srwatson		differences = 0;
251239675Srwatson		if (altera_sdcard_verify_rxtx_writes) {
252239675Srwatson			for (i = 0; i < ALTERA_SDCARD_SECTORSIZE; i += 2) {
253239675Srwatson				v = bus_read_2(sc->as_res,
254239675Srwatson				    ALTERA_SDCARD_OFF_RXTX_BUFFER + i);
255239675Srwatson				d = *(uint16_t *)((uint8_t *)data + i);
256239675Srwatson				if (v != d) {
257239675Srwatson					if (retry_counter == 0) {
258239675Srwatson						bus_write_2(sc->as_res,
259239675Srwatson						    ALTERA_SDCARD_OFF_RXTX_BUFFER + i,
260239675Srwatson						    d);
261239675Srwatson						v = bus_read_2(sc->as_res,
262239675Srwatson						    ALTERA_SDCARD_OFF_RXTX_BUFFER + i);
263239675Srwatson						if (v == d) {
264239675Srwatson							corrections++;
265239675Srwatson							device_printf(sc->as_dev,
266239675Srwatson							    "%s: single word rewrite worked"
267239675Srwatson							    " at offset %u\n",
268239675Srwatson							    __func__, i);
269239675Srwatson							continue;
270239675Srwatson						}
271239675Srwatson					}
272239675Srwatson					differences++;
273239675Srwatson					device_printf(sc->as_dev,
274239675Srwatson					    "%s: retrying write -- difference"
275239675Srwatson					    " %u at offset %u, retry %u\n",
276239675Srwatson					    __func__, differences, i,
277239675Srwatson					    retry_counter);
278239675Srwatson				}
279239675Srwatson			}
280239675Srwatson			if (differences != 0) {
281239675Srwatson				retry_counter++;
282239675Srwatson				if (retry_counter == 1 &&
283239675Srwatson				    corrections == differences)
284239675Srwatson					goto recheck;
285239675Srwatson			}
286239675Srwatson		}
287239675Srwatson	} while (differences != 0);
288239675Srwatson	if (retry_counter)
289239675Srwatson		device_printf(sc->as_dev, "%s: succeeded after %u retries\n",
290239675Srwatson		    __func__, retry_counter);
291239675Srwatson}
292239675Srwatson
293239675Srwatsonstatic void
294239675Srwatsonaltera_sdcard_io_start_internal(struct altera_sdcard_softc *sc, struct bio *bp)
295239675Srwatson{
296239675Srwatson
297239675Srwatson	switch (bp->bio_cmd) {
298239675Srwatson	case BIO_READ:
299239675Srwatson		altera_sdcard_write_cmd_arg(sc, bp->bio_pblkno *
300239675Srwatson		    ALTERA_SDCARD_SECTORSIZE);
301239675Srwatson		altera_sdcard_write_cmd(sc, ALTERA_SDCARD_CMD_READ_BLOCK);
302239675Srwatson		break;
303239675Srwatson
304239675Srwatson	case BIO_WRITE:
305239675Srwatson		altera_sdcard_write_rxtx_buffer(sc, bp->bio_data,
306239675Srwatson		    bp->bio_bcount);
307239675Srwatson		altera_sdcard_write_cmd_arg(sc, bp->bio_pblkno *
308239675Srwatson		    ALTERA_SDCARD_SECTORSIZE);
309239675Srwatson		altera_sdcard_write_cmd(sc, ALTERA_SDCARD_CMD_WRITE_BLOCK);
310239675Srwatson		break;
311239675Srwatson
312239675Srwatson	default:
313239675Srwatson		panic("%s: unsupported I/O operation %d", __func__,
314239675Srwatson		    bp->bio_cmd);
315239675Srwatson	}
316239675Srwatson}
317239675Srwatson
318239675Srwatsonvoid
319239675Srwatsonaltera_sdcard_io_start(struct altera_sdcard_softc *sc, struct bio *bp)
320239675Srwatson{
321239675Srwatson
322239675Srwatson	ALTERA_SDCARD_LOCK_ASSERT(sc);
323239675Srwatson	KASSERT(sc->as_currentbio == NULL,
324239675Srwatson	    ("%s: bio already started", __func__));
325239675Srwatson
326239675Srwatson	/*
327239675Srwatson	 * We advertise a block size and maximum I/O size up the stack of the
328239675Srwatson	 * SD Card IP Core sector size.  Catch any attempts to not follow the
329239675Srwatson	 * rules.
330239675Srwatson	 */
331239675Srwatson	KASSERT(bp->bio_bcount == ALTERA_SDCARD_SECTORSIZE,
332239675Srwatson	    ("%s: I/O size not %d", __func__, ALTERA_SDCARD_SECTORSIZE));
333239675Srwatson	altera_sdcard_io_start_internal(sc, bp);
334239675Srwatson	sc->as_currentbio = bp;
335239675Srwatson	sc->as_retriesleft = ALTERA_SDCARD_RETRY_LIMIT;
336239675Srwatson}
337239675Srwatson
338239675Srwatson/*
339239675Srwatson * Handle completed I/O.  ASR is passed in to avoid reading it more than once.
340239675Srwatson * Return 1 if the I/O is actually complete (success, or retry limit
341239675Srwatson * exceeded), or 0 if not.
342239675Srwatson */
343239675Srwatsonint
344239675Srwatsonaltera_sdcard_io_complete(struct altera_sdcard_softc *sc, uint16_t asr)
345239675Srwatson{
346239675Srwatson	struct bio *bp;
347239675Srwatson	uint16_t rr1, mask;
348239675Srwatson	int error;
349239675Srwatson
350239675Srwatson	ALTERA_SDCARD_LOCK_ASSERT(sc);
351239675Srwatson	KASSERT(!(asr & ALTERA_SDCARD_ASR_CMDINPROGRESS),
352239675Srwatson	    ("%s: still in progress", __func__));
353239675Srwatson	KASSERT(asr & ALTERA_SDCARD_ASR_CARDPRESENT,
354239675Srwatson	    ("%s: card removed", __func__));
355239675Srwatson
356239675Srwatson	bp = sc->as_currentbio;
357239675Srwatson
358239675Srwatson	/*-
359239675Srwatson	 * Handle I/O retries if an error is returned by the device.  Various
360239675Srwatson	 * quirks handled in the process:
361239675Srwatson	 *
362239675Srwatson	 * 1. ALTERA_SDCARD_ASR_CMDDATAERROR is ignored for BIO_WRITE.
363239675Srwatson	 * 2. ALTERA_SDCARD_RR1_COMMANDCRCFAILED is optionally ignored for
364239675Srwatson	 *    BIO_READ.
365239675Srwatson	 */
366239675Srwatson	error = 0;
367239675Srwatson	rr1 = altera_sdcard_read_rr1(sc);
368239675Srwatson	switch (bp->bio_cmd) {
369239675Srwatson	case BIO_READ:
370239675Srwatson		mask = ALTERA_SDCARD_RR1_ERRORMASK;
371239675Srwatson		if (altera_sdcard_ignore_crc_errors)
372239675Srwatson			mask &= ~ALTERA_SDCARD_RR1_COMMANDCRCFAILED;
373239675Srwatson		if (asr & ALTERA_SDCARD_ASR_CMDTIMEOUT)
374239675Srwatson			error = EIO;
375239675Srwatson		else if ((asr & ALTERA_SDCARD_ASR_CMDDATAERROR) &&
376239675Srwatson		    (rr1 & mask))
377239675Srwatson			error = EIO;
378239675Srwatson		else
379239675Srwatson			error = 0;
380239675Srwatson		break;
381239675Srwatson
382239675Srwatson	case BIO_WRITE:
383239675Srwatson		if (asr & ALTERA_SDCARD_ASR_CMDTIMEOUT)
384239675Srwatson			error = EIO;
385239675Srwatson		else
386239675Srwatson			error = 0;
387239675Srwatson		break;
388239675Srwatson
389239675Srwatson	default:
390239675Srwatson		break;
391239675Srwatson	}
392239675Srwatson	if (error) {
393257445Sbrooks		sc->as_retriesleft--;
394257445Sbrooks		if (sc->as_retriesleft == 0 || bootverbose)
395257445Sbrooks			device_printf(sc->as_dev, "%s: %s operation block %ju "
396257445Sbrooks			    "length %ju failed; asr 0x%08x (rr1: 0x%04x)%s\n",
397257445Sbrooks			    __func__, bp->bio_cmd == BIO_READ ? "BIO_READ" :
398257445Sbrooks			    (bp->bio_cmd == BIO_WRITE ? "BIO_WRITE" :
399257445Sbrooks			    "unknown"),
400257445Sbrooks			    bp->bio_pblkno, bp->bio_bcount, asr, rr1,
401257445Sbrooks			    sc->as_retriesleft != 0 ? " retrying" : "");
402239675Srwatson		/*
403239675Srwatson		 * This attempt experienced an error; possibly retry.
404239675Srwatson		 */
405239675Srwatson		if (sc->as_retriesleft != 0) {
406239675Srwatson			sc->as_flags |= ALTERA_SDCARD_FLAG_IOERROR;
407239675Srwatson			altera_sdcard_io_start_internal(sc, bp);
408239675Srwatson			return (0);
409239675Srwatson		}
410239675Srwatson		sc->as_flags &= ~ALTERA_SDCARD_FLAG_IOERROR;
411239675Srwatson	} else {
412239675Srwatson		/*
413239675Srwatson		 * Successful I/O completion path.
414239675Srwatson		 */
415239675Srwatson		if (sc->as_flags & ALTERA_SDCARD_FLAG_IOERROR) {
416239675Srwatson			device_printf(sc->as_dev, "%s: %s operation block %ju"
417239675Srwatson			    " length %ju succeeded after %d retries\n",
418239675Srwatson			    __func__, bp->bio_cmd == BIO_READ ? "BIO_READ" :
419239675Srwatson			    (bp->bio_cmd == BIO_WRITE ? "write" : "unknown"),
420239675Srwatson			    bp->bio_pblkno, bp->bio_bcount,
421239675Srwatson			    ALTERA_SDCARD_RETRY_LIMIT - sc->as_retriesleft);
422239675Srwatson			sc->as_flags &= ~ALTERA_SDCARD_FLAG_IOERROR;
423239675Srwatson		}
424239675Srwatson		switch (bp->bio_cmd) {
425239675Srwatson		case BIO_READ:
426239675Srwatson			altera_sdcard_read_rxtx_buffer(sc, bp->bio_data,
427239675Srwatson			    bp->bio_bcount);
428239675Srwatson			break;
429239675Srwatson
430239675Srwatson		case BIO_WRITE:
431239675Srwatson			break;
432239675Srwatson
433239675Srwatson		default:
434239675Srwatson			panic("%s: unsupported I/O operation %d", __func__,
435239675Srwatson			    bp->bio_cmd);
436239675Srwatson		}
437239675Srwatson		bp->bio_resid = 0;
438239675Srwatson		error = 0;
439239675Srwatson	}
440239675Srwatson	biofinish(bp, NULL, error);
441239675Srwatson	sc->as_currentbio = NULL;
442239675Srwatson	return (1);
443239675Srwatson}
444