4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore/*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * CDDL HEADER START
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *
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 *
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 *
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 *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * CDDL HEADER END
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore/*
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore/*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * SD card common framework. This module provides most of the common
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * functionality so that SecureDigital host adapters and client devices
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * (such as the sdcard driver) can share common code.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#include <sys/types.h>
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#include <sys/kmem.h>
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#include <sys/sysmacros.h>
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#include <sys/ddi.h>
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#include <sys/sunddi.h>
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#include <sys/sunndi.h>
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#include <sys/sdcard/sda_impl.h>
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore/*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Types and Structures.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoretypedef struct sda_cmd_impl {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore struct sda_cmd c_public;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Implementation private stuff.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_slot_t *c_slot;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore kmutex_t c_lock;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore kcondvar_t c_cv;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore list_node_t c_list;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_err_t c_errno;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_index_t c_acmd; /* saved acmd */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_rtype_t c_artype; /* saved rtype */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint32_t c_aarg; /* saved argument */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore void (*c_done)(struct sda_cmd *);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore void *c_private;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore} sda_cmd_impl_t;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define c_index c_public.sc_index
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define c_argument c_public.sc_argument
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define c_rtype c_public.sc_rtype
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define c_response c_public.sc_response
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define c_blksz c_public.sc_blksz
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define c_nblks c_public.sc_nblks
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define c_resid c_public.sc_resid
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define c_flags c_public.sc_flags
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define c_ndmac c_public.sc_ndmac
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore#define c_dmah c_public.sc_dmah
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore#define c_dmac c_public.sc_dmac
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define c_kvaddr c_public.sc_kvaddr
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore/*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Local Prototypes.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic void sda_cmd_wait(sda_cmd_t *);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic int sda_cmd_ctor(void *, void *, int);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic void sda_cmd_dtor(void *, void *);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore/*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Static Variables.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic kmem_cache_t *sda_cmd_cache;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore/*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Macros.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define CIP(cmdp) ((sda_cmd_impl_t *)(void *)cmdp)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore/*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Implementation.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorevoid
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_cmd_init(void)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_cmd_cache = kmem_cache_create("sda_cmd_cache",
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sizeof (struct sda_cmd_impl), 0, sda_cmd_ctor, sda_cmd_dtor,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore NULL, NULL, NULL, 0);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorevoid
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_cmd_fini(void)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore kmem_cache_destroy(sda_cmd_cache);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorevoid
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_cmd_list_init(list_t *list)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore list_create(list, sizeof (struct sda_cmd_impl),
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore offsetof(struct sda_cmd_impl, c_list));
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorevoid
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_cmd_list_fini(list_t *list)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore list_destroy(list);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore/*ARGSUSED1*/
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoreint
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_cmd_ctor(void *cbuf, void *arg, int kmflags)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_cmd_impl_t *c = cbuf;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_init(&c->c_lock, NULL, MUTEX_DRIVER, NULL);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cv_init(&c->c_cv, NULL, CV_DRIVER, NULL);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (0);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore/*ARGSUSED1*/
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorevoid
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_cmd_dtor(void *cbuf, void *arg)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_cmd_impl_t *c = cbuf;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cv_destroy(&c->c_cv);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_destroy(&c->c_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorevoid *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_cmd_data(sda_cmd_t *cmdp)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (CIP(cmdp)->c_private);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_err_t
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_cmd_errno(sda_cmd_t *cmdp)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (CIP(cmdp)->c_errno);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorevoid
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_cmd_notify(sda_cmd_t *cmdp, uint16_t flags, sda_err_t errno)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_cmd_impl_t *c = CIP(cmdp);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Now we need to make sure that we wake anyone waiting on this
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * command to complete, if it is complete.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_enter(&c->c_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_flags &= ~(flags);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Don't overwrite an earlier error.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (c->c_errno == SDA_EOK) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_errno = errno;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((c->c_flags & (SDA_CMDF_BUSY | SDA_CMDF_DAT)) == 0) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (c->c_done != NULL) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&c->c_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_done(cmdp);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore } else {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cv_broadcast(&c->c_cv);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&c->c_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore } else {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&c->c_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorevoid
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_cmd_wait(sda_cmd_t *cmdp)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_cmd_impl_t *c = CIP(cmdp);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_enter(&c->c_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore while ((c->c_flags & (SDA_CMDF_BUSY | SDA_CMDF_DAT)) != 0)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cv_wait(&c->c_cv, &c->c_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&c->c_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorevoid
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_cmd_submit(sda_slot_t *slot, sda_cmd_t *cmdp, void (*done)(sda_cmd_t *))
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_cmd_impl_t *c = CIP(cmdp);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_err_t errno = 0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_enter(&c->c_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_done = done;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_flags |= SDA_CMDF_BUSY;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&c->c_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_slot_enter(slot);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* checks for cases where the slot can't accept the command */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (slot->s_failed) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore errno = SDA_EFAULT;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (!slot->s_inserted) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore errno = SDA_ENODEV;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (errno != SDA_EOK) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore /*
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * We have to return failure conditions asynchronously.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * What we do in this case is mark the command failed,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * and move it to the abortlist so that the slot thread
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * will execute the failure notification asynchronously.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore *
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * NB: using 0 for flags ensures that we don't execute
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * the notification callback yet, we're just stashing
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * the errno.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore sda_cmd_notify(cmdp, 0, errno);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore list_insert_tail(&slot->s_abortlist, cmdp);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore } else if (c->c_flags & SDA_CMDF_INIT) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore /* Initialization commands go to the head of the class */
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore list_insert_head(&slot->s_cmdlist, c);
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore } else {
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore list_insert_tail(&slot->s_cmdlist, c);
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_slot_exit(slot);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_slot_wakeup(slot);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorevoid
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_cmd_resubmit_acmd(sda_slot_t *slot, sda_cmd_t *cmdp)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_cmd_impl_t *c = CIP(cmdp);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ASSERT(sda_slot_owned(slot));
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_index = c->c_acmd;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_argument = c->c_aarg;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_rtype = c->c_artype;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_acmd = 0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore list_insert_head(&slot->s_cmdlist, c);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_cmd_t *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_cmd_alloc(sda_slot_t *slot, sda_index_t index, uint32_t argument,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_rtype_t rtype, void *data, int kmflag)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_cmd_impl_t *c;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c = kmem_cache_alloc(sda_cmd_cache, kmflag);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (c == NULL) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (NULL);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_index = index;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_rtype = rtype;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_argument = argument;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_resid = 0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_nblks = 0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_blksz = 0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_kvaddr = 0;
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore c->c_dmah = 0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_ndmac = 0;
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore c->c_dmah = NULL;
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore bzero(&c->c_dmac, sizeof (c->c_dmac));
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_flags = 0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_slot = slot;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_errno = SDA_EOK;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_done = NULL;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_private = data;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_acmd = 0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (&(c->c_public));
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_cmd_t *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_cmd_alloc_acmd(sda_slot_t *slot, sda_index_t index, uint32_t argument,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_rtype_t rtype, void *data, int kmflag)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_cmd_impl_t *c;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c = kmem_cache_alloc(sda_cmd_cache, kmflag);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (c == NULL) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (NULL);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_index = CMD_APP_CMD;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_argument = index == ACMD_SD_SEND_OCR ? 0 : slot->s_rca << 16;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_rtype = R1;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_acmd = index;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_artype = rtype;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_aarg = argument;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_resid = 0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_nblks = 0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_blksz = 0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_kvaddr = 0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_ndmac = 0;
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore c->c_dmah = NULL;
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore bzero(&c->c_dmac, sizeof (c->c_dmac));
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_flags = 0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_slot = slot;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_errno = SDA_EOK;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_done = NULL;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore c->c_private = data;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (&(c->c_public));
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorevoid
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_cmd_free(sda_cmd_t *cmdp)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore kmem_cache_free(sda_cmd_cache, cmdp);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_err_t
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_cmd_exec(sda_slot_t *slot, sda_cmd_t *cmdp, uint32_t *resp)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int errno;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((cmdp->sc_rtype & Rb) || (cmdp->sc_nblks != 0)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cmdp->sc_flags |= SDA_CMDF_DAT;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_cmd_submit(slot, cmdp, NULL);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_cmd_wait(cmdp);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (resp != NULL) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore switch (cmdp->sc_rtype) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case R0:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case R2:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore resp[0] = cmdp->sc_response[0];
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore resp[1] = cmdp->sc_response[1];
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore resp[2] = cmdp->sc_response[2];
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore resp[3] = cmdp->sc_response[3];
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore default:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore resp[0] = cmdp->sc_response[0];
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore errno = CIP(cmdp)->c_errno;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (errno);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}