xref: /illumos-gate/usr/src/uts/common/io/1394/s1394_asynch.c (revision 2570281cf351044b6936651ce26dbe1f801dcbd8)
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