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