14bb7efa7SGarrett D'Amore /*
24bb7efa7SGarrett D'Amore  * CDDL HEADER START
34bb7efa7SGarrett D'Amore  *
44bb7efa7SGarrett D'Amore  * The contents of this file are subject to the terms of the
54bb7efa7SGarrett D'Amore  * Common Development and Distribution License (the "License").
64bb7efa7SGarrett D'Amore  * You may not use this file except in compliance with the License.
74bb7efa7SGarrett D'Amore  *
84bb7efa7SGarrett D'Amore  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94bb7efa7SGarrett D'Amore  * or http://www.opensolaris.org/os/licensing.
104bb7efa7SGarrett D'Amore  * See the License for the specific language governing permissions
114bb7efa7SGarrett D'Amore  * and limitations under the License.
124bb7efa7SGarrett D'Amore  *
134bb7efa7SGarrett D'Amore  * When distributing Covered Code, include this CDDL HEADER in each
144bb7efa7SGarrett D'Amore  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154bb7efa7SGarrett D'Amore  * If applicable, add the following below this CDDL HEADER, with the
164bb7efa7SGarrett D'Amore  * fields enclosed by brackets "[]" replaced with your own identifying
174bb7efa7SGarrett D'Amore  * information: Portions Copyright [yyyy] [name of copyright owner]
184bb7efa7SGarrett D'Amore  *
194bb7efa7SGarrett D'Amore  * CDDL HEADER END
204bb7efa7SGarrett D'Amore  */
214bb7efa7SGarrett D'Amore /*
22*3f7d54a6SGarrett D'Amore  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
234bb7efa7SGarrett D'Amore  */
244bb7efa7SGarrett D'Amore 
254bb7efa7SGarrett D'Amore /*
264bb7efa7SGarrett D'Amore  * SD card common framework.  This module provides most of the common
274bb7efa7SGarrett D'Amore  * functionality so that SecureDigital host adapters and client devices
284bb7efa7SGarrett D'Amore  * (such as the sdcard driver) can share common code.
294bb7efa7SGarrett D'Amore  */
304bb7efa7SGarrett D'Amore 
314bb7efa7SGarrett D'Amore #include <sys/types.h>
324bb7efa7SGarrett D'Amore #include <sys/kmem.h>
334bb7efa7SGarrett D'Amore #include <sys/sysmacros.h>
344bb7efa7SGarrett D'Amore #include <sys/ddi.h>
354bb7efa7SGarrett D'Amore #include <sys/sunddi.h>
364bb7efa7SGarrett D'Amore #include <sys/sunndi.h>
374bb7efa7SGarrett D'Amore #include <sys/sdcard/sda_impl.h>
384bb7efa7SGarrett D'Amore 
394bb7efa7SGarrett D'Amore /*
404bb7efa7SGarrett D'Amore  * Types and Structures.
414bb7efa7SGarrett D'Amore  */
424bb7efa7SGarrett D'Amore 
434bb7efa7SGarrett D'Amore typedef struct sda_cmd_impl {
444bb7efa7SGarrett D'Amore 	struct sda_cmd	c_public;
454bb7efa7SGarrett D'Amore 
464bb7efa7SGarrett D'Amore 	/*
474bb7efa7SGarrett D'Amore 	 * Implementation private stuff.
484bb7efa7SGarrett D'Amore 	 */
494bb7efa7SGarrett D'Amore 	sda_slot_t	*c_slot;
504bb7efa7SGarrett D'Amore 	kmutex_t	c_lock;
514bb7efa7SGarrett D'Amore 	kcondvar_t	c_cv;
524bb7efa7SGarrett D'Amore 	list_node_t	c_list;
534bb7efa7SGarrett D'Amore 	sda_err_t	c_errno;
544bb7efa7SGarrett D'Amore 
554bb7efa7SGarrett D'Amore 	sda_index_t	c_acmd;		/* saved acmd */
564bb7efa7SGarrett D'Amore 	sda_rtype_t	c_artype;	/* saved rtype */
574bb7efa7SGarrett D'Amore 	uint32_t	c_aarg;		/* saved argument */
584bb7efa7SGarrett D'Amore 
594bb7efa7SGarrett D'Amore 	void		(*c_done)(struct sda_cmd *);
604bb7efa7SGarrett D'Amore 	void		*c_private;
614bb7efa7SGarrett D'Amore } sda_cmd_impl_t;
624bb7efa7SGarrett D'Amore 
634bb7efa7SGarrett D'Amore #define	c_index		c_public.sc_index
644bb7efa7SGarrett D'Amore #define	c_argument	c_public.sc_argument
654bb7efa7SGarrett D'Amore #define	c_rtype		c_public.sc_rtype
664bb7efa7SGarrett D'Amore #define	c_response	c_public.sc_response
674bb7efa7SGarrett D'Amore #define	c_blksz		c_public.sc_blksz
684bb7efa7SGarrett D'Amore #define	c_nblks		c_public.sc_nblks
694bb7efa7SGarrett D'Amore #define	c_resid		c_public.sc_resid
704bb7efa7SGarrett D'Amore #define	c_flags		c_public.sc_flags
714bb7efa7SGarrett D'Amore #define	c_ndmac		c_public.sc_ndmac
72*3f7d54a6SGarrett D'Amore #define	c_dmah		c_public.sc_dmah
73*3f7d54a6SGarrett D'Amore #define	c_dmac		c_public.sc_dmac
744bb7efa7SGarrett D'Amore #define	c_kvaddr	c_public.sc_kvaddr
754bb7efa7SGarrett D'Amore 
764bb7efa7SGarrett D'Amore /*
774bb7efa7SGarrett D'Amore  * Local Prototypes.
784bb7efa7SGarrett D'Amore  */
794bb7efa7SGarrett D'Amore 
804bb7efa7SGarrett D'Amore static void sda_cmd_wait(sda_cmd_t *);
814bb7efa7SGarrett D'Amore static int sda_cmd_ctor(void *, void *, int);
824bb7efa7SGarrett D'Amore static void sda_cmd_dtor(void *, void *);
834bb7efa7SGarrett D'Amore 
844bb7efa7SGarrett D'Amore /*
854bb7efa7SGarrett D'Amore  * Static Variables.
864bb7efa7SGarrett D'Amore  */
874bb7efa7SGarrett D'Amore 
884bb7efa7SGarrett D'Amore static kmem_cache_t *sda_cmd_cache;
894bb7efa7SGarrett D'Amore 
904bb7efa7SGarrett D'Amore /*
914bb7efa7SGarrett D'Amore  * Macros.
924bb7efa7SGarrett D'Amore  */
934bb7efa7SGarrett D'Amore 
944bb7efa7SGarrett D'Amore #define	CIP(cmdp)	((sda_cmd_impl_t *)(void *)cmdp)
954bb7efa7SGarrett D'Amore 
964bb7efa7SGarrett D'Amore /*
974bb7efa7SGarrett D'Amore  * Implementation.
984bb7efa7SGarrett D'Amore  */
994bb7efa7SGarrett D'Amore 
1004bb7efa7SGarrett D'Amore void
sda_cmd_init(void)1014bb7efa7SGarrett D'Amore sda_cmd_init(void)
1024bb7efa7SGarrett D'Amore {
1034bb7efa7SGarrett D'Amore 	sda_cmd_cache = kmem_cache_create("sda_cmd_cache",
1044bb7efa7SGarrett D'Amore 	    sizeof (struct sda_cmd_impl), 0, sda_cmd_ctor, sda_cmd_dtor,
1054bb7efa7SGarrett D'Amore 	    NULL, NULL, NULL, 0);
1064bb7efa7SGarrett D'Amore }
1074bb7efa7SGarrett D'Amore 
1084bb7efa7SGarrett D'Amore void
sda_cmd_fini(void)1094bb7efa7SGarrett D'Amore sda_cmd_fini(void)
1104bb7efa7SGarrett D'Amore {
1114bb7efa7SGarrett D'Amore 	kmem_cache_destroy(sda_cmd_cache);
1124bb7efa7SGarrett D'Amore }
1134bb7efa7SGarrett D'Amore 
1144bb7efa7SGarrett D'Amore void
sda_cmd_list_init(list_t * list)1154bb7efa7SGarrett D'Amore sda_cmd_list_init(list_t *list)
1164bb7efa7SGarrett D'Amore {
1174bb7efa7SGarrett D'Amore 	list_create(list, sizeof (struct sda_cmd_impl),
1184bb7efa7SGarrett D'Amore 	    offsetof(struct sda_cmd_impl, c_list));
1194bb7efa7SGarrett D'Amore }
1204bb7efa7SGarrett D'Amore 
1214bb7efa7SGarrett D'Amore void
sda_cmd_list_fini(list_t * list)1224bb7efa7SGarrett D'Amore sda_cmd_list_fini(list_t *list)
1234bb7efa7SGarrett D'Amore {
1244bb7efa7SGarrett D'Amore 	list_destroy(list);
1254bb7efa7SGarrett D'Amore }
1264bb7efa7SGarrett D'Amore 
1274bb7efa7SGarrett D'Amore /*ARGSUSED1*/
1284bb7efa7SGarrett D'Amore int
sda_cmd_ctor(void * cbuf,void * arg,int kmflags)1294bb7efa7SGarrett D'Amore sda_cmd_ctor(void *cbuf, void *arg, int kmflags)
1304bb7efa7SGarrett D'Amore {
1314bb7efa7SGarrett D'Amore 	sda_cmd_impl_t	*c = cbuf;
1324bb7efa7SGarrett D'Amore 
1334bb7efa7SGarrett D'Amore 	mutex_init(&c->c_lock, NULL, MUTEX_DRIVER, NULL);
1344bb7efa7SGarrett D'Amore 	cv_init(&c->c_cv, NULL, CV_DRIVER, NULL);
1354bb7efa7SGarrett D'Amore 	return (0);
1364bb7efa7SGarrett D'Amore }
1374bb7efa7SGarrett D'Amore 
1384bb7efa7SGarrett D'Amore /*ARGSUSED1*/
1394bb7efa7SGarrett D'Amore void
sda_cmd_dtor(void * cbuf,void * arg)1404bb7efa7SGarrett D'Amore sda_cmd_dtor(void *cbuf, void *arg)
1414bb7efa7SGarrett D'Amore {
1424bb7efa7SGarrett D'Amore 	sda_cmd_impl_t	*c = cbuf;
1434bb7efa7SGarrett D'Amore 
1444bb7efa7SGarrett D'Amore 	cv_destroy(&c->c_cv);
1454bb7efa7SGarrett D'Amore 	mutex_destroy(&c->c_lock);
1464bb7efa7SGarrett D'Amore }
1474bb7efa7SGarrett D'Amore 
1484bb7efa7SGarrett D'Amore void *
sda_cmd_data(sda_cmd_t * cmdp)1494bb7efa7SGarrett D'Amore sda_cmd_data(sda_cmd_t *cmdp)
1504bb7efa7SGarrett D'Amore {
1514bb7efa7SGarrett D'Amore 	return (CIP(cmdp)->c_private);
1524bb7efa7SGarrett D'Amore }
1534bb7efa7SGarrett D'Amore 
1544bb7efa7SGarrett D'Amore sda_err_t
sda_cmd_errno(sda_cmd_t * cmdp)1554bb7efa7SGarrett D'Amore sda_cmd_errno(sda_cmd_t *cmdp)
1564bb7efa7SGarrett D'Amore {
1574bb7efa7SGarrett D'Amore 	return (CIP(cmdp)->c_errno);
1584bb7efa7SGarrett D'Amore }
1594bb7efa7SGarrett D'Amore 
1604bb7efa7SGarrett D'Amore void
sda_cmd_notify(sda_cmd_t * cmdp,uint16_t flags,sda_err_t errno)1614bb7efa7SGarrett D'Amore sda_cmd_notify(sda_cmd_t *cmdp, uint16_t flags, sda_err_t errno)
1624bb7efa7SGarrett D'Amore {
1634bb7efa7SGarrett D'Amore 	sda_cmd_impl_t	*c = CIP(cmdp);
1644bb7efa7SGarrett D'Amore 
1654bb7efa7SGarrett D'Amore 	/*
1664bb7efa7SGarrett D'Amore 	 * Now we need to make sure that we wake anyone waiting on this
1674bb7efa7SGarrett D'Amore 	 * command to complete, if it is complete.
1684bb7efa7SGarrett D'Amore 	 */
1694bb7efa7SGarrett D'Amore 	mutex_enter(&c->c_lock);
1704bb7efa7SGarrett D'Amore 	c->c_flags &= ~(flags);
1714bb7efa7SGarrett D'Amore 	/*
1724bb7efa7SGarrett D'Amore 	 * Don't overwrite an earlier error.
1734bb7efa7SGarrett D'Amore 	 */
1744bb7efa7SGarrett D'Amore 	if (c->c_errno == SDA_EOK) {
1754bb7efa7SGarrett D'Amore 		c->c_errno = errno;
1764bb7efa7SGarrett D'Amore 	}
1774bb7efa7SGarrett D'Amore 	if ((c->c_flags & (SDA_CMDF_BUSY | SDA_CMDF_DAT)) == 0) {
1784bb7efa7SGarrett D'Amore 
1794bb7efa7SGarrett D'Amore 		if (c->c_done != NULL) {
1804bb7efa7SGarrett D'Amore 			mutex_exit(&c->c_lock);
1814bb7efa7SGarrett D'Amore 			c->c_done(cmdp);
1824bb7efa7SGarrett D'Amore 		} else {
1834bb7efa7SGarrett D'Amore 			cv_broadcast(&c->c_cv);
1844bb7efa7SGarrett D'Amore 			mutex_exit(&c->c_lock);
1854bb7efa7SGarrett D'Amore 		}
1864bb7efa7SGarrett D'Amore 	} else {
1874bb7efa7SGarrett D'Amore 		mutex_exit(&c->c_lock);
1884bb7efa7SGarrett D'Amore 	}
1894bb7efa7SGarrett D'Amore }
1904bb7efa7SGarrett D'Amore 
1914bb7efa7SGarrett D'Amore void
sda_cmd_wait(sda_cmd_t * cmdp)1924bb7efa7SGarrett D'Amore sda_cmd_wait(sda_cmd_t *cmdp)
1934bb7efa7SGarrett D'Amore {
1944bb7efa7SGarrett D'Amore 	sda_cmd_impl_t	*c = CIP(cmdp);
1954bb7efa7SGarrett D'Amore 
1964bb7efa7SGarrett D'Amore 	mutex_enter(&c->c_lock);
1974bb7efa7SGarrett D'Amore 	while ((c->c_flags & (SDA_CMDF_BUSY | SDA_CMDF_DAT)) != 0)
1984bb7efa7SGarrett D'Amore 		cv_wait(&c->c_cv, &c->c_lock);
1994bb7efa7SGarrett D'Amore 	mutex_exit(&c->c_lock);
2004bb7efa7SGarrett D'Amore }
2014bb7efa7SGarrett D'Amore 
2024bb7efa7SGarrett D'Amore void
sda_cmd_submit(sda_slot_t * slot,sda_cmd_t * cmdp,void (* done)(sda_cmd_t *))2034bb7efa7SGarrett D'Amore sda_cmd_submit(sda_slot_t *slot, sda_cmd_t *cmdp, void (*done)(sda_cmd_t *))
2044bb7efa7SGarrett D'Amore {
2054bb7efa7SGarrett D'Amore 	sda_cmd_impl_t	*c = CIP(cmdp);
2064bb7efa7SGarrett D'Amore 	sda_err_t	errno = 0;
2074bb7efa7SGarrett D'Amore 
2084bb7efa7SGarrett D'Amore 	mutex_enter(&c->c_lock);
2094bb7efa7SGarrett D'Amore 	c->c_done = done;
2104bb7efa7SGarrett D'Amore 	c->c_flags |= SDA_CMDF_BUSY;
2114bb7efa7SGarrett D'Amore 	mutex_exit(&c->c_lock);
2124bb7efa7SGarrett D'Amore 
2134bb7efa7SGarrett D'Amore 	sda_slot_enter(slot);
2144bb7efa7SGarrett D'Amore 
2154bb7efa7SGarrett D'Amore 	/* checks for cases where the slot can't accept the command */
2164bb7efa7SGarrett D'Amore 	if (slot->s_failed) {
2174bb7efa7SGarrett D'Amore 		errno = SDA_EFAULT;
2184bb7efa7SGarrett D'Amore 	}
2194bb7efa7SGarrett D'Amore 	if (!slot->s_inserted) {
2204bb7efa7SGarrett D'Amore 		errno = SDA_ENODEV;
2214bb7efa7SGarrett D'Amore 	}
2224bb7efa7SGarrett D'Amore 	if (errno != SDA_EOK) {
223*3f7d54a6SGarrett D'Amore 		/*
224*3f7d54a6SGarrett D'Amore 		 * We have to return failure conditions asynchronously.
225*3f7d54a6SGarrett D'Amore 		 * What we do in this case is mark the command failed,
226*3f7d54a6SGarrett D'Amore 		 * and move it to the abortlist so that the slot thread
227*3f7d54a6SGarrett D'Amore 		 * will execute the failure notification asynchronously.
228*3f7d54a6SGarrett D'Amore 		 *
229*3f7d54a6SGarrett D'Amore 		 * NB: using 0 for flags ensures that we don't execute
230*3f7d54a6SGarrett D'Amore 		 * the notification callback yet, we're just stashing
231*3f7d54a6SGarrett D'Amore 		 * the errno.
232*3f7d54a6SGarrett D'Amore 		 */
233*3f7d54a6SGarrett D'Amore 		sda_cmd_notify(cmdp, 0, errno);
234*3f7d54a6SGarrett D'Amore 		list_insert_tail(&slot->s_abortlist, cmdp);
235*3f7d54a6SGarrett D'Amore 
236*3f7d54a6SGarrett D'Amore 	} else if (c->c_flags & SDA_CMDF_INIT) {
237*3f7d54a6SGarrett D'Amore 		/* Initialization commands go to the head of the class */
238f2b90c3cSGarrett D'Amore 		list_insert_head(&slot->s_cmdlist, c);
239f2b90c3cSGarrett D'Amore 	} else {
240f2b90c3cSGarrett D'Amore 		list_insert_tail(&slot->s_cmdlist, c);
241f2b90c3cSGarrett D'Amore 	}
2424bb7efa7SGarrett D'Amore 	sda_slot_exit(slot);
2434bb7efa7SGarrett D'Amore 
2444bb7efa7SGarrett D'Amore 	sda_slot_wakeup(slot);
2454bb7efa7SGarrett D'Amore }
2464bb7efa7SGarrett D'Amore 
2474bb7efa7SGarrett D'Amore void
sda_cmd_resubmit_acmd(sda_slot_t * slot,sda_cmd_t * cmdp)2484bb7efa7SGarrett D'Amore sda_cmd_resubmit_acmd(sda_slot_t *slot, sda_cmd_t *cmdp)
2494bb7efa7SGarrett D'Amore {
2504bb7efa7SGarrett D'Amore 	sda_cmd_impl_t	*c = CIP(cmdp);
2514bb7efa7SGarrett D'Amore 
2524bb7efa7SGarrett D'Amore 	ASSERT(sda_slot_owned(slot));
2534bb7efa7SGarrett D'Amore 
2544bb7efa7SGarrett D'Amore 	c->c_index = c->c_acmd;
2554bb7efa7SGarrett D'Amore 	c->c_argument = c->c_aarg;
2564bb7efa7SGarrett D'Amore 	c->c_rtype = c->c_artype;
2574bb7efa7SGarrett D'Amore 	c->c_acmd = 0;
2584bb7efa7SGarrett D'Amore 
2594bb7efa7SGarrett D'Amore 	list_insert_head(&slot->s_cmdlist, c);
2604bb7efa7SGarrett D'Amore }
2614bb7efa7SGarrett D'Amore 
2624bb7efa7SGarrett D'Amore sda_cmd_t *
sda_cmd_alloc(sda_slot_t * slot,sda_index_t index,uint32_t argument,sda_rtype_t rtype,void * data,int kmflag)2634bb7efa7SGarrett D'Amore sda_cmd_alloc(sda_slot_t *slot, sda_index_t index, uint32_t argument,
2644bb7efa7SGarrett D'Amore     sda_rtype_t rtype, void *data, int kmflag)
2654bb7efa7SGarrett D'Amore {
2664bb7efa7SGarrett D'Amore 	sda_cmd_impl_t	*c;
2674bb7efa7SGarrett D'Amore 
2684bb7efa7SGarrett D'Amore 	c = kmem_cache_alloc(sda_cmd_cache, kmflag);
2694bb7efa7SGarrett D'Amore 	if (c == NULL) {
2704bb7efa7SGarrett D'Amore 		return (NULL);
2714bb7efa7SGarrett D'Amore 	}
2724bb7efa7SGarrett D'Amore 	c->c_index = index;
2734bb7efa7SGarrett D'Amore 	c->c_rtype = rtype;
2744bb7efa7SGarrett D'Amore 	c->c_argument = argument;
2754bb7efa7SGarrett D'Amore 	c->c_resid = 0;
2764bb7efa7SGarrett D'Amore 	c->c_nblks = 0;
2774bb7efa7SGarrett D'Amore 	c->c_blksz = 0;
2784bb7efa7SGarrett D'Amore 
2794bb7efa7SGarrett D'Amore 	c->c_kvaddr = 0;
280*3f7d54a6SGarrett D'Amore 	c->c_dmah = 0;
2814bb7efa7SGarrett D'Amore 	c->c_ndmac = 0;
282*3f7d54a6SGarrett D'Amore 	c->c_dmah = NULL;
283*3f7d54a6SGarrett D'Amore 	bzero(&c->c_dmac, sizeof (c->c_dmac));
2844bb7efa7SGarrett D'Amore 	c->c_flags = 0;
2854bb7efa7SGarrett D'Amore 
2864bb7efa7SGarrett D'Amore 	c->c_slot = slot;
2874bb7efa7SGarrett D'Amore 	c->c_errno = SDA_EOK;
2884bb7efa7SGarrett D'Amore 	c->c_done = NULL;
2894bb7efa7SGarrett D'Amore 	c->c_private = data;
2904bb7efa7SGarrett D'Amore 	c->c_acmd = 0;
2914bb7efa7SGarrett D'Amore 
2924bb7efa7SGarrett D'Amore 	return (&(c->c_public));
2934bb7efa7SGarrett D'Amore }
2944bb7efa7SGarrett D'Amore 
2954bb7efa7SGarrett D'Amore sda_cmd_t *
sda_cmd_alloc_acmd(sda_slot_t * slot,sda_index_t index,uint32_t argument,sda_rtype_t rtype,void * data,int kmflag)2964bb7efa7SGarrett D'Amore sda_cmd_alloc_acmd(sda_slot_t *slot, sda_index_t index, uint32_t argument,
2974bb7efa7SGarrett D'Amore     sda_rtype_t rtype, void *data, int kmflag)
2984bb7efa7SGarrett D'Amore {
2994bb7efa7SGarrett D'Amore 	sda_cmd_impl_t	*c;
3004bb7efa7SGarrett D'Amore 
3014bb7efa7SGarrett D'Amore 	c = kmem_cache_alloc(sda_cmd_cache, kmflag);
3024bb7efa7SGarrett D'Amore 	if (c == NULL) {
3034bb7efa7SGarrett D'Amore 		return (NULL);
3044bb7efa7SGarrett D'Amore 	}
3054bb7efa7SGarrett D'Amore 	c->c_index = CMD_APP_CMD;
3064bb7efa7SGarrett D'Amore 	c->c_argument = index == ACMD_SD_SEND_OCR ? 0 : slot->s_rca << 16;
3074bb7efa7SGarrett D'Amore 	c->c_rtype = R1;
3084bb7efa7SGarrett D'Amore 	c->c_acmd = index;
3094bb7efa7SGarrett D'Amore 	c->c_artype = rtype;
3104bb7efa7SGarrett D'Amore 	c->c_aarg = argument;
3114bb7efa7SGarrett D'Amore 	c->c_resid = 0;
3124bb7efa7SGarrett D'Amore 	c->c_nblks = 0;
3134bb7efa7SGarrett D'Amore 	c->c_blksz = 0;
3144bb7efa7SGarrett D'Amore 
3154bb7efa7SGarrett D'Amore 	c->c_kvaddr = 0;
3164bb7efa7SGarrett D'Amore 	c->c_ndmac = 0;
317*3f7d54a6SGarrett D'Amore 	c->c_dmah = NULL;
318*3f7d54a6SGarrett D'Amore 	bzero(&c->c_dmac, sizeof (c->c_dmac));
3194bb7efa7SGarrett D'Amore 	c->c_flags = 0;
3204bb7efa7SGarrett D'Amore 
3214bb7efa7SGarrett D'Amore 	c->c_slot = slot;
3224bb7efa7SGarrett D'Amore 	c->c_errno = SDA_EOK;
3234bb7efa7SGarrett D'Amore 	c->c_done = NULL;
3244bb7efa7SGarrett D'Amore 	c->c_private = data;
3254bb7efa7SGarrett D'Amore 
3264bb7efa7SGarrett D'Amore 	return (&(c->c_public));
3274bb7efa7SGarrett D'Amore }
3284bb7efa7SGarrett D'Amore 
3294bb7efa7SGarrett D'Amore void
sda_cmd_free(sda_cmd_t * cmdp)3304bb7efa7SGarrett D'Amore sda_cmd_free(sda_cmd_t *cmdp)
3314bb7efa7SGarrett D'Amore {
3324bb7efa7SGarrett D'Amore 	kmem_cache_free(sda_cmd_cache, cmdp);
3334bb7efa7SGarrett D'Amore }
3344bb7efa7SGarrett D'Amore 
3354bb7efa7SGarrett D'Amore sda_err_t
sda_cmd_exec(sda_slot_t * slot,sda_cmd_t * cmdp,uint32_t * resp)3364bb7efa7SGarrett D'Amore sda_cmd_exec(sda_slot_t *slot, sda_cmd_t *cmdp, uint32_t *resp)
3374bb7efa7SGarrett D'Amore {
3384bb7efa7SGarrett D'Amore 	int		errno;
3394bb7efa7SGarrett D'Amore 
3404bb7efa7SGarrett D'Amore 	if ((cmdp->sc_rtype & Rb) || (cmdp->sc_nblks != 0)) {
3414bb7efa7SGarrett D'Amore 		cmdp->sc_flags |= SDA_CMDF_DAT;
3424bb7efa7SGarrett D'Amore 	}
3434bb7efa7SGarrett D'Amore 	sda_cmd_submit(slot, cmdp,  NULL);
3444bb7efa7SGarrett D'Amore 
3454bb7efa7SGarrett D'Amore 	sda_cmd_wait(cmdp);
3464bb7efa7SGarrett D'Amore 
3474bb7efa7SGarrett D'Amore 	if (resp != NULL) {
3484bb7efa7SGarrett D'Amore 		switch (cmdp->sc_rtype) {
3494bb7efa7SGarrett D'Amore 		case R0:
3504bb7efa7SGarrett D'Amore 			break;
3514bb7efa7SGarrett D'Amore 		case R2:
3524bb7efa7SGarrett D'Amore 			resp[0] = cmdp->sc_response[0];
3534bb7efa7SGarrett D'Amore 			resp[1] = cmdp->sc_response[1];
3544bb7efa7SGarrett D'Amore 			resp[2] = cmdp->sc_response[2];
3554bb7efa7SGarrett D'Amore 			resp[3] = cmdp->sc_response[3];
3564bb7efa7SGarrett D'Amore 			break;
3574bb7efa7SGarrett D'Amore 		default:
3584bb7efa7SGarrett D'Amore 			resp[0] = cmdp->sc_response[0];
3594bb7efa7SGarrett D'Amore 			break;
3604bb7efa7SGarrett D'Amore 		}
3614bb7efa7SGarrett D'Amore 	}
3624bb7efa7SGarrett D'Amore 
3634bb7efa7SGarrett D'Amore 	errno = CIP(cmdp)->c_errno;
3644bb7efa7SGarrett D'Amore 
3654bb7efa7SGarrett D'Amore 	return (errno);
3664bb7efa7SGarrett D'Amore }
367