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
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * s1394_misc.c
297c478bd9Sstevel@tonic-gate  *    1394 Services Layer Miscellaneous Routines
307c478bd9Sstevel@tonic-gate  *    This file contains miscellaneous routines used as "helper" functions
317c478bd9Sstevel@tonic-gate  *    by various other files in the Services Layer.
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <sys/conf.h>
357c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
367c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
377c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
387c478bd9Sstevel@tonic-gate #include <sys/types.h>
397c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
407c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
417c478bd9Sstevel@tonic-gate #include <sys/1394/t1394.h>
427c478bd9Sstevel@tonic-gate #include <sys/1394/s1394.h>
437c478bd9Sstevel@tonic-gate #include <sys/1394/h1394.h>
447c478bd9Sstevel@tonic-gate #include <sys/1394/ieee1394.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate int s1394_print_guids = 0;		/* patch to print GUIDs */
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate extern void nx1394_undefine_events(s1394_hal_t *hal);
497c478bd9Sstevel@tonic-gate static void s1394_cleanup_node_cfgrom(s1394_hal_t *hal);
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate /*
527c478bd9Sstevel@tonic-gate  * s1394_cleanup_for_detach()
537c478bd9Sstevel@tonic-gate  *    is used to do all of the necessary cleanup to handle a detach or a
547c478bd9Sstevel@tonic-gate  *    failure in h1394_attach().  The cleanup_level specifies how far we
557c478bd9Sstevel@tonic-gate  *    got in h1394_attach() before failure.
567c478bd9Sstevel@tonic-gate  */
577c478bd9Sstevel@tonic-gate void
s1394_cleanup_for_detach(s1394_hal_t * hal,uint_t cleanup_level)587c478bd9Sstevel@tonic-gate s1394_cleanup_for_detach(s1394_hal_t *hal, uint_t cleanup_level)
597c478bd9Sstevel@tonic-gate {
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate 	switch (cleanup_level) {
627c478bd9Sstevel@tonic-gate 	case H1394_CLEANUP_LEVEL7:
637c478bd9Sstevel@tonic-gate 		/* remove HAL from the global HAL list */
647c478bd9Sstevel@tonic-gate 		mutex_enter(&s1394_statep->hal_list_mutex);
657c478bd9Sstevel@tonic-gate 		if ((s1394_statep->hal_head == hal) &&
667c478bd9Sstevel@tonic-gate 		    (s1394_statep->hal_tail == hal)) {
677c478bd9Sstevel@tonic-gate 			s1394_statep->hal_head = NULL;
687c478bd9Sstevel@tonic-gate 			s1394_statep->hal_tail = NULL;
697c478bd9Sstevel@tonic-gate 		} else {
707c478bd9Sstevel@tonic-gate 			if (hal->hal_prev)
717c478bd9Sstevel@tonic-gate 				hal->hal_prev->hal_next = hal->hal_next;
727c478bd9Sstevel@tonic-gate 			if (hal->hal_next)
737c478bd9Sstevel@tonic-gate 				hal->hal_next->hal_prev = hal->hal_prev;
747c478bd9Sstevel@tonic-gate 			if (s1394_statep->hal_head == hal)
757c478bd9Sstevel@tonic-gate 				s1394_statep->hal_head = hal->hal_next;
767c478bd9Sstevel@tonic-gate 			if (s1394_statep->hal_tail == hal)
777c478bd9Sstevel@tonic-gate 				s1394_statep->hal_tail = hal->hal_prev;
787c478bd9Sstevel@tonic-gate 		}
797c478bd9Sstevel@tonic-gate 		mutex_exit(&s1394_statep->hal_list_mutex);
807c478bd9Sstevel@tonic-gate 		/*
817c478bd9Sstevel@tonic-gate 		 * No FCP cleanup needed at this time -- the following call
827c478bd9Sstevel@tonic-gate 		 * to s1394_destroy_addr_space() takes care of everything.
837c478bd9Sstevel@tonic-gate 		 */
847c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 	case H1394_CLEANUP_LEVEL6:
877c478bd9Sstevel@tonic-gate 		s1394_destroy_addr_space(hal);
887c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 	case H1394_CLEANUP_LEVEL5:
917c478bd9Sstevel@tonic-gate 		s1394_destroy_local_config_rom(hal);
927c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 	case H1394_CLEANUP_LEVEL4:
957c478bd9Sstevel@tonic-gate 		/* Undo all the kstat stuff */
967c478bd9Sstevel@tonic-gate 		(void) s1394_kstat_delete(hal);
977c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	case H1394_CLEANUP_LEVEL3:
1007c478bd9Sstevel@tonic-gate 		/* Free up the memory for selfID buffer #1 */
1017c478bd9Sstevel@tonic-gate 		kmem_free(hal->selfid_buf1, S1394_SELFID_BUF_SIZE);
1027c478bd9Sstevel@tonic-gate 		/* Free up the memory for selfID buffer #0 */
1037c478bd9Sstevel@tonic-gate 		kmem_free(hal->selfid_buf0, S1394_SELFID_BUF_SIZE);
1047c478bd9Sstevel@tonic-gate 		/* Turn off any timers that might be set */
1057c478bd9Sstevel@tonic-gate 		s1394_destroy_timers(hal);
1067c478bd9Sstevel@tonic-gate 		/* Destroy the bus_reset thread */
1077c478bd9Sstevel@tonic-gate 		s1394_destroy_br_thread(hal);
1087c478bd9Sstevel@tonic-gate 		/* Cleanup the Config ROM buffers in the topology_tree */
1097c478bd9Sstevel@tonic-gate 		s1394_cleanup_node_cfgrom(hal);
1107c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	case H1394_CLEANUP_LEVEL2:
1137c478bd9Sstevel@tonic-gate 		/* Destroy the br_cmplq_cv and br_cmplq_mutex */
1147c478bd9Sstevel@tonic-gate 		cv_destroy(&hal->br_cmplq_cv);
1157c478bd9Sstevel@tonic-gate 		mutex_destroy(&hal->br_cmplq_mutex);
1167c478bd9Sstevel@tonic-gate 		/* Destroy the br_thread_cv and br_thread_mutex */
1177c478bd9Sstevel@tonic-gate 		cv_destroy(&hal->br_thread_cv);
1187c478bd9Sstevel@tonic-gate 		mutex_destroy(&hal->br_thread_mutex);
1197c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 	case H1394_CLEANUP_LEVEL1:
1227c478bd9Sstevel@tonic-gate 		(void) ddi_prop_remove_all(hal->halinfo.dip);
1237c478bd9Sstevel@tonic-gate 		nx1394_undefine_events(hal);
1247c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	case H1394_CLEANUP_LEVEL0:
1277c478bd9Sstevel@tonic-gate 		kmem_cache_destroy(hal->hal_kmem_cachep);
1287c478bd9Sstevel@tonic-gate 		/* Destroy pending_q_mutex and outstanding_q_mutex */
1297c478bd9Sstevel@tonic-gate 		mutex_destroy(&hal->pending_q_mutex);
1307c478bd9Sstevel@tonic-gate 		mutex_destroy(&hal->outstanding_q_mutex);
1317c478bd9Sstevel@tonic-gate 		/* Destroy target_list_rwlock */
1327c478bd9Sstevel@tonic-gate 		rw_destroy(&hal->target_list_rwlock);
1337c478bd9Sstevel@tonic-gate 		/* Destroy bus_mgr_node_mutex and bus_mgr_node_cv */
1347c478bd9Sstevel@tonic-gate 		cv_destroy(&hal->bus_mgr_node_cv);
1357c478bd9Sstevel@tonic-gate 		mutex_destroy(&hal->bus_mgr_node_mutex);
1367c478bd9Sstevel@tonic-gate 		/* Destroy isoch_cec_list_mutex */
1377c478bd9Sstevel@tonic-gate 		mutex_destroy(&hal->isoch_cec_list_mutex);
1387c478bd9Sstevel@tonic-gate 		/* Destroy the Cycle Master timer mutex */
1397c478bd9Sstevel@tonic-gate 		mutex_destroy(&hal->cm_timer_mutex);
1407c478bd9Sstevel@tonic-gate 		/* Destroy topology_tree_mutex */
1417c478bd9Sstevel@tonic-gate 		mutex_destroy(&hal->topology_tree_mutex);
1427c478bd9Sstevel@tonic-gate 		/* Free the hal structure */
1437c478bd9Sstevel@tonic-gate 		kmem_free(hal, sizeof (s1394_hal_t));
1447c478bd9Sstevel@tonic-gate 		break;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	default:
1477c478bd9Sstevel@tonic-gate 		/* Error */
1487c478bd9Sstevel@tonic-gate 		break;
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate /*
1537c478bd9Sstevel@tonic-gate  * s1394_hal_shutdown()
1547c478bd9Sstevel@tonic-gate  *    is used to shutdown the HAL.  If the HAL indicates that an error
1557c478bd9Sstevel@tonic-gate  *    condition (hardware or software) has occurred, it is shutdown. This
1567c478bd9Sstevel@tonic-gate  *    routine is also called when HAL informs the services layer of a shutdown
1577c478bd9Sstevel@tonic-gate  *    (due an internal shutdown, for eg). disable_hal indicates whether the
1587c478bd9Sstevel@tonic-gate  *    caller intends to inform the hal of the (services layer) shutdown or not.
1597c478bd9Sstevel@tonic-gate  */
1607c478bd9Sstevel@tonic-gate void
s1394_hal_shutdown(s1394_hal_t * hal,boolean_t disable_hal)1617c478bd9Sstevel@tonic-gate s1394_hal_shutdown(s1394_hal_t *hal, boolean_t disable_hal)
1627c478bd9Sstevel@tonic-gate {
1637c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t cookie;
1647c478bd9Sstevel@tonic-gate 	t1394_localinfo_t localinfo;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->topology_tree_mutex);
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	if (hal->hal_state == S1394_HAL_SHUTDOWN) {
1697c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->topology_tree_mutex);
1707c478bd9Sstevel@tonic-gate 		if (disable_hal == B_TRUE)
1717c478bd9Sstevel@tonic-gate 			HAL_CALL(hal).shutdown(hal->halinfo.hal_private);
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 		return;
1747c478bd9Sstevel@tonic-gate 	}
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	hal->hal_state = S1394_HAL_SHUTDOWN;
1777c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->topology_tree_mutex);
1787c478bd9Sstevel@tonic-gate 	/* Disable the HAL */
1797c478bd9Sstevel@tonic-gate 	if (disable_hal == B_TRUE)
1807c478bd9Sstevel@tonic-gate 		HAL_CALL(hal).shutdown(hal->halinfo.hal_private);
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	/*
1837c478bd9Sstevel@tonic-gate 	 * Send a remove event to all interested parties
1847c478bd9Sstevel@tonic-gate 	 */
1857c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->topology_tree_mutex);
1867c478bd9Sstevel@tonic-gate 	localinfo.bus_generation = hal->generation_count;
1877c478bd9Sstevel@tonic-gate 	localinfo.local_nodeID	 = hal->node_id;
1887c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->topology_tree_mutex);
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	if (ndi_event_retrieve_cookie(hal->hal_ndi_event_hdl, NULL,
1917c478bd9Sstevel@tonic-gate 	    DDI_DEVI_REMOVE_EVENT, &cookie, NDI_EVENT_NOPASS) ==
1927c478bd9Sstevel@tonic-gate 	    NDI_SUCCESS)
1937c478bd9Sstevel@tonic-gate 		(void) ndi_event_run_callbacks(hal->hal_ndi_event_hdl, NULL,
1947c478bd9Sstevel@tonic-gate 		    cookie, &localinfo);
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate /*
1987c478bd9Sstevel@tonic-gate  * s1394_initiate_hal_reset()
1997c478bd9Sstevel@tonic-gate  *    sets up the HAL structure to indicate a self-initiated bus reset and
2007c478bd9Sstevel@tonic-gate  *    calls the appropriate HAL entry point.  If too many bus resets have
2017c478bd9Sstevel@tonic-gate  *    happened, a message is printed out and the call is ignored.
2027c478bd9Sstevel@tonic-gate  */
2037c478bd9Sstevel@tonic-gate void
s1394_initiate_hal_reset(s1394_hal_t * hal,int reason)2047c478bd9Sstevel@tonic-gate s1394_initiate_hal_reset(s1394_hal_t *hal, int reason)
2057c478bd9Sstevel@tonic-gate {
2067c478bd9Sstevel@tonic-gate 	if (hal->num_bus_reset_till_fail > 0) {
2077c478bd9Sstevel@tonic-gate 		hal->initiated_bus_reset = B_TRUE;
2087c478bd9Sstevel@tonic-gate 		hal->initiated_br_reason = reason;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 		/* Reset the bus */
211*2570281cSToomas Soome 		(void) HAL_CALL(hal).bus_reset(hal->halinfo.hal_private);
2127c478bd9Sstevel@tonic-gate 	} else {
2137c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "Unable to reenumerate the 1394 bus - If new"
2147c478bd9Sstevel@tonic-gate 		    " devices have recently been added, remove them.");
2157c478bd9Sstevel@tonic-gate 	}
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate /*
2197c478bd9Sstevel@tonic-gate  * s1394_on_br_thread()
2207c478bd9Sstevel@tonic-gate  *    is used to determine if the current thread of execution is the same
2217c478bd9Sstevel@tonic-gate  *    as the bus reset thread.  This is useful during bus reset callbacks
2227c478bd9Sstevel@tonic-gate  *    to determine whether or not a target may block.
2237c478bd9Sstevel@tonic-gate  */
2247c478bd9Sstevel@tonic-gate boolean_t
s1394_on_br_thread(s1394_hal_t * hal)2257c478bd9Sstevel@tonic-gate s1394_on_br_thread(s1394_hal_t *hal)
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate 	if (hal->br_thread == curthread)
2287c478bd9Sstevel@tonic-gate 		return (B_TRUE);
2297c478bd9Sstevel@tonic-gate 	else
2307c478bd9Sstevel@tonic-gate 		return (B_FALSE);
2317c478bd9Sstevel@tonic-gate }
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate /*
2347c478bd9Sstevel@tonic-gate  * s1394_destroy_br_thread()
2357c478bd9Sstevel@tonic-gate  *    is used in h1394_detach() to signal the bus reset thread to go away.
2367c478bd9Sstevel@tonic-gate  */
2377c478bd9Sstevel@tonic-gate void
s1394_destroy_br_thread(s1394_hal_t * hal)2387c478bd9Sstevel@tonic-gate s1394_destroy_br_thread(s1394_hal_t *hal)
2397c478bd9Sstevel@tonic-gate {
2407c478bd9Sstevel@tonic-gate 	/* Send the signal to the reset thread to go away */
2417c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->br_thread_mutex);
2427c478bd9Sstevel@tonic-gate 	hal->br_thread_ev_type |= BR_THR_GO_AWAY;
2437c478bd9Sstevel@tonic-gate 	cv_signal(&hal->br_thread_cv);
2447c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->br_thread_mutex);
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	/* Wakeup the bus_reset thread if waiting for bus_mgr timer */
2477c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->bus_mgr_node_mutex);
2487c478bd9Sstevel@tonic-gate 	hal->bus_mgr_node = S1394_INVALID_NODE_NUM;
2497c478bd9Sstevel@tonic-gate 	cv_signal(&hal->bus_mgr_node_cv);
2507c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->bus_mgr_node_mutex);
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->br_cmplq_mutex);
2537c478bd9Sstevel@tonic-gate 	cv_signal(&hal->br_cmplq_cv);
2547c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->br_cmplq_mutex);
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	/* Wait for the br_thread to be done */
2577c478bd9Sstevel@tonic-gate 	while (hal->br_thread_ev_type & BR_THR_GO_AWAY)
2587c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(10));
2597c478bd9Sstevel@tonic-gate }
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate /*
2627c478bd9Sstevel@tonic-gate  * s1394_tickle_bus_reset_thread()
2637c478bd9Sstevel@tonic-gate  *    is used to wakeup the bus reset thread after the interrupt routine
2647c478bd9Sstevel@tonic-gate  *    has completed its bus reset processing.
2657c478bd9Sstevel@tonic-gate  */
2667c478bd9Sstevel@tonic-gate void
s1394_tickle_bus_reset_thread(s1394_hal_t * hal)2677c478bd9Sstevel@tonic-gate s1394_tickle_bus_reset_thread(s1394_hal_t *hal)
2687c478bd9Sstevel@tonic-gate {
2697c478bd9Sstevel@tonic-gate 	if (hal->topology_tree_processed != B_TRUE) {
2707c478bd9Sstevel@tonic-gate 		/* Send the signal to the reset thread */
2717c478bd9Sstevel@tonic-gate 		mutex_enter(&hal->br_thread_mutex);
2727c478bd9Sstevel@tonic-gate 		hal->br_thread_ev_type |= BR_THR_CFGROM_SCAN;
2737c478bd9Sstevel@tonic-gate 		cv_signal(&hal->br_thread_cv);
2747c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->br_thread_mutex);
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 		/* Signal the msgq wait, too (just in case) */
2777c478bd9Sstevel@tonic-gate 		mutex_enter(&hal->br_cmplq_mutex);
2787c478bd9Sstevel@tonic-gate 		cv_signal(&hal->br_cmplq_cv);
2797c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->br_cmplq_mutex);
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 		/* Signal the bus_mgr wait, too (just in case) */
2827c478bd9Sstevel@tonic-gate 		mutex_enter(&hal->bus_mgr_node_mutex);
2837c478bd9Sstevel@tonic-gate 		cv_signal(&hal->bus_mgr_node_cv);
2847c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->bus_mgr_node_mutex);
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate /*
2897c478bd9Sstevel@tonic-gate  * s1394_block_on_asynch_cmd()
2907c478bd9Sstevel@tonic-gate  *    is used by many of the asynch routines to block (if necessary)
2917c478bd9Sstevel@tonic-gate  *    while waiting for command completion.
2927c478bd9Sstevel@tonic-gate  */
2937c478bd9Sstevel@tonic-gate void
s1394_block_on_asynch_cmd(cmd1394_cmd_t * cmd)2947c478bd9Sstevel@tonic-gate s1394_block_on_asynch_cmd(cmd1394_cmd_t	*cmd)
2957c478bd9Sstevel@tonic-gate {
2967c478bd9Sstevel@tonic-gate 	s1394_cmd_priv_t  *s_priv;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	/* Get the Services Layer private area */
2997c478bd9Sstevel@tonic-gate 	s_priv = S1394_GET_CMD_PRIV(cmd);
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	/* Is this a blocking command? */
3027c478bd9Sstevel@tonic-gate 	if (cmd->cmd_options & CMD1394_BLOCKING) {
3037c478bd9Sstevel@tonic-gate 		/* Block until command completes */
3047c478bd9Sstevel@tonic-gate 		mutex_enter(&s_priv->blocking_mutex);
3057c478bd9Sstevel@tonic-gate 		while (s_priv->blocking_flag != B_TRUE)
3067c478bd9Sstevel@tonic-gate 			cv_wait(&s_priv->blocking_cv, &s_priv->blocking_mutex);
3077c478bd9Sstevel@tonic-gate 		s_priv->blocking_flag = B_FALSE;
3087c478bd9Sstevel@tonic-gate 		mutex_exit(&s_priv->blocking_mutex);
3097c478bd9Sstevel@tonic-gate 	}
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate /*
3137c478bd9Sstevel@tonic-gate  * s1394_HAL_asynch_error()
3147c478bd9Sstevel@tonic-gate  *    is used by many of the asynch routines to determine what error
3157c478bd9Sstevel@tonic-gate  *    code is expected in a given situation (based on HAL state).
3167c478bd9Sstevel@tonic-gate  */
3177c478bd9Sstevel@tonic-gate /* ARGSUSED */
3187c478bd9Sstevel@tonic-gate int
s1394_HAL_asynch_error(s1394_hal_t * hal,cmd1394_cmd_t * cmd,s1394_hal_state_t state)3197c478bd9Sstevel@tonic-gate s1394_HAL_asynch_error(s1394_hal_t *hal, cmd1394_cmd_t *cmd,
3207c478bd9Sstevel@tonic-gate     s1394_hal_state_t state)
3217c478bd9Sstevel@tonic-gate {
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	switch (state) {
3267c478bd9Sstevel@tonic-gate 	case S1394_HAL_RESET:
3277c478bd9Sstevel@tonic-gate 		/* "dreq" bit is set (CSR) */
3287c478bd9Sstevel@tonic-gate 		if (hal->disable_requests_bit == 1)
3297c478bd9Sstevel@tonic-gate 			return (CMD1394_ENO_ATREQ);
3307c478bd9Sstevel@tonic-gate 		else
3317c478bd9Sstevel@tonic-gate 			return (CMD1394_CMDSUCCESS);
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	case S1394_HAL_DREQ:
3347c478bd9Sstevel@tonic-gate 		/* "dreq" bit is set (CSR) */
3357c478bd9Sstevel@tonic-gate 		return (CMD1394_ENO_ATREQ);
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	case S1394_HAL_SHUTDOWN:
3387c478bd9Sstevel@tonic-gate 		return (CMD1394_EFATAL_ERROR);
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	default:
3417c478bd9Sstevel@tonic-gate 		return (CMD1394_CMDSUCCESS);
3427c478bd9Sstevel@tonic-gate 	}
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate /*
3467c478bd9Sstevel@tonic-gate  * s1394_mblk_too_small()
3477c478bd9Sstevel@tonic-gate  *    is used to determine if the mlbk_t structure(s) given in an asynch
3487c478bd9Sstevel@tonic-gate  *    block request are sufficient to hold the amount of data requested.
3497c478bd9Sstevel@tonic-gate  */
3507c478bd9Sstevel@tonic-gate boolean_t
s1394_mblk_too_small(cmd1394_cmd_t * cmd)3517c478bd9Sstevel@tonic-gate s1394_mblk_too_small(cmd1394_cmd_t *cmd)
3527c478bd9Sstevel@tonic-gate {
3537c478bd9Sstevel@tonic-gate 	mblk_t	  *curr_blk;
3547c478bd9Sstevel@tonic-gate 	boolean_t flag;
3557c478bd9Sstevel@tonic-gate 	size_t	  msgb_len;
3567c478bd9Sstevel@tonic-gate 	size_t	  size;
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	curr_blk = cmd->cmd_u.b.data_block;
3597c478bd9Sstevel@tonic-gate 	msgb_len = 0;
3607c478bd9Sstevel@tonic-gate 	flag = B_TRUE;
3617c478bd9Sstevel@tonic-gate 	size = cmd->cmd_u.b.blk_length;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	while (curr_blk != NULL) {
3647c478bd9Sstevel@tonic-gate 		if (cmd->cmd_type == CMD1394_ASYNCH_WR_BLOCK) {
3657c478bd9Sstevel@tonic-gate 			msgb_len += (curr_blk->b_wptr - curr_blk->b_rptr);
3667c478bd9Sstevel@tonic-gate 		} else {
3677c478bd9Sstevel@tonic-gate 			msgb_len +=
3687c478bd9Sstevel@tonic-gate 			    (curr_blk->b_datap->db_lim - curr_blk->b_wptr);
3697c478bd9Sstevel@tonic-gate 		}
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 		if (msgb_len >= size) {
3727c478bd9Sstevel@tonic-gate 			flag = B_FALSE;
3737c478bd9Sstevel@tonic-gate 			break;
3747c478bd9Sstevel@tonic-gate 		}
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 		curr_blk = curr_blk->b_cont;
3777c478bd9Sstevel@tonic-gate 	}
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	return (flag);
3807c478bd9Sstevel@tonic-gate }
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate /*
3837c478bd9Sstevel@tonic-gate  * s1394_address_rollover()
3847c478bd9Sstevel@tonic-gate  *    is used to determine if the address given will rollover the 48-bit
3857c478bd9Sstevel@tonic-gate  *    address space.
3867c478bd9Sstevel@tonic-gate  */
3877c478bd9Sstevel@tonic-gate boolean_t
s1394_address_rollover(cmd1394_cmd_t * cmd)3887c478bd9Sstevel@tonic-gate s1394_address_rollover(cmd1394_cmd_t *cmd)
3897c478bd9Sstevel@tonic-gate {
3907c478bd9Sstevel@tonic-gate 	uint64_t addr_before;
3917c478bd9Sstevel@tonic-gate 	uint64_t addr_after;
3927c478bd9Sstevel@tonic-gate 	size_t	 length;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	switch (cmd->cmd_type) {
3957c478bd9Sstevel@tonic-gate 	case CMD1394_ASYNCH_RD_QUAD:
3967c478bd9Sstevel@tonic-gate 	case CMD1394_ASYNCH_WR_QUAD:
3977c478bd9Sstevel@tonic-gate 	case CMD1394_ASYNCH_LOCK_32:
3987c478bd9Sstevel@tonic-gate 		length = IEEE1394_QUADLET;
3997c478bd9Sstevel@tonic-gate 		break;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	case CMD1394_ASYNCH_LOCK_64:
4027c478bd9Sstevel@tonic-gate 		length = IEEE1394_OCTLET;
4037c478bd9Sstevel@tonic-gate 		break;
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	case CMD1394_ASYNCH_RD_BLOCK:
4067c478bd9Sstevel@tonic-gate 	case CMD1394_ASYNCH_WR_BLOCK:
4077c478bd9Sstevel@tonic-gate 		length = cmd->cmd_u.b.blk_length;
4087c478bd9Sstevel@tonic-gate 		break;
4097c478bd9Sstevel@tonic-gate 	}
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	addr_before = cmd->cmd_addr & IEEE1394_ADDR_OFFSET_MASK;
4127c478bd9Sstevel@tonic-gate 	addr_after = (addr_before + length) & IEEE1394_ADDR_OFFSET_MASK;
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	if (addr_after < addr_before) {
4157c478bd9Sstevel@tonic-gate 		return (B_TRUE);
4167c478bd9Sstevel@tonic-gate 	}
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	return (B_FALSE);
4197c478bd9Sstevel@tonic-gate }
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate /*
4227c478bd9Sstevel@tonic-gate  * s1394_stoi()
4237c478bd9Sstevel@tonic-gate  *    returns the integer value of the string of hex/dec/oct numeric characters
4247c478bd9Sstevel@tonic-gate  *    beginning at *p. Does no overflow checking.
4257c478bd9Sstevel@tonic-gate  */
4267c478bd9Sstevel@tonic-gate uint_t
s1394_stoi(char * p,int len,int base)4277c478bd9Sstevel@tonic-gate s1394_stoi(char *p, int len, int base)
4287c478bd9Sstevel@tonic-gate {
4297c478bd9Sstevel@tonic-gate 	int	n;
4307c478bd9Sstevel@tonic-gate 	int	c;
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	if (len == 0)
4337c478bd9Sstevel@tonic-gate 		return (0);
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	for (n = 0; len && (c = *p); p++, len--) {
4367c478bd9Sstevel@tonic-gate 		if (c >= '0' && c <= '9')
4377c478bd9Sstevel@tonic-gate 			c = c - '0';
4387c478bd9Sstevel@tonic-gate 		else if (c >= 'a' && c <= 'f')
4397c478bd9Sstevel@tonic-gate 			c = c - 'a' + 10;
4407c478bd9Sstevel@tonic-gate 		else if (c >= 'A' && c <= 'F')
4417c478bd9Sstevel@tonic-gate 			c = c - 'F' + 10;
4427c478bd9Sstevel@tonic-gate 		n = (n * base) + c;
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	return (n);
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate /*
4497c478bd9Sstevel@tonic-gate  * s1394_CRC16()
4507c478bd9Sstevel@tonic-gate  *    implements ISO/IEC 13213:1994, ANSI/IEEE Std 1212, 1994 - 8.1.5
4517c478bd9Sstevel@tonic-gate  */
4527c478bd9Sstevel@tonic-gate uint_t
s1394_CRC16(uint_t * d,uint_t crc_length)4537c478bd9Sstevel@tonic-gate s1394_CRC16(uint_t *d, uint_t crc_length)
4547c478bd9Sstevel@tonic-gate {
4557c478bd9Sstevel@tonic-gate 	uint_t	CRC = 0;
4567c478bd9Sstevel@tonic-gate 	uint_t	data;
4577c478bd9Sstevel@tonic-gate 	uint_t	next;
4587c478bd9Sstevel@tonic-gate 	uint_t	sum;
4597c478bd9Sstevel@tonic-gate 	int	shift;
4607c478bd9Sstevel@tonic-gate 	int	i;
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	for (i = 0; i < crc_length; i++) {
4637c478bd9Sstevel@tonic-gate 		data = d[i];
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 		/* Another check should be made with "shift > 0" in  */
4667c478bd9Sstevel@tonic-gate 		/* order to support any devices that coded it wrong. */
4677c478bd9Sstevel@tonic-gate 		for (next = CRC, shift = 28; shift >= 0; shift -= 4) {
4687c478bd9Sstevel@tonic-gate 			sum = ((next >> 12) ^ (data >> shift)) & 0xF;
4697c478bd9Sstevel@tonic-gate 			next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
4707c478bd9Sstevel@tonic-gate 		}
4717c478bd9Sstevel@tonic-gate 		CRC = next & IEEE1394_CRC16_MASK;
4727c478bd9Sstevel@tonic-gate 	}
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	return (CRC);
4757c478bd9Sstevel@tonic-gate }
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate /*
4787c478bd9Sstevel@tonic-gate  * s1394_CRC16_old()
4797c478bd9Sstevel@tonic-gate  *    implements a slightly modified version of ISO/IEC 13213:1994,
4807c478bd9Sstevel@tonic-gate  *    ANSI/IEEE Std 1212, 1994 - 8.1.5.  In the original IEEE 1212-1994
4817c478bd9Sstevel@tonic-gate  *    specification the C code example was incorrect and some devices
4827c478bd9Sstevel@tonic-gate  *    were manufactured using this incorrect CRC.  On CRC16 failures
4837c478bd9Sstevel@tonic-gate  *    this CRC is tried in case it is a legacy device.
4847c478bd9Sstevel@tonic-gate  */
4857c478bd9Sstevel@tonic-gate uint_t
s1394_CRC16_old(uint_t * d,uint_t crc_length)4867c478bd9Sstevel@tonic-gate s1394_CRC16_old(uint_t *d, uint_t crc_length)
4877c478bd9Sstevel@tonic-gate {
4887c478bd9Sstevel@tonic-gate 	uint_t	CRC = 0;
4897c478bd9Sstevel@tonic-gate 	uint_t	data;
4907c478bd9Sstevel@tonic-gate 	uint_t	next;
4917c478bd9Sstevel@tonic-gate 	uint_t	sum;
4927c478bd9Sstevel@tonic-gate 	int	shift;
4937c478bd9Sstevel@tonic-gate 	int	i;
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	for (i = 0; i < crc_length; i++) {
4967c478bd9Sstevel@tonic-gate 		data = d[i];
4977c478bd9Sstevel@tonic-gate 		for (next = CRC, shift = 28; shift > 0; shift -= 4) {
4987c478bd9Sstevel@tonic-gate 			sum = ((next >> 12) ^ (data >> shift)) & 0xF;
4997c478bd9Sstevel@tonic-gate 			next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
5007c478bd9Sstevel@tonic-gate 		}
5017c478bd9Sstevel@tonic-gate 		CRC = next & IEEE1394_CRC16_MASK;
5027c478bd9Sstevel@tonic-gate 	}
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	return (CRC);
5057c478bd9Sstevel@tonic-gate }
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate /*
5087c478bd9Sstevel@tonic-gate  * s1394_ioctl()
5097c478bd9Sstevel@tonic-gate  *    implements generic ioctls (eg. devctl support) and any non-HAL ioctls.
5107c478bd9Sstevel@tonic-gate  *    Only ioctls required for devctl support are implemented at present.
5117c478bd9Sstevel@tonic-gate  */
5127c478bd9Sstevel@tonic-gate /* ARGSUSED */
5137c478bd9Sstevel@tonic-gate int
s1394_ioctl(s1394_hal_t * hal,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)5147c478bd9Sstevel@tonic-gate s1394_ioctl(s1394_hal_t *hal, int cmd, intptr_t arg, int mode, cred_t *cred_p,
5157c478bd9Sstevel@tonic-gate     int *rval_p)
5167c478bd9Sstevel@tonic-gate {
5177c478bd9Sstevel@tonic-gate 	struct devctl_iocdata	*dcp;
5187c478bd9Sstevel@tonic-gate 	dev_info_t		*self;
5197c478bd9Sstevel@tonic-gate 	int			rv = 0;
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	self = hal->halinfo.dip;
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	/*
5247c478bd9Sstevel@tonic-gate 	 * We can use the generic implementation for these ioctls
5257c478bd9Sstevel@tonic-gate 	 */
5267c478bd9Sstevel@tonic-gate 	switch (cmd) {
5277c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_GETSTATE:
5287c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_ONLINE:
5297c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_OFFLINE:
5307c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_REMOVE:
5317c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_GETSTATE:
5327c478bd9Sstevel@tonic-gate 		return (ndi_devctl_ioctl(self, cmd, arg, mode, 0));
5337c478bd9Sstevel@tonic-gate 	}
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	/* Read devctl ioctl data */
5367c478bd9Sstevel@tonic-gate 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) {
5377c478bd9Sstevel@tonic-gate 		return (EFAULT);
5387c478bd9Sstevel@tonic-gate 	}
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	switch (cmd) {
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_RESET:
5437c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_REMOVE:
5447c478bd9Sstevel@tonic-gate 		rv = ENOTSUP;
5457c478bd9Sstevel@tonic-gate 		break;
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_CONFIGURE:
5487c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_UNCONFIGURE:
5497c478bd9Sstevel@tonic-gate 		rv = ENOTSUP;
5507c478bd9Sstevel@tonic-gate 		break;
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_QUIESCE:
5537c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_UNQUIESCE:
5547c478bd9Sstevel@tonic-gate 		rv = ENOTSUP;	/* Or call up the tree? */
5557c478bd9Sstevel@tonic-gate 		break;
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_RESET:
5587c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_RESETALL:
5597c478bd9Sstevel@tonic-gate 		if (hal->halinfo.phy == H1394_PHY_1394A) {
560*2570281cSToomas Soome 			(void) HAL_CALL(hal).short_bus_reset(
5617c478bd9Sstevel@tonic-gate 			    hal->halinfo.hal_private);
5627c478bd9Sstevel@tonic-gate 		} else {
563*2570281cSToomas Soome 			(void)
564*2570281cSToomas Soome 			    HAL_CALL(hal).bus_reset(hal->halinfo.hal_private);
5657c478bd9Sstevel@tonic-gate 		}
5667c478bd9Sstevel@tonic-gate 		break;
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	default:
5697c478bd9Sstevel@tonic-gate 		rv = ENOTTY;
5707c478bd9Sstevel@tonic-gate 	}
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	ndi_dc_freehdl(dcp);
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	return (rv);
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate /*
5787c478bd9Sstevel@tonic-gate  * s1394_kstat_init()
5797c478bd9Sstevel@tonic-gate  *    is used to initialize and the Services Layer's kernel statistics.
5807c478bd9Sstevel@tonic-gate  */
5817c478bd9Sstevel@tonic-gate int
s1394_kstat_init(s1394_hal_t * hal)5827c478bd9Sstevel@tonic-gate s1394_kstat_init(s1394_hal_t *hal)
5837c478bd9Sstevel@tonic-gate {
5847c478bd9Sstevel@tonic-gate 	int instance;
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	hal->hal_kstats = (s1394_kstat_t *)kmem_zalloc(sizeof (s1394_kstat_t),
5877c478bd9Sstevel@tonic-gate 	    KM_SLEEP);
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(hal->halinfo.dip);
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	hal->hal_ksp = kstat_create("s1394", instance, "stats", "misc",
5927c478bd9Sstevel@tonic-gate 	    KSTAT_TYPE_RAW, sizeof (s1394_kstat_t), KSTAT_FLAG_VIRTUAL);
5937c478bd9Sstevel@tonic-gate 	if (hal->hal_ksp != NULL) {
5947c478bd9Sstevel@tonic-gate 		hal->hal_ksp->ks_private = (void *)hal;
5957c478bd9Sstevel@tonic-gate 		hal->hal_ksp->ks_update = s1394_kstat_update;
5967c478bd9Sstevel@tonic-gate 		kstat_install(hal->hal_ksp);
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
5997c478bd9Sstevel@tonic-gate 	} else {
6007c478bd9Sstevel@tonic-gate 		kmem_free((void *)hal->hal_kstats, sizeof (s1394_kstat_t));
6017c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6027c478bd9Sstevel@tonic-gate 	}
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate /*
6067c478bd9Sstevel@tonic-gate  * s1394_kstat_delete()
6077c478bd9Sstevel@tonic-gate  *    is used (in h1394_detach()) to cleanup/free and the Services Layer's
6087c478bd9Sstevel@tonic-gate  *    kernel statistics.
6097c478bd9Sstevel@tonic-gate  */
6107c478bd9Sstevel@tonic-gate int
s1394_kstat_delete(s1394_hal_t * hal)6117c478bd9Sstevel@tonic-gate s1394_kstat_delete(s1394_hal_t *hal)
6127c478bd9Sstevel@tonic-gate {
6137c478bd9Sstevel@tonic-gate 	kstat_delete(hal->hal_ksp);
6147c478bd9Sstevel@tonic-gate 	kmem_free((void *)hal->hal_kstats, sizeof (s1394_kstat_t));
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
6177c478bd9Sstevel@tonic-gate }
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate /*
6207c478bd9Sstevel@tonic-gate  * s1394_kstat_update()
6217c478bd9Sstevel@tonic-gate  *    is a callback that is called whenever a request to read the kernel
6227c478bd9Sstevel@tonic-gate  *    statistics is made.
6237c478bd9Sstevel@tonic-gate  */
6247c478bd9Sstevel@tonic-gate int
s1394_kstat_update(kstat_t * ksp,int rw)6257c478bd9Sstevel@tonic-gate s1394_kstat_update(kstat_t *ksp, int rw)
6267c478bd9Sstevel@tonic-gate {
6277c478bd9Sstevel@tonic-gate 	s1394_hal_t	*hal;
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	hal = ksp->ks_private;
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	if (rw == KSTAT_WRITE) {
6327c478bd9Sstevel@tonic-gate 		return (EACCES);
6337c478bd9Sstevel@tonic-gate 	} else {
6347c478bd9Sstevel@tonic-gate 		ksp->ks_data = hal->hal_kstats;
6357c478bd9Sstevel@tonic-gate 	}
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	return (0);
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate /*
6417c478bd9Sstevel@tonic-gate  * s1394_addr_alloc_kstat()
6427c478bd9Sstevel@tonic-gate  *    is used by the kernel statistics to update the count for each type of
6437c478bd9Sstevel@tonic-gate  *    address allocation.
6447c478bd9Sstevel@tonic-gate  */
6457c478bd9Sstevel@tonic-gate void
s1394_addr_alloc_kstat(s1394_hal_t * hal,uint64_t addr)6467c478bd9Sstevel@tonic-gate s1394_addr_alloc_kstat(s1394_hal_t *hal, uint64_t addr)
6477c478bd9Sstevel@tonic-gate {
6487c478bd9Sstevel@tonic-gate 	/* kstats - number of addr allocs */
6497c478bd9Sstevel@tonic-gate 	if (s1394_is_posted_write(hal, addr) == B_TRUE)
6507c478bd9Sstevel@tonic-gate 		hal->hal_kstats->addr_posted_alloc++;
6517c478bd9Sstevel@tonic-gate 	else if (s1394_is_normal_addr(hal, addr) == B_TRUE)
6527c478bd9Sstevel@tonic-gate 		hal->hal_kstats->addr_normal_alloc++;
6537c478bd9Sstevel@tonic-gate 	else if (s1394_is_csr_addr(hal, addr) == B_TRUE)
6547c478bd9Sstevel@tonic-gate 		hal->hal_kstats->addr_csr_alloc++;
6557c478bd9Sstevel@tonic-gate 	else if (s1394_is_physical_addr(hal, addr) == B_TRUE)
6567c478bd9Sstevel@tonic-gate 		hal->hal_kstats->addr_phys_alloc++;
6577c478bd9Sstevel@tonic-gate }
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate /*
6607c478bd9Sstevel@tonic-gate  * s1394_print_node_info()
6617c478bd9Sstevel@tonic-gate  *    is used to print speed map and GUID information on the console.
6627c478bd9Sstevel@tonic-gate  */
6637c478bd9Sstevel@tonic-gate void
s1394_print_node_info(s1394_hal_t * hal)6647c478bd9Sstevel@tonic-gate s1394_print_node_info(s1394_hal_t *hal)
6657c478bd9Sstevel@tonic-gate {
6667c478bd9Sstevel@tonic-gate 	int	i, j;
6677c478bd9Sstevel@tonic-gate 	uint_t	hal_node_num;
6687c478bd9Sstevel@tonic-gate 	char	str[200], tmp[200];
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	/* These are in common/os/logsubr.c */
6717c478bd9Sstevel@tonic-gate 	extern void log_enter(void);
6727c478bd9Sstevel@tonic-gate 	extern void log_exit(void);
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 	if (s1394_print_guids == 0)
6757c478bd9Sstevel@tonic-gate 		return;
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	log_enter();
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "Speed Map (%d):\n",
6827c478bd9Sstevel@tonic-gate 	    ddi_get_instance(hal->halinfo.dip));
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	(void) strcpy(str, "    |");
6857c478bd9Sstevel@tonic-gate 	for (i = 0; i < hal->number_of_nodes; i++) {
6867c478bd9Sstevel@tonic-gate 	    (void) sprintf(tmp, " %2d ", i);
6877c478bd9Sstevel@tonic-gate 	    (void) strcat(str, tmp);
6887c478bd9Sstevel@tonic-gate 	}
6897c478bd9Sstevel@tonic-gate 	(void) strcat(str, "  |       GUID\n");
6907c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, str);
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 	(void) strcpy(str, "----|");
6937c478bd9Sstevel@tonic-gate 	for (i = 0; i < hal->number_of_nodes; i++) {
6947c478bd9Sstevel@tonic-gate 	    (void) sprintf(tmp, "----");
6957c478bd9Sstevel@tonic-gate 	    (void) strcat(str, tmp);
6967c478bd9Sstevel@tonic-gate 	}
6977c478bd9Sstevel@tonic-gate 	(void) strcat(str, "--|------------------\n");
6987c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, str);
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	for (i = 0; i < hal->number_of_nodes; i++) {
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	    (void) sprintf(str, " %2d |", i);
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 	    for (j = 0; j < hal->number_of_nodes; j++) {
7057c478bd9Sstevel@tonic-gate 		(void) sprintf(tmp, " %3d", hal->speed_map[i][j]);
7067c478bd9Sstevel@tonic-gate 		(void) strcat(str, tmp);
7077c478bd9Sstevel@tonic-gate 	    }
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	    if (i == hal_node_num) {
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 		(void) strcat(str, "  | Local OHCI Card\n");
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	    } else if (CFGROM_BIB_READ(&hal->topology_tree[i])) {
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 		(void) sprintf(tmp, "  | %08x%08x\n",
7167c478bd9Sstevel@tonic-gate 				    hal->topology_tree[i].node_guid_hi,
7177c478bd9Sstevel@tonic-gate 				    hal->topology_tree[i].node_guid_lo);
7187c478bd9Sstevel@tonic-gate 		(void) strcat(str, tmp);
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	    } else if (hal->topology_tree[i].link_active == 0) {
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 		(void) strcat(str, "  | Link off\n");
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 	    } else {
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 		(void) strcat(str, "  | ????????????????\n");
7277c478bd9Sstevel@tonic-gate 	    }
7287c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, str);
7297c478bd9Sstevel@tonic-gate 	}
7307c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "\n");
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	log_exit();
7337c478bd9Sstevel@tonic-gate }
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate /*
7367c478bd9Sstevel@tonic-gate  * s1394_dip_to_hal()
7377c478bd9Sstevel@tonic-gate  *    is used to lookup a HAL's structure pointer by its dip.
7387c478bd9Sstevel@tonic-gate  */
7397c478bd9Sstevel@tonic-gate s1394_hal_t *
s1394_dip_to_hal(dev_info_t * hal_dip)7407c478bd9Sstevel@tonic-gate s1394_dip_to_hal(dev_info_t *hal_dip)
7417c478bd9Sstevel@tonic-gate {
7427c478bd9Sstevel@tonic-gate 	s1394_hal_t	*current_hal = NULL;
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	mutex_enter(&s1394_statep->hal_list_mutex);
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 	/* Search the HAL list for this dip */
7477c478bd9Sstevel@tonic-gate 	current_hal = s1394_statep->hal_head;
7487c478bd9Sstevel@tonic-gate 	while (current_hal != NULL) {
7497c478bd9Sstevel@tonic-gate 		if (current_hal->halinfo.dip == hal_dip) {
7507c478bd9Sstevel@tonic-gate 			break;
7517c478bd9Sstevel@tonic-gate 		}
7527c478bd9Sstevel@tonic-gate 		current_hal = current_hal->hal_next;
7537c478bd9Sstevel@tonic-gate 	}
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	mutex_exit(&s1394_statep->hal_list_mutex);
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	return (current_hal);
7587c478bd9Sstevel@tonic-gate }
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate /*
7617c478bd9Sstevel@tonic-gate  * s1394_target_from_dip_locked()
7627c478bd9Sstevel@tonic-gate  *    searches target_list on the HAL for target corresponding to tdip;
7637c478bd9Sstevel@tonic-gate  *    if found, target is returned, else returns NULL. This routine assumes
7647c478bd9Sstevel@tonic-gate  *    target_list_rwlock is locked.
7657c478bd9Sstevel@tonic-gate  *    NOTE: the callers may have the list locked in either write mode or read
7667c478bd9Sstevel@tonic-gate  *    mode. Currently, there is no ddi-compliant way we can assert on the lock
7677c478bd9Sstevel@tonic-gate  *    being held in write mode.
7687c478bd9Sstevel@tonic-gate  */
7697c478bd9Sstevel@tonic-gate s1394_target_t *
s1394_target_from_dip_locked(s1394_hal_t * hal,dev_info_t * tdip)7707c478bd9Sstevel@tonic-gate s1394_target_from_dip_locked(s1394_hal_t *hal, dev_info_t *tdip)
7717c478bd9Sstevel@tonic-gate {
7727c478bd9Sstevel@tonic-gate 	s1394_target_t	*temp;
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	temp = hal->target_head;
7757c478bd9Sstevel@tonic-gate 	while (temp != NULL) {
7767c478bd9Sstevel@tonic-gate 	    if (temp->target_dip == tdip) {
7777c478bd9Sstevel@tonic-gate 		return (temp);
7787c478bd9Sstevel@tonic-gate 	    }
7797c478bd9Sstevel@tonic-gate 	    temp = temp->target_next;
7807c478bd9Sstevel@tonic-gate 	}
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	return (NULL);
7837c478bd9Sstevel@tonic-gate }
7847c478bd9Sstevel@tonic-gate /*
7857c478bd9Sstevel@tonic-gate  * s1394_target_from_dip()
7867c478bd9Sstevel@tonic-gate  *    searches target_list on the HAL for target corresponding to tdip;
7877c478bd9Sstevel@tonic-gate  *    if found, target is returned locked.
7887c478bd9Sstevel@tonic-gate  */
7897c478bd9Sstevel@tonic-gate s1394_target_t *
s1394_target_from_dip(s1394_hal_t * hal,dev_info_t * tdip)7907c478bd9Sstevel@tonic-gate s1394_target_from_dip(s1394_hal_t *hal, dev_info_t *tdip)
7917c478bd9Sstevel@tonic-gate {
7927c478bd9Sstevel@tonic-gate 	s1394_target_t	*target;
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	rw_enter(&hal->target_list_rwlock, RW_READER);
7957c478bd9Sstevel@tonic-gate 	target = s1394_target_from_dip_locked(hal, tdip);
7967c478bd9Sstevel@tonic-gate 	rw_exit(&hal->target_list_rwlock);
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	return (target);
7997c478bd9Sstevel@tonic-gate }
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate /*
8027c478bd9Sstevel@tonic-gate  * s1394_destroy_timers()
8037c478bd9Sstevel@tonic-gate  *    turns off any outstanding timers in preparation for detach or suspend.
8047c478bd9Sstevel@tonic-gate  */
8057c478bd9Sstevel@tonic-gate void
s1394_destroy_timers(s1394_hal_t * hal)8067c478bd9Sstevel@tonic-gate s1394_destroy_timers(s1394_hal_t *hal)
8077c478bd9Sstevel@tonic-gate {
8087c478bd9Sstevel@tonic-gate 	/* Destroy both of the Bus Mgr timers */
8097c478bd9Sstevel@tonic-gate 	(void) untimeout(hal->bus_mgr_timeout_id);
8107c478bd9Sstevel@tonic-gate 	(void) untimeout(hal->bus_mgr_query_timeout_id);
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	/* Destroy the Cycle Master timer */
8137c478bd9Sstevel@tonic-gate 	(void) untimeout(hal->cm_timer);
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 	/* Wait for the Config ROM timer (if necessary) */
8167c478bd9Sstevel@tonic-gate 	while (hal->config_rom_timer_set == B_TRUE) {
8177c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(10));
8187c478bd9Sstevel@tonic-gate 	}
8197c478bd9Sstevel@tonic-gate }
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate /*
8237c478bd9Sstevel@tonic-gate  * s1394_cleanup_node_cfgrom()
8247c478bd9Sstevel@tonic-gate  *    frees up all of the Config ROM in use by nodes in the topology_tree
8257c478bd9Sstevel@tonic-gate  */
8267c478bd9Sstevel@tonic-gate static void
s1394_cleanup_node_cfgrom(s1394_hal_t * hal)8277c478bd9Sstevel@tonic-gate s1394_cleanup_node_cfgrom(s1394_hal_t *hal)
8287c478bd9Sstevel@tonic-gate {
8297c478bd9Sstevel@tonic-gate 	uint32_t *cfgrom;
8307c478bd9Sstevel@tonic-gate 	int	 i;
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	for (i = 0; i < IEEE1394_MAX_NODES; i++) {
8337c478bd9Sstevel@tonic-gate 		if ((cfgrom = hal->topology_tree[i].cfgrom) != NULL)
8347c478bd9Sstevel@tonic-gate 			kmem_free(cfgrom, IEEE1394_CONFIG_ROM_SZ);
8357c478bd9Sstevel@tonic-gate 	}
8367c478bd9Sstevel@tonic-gate }
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate /*
8397c478bd9Sstevel@tonic-gate  * s1394_cycle_too_long_callback()
8407c478bd9Sstevel@tonic-gate  *    turns on the cycle master bit of the root node (current Cycle Master)
8417c478bd9Sstevel@tonic-gate  */
8427c478bd9Sstevel@tonic-gate void
s1394_cycle_too_long_callback(void * arg)8437c478bd9Sstevel@tonic-gate s1394_cycle_too_long_callback(void *arg)
8447c478bd9Sstevel@tonic-gate {
8457c478bd9Sstevel@tonic-gate 	s1394_hal_t	*hal;
8467c478bd9Sstevel@tonic-gate 	ushort_t	root_node_num;
8477c478bd9Sstevel@tonic-gate 	ushort_t	hal_node_num;
8487c478bd9Sstevel@tonic-gate 	uint32_t	data;
8497c478bd9Sstevel@tonic-gate 	uint_t		offset;
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	hal = (s1394_hal_t *)arg;
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	/* Clear the cm_timer_cet bit */
8547c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->topology_tree_mutex);
8557c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->cm_timer_mutex);
8567c478bd9Sstevel@tonic-gate 	hal->cm_timer_set = B_FALSE;
8577c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->cm_timer_mutex);
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	/* Get the root node and host node numbers */
8607c478bd9Sstevel@tonic-gate 	root_node_num = hal->number_of_nodes - 1;
8617c478bd9Sstevel@tonic-gate 	hal_node_num  = IEEE1394_NODE_NUM(hal->node_id);
8627c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->topology_tree_mutex);
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	/* If we are the root node, set the cycle master bit */
8657c478bd9Sstevel@tonic-gate 	if (hal_node_num == root_node_num) {
8667c478bd9Sstevel@tonic-gate 		data	= IEEE1394_CSR_STATE_CMSTR;
8677c478bd9Sstevel@tonic-gate 		offset  = (IEEE1394_CSR_STATE_SET & IEEE1394_CSR_OFFSET_MASK);
8687c478bd9Sstevel@tonic-gate 		(void) HAL_CALL(hal).csr_write(hal->halinfo.hal_private,
8697c478bd9Sstevel@tonic-gate 		    offset, data);
8707c478bd9Sstevel@tonic-gate 	}
8717c478bd9Sstevel@tonic-gate }
872