4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * CDDL HEADER START
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * The contents of this file are subject to the terms of the
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Common Development and Distribution License (the "License").
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * You may not use this file except in compliance with the License.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * or http://www.opensolaris.org/os/licensing.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * See the License for the specific language governing permissions
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * and limitations under the License.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * CDDL HEADER END
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * SD card slot support.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Prototypes.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic void sda_slot_insert(void *);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic sda_err_t sda_slot_check_response(sda_cmd_t *);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic void sda_slot_handle_detect(sda_slot_t *);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic void sda_slot_handle_transfer(sda_slot_t *, sda_err_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic void sda_slot_handle_fault(sda_slot_t *, sda_fault_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic void sda_slot_abort(sda_slot_t *, sda_err_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic void sda_slot_thread(void *);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic void sda_slot_vprintf(sda_slot_t *, int, const char *, va_list);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Static Variables.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic struct {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore { SDA_FAULT_TIMEOUT, "Data transfer timed out" },
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore { SDA_FAULT_CRC7, "CRC7 failure on CMD/DAT line" },
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore { SDA_FAULT_PROTO, "SD/MMC protocol signaling error" },
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore { SDA_FAULT_INIT, "Card initialization failure" },
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore { SDA_FAULT_HOST, "Internal host or slot failure" },
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore { SDA_FAULT_CURRENT, "Current overlimit detected" },
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore { SDA_FAULT_RESET, "Failed to reset slot" },
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore { SDA_FAULT_NONE, NULL }, /* sentinel, must be last! */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Internal implementation.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * These allow for recursive entry. This is necessary to facilitate
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * simpler locking with things like the fault handler, where a caller
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * might already be "holding" the slot.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * This is modeled in part after ndi_devi_enter and ndi_devi_exit.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore while ((slot->s_owner != 0) && (slot->s_owner != self)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((errs = (cmdp->sc_response[0] & R1_ERRS)) != 0) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (errs & (R1_WP_VIOLATION | R1_CSD_OVERWRITE)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (errs & (R1_ADDRESS_ERROR | R1_BLOCK_LEN_ERROR |
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((errs = (cmdp->sc_response[0] & R5_ERRS)) != 0) {
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore /* We need to wait 1 msec for power down. */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (slot->s_ops.so_reset(slot->s_prv) != 0) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Get the voltage supplied by the host. Note that we expect
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * hosts will include a range of 2.7-3.7 in their supported
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * voltage ranges. The spec does not allow for hosts that
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * cannot supply a voltage in this range, yet.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((rv = sda_getprop(slot, SDA_PROP_OCR, &ocr)) != 0) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_slot_err(slot, "Failed to get host OCR (%d)", rv);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_slot_err(slot, "Host does not support standard voltages.");
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * We prefer 3.3V, 3.0V, and failing that, just use the
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * maximum that the host supports. 3.3V is preferable,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * because it is the typical common voltage that just about
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * everything supports. Otherwise we just pick the highest
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * supported voltage. This facilitates initial power up.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore slot->s_cur_ocr = (1U << (ddi_fls(ocr) - 1));
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Turn on the power.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((rv = sda_setprop(slot, SDA_PROP_OCR, slot->s_cur_ocr)) != 0) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_slot_err(slot, "Failed to set OCR %x (%d)",
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Wait 250 msec (per spec) for power ramp to complete.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* XXX: FMA: on failure this should cause a fault to be generated */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* spec requires voltage to stay low for at least 1 msec */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Remove power from the slot. If a more severe fault
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * occurred, then a manual reset with cfgadm will be needed.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_slot_err(slot, "Unable to initialize card!");
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore } else if ((slot->s_flags & SLOTF_MEMORY) == 0) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * SDIO: For SDIO, we can write the card's
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * MANFID tuple in CIS to the UUID. Until we
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * support SDIO, we just suppress creating
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * devinfo nodes.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore sda_slot_err(slot, "Non-memory target not supported");
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if (sda_mem_parse_cid_csd(slot) != DDI_SUCCESS) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore "Unable to parse card identification");
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_slot_abort(sda_slot_t *slot, sda_err_t errno)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore while ((cmdp = list_head(&slot->s_cmdlist)) != NULL) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_slot_handle_transfer(sda_slot_t *slot, sda_err_t errno)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_slot_handle_fault(sda_slot_t *slot, sda_fault_t fault)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((fault == SDA_FAULT_TIMEOUT) && (slot->s_init)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Timeouts during initialization are quite normal.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore for (i = 0; sda_slot_faults[i].msg != NULL; i++) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * FMA would be a better choice here.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Shut down the slot. Interaction from userland via cfgadm
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * can revive it.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * FMA can help here.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_getprop(slot, SDA_PROP_INSERTED, &inserted);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * We need to initialize the card, so we only support
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * hipri commands for now.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Card insertion occurred. We have to run this on
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * another task, to avoid deadlock as the task may
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * need to dispatch commands.
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore (void) ddi_taskq_dispatch(slot->s_hp_tq, sda_slot_insert, slot,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Nuke in-flight commands.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Restart the slot (incl. power cycle). This gets the
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * slot to a known good state.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_slot_transfer(sda_slot_t *slot, sda_err_t errno)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_slot_fault(sda_slot_t *slot, sda_fault_t fault)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_init(&slot->s_lock, NULL, MUTEX_DRIVER, NULL);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cv_init(&slot->s_cv, NULL, CV_DRIVER, NULL);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_init(&slot->s_evlock, NULL, MUTEX_DRIVER, NULL);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cv_init(&slot->s_evcv, NULL, CV_DRIVER, NULL);
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore * We have two taskqs. The first taskq is used for
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * card initialization.
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore * The second is used for the main processing loop.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * The reason for a separate taskq is that initialization
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * needs to acquire locks which may be held by the slot
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * thread, or by device driver context... use of the separate
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * taskq breaks the deadlock. Additionally, the
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * initialization task may need to sleep quite a while during
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * card initialization.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore slot->s_bdh = bd_alloc_handle(slot, &sda_bd_ops, h->h_dma, KM_SLEEP);
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore (void) snprintf(name, sizeof (name), "slot_%d_hp_tq",
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore slot->s_hp_tq = ddi_taskq_create(h->h_dip, name, 1,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* Generally, this failure should never occur */
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore sda_slot_err(slot, "Unable to create hotplug slot taskq");
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* create the main processing thread */
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore (void) snprintf(name, sizeof (name), "slot_%d_main_tq",
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore slot->s_main_tq = ddi_taskq_create(h->h_dip, name, 1,
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore /* Generally, this failure should never occur */
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore sda_slot_err(slot, "Unable to create main slot taskq");
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore (void) ddi_taskq_dispatch(slot->s_main_tq, sda_slot_thread, slot,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Determine slot capabilities.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((sda_getprop(slot, SDA_PROP_CAP_NOPIO, &cap) == 0) && (cap != 0)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((sda_getprop(slot, SDA_PROP_CAP_4BITS, &cap) == 0) && (cap != 0)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((sda_getprop(slot, SDA_PROP_CAP_HISPEED, &cap) == 0) &&
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* make sure that the host is started up */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (slot->s_ops.so_reset(slot->s_prv) != 0) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore (void) bd_attach_handle(h->h_dip, slot->s_bdh);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Shut down the thread.
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore * Nuke the taskqs. We do this after stopping the background
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore * thread to avoid deadlock.
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore * A card change event may have occurred, and in any case we need
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore * to reinitialize the card.
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore /* Start up a new instance of the main processing task. */
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore (void) ddi_taskq_dispatch(slot->s_main_tq, sda_slot_thread, slot,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Process any abort list first.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((cmdp = list_head(&slot->s_abortlist)) != NULL) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * EOK used here, to avoid clobbering previous
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * error code.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_cmd_notify(cmdp, SDA_CMDF_BUSY | SDA_CMDF_DAT,
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore /* Parent is detaching the slot, bail out. */
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore if ((slot->s_suspend) && (slot->s_xfrp == NULL)) {
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore * Host wants to suspend, but don't do it if
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore * we have a transfer outstanding.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((slot->s_xfrp != NULL) && (gethrtime() > slot->s_xfrtmo)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * The device stalled processing the data request.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * At this point, we really have no choice but to
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * nuke the request, and flag a fault.
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore * If the slot has suspended, then we can't process
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore * any new commands yet.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * We use a timed wait if we are waiting for a
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * data transfer to complete. Otherwise we
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * avoid the timed wait to avoid waking CPU
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * (power savings.)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((slot->s_xfrp != NULL) || (slot->s_reap)) {
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore /* Wait 3 sec (reap attempts). */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (void) cv_wait(&slot->s_evcv, &slot->s_evlock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * We're awake now, so look for work to do. First
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * acquire access to the slot.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * If no more commands to process, go back to sleep.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((cmdp = list_head(&slot->s_cmdlist)) == NULL) {
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore * If the current command is not an initialization
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore * command, but we are initializing, go back to sleep.
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore * (This happens potentially during a card reset or
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore * suspend/resume cycle, where the card has not been
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore * removed, but a reset is in progress.)
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore if (slot->s_init && !(cmdp->sc_flags & SDA_CMDF_INIT)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore datline = ((cmdp->sc_flags & SDA_CMDF_DAT) != 0);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * If the current command has a data phase
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * while a transfer is in progress, then go
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * back to sleep.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Note that APP_CMD doesn't have a data phase,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * although the associated ACMD might.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * All commands should complete in
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * less than 5 seconds. The worst
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * case is actually somewhere around 4
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * seconds, but that is when the clock
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * is only 100 kHz.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore 5000000000ULL;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * We're committed to dispatching this command now,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * so remove it from the list.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * There could be more commands after this one, so we
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * mark ourself so we stay awake for another cycle.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Submit the command. Note that we are holding the
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * slot lock here, so it is critical that the caller
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * *not* call back up into the framework. The caller
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * must break context. But doing it this way prevents
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * a critical race on card removal.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Note that we don't resubmit memory to the device if
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * it isn't flagged as ready (e.g. if the wrong device
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * was inserted!)
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore if ((!slot->s_ready) && (cmdp->sc_flags & SDA_CMDF_MEM)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * If APP_CMD completed properly, then
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * resubmit with ACMD index. Note wake was
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * already set above.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((cmdp->sc_response[0] & R1_APP_CMD) == 0) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * If an error occurred and we were expecting
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * a transfer phase, we have to clean up.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * And notify any waiter.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_cmd_notify(cmdp, SDA_CMDF_BUSY | SDA_CMDF_DAT, rv);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Wake any waiter.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_slot_vprintf(sda_slot_t *s, int level, const char *fmt, va_list ap)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ddi_driver_name(dip), ddi_get_instance(dip),
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (void) snprintf(msgbuf, sizeof (msgbuf), "%ssda: %s%s",
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_slot_err(sda_slot_t *s, const char *fmt, ...)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_slot_log(sda_slot_t *s, const char *fmt, ...)