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