17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
580a70ef3Sap25164 * Common Development and Distribution License (the "License").
680a70ef3Sap25164 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
2280a70ef3Sap25164 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate * s1394_asynch.c
287c478bd9Sstevel@tonic-gate * 1394 Services Layer Asynchronous Communications Routines
297c478bd9Sstevel@tonic-gate * These routines handle all of the tasks relating to asynch commands
307c478bd9Sstevel@tonic-gate */
317c478bd9Sstevel@tonic-gate
327c478bd9Sstevel@tonic-gate #include <sys/conf.h>
337c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
347c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
357c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
367c478bd9Sstevel@tonic-gate #include <sys/types.h>
377c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
3880a70ef3Sap25164 #include <sys/disp.h>
397c478bd9Sstevel@tonic-gate #include <sys/1394/t1394.h>
407c478bd9Sstevel@tonic-gate #include <sys/1394/s1394.h>
417c478bd9Sstevel@tonic-gate #include <sys/1394/h1394.h>
427c478bd9Sstevel@tonic-gate #include <sys/1394/ieee1394.h>
437c478bd9Sstevel@tonic-gate #include <sys/1394/ieee1212.h>
447c478bd9Sstevel@tonic-gate
457c478bd9Sstevel@tonic-gate static void s1394_handle_lock(cmd1394_cmd_t *cmd);
467c478bd9Sstevel@tonic-gate
477c478bd9Sstevel@tonic-gate static cmd1394_cmd_t *s1394_pending_q_remove(s1394_hal_t *hal);
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate static boolean_t s1394_process_pending_q(s1394_hal_t *hal);
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate static boolean_t s1394_pending_q_helper(s1394_hal_t *hal, cmd1394_cmd_t *cmd);
527c478bd9Sstevel@tonic-gate
537c478bd9Sstevel@tonic-gate static int s1394_process_split_lock(cmd1394_cmd_t *cmd,
547c478bd9Sstevel@tonic-gate cmd1394_cmd_t *target_cmd);
557c478bd9Sstevel@tonic-gate
567c478bd9Sstevel@tonic-gate static int s1394_finish_split_lock(cmd1394_cmd_t *cmd,
577c478bd9Sstevel@tonic-gate cmd1394_cmd_t *target_cmd);
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate /*
607c478bd9Sstevel@tonic-gate * s1394_alloc_cmd()
617c478bd9Sstevel@tonic-gate * is used to allocate a command for a target or for a HAL.
627c478bd9Sstevel@tonic-gate */
637c478bd9Sstevel@tonic-gate int
s1394_alloc_cmd(s1394_hal_t * hal,uint_t flags,cmd1394_cmd_t ** cmdp)647c478bd9Sstevel@tonic-gate s1394_alloc_cmd(s1394_hal_t *hal, uint_t flags, cmd1394_cmd_t **cmdp)
657c478bd9Sstevel@tonic-gate {
667c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *s_priv;
677c478bd9Sstevel@tonic-gate void *hal_overhead;
687c478bd9Sstevel@tonic-gate uint_t cmd_size;
697c478bd9Sstevel@tonic-gate int alloc_sleep;
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate alloc_sleep = (flags & T1394_ALLOC_CMD_NOSLEEP) ? KM_NOSLEEP : KM_SLEEP;
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate if ((alloc_sleep == KM_SLEEP) &&
7480a70ef3Sap25164 (servicing_interrupt())) {
757c478bd9Sstevel@tonic-gate ASSERT(alloc_sleep != KM_SLEEP); /* fail */
767c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
777c478bd9Sstevel@tonic-gate }
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate /* either FCP command or response, but not both */
807c478bd9Sstevel@tonic-gate if ((flags &
817c478bd9Sstevel@tonic-gate (T1394_ALLOC_CMD_FCP_COMMAND | T1394_ALLOC_CMD_FCP_RESPONSE)) ==
827c478bd9Sstevel@tonic-gate (T1394_ALLOC_CMD_FCP_COMMAND | T1394_ALLOC_CMD_FCP_RESPONSE)) {
837c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
847c478bd9Sstevel@tonic-gate }
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate *cmdp = kmem_cache_alloc(hal->hal_kmem_cachep, alloc_sleep);
877c478bd9Sstevel@tonic-gate if (*cmdp == NULL) {
887c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
897c478bd9Sstevel@tonic-gate }
907c478bd9Sstevel@tonic-gate cmd_size = sizeof (cmd1394_cmd_t) +
917c478bd9Sstevel@tonic-gate sizeof (s1394_cmd_priv_t) + hal->halinfo.hal_overhead;
927c478bd9Sstevel@tonic-gate bzero((void *)*cmdp, cmd_size);
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate (*cmdp)->cmd_version = T1394_VERSION_V1;
957c478bd9Sstevel@tonic-gate (*cmdp)->cmd_result = CMD1394_NOSTATUS;
967c478bd9Sstevel@tonic-gate
977c478bd9Sstevel@tonic-gate /* Get the Services Layer private area */
987c478bd9Sstevel@tonic-gate s_priv = S1394_GET_CMD_PRIV(*cmdp);
997c478bd9Sstevel@tonic-gate
1007c478bd9Sstevel@tonic-gate /* Set extension type */
1017c478bd9Sstevel@tonic-gate if (flags & T1394_ALLOC_CMD_FCP_COMMAND) {
1027c478bd9Sstevel@tonic-gate s1394_fa_init_cmd(s_priv, S1394_FA_TYPE_FCP_CTL);
1037c478bd9Sstevel@tonic-gate } else if (flags & T1394_ALLOC_CMD_FCP_RESPONSE) {
1047c478bd9Sstevel@tonic-gate s1394_fa_init_cmd(s_priv, S1394_FA_TYPE_FCP_TGT);
1057c478bd9Sstevel@tonic-gate }
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate /* Set up the hal_overhead ptr in the hal_cmd_private */
1087c478bd9Sstevel@tonic-gate hal_overhead = (uchar_t *)s_priv + sizeof (s1394_cmd_priv_t);
1097c478bd9Sstevel@tonic-gate s_priv->hal_cmd_private.hal_overhead = (void *)hal_overhead;
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate /* kstats - number of cmd allocs */
1127c478bd9Sstevel@tonic-gate hal->hal_kstats->cmd_alloc++;
1137c478bd9Sstevel@tonic-gate
1147c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
1157c478bd9Sstevel@tonic-gate }
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate /*
1187c478bd9Sstevel@tonic-gate * s1394_free_cmd()
1197c478bd9Sstevel@tonic-gate * is used to free a command that had been previously allocated by
1207c478bd9Sstevel@tonic-gate * s1394_alloc_cmd().
1217c478bd9Sstevel@tonic-gate */
1227c478bd9Sstevel@tonic-gate int
s1394_free_cmd(s1394_hal_t * hal,cmd1394_cmd_t ** cmdp)1237c478bd9Sstevel@tonic-gate s1394_free_cmd(s1394_hal_t *hal, cmd1394_cmd_t **cmdp)
1247c478bd9Sstevel@tonic-gate {
1257c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *s_priv;
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate /* Get the Services Layer private area */
1287c478bd9Sstevel@tonic-gate s_priv = S1394_GET_CMD_PRIV(*cmdp);
1297c478bd9Sstevel@tonic-gate
1307c478bd9Sstevel@tonic-gate /* Check that command isn't in use */
1317c478bd9Sstevel@tonic-gate if (s_priv->cmd_in_use == B_TRUE) {
1327c478bd9Sstevel@tonic-gate ASSERT(s_priv->cmd_in_use == B_FALSE);
1337c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
1347c478bd9Sstevel@tonic-gate }
1357c478bd9Sstevel@tonic-gate
1367c478bd9Sstevel@tonic-gate /* kstats - number of cmd allocs */
1377c478bd9Sstevel@tonic-gate kmem_cache_free(hal->hal_kmem_cachep, *cmdp);
1387c478bd9Sstevel@tonic-gate
1397c478bd9Sstevel@tonic-gate /* Command pointer is set to NULL before returning */
1407c478bd9Sstevel@tonic-gate *cmdp = NULL;
1417c478bd9Sstevel@tonic-gate
1427c478bd9Sstevel@tonic-gate /* kstats - number of cmd frees */
1437c478bd9Sstevel@tonic-gate hal->hal_kstats->cmd_free++;
1447c478bd9Sstevel@tonic-gate
1457c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate /*
1497c478bd9Sstevel@tonic-gate * s1394_xfer_asynch_command()
1507c478bd9Sstevel@tonic-gate * is used to send an asynch command down to the HAL. Based upon the type
1517c478bd9Sstevel@tonic-gate * of command that is being sent, the appropriate HAL function is called.
1527c478bd9Sstevel@tonic-gate * Command failures are handled be returning an error and/or shutting down
1537c478bd9Sstevel@tonic-gate * the HAL, depending on the severity of the error.
1547c478bd9Sstevel@tonic-gate */
1557c478bd9Sstevel@tonic-gate int
s1394_xfer_asynch_command(s1394_hal_t * hal,cmd1394_cmd_t * cmd,int * err)1567c478bd9Sstevel@tonic-gate s1394_xfer_asynch_command(s1394_hal_t *hal, cmd1394_cmd_t *cmd, int *err)
1577c478bd9Sstevel@tonic-gate {
1587c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *s_priv;
1597c478bd9Sstevel@tonic-gate h1394_cmd_priv_t *h_priv;
1607c478bd9Sstevel@tonic-gate s1394_hal_state_t state;
1617c478bd9Sstevel@tonic-gate dev_info_t *dip;
1627c478bd9Sstevel@tonic-gate int result_from_hal;
1637c478bd9Sstevel@tonic-gate int ret;
1647c478bd9Sstevel@tonic-gate
1657c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate mutex_enter(&hal->topology_tree_mutex);
1687c478bd9Sstevel@tonic-gate state = hal->hal_state;
1697c478bd9Sstevel@tonic-gate if (((state != S1394_HAL_NORMAL) && (state != S1394_HAL_RESET)) ||
1707c478bd9Sstevel@tonic-gate (hal->disable_requests_bit == 1)) {
1717c478bd9Sstevel@tonic-gate *err = s1394_HAL_asynch_error(hal, cmd, state);
1727c478bd9Sstevel@tonic-gate mutex_exit(&hal->topology_tree_mutex);
1737c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate mutex_exit(&hal->topology_tree_mutex);
1767c478bd9Sstevel@tonic-gate
1777c478bd9Sstevel@tonic-gate /* Get the Services Layer private area */
1787c478bd9Sstevel@tonic-gate s_priv = S1394_GET_CMD_PRIV(cmd);
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate /* Get a pointer to the HAL private struct */
1817c478bd9Sstevel@tonic-gate h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate /* kstats - number of AT requests sent */
1847c478bd9Sstevel@tonic-gate switch (cmd->cmd_type) {
1857c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_RD_QUAD:
1867c478bd9Sstevel@tonic-gate hal->hal_kstats->atreq_quad_rd++;
1877c478bd9Sstevel@tonic-gate break;
1887c478bd9Sstevel@tonic-gate
1897c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_RD_BLOCK:
1907c478bd9Sstevel@tonic-gate hal->hal_kstats->atreq_blk_rd++;
1917c478bd9Sstevel@tonic-gate break;
1927c478bd9Sstevel@tonic-gate
1937c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_WR_QUAD:
1947c478bd9Sstevel@tonic-gate hal->hal_kstats->atreq_quad_wr++;
1957c478bd9Sstevel@tonic-gate break;
1967c478bd9Sstevel@tonic-gate
1977c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_WR_BLOCK:
1987c478bd9Sstevel@tonic-gate hal->hal_kstats->atreq_blk_wr++;
1997c478bd9Sstevel@tonic-gate hal->hal_kstats->atreq_blk_wr_size += h_priv->mblk.length;
2007c478bd9Sstevel@tonic-gate break;
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_LOCK_32:
2037c478bd9Sstevel@tonic-gate hal->hal_kstats->atreq_lock32++;
2047c478bd9Sstevel@tonic-gate break;
2057c478bd9Sstevel@tonic-gate
2067c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_LOCK_64:
2077c478bd9Sstevel@tonic-gate hal->hal_kstats->atreq_lock64++;
2087c478bd9Sstevel@tonic-gate break;
2097c478bd9Sstevel@tonic-gate }
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate switch (s_priv->cmd_priv_xfer_type) {
2127c478bd9Sstevel@tonic-gate /* Call the HAL's read entry point */
2137c478bd9Sstevel@tonic-gate case S1394_CMD_READ:
2147c478bd9Sstevel@tonic-gate ret = HAL_CALL(hal).read(hal->halinfo.hal_private,
2157c478bd9Sstevel@tonic-gate (cmd1394_cmd_t *)cmd,
2167c478bd9Sstevel@tonic-gate (h1394_cmd_priv_t *)&s_priv->hal_cmd_private,
2177c478bd9Sstevel@tonic-gate &result_from_hal);
2187c478bd9Sstevel@tonic-gate break;
2197c478bd9Sstevel@tonic-gate
2207c478bd9Sstevel@tonic-gate /* Call the HAL's write entry point */
2217c478bd9Sstevel@tonic-gate case S1394_CMD_WRITE:
2227c478bd9Sstevel@tonic-gate ret = HAL_CALL(hal).write(hal->halinfo.hal_private,
2237c478bd9Sstevel@tonic-gate (cmd1394_cmd_t *)cmd,
2247c478bd9Sstevel@tonic-gate (h1394_cmd_priv_t *)&s_priv->hal_cmd_private,
2257c478bd9Sstevel@tonic-gate &result_from_hal);
2267c478bd9Sstevel@tonic-gate break;
2277c478bd9Sstevel@tonic-gate
2287c478bd9Sstevel@tonic-gate /* Call the HAL's lock entry point */
2297c478bd9Sstevel@tonic-gate case S1394_CMD_LOCK:
2307c478bd9Sstevel@tonic-gate ret = HAL_CALL(hal).lock(hal->halinfo.hal_private,
2317c478bd9Sstevel@tonic-gate (cmd1394_cmd_t *)cmd,
2327c478bd9Sstevel@tonic-gate (h1394_cmd_priv_t *)&s_priv->hal_cmd_private,
2337c478bd9Sstevel@tonic-gate &result_from_hal);
2347c478bd9Sstevel@tonic-gate break;
2357c478bd9Sstevel@tonic-gate
2367c478bd9Sstevel@tonic-gate default:
2377c478bd9Sstevel@tonic-gate *err = CMD1394_EUNKNOWN_ERROR;
2387c478bd9Sstevel@tonic-gate
2397c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate if (ret == DDI_FAILURE) {
2437c478bd9Sstevel@tonic-gate switch (result_from_hal) {
2447c478bd9Sstevel@tonic-gate case H1394_STATUS_EMPTY_TLABEL:
2457c478bd9Sstevel@tonic-gate /* Out of TLABELs - Unable to send AT req */
2467c478bd9Sstevel@tonic-gate *err = CMD1394_ENO_ATREQ;
2477c478bd9Sstevel@tonic-gate break;
2487c478bd9Sstevel@tonic-gate
2497c478bd9Sstevel@tonic-gate case H1394_STATUS_INVALID_BUSGEN:
2507c478bd9Sstevel@tonic-gate /* Out of TLABELs - Unable to send AT req */
2517c478bd9Sstevel@tonic-gate *err = CMD1394_ESTALE_GENERATION;
2527c478bd9Sstevel@tonic-gate break;
2537c478bd9Sstevel@tonic-gate
2547c478bd9Sstevel@tonic-gate case H1394_STATUS_NOMORE_SPACE:
2557c478bd9Sstevel@tonic-gate /* No more space on HAL's HW queue */
2567c478bd9Sstevel@tonic-gate *err = CMD1394_ENO_ATREQ;
2577c478bd9Sstevel@tonic-gate break;
2587c478bd9Sstevel@tonic-gate
2597c478bd9Sstevel@tonic-gate case H1394_STATUS_INTERNAL_ERROR:
2607c478bd9Sstevel@tonic-gate dip = hal->halinfo.dip;
2617c478bd9Sstevel@tonic-gate
2627c478bd9Sstevel@tonic-gate /* An unexpected error in the HAL */
2637c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
2647c478bd9Sstevel@tonic-gate ddi_node_name(dip), ddi_get_instance(dip));
2657c478bd9Sstevel@tonic-gate
2667c478bd9Sstevel@tonic-gate /* Disable the HAL */
2677c478bd9Sstevel@tonic-gate s1394_hal_shutdown(hal, B_TRUE);
2687c478bd9Sstevel@tonic-gate
2697c478bd9Sstevel@tonic-gate *err = CMD1394_EFATAL_ERROR;
2707c478bd9Sstevel@tonic-gate break;
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate default:
2737c478bd9Sstevel@tonic-gate dip = hal->halinfo.dip;
2747c478bd9Sstevel@tonic-gate
2757c478bd9Sstevel@tonic-gate /* An unexpected error in the HAL */
2767c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
2777c478bd9Sstevel@tonic-gate ddi_node_name(dip), ddi_get_instance(dip));
2787c478bd9Sstevel@tonic-gate
2797c478bd9Sstevel@tonic-gate /* Disable the HAL */
2807c478bd9Sstevel@tonic-gate s1394_hal_shutdown(hal, B_TRUE);
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate *err = CMD1394_EFATAL_ERROR;
2837c478bd9Sstevel@tonic-gate break;
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate
2867c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
2877c478bd9Sstevel@tonic-gate }
2887c478bd9Sstevel@tonic-gate
2897c478bd9Sstevel@tonic-gate /* No errors, return success */
2907c478bd9Sstevel@tonic-gate *err = CMD1394_NOSTATUS;
2917c478bd9Sstevel@tonic-gate
2927c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate
2957c478bd9Sstevel@tonic-gate /*
2967c478bd9Sstevel@tonic-gate * s1394_setup_asynch_command()
2977c478bd9Sstevel@tonic-gate * is used to setup an asynch command to be sent down to the HAL and out
2987c478bd9Sstevel@tonic-gate * onto the bus. This function handles setting up the destination address
2997c478bd9Sstevel@tonic-gate * (if necessary), speed, max_payload, putting the command onto the
3007c478bd9Sstevel@tonic-gate * outstanding Q list, and any other things that must be done prior to
3017c478bd9Sstevel@tonic-gate * calling the HAL.
3027c478bd9Sstevel@tonic-gate */
3037c478bd9Sstevel@tonic-gate int
s1394_setup_asynch_command(s1394_hal_t * hal,s1394_target_t * target,cmd1394_cmd_t * cmd,uint32_t xfer_type,int * err)3047c478bd9Sstevel@tonic-gate s1394_setup_asynch_command(s1394_hal_t *hal, s1394_target_t *target,
3057c478bd9Sstevel@tonic-gate cmd1394_cmd_t *cmd, uint32_t xfer_type, int *err)
3067c478bd9Sstevel@tonic-gate {
3077c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *s_priv;
3087c478bd9Sstevel@tonic-gate h1394_cmd_priv_t *h_priv;
3097c478bd9Sstevel@tonic-gate uint64_t node;
3107c478bd9Sstevel@tonic-gate uint32_t from_node;
3117c478bd9Sstevel@tonic-gate uint32_t to_node;
3127c478bd9Sstevel@tonic-gate uint32_t bus_capabilities;
3137c478bd9Sstevel@tonic-gate uint_t current_max_payload;
3147c478bd9Sstevel@tonic-gate uint_t max_rec;
3157c478bd9Sstevel@tonic-gate uint_t max_blk;
3167c478bd9Sstevel@tonic-gate
3177c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate switch (cmd->cmd_type) {
3207c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_RD_QUAD:
3217c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_WR_QUAD:
3227c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_RD_BLOCK:
3237c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_WR_BLOCK:
3247c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_LOCK_32:
3257c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_LOCK_64:
3267c478bd9Sstevel@tonic-gate break;
3277c478bd9Sstevel@tonic-gate
3287c478bd9Sstevel@tonic-gate default:
3297c478bd9Sstevel@tonic-gate *err = CMD1394_EINVALID_COMMAND;
3307c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
3317c478bd9Sstevel@tonic-gate }
3327c478bd9Sstevel@tonic-gate
3337c478bd9Sstevel@tonic-gate /* Check for potential address roll-over */
3347c478bd9Sstevel@tonic-gate if (s1394_address_rollover(cmd) != B_FALSE) {
3357c478bd9Sstevel@tonic-gate *err = CMD1394_EADDRESS_ERROR;
3367c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
3377c478bd9Sstevel@tonic-gate }
3387c478bd9Sstevel@tonic-gate
3397c478bd9Sstevel@tonic-gate /* Get the Services Layer private area */
3407c478bd9Sstevel@tonic-gate s_priv = S1394_GET_CMD_PRIV(cmd);
3417c478bd9Sstevel@tonic-gate
3427c478bd9Sstevel@tonic-gate /* Set up who sent command on which hal */
3437c478bd9Sstevel@tonic-gate s_priv->sent_by_target = (s1394_target_t *)target;
3447c478bd9Sstevel@tonic-gate s_priv->sent_on_hal = (s1394_hal_t *)hal;
3457c478bd9Sstevel@tonic-gate
3467c478bd9Sstevel@tonic-gate /* Set up command transfer type */
3477c478bd9Sstevel@tonic-gate s_priv->cmd_priv_xfer_type = xfer_type;
3487c478bd9Sstevel@tonic-gate
3497c478bd9Sstevel@tonic-gate if (cmd->cmd_options & CMD1394_OVERRIDE_ADDR) {
3507c478bd9Sstevel@tonic-gate /* Compare the current generation from the HAL struct */
3517c478bd9Sstevel@tonic-gate /* to the one given by the target */
3527c478bd9Sstevel@tonic-gate
3537c478bd9Sstevel@tonic-gate /* Speed is to be filled in from speed map */
3547c478bd9Sstevel@tonic-gate from_node = IEEE1394_NODE_NUM(hal->node_id);
3557c478bd9Sstevel@tonic-gate to_node = IEEE1394_ADDR_PHY_ID(cmd->cmd_addr);
3567c478bd9Sstevel@tonic-gate
3577c478bd9Sstevel@tonic-gate if (cmd->bus_generation != hal->generation_count) {
3587c478bd9Sstevel@tonic-gate *err = CMD1394_ESTALE_GENERATION;
3597c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
3607c478bd9Sstevel@tonic-gate }
3617c478bd9Sstevel@tonic-gate
3627c478bd9Sstevel@tonic-gate } else {
3637c478bd9Sstevel@tonic-gate /* Set the generation */
3647c478bd9Sstevel@tonic-gate cmd->bus_generation = hal->generation_count;
3657c478bd9Sstevel@tonic-gate
3667c478bd9Sstevel@tonic-gate /* If not OVERRIDE_ADDR, then target may not be NULL */
3677c478bd9Sstevel@tonic-gate ASSERT(target != NULL);
3687c478bd9Sstevel@tonic-gate
3697c478bd9Sstevel@tonic-gate rw_enter(&hal->target_list_rwlock, RW_READER);
3707c478bd9Sstevel@tonic-gate
3717c478bd9Sstevel@tonic-gate if ((target->target_state & S1394_TARG_GONE) != 0 ||
3727c478bd9Sstevel@tonic-gate target->on_node == NULL) {
3737c478bd9Sstevel@tonic-gate rw_exit(&hal->target_list_rwlock);
3747c478bd9Sstevel@tonic-gate *err = CMD1394_EDEVICE_REMOVED;
3757c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate
3787c478bd9Sstevel@tonic-gate ASSERT((target->target_state & S1394_TARG_GONE) == 0);
3797c478bd9Sstevel@tonic-gate node = target->on_node->node_num;
3807c478bd9Sstevel@tonic-gate rw_exit(&hal->target_list_rwlock);
3817c478bd9Sstevel@tonic-gate
3827c478bd9Sstevel@tonic-gate /* Mask in the top 16-bits */
3837c478bd9Sstevel@tonic-gate cmd->cmd_addr = (cmd->cmd_addr & IEEE1394_ADDR_OFFSET_MASK);
3847c478bd9Sstevel@tonic-gate cmd->cmd_addr = (cmd->cmd_addr |
3857c478bd9Sstevel@tonic-gate (node << IEEE1394_ADDR_PHY_ID_SHIFT));
3867c478bd9Sstevel@tonic-gate cmd->cmd_addr = (cmd->cmd_addr | IEEE1394_ADDR_BUS_ID_MASK);
3877c478bd9Sstevel@tonic-gate
3887c478bd9Sstevel@tonic-gate /* Speed is to be filled in from speed map */
3897c478bd9Sstevel@tonic-gate from_node = IEEE1394_NODE_NUM(hal->node_id);
3907c478bd9Sstevel@tonic-gate to_node = (uint32_t)node;
3917c478bd9Sstevel@tonic-gate }
3927c478bd9Sstevel@tonic-gate
3937c478bd9Sstevel@tonic-gate /* Get a pointer to the HAL private struct */
3947c478bd9Sstevel@tonic-gate h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
3957c478bd9Sstevel@tonic-gate
3967c478bd9Sstevel@tonic-gate /* Copy the generation into the HAL's private field */
3977c478bd9Sstevel@tonic-gate h_priv->bus_generation = cmd->bus_generation;
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate /* Fill in the nodeID */
4007c478bd9Sstevel@tonic-gate cmd->nodeID = (cmd->cmd_addr & IEEE1394_ADDR_NODE_ID_MASK) >>
4017c478bd9Sstevel@tonic-gate IEEE1394_ADDR_NODE_ID_SHIFT;
4027c478bd9Sstevel@tonic-gate
4037c478bd9Sstevel@tonic-gate if (cmd->cmd_options & CMD1394_OVERRIDE_SPEED) {
4047c478bd9Sstevel@tonic-gate if (cmd->cmd_speed > IEEE1394_S400) {
4057c478bd9Sstevel@tonic-gate *err = CMD1394_EINVALID_COMMAND;
4067c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
4077c478bd9Sstevel@tonic-gate
4087c478bd9Sstevel@tonic-gate } else {
4097c478bd9Sstevel@tonic-gate s_priv->hal_cmd_private.speed = (int)cmd->cmd_speed;
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate
4127c478bd9Sstevel@tonic-gate } else {
4137c478bd9Sstevel@tonic-gate /* Speed is to be filled in from speed map */
4147c478bd9Sstevel@tonic-gate s_priv->hal_cmd_private.speed = (int)s1394_speed_map_get(hal,
4157c478bd9Sstevel@tonic-gate from_node, to_node);
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate /* Is it a block request? */
4197c478bd9Sstevel@tonic-gate if ((cmd->cmd_type == CMD1394_ASYNCH_RD_BLOCK) ||
4207c478bd9Sstevel@tonic-gate (cmd->cmd_type == CMD1394_ASYNCH_WR_BLOCK)) {
4217c478bd9Sstevel@tonic-gate
4227c478bd9Sstevel@tonic-gate if (cmd->cmd_u.b.data_block == NULL) {
4237c478bd9Sstevel@tonic-gate *err = CMD1394_ENULL_MBLK;
4247c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
4257c478bd9Sstevel@tonic-gate }
4267c478bd9Sstevel@tonic-gate
4277c478bd9Sstevel@tonic-gate /* Also need to check for MBLK_TOO_SMALL */
4287c478bd9Sstevel@tonic-gate if (s1394_mblk_too_small(cmd) != B_FALSE) {
4297c478bd9Sstevel@tonic-gate *err = CMD1394_EMBLK_TOO_SMALL;
4307c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
4317c478bd9Sstevel@tonic-gate }
4327c478bd9Sstevel@tonic-gate
4337c478bd9Sstevel@tonic-gate /* Initialize bytes_transferred to zero */
4347c478bd9Sstevel@tonic-gate cmd->cmd_u.b.bytes_transferred = 0;
4357c478bd9Sstevel@tonic-gate
4367c478bd9Sstevel@tonic-gate /* Handle the MAX_PAYLOAD size */
4377c478bd9Sstevel@tonic-gate if (cmd->cmd_options & CMD1394_OVERRIDE_ADDR) {
4387c478bd9Sstevel@tonic-gate
4397c478bd9Sstevel@tonic-gate current_max_payload = 512 <<
4407c478bd9Sstevel@tonic-gate (s_priv->hal_cmd_private.speed);
4417c478bd9Sstevel@tonic-gate if (hal->topology_tree[to_node].cfgrom) {
4427c478bd9Sstevel@tonic-gate bus_capabilities =
4437c478bd9Sstevel@tonic-gate hal->topology_tree[to_node].cfgrom[
4447c478bd9Sstevel@tonic-gate IEEE1212_NODE_CAP_QUAD];
4457c478bd9Sstevel@tonic-gate max_rec = (bus_capabilities &
4467c478bd9Sstevel@tonic-gate IEEE1394_BIB_MAXREC_MASK) >>
4477c478bd9Sstevel@tonic-gate IEEE1394_BIB_MAXREC_SHIFT;
4487c478bd9Sstevel@tonic-gate } else {
4497c478bd9Sstevel@tonic-gate max_rec = 0;
4507c478bd9Sstevel@tonic-gate }
4517c478bd9Sstevel@tonic-gate
4527c478bd9Sstevel@tonic-gate if ((max_rec > 0) && (max_rec < 14)) {
4537c478bd9Sstevel@tonic-gate max_blk = 1 << (max_rec + 1);
4547c478bd9Sstevel@tonic-gate
4557c478bd9Sstevel@tonic-gate } else {
4567c478bd9Sstevel@tonic-gate /* These are either unspecified or reserved */
4577c478bd9Sstevel@tonic-gate max_blk = 4;
4587c478bd9Sstevel@tonic-gate }
4597c478bd9Sstevel@tonic-gate if (max_blk < current_max_payload)
4607c478bd9Sstevel@tonic-gate current_max_payload = max_blk;
4617c478bd9Sstevel@tonic-gate
4627c478bd9Sstevel@tonic-gate } else {
4637c478bd9Sstevel@tonic-gate rw_enter(&hal->target_list_rwlock, RW_READER);
4647c478bd9Sstevel@tonic-gate current_max_payload = target->current_max_payload;
4657c478bd9Sstevel@tonic-gate rw_exit(&hal->target_list_rwlock);
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate
4687c478bd9Sstevel@tonic-gate if (cmd->cmd_options & CMD1394_OVERRIDE_MAX_PAYLOAD) {
4697c478bd9Sstevel@tonic-gate if (current_max_payload > cmd->cmd_u.b.max_payload)
4707c478bd9Sstevel@tonic-gate current_max_payload = cmd->cmd_u.b.max_payload;
4717c478bd9Sstevel@tonic-gate }
4727c478bd9Sstevel@tonic-gate
4737c478bd9Sstevel@tonic-gate h_priv->mblk.curr_mblk = cmd->cmd_u.b.data_block;
4747c478bd9Sstevel@tonic-gate
4757c478bd9Sstevel@tonic-gate if (cmd->cmd_type == CMD1394_ASYNCH_WR_BLOCK) {
4767c478bd9Sstevel@tonic-gate h_priv->mblk.curr_offset =
4777c478bd9Sstevel@tonic-gate cmd->cmd_u.b.data_block->b_rptr;
4787c478bd9Sstevel@tonic-gate } else {
4797c478bd9Sstevel@tonic-gate h_priv->mblk.curr_offset =
4807c478bd9Sstevel@tonic-gate cmd->cmd_u.b.data_block->b_wptr;
4817c478bd9Sstevel@tonic-gate }
4827c478bd9Sstevel@tonic-gate
4837c478bd9Sstevel@tonic-gate if (cmd->cmd_u.b.blk_length > current_max_payload) {
4847c478bd9Sstevel@tonic-gate h_priv->mblk.length = current_max_payload;
4857c478bd9Sstevel@tonic-gate s_priv->data_remaining = cmd->cmd_u.b.blk_length;
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate } else {
4887c478bd9Sstevel@tonic-gate h_priv->mblk.length = cmd->cmd_u.b.blk_length;
4897c478bd9Sstevel@tonic-gate s_priv->data_remaining = cmd->cmd_u.b.blk_length;
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate }
4927c478bd9Sstevel@tonic-gate
4937c478bd9Sstevel@tonic-gate /* Mark command as being used */
4947c478bd9Sstevel@tonic-gate s_priv->cmd_in_use = B_TRUE;
4957c478bd9Sstevel@tonic-gate
4967c478bd9Sstevel@tonic-gate /* Put command on the HAL's outstanding request Q */
4977c478bd9Sstevel@tonic-gate s1394_insert_q_asynch_cmd(hal, cmd);
4987c478bd9Sstevel@tonic-gate
4997c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
5007c478bd9Sstevel@tonic-gate }
5017c478bd9Sstevel@tonic-gate
5027c478bd9Sstevel@tonic-gate /*
5037c478bd9Sstevel@tonic-gate * s1394_insert_q_asynch_cmd()
5047c478bd9Sstevel@tonic-gate * is used to insert a given command structure onto a HAL's outstanding
5057c478bd9Sstevel@tonic-gate * asynch queue.
5067c478bd9Sstevel@tonic-gate */
5077c478bd9Sstevel@tonic-gate void
s1394_insert_q_asynch_cmd(s1394_hal_t * hal,cmd1394_cmd_t * cmd)5087c478bd9Sstevel@tonic-gate s1394_insert_q_asynch_cmd(s1394_hal_t *hal, cmd1394_cmd_t *cmd)
5097c478bd9Sstevel@tonic-gate {
5107c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *s_priv;
5117c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *c_priv;
5127c478bd9Sstevel@tonic-gate cmd1394_cmd_t *temp_cmd;
5137c478bd9Sstevel@tonic-gate
5147c478bd9Sstevel@tonic-gate mutex_enter(&hal->outstanding_q_mutex);
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate /* Get the Services Layer private area */
5177c478bd9Sstevel@tonic-gate s_priv = S1394_GET_CMD_PRIV(cmd);
5187c478bd9Sstevel@tonic-gate
5197c478bd9Sstevel@tonic-gate /* Is the outstanding request queue empty? */
5207c478bd9Sstevel@tonic-gate if ((hal->outstanding_q_head == NULL) &&
5217c478bd9Sstevel@tonic-gate (hal->outstanding_q_tail == NULL)) {
5227c478bd9Sstevel@tonic-gate
5237c478bd9Sstevel@tonic-gate hal->outstanding_q_head = (cmd1394_cmd_t *)cmd;
5247c478bd9Sstevel@tonic-gate hal->outstanding_q_tail = (cmd1394_cmd_t *)cmd;
5257c478bd9Sstevel@tonic-gate s_priv->cmd_priv_next = (cmd1394_cmd_t *)NULL;
5267c478bd9Sstevel@tonic-gate s_priv->cmd_priv_prev = (cmd1394_cmd_t *)NULL;
5277c478bd9Sstevel@tonic-gate
5287c478bd9Sstevel@tonic-gate } else {
5297c478bd9Sstevel@tonic-gate s_priv->cmd_priv_next = hal->outstanding_q_head;
5307c478bd9Sstevel@tonic-gate s_priv->cmd_priv_prev = (cmd1394_cmd_t *)NULL;
5317c478bd9Sstevel@tonic-gate
5327c478bd9Sstevel@tonic-gate temp_cmd = (cmd1394_cmd_t *)hal->outstanding_q_head;
5337c478bd9Sstevel@tonic-gate c_priv = (s1394_cmd_priv_t *)((uchar_t *)temp_cmd +
5347c478bd9Sstevel@tonic-gate sizeof (cmd1394_cmd_t));
5357c478bd9Sstevel@tonic-gate c_priv->cmd_priv_prev = (cmd1394_cmd_t *)cmd;
5367c478bd9Sstevel@tonic-gate
5377c478bd9Sstevel@tonic-gate hal->outstanding_q_head = (cmd1394_cmd_t *)cmd;
5387c478bd9Sstevel@tonic-gate }
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate mutex_exit(&hal->outstanding_q_mutex);
5417c478bd9Sstevel@tonic-gate }
5427c478bd9Sstevel@tonic-gate
5437c478bd9Sstevel@tonic-gate /*
5447c478bd9Sstevel@tonic-gate * s1394_remove_q_asynch_cmd()
5457c478bd9Sstevel@tonic-gate * is used to remove a given command structure from a HAL's outstanding
5467c478bd9Sstevel@tonic-gate * asynch queue.
5477c478bd9Sstevel@tonic-gate */
5487c478bd9Sstevel@tonic-gate void
s1394_remove_q_asynch_cmd(s1394_hal_t * hal,cmd1394_cmd_t * cmd)5497c478bd9Sstevel@tonic-gate s1394_remove_q_asynch_cmd(s1394_hal_t *hal, cmd1394_cmd_t *cmd)
5507c478bd9Sstevel@tonic-gate {
5517c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *s_priv;
5527c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *c_priv;
5537c478bd9Sstevel@tonic-gate cmd1394_cmd_t *prev_cmd;
5547c478bd9Sstevel@tonic-gate cmd1394_cmd_t *next_cmd;
5557c478bd9Sstevel@tonic-gate
5567c478bd9Sstevel@tonic-gate mutex_enter(&hal->outstanding_q_mutex);
5577c478bd9Sstevel@tonic-gate
5587c478bd9Sstevel@tonic-gate /* Get the Services Layer private area */
5597c478bd9Sstevel@tonic-gate s_priv = S1394_GET_CMD_PRIV(cmd);
5607c478bd9Sstevel@tonic-gate
5617c478bd9Sstevel@tonic-gate prev_cmd = (cmd1394_cmd_t *)s_priv->cmd_priv_prev;
5627c478bd9Sstevel@tonic-gate next_cmd = (cmd1394_cmd_t *)s_priv->cmd_priv_next;
5637c478bd9Sstevel@tonic-gate
5647c478bd9Sstevel@tonic-gate s_priv->cmd_priv_prev = (cmd1394_cmd_t *)NULL;
5657c478bd9Sstevel@tonic-gate s_priv->cmd_priv_next = (cmd1394_cmd_t *)NULL;
5667c478bd9Sstevel@tonic-gate
5677c478bd9Sstevel@tonic-gate if (prev_cmd != NULL) {
5687c478bd9Sstevel@tonic-gate c_priv = (s1394_cmd_priv_t *)((uchar_t *)prev_cmd +
5697c478bd9Sstevel@tonic-gate sizeof (cmd1394_cmd_t));
5707c478bd9Sstevel@tonic-gate c_priv->cmd_priv_next = (cmd1394_cmd_t *)next_cmd;
5717c478bd9Sstevel@tonic-gate
5727c478bd9Sstevel@tonic-gate } else {
5737c478bd9Sstevel@tonic-gate if (hal->outstanding_q_head == (cmd1394_cmd_t *)cmd)
5747c478bd9Sstevel@tonic-gate hal->outstanding_q_head = (cmd1394_cmd_t *)next_cmd;
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate
5777c478bd9Sstevel@tonic-gate if (next_cmd != NULL) {
5787c478bd9Sstevel@tonic-gate c_priv = (s1394_cmd_priv_t *)((uchar_t *)next_cmd +
5797c478bd9Sstevel@tonic-gate sizeof (cmd1394_cmd_t));
5807c478bd9Sstevel@tonic-gate c_priv->cmd_priv_prev = (cmd1394_cmd_t *)prev_cmd;
5817c478bd9Sstevel@tonic-gate
5827c478bd9Sstevel@tonic-gate } else {
5837c478bd9Sstevel@tonic-gate if (hal->outstanding_q_tail == (cmd1394_cmd_t *)cmd)
5847c478bd9Sstevel@tonic-gate hal->outstanding_q_tail = (cmd1394_cmd_t *)prev_cmd;
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate
5877c478bd9Sstevel@tonic-gate mutex_exit(&hal->outstanding_q_mutex);
5887c478bd9Sstevel@tonic-gate }
5897c478bd9Sstevel@tonic-gate
5907c478bd9Sstevel@tonic-gate /*
5917c478bd9Sstevel@tonic-gate * s1394_atreq_cmd_complete()
5927c478bd9Sstevel@tonic-gate * is called by h1394_cmd_is_complete() when an AT request has completed.
5937c478bd9Sstevel@tonic-gate * Based upon a command's completion status, s1394_atreq_cmd_complete()
5947c478bd9Sstevel@tonic-gate * determines whether to call the target (or unblock), put the command onto
5957c478bd9Sstevel@tonic-gate * the pending Q to be sent out later, or to resend the command
5967c478bd9Sstevel@tonic-gate * (multi-part command).
5977c478bd9Sstevel@tonic-gate */
5987c478bd9Sstevel@tonic-gate void
s1394_atreq_cmd_complete(s1394_hal_t * hal,cmd1394_cmd_t * req,int status)5997c478bd9Sstevel@tonic-gate s1394_atreq_cmd_complete(s1394_hal_t *hal, cmd1394_cmd_t *req, int status)
6007c478bd9Sstevel@tonic-gate {
6017c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *s_priv;
6027c478bd9Sstevel@tonic-gate h1394_cmd_priv_t *h_priv;
6037c478bd9Sstevel@tonic-gate dev_info_t *dip;
6047c478bd9Sstevel@tonic-gate int ret;
6057c478bd9Sstevel@tonic-gate int cmd_result;
6067c478bd9Sstevel@tonic-gate int err;
6077c478bd9Sstevel@tonic-gate
6087c478bd9Sstevel@tonic-gate /* Get the Services Layer private area */
6097c478bd9Sstevel@tonic-gate s_priv = S1394_GET_CMD_PRIV(req);
6107c478bd9Sstevel@tonic-gate
6117c478bd9Sstevel@tonic-gate /* If not an ack_complete... */
6127c478bd9Sstevel@tonic-gate if (status != H1394_CMD_SUCCESS) {
6137c478bd9Sstevel@tonic-gate /* kstats - number of failure AT responses */
6147c478bd9Sstevel@tonic-gate switch (req->cmd_type) {
6157c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_RD_QUAD:
6167c478bd9Sstevel@tonic-gate hal->hal_kstats->atresp_quad_rd_fail++;
6177c478bd9Sstevel@tonic-gate break;
6187c478bd9Sstevel@tonic-gate
6197c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_RD_BLOCK:
6207c478bd9Sstevel@tonic-gate hal->hal_kstats->atresp_blk_rd_fail++;
6217c478bd9Sstevel@tonic-gate break;
6227c478bd9Sstevel@tonic-gate
6237c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_WR_QUAD:
6247c478bd9Sstevel@tonic-gate hal->hal_kstats->atresp_quad_wr_fail++;
6257c478bd9Sstevel@tonic-gate break;
6267c478bd9Sstevel@tonic-gate
6277c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_WR_BLOCK:
6287c478bd9Sstevel@tonic-gate hal->hal_kstats->atresp_blk_wr_fail++;
6297c478bd9Sstevel@tonic-gate break;
6307c478bd9Sstevel@tonic-gate
6317c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_LOCK_32:
6327c478bd9Sstevel@tonic-gate hal->hal_kstats->atresp_lock32_fail++;
6337c478bd9Sstevel@tonic-gate break;
6347c478bd9Sstevel@tonic-gate
6357c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_LOCK_64:
6367c478bd9Sstevel@tonic-gate hal->hal_kstats->atresp_lock64_fail++;
6377c478bd9Sstevel@tonic-gate break;
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate
6407c478bd9Sstevel@tonic-gate
6417c478bd9Sstevel@tonic-gate switch (status) {
6427c478bd9Sstevel@tonic-gate /* evt_missing_ack */
6437c478bd9Sstevel@tonic-gate case H1394_CMD_ETIMEOUT:
6447c478bd9Sstevel@tonic-gate cmd_result = CMD1394_ETIMEOUT;
6457c478bd9Sstevel@tonic-gate break;
6467c478bd9Sstevel@tonic-gate
6477c478bd9Sstevel@tonic-gate /* evt_flushed */
6487c478bd9Sstevel@tonic-gate case H1394_CMD_EBUSRESET:
6497c478bd9Sstevel@tonic-gate /* Move request to pending Q if cancel on */
6507c478bd9Sstevel@tonic-gate /* reset is not set */
6517c478bd9Sstevel@tonic-gate if (req->cmd_options & CMD1394_CANCEL_ON_BUS_RESET) {
6527c478bd9Sstevel@tonic-gate cmd_result = CMD1394_EBUSRESET;
6537c478bd9Sstevel@tonic-gate break;
6547c478bd9Sstevel@tonic-gate }
6557c478bd9Sstevel@tonic-gate s1394_remove_q_asynch_cmd(hal, req);
6567c478bd9Sstevel@tonic-gate s1394_pending_q_insert(hal, req, S1394_PENDING_Q_REAR);
6577c478bd9Sstevel@tonic-gate return;
6587c478bd9Sstevel@tonic-gate
6597c478bd9Sstevel@tonic-gate /* ack_busy_X */
6607c478bd9Sstevel@tonic-gate /* ack_busy_A */
6617c478bd9Sstevel@tonic-gate /* ack_busy_B */
6627c478bd9Sstevel@tonic-gate case H1394_CMD_EDEVICE_BUSY:
6637c478bd9Sstevel@tonic-gate cmd_result = CMD1394_EDEVICE_BUSY;
6647c478bd9Sstevel@tonic-gate break;
6657c478bd9Sstevel@tonic-gate
6667c478bd9Sstevel@tonic-gate /* ack_data_error */
6677c478bd9Sstevel@tonic-gate case H1394_CMD_EDATA_ERROR:
6687c478bd9Sstevel@tonic-gate cmd_result = CMD1394_EDATA_ERROR;
6697c478bd9Sstevel@tonic-gate break;
6707c478bd9Sstevel@tonic-gate
6717c478bd9Sstevel@tonic-gate /* ack_type_error */
6727c478bd9Sstevel@tonic-gate case H1394_CMD_ETYPE_ERROR:
6737c478bd9Sstevel@tonic-gate cmd_result = CMD1394_ETYPE_ERROR;
6747c478bd9Sstevel@tonic-gate break;
6757c478bd9Sstevel@tonic-gate
6767c478bd9Sstevel@tonic-gate /* resp_address_error */
6777c478bd9Sstevel@tonic-gate /* ack_address_error */
6787c478bd9Sstevel@tonic-gate case H1394_CMD_EADDR_ERROR:
6797c478bd9Sstevel@tonic-gate cmd_result = CMD1394_EADDRESS_ERROR;
6807c478bd9Sstevel@tonic-gate break;
6817c478bd9Sstevel@tonic-gate
6827c478bd9Sstevel@tonic-gate /* resp_conflict_error */
6837c478bd9Sstevel@tonic-gate /* ack_conflict_error */
6847c478bd9Sstevel@tonic-gate case H1394_CMD_ERSRC_CONFLICT:
6857c478bd9Sstevel@tonic-gate cmd_result = CMD1394_ERSRC_CONFLICT;
6867c478bd9Sstevel@tonic-gate break;
6877c478bd9Sstevel@tonic-gate
6887c478bd9Sstevel@tonic-gate /* ack_tardy */
6897c478bd9Sstevel@tonic-gate case H1394_CMD_EDEVICE_POWERUP:
6907c478bd9Sstevel@tonic-gate cmd_result = CMD1394_EDEVICE_BUSY;
6917c478bd9Sstevel@tonic-gate break;
6927c478bd9Sstevel@tonic-gate
6937c478bd9Sstevel@tonic-gate /* device errors (bad tcodes, ACKs, etc...) */
6947c478bd9Sstevel@tonic-gate case H1394_CMD_EDEVICE_ERROR:
6957c478bd9Sstevel@tonic-gate cmd_result = CMD1394_EDEVICE_ERROR;
6967c478bd9Sstevel@tonic-gate break;
6977c478bd9Sstevel@tonic-gate
6987c478bd9Sstevel@tonic-gate /* Unknown error type */
6997c478bd9Sstevel@tonic-gate case H1394_CMD_EUNKNOWN_ERROR:
7007c478bd9Sstevel@tonic-gate cmd_result = CMD1394_EUNKNOWN_ERROR;
7017c478bd9Sstevel@tonic-gate break;
7027c478bd9Sstevel@tonic-gate
7037c478bd9Sstevel@tonic-gate /* Unrecognized error */
7047c478bd9Sstevel@tonic-gate default:
7057c478bd9Sstevel@tonic-gate dip = hal->halinfo.dip;
7067c478bd9Sstevel@tonic-gate
7077c478bd9Sstevel@tonic-gate /* An unexpected error in the HAL */
7087c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
7097c478bd9Sstevel@tonic-gate ddi_node_name(dip), ddi_get_instance(dip));
7107c478bd9Sstevel@tonic-gate
7117c478bd9Sstevel@tonic-gate /* Disable the HAL */
7127c478bd9Sstevel@tonic-gate s1394_hal_shutdown(hal, B_TRUE);
7137c478bd9Sstevel@tonic-gate
7147c478bd9Sstevel@tonic-gate return;
7157c478bd9Sstevel@tonic-gate }
7167c478bd9Sstevel@tonic-gate
7177c478bd9Sstevel@tonic-gate /* Remove command from the HAL's outstanding request Q */
7187c478bd9Sstevel@tonic-gate s1394_remove_q_asynch_cmd(hal, req);
7197c478bd9Sstevel@tonic-gate
7207c478bd9Sstevel@tonic-gate s_priv->cmd_in_use = B_FALSE;
7217c478bd9Sstevel@tonic-gate
7227c478bd9Sstevel@tonic-gate req->cmd_result = cmd_result;
7237c478bd9Sstevel@tonic-gate
7247c478bd9Sstevel@tonic-gate /* Is this a blocking command? */
7257c478bd9Sstevel@tonic-gate if (req->cmd_options & CMD1394_BLOCKING) {
7267c478bd9Sstevel@tonic-gate /* Unblock the waiting command */
7277c478bd9Sstevel@tonic-gate mutex_enter(&s_priv->blocking_mutex);
7287c478bd9Sstevel@tonic-gate s_priv->blocking_flag = B_TRUE;
7297c478bd9Sstevel@tonic-gate cv_signal(&s_priv->blocking_cv);
7307c478bd9Sstevel@tonic-gate mutex_exit(&s_priv->blocking_mutex);
7317c478bd9Sstevel@tonic-gate
7327c478bd9Sstevel@tonic-gate return;
7337c478bd9Sstevel@tonic-gate }
7347c478bd9Sstevel@tonic-gate
7357c478bd9Sstevel@tonic-gate /* Call the target's completion_callback() */
7367c478bd9Sstevel@tonic-gate if (req->completion_callback != NULL) {
7377c478bd9Sstevel@tonic-gate req->completion_callback(req);
7387c478bd9Sstevel@tonic-gate }
7397c478bd9Sstevel@tonic-gate
7407c478bd9Sstevel@tonic-gate return;
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate
7437c478bd9Sstevel@tonic-gate /* Successful unless otherwise modified */
7447c478bd9Sstevel@tonic-gate err = CMD1394_CMDSUCCESS;
7457c478bd9Sstevel@tonic-gate
7467c478bd9Sstevel@tonic-gate if ((req->cmd_type == CMD1394_ASYNCH_RD_BLOCK) ||
7477c478bd9Sstevel@tonic-gate (req->cmd_type == CMD1394_ASYNCH_WR_BLOCK)) {
7487c478bd9Sstevel@tonic-gate
7497c478bd9Sstevel@tonic-gate /* Get a pointer to the HAL private struct */
7507c478bd9Sstevel@tonic-gate h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
7517c478bd9Sstevel@tonic-gate
7527c478bd9Sstevel@tonic-gate /* Update data_remaining */
7537c478bd9Sstevel@tonic-gate s_priv->data_remaining -= h_priv->mblk.length;
7547c478bd9Sstevel@tonic-gate
7557c478bd9Sstevel@tonic-gate /* Increment bytes_transferred */
7567c478bd9Sstevel@tonic-gate req->cmd_u.b.bytes_transferred += h_priv->mblk.length;
7577c478bd9Sstevel@tonic-gate
7587c478bd9Sstevel@tonic-gate if (req->cmd_type == CMD1394_ASYNCH_RD_BLOCK)
7597c478bd9Sstevel@tonic-gate hal->hal_kstats->atreq_blk_rd_size +=
7607c478bd9Sstevel@tonic-gate h_priv->mblk.length;
7617c478bd9Sstevel@tonic-gate
7627c478bd9Sstevel@tonic-gate /* Is there still more to send? */
7637c478bd9Sstevel@tonic-gate if (s_priv->data_remaining > 0) {
7647c478bd9Sstevel@tonic-gate
7657c478bd9Sstevel@tonic-gate /* Setup the new mblk and offset */
7667c478bd9Sstevel@tonic-gate h_priv->mblk.curr_mblk = h_priv->mblk.next_mblk;
7677c478bd9Sstevel@tonic-gate h_priv->mblk.curr_offset = h_priv->mblk.next_offset;
7687c478bd9Sstevel@tonic-gate
7697c478bd9Sstevel@tonic-gate /* Update destination address */
7707c478bd9Sstevel@tonic-gate if (!(req->cmd_options &
7717c478bd9Sstevel@tonic-gate CMD1394_DISABLE_ADDR_INCREMENT)) {
7727c478bd9Sstevel@tonic-gate req->cmd_addr += h_priv->mblk.length;
7737c478bd9Sstevel@tonic-gate }
7747c478bd9Sstevel@tonic-gate
7757c478bd9Sstevel@tonic-gate /*
7767c478bd9Sstevel@tonic-gate * Use the current MAX_PAYLOAD size. This value
7777c478bd9Sstevel@tonic-gate * doesn't need to be recalculated because we must
7787c478bd9Sstevel@tonic-gate * be in the same generation on the bus, else we
7797c478bd9Sstevel@tonic-gate * would have seen a bus reset error.
7807c478bd9Sstevel@tonic-gate */
7817c478bd9Sstevel@tonic-gate if (s_priv->data_remaining < h_priv->mblk.length) {
7827c478bd9Sstevel@tonic-gate h_priv->mblk.length = s_priv->data_remaining;
7837c478bd9Sstevel@tonic-gate }
7847c478bd9Sstevel@tonic-gate
7857c478bd9Sstevel@tonic-gate /* Send command out again */
7867c478bd9Sstevel@tonic-gate ret = s1394_xfer_asynch_command(hal, req, &err);
7877c478bd9Sstevel@tonic-gate
7887c478bd9Sstevel@tonic-gate if (ret == DDI_SUCCESS) {
7897c478bd9Sstevel@tonic-gate return;
7907c478bd9Sstevel@tonic-gate
7917c478bd9Sstevel@tonic-gate } else if (err == CMD1394_ESTALE_GENERATION) {
7927c478bd9Sstevel@tonic-gate /* Remove cmd from outstanding request Q */
7937c478bd9Sstevel@tonic-gate s1394_remove_q_asynch_cmd(hal, req);
7947c478bd9Sstevel@tonic-gate s1394_pending_q_insert(hal, req,
7957c478bd9Sstevel@tonic-gate S1394_PENDING_Q_REAR);
7967c478bd9Sstevel@tonic-gate
7977c478bd9Sstevel@tonic-gate return;
7987c478bd9Sstevel@tonic-gate }
7997c478bd9Sstevel@tonic-gate }
8007c478bd9Sstevel@tonic-gate }
8017c478bd9Sstevel@tonic-gate
8027c478bd9Sstevel@tonic-gate /* Remove command from the HAL's outstanding request Q */
8037c478bd9Sstevel@tonic-gate s1394_remove_q_asynch_cmd(hal, req);
8047c478bd9Sstevel@tonic-gate
8057c478bd9Sstevel@tonic-gate s_priv->cmd_in_use = B_FALSE;
8067c478bd9Sstevel@tonic-gate
8077c478bd9Sstevel@tonic-gate /* Set status */
8087c478bd9Sstevel@tonic-gate req->cmd_result = err;
8097c478bd9Sstevel@tonic-gate
8107c478bd9Sstevel@tonic-gate /* Is this a blocking command? */
8117c478bd9Sstevel@tonic-gate if (req->cmd_options & CMD1394_BLOCKING) {
8127c478bd9Sstevel@tonic-gate /* Unblock the waiting command */
8137c478bd9Sstevel@tonic-gate mutex_enter(&s_priv->blocking_mutex);
8147c478bd9Sstevel@tonic-gate s_priv->blocking_flag = B_TRUE;
8157c478bd9Sstevel@tonic-gate cv_signal(&s_priv->blocking_cv);
8167c478bd9Sstevel@tonic-gate mutex_exit(&s_priv->blocking_mutex);
8177c478bd9Sstevel@tonic-gate
8187c478bd9Sstevel@tonic-gate return;
8197c478bd9Sstevel@tonic-gate }
8207c478bd9Sstevel@tonic-gate
8217c478bd9Sstevel@tonic-gate /* Set status and call completion_callback() */
8227c478bd9Sstevel@tonic-gate if (req->completion_callback != NULL) {
8237c478bd9Sstevel@tonic-gate
8247c478bd9Sstevel@tonic-gate req->completion_callback(req);
8257c478bd9Sstevel@tonic-gate
8267c478bd9Sstevel@tonic-gate return;
8277c478bd9Sstevel@tonic-gate }
8287c478bd9Sstevel@tonic-gate }
8297c478bd9Sstevel@tonic-gate
8307c478bd9Sstevel@tonic-gate /*
8317c478bd9Sstevel@tonic-gate * s1394_atresp_cmd_complete()
8327c478bd9Sstevel@tonic-gate * is similar to s1394_atreq_cmd_complete(). It is also called by
8337c478bd9Sstevel@tonic-gate * h1394_cmd_is_complete(), but when an AT response has completed.
8347c478bd9Sstevel@tonic-gate * Again, based upon the command's completion status,
8357c478bd9Sstevel@tonic-gate * s1394_atresp_cmd_complete() determines whether to call the target or
8367c478bd9Sstevel@tonic-gate * to simply cleanup the command and return.
8377c478bd9Sstevel@tonic-gate */
8387c478bd9Sstevel@tonic-gate void
s1394_atresp_cmd_complete(s1394_hal_t * hal,cmd1394_cmd_t * resp,int status)8397c478bd9Sstevel@tonic-gate s1394_atresp_cmd_complete(s1394_hal_t *hal, cmd1394_cmd_t *resp, int status)
8407c478bd9Sstevel@tonic-gate {
8417c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *s_priv;
8427c478bd9Sstevel@tonic-gate h1394_cmd_priv_t *h_priv;
8437c478bd9Sstevel@tonic-gate dev_info_t *dip;
8447c478bd9Sstevel@tonic-gate boolean_t valid_addr_blk;
8457c478bd9Sstevel@tonic-gate int target_status;
8467c478bd9Sstevel@tonic-gate
8477c478bd9Sstevel@tonic-gate target_status = CMD1394_CMDSUCCESS;
8487c478bd9Sstevel@tonic-gate
8497c478bd9Sstevel@tonic-gate /* If not an ack_complete */
8507c478bd9Sstevel@tonic-gate if (status != H1394_CMD_SUCCESS) {
8517c478bd9Sstevel@tonic-gate switch (status) {
8527c478bd9Sstevel@tonic-gate /* evt_missing_ack */
8537c478bd9Sstevel@tonic-gate case H1394_CMD_ETIMEOUT:
8547c478bd9Sstevel@tonic-gate target_status = CMD1394_ETIMEOUT;
8557c478bd9Sstevel@tonic-gate break;
8567c478bd9Sstevel@tonic-gate
8577c478bd9Sstevel@tonic-gate /* evt_flushed */
8587c478bd9Sstevel@tonic-gate case H1394_CMD_EBUSRESET:
8597c478bd9Sstevel@tonic-gate target_status = CMD1394_EBUSRESET;
8607c478bd9Sstevel@tonic-gate break;
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate /* ack_busy_X */
8637c478bd9Sstevel@tonic-gate /* ack_busy_A */
8647c478bd9Sstevel@tonic-gate /* ack_busy_B */
8657c478bd9Sstevel@tonic-gate case H1394_CMD_EDEVICE_BUSY:
8667c478bd9Sstevel@tonic-gate target_status = CMD1394_EDEVICE_BUSY;
8677c478bd9Sstevel@tonic-gate break;
8687c478bd9Sstevel@tonic-gate
8697c478bd9Sstevel@tonic-gate /* ack_data_error */
8707c478bd9Sstevel@tonic-gate case H1394_CMD_EDATA_ERROR:
8717c478bd9Sstevel@tonic-gate target_status = CMD1394_EDATA_ERROR;
8727c478bd9Sstevel@tonic-gate break;
8737c478bd9Sstevel@tonic-gate
8747c478bd9Sstevel@tonic-gate /* ack_type_error */
8757c478bd9Sstevel@tonic-gate case H1394_CMD_ETYPE_ERROR:
8767c478bd9Sstevel@tonic-gate target_status = CMD1394_ETYPE_ERROR;
8777c478bd9Sstevel@tonic-gate break;
8787c478bd9Sstevel@tonic-gate
8797c478bd9Sstevel@tonic-gate /* ack_address_error */
8807c478bd9Sstevel@tonic-gate case H1394_CMD_EADDR_ERROR:
8817c478bd9Sstevel@tonic-gate target_status = CMD1394_EADDRESS_ERROR;
8827c478bd9Sstevel@tonic-gate break;
8837c478bd9Sstevel@tonic-gate
8847c478bd9Sstevel@tonic-gate /* ack_conflict_error */
8857c478bd9Sstevel@tonic-gate case H1394_CMD_ERSRC_CONFLICT:
8867c478bd9Sstevel@tonic-gate target_status = CMD1394_ERSRC_CONFLICT;
8877c478bd9Sstevel@tonic-gate break;
8887c478bd9Sstevel@tonic-gate
8897c478bd9Sstevel@tonic-gate /* ack_tardy */
8907c478bd9Sstevel@tonic-gate case H1394_CMD_EDEVICE_POWERUP:
8917c478bd9Sstevel@tonic-gate target_status = CMD1394_EDEVICE_BUSY;
8927c478bd9Sstevel@tonic-gate break;
8937c478bd9Sstevel@tonic-gate
8947c478bd9Sstevel@tonic-gate /* device errors (bad tcodes, ACKs, etc...) */
8957c478bd9Sstevel@tonic-gate case H1394_CMD_EDEVICE_ERROR:
8967c478bd9Sstevel@tonic-gate target_status = CMD1394_EDEVICE_ERROR;
8977c478bd9Sstevel@tonic-gate break;
8987c478bd9Sstevel@tonic-gate
8997c478bd9Sstevel@tonic-gate /* Unknown error type */
9007c478bd9Sstevel@tonic-gate case H1394_CMD_EUNKNOWN_ERROR:
9017c478bd9Sstevel@tonic-gate target_status = CMD1394_EUNKNOWN_ERROR;
9027c478bd9Sstevel@tonic-gate break;
9037c478bd9Sstevel@tonic-gate
9047c478bd9Sstevel@tonic-gate /* Unrecognized error */
9057c478bd9Sstevel@tonic-gate default:
9067c478bd9Sstevel@tonic-gate dip = hal->halinfo.dip;
9077c478bd9Sstevel@tonic-gate
9087c478bd9Sstevel@tonic-gate /* An unexpected error in the HAL */
9097c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
9107c478bd9Sstevel@tonic-gate ddi_node_name(dip), ddi_get_instance(dip));
9117c478bd9Sstevel@tonic-gate
9127c478bd9Sstevel@tonic-gate /* Disable the HAL */
9137c478bd9Sstevel@tonic-gate s1394_hal_shutdown(hal, B_TRUE);
9147c478bd9Sstevel@tonic-gate
9157c478bd9Sstevel@tonic-gate return;
9167c478bd9Sstevel@tonic-gate }
9177c478bd9Sstevel@tonic-gate }
9187c478bd9Sstevel@tonic-gate
9197c478bd9Sstevel@tonic-gate /* Get the Services Layer private area */
9207c478bd9Sstevel@tonic-gate s_priv = S1394_GET_CMD_PRIV(resp);
9217c478bd9Sstevel@tonic-gate
9227c478bd9Sstevel@tonic-gate /* Get a pointer to the HAL private struct */
9237c478bd9Sstevel@tonic-gate h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
9247c478bd9Sstevel@tonic-gate
9257c478bd9Sstevel@tonic-gate valid_addr_blk = s_priv->arreq_valid_addr;
9267c478bd9Sstevel@tonic-gate
9277c478bd9Sstevel@tonic-gate if (valid_addr_blk == B_TRUE) {
9287c478bd9Sstevel@tonic-gate /* Set the command status */
9297c478bd9Sstevel@tonic-gate resp->cmd_result = target_status;
9307c478bd9Sstevel@tonic-gate
9317c478bd9Sstevel@tonic-gate switch (s_priv->cmd_priv_xfer_type) {
9327c478bd9Sstevel@tonic-gate case S1394_CMD_READ:
9337c478bd9Sstevel@tonic-gate case S1394_CMD_WRITE:
9347c478bd9Sstevel@tonic-gate case S1394_CMD_LOCK:
9357c478bd9Sstevel@tonic-gate if (resp->completion_callback != NULL) {
9367c478bd9Sstevel@tonic-gate resp->completion_callback(resp);
9377c478bd9Sstevel@tonic-gate }
9387c478bd9Sstevel@tonic-gate break;
9397c478bd9Sstevel@tonic-gate
9407c478bd9Sstevel@tonic-gate default:
9417c478bd9Sstevel@tonic-gate dip = hal->halinfo.dip;
9427c478bd9Sstevel@tonic-gate
9437c478bd9Sstevel@tonic-gate /* An unexpected error in the HAL */
9447c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
9457c478bd9Sstevel@tonic-gate ddi_node_name(dip), ddi_get_instance(dip));
9467c478bd9Sstevel@tonic-gate
9477c478bd9Sstevel@tonic-gate /* Disable the HAL */
9487c478bd9Sstevel@tonic-gate s1394_hal_shutdown(hal, B_TRUE);
9497c478bd9Sstevel@tonic-gate
9507c478bd9Sstevel@tonic-gate return;
9517c478bd9Sstevel@tonic-gate }
9527c478bd9Sstevel@tonic-gate }
9537c478bd9Sstevel@tonic-gate
9547c478bd9Sstevel@tonic-gate /* Free the command - Pass it back to the HAL */
9557c478bd9Sstevel@tonic-gate HAL_CALL(hal).response_complete(hal->halinfo.hal_private, resp, h_priv);
9567c478bd9Sstevel@tonic-gate }
9577c478bd9Sstevel@tonic-gate
9587c478bd9Sstevel@tonic-gate /*
9597c478bd9Sstevel@tonic-gate * s1394_send_response()
9607c478bd9Sstevel@tonic-gate * is used to send a response to an AR request. Depending on whether the
9617c478bd9Sstevel@tonic-gate * request was a broadcast request, a write to posted write address space,
9627c478bd9Sstevel@tonic-gate * or some other request, either a response packet is sent, or the command
9637c478bd9Sstevel@tonic-gate * is returned to the HAL. A return value of DDI_SUCCESS means that the
9647c478bd9Sstevel@tonic-gate * command has been handled correctly. It was either successfully sent to
9657c478bd9Sstevel@tonic-gate * the HAL, or, if it was posted_write of broadcast, it was freed up. A
9667c478bd9Sstevel@tonic-gate * return value of DDI_FAILURE indicates either a serious error, in which
9677c478bd9Sstevel@tonic-gate * case the HAL is shutdown, or a failure returned by the HAL, in which
9687c478bd9Sstevel@tonic-gate * case the command is freed up and notice of the failure is returned.
9697c478bd9Sstevel@tonic-gate */
9707c478bd9Sstevel@tonic-gate int
s1394_send_response(s1394_hal_t * hal,cmd1394_cmd_t * resp)9717c478bd9Sstevel@tonic-gate s1394_send_response(s1394_hal_t *hal, cmd1394_cmd_t *resp)
9727c478bd9Sstevel@tonic-gate {
9737c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *s_priv;
9747c478bd9Sstevel@tonic-gate h1394_cmd_priv_t *h_priv;
9757c478bd9Sstevel@tonic-gate dev_info_t *dip;
9767c478bd9Sstevel@tonic-gate int ret;
9777c478bd9Sstevel@tonic-gate int result;
9787c478bd9Sstevel@tonic-gate
9797c478bd9Sstevel@tonic-gate /* Get the Services Layer private area */
9807c478bd9Sstevel@tonic-gate s_priv = S1394_GET_CMD_PRIV(resp);
9817c478bd9Sstevel@tonic-gate
9827c478bd9Sstevel@tonic-gate /* Get a pointer to the HAL private struct */
9837c478bd9Sstevel@tonic-gate h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
9847c478bd9Sstevel@tonic-gate
9857c478bd9Sstevel@tonic-gate /*
9867c478bd9Sstevel@tonic-gate * If request was broadcast or a write request to a posted write
9877c478bd9Sstevel@tonic-gate * address, don't send a response
9887c478bd9Sstevel@tonic-gate */
9897c478bd9Sstevel@tonic-gate if ((resp->broadcast == 1) || ((s_priv->posted_write == B_TRUE) &&
9907c478bd9Sstevel@tonic-gate ((resp->cmd_result == CMD1394_ASYNCH_WR_QUAD) ||
9917c478bd9Sstevel@tonic-gate (resp->cmd_result == CMD1394_ASYNCH_WR_BLOCK)))) {
9927c478bd9Sstevel@tonic-gate
9937c478bd9Sstevel@tonic-gate /* Free the command - Pass it back to the HAL */
9947c478bd9Sstevel@tonic-gate HAL_CALL(hal).response_complete(hal->halinfo.hal_private,
9957c478bd9Sstevel@tonic-gate resp, h_priv);
9967c478bd9Sstevel@tonic-gate
9977c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
9987c478bd9Sstevel@tonic-gate }
9997c478bd9Sstevel@tonic-gate
10007c478bd9Sstevel@tonic-gate /* kstats - number of failure responses sent */
10017c478bd9Sstevel@tonic-gate if (resp->cmd_result != IEEE1394_RESP_COMPLETE) {
10027c478bd9Sstevel@tonic-gate switch (resp->cmd_type) {
10037c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_RD_QUAD:
10047c478bd9Sstevel@tonic-gate hal->hal_kstats->arresp_quad_rd_fail++;
10057c478bd9Sstevel@tonic-gate break;
10067c478bd9Sstevel@tonic-gate
10077c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_RD_BLOCK:
10087c478bd9Sstevel@tonic-gate hal->hal_kstats->arresp_blk_rd_fail++;
10097c478bd9Sstevel@tonic-gate break;
10107c478bd9Sstevel@tonic-gate
10117c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_WR_QUAD:
10127c478bd9Sstevel@tonic-gate hal->hal_kstats->arresp_quad_wr_fail++;
10137c478bd9Sstevel@tonic-gate break;
10147c478bd9Sstevel@tonic-gate
10157c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_WR_BLOCK:
10167c478bd9Sstevel@tonic-gate hal->hal_kstats->arresp_blk_wr_fail++;
10177c478bd9Sstevel@tonic-gate break;
10187c478bd9Sstevel@tonic-gate
10197c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_LOCK_32:
10207c478bd9Sstevel@tonic-gate hal->hal_kstats->arresp_lock32_fail++;
10217c478bd9Sstevel@tonic-gate break;
10227c478bd9Sstevel@tonic-gate
10237c478bd9Sstevel@tonic-gate case CMD1394_ASYNCH_LOCK_64:
10247c478bd9Sstevel@tonic-gate hal->hal_kstats->arresp_lock64_fail++;
10257c478bd9Sstevel@tonic-gate break;
10267c478bd9Sstevel@tonic-gate }
10277c478bd9Sstevel@tonic-gate } else {
10287c478bd9Sstevel@tonic-gate if (resp->cmd_type == CMD1394_ASYNCH_RD_BLOCK)
10297c478bd9Sstevel@tonic-gate hal->hal_kstats->arreq_blk_rd_size +=
10307c478bd9Sstevel@tonic-gate resp->cmd_u.b.blk_length;
10317c478bd9Sstevel@tonic-gate }
10327c478bd9Sstevel@tonic-gate
10337c478bd9Sstevel@tonic-gate if (resp->cmd_type == CMD1394_ASYNCH_RD_BLOCK) {
10347c478bd9Sstevel@tonic-gate h_priv->mblk.curr_mblk = resp->cmd_u.b.data_block;
10357c478bd9Sstevel@tonic-gate h_priv->mblk.curr_offset = resp->cmd_u.b.data_block->b_rptr;
10367c478bd9Sstevel@tonic-gate h_priv->mblk.length = resp->cmd_u.b.blk_length;
10377c478bd9Sstevel@tonic-gate }
10387c478bd9Sstevel@tonic-gate
10397c478bd9Sstevel@tonic-gate switch (s_priv->cmd_priv_xfer_type) {
10407c478bd9Sstevel@tonic-gate case S1394_CMD_READ:
10417c478bd9Sstevel@tonic-gate ret = HAL_CALL(hal).read_response(hal->halinfo.hal_private,
10427c478bd9Sstevel@tonic-gate resp, h_priv, &result);
10437c478bd9Sstevel@tonic-gate break;
10447c478bd9Sstevel@tonic-gate
10457c478bd9Sstevel@tonic-gate case S1394_CMD_WRITE:
10467c478bd9Sstevel@tonic-gate ret = HAL_CALL(hal).write_response(hal->halinfo.hal_private,
10477c478bd9Sstevel@tonic-gate resp, h_priv, &result);
10487c478bd9Sstevel@tonic-gate break;
10497c478bd9Sstevel@tonic-gate
10507c478bd9Sstevel@tonic-gate case S1394_CMD_LOCK:
10517c478bd9Sstevel@tonic-gate ret = HAL_CALL(hal).lock_response(hal->halinfo.hal_private,
10527c478bd9Sstevel@tonic-gate resp, h_priv, &result);
10537c478bd9Sstevel@tonic-gate break;
10547c478bd9Sstevel@tonic-gate
10557c478bd9Sstevel@tonic-gate default:
10567c478bd9Sstevel@tonic-gate dip = hal->halinfo.dip;
10577c478bd9Sstevel@tonic-gate
10587c478bd9Sstevel@tonic-gate /* An unexpected error in the HAL */
10597c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
10607c478bd9Sstevel@tonic-gate ddi_node_name(dip), ddi_get_instance(dip));
10617c478bd9Sstevel@tonic-gate
10627c478bd9Sstevel@tonic-gate /* Disable the HAL */
10637c478bd9Sstevel@tonic-gate s1394_hal_shutdown(hal, B_TRUE);
10647c478bd9Sstevel@tonic-gate
10657c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
10667c478bd9Sstevel@tonic-gate }
10677c478bd9Sstevel@tonic-gate
10687c478bd9Sstevel@tonic-gate /* Unable to send a response */
10697c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) {
10707c478bd9Sstevel@tonic-gate /* Free the command - Pass it back to the HAL */
10717c478bd9Sstevel@tonic-gate HAL_CALL(hal).response_complete(hal->halinfo.hal_private,
10727c478bd9Sstevel@tonic-gate resp, h_priv);
10737c478bd9Sstevel@tonic-gate
10747c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
10757c478bd9Sstevel@tonic-gate }
10767c478bd9Sstevel@tonic-gate
10777c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
10787c478bd9Sstevel@tonic-gate }
10797c478bd9Sstevel@tonic-gate
10807c478bd9Sstevel@tonic-gate /*
10817c478bd9Sstevel@tonic-gate * s1394_compare_swap()
10827c478bd9Sstevel@tonic-gate * is used by t1394_lock() to send a lock request. Any of the lock
10837c478bd9Sstevel@tonic-gate * requests specified explicitly by the 1394 spec will pass thru here,
10847c478bd9Sstevel@tonic-gate * i.e compare-swap, mask-swap, etc.
10857c478bd9Sstevel@tonic-gate */
10867c478bd9Sstevel@tonic-gate int
s1394_compare_swap(s1394_hal_t * hal,s1394_target_t * target,cmd1394_cmd_t * cmd)10877c478bd9Sstevel@tonic-gate s1394_compare_swap(s1394_hal_t *hal, s1394_target_t *target, cmd1394_cmd_t *cmd)
10887c478bd9Sstevel@tonic-gate {
10897c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *s_priv;
10907c478bd9Sstevel@tonic-gate s1394_hal_state_t state;
10917c478bd9Sstevel@tonic-gate int err;
10927c478bd9Sstevel@tonic-gate int ret;
10937c478bd9Sstevel@tonic-gate
10947c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
10957c478bd9Sstevel@tonic-gate
10967c478bd9Sstevel@tonic-gate /* Lock the topology tree - protect from bus reset */
10977c478bd9Sstevel@tonic-gate mutex_enter(&hal->topology_tree_mutex);
10987c478bd9Sstevel@tonic-gate
10997c478bd9Sstevel@tonic-gate ret = s1394_setup_asynch_command(hal, target, cmd, S1394_CMD_LOCK,
11007c478bd9Sstevel@tonic-gate &err);
11017c478bd9Sstevel@tonic-gate
11027c478bd9Sstevel@tonic-gate /* Unlock the topology tree */
11037c478bd9Sstevel@tonic-gate mutex_exit(&hal->topology_tree_mutex);
11047c478bd9Sstevel@tonic-gate
11057c478bd9Sstevel@tonic-gate /* Get the Services Layer private area */
11067c478bd9Sstevel@tonic-gate s_priv = S1394_GET_CMD_PRIV(cmd);
11077c478bd9Sstevel@tonic-gate
11087c478bd9Sstevel@tonic-gate /* Command has now been put onto the queue! */
11097c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) {
11107c478bd9Sstevel@tonic-gate /* Copy error code into result */
11117c478bd9Sstevel@tonic-gate cmd->cmd_result = err;
11127c478bd9Sstevel@tonic-gate
11137c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
11147c478bd9Sstevel@tonic-gate }
11157c478bd9Sstevel@tonic-gate
11167c478bd9Sstevel@tonic-gate mutex_enter(&hal->topology_tree_mutex);
11177c478bd9Sstevel@tonic-gate state = hal->hal_state;
11187c478bd9Sstevel@tonic-gate /* If this command was sent during a bus reset, */
11197c478bd9Sstevel@tonic-gate /* then put it onto the pending Q. */
11207c478bd9Sstevel@tonic-gate if (state == S1394_HAL_RESET) {
11217c478bd9Sstevel@tonic-gate /* Remove cmd from outstanding request Q */
11227c478bd9Sstevel@tonic-gate s1394_remove_q_asynch_cmd(hal, cmd);
11237c478bd9Sstevel@tonic-gate
11247c478bd9Sstevel@tonic-gate /* Are we on the bus reset event stack? */
11257c478bd9Sstevel@tonic-gate if (s1394_on_br_thread(hal) == B_TRUE) {
11267c478bd9Sstevel@tonic-gate /* Blocking commands are not allowed */
11277c478bd9Sstevel@tonic-gate if (cmd->cmd_options & CMD1394_BLOCKING) {
11287c478bd9Sstevel@tonic-gate mutex_exit(&hal->topology_tree_mutex);
11297c478bd9Sstevel@tonic-gate
11307c478bd9Sstevel@tonic-gate s_priv->cmd_in_use = B_FALSE;
11317c478bd9Sstevel@tonic-gate
11327c478bd9Sstevel@tonic-gate cmd->cmd_result = CMD1394_EINVALID_CONTEXT;
11337c478bd9Sstevel@tonic-gate
11347c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
11357c478bd9Sstevel@tonic-gate }
11367c478bd9Sstevel@tonic-gate }
11377c478bd9Sstevel@tonic-gate
11387c478bd9Sstevel@tonic-gate s1394_pending_q_insert(hal, cmd, S1394_PENDING_Q_FRONT);
11397c478bd9Sstevel@tonic-gate mutex_exit(&hal->topology_tree_mutex);
11407c478bd9Sstevel@tonic-gate
11417c478bd9Sstevel@tonic-gate /* Block (if necessary) */
11427c478bd9Sstevel@tonic-gate s1394_block_on_asynch_cmd(cmd);
11437c478bd9Sstevel@tonic-gate
11447c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
11457c478bd9Sstevel@tonic-gate }
11467c478bd9Sstevel@tonic-gate mutex_exit(&hal->topology_tree_mutex);
11477c478bd9Sstevel@tonic-gate
11487c478bd9Sstevel@tonic-gate /* Send the command out */
11497c478bd9Sstevel@tonic-gate ret = s1394_xfer_asynch_command(hal, cmd, &err);
11507c478bd9Sstevel@tonic-gate
11517c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) {
11527c478bd9Sstevel@tonic-gate if (err == CMD1394_ESTALE_GENERATION) {
11537c478bd9Sstevel@tonic-gate /* Remove cmd from outstanding request Q */
11547c478bd9Sstevel@tonic-gate s1394_remove_q_asynch_cmd(hal, cmd);
11557c478bd9Sstevel@tonic-gate s1394_pending_q_insert(hal, cmd, S1394_PENDING_Q_FRONT);
11567c478bd9Sstevel@tonic-gate
11577c478bd9Sstevel@tonic-gate /* Block (if necessary) */
11587c478bd9Sstevel@tonic-gate s1394_block_on_asynch_cmd(cmd);
11597c478bd9Sstevel@tonic-gate
11607c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
11617c478bd9Sstevel@tonic-gate
11627c478bd9Sstevel@tonic-gate } else {
11637c478bd9Sstevel@tonic-gate /* Remove cmd from outstanding request Q */
11647c478bd9Sstevel@tonic-gate s1394_remove_q_asynch_cmd(hal, cmd);
11657c478bd9Sstevel@tonic-gate
11667c478bd9Sstevel@tonic-gate s_priv->cmd_in_use = B_FALSE;
11677c478bd9Sstevel@tonic-gate
11687c478bd9Sstevel@tonic-gate /* Copy error code into result */
11697c478bd9Sstevel@tonic-gate cmd->cmd_result = err;
11707c478bd9Sstevel@tonic-gate
11717c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
11727c478bd9Sstevel@tonic-gate }
11737c478bd9Sstevel@tonic-gate } else {
11747c478bd9Sstevel@tonic-gate /* Block (if necessary) */
11757c478bd9Sstevel@tonic-gate s1394_block_on_asynch_cmd(cmd);
11767c478bd9Sstevel@tonic-gate
11777c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
11787c478bd9Sstevel@tonic-gate }
11797c478bd9Sstevel@tonic-gate }
11807c478bd9Sstevel@tonic-gate
11817c478bd9Sstevel@tonic-gate /*
11827c478bd9Sstevel@tonic-gate * s1394_split_lock_req()
11837c478bd9Sstevel@tonic-gate * is also used by t1394_lock() to send a lock request. The difference
11847c478bd9Sstevel@tonic-gate * is that s1394_split_lock_req() is used to send the software supported
11857c478bd9Sstevel@tonic-gate * lock types, i.e. bit_and, bit_or, etc. These lock requests require
11867c478bd9Sstevel@tonic-gate * more than one transaction, typically compare-swap's.
11877c478bd9Sstevel@tonic-gate */
11887c478bd9Sstevel@tonic-gate int
s1394_split_lock_req(s1394_hal_t * hal,s1394_target_t * target,cmd1394_cmd_t * cmd)11897c478bd9Sstevel@tonic-gate s1394_split_lock_req(s1394_hal_t *hal, s1394_target_t *target,
11907c478bd9Sstevel@tonic-gate cmd1394_cmd_t *cmd)
11917c478bd9Sstevel@tonic-gate {
11927c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *s_priv;
11937c478bd9Sstevel@tonic-gate cmd1394_cmd_t *tmp_cmd;
11947c478bd9Sstevel@tonic-gate
11957c478bd9Sstevel@tonic-gate /* Allocate a temporary command */
11967c478bd9Sstevel@tonic-gate if (s1394_alloc_cmd(hal, T1394_ALLOC_CMD_NOSLEEP, &tmp_cmd) !=
11977c478bd9Sstevel@tonic-gate DDI_SUCCESS) {
11987c478bd9Sstevel@tonic-gate cmd->cmd_result = CMD1394_EUNKNOWN_ERROR;
11997c478bd9Sstevel@tonic-gate
12007c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
12017c478bd9Sstevel@tonic-gate }
12027c478bd9Sstevel@tonic-gate
12037c478bd9Sstevel@tonic-gate /* Get the Services Layer private area */
12047c478bd9Sstevel@tonic-gate s_priv = S1394_GET_CMD_PRIV(tmp_cmd);
12057c478bd9Sstevel@tonic-gate
12067c478bd9Sstevel@tonic-gate tmp_cmd->completion_callback = s1394_handle_lock;
12077c478bd9Sstevel@tonic-gate tmp_cmd->cmd_callback_arg = (opaque_t)cmd;
12087c478bd9Sstevel@tonic-gate tmp_cmd->cmd_type = cmd->cmd_type;
12097c478bd9Sstevel@tonic-gate tmp_cmd->cmd_addr = cmd->cmd_addr;
12107c478bd9Sstevel@tonic-gate tmp_cmd->cmd_options = cmd->cmd_options;
12117c478bd9Sstevel@tonic-gate tmp_cmd->bus_generation = cmd->bus_generation;
12127c478bd9Sstevel@tonic-gate
12137c478bd9Sstevel@tonic-gate /* The temporary command can not block */
12147c478bd9Sstevel@tonic-gate tmp_cmd->cmd_options = tmp_cmd->cmd_options & ~CMD1394_BLOCKING;
12157c478bd9Sstevel@tonic-gate
12167c478bd9Sstevel@tonic-gate /* Setup compare-swap with data_value == arg_value (read) */
12177c478bd9Sstevel@tonic-gate if (tmp_cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) {
12187c478bd9Sstevel@tonic-gate tmp_cmd->cmd_u.l32.data_value = 0;
12197c478bd9Sstevel@tonic-gate tmp_cmd->cmd_u.l32.arg_value = 0;
12207c478bd9Sstevel@tonic-gate tmp_cmd->cmd_u.l32.lock_type = CMD1394_LOCK_COMPARE_SWAP;
12217c478bd9Sstevel@tonic-gate s_priv->temp_num_retries = cmd->cmd_u.l32.num_retries;
12227c478bd9Sstevel@tonic-gate } else {
12237c478bd9Sstevel@tonic-gate tmp_cmd->cmd_u.l64.data_value = 0;
12247c478bd9Sstevel@tonic-gate tmp_cmd->cmd_u.l64.arg_value = 0;
12257c478bd9Sstevel@tonic-gate tmp_cmd->cmd_u.l64.lock_type = CMD1394_LOCK_COMPARE_SWAP;
12267c478bd9Sstevel@tonic-gate s_priv->temp_num_retries = cmd->cmd_u.l64.num_retries;
12277c478bd9Sstevel@tonic-gate }
12287c478bd9Sstevel@tonic-gate
12297c478bd9Sstevel@tonic-gate /* Initialize lock_req_step */
12307c478bd9Sstevel@tonic-gate s_priv->lock_req_step = 0;
12317c478bd9Sstevel@tonic-gate
12327c478bd9Sstevel@tonic-gate /* Get the Services Layer private area for the target cmd */
12337c478bd9Sstevel@tonic-gate s_priv = S1394_GET_CMD_PRIV(cmd);
12347c478bd9Sstevel@tonic-gate
12357c478bd9Sstevel@tonic-gate s_priv->cmd_in_use = B_TRUE;
12367c478bd9Sstevel@tonic-gate
12377c478bd9Sstevel@tonic-gate /* Send the request */
12387c478bd9Sstevel@tonic-gate if (s1394_compare_swap(hal, target, tmp_cmd) != DDI_SUCCESS) {
12397c478bd9Sstevel@tonic-gate s_priv->cmd_in_use = B_FALSE;
12407c478bd9Sstevel@tonic-gate
12417c478bd9Sstevel@tonic-gate /* Free the temporary command */
12427c478bd9Sstevel@tonic-gate if (s1394_free_cmd(hal, &tmp_cmd) != DDI_SUCCESS)
12437c478bd9Sstevel@tonic-gate cmd->cmd_result = CMD1394_EUNKNOWN_ERROR;
12447c478bd9Sstevel@tonic-gate
12457c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
12467c478bd9Sstevel@tonic-gate }
12477c478bd9Sstevel@tonic-gate
12487c478bd9Sstevel@tonic-gate /* Block (if necessary) */
12497c478bd9Sstevel@tonic-gate s1394_block_on_asynch_cmd(cmd);
12507c478bd9Sstevel@tonic-gate
12517c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
12527c478bd9Sstevel@tonic-gate }
12537c478bd9Sstevel@tonic-gate
12547c478bd9Sstevel@tonic-gate /*
12557c478bd9Sstevel@tonic-gate * s1394_handle_lock()
12567c478bd9Sstevel@tonic-gate * is the callback for s1394_split_lock_req(). It does all of the real
12577c478bd9Sstevel@tonic-gate * work. Based on the specific lock type all necessary manipulation is
12587c478bd9Sstevel@tonic-gate * performed and another compare swap is sent out. If the transaction
12597c478bd9Sstevel@tonic-gate * is unsuccessful, it is retried.
12607c478bd9Sstevel@tonic-gate */
12617c478bd9Sstevel@tonic-gate static void
s1394_handle_lock(cmd1394_cmd_t * cmd)12627c478bd9Sstevel@tonic-gate s1394_handle_lock(cmd1394_cmd_t *cmd)
12637c478bd9Sstevel@tonic-gate {
12647c478bd9Sstevel@tonic-gate s1394_hal_t *to_hal;
12657c478bd9Sstevel@tonic-gate s1394_target_t *target;
12667c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *s_priv;
12677c478bd9Sstevel@tonic-gate cmd1394_cmd_t *target_cmd;
12687c478bd9Sstevel@tonic-gate uint32_t lock_req_step;
12697c478bd9Sstevel@tonic-gate int tcmd_result;
12707c478bd9Sstevel@tonic-gate int ret;
12717c478bd9Sstevel@tonic-gate
12727c478bd9Sstevel@tonic-gate /* Get the Services Layer private area */
12737c478bd9Sstevel@tonic-gate s_priv = S1394_GET_CMD_PRIV(cmd);
12747c478bd9Sstevel@tonic-gate
12757c478bd9Sstevel@tonic-gate lock_req_step = s_priv->lock_req_step;
12767c478bd9Sstevel@tonic-gate
12777c478bd9Sstevel@tonic-gate /* Get the target's command */
12787c478bd9Sstevel@tonic-gate target_cmd = (cmd1394_cmd_t *)cmd->cmd_callback_arg;
12797c478bd9Sstevel@tonic-gate
12807c478bd9Sstevel@tonic-gate /* Get the destination of the command */
12817c478bd9Sstevel@tonic-gate to_hal = s_priv->sent_on_hal;
12827c478bd9Sstevel@tonic-gate
12837c478bd9Sstevel@tonic-gate lock_req_step_0:
12847c478bd9Sstevel@tonic-gate /* Is this step 0 completing? */
12857c478bd9Sstevel@tonic-gate if (lock_req_step == 0) {
12867c478bd9Sstevel@tonic-gate /* Was the request successful? */
12877c478bd9Sstevel@tonic-gate if (cmd->cmd_result == CMD1394_CMDSUCCESS) {
12887c478bd9Sstevel@tonic-gate /* Do any math, bit ops, or byte-swapping necessary */
12897c478bd9Sstevel@tonic-gate ret = s1394_process_split_lock(cmd, target_cmd);
12907c478bd9Sstevel@tonic-gate
12917c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) {
12927c478bd9Sstevel@tonic-gate tcmd_result = target_cmd->cmd_result;
12937c478bd9Sstevel@tonic-gate goto lock_req_done;
12947c478bd9Sstevel@tonic-gate }
12957c478bd9Sstevel@tonic-gate
12967c478bd9Sstevel@tonic-gate s_priv->lock_req_step = 1;
12977c478bd9Sstevel@tonic-gate
12987c478bd9Sstevel@tonic-gate target = s_priv->sent_by_target;
12997c478bd9Sstevel@tonic-gate
13007c478bd9Sstevel@tonic-gate if (s1394_compare_swap(to_hal, target, cmd) !=
13017c478bd9Sstevel@tonic-gate DDI_SUCCESS) {
13027c478bd9Sstevel@tonic-gate tcmd_result = cmd->cmd_result;
13037c478bd9Sstevel@tonic-gate goto lock_req_done;
13047c478bd9Sstevel@tonic-gate } else {
13057c478bd9Sstevel@tonic-gate return;
13067c478bd9Sstevel@tonic-gate }
13077c478bd9Sstevel@tonic-gate } else {
13087c478bd9Sstevel@tonic-gate /* Command failed for some reason */
13097c478bd9Sstevel@tonic-gate tcmd_result = cmd->cmd_result;
13107c478bd9Sstevel@tonic-gate goto lock_req_done;
13117c478bd9Sstevel@tonic-gate }
13127c478bd9Sstevel@tonic-gate } else { /* lock_req_step == 1 */
13137c478bd9Sstevel@tonic-gate /* Was the request successful? */
13147c478bd9Sstevel@tonic-gate if (cmd->cmd_result == CMD1394_CMDSUCCESS) {
13157c478bd9Sstevel@tonic-gate /* Do whatever's necessary to finish up the lock */
13167c478bd9Sstevel@tonic-gate ret = s1394_finish_split_lock(cmd, target_cmd);
13177c478bd9Sstevel@tonic-gate
13187c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) {
13197c478bd9Sstevel@tonic-gate lock_req_step = 0;
13207c478bd9Sstevel@tonic-gate goto lock_req_step_0;
13217c478bd9Sstevel@tonic-gate } else {
13227c478bd9Sstevel@tonic-gate tcmd_result = cmd->cmd_result;
13237c478bd9Sstevel@tonic-gate goto lock_req_done;
13247c478bd9Sstevel@tonic-gate }
13257c478bd9Sstevel@tonic-gate } else {
13267c478bd9Sstevel@tonic-gate /* Command failed for some reason */
13277c478bd9Sstevel@tonic-gate tcmd_result = cmd->cmd_result;
13287c478bd9Sstevel@tonic-gate goto lock_req_done;
13297c478bd9Sstevel@tonic-gate }
13307c478bd9Sstevel@tonic-gate }
13317c478bd9Sstevel@tonic-gate
13327c478bd9Sstevel@tonic-gate lock_req_done:
1333*2570281cSToomas Soome (void) s1394_free_cmd(to_hal, &cmd);
13347c478bd9Sstevel@tonic-gate
13357c478bd9Sstevel@tonic-gate /* Get the Services Layer private area */
13367c478bd9Sstevel@tonic-gate s_priv = S1394_GET_CMD_PRIV(target_cmd);
13377c478bd9Sstevel@tonic-gate
13387c478bd9Sstevel@tonic-gate s_priv->cmd_in_use = B_FALSE;
13397c478bd9Sstevel@tonic-gate
13407c478bd9Sstevel@tonic-gate target_cmd->cmd_result = tcmd_result;
13417c478bd9Sstevel@tonic-gate
13427c478bd9Sstevel@tonic-gate /* Is this a blocking command? */
13437c478bd9Sstevel@tonic-gate if (target_cmd->cmd_options & CMD1394_BLOCKING) {
13447c478bd9Sstevel@tonic-gate /* Unblock the waiting command */
13457c478bd9Sstevel@tonic-gate mutex_enter(&s_priv->blocking_mutex);
13467c478bd9Sstevel@tonic-gate s_priv->blocking_flag = B_TRUE;
13477c478bd9Sstevel@tonic-gate cv_signal(&s_priv->blocking_cv);
13487c478bd9Sstevel@tonic-gate mutex_exit(&s_priv->blocking_mutex);
13497c478bd9Sstevel@tonic-gate
13507c478bd9Sstevel@tonic-gate return;
13517c478bd9Sstevel@tonic-gate }
13527c478bd9Sstevel@tonic-gate
13537c478bd9Sstevel@tonic-gate /* Call the target's completion_callback() */
13547c478bd9Sstevel@tonic-gate if (target_cmd->completion_callback != NULL)
13557c478bd9Sstevel@tonic-gate target_cmd->completion_callback(target_cmd);
13567c478bd9Sstevel@tonic-gate }
13577c478bd9Sstevel@tonic-gate
13587c478bd9Sstevel@tonic-gate /*
13597c478bd9Sstevel@tonic-gate * s1394_pending_q_insert()
13607c478bd9Sstevel@tonic-gate * is used to insert a given command structure onto a HAL's pending queue
13617c478bd9Sstevel@tonic-gate * for later processing (after the bus reset). All commands returned by
13627c478bd9Sstevel@tonic-gate * the HAL, are inserted onto the rear of the list (first priority), and
13637c478bd9Sstevel@tonic-gate * all other commands (from targets during bus reset) are put onto the front.
13647c478bd9Sstevel@tonic-gate */
13657c478bd9Sstevel@tonic-gate void
s1394_pending_q_insert(s1394_hal_t * hal,cmd1394_cmd_t * cmd,uint_t flags)13667c478bd9Sstevel@tonic-gate s1394_pending_q_insert(s1394_hal_t *hal, cmd1394_cmd_t *cmd, uint_t flags)
13677c478bd9Sstevel@tonic-gate {
13687c478bd9Sstevel@tonic-gate cmd1394_cmd_t *temp_cmd;
13697c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *s_priv;
13707c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *c_priv;
13717c478bd9Sstevel@tonic-gate
13727c478bd9Sstevel@tonic-gate mutex_enter(&hal->pending_q_mutex);
13737c478bd9Sstevel@tonic-gate
13747c478bd9Sstevel@tonic-gate /* Get the Services Layer private area */
13757c478bd9Sstevel@tonic-gate s_priv = S1394_GET_CMD_PRIV(cmd);
13767c478bd9Sstevel@tonic-gate
13777c478bd9Sstevel@tonic-gate /* Is the outstanding request queue empty? */
13787c478bd9Sstevel@tonic-gate if ((hal->pending_q_head == NULL) && (hal->pending_q_tail == NULL)) {
13797c478bd9Sstevel@tonic-gate
13807c478bd9Sstevel@tonic-gate hal->pending_q_head = (cmd1394_cmd_t *)cmd;
13817c478bd9Sstevel@tonic-gate hal->pending_q_tail = (cmd1394_cmd_t *)cmd;
13827c478bd9Sstevel@tonic-gate s_priv->cmd_priv_next = (cmd1394_cmd_t *)NULL;
13837c478bd9Sstevel@tonic-gate s_priv->cmd_priv_prev = (cmd1394_cmd_t *)NULL;
13847c478bd9Sstevel@tonic-gate
13857c478bd9Sstevel@tonic-gate } else if (flags == S1394_PENDING_Q_FRONT) {
13867c478bd9Sstevel@tonic-gate s_priv->cmd_priv_next = hal->pending_q_head;
13877c478bd9Sstevel@tonic-gate s_priv->cmd_priv_prev = (cmd1394_cmd_t *)NULL;
13887c478bd9Sstevel@tonic-gate
13897c478bd9Sstevel@tonic-gate temp_cmd = (cmd1394_cmd_t *)hal->pending_q_head;
13907c478bd9Sstevel@tonic-gate c_priv = (s1394_cmd_priv_t *)((uchar_t *)temp_cmd +
13917c478bd9Sstevel@tonic-gate sizeof (cmd1394_cmd_t));
13927c478bd9Sstevel@tonic-gate c_priv->cmd_priv_prev = (cmd1394_cmd_t *)cmd;
13937c478bd9Sstevel@tonic-gate
13947c478bd9Sstevel@tonic-gate hal->pending_q_head = (cmd1394_cmd_t *)cmd;
13957c478bd9Sstevel@tonic-gate
13967c478bd9Sstevel@tonic-gate } else {
13977c478bd9Sstevel@tonic-gate s_priv->cmd_priv_prev = hal->pending_q_tail;
13987c478bd9Sstevel@tonic-gate s_priv->cmd_priv_next = (cmd1394_cmd_t *)NULL;
13997c478bd9Sstevel@tonic-gate
14007c478bd9Sstevel@tonic-gate temp_cmd = (cmd1394_cmd_t *)hal->pending_q_tail;
14017c478bd9Sstevel@tonic-gate c_priv = (s1394_cmd_priv_t *)((uchar_t *)temp_cmd +
14027c478bd9Sstevel@tonic-gate sizeof (cmd1394_cmd_t));
14037c478bd9Sstevel@tonic-gate c_priv->cmd_priv_next = (cmd1394_cmd_t *)cmd;
14047c478bd9Sstevel@tonic-gate
14057c478bd9Sstevel@tonic-gate hal->pending_q_tail = (cmd1394_cmd_t *)cmd;
14067c478bd9Sstevel@tonic-gate }
14077c478bd9Sstevel@tonic-gate
14087c478bd9Sstevel@tonic-gate mutex_exit(&hal->pending_q_mutex);
14097c478bd9Sstevel@tonic-gate
14107c478bd9Sstevel@tonic-gate /* kstats - number of pending Q insertions */
14117c478bd9Sstevel@tonic-gate hal->hal_kstats->pending_q_insert++;
14127c478bd9Sstevel@tonic-gate }
14137c478bd9Sstevel@tonic-gate
14147c478bd9Sstevel@tonic-gate /*
14157c478bd9Sstevel@tonic-gate * s1394_pending_q_remove()
14167c478bd9Sstevel@tonic-gate * is used to remove a command structure from a HAL's pending queue for
14177c478bd9Sstevel@tonic-gate * processing.
14187c478bd9Sstevel@tonic-gate */
14197c478bd9Sstevel@tonic-gate static cmd1394_cmd_t *
s1394_pending_q_remove(s1394_hal_t * hal)14207c478bd9Sstevel@tonic-gate s1394_pending_q_remove(s1394_hal_t *hal)
14217c478bd9Sstevel@tonic-gate {
14227c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *s_priv;
14237c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *c_priv;
14247c478bd9Sstevel@tonic-gate cmd1394_cmd_t *cmd;
14257c478bd9Sstevel@tonic-gate cmd1394_cmd_t *prev_cmd;
14267c478bd9Sstevel@tonic-gate
14277c478bd9Sstevel@tonic-gate mutex_enter(&hal->pending_q_mutex);
14287c478bd9Sstevel@tonic-gate
14297c478bd9Sstevel@tonic-gate cmd = (cmd1394_cmd_t *)hal->pending_q_tail;
14307c478bd9Sstevel@tonic-gate if (cmd == NULL) {
14317c478bd9Sstevel@tonic-gate mutex_exit(&hal->pending_q_mutex);
14327c478bd9Sstevel@tonic-gate return (NULL);
14337c478bd9Sstevel@tonic-gate }
14347c478bd9Sstevel@tonic-gate
14357c478bd9Sstevel@tonic-gate /* Get the Services Layer private area */
14367c478bd9Sstevel@tonic-gate s_priv = S1394_GET_CMD_PRIV(cmd);
14377c478bd9Sstevel@tonic-gate
14387c478bd9Sstevel@tonic-gate prev_cmd = (cmd1394_cmd_t *)s_priv->cmd_priv_prev;
14397c478bd9Sstevel@tonic-gate
14407c478bd9Sstevel@tonic-gate s_priv->cmd_priv_prev = (cmd1394_cmd_t *)NULL;
14417c478bd9Sstevel@tonic-gate s_priv->cmd_priv_next = (cmd1394_cmd_t *)NULL;
14427c478bd9Sstevel@tonic-gate
14437c478bd9Sstevel@tonic-gate if (prev_cmd != NULL) {
14447c478bd9Sstevel@tonic-gate c_priv = (s1394_cmd_priv_t *)((uchar_t *)prev_cmd +
14457c478bd9Sstevel@tonic-gate sizeof (cmd1394_cmd_t));
14467c478bd9Sstevel@tonic-gate c_priv->cmd_priv_next = (cmd1394_cmd_t *)NULL;
14477c478bd9Sstevel@tonic-gate
14487c478bd9Sstevel@tonic-gate } else {
14497c478bd9Sstevel@tonic-gate hal->pending_q_head = (cmd1394_cmd_t *)NULL;
14507c478bd9Sstevel@tonic-gate }
14517c478bd9Sstevel@tonic-gate hal->pending_q_tail = (cmd1394_cmd_t *)prev_cmd;
14527c478bd9Sstevel@tonic-gate
14537c478bd9Sstevel@tonic-gate mutex_exit(&hal->pending_q_mutex);
14547c478bd9Sstevel@tonic-gate
14557c478bd9Sstevel@tonic-gate return (cmd);
14567c478bd9Sstevel@tonic-gate }
14577c478bd9Sstevel@tonic-gate
14587c478bd9Sstevel@tonic-gate /*
14597c478bd9Sstevel@tonic-gate * s1394_resend_pending_cmds()
14607c478bd9Sstevel@tonic-gate * is called when the pending queue is to be flushed. After most of the
14617c478bd9Sstevel@tonic-gate * bus reset processing is completed, the pending commands are sent/resent.
14627c478bd9Sstevel@tonic-gate */
14637c478bd9Sstevel@tonic-gate void
s1394_resend_pending_cmds(s1394_hal_t * hal)14647c478bd9Sstevel@tonic-gate s1394_resend_pending_cmds(s1394_hal_t *hal)
14657c478bd9Sstevel@tonic-gate {
14667c478bd9Sstevel@tonic-gate int done;
14677c478bd9Sstevel@tonic-gate
14687c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
14697c478bd9Sstevel@tonic-gate
14707c478bd9Sstevel@tonic-gate do {
14717c478bd9Sstevel@tonic-gate done = s1394_process_pending_q(hal);
14727c478bd9Sstevel@tonic-gate } while (done == B_FALSE);
14737c478bd9Sstevel@tonic-gate
14747c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
14757c478bd9Sstevel@tonic-gate }
14767c478bd9Sstevel@tonic-gate
14777c478bd9Sstevel@tonic-gate /*
14787c478bd9Sstevel@tonic-gate * s1394_process_pending_q()
14797c478bd9Sstevel@tonic-gate * is called to send/resend the commands on the pending queue. All command
14807c478bd9Sstevel@tonic-gate * handling can be done here, including notifying the target of failed
14817c478bd9Sstevel@tonic-gate * commands, etc. If it is necessary to recompute the address, speed,
14827c478bd9Sstevel@tonic-gate * or max_payload for a command, that can be done here too. And if there
14837c478bd9Sstevel@tonic-gate * is no reason not to continue sending commands from the pending queue,
14847c478bd9Sstevel@tonic-gate * then a B_FALSE is returned, else B_TRUE is returned.
14857c478bd9Sstevel@tonic-gate */
14867c478bd9Sstevel@tonic-gate static boolean_t
s1394_process_pending_q(s1394_hal_t * hal)14877c478bd9Sstevel@tonic-gate s1394_process_pending_q(s1394_hal_t *hal)
14887c478bd9Sstevel@tonic-gate {
14897c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *s_priv;
14907c478bd9Sstevel@tonic-gate h1394_cmd_priv_t *h_priv;
14917c478bd9Sstevel@tonic-gate s1394_target_t *target;
14927c478bd9Sstevel@tonic-gate cmd1394_cmd_t *cmd;
14937c478bd9Sstevel@tonic-gate uint64_t node;
14947c478bd9Sstevel@tonic-gate uint32_t from_node;
14957c478bd9Sstevel@tonic-gate uint32_t to_node;
14967c478bd9Sstevel@tonic-gate uint_t current_max_payload;
14977c478bd9Sstevel@tonic-gate int ret;
14987c478bd9Sstevel@tonic-gate
14997c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
15007c478bd9Sstevel@tonic-gate
15017c478bd9Sstevel@tonic-gate /* Pull a command from the Pending Q */
15027c478bd9Sstevel@tonic-gate cmd = s1394_pending_q_remove(hal);
15037c478bd9Sstevel@tonic-gate
15047c478bd9Sstevel@tonic-gate if (cmd == NULL) {
15057c478bd9Sstevel@tonic-gate return (B_TRUE);
15067c478bd9Sstevel@tonic-gate }
15077c478bd9Sstevel@tonic-gate
15087c478bd9Sstevel@tonic-gate /* Get the Services Layer private area */
15097c478bd9Sstevel@tonic-gate s_priv = S1394_GET_CMD_PRIV(cmd);
15107c478bd9Sstevel@tonic-gate
15117c478bd9Sstevel@tonic-gate /* Get a pointer to the HAL private struct */
15127c478bd9Sstevel@tonic-gate h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
15137c478bd9Sstevel@tonic-gate
15147c478bd9Sstevel@tonic-gate if ((cmd->cmd_options & CMD1394_OVERRIDE_ADDR) ||
15157c478bd9Sstevel@tonic-gate (cmd->cmd_options & CMD1394_CANCEL_ON_BUS_RESET)) {
15167c478bd9Sstevel@tonic-gate if (h_priv->bus_generation == hal->generation_count) {
15177c478bd9Sstevel@tonic-gate ret = s1394_pending_q_helper(hal, cmd);
15187c478bd9Sstevel@tonic-gate return (ret);
15197c478bd9Sstevel@tonic-gate } else {
15207c478bd9Sstevel@tonic-gate
15217c478bd9Sstevel@tonic-gate s_priv->cmd_in_use = B_FALSE;
15227c478bd9Sstevel@tonic-gate
15237c478bd9Sstevel@tonic-gate cmd->cmd_result = CMD1394_EBUSRESET;
15247c478bd9Sstevel@tonic-gate
15257c478bd9Sstevel@tonic-gate /* Is this a blocking command? */
15267c478bd9Sstevel@tonic-gate if (cmd->cmd_options & CMD1394_BLOCKING) {
15277c478bd9Sstevel@tonic-gate /* Unblock the waiting command */
15287c478bd9Sstevel@tonic-gate mutex_enter(&s_priv->blocking_mutex);
15297c478bd9Sstevel@tonic-gate s_priv->blocking_flag = B_TRUE;
15307c478bd9Sstevel@tonic-gate cv_signal(&s_priv->blocking_cv);
15317c478bd9Sstevel@tonic-gate mutex_exit(&s_priv->blocking_mutex);
15327c478bd9Sstevel@tonic-gate
15337c478bd9Sstevel@tonic-gate return (B_FALSE);
15347c478bd9Sstevel@tonic-gate }
15357c478bd9Sstevel@tonic-gate
15367c478bd9Sstevel@tonic-gate /* Call the target's completion_callback() */
15377c478bd9Sstevel@tonic-gate if (cmd->completion_callback != NULL) {
15387c478bd9Sstevel@tonic-gate cmd->completion_callback(cmd);
15397c478bd9Sstevel@tonic-gate }
15407c478bd9Sstevel@tonic-gate
15417c478bd9Sstevel@tonic-gate return (B_FALSE);
15427c478bd9Sstevel@tonic-gate }
15437c478bd9Sstevel@tonic-gate } else {
15447c478bd9Sstevel@tonic-gate if (h_priv->bus_generation == hal->generation_count) {
15457c478bd9Sstevel@tonic-gate ret = s1394_pending_q_helper(hal, cmd);
15467c478bd9Sstevel@tonic-gate return (ret);
15477c478bd9Sstevel@tonic-gate } else {
15487c478bd9Sstevel@tonic-gate /* Make sure we can get the topology_tree_mutex */
15497c478bd9Sstevel@tonic-gate if (s1394_lock_tree(hal) != DDI_SUCCESS)
15507c478bd9Sstevel@tonic-gate return (B_TRUE);
15517c478bd9Sstevel@tonic-gate
15527c478bd9Sstevel@tonic-gate /* Set the generation */
15537c478bd9Sstevel@tonic-gate cmd->bus_generation = hal->generation_count;
15547c478bd9Sstevel@tonic-gate
15557c478bd9Sstevel@tonic-gate /* Copy the generation into the HAL's private field */
15567c478bd9Sstevel@tonic-gate h_priv->bus_generation = cmd->bus_generation;
15577c478bd9Sstevel@tonic-gate
15587c478bd9Sstevel@tonic-gate target = s_priv->sent_by_target;
15597c478bd9Sstevel@tonic-gate
15607c478bd9Sstevel@tonic-gate /* If not OVERRIDE_ADDR, then target may not be NULL */
15617c478bd9Sstevel@tonic-gate ASSERT(target != NULL);
15627c478bd9Sstevel@tonic-gate
15637c478bd9Sstevel@tonic-gate rw_enter(&hal->target_list_rwlock, RW_READER);
15647c478bd9Sstevel@tonic-gate
15657c478bd9Sstevel@tonic-gate if (((target->target_state & S1394_TARG_GONE) == 0) &&
15667c478bd9Sstevel@tonic-gate (target->on_node != NULL)) {
15677c478bd9Sstevel@tonic-gate node = target->on_node->node_num;
15687c478bd9Sstevel@tonic-gate rw_exit(&hal->target_list_rwlock);
15697c478bd9Sstevel@tonic-gate } else {
15707c478bd9Sstevel@tonic-gate rw_exit(&hal->target_list_rwlock);
15717c478bd9Sstevel@tonic-gate
15727c478bd9Sstevel@tonic-gate s_priv->cmd_in_use = B_FALSE;
15737c478bd9Sstevel@tonic-gate
15747c478bd9Sstevel@tonic-gate cmd->cmd_result = CMD1394_EDEVICE_REMOVED;
15757c478bd9Sstevel@tonic-gate
15767c478bd9Sstevel@tonic-gate /* Is this a blocking command? */
15777c478bd9Sstevel@tonic-gate if (cmd->cmd_options & CMD1394_BLOCKING) {
15787c478bd9Sstevel@tonic-gate s1394_unlock_tree(hal);
15797c478bd9Sstevel@tonic-gate
15807c478bd9Sstevel@tonic-gate /* Unblock the waiting command */
15817c478bd9Sstevel@tonic-gate mutex_enter(&s_priv->blocking_mutex);
15827c478bd9Sstevel@tonic-gate s_priv->blocking_flag = B_TRUE;
15837c478bd9Sstevel@tonic-gate cv_signal(&s_priv->blocking_cv);
15847c478bd9Sstevel@tonic-gate mutex_exit(&s_priv->blocking_mutex);
15857c478bd9Sstevel@tonic-gate
15867c478bd9Sstevel@tonic-gate return (B_FALSE);
15877c478bd9Sstevel@tonic-gate }
15887c478bd9Sstevel@tonic-gate
15897c478bd9Sstevel@tonic-gate /* Call the target's completion_callback() */
15907c478bd9Sstevel@tonic-gate if (cmd->completion_callback != NULL) {
15917c478bd9Sstevel@tonic-gate s1394_unlock_tree(hal);
15927c478bd9Sstevel@tonic-gate cmd->completion_callback(cmd);
15937c478bd9Sstevel@tonic-gate return (B_FALSE);
15947c478bd9Sstevel@tonic-gate } else {
15957c478bd9Sstevel@tonic-gate s1394_unlock_tree(hal);
15967c478bd9Sstevel@tonic-gate return (B_FALSE);
15977c478bd9Sstevel@tonic-gate }
15987c478bd9Sstevel@tonic-gate }
15997c478bd9Sstevel@tonic-gate
16007c478bd9Sstevel@tonic-gate /* Mask in the top 16-bits */
16017c478bd9Sstevel@tonic-gate cmd->cmd_addr = cmd->cmd_addr &
16027c478bd9Sstevel@tonic-gate IEEE1394_ADDR_OFFSET_MASK;
16037c478bd9Sstevel@tonic-gate cmd->cmd_addr = cmd->cmd_addr |
16047c478bd9Sstevel@tonic-gate (node << IEEE1394_ADDR_PHY_ID_SHIFT);
16057c478bd9Sstevel@tonic-gate cmd->cmd_addr = cmd->cmd_addr |
16067c478bd9Sstevel@tonic-gate IEEE1394_ADDR_BUS_ID_MASK;
16077c478bd9Sstevel@tonic-gate
16087c478bd9Sstevel@tonic-gate /* Speed is to be filled in from speed map */
16097c478bd9Sstevel@tonic-gate from_node = IEEE1394_NODE_NUM(hal->node_id);
16107c478bd9Sstevel@tonic-gate to_node = (uint32_t)node;
16117c478bd9Sstevel@tonic-gate
16127c478bd9Sstevel@tonic-gate /* Fill in the nodeID */
16137c478bd9Sstevel@tonic-gate cmd->nodeID =
16147c478bd9Sstevel@tonic-gate (cmd->cmd_addr & IEEE1394_ADDR_NODE_ID_MASK) >>
16157c478bd9Sstevel@tonic-gate IEEE1394_ADDR_NODE_ID_SHIFT;
16167c478bd9Sstevel@tonic-gate
16177c478bd9Sstevel@tonic-gate if (cmd->cmd_options & CMD1394_OVERRIDE_SPEED) {
16187c478bd9Sstevel@tonic-gate s_priv->hal_cmd_private.speed =
16197c478bd9Sstevel@tonic-gate (int)cmd->cmd_speed;
16207c478bd9Sstevel@tonic-gate } else {
16217c478bd9Sstevel@tonic-gate /* Speed is to be filled in from speed map */
16227c478bd9Sstevel@tonic-gate s_priv->hal_cmd_private.speed =
16237c478bd9Sstevel@tonic-gate (int)s1394_speed_map_get(hal, from_node,
16247c478bd9Sstevel@tonic-gate to_node);
16257c478bd9Sstevel@tonic-gate }
16267c478bd9Sstevel@tonic-gate
16277c478bd9Sstevel@tonic-gate /* Is it a block request? */
16287c478bd9Sstevel@tonic-gate if ((cmd->cmd_type == CMD1394_ASYNCH_RD_BLOCK) ||
16297c478bd9Sstevel@tonic-gate (cmd->cmd_type == CMD1394_ASYNCH_WR_BLOCK)) {
16307c478bd9Sstevel@tonic-gate
16317c478bd9Sstevel@tonic-gate /* Get a pointer to the HAL private struct */
16327c478bd9Sstevel@tonic-gate h_priv = (h1394_cmd_priv_t *)&s_priv->
16337c478bd9Sstevel@tonic-gate hal_cmd_private;
16347c478bd9Sstevel@tonic-gate
16357c478bd9Sstevel@tonic-gate /* Handle the MAX_PAYLOAD size */
16367c478bd9Sstevel@tonic-gate if (s_priv->sent_by_target != NULL) {
16377c478bd9Sstevel@tonic-gate current_max_payload =
16387c478bd9Sstevel@tonic-gate s_priv->sent_by_target->
16397c478bd9Sstevel@tonic-gate current_max_payload;
16407c478bd9Sstevel@tonic-gate } else {
16417c478bd9Sstevel@tonic-gate current_max_payload = 4;
16427c478bd9Sstevel@tonic-gate }
16437c478bd9Sstevel@tonic-gate if (cmd->cmd_options &
16447c478bd9Sstevel@tonic-gate CMD1394_OVERRIDE_MAX_PAYLOAD) {
16457c478bd9Sstevel@tonic-gate if (current_max_payload >
16467c478bd9Sstevel@tonic-gate cmd->cmd_u.b.max_payload)
16477c478bd9Sstevel@tonic-gate current_max_payload =
16487c478bd9Sstevel@tonic-gate cmd->cmd_u.b.max_payload;
16497c478bd9Sstevel@tonic-gate }
16507c478bd9Sstevel@tonic-gate if (s_priv->data_remaining <
16517c478bd9Sstevel@tonic-gate current_max_payload) {
16527c478bd9Sstevel@tonic-gate h_priv->mblk.length =
16537c478bd9Sstevel@tonic-gate s_priv->data_remaining;
16547c478bd9Sstevel@tonic-gate } else {
16557c478bd9Sstevel@tonic-gate h_priv->mblk.length =
16567c478bd9Sstevel@tonic-gate current_max_payload;
16577c478bd9Sstevel@tonic-gate }
16587c478bd9Sstevel@tonic-gate }
16597c478bd9Sstevel@tonic-gate s1394_unlock_tree(hal);
16607c478bd9Sstevel@tonic-gate ret = s1394_pending_q_helper(hal, cmd);
16617c478bd9Sstevel@tonic-gate return (ret);
16627c478bd9Sstevel@tonic-gate }
16637c478bd9Sstevel@tonic-gate }
16647c478bd9Sstevel@tonic-gate }
16657c478bd9Sstevel@tonic-gate
16667c478bd9Sstevel@tonic-gate /*
16677c478bd9Sstevel@tonic-gate * s1394_pending_q_helper()
16687c478bd9Sstevel@tonic-gate * is a "helper" function for s1394_process_pending_q(). It attempts to
16697c478bd9Sstevel@tonic-gate * resend commands, handling error conditions whenever necessary.
16707c478bd9Sstevel@tonic-gate */
16717c478bd9Sstevel@tonic-gate static boolean_t
s1394_pending_q_helper(s1394_hal_t * hal,cmd1394_cmd_t * cmd)16727c478bd9Sstevel@tonic-gate s1394_pending_q_helper(s1394_hal_t *hal, cmd1394_cmd_t *cmd)
16737c478bd9Sstevel@tonic-gate {
16747c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *s_priv;
16757c478bd9Sstevel@tonic-gate int err;
16767c478bd9Sstevel@tonic-gate int ret;
16777c478bd9Sstevel@tonic-gate
16787c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
16797c478bd9Sstevel@tonic-gate
16807c478bd9Sstevel@tonic-gate /* Get the Services Layer private area */
16817c478bd9Sstevel@tonic-gate s_priv = S1394_GET_CMD_PRIV(cmd);
16827c478bd9Sstevel@tonic-gate
16837c478bd9Sstevel@tonic-gate /* Put cmd on outstanding request Q */
16847c478bd9Sstevel@tonic-gate s1394_insert_q_asynch_cmd(hal, cmd);
16857c478bd9Sstevel@tonic-gate
16867c478bd9Sstevel@tonic-gate /* Send command out again */
16877c478bd9Sstevel@tonic-gate ret = s1394_xfer_asynch_command(hal, cmd, &err);
16887c478bd9Sstevel@tonic-gate
16897c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) {
16907c478bd9Sstevel@tonic-gate if (err == CMD1394_ESTALE_GENERATION) {
16917c478bd9Sstevel@tonic-gate /* Remove cmd outstanding req Q */
16927c478bd9Sstevel@tonic-gate s1394_remove_q_asynch_cmd(hal, cmd);
16937c478bd9Sstevel@tonic-gate s1394_pending_q_insert(hal, cmd, S1394_PENDING_Q_FRONT);
16947c478bd9Sstevel@tonic-gate
16957c478bd9Sstevel@tonic-gate return (B_TRUE);
16967c478bd9Sstevel@tonic-gate } else {
16977c478bd9Sstevel@tonic-gate /* Remove cmd from outstanding request Q */
16987c478bd9Sstevel@tonic-gate s1394_remove_q_asynch_cmd(hal, cmd);
16997c478bd9Sstevel@tonic-gate
17007c478bd9Sstevel@tonic-gate s_priv->cmd_in_use = B_FALSE;
17017c478bd9Sstevel@tonic-gate
17027c478bd9Sstevel@tonic-gate cmd->cmd_result = err;
17037c478bd9Sstevel@tonic-gate
17047c478bd9Sstevel@tonic-gate /* Is this a blocking command? */
17057c478bd9Sstevel@tonic-gate if (cmd->cmd_options & CMD1394_BLOCKING) {
17067c478bd9Sstevel@tonic-gate /* Unblock waiting command */
17077c478bd9Sstevel@tonic-gate mutex_enter(&s_priv->blocking_mutex);
17087c478bd9Sstevel@tonic-gate s_priv->blocking_flag = B_TRUE;
17097c478bd9Sstevel@tonic-gate cv_signal(&s_priv->blocking_cv);
17107c478bd9Sstevel@tonic-gate mutex_exit(&s_priv->blocking_mutex);
17117c478bd9Sstevel@tonic-gate
17127c478bd9Sstevel@tonic-gate return (B_FALSE);
17137c478bd9Sstevel@tonic-gate }
17147c478bd9Sstevel@tonic-gate
17157c478bd9Sstevel@tonic-gate /* Call target completion_callback() */
17167c478bd9Sstevel@tonic-gate if (cmd->completion_callback != NULL) {
17177c478bd9Sstevel@tonic-gate cmd->completion_callback(cmd);
17187c478bd9Sstevel@tonic-gate return (B_FALSE);
17197c478bd9Sstevel@tonic-gate } else {
17207c478bd9Sstevel@tonic-gate return (B_FALSE);
17217c478bd9Sstevel@tonic-gate }
17227c478bd9Sstevel@tonic-gate }
17237c478bd9Sstevel@tonic-gate }
17247c478bd9Sstevel@tonic-gate
17257c478bd9Sstevel@tonic-gate return (B_FALSE);
17267c478bd9Sstevel@tonic-gate }
17277c478bd9Sstevel@tonic-gate
17287c478bd9Sstevel@tonic-gate /*
17297c478bd9Sstevel@tonic-gate * s1394_process_split_lock()
17307c478bd9Sstevel@tonic-gate * is a "helper" function for the s1394_handle_lock() callback. Its
17317c478bd9Sstevel@tonic-gate * job is to perform whatever manipulation is required for the given
17327c478bd9Sstevel@tonic-gate * request.
17337c478bd9Sstevel@tonic-gate */
17347c478bd9Sstevel@tonic-gate static int
s1394_process_split_lock(cmd1394_cmd_t * cmd,cmd1394_cmd_t * target_cmd)17357c478bd9Sstevel@tonic-gate s1394_process_split_lock(cmd1394_cmd_t *cmd, cmd1394_cmd_t *target_cmd)
17367c478bd9Sstevel@tonic-gate {
17377c478bd9Sstevel@tonic-gate uint64_t new_value64;
17387c478bd9Sstevel@tonic-gate uint64_t data_value64;
17397c478bd9Sstevel@tonic-gate uint64_t arg_value64;
17407c478bd9Sstevel@tonic-gate uint64_t old_value64;
17417c478bd9Sstevel@tonic-gate uint64_t temp_value64;
17427c478bd9Sstevel@tonic-gate uint32_t new_value32;
17437c478bd9Sstevel@tonic-gate uint32_t data_value32;
17447c478bd9Sstevel@tonic-gate uint32_t arg_value32;
17457c478bd9Sstevel@tonic-gate uint32_t old_value32;
17467c478bd9Sstevel@tonic-gate uint32_t temp_value32;
17477c478bd9Sstevel@tonic-gate
17487c478bd9Sstevel@tonic-gate if (cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) {
17497c478bd9Sstevel@tonic-gate old_value32 = cmd->cmd_u.l32.old_value;
17507c478bd9Sstevel@tonic-gate data_value32 = target_cmd->cmd_u.l32.data_value;
17517c478bd9Sstevel@tonic-gate arg_value32 = target_cmd->cmd_u.l32.arg_value;
17527c478bd9Sstevel@tonic-gate
17537c478bd9Sstevel@tonic-gate /* Lock type specific */
17547c478bd9Sstevel@tonic-gate switch (target_cmd->cmd_u.l32.lock_type) {
17557c478bd9Sstevel@tonic-gate case CMD1394_LOCK_BIT_AND:
17567c478bd9Sstevel@tonic-gate new_value32 = old_value32 & data_value32;
17577c478bd9Sstevel@tonic-gate break;
17587c478bd9Sstevel@tonic-gate
17597c478bd9Sstevel@tonic-gate case CMD1394_LOCK_BIT_OR:
17607c478bd9Sstevel@tonic-gate new_value32 = old_value32 | data_value32;
17617c478bd9Sstevel@tonic-gate break;
17627c478bd9Sstevel@tonic-gate
17637c478bd9Sstevel@tonic-gate case CMD1394_LOCK_BIT_XOR:
17647c478bd9Sstevel@tonic-gate new_value32 = old_value32 ^ data_value32;
17657c478bd9Sstevel@tonic-gate break;
17667c478bd9Sstevel@tonic-gate
17677c478bd9Sstevel@tonic-gate case CMD1394_LOCK_INCREMENT:
17687c478bd9Sstevel@tonic-gate old_value32 = T1394_DATA32(old_value32);
17697c478bd9Sstevel@tonic-gate new_value32 = old_value32 + 1;
17707c478bd9Sstevel@tonic-gate new_value32 = T1394_DATA32(new_value32);
17717c478bd9Sstevel@tonic-gate old_value32 = T1394_DATA32(old_value32);
17727c478bd9Sstevel@tonic-gate break;
17737c478bd9Sstevel@tonic-gate
17747c478bd9Sstevel@tonic-gate case CMD1394_LOCK_DECREMENT:
17757c478bd9Sstevel@tonic-gate old_value32 = T1394_DATA32(old_value32);
17767c478bd9Sstevel@tonic-gate new_value32 = old_value32 - 1;
17777c478bd9Sstevel@tonic-gate new_value32 = T1394_DATA32(new_value32);
17787c478bd9Sstevel@tonic-gate old_value32 = T1394_DATA32(old_value32);
17797c478bd9Sstevel@tonic-gate break;
17807c478bd9Sstevel@tonic-gate
17817c478bd9Sstevel@tonic-gate case CMD1394_LOCK_ADD:
17827c478bd9Sstevel@tonic-gate old_value32 = T1394_DATA32(old_value32);
17837c478bd9Sstevel@tonic-gate new_value32 = old_value32 + data_value32;
17847c478bd9Sstevel@tonic-gate new_value32 = T1394_DATA32(new_value32);
17857c478bd9Sstevel@tonic-gate old_value32 = T1394_DATA32(old_value32);
17867c478bd9Sstevel@tonic-gate break;
17877c478bd9Sstevel@tonic-gate
17887c478bd9Sstevel@tonic-gate case CMD1394_LOCK_SUBTRACT:
17897c478bd9Sstevel@tonic-gate old_value32 = T1394_DATA32(old_value32);
17907c478bd9Sstevel@tonic-gate new_value32 = old_value32 - data_value32;
17917c478bd9Sstevel@tonic-gate new_value32 = T1394_DATA32(new_value32);
17927c478bd9Sstevel@tonic-gate old_value32 = T1394_DATA32(old_value32);
17937c478bd9Sstevel@tonic-gate break;
17947c478bd9Sstevel@tonic-gate
17957c478bd9Sstevel@tonic-gate case CMD1394_LOCK_THRESH_ADD:
17967c478bd9Sstevel@tonic-gate old_value32 = T1394_DATA32(old_value32);
17977c478bd9Sstevel@tonic-gate temp_value32 = (old_value32 + data_value32);
17987c478bd9Sstevel@tonic-gate if ((temp_value32 >= old_value32) &&
17997c478bd9Sstevel@tonic-gate (temp_value32 <= arg_value32)) {
18007c478bd9Sstevel@tonic-gate new_value32 = T1394_DATA32(temp_value32);
18017c478bd9Sstevel@tonic-gate old_value32 = T1394_DATA32(old_value32);
18027c478bd9Sstevel@tonic-gate } else {
18037c478bd9Sstevel@tonic-gate /* Failed threshold add */
18047c478bd9Sstevel@tonic-gate target_cmd->cmd_u.l32.old_value =
18057c478bd9Sstevel@tonic-gate T1394_DATA32(cmd->cmd_u.l32.old_value);
18067c478bd9Sstevel@tonic-gate target_cmd->cmd_result = CMD1394_CMDSUCCESS;
18077c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
18087c478bd9Sstevel@tonic-gate }
18097c478bd9Sstevel@tonic-gate break;
18107c478bd9Sstevel@tonic-gate
18117c478bd9Sstevel@tonic-gate case CMD1394_LOCK_THRESH_SUBTRACT:
18127c478bd9Sstevel@tonic-gate old_value32 = T1394_DATA32(old_value32);
18137c478bd9Sstevel@tonic-gate temp_value32 = (old_value32 - data_value32);
18147c478bd9Sstevel@tonic-gate if ((old_value32 >= data_value32) &&
18157c478bd9Sstevel@tonic-gate (temp_value32 >= arg_value32)) {
18167c478bd9Sstevel@tonic-gate new_value32 = T1394_DATA32(temp_value32);
18177c478bd9Sstevel@tonic-gate old_value32 = T1394_DATA32(old_value32);
18187c478bd9Sstevel@tonic-gate } else {
18197c478bd9Sstevel@tonic-gate /* Failed threshold subtract */
18207c478bd9Sstevel@tonic-gate target_cmd->cmd_u.l32.old_value =
18217c478bd9Sstevel@tonic-gate T1394_DATA32(cmd->cmd_u.l32.old_value);
18227c478bd9Sstevel@tonic-gate target_cmd->cmd_result = CMD1394_CMDSUCCESS;
18237c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
18247c478bd9Sstevel@tonic-gate }
18257c478bd9Sstevel@tonic-gate break;
18267c478bd9Sstevel@tonic-gate
18277c478bd9Sstevel@tonic-gate case CMD1394_LOCK_CLIP_ADD:
18287c478bd9Sstevel@tonic-gate old_value32 = T1394_DATA32(old_value32);
18297c478bd9Sstevel@tonic-gate temp_value32 = (old_value32 + data_value32);
18307c478bd9Sstevel@tonic-gate if ((temp_value32 < old_value32) ||
18317c478bd9Sstevel@tonic-gate (temp_value32 > arg_value32))
18327c478bd9Sstevel@tonic-gate new_value32 = T1394_DATA32(arg_value32);
18337c478bd9Sstevel@tonic-gate else
18347c478bd9Sstevel@tonic-gate new_value32 = T1394_DATA32(temp_value32);
18357c478bd9Sstevel@tonic-gate old_value32 = T1394_DATA32(old_value32);
18367c478bd9Sstevel@tonic-gate break;
18377c478bd9Sstevel@tonic-gate
18387c478bd9Sstevel@tonic-gate case CMD1394_LOCK_CLIP_SUBTRACT:
18397c478bd9Sstevel@tonic-gate old_value32 = T1394_DATA32(old_value32);
18407c478bd9Sstevel@tonic-gate temp_value32 = (old_value32 - data_value32);
18417c478bd9Sstevel@tonic-gate if ((data_value32 > old_value32) ||
18427c478bd9Sstevel@tonic-gate (temp_value32 < arg_value32))
18437c478bd9Sstevel@tonic-gate new_value32 = T1394_DATA32(arg_value32);
18447c478bd9Sstevel@tonic-gate else
18457c478bd9Sstevel@tonic-gate new_value32 = T1394_DATA32(temp_value32);
18467c478bd9Sstevel@tonic-gate old_value32 = T1394_DATA32(old_value32);
18477c478bd9Sstevel@tonic-gate break;
18487c478bd9Sstevel@tonic-gate }
18497c478bd9Sstevel@tonic-gate
18507c478bd9Sstevel@tonic-gate /* Send compare-swap lock request */
18517c478bd9Sstevel@tonic-gate cmd->cmd_u.l32.arg_value = old_value32;
18527c478bd9Sstevel@tonic-gate cmd->cmd_u.l32.data_value = new_value32;
18537c478bd9Sstevel@tonic-gate } else {
18547c478bd9Sstevel@tonic-gate old_value64 = cmd->cmd_u.l64.old_value;
18557c478bd9Sstevel@tonic-gate data_value64 = target_cmd->cmd_u.l64.data_value;
18567c478bd9Sstevel@tonic-gate arg_value64 = target_cmd->cmd_u.l64.arg_value;
18577c478bd9Sstevel@tonic-gate
18587c478bd9Sstevel@tonic-gate /* Lock type specific */
18597c478bd9Sstevel@tonic-gate switch (target_cmd->cmd_u.l64.lock_type) {
18607c478bd9Sstevel@tonic-gate case CMD1394_LOCK_BIT_AND:
18617c478bd9Sstevel@tonic-gate new_value64 = old_value64 & data_value64;
18627c478bd9Sstevel@tonic-gate break;
18637c478bd9Sstevel@tonic-gate
18647c478bd9Sstevel@tonic-gate case CMD1394_LOCK_BIT_OR:
18657c478bd9Sstevel@tonic-gate new_value64 = old_value64 | data_value64;
18667c478bd9Sstevel@tonic-gate break;
18677c478bd9Sstevel@tonic-gate
18687c478bd9Sstevel@tonic-gate case CMD1394_LOCK_BIT_XOR:
18697c478bd9Sstevel@tonic-gate new_value64 = old_value64 ^ data_value64;
18707c478bd9Sstevel@tonic-gate break;
18717c478bd9Sstevel@tonic-gate
18727c478bd9Sstevel@tonic-gate case CMD1394_LOCK_INCREMENT:
18737c478bd9Sstevel@tonic-gate old_value64 = T1394_DATA64(old_value64);
18747c478bd9Sstevel@tonic-gate new_value64 = old_value64 + 1;
18757c478bd9Sstevel@tonic-gate new_value64 = T1394_DATA64(new_value64);
18767c478bd9Sstevel@tonic-gate old_value64 = T1394_DATA64(old_value64);
18777c478bd9Sstevel@tonic-gate break;
18787c478bd9Sstevel@tonic-gate
18797c478bd9Sstevel@tonic-gate case CMD1394_LOCK_DECREMENT:
18807c478bd9Sstevel@tonic-gate old_value64 = T1394_DATA64(old_value64);
18817c478bd9Sstevel@tonic-gate new_value64 = old_value64 - 1;
18827c478bd9Sstevel@tonic-gate new_value64 = T1394_DATA64(new_value64);
18837c478bd9Sstevel@tonic-gate old_value64 = T1394_DATA64(old_value64);
18847c478bd9Sstevel@tonic-gate break;
18857c478bd9Sstevel@tonic-gate
18867c478bd9Sstevel@tonic-gate case CMD1394_LOCK_ADD:
18877c478bd9Sstevel@tonic-gate old_value64 = T1394_DATA64(old_value64);
18887c478bd9Sstevel@tonic-gate new_value64 = old_value64 + data_value64;
18897c478bd9Sstevel@tonic-gate new_value64 = T1394_DATA64(new_value64);
18907c478bd9Sstevel@tonic-gate old_value64 = T1394_DATA64(old_value64);
18917c478bd9Sstevel@tonic-gate break;
18927c478bd9Sstevel@tonic-gate
18937c478bd9Sstevel@tonic-gate case CMD1394_LOCK_SUBTRACT:
18947c478bd9Sstevel@tonic-gate old_value64 = T1394_DATA64(old_value64);
18957c478bd9Sstevel@tonic-gate new_value64 = old_value64 - data_value64;
18967c478bd9Sstevel@tonic-gate new_value64 = T1394_DATA64(new_value64);
18977c478bd9Sstevel@tonic-gate old_value64 = T1394_DATA64(old_value64);
18987c478bd9Sstevel@tonic-gate break;
18997c478bd9Sstevel@tonic-gate
19007c478bd9Sstevel@tonic-gate case CMD1394_LOCK_THRESH_ADD:
19017c478bd9Sstevel@tonic-gate old_value64 = T1394_DATA64(old_value64);
19027c478bd9Sstevel@tonic-gate temp_value64 = (old_value64 + data_value64);
19037c478bd9Sstevel@tonic-gate if ((temp_value64 >= old_value64) &&
19047c478bd9Sstevel@tonic-gate (temp_value64 <= arg_value64)) {
19057c478bd9Sstevel@tonic-gate new_value64 = T1394_DATA64(temp_value64);
19067c478bd9Sstevel@tonic-gate old_value64 = T1394_DATA64(old_value64);
19077c478bd9Sstevel@tonic-gate } else {
19087c478bd9Sstevel@tonic-gate /* Failed threshold add */
19097c478bd9Sstevel@tonic-gate target_cmd->cmd_u.l64.old_value =
19107c478bd9Sstevel@tonic-gate T1394_DATA64(cmd->cmd_u.l64.old_value);
19117c478bd9Sstevel@tonic-gate target_cmd->cmd_result = CMD1394_CMDSUCCESS;
19127c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
19137c478bd9Sstevel@tonic-gate }
19147c478bd9Sstevel@tonic-gate break;
19157c478bd9Sstevel@tonic-gate
19167c478bd9Sstevel@tonic-gate case CMD1394_LOCK_THRESH_SUBTRACT:
19177c478bd9Sstevel@tonic-gate old_value64 = T1394_DATA64(old_value64);
19187c478bd9Sstevel@tonic-gate temp_value64 = (old_value64 - data_value64);
19197c478bd9Sstevel@tonic-gate if ((old_value64 >= data_value64) &&
19207c478bd9Sstevel@tonic-gate (temp_value64 >= arg_value64)) {
19217c478bd9Sstevel@tonic-gate new_value64 = T1394_DATA64(temp_value64);
19227c478bd9Sstevel@tonic-gate old_value64 = T1394_DATA64(old_value64);
19237c478bd9Sstevel@tonic-gate } else {
19247c478bd9Sstevel@tonic-gate /* Failed threshold subtract */
19257c478bd9Sstevel@tonic-gate target_cmd->cmd_u.l64.old_value =
19267c478bd9Sstevel@tonic-gate T1394_DATA64(cmd->cmd_u.l64.old_value);
19277c478bd9Sstevel@tonic-gate target_cmd->cmd_result = CMD1394_CMDSUCCESS;
19287c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
19297c478bd9Sstevel@tonic-gate }
19307c478bd9Sstevel@tonic-gate break;
19317c478bd9Sstevel@tonic-gate
19327c478bd9Sstevel@tonic-gate case CMD1394_LOCK_CLIP_ADD:
19337c478bd9Sstevel@tonic-gate old_value64 = T1394_DATA64(old_value64);
19347c478bd9Sstevel@tonic-gate temp_value64 = (old_value64 + data_value64);
19357c478bd9Sstevel@tonic-gate if ((temp_value64 < old_value64) ||
19367c478bd9Sstevel@tonic-gate (temp_value64 > arg_value64))
19377c478bd9Sstevel@tonic-gate new_value64 = T1394_DATA64(arg_value64);
19387c478bd9Sstevel@tonic-gate else
19397c478bd9Sstevel@tonic-gate new_value64 = T1394_DATA64(temp_value64);
19407c478bd9Sstevel@tonic-gate old_value64 = T1394_DATA64(old_value64);
19417c478bd9Sstevel@tonic-gate break;
19427c478bd9Sstevel@tonic-gate
19437c478bd9Sstevel@tonic-gate case CMD1394_LOCK_CLIP_SUBTRACT:
19447c478bd9Sstevel@tonic-gate old_value64 = T1394_DATA64(old_value64);
19457c478bd9Sstevel@tonic-gate temp_value64 = (old_value64 - data_value64);
19467c478bd9Sstevel@tonic-gate if ((data_value64 > old_value64) ||
19477c478bd9Sstevel@tonic-gate (temp_value64 < arg_value64))
19487c478bd9Sstevel@tonic-gate new_value64 = T1394_DATA64(arg_value64);
19497c478bd9Sstevel@tonic-gate else
19507c478bd9Sstevel@tonic-gate new_value64 = T1394_DATA64(temp_value64);
19517c478bd9Sstevel@tonic-gate old_value64 = T1394_DATA64(old_value64);
19527c478bd9Sstevel@tonic-gate break;
19537c478bd9Sstevel@tonic-gate }
19547c478bd9Sstevel@tonic-gate
19557c478bd9Sstevel@tonic-gate /* Send compare-swap lock request */
19567c478bd9Sstevel@tonic-gate cmd->cmd_u.l64.arg_value = old_value64;
19577c478bd9Sstevel@tonic-gate cmd->cmd_u.l64.data_value = new_value64;
19587c478bd9Sstevel@tonic-gate }
19597c478bd9Sstevel@tonic-gate
19607c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
19617c478bd9Sstevel@tonic-gate }
19627c478bd9Sstevel@tonic-gate
19637c478bd9Sstevel@tonic-gate /*
19647c478bd9Sstevel@tonic-gate * s1394_finish_split_lock()
19657c478bd9Sstevel@tonic-gate * is another "helper" function for the s1394_handle_lock() callback.
19667c478bd9Sstevel@tonic-gate * Its job is to finish up whatever lock request procesing is necessary.
19677c478bd9Sstevel@tonic-gate */
19687c478bd9Sstevel@tonic-gate static int
s1394_finish_split_lock(cmd1394_cmd_t * cmd,cmd1394_cmd_t * target_cmd)19697c478bd9Sstevel@tonic-gate s1394_finish_split_lock(cmd1394_cmd_t *cmd, cmd1394_cmd_t *target_cmd)
19707c478bd9Sstevel@tonic-gate {
19717c478bd9Sstevel@tonic-gate s1394_cmd_priv_t *s_priv;
19727c478bd9Sstevel@tonic-gate uint64_t tmp_value64;
19737c478bd9Sstevel@tonic-gate uint32_t tmp_value32;
19747c478bd9Sstevel@tonic-gate
19757c478bd9Sstevel@tonic-gate /* Get the Services Layer private area */
19767c478bd9Sstevel@tonic-gate s_priv = S1394_GET_CMD_PRIV(cmd);
19777c478bd9Sstevel@tonic-gate
19787c478bd9Sstevel@tonic-gate if (((cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) &&
19797c478bd9Sstevel@tonic-gate (cmd->cmd_u.l32.old_value == cmd->cmd_u.l32.arg_value)) ||
19807c478bd9Sstevel@tonic-gate ((cmd->cmd_type == CMD1394_ASYNCH_LOCK_64) &&
19817c478bd9Sstevel@tonic-gate (cmd->cmd_u.l64.old_value == cmd->cmd_u.l64.arg_value))) {
19827c478bd9Sstevel@tonic-gate
19837c478bd9Sstevel@tonic-gate if (cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) {
19847c478bd9Sstevel@tonic-gate switch (cmd->cmd_u.l32.lock_type) {
19857c478bd9Sstevel@tonic-gate case CMD1394_LOCK_INCREMENT:
19867c478bd9Sstevel@tonic-gate case CMD1394_LOCK_DECREMENT:
19877c478bd9Sstevel@tonic-gate case CMD1394_LOCK_ADD:
19887c478bd9Sstevel@tonic-gate case CMD1394_LOCK_SUBTRACT:
19897c478bd9Sstevel@tonic-gate case CMD1394_LOCK_THRESH_ADD:
19907c478bd9Sstevel@tonic-gate case CMD1394_LOCK_THRESH_SUBTRACT:
19917c478bd9Sstevel@tonic-gate case CMD1394_LOCK_CLIP_ADD:
19927c478bd9Sstevel@tonic-gate case CMD1394_LOCK_CLIP_SUBTRACT:
19937c478bd9Sstevel@tonic-gate tmp_value32 = cmd->cmd_u.l32.old_value;
19947c478bd9Sstevel@tonic-gate tmp_value32 = T1394_DATA32(tmp_value32);
19957c478bd9Sstevel@tonic-gate target_cmd->cmd_u.l32.old_value = tmp_value32;
19967c478bd9Sstevel@tonic-gate break;
19977c478bd9Sstevel@tonic-gate default:
19987c478bd9Sstevel@tonic-gate tmp_value32 = cmd->cmd_u.l32.old_value;
19997c478bd9Sstevel@tonic-gate target_cmd->cmd_u.l32.old_value = tmp_value32;
20007c478bd9Sstevel@tonic-gate break;
20017c478bd9Sstevel@tonic-gate }
20027c478bd9Sstevel@tonic-gate } else {
20037c478bd9Sstevel@tonic-gate switch (cmd->cmd_u.l64.lock_type) {
20047c478bd9Sstevel@tonic-gate case CMD1394_LOCK_INCREMENT:
20057c478bd9Sstevel@tonic-gate case CMD1394_LOCK_DECREMENT:
20067c478bd9Sstevel@tonic-gate case CMD1394_LOCK_ADD:
20077c478bd9Sstevel@tonic-gate case CMD1394_LOCK_SUBTRACT:
20087c478bd9Sstevel@tonic-gate case CMD1394_LOCK_THRESH_ADD:
20097c478bd9Sstevel@tonic-gate case CMD1394_LOCK_THRESH_SUBTRACT:
20107c478bd9Sstevel@tonic-gate case CMD1394_LOCK_CLIP_ADD:
20117c478bd9Sstevel@tonic-gate case CMD1394_LOCK_CLIP_SUBTRACT:
20127c478bd9Sstevel@tonic-gate tmp_value64 = cmd->cmd_u.l64.old_value;
20137c478bd9Sstevel@tonic-gate tmp_value64 = T1394_DATA64(tmp_value64);
20147c478bd9Sstevel@tonic-gate target_cmd->cmd_u.l64.old_value = tmp_value64;
20157c478bd9Sstevel@tonic-gate break;
20167c478bd9Sstevel@tonic-gate default:
20177c478bd9Sstevel@tonic-gate tmp_value64 = cmd->cmd_u.l64.old_value;
20187c478bd9Sstevel@tonic-gate target_cmd->cmd_u.l64.old_value = tmp_value64;
20197c478bd9Sstevel@tonic-gate break;
20207c478bd9Sstevel@tonic-gate }
20217c478bd9Sstevel@tonic-gate }
20227c478bd9Sstevel@tonic-gate /* Set status */
20237c478bd9Sstevel@tonic-gate target_cmd->cmd_result = CMD1394_CMDSUCCESS;
20247c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
20257c478bd9Sstevel@tonic-gate } else {
20267c478bd9Sstevel@tonic-gate if (s_priv->temp_num_retries > 0) {
20277c478bd9Sstevel@tonic-gate /* Decrement retry count */
20287c478bd9Sstevel@tonic-gate s_priv->temp_num_retries--;
20297c478bd9Sstevel@tonic-gate
20307c478bd9Sstevel@tonic-gate /* Reset lock_req_step */
20317c478bd9Sstevel@tonic-gate s_priv->lock_req_step = 0;
20327c478bd9Sstevel@tonic-gate
20337c478bd9Sstevel@tonic-gate /* Resend... start at step 0 again */
20347c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
20357c478bd9Sstevel@tonic-gate } else {
20367c478bd9Sstevel@tonic-gate /* Failed... RETRIES_EXCEEDED */
20377c478bd9Sstevel@tonic-gate target_cmd->cmd_result = CMD1394_ERETRIES_EXCEEDED;
20387c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
20397c478bd9Sstevel@tonic-gate }
20407c478bd9Sstevel@tonic-gate }
20417c478bd9Sstevel@tonic-gate }
2042