17302Sgdamore@opensolaris.org /*
27302Sgdamore@opensolaris.org * CDDL HEADER START
37302Sgdamore@opensolaris.org *
47302Sgdamore@opensolaris.org * The contents of this file are subject to the terms of the
57302Sgdamore@opensolaris.org * Common Development and Distribution License (the "License").
67302Sgdamore@opensolaris.org * You may not use this file except in compliance with the License.
77302Sgdamore@opensolaris.org *
87302Sgdamore@opensolaris.org * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97302Sgdamore@opensolaris.org * or http://www.opensolaris.org/os/licensing.
107302Sgdamore@opensolaris.org * See the License for the specific language governing permissions
117302Sgdamore@opensolaris.org * and limitations under the License.
127302Sgdamore@opensolaris.org *
137302Sgdamore@opensolaris.org * When distributing Covered Code, include this CDDL HEADER in each
147302Sgdamore@opensolaris.org * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157302Sgdamore@opensolaris.org * If applicable, add the following below this CDDL HEADER, with the
167302Sgdamore@opensolaris.org * fields enclosed by brackets "[]" replaced with your own identifying
177302Sgdamore@opensolaris.org * information: Portions Copyright [yyyy] [name of copyright owner]
187302Sgdamore@opensolaris.org *
197302Sgdamore@opensolaris.org * CDDL HEADER END
207302Sgdamore@opensolaris.org */
217302Sgdamore@opensolaris.org /*
22*12426Sgdamore@opensolaris.org * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
237302Sgdamore@opensolaris.org */
247302Sgdamore@opensolaris.org
257302Sgdamore@opensolaris.org /*
267302Sgdamore@opensolaris.org * SD card common framework. This module provides most of the common
277302Sgdamore@opensolaris.org * functionality so that SecureDigital host adapters and client devices
287302Sgdamore@opensolaris.org * (such as the sdcard driver) can share common code.
297302Sgdamore@opensolaris.org */
307302Sgdamore@opensolaris.org
317302Sgdamore@opensolaris.org #include <sys/types.h>
327302Sgdamore@opensolaris.org #include <sys/kmem.h>
337302Sgdamore@opensolaris.org #include <sys/sysmacros.h>
347302Sgdamore@opensolaris.org #include <sys/ddi.h>
357302Sgdamore@opensolaris.org #include <sys/sunddi.h>
367302Sgdamore@opensolaris.org #include <sys/sunndi.h>
377302Sgdamore@opensolaris.org #include <sys/sdcard/sda_impl.h>
387302Sgdamore@opensolaris.org
397302Sgdamore@opensolaris.org /*
407302Sgdamore@opensolaris.org * Types and Structures.
417302Sgdamore@opensolaris.org */
427302Sgdamore@opensolaris.org
437302Sgdamore@opensolaris.org typedef struct sda_cmd_impl {
447302Sgdamore@opensolaris.org struct sda_cmd c_public;
457302Sgdamore@opensolaris.org
467302Sgdamore@opensolaris.org /*
477302Sgdamore@opensolaris.org * Implementation private stuff.
487302Sgdamore@opensolaris.org */
497302Sgdamore@opensolaris.org sda_slot_t *c_slot;
507302Sgdamore@opensolaris.org kmutex_t c_lock;
517302Sgdamore@opensolaris.org kcondvar_t c_cv;
527302Sgdamore@opensolaris.org list_node_t c_list;
537302Sgdamore@opensolaris.org sda_err_t c_errno;
547302Sgdamore@opensolaris.org
557302Sgdamore@opensolaris.org sda_index_t c_acmd; /* saved acmd */
567302Sgdamore@opensolaris.org sda_rtype_t c_artype; /* saved rtype */
577302Sgdamore@opensolaris.org uint32_t c_aarg; /* saved argument */
587302Sgdamore@opensolaris.org
597302Sgdamore@opensolaris.org void (*c_done)(struct sda_cmd *);
607302Sgdamore@opensolaris.org void *c_private;
617302Sgdamore@opensolaris.org } sda_cmd_impl_t;
627302Sgdamore@opensolaris.org
637302Sgdamore@opensolaris.org #define c_index c_public.sc_index
647302Sgdamore@opensolaris.org #define c_argument c_public.sc_argument
657302Sgdamore@opensolaris.org #define c_rtype c_public.sc_rtype
667302Sgdamore@opensolaris.org #define c_response c_public.sc_response
677302Sgdamore@opensolaris.org #define c_blksz c_public.sc_blksz
687302Sgdamore@opensolaris.org #define c_nblks c_public.sc_nblks
697302Sgdamore@opensolaris.org #define c_resid c_public.sc_resid
707302Sgdamore@opensolaris.org #define c_flags c_public.sc_flags
717302Sgdamore@opensolaris.org #define c_ndmac c_public.sc_ndmac
72*12426Sgdamore@opensolaris.org #define c_dmah c_public.sc_dmah
73*12426Sgdamore@opensolaris.org #define c_dmac c_public.sc_dmac
747302Sgdamore@opensolaris.org #define c_kvaddr c_public.sc_kvaddr
757302Sgdamore@opensolaris.org
767302Sgdamore@opensolaris.org /*
777302Sgdamore@opensolaris.org * Local Prototypes.
787302Sgdamore@opensolaris.org */
797302Sgdamore@opensolaris.org
807302Sgdamore@opensolaris.org static void sda_cmd_wait(sda_cmd_t *);
817302Sgdamore@opensolaris.org static int sda_cmd_ctor(void *, void *, int);
827302Sgdamore@opensolaris.org static void sda_cmd_dtor(void *, void *);
837302Sgdamore@opensolaris.org
847302Sgdamore@opensolaris.org /*
857302Sgdamore@opensolaris.org * Static Variables.
867302Sgdamore@opensolaris.org */
877302Sgdamore@opensolaris.org
887302Sgdamore@opensolaris.org static kmem_cache_t *sda_cmd_cache;
897302Sgdamore@opensolaris.org
907302Sgdamore@opensolaris.org /*
917302Sgdamore@opensolaris.org * Macros.
927302Sgdamore@opensolaris.org */
937302Sgdamore@opensolaris.org
947302Sgdamore@opensolaris.org #define CIP(cmdp) ((sda_cmd_impl_t *)(void *)cmdp)
957302Sgdamore@opensolaris.org
967302Sgdamore@opensolaris.org /*
977302Sgdamore@opensolaris.org * Implementation.
987302Sgdamore@opensolaris.org */
997302Sgdamore@opensolaris.org
1007302Sgdamore@opensolaris.org void
sda_cmd_init(void)1017302Sgdamore@opensolaris.org sda_cmd_init(void)
1027302Sgdamore@opensolaris.org {
1037302Sgdamore@opensolaris.org sda_cmd_cache = kmem_cache_create("sda_cmd_cache",
1047302Sgdamore@opensolaris.org sizeof (struct sda_cmd_impl), 0, sda_cmd_ctor, sda_cmd_dtor,
1057302Sgdamore@opensolaris.org NULL, NULL, NULL, 0);
1067302Sgdamore@opensolaris.org }
1077302Sgdamore@opensolaris.org
1087302Sgdamore@opensolaris.org void
sda_cmd_fini(void)1097302Sgdamore@opensolaris.org sda_cmd_fini(void)
1107302Sgdamore@opensolaris.org {
1117302Sgdamore@opensolaris.org kmem_cache_destroy(sda_cmd_cache);
1127302Sgdamore@opensolaris.org }
1137302Sgdamore@opensolaris.org
1147302Sgdamore@opensolaris.org void
sda_cmd_list_init(list_t * list)1157302Sgdamore@opensolaris.org sda_cmd_list_init(list_t *list)
1167302Sgdamore@opensolaris.org {
1177302Sgdamore@opensolaris.org list_create(list, sizeof (struct sda_cmd_impl),
1187302Sgdamore@opensolaris.org offsetof(struct sda_cmd_impl, c_list));
1197302Sgdamore@opensolaris.org }
1207302Sgdamore@opensolaris.org
1217302Sgdamore@opensolaris.org void
sda_cmd_list_fini(list_t * list)1227302Sgdamore@opensolaris.org sda_cmd_list_fini(list_t *list)
1237302Sgdamore@opensolaris.org {
1247302Sgdamore@opensolaris.org list_destroy(list);
1257302Sgdamore@opensolaris.org }
1267302Sgdamore@opensolaris.org
1277302Sgdamore@opensolaris.org /*ARGSUSED1*/
1287302Sgdamore@opensolaris.org int
sda_cmd_ctor(void * cbuf,void * arg,int kmflags)1297302Sgdamore@opensolaris.org sda_cmd_ctor(void *cbuf, void *arg, int kmflags)
1307302Sgdamore@opensolaris.org {
1317302Sgdamore@opensolaris.org sda_cmd_impl_t *c = cbuf;
1327302Sgdamore@opensolaris.org
1337302Sgdamore@opensolaris.org mutex_init(&c->c_lock, NULL, MUTEX_DRIVER, NULL);
1347302Sgdamore@opensolaris.org cv_init(&c->c_cv, NULL, CV_DRIVER, NULL);
1357302Sgdamore@opensolaris.org return (0);
1367302Sgdamore@opensolaris.org }
1377302Sgdamore@opensolaris.org
1387302Sgdamore@opensolaris.org /*ARGSUSED1*/
1397302Sgdamore@opensolaris.org void
sda_cmd_dtor(void * cbuf,void * arg)1407302Sgdamore@opensolaris.org sda_cmd_dtor(void *cbuf, void *arg)
1417302Sgdamore@opensolaris.org {
1427302Sgdamore@opensolaris.org sda_cmd_impl_t *c = cbuf;
1437302Sgdamore@opensolaris.org
1447302Sgdamore@opensolaris.org cv_destroy(&c->c_cv);
1457302Sgdamore@opensolaris.org mutex_destroy(&c->c_lock);
1467302Sgdamore@opensolaris.org }
1477302Sgdamore@opensolaris.org
1487302Sgdamore@opensolaris.org void *
sda_cmd_data(sda_cmd_t * cmdp)1497302Sgdamore@opensolaris.org sda_cmd_data(sda_cmd_t *cmdp)
1507302Sgdamore@opensolaris.org {
1517302Sgdamore@opensolaris.org return (CIP(cmdp)->c_private);
1527302Sgdamore@opensolaris.org }
1537302Sgdamore@opensolaris.org
1547302Sgdamore@opensolaris.org sda_err_t
sda_cmd_errno(sda_cmd_t * cmdp)1557302Sgdamore@opensolaris.org sda_cmd_errno(sda_cmd_t *cmdp)
1567302Sgdamore@opensolaris.org {
1577302Sgdamore@opensolaris.org return (CIP(cmdp)->c_errno);
1587302Sgdamore@opensolaris.org }
1597302Sgdamore@opensolaris.org
1607302Sgdamore@opensolaris.org void
sda_cmd_notify(sda_cmd_t * cmdp,uint16_t flags,sda_err_t errno)1617302Sgdamore@opensolaris.org sda_cmd_notify(sda_cmd_t *cmdp, uint16_t flags, sda_err_t errno)
1627302Sgdamore@opensolaris.org {
1637302Sgdamore@opensolaris.org sda_cmd_impl_t *c = CIP(cmdp);
1647302Sgdamore@opensolaris.org
1657302Sgdamore@opensolaris.org /*
1667302Sgdamore@opensolaris.org * Now we need to make sure that we wake anyone waiting on this
1677302Sgdamore@opensolaris.org * command to complete, if it is complete.
1687302Sgdamore@opensolaris.org */
1697302Sgdamore@opensolaris.org mutex_enter(&c->c_lock);
1707302Sgdamore@opensolaris.org c->c_flags &= ~(flags);
1717302Sgdamore@opensolaris.org /*
1727302Sgdamore@opensolaris.org * Don't overwrite an earlier error.
1737302Sgdamore@opensolaris.org */
1747302Sgdamore@opensolaris.org if (c->c_errno == SDA_EOK) {
1757302Sgdamore@opensolaris.org c->c_errno = errno;
1767302Sgdamore@opensolaris.org }
1777302Sgdamore@opensolaris.org if ((c->c_flags & (SDA_CMDF_BUSY | SDA_CMDF_DAT)) == 0) {
1787302Sgdamore@opensolaris.org
1797302Sgdamore@opensolaris.org if (c->c_done != NULL) {
1807302Sgdamore@opensolaris.org mutex_exit(&c->c_lock);
1817302Sgdamore@opensolaris.org c->c_done(cmdp);
1827302Sgdamore@opensolaris.org } else {
1837302Sgdamore@opensolaris.org cv_broadcast(&c->c_cv);
1847302Sgdamore@opensolaris.org mutex_exit(&c->c_lock);
1857302Sgdamore@opensolaris.org }
1867302Sgdamore@opensolaris.org } else {
1877302Sgdamore@opensolaris.org mutex_exit(&c->c_lock);
1887302Sgdamore@opensolaris.org }
1897302Sgdamore@opensolaris.org }
1907302Sgdamore@opensolaris.org
1917302Sgdamore@opensolaris.org void
sda_cmd_wait(sda_cmd_t * cmdp)1927302Sgdamore@opensolaris.org sda_cmd_wait(sda_cmd_t *cmdp)
1937302Sgdamore@opensolaris.org {
1947302Sgdamore@opensolaris.org sda_cmd_impl_t *c = CIP(cmdp);
1957302Sgdamore@opensolaris.org
1967302Sgdamore@opensolaris.org mutex_enter(&c->c_lock);
1977302Sgdamore@opensolaris.org while ((c->c_flags & (SDA_CMDF_BUSY | SDA_CMDF_DAT)) != 0)
1987302Sgdamore@opensolaris.org cv_wait(&c->c_cv, &c->c_lock);
1997302Sgdamore@opensolaris.org mutex_exit(&c->c_lock);
2007302Sgdamore@opensolaris.org }
2017302Sgdamore@opensolaris.org
2027302Sgdamore@opensolaris.org void
sda_cmd_submit(sda_slot_t * slot,sda_cmd_t * cmdp,void (* done)(sda_cmd_t *))2037302Sgdamore@opensolaris.org sda_cmd_submit(sda_slot_t *slot, sda_cmd_t *cmdp, void (*done)(sda_cmd_t *))
2047302Sgdamore@opensolaris.org {
2057302Sgdamore@opensolaris.org sda_cmd_impl_t *c = CIP(cmdp);
2067302Sgdamore@opensolaris.org sda_err_t errno = 0;
2077302Sgdamore@opensolaris.org
2087302Sgdamore@opensolaris.org mutex_enter(&c->c_lock);
2097302Sgdamore@opensolaris.org c->c_done = done;
2107302Sgdamore@opensolaris.org c->c_flags |= SDA_CMDF_BUSY;
2117302Sgdamore@opensolaris.org mutex_exit(&c->c_lock);
2127302Sgdamore@opensolaris.org
2137302Sgdamore@opensolaris.org sda_slot_enter(slot);
2147302Sgdamore@opensolaris.org
2157302Sgdamore@opensolaris.org /* checks for cases where the slot can't accept the command */
2167302Sgdamore@opensolaris.org if (slot->s_failed) {
2177302Sgdamore@opensolaris.org errno = SDA_EFAULT;
2187302Sgdamore@opensolaris.org }
2197302Sgdamore@opensolaris.org if (!slot->s_inserted) {
2207302Sgdamore@opensolaris.org errno = SDA_ENODEV;
2217302Sgdamore@opensolaris.org }
2227302Sgdamore@opensolaris.org if (errno != SDA_EOK) {
223*12426Sgdamore@opensolaris.org /*
224*12426Sgdamore@opensolaris.org * We have to return failure conditions asynchronously.
225*12426Sgdamore@opensolaris.org * What we do in this case is mark the command failed,
226*12426Sgdamore@opensolaris.org * and move it to the abortlist so that the slot thread
227*12426Sgdamore@opensolaris.org * will execute the failure notification asynchronously.
228*12426Sgdamore@opensolaris.org *
229*12426Sgdamore@opensolaris.org * NB: using 0 for flags ensures that we don't execute
230*12426Sgdamore@opensolaris.org * the notification callback yet, we're just stashing
231*12426Sgdamore@opensolaris.org * the errno.
232*12426Sgdamore@opensolaris.org */
233*12426Sgdamore@opensolaris.org sda_cmd_notify(cmdp, 0, errno);
234*12426Sgdamore@opensolaris.org list_insert_tail(&slot->s_abortlist, cmdp);
2357302Sgdamore@opensolaris.org
236*12426Sgdamore@opensolaris.org } else if (c->c_flags & SDA_CMDF_INIT) {
237*12426Sgdamore@opensolaris.org /* Initialization commands go to the head of the class */
2388289Sgdamore@opensolaris.org list_insert_head(&slot->s_cmdlist, c);
2398289Sgdamore@opensolaris.org } else {
2408289Sgdamore@opensolaris.org list_insert_tail(&slot->s_cmdlist, c);
2418289Sgdamore@opensolaris.org }
2427302Sgdamore@opensolaris.org sda_slot_exit(slot);
2437302Sgdamore@opensolaris.org
2447302Sgdamore@opensolaris.org sda_slot_wakeup(slot);
2457302Sgdamore@opensolaris.org }
2467302Sgdamore@opensolaris.org
2477302Sgdamore@opensolaris.org void
sda_cmd_resubmit_acmd(sda_slot_t * slot,sda_cmd_t * cmdp)2487302Sgdamore@opensolaris.org sda_cmd_resubmit_acmd(sda_slot_t *slot, sda_cmd_t *cmdp)
2497302Sgdamore@opensolaris.org {
2507302Sgdamore@opensolaris.org sda_cmd_impl_t *c = CIP(cmdp);
2517302Sgdamore@opensolaris.org
2527302Sgdamore@opensolaris.org ASSERT(sda_slot_owned(slot));
2537302Sgdamore@opensolaris.org
2547302Sgdamore@opensolaris.org c->c_index = c->c_acmd;
2557302Sgdamore@opensolaris.org c->c_argument = c->c_aarg;
2567302Sgdamore@opensolaris.org c->c_rtype = c->c_artype;
2577302Sgdamore@opensolaris.org c->c_acmd = 0;
2587302Sgdamore@opensolaris.org
2597302Sgdamore@opensolaris.org list_insert_head(&slot->s_cmdlist, c);
2607302Sgdamore@opensolaris.org }
2617302Sgdamore@opensolaris.org
2627302Sgdamore@opensolaris.org 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)2637302Sgdamore@opensolaris.org sda_cmd_alloc(sda_slot_t *slot, sda_index_t index, uint32_t argument,
2647302Sgdamore@opensolaris.org sda_rtype_t rtype, void *data, int kmflag)
2657302Sgdamore@opensolaris.org {
2667302Sgdamore@opensolaris.org sda_cmd_impl_t *c;
2677302Sgdamore@opensolaris.org
2687302Sgdamore@opensolaris.org c = kmem_cache_alloc(sda_cmd_cache, kmflag);
2697302Sgdamore@opensolaris.org if (c == NULL) {
2707302Sgdamore@opensolaris.org return (NULL);
2717302Sgdamore@opensolaris.org }
2727302Sgdamore@opensolaris.org c->c_index = index;
2737302Sgdamore@opensolaris.org c->c_rtype = rtype;
2747302Sgdamore@opensolaris.org c->c_argument = argument;
2757302Sgdamore@opensolaris.org c->c_resid = 0;
2767302Sgdamore@opensolaris.org c->c_nblks = 0;
2777302Sgdamore@opensolaris.org c->c_blksz = 0;
2787302Sgdamore@opensolaris.org
2797302Sgdamore@opensolaris.org c->c_kvaddr = 0;
280*12426Sgdamore@opensolaris.org c->c_dmah = 0;
2817302Sgdamore@opensolaris.org c->c_ndmac = 0;
282*12426Sgdamore@opensolaris.org c->c_dmah = NULL;
283*12426Sgdamore@opensolaris.org bzero(&c->c_dmac, sizeof (c->c_dmac));
2847302Sgdamore@opensolaris.org c->c_flags = 0;
2857302Sgdamore@opensolaris.org
2867302Sgdamore@opensolaris.org c->c_slot = slot;
2877302Sgdamore@opensolaris.org c->c_errno = SDA_EOK;
2887302Sgdamore@opensolaris.org c->c_done = NULL;
2897302Sgdamore@opensolaris.org c->c_private = data;
2907302Sgdamore@opensolaris.org c->c_acmd = 0;
2917302Sgdamore@opensolaris.org
2927302Sgdamore@opensolaris.org return (&(c->c_public));
2937302Sgdamore@opensolaris.org }
2947302Sgdamore@opensolaris.org
2957302Sgdamore@opensolaris.org 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)2967302Sgdamore@opensolaris.org sda_cmd_alloc_acmd(sda_slot_t *slot, sda_index_t index, uint32_t argument,
2977302Sgdamore@opensolaris.org sda_rtype_t rtype, void *data, int kmflag)
2987302Sgdamore@opensolaris.org {
2997302Sgdamore@opensolaris.org sda_cmd_impl_t *c;
3007302Sgdamore@opensolaris.org
3017302Sgdamore@opensolaris.org c = kmem_cache_alloc(sda_cmd_cache, kmflag);
3027302Sgdamore@opensolaris.org if (c == NULL) {
3037302Sgdamore@opensolaris.org return (NULL);
3047302Sgdamore@opensolaris.org }
3057302Sgdamore@opensolaris.org c->c_index = CMD_APP_CMD;
3067302Sgdamore@opensolaris.org c->c_argument = index == ACMD_SD_SEND_OCR ? 0 : slot->s_rca << 16;
3077302Sgdamore@opensolaris.org c->c_rtype = R1;
3087302Sgdamore@opensolaris.org c->c_acmd = index;
3097302Sgdamore@opensolaris.org c->c_artype = rtype;
3107302Sgdamore@opensolaris.org c->c_aarg = argument;
3117302Sgdamore@opensolaris.org c->c_resid = 0;
3127302Sgdamore@opensolaris.org c->c_nblks = 0;
3137302Sgdamore@opensolaris.org c->c_blksz = 0;
3147302Sgdamore@opensolaris.org
3157302Sgdamore@opensolaris.org c->c_kvaddr = 0;
3167302Sgdamore@opensolaris.org c->c_ndmac = 0;
317*12426Sgdamore@opensolaris.org c->c_dmah = NULL;
318*12426Sgdamore@opensolaris.org bzero(&c->c_dmac, sizeof (c->c_dmac));
3197302Sgdamore@opensolaris.org c->c_flags = 0;
3207302Sgdamore@opensolaris.org
3217302Sgdamore@opensolaris.org c->c_slot = slot;
3227302Sgdamore@opensolaris.org c->c_errno = SDA_EOK;
3237302Sgdamore@opensolaris.org c->c_done = NULL;
3247302Sgdamore@opensolaris.org c->c_private = data;
3257302Sgdamore@opensolaris.org
3267302Sgdamore@opensolaris.org return (&(c->c_public));
3277302Sgdamore@opensolaris.org }
3287302Sgdamore@opensolaris.org
3297302Sgdamore@opensolaris.org void
sda_cmd_free(sda_cmd_t * cmdp)3307302Sgdamore@opensolaris.org sda_cmd_free(sda_cmd_t *cmdp)
3317302Sgdamore@opensolaris.org {
3327302Sgdamore@opensolaris.org kmem_cache_free(sda_cmd_cache, cmdp);
3337302Sgdamore@opensolaris.org }
3347302Sgdamore@opensolaris.org
3357302Sgdamore@opensolaris.org sda_err_t
sda_cmd_exec(sda_slot_t * slot,sda_cmd_t * cmdp,uint32_t * resp)3367302Sgdamore@opensolaris.org sda_cmd_exec(sda_slot_t *slot, sda_cmd_t *cmdp, uint32_t *resp)
3377302Sgdamore@opensolaris.org {
3387302Sgdamore@opensolaris.org int errno;
3397302Sgdamore@opensolaris.org
3407302Sgdamore@opensolaris.org if ((cmdp->sc_rtype & Rb) || (cmdp->sc_nblks != 0)) {
3417302Sgdamore@opensolaris.org cmdp->sc_flags |= SDA_CMDF_DAT;
3427302Sgdamore@opensolaris.org }
3437302Sgdamore@opensolaris.org sda_cmd_submit(slot, cmdp, NULL);
3447302Sgdamore@opensolaris.org
3457302Sgdamore@opensolaris.org sda_cmd_wait(cmdp);
3467302Sgdamore@opensolaris.org
3477302Sgdamore@opensolaris.org if (resp != NULL) {
3487302Sgdamore@opensolaris.org switch (cmdp->sc_rtype) {
3497302Sgdamore@opensolaris.org case R0:
3507302Sgdamore@opensolaris.org break;
3517302Sgdamore@opensolaris.org case R2:
3527302Sgdamore@opensolaris.org resp[0] = cmdp->sc_response[0];
3537302Sgdamore@opensolaris.org resp[1] = cmdp->sc_response[1];
3547302Sgdamore@opensolaris.org resp[2] = cmdp->sc_response[2];
3557302Sgdamore@opensolaris.org resp[3] = cmdp->sc_response[3];
3567302Sgdamore@opensolaris.org break;
3577302Sgdamore@opensolaris.org default:
3587302Sgdamore@opensolaris.org resp[0] = cmdp->sc_response[0];
3597302Sgdamore@opensolaris.org break;
3607302Sgdamore@opensolaris.org }
3617302Sgdamore@opensolaris.org }
3627302Sgdamore@opensolaris.org
3637302Sgdamore@opensolaris.org errno = CIP(cmdp)->c_errno;
3647302Sgdamore@opensolaris.org
3657302Sgdamore@opensolaris.org return (errno);
3667302Sgdamore@opensolaris.org }
367