xref: /illumos-gate/usr/src/uts/common/pcmcia/cs/cs.c (revision c48c3045)
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 /*
235f9e250aShx  * Copyright 2006 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  * PCMCIA Card Services
297c478bd9Sstevel@tonic-gate  *	The PCMCIA Card Services is a loadable module which
307c478bd9Sstevel@tonic-gate  *	presents the Card Services interface to client device
317c478bd9Sstevel@tonic-gate  *	drivers.
327c478bd9Sstevel@tonic-gate  *
337c478bd9Sstevel@tonic-gate  *	Card Services uses Socket Services-like calls into the
347c478bd9Sstevel@tonic-gate  *	PCMCIA nexus driver to manipulate socket and adapter
357c478bd9Sstevel@tonic-gate  *	resources.
367c478bd9Sstevel@tonic-gate  *
377c478bd9Sstevel@tonic-gate  * Note that a bunch of comments are not indented correctly with the
387c478bd9Sstevel@tonic-gate  *	code that they are commenting on. This is because cstyle is
397c478bd9Sstevel@tonic-gate  *	is inflexible concerning 4-column indenting.
407c478bd9Sstevel@tonic-gate  */
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #if defined(DEBUG)
437c478bd9Sstevel@tonic-gate #define	CS_DEBUG
447c478bd9Sstevel@tonic-gate #endif
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #include <sys/types.h>
477c478bd9Sstevel@tonic-gate #include <sys/systm.h>
487c478bd9Sstevel@tonic-gate #include <sys/user.h>
497c478bd9Sstevel@tonic-gate #include <sys/buf.h>
507c478bd9Sstevel@tonic-gate #include <sys/file.h>
517c478bd9Sstevel@tonic-gate #include <sys/uio.h>
527c478bd9Sstevel@tonic-gate #include <sys/conf.h>
537c478bd9Sstevel@tonic-gate #include <sys/stat.h>
547c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
557c478bd9Sstevel@tonic-gate #include <sys/vtoc.h>
567c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
577c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
587c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
597c478bd9Sstevel@tonic-gate #include <sys/debug.h>
607c478bd9Sstevel@tonic-gate #include <sys/varargs.h>
617c478bd9Sstevel@tonic-gate #include <sys/var.h>
627c478bd9Sstevel@tonic-gate #include <sys/proc.h>
637c478bd9Sstevel@tonic-gate #include <sys/thread.h>
647c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
657c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
667c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
677c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
687c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
697c478bd9Sstevel@tonic-gate #include <sys/kobj.h>
707c478bd9Sstevel@tonic-gate #include <sys/callb.h>
717c478bd9Sstevel@tonic-gate #include <sys/time.h>
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate #include <sys/pctypes.h>
747c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cs_types.h>
757c478bd9Sstevel@tonic-gate #include <sys/pcmcia.h>
767c478bd9Sstevel@tonic-gate #include <sys/sservice.h>
777c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cis.h>
787c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cis_handlers.h>
797c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cs.h>
807c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cs_priv.h>
817c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cs_stubs.h>
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate  * The cs_strings header file is where all of the major strings that
857c478bd9Sstevel@tonic-gate  *	Card Services uses are located.
867c478bd9Sstevel@tonic-gate  */
877c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cs_strings.h>
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate /*
917c478bd9Sstevel@tonic-gate  * Function declarations
927c478bd9Sstevel@tonic-gate  *
937c478bd9Sstevel@tonic-gate  * The main Card Services entry point
947c478bd9Sstevel@tonic-gate  */
957c478bd9Sstevel@tonic-gate int CardServices(int function, ...);
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate /*
987c478bd9Sstevel@tonic-gate  * functions and globals used by Socket Services
997c478bd9Sstevel@tonic-gate  *
1007c478bd9Sstevel@tonic-gate  * WAS: void *(*cis_parser)(int, ...) = NULL;
1017c478bd9Sstevel@tonic-gate  */
1027c478bd9Sstevel@tonic-gate void *(*cis_parser)(int, ...) = NULL;
1037c478bd9Sstevel@tonic-gate csfunction_t *cs_socket_services = NULL;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate /*
1067c478bd9Sstevel@tonic-gate  * event handling functions
1077c478bd9Sstevel@tonic-gate  */
1087c478bd9Sstevel@tonic-gate static event_t ss_to_cs_events(cs_socket_t *, event_t);
1097c478bd9Sstevel@tonic-gate static event_t cs_cse2sbm(event_t);
1107c478bd9Sstevel@tonic-gate static void cs_event_thread(uint32_t);
1117c478bd9Sstevel@tonic-gate static int cs_card_insertion(cs_socket_t *, event_t);
1127c478bd9Sstevel@tonic-gate static int cs_card_removal(cs_socket_t *);
1137c478bd9Sstevel@tonic-gate static void cs_ss_thread(uint32_t);
1147c478bd9Sstevel@tonic-gate void cs_ready_timeout(void *);
1157c478bd9Sstevel@tonic-gate static int cs_card_for_client(client_t *);
1167c478bd9Sstevel@tonic-gate static int cs_request_socket_mask(client_handle_t, request_socket_mask_t *);
1177c478bd9Sstevel@tonic-gate static int cs_release_socket_mask(client_handle_t, release_socket_mask_t *);
1187c478bd9Sstevel@tonic-gate static int cs_get_event_mask(client_handle_t, sockevent_t *);
1197c478bd9Sstevel@tonic-gate static int cs_set_event_mask(client_handle_t, sockevent_t *);
1207c478bd9Sstevel@tonic-gate static int cs_event2text(event2text_t *, int);
1217c478bd9Sstevel@tonic-gate static int cs_read_event_status(cs_socket_t *, client_t *, event_t *,
1227c478bd9Sstevel@tonic-gate 						get_ss_status_t *, int);
1237c478bd9Sstevel@tonic-gate uint32_t cs_socket_event_softintr(caddr_t);
1247c478bd9Sstevel@tonic-gate void cs_event_softintr_timeout(void *);
1257c478bd9Sstevel@tonic-gate static int cs_get_status(client_handle_t, get_status_t *);
1267c478bd9Sstevel@tonic-gate static uint32_t cs_sbm2cse(uint32_t);
1277c478bd9Sstevel@tonic-gate static unsigned cs_merge_event_masks(cs_socket_t *, client_t *);
1287c478bd9Sstevel@tonic-gate static int cs_set_socket_event_mask(cs_socket_t *, unsigned);
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate /*
1317c478bd9Sstevel@tonic-gate  * SS<->CS communication and internal socket and window  handling functions
1327c478bd9Sstevel@tonic-gate  */
1337c478bd9Sstevel@tonic-gate static uint32_t cs_add_socket(uint32_t);
1347c478bd9Sstevel@tonic-gate static uint32_t cs_drop_socket(uint32_t);
1357c478bd9Sstevel@tonic-gate static cs_socket_t *cs_get_sp(uint32_t);
1367c478bd9Sstevel@tonic-gate static cs_socket_t *cs_find_sp(uint32_t);
1377c478bd9Sstevel@tonic-gate static cs_window_t *cs_get_wp(uint32_t);
1387c478bd9Sstevel@tonic-gate static cs_window_t *cs_find_wp(uint32_t);
1397c478bd9Sstevel@tonic-gate static int cs_add_windows(int, uint32_t);
1407c478bd9Sstevel@tonic-gate static uint32_t cs_ss_init();
1417c478bd9Sstevel@tonic-gate static void cs_set_acc_attributes(set_window_t *, uint32_t);
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate /*
1447c478bd9Sstevel@tonic-gate  * CIS handling functions
1457c478bd9Sstevel@tonic-gate  */
1467c478bd9Sstevel@tonic-gate cistpl_callout_t *cis_cistpl_std_callout;
1477c478bd9Sstevel@tonic-gate static int cs_parse_tuple(client_handle_t,  tuple_t *, cisparse_t *, cisdata_t);
1487c478bd9Sstevel@tonic-gate static int cs_get_tuple_data(client_handle_t, tuple_t *);
1497c478bd9Sstevel@tonic-gate static int cs_validate_cis(client_handle_t, cisinfo_t *);
1507c478bd9Sstevel@tonic-gate static int cs_get_firstnext_tuple(client_handle_t, tuple_t *, uint32_t);
1517c478bd9Sstevel@tonic-gate static int cs_create_cis(cs_socket_t *);
1527c478bd9Sstevel@tonic-gate static int cs_destroy_cis(cs_socket_t *);
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate /*
1557c478bd9Sstevel@tonic-gate  * client handling functions
1567c478bd9Sstevel@tonic-gate  */
1577c478bd9Sstevel@tonic-gate unsigned cs_create_next_client_minor(unsigned, unsigned);
1587c478bd9Sstevel@tonic-gate static client_t *cs_find_client(client_handle_t, int *);
1597c478bd9Sstevel@tonic-gate static client_handle_t cs_create_client_handle(unsigned, client_t *);
1607c478bd9Sstevel@tonic-gate static int cs_destroy_client_handle(client_handle_t);
1617c478bd9Sstevel@tonic-gate static int cs_register_client(client_handle_t *, client_reg_t *);
1627c478bd9Sstevel@tonic-gate static int cs_deregister_client(client_handle_t);
1637c478bd9Sstevel@tonic-gate static int cs_deregister_mtd(client_handle_t);
1647c478bd9Sstevel@tonic-gate static void cs_clear_superclient_lock(int);
1657c478bd9Sstevel@tonic-gate static int cs_add_client_to_socket(unsigned, client_handle_t *,
1667c478bd9Sstevel@tonic-gate 						client_reg_t *, int);
1677c478bd9Sstevel@tonic-gate static int cs_get_client_info(client_handle_t, client_info_t *);
1687c478bd9Sstevel@tonic-gate static int cs_get_firstnext_client(get_firstnext_client_t *, uint32_t);
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate /*
1717c478bd9Sstevel@tonic-gate  * window handling functions
1727c478bd9Sstevel@tonic-gate  */
1737c478bd9Sstevel@tonic-gate static int cs_request_window(client_handle_t, window_handle_t *, win_req_t *);
1747c478bd9Sstevel@tonic-gate static int cs_release_window(window_handle_t);
1757c478bd9Sstevel@tonic-gate static int cs_modify_window(window_handle_t, modify_win_t *);
1767c478bd9Sstevel@tonic-gate static int cs_modify_mem_window(window_handle_t, modify_win_t *, win_req_t *,
1777c478bd9Sstevel@tonic-gate 									int);
1787c478bd9Sstevel@tonic-gate static int cs_map_mem_page(window_handle_t, map_mem_page_t *);
1797c478bd9Sstevel@tonic-gate static int cs_find_mem_window(uint32_t, win_req_t *, uint32_t *);
1807c478bd9Sstevel@tonic-gate static int cs_memwin_space_and_map_ok(inquire_window_t *, win_req_t *);
1817c478bd9Sstevel@tonic-gate static int cs_valid_window_speed(inquire_window_t *, uint32_t);
1827c478bd9Sstevel@tonic-gate static window_handle_t cs_create_window_handle(uint32_t);
1837c478bd9Sstevel@tonic-gate static cs_window_t *cs_find_window(window_handle_t);
1847c478bd9Sstevel@tonic-gate static int cs_find_io_win(uint32_t, iowin_char_t *, uint32_t *, uint32_t *);
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate /*
1877c478bd9Sstevel@tonic-gate  * IO, IRQ and configuration handling functions
1887c478bd9Sstevel@tonic-gate  */
1897c478bd9Sstevel@tonic-gate static int cs_request_io(client_handle_t, io_req_t *);
1907c478bd9Sstevel@tonic-gate static int cs_release_io(client_handle_t, io_req_t *);
1917c478bd9Sstevel@tonic-gate static int cs_allocate_io_win(uint32_t, uint32_t, uint32_t *);
1927c478bd9Sstevel@tonic-gate static int cs_setup_io_win(uint32_t, uint32_t, baseaddru_t *,
1937c478bd9Sstevel@tonic-gate 					uint32_t *, uint32_t, uint32_t);
1947c478bd9Sstevel@tonic-gate static int cs_request_irq(client_handle_t, irq_req_t *);
1957c478bd9Sstevel@tonic-gate static int cs_release_irq(client_handle_t, irq_req_t *);
1967c478bd9Sstevel@tonic-gate static int cs_request_configuration(client_handle_t, config_req_t *);
1977c478bd9Sstevel@tonic-gate static int cs_release_configuration(client_handle_t, release_config_t *);
1987c478bd9Sstevel@tonic-gate static int cs_modify_configuration(client_handle_t, modify_config_t *);
1997c478bd9Sstevel@tonic-gate static int cs_access_configuration_register(client_handle_t,
2007c478bd9Sstevel@tonic-gate 						access_config_reg_t *);
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate /*
2037c478bd9Sstevel@tonic-gate  * RESET and general info functions
2047c478bd9Sstevel@tonic-gate  */
2057c478bd9Sstevel@tonic-gate static int cs_reset_function(client_handle_t, reset_function_t *);
2067c478bd9Sstevel@tonic-gate static int cs_get_configuration_info(client_handle_t *,
2077c478bd9Sstevel@tonic-gate 						get_configuration_info_t *);
2087c478bd9Sstevel@tonic-gate static int cs_get_cardservices_info(client_handle_t,
2097c478bd9Sstevel@tonic-gate 						get_cardservices_info_t *);
2107c478bd9Sstevel@tonic-gate static int cs_get_physical_adapter_info(client_handle_t,
2117c478bd9Sstevel@tonic-gate 						get_physical_adapter_info_t *);
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate /*
2147c478bd9Sstevel@tonic-gate  * general functions
2157c478bd9Sstevel@tonic-gate  */
2167c478bd9Sstevel@tonic-gate static uint32_t cs_get_socket(client_handle_t, uint32_t *, uint32_t *,
2177c478bd9Sstevel@tonic-gate 					cs_socket_t **, client_t **);
2187c478bd9Sstevel@tonic-gate static int cs_convert_speed(convert_speed_t *);
2197c478bd9Sstevel@tonic-gate static int cs_convert_size(convert_size_t *);
2207c478bd9Sstevel@tonic-gate static char *cs_error2text(int, int);
2217c478bd9Sstevel@tonic-gate static int cs_map_log_socket(client_handle_t, map_log_socket_t *);
2227c478bd9Sstevel@tonic-gate static int cs_convert_powerlevel(uint32_t, uint32_t, uint32_t, unsigned *);
2237c478bd9Sstevel@tonic-gate static int cs_make_device_node(client_handle_t, make_device_node_t *);
2247c478bd9Sstevel@tonic-gate static int cs_remove_device_node(client_handle_t, remove_device_node_t *);
2257c478bd9Sstevel@tonic-gate static int cs_ddi_info(cs_ddi_info_t *);
2267c478bd9Sstevel@tonic-gate static int cs_init_cis_window(cs_socket_t *, uint32_t *, acc_handle_t *,
2277c478bd9Sstevel@tonic-gate 				uint32_t);
2287c478bd9Sstevel@tonic-gate static int cs_sys_ctl(cs_sys_ctl_t *);
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate /*
2317c478bd9Sstevel@tonic-gate  * global variables
2327c478bd9Sstevel@tonic-gate  */
2337c478bd9Sstevel@tonic-gate static int cs_max_client_handles = CS_MAX_CLIENTS;
2347c478bd9Sstevel@tonic-gate static client_t cs_socket_services_client;	/* global SS client */
2357c478bd9Sstevel@tonic-gate static client_types_t client_types[MAX_CLIENT_TYPES];
2367c478bd9Sstevel@tonic-gate static cs_globals_t cs_globals;
2377c478bd9Sstevel@tonic-gate int cs_reset_timeout_time = RESET_TIMEOUT_TIME;
2387c478bd9Sstevel@tonic-gate int cs_rc1_delay = CS_RC1_DELAY;
2397c478bd9Sstevel@tonic-gate int cs_rc2_delay = CS_RC2_DELAY;
2407c478bd9Sstevel@tonic-gate int cs_rq_delay = CS_RQ_DELAY;
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
2437c478bd9Sstevel@tonic-gate int	cs_debug = 0;
2447c478bd9Sstevel@tonic-gate #endif
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate /*
2477c478bd9Sstevel@tonic-gate  * cs_init - Initialize CS internal structures, databases, and state,
2487c478bd9Sstevel@tonic-gate  *		and register with SS
2497c478bd9Sstevel@tonic-gate  *
2507c478bd9Sstevel@tonic-gate  * XXX - Need to make sure that if we fail at any point that we free
2517c478bd9Sstevel@tonic-gate  *		any resources that we allocated, as well as kill any
2527c478bd9Sstevel@tonic-gate  *		threads that may have been started.
2537c478bd9Sstevel@tonic-gate  */
2547c478bd9Sstevel@tonic-gate int
cs_init()2557c478bd9Sstevel@tonic-gate cs_init()
2567c478bd9Sstevel@tonic-gate {
2577c478bd9Sstevel@tonic-gate 	client_types_t *ct;
2587c478bd9Sstevel@tonic-gate 	client_t *client;
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	/*
2617c478bd9Sstevel@tonic-gate 	 * Initialize the CS global structure
2627c478bd9Sstevel@tonic-gate 	 */
2637c478bd9Sstevel@tonic-gate 	bzero((caddr_t)&cs_globals, sizeof (cs_globals_t));
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	mutex_init(&cs_globals.global_lock, NULL, MUTEX_DRIVER, NULL);
2667c478bd9Sstevel@tonic-gate 	mutex_init(&cs_globals.window_lock, NULL, MUTEX_DRIVER, NULL);
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	cs_globals.init_state = GLOBAL_INIT_STATE_MUTEX;
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	/*
2717c478bd9Sstevel@tonic-gate 	 * Set up the global Socket Services client, since we're going to
2727c478bd9Sstevel@tonic-gate 	 *	need it once we register with SS.
2737c478bd9Sstevel@tonic-gate 	 */
2747c478bd9Sstevel@tonic-gate 	client = &cs_socket_services_client;
2757c478bd9Sstevel@tonic-gate 	bzero((caddr_t)client, sizeof (client_t));
2767c478bd9Sstevel@tonic-gate 	client->client_handle = CS_SS_CLIENT_HANDLE;
2777c478bd9Sstevel@tonic-gate 	client->flags |= (INFO_SOCKET_SERVICES | CLIENT_CARD_INSERTED);
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	/*
2807c478bd9Sstevel@tonic-gate 	 * Setup the client type structure - this is used in the socket event
2817c478bd9Sstevel@tonic-gate 	 *	thread to sequence the delivery of events to all clients on
2827c478bd9Sstevel@tonic-gate 	 *	the socket.
2837c478bd9Sstevel@tonic-gate 	 */
2847c478bd9Sstevel@tonic-gate 	ct = &client_types[0];
2857c478bd9Sstevel@tonic-gate 	ct->type = INFO_IO_CLIENT;
2867c478bd9Sstevel@tonic-gate 	ct->order = CLIENT_EVENTS_LIFO;
2877c478bd9Sstevel@tonic-gate 	ct->next = &client_types[1];
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	ct = ct->next;
2907c478bd9Sstevel@tonic-gate 	ct->type = INFO_MTD_CLIENT;
2917c478bd9Sstevel@tonic-gate 	ct->order = CLIENT_EVENTS_FIFO;
2927c478bd9Sstevel@tonic-gate 	ct->next = &client_types[2];
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	ct = ct->next;
2957c478bd9Sstevel@tonic-gate 	ct->type = INFO_MEM_CLIENT;
2967c478bd9Sstevel@tonic-gate 	ct->order = CLIENT_EVENTS_FIFO;
2977c478bd9Sstevel@tonic-gate 	ct->next = NULL;
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
3007c478bd9Sstevel@tonic-gate }
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate /*
3037c478bd9Sstevel@tonic-gate  * cs_deinit - Deinitialize CS
3047c478bd9Sstevel@tonic-gate  *
3057c478bd9Sstevel@tonic-gate  * This function cleans up any allocated resources, stops any running threads,
3067c478bd9Sstevel@tonic-gate  *	destroys any mutexes and condition variables, and finally frees up the
3077c478bd9Sstevel@tonic-gate  *	global socket and window structure arrays.
3087c478bd9Sstevel@tonic-gate  */
3097c478bd9Sstevel@tonic-gate int
cs_deinit()3107c478bd9Sstevel@tonic-gate cs_deinit()
3117c478bd9Sstevel@tonic-gate {
3127c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
3137c478bd9Sstevel@tonic-gate 	int sn, have_clients = 0, have_sockets = 0;
3147c478bd9Sstevel@tonic-gate 	cs_register_cardservices_t rcs;
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate #if defined(CS_DEBUG)
3177c478bd9Sstevel@tonic-gate 	if (cs_debug > 1)
3187c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "CS: cs_deinit\n");
3197c478bd9Sstevel@tonic-gate #endif
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	/*
3227c478bd9Sstevel@tonic-gate 	 * Deregister with the Card Services kernel stubs module
3237c478bd9Sstevel@tonic-gate 	 */
3247c478bd9Sstevel@tonic-gate 	rcs.magic = CS_STUBS_MAGIC;
3257c478bd9Sstevel@tonic-gate 	rcs.function = CS_ENTRY_DEREGISTER;
3267c478bd9Sstevel@tonic-gate 	(void) csx_register_cardservices(&rcs);
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	/*
3297c478bd9Sstevel@tonic-gate 	 * Set the GLOBAL_INIT_STATE_NO_CLIENTS flag to prevent new clients
3307c478bd9Sstevel@tonic-gate 	 *	from registering.
3317c478bd9Sstevel@tonic-gate 	 */
3327c478bd9Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
3337c478bd9Sstevel@tonic-gate 	cs_globals.init_state |= GLOBAL_INIT_STATE_NO_CLIENTS;
3347c478bd9Sstevel@tonic-gate 	mutex_exit(&cs_globals.global_lock);
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	/*
3377c478bd9Sstevel@tonic-gate 	 * Go through each socket and make sure that there are no clients
3387c478bd9Sstevel@tonic-gate 	 *	on any of the sockets.  If there are, we can't deinit until
3397c478bd9Sstevel@tonic-gate 	 *	all the clients for every socket are gone.
3407c478bd9Sstevel@tonic-gate 	 */
3417c478bd9Sstevel@tonic-gate 	for (sn = 0; sn < cs_globals.max_socket_num; sn++) {
3427c478bd9Sstevel@tonic-gate 	    if ((sp = cs_get_sp(sn)) != NULL) {
3437c478bd9Sstevel@tonic-gate 		have_sockets++;
3447c478bd9Sstevel@tonic-gate 		if (sp->client_list) {
3457c478bd9Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_deinit: cannot unload module since "
3467c478bd9Sstevel@tonic-gate 				"socket %d has registered clients\n", sn);
3477c478bd9Sstevel@tonic-gate 		    have_clients++;
3487c478bd9Sstevel@tonic-gate 		}
3497c478bd9Sstevel@tonic-gate 	    }
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	/*
3537c478bd9Sstevel@tonic-gate 	 * We don't allow unload if there are any clients registered
3547c478bd9Sstevel@tonic-gate 	 *	or if there are still sockets that are active.
3557c478bd9Sstevel@tonic-gate 	 */
3567c478bd9Sstevel@tonic-gate 	if ((have_clients > 0) || (have_sockets > 0))
3577c478bd9Sstevel@tonic-gate 	    return (BAD_FUNCTION);
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate #ifdef	XXX
3607c478bd9Sstevel@tonic-gate 	/*
3617c478bd9Sstevel@tonic-gate 	 * If one or more sockets have been added, we need to deallocate
3627c478bd9Sstevel@tonic-gate 	 *	the resources associated with those sockets.
3637c478bd9Sstevel@tonic-gate 	 */
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	/*
3667c478bd9Sstevel@tonic-gate 	 * First, tell Socket Services that we're leaving, so that we
3677c478bd9Sstevel@tonic-gate 	 *	don't get any more event callbacks.
3687c478bd9Sstevel@tonic-gate 	 */
3697c478bd9Sstevel@tonic-gate 	SocketServices(CSUnregister);
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	/*
3727c478bd9Sstevel@tonic-gate 	 * Wait for the soft int timer to tell us it's done
3737c478bd9Sstevel@tonic-gate 	 */
3747c478bd9Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
3757c478bd9Sstevel@tonic-gate 	cs_globals.init_state |= GLOBAL_INIT_STATE_UNLOADING;
3767c478bd9Sstevel@tonic-gate 	mutex_exit(&cs_globals.global_lock);
3777c478bd9Sstevel@tonic-gate 	UNTIMEOUT(cs_globals.sotfint_tmo);
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	/*
3807c478bd9Sstevel@tonic-gate 	 * Remove the soft interrupt handler.
3817c478bd9Sstevel@tonic-gate 	 */
3827c478bd9Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
3837c478bd9Sstevel@tonic-gate 	if (cs_globals.init_state & GLOBAL_INIT_STATE_SOFTINTR) {
3847c478bd9Sstevel@tonic-gate 	    ddi_remove_softintr(cs_globals.softint_id);
3857c478bd9Sstevel@tonic-gate 	    cs_globals.init_state &= ~GLOBAL_INIT_STATE_SOFTINTR;
3867c478bd9Sstevel@tonic-gate 	}
3877c478bd9Sstevel@tonic-gate 	mutex_exit(&cs_globals.global_lock);
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	/*
3927c478bd9Sstevel@tonic-gate 	 * Go through each socket and free any resource allocated to that
3937c478bd9Sstevel@tonic-gate 	 *	socket, as well as any mutexs and condition variables.
3947c478bd9Sstevel@tonic-gate 	 */
3957c478bd9Sstevel@tonic-gate 	for (sn = 0; sn < cs_globals.max_socket_num; sn++) {
3967c478bd9Sstevel@tonic-gate 	    set_socket_t set_socket;
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	    if ((sp = cs_get_sp(sn)) != NULL) {
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 		/*
4017c478bd9Sstevel@tonic-gate 		 * untimeout possible pending ready/busy timer
4027c478bd9Sstevel@tonic-gate 		 */
4037c478bd9Sstevel@tonic-gate 		UNTIMEOUT(sp->rdybsy_tmo_id);
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4067c478bd9Sstevel@tonic-gate 		    mutex_enter(&sp->lock);
4077c478bd9Sstevel@tonic-gate 		sp->flags = SOCKET_UNLOAD_MODULE;
4087c478bd9Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_SOFTINTR)
4097c478bd9Sstevel@tonic-gate 		    sp->init_state &= ~SOCKET_INIT_STATE_SOFTINTR;
4107c478bd9Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4117c478bd9Sstevel@tonic-gate 		    mutex_exit(&sp->lock);
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4147c478bd9Sstevel@tonic-gate 		    mutex_enter(&sp->cis_lock);
4157c478bd9Sstevel@tonic-gate 		(void) cs_destroy_cis(sp);
4167c478bd9Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4177c478bd9Sstevel@tonic-gate 		    mutex_exit(&sp->cis_lock);
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 		/*
4207c478bd9Sstevel@tonic-gate 		 * Tell the event handler thread that we want it to exit, then
4217c478bd9Sstevel@tonic-gate 		 *	wait around until it tells us that it has exited.
4227c478bd9Sstevel@tonic-gate 		 */
4237c478bd9Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4247c478bd9Sstevel@tonic-gate 		    mutex_enter(&sp->client_lock);
4257c478bd9Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_THREAD) {
4267c478bd9Sstevel@tonic-gate 		    sp->thread_state = SOCKET_THREAD_EXIT;
4277c478bd9Sstevel@tonic-gate 		    cv_broadcast(&sp->thread_cv);
4287c478bd9Sstevel@tonic-gate 		    cv_wait(&sp->caller_cv, &sp->client_lock);
4297c478bd9Sstevel@tonic-gate 		}
4307c478bd9Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4317c478bd9Sstevel@tonic-gate 		    mutex_exit(&sp->client_lock);
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 		/*
4347c478bd9Sstevel@tonic-gate 		 * Tell the SS work thread that we want it to exit, then
4357c478bd9Sstevel@tonic-gate 		 *	wait around until it tells us that it has exited.
4367c478bd9Sstevel@tonic-gate 		 */
4377c478bd9Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4387c478bd9Sstevel@tonic-gate 		    mutex_enter(&sp->ss_thread_lock);
4397c478bd9Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_SS_THREAD) {
4407c478bd9Sstevel@tonic-gate 		    sp->ss_thread_state = SOCKET_THREAD_EXIT;
4417c478bd9Sstevel@tonic-gate 		    cv_broadcast(&sp->ss_thread_cv);
4427c478bd9Sstevel@tonic-gate 		    cv_wait(&sp->ss_caller_cv, &sp->ss_thread_lock);
4437c478bd9Sstevel@tonic-gate 		}
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4467c478bd9Sstevel@tonic-gate 		    mutex_exit(&sp->ss_thread_lock);
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 		/*
4497c478bd9Sstevel@tonic-gate 		 * Free the mutexii and condition variables that we used.
4507c478bd9Sstevel@tonic-gate 		 */
4517c478bd9Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX) {
4527c478bd9Sstevel@tonic-gate 		    mutex_destroy(&sp->lock);
4537c478bd9Sstevel@tonic-gate 		    mutex_destroy(&sp->client_lock);
4547c478bd9Sstevel@tonic-gate 		    mutex_destroy(&sp->cis_lock);
4557c478bd9Sstevel@tonic-gate 		    mutex_destroy(&sp->ss_thread_lock);
4567c478bd9Sstevel@tonic-gate 		}
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_CV) {
4597c478bd9Sstevel@tonic-gate 		    cv_destroy(&sp->thread_cv);
4607c478bd9Sstevel@tonic-gate 		    cv_destroy(&sp->caller_cv);
4617c478bd9Sstevel@tonic-gate 		    cv_destroy(&sp->reset_cv);
4627c478bd9Sstevel@tonic-gate 		    cv_destroy(&sp->ss_thread_cv);
4637c478bd9Sstevel@tonic-gate 		    cv_destroy(&sp->ss_caller_cv);
4647c478bd9Sstevel@tonic-gate 		}
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate #ifdef	USE_IOMMAP_WINDOW
4677c478bd9Sstevel@tonic-gate 		/*
4687c478bd9Sstevel@tonic-gate 		 * Free the memory-mapped IO structure if we allocated one.
4697c478bd9Sstevel@tonic-gate 		 */
4707c478bd9Sstevel@tonic-gate 		if (sp->io_mmap_window)
4717c478bd9Sstevel@tonic-gate 		    kmem_free(sp->io_mmap_window, sizeof (io_mmap_window_t));
4727c478bd9Sstevel@tonic-gate #endif	/* USE_IOMMAP_WINDOW */
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 		/*
4757c478bd9Sstevel@tonic-gate 		 * Return the socket to memory-only mode and turn off the
4767c478bd9Sstevel@tonic-gate 		 *	socket power.
4777c478bd9Sstevel@tonic-gate 		 */
4787c478bd9Sstevel@tonic-gate 		sp->event_mask = 0;
4797c478bd9Sstevel@tonic-gate 		set_socket.socket = sp->socket_num;
4807c478bd9Sstevel@tonic-gate 		set_socket.SCIntMask = 0;
4817c478bd9Sstevel@tonic-gate 		set_socket.IREQRouting = 0;
4827c478bd9Sstevel@tonic-gate 		set_socket.IFType = IF_MEMORY;
4837c478bd9Sstevel@tonic-gate 		set_socket.CtlInd = 0; /* turn off controls and indicators */
4847c478bd9Sstevel@tonic-gate 		set_socket.State = (unsigned)~0; /* clear latched state bits */
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 		(void) cs_convert_powerlevel(sp->socket_num, 0, VCC,
4877c478bd9Sstevel@tonic-gate 						&set_socket.VccLevel);
4887c478bd9Sstevel@tonic-gate 		(void) cs_convert_powerlevel(sp->socket_num, 0, VPP1,
4897c478bd9Sstevel@tonic-gate 						&set_socket.Vpp1Level);
4907c478bd9Sstevel@tonic-gate 		(void) cs_convert_powerlevel(sp->socket_num, 0, VPP2,
4917c478bd9Sstevel@tonic-gate 						&set_socket.Vpp2Level);
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 		/*
4947c478bd9Sstevel@tonic-gate 		 * If we fail this call, there's not much we can do, so
4957c478bd9Sstevel@tonic-gate 		 *	just continue with the resource deallocation.
4967c478bd9Sstevel@tonic-gate 		 */
4977c478bd9Sstevel@tonic-gate 		if ((ret =
4987c478bd9Sstevel@tonic-gate 			SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
4997c478bd9Sstevel@tonic-gate 		    cmn_err(CE_CONT,
5007c478bd9Sstevel@tonic-gate 			"cs_deinit: socket %d SS_SetSocket failure %d\n",
5017c478bd9Sstevel@tonic-gate 							sp->socket_num, ret);
5027c478bd9Sstevel@tonic-gate 		}
5037c478bd9Sstevel@tonic-gate 	    } /* cs_get_sp */
5047c478bd9Sstevel@tonic-gate 	} /* for (sn) */
5057c478bd9Sstevel@tonic-gate #endif	/* XXX */
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	/*
5087c478bd9Sstevel@tonic-gate 	 * Destroy the global mutexii.
5097c478bd9Sstevel@tonic-gate 	 */
5107c478bd9Sstevel@tonic-gate 	mutex_destroy(&cs_globals.global_lock);
5117c478bd9Sstevel@tonic-gate 	mutex_destroy(&cs_globals.window_lock);
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate #ifdef	XXX
5147c478bd9Sstevel@tonic-gate 	/*
5157c478bd9Sstevel@tonic-gate 	 * Free the global "super-client" structure
5167c478bd9Sstevel@tonic-gate 	 */
5177c478bd9Sstevel@tonic-gate 	if (cs_globals.sclient_list)
5187c478bd9Sstevel@tonic-gate 	    kmem_free(cs_globals.sclient_list,
5197c478bd9Sstevel@tonic-gate 		(cs_globals.num_sockets * sizeof (struct sclient_list_t)));
5207c478bd9Sstevel@tonic-gate 	cs_globals.sclient_list = NULL;
5217c478bd9Sstevel@tonic-gate #endif	/* XXX */
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
5247c478bd9Sstevel@tonic-gate }
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate /*
5277c478bd9Sstevel@tonic-gate  * ==== drip, drip, drip - the Card Services waterfall :-) ====
5287c478bd9Sstevel@tonic-gate  */
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate /*
5317c478bd9Sstevel@tonic-gate  * CardServices - general Card Services entry point for CS clients
5327c478bd9Sstevel@tonic-gate  *			and Socket Services; the address of this
5337c478bd9Sstevel@tonic-gate  *			function is handed to SS via the CSRegister
5347c478bd9Sstevel@tonic-gate  *			SS call
5357c478bd9Sstevel@tonic-gate  */
5367c478bd9Sstevel@tonic-gate int
CardServices(int function,...)5377c478bd9Sstevel@tonic-gate CardServices(int function, ...)
5387c478bd9Sstevel@tonic-gate {
5397c478bd9Sstevel@tonic-gate 	va_list arglist;
5407c478bd9Sstevel@tonic-gate 	int retcode = CS_UNSUPPORTED_FUNCTION;
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	cs_socket_t	*socp;
5437c478bd9Sstevel@tonic-gate 	uint32_t	*offp;
5447c478bd9Sstevel@tonic-gate 	acc_handle_t	*hp;
5457c478bd9Sstevel@tonic-gate 	client_handle_t	ch;
5467c478bd9Sstevel@tonic-gate 	client_handle_t	*chp;
5477c478bd9Sstevel@tonic-gate 	window_handle_t	wh;
5487c478bd9Sstevel@tonic-gate 	window_handle_t	*whp;
5497c478bd9Sstevel@tonic-gate 	tuple_t		*tuple;
5507c478bd9Sstevel@tonic-gate 	cisparse_t	*cisparse;
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
5537c478bd9Sstevel@tonic-gate 	if (cs_debug > 127) {
5547c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "CardServices: called for function %s (0x%x)\n",
5557c478bd9Sstevel@tonic-gate 				cs_error2text(function, CSFUN2TEXT_FUNCTION),
5567c478bd9Sstevel@tonic-gate 				function);
5577c478bd9Sstevel@tonic-gate 	}
5587c478bd9Sstevel@tonic-gate #endif
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	va_start(arglist, function);
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	/*
5637c478bd9Sstevel@tonic-gate 	 * Here's the Card Services waterfall
5647c478bd9Sstevel@tonic-gate 	 */
5657c478bd9Sstevel@tonic-gate 	switch (function) {
5667c478bd9Sstevel@tonic-gate 	/*
5677c478bd9Sstevel@tonic-gate 	 * We got here as a result of the CIS module calling us
5687c478bd9Sstevel@tonic-gate 	 *	in response to cs_ss_init() calling the CIS module
5697c478bd9Sstevel@tonic-gate 	 *	at CIS_PARSER(CISP_CIS_SETUP, ...)
5707c478bd9Sstevel@tonic-gate 	 */
5717c478bd9Sstevel@tonic-gate 	    case CISRegister: {
5727c478bd9Sstevel@tonic-gate 		cisregister_t *cisr;
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 		    cisr = va_arg(arglist, cisregister_t *);
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 		    if (cisr->cis_magic != PCCS_MAGIC ||
5777c478bd9Sstevel@tonic-gate 			cisr->cis_version != PCCS_VERSION) {
5787c478bd9Sstevel@tonic-gate 			    cmn_err(CE_WARN,
5797c478bd9Sstevel@tonic-gate 				"CS: CISRegister (%lx, %lx, %lx, %lx) *ERROR*",
5807c478bd9Sstevel@tonic-gate 					(long)cisr->cis_magic,
5817c478bd9Sstevel@tonic-gate 					(long)cisr->cis_version,
5827c478bd9Sstevel@tonic-gate 					(long)cisr->cis_parser,
5837c478bd9Sstevel@tonic-gate 					(long)cisr->cistpl_std_callout);
5847c478bd9Sstevel@tonic-gate 			retcode = CS_BAD_ARGS;
5857c478bd9Sstevel@tonic-gate 		    } else {
5867c478bd9Sstevel@tonic-gate 			/*
5877c478bd9Sstevel@tonic-gate 			 * Replace the CIS Parser entry point if
5887c478bd9Sstevel@tonic-gate 			 *	necessary.
5897c478bd9Sstevel@tonic-gate 			 */
5907c478bd9Sstevel@tonic-gate 			if (cisr->cis_parser != NULL)
5917c478bd9Sstevel@tonic-gate 			    cis_parser = cisr->cis_parser;
5927c478bd9Sstevel@tonic-gate 			cis_cistpl_std_callout = cisr->cistpl_std_callout;
5937c478bd9Sstevel@tonic-gate 			retcode = CS_SUCCESS;
5947c478bd9Sstevel@tonic-gate 		    }
5957c478bd9Sstevel@tonic-gate 		}
5967c478bd9Sstevel@tonic-gate 		break;
5977c478bd9Sstevel@tonic-gate 	    case CISUnregister:	/* XXX - should we do some more checking */
5987c478bd9Sstevel@tonic-gate 		/* XXX - need to protect this by a mutex */
5997c478bd9Sstevel@tonic-gate 		cis_parser = NULL;
6007c478bd9Sstevel@tonic-gate 		cis_cistpl_std_callout = NULL;
6017c478bd9Sstevel@tonic-gate 		retcode = CS_SUCCESS;
6027c478bd9Sstevel@tonic-gate 		break;
6037c478bd9Sstevel@tonic-gate 	    case InitCISWindow:
6047c478bd9Sstevel@tonic-gate 		socp	= va_arg(arglist, cs_socket_t *);
6057c478bd9Sstevel@tonic-gate 		offp	= va_arg(arglist, uint32_t *);
6067c478bd9Sstevel@tonic-gate 		hp	= va_arg(arglist, acc_handle_t *);
6077c478bd9Sstevel@tonic-gate 		retcode = cs_init_cis_window(socp, offp, hp,
6087c478bd9Sstevel@tonic-gate 				va_arg(arglist, uint32_t));
6097c478bd9Sstevel@tonic-gate 		break;
6107c478bd9Sstevel@tonic-gate 	    case RegisterClient:
6117c478bd9Sstevel@tonic-gate 		chp = va_arg(arglist, client_handle_t *),
6127c478bd9Sstevel@tonic-gate 		retcode = cs_register_client(chp,
6137c478bd9Sstevel@tonic-gate 				va_arg(arglist, client_reg_t *));
6147c478bd9Sstevel@tonic-gate 		break;
6157c478bd9Sstevel@tonic-gate 	    case DeregisterClient:
6167c478bd9Sstevel@tonic-gate 		retcode = cs_deregister_client(
6177c478bd9Sstevel@tonic-gate 				va_arg(arglist, client_handle_t));
6187c478bd9Sstevel@tonic-gate 		break;
6197c478bd9Sstevel@tonic-gate 	    case GetStatus:
6207c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6217c478bd9Sstevel@tonic-gate 		retcode = cs_get_status(ch,
6227c478bd9Sstevel@tonic-gate 				va_arg(arglist, get_status_t *));
6237c478bd9Sstevel@tonic-gate 		break;
6247c478bd9Sstevel@tonic-gate 	    case ResetFunction:
6257c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6267c478bd9Sstevel@tonic-gate 		retcode = cs_reset_function(ch,
6277c478bd9Sstevel@tonic-gate 				va_arg(arglist, reset_function_t *));
6287c478bd9Sstevel@tonic-gate 		break;
6297c478bd9Sstevel@tonic-gate 	    case SetEventMask:
6307c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6317c478bd9Sstevel@tonic-gate 		retcode = cs_set_event_mask(ch,
6327c478bd9Sstevel@tonic-gate 				va_arg(arglist, sockevent_t *));
6337c478bd9Sstevel@tonic-gate 		break;
6347c478bd9Sstevel@tonic-gate 	    case GetEventMask:
6357c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6367c478bd9Sstevel@tonic-gate 		retcode = cs_get_event_mask(ch,
6377c478bd9Sstevel@tonic-gate 				va_arg(arglist, sockevent_t *));
6387c478bd9Sstevel@tonic-gate 		break;
6397c478bd9Sstevel@tonic-gate 	    case RequestIO:
6407c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6417c478bd9Sstevel@tonic-gate 		retcode = cs_request_io(ch,
6427c478bd9Sstevel@tonic-gate 				va_arg(arglist, io_req_t *));
6437c478bd9Sstevel@tonic-gate 		break;
6447c478bd9Sstevel@tonic-gate 	    case ReleaseIO:
6457c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6467c478bd9Sstevel@tonic-gate 		retcode = cs_release_io(ch,
6477c478bd9Sstevel@tonic-gate 				va_arg(arglist, io_req_t *));
6487c478bd9Sstevel@tonic-gate 		break;
6497c478bd9Sstevel@tonic-gate 	    case RequestIRQ:
6507c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6517c478bd9Sstevel@tonic-gate 		retcode = cs_request_irq(ch,
6527c478bd9Sstevel@tonic-gate 				va_arg(arglist, irq_req_t *));
6537c478bd9Sstevel@tonic-gate 		break;
6547c478bd9Sstevel@tonic-gate 	    case ReleaseIRQ:
6557c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6567c478bd9Sstevel@tonic-gate 		retcode = cs_release_irq(ch,
6577c478bd9Sstevel@tonic-gate 				va_arg(arglist, irq_req_t *));
6587c478bd9Sstevel@tonic-gate 		break;
6597c478bd9Sstevel@tonic-gate 	    case RequestWindow:
6607c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6617c478bd9Sstevel@tonic-gate 		whp = va_arg(arglist, window_handle_t *);
6627c478bd9Sstevel@tonic-gate 		retcode = cs_request_window(ch, whp,
6637c478bd9Sstevel@tonic-gate 				va_arg(arglist, win_req_t *));
6647c478bd9Sstevel@tonic-gate 		break;
6657c478bd9Sstevel@tonic-gate 	    case ReleaseWindow:
6667c478bd9Sstevel@tonic-gate 		retcode = cs_release_window(
6677c478bd9Sstevel@tonic-gate 				va_arg(arglist, window_handle_t));
6687c478bd9Sstevel@tonic-gate 		break;
6697c478bd9Sstevel@tonic-gate 	    case ModifyWindow:
6707c478bd9Sstevel@tonic-gate 		wh = va_arg(arglist, window_handle_t);
6717c478bd9Sstevel@tonic-gate 		retcode = cs_modify_window(wh,
6727c478bd9Sstevel@tonic-gate 				va_arg(arglist, modify_win_t *));
6737c478bd9Sstevel@tonic-gate 		break;
6747c478bd9Sstevel@tonic-gate 	    case MapMemPage:
6757c478bd9Sstevel@tonic-gate 		wh = va_arg(arglist, window_handle_t);
6767c478bd9Sstevel@tonic-gate 		retcode = cs_map_mem_page(wh,
6777c478bd9Sstevel@tonic-gate 				va_arg(arglist, map_mem_page_t *));
6787c478bd9Sstevel@tonic-gate 		break;
6797c478bd9Sstevel@tonic-gate 	    case RequestSocketMask:
6807c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6817c478bd9Sstevel@tonic-gate 		retcode = cs_request_socket_mask(ch,
6827c478bd9Sstevel@tonic-gate 				va_arg(arglist, request_socket_mask_t *));
6837c478bd9Sstevel@tonic-gate 		break;
6847c478bd9Sstevel@tonic-gate 	    case ReleaseSocketMask:
6857c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6867c478bd9Sstevel@tonic-gate 		retcode = cs_release_socket_mask(ch,
6877c478bd9Sstevel@tonic-gate 				va_arg(arglist, release_socket_mask_t *));
6887c478bd9Sstevel@tonic-gate 		break;
6897c478bd9Sstevel@tonic-gate 	    case RequestConfiguration:
6907c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6917c478bd9Sstevel@tonic-gate 		retcode = cs_request_configuration(ch,
6927c478bd9Sstevel@tonic-gate 				va_arg(arglist, config_req_t *));
6937c478bd9Sstevel@tonic-gate 		break;
6947c478bd9Sstevel@tonic-gate 	    case GetPhysicalAdapterInfo:
6957c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6967c478bd9Sstevel@tonic-gate 		retcode = cs_get_physical_adapter_info(ch,
6977c478bd9Sstevel@tonic-gate 				va_arg(arglist, get_physical_adapter_info_t *));
6987c478bd9Sstevel@tonic-gate 		break;
6997c478bd9Sstevel@tonic-gate 	    case GetCardServicesInfo:
7007c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
7017c478bd9Sstevel@tonic-gate 		retcode = cs_get_cardservices_info(ch,
7027c478bd9Sstevel@tonic-gate 				va_arg(arglist, get_cardservices_info_t *));
7037c478bd9Sstevel@tonic-gate 		break;
7047c478bd9Sstevel@tonic-gate 	    case GetConfigurationInfo:
7057c478bd9Sstevel@tonic-gate 		chp = va_arg(arglist, client_handle_t *);
7067c478bd9Sstevel@tonic-gate 		retcode = cs_get_configuration_info(chp,
7077c478bd9Sstevel@tonic-gate 				va_arg(arglist, get_configuration_info_t *));
7087c478bd9Sstevel@tonic-gate 		break;
7097c478bd9Sstevel@tonic-gate 	    case ModifyConfiguration:
7107c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
7117c478bd9Sstevel@tonic-gate 		retcode = cs_modify_configuration(ch,
7127c478bd9Sstevel@tonic-gate 				va_arg(arglist, modify_config_t *));
7137c478bd9Sstevel@tonic-gate 		break;
7147c478bd9Sstevel@tonic-gate 	    case AccessConfigurationRegister:
7157c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
7167c478bd9Sstevel@tonic-gate 		retcode = cs_access_configuration_register(ch,
7177c478bd9Sstevel@tonic-gate 				va_arg(arglist, access_config_reg_t *));
7187c478bd9Sstevel@tonic-gate 		break;
7197c478bd9Sstevel@tonic-gate 	    case ReleaseConfiguration:
7207c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
7217c478bd9Sstevel@tonic-gate 		retcode = cs_release_configuration(ch,
7227c478bd9Sstevel@tonic-gate 				va_arg(arglist, release_config_t *));
7237c478bd9Sstevel@tonic-gate 		break;
7247c478bd9Sstevel@tonic-gate 	    case OpenMemory:
7257c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: OpenMemory\n");
7267c478bd9Sstevel@tonic-gate 		break;
7277c478bd9Sstevel@tonic-gate 	    case ReadMemory:
7287c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: ReadMemory\n");
7297c478bd9Sstevel@tonic-gate 		break;
7307c478bd9Sstevel@tonic-gate 	    case WriteMemory:
7317c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: WriteMemory\n");
7327c478bd9Sstevel@tonic-gate 		break;
7337c478bd9Sstevel@tonic-gate 	    case CopyMemory:
7347c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: CopyMemory\n");
7357c478bd9Sstevel@tonic-gate 		break;
7367c478bd9Sstevel@tonic-gate 	    case RegisterEraseQueue:
7377c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: RegisterEraseQueue\n");
7387c478bd9Sstevel@tonic-gate 		break;
7397c478bd9Sstevel@tonic-gate 	    case CheckEraseQueue:
7407c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: CheckEraseQueue\n");
7417c478bd9Sstevel@tonic-gate 		break;
7427c478bd9Sstevel@tonic-gate 	    case DeregisterEraseQueue:
7437c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: DeregisterEraseQueue\n");
7447c478bd9Sstevel@tonic-gate 		break;
7457c478bd9Sstevel@tonic-gate 	    case CloseMemory:
7467c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: CloseMemory\n");
7477c478bd9Sstevel@tonic-gate 		break;
7487c478bd9Sstevel@tonic-gate 	    case GetFirstRegion:
7497c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: GetFirstRegion\n");
7507c478bd9Sstevel@tonic-gate 		break;
7517c478bd9Sstevel@tonic-gate 	    case GetNextRegion:
7527c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: GetNextRegion\n");
7537c478bd9Sstevel@tonic-gate 		break;
7547c478bd9Sstevel@tonic-gate 	    case GetFirstPartition:
7557c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: GetFirstPartition\n");
7567c478bd9Sstevel@tonic-gate 		break;
7577c478bd9Sstevel@tonic-gate 	    case GetNextPartition:
7587c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: GetNextPartition\n");
7597c478bd9Sstevel@tonic-gate 		break;
7607c478bd9Sstevel@tonic-gate 	    case ReturnSSEntry:
7617c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: ReturnSSEntry\n");
7627c478bd9Sstevel@tonic-gate 		break;
7637c478bd9Sstevel@tonic-gate 	    case MapLogSocket:
7647c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
7657c478bd9Sstevel@tonic-gate 		retcode = cs_map_log_socket(ch,
7667c478bd9Sstevel@tonic-gate 				va_arg(arglist, map_log_socket_t *));
7677c478bd9Sstevel@tonic-gate 		break;
7687c478bd9Sstevel@tonic-gate 	    case MapPhySocket:
7697c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: MapPhySocket\n");
7707c478bd9Sstevel@tonic-gate 		break;
7717c478bd9Sstevel@tonic-gate 	    case MapLogWindow:
7727c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: MapLogWindow\n");
7737c478bd9Sstevel@tonic-gate 		break;
7747c478bd9Sstevel@tonic-gate 	    case MapPhyWindow:
7757c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: MapPhyWindow\n");
7767c478bd9Sstevel@tonic-gate 		break;
7777c478bd9Sstevel@tonic-gate 	    case RegisterMTD:
7787c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: RegisterMTD\n");
7797c478bd9Sstevel@tonic-gate 		break;
7807c478bd9Sstevel@tonic-gate 	    case RegisterTimer:
7817c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: RegisterTimer\n");
7827c478bd9Sstevel@tonic-gate 		break;
7837c478bd9Sstevel@tonic-gate 	    case SetRegion:
7847c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: SetRegion\n");
7857c478bd9Sstevel@tonic-gate 		break;
7867c478bd9Sstevel@tonic-gate 	    case RequestExclusive:
7877c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: RequestExclusive\n");
7887c478bd9Sstevel@tonic-gate 		break;
7897c478bd9Sstevel@tonic-gate 	    case ReleaseExclusive:
7907c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: ReleaseExclusive\n");
7917c478bd9Sstevel@tonic-gate 		break;
7927c478bd9Sstevel@tonic-gate 	    case GetFirstClient:
7937c478bd9Sstevel@tonic-gate 		retcode = cs_get_firstnext_client(
7947c478bd9Sstevel@tonic-gate 				va_arg(arglist, get_firstnext_client_t *),
7957c478bd9Sstevel@tonic-gate 				CS_GET_FIRST_FLAG);
7967c478bd9Sstevel@tonic-gate 		break;
7977c478bd9Sstevel@tonic-gate 	    case GetNextClient:
7987c478bd9Sstevel@tonic-gate 		retcode = cs_get_firstnext_client(
7997c478bd9Sstevel@tonic-gate 				va_arg(arglist, get_firstnext_client_t *),
8007c478bd9Sstevel@tonic-gate 				CS_GET_NEXT_FLAG);
8017c478bd9Sstevel@tonic-gate 		break;
8027c478bd9Sstevel@tonic-gate 	    case GetClientInfo:
8037c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
8047c478bd9Sstevel@tonic-gate 		retcode = cs_get_client_info(ch,
8057c478bd9Sstevel@tonic-gate 				va_arg(arglist, client_info_t *));
8067c478bd9Sstevel@tonic-gate 		break;
8077c478bd9Sstevel@tonic-gate 	    case AddSocketServices:
8087c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: AddSocketServices\n");
8097c478bd9Sstevel@tonic-gate 		break;
8107c478bd9Sstevel@tonic-gate 	    case ReplaceSocketServices:
8117c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: ReplaceSocketServices\n");
8127c478bd9Sstevel@tonic-gate 		break;
8137c478bd9Sstevel@tonic-gate 	    case VendorSpecific:
8147c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: VendorSpecific\n");
8157c478bd9Sstevel@tonic-gate 		break;
8167c478bd9Sstevel@tonic-gate 	    case AdjustResourceInfo:
8177c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: AdjustResourceInfo\n");
8187c478bd9Sstevel@tonic-gate 		break;
8197c478bd9Sstevel@tonic-gate 	    case ValidateCIS:
8207c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
8217c478bd9Sstevel@tonic-gate 		retcode = cs_validate_cis(ch,
8227c478bd9Sstevel@tonic-gate 				va_arg(arglist, cisinfo_t *));
8237c478bd9Sstevel@tonic-gate 		break;
8247c478bd9Sstevel@tonic-gate 	    case GetFirstTuple:
8257c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
8267c478bd9Sstevel@tonic-gate 		retcode = cs_get_firstnext_tuple(ch,
8277c478bd9Sstevel@tonic-gate 				va_arg(arglist, tuple_t *),
8287c478bd9Sstevel@tonic-gate 				CS_GET_FIRST_FLAG);
8297c478bd9Sstevel@tonic-gate 		break;
8307c478bd9Sstevel@tonic-gate 	    case GetNextTuple:
8317c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
8327c478bd9Sstevel@tonic-gate 		retcode = cs_get_firstnext_tuple(ch,
8337c478bd9Sstevel@tonic-gate 				va_arg(arglist, tuple_t *),
8347c478bd9Sstevel@tonic-gate 				CS_GET_NEXT_FLAG);
8357c478bd9Sstevel@tonic-gate 		break;
8367c478bd9Sstevel@tonic-gate 	    case GetTupleData:
8377c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
8387c478bd9Sstevel@tonic-gate 		retcode = cs_get_tuple_data(ch,
8397c478bd9Sstevel@tonic-gate 				va_arg(arglist, tuple_t *));
8407c478bd9Sstevel@tonic-gate 		break;
8417c478bd9Sstevel@tonic-gate 	    case ParseTuple:
8427c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
8437c478bd9Sstevel@tonic-gate 		tuple = va_arg(arglist, tuple_t *);
8447c478bd9Sstevel@tonic-gate 		cisparse = va_arg(arglist, cisparse_t *);
8457c478bd9Sstevel@tonic-gate 		retcode = cs_parse_tuple(ch, tuple, cisparse,
8467c478bd9Sstevel@tonic-gate 				va_arg(arglist, uint_t));
8477c478bd9Sstevel@tonic-gate 		break;
8487c478bd9Sstevel@tonic-gate 	    case MakeDeviceNode:
8497c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
8507c478bd9Sstevel@tonic-gate 		retcode = cs_make_device_node(ch,
8517c478bd9Sstevel@tonic-gate 				va_arg(arglist, make_device_node_t *));
8527c478bd9Sstevel@tonic-gate 		break;
8537c478bd9Sstevel@tonic-gate 	    case RemoveDeviceNode:
8547c478bd9Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
8557c478bd9Sstevel@tonic-gate 		retcode = cs_remove_device_node(ch,
8567c478bd9Sstevel@tonic-gate 				va_arg(arglist, remove_device_node_t *));
8577c478bd9Sstevel@tonic-gate 		break;
8587c478bd9Sstevel@tonic-gate 	    case ConvertSpeed:
8597c478bd9Sstevel@tonic-gate 		retcode = cs_convert_speed(
8607c478bd9Sstevel@tonic-gate 				va_arg(arglist, convert_speed_t *));
8617c478bd9Sstevel@tonic-gate 		break;
8627c478bd9Sstevel@tonic-gate 	    case ConvertSize:
8637c478bd9Sstevel@tonic-gate 		retcode = cs_convert_size(
8647c478bd9Sstevel@tonic-gate 				va_arg(arglist, convert_size_t *));
8657c478bd9Sstevel@tonic-gate 		break;
8667c478bd9Sstevel@tonic-gate 	    case Event2Text:
8677c478bd9Sstevel@tonic-gate 		retcode = cs_event2text(
8687c478bd9Sstevel@tonic-gate 				va_arg(arglist, event2text_t *), 1);
8697c478bd9Sstevel@tonic-gate 		break;
8707c478bd9Sstevel@tonic-gate 	    case Error2Text: {
8717c478bd9Sstevel@tonic-gate 		error2text_t *cft;
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 		cft = va_arg(arglist, error2text_t *);
8747c478bd9Sstevel@tonic-gate 		(void) strcpy(cft->text,
8757c478bd9Sstevel@tonic-gate 				cs_error2text(cft->item, CSFUN2TEXT_RETURN));
8767c478bd9Sstevel@tonic-gate 		retcode = CS_SUCCESS;
8777c478bd9Sstevel@tonic-gate 		}
8787c478bd9Sstevel@tonic-gate 		break;
8797c478bd9Sstevel@tonic-gate 	    case CS_DDI_Info:
8807c478bd9Sstevel@tonic-gate 		retcode = cs_ddi_info(va_arg(arglist, cs_ddi_info_t *));
8817c478bd9Sstevel@tonic-gate 		break;
8827c478bd9Sstevel@tonic-gate 	    case CS_Sys_Ctl:
8837c478bd9Sstevel@tonic-gate 		retcode = cs_sys_ctl(va_arg(arglist, cs_sys_ctl_t *));
8847c478bd9Sstevel@tonic-gate 		break;
8857c478bd9Sstevel@tonic-gate 	    default:
8867c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: {unknown function %d}\n", function);
8877c478bd9Sstevel@tonic-gate 		break;
8887c478bd9Sstevel@tonic-gate 	} /* switch(function) */
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 	va_end(arglist);
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
8937c478bd9Sstevel@tonic-gate 	if (cs_debug > 127) {
8947c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "CardServices: returning %s (0x%x)\n",
8957c478bd9Sstevel@tonic-gate 				cs_error2text(retcode, CSFUN2TEXT_RETURN),
8967c478bd9Sstevel@tonic-gate 				retcode);
8977c478bd9Sstevel@tonic-gate 	}
8987c478bd9Sstevel@tonic-gate #endif
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	return (retcode);
9017c478bd9Sstevel@tonic-gate }
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate /*
9047c478bd9Sstevel@tonic-gate  * ==== tuple and CIS handling section ====
9057c478bd9Sstevel@tonic-gate  */
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate /*
9087c478bd9Sstevel@tonic-gate  * cs_parse_tuple - This function supports the CS ParseTuple function call.
9097c478bd9Sstevel@tonic-gate  *
9107c478bd9Sstevel@tonic-gate  *    returns:	CS_SUCCESS - if tuple parsed sucessfully
9117c478bd9Sstevel@tonic-gate  *		CS_NO_CARD - if no card in socket
9127c478bd9Sstevel@tonic-gate  *		CS_BAD_ARGS - if passed CIS list pointer is NULL
9137c478bd9Sstevel@tonic-gate  *		CS_UNKNOWN_TUPLE - if unknown tuple passed to CIS parser
9147c478bd9Sstevel@tonic-gate  *		CS_BAD_CIS - if generic parser error
9157c478bd9Sstevel@tonic-gate  *		CS_NO_CIS - if no CIS for card/function
9167c478bd9Sstevel@tonic-gate  *
9177c478bd9Sstevel@tonic-gate  *    See notes for the cs_get_firstnext_tuple function.
9187c478bd9Sstevel@tonic-gate  */
9197c478bd9Sstevel@tonic-gate static int
cs_parse_tuple(client_handle_t client_handle,tuple_t * tuple,cisparse_t * cisparse,cisdata_t cisdata)9207c478bd9Sstevel@tonic-gate cs_parse_tuple(client_handle_t client_handle, tuple_t *tuple,
9217c478bd9Sstevel@tonic-gate 				cisparse_t *cisparse, cisdata_t cisdata)
9227c478bd9Sstevel@tonic-gate {
9237c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
9247c478bd9Sstevel@tonic-gate 	client_t *client;
9257c478bd9Sstevel@tonic-gate 	uint32_t fn;
9267c478bd9Sstevel@tonic-gate 	int ret;
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	if ((ret = cs_get_socket(client_handle, &tuple->Socket,
9297c478bd9Sstevel@tonic-gate 					&fn, &sp, &client)) != CS_SUCCESS)
9307c478bd9Sstevel@tonic-gate 	    return (ret);
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	/*
9337c478bd9Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
9347c478bd9Sstevel@tonic-gate 	 *	for this client, then return an error.
9357c478bd9Sstevel@tonic-gate 	 */
9367c478bd9Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED))
9377c478bd9Sstevel@tonic-gate 	    return (CS_NO_CARD);
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 	/*
9407c478bd9Sstevel@tonic-gate 	 * Sanity check to be sure that we've got a non-NULL CIS list
9417c478bd9Sstevel@tonic-gate 	 *	pointer.
9427c478bd9Sstevel@tonic-gate 	 */
9437c478bd9Sstevel@tonic-gate 	if (!(tuple->CISOffset))
9447c478bd9Sstevel@tonic-gate 	    return (CS_BAD_ARGS);
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 	/*
9497c478bd9Sstevel@tonic-gate 	 * Check to see if there is a valid CIS for this function.
9507c478bd9Sstevel@tonic-gate 	 *	There is an implicit assumption here that if this
9517c478bd9Sstevel@tonic-gate 	 *	is a multi-function CIS and the specified function
9527c478bd9Sstevel@tonic-gate 	 *	number is not CS_GLOBAL_CIS that in order for there
9537c478bd9Sstevel@tonic-gate 	 *	to be a valid function-specific CIS, there also must
9547c478bd9Sstevel@tonic-gate 	 *	be a valid global CIS. This means that we don't need
9557c478bd9Sstevel@tonic-gate 	 *	to know whether this tuple came from the global CIS
9567c478bd9Sstevel@tonic-gate 	 *	or from the function-specific CIS.
9577c478bd9Sstevel@tonic-gate 	 */
9587c478bd9Sstevel@tonic-gate 	if ((sp->cis_flags & CW_VALID_CIS) &&
9597c478bd9Sstevel@tonic-gate 				(sp->cis[fn].flags & CW_VALID_CIS)) {
9607c478bd9Sstevel@tonic-gate 	    ret = (int)(uintptr_t)CIS_PARSER(CISP_CIS_PARSE_TUPLE,
9617c478bd9Sstevel@tonic-gate 				cis_cistpl_std_callout,
9627c478bd9Sstevel@tonic-gate 				tuple->CISOffset,
9637c478bd9Sstevel@tonic-gate 				(tuple->Attributes & TUPLE_RETURN_NAME)?
9647c478bd9Sstevel@tonic-gate 							HANDTPL_RETURN_NAME:
9657c478bd9Sstevel@tonic-gate 							HANDTPL_PARSE_LTUPLE,
9667c478bd9Sstevel@tonic-gate 				cisparse, cisdata);
9677c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
9687c478bd9Sstevel@tonic-gate 	    if (ret == CISTPLF_UNKNOWN)
9697c478bd9Sstevel@tonic-gate 		return (CS_UNKNOWN_TUPLE);
9707c478bd9Sstevel@tonic-gate 	    if (ret != CISTPLF_NOERROR)
9717c478bd9Sstevel@tonic-gate 		return (CS_BAD_CIS);
9727c478bd9Sstevel@tonic-gate 	    ret = CS_SUCCESS;
9737c478bd9Sstevel@tonic-gate 	} else {
9747c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
9757c478bd9Sstevel@tonic-gate 	    ret = CS_NO_CIS;
9767c478bd9Sstevel@tonic-gate 	} /* if (CW_VALID_CIS) */
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 	return (ret);
9797c478bd9Sstevel@tonic-gate }
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate /*
9827c478bd9Sstevel@tonic-gate  * cs_get_firstnext_tuple - returns the first/next tuple of the specified type
9837c478bd9Sstevel@tonic-gate  *				this is to support the GetFirstTuple and
9847c478bd9Sstevel@tonic-gate  *				GetNextTuple function call
9857c478bd9Sstevel@tonic-gate  *
9867c478bd9Sstevel@tonic-gate  *    flags - one of:
9877c478bd9Sstevel@tonic-gate  *		CS_GET_FIRST_FLAG causes function to support GetFirstTuple
9887c478bd9Sstevel@tonic-gate  *		CS_GET_NEXT_FLAG causes function to support GetNextTuple
9897c478bd9Sstevel@tonic-gate  *
9907c478bd9Sstevel@tonic-gate  *	tuple_t->Attributes flags:
9917c478bd9Sstevel@tonic-gate  *		TUPLE_RETURN_LINK - XXX Not implemented, see notes below.
9927c478bd9Sstevel@tonic-gate  *		TUPLE_RETURN_IGNORED_TUPLES - return tuples with
9937c478bd9Sstevel@tonic-gate  *				CISTPLF_IGNORE_TUPLE set in the
9947c478bd9Sstevel@tonic-gate  *				cistpl_t->flags member.
9957c478bd9Sstevel@tonic-gate  *
9967c478bd9Sstevel@tonic-gate  *    Notes for regular PC card driver callers:
9977c478bd9Sstevel@tonic-gate  *
9987c478bd9Sstevel@tonic-gate  *	On a single-function card, the caller will get back all the tuples in
9997c478bd9Sstevel@tonic-gate  *	the CIS.
10007c478bd9Sstevel@tonic-gate  *
10017c478bd9Sstevel@tonic-gate  *	On a multi-function card, the caller will get the tuples from the
10027c478bd9Sstevel@tonic-gate  *	global CIS followed by the tuples in the function-specific CIS. The
10037c478bd9Sstevel@tonic-gate  *	caller will not get any tuples from a function-specific CIS that
10047c478bd9Sstevel@tonic-gate  *	does not belong to the caller's function.
10057c478bd9Sstevel@tonic-gate  *
10067c478bd9Sstevel@tonic-gate  *    Notes for Socket Services, the "super-client" or CSI driver callers:
10077c478bd9Sstevel@tonic-gate  *
10087c478bd9Sstevel@tonic-gate  *	On a single-function card, the operation is the same as for regular
10097c478bd9Sstevel@tonic-gate  *	PC card driver callers with the addition that if the function number
10107c478bd9Sstevel@tonic-gate  *	is set to CS_GLOBAL_CIS this function will return CS_NO_CIS.
10117c478bd9Sstevel@tonic-gate  *
10127c478bd9Sstevel@tonic-gate  *	On a multi-function card, the operation is the same as for regular
10137c478bd9Sstevel@tonic-gate  *	PC card driver callers with the addition that if the function number
10147c478bd9Sstevel@tonic-gate  *	is set to CS_GLOBAL_CIS the caller will only get tuples from the
10157c478bd9Sstevel@tonic-gate  *	global CIS. If a particular function nubmer does not exist, this
10167c478bd9Sstevel@tonic-gate  *	function will return CS_NO_CIS for that function.
10177c478bd9Sstevel@tonic-gate  *
10187c478bd9Sstevel@tonic-gate  *    General notes:
10197c478bd9Sstevel@tonic-gate  *
10207c478bd9Sstevel@tonic-gate  *	On both a single-function card and a multi-function card, if the tuple
10217c478bd9Sstevel@tonic-gate  *	comes from the global CIS chain, the CISTPLF_GLOBAL_CIS flag will be
10227c478bd9Sstevel@tonic-gate  *	set in the tuple_t->flags member.
10237c478bd9Sstevel@tonic-gate  *
10247c478bd9Sstevel@tonic-gate  *	On a multi-function card, if the tuple comes from the function-specific
10257c478bd9Sstevel@tonic-gate  *	CIS chain, the CISTPLF_MF_CIS flag will be set in the tuple_t->flags
10267c478bd9Sstevel@tonic-gate  *	member.
10277c478bd9Sstevel@tonic-gate  *
10287c478bd9Sstevel@tonic-gate  *	For other flags that are set in the tuple_t->flags member, see the
10297c478bd9Sstevel@tonic-gate  *	comments for the cis_list_lcreate function in the cis.c file.
10307c478bd9Sstevel@tonic-gate  *
10317c478bd9Sstevel@tonic-gate  *	The CIS parser may not include all the tuples that are in the CIS in
10327c478bd9Sstevel@tonic-gate  *	the private CIS list that it creates and maintains. See the CIS
10337c478bd9Sstevel@tonic-gate  *	parser documentation for a list of tuples that the parser does not
10347c478bd9Sstevel@tonic-gate  *	include in the list.
10357c478bd9Sstevel@tonic-gate  *
10367c478bd9Sstevel@tonic-gate  *	If a tuple has the CISTPLF_IGNORE_TUPLE flag set and the flags
10377c478bd9Sstevel@tonic-gate  *	parameter CIS_GET_LTUPLE_IGNORE is not set, that tuple will not
10387c478bd9Sstevel@tonic-gate  *	be returned to the caller. Instead, the next tuple that matches
10397c478bd9Sstevel@tonic-gate  *	the calling criteria will be returned (or NULL if no other tuples
10407c478bd9Sstevel@tonic-gate  *	match the calling criteria). If CIS_GET_LTUPLE_IGNORE is set in
10417c478bd9Sstevel@tonic-gate  *	the flags paramter, tuples in the CIS list that match the calling
10427c478bd9Sstevel@tonic-gate  *	criteria will be returned.
10437c478bd9Sstevel@tonic-gate  *
10447c478bd9Sstevel@tonic-gate  * XXX The PC Card 95 Standard says that if the TUPLE_RETURN_LINK flag in
10457c478bd9Sstevel@tonic-gate  *	the tuple_t->Attributes member is not set, then we don't return
10467c478bd9Sstevel@tonic-gate  *	any of the link tuples. This function ignores this flag and always
10477c478bd9Sstevel@tonic-gate  *	returns link tuples.
10487c478bd9Sstevel@tonic-gate  *
10497c478bd9Sstevel@tonic-gate  *    Return codes:
10507c478bd9Sstevel@tonic-gate  *		CS_SUCCESS - if tuple sucessfully found and returned
10517c478bd9Sstevel@tonic-gate  *		CS_NO_CARD - if no card inserted
10527c478bd9Sstevel@tonic-gate  *		CS_NO_CIS - if no CIS for the specified card/function
10537c478bd9Sstevel@tonic-gate  *		CS_NO_MORE_ITEMS - if tuple not found or no more tuples
10547c478bd9Sstevel@tonic-gate  *					to return
10557c478bd9Sstevel@tonic-gate  *
10567c478bd9Sstevel@tonic-gate  *    See notes for cs_get_socket for a description of valid client, socket
10577c478bd9Sstevel@tonic-gate  *	and function number combinations.
10587c478bd9Sstevel@tonic-gate  */
10597c478bd9Sstevel@tonic-gate static int
cs_get_firstnext_tuple(client_handle_t client_handle,tuple_t * tuple,uint32_t flags)10607c478bd9Sstevel@tonic-gate cs_get_firstnext_tuple(client_handle_t client_handle,
10617c478bd9Sstevel@tonic-gate     tuple_t *tuple, uint32_t flags)
10627c478bd9Sstevel@tonic-gate {
10637c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
10647c478bd9Sstevel@tonic-gate 	client_t *client;
10657c478bd9Sstevel@tonic-gate 	uint32_t fn;
10667c478bd9Sstevel@tonic-gate 	int ret;
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 	if ((ret = cs_get_socket(client_handle, &tuple->Socket, &fn,
10697c478bd9Sstevel@tonic-gate 						&sp, &client)) != CS_SUCCESS)
10707c478bd9Sstevel@tonic-gate 	    return (ret);
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 	/*
10737c478bd9Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
10747c478bd9Sstevel@tonic-gate 	 *	for this client, then return an error.
10757c478bd9Sstevel@tonic-gate 	 */
10767c478bd9Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED))
10777c478bd9Sstevel@tonic-gate 	    return (CS_NO_CARD);
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 	/*
10827c478bd9Sstevel@tonic-gate 	 * If there's no CIS on this card or no CIS for the specified
10837c478bd9Sstevel@tonic-gate 	 *	function, then we can't do much.
10847c478bd9Sstevel@tonic-gate 	 */
10857c478bd9Sstevel@tonic-gate 	if ((!(sp->cis_flags & CW_VALID_CIS)) ||
10867c478bd9Sstevel@tonic-gate 				(!(sp->cis[fn].flags & CW_VALID_CIS))) {
10877c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
10887c478bd9Sstevel@tonic-gate 	    return (CS_NO_CIS);
10897c478bd9Sstevel@tonic-gate 	}
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 	/*
10927c478bd9Sstevel@tonic-gate 	 * This will set the CIS_GET_LTUPLE_IGNORE flag if the
10937c478bd9Sstevel@tonic-gate 	 *	TUPLE_RETURN_IGNORED_TUPLES flag is set. The
10947c478bd9Sstevel@tonic-gate 	 *	assumption here is that the CIS_GET_LTUPLE_IGNORE
10957c478bd9Sstevel@tonic-gate 	 *	flag and the TUPLE_RETURN_IGNORED_TUPLES flag
10967c478bd9Sstevel@tonic-gate 	 *	shares the same bit position. If this ever changes,
10977c478bd9Sstevel@tonic-gate 	 *	we'll ahve to re-work this section of code.
10987c478bd9Sstevel@tonic-gate 	 */
10997c478bd9Sstevel@tonic-gate 	if (tuple->Attributes & TUPLE_RETURN_IGNORED_TUPLES)
11007c478bd9Sstevel@tonic-gate 	    flags |= CIS_GET_LTUPLE_IGNORE;
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 	/*
11037c478bd9Sstevel@tonic-gate 	 * Are we GetFirstTuple or GetNextTuple?
11047c478bd9Sstevel@tonic-gate 	 */
11057c478bd9Sstevel@tonic-gate 	if ((flags & CIS_GET_LTUPLE_OPMASK) & CS_GET_FIRST_FLAG) {
11067c478bd9Sstevel@tonic-gate 	/*
11077c478bd9Sstevel@tonic-gate 	 * Initialize the tuple structure; we need this information when
11087c478bd9Sstevel@tonic-gate 	 *	we have to process a GetNextTuple or ParseTuple call.
11097c478bd9Sstevel@tonic-gate 	 * If this card has a multi-function CIS, then we always start out
11107c478bd9Sstevel@tonic-gate 	 *	delivering tuples from the global CIS chain. If this card does
11117c478bd9Sstevel@tonic-gate 	 *	not have a multi-function CIS, then the function 0 CIS chain
11127c478bd9Sstevel@tonic-gate 	 *	will contain the complete CIS list.
11137c478bd9Sstevel@tonic-gate 	 * If this is a multi-function card, then use the GET_FIRST_LTUPLE
11147c478bd9Sstevel@tonic-gate 	 *	macro to return the first tuple in the CIS list - we do this
11157c478bd9Sstevel@tonic-gate 	 *	since we don't want to return tuples with CISTPLF_IGNORE_TUPLE
11167c478bd9Sstevel@tonic-gate 	 *	set unless CIS_GET_LTUPLE_IGNORE is set in the flags parameter.
11177c478bd9Sstevel@tonic-gate 	 * Note that we don't have to cross over into the fucntion-specific
11187c478bd9Sstevel@tonic-gate 	 *	CIS chain if GET_FIRST_LTUPLE returns NULL, since a MF CIS will
11197c478bd9Sstevel@tonic-gate 	 *	always have at least a CISTPL_LONGLINK_MFC tuple in the global
11207c478bd9Sstevel@tonic-gate 	 *	CIS chain - the test for NULL is just a sanity check.
11217c478bd9Sstevel@tonic-gate 	 */
11227c478bd9Sstevel@tonic-gate 	    if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
11237c478bd9Sstevel@tonic-gate 		if ((tuple->CISOffset =
11247c478bd9Sstevel@tonic-gate 			GET_FIRST_LTUPLE(sp->cis[CS_GLOBAL_CIS].cis,
11257c478bd9Sstevel@tonic-gate 							flags)) == NULL) {
11267c478bd9Sstevel@tonic-gate 		    mutex_exit(&sp->cis_lock);
11277c478bd9Sstevel@tonic-gate 		    return (CS_NO_MORE_ITEMS);
11287c478bd9Sstevel@tonic-gate 		} /* GET_FIRST_LTUPLE */
11297c478bd9Sstevel@tonic-gate 	    } else {
11307c478bd9Sstevel@tonic-gate 		tuple->CISOffset = sp->cis[0].cis;
11317c478bd9Sstevel@tonic-gate 	    } /* CW_MULTI_FUNCTION_CIS */
11327c478bd9Sstevel@tonic-gate 	} else {
11337c478bd9Sstevel@tonic-gate 	    cistpl_t *tp;
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate 		/*
11367c478bd9Sstevel@tonic-gate 		 * Check to be sure that we have a non-NULL tuple list pointer.
11377c478bd9Sstevel@tonic-gate 		 *	This is necessary in the case where the caller calls us
11387c478bd9Sstevel@tonic-gate 		 *	with get next tuple requests but we don't have any more
11397c478bd9Sstevel@tonic-gate 		 *	tuples to give back.
11407c478bd9Sstevel@tonic-gate 		 */
11417c478bd9Sstevel@tonic-gate 	    if (tuple->CISOffset == NULL) {
11427c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
11437c478bd9Sstevel@tonic-gate 		return (CS_NO_MORE_ITEMS);
11447c478bd9Sstevel@tonic-gate 	    }
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 		/*
11477c478bd9Sstevel@tonic-gate 		 * Point to the next tuple in the list.  If we're searching for
11487c478bd9Sstevel@tonic-gate 		 *	a particular tuple, FIND_LTUPLE_FWD will find it.
11497c478bd9Sstevel@tonic-gate 		 *
11507c478bd9Sstevel@tonic-gate 		 * If there are no more tuples in the chain that we're looking
11517c478bd9Sstevel@tonic-gate 		 *	at, then if we're looking at the global portion of a
11527c478bd9Sstevel@tonic-gate 		 *	multi-function CIS, switch to the function-specific list
11537c478bd9Sstevel@tonic-gate 		 *	and start looking there.
11547c478bd9Sstevel@tonic-gate 		 */
11557c478bd9Sstevel@tonic-gate 	    if ((tp = GET_NEXT_TUPLE(tuple->CISOffset, flags)) == NULL) {
11567c478bd9Sstevel@tonic-gate 		if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
11577c478bd9Sstevel@tonic-gate 		    if ((tuple->CISOffset->flags & CISTPLF_GLOBAL_CIS) &&
11587c478bd9Sstevel@tonic-gate 							(fn != CS_GLOBAL_CIS)) {
11597c478bd9Sstevel@tonic-gate 			tp = GET_FIRST_LTUPLE(sp->cis[fn].cis, flags);
11607c478bd9Sstevel@tonic-gate 		    } /* CISTPLF_GLOBAL_CIS */
11617c478bd9Sstevel@tonic-gate 		} /* CW_MULTI_FUNCTION_CIS */
11627c478bd9Sstevel@tonic-gate 	    } /* GET_NEXT_TUPLE */
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 		/*
11657c478bd9Sstevel@tonic-gate 		 * If there are no more tuples in the chain, then return.
11667c478bd9Sstevel@tonic-gate 		 */
11677c478bd9Sstevel@tonic-gate 	    if ((tuple->CISOffset = tp) == NULL) {
11687c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
11697c478bd9Sstevel@tonic-gate 		return (CS_NO_MORE_ITEMS);
11707c478bd9Sstevel@tonic-gate 	    }
11717c478bd9Sstevel@tonic-gate 	} /* CS_GET_FIRST_FLAG */
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 	/*
11747c478bd9Sstevel@tonic-gate 	 * Check if we want to get the first of a particular type of tuple
11757c478bd9Sstevel@tonic-gate 	 *	or just the first tuple in the chain.
11767c478bd9Sstevel@tonic-gate 	 * If there are no more tuples of the type we're searching for in
11777c478bd9Sstevel@tonic-gate 	 *	the chain that we're looking at, then if we're looking at
11787c478bd9Sstevel@tonic-gate 	 *	the global portion of a multi-function CIS, switch to the
11797c478bd9Sstevel@tonic-gate 	 *	function-specific list and start looking there.
11807c478bd9Sstevel@tonic-gate 	 */
11817c478bd9Sstevel@tonic-gate 	if (tuple->DesiredTuple != RETURN_FIRST_TUPLE) {
11827c478bd9Sstevel@tonic-gate 	    cistpl_t *tp;
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 	    if ((tp = FIND_LTUPLE_FWD(tuple->CISOffset,
11857c478bd9Sstevel@tonic-gate 					tuple->DesiredTuple, flags)) == NULL) {
11867c478bd9Sstevel@tonic-gate 		if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
11877c478bd9Sstevel@tonic-gate 		    if ((tuple->CISOffset->flags & CISTPLF_GLOBAL_CIS) &&
11887c478bd9Sstevel@tonic-gate 							(fn != CS_GLOBAL_CIS)) {
11897c478bd9Sstevel@tonic-gate 			tp = FIND_FIRST_LTUPLE(sp->cis[fn].cis,
11907c478bd9Sstevel@tonic-gate 						tuple->DesiredTuple, flags);
11917c478bd9Sstevel@tonic-gate 		    } /* CISTPLF_GLOBAL_CIS */
11927c478bd9Sstevel@tonic-gate 		} /* CW_MULTI_FUNCTION_CIS */
11937c478bd9Sstevel@tonic-gate 	    } /* FIND_LTUPLE_FWD */
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 		/*
11967c478bd9Sstevel@tonic-gate 		 * If there are no more tuples in the chain, then return.
11977c478bd9Sstevel@tonic-gate 		 */
11987c478bd9Sstevel@tonic-gate 	    if ((tuple->CISOffset = tp) == NULL) {
11997c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
12007c478bd9Sstevel@tonic-gate 		return (CS_NO_MORE_ITEMS);
12017c478bd9Sstevel@tonic-gate 	    }
12027c478bd9Sstevel@tonic-gate 	} /* !RETURN_FIRST_TUPLE */
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate 	/*
12057c478bd9Sstevel@tonic-gate 	 * We've got a tuple, now fill out the rest of the tuple_t
12067c478bd9Sstevel@tonic-gate 	 *	structure.  Callers can use the flags member to
12077c478bd9Sstevel@tonic-gate 	 *	determine whether or not the tuple data was copied
12087c478bd9Sstevel@tonic-gate 	 *	to the linked list or if it's still on the card.
12097c478bd9Sstevel@tonic-gate 	 */
12107c478bd9Sstevel@tonic-gate 	tuple->Flags = tuple->CISOffset->flags;
12117c478bd9Sstevel@tonic-gate 	tuple->TupleCode = tuple->CISOffset->type;
12127c478bd9Sstevel@tonic-gate 	tuple->TupleLink = tuple->CISOffset->len;
12137c478bd9Sstevel@tonic-gate 	tuple->TupleDataLen = tuple->CISOffset->len;
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
12187c478bd9Sstevel@tonic-gate }
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate /*
12217c478bd9Sstevel@tonic-gate  * cs_get_tuple_data - get the data portion of a tuple; this is to
12227c478bd9Sstevel@tonic-gate  *	support the GetTupleData function call.
12237c478bd9Sstevel@tonic-gate  *
12247c478bd9Sstevel@tonic-gate  *    Note that if the data body of a tuple was not read from the CIS,
12257c478bd9Sstevel@tonic-gate  *	then this function will return CS_NO_MORE_ITEMS.
12267c478bd9Sstevel@tonic-gate  *
12277c478bd9Sstevel@tonic-gate  *    For flags that are set in the tuple_t->flags member, see the
12287c478bd9Sstevel@tonic-gate  *	comments for the cis_list_lcreate function in the cis.c file.
12297c478bd9Sstevel@tonic-gate  *	These flags are copied into the tuple_t->flags member by the
12307c478bd9Sstevel@tonic-gate  *	cs_get_firstnext_tuple function call.
12317c478bd9Sstevel@tonic-gate  *
12327c478bd9Sstevel@tonic-gate  *    See notes for the cs_get_firstnext_tuple function.
12337c478bd9Sstevel@tonic-gate  */
12347c478bd9Sstevel@tonic-gate static int
cs_get_tuple_data(client_handle_t client_handle,tuple_t * tuple)12357c478bd9Sstevel@tonic-gate cs_get_tuple_data(client_handle_t client_handle, tuple_t *tuple)
12367c478bd9Sstevel@tonic-gate {
12377c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
12387c478bd9Sstevel@tonic-gate 	client_t *client;
12397c478bd9Sstevel@tonic-gate 	int ret, nbytes;
12407c478bd9Sstevel@tonic-gate 	uint32_t fn, flags;
12417c478bd9Sstevel@tonic-gate 	cisdata_t *tsd, *tdd;
12427c478bd9Sstevel@tonic-gate 	uint32_t newoffset;
12437c478bd9Sstevel@tonic-gate 	acc_handle_t cis_handle;
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate 	if ((ret = cs_get_socket(client_handle, &tuple->Socket, &fn,
12467c478bd9Sstevel@tonic-gate 						&sp, &client)) != CS_SUCCESS)
12477c478bd9Sstevel@tonic-gate 	    return (ret);
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate 	/*
12507c478bd9Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
12517c478bd9Sstevel@tonic-gate 	 *	for this client, then return an error.
12527c478bd9Sstevel@tonic-gate 	 */
12537c478bd9Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED))
12547c478bd9Sstevel@tonic-gate 	    return (CS_NO_CARD);
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
12577c478bd9Sstevel@tonic-gate 
12587c478bd9Sstevel@tonic-gate 	if ((sp->cis_flags & CW_VALID_CIS) &&
12597c478bd9Sstevel@tonic-gate 				(sp->cis[fn].flags & CW_VALID_CIS)) {
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 		/*
12627c478bd9Sstevel@tonic-gate 		 * Check to be sure that we have a non-NULL pointer to
12637c478bd9Sstevel@tonic-gate 		 *	a CIS list.
12647c478bd9Sstevel@tonic-gate 		 */
12657c478bd9Sstevel@tonic-gate 	    if (!(tuple->CISOffset)) {
12667c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
12677c478bd9Sstevel@tonic-gate 		return (CS_NO_MORE_ITEMS);
12687c478bd9Sstevel@tonic-gate 	    }
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 	/*
12717c478bd9Sstevel@tonic-gate 	 * Since the tuple data buffer that the caller calls us with
12727c478bd9Sstevel@tonic-gate 	 *	is preallocated in the tuple_t structure, we ignore any
12737c478bd9Sstevel@tonic-gate 	 *	TupleDataMax value that the caller has setup and use the
12747c478bd9Sstevel@tonic-gate 	 *	actual size of the tuple data buffer in the structure.
12757c478bd9Sstevel@tonic-gate 	 */
12767c478bd9Sstevel@tonic-gate 	    tuple->TupleDataMax = sizeof (tuple->TupleData);
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate 	/*
12797c478bd9Sstevel@tonic-gate 	 * Make sure the requested offset is not past the end of the
12807c478bd9Sstevel@tonic-gate 	 *	tuple data body nor past the end of the user-supplied
12817c478bd9Sstevel@tonic-gate 	 *	buffer.
12827c478bd9Sstevel@tonic-gate 	 */
12837c478bd9Sstevel@tonic-gate 	    if ((int)tuple->TupleOffset >= min((int)tuple->TupleLink,
12847c478bd9Sstevel@tonic-gate 						(int)tuple->TupleDataMax)) {
12857c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
12867c478bd9Sstevel@tonic-gate 		return (CS_NO_MORE_ITEMS);
12877c478bd9Sstevel@tonic-gate 	    }
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 	    tuple->TupleDataLen = tuple->TupleLink;
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate 	    if ((nbytes = min((int)tuple->TupleDataMax -
12927c478bd9Sstevel@tonic-gate 						(int)tuple->TupleOffset,
12937c478bd9Sstevel@tonic-gate 						(int)tuple->TupleDataLen -
12947c478bd9Sstevel@tonic-gate 						(int)tuple->TupleOffset)) < 1) {
12957c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
12967c478bd9Sstevel@tonic-gate 		return (CS_BAD_ARGS);
12977c478bd9Sstevel@tonic-gate 	    }
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 	/*
13007c478bd9Sstevel@tonic-gate 	 * The tuple data destination is always the tuple_t->TupleData
13017c478bd9Sstevel@tonic-gate 	 *	buffer in the tuple_t structure no matter where we read the
13027c478bd9Sstevel@tonic-gate 	 *	tuple data from.
13037c478bd9Sstevel@tonic-gate 	 */
13047c478bd9Sstevel@tonic-gate 	    tdd = tuple->TupleData;
13057c478bd9Sstevel@tonic-gate 	    bzero((caddr_t)tdd, sizeof (tuple->TupleData));
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 	/*
13087c478bd9Sstevel@tonic-gate 	 * Do we have a copy of the tuple data?  If not, we have to
13097c478bd9Sstevel@tonic-gate 	 *	get a pointer to the CIS and read the tuple data from the
13107c478bd9Sstevel@tonic-gate 	 *	card itself.
13117c478bd9Sstevel@tonic-gate 	 */
13127c478bd9Sstevel@tonic-gate 	    switch (tuple->CISOffset->flags & CISTPLF_SPACE_MASK) {
13137c478bd9Sstevel@tonic-gate 		case CISTPLF_LM_SPACE:
13147c478bd9Sstevel@tonic-gate 		    tsd = (tuple->CISOffset->data +
13157c478bd9Sstevel@tonic-gate 					(unsigned)tuple->TupleOffset);
13167c478bd9Sstevel@tonic-gate 		    while (nbytes--)
13177c478bd9Sstevel@tonic-gate 			*tdd++ = *tsd++;
13187c478bd9Sstevel@tonic-gate 		    break;
13197c478bd9Sstevel@tonic-gate 		case CISTPLF_AM_SPACE:
13207c478bd9Sstevel@tonic-gate 		case CISTPLF_CM_SPACE:
13217c478bd9Sstevel@tonic-gate 		    newoffset = tuple->CISOffset->offset;
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate 		/*
13247c478bd9Sstevel@tonic-gate 		 * Setup the proper space flags as well as setup the
13257c478bd9Sstevel@tonic-gate 		 *	address offset to point to the start of the tuple
13267c478bd9Sstevel@tonic-gate 		 *	data area; we need to do the latter since the
13277c478bd9Sstevel@tonic-gate 		 *	cis_store_cis_addr function in cis.c sets up the
13287c478bd9Sstevel@tonic-gate 		 *	tuple->CISOffset->offset offset to point to the
13297c478bd9Sstevel@tonic-gate 		 *	start of the tuple.
13307c478bd9Sstevel@tonic-gate 		 */
13317c478bd9Sstevel@tonic-gate 		    if (tuple->CISOffset->flags & CISTPLF_AM_SPACE) {
13327c478bd9Sstevel@tonic-gate 			flags = CISTPLF_AM_SPACE;
13337c478bd9Sstevel@tonic-gate 			newoffset += ((tuple->TupleOffset * 2) + 4);
13347c478bd9Sstevel@tonic-gate 		    } else {
13357c478bd9Sstevel@tonic-gate 			flags = CISTPLF_CM_SPACE;
13367c478bd9Sstevel@tonic-gate 			newoffset += (tuple->TupleOffset + 2);
13377c478bd9Sstevel@tonic-gate 		    }
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate 		    if (cs_init_cis_window(sp, &newoffset, &cis_handle,
13407c478bd9Sstevel@tonic-gate 							flags) != CS_SUCCESS) {
13417c478bd9Sstevel@tonic-gate 			mutex_exit(&sp->cis_lock);
13427c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_get_tuple_data: socket %d "
13437c478bd9Sstevel@tonic-gate 						"can't init CIS window\n",
13447c478bd9Sstevel@tonic-gate 							sp->socket_num);
13457c478bd9Sstevel@tonic-gate 			return (CS_GENERAL_FAILURE);
13467c478bd9Sstevel@tonic-gate 		    } /* cs_init_cis_window */
13477c478bd9Sstevel@tonic-gate 		    while (nbytes--) {
13487c478bd9Sstevel@tonic-gate 			*tdd++ = csx_Get8(cis_handle, newoffset++);
13497c478bd9Sstevel@tonic-gate 			if (tuple->CISOffset->flags & CISTPLF_AM_SPACE)
13507c478bd9Sstevel@tonic-gate 			    newoffset++;
13517c478bd9Sstevel@tonic-gate 		    } /* while */
13527c478bd9Sstevel@tonic-gate 		    break;
13537c478bd9Sstevel@tonic-gate 		default:
13547c478bd9Sstevel@tonic-gate 		    mutex_exit(&sp->cis_lock);
13557c478bd9Sstevel@tonic-gate 		    return (CS_GENERAL_FAILURE);
13567c478bd9Sstevel@tonic-gate 	    } /* switch */
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate 	    ret = CS_SUCCESS;
13597c478bd9Sstevel@tonic-gate 	} else {
13607c478bd9Sstevel@tonic-gate 	    ret = CS_NO_CIS;
13617c478bd9Sstevel@tonic-gate 	} /* if (CW_VALID_CIS) */
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
13647c478bd9Sstevel@tonic-gate 
13657c478bd9Sstevel@tonic-gate 	return (ret);
13667c478bd9Sstevel@tonic-gate }
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate /*
13697c478bd9Sstevel@tonic-gate  * cs_validate_cis - validates the CIS on a card in the given socket; this
13707c478bd9Sstevel@tonic-gate  *			is to support the ValidateCIS function call.
13717c478bd9Sstevel@tonic-gate  *
13727c478bd9Sstevel@tonic-gate  *    Notes for regular PC card driver callers:
13737c478bd9Sstevel@tonic-gate  *
13747c478bd9Sstevel@tonic-gate  *	Regular PC card drivers calling ValidateCIS will get the meaning of
13757c478bd9Sstevel@tonic-gate  *	the structure members as specified in the standard.
13767c478bd9Sstevel@tonic-gate  *
13777c478bd9Sstevel@tonic-gate  *    Notes for Socket Services, the "super-client" or CSI driver callers:
13787c478bd9Sstevel@tonic-gate  *
13797c478bd9Sstevel@tonic-gate  *		with: Function Number = CS_GLOBAL_CIS
13807c478bd9Sstevel@tonic-gate  *
13817c478bd9Sstevel@tonic-gate  *	For a single-function card, CS_NO_CIS will be returned and the
13827c478bd9Sstevel@tonic-gate  *	cisinfo_t->Chains and cisinfo_t->Tuples members will be set to 0.
13837c478bd9Sstevel@tonic-gate  *
13847c478bd9Sstevel@tonic-gate  *	For a multi-function card, cisinfo_t->Chains will contain a count of
13857c478bd9Sstevel@tonic-gate  *	the number of CIS chains in the global portion of the CIS, and
13867c478bd9Sstevel@tonic-gate  *	cisinfo_t->Tuples will contain a count of the number of tuples in
13877c478bd9Sstevel@tonic-gate  *	the global portion of the CIS.
13887c478bd9Sstevel@tonic-gate  *
13897c478bd9Sstevel@tonic-gate  *		with: 0 <= Function Number < CIS_MAX_FUNCTIONS
13907c478bd9Sstevel@tonic-gate  *
13917c478bd9Sstevel@tonic-gate  *	For a single-function card, if the function number is equal to 0 and
13927c478bd9Sstevel@tonic-gate  *	has a CIS, cisinfo_t->Chains will contain a count of the number of
13937c478bd9Sstevel@tonic-gate  *	CIS chains in the CIS, and cisinfo_t->Tuples will contain a count of
13947c478bd9Sstevel@tonic-gate  *	the number of tuples in the CIS. If the card does not have a CIS, or
13957c478bd9Sstevel@tonic-gate  *	if the function number is not equal to 0, CS_NO_CIS will be returned
13967c478bd9Sstevel@tonic-gate  *	and the cisinfo_t->Chains and cisinfo_t->Tuples members will be set
13977c478bd9Sstevel@tonic-gate  *	to 0.
13987c478bd9Sstevel@tonic-gate  *
13997c478bd9Sstevel@tonic-gate  *	For a multi-function card, cisinfo_t->Chains will contain a count of
14007c478bd9Sstevel@tonic-gate  *	the number of CIS chains in the global and function-specific
14017c478bd9Sstevel@tonic-gate  *	portions of the CIS, and cisinfo_t->Tuples will contain a count of
14027c478bd9Sstevel@tonic-gate  *	the number of tuples in the global and function-specific portions of
14037c478bd9Sstevel@tonic-gate  *	the CIS. If the function does not exist or has no CIS, CS_NO_CIS
14047c478bd9Sstevel@tonic-gate  *	will be returned and the cisinfo_t->Chains and cisinfo_t->Tuples
14057c478bd9Sstevel@tonic-gate  *	members will be set to 0.
14067c478bd9Sstevel@tonic-gate  *
14077c478bd9Sstevel@tonic-gate  *    General notes:
14087c478bd9Sstevel@tonic-gate  *
14097c478bd9Sstevel@tonic-gate  *	If the card does not have a CIS, or if the function does not exist
14107c478bd9Sstevel@tonic-gate  *	or has no CIS, CS_NO_CIS will be returned and the cisinfo_t->Chains
14117c478bd9Sstevel@tonic-gate  *	and cisinfo_t->Tuples members will be set to 0.
14127c478bd9Sstevel@tonic-gate  *
14137c478bd9Sstevel@tonic-gate  *	Most of the work of validating the CIS has already been done by the
14147c478bd9Sstevel@tonic-gate  *	CIS parser module, so we don't have to do much here except for
14157c478bd9Sstevel@tonic-gate  *	looking at the various flags and tuple/chain counts that were already
14167c478bd9Sstevel@tonic-gate  *	setup by the CIS parser.
14177c478bd9Sstevel@tonic-gate  *
14187c478bd9Sstevel@tonic-gate  *    See notes for the cs_get_firstnext_tuple function.
14197c478bd9Sstevel@tonic-gate  */
14207c478bd9Sstevel@tonic-gate static int
cs_validate_cis(client_handle_t client_handle,cisinfo_t * cisinfo)14217c478bd9Sstevel@tonic-gate cs_validate_cis(client_handle_t client_handle, cisinfo_t *cisinfo)
14227c478bd9Sstevel@tonic-gate {
14237c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
14247c478bd9Sstevel@tonic-gate 	client_t *client;
14257c478bd9Sstevel@tonic-gate 	uint32_t fn;
14267c478bd9Sstevel@tonic-gate 	int ret;
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 	if ((ret = cs_get_socket(client_handle, &cisinfo->Socket, &fn,
14297c478bd9Sstevel@tonic-gate 						&sp, &client)) != CS_SUCCESS)
14307c478bd9Sstevel@tonic-gate 	    return (ret);
14317c478bd9Sstevel@tonic-gate 
14327c478bd9Sstevel@tonic-gate 	/*
14337c478bd9Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
14347c478bd9Sstevel@tonic-gate 	 *	for this client, then return an error.
14357c478bd9Sstevel@tonic-gate 	 */
14367c478bd9Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED))
14377c478bd9Sstevel@tonic-gate 	    return (CS_NO_CARD);
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
14407c478bd9Sstevel@tonic-gate 	if ((sp->cis_flags & CW_VALID_CIS) &&
14417c478bd9Sstevel@tonic-gate 				(sp->cis[fn].flags & CW_VALID_CIS)) {
14427c478bd9Sstevel@tonic-gate 	    cisinfo->Chains = sp->cis[fn].nchains;
14437c478bd9Sstevel@tonic-gate 	    cisinfo->Tuples = sp->cis[fn].ntuples;
14447c478bd9Sstevel@tonic-gate 
14457c478bd9Sstevel@tonic-gate 	    if ((fn != CS_GLOBAL_CIS) &&
14467c478bd9Sstevel@tonic-gate 			(sp->cis[CS_GLOBAL_CIS].flags & CW_VALID_CIS)) {
14477c478bd9Sstevel@tonic-gate 		cisinfo->Chains += sp->cis[CS_GLOBAL_CIS].nchains;
14487c478bd9Sstevel@tonic-gate 		cisinfo->Tuples += sp->cis[CS_GLOBAL_CIS].ntuples;
14497c478bd9Sstevel@tonic-gate 	    } /* !CS_GLOBAL_CIS */
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 	    ret = CS_SUCCESS;
14527c478bd9Sstevel@tonic-gate 	} else {
14537c478bd9Sstevel@tonic-gate 	    cisinfo->Chains = 0;
14547c478bd9Sstevel@tonic-gate 	    cisinfo->Tuples = 0;
14557c478bd9Sstevel@tonic-gate 	    ret = CS_NO_CIS;
14567c478bd9Sstevel@tonic-gate 	}
14577c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
14587c478bd9Sstevel@tonic-gate 
14597c478bd9Sstevel@tonic-gate 	return (ret);
14607c478bd9Sstevel@tonic-gate }
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate /*
14637c478bd9Sstevel@tonic-gate  * cs_init_cis_window - initializes the CIS window for the passed socket
14647c478bd9Sstevel@tonic-gate  *
14657c478bd9Sstevel@tonic-gate  *	calling: *sp - pointer to the per-socket structure
14667c478bd9Sstevel@tonic-gate  *		 *offset - offset from start of AM or CM space
14677c478bd9Sstevel@tonic-gate  *		 *hp - pointer to acc_handle_t to store modified
14687c478bd9Sstevel@tonic-gate  *				window access handle in
14697c478bd9Sstevel@tonic-gate  *		 flags - one of:
14707c478bd9Sstevel@tonic-gate  *				CISTPLF_AM_SPACE - set window to AM space
14717c478bd9Sstevel@tonic-gate  *				CISTPLF_CM_SPACE - set window to CM space
14727c478bd9Sstevel@tonic-gate  *
14737c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS if CIS window was set up
14747c478bd9Sstevel@tonic-gate  *		 *offset - contains adjusted offset to use to access
14757c478bd9Sstevel@tonic-gate  *				requested space
14767c478bd9Sstevel@tonic-gate  *		 CS_BAD_WINDOW if CIS window could not be setup
14777c478bd9Sstevel@tonic-gate  *		 CS_GENERAL_FAILURE if socket has a CIS window number
14787c478bd9Sstevel@tonic-gate  *					but the window flags are wrong
14797c478bd9Sstevel@tonic-gate  *
14807c478bd9Sstevel@tonic-gate  *	Note: This function will check to be sure that there is a valid
14817c478bd9Sstevel@tonic-gate  *		CIS window allocated to this socket.
14827c478bd9Sstevel@tonic-gate  *	      If there is an error in setting up the window hardware, the
14837c478bd9Sstevel@tonic-gate  *		CIS window information for this socket is cleared.
14847c478bd9Sstevel@tonic-gate  *	      This function is also used by routines that need to get
14857c478bd9Sstevel@tonic-gate  *		a pointer to the base of AM space to access the card's
14867c478bd9Sstevel@tonic-gate  *		configuration registers.
14877c478bd9Sstevel@tonic-gate  *	      The passed offset is the un-window-size-aligned offset.
14887c478bd9Sstevel@tonic-gate  */
14897c478bd9Sstevel@tonic-gate int
cs_init_cis_window(cs_socket_t * sp,uint32_t * offset,acc_handle_t * hp,uint32_t flags)14907c478bd9Sstevel@tonic-gate cs_init_cis_window(cs_socket_t *sp, uint32_t *offset,
14917c478bd9Sstevel@tonic-gate     acc_handle_t *hp, uint32_t flags)
14927c478bd9Sstevel@tonic-gate {
14937c478bd9Sstevel@tonic-gate 	set_window_t sw;
14947c478bd9Sstevel@tonic-gate 	get_window_t gw;
14957c478bd9Sstevel@tonic-gate 	inquire_window_t iw;
14967c478bd9Sstevel@tonic-gate 	set_page_t set_page;
14977c478bd9Sstevel@tonic-gate 	cs_window_t *cw;
14987c478bd9Sstevel@tonic-gate 
14997c478bd9Sstevel@tonic-gate 	/*
15007c478bd9Sstevel@tonic-gate 	 * Check to be sure that we have a valid CIS window
15017c478bd9Sstevel@tonic-gate 	 */
15027c478bd9Sstevel@tonic-gate 	if (!SOCKET_HAS_CIS_WINDOW(sp)) {
15037c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT,
15047c478bd9Sstevel@tonic-gate 			"cs_init_cis_window: socket %d has no CIS window\n",
15057c478bd9Sstevel@tonic-gate 				sp->socket_num);
15067c478bd9Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
15077c478bd9Sstevel@tonic-gate 	}
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate 	/*
15107c478bd9Sstevel@tonic-gate 	 * Check to be sure that this window is allocated for CIS use
15117c478bd9Sstevel@tonic-gate 	 */
15127c478bd9Sstevel@tonic-gate 	if ((cw = cs_get_wp(sp->cis_win_num)) == NULL)
15137c478bd9Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 	if (!(cw->state & CW_CIS)) {
15167c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT,
15177c478bd9Sstevel@tonic-gate 		"cs_init_cis_window: socket %d invalid CIS window state 0x%x\n",
15187c478bd9Sstevel@tonic-gate 				sp->socket_num, cw->state);
15197c478bd9Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
15207c478bd9Sstevel@tonic-gate 	}
15217c478bd9Sstevel@tonic-gate 
15227c478bd9Sstevel@tonic-gate 	/*
15237c478bd9Sstevel@tonic-gate 	 * Get the characteristics of this window - we use this to
15247c478bd9Sstevel@tonic-gate 	 *	determine whether we need to re-map the window or
15257c478bd9Sstevel@tonic-gate 	 *	just move the window offset on the card.
15267c478bd9Sstevel@tonic-gate 	 */
15277c478bd9Sstevel@tonic-gate 	iw.window = sp->cis_win_num;
15287c478bd9Sstevel@tonic-gate 	SocketServices(SS_InquireWindow, &iw);
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 	/*
15317c478bd9Sstevel@tonic-gate 	 * We've got a window, now set up the hardware. If we've got
15327c478bd9Sstevel@tonic-gate 	 *	a variable sized window, then all we need to do is to
15337c478bd9Sstevel@tonic-gate 	 *	get a valid mapping to the base of the window using
15347c478bd9Sstevel@tonic-gate 	 *	the current window size; if we've got a fixed-size
15357c478bd9Sstevel@tonic-gate 	 *	window, then we need to get a mapping to the window
15367c478bd9Sstevel@tonic-gate 	 *	starting at offset zero of the window.
15377c478bd9Sstevel@tonic-gate 	 */
15387c478bd9Sstevel@tonic-gate 	if (iw.mem_win_char.MemWndCaps & WC_SIZE) {
15397c478bd9Sstevel@tonic-gate 	    sw.WindowSize = sp->cis_win_size;
15407c478bd9Sstevel@tonic-gate 	    set_page.offset = ((*offset / sp->cis_win_size) *
15417c478bd9Sstevel@tonic-gate 						sp->cis_win_size);
15427c478bd9Sstevel@tonic-gate 	} else {
15437c478bd9Sstevel@tonic-gate 	    set_page.offset = ((*offset / iw.mem_win_char.MinSize) *
15447c478bd9Sstevel@tonic-gate 						iw.mem_win_char.MinSize);
15457c478bd9Sstevel@tonic-gate 	    sw.WindowSize = (((*offset & ~(PAGESIZE - 1)) &
15467c478bd9Sstevel@tonic-gate 					(set_page.offset - 1)) + PAGESIZE);
15477c478bd9Sstevel@tonic-gate 	}
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate 	/*
15507c478bd9Sstevel@tonic-gate 	 * Return a normalized base offset; this takes care of the case
15517c478bd9Sstevel@tonic-gate 	 *	where the required offset is greater than the window size.
15527c478bd9Sstevel@tonic-gate 	 * BugID 1236404
15537c478bd9Sstevel@tonic-gate 	 *	code was:
15547c478bd9Sstevel@tonic-gate 	 *		*offset = *offset & (set_page.offset - 1);
15557c478bd9Sstevel@tonic-gate 	 */
15567c478bd9Sstevel@tonic-gate 	*offset = *offset - set_page.offset;
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
15597c478bd9Sstevel@tonic-gate 	if (cs_debug > 1)
15607c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_init_cis_window: WindowSize 0x%x "
15617c478bd9Sstevel@tonic-gate 							"offset 0x%x\n",
15627c478bd9Sstevel@tonic-gate 							(int)sw.WindowSize,
15637c478bd9Sstevel@tonic-gate 							(int)set_page.offset);
15647c478bd9Sstevel@tonic-gate 	if (cs_debug > 1)
15657c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "\t*offset = 0x%x space = %s\n",
15667c478bd9Sstevel@tonic-gate 							(int)*offset,
15677c478bd9Sstevel@tonic-gate 					(flags & CISTPLF_AM_SPACE)?
15687c478bd9Sstevel@tonic-gate 					"CISTPLF_AM_SPACE":"CISTPLF_CM_SPACE");
15697c478bd9Sstevel@tonic-gate #endif
15707c478bd9Sstevel@tonic-gate 
15717c478bd9Sstevel@tonic-gate 	sw.window = sp->cis_win_num;
15727c478bd9Sstevel@tonic-gate 	sw.socket = sp->socket_num;
15737c478bd9Sstevel@tonic-gate 	sw.state = (WS_ENABLED | WS_EXACT_MAPIN);
15747c478bd9Sstevel@tonic-gate 	sw.attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
15757c478bd9Sstevel@tonic-gate 	sw.attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
15767c478bd9Sstevel@tonic-gate 	sw.attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
15777c478bd9Sstevel@tonic-gate 
15787c478bd9Sstevel@tonic-gate 	/*
15797c478bd9Sstevel@tonic-gate 	 * The PCMCIA SS spec specifies this be expressed in
15807c478bd9Sstevel@tonic-gate 	 *	a device speed format per 5.2.7.1.3 but
15817c478bd9Sstevel@tonic-gate 	 *	our implementation of SS_SetWindow uses
15827c478bd9Sstevel@tonic-gate 	 *	actual nanoseconds.
15837c478bd9Sstevel@tonic-gate 	 */
15847c478bd9Sstevel@tonic-gate 	sw.speed = CIS_DEFAULT_SPEED;
15857c478bd9Sstevel@tonic-gate 	sw.base = 0;
15867c478bd9Sstevel@tonic-gate 	/*
15877c478bd9Sstevel@tonic-gate 	 * Set up the window - if this fails, then just set the
15887c478bd9Sstevel@tonic-gate 	 *	CIS window number back to it's initialized value so
15897c478bd9Sstevel@tonic-gate 	 *	that we'll fail when we break out of the loop.
15907c478bd9Sstevel@tonic-gate 	 */
15917c478bd9Sstevel@tonic-gate 	if (SocketServices(SS_SetWindow, &sw) != SUCCESS) {
15927c478bd9Sstevel@tonic-gate 	    sp->cis_win_num = PCMCIA_MAX_WINDOWS;
15937c478bd9Sstevel@tonic-gate 	    cw->state = 0; /* XXX do we really want to do this? */
15947c478bd9Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
15957c478bd9Sstevel@tonic-gate 	} else {
15967c478bd9Sstevel@tonic-gate 		set_page.window = sp->cis_win_num;
15977c478bd9Sstevel@tonic-gate 		set_page.page = 0;
15987c478bd9Sstevel@tonic-gate 		set_page.state = PS_ENABLED;
15997c478bd9Sstevel@tonic-gate 		if (flags & CISTPLF_AM_SPACE)
16007c478bd9Sstevel@tonic-gate 		    set_page.state |= PS_ATTRIBUTE;
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 		if (SocketServices(SS_SetPage, &set_page) != SUCCESS) {
16037c478bd9Sstevel@tonic-gate 		    sp->cis_win_num = PCMCIA_MAX_WINDOWS;
16047c478bd9Sstevel@tonic-gate 		    cw->state = 0; /* XXX do we really want to do this? */
16057c478bd9Sstevel@tonic-gate 		    return (CS_BAD_WINDOW);
16067c478bd9Sstevel@tonic-gate 		} /* if (SS_SetPage) */
16077c478bd9Sstevel@tonic-gate 	} /* if (SS_SetWindow) */
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 	/*
16107c478bd9Sstevel@tonic-gate 	 * Get the window information for the CIS window for this socket.
16117c478bd9Sstevel@tonic-gate 	 */
16127c478bd9Sstevel@tonic-gate 	gw.window = sp->cis_win_num;
16137c478bd9Sstevel@tonic-gate 	gw.socket = sp->socket_num; /* XXX - SS_GetWindow should set this */
16147c478bd9Sstevel@tonic-gate 	if (SocketServices(SS_GetWindow, &gw) != SUCCESS)
16157c478bd9Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
16167c478bd9Sstevel@tonic-gate 
16177c478bd9Sstevel@tonic-gate 	*hp = (acc_handle_t)gw.handle;
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
16207c478bd9Sstevel@tonic-gate }
16217c478bd9Sstevel@tonic-gate 
16227c478bd9Sstevel@tonic-gate /*
16237c478bd9Sstevel@tonic-gate  * ==== client registration/deregistration section ====
16247c478bd9Sstevel@tonic-gate  */
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate /*
16277c478bd9Sstevel@tonic-gate  * cs_register_client - This supports the RegisterClient call.
16287c478bd9Sstevel@tonic-gate  *
16297c478bd9Sstevel@tonic-gate  * Upon successful registration, the client_handle_t * handle argument will
16307c478bd9Sstevel@tonic-gate  *	contain the new client handle and we return CS_SUCCESS.
16317c478bd9Sstevel@tonic-gate  */
16327c478bd9Sstevel@tonic-gate static int
cs_register_client(client_handle_t * ch,client_reg_t * cr)16337c478bd9Sstevel@tonic-gate cs_register_client(client_handle_t *ch, client_reg_t *cr)
16347c478bd9Sstevel@tonic-gate {
16357c478bd9Sstevel@tonic-gate 	uint32_t sn;
16367c478bd9Sstevel@tonic-gate 	int super_client = 0;
16377c478bd9Sstevel@tonic-gate 	sclient_reg_t *scr = cr->priv;
16387c478bd9Sstevel@tonic-gate 	struct sclient_list_t *scli;
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate 	/*
16417c478bd9Sstevel@tonic-gate 	 * See if we're not supposed to register any new clients.
16427c478bd9Sstevel@tonic-gate 	 */
16437c478bd9Sstevel@tonic-gate 	if (cs_globals.init_state & GLOBAL_INIT_STATE_NO_CLIENTS)
16447c478bd9Sstevel@tonic-gate 	    return (CS_OUT_OF_RESOURCE);
16457c478bd9Sstevel@tonic-gate 
16467c478bd9Sstevel@tonic-gate 	/*
16477c478bd9Sstevel@tonic-gate 	 * Do a version check - if the client expects a later version of
16487c478bd9Sstevel@tonic-gate 	 *	Card Services than what we are, return CS_BAD_VERSION.
16497c478bd9Sstevel@tonic-gate 	 * XXX - How do we specify just a PARTICULAR version of CS??
16507c478bd9Sstevel@tonic-gate 	 */
16517c478bd9Sstevel@tonic-gate 	if (CS_VERSION < cr->Version)
16527c478bd9Sstevel@tonic-gate 	    return (CS_BAD_VERSION);
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 	/*
16557c478bd9Sstevel@tonic-gate 	 * Check to be sure that the client has given us a valid set of
16567c478bd9Sstevel@tonic-gate 	 *	client type flags.  We also use this opportunity to see
16577c478bd9Sstevel@tonic-gate 	 *	if the registering client is Socket Services or is a
16587c478bd9Sstevel@tonic-gate 	 *	"super-client" or a CSI client.
16597c478bd9Sstevel@tonic-gate 	 *
16607c478bd9Sstevel@tonic-gate 	 * Note that SS can not set any flag in the Attributes field other
16617c478bd9Sstevel@tonic-gate 	 *	than the INFO_SOCKET_SERVICES flag.
16627c478bd9Sstevel@tonic-gate 	 *
16637c478bd9Sstevel@tonic-gate 	 * Valid combinations of cr->Attributes and cr->EventMask flags:
16647c478bd9Sstevel@tonic-gate 	 *
16657c478bd9Sstevel@tonic-gate 	 *  for Socket Services:
16667c478bd9Sstevel@tonic-gate 	 *	cr->Attributes:
16677c478bd9Sstevel@tonic-gate 	 *	    set:
16687c478bd9Sstevel@tonic-gate 	 *		INFO_SOCKET_SERVICES
16697c478bd9Sstevel@tonic-gate 	 *	    clear:
16707c478bd9Sstevel@tonic-gate 	 *		{all other flags}
16717c478bd9Sstevel@tonic-gate 	 *	cr->EventMask:
16727c478bd9Sstevel@tonic-gate 	 *	    don't care:
16737c478bd9Sstevel@tonic-gate 	 *		{all flags}
16747c478bd9Sstevel@tonic-gate 	 *
16757c478bd9Sstevel@tonic-gate 	 *  for regular clients:
16767c478bd9Sstevel@tonic-gate 	 *	cr->Attributes:
16777c478bd9Sstevel@tonic-gate 	 *	    only one of:
16787c478bd9Sstevel@tonic-gate 	 *		INFO_IO_CLIENT
16797c478bd9Sstevel@tonic-gate 	 *		INFO_MTD_CLIENT
16807c478bd9Sstevel@tonic-gate 	 *		INFO_MEM_CLIENT
16817c478bd9Sstevel@tonic-gate 	 *	    don't care:
16827c478bd9Sstevel@tonic-gate 	 *		INFO_CARD_SHARE
16837c478bd9Sstevel@tonic-gate 	 *		INFO_CARD_EXCL
16847c478bd9Sstevel@tonic-gate 	 *	cr->EventMask:
16857c478bd9Sstevel@tonic-gate 	 *	    clear:
16867c478bd9Sstevel@tonic-gate 	 *		CS_EVENT_ALL_CLIENTS
16877c478bd9Sstevel@tonic-gate 	 *	    don't care:
16887c478bd9Sstevel@tonic-gate 	 *		{all other flags}
16897c478bd9Sstevel@tonic-gate 	 *
16907c478bd9Sstevel@tonic-gate 	 *  for CSI clients:
16917c478bd9Sstevel@tonic-gate 	 *	cr->Attributes:
16927c478bd9Sstevel@tonic-gate 	 *	    set:
16937c478bd9Sstevel@tonic-gate 	 *		INFO_IO_CLIENT
16947c478bd9Sstevel@tonic-gate 	 *		INFO_CSI_CLIENT
16957c478bd9Sstevel@tonic-gate 	 *	    clear:
16967c478bd9Sstevel@tonic-gate 	 *		INFO_MTD_CLIENT
16977c478bd9Sstevel@tonic-gate 	 *		INFO_MEM_CLIENT
16987c478bd9Sstevel@tonic-gate 	 *	    don't care:
16997c478bd9Sstevel@tonic-gate 	 *		INFO_CARD_SHARE
17007c478bd9Sstevel@tonic-gate 	 *		INFO_CARD_EXCL
17017c478bd9Sstevel@tonic-gate 	 *	cr->EventMask:
17027c478bd9Sstevel@tonic-gate 	 *	    don't care:
17037c478bd9Sstevel@tonic-gate 	 *		{all flags}
17047c478bd9Sstevel@tonic-gate 	 *
17057c478bd9Sstevel@tonic-gate 	 *  for "super-clients":
17067c478bd9Sstevel@tonic-gate 	 *	cr->Attributes:
17077c478bd9Sstevel@tonic-gate 	 *	    set:
17087c478bd9Sstevel@tonic-gate 	 *		INFO_IO_CLIENT
17097c478bd9Sstevel@tonic-gate 	 *		INFO_MTD_CLIENT
17107c478bd9Sstevel@tonic-gate 	 *		INFO_SOCKET_SERVICES
17117c478bd9Sstevel@tonic-gate 	 *		INFO_CARD_SHARE
17127c478bd9Sstevel@tonic-gate 	 *	    clear:
17137c478bd9Sstevel@tonic-gate 	 *		INFO_MEM_CLIENT
17147c478bd9Sstevel@tonic-gate 	 *		INFO_CARD_EXCL
17157c478bd9Sstevel@tonic-gate 	 *	cr->EventMask:
17167c478bd9Sstevel@tonic-gate 	 *	    don't care:
17177c478bd9Sstevel@tonic-gate 	 *		{all flags}
17187c478bd9Sstevel@tonic-gate 	 */
17197c478bd9Sstevel@tonic-gate 	switch (cr->Attributes & INFO_CLIENT_TYPE_MASK) {
17207c478bd9Sstevel@tonic-gate 	/*
17217c478bd9Sstevel@tonic-gate 	 * Check first to see if this is Socket Services registering; if
17227c478bd9Sstevel@tonic-gate 	 *	so, we don't do anything but return the client handle that is
17237c478bd9Sstevel@tonic-gate 	 *	in the global SS client.
17247c478bd9Sstevel@tonic-gate 	 */
17257c478bd9Sstevel@tonic-gate 	    case INFO_SOCKET_SERVICES:
17267c478bd9Sstevel@tonic-gate 		*ch = cs_socket_services_client.client_handle;
17277c478bd9Sstevel@tonic-gate 		return (CS_SUCCESS);
17287c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
17297c478bd9Sstevel@tonic-gate 	    /* CSI clients */
17307c478bd9Sstevel@tonic-gate 	    case (INFO_CSI_CLIENT | INFO_IO_CLIENT):
17317c478bd9Sstevel@tonic-gate 		break;
17327c478bd9Sstevel@tonic-gate 	    /* regular clients */
17337c478bd9Sstevel@tonic-gate 	    case INFO_IO_CLIENT:
17347c478bd9Sstevel@tonic-gate 	    case INFO_MTD_CLIENT:
17357c478bd9Sstevel@tonic-gate 	    case INFO_MEM_CLIENT:
17367c478bd9Sstevel@tonic-gate 		if (cr->EventMask & CS_EVENT_ALL_CLIENTS)
17377c478bd9Sstevel@tonic-gate 		    return (CS_BAD_ATTRIBUTE);
17387c478bd9Sstevel@tonic-gate 		break;
17397c478bd9Sstevel@tonic-gate 	    /* "super-client" clients */
17407c478bd9Sstevel@tonic-gate 	    case (INFO_IO_CLIENT | INFO_MTD_CLIENT | INFO_SOCKET_SERVICES):
17417c478bd9Sstevel@tonic-gate 		if ((!(cr->Attributes & INFO_CARD_SHARE)) ||
17427c478bd9Sstevel@tonic-gate 				(cr->Attributes & INFO_CARD_EXCL))
17437c478bd9Sstevel@tonic-gate 		    return (CS_BAD_ATTRIBUTE);
17447c478bd9Sstevel@tonic-gate 		/*
17457c478bd9Sstevel@tonic-gate 		 * We only allow one "super-client" per system.
17467c478bd9Sstevel@tonic-gate 		 */
17477c478bd9Sstevel@tonic-gate 		mutex_enter(&cs_globals.global_lock);
17487c478bd9Sstevel@tonic-gate 		if (cs_globals.flags & GLOBAL_SUPER_CLIENT_REGISTERED) {
17497c478bd9Sstevel@tonic-gate 		    mutex_exit(&cs_globals.global_lock);
17507c478bd9Sstevel@tonic-gate 		    return (CS_NO_MORE_ITEMS);
17517c478bd9Sstevel@tonic-gate 		}
17527c478bd9Sstevel@tonic-gate 		cs_globals.flags |= GLOBAL_SUPER_CLIENT_REGISTERED;
17537c478bd9Sstevel@tonic-gate 		mutex_exit(&cs_globals.global_lock);
17547c478bd9Sstevel@tonic-gate 		super_client = CLIENT_SUPER_CLIENT;
17557c478bd9Sstevel@tonic-gate 		break;
17567c478bd9Sstevel@tonic-gate 	    default:
17577c478bd9Sstevel@tonic-gate 		return (CS_BAD_ATTRIBUTE);
17587c478bd9Sstevel@tonic-gate 	} /* switch (cr->Attributes) */
17597c478bd9Sstevel@tonic-gate 
17607c478bd9Sstevel@tonic-gate 	/*
17617c478bd9Sstevel@tonic-gate 	 * Now, actually create the client node on the socket; this will
17627c478bd9Sstevel@tonic-gate 	 *	also return the new client handle if there were no errors
17637c478bd9Sstevel@tonic-gate 	 *	creating the client node.
17647c478bd9Sstevel@tonic-gate 	 * The DIP2SOCKET_NUM macro will return the socket and function
17657c478bd9Sstevel@tonic-gate 	 *	number using the encoding specified in the cs_priv.h file.
17667c478bd9Sstevel@tonic-gate 	 */
17677c478bd9Sstevel@tonic-gate 	if (super_client != CLIENT_SUPER_CLIENT) {
17687c478bd9Sstevel@tonic-gate 	    if (cr->Attributes & INFO_CSI_CLIENT)
17697c478bd9Sstevel@tonic-gate 		sn = (uint32_t)(uintptr_t)cr->priv;
17707c478bd9Sstevel@tonic-gate 	    else
17717c478bd9Sstevel@tonic-gate 		sn = DIP2SOCKET_NUM(cr->dip);
17727c478bd9Sstevel@tonic-gate 	    return (cs_add_client_to_socket(sn, ch, cr, super_client));
17737c478bd9Sstevel@tonic-gate 	} /* CLIENT_SUPER_CLIENT */
17747c478bd9Sstevel@tonic-gate 
17757c478bd9Sstevel@tonic-gate 	/*
17767c478bd9Sstevel@tonic-gate 	 * This registering client is a "super-client", so we create one
17777c478bd9Sstevel@tonic-gate 	 *	client node for each socket in the system.  We use the
17787c478bd9Sstevel@tonic-gate 	 *	client_reg_t.priv structure member to point to a struct
17797c478bd9Sstevel@tonic-gate 	 *	that the "super-client" client knows about.  The client
17807c478bd9Sstevel@tonic-gate 	 *	handle pointer is not used in this case.
17817c478bd9Sstevel@tonic-gate 	 * We return CS_SUCCESS if at least one client node could be
17827c478bd9Sstevel@tonic-gate 	 *	created.  The client must check the error codes in the
17837c478bd9Sstevel@tonic-gate 	 *	error code array to determine which clients could not
17847c478bd9Sstevel@tonic-gate 	 *	be created on which sockets.
17857c478bd9Sstevel@tonic-gate 	 * We return CS_BAD_HANDLE if no client nodes could be created.
17867c478bd9Sstevel@tonic-gate 	 */
17877c478bd9Sstevel@tonic-gate 	scr->num_clients = 0;
17887c478bd9Sstevel@tonic-gate 	scr->max_socket_num = cs_globals.max_socket_num;
17897c478bd9Sstevel@tonic-gate 	scr->num_sockets = cs_globals.num_sockets;
17907c478bd9Sstevel@tonic-gate 	scr->num_windows = cs_globals.num_windows;
17917c478bd9Sstevel@tonic-gate 
17927c478bd9Sstevel@tonic-gate 	*(scr->sclient_list) = cs_globals.sclient_list;
17937c478bd9Sstevel@tonic-gate 
17947c478bd9Sstevel@tonic-gate 	for (sn = 0; sn < scr->num_sockets; sn++) {
17957c478bd9Sstevel@tonic-gate 	    scli = scr->sclient_list[sn];
17967c478bd9Sstevel@tonic-gate 	    if ((scli->error = cs_add_client_to_socket(sn, &scli->client_handle,
17977c478bd9Sstevel@tonic-gate 					    cr, super_client)) == CS_SUCCESS) {
17987c478bd9Sstevel@tonic-gate 		scr->num_clients++;
17997c478bd9Sstevel@tonic-gate 	    }
18007c478bd9Sstevel@tonic-gate 	}
18017c478bd9Sstevel@tonic-gate 
18027c478bd9Sstevel@tonic-gate 	/*
18037c478bd9Sstevel@tonic-gate 	 * If we couldn't create any client nodes at all, then
18047c478bd9Sstevel@tonic-gate 	 *	return an error.
18057c478bd9Sstevel@tonic-gate 	 */
18067c478bd9Sstevel@tonic-gate 	if (!scr->num_clients) {
18077c478bd9Sstevel@tonic-gate 	/*
18087c478bd9Sstevel@tonic-gate 	 * XXX - The global superclient lock now gets
18097c478bd9Sstevel@tonic-gate 	 * cleared in cs_deregister_client
18107c478bd9Sstevel@tonic-gate 	 */
18117c478bd9Sstevel@tonic-gate 	    /* cs_clear_superclient_lock(super_client); */
18127c478bd9Sstevel@tonic-gate 	    return (CS_BAD_HANDLE);
18137c478bd9Sstevel@tonic-gate 	}
18147c478bd9Sstevel@tonic-gate 
18157c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
18167c478bd9Sstevel@tonic-gate }
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate /*
18197c478bd9Sstevel@tonic-gate  * cs_add_client_to_socket - this function creates the client node on the
18207c478bd9Sstevel@tonic-gate  *				requested socket.
18217c478bd9Sstevel@tonic-gate  *
18227c478bd9Sstevel@tonic-gate  * Note that if we return an error, there is no state that can be cleaned
18237c478bd9Sstevel@tonic-gate  *	up.  The only way that we can return an error with allocated resources
18247c478bd9Sstevel@tonic-gate  *	would be if one of the client handle functions had an internal error.
18257c478bd9Sstevel@tonic-gate  *	Since we wouldn't get a valid client handle in this case anyway, there
18267c478bd9Sstevel@tonic-gate  *	would be no way to find out what was allocated and what wasn't.
18277c478bd9Sstevel@tonic-gate  */
18287c478bd9Sstevel@tonic-gate static int
cs_add_client_to_socket(unsigned sn,client_handle_t * ch,client_reg_t * cr,int super_client)18297c478bd9Sstevel@tonic-gate cs_add_client_to_socket(unsigned sn, client_handle_t *ch,
18307c478bd9Sstevel@tonic-gate 					client_reg_t *cr, int super_client)
18317c478bd9Sstevel@tonic-gate {
18327c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
18337c478bd9Sstevel@tonic-gate 	client_t *client, *cclp;
18347c478bd9Sstevel@tonic-gate 	int error, cie = 1;
18357c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 	if (cr->event_handler == NULL)
18387c478bd9Sstevel@tonic-gate 	    return (CS_BAD_ARGS);
18397c478bd9Sstevel@tonic-gate 
18407c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(sn)) == NULL)
18417c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
18427c478bd9Sstevel@tonic-gate 
18437c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
18447c478bd9Sstevel@tonic-gate 
18457c478bd9Sstevel@tonic-gate 	/*
18467c478bd9Sstevel@tonic-gate 	 * Run through all of the registered clients and compare the passed
18477c478bd9Sstevel@tonic-gate 	 *	dip to the dip of each client to make sure that this client
18487c478bd9Sstevel@tonic-gate 	 *	is not trying to register more than once.  If they are, then
18497c478bd9Sstevel@tonic-gate 	 *	display a message and return an error.
18507c478bd9Sstevel@tonic-gate 	 * XXX - we should really check all the sockets in case the client
18517c478bd9Sstevel@tonic-gate 	 *	manipulates the instance number in the dip.
18527c478bd9Sstevel@tonic-gate 	 * XXX - if we check each socket, we ned to also check for the
18537c478bd9Sstevel@tonic-gate 	 *	"super-client" since it will use the same dip for all
18547c478bd9Sstevel@tonic-gate 	 *	of it's client nodes.
18557c478bd9Sstevel@tonic-gate 	 */
18567c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
18577c478bd9Sstevel@tonic-gate 	client = sp->client_list;
18587c478bd9Sstevel@tonic-gate 	while (client) {
18597c478bd9Sstevel@tonic-gate 	    if (!(cr->Attributes & INFO_CSI_CLIENT) &&
18607c478bd9Sstevel@tonic-gate 						(client->dip == cr->dip)) {
18617c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->lock);
18627c478bd9Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
18637c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_add_client_to_socket: socket %d "
18647c478bd9Sstevel@tonic-gate 					"function 0x%x\n"
18657c478bd9Sstevel@tonic-gate 					"\tclient already registered with "
18667c478bd9Sstevel@tonic-gate 					"handle 0x%x\n",
18677c478bd9Sstevel@tonic-gate 						(int)CS_GET_SOCKET_NUMBER(sn),
18687c478bd9Sstevel@tonic-gate 						(int)CS_GET_FUNCTION_NUMBER(sn),
18697c478bd9Sstevel@tonic-gate 						(int)client->client_handle);
18707c478bd9Sstevel@tonic-gate 		return (CS_BAD_HANDLE);
18717c478bd9Sstevel@tonic-gate 	    }
18727c478bd9Sstevel@tonic-gate 	    client = client->next;
18737c478bd9Sstevel@tonic-gate 	} /* while (client) */
18747c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
18757c478bd9Sstevel@tonic-gate 
18767c478bd9Sstevel@tonic-gate 	/*
18777c478bd9Sstevel@tonic-gate 	 * Create a unique client handle then make sure that we can find it.
18787c478bd9Sstevel@tonic-gate 	 *	This has the side effect of getting us a pointer to the
18797c478bd9Sstevel@tonic-gate 	 *	client structure as well.
18807c478bd9Sstevel@tonic-gate 	 * Create a client list entry - cs_create_client_handle will use this
18817c478bd9Sstevel@tonic-gate 	 *	as the new client node.
18827c478bd9Sstevel@tonic-gate 	 * We do it here so that we can grab the sp->lock mutex for the
18837c478bd9Sstevel@tonic-gate 	 *	duration of our manipulation of the client list.
18847c478bd9Sstevel@tonic-gate 	 * If this function fails, then it will not have added the newly
18857c478bd9Sstevel@tonic-gate 	 *	allocated client node to the client list on this socket,
18867c478bd9Sstevel@tonic-gate 	 *	so we have to free the node that we allocated.
18877c478bd9Sstevel@tonic-gate 	 */
18887c478bd9Sstevel@tonic-gate 	cclp = (client_t *)kmem_zalloc(sizeof (client_t), KM_SLEEP);
18897c478bd9Sstevel@tonic-gate 
18907c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
18917c478bd9Sstevel@tonic-gate 	if (!(*ch = cs_create_client_handle(sn, cclp))) {
18927c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
18937c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
18947c478bd9Sstevel@tonic-gate 	    kmem_free(cclp, sizeof (client_t));
18957c478bd9Sstevel@tonic-gate 	    return (CS_OUT_OF_RESOURCE);
18967c478bd9Sstevel@tonic-gate 	}
18977c478bd9Sstevel@tonic-gate 
18987c478bd9Sstevel@tonic-gate 	/*
18997c478bd9Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.  We should never
19007c478bd9Sstevel@tonic-gate 	 *	fail this since we just got a valid client handle.
19017c478bd9Sstevel@tonic-gate 	 * If this fails, then we have an internal error so don't bother
19027c478bd9Sstevel@tonic-gate 	 *	trying to clean up the allocated client handle since the
19037c478bd9Sstevel@tonic-gate 	 *	whole system is probably hosed anyway and will shortly
19047c478bd9Sstevel@tonic-gate 	 *	esplode.
19057c478bd9Sstevel@tonic-gate 	 * It doesn't make sense to call cs_deregister_client at this point
19067c478bd9Sstevel@tonic-gate 	 *	to clean up this broken client since the deregistration
19077c478bd9Sstevel@tonic-gate 	 *	code will also call cs_find_client and most likely fail.
19087c478bd9Sstevel@tonic-gate 	 */
19097c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(*ch, &error))) {
19107c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
19117c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
19127c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_add_client_to_socket: socket %d function 0x%x "
19137c478bd9Sstevel@tonic-gate 				"invalid client handle created handle 0x%x\n",
19147c478bd9Sstevel@tonic-gate 						(int)CS_GET_SOCKET_NUMBER(sn),
19157c478bd9Sstevel@tonic-gate 						(int)CS_GET_FUNCTION_NUMBER(sn),
19167c478bd9Sstevel@tonic-gate 						(int)*ch);
19177c478bd9Sstevel@tonic-gate 	    return (error);
19187c478bd9Sstevel@tonic-gate 	}
19197c478bd9Sstevel@tonic-gate 
19207c478bd9Sstevel@tonic-gate 	/*
19217c478bd9Sstevel@tonic-gate 	 * Save the DDI information.
19227c478bd9Sstevel@tonic-gate 	 */
19237c478bd9Sstevel@tonic-gate 	client->dip = cr->dip;
1924*c48c3045SToomas Soome 	cr->driver_name[MODMAXNAMELEN - 1] = '\0';
1925*c48c3045SToomas Soome 	client->driver_name = kmem_zalloc(strlen(cr->driver_name) + 1,
1926*c48c3045SToomas Soome 	    KM_SLEEP);
19277c478bd9Sstevel@tonic-gate 	(void) strcpy(client->driver_name, cr->driver_name);
19287c478bd9Sstevel@tonic-gate 	client->instance = ddi_get_instance(cr->dip);
19297c478bd9Sstevel@tonic-gate 
19307c478bd9Sstevel@tonic-gate 	/*
19317c478bd9Sstevel@tonic-gate 	 * Copy over the interesting items that the client gave us.
19327c478bd9Sstevel@tonic-gate 	 */
19337c478bd9Sstevel@tonic-gate 	client->flags = (cr->Attributes & INFO_CLIENT_TYPE_MASK);
19347c478bd9Sstevel@tonic-gate 	client->event_callback_handler = cr->event_handler;
19357c478bd9Sstevel@tonic-gate 	bcopy((caddr_t)&cr->event_callback_args,
19367c478bd9Sstevel@tonic-gate 				(caddr_t)&client->event_callback_args,
19377c478bd9Sstevel@tonic-gate 				sizeof (event_callback_args_t));
19387c478bd9Sstevel@tonic-gate 	/*
19397c478bd9Sstevel@tonic-gate 	 * Set the client handle since the client needs a client handle
19407c478bd9Sstevel@tonic-gate 	 *	when they call us for their event handler.
19417c478bd9Sstevel@tonic-gate 	 */
19427c478bd9Sstevel@tonic-gate 	client->event_callback_args.client_handle = *ch;
19437c478bd9Sstevel@tonic-gate 
19447c478bd9Sstevel@tonic-gate 	/*
19457c478bd9Sstevel@tonic-gate 	 * Initialize the IO window numbers; if an IO window number is equal
19467c478bd9Sstevel@tonic-gate 	 *	to PCMCIA_MAX_WINDOWS it means that IO range is not in use.
19477c478bd9Sstevel@tonic-gate 	 */
19487c478bd9Sstevel@tonic-gate 	client->io_alloc.Window1 = PCMCIA_MAX_WINDOWS;
19497c478bd9Sstevel@tonic-gate 	client->io_alloc.Window2 = PCMCIA_MAX_WINDOWS;
19507c478bd9Sstevel@tonic-gate 
19517c478bd9Sstevel@tonic-gate 	/*
19527c478bd9Sstevel@tonic-gate 	 * Give the client the iblock and idevice cookies to use in
19537c478bd9Sstevel@tonic-gate 	 *	the client's event handler high priority mutex.
19547c478bd9Sstevel@tonic-gate 	 */
19557c478bd9Sstevel@tonic-gate 	cr->iblk_cookie = sp->iblk;
19567c478bd9Sstevel@tonic-gate 	cr->idev_cookie = sp->idev;
19577c478bd9Sstevel@tonic-gate 
19587c478bd9Sstevel@tonic-gate 	/*
19597c478bd9Sstevel@tonic-gate 	 * Set up the global event mask information; we copy this directly
19607c478bd9Sstevel@tonic-gate 	 *	from the client; since we are the only source of events,
19617c478bd9Sstevel@tonic-gate 	 *	any bogus bits that the client puts in here won't matter
19627c478bd9Sstevel@tonic-gate 	 *	because we'll never look at them.
19637c478bd9Sstevel@tonic-gate 	 */
19647c478bd9Sstevel@tonic-gate 	client->global_mask = cr->EventMask;
19657c478bd9Sstevel@tonic-gate 
19667c478bd9Sstevel@tonic-gate 	/*
19677c478bd9Sstevel@tonic-gate 	 * If this client registered as a CSI client, set the appropriate
19687c478bd9Sstevel@tonic-gate 	 *	flag in the client's flags area.
19697c478bd9Sstevel@tonic-gate 	 */
19707c478bd9Sstevel@tonic-gate 	if (cr->Attributes & INFO_CSI_CLIENT)
19717c478bd9Sstevel@tonic-gate 	    client->flags |= CLIENT_CSI_CLIENT;
19727c478bd9Sstevel@tonic-gate 
19737c478bd9Sstevel@tonic-gate 	/*
19747c478bd9Sstevel@tonic-gate 	 * If this client registered as a "super-client" set the appropriate
19757c478bd9Sstevel@tonic-gate 	 *	flag in the client's flags area.
19767c478bd9Sstevel@tonic-gate 	 */
19777c478bd9Sstevel@tonic-gate 	if (super_client == CLIENT_SUPER_CLIENT)
19787c478bd9Sstevel@tonic-gate 	    client->flags |= CLIENT_SUPER_CLIENT;
19797c478bd9Sstevel@tonic-gate 
19807c478bd9Sstevel@tonic-gate 	/*
19817c478bd9Sstevel@tonic-gate 	 * Save other misc information that this client gave us - it is
19827c478bd9Sstevel@tonic-gate 	 *	used in the GetClientInfo function.
19837c478bd9Sstevel@tonic-gate 	 */
19847c478bd9Sstevel@tonic-gate 	client->flags |= (cr->Attributes & INFO_CARD_FLAGS_MASK);
19857c478bd9Sstevel@tonic-gate 
19867c478bd9Sstevel@tonic-gate 	/*
19877c478bd9Sstevel@tonic-gate 	 * Determine if we should give artificial card insertion events and
19887c478bd9Sstevel@tonic-gate 	 *	a registration complete event. Since we don't differentiate
19897c478bd9Sstevel@tonic-gate 	 *	between sharable and exclusive use cards when giving clients
19907c478bd9Sstevel@tonic-gate 	 *	event notification, we modify the definition of the share/excl
19917c478bd9Sstevel@tonic-gate 	 *	flags as follows:
19927c478bd9Sstevel@tonic-gate 	 *
19937c478bd9Sstevel@tonic-gate 	 *	    If either INFO_CARD_SHARE or INFO_CARD_EXCL is set,
19947c478bd9Sstevel@tonic-gate 	 *	    the client will receive artificial card insertion
19957c478bd9Sstevel@tonic-gate 	 *	    events (if the client's card is currently in the
19967c478bd9Sstevel@tonic-gate 	 *	    socket) and a registration complete event.
19977c478bd9Sstevel@tonic-gate 	 *
19987c478bd9Sstevel@tonic-gate 	 *	    If neither of the INFO_CARD_SHARE or INFO_CARD_EXCL is
19997c478bd9Sstevel@tonic-gate 	 *	    set, the client will not receive an artificial card
20007c478bd9Sstevel@tonic-gate 	 *	    insertion event nor a registration complete event
20017c478bd9Sstevel@tonic-gate 	 *	    due to the client's call to register client.
20027c478bd9Sstevel@tonic-gate 	 *
20037c478bd9Sstevel@tonic-gate 	 *	    The client's event mask is not affected by the setting
20047c478bd9Sstevel@tonic-gate 	 *	    of these two bits.
20057c478bd9Sstevel@tonic-gate 	 */
20067c478bd9Sstevel@tonic-gate 	if (cr->Attributes & (INFO_CARD_SHARE | INFO_CARD_EXCL))
20077c478bd9Sstevel@tonic-gate 	    client->pending_events = CS_EVENT_REGISTRATION_COMPLETE;
20087c478bd9Sstevel@tonic-gate 
20097c478bd9Sstevel@tonic-gate 	/*
20107c478bd9Sstevel@tonic-gate 	 * Check to see if the card for this client is currently in
20117c478bd9Sstevel@tonic-gate 	 *	the socket. If it is, then set CLIENT_CARD_INSERTED
20127c478bd9Sstevel@tonic-gate 	 *	since clients that are calling GetStatus at attach
20137c478bd9Sstevel@tonic-gate 	 *	time will typically check to see if their card is
20147c478bd9Sstevel@tonic-gate 	 *	currently installed.
20157c478bd9Sstevel@tonic-gate 	 * If this is the CSI client, we also need to check to see
20167c478bd9Sstevel@tonic-gate 	 *	if there is any card inserted in the socket, since
20177c478bd9Sstevel@tonic-gate 	 *	the cs_card_for_client function will always return
20187c478bd9Sstevel@tonic-gate 	 *	TRUE for a CSI client.
20197c478bd9Sstevel@tonic-gate 	 * XXX What about super-clients?
20207c478bd9Sstevel@tonic-gate 	 */
20217c478bd9Sstevel@tonic-gate 	if (client->flags & CLIENT_CSI_CLIENT) {
20227c478bd9Sstevel@tonic-gate 	    get_ss_status_t get_ss_status;
20237c478bd9Sstevel@tonic-gate 
20247c478bd9Sstevel@tonic-gate 	    get_ss_status.socket = sp->socket_num;
20257c478bd9Sstevel@tonic-gate 
20267c478bd9Sstevel@tonic-gate 	    if (SocketServices(SS_GetStatus, &get_ss_status) != SUCCESS) {
20277c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->lock);
20287c478bd9Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
20297c478bd9Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
20307c478bd9Sstevel@tonic-gate 	    } /* SS_GetStatus */
20317c478bd9Sstevel@tonic-gate 
20327c478bd9Sstevel@tonic-gate 	    if (!(cs_sbm2cse(get_ss_status.CardState) &
20337c478bd9Sstevel@tonic-gate 			CS_EVENT_CARD_INSERTION))
20347c478bd9Sstevel@tonic-gate 		cie = 0;
20357c478bd9Sstevel@tonic-gate 
20367c478bd9Sstevel@tonic-gate 	} /* CLIENT_CSI_CLIENT */
20377c478bd9Sstevel@tonic-gate 
20387c478bd9Sstevel@tonic-gate 	if (cs_card_for_client(client) && (cie != 0)) {
20397c478bd9Sstevel@tonic-gate 	    client->pending_events |= CS_EVENT_CARD_INSERTION;
20407c478bd9Sstevel@tonic-gate 	    client->flags |= CLIENT_CARD_INSERTED;
20417c478bd9Sstevel@tonic-gate 	} /* cs_card_for_client */
20427c478bd9Sstevel@tonic-gate 
20437c478bd9Sstevel@tonic-gate 	sp->num_clients++;
20447c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
20457c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
20467c478bd9Sstevel@tonic-gate 
20477c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
20487c478bd9Sstevel@tonic-gate }
20497c478bd9Sstevel@tonic-gate 
20507c478bd9Sstevel@tonic-gate /*
20517c478bd9Sstevel@tonic-gate  * cs_deregister_client - This supports the DeregisterClient call.
20527c478bd9Sstevel@tonic-gate  */
20537c478bd9Sstevel@tonic-gate static int
cs_deregister_client(client_handle_t client_handle)20547c478bd9Sstevel@tonic-gate cs_deregister_client(client_handle_t client_handle)
20557c478bd9Sstevel@tonic-gate {
20567c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
20577c478bd9Sstevel@tonic-gate 	client_t *client;
20587c478bd9Sstevel@tonic-gate 	int error, super_client = 0;
20597c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
20607c478bd9Sstevel@tonic-gate 
20617c478bd9Sstevel@tonic-gate 	/*
20627c478bd9Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
20637c478bd9Sstevel@tonic-gate 	 *	is, we don't do anything except for return success.
20647c478bd9Sstevel@tonic-gate 	 */
20657c478bd9Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
20667c478bd9Sstevel@tonic-gate 	    return (CS_SUCCESS);
20677c478bd9Sstevel@tonic-gate 
20687c478bd9Sstevel@tonic-gate 	/*
20697c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
20707c478bd9Sstevel@tonic-gate 	 */
20717c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
20727c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate 	/*
20777c478bd9Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
20787c478bd9Sstevel@tonic-gate 	 */
20797c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
20807c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
20817c478bd9Sstevel@tonic-gate 	    return (error);
20827c478bd9Sstevel@tonic-gate 	}
20837c478bd9Sstevel@tonic-gate 
20847c478bd9Sstevel@tonic-gate 	/*
20857c478bd9Sstevel@tonic-gate 	 * Make sure that any resources allocated by this client are
20867c478bd9Sstevel@tonic-gate 	 *	not still allocated, and that if this is an MTD that
20877c478bd9Sstevel@tonic-gate 	 *	no MTD operations are still in progress.
20887c478bd9Sstevel@tonic-gate 	 */
20897c478bd9Sstevel@tonic-gate 	if (client->flags &    (CLIENT_IO_ALLOCATED	|
20907c478bd9Sstevel@tonic-gate 				CLIENT_IRQ_ALLOCATED	|
20917c478bd9Sstevel@tonic-gate 				CLIENT_WIN_ALLOCATED	|
20927c478bd9Sstevel@tonic-gate 				REQ_CONFIGURATION_DONE	|
20937c478bd9Sstevel@tonic-gate 				REQ_SOCKET_MASK_DONE	|
20947c478bd9Sstevel@tonic-gate 				REQ_IO_DONE		|
20957c478bd9Sstevel@tonic-gate 				REQ_IRQ_DONE)) {
20967c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
20977c478bd9Sstevel@tonic-gate 	    return (CS_BUSY);
20987c478bd9Sstevel@tonic-gate 	}
20997c478bd9Sstevel@tonic-gate 
21007c478bd9Sstevel@tonic-gate 	if (client->flags & CLIENT_MTD_IN_PROGRESS) {
21017c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
21027c478bd9Sstevel@tonic-gate 	    return (CS_IN_USE);
21037c478bd9Sstevel@tonic-gate 	}
21047c478bd9Sstevel@tonic-gate 
21057c478bd9Sstevel@tonic-gate 	/*
21067c478bd9Sstevel@tonic-gate 	 * Any previously allocated resources are not allocated anymore, and
21077c478bd9Sstevel@tonic-gate 	 *	no MTD operations are in progress, so if this is an MTD client
21087c478bd9Sstevel@tonic-gate 	 *	then do any MTD-specific client deregistration, and then
21097c478bd9Sstevel@tonic-gate 	 *	nuke this client.
21107c478bd9Sstevel@tonic-gate 	 * We expect cs_deregister_mtd to never fail.
21117c478bd9Sstevel@tonic-gate 	 */
21127c478bd9Sstevel@tonic-gate 	if (client->flags & INFO_MTD_CLIENT)
21137c478bd9Sstevel@tonic-gate 	    (void) cs_deregister_mtd(client_handle);
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate 	if (client->flags & CLIENT_SUPER_CLIENT)
21167c478bd9Sstevel@tonic-gate 	    super_client = CLIENT_SUPER_CLIENT;
21177c478bd9Sstevel@tonic-gate 
21187c478bd9Sstevel@tonic-gate 	kmem_free(client->driver_name, strlen(client->driver_name) + 1);
21197c478bd9Sstevel@tonic-gate 
21207c478bd9Sstevel@tonic-gate 	error = cs_destroy_client_handle(client_handle);
21217c478bd9Sstevel@tonic-gate 
21227c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
21237c478bd9Sstevel@tonic-gate 
21247c478bd9Sstevel@tonic-gate 	/*
21257c478bd9Sstevel@tonic-gate 	 * If this was the "super-client" deregistering, then this
21267c478bd9Sstevel@tonic-gate 	 *	will clear the global "super-client" lock.
21277c478bd9Sstevel@tonic-gate 	 * XXX - move this outside the per-socket code.
21287c478bd9Sstevel@tonic-gate 	 */
21297c478bd9Sstevel@tonic-gate 	cs_clear_superclient_lock(super_client);
21307c478bd9Sstevel@tonic-gate 
21317c478bd9Sstevel@tonic-gate 	return (error);
21327c478bd9Sstevel@tonic-gate }
21337c478bd9Sstevel@tonic-gate 
21347c478bd9Sstevel@tonic-gate /*
21357c478bd9Sstevel@tonic-gate  * cs_create_next_client_minor - returns the next available client minor
21367c478bd9Sstevel@tonic-gate  *					number or 0 if none available
21377c478bd9Sstevel@tonic-gate  *
21387c478bd9Sstevel@tonic-gate  * Note that cs_find_client will always return a valid pointer to the
21397c478bd9Sstevel@tonic-gate  *	global Socket Services client which has a client minor number
21407c478bd9Sstevel@tonic-gate  *	of 0; this means that this function can never return a 0 as the
21417c478bd9Sstevel@tonic-gate  *	next valid available client minor number.
21427c478bd9Sstevel@tonic-gate  */
21437c478bd9Sstevel@tonic-gate unsigned
cs_create_next_client_minor(unsigned socket_num,unsigned next_minor)21447c478bd9Sstevel@tonic-gate cs_create_next_client_minor(unsigned socket_num, unsigned next_minor)
21457c478bd9Sstevel@tonic-gate {
21467c478bd9Sstevel@tonic-gate 	unsigned max_client_handles = cs_max_client_handles;
21477c478bd9Sstevel@tonic-gate 
21487c478bd9Sstevel@tonic-gate 	do {
21497c478bd9Sstevel@tonic-gate 	    next_minor &= CS_MAX_CLIENTS_MASK;
21507c478bd9Sstevel@tonic-gate 	    if (!cs_find_client(MAKE_CLIENT_HANDLE(
21517c478bd9Sstevel@tonic-gate 					CS_GET_SOCKET_NUMBER(socket_num),
21527c478bd9Sstevel@tonic-gate 					CS_GET_FUNCTION_NUMBER(socket_num),
21537c478bd9Sstevel@tonic-gate 							next_minor), NULL)) {
21547c478bd9Sstevel@tonic-gate 		return (next_minor);
21557c478bd9Sstevel@tonic-gate 	    }
21567c478bd9Sstevel@tonic-gate 	    next_minor++;
21577c478bd9Sstevel@tonic-gate 	} while (max_client_handles--);
21587c478bd9Sstevel@tonic-gate 
21597c478bd9Sstevel@tonic-gate 	return (0);
21607c478bd9Sstevel@tonic-gate }
21617c478bd9Sstevel@tonic-gate 
21627c478bd9Sstevel@tonic-gate /*
21637c478bd9Sstevel@tonic-gate  * cs_find_client - finds the client pointer associated with the client handle
21647c478bd9Sstevel@tonic-gate  *			or NULL if client not found
21657c478bd9Sstevel@tonic-gate  *
21667c478bd9Sstevel@tonic-gate  * returns:	(client_t *)NULL - if client not found or an error occured
21677c478bd9Sstevel@tonic-gate  *					If the error argument is not NULL,
21687c478bd9Sstevel@tonic-gate  *					it is set to:
21697c478bd9Sstevel@tonic-gate  *			CS_BAD_SOCKET - socket number in client_handle_t is
21707c478bd9Sstevel@tonic-gate  *						invalid
21717c478bd9Sstevel@tonic-gate  *			CS_BAD_HANDLE - client not found
21727c478bd9Sstevel@tonic-gate  *			If no error, the error argument is not modified.
21737c478bd9Sstevel@tonic-gate  *		(client_t *) - pointer to client_t structure
21747c478bd9Sstevel@tonic-gate  *
21757c478bd9Sstevel@tonic-gate  * Note that each socket always has a pseudo client with a client minor number
21767c478bd9Sstevel@tonic-gate  *	of 0; this client minor number is used for Socket Services access to
21777c478bd9Sstevel@tonic-gate  *	Card Services functions. The client pointer returned for client minor
21787c478bd9Sstevel@tonic-gate  *	number 0 is the global Socket Services client pointer.
21797c478bd9Sstevel@tonic-gate  */
21807c478bd9Sstevel@tonic-gate static client_t *
cs_find_client(client_handle_t client_handle,int * error)21817c478bd9Sstevel@tonic-gate cs_find_client(client_handle_t client_handle, int *error)
21827c478bd9Sstevel@tonic-gate {
21837c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
21847c478bd9Sstevel@tonic-gate 	client_t *clp;
21857c478bd9Sstevel@tonic-gate 
21867c478bd9Sstevel@tonic-gate 	/*
21877c478bd9Sstevel@tonic-gate 	 * If we are being asked to see if a client with a minor number
21887c478bd9Sstevel@tonic-gate 	 *	of 0 exists, always return a pointer to the global Socket
21897c478bd9Sstevel@tonic-gate 	 *	Services client, since this client always exists, and is
21907c478bd9Sstevel@tonic-gate 	 *	only for use by Socket Services.  There is no socket
21917c478bd9Sstevel@tonic-gate 	 *	associated with this special client handle.
21927c478bd9Sstevel@tonic-gate 	 */
21937c478bd9Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
21947c478bd9Sstevel@tonic-gate 	    return (&cs_socket_services_client);
21957c478bd9Sstevel@tonic-gate 
21967c478bd9Sstevel@tonic-gate 	/*
21977c478bd9Sstevel@tonic-gate 	 * Check to be sure that the socket number is in range
21987c478bd9Sstevel@tonic-gate 	 */
21997c478bd9Sstevel@tonic-gate 	if (!(CHECK_SOCKET_NUM(GET_CLIENT_SOCKET(client_handle),
22007c478bd9Sstevel@tonic-gate 					cs_globals.max_socket_num))) {
22017c478bd9Sstevel@tonic-gate 	    if (error)
22027c478bd9Sstevel@tonic-gate 		*error = CS_BAD_SOCKET;
22037c478bd9Sstevel@tonic-gate 	    return (NULL);
22047c478bd9Sstevel@tonic-gate 	}
22057c478bd9Sstevel@tonic-gate 
22067c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) {
22077c478bd9Sstevel@tonic-gate 	    if (error)
22087c478bd9Sstevel@tonic-gate 		*error = CS_BAD_SOCKET;
22097c478bd9Sstevel@tonic-gate 	    return (NULL);
22107c478bd9Sstevel@tonic-gate 	}
22117c478bd9Sstevel@tonic-gate 
22127c478bd9Sstevel@tonic-gate 	clp = sp->client_list;
22137c478bd9Sstevel@tonic-gate 
22147c478bd9Sstevel@tonic-gate 	while (clp) {
22157c478bd9Sstevel@tonic-gate 	    if (clp->client_handle == client_handle)
22167c478bd9Sstevel@tonic-gate 		return (clp);
22177c478bd9Sstevel@tonic-gate 	    clp = clp->next;
22187c478bd9Sstevel@tonic-gate 	}
22197c478bd9Sstevel@tonic-gate 
22207c478bd9Sstevel@tonic-gate 	if (error)
22217c478bd9Sstevel@tonic-gate 	    *error = CS_BAD_HANDLE;
22227c478bd9Sstevel@tonic-gate 
22237c478bd9Sstevel@tonic-gate 	return (NULL);
22247c478bd9Sstevel@tonic-gate }
22257c478bd9Sstevel@tonic-gate 
22267c478bd9Sstevel@tonic-gate /*
22277c478bd9Sstevel@tonic-gate  * cs_destroy_client_handle - destroys client handle and client structure of
22287c478bd9Sstevel@tonic-gate  *				passed client handle
22297c478bd9Sstevel@tonic-gate  *
22307c478bd9Sstevel@tonic-gate  * returns:	CS_SUCCESS - if client handle sucessfully destroyed
22317c478bd9Sstevel@tonic-gate  *		CS_BAD_HANDLE - if client handle is invalid or if trying
22327c478bd9Sstevel@tonic-gate  *					to destroy global SS client
22337c478bd9Sstevel@tonic-gate  *		{other errors} - other errors from cs_find_client()
22347c478bd9Sstevel@tonic-gate  */
22357c478bd9Sstevel@tonic-gate static int
cs_destroy_client_handle(client_handle_t client_handle)22367c478bd9Sstevel@tonic-gate cs_destroy_client_handle(client_handle_t client_handle)
22377c478bd9Sstevel@tonic-gate {
22387c478bd9Sstevel@tonic-gate 	client_t *clp;
22397c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
22407c478bd9Sstevel@tonic-gate 	int error = CS_BAD_HANDLE;
22417c478bd9Sstevel@tonic-gate 
22427c478bd9Sstevel@tonic-gate 	/*
22437c478bd9Sstevel@tonic-gate 	 * See if we were passed a valid client handle or if we're being asked
22447c478bd9Sstevel@tonic-gate 	 *	to destroy the Socket Services client
22457c478bd9Sstevel@tonic-gate 	 */
22467c478bd9Sstevel@tonic-gate 	if ((!(clp = cs_find_client(client_handle, &error))) ||
22477c478bd9Sstevel@tonic-gate 			(CLIENT_HANDLE_IS_SS(client_handle)))
22487c478bd9Sstevel@tonic-gate 	    return (error);
22497c478bd9Sstevel@tonic-gate 
22507c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
22517c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
22527c478bd9Sstevel@tonic-gate 
22537c478bd9Sstevel@tonic-gate 	/*
22547c478bd9Sstevel@tonic-gate 	 * Recycle this client's minor number.  This will most likely
22557c478bd9Sstevel@tonic-gate 	 *	be the next client minor number we use, but it is also
22567c478bd9Sstevel@tonic-gate 	 *	a hint to cs_create_client_handle, and that function
22577c478bd9Sstevel@tonic-gate 	 *	may actually create a new client handle using a minor
22587c478bd9Sstevel@tonic-gate 	 *	number different that this number.
22597c478bd9Sstevel@tonic-gate 	 */
22607c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
22617c478bd9Sstevel@tonic-gate 	sp->next_cl_minor = GET_CLIENT_MINOR(client_handle);
22627c478bd9Sstevel@tonic-gate 
22637c478bd9Sstevel@tonic-gate 	/*
22647c478bd9Sstevel@tonic-gate 	 * See if we're the first or not in the client list; if we're
22657c478bd9Sstevel@tonic-gate 	 *	not first, then just adjust the client behind us to
22667c478bd9Sstevel@tonic-gate 	 *	point to the client ahead of us; this could be NULL
22677c478bd9Sstevel@tonic-gate 	 *	if we're the last client in the list.
22687c478bd9Sstevel@tonic-gate 	 */
22697c478bd9Sstevel@tonic-gate 	if (clp->prev) {
22707c478bd9Sstevel@tonic-gate 	    clp->prev->next = clp->next;
22717c478bd9Sstevel@tonic-gate 	} else {
22727c478bd9Sstevel@tonic-gate 	/*
22737c478bd9Sstevel@tonic-gate 	 * We are first, so adjust the client list head pointer
22747c478bd9Sstevel@tonic-gate 	 *	in the socket to point to the client structure that
22757c478bd9Sstevel@tonic-gate 	 *	follows us; this could turn out to be NULL if we're
22767c478bd9Sstevel@tonic-gate 	 *	the only client on this socket.
22777c478bd9Sstevel@tonic-gate 	 */
22787c478bd9Sstevel@tonic-gate 	    sp->client_list = clp->next;
22797c478bd9Sstevel@tonic-gate 	}
22807c478bd9Sstevel@tonic-gate 
22817c478bd9Sstevel@tonic-gate 	/*
22827c478bd9Sstevel@tonic-gate 	 * If we're not the last client in the list, point the next
22837c478bd9Sstevel@tonic-gate 	 *	client to the client behind us; this could turn out
22847c478bd9Sstevel@tonic-gate 	 *	to be NULL if we're the first client on this socket.
22857c478bd9Sstevel@tonic-gate 	 */
22867c478bd9Sstevel@tonic-gate 	if (clp->next)
22877c478bd9Sstevel@tonic-gate 	    clp->next->prev = clp->prev;
22887c478bd9Sstevel@tonic-gate 
22897c478bd9Sstevel@tonic-gate 	sp->num_clients--;
22907c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
22917c478bd9Sstevel@tonic-gate 
22927c478bd9Sstevel@tonic-gate 	/*
22937c478bd9Sstevel@tonic-gate 	 * Free this client's memory.
22947c478bd9Sstevel@tonic-gate 	 */
22957c478bd9Sstevel@tonic-gate 	kmem_free(clp, sizeof (client_t));
22967c478bd9Sstevel@tonic-gate 
22977c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
22987c478bd9Sstevel@tonic-gate }
22997c478bd9Sstevel@tonic-gate 
23007c478bd9Sstevel@tonic-gate /*
23017c478bd9Sstevel@tonic-gate  * cs_create_client_handle - create a new client handle for the passed
23027c478bd9Sstevel@tonic-gate  *				socket and function number
23037c478bd9Sstevel@tonic-gate  *
23047c478bd9Sstevel@tonic-gate  * returns:	0 -  if can't create client for some reason
23057c478bd9Sstevel@tonic-gate  *		client_handle_t - new client handle
23067c478bd9Sstevel@tonic-gate  */
23077c478bd9Sstevel@tonic-gate static client_handle_t
cs_create_client_handle(unsigned socket_num,client_t * cclp)23087c478bd9Sstevel@tonic-gate cs_create_client_handle(unsigned socket_num, client_t *cclp)
23097c478bd9Sstevel@tonic-gate {
23107c478bd9Sstevel@tonic-gate 	client_t *clp;
23117c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
23127c478bd9Sstevel@tonic-gate 	unsigned next_minor;
23137c478bd9Sstevel@tonic-gate 	client_handle_t client_handle;
23147c478bd9Sstevel@tonic-gate 
23157c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(socket_num)) == NULL)
23167c478bd9Sstevel@tonic-gate 	    return (0);
23177c478bd9Sstevel@tonic-gate 
23187c478bd9Sstevel@tonic-gate 	/*
23197c478bd9Sstevel@tonic-gate 	 * Get the next available minor number that we can use.  We use the
23207c478bd9Sstevel@tonic-gate 	 *	next_cl_minor number as a hint to cs_create_next_client_minor
23217c478bd9Sstevel@tonic-gate 	 *	and in most cases this will be the minor number we get back.
23227c478bd9Sstevel@tonic-gate 	 * If for some reason we can't get a minor number, return an error.
23237c478bd9Sstevel@tonic-gate 	 *	The only way we could get an error would be if there are
23247c478bd9Sstevel@tonic-gate 	 *	already the maximum number of clients for this socket. Since
23257c478bd9Sstevel@tonic-gate 	 *	the maximum number of clients per socket is pretty large,
23267c478bd9Sstevel@tonic-gate 	 *	this error is unlikely to occur.
23277c478bd9Sstevel@tonic-gate 	 */
23287c478bd9Sstevel@tonic-gate 	if (!(next_minor =
23297c478bd9Sstevel@tonic-gate 		cs_create_next_client_minor(socket_num, sp->next_cl_minor)))
23307c478bd9Sstevel@tonic-gate 	    return (0);
23317c478bd9Sstevel@tonic-gate 
23327c478bd9Sstevel@tonic-gate 	/*
23337c478bd9Sstevel@tonic-gate 	 * Got a new client minor number, now create a new client handle.
23347c478bd9Sstevel@tonic-gate 	 */
23357c478bd9Sstevel@tonic-gate 	client_handle = MAKE_CLIENT_HANDLE(CS_GET_SOCKET_NUMBER(socket_num),
23367c478bd9Sstevel@tonic-gate 					CS_GET_FUNCTION_NUMBER(socket_num),
23377c478bd9Sstevel@tonic-gate 					next_minor);
23387c478bd9Sstevel@tonic-gate 
23397c478bd9Sstevel@tonic-gate 	/*
23407c478bd9Sstevel@tonic-gate 	 * If this client handle exists, then we have an internal
23417c478bd9Sstevel@tonic-gate 	 *	error; this should never happen, BTW.  This is really
23427c478bd9Sstevel@tonic-gate 	 *	a double-check on the cs_create_next_client_minor
23437c478bd9Sstevel@tonic-gate 	 *	function, which also calls cs_find_client.
23447c478bd9Sstevel@tonic-gate 	 */
23457c478bd9Sstevel@tonic-gate 	if (cs_find_client(client_handle, NULL)) {
23467c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT,
23477c478bd9Sstevel@tonic-gate 		"cs_create_client_handle: duplicate client handle 0x%x\n",
23487c478bd9Sstevel@tonic-gate 							(int)client_handle);
23497c478bd9Sstevel@tonic-gate 	    return (0);
23507c478bd9Sstevel@tonic-gate 	}
23517c478bd9Sstevel@tonic-gate 
23527c478bd9Sstevel@tonic-gate 	/*
23537c478bd9Sstevel@tonic-gate 	 * If we don't have any clients on this socket yet, create
23547c478bd9Sstevel@tonic-gate 	 *	a new client and hang it on the socket client list.
23557c478bd9Sstevel@tonic-gate 	 */
23567c478bd9Sstevel@tonic-gate 	if (!sp->client_list) {
23577c478bd9Sstevel@tonic-gate 	    sp->client_list = cclp;
23587c478bd9Sstevel@tonic-gate 	    clp = sp->client_list;
23597c478bd9Sstevel@tonic-gate 	} else {
23607c478bd9Sstevel@tonic-gate 	/*
23617c478bd9Sstevel@tonic-gate 	 * There are other clients on this socket, so look for
23627c478bd9Sstevel@tonic-gate 	 *	the last client and add our new client after it.
23637c478bd9Sstevel@tonic-gate 	 */
23647c478bd9Sstevel@tonic-gate 	    clp = sp->client_list;
23657c478bd9Sstevel@tonic-gate 	    while (clp->next) {
23667c478bd9Sstevel@tonic-gate 		clp = clp->next;
23677c478bd9Sstevel@tonic-gate 	    }
23687c478bd9Sstevel@tonic-gate 
23697c478bd9Sstevel@tonic-gate 	    clp->next = cclp;
23707c478bd9Sstevel@tonic-gate 	    clp->next->prev = clp;
23717c478bd9Sstevel@tonic-gate 	    clp = clp->next;
23727c478bd9Sstevel@tonic-gate 	} /* if (!sp->client_list) */
23737c478bd9Sstevel@tonic-gate 
23747c478bd9Sstevel@tonic-gate 	/*
23757c478bd9Sstevel@tonic-gate 	 * Assign the new client handle to this new client structure.
23767c478bd9Sstevel@tonic-gate 	 */
23777c478bd9Sstevel@tonic-gate 	clp->client_handle = client_handle;
23787c478bd9Sstevel@tonic-gate 
23797c478bd9Sstevel@tonic-gate 	/*
23807c478bd9Sstevel@tonic-gate 	 * Create the next available client minor number for this socket
23817c478bd9Sstevel@tonic-gate 	 *	and save it away.
23827c478bd9Sstevel@tonic-gate 	 */
23837c478bd9Sstevel@tonic-gate 	sp->next_cl_minor =
23847c478bd9Sstevel@tonic-gate 		cs_create_next_client_minor(socket_num, sp->next_cl_minor);
23857c478bd9Sstevel@tonic-gate 
23867c478bd9Sstevel@tonic-gate 	return (client_handle);
23877c478bd9Sstevel@tonic-gate }
23887c478bd9Sstevel@tonic-gate 
23897c478bd9Sstevel@tonic-gate /*
23907c478bd9Sstevel@tonic-gate  * cs_clear_superclient_lock - clears the global "super-client" lock
23917c478bd9Sstevel@tonic-gate  *
23927c478bd9Sstevel@tonic-gate  * Note: this function uses the cs_globals.global_lock so observe proper
23937c478bd9Sstevel@tonic-gate  *		nexting of locks!!
23947c478bd9Sstevel@tonic-gate  */
23957c478bd9Sstevel@tonic-gate static void
cs_clear_superclient_lock(int super_client)23967c478bd9Sstevel@tonic-gate cs_clear_superclient_lock(int super_client)
23977c478bd9Sstevel@tonic-gate {
23987c478bd9Sstevel@tonic-gate 
23997c478bd9Sstevel@tonic-gate 	/*
24007c478bd9Sstevel@tonic-gate 	 * If this was a "super-client" registering then we need
24017c478bd9Sstevel@tonic-gate 	 *	to clear the GLOBAL_SUPER_CLIENT_REGISTERED flag
24027c478bd9Sstevel@tonic-gate 	 *	so that other "super-clients" can register.
24037c478bd9Sstevel@tonic-gate 	 */
24047c478bd9Sstevel@tonic-gate 	if (super_client == CLIENT_SUPER_CLIENT) {
24057c478bd9Sstevel@tonic-gate 	    mutex_enter(&cs_globals.global_lock);
24067c478bd9Sstevel@tonic-gate 	    cs_globals.flags &= ~GLOBAL_SUPER_CLIENT_REGISTERED;
24077c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.global_lock);
24087c478bd9Sstevel@tonic-gate 	}
24097c478bd9Sstevel@tonic-gate }
24107c478bd9Sstevel@tonic-gate 
24117c478bd9Sstevel@tonic-gate /*
24127c478bd9Sstevel@tonic-gate  * ==== event handling section ====
24137c478bd9Sstevel@tonic-gate  */
24147c478bd9Sstevel@tonic-gate 
24157c478bd9Sstevel@tonic-gate /*
24167c478bd9Sstevel@tonic-gate  * cs_event - CS event hi-priority callback handler
24177c478bd9Sstevel@tonic-gate  *
24187c478bd9Sstevel@tonic-gate  *	This function gets called by SS and is passed the event type in
24197c478bd9Sstevel@tonic-gate  *		the "event" argument, and the socket number in the "sn"
24207c478bd9Sstevel@tonic-gate  *		argument. The "sn" argument is a valid logical socket
24217c478bd9Sstevel@tonic-gate  *		number for all events except the PCE_SS_READY event.
24227c478bd9Sstevel@tonic-gate  *
24237c478bd9Sstevel@tonic-gate  *	The PCE_SS_INIT_STATE, PCE_ADD_SOCKET and PCE_DROP_SOCKET events
24247c478bd9Sstevel@tonic-gate  *		are never called at high priority. These events return
24257c478bd9Sstevel@tonic-gate  *		the following return codes:
24267c478bd9Sstevel@tonic-gate  *
24277c478bd9Sstevel@tonic-gate  *			CS_SUCCESS - operation sucessful
24287c478bd9Sstevel@tonic-gate  *			CS_BAD_SOCKET - unable to complete operation
24297c478bd9Sstevel@tonic-gate  *			CS_UNSUPPORTED_FUNCTION - bad subfunction of
24307c478bd9Sstevel@tonic-gate  *							PCE_SS_INIT_STATE
24317c478bd9Sstevel@tonic-gate  *
24327c478bd9Sstevel@tonic-gate  *		The caller MUST look at these return codes!
24337c478bd9Sstevel@tonic-gate  *
24347c478bd9Sstevel@tonic-gate  *	This function is called at high-priority interrupt time for standard
24357c478bd9Sstevel@tonic-gate  *		Card Services events, and the only standard Card Services
24367c478bd9Sstevel@tonic-gate  *		event that it handles directly is the CS_EVENT_CARD_REMOVAL
24377c478bd9Sstevel@tonic-gate  *		event, which gets shuttled right into the client's event
24387c478bd9Sstevel@tonic-gate  *		handler.  All other events are just queued up and the socket
24397c478bd9Sstevel@tonic-gate  *		event thread is woken up via the soft interrupt handler.
24407c478bd9Sstevel@tonic-gate  *	Note that CS_EVENT_CARD_INSERTION events are not set in the clients'
24417c478bd9Sstevel@tonic-gate  *		event field, since the CS card insertion/card ready processing
24427c478bd9Sstevel@tonic-gate  *		code is responsible for setting this event in a client's
24437c478bd9Sstevel@tonic-gate  *		event field.
24447c478bd9Sstevel@tonic-gate  *
24457c478bd9Sstevel@tonic-gate  */
24467c478bd9Sstevel@tonic-gate /*ARGSUSED*/
24477c478bd9Sstevel@tonic-gate uint32_t
cs_event(event_t event,uint32_t sn,uint32_t arg)24487c478bd9Sstevel@tonic-gate cs_event(event_t event, uint32_t sn, uint32_t arg)
24497c478bd9Sstevel@tonic-gate {
24507c478bd9Sstevel@tonic-gate 	client_t *client;
24517c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
24527c478bd9Sstevel@tonic-gate 	client_types_t *ct;
24537c478bd9Sstevel@tonic-gate 	uint32_t ret = CS_SUCCESS;
24547c478bd9Sstevel@tonic-gate 
24557c478bd9Sstevel@tonic-gate 	/*
24567c478bd9Sstevel@tonic-gate 	 * Handle special SS<->CS events
24577c478bd9Sstevel@tonic-gate 	 */
24587c478bd9Sstevel@tonic-gate 	switch (event) {
24597c478bd9Sstevel@tonic-gate 	    case PCE_SS_INIT_STATE:
24607c478bd9Sstevel@tonic-gate 		mutex_enter(&cs_globals.global_lock);
24617c478bd9Sstevel@tonic-gate 		switch (sn) {
24627c478bd9Sstevel@tonic-gate 		    case PCE_SS_STATE_INIT:
24637c478bd9Sstevel@tonic-gate 			if ((ret = cs_ss_init()) == CS_SUCCESS)
24647c478bd9Sstevel@tonic-gate 			    cs_globals.init_state |= GLOBAL_INIT_STATE_SS_READY;
24657c478bd9Sstevel@tonic-gate 			break;
24667c478bd9Sstevel@tonic-gate 		    case PCE_SS_STATE_DEINIT:
24677c478bd9Sstevel@tonic-gate 			cs_globals.init_state &= ~GLOBAL_INIT_STATE_SS_READY;
24687c478bd9Sstevel@tonic-gate 			break;
24697c478bd9Sstevel@tonic-gate 		    default:
24707c478bd9Sstevel@tonic-gate 			ret = CS_UNSUPPORTED_FUNCTION;
24717c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_event: PCE_SS_INIT_STATE invalid "
24727c478bd9Sstevel@tonic-gate 						"directive: 0x%x\n", sn);
24737c478bd9Sstevel@tonic-gate 			break;
24747c478bd9Sstevel@tonic-gate 		} /* switch (sn) */
24757c478bd9Sstevel@tonic-gate 		mutex_exit(&cs_globals.global_lock);
24767c478bd9Sstevel@tonic-gate 		return (ret);
24777c478bd9Sstevel@tonic-gate 	    case PCE_ADD_SOCKET:
24787c478bd9Sstevel@tonic-gate 		return (cs_add_socket(sn));
24797c478bd9Sstevel@tonic-gate 	    case PCE_DROP_SOCKET:
24807c478bd9Sstevel@tonic-gate 		return (cs_drop_socket(sn));
24817c478bd9Sstevel@tonic-gate 	} /* switch (event) */
24827c478bd9Sstevel@tonic-gate 
24837c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(sn)) == NULL)
24847c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
24857c478bd9Sstevel@tonic-gate 
24867c478bd9Sstevel@tonic-gate 	/*
24877c478bd9Sstevel@tonic-gate 	 * Check to see if CS wants to unload - we do this since it's possible
24887c478bd9Sstevel@tonic-gate 	 *	to disable certain sockets.  Do NOT acquire any locks yet.
24897c478bd9Sstevel@tonic-gate 	 */
24907c478bd9Sstevel@tonic-gate 	if (sp->flags & SOCKET_UNLOAD_MODULE) {
24917c478bd9Sstevel@tonic-gate 	    if (event == PCE_CARD_INSERT)
24927c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "PCMCIA: socket %d disabled - please "
24937c478bd9Sstevel@tonic-gate 							"remove card\n", sn);
24947c478bd9Sstevel@tonic-gate 	    return (CS_SUCCESS);
24957c478bd9Sstevel@tonic-gate 	}
24967c478bd9Sstevel@tonic-gate 
24977c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
24987c478bd9Sstevel@tonic-gate 
24997c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
25007c478bd9Sstevel@tonic-gate 	if (cs_debug > 1) {
25017c478bd9Sstevel@tonic-gate 	    event2text_t event2text;
25027c478bd9Sstevel@tonic-gate 
25037c478bd9Sstevel@tonic-gate 	    event2text.event = event;
25047c478bd9Sstevel@tonic-gate 	    (void) cs_event2text(&event2text, 0);
25057c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_event: event=%s (x%x), socket=0x%x\n",
25067c478bd9Sstevel@tonic-gate 				event2text.text, (int)event, (int)sn);
25077c478bd9Sstevel@tonic-gate 	}
25087c478bd9Sstevel@tonic-gate #endif
25097c478bd9Sstevel@tonic-gate 
25107c478bd9Sstevel@tonic-gate 	/*
25117c478bd9Sstevel@tonic-gate 	 * Convert SS events to CS events; handle the PRR if necessary.
25127c478bd9Sstevel@tonic-gate 	 */
25137c478bd9Sstevel@tonic-gate 	sp->events |= ss_to_cs_events(sp, event);
25147c478bd9Sstevel@tonic-gate 
25157c478bd9Sstevel@tonic-gate 	/*
25167c478bd9Sstevel@tonic-gate 	 * We want to maintain the required event dispatching order as
25177c478bd9Sstevel@tonic-gate 	 *	specified in the PCMCIA spec, so we cycle through all
25187c478bd9Sstevel@tonic-gate 	 *	clients on this socket to make sure that they are
25197c478bd9Sstevel@tonic-gate 	 *	notified in the correct order of any high-priority
25207c478bd9Sstevel@tonic-gate 	 *	events.
25217c478bd9Sstevel@tonic-gate 	 */
25227c478bd9Sstevel@tonic-gate 	ct = &client_types[0];
25237c478bd9Sstevel@tonic-gate 	while (ct) {
25247c478bd9Sstevel@tonic-gate 	/*
25257c478bd9Sstevel@tonic-gate 	 * Point to the head of the client list for this socket, and go
25267c478bd9Sstevel@tonic-gate 	 *	through each client to set up the client events as well as
25277c478bd9Sstevel@tonic-gate 	 *	call the client's event handler directly if we have a high
25287c478bd9Sstevel@tonic-gate 	 *	priority event that we need to tell the client about.
25297c478bd9Sstevel@tonic-gate 	 */
25307c478bd9Sstevel@tonic-gate 	    client = sp->client_list;
25317c478bd9Sstevel@tonic-gate 
25327c478bd9Sstevel@tonic-gate 	    if (ct->order & CLIENT_EVENTS_LIFO) {
25337c478bd9Sstevel@tonic-gate 		client_t *clp = NULL;
25347c478bd9Sstevel@tonic-gate 
25357c478bd9Sstevel@tonic-gate 		while (client) {
25367c478bd9Sstevel@tonic-gate 		    clp = client;
25377c478bd9Sstevel@tonic-gate 		    client = client->next;
25387c478bd9Sstevel@tonic-gate 		}
25397c478bd9Sstevel@tonic-gate 		client = clp;
25407c478bd9Sstevel@tonic-gate 	    }
25417c478bd9Sstevel@tonic-gate 
25427c478bd9Sstevel@tonic-gate 	    while (client) {
25437c478bd9Sstevel@tonic-gate 		client->events |= ((sp->events & ~CS_EVENT_CARD_INSERTION) &
25447c478bd9Sstevel@tonic-gate 				    (client->event_mask | client->global_mask));
25457c478bd9Sstevel@tonic-gate 		if (client->flags & ct->type) {
25467c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
25477c478bd9Sstevel@tonic-gate 		    if (cs_debug > 1) {
25487c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_event: socket %d client [%s] "
25497c478bd9Sstevel@tonic-gate 						"events 0x%x flags 0x%x\n",
25507c478bd9Sstevel@tonic-gate 						sn, client->driver_name,
25517c478bd9Sstevel@tonic-gate 						(int)client->events,
25527c478bd9Sstevel@tonic-gate 						(int)client->flags);
25537c478bd9Sstevel@tonic-gate 		    }
25547c478bd9Sstevel@tonic-gate #endif
25557c478bd9Sstevel@tonic-gate 
25567c478bd9Sstevel@tonic-gate 		/*
25577c478bd9Sstevel@tonic-gate 		 * Handle the suspend and card removal events
25587c478bd9Sstevel@tonic-gate 		 *	specially here so that the client can receive
25597c478bd9Sstevel@tonic-gate 		 *	these events at high-priority.
25607c478bd9Sstevel@tonic-gate 		 */
25617c478bd9Sstevel@tonic-gate 		    if (client->events & CS_EVENT_PM_SUSPEND) {
25627c478bd9Sstevel@tonic-gate 			if (client->flags & CLIENT_CARD_INSERTED) {
25637c478bd9Sstevel@tonic-gate 			    CLIENT_EVENT_CALLBACK(client, CS_EVENT_PM_SUSPEND,
25647c478bd9Sstevel@tonic-gate 							CS_EVENT_PRI_HIGH);
25657c478bd9Sstevel@tonic-gate 			} /* if (CLIENT_CARD_INSERTED) */
25667c478bd9Sstevel@tonic-gate 			client->events &= ~CS_EVENT_PM_SUSPEND;
25677c478bd9Sstevel@tonic-gate 		    } /* if (CS_EVENT_PM_SUSPEND) */
25687c478bd9Sstevel@tonic-gate 
25697c478bd9Sstevel@tonic-gate 		    if (client->events & CS_EVENT_CARD_REMOVAL) {
25707c478bd9Sstevel@tonic-gate 			if (client->flags & CLIENT_CARD_INSERTED) {
25717c478bd9Sstevel@tonic-gate 			    client->flags &= ~(CLIENT_CARD_INSERTED |
25727c478bd9Sstevel@tonic-gate 						CLIENT_SENT_INSERTION);
25737c478bd9Sstevel@tonic-gate 			    CLIENT_EVENT_CALLBACK(client,
25747c478bd9Sstevel@tonic-gate 							CS_EVENT_CARD_REMOVAL,
25757c478bd9Sstevel@tonic-gate 							CS_EVENT_PRI_HIGH);
25767c478bd9Sstevel@tonic-gate 			/*
25777c478bd9Sstevel@tonic-gate 			 * Check to see if the client wants low priority
25787c478bd9Sstevel@tonic-gate 			 *	removal events as well.
25797c478bd9Sstevel@tonic-gate 			 */
25807c478bd9Sstevel@tonic-gate 			    if ((client->event_mask | client->global_mask) &
25817c478bd9Sstevel@tonic-gate 						CS_EVENT_CARD_REMOVAL_LOWP) {
25827c478bd9Sstevel@tonic-gate 				client->events |= CS_EVENT_CARD_REMOVAL_LOWP;
25837c478bd9Sstevel@tonic-gate 			    }
25847c478bd9Sstevel@tonic-gate 			} /* if (CLIENT_CARD_INSERTED) */
25857c478bd9Sstevel@tonic-gate 			client->events &= ~CS_EVENT_CARD_REMOVAL;
25867c478bd9Sstevel@tonic-gate 		    } /* if (CS_EVENT_CARD_REMOVAL) */
25877c478bd9Sstevel@tonic-gate 
25887c478bd9Sstevel@tonic-gate 		} /* if (ct->type) */
25897c478bd9Sstevel@tonic-gate 		if (ct->order & CLIENT_EVENTS_LIFO) {
25907c478bd9Sstevel@tonic-gate 		    client = client->prev;
25917c478bd9Sstevel@tonic-gate 		} else {
25927c478bd9Sstevel@tonic-gate 		    client = client->next;
25937c478bd9Sstevel@tonic-gate 		}
25947c478bd9Sstevel@tonic-gate 	    } /* while (client) */
25957c478bd9Sstevel@tonic-gate 
25967c478bd9Sstevel@tonic-gate 	    ct = ct->next;
25977c478bd9Sstevel@tonic-gate 	} /* while (ct) */
25987c478bd9Sstevel@tonic-gate 
25997c478bd9Sstevel@tonic-gate 	/*
26007c478bd9Sstevel@tonic-gate 	 * Set the SOCKET_NEEDS_THREAD flag so that the soft interrupt
26017c478bd9Sstevel@tonic-gate 	 *	handler will wakeup this socket's event thread.
26027c478bd9Sstevel@tonic-gate 	 */
26037c478bd9Sstevel@tonic-gate 	if (sp->events)
26047c478bd9Sstevel@tonic-gate 	    sp->flags |= SOCKET_NEEDS_THREAD;
26057c478bd9Sstevel@tonic-gate 
26067c478bd9Sstevel@tonic-gate 	/*
26077c478bd9Sstevel@tonic-gate 	 * Fire off a soft interrupt that will cause the socket thread
26087c478bd9Sstevel@tonic-gate 	 *	to be woken up and any remaining events to be sent to
26097c478bd9Sstevel@tonic-gate 	 *	the clients on this socket.
26107c478bd9Sstevel@tonic-gate 	 */
26117c478bd9Sstevel@tonic-gate 	if ((sp->init_state & SOCKET_INIT_STATE_SOFTINTR) &&
26127c478bd9Sstevel@tonic-gate 			!(cs_globals.init_state & GLOBAL_INIT_STATE_UNLOADING))
26137c478bd9Sstevel@tonic-gate 	    ddi_trigger_softintr(sp->softint_id);
26147c478bd9Sstevel@tonic-gate 
26157c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
26167c478bd9Sstevel@tonic-gate 
26177c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
26187c478bd9Sstevel@tonic-gate }
26197c478bd9Sstevel@tonic-gate 
26207c478bd9Sstevel@tonic-gate /*
26217c478bd9Sstevel@tonic-gate  * cs_card_insertion - handle card insertion and card ready events
26227c478bd9Sstevel@tonic-gate  *
26237c478bd9Sstevel@tonic-gate  * We read the CIS, if present, and store it away, then tell SS that
26247c478bd9Sstevel@tonic-gate  *	we have read the CIS and it's ready to be parsed.  Since card
26257c478bd9Sstevel@tonic-gate  *	insertion and card ready events are pretty closely intertwined,
26267c478bd9Sstevel@tonic-gate  *	we handle both here.  For card ready events that are not the
26277c478bd9Sstevel@tonic-gate  *	result of a card insertion event, we expect that the caller has
26287c478bd9Sstevel@tonic-gate  *	already done the appropriate processing and that we will not be
26297c478bd9Sstevel@tonic-gate  *	called unless we received a card ready event right after a card
26307c478bd9Sstevel@tonic-gate  *	insertion event, i.e. that the SOCKET_WAIT_FOR_READY flag in
26317c478bd9Sstevel@tonic-gate  *	sp->thread_state was set or if we get a CARD_READY event right
26327c478bd9Sstevel@tonic-gate  *	after a CARD_INSERTION event.
26337c478bd9Sstevel@tonic-gate  *
26347c478bd9Sstevel@tonic-gate  *    calling:	sp - pointer to socket structure
26357c478bd9Sstevel@tonic-gate  *		event - event to handle, one of:
26367c478bd9Sstevel@tonic-gate  *				CS_EVENT_CARD_INSERTION
26377c478bd9Sstevel@tonic-gate  *				CS_EVENT_CARD_READY
26387c478bd9Sstevel@tonic-gate  *				CS_EVENT_SS_UPDATED
26397c478bd9Sstevel@tonic-gate  */
26407c478bd9Sstevel@tonic-gate static int
cs_card_insertion(cs_socket_t * sp,event_t event)26417c478bd9Sstevel@tonic-gate cs_card_insertion(cs_socket_t *sp, event_t event)
26427c478bd9Sstevel@tonic-gate {
26437c478bd9Sstevel@tonic-gate 	int ret;
26447c478bd9Sstevel@tonic-gate 
26457c478bd9Sstevel@tonic-gate 	/*
26467c478bd9Sstevel@tonic-gate 	 * Since we're only called while waiting for the card insertion
26477c478bd9Sstevel@tonic-gate 	 *	and card ready sequence to occur, we may have a pending
26487c478bd9Sstevel@tonic-gate 	 *	card ready timer that hasn't gone off yet if we got a
26497c478bd9Sstevel@tonic-gate 	 *	real card ready event.
26507c478bd9Sstevel@tonic-gate 	 */
26517c478bd9Sstevel@tonic-gate 	UNTIMEOUT(sp->rdybsy_tmo_id);
26527c478bd9Sstevel@tonic-gate 
26537c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
26547c478bd9Sstevel@tonic-gate 	if (cs_debug > 1) {
26557c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_card_insertion: event=0x%x, socket=0x%x\n",
26567c478bd9Sstevel@tonic-gate 						(int)event, sp->socket_num);
26577c478bd9Sstevel@tonic-gate 	}
26587c478bd9Sstevel@tonic-gate #endif
26597c478bd9Sstevel@tonic-gate 
26607c478bd9Sstevel@tonic-gate 	/*
26617c478bd9Sstevel@tonic-gate 	 * Handle card insertion processing
26627c478bd9Sstevel@tonic-gate 	 */
26637c478bd9Sstevel@tonic-gate 	if (event & CS_EVENT_CARD_INSERTION) {
26647c478bd9Sstevel@tonic-gate 	    set_socket_t set_socket;
26657c478bd9Sstevel@tonic-gate 	    get_ss_status_t gs;
26667c478bd9Sstevel@tonic-gate 
26677c478bd9Sstevel@tonic-gate 	/*
26687c478bd9Sstevel@tonic-gate 	 * Check to be sure that we have a valid CIS window
26697c478bd9Sstevel@tonic-gate 	 */
26707c478bd9Sstevel@tonic-gate 	    if (!SOCKET_HAS_CIS_WINDOW(sp)) {
26717c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
26727c478bd9Sstevel@tonic-gate 			"cs_card_insertion: socket %d has no "
26737c478bd9Sstevel@tonic-gate 							"CIS window\n",
26747c478bd9Sstevel@tonic-gate 				sp->socket_num);
26757c478bd9Sstevel@tonic-gate 		return (CS_GENERAL_FAILURE);
26767c478bd9Sstevel@tonic-gate 	    }
26777c478bd9Sstevel@tonic-gate 
26787c478bd9Sstevel@tonic-gate 	/*
26797c478bd9Sstevel@tonic-gate 	 * Apply power to the socket, enable card detect and card ready
26807c478bd9Sstevel@tonic-gate 	 *	events, then reset the socket.
26817c478bd9Sstevel@tonic-gate 	 */
26827c478bd9Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
26837c478bd9Sstevel@tonic-gate 	    sp->event_mask =   (CS_EVENT_CARD_REMOVAL   |
26847c478bd9Sstevel@tonic-gate 				CS_EVENT_CARD_READY);
26857c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
26867c478bd9Sstevel@tonic-gate 	    set_socket.socket = sp->socket_num;
26877c478bd9Sstevel@tonic-gate 	    set_socket.SCIntMask = (SBM_CD | SBM_RDYBSY);
26887c478bd9Sstevel@tonic-gate 	    set_socket.IREQRouting = 0;
26897c478bd9Sstevel@tonic-gate 	    set_socket.IFType = IF_MEMORY;
26907c478bd9Sstevel@tonic-gate 	    set_socket.CtlInd = 0; /* turn off controls and indicators */
26917c478bd9Sstevel@tonic-gate 	    set_socket.State = (unsigned)~0;	/* clear latched state bits */
26927c478bd9Sstevel@tonic-gate 
26937c478bd9Sstevel@tonic-gate 	    (void) cs_convert_powerlevel(sp->socket_num, 50, VCC,
26947c478bd9Sstevel@tonic-gate 						&set_socket.VccLevel);
26957c478bd9Sstevel@tonic-gate 	    (void) cs_convert_powerlevel(sp->socket_num, 50, VPP1,
26967c478bd9Sstevel@tonic-gate 						&set_socket.Vpp1Level);
26977c478bd9Sstevel@tonic-gate 	    (void) cs_convert_powerlevel(sp->socket_num, 50, VPP2,
26987c478bd9Sstevel@tonic-gate 						&set_socket.Vpp2Level);
26997c478bd9Sstevel@tonic-gate 
27007c478bd9Sstevel@tonic-gate 	    if ((ret = SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
27017c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
27027c478bd9Sstevel@tonic-gate 		    "cs_card_insertion: socket %d SS_SetSocket failure %d\n",
27037c478bd9Sstevel@tonic-gate 				sp->socket_num, ret);
27047c478bd9Sstevel@tonic-gate 		return (ret);
27057c478bd9Sstevel@tonic-gate 	    }
27067c478bd9Sstevel@tonic-gate 
27077c478bd9Sstevel@tonic-gate 	/*
27087c478bd9Sstevel@tonic-gate 	 * Clear the ready and ready_timeout events since they are now
27097c478bd9Sstevel@tonic-gate 	 *	bogus since we're about to reset the socket.
27107c478bd9Sstevel@tonic-gate 	 * XXX - should these be cleared right after the RESET??
27117c478bd9Sstevel@tonic-gate 	 */
27127c478bd9Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
27137c478bd9Sstevel@tonic-gate 
27147c478bd9Sstevel@tonic-gate 	    sp->events &= ~(CS_EVENT_CARD_READY | CS_EVENT_READY_TIMEOUT);
27157c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
27167c478bd9Sstevel@tonic-gate 
27177c478bd9Sstevel@tonic-gate 	    SocketServices(SS_ResetSocket, sp->socket_num,
27187c478bd9Sstevel@tonic-gate 						RESET_MODE_CARD_ONLY);
27197c478bd9Sstevel@tonic-gate 
27207c478bd9Sstevel@tonic-gate 	/*
27217c478bd9Sstevel@tonic-gate 	 * We are required by the PCMCIA spec to wait some number of
27227c478bd9Sstevel@tonic-gate 	 *	milliseconds after reset before we access the card, so
27237c478bd9Sstevel@tonic-gate 	 *	we set up a timer here that will wake us up and allow us
27247c478bd9Sstevel@tonic-gate 	 *	to continue with our card initialization.
27257c478bd9Sstevel@tonic-gate 	 */
27267c478bd9Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
27277c478bd9Sstevel@tonic-gate 	    sp->thread_state |= SOCKET_RESET_TIMER;
27287c478bd9Sstevel@tonic-gate 	    (void) timeout(cs_ready_timeout, sp,
27297c478bd9Sstevel@tonic-gate 		drv_usectohz(cs_reset_timeout_time * 1000));
27307c478bd9Sstevel@tonic-gate 	    cv_wait(&sp->reset_cv, &sp->lock);
27317c478bd9Sstevel@tonic-gate 	    sp->thread_state &= ~SOCKET_RESET_TIMER;
27327c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
27337c478bd9Sstevel@tonic-gate 
27347c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
27357c478bd9Sstevel@tonic-gate 	    if (cs_debug > 2) {
27367c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_card_insertion: socket %d out of RESET "
27377c478bd9Sstevel@tonic-gate 		    "for %d mS sp->events 0x%x\n",
27387c478bd9Sstevel@tonic-gate 		    sp->socket_num, cs_reset_timeout_time, (int)sp->events);
27397c478bd9Sstevel@tonic-gate 	    }
27407c478bd9Sstevel@tonic-gate #endif
27417c478bd9Sstevel@tonic-gate 
27427c478bd9Sstevel@tonic-gate 	/*
27437c478bd9Sstevel@tonic-gate 	 * If we have a pending CS_EVENT_CARD_REMOVAL event it
27447c478bd9Sstevel@tonic-gate 	 *	means that we likely got CD line bounce on the
27457c478bd9Sstevel@tonic-gate 	 *	insertion, so terminate this processing.
27467c478bd9Sstevel@tonic-gate 	 */
27477c478bd9Sstevel@tonic-gate 	    if (sp->events & CS_EVENT_CARD_REMOVAL) {
27487c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
27497c478bd9Sstevel@tonic-gate 		if (cs_debug > 0) {
27507c478bd9Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_card_insertion: socket %d "
27517c478bd9Sstevel@tonic-gate 						"CS_EVENT_CARD_REMOVAL event "
27527c478bd9Sstevel@tonic-gate 						"terminating insertion "
27537c478bd9Sstevel@tonic-gate 						"processing\n",
27547c478bd9Sstevel@tonic-gate 							sp->socket_num);
27557c478bd9Sstevel@tonic-gate 		}
27567c478bd9Sstevel@tonic-gate #endif
27577c478bd9Sstevel@tonic-gate 	    return (CS_SUCCESS);
27587c478bd9Sstevel@tonic-gate 	    } /* if (CS_EVENT_CARD_REMOVAL) */
27597c478bd9Sstevel@tonic-gate 
27607c478bd9Sstevel@tonic-gate 	/*
27617c478bd9Sstevel@tonic-gate 	 * If we got a card ready event after the reset, then don't
27627c478bd9Sstevel@tonic-gate 	 *	bother setting up a card ready timer, since we'll blast
27637c478bd9Sstevel@tonic-gate 	 *	right on through to the card ready processing.
27647c478bd9Sstevel@tonic-gate 	 * Get the current card status to see if it's ready; if it
27657c478bd9Sstevel@tonic-gate 	 *	is, we probably won't get a card ready event.
27667c478bd9Sstevel@tonic-gate 	 */
27677c478bd9Sstevel@tonic-gate 	    gs.socket = sp->socket_num;
27687c478bd9Sstevel@tonic-gate 	    gs.CardState = 0;
27697c478bd9Sstevel@tonic-gate 	    if ((ret = SocketServices(SS_GetStatus, &gs)) != SUCCESS) {
27707c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
27717c478bd9Sstevel@tonic-gate 		    "cs_card_insertion: socket %d SS_GetStatus failure %d\n",
27727c478bd9Sstevel@tonic-gate 				sp->socket_num, ret);
27737c478bd9Sstevel@tonic-gate 		return (ret);
27747c478bd9Sstevel@tonic-gate 	    }
27757c478bd9Sstevel@tonic-gate 
27767c478bd9Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
27777c478bd9Sstevel@tonic-gate 	    if ((sp->events & CS_EVENT_CARD_READY) ||
27787c478bd9Sstevel@tonic-gate 					(gs.CardState & SBM_RDYBSY)) {
27797c478bd9Sstevel@tonic-gate 		event = CS_EVENT_CARD_READY;
27807c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
27817c478bd9Sstevel@tonic-gate 		if (cs_debug > 1) {
27827c478bd9Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_card_insertion: socket %d card "
27837c478bd9Sstevel@tonic-gate 						"READY\n", sp->socket_num);
27847c478bd9Sstevel@tonic-gate 		}
27857c478bd9Sstevel@tonic-gate #endif
27867c478bd9Sstevel@tonic-gate 
27877c478bd9Sstevel@tonic-gate 	    } else {
27887c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
27897c478bd9Sstevel@tonic-gate 		if (cs_debug > 1) {
27907c478bd9Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_card_insertion: socket %d setting "
27917c478bd9Sstevel@tonic-gate 					"READY timer\n", sp->socket_num);
27927c478bd9Sstevel@tonic-gate 		}
27937c478bd9Sstevel@tonic-gate #endif
27947c478bd9Sstevel@tonic-gate 
27957c478bd9Sstevel@tonic-gate 		sp->rdybsy_tmo_id = timeout(cs_ready_timeout, sp,
27967c478bd9Sstevel@tonic-gate 		    READY_TIMEOUT_TIME);
27977c478bd9Sstevel@tonic-gate 		sp->thread_state |= SOCKET_WAIT_FOR_READY;
27987c478bd9Sstevel@tonic-gate 
27997c478bd9Sstevel@tonic-gate 	    } /* if (CS_EVENT_CARD_READY) */
28007c478bd9Sstevel@tonic-gate 
28017c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
28027c478bd9Sstevel@tonic-gate 
28037c478bd9Sstevel@tonic-gate 	} /* if (CS_EVENT_CARD_INSERTION) */
28047c478bd9Sstevel@tonic-gate 
28057c478bd9Sstevel@tonic-gate 	/*
28067c478bd9Sstevel@tonic-gate 	 * Handle card ready processing.  This is only card ready processing
28077c478bd9Sstevel@tonic-gate 	 *	for card ready events in conjunction with a card insertion.
28087c478bd9Sstevel@tonic-gate 	 */
28097c478bd9Sstevel@tonic-gate 	if (event == CS_EVENT_CARD_READY) {
28107c478bd9Sstevel@tonic-gate 	    get_socket_t get_socket;
28117c478bd9Sstevel@tonic-gate 	    set_socket_t set_socket;
28127c478bd9Sstevel@tonic-gate 
28137c478bd9Sstevel@tonic-gate 	/*
28147c478bd9Sstevel@tonic-gate 	 * The only events that we want to see now are card removal
28157c478bd9Sstevel@tonic-gate 	 *	events.
28167c478bd9Sstevel@tonic-gate 	 */
28177c478bd9Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
28187c478bd9Sstevel@tonic-gate 	    sp->event_mask = CS_EVENT_CARD_REMOVAL;
28197c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
28207c478bd9Sstevel@tonic-gate 	    get_socket.socket = sp->socket_num;
28217c478bd9Sstevel@tonic-gate 	    if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
28227c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
28237c478bd9Sstevel@tonic-gate 			"cs_card_insertion: socket %d SS_GetSocket failed\n",
28247c478bd9Sstevel@tonic-gate 							sp->socket_num);
28257c478bd9Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
28267c478bd9Sstevel@tonic-gate 	    }
28277c478bd9Sstevel@tonic-gate 
28287c478bd9Sstevel@tonic-gate 	    set_socket.socket = sp->socket_num;
28297c478bd9Sstevel@tonic-gate 	    set_socket.SCIntMask = SBM_CD;
28307c478bd9Sstevel@tonic-gate 	    set_socket.VccLevel = get_socket.VccLevel;
28317c478bd9Sstevel@tonic-gate 	    set_socket.Vpp1Level = get_socket.Vpp1Level;
28327c478bd9Sstevel@tonic-gate 	    set_socket.Vpp2Level = get_socket.Vpp2Level;
28337c478bd9Sstevel@tonic-gate 	    set_socket.IREQRouting = get_socket.IRQRouting;
28347c478bd9Sstevel@tonic-gate 	    set_socket.IFType = get_socket.IFType;
28357c478bd9Sstevel@tonic-gate 	    set_socket.CtlInd = get_socket.CtlInd;
28367c478bd9Sstevel@tonic-gate 	    /* XXX (is ~0 correct here?) to reset latched values */
28377c478bd9Sstevel@tonic-gate 	    set_socket.State = (unsigned)~0;
28387c478bd9Sstevel@tonic-gate 
28397c478bd9Sstevel@tonic-gate 	    if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
28407c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
28417c478bd9Sstevel@tonic-gate 			"cs_card_insertion: socket %d SS_SetSocket failed\n",
28427c478bd9Sstevel@tonic-gate 							sp->socket_num);
28437c478bd9Sstevel@tonic-gate 
28447c478bd9Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
28457c478bd9Sstevel@tonic-gate 	    }
28467c478bd9Sstevel@tonic-gate 
28477c478bd9Sstevel@tonic-gate 		/*
28487c478bd9Sstevel@tonic-gate 		 * Grab the cis_lock mutex to protect the CIS-to-be and
28497c478bd9Sstevel@tonic-gate 		 *	the CIS window, then fire off the CIS parser to
28507c478bd9Sstevel@tonic-gate 		 *	create a local copy of the card's CIS.
28517c478bd9Sstevel@tonic-gate 		 */
28527c478bd9Sstevel@tonic-gate 		mutex_enter(&sp->cis_lock);
28537c478bd9Sstevel@tonic-gate 
28547c478bd9Sstevel@tonic-gate 		if ((ret = cs_create_cis(sp)) != CS_SUCCESS) {
28557c478bd9Sstevel@tonic-gate 		    mutex_exit(&sp->cis_lock);
28567c478bd9Sstevel@tonic-gate 		    return (ret);
28577c478bd9Sstevel@tonic-gate 		}
28587c478bd9Sstevel@tonic-gate 
28597c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
28607c478bd9Sstevel@tonic-gate 
28617c478bd9Sstevel@tonic-gate 		/*
28627c478bd9Sstevel@tonic-gate 		 * If we have a pending CS_EVENT_CARD_REMOVAL event it
28637c478bd9Sstevel@tonic-gate 		 *	means that we likely got CD line bounce on the
28647c478bd9Sstevel@tonic-gate 		 *	insertion, so destroy the CIS and terminate this
28657c478bd9Sstevel@tonic-gate 		 *	processing. We'll get called back to handle the
28667c478bd9Sstevel@tonic-gate 		 *	insertion again later.
28677c478bd9Sstevel@tonic-gate 		 */
28687c478bd9Sstevel@tonic-gate 		if (sp->events & CS_EVENT_CARD_REMOVAL) {
28697c478bd9Sstevel@tonic-gate 		    mutex_enter(&sp->cis_lock);
28707c478bd9Sstevel@tonic-gate 		    (void) cs_destroy_cis(sp);
28717c478bd9Sstevel@tonic-gate 		    mutex_exit(&sp->cis_lock);
28727c478bd9Sstevel@tonic-gate 		} else {
28737c478bd9Sstevel@tonic-gate 			/*
28747c478bd9Sstevel@tonic-gate 			 * Schedule the call to the Socket Services work thread.
28757c478bd9Sstevel@tonic-gate 			 */
28767c478bd9Sstevel@tonic-gate 		    mutex_enter(&sp->ss_thread_lock);
28777c478bd9Sstevel@tonic-gate 		    sp->ss_thread_state |= SOCKET_THREAD_CSCISInit;
28787c478bd9Sstevel@tonic-gate 		    cv_broadcast(&sp->ss_thread_cv);
28797c478bd9Sstevel@tonic-gate 		    mutex_exit(&sp->ss_thread_lock);
28807c478bd9Sstevel@tonic-gate 		} /* if (CS_EVENT_CARD_REMOVAL) */
28817c478bd9Sstevel@tonic-gate 	} /* if (CS_EVENT_CARD_READY) */
28827c478bd9Sstevel@tonic-gate 
28837c478bd9Sstevel@tonic-gate 	/*
28847c478bd9Sstevel@tonic-gate 	 * Socket Services has parsed the CIS and has done any other
28857c478bd9Sstevel@tonic-gate 	 *	work to get the client driver loaded and attached if
28867c478bd9Sstevel@tonic-gate 	 *	necessary, so setup the per-client state.
28877c478bd9Sstevel@tonic-gate 	 */
28887c478bd9Sstevel@tonic-gate 	if (event == CS_EVENT_SS_UPDATED) {
28897c478bd9Sstevel@tonic-gate 	    client_t *client;
28907c478bd9Sstevel@tonic-gate 
28917c478bd9Sstevel@tonic-gate 	/*
28927c478bd9Sstevel@tonic-gate 	 * Now that we and SS are done handling the card insertion
28937c478bd9Sstevel@tonic-gate 	 *	semantics, go through each client on this socket and set
28947c478bd9Sstevel@tonic-gate 	 *	the CS_EVENT_CARD_INSERTION event in each client's event
28957c478bd9Sstevel@tonic-gate 	 *	field.  We do this here instead of in cs_event so that
28967c478bd9Sstevel@tonic-gate 	 *	when a client gets a CS_EVENT_CARD_INSERTION event, the
28977c478bd9Sstevel@tonic-gate 	 *	card insertion and ready processing has already been done
28987c478bd9Sstevel@tonic-gate 	 *	and SocketServices has had a chance to create a dip for
28997c478bd9Sstevel@tonic-gate 	 *	the card in this socket.
29007c478bd9Sstevel@tonic-gate 	 */
29017c478bd9Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
29027c478bd9Sstevel@tonic-gate 	    client = sp->client_list;
29037c478bd9Sstevel@tonic-gate 	    while (client) {
29047c478bd9Sstevel@tonic-gate 		client->events |= (CS_EVENT_CARD_INSERTION &
29057c478bd9Sstevel@tonic-gate 				(client->event_mask | client->global_mask));
29067c478bd9Sstevel@tonic-gate 		client = client->next;
29077c478bd9Sstevel@tonic-gate 	    } /* while (client) */
29087c478bd9Sstevel@tonic-gate 
29097c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
29107c478bd9Sstevel@tonic-gate 
29117c478bd9Sstevel@tonic-gate 	} /* if (CS_EVENT_SS_UPDATED) */
29127c478bd9Sstevel@tonic-gate 
29137c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
29147c478bd9Sstevel@tonic-gate }
29157c478bd9Sstevel@tonic-gate 
29167c478bd9Sstevel@tonic-gate /*
29177c478bd9Sstevel@tonic-gate  * cs_card_removal - handle card removal events
29187c478bd9Sstevel@tonic-gate  *
29197c478bd9Sstevel@tonic-gate  * Destroy the CIS.
29207c478bd9Sstevel@tonic-gate  *
29217c478bd9Sstevel@tonic-gate  *    calling:	sp - pointer to socket structure
29227c478bd9Sstevel@tonic-gate  *
29237c478bd9Sstevel@tonic-gate  */
29247c478bd9Sstevel@tonic-gate static int
cs_card_removal(cs_socket_t * sp)29257c478bd9Sstevel@tonic-gate cs_card_removal(cs_socket_t *sp)
29267c478bd9Sstevel@tonic-gate {
29277c478bd9Sstevel@tonic-gate 	set_socket_t set_socket;
29287c478bd9Sstevel@tonic-gate 	int ret;
29297c478bd9Sstevel@tonic-gate 
29307c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
29317c478bd9Sstevel@tonic-gate 	if (cs_debug > 0) {
29327c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_card_removal: socket %d\n", sp->socket_num);
29337c478bd9Sstevel@tonic-gate 	}
29347c478bd9Sstevel@tonic-gate #endif
29357c478bd9Sstevel@tonic-gate 
29367c478bd9Sstevel@tonic-gate 	/*
29377c478bd9Sstevel@tonic-gate 	 * Remove any pending card ready timer
29387c478bd9Sstevel@tonic-gate 	 */
29397c478bd9Sstevel@tonic-gate 	UNTIMEOUT(sp->rdybsy_tmo_id);
29407c478bd9Sstevel@tonic-gate 
29417c478bd9Sstevel@tonic-gate 	/*
29427c478bd9Sstevel@tonic-gate 	 * Clear various flags so that everyone else knows that there's
29437c478bd9Sstevel@tonic-gate 	 *	nothing on this socket anymore.  Note that we clear the
29447c478bd9Sstevel@tonic-gate 	 *	SOCKET_CARD_INSERTED and SOCKET_IS_IO flags in the
29457c478bd9Sstevel@tonic-gate 	 *	ss_to_cs_events event mapping function.
29467c478bd9Sstevel@tonic-gate 	 */
29477c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
29487c478bd9Sstevel@tonic-gate 	sp->thread_state &= ~(SOCKET_WAIT_FOR_READY | SOCKET_RESET_TIMER);
29497c478bd9Sstevel@tonic-gate 
29507c478bd9Sstevel@tonic-gate 	/*
29517c478bd9Sstevel@tonic-gate 	 * Turn off socket power and set the socket back to memory mode.
29527c478bd9Sstevel@tonic-gate 	 * Disable all socket events except for CARD_INSERTION events.
29537c478bd9Sstevel@tonic-gate 	 */
29547c478bd9Sstevel@tonic-gate 	sp->event_mask = CS_EVENT_CARD_INSERTION;
29557c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
29567c478bd9Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
29577c478bd9Sstevel@tonic-gate 	set_socket.SCIntMask = SBM_CD;
29587c478bd9Sstevel@tonic-gate 	set_socket.IREQRouting = 0;
29597c478bd9Sstevel@tonic-gate 	set_socket.IFType = IF_MEMORY;
29607c478bd9Sstevel@tonic-gate 	set_socket.CtlInd = 0; /* turn off controls and indicators */
29617c478bd9Sstevel@tonic-gate 	set_socket.State = (unsigned)~0;	/* clear latched state bits */
29627c478bd9Sstevel@tonic-gate 
29637c478bd9Sstevel@tonic-gate 	(void) cs_convert_powerlevel(sp->socket_num, 0, VCC,
29647c478bd9Sstevel@tonic-gate 					&set_socket.VccLevel);
29657c478bd9Sstevel@tonic-gate 	(void) cs_convert_powerlevel(sp->socket_num, 0, VPP1,
29667c478bd9Sstevel@tonic-gate 					&set_socket.Vpp1Level);
29677c478bd9Sstevel@tonic-gate 	(void) cs_convert_powerlevel(sp->socket_num, 0, VPP2,
29687c478bd9Sstevel@tonic-gate 					&set_socket.Vpp2Level);
29697c478bd9Sstevel@tonic-gate 
29707c478bd9Sstevel@tonic-gate 	if ((ret = SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
29717c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT,
29727c478bd9Sstevel@tonic-gate 		"cs_card_removal: socket %d SS_SetSocket failure %d\n",
29737c478bd9Sstevel@tonic-gate 				sp->socket_num, ret);
29747c478bd9Sstevel@tonic-gate 	    return (ret);
29757c478bd9Sstevel@tonic-gate 	}
29767c478bd9Sstevel@tonic-gate 
29777c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
29787c478bd9Sstevel@tonic-gate 	if (cs_debug > 2) {
29797c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_card_removal: socket %d "
29807c478bd9Sstevel@tonic-gate 					"calling cs_destroy_cis\n",
29817c478bd9Sstevel@tonic-gate 							sp->socket_num);
29827c478bd9Sstevel@tonic-gate 	}
29837c478bd9Sstevel@tonic-gate #endif
29847c478bd9Sstevel@tonic-gate 
29857c478bd9Sstevel@tonic-gate 	/*
29867c478bd9Sstevel@tonic-gate 	 * Destroy the CIS and tell Socket Services that we're done
29877c478bd9Sstevel@tonic-gate 	 *	handling the card removal event.
29887c478bd9Sstevel@tonic-gate 	 */
29897c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
29907c478bd9Sstevel@tonic-gate 	(void) cs_destroy_cis(sp);
29917c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
29927c478bd9Sstevel@tonic-gate 
29937c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
29947c478bd9Sstevel@tonic-gate 	if (cs_debug > 2) {
29957c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_card_removal: calling CSCardRemoved\n");
29967c478bd9Sstevel@tonic-gate 	}
29977c478bd9Sstevel@tonic-gate #endif
29987c478bd9Sstevel@tonic-gate 
29997c478bd9Sstevel@tonic-gate 	SocketServices(CSCardRemoved, sp->socket_num);
30007c478bd9Sstevel@tonic-gate 
30017c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
30027c478bd9Sstevel@tonic-gate }
30037c478bd9Sstevel@tonic-gate 
30047c478bd9Sstevel@tonic-gate /*
30057c478bd9Sstevel@tonic-gate  * ss_to_cs_events - convert Socket Services events to Card Services event
30067c478bd9Sstevel@tonic-gate  *			masks; this function will not read the PRR if the
30077c478bd9Sstevel@tonic-gate  *			socket is in IO mode; this happens in cs_event_thread
30087c478bd9Sstevel@tonic-gate  *
30097c478bd9Sstevel@tonic-gate  * This function returns a bit mask of events.
30107c478bd9Sstevel@tonic-gate  *
30117c478bd9Sstevel@tonic-gate  * Note that we do some simple hysterious on card insertion and card removal
30127c478bd9Sstevel@tonic-gate  *	events to prevent spurious insertion and removal events from being
30137c478bd9Sstevel@tonic-gate  *	propogated down the chain.
30147c478bd9Sstevel@tonic-gate  */
30157c478bd9Sstevel@tonic-gate static event_t
ss_to_cs_events(cs_socket_t * sp,event_t event)30167c478bd9Sstevel@tonic-gate ss_to_cs_events(cs_socket_t *sp, event_t event)
30177c478bd9Sstevel@tonic-gate {
30187c478bd9Sstevel@tonic-gate 	event_t revent = 0;
30197c478bd9Sstevel@tonic-gate 
30207c478bd9Sstevel@tonic-gate 	switch (event) {
30217c478bd9Sstevel@tonic-gate 	    case PCE_CARD_STATUS_CHANGE:
30227c478bd9Sstevel@tonic-gate 		revent |= CS_EVENT_STATUS_CHANGE;
30237c478bd9Sstevel@tonic-gate 		break;
30247c478bd9Sstevel@tonic-gate 	    case PCE_CARD_REMOVAL:
30257c478bd9Sstevel@tonic-gate 		if (sp->flags & SOCKET_CARD_INSERTED) {
30267c478bd9Sstevel@tonic-gate 		    sp->flags &= ~(SOCKET_CARD_INSERTED | SOCKET_IS_IO);
30277c478bd9Sstevel@tonic-gate 		    revent |= CS_EVENT_CARD_REMOVAL;
30287c478bd9Sstevel@tonic-gate 			/*
30297c478bd9Sstevel@tonic-gate 			 * If we're processing a removal event, it makes
30307c478bd9Sstevel@tonic-gate 			 *	no sense to keep any insertion or ready events,
30317c478bd9Sstevel@tonic-gate 			 *	so nuke them here.  This will not clear any
30327c478bd9Sstevel@tonic-gate 			 *	insertion events in the per-client event field.
30337c478bd9Sstevel@tonic-gate 			 */
30347c478bd9Sstevel@tonic-gate 		    sp->events &= ~(CS_EVENT_CARD_INSERTION |
30357c478bd9Sstevel@tonic-gate 				    CS_EVENT_CARD_READY |
30367c478bd9Sstevel@tonic-gate 				    CS_EVENT_READY_TIMEOUT);
30377c478bd9Sstevel@tonic-gate 
30387c478bd9Sstevel@tonic-gate 		/*
30397c478bd9Sstevel@tonic-gate 		 * We also don't need to wait for READY anymore since
30407c478bd9Sstevel@tonic-gate 		 *	it probably won't show up, or if it does, it will
30417c478bd9Sstevel@tonic-gate 		 *	be a bogus READY event as the card is sliding out
30427c478bd9Sstevel@tonic-gate 		 *	of the socket.  Since we never do a cv_wait on the
30437c478bd9Sstevel@tonic-gate 		 *	card ready timer, it's OK for that timer to either
30447c478bd9Sstevel@tonic-gate 		 *	never go off (via an UNTIMEOUT in cs_card_removal)
30457c478bd9Sstevel@tonic-gate 		 *	or to go off but not do a cv_broadcast (since the
30467c478bd9Sstevel@tonic-gate 		 *	SOCKET_WAIT_FOR_READY flag is cleared here).
30477c478bd9Sstevel@tonic-gate 		 */
30487c478bd9Sstevel@tonic-gate 		    sp->thread_state &= ~SOCKET_WAIT_FOR_READY;
30497c478bd9Sstevel@tonic-gate 
30507c478bd9Sstevel@tonic-gate 		}
30517c478bd9Sstevel@tonic-gate 		break;
30527c478bd9Sstevel@tonic-gate 	    case PCE_CARD_INSERT:
30537c478bd9Sstevel@tonic-gate 		if (!(sp->flags & SOCKET_CARD_INSERTED)) {
30547c478bd9Sstevel@tonic-gate 		    sp->flags |= SOCKET_CARD_INSERTED;
30557c478bd9Sstevel@tonic-gate 		    revent |= CS_EVENT_CARD_INSERTION;
30567c478bd9Sstevel@tonic-gate 		}
30577c478bd9Sstevel@tonic-gate 		break;
30587c478bd9Sstevel@tonic-gate 	    case PCE_CARD_READY:
30597c478bd9Sstevel@tonic-gate 		if (sp->flags & SOCKET_CARD_INSERTED)
30607c478bd9Sstevel@tonic-gate 		    revent |= CS_EVENT_CARD_READY;
30617c478bd9Sstevel@tonic-gate 		break;
30627c478bd9Sstevel@tonic-gate 	    case PCE_CARD_BATTERY_WARN:
30637c478bd9Sstevel@tonic-gate 		if (sp->flags & SOCKET_CARD_INSERTED)
30647c478bd9Sstevel@tonic-gate 		    revent |= CS_EVENT_BATTERY_LOW;
30657c478bd9Sstevel@tonic-gate 		break;
30667c478bd9Sstevel@tonic-gate 	    case PCE_CARD_BATTERY_DEAD:
30677c478bd9Sstevel@tonic-gate 		if (sp->flags & SOCKET_CARD_INSERTED)
30687c478bd9Sstevel@tonic-gate 		    revent |= CS_EVENT_BATTERY_DEAD;
30697c478bd9Sstevel@tonic-gate 		break;
30707c478bd9Sstevel@tonic-gate 	    case PCE_CARD_WRITE_PROTECT:
30717c478bd9Sstevel@tonic-gate 		if (sp->flags & SOCKET_CARD_INSERTED)
30727c478bd9Sstevel@tonic-gate 		    revent |= CS_EVENT_WRITE_PROTECT;
30737c478bd9Sstevel@tonic-gate 		break;
30747c478bd9Sstevel@tonic-gate 	    case PCE_PM_RESUME:
30757c478bd9Sstevel@tonic-gate 		revent |= CS_EVENT_PM_RESUME;
30767c478bd9Sstevel@tonic-gate 		break;
30777c478bd9Sstevel@tonic-gate 	    case PCE_PM_SUSPEND:
30787c478bd9Sstevel@tonic-gate 		revent |= CS_EVENT_PM_SUSPEND;
30797c478bd9Sstevel@tonic-gate 		break;
30807c478bd9Sstevel@tonic-gate 	    default:
30817c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "ss_to_cs_events: unknown event 0x%x\n",
30827c478bd9Sstevel@tonic-gate 								(int)event);
30837c478bd9Sstevel@tonic-gate 		break;
30847c478bd9Sstevel@tonic-gate 	} /* switch(event) */
30857c478bd9Sstevel@tonic-gate 
30867c478bd9Sstevel@tonic-gate 	return (revent);
30877c478bd9Sstevel@tonic-gate }
30887c478bd9Sstevel@tonic-gate 
30897c478bd9Sstevel@tonic-gate /*
30907c478bd9Sstevel@tonic-gate  * cs_ready_timeout - general purpose READY/BUSY and RESET timer
30917c478bd9Sstevel@tonic-gate  *
30927c478bd9Sstevel@tonic-gate  * Note that we really only expect one of the two events to be asserted when
30937c478bd9Sstevel@tonic-gate  *	we are called.  XXX - Perhaps this might be a problem later on??
30947c478bd9Sstevel@tonic-gate  *
30957c478bd9Sstevel@tonic-gate  *	There is also the problem of cv_broadcast dropping the interrupt
30967c478bd9Sstevel@tonic-gate  *	priority, even though we have our high-priority mutex held.  If
30977c478bd9Sstevel@tonic-gate  *	we hold our high-priority mutex (sp->lock) over a cv_broadcast, and
30987c478bd9Sstevel@tonic-gate  *	we get a high-priority interrupt during this time, the system will
30997c478bd9Sstevel@tonic-gate  *	deadlock or panic.  Thanks to Andy Banta for finding this out in
31007c478bd9Sstevel@tonic-gate  *	the SPC/S (stc.c) driver.
31017c478bd9Sstevel@tonic-gate  *
31027c478bd9Sstevel@tonic-gate  * This callback routine can not grab the sp->client_lock mutex or deadlock
31037c478bd9Sstevel@tonic-gate  *	will result.
31047c478bd9Sstevel@tonic-gate  */
31057c478bd9Sstevel@tonic-gate void
cs_ready_timeout(void * arg)31067c478bd9Sstevel@tonic-gate cs_ready_timeout(void *arg)
31077c478bd9Sstevel@tonic-gate {
31087c478bd9Sstevel@tonic-gate 	cs_socket_t *sp = arg;
31097c478bd9Sstevel@tonic-gate 	kcondvar_t *cvp = NULL;
31107c478bd9Sstevel@tonic-gate 
31117c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
31127c478bd9Sstevel@tonic-gate 
31137c478bd9Sstevel@tonic-gate 	if (sp->thread_state & SOCKET_RESET_TIMER) {
31147c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
31157c478bd9Sstevel@tonic-gate 	if (cs_debug > 1) {
31167c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_ready_timeout: SOCKET_RESET_TIMER socket %d\n",
31177c478bd9Sstevel@tonic-gate 							sp->socket_num);
31187c478bd9Sstevel@tonic-gate 	}
31197c478bd9Sstevel@tonic-gate #endif
31207c478bd9Sstevel@tonic-gate 
31217c478bd9Sstevel@tonic-gate 	    cvp = &sp->reset_cv;
31227c478bd9Sstevel@tonic-gate 	}
31237c478bd9Sstevel@tonic-gate 
31247c478bd9Sstevel@tonic-gate 	if (sp->thread_state & SOCKET_WAIT_FOR_READY) {
31257c478bd9Sstevel@tonic-gate 	    sp->events |= CS_EVENT_READY_TIMEOUT;
31267c478bd9Sstevel@tonic-gate 	    cvp = &sp->thread_cv;
31277c478bd9Sstevel@tonic-gate 
31287c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
31297c478bd9Sstevel@tonic-gate 	    if (cs_debug > 1) {
31307c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_ready_timeout: SOCKET_WAIT_FOR_READY "
31317c478bd9Sstevel@tonic-gate 						"socket %d\n", sp->socket_num);
31327c478bd9Sstevel@tonic-gate 	    }
31337c478bd9Sstevel@tonic-gate #endif
31347c478bd9Sstevel@tonic-gate 
31357c478bd9Sstevel@tonic-gate 	}
31367c478bd9Sstevel@tonic-gate 
31377c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
31387c478bd9Sstevel@tonic-gate 
31397c478bd9Sstevel@tonic-gate 	if (cvp)
31407c478bd9Sstevel@tonic-gate 	    cv_broadcast(cvp);
31417c478bd9Sstevel@tonic-gate }
31427c478bd9Sstevel@tonic-gate 
31437c478bd9Sstevel@tonic-gate /*
31447c478bd9Sstevel@tonic-gate  * cs_event_softintr_timeout - wrapper function to call cs_socket_event_softintr
31457c478bd9Sstevel@tonic-gate  */
31467c478bd9Sstevel@tonic-gate /* ARGSUSED */
31477c478bd9Sstevel@tonic-gate void
cs_event_softintr_timeout(void * arg)31487c478bd9Sstevel@tonic-gate cs_event_softintr_timeout(void *arg)
31497c478bd9Sstevel@tonic-gate {
31507c478bd9Sstevel@tonic-gate 
31517c478bd9Sstevel@tonic-gate 	/*
31527c478bd9Sstevel@tonic-gate 	 * If we're trying to unload this module, then don't do
31537c478bd9Sstevel@tonic-gate 	 *	anything but exit.
31547c478bd9Sstevel@tonic-gate 	 * We acquire the cs_globals.global_lock mutex here so that
31557c478bd9Sstevel@tonic-gate 	 *	we can correctly synchronize with cs_deinit when it
31567c478bd9Sstevel@tonic-gate 	 *	is telling us to shut down. XXX - is this bogus??
31577c478bd9Sstevel@tonic-gate 	 */
31587c478bd9Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
31597c478bd9Sstevel@tonic-gate 	if (!(cs_globals.init_state & GLOBAL_INIT_STATE_UNLOADING)) {
31607c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.global_lock);
31617c478bd9Sstevel@tonic-gate 	    (void) cs_socket_event_softintr(NULL);
31627c478bd9Sstevel@tonic-gate 	    cs_globals.sotfint_tmo = timeout(cs_event_softintr_timeout,
31637c478bd9Sstevel@tonic-gate 		NULL, SOFTINT_TIMEOUT_TIME);
31647c478bd9Sstevel@tonic-gate 	} else {
31657c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.global_lock);
31667c478bd9Sstevel@tonic-gate 	}
31677c478bd9Sstevel@tonic-gate }
31687c478bd9Sstevel@tonic-gate 
31697c478bd9Sstevel@tonic-gate /*
31707c478bd9Sstevel@tonic-gate  * cs_socket_event_softintr - This function just does a cv_broadcast on behalf
31717c478bd9Sstevel@tonic-gate  *				of the high-priority interrupt handler.
31727c478bd9Sstevel@tonic-gate  *
31737c478bd9Sstevel@tonic-gate  *	Note: There is no calling argument.
31747c478bd9Sstevel@tonic-gate  */
31757c478bd9Sstevel@tonic-gate /*ARGSUSED*/
31767c478bd9Sstevel@tonic-gate uint32_t
cs_socket_event_softintr(caddr_t notused)31777c478bd9Sstevel@tonic-gate cs_socket_event_softintr(caddr_t notused)
31787c478bd9Sstevel@tonic-gate {
31797c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
31807c478bd9Sstevel@tonic-gate 	uint32_t sn;
31817c478bd9Sstevel@tonic-gate 	int ret = DDI_INTR_UNCLAIMED;
31827c478bd9Sstevel@tonic-gate 
31837c478bd9Sstevel@tonic-gate 	/*
31847c478bd9Sstevel@tonic-gate 	 * If the module is on it's way out, then don't bother
31857c478bd9Sstevel@tonic-gate 	 *	to do anything else except return.
31867c478bd9Sstevel@tonic-gate 	 */
31877c478bd9Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
31887c478bd9Sstevel@tonic-gate 	if ((cs_globals.init_state & GLOBAL_INIT_STATE_UNLOADING) ||
31897c478bd9Sstevel@tonic-gate 				(cs_globals.init_state & GLOBAL_IN_SOFTINTR)) {
31907c478bd9Sstevel@tonic-gate 		mutex_exit(&cs_globals.global_lock);
31917c478bd9Sstevel@tonic-gate 
31927c478bd9Sstevel@tonic-gate 		/*
31937c478bd9Sstevel@tonic-gate 		 * Note that we return DDI_INTR_UNCLAIMED here
31947c478bd9Sstevel@tonic-gate 		 *	since we don't want to be constantly
31957c478bd9Sstevel@tonic-gate 		 *	called back.
31967c478bd9Sstevel@tonic-gate 		 */
31977c478bd9Sstevel@tonic-gate 		return (ret);
31987c478bd9Sstevel@tonic-gate 	} else {
31997c478bd9Sstevel@tonic-gate 	    cs_globals.init_state |= GLOBAL_IN_SOFTINTR;
32007c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.global_lock);
32017c478bd9Sstevel@tonic-gate 	}
32027c478bd9Sstevel@tonic-gate 
32037c478bd9Sstevel@tonic-gate 	/*
32047c478bd9Sstevel@tonic-gate 	 * Go through each socket and dispatch the appropriate events.
32057c478bd9Sstevel@tonic-gate 	 *	We have to funnel everything through this one routine because
32067c478bd9Sstevel@tonic-gate 	 *	we can't do a cv_broadcast from a high level interrupt handler
32077c478bd9Sstevel@tonic-gate 	 *	and we also can't have more than one soft interrupt handler
32087c478bd9Sstevel@tonic-gate 	 *	on a single dip and using the same handler address.
32097c478bd9Sstevel@tonic-gate 	 */
32107c478bd9Sstevel@tonic-gate 	for (sn = 0; sn < cs_globals.max_socket_num; sn++) {
32117c478bd9Sstevel@tonic-gate 	    if ((sp = cs_get_sp(sn)) != NULL) {
32127c478bd9Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_READY) {
32137c478bd9Sstevel@tonic-gate 			/*
32147c478bd9Sstevel@tonic-gate 			 * If we're being asked to unload CS, then don't bother
32157c478bd9Sstevel@tonic-gate 			 *	waking up the socket event thread handler.
32167c478bd9Sstevel@tonic-gate 			 */
32177c478bd9Sstevel@tonic-gate 		    if (!(sp->flags & SOCKET_UNLOAD_MODULE) &&
32187c478bd9Sstevel@tonic-gate 					(sp->flags & SOCKET_NEEDS_THREAD)) {
32197c478bd9Sstevel@tonic-gate 			ret = DDI_INTR_CLAIMED;
32207c478bd9Sstevel@tonic-gate 			mutex_enter(&sp->client_lock);
32217c478bd9Sstevel@tonic-gate 			cv_broadcast(&sp->thread_cv);
32227c478bd9Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
32237c478bd9Sstevel@tonic-gate 		    } /* if (SOCKET_NEEDS_THREAD) */
32247c478bd9Sstevel@tonic-gate 		} /* if (SOCKET_INIT_STATE_READY) */
32257c478bd9Sstevel@tonic-gate 	    } /* cs_get_sp */
32267c478bd9Sstevel@tonic-gate 	} /* for (sn) */
32277c478bd9Sstevel@tonic-gate 
32287c478bd9Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
32297c478bd9Sstevel@tonic-gate 	cs_globals.init_state &= ~GLOBAL_IN_SOFTINTR;
32307c478bd9Sstevel@tonic-gate 	mutex_exit(&cs_globals.global_lock);
32317c478bd9Sstevel@tonic-gate 
32327c478bd9Sstevel@tonic-gate 	return (ret);
32337c478bd9Sstevel@tonic-gate }
32347c478bd9Sstevel@tonic-gate 
32357c478bd9Sstevel@tonic-gate /*
32367c478bd9Sstevel@tonic-gate  * cs_event_thread - This is the per-socket event thread.
32377c478bd9Sstevel@tonic-gate  */
32387c478bd9Sstevel@tonic-gate static void
cs_event_thread(uint32_t sn)32397c478bd9Sstevel@tonic-gate cs_event_thread(uint32_t sn)
32407c478bd9Sstevel@tonic-gate {
32417c478bd9Sstevel@tonic-gate 	cs_socket_t	*sp;
32427c478bd9Sstevel@tonic-gate 	client_t	*client;
32437c478bd9Sstevel@tonic-gate 	client_types_t	*ct;
32447c478bd9Sstevel@tonic-gate 
32457c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(sn)) == NULL)
32467c478bd9Sstevel@tonic-gate 	    return;
32477c478bd9Sstevel@tonic-gate 
32487c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
32497c478bd9Sstevel@tonic-gate 	if (cs_debug > 1) {
32507c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_event_thread: socket %d thread started\n",
32517c478bd9Sstevel@tonic-gate 								sp->socket_num);
32527c478bd9Sstevel@tonic-gate 	}
32537c478bd9Sstevel@tonic-gate #endif
32547c478bd9Sstevel@tonic-gate 
32557c478bd9Sstevel@tonic-gate 	CALLB_CPR_INIT(&sp->cprinfo_cs, &sp->client_lock,
32567c478bd9Sstevel@tonic-gate 					callb_generic_cpr, "cs_event_thread");
32577c478bd9Sstevel@tonic-gate 
32587c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->client_lock);
32597c478bd9Sstevel@tonic-gate 
32607c478bd9Sstevel@tonic-gate 	for (;;) {
32617c478bd9Sstevel@tonic-gate 
32627c478bd9Sstevel@tonic-gate 	    CALLB_CPR_SAFE_BEGIN(&sp->cprinfo_cs);
32637c478bd9Sstevel@tonic-gate 	    cv_wait(&sp->thread_cv, &sp->client_lock);
32647c478bd9Sstevel@tonic-gate 	    CALLB_CPR_SAFE_END(&sp->cprinfo_cs, &sp->client_lock);
32657c478bd9Sstevel@tonic-gate 
32667c478bd9Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
32677c478bd9Sstevel@tonic-gate 	    sp->flags &= ~SOCKET_NEEDS_THREAD;
32687c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
32697c478bd9Sstevel@tonic-gate 
32707c478bd9Sstevel@tonic-gate 	/*
32717c478bd9Sstevel@tonic-gate 	 * Check to see if there are any special thread operations that
32727c478bd9Sstevel@tonic-gate 	 *	we are being asked to perform.
32737c478bd9Sstevel@tonic-gate 	 */
32747c478bd9Sstevel@tonic-gate 	    if (sp->thread_state & SOCKET_THREAD_EXIT) {
32757c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
32767c478bd9Sstevel@tonic-gate 		if (cs_debug > 1) {
32777c478bd9Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_event_thread: socket %d "
32787c478bd9Sstevel@tonic-gate 							"SOCKET_THREAD_EXIT\n",
32797c478bd9Sstevel@tonic-gate 							sp->socket_num);
32807c478bd9Sstevel@tonic-gate 		}
32817c478bd9Sstevel@tonic-gate #endif
32827c478bd9Sstevel@tonic-gate 		CALLB_CPR_EXIT(&sp->cprinfo_cs);
32837c478bd9Sstevel@tonic-gate 		cv_broadcast(&sp->caller_cv);	/* wakes up cs_deinit */
32847c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->client_lock);
32857c478bd9Sstevel@tonic-gate 		return;
32867c478bd9Sstevel@tonic-gate 	    } /* if (SOCKET_THREAD_EXIT) */
32877c478bd9Sstevel@tonic-gate 
32887c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
32897c478bd9Sstevel@tonic-gate 	    if (cs_debug > 1) {
32907c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_event_thread: socket %d sp->events 0x%x\n",
32917c478bd9Sstevel@tonic-gate 							sp->socket_num,
32927c478bd9Sstevel@tonic-gate 							(int)sp->events);
32937c478bd9Sstevel@tonic-gate 	    }
32947c478bd9Sstevel@tonic-gate #endif
32957c478bd9Sstevel@tonic-gate 
32967c478bd9Sstevel@tonic-gate 	/*
32977c478bd9Sstevel@tonic-gate 	 * Handle CS_EVENT_CARD_INSERTION events
32987c478bd9Sstevel@tonic-gate 	 */
32997c478bd9Sstevel@tonic-gate 	    if (sp->events & CS_EVENT_CARD_INSERTION) {
33007c478bd9Sstevel@tonic-gate 		mutex_enter(&sp->lock);
33017c478bd9Sstevel@tonic-gate 		sp->events &= ~CS_EVENT_CARD_INSERTION;
33027c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->lock);
33037c478bd9Sstevel@tonic-gate 
33047c478bd9Sstevel@tonic-gate 		/*
33057c478bd9Sstevel@tonic-gate 		 * If we have a pending CS_EVENT_CARD_REMOVAL event it
33067c478bd9Sstevel@tonic-gate 		 *	means that we likely got CD line bounce on the
33077c478bd9Sstevel@tonic-gate 		 *	insertion, so terminate this processing.
33087c478bd9Sstevel@tonic-gate 		 */
33097c478bd9Sstevel@tonic-gate 		if ((sp->events & CS_EVENT_CARD_REMOVAL) == 0) {
33107c478bd9Sstevel@tonic-gate 		    (void) cs_card_insertion(sp, CS_EVENT_CARD_INSERTION);
33117c478bd9Sstevel@tonic-gate 		}
33127c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
33137c478bd9Sstevel@tonic-gate 		else if (cs_debug > 0) {
33147c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_event_thread: socket %d "
33157c478bd9Sstevel@tonic-gate 					"CS_EVENT_CARD_REMOVAL event "
33167c478bd9Sstevel@tonic-gate 					"terminating "
33177c478bd9Sstevel@tonic-gate 					"CS_EVENT_CARD_INSERTION "
33187c478bd9Sstevel@tonic-gate 					"processing\n", sp->socket_num);
33197c478bd9Sstevel@tonic-gate 		    }
33207c478bd9Sstevel@tonic-gate #endif
33217c478bd9Sstevel@tonic-gate 	} /* if (CS_EVENT_CARD_INSERTION) */
33227c478bd9Sstevel@tonic-gate 
33237c478bd9Sstevel@tonic-gate 	/*
33247c478bd9Sstevel@tonic-gate 	 * Handle CS_EVENT_CARD_READY and CS_EVENT_READY_TIMEOUT events
33257c478bd9Sstevel@tonic-gate 	 */
33267c478bd9Sstevel@tonic-gate 	    if (sp->events & (CS_EVENT_CARD_READY | CS_EVENT_READY_TIMEOUT)) {
33277c478bd9Sstevel@tonic-gate 		mutex_enter(&sp->lock);
33287c478bd9Sstevel@tonic-gate 		sp->events &= ~(CS_EVENT_CARD_READY | CS_EVENT_READY_TIMEOUT);
33297c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->lock);
33307c478bd9Sstevel@tonic-gate 		if (sp->thread_state & SOCKET_WAIT_FOR_READY) {
33317c478bd9Sstevel@tonic-gate 		    mutex_enter(&sp->lock);
33327c478bd9Sstevel@tonic-gate 		    sp->thread_state &= ~SOCKET_WAIT_FOR_READY;
33337c478bd9Sstevel@tonic-gate 		    mutex_exit(&sp->lock);
33347c478bd9Sstevel@tonic-gate 		    (void) cs_card_insertion(sp, CS_EVENT_CARD_READY);
33357c478bd9Sstevel@tonic-gate 		} /* if (SOCKET_WAIT_FOR_READY) */
33367c478bd9Sstevel@tonic-gate 	    } /* if (CS_EVENT_CARD_READY) */
33377c478bd9Sstevel@tonic-gate 
33387c478bd9Sstevel@tonic-gate 	/*
33397c478bd9Sstevel@tonic-gate 	 * Handle CS_EVENT_SS_UPDATED events
33407c478bd9Sstevel@tonic-gate 	 */
33417c478bd9Sstevel@tonic-gate 	    if (sp->events & CS_EVENT_SS_UPDATED) {
33427c478bd9Sstevel@tonic-gate 		mutex_enter(&sp->lock);
33437c478bd9Sstevel@tonic-gate 		sp->events &= ~CS_EVENT_SS_UPDATED;
33447c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->lock);
33457c478bd9Sstevel@tonic-gate 		(void) cs_card_insertion(sp, CS_EVENT_SS_UPDATED);
33467c478bd9Sstevel@tonic-gate 	    } /* if (CS_EVENT_SS_UPDATED) */
33477c478bd9Sstevel@tonic-gate 
33487c478bd9Sstevel@tonic-gate 	/*
33497c478bd9Sstevel@tonic-gate 	 * Handle CS_EVENT_STATUS_CHANGE events
33507c478bd9Sstevel@tonic-gate 	 */
33517c478bd9Sstevel@tonic-gate 	    if (sp->events & CS_EVENT_STATUS_CHANGE) {
33527c478bd9Sstevel@tonic-gate 		event_t revent;
33537c478bd9Sstevel@tonic-gate 
33547c478bd9Sstevel@tonic-gate 		mutex_enter(&sp->cis_lock);
33557c478bd9Sstevel@tonic-gate 		mutex_enter(&sp->lock);
33567c478bd9Sstevel@tonic-gate 		sp->events &= ~CS_EVENT_STATUS_CHANGE;
33577c478bd9Sstevel@tonic-gate 
33587c478bd9Sstevel@tonic-gate 		/*
33597c478bd9Sstevel@tonic-gate 		 * Go through each client and add any events that we saw to
33607c478bd9Sstevel@tonic-gate 		 *	the client's event list if the client has that event
33617c478bd9Sstevel@tonic-gate 		 *	enabled in their event mask.
33627c478bd9Sstevel@tonic-gate 		 * Remove any events that may be pending for this client if
33637c478bd9Sstevel@tonic-gate 		 *	the client's event mask says that the client doesn't
33647c478bd9Sstevel@tonic-gate 		 *	want to see those events anymore. This handles the
33657c478bd9Sstevel@tonic-gate 		 *	case where the client had an event enabled in it's
33667c478bd9Sstevel@tonic-gate 		 *	event mask when the event came in but between that
33677c478bd9Sstevel@tonic-gate 		 *	time and the time we're called here the client
33687c478bd9Sstevel@tonic-gate 		 *	disabled that event.
33697c478bd9Sstevel@tonic-gate 		 */
33707c478bd9Sstevel@tonic-gate 		client = sp->client_list;
33717c478bd9Sstevel@tonic-gate 
33727c478bd9Sstevel@tonic-gate 		while (client) {
33737c478bd9Sstevel@tonic-gate 			/*
33747c478bd9Sstevel@tonic-gate 			 * Read the PRR (if it exists) and check for any events.
33757c478bd9Sstevel@tonic-gate 			 * The PRR will only be read if the socket is in IO
33767c478bd9Sstevel@tonic-gate 			 * mode, if there is a card in the socket, and if there
33777c478bd9Sstevel@tonic-gate 			 * is a PRR.
33787c478bd9Sstevel@tonic-gate 			 * We don't have to clear revent before we call the
33797c478bd9Sstevel@tonic-gate 			 * cs_read_event_status function since it will
33807c478bd9Sstevel@tonic-gate 			 * clear it before adding any current events.
33817c478bd9Sstevel@tonic-gate 			 */
33827c478bd9Sstevel@tonic-gate 		    if (client->flags & CLIENT_CARD_INSERTED) {
33837c478bd9Sstevel@tonic-gate 			(void) cs_read_event_status(sp, client,
33847c478bd9Sstevel@tonic-gate 							&revent, NULL, 0);
33857c478bd9Sstevel@tonic-gate 
33867c478bd9Sstevel@tonic-gate 			client->events = ((client->events | revent) &
33877c478bd9Sstevel@tonic-gate 						(client->event_mask |
33887c478bd9Sstevel@tonic-gate 							client->global_mask));
33897c478bd9Sstevel@tonic-gate 		    } /* CLIENT_CARD_INSERTED */
33907c478bd9Sstevel@tonic-gate 		    client = client->next;
33917c478bd9Sstevel@tonic-gate 		} /* while (client) */
33927c478bd9Sstevel@tonic-gate 
33937c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->lock);
33947c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
33957c478bd9Sstevel@tonic-gate 	    } /* if (CS_EVENT_STATUS_CHANGE) */
33967c478bd9Sstevel@tonic-gate 
33977c478bd9Sstevel@tonic-gate 	/*
33987c478bd9Sstevel@tonic-gate 	 * We want to maintain the required event dispatching order as
33997c478bd9Sstevel@tonic-gate 	 *	specified in the PCMCIA spec, so we cycle through all
34007c478bd9Sstevel@tonic-gate 	 *	clients on this socket to make sure that they are
34017c478bd9Sstevel@tonic-gate 	 *	notified in the correct order.
34027c478bd9Sstevel@tonic-gate 	 */
34037c478bd9Sstevel@tonic-gate 	    ct = &client_types[0];
34047c478bd9Sstevel@tonic-gate 	    while (ct) {
34057c478bd9Sstevel@tonic-gate 		/*
34067c478bd9Sstevel@tonic-gate 		 * Point to the head of the client list for this socket, and go
34077c478bd9Sstevel@tonic-gate 		 *	through each client to set up the client events as well
34087c478bd9Sstevel@tonic-gate 		 *	as call the client's event handler directly if we have
34097c478bd9Sstevel@tonic-gate 		 *	a high priority event that we need to tell the client
34107c478bd9Sstevel@tonic-gate 		 *	about.
34117c478bd9Sstevel@tonic-gate 		 */
34127c478bd9Sstevel@tonic-gate 		client = sp->client_list;
34137c478bd9Sstevel@tonic-gate 
34147c478bd9Sstevel@tonic-gate 		if (ct->order & CLIENT_EVENTS_LIFO) {
34157c478bd9Sstevel@tonic-gate 		    client_t *clp = NULL;
34167c478bd9Sstevel@tonic-gate 
34177c478bd9Sstevel@tonic-gate 		    while (client) {
34187c478bd9Sstevel@tonic-gate 			clp = client;
34197c478bd9Sstevel@tonic-gate 			client = client->next;
34207c478bd9Sstevel@tonic-gate 		    }
34217c478bd9Sstevel@tonic-gate 		    client = clp;
34227c478bd9Sstevel@tonic-gate 		}
34237c478bd9Sstevel@tonic-gate 
34247c478bd9Sstevel@tonic-gate 		while (client) {
34257c478bd9Sstevel@tonic-gate 		    if (client->flags & ct->type) {
34267c478bd9Sstevel@tonic-gate 			    uint32_t bit = 0;
34277c478bd9Sstevel@tonic-gate 			    event_t event;
34287c478bd9Sstevel@tonic-gate 
34297c478bd9Sstevel@tonic-gate 			while (client->events) {
34307c478bd9Sstevel@tonic-gate 
34317c478bd9Sstevel@tonic-gate 			    switch (event = CS_BIT_GET(client->events, bit)) {
34327c478bd9Sstevel@tonic-gate 				/*
34337c478bd9Sstevel@tonic-gate 				 * Clients always receive registration complete
34347c478bd9Sstevel@tonic-gate 				 *	events, even if there is no card of
34357c478bd9Sstevel@tonic-gate 				 *	their type currently in the socket.
34367c478bd9Sstevel@tonic-gate 				 */
34377c478bd9Sstevel@tonic-gate 				case CS_EVENT_REGISTRATION_COMPLETE:
34387c478bd9Sstevel@tonic-gate 				    CLIENT_EVENT_CALLBACK(client, event,
34397c478bd9Sstevel@tonic-gate 							CS_EVENT_PRI_LOW);
34407c478bd9Sstevel@tonic-gate 				    break;
34417c478bd9Sstevel@tonic-gate 				/*
34427c478bd9Sstevel@tonic-gate 				 * The client only gets a card insertion event
34437c478bd9Sstevel@tonic-gate 				 *	if there is currently a card in the
34447c478bd9Sstevel@tonic-gate 				 *	socket that the client can control.
34457c478bd9Sstevel@tonic-gate 				 *	The nexus determines this. We also
34467c478bd9Sstevel@tonic-gate 				 *	prevent the client from receiving
34477c478bd9Sstevel@tonic-gate 				 *	multiple CS_EVENT_CARD_INSERTION
34487c478bd9Sstevel@tonic-gate 				 *	events without receiving intervening
34497c478bd9Sstevel@tonic-gate 				 *	CS_EVENT_CARD_REMOVAL events.
34507c478bd9Sstevel@tonic-gate 				 */
34517c478bd9Sstevel@tonic-gate 				case CS_EVENT_CARD_INSERTION:
34527c478bd9Sstevel@tonic-gate 				    if (cs_card_for_client(client)) {
34537c478bd9Sstevel@tonic-gate 					int send_insertion;
34547c478bd9Sstevel@tonic-gate 
34557c478bd9Sstevel@tonic-gate 					mutex_enter(&sp->lock);
34567c478bd9Sstevel@tonic-gate 					send_insertion = client->flags;
34577c478bd9Sstevel@tonic-gate 					client->flags |=
34587c478bd9Sstevel@tonic-gate 						(CLIENT_CARD_INSERTED |
34597c478bd9Sstevel@tonic-gate 						CLIENT_SENT_INSERTION);
34607c478bd9Sstevel@tonic-gate 					mutex_exit(&sp->lock);
34617c478bd9Sstevel@tonic-gate 					if (!(send_insertion &
34627c478bd9Sstevel@tonic-gate 						    CLIENT_SENT_INSERTION)) {
34637c478bd9Sstevel@tonic-gate 					    CLIENT_EVENT_CALLBACK(client,
34647c478bd9Sstevel@tonic-gate 						event, CS_EVENT_PRI_LOW);
34657c478bd9Sstevel@tonic-gate 					} /* if (!CLIENT_SENT_INSERTION) */
34667c478bd9Sstevel@tonic-gate 				    }
34677c478bd9Sstevel@tonic-gate 				    break;
34687c478bd9Sstevel@tonic-gate 				/*
34697c478bd9Sstevel@tonic-gate 				 * The CS_EVENT_CARD_REMOVAL_LOWP is a low
34707c478bd9Sstevel@tonic-gate 				 *	priority CS_EVENT_CARD_REMOVAL event.
34717c478bd9Sstevel@tonic-gate 				 */
34727c478bd9Sstevel@tonic-gate 				case CS_EVENT_CARD_REMOVAL_LOWP:
34737c478bd9Sstevel@tonic-gate 				    mutex_enter(&sp->lock);
34747c478bd9Sstevel@tonic-gate 				    client->flags &= ~CLIENT_SENT_INSERTION;
34757c478bd9Sstevel@tonic-gate 				    mutex_exit(&sp->lock);
34767c478bd9Sstevel@tonic-gate 				    CLIENT_EVENT_CALLBACK(client,
34777c478bd9Sstevel@tonic-gate 							CS_EVENT_CARD_REMOVAL,
34787c478bd9Sstevel@tonic-gate 							CS_EVENT_PRI_LOW);
34797c478bd9Sstevel@tonic-gate 				    break;
34807c478bd9Sstevel@tonic-gate 				/*
34817c478bd9Sstevel@tonic-gate 				 * The hardware card removal events are handed
34827c478bd9Sstevel@tonic-gate 				 *	to the client in cs_event at high
34837c478bd9Sstevel@tonic-gate 				 *	priority interrupt time; this card
34847c478bd9Sstevel@tonic-gate 				 *	removal event is a software-generated
34857c478bd9Sstevel@tonic-gate 				 *	event.
34867c478bd9Sstevel@tonic-gate 				 */
34877c478bd9Sstevel@tonic-gate 				case CS_EVENT_CARD_REMOVAL:
34887c478bd9Sstevel@tonic-gate 				    if (client->flags & CLIENT_CARD_INSERTED) {
34897c478bd9Sstevel@tonic-gate 					mutex_enter(&sp->lock);
34907c478bd9Sstevel@tonic-gate 					client->flags &=
34917c478bd9Sstevel@tonic-gate 						~(CLIENT_CARD_INSERTED |
34927c478bd9Sstevel@tonic-gate 						CLIENT_SENT_INSERTION);
34937c478bd9Sstevel@tonic-gate 					mutex_exit(&sp->lock);
34947c478bd9Sstevel@tonic-gate 					CLIENT_EVENT_CALLBACK(client, event,
34957c478bd9Sstevel@tonic-gate 							CS_EVENT_PRI_LOW);
34967c478bd9Sstevel@tonic-gate 				    }
34977c478bd9Sstevel@tonic-gate 				    break;
34987c478bd9Sstevel@tonic-gate 				/*
34997c478bd9Sstevel@tonic-gate 				 * Write protect events require the info field
35007c478bd9Sstevel@tonic-gate 				 *	of the client's event callback args to
35017c478bd9Sstevel@tonic-gate 				 *	be zero if the card is not write
35027c478bd9Sstevel@tonic-gate 				 *	protected and one if it is.
35037c478bd9Sstevel@tonic-gate 				 */
35047c478bd9Sstevel@tonic-gate 				case CS_EVENT_WRITE_PROTECT:
35057c478bd9Sstevel@tonic-gate 				    if (client->flags & CLIENT_CARD_INSERTED) {
35067c478bd9Sstevel@tonic-gate 					get_ss_status_t gs;
35077c478bd9Sstevel@tonic-gate 
35087c478bd9Sstevel@tonic-gate 					mutex_enter(&sp->cis_lock);
35097c478bd9Sstevel@tonic-gate 					mutex_enter(&sp->lock);
35107c478bd9Sstevel@tonic-gate 					(void) cs_read_event_status(sp, client,
35117c478bd9Sstevel@tonic-gate 									NULL,
35127c478bd9Sstevel@tonic-gate 									&gs, 0);
35137c478bd9Sstevel@tonic-gate 					if (gs.CardState & SBM_WP) {
35147c478bd9Sstevel@tonic-gate 					    client->event_callback_args.info =
35157c478bd9Sstevel@tonic-gate 						(void *)
35167c478bd9Sstevel@tonic-gate 						CS_EVENT_WRITE_PROTECT_WPON;
35177c478bd9Sstevel@tonic-gate 					} else {
35187c478bd9Sstevel@tonic-gate 					    client->event_callback_args.info =
35197c478bd9Sstevel@tonic-gate 						(void *)
35207c478bd9Sstevel@tonic-gate 						CS_EVENT_WRITE_PROTECT_WPOFF;
35217c478bd9Sstevel@tonic-gate 					}
35227c478bd9Sstevel@tonic-gate 					mutex_exit(&sp->lock);
35237c478bd9Sstevel@tonic-gate 					mutex_exit(&sp->cis_lock);
35247c478bd9Sstevel@tonic-gate 					CLIENT_EVENT_CALLBACK(client, event,
35257c478bd9Sstevel@tonic-gate 							CS_EVENT_PRI_LOW);
35267c478bd9Sstevel@tonic-gate 				    } /* CLIENT_CARD_INSERTED */
35277c478bd9Sstevel@tonic-gate 				    break;
35287c478bd9Sstevel@tonic-gate 				case CS_EVENT_CLIENT_INFO:
35297c478bd9Sstevel@tonic-gate 				    CLIENT_EVENT_CALLBACK(client, event,
35307c478bd9Sstevel@tonic-gate 							CS_EVENT_PRI_LOW);
35317c478bd9Sstevel@tonic-gate 				    break;
35327c478bd9Sstevel@tonic-gate 				case 0:
35337c478bd9Sstevel@tonic-gate 				    break;
35347c478bd9Sstevel@tonic-gate 				default:
35357c478bd9Sstevel@tonic-gate 				    if (client->flags & CLIENT_CARD_INSERTED) {
35367c478bd9Sstevel@tonic-gate 					CLIENT_EVENT_CALLBACK(client, event,
35377c478bd9Sstevel@tonic-gate 							CS_EVENT_PRI_LOW);
35387c478bd9Sstevel@tonic-gate 				    }
35397c478bd9Sstevel@tonic-gate 				    break;
35407c478bd9Sstevel@tonic-gate 			    } /* switch */
35417c478bd9Sstevel@tonic-gate 			    mutex_enter(&sp->lock);
35427c478bd9Sstevel@tonic-gate 			    CS_BIT_CLEAR(client->events, bit);
35437c478bd9Sstevel@tonic-gate 			    mutex_exit(&sp->lock);
35447c478bd9Sstevel@tonic-gate 			    bit++;
35457c478bd9Sstevel@tonic-gate 			} /* while (client->events) */
35467c478bd9Sstevel@tonic-gate 		    } /* if (ct->type) */
35477c478bd9Sstevel@tonic-gate 		    if (ct->order & CLIENT_EVENTS_LIFO) {
35487c478bd9Sstevel@tonic-gate 			client = client->prev;
35497c478bd9Sstevel@tonic-gate 		    } else {
35507c478bd9Sstevel@tonic-gate 			client = client->next;
35517c478bd9Sstevel@tonic-gate 		    }
35527c478bd9Sstevel@tonic-gate 		} /* while (client) */
35537c478bd9Sstevel@tonic-gate 
35547c478bd9Sstevel@tonic-gate 		ct = ct->next;
35557c478bd9Sstevel@tonic-gate 	    } /* while (ct) */
35567c478bd9Sstevel@tonic-gate 
35577c478bd9Sstevel@tonic-gate 	/*
35587c478bd9Sstevel@tonic-gate 	 * Handle CS_EVENT_CARD_REMOVAL events
35597c478bd9Sstevel@tonic-gate 	 */
35607c478bd9Sstevel@tonic-gate 	    if (sp->events & CS_EVENT_CARD_REMOVAL) {
35617c478bd9Sstevel@tonic-gate 		mutex_enter(&sp->lock);
35627c478bd9Sstevel@tonic-gate 		sp->events &= ~CS_EVENT_CARD_REMOVAL;
35637c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->lock);
35647c478bd9Sstevel@tonic-gate 		(void) cs_card_removal(sp);
35657c478bd9Sstevel@tonic-gate 	    } /* if (CS_EVENT_CARD_REMOVAL) */
35667c478bd9Sstevel@tonic-gate 
35677c478bd9Sstevel@tonic-gate 		/*
35687c478bd9Sstevel@tonic-gate 		 * If someone is waiting for us to complete, signal them now.
35697c478bd9Sstevel@tonic-gate 		 */
35707c478bd9Sstevel@tonic-gate 	    if (sp->thread_state & SOCKET_WAIT_SYNC) {
35717c478bd9Sstevel@tonic-gate 		mutex_enter(&sp->lock);
35727c478bd9Sstevel@tonic-gate 		sp->thread_state &= ~SOCKET_WAIT_SYNC;
35737c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->lock);
35747c478bd9Sstevel@tonic-gate 		cv_broadcast(&sp->caller_cv);
35757c478bd9Sstevel@tonic-gate 	    } /* SOCKET_WAIT_SYNC */
35767c478bd9Sstevel@tonic-gate 
35777c478bd9Sstevel@tonic-gate 	} /* for (;;) */
35787c478bd9Sstevel@tonic-gate }
35797c478bd9Sstevel@tonic-gate 
35807c478bd9Sstevel@tonic-gate /*
35817c478bd9Sstevel@tonic-gate  * cs_card_for_client - checks to see if a card that the client can control
35827c478bd9Sstevel@tonic-gate  *			is currently inserted in the socket.  Socket Services
35837c478bd9Sstevel@tonic-gate  *			has to tell us if this is the case.
35847c478bd9Sstevel@tonic-gate  */
35857c478bd9Sstevel@tonic-gate static int
cs_card_for_client(client_t * client)35867c478bd9Sstevel@tonic-gate cs_card_for_client(client_t *client)
35877c478bd9Sstevel@tonic-gate {
35887c478bd9Sstevel@tonic-gate 
35897c478bd9Sstevel@tonic-gate 	/*
35907c478bd9Sstevel@tonic-gate 	 * If the client has set the CS_EVENT_ALL_CLIENTS it means that they
35917c478bd9Sstevel@tonic-gate 	 *	want to get all events for all clients, irrespective of
35927c478bd9Sstevel@tonic-gate 	 *	whether or not there is a card in the socket.  Such clients
35937c478bd9Sstevel@tonic-gate 	 *	have to be very careful if they touch the card hardware in
35947c478bd9Sstevel@tonic-gate 	 *	any way to prevent causing problems for other clients on the
35957c478bd9Sstevel@tonic-gate 	 *	same socket.  This flag will typically only be set by the
35967c478bd9Sstevel@tonic-gate 	 *	"super-client" or CSI types of clients that wish to get
35977c478bd9Sstevel@tonic-gate 	 *	information on other clients or cards in the system.
35987c478bd9Sstevel@tonic-gate 	 * Note that the CS_EVENT_ALL_CLIENTS must be set in either the
35997c478bd9Sstevel@tonic-gate 	 *	client's global event mask or client event mask.
36007c478bd9Sstevel@tonic-gate 	 * The client must also have registered as a "super-client" or as a
36017c478bd9Sstevel@tonic-gate 	 *	CSI client for this socket.
36027c478bd9Sstevel@tonic-gate 	 */
36037c478bd9Sstevel@tonic-gate 	if ((client->flags & (CLIENT_SUPER_CLIENT | CLIENT_CSI_CLIENT)) &&
36047c478bd9Sstevel@tonic-gate 			((client->global_mask | client->event_mask) &
36057c478bd9Sstevel@tonic-gate 							CS_EVENT_ALL_CLIENTS))
36067c478bd9Sstevel@tonic-gate 	    return (1);
36077c478bd9Sstevel@tonic-gate 
36087c478bd9Sstevel@tonic-gate 	/*
36097c478bd9Sstevel@tonic-gate 	 * Look for the PCM_DEV_ACTIVE property on this client's dip; if
36107c478bd9Sstevel@tonic-gate 	 *	it's found, it means that this client can control the card
36117c478bd9Sstevel@tonic-gate 	 *	that is currently in the socket.  This is a boolean
36127c478bd9Sstevel@tonic-gate 	 *	property managed by Socket Services.
36137c478bd9Sstevel@tonic-gate 	 */
36147c478bd9Sstevel@tonic-gate 	if (ddi_getprop(DDI_DEV_T_ANY, client->dip,    (DDI_PROP_CANSLEEP |
36157c478bd9Sstevel@tonic-gate 							DDI_PROP_NOTPROM),
3616*c48c3045SToomas Soome 							PCM_DEV_ACTIVE, 0)) {
36177c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
36187c478bd9Sstevel@tonic-gate 	    if (cs_debug > 1) {
36197c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_card_for_client: client handle 0x%x "
36207c478bd9Sstevel@tonic-gate 					"driver [%s] says %s found\n",
36217c478bd9Sstevel@tonic-gate 						(int)client->client_handle,
36227c478bd9Sstevel@tonic-gate 						client->driver_name,
36237c478bd9Sstevel@tonic-gate 						PCM_DEV_ACTIVE);
36247c478bd9Sstevel@tonic-gate 	    }
36257c478bd9Sstevel@tonic-gate #endif
36267c478bd9Sstevel@tonic-gate 	    return (1);
36277c478bd9Sstevel@tonic-gate 	}
36287c478bd9Sstevel@tonic-gate 
36297c478bd9Sstevel@tonic-gate 	return (0);
36307c478bd9Sstevel@tonic-gate }
36317c478bd9Sstevel@tonic-gate 
36327c478bd9Sstevel@tonic-gate /*
36337c478bd9Sstevel@tonic-gate  * cs_ss_thread - This is the Socket Services work thread. We fire off
36347c478bd9Sstevel@tonic-gate  *			any calls to Socket Services here that we want
36357c478bd9Sstevel@tonic-gate  *			to run on a thread that is seperate from the
36367c478bd9Sstevel@tonic-gate  *			per-socket event thread.
36377c478bd9Sstevel@tonic-gate  */
36387c478bd9Sstevel@tonic-gate static void
cs_ss_thread(uint32_t sn)36397c478bd9Sstevel@tonic-gate cs_ss_thread(uint32_t sn)
36407c478bd9Sstevel@tonic-gate {
36417c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
36427c478bd9Sstevel@tonic-gate 
36437c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(sn)) == NULL)
36447c478bd9Sstevel@tonic-gate 	    return;
36457c478bd9Sstevel@tonic-gate 
36467c478bd9Sstevel@tonic-gate 	/*
36477c478bd9Sstevel@tonic-gate 	 * Tell CPR that we've started a new thread.
36487c478bd9Sstevel@tonic-gate 	 */
36497c478bd9Sstevel@tonic-gate 	CALLB_CPR_INIT(&sp->cprinfo_ss, &sp->ss_thread_lock,
36507c478bd9Sstevel@tonic-gate 					callb_generic_cpr, "cs_ss_thread");
36517c478bd9Sstevel@tonic-gate 
36527c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->ss_thread_lock);
36537c478bd9Sstevel@tonic-gate 
36547c478bd9Sstevel@tonic-gate 	for (;;) {
36557c478bd9Sstevel@tonic-gate 
36567c478bd9Sstevel@tonic-gate 	    CALLB_CPR_SAFE_BEGIN(&sp->cprinfo_ss);
36577c478bd9Sstevel@tonic-gate 	    cv_wait(&sp->ss_thread_cv, &sp->ss_thread_lock);
36587c478bd9Sstevel@tonic-gate 	    CALLB_CPR_SAFE_END(&sp->cprinfo_ss, &sp->ss_thread_lock);
36597c478bd9Sstevel@tonic-gate 
36607c478bd9Sstevel@tonic-gate 		/*
36617c478bd9Sstevel@tonic-gate 		 * Check to see if there are any special thread operations
36627c478bd9Sstevel@tonic-gate 		 * that we are being asked to perform.
36637c478bd9Sstevel@tonic-gate 		 */
36647c478bd9Sstevel@tonic-gate 	    if (sp->ss_thread_state & SOCKET_THREAD_EXIT) {
36657c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
36667c478bd9Sstevel@tonic-gate 		if (cs_debug > 1) {
36677c478bd9Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_ss_thread: socket %d "
36687c478bd9Sstevel@tonic-gate 					"SOCKET_THREAD_EXIT\n",
36697c478bd9Sstevel@tonic-gate 						sp->socket_num);
36707c478bd9Sstevel@tonic-gate 		}
36717c478bd9Sstevel@tonic-gate #endif
36727c478bd9Sstevel@tonic-gate 		CALLB_CPR_EXIT(&sp->cprinfo_ss);
36737c478bd9Sstevel@tonic-gate 		cv_broadcast(&sp->ss_caller_cv);	/* wake up cs_deinit */
36747c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->ss_thread_lock);
36757c478bd9Sstevel@tonic-gate 		return;
36767c478bd9Sstevel@tonic-gate 	    } /* if (SOCKET_THREAD_EXIT) */
36777c478bd9Sstevel@tonic-gate 
36787c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
36797c478bd9Sstevel@tonic-gate 	    if (cs_debug > 1) {
36807c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_ss_thread: socket %d "
36817c478bd9Sstevel@tonic-gate 					"ss_thread_state = 0x%x\n",
36827c478bd9Sstevel@tonic-gate 						(int)sp->socket_num,
36837c478bd9Sstevel@tonic-gate 						(int)sp->ss_thread_state);
36847c478bd9Sstevel@tonic-gate 	    }
36857c478bd9Sstevel@tonic-gate #endif
36867c478bd9Sstevel@tonic-gate 
36877c478bd9Sstevel@tonic-gate 		/*
36887c478bd9Sstevel@tonic-gate 		 * Call SocketServices(CSCISInit) to have SS parse the
36897c478bd9Sstevel@tonic-gate 		 *	CIS and load/attach any client drivers necessary.
36907c478bd9Sstevel@tonic-gate 		 */
36917c478bd9Sstevel@tonic-gate 	    if (sp->ss_thread_state & SOCKET_THREAD_CSCISInit) {
36927c478bd9Sstevel@tonic-gate 
36937c478bd9Sstevel@tonic-gate 		sp->ss_thread_state &= ~SOCKET_THREAD_CSCISInit;
36947c478bd9Sstevel@tonic-gate 
36957c478bd9Sstevel@tonic-gate 		if (!(sp->flags & SOCKET_CARD_INSERTED)) {
36967c478bd9Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_ss_thread %d "
36977c478bd9Sstevel@tonic-gate 					"card NOT inserted\n",
36987c478bd9Sstevel@tonic-gate 					sp->socket_num);
36997c478bd9Sstevel@tonic-gate 		}
37007c478bd9Sstevel@tonic-gate 
37017c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
37027c478bd9Sstevel@tonic-gate 		if (cs_debug > 1) {
37037c478bd9Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_ss_thread: socket %d calling "
37047c478bd9Sstevel@tonic-gate 						"CSCISInit\n", sp->socket_num);
37057c478bd9Sstevel@tonic-gate 		}
37067c478bd9Sstevel@tonic-gate #endif
37077c478bd9Sstevel@tonic-gate 
37087c478bd9Sstevel@tonic-gate 		/*
37097c478bd9Sstevel@tonic-gate 		 * Tell SS that we have a complete CIS and that it can now
37107c478bd9Sstevel@tonic-gate 		 *	be parsed.
37117c478bd9Sstevel@tonic-gate 		 * Note that in some cases the client driver may block in
37127c478bd9Sstevel@tonic-gate 		 *	their attach routine, causing this call to block until
37137c478bd9Sstevel@tonic-gate 		 *	the client completes their attach.
37147c478bd9Sstevel@tonic-gate 		 */
37157c478bd9Sstevel@tonic-gate 		SocketServices(CSCISInit, sp->socket_num);
37167c478bd9Sstevel@tonic-gate 
37177c478bd9Sstevel@tonic-gate 		/*
37187c478bd9Sstevel@tonic-gate 		 * Set the CS_EVENT_SS_UPDATED event for this socket so that the
37197c478bd9Sstevel@tonic-gate 		 *	event thread can continue any card insertion processing
37207c478bd9Sstevel@tonic-gate 		 *	that it has to do.
37217c478bd9Sstevel@tonic-gate 		 */
37227c478bd9Sstevel@tonic-gate 		mutex_enter(&sp->lock);
37237c478bd9Sstevel@tonic-gate 		sp->events |= CS_EVENT_SS_UPDATED;
37247c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->lock);
37257c478bd9Sstevel@tonic-gate 
37267c478bd9Sstevel@tonic-gate 		/*
37277c478bd9Sstevel@tonic-gate 		 * Wake up this socket's event thread so that clients can
37287c478bd9Sstevel@tonic-gate 		 *	continue any card insertion or attach processing
37297c478bd9Sstevel@tonic-gate 		 *	that they need to do.
37307c478bd9Sstevel@tonic-gate 		 */
37317c478bd9Sstevel@tonic-gate 		cv_broadcast(&sp->thread_cv);
37327c478bd9Sstevel@tonic-gate 	    } /* if ST_CSCISInit */
37337c478bd9Sstevel@tonic-gate 
37347c478bd9Sstevel@tonic-gate 	} /* for (;;) */
37357c478bd9Sstevel@tonic-gate }
37367c478bd9Sstevel@tonic-gate 
37377c478bd9Sstevel@tonic-gate /*
37387c478bd9Sstevel@tonic-gate  * cs_request_socket_mask - set the client's event mask as well as causes
37397c478bd9Sstevel@tonic-gate  *				any events pending from RegisterClient to
37407c478bd9Sstevel@tonic-gate  *				be scheduled to be sent to the client
37417c478bd9Sstevel@tonic-gate  */
37427c478bd9Sstevel@tonic-gate static int
cs_request_socket_mask(client_handle_t client_handle,request_socket_mask_t * se)37437c478bd9Sstevel@tonic-gate cs_request_socket_mask(client_handle_t client_handle,
37447c478bd9Sstevel@tonic-gate 					request_socket_mask_t *se)
37457c478bd9Sstevel@tonic-gate {
37467c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
37477c478bd9Sstevel@tonic-gate 	client_t *client;
37487c478bd9Sstevel@tonic-gate 	int error;
37497c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
37507c478bd9Sstevel@tonic-gate 
37517c478bd9Sstevel@tonic-gate 	/*
37527c478bd9Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
37537c478bd9Sstevel@tonic-gate 	 *	is, we don't do anything except for return success.
37547c478bd9Sstevel@tonic-gate 	 */
37557c478bd9Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
37567c478bd9Sstevel@tonic-gate 	    return (CS_SUCCESS);
37577c478bd9Sstevel@tonic-gate 
37587c478bd9Sstevel@tonic-gate 	/*
37597c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
37607c478bd9Sstevel@tonic-gate 	 */
37617c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
37627c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
37637c478bd9Sstevel@tonic-gate 
37647c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
37657c478bd9Sstevel@tonic-gate 
37667c478bd9Sstevel@tonic-gate 	/*
37677c478bd9Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
37687c478bd9Sstevel@tonic-gate 	 */
37697c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
37707c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
37717c478bd9Sstevel@tonic-gate 	    return (error);
37727c478bd9Sstevel@tonic-gate 	}
37737c478bd9Sstevel@tonic-gate 
37747c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
37757c478bd9Sstevel@tonic-gate 
37767c478bd9Sstevel@tonic-gate 	/*
37777c478bd9Sstevel@tonic-gate 	 * If this client has already done a RequestSocketMask without
37787c478bd9Sstevel@tonic-gate 	 *	a corresponding ReleaseSocketMask, then return an error.
37797c478bd9Sstevel@tonic-gate 	 */
37807c478bd9Sstevel@tonic-gate 	if (client->flags & REQ_SOCKET_MASK_DONE) {
37817c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
37827c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
37837c478bd9Sstevel@tonic-gate 	    return (CS_IN_USE);
37847c478bd9Sstevel@tonic-gate 	}
37857c478bd9Sstevel@tonic-gate 
37867c478bd9Sstevel@tonic-gate 	/*
37877c478bd9Sstevel@tonic-gate 	 * Set up the event mask information; we copy this directly from
37887c478bd9Sstevel@tonic-gate 	 *	the client; since we are the only source of events, any
37897c478bd9Sstevel@tonic-gate 	 *	bogus bits that the client puts in here won't matter
37907c478bd9Sstevel@tonic-gate 	 *	because we'll never look at them.
37917c478bd9Sstevel@tonic-gate 	 */
37927c478bd9Sstevel@tonic-gate 	client->event_mask = se->EventMask;
37937c478bd9Sstevel@tonic-gate 
37947c478bd9Sstevel@tonic-gate 	/*
37957c478bd9Sstevel@tonic-gate 	 * If RegisterClient left us some events to process, set these
37967c478bd9Sstevel@tonic-gate 	 *	events up here.
37977c478bd9Sstevel@tonic-gate 	 */
37987c478bd9Sstevel@tonic-gate 	if (client->pending_events) {
37997c478bd9Sstevel@tonic-gate 	    client->events |= client->pending_events;
38007c478bd9Sstevel@tonic-gate 	    client->pending_events = 0;
38017c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
38027c478bd9Sstevel@tonic-gate 	    if (cs_debug > 1) {
38037c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_request_socket_mask: client_handle = 0x%x "
38047c478bd9Sstevel@tonic-gate 				"driver_name = [%s] events = 0x%x\n",
38057c478bd9Sstevel@tonic-gate 					(int)client->client_handle,
38067c478bd9Sstevel@tonic-gate 					client->driver_name,
38077c478bd9Sstevel@tonic-gate 					(int)client->events);
38087c478bd9Sstevel@tonic-gate 	    }
38097c478bd9Sstevel@tonic-gate #endif
38107c478bd9Sstevel@tonic-gate 	}
38117c478bd9Sstevel@tonic-gate 
38127c478bd9Sstevel@tonic-gate 	client->flags |= REQ_SOCKET_MASK_DONE;
38137c478bd9Sstevel@tonic-gate 
38147c478bd9Sstevel@tonic-gate 	/*
38157c478bd9Sstevel@tonic-gate 	 * Merge all the clients' event masks and set the socket
38167c478bd9Sstevel@tonic-gate 	 *	to generate the appropriate events.
38177c478bd9Sstevel@tonic-gate 	 */
38187c478bd9Sstevel@tonic-gate 	(void) cs_set_socket_event_mask(sp, cs_merge_event_masks(sp, client));
38197c478bd9Sstevel@tonic-gate 
38207c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
38217c478bd9Sstevel@tonic-gate 
38227c478bd9Sstevel@tonic-gate 	/*
38237c478bd9Sstevel@tonic-gate 	 * Wakeup the event thread if there are any client events to process.
38247c478bd9Sstevel@tonic-gate 	 */
38257c478bd9Sstevel@tonic-gate 	if (client->events) {
38267c478bd9Sstevel@tonic-gate 	    cv_broadcast(&sp->thread_cv);
38277c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
38287c478bd9Sstevel@tonic-gate 	    if (cs_debug > 1) {
38297c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_request_socket_mask: did cv_broadcast for "
38307c478bd9Sstevel@tonic-gate 				"client_handle = 0x%x "
38317c478bd9Sstevel@tonic-gate 				"driver_name = [%s] events = 0x%x\n",
38327c478bd9Sstevel@tonic-gate 					(int)client->client_handle,
38337c478bd9Sstevel@tonic-gate 					client->driver_name,
38347c478bd9Sstevel@tonic-gate 					(int)client->events);
38357c478bd9Sstevel@tonic-gate 	    }
38367c478bd9Sstevel@tonic-gate #endif
38377c478bd9Sstevel@tonic-gate 
38387c478bd9Sstevel@tonic-gate 	}
38397c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
38407c478bd9Sstevel@tonic-gate 
38417c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
38427c478bd9Sstevel@tonic-gate }
38437c478bd9Sstevel@tonic-gate 
38447c478bd9Sstevel@tonic-gate /*
38457c478bd9Sstevel@tonic-gate  * cs_release_socket_mask - clear the client's event mask
38467c478bd9Sstevel@tonic-gate  *
38477c478bd9Sstevel@tonic-gate  * Once this function returns, the client is guaranteed
38487c478bd9Sstevel@tonic-gate  *	not to get any more event callbacks.
38497c478bd9Sstevel@tonic-gate  */
38507c478bd9Sstevel@tonic-gate /*ARGSUSED*/
38517c478bd9Sstevel@tonic-gate static int
cs_release_socket_mask(client_handle_t client_handle,release_socket_mask_t * rsm)38527c478bd9Sstevel@tonic-gate cs_release_socket_mask(client_handle_t client_handle,
38537c478bd9Sstevel@tonic-gate 					release_socket_mask_t *rsm)
38547c478bd9Sstevel@tonic-gate {
38557c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
38567c478bd9Sstevel@tonic-gate 	client_t *client;
38577c478bd9Sstevel@tonic-gate 	int error;
38587c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
38597c478bd9Sstevel@tonic-gate 
38607c478bd9Sstevel@tonic-gate 	/*
38617c478bd9Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
38627c478bd9Sstevel@tonic-gate 	 *	is, we don't do anything except for return success.
38637c478bd9Sstevel@tonic-gate 	 */
38647c478bd9Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
38657c478bd9Sstevel@tonic-gate 	    return (CS_SUCCESS);
38667c478bd9Sstevel@tonic-gate 
38677c478bd9Sstevel@tonic-gate 	/*
38687c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
38697c478bd9Sstevel@tonic-gate 	 */
38707c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
38717c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
38727c478bd9Sstevel@tonic-gate 
38737c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
38747c478bd9Sstevel@tonic-gate 
38757c478bd9Sstevel@tonic-gate 	/*
38767c478bd9Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
38777c478bd9Sstevel@tonic-gate 	 */
38787c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
38797c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
38807c478bd9Sstevel@tonic-gate 	    return (error);
38817c478bd9Sstevel@tonic-gate 	}
38827c478bd9Sstevel@tonic-gate 
38837c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
38847c478bd9Sstevel@tonic-gate 
38857c478bd9Sstevel@tonic-gate 	/*
38867c478bd9Sstevel@tonic-gate 	 * If this client has already done a RequestSocketMask without
38877c478bd9Sstevel@tonic-gate 	 *	a corresponding ReleaseSocketMask, then return an error.
38887c478bd9Sstevel@tonic-gate 	 */
38897c478bd9Sstevel@tonic-gate 	if (!(client->flags & REQ_SOCKET_MASK_DONE)) {
38907c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
38917c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
38927c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
38937c478bd9Sstevel@tonic-gate 	}
38947c478bd9Sstevel@tonic-gate 
38957c478bd9Sstevel@tonic-gate 	/*
38967c478bd9Sstevel@tonic-gate 	 * Clear both the client event mask and the global event mask.
38977c478bd9Sstevel@tonic-gate 	 *	We clear both since the semantics of this function are
38987c478bd9Sstevel@tonic-gate 	 *	that once it returns, the client will not be called at
38997c478bd9Sstevel@tonic-gate 	 *	it's event handler for any events until RequestSocketMask
39007c478bd9Sstevel@tonic-gate 	 *	is called again.
39017c478bd9Sstevel@tonic-gate 	 */
39027c478bd9Sstevel@tonic-gate 	client->event_mask = 0;
39037c478bd9Sstevel@tonic-gate 	client->global_mask = 0;
39047c478bd9Sstevel@tonic-gate 	client->flags &= ~REQ_SOCKET_MASK_DONE;
39057c478bd9Sstevel@tonic-gate 
39067c478bd9Sstevel@tonic-gate 	/*
39077c478bd9Sstevel@tonic-gate 	 * Merge all the clients' event masks and set the socket
39087c478bd9Sstevel@tonic-gate 	 *	to generate the appropriate events.
39097c478bd9Sstevel@tonic-gate 	 */
39107c478bd9Sstevel@tonic-gate 	(void) cs_set_socket_event_mask(sp, cs_merge_event_masks(sp, client));
39117c478bd9Sstevel@tonic-gate 
39127c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
39137c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
39147c478bd9Sstevel@tonic-gate 
39157c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
39167c478bd9Sstevel@tonic-gate }
39177c478bd9Sstevel@tonic-gate 
39187c478bd9Sstevel@tonic-gate /*
39197c478bd9Sstevel@tonic-gate  * cs_get_event_mask - return the event mask for this client
39207c478bd9Sstevel@tonic-gate  */
39217c478bd9Sstevel@tonic-gate static int
cs_get_event_mask(client_handle_t client_handle,sockevent_t * se)39227c478bd9Sstevel@tonic-gate cs_get_event_mask(client_handle_t client_handle, sockevent_t *se)
39237c478bd9Sstevel@tonic-gate {
39247c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
39257c478bd9Sstevel@tonic-gate 	client_t *client;
39267c478bd9Sstevel@tonic-gate 	int error;
39277c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
39287c478bd9Sstevel@tonic-gate 
39297c478bd9Sstevel@tonic-gate 	/*
39307c478bd9Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
39317c478bd9Sstevel@tonic-gate 	 *	is, we don't do anything except for return success.
39327c478bd9Sstevel@tonic-gate 	 */
39337c478bd9Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
39347c478bd9Sstevel@tonic-gate 	    return (CS_SUCCESS);
39357c478bd9Sstevel@tonic-gate 
39367c478bd9Sstevel@tonic-gate 	/*
39377c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
39387c478bd9Sstevel@tonic-gate 	 */
39397c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
39407c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
39417c478bd9Sstevel@tonic-gate 
39427c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
39437c478bd9Sstevel@tonic-gate 
39447c478bd9Sstevel@tonic-gate 	/*
39457c478bd9Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
39467c478bd9Sstevel@tonic-gate 	 */
39477c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
39487c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
39497c478bd9Sstevel@tonic-gate 	    return (error);
39507c478bd9Sstevel@tonic-gate 	}
39517c478bd9Sstevel@tonic-gate 
39527c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
39537c478bd9Sstevel@tonic-gate 
39547c478bd9Sstevel@tonic-gate #ifdef	XXX
39557c478bd9Sstevel@tonic-gate 	/*
39567c478bd9Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
39577c478bd9Sstevel@tonic-gate 	 *	for this client, then return an error.
39587c478bd9Sstevel@tonic-gate 	 * XXX - how can a client get their event masks if their card
39597c478bd9Sstevel@tonic-gate 	 *	goes away?
39607c478bd9Sstevel@tonic-gate 	 */
39617c478bd9Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
39627c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
39637c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
39647c478bd9Sstevel@tonic-gate 	    return (CS_NO_CARD);
39657c478bd9Sstevel@tonic-gate 	}
39667c478bd9Sstevel@tonic-gate #endif
39677c478bd9Sstevel@tonic-gate 
39687c478bd9Sstevel@tonic-gate 	/*
39697c478bd9Sstevel@tonic-gate 	 * We are only allowed to get the client event mask if a
39707c478bd9Sstevel@tonic-gate 	 *	RequestSocketMask has been called previously.  We
39717c478bd9Sstevel@tonic-gate 	 *	are allowed to get the global event mask at any
39727c478bd9Sstevel@tonic-gate 	 *	time.
39737c478bd9Sstevel@tonic-gate 	 * The global event mask is initially set by the client
39747c478bd9Sstevel@tonic-gate 	 *	in the call to RegisterClient.  The client event
39757c478bd9Sstevel@tonic-gate 	 *	mask is set by the client in calls to SetEventMask
39767c478bd9Sstevel@tonic-gate 	 *	and RequestSocketMask and gotten in calls to
39777c478bd9Sstevel@tonic-gate 	 *	GetEventMask.
39787c478bd9Sstevel@tonic-gate 	 */
39797c478bd9Sstevel@tonic-gate 	if (se->Attributes & CONF_EVENT_MASK_CLIENT) {
39807c478bd9Sstevel@tonic-gate 	    if (!(client->flags & REQ_SOCKET_MASK_DONE)) {
39817c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->lock);
39827c478bd9Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
39837c478bd9Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
39847c478bd9Sstevel@tonic-gate 	    }
39857c478bd9Sstevel@tonic-gate 	    se->EventMask = client->event_mask;
39867c478bd9Sstevel@tonic-gate 	} else {
39877c478bd9Sstevel@tonic-gate 	    se->EventMask = client->global_mask;
39887c478bd9Sstevel@tonic-gate 	}
39897c478bd9Sstevel@tonic-gate 
39907c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
39917c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
39927c478bd9Sstevel@tonic-gate 
39937c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
39947c478bd9Sstevel@tonic-gate }
39957c478bd9Sstevel@tonic-gate 
39967c478bd9Sstevel@tonic-gate /*
39977c478bd9Sstevel@tonic-gate  * cs_set_event_mask - set the event mask for this client
39987c478bd9Sstevel@tonic-gate  */
39997c478bd9Sstevel@tonic-gate static int
cs_set_event_mask(client_handle_t client_handle,sockevent_t * se)40007c478bd9Sstevel@tonic-gate cs_set_event_mask(client_handle_t client_handle, sockevent_t *se)
40017c478bd9Sstevel@tonic-gate {
40027c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
40037c478bd9Sstevel@tonic-gate 	client_t *client;
40047c478bd9Sstevel@tonic-gate 	int error;
40057c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
40067c478bd9Sstevel@tonic-gate 
40077c478bd9Sstevel@tonic-gate 	/*
40087c478bd9Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
40097c478bd9Sstevel@tonic-gate 	 *	is, we don't do anything except for return success.
40107c478bd9Sstevel@tonic-gate 	 */
40117c478bd9Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
40127c478bd9Sstevel@tonic-gate 	    return (CS_SUCCESS);
40137c478bd9Sstevel@tonic-gate 
40147c478bd9Sstevel@tonic-gate 	/*
40157c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
40167c478bd9Sstevel@tonic-gate 	 */
40177c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
40187c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
40197c478bd9Sstevel@tonic-gate 
40207c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
40217c478bd9Sstevel@tonic-gate 
40227c478bd9Sstevel@tonic-gate 	/*
40237c478bd9Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
40247c478bd9Sstevel@tonic-gate 	 */
40257c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
40267c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
40277c478bd9Sstevel@tonic-gate 	    return (error);
40287c478bd9Sstevel@tonic-gate 	}
40297c478bd9Sstevel@tonic-gate 
40307c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
40317c478bd9Sstevel@tonic-gate 
40327c478bd9Sstevel@tonic-gate #ifdef	XXX
40337c478bd9Sstevel@tonic-gate 	/*
40347c478bd9Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
40357c478bd9Sstevel@tonic-gate 	 *	for this client, then return an error.
40367c478bd9Sstevel@tonic-gate 	 */
40377c478bd9Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
40387c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
40397c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
40407c478bd9Sstevel@tonic-gate 	    return (CS_NO_CARD);
40417c478bd9Sstevel@tonic-gate 	}
40427c478bd9Sstevel@tonic-gate #endif
40437c478bd9Sstevel@tonic-gate 
40447c478bd9Sstevel@tonic-gate 	/*
40457c478bd9Sstevel@tonic-gate 	 * We are only allowed to set the client event mask if a
40467c478bd9Sstevel@tonic-gate 	 *	RequestSocketMask has been called previously.  We
40477c478bd9Sstevel@tonic-gate 	 *	are allowed to set the global event mask at any
40487c478bd9Sstevel@tonic-gate 	 *	time.
40497c478bd9Sstevel@tonic-gate 	 * The global event mask is initially set by the client
40507c478bd9Sstevel@tonic-gate 	 *	in the call to RegisterClient.  The client event
40517c478bd9Sstevel@tonic-gate 	 *	mask is set by the client in calls to SetEventMask
40527c478bd9Sstevel@tonic-gate 	 *	and RequestSocketMask and gotten in calls to
40537c478bd9Sstevel@tonic-gate 	 *	GetEventMask.
40547c478bd9Sstevel@tonic-gate 	 */
40557c478bd9Sstevel@tonic-gate 	if (se->Attributes & CONF_EVENT_MASK_CLIENT) {
40567c478bd9Sstevel@tonic-gate 	    if (!(client->flags & REQ_SOCKET_MASK_DONE)) {
40577c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->lock);
40587c478bd9Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
40597c478bd9Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
40607c478bd9Sstevel@tonic-gate 	    }
40617c478bd9Sstevel@tonic-gate 	    client->event_mask = se->EventMask;
40627c478bd9Sstevel@tonic-gate 	} else {
40637c478bd9Sstevel@tonic-gate 	    client->global_mask = se->EventMask;
40647c478bd9Sstevel@tonic-gate 	}
40657c478bd9Sstevel@tonic-gate 
40667c478bd9Sstevel@tonic-gate 	/*
40677c478bd9Sstevel@tonic-gate 	 * Merge all the clients' event masks and set the socket
40687c478bd9Sstevel@tonic-gate 	 *	to generate the appropriate events.
40697c478bd9Sstevel@tonic-gate 	 */
40707c478bd9Sstevel@tonic-gate 	(void) cs_set_socket_event_mask(sp, cs_merge_event_masks(sp, client));
40717c478bd9Sstevel@tonic-gate 
40727c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
40737c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
40747c478bd9Sstevel@tonic-gate 
40757c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
40767c478bd9Sstevel@tonic-gate }
40777c478bd9Sstevel@tonic-gate 
40787c478bd9Sstevel@tonic-gate /*
40797c478bd9Sstevel@tonic-gate  * cs_read_event_status - handles PRR events and returns card status
40807c478bd9Sstevel@tonic-gate  *
40817c478bd9Sstevel@tonic-gate  *	calling: *sp - socket struct point
40827c478bd9Sstevel@tonic-gate  *		 *client - client to check events on
40837c478bd9Sstevel@tonic-gate  *		 *revent - pointer to event mask to update; if NULL, will
40847c478bd9Sstevel@tonic-gate  *				not be updated, if non-NULL, will be updated
40857c478bd9Sstevel@tonic-gate  *				with CS-format events; it is NOT necessary
40867c478bd9Sstevel@tonic-gate  *				to clear this value before calling this
40877c478bd9Sstevel@tonic-gate  *				function
40887c478bd9Sstevel@tonic-gate  *		 *gs - pointer to a get_ss_status_t used for the SS GetStatus
40897c478bd9Sstevel@tonic-gate  *				call; it is not necessary to initialize any
40907c478bd9Sstevel@tonic-gate  *				members in this structure; set to NULL if
40917c478bd9Sstevel@tonic-gate  *				not used
40927c478bd9Sstevel@tonic-gate  *		flags - if CS_RES_IGNORE_NO_CARD is set, the check for a
40937c478bd9Sstevel@tonic-gate  *				card present will not be done
40947c478bd9Sstevel@tonic-gate  *
40957c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS
40967c478bd9Sstevel@tonic-gate  *		 CS_NO_CARD - if no card is in the socket and the flags arg
40977c478bd9Sstevel@tonic-gate  *				is not set to CS_RES_IGNORE_NO_CARD
40987c478bd9Sstevel@tonic-gate  *		 CS_BAD_SOCKET - if the SS_GetStatus function returned an
40997c478bd9Sstevel@tonic-gate  *					error
41007c478bd9Sstevel@tonic-gate  *
41017c478bd9Sstevel@tonic-gate  *	Note that if the client that configured this socket has told us that
41027c478bd9Sstevel@tonic-gate  *		the READY pin in the PRR isn't valid and the socket is in IO
41037c478bd9Sstevel@tonic-gate  *		mode, we always return that the card is READY.
41047c478bd9Sstevel@tonic-gate  *
41057c478bd9Sstevel@tonic-gate  *	Note that if gs is not NULL, the current card state will be returned
41067c478bd9Sstevel@tonic-gate  *		in the gs->CardState member; this will always reflect the
41077c478bd9Sstevel@tonic-gate  *		current card state and the state will come from both the
41087c478bd9Sstevel@tonic-gate  *		SS_GetStatus call and the PRR, whichever is appropriate for
41097c478bd9Sstevel@tonic-gate  *		the mode that the socket is currently in.
41107c478bd9Sstevel@tonic-gate  */
41117c478bd9Sstevel@tonic-gate static int
cs_read_event_status(cs_socket_t * sp,client_t * client,event_t * revent,get_ss_status_t * gs,int flags)41127c478bd9Sstevel@tonic-gate cs_read_event_status(cs_socket_t *sp, client_t *client, event_t *revent,
41137c478bd9Sstevel@tonic-gate 						get_ss_status_t *gs, int flags)
41147c478bd9Sstevel@tonic-gate {
41157c478bd9Sstevel@tonic-gate 	cfg_regs_t prrd = 0;
41167c478bd9Sstevel@tonic-gate 
41177c478bd9Sstevel@tonic-gate 	/*
41187c478bd9Sstevel@tonic-gate 	 * SOCKET_IS_IO will only be set if a RequestConfiguration
41197c478bd9Sstevel@tonic-gate 	 *	has been done by at least one client on this socket.
41207c478bd9Sstevel@tonic-gate 	 * If there isn't a card in the socket or the caller wants to ignore
41217c478bd9Sstevel@tonic-gate 	 *	whether the card is in the socket or not, get the current
41227c478bd9Sstevel@tonic-gate 	 *	card status.
41237c478bd9Sstevel@tonic-gate 	 */
41247c478bd9Sstevel@tonic-gate 	if ((sp->flags & SOCKET_CARD_INSERTED) ||
41257c478bd9Sstevel@tonic-gate 					(flags & CS_RES_IGNORE_NO_CARD)) {
41267c478bd9Sstevel@tonic-gate 	    if (sp->flags & SOCKET_IS_IO) {
41277c478bd9Sstevel@tonic-gate 		if (client->present & CONFIG_PINREPL_REG_PRESENT) {
41287c478bd9Sstevel@tonic-gate 		    acc_handle_t cis_handle;
41297c478bd9Sstevel@tonic-gate 		    uint32_t newoffset = client->config_regs_offset;
41307c478bd9Sstevel@tonic-gate 
41317c478bd9Sstevel@tonic-gate 			/*
41327c478bd9Sstevel@tonic-gate 			 * Get a handle to the CIS window
41337c478bd9Sstevel@tonic-gate 			 */
41347c478bd9Sstevel@tonic-gate 		    if (cs_init_cis_window(sp, &newoffset, &cis_handle,
41357c478bd9Sstevel@tonic-gate 					CISTPLF_AM_SPACE) != CS_SUCCESS) {
41367c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_read_event_status: socket %d "
41377c478bd9Sstevel@tonic-gate 					    "can't init CIS window\n",
41387c478bd9Sstevel@tonic-gate 							sp->socket_num);
41397c478bd9Sstevel@tonic-gate 			return (CS_GENERAL_FAILURE);
41407c478bd9Sstevel@tonic-gate 		    } /* cs_init_cis_window */
41417c478bd9Sstevel@tonic-gate 
41427c478bd9Sstevel@tonic-gate 		    prrd = csx_Get8(cis_handle, client->config_regs.prr_p);
41437c478bd9Sstevel@tonic-gate 		    prrd &= client->pin;
41447c478bd9Sstevel@tonic-gate 
41457c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
41467c478bd9Sstevel@tonic-gate 		    if (cs_debug > 1) {
41477c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_read_event_status: "
41487c478bd9Sstevel@tonic-gate 						"prrd 0x%x client->pin 0x%x\n",
41497c478bd9Sstevel@tonic-gate 								(int)prrd,
41507c478bd9Sstevel@tonic-gate 								client->pin);
41517c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "PRR(1) = [%s%s%s%s%s%s%s%s]\n",
41527c478bd9Sstevel@tonic-gate 						((prrd & PRR_WP_STATUS)?
41537c478bd9Sstevel@tonic-gate 							"PRR_WP_STATUS ":""),
41547c478bd9Sstevel@tonic-gate 						((prrd & PRR_READY_STATUS)?
41557c478bd9Sstevel@tonic-gate 							"PRR_READY_STATUS ":""),
41567c478bd9Sstevel@tonic-gate 						((prrd & PRR_BVD2_STATUS)?
41577c478bd9Sstevel@tonic-gate 							"PRR_BVD2_STATUS ":""),
41587c478bd9Sstevel@tonic-gate 						((prrd & PRR_BVD1_STATUS)?
41597c478bd9Sstevel@tonic-gate 							"PRR_BVD1_STATUS ":""),
41607c478bd9Sstevel@tonic-gate 						((prrd & PRR_WP_EVENT)?
41617c478bd9Sstevel@tonic-gate 							"PRR_WP_EVENT ":""),
41627c478bd9Sstevel@tonic-gate 						((prrd & PRR_READY_EVENT)?
41637c478bd9Sstevel@tonic-gate 							"PRR_READY_EVENT ":""),
41647c478bd9Sstevel@tonic-gate 						((prrd & PRR_BVD2_EVENT)?
41657c478bd9Sstevel@tonic-gate 							"PRR_BVD2_EVENT ":""),
41667c478bd9Sstevel@tonic-gate 						((prrd & PRR_BVD1_EVENT)?
41677c478bd9Sstevel@tonic-gate 							"PRR_BVD1_EVENT ":""));
41687c478bd9Sstevel@tonic-gate 		    }
41697c478bd9Sstevel@tonic-gate #endif
41707c478bd9Sstevel@tonic-gate 
41717c478bd9Sstevel@tonic-gate 			/*
41727c478bd9Sstevel@tonic-gate 			 * The caller wants the event changes sent back and
41737c478bd9Sstevel@tonic-gate 			 * the PRR event change bits cleared.
41747c478bd9Sstevel@tonic-gate 			 */
41757c478bd9Sstevel@tonic-gate 		    if (revent) {
41767c478bd9Sstevel@tonic-gate 			get_socket_t get_socket;
41777c478bd9Sstevel@tonic-gate 			set_socket_t set_socket;
41787c478bd9Sstevel@tonic-gate 
41797c478bd9Sstevel@tonic-gate 			/*
41807c478bd9Sstevel@tonic-gate 			 * Bug ID: 1193636 - Card Services sends bogus
41817c478bd9Sstevel@tonic-gate 			 *	events on CS_EVENT_STATUS_CHANGE events
41827c478bd9Sstevel@tonic-gate 			 * Clear this before we OR-in any values.
41837c478bd9Sstevel@tonic-gate 			 */
41847c478bd9Sstevel@tonic-gate 			*revent = 0;
41857c478bd9Sstevel@tonic-gate 
41867c478bd9Sstevel@tonic-gate 			PRR_EVENT(prrd, PRR_WP_EVENT, PRR_WP_STATUS,
41877c478bd9Sstevel@tonic-gate 					CS_EVENT_WRITE_PROTECT, *revent);
41887c478bd9Sstevel@tonic-gate 
41897c478bd9Sstevel@tonic-gate 			PRR_EVENT(prrd, PRR_READY_EVENT, PRR_READY_STATUS,
41907c478bd9Sstevel@tonic-gate 					CS_EVENT_CARD_READY, *revent);
41917c478bd9Sstevel@tonic-gate 
41927c478bd9Sstevel@tonic-gate 			PRR_EVENT(prrd, PRR_BVD2_EVENT, PRR_BVD2_STATUS,
41937c478bd9Sstevel@tonic-gate 					CS_EVENT_BATTERY_LOW, *revent);
41947c478bd9Sstevel@tonic-gate 
41957c478bd9Sstevel@tonic-gate 			PRR_EVENT(prrd, PRR_BVD1_EVENT, PRR_BVD1_STATUS,
41967c478bd9Sstevel@tonic-gate 					CS_EVENT_BATTERY_DEAD, *revent);
41977c478bd9Sstevel@tonic-gate 
41987c478bd9Sstevel@tonic-gate 
41997c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
42007c478bd9Sstevel@tonic-gate 			if (cs_debug > 1) {
42017c478bd9Sstevel@tonic-gate 
42027c478bd9Sstevel@tonic-gate 			    cmn_err(CE_CONT, "PRR() = [%s%s%s%s%s%s%s%s]\n",
42037c478bd9Sstevel@tonic-gate 						((prrd & PRR_WP_STATUS)?
42047c478bd9Sstevel@tonic-gate 							"PRR_WP_STATUS ":""),
42057c478bd9Sstevel@tonic-gate 						((prrd & PRR_READY_STATUS)?
42067c478bd9Sstevel@tonic-gate 							"PRR_READY_STATUS ":""),
42077c478bd9Sstevel@tonic-gate 						((prrd & PRR_BVD2_STATUS)?
42087c478bd9Sstevel@tonic-gate 							"PRR_BVD2_STATUS ":""),
42097c478bd9Sstevel@tonic-gate 						((prrd & PRR_BVD1_STATUS)?
42107c478bd9Sstevel@tonic-gate 							"PRR_BVD1_STATUS ":""),
42117c478bd9Sstevel@tonic-gate 						((prrd & PRR_WP_EVENT)?
42127c478bd9Sstevel@tonic-gate 							"PRR_WP_EVENT ":""),
42137c478bd9Sstevel@tonic-gate 						((prrd & PRR_READY_EVENT)?
42147c478bd9Sstevel@tonic-gate 							"PRR_READY_EVENT ":""),
42157c478bd9Sstevel@tonic-gate 						((prrd & PRR_BVD2_EVENT)?
42167c478bd9Sstevel@tonic-gate 							"PRR_BVD2_EVENT ":""),
42177c478bd9Sstevel@tonic-gate 						((prrd & PRR_BVD1_EVENT)?
42187c478bd9Sstevel@tonic-gate 							"PRR_BVD1_EVENT ":""));
42197c478bd9Sstevel@tonic-gate 			}
42207c478bd9Sstevel@tonic-gate #endif
42217c478bd9Sstevel@tonic-gate 
42227c478bd9Sstevel@tonic-gate 			if (prrd)
42237c478bd9Sstevel@tonic-gate 			    csx_Put8(cis_handle, client->config_regs.prr_p,
42247c478bd9Sstevel@tonic-gate 				prrd);
42257c478bd9Sstevel@tonic-gate 
42267c478bd9Sstevel@tonic-gate 			/*
42277c478bd9Sstevel@tonic-gate 			 * We now have to reenable the status change interrupts
42287c478bd9Sstevel@tonic-gate 			 *	if there are any valid bits in the PRR. Since
42297c478bd9Sstevel@tonic-gate 			 *	the BVD1 signal becomes the STATUS_CHANGE
42307c478bd9Sstevel@tonic-gate 			 *	signal when the socket is in IO mode, we just
42317c478bd9Sstevel@tonic-gate 			 *	have to set the SBM_BVD1 enable bit in the
42327c478bd9Sstevel@tonic-gate 			 *	event mask.
42337c478bd9Sstevel@tonic-gate 			 */
42347c478bd9Sstevel@tonic-gate 			if (client->pin) {
42357c478bd9Sstevel@tonic-gate 			    get_socket.socket = sp->socket_num;
42367c478bd9Sstevel@tonic-gate 			    SocketServices(SS_GetSocket, &get_socket);
42377c478bd9Sstevel@tonic-gate 			    set_socket.socket = sp->socket_num;
42387c478bd9Sstevel@tonic-gate 			    set_socket.SCIntMask =
42397c478bd9Sstevel@tonic-gate 					get_socket.SCIntMask | SBM_BVD1;
42407c478bd9Sstevel@tonic-gate 			    set_socket.VccLevel = get_socket.VccLevel;
42417c478bd9Sstevel@tonic-gate 			    set_socket.Vpp1Level = get_socket.Vpp1Level;
42427c478bd9Sstevel@tonic-gate 			    set_socket.Vpp2Level = get_socket.Vpp2Level;
42437c478bd9Sstevel@tonic-gate 			    set_socket.IREQRouting = get_socket.IRQRouting;
42447c478bd9Sstevel@tonic-gate 			    set_socket.IFType = get_socket.IFType;
42457c478bd9Sstevel@tonic-gate 			    set_socket.CtlInd = get_socket.CtlInd;
42467c478bd9Sstevel@tonic-gate 			    set_socket.State = get_socket.state;
42477c478bd9Sstevel@tonic-gate 			    SocketServices(SS_SetSocket, &set_socket);
42487c478bd9Sstevel@tonic-gate 			} /* if (client->pin) */
42497c478bd9Sstevel@tonic-gate 		    } /* if (revent) */
42507c478bd9Sstevel@tonic-gate 
42517c478bd9Sstevel@tonic-gate 		} /* if (CONFIG_PINREPL_REG_PRESENT) */
42527c478bd9Sstevel@tonic-gate 	    } /* if (SOCKET_IS_IO) */
42537c478bd9Sstevel@tonic-gate 
42547c478bd9Sstevel@tonic-gate 	/*
42557c478bd9Sstevel@tonic-gate 	 * The caller wants the current card state; we just read
42567c478bd9Sstevel@tonic-gate 	 *	it and return a copy of it but do not clear any of
42577c478bd9Sstevel@tonic-gate 	 *	the event changed bits (if we're reading the PRR).
42587c478bd9Sstevel@tonic-gate 	 */
42597c478bd9Sstevel@tonic-gate 	    if (gs) {
42607c478bd9Sstevel@tonic-gate 		gs->socket = sp->socket_num;
42617c478bd9Sstevel@tonic-gate 		gs->CardState = 0;
42627c478bd9Sstevel@tonic-gate 		if (SocketServices(SS_GetStatus, gs) != SUCCESS)
42637c478bd9Sstevel@tonic-gate 		    return (CS_BAD_SOCKET);
42647c478bd9Sstevel@tonic-gate 		if (sp->flags & SOCKET_IS_IO) {
42657c478bd9Sstevel@tonic-gate 		/*
42667c478bd9Sstevel@tonic-gate 		 * If the socket is in IO mode, then clear the
42677c478bd9Sstevel@tonic-gate 		 *	gs->CardState bits that are now in the PRR
42687c478bd9Sstevel@tonic-gate 		 */
42697c478bd9Sstevel@tonic-gate 		    gs->CardState &= ~(SBM_WP | SBM_BVD1 |
42707c478bd9Sstevel@tonic-gate 						SBM_BVD2 | SBM_RDYBSY);
42717c478bd9Sstevel@tonic-gate 
42727c478bd9Sstevel@tonic-gate 		/*
42737c478bd9Sstevel@tonic-gate 		 * Convert PRR status to SS_GetStatus status
42747c478bd9Sstevel@tonic-gate 		 */
42757c478bd9Sstevel@tonic-gate 		    if (prrd & PRR_WP_STATUS)
42767c478bd9Sstevel@tonic-gate 			gs->CardState |= SBM_WP;
42777c478bd9Sstevel@tonic-gate 		    if (prrd & PRR_BVD2_STATUS)
42787c478bd9Sstevel@tonic-gate 			gs->CardState |= SBM_BVD2;
42797c478bd9Sstevel@tonic-gate 		    if (prrd & PRR_BVD1_STATUS)
42807c478bd9Sstevel@tonic-gate 			gs->CardState |= SBM_BVD1;
42817c478bd9Sstevel@tonic-gate 
42827c478bd9Sstevel@tonic-gate 		/*
42837c478bd9Sstevel@tonic-gate 		 * If the client has indicated that there is no
42847c478bd9Sstevel@tonic-gate 		 *	PRR or that the READY bit in the PRR isn't
42857c478bd9Sstevel@tonic-gate 		 *	valid, then we simulate the READY bit by
42867c478bd9Sstevel@tonic-gate 		 *	always returning READY.
42877c478bd9Sstevel@tonic-gate 		 */
42887c478bd9Sstevel@tonic-gate 		    if (!(client->present & CONFIG_PINREPL_REG_PRESENT) ||
42897c478bd9Sstevel@tonic-gate 			((client->present & CONFIG_PINREPL_REG_PRESENT) &&
42907c478bd9Sstevel@tonic-gate 			!((client->pin &
42917c478bd9Sstevel@tonic-gate 			    (PRR_READY_STATUS | PRR_READY_EVENT)) ==
42927c478bd9Sstevel@tonic-gate 				(PRR_READY_STATUS | PRR_READY_EVENT))) ||
42937c478bd9Sstevel@tonic-gate 				(prrd & PRR_READY_STATUS))
42947c478bd9Sstevel@tonic-gate 			gs->CardState |= SBM_RDYBSY;
42957c478bd9Sstevel@tonic-gate 
42967c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
42977c478bd9Sstevel@tonic-gate 			if (cs_debug > 1) {
42987c478bd9Sstevel@tonic-gate 			    cmn_err(CE_CONT, "cs_read_event_status: prrd 0x%x "
42997c478bd9Sstevel@tonic-gate 				"client->pin 0x%x "
43007c478bd9Sstevel@tonic-gate 				"gs->CardState 0x%x\n",
43017c478bd9Sstevel@tonic-gate 				prrd, client->pin, gs->CardState);
43027c478bd9Sstevel@tonic-gate 			}
43037c478bd9Sstevel@tonic-gate #endif
43047c478bd9Sstevel@tonic-gate 
43057c478bd9Sstevel@tonic-gate 		} /* if (SOCKET_IS_IO) */
43067c478bd9Sstevel@tonic-gate 	    } /* if (gs) */
43077c478bd9Sstevel@tonic-gate 	    return (CS_SUCCESS);
43087c478bd9Sstevel@tonic-gate 	} /* if (SOCKET_CARD_INSERTED) */
43097c478bd9Sstevel@tonic-gate 
43107c478bd9Sstevel@tonic-gate 	return (CS_NO_CARD);
43117c478bd9Sstevel@tonic-gate }
43127c478bd9Sstevel@tonic-gate 
43137c478bd9Sstevel@tonic-gate /*
43147c478bd9Sstevel@tonic-gate  * cs_get_status - gets live card status and latched card status changes
43157c478bd9Sstevel@tonic-gate  *			supports the GetStatus CS call
43167c478bd9Sstevel@tonic-gate  *
43177c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS
43187c478bd9Sstevel@tonic-gate  *		 CS_BAD_HANDLE if the passed client handle is invalid
43197c478bd9Sstevel@tonic-gate  *
43207c478bd9Sstevel@tonic-gate  *	Note: This function resets the latched status values maintained
43217c478bd9Sstevel@tonic-gate  *		by Socket Services
43227c478bd9Sstevel@tonic-gate  */
43237c478bd9Sstevel@tonic-gate static int
cs_get_status(client_handle_t client_handle,get_status_t * gs)43247c478bd9Sstevel@tonic-gate cs_get_status(client_handle_t client_handle, get_status_t *gs)
43257c478bd9Sstevel@tonic-gate {
43267c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
43277c478bd9Sstevel@tonic-gate 	client_t *client;
43287c478bd9Sstevel@tonic-gate 	get_ss_status_t get_ss_status;
43297c478bd9Sstevel@tonic-gate 	get_socket_t get_socket;
43307c478bd9Sstevel@tonic-gate 	set_socket_t set_socket;
43317c478bd9Sstevel@tonic-gate 	int error;
43327c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
43337c478bd9Sstevel@tonic-gate 
43347c478bd9Sstevel@tonic-gate 	/*
43357c478bd9Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
43367c478bd9Sstevel@tonic-gate 	 *	is, we don't do anything except for return success.
43377c478bd9Sstevel@tonic-gate 	 */
43387c478bd9Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
43397c478bd9Sstevel@tonic-gate 	    return (CS_SUCCESS);
43407c478bd9Sstevel@tonic-gate 
43417c478bd9Sstevel@tonic-gate 	/*
43427c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
43437c478bd9Sstevel@tonic-gate 	 */
43447c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
43457c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
43467c478bd9Sstevel@tonic-gate 
43477c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
43487c478bd9Sstevel@tonic-gate 
43497c478bd9Sstevel@tonic-gate 	/*
43507c478bd9Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
43517c478bd9Sstevel@tonic-gate 	 */
43527c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
43537c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
43547c478bd9Sstevel@tonic-gate 	    return (error);
43557c478bd9Sstevel@tonic-gate 	}
43567c478bd9Sstevel@tonic-gate 
43577c478bd9Sstevel@tonic-gate 	/*
43587c478bd9Sstevel@tonic-gate 	 * Get the current card status as well as the latched card
43597c478bd9Sstevel@tonic-gate 	 *	state.  Set the CS_RES_IGNORE_NO_CARD so that even
43607c478bd9Sstevel@tonic-gate 	 *	if there is no card in the socket we'll still get
43617c478bd9Sstevel@tonic-gate 	 *	a valid status.
43627c478bd9Sstevel@tonic-gate 	 * Note that it is not necessary to initialize any values
43637c478bd9Sstevel@tonic-gate 	 *	in the get_ss_status structure.
43647c478bd9Sstevel@tonic-gate 	 */
43657c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
43667c478bd9Sstevel@tonic-gate 	if ((error = cs_read_event_status(sp, client, NULL, &get_ss_status,
43677c478bd9Sstevel@tonic-gate 					CS_RES_IGNORE_NO_CARD)) != CS_SUCCESS) {
43687c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
43697c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
43707c478bd9Sstevel@tonic-gate 	    return (error);
43717c478bd9Sstevel@tonic-gate 	}
43727c478bd9Sstevel@tonic-gate 
43737c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
43747c478bd9Sstevel@tonic-gate 
43757c478bd9Sstevel@tonic-gate 	gs->raw_CardState = cs_sbm2cse(get_ss_status.CardState);
43767c478bd9Sstevel@tonic-gate 
43777c478bd9Sstevel@tonic-gate 	/*
43787c478bd9Sstevel@tonic-gate 	 * Assign the "live" card state to the "real" card state. If there's
43797c478bd9Sstevel@tonic-gate 	 *	no card in the socket or the card in the socket is not
43807c478bd9Sstevel@tonic-gate 	 *	for this client, then we lie and tell the caller that the
43817c478bd9Sstevel@tonic-gate 	 *	card is not inserted.
43827c478bd9Sstevel@tonic-gate 	 */
43837c478bd9Sstevel@tonic-gate 	gs->CardState = gs->raw_CardState;
43847c478bd9Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED))
43857c478bd9Sstevel@tonic-gate 	    gs->CardState &= ~CS_EVENT_CARD_INSERTION;
43867c478bd9Sstevel@tonic-gate 
43877c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
43887c478bd9Sstevel@tonic-gate 
43897c478bd9Sstevel@tonic-gate 	get_socket.socket = sp->socket_num;
43907c478bd9Sstevel@tonic-gate 	if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS)
43917c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
43927c478bd9Sstevel@tonic-gate 
43937c478bd9Sstevel@tonic-gate 	gs->SocketState = cs_sbm2cse(get_socket.state);
43947c478bd9Sstevel@tonic-gate 
43957c478bd9Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
43967c478bd9Sstevel@tonic-gate 	set_socket.SCIntMask = get_socket.SCIntMask;
43977c478bd9Sstevel@tonic-gate 	set_socket.VccLevel = get_socket.VccLevel;
43987c478bd9Sstevel@tonic-gate 	set_socket.Vpp1Level = get_socket.Vpp1Level;
43997c478bd9Sstevel@tonic-gate 	set_socket.Vpp2Level = get_socket.Vpp2Level;
44007c478bd9Sstevel@tonic-gate 	set_socket.IREQRouting = get_socket.IRQRouting;
44017c478bd9Sstevel@tonic-gate 	set_socket.IFType = get_socket.IFType;
44027c478bd9Sstevel@tonic-gate 	set_socket.CtlInd = get_socket.CtlInd;
44037c478bd9Sstevel@tonic-gate 	/* XXX (is ~0 correct here?) reset latched values */
44047c478bd9Sstevel@tonic-gate 	set_socket.State = (unsigned)~0;
44057c478bd9Sstevel@tonic-gate 
44067c478bd9Sstevel@tonic-gate 	if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS)
44077c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
44087c478bd9Sstevel@tonic-gate 
44097c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
44107c478bd9Sstevel@tonic-gate }
44117c478bd9Sstevel@tonic-gate 
44127c478bd9Sstevel@tonic-gate /*
44137c478bd9Sstevel@tonic-gate  * cs_cse2sbm - converts a CS event mask to an SS (SBM_XXX) event mask
44147c478bd9Sstevel@tonic-gate  */
44157c478bd9Sstevel@tonic-gate static event_t
cs_cse2sbm(event_t event_mask)44167c478bd9Sstevel@tonic-gate cs_cse2sbm(event_t event_mask)
44177c478bd9Sstevel@tonic-gate {
44187c478bd9Sstevel@tonic-gate 	event_t sbm_event = 0;
44197c478bd9Sstevel@tonic-gate 
44207c478bd9Sstevel@tonic-gate 	/*
44217c478bd9Sstevel@tonic-gate 	 * XXX - we need to handle PM_CHANGE and RESET here as well
44227c478bd9Sstevel@tonic-gate 	 */
44237c478bd9Sstevel@tonic-gate 	if (event_mask & CS_EVENT_WRITE_PROTECT)
44247c478bd9Sstevel@tonic-gate 	    sbm_event |= SBM_WP;
44257c478bd9Sstevel@tonic-gate 	if (event_mask & CS_EVENT_BATTERY_DEAD)
44267c478bd9Sstevel@tonic-gate 	    sbm_event |= SBM_BVD1;
44277c478bd9Sstevel@tonic-gate 	if (event_mask & CS_EVENT_BATTERY_LOW)
44287c478bd9Sstevel@tonic-gate 	    sbm_event |= SBM_BVD2;
44297c478bd9Sstevel@tonic-gate 	if (event_mask & CS_EVENT_CARD_READY)
44307c478bd9Sstevel@tonic-gate 	    sbm_event |= SBM_RDYBSY;
44317c478bd9Sstevel@tonic-gate 	if (event_mask & CS_EVENT_CARD_LOCK)
44327c478bd9Sstevel@tonic-gate 	    sbm_event |= SBM_LOCKED;
44337c478bd9Sstevel@tonic-gate 	if (event_mask & CS_EVENT_EJECTION_REQUEST)
44347c478bd9Sstevel@tonic-gate 	    sbm_event |= SBM_EJECT;
44357c478bd9Sstevel@tonic-gate 	if (event_mask & CS_EVENT_INSERTION_REQUEST)
44367c478bd9Sstevel@tonic-gate 	    sbm_event |= SBM_INSERT;
44377c478bd9Sstevel@tonic-gate 	if (event_mask & (CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL))
44387c478bd9Sstevel@tonic-gate 	    sbm_event |= SBM_CD;
44397c478bd9Sstevel@tonic-gate 
44407c478bd9Sstevel@tonic-gate 	return (sbm_event);
44417c478bd9Sstevel@tonic-gate }
44427c478bd9Sstevel@tonic-gate 
44437c478bd9Sstevel@tonic-gate /*
44447c478bd9Sstevel@tonic-gate  * cs_sbm2cse - converts SBM_xxx state to CS event bits
44457c478bd9Sstevel@tonic-gate  *
44467c478bd9Sstevel@tonic-gate  * This function should never set any of the following bits:
44477c478bd9Sstevel@tonic-gate  *
44487c478bd9Sstevel@tonic-gate  *		CS_EVENT_MTD_REQUEST
44497c478bd9Sstevel@tonic-gate  *		CS_EVENT_CLIENT_INFO
44507c478bd9Sstevel@tonic-gate  *		CS_EVENT_TIMER_EXPIRED
44517c478bd9Sstevel@tonic-gate  *		CS_EVENT_CARD_REMOVAL
44527c478bd9Sstevel@tonic-gate  *		CS_EVENT_CARD_REMOVAL_LOWP
44537c478bd9Sstevel@tonic-gate  *		CS_EVENT_ALL_CLIENTS
44547c478bd9Sstevel@tonic-gate  *		CS_EVENT_READY_TIMEOUT
44557c478bd9Sstevel@tonic-gate  *
44567c478bd9Sstevel@tonic-gate  *	These bits are defined in the CS_STATUS_XXX series and are
44577c478bd9Sstevel@tonic-gate  *	used by GetStatus.
44587c478bd9Sstevel@tonic-gate  */
44597c478bd9Sstevel@tonic-gate static uint32_t
cs_sbm2cse(uint32_t state)44607c478bd9Sstevel@tonic-gate cs_sbm2cse(uint32_t state)
44617c478bd9Sstevel@tonic-gate {
44627c478bd9Sstevel@tonic-gate 	uint32_t rstate = 0;
44637c478bd9Sstevel@tonic-gate 
44647c478bd9Sstevel@tonic-gate 	/*
44657c478bd9Sstevel@tonic-gate 	 * XXX - we need to handle PM_CHANGE and RESET here as well
44667c478bd9Sstevel@tonic-gate 	 */
44677c478bd9Sstevel@tonic-gate 	if (state & SBM_WP)
44687c478bd9Sstevel@tonic-gate 	    rstate |= CS_EVENT_WRITE_PROTECT;
44697c478bd9Sstevel@tonic-gate 	if (state & SBM_BVD1)
44707c478bd9Sstevel@tonic-gate 	    rstate |= CS_EVENT_BATTERY_DEAD;
44717c478bd9Sstevel@tonic-gate 	if (state & SBM_BVD2)
44727c478bd9Sstevel@tonic-gate 	    rstate |= CS_EVENT_BATTERY_LOW;
44737c478bd9Sstevel@tonic-gate 	if (state & SBM_RDYBSY)
44747c478bd9Sstevel@tonic-gate 	    rstate |= CS_EVENT_CARD_READY;
44757c478bd9Sstevel@tonic-gate 	if (state & SBM_LOCKED)
44767c478bd9Sstevel@tonic-gate 	    rstate |= CS_EVENT_CARD_LOCK;
44777c478bd9Sstevel@tonic-gate 	if (state & SBM_EJECT)
44787c478bd9Sstevel@tonic-gate 	    rstate |= CS_EVENT_EJECTION_REQUEST;
44797c478bd9Sstevel@tonic-gate 	if (state & SBM_INSERT)
44807c478bd9Sstevel@tonic-gate 	    rstate |= CS_EVENT_INSERTION_REQUEST;
44817c478bd9Sstevel@tonic-gate 	if (state & SBM_CD)
44827c478bd9Sstevel@tonic-gate 	    rstate |= CS_EVENT_CARD_INSERTION;
44837c478bd9Sstevel@tonic-gate 
44847c478bd9Sstevel@tonic-gate 	return (rstate);
44857c478bd9Sstevel@tonic-gate }
44867c478bd9Sstevel@tonic-gate 
44877c478bd9Sstevel@tonic-gate /*
44887c478bd9Sstevel@tonic-gate  * cs_merge_event_masks - merge the CS global socket event mask with the
44897c478bd9Sstevel@tonic-gate  *				passed client's event masks
44907c478bd9Sstevel@tonic-gate  */
44917c478bd9Sstevel@tonic-gate static unsigned
cs_merge_event_masks(cs_socket_t * sp,client_t * client)44927c478bd9Sstevel@tonic-gate cs_merge_event_masks(cs_socket_t *sp, client_t *client)
44937c478bd9Sstevel@tonic-gate {
44947c478bd9Sstevel@tonic-gate 	unsigned SCIntMask;
44957c478bd9Sstevel@tonic-gate 	uint32_t event_mask;
44967c478bd9Sstevel@tonic-gate 
44977c478bd9Sstevel@tonic-gate 	/*
44987c478bd9Sstevel@tonic-gate 	 * We always want to see card detect and status change events.
44997c478bd9Sstevel@tonic-gate 	 */
45007c478bd9Sstevel@tonic-gate 	SCIntMask = SBM_CD;
45017c478bd9Sstevel@tonic-gate 
45027c478bd9Sstevel@tonic-gate 	event_mask = client->event_mask | client->global_mask |
45037c478bd9Sstevel@tonic-gate 							sp->event_mask;
45047c478bd9Sstevel@tonic-gate 
45057c478bd9Sstevel@tonic-gate 	if (!(sp->flags & SOCKET_IS_IO)) {
45067c478bd9Sstevel@tonic-gate 	    SCIntMask |= cs_cse2sbm(event_mask);
45077c478bd9Sstevel@tonic-gate 	} else {
45087c478bd9Sstevel@tonic-gate 		/*
45097c478bd9Sstevel@tonic-gate 		 * If the socket is in IO mode and there is a PRR present,
45107c478bd9Sstevel@tonic-gate 		 *	then we may need to enable PCE_CARD_STATUS_CHANGE
45117c478bd9Sstevel@tonic-gate 		 *	events.
45127c478bd9Sstevel@tonic-gate 		 */
45137c478bd9Sstevel@tonic-gate 	    if (client->present & CONFIG_PINREPL_REG_PRESENT) {
45147c478bd9Sstevel@tonic-gate 
45157c478bd9Sstevel@tonic-gate 		SCIntMask |= (cs_cse2sbm(event_mask) &
45167c478bd9Sstevel@tonic-gate 				~(SBM_WP | SBM_BVD1 | SBM_BVD2 | SBM_RDYBSY));
45177c478bd9Sstevel@tonic-gate 
45187c478bd9Sstevel@tonic-gate 		if ((client->pin & (PRR_WP_STATUS | PRR_WP_EVENT)) ==
45197c478bd9Sstevel@tonic-gate 					(PRR_WP_STATUS | PRR_WP_EVENT))
45207c478bd9Sstevel@tonic-gate 		    if (event_mask & CS_EVENT_WRITE_PROTECT)
45217c478bd9Sstevel@tonic-gate 			SCIntMask |= SBM_BVD1;
45227c478bd9Sstevel@tonic-gate 
45237c478bd9Sstevel@tonic-gate 		if ((client->pin & (PRR_READY_STATUS | PRR_READY_EVENT)) ==
45247c478bd9Sstevel@tonic-gate 					(PRR_READY_STATUS | PRR_READY_EVENT))
45257c478bd9Sstevel@tonic-gate 		    if (event_mask & CS_EVENT_CARD_READY)
45267c478bd9Sstevel@tonic-gate 			    SCIntMask |= SBM_BVD1;
45277c478bd9Sstevel@tonic-gate 
45287c478bd9Sstevel@tonic-gate 		if ((client->pin & (PRR_BVD2_STATUS | PRR_BVD2_EVENT)) ==
45297c478bd9Sstevel@tonic-gate 					(PRR_BVD2_STATUS | PRR_BVD2_EVENT))
45307c478bd9Sstevel@tonic-gate 		    if (event_mask & CS_EVENT_BATTERY_LOW)
45317c478bd9Sstevel@tonic-gate 			    SCIntMask |= SBM_BVD1;
45327c478bd9Sstevel@tonic-gate 
45337c478bd9Sstevel@tonic-gate 		if ((client->pin & (PRR_BVD1_STATUS | PRR_BVD1_EVENT)) ==
45347c478bd9Sstevel@tonic-gate 					(PRR_BVD1_STATUS | PRR_BVD1_EVENT))
45357c478bd9Sstevel@tonic-gate 		    if (event_mask & CS_EVENT_BATTERY_DEAD)
45367c478bd9Sstevel@tonic-gate 			    SCIntMask |= SBM_BVD1;
45377c478bd9Sstevel@tonic-gate 
45387c478bd9Sstevel@tonic-gate 	    } /* if (CONFIG_PINREPL_REG_PRESENT) */
45397c478bd9Sstevel@tonic-gate 	} /* if (!SOCKET_IS_IO) */
45407c478bd9Sstevel@tonic-gate 
45417c478bd9Sstevel@tonic-gate 	return (SCIntMask);
45427c478bd9Sstevel@tonic-gate }
45437c478bd9Sstevel@tonic-gate 
45447c478bd9Sstevel@tonic-gate /*
45457c478bd9Sstevel@tonic-gate  * cs_set_socket_event_mask - set the event mask for the socket
45467c478bd9Sstevel@tonic-gate  */
45477c478bd9Sstevel@tonic-gate static int
cs_set_socket_event_mask(cs_socket_t * sp,unsigned event_mask)45487c478bd9Sstevel@tonic-gate cs_set_socket_event_mask(cs_socket_t *sp, unsigned event_mask)
45497c478bd9Sstevel@tonic-gate {
45507c478bd9Sstevel@tonic-gate 	get_socket_t get_socket;
45517c478bd9Sstevel@tonic-gate 	set_socket_t set_socket;
45527c478bd9Sstevel@tonic-gate 
45537c478bd9Sstevel@tonic-gate 	get_socket.socket = sp->socket_num;
45547c478bd9Sstevel@tonic-gate 	if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS)
45557c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
45567c478bd9Sstevel@tonic-gate 
45577c478bd9Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
45587c478bd9Sstevel@tonic-gate 	set_socket.SCIntMask = event_mask;
45597c478bd9Sstevel@tonic-gate 	set_socket.VccLevel = get_socket.VccLevel;
45607c478bd9Sstevel@tonic-gate 	set_socket.Vpp1Level = get_socket.Vpp1Level;
45617c478bd9Sstevel@tonic-gate 	set_socket.Vpp2Level = get_socket.Vpp2Level;
45627c478bd9Sstevel@tonic-gate 	set_socket.IREQRouting = get_socket.IRQRouting;
45637c478bd9Sstevel@tonic-gate 	set_socket.IFType = get_socket.IFType;
45647c478bd9Sstevel@tonic-gate 	set_socket.CtlInd = get_socket.CtlInd;
45657c478bd9Sstevel@tonic-gate 	/* XXX (is ~0 correct here?) reset latched values */
45667c478bd9Sstevel@tonic-gate 	set_socket.State = (unsigned)~0;
45677c478bd9Sstevel@tonic-gate 
45687c478bd9Sstevel@tonic-gate 	if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS)
45697c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
45707c478bd9Sstevel@tonic-gate 
45717c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
45727c478bd9Sstevel@tonic-gate }
45737c478bd9Sstevel@tonic-gate 
45747c478bd9Sstevel@tonic-gate /*
45757c478bd9Sstevel@tonic-gate  * ==== MTD handling section ====
45767c478bd9Sstevel@tonic-gate  */
45777c478bd9Sstevel@tonic-gate static int
cs_deregister_mtd(client_handle_t client_handle)45787c478bd9Sstevel@tonic-gate cs_deregister_mtd(client_handle_t client_handle)
45797c478bd9Sstevel@tonic-gate {
45807c478bd9Sstevel@tonic-gate 
45817c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "cs_deregister_mtd: client_handle 0x%x\n",
45827c478bd9Sstevel@tonic-gate 							(int)client_handle);
45837c478bd9Sstevel@tonic-gate 
45847c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
45857c478bd9Sstevel@tonic-gate }
45867c478bd9Sstevel@tonic-gate 
45877c478bd9Sstevel@tonic-gate /*
45887c478bd9Sstevel@tonic-gate  * ==== memory window handling section ====
45897c478bd9Sstevel@tonic-gate  */
45907c478bd9Sstevel@tonic-gate 
45917c478bd9Sstevel@tonic-gate /*
45927c478bd9Sstevel@tonic-gate  * cs_request_window  - searches through window list for the socket to find a
45937c478bd9Sstevel@tonic-gate  *			memory window that matches the requested criteria;
45947c478bd9Sstevel@tonic-gate  *			this is RequestWindow
45957c478bd9Sstevel@tonic-gate  *
45967c478bd9Sstevel@tonic-gate  * calling:  cs_request_window(client_handle_t, *window_handle_t, win_req_t *)
45977c478bd9Sstevel@tonic-gate  *
45987c478bd9Sstevel@tonic-gate  *	On sucessful return, the window_handle_t * pointed to will
45997c478bd9Sstevel@tonic-gate  *		contain a valid window handle for this window.
46007c478bd9Sstevel@tonic-gate  *
46017c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS - if window found
46027c478bd9Sstevel@tonic-gate  *		 CS_OUT_OF_RESOURCE - if no windows match requirements
46037c478bd9Sstevel@tonic-gate  *		 CS_BAD_HANDLE - client handle is invalid
46047c478bd9Sstevel@tonic-gate  *		 CS_BAD_SIZE - if requested size can not be met
46057c478bd9Sstevel@tonic-gate  *		 CS_BAD_WINDOW - if an internal error occured
46067c478bd9Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
46077c478bd9Sstevel@tonic-gate  *		 CS_NO_CARD - if no card is in socket
46087c478bd9Sstevel@tonic-gate  *		 CS_BAD_ATTRIBUTE - if any of the unsupported Attrbute
46097c478bd9Sstevel@tonic-gate  *					flags are set
46107c478bd9Sstevel@tonic-gate  */
46117c478bd9Sstevel@tonic-gate static int
cs_request_window(client_handle_t client_handle,window_handle_t * wh,win_req_t * rw)46127c478bd9Sstevel@tonic-gate cs_request_window(client_handle_t client_handle,
46137c478bd9Sstevel@tonic-gate 				window_handle_t *wh,
46147c478bd9Sstevel@tonic-gate 				win_req_t *rw)
46157c478bd9Sstevel@tonic-gate {
46167c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
46177c478bd9Sstevel@tonic-gate 	cs_window_t *cw;
46187c478bd9Sstevel@tonic-gate 	client_t *client;
46197c478bd9Sstevel@tonic-gate 	modify_win_t mw;
46207c478bd9Sstevel@tonic-gate 	inquire_window_t iw;
46217c478bd9Sstevel@tonic-gate 	uint32_t aw;
46227c478bd9Sstevel@tonic-gate 	int error;
46237c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
46247c478bd9Sstevel@tonic-gate 	uint32_t socket_num;
46257c478bd9Sstevel@tonic-gate 
46267c478bd9Sstevel@tonic-gate 	/*
46277c478bd9Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
46287c478bd9Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
46297c478bd9Sstevel@tonic-gate 	 */
46307c478bd9Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
46317c478bd9Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
46327c478bd9Sstevel@tonic-gate 
46337c478bd9Sstevel@tonic-gate 	/*
46347c478bd9Sstevel@tonic-gate 	 * Make sure that none of the unsupported flags are set.
46357c478bd9Sstevel@tonic-gate 	 */
46367c478bd9Sstevel@tonic-gate 	if (rw->Attributes &   (/* Compatability */
46377c478bd9Sstevel@tonic-gate 				WIN_PAGED |
46387c478bd9Sstevel@tonic-gate 				WIN_SHARED |
46397c478bd9Sstevel@tonic-gate 				WIN_FIRST_SHARED |
46407c478bd9Sstevel@tonic-gate 				WIN_BINDING_SPECIFIC |
46417c478bd9Sstevel@tonic-gate 				/* CS internal */
46427c478bd9Sstevel@tonic-gate 				WIN_DATA_WIDTH_VALID |
46437c478bd9Sstevel@tonic-gate 				/* IO window flags */
46447c478bd9Sstevel@tonic-gate 				WIN_MEMORY_TYPE_IO |
46457c478bd9Sstevel@tonic-gate 				/* CardBus flags */
46467c478bd9Sstevel@tonic-gate 				WIN_DATA_WIDTH_32 |
46477c478bd9Sstevel@tonic-gate 				WIN_PREFETCH_CACHE_MASK |
46487c478bd9Sstevel@tonic-gate 				WIN_BAR_MASK))
46497c478bd9Sstevel@tonic-gate 	    return (CS_BAD_ATTRIBUTE);
46507c478bd9Sstevel@tonic-gate 
46517c478bd9Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
46527c478bd9Sstevel@tonic-gate 
46537c478bd9Sstevel@tonic-gate 	/*
46547c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
46557c478bd9Sstevel@tonic-gate 	 */
46567c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
46577c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
46587c478bd9Sstevel@tonic-gate 
46597c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
46607c478bd9Sstevel@tonic-gate 
46617c478bd9Sstevel@tonic-gate 	/*
46627c478bd9Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
46637c478bd9Sstevel@tonic-gate 	 */
46647c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
46657c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
46667c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
46677c478bd9Sstevel@tonic-gate 	    return (error);
46687c478bd9Sstevel@tonic-gate 	}
46697c478bd9Sstevel@tonic-gate 
46707c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
46717c478bd9Sstevel@tonic-gate 
46727c478bd9Sstevel@tonic-gate 	/*
46737c478bd9Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
46747c478bd9Sstevel@tonic-gate 	 *	for this client, then return an error.
46757c478bd9Sstevel@tonic-gate 	 */
46767c478bd9Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
46777c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
46787c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
46797c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
46807c478bd9Sstevel@tonic-gate 	    return (CS_NO_CARD);
46817c478bd9Sstevel@tonic-gate 	}
46827c478bd9Sstevel@tonic-gate 
46837c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
46847c478bd9Sstevel@tonic-gate 
46857c478bd9Sstevel@tonic-gate 	socket_num = CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
46867c478bd9Sstevel@tonic-gate 	    GET_CLIENT_FUNCTION(client_handle));
46877c478bd9Sstevel@tonic-gate 
46887c478bd9Sstevel@tonic-gate 
46897c478bd9Sstevel@tonic-gate 	/*
46907c478bd9Sstevel@tonic-gate 	 * See if we can find a window that matches the caller's criteria.
46917c478bd9Sstevel@tonic-gate 	 *	If we can't, then thre's not much more that we can do except
46927c478bd9Sstevel@tonic-gate 	 *	for return an error.
46937c478bd9Sstevel@tonic-gate 	 */
46947c478bd9Sstevel@tonic-gate 	if ((error = cs_find_mem_window(sp->socket_num, rw, &aw)) !=
46957c478bd9Sstevel@tonic-gate 								CS_SUCCESS) {
46967c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
46977c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
46987c478bd9Sstevel@tonic-gate 	    return (error);
46997c478bd9Sstevel@tonic-gate 	}
47007c478bd9Sstevel@tonic-gate 
47017c478bd9Sstevel@tonic-gate 	/*
47027c478bd9Sstevel@tonic-gate 	 * We got a window, now synthesize a new window handle for this
47037c478bd9Sstevel@tonic-gate 	 *	client and get a pointer to the global window structs
47047c478bd9Sstevel@tonic-gate 	 *	and assign this window to this client.
47057c478bd9Sstevel@tonic-gate 	 * We don't have to check for errors from cs_create_window_handle
47067c478bd9Sstevel@tonic-gate 	 *	since that function always returns a valid window handle
47077c478bd9Sstevel@tonic-gate 	 *	if it is given a valid window number.
47087c478bd9Sstevel@tonic-gate 	 */
47097c478bd9Sstevel@tonic-gate 	*wh = cs_create_window_handle(aw);
47107c478bd9Sstevel@tonic-gate 	if ((cw = cs_get_wp(aw)) == NULL) {
47117c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
47127c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
47137c478bd9Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
47147c478bd9Sstevel@tonic-gate 	}
47157c478bd9Sstevel@tonic-gate 
47167c478bd9Sstevel@tonic-gate 	cw->window_handle = *wh;
47177c478bd9Sstevel@tonic-gate 	cw->client_handle = client_handle;
47187c478bd9Sstevel@tonic-gate 	cw->socket_num = sp->socket_num;
47197c478bd9Sstevel@tonic-gate 	cw->state |= (CW_ALLOCATED | CW_MEM);
47207c478bd9Sstevel@tonic-gate 
47217c478bd9Sstevel@tonic-gate 	mw.Attributes = (
47227c478bd9Sstevel@tonic-gate 				rw->Attributes |
47237c478bd9Sstevel@tonic-gate 				WIN_DATA_WIDTH_VALID |
47247c478bd9Sstevel@tonic-gate 				WIN_ACCESS_SPEED_VALID);
47257c478bd9Sstevel@tonic-gate 	mw.AccessSpeed = rw->win_params.AccessSpeed;
47267c478bd9Sstevel@tonic-gate 
47277c478bd9Sstevel@tonic-gate 	if ((error = cs_modify_mem_window(*wh, &mw, rw, socket_num)) !=
47287c478bd9Sstevel@tonic-gate 	    CS_SUCCESS) {
47297c478bd9Sstevel@tonic-gate 	    cw->state = 0;
47307c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
47317c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
47327c478bd9Sstevel@tonic-gate 	    return (error);
47337c478bd9Sstevel@tonic-gate 	}
47347c478bd9Sstevel@tonic-gate 
47357c478bd9Sstevel@tonic-gate 	/*
47367c478bd9Sstevel@tonic-gate 	 * Get any required card offset and pass it back to the client.
47377c478bd9Sstevel@tonic-gate 	 *	This is not defined in the current PCMCIA spec.  It is
47387c478bd9Sstevel@tonic-gate 	 *	an aid to clients that want to use it to generate an
47397c478bd9Sstevel@tonic-gate 	 *	optimum card offset.
47407c478bd9Sstevel@tonic-gate 	 */
47417c478bd9Sstevel@tonic-gate 	iw.window = GET_WINDOW_NUMBER(*wh);
47427c478bd9Sstevel@tonic-gate 	SocketServices(SS_InquireWindow, &iw);
47437c478bd9Sstevel@tonic-gate 
47447c478bd9Sstevel@tonic-gate 	if (iw.mem_win_char.MemWndCaps & WC_CALIGN)
47457c478bd9Sstevel@tonic-gate 	    rw->ReqOffset = rw->Size;
47467c478bd9Sstevel@tonic-gate 	else
47477c478bd9Sstevel@tonic-gate 	    rw->ReqOffset = iw.mem_win_char.ReqOffset;
47487c478bd9Sstevel@tonic-gate 
47497c478bd9Sstevel@tonic-gate 	/*
47507c478bd9Sstevel@tonic-gate 	 * Increment the client's memory window count; this is how we know
47517c478bd9Sstevel@tonic-gate 	 *	when a client has any allocated memory windows.
47527c478bd9Sstevel@tonic-gate 	 */
47537c478bd9Sstevel@tonic-gate 	client->memwin_count++;
47547c478bd9Sstevel@tonic-gate 
47557c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
47567c478bd9Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
47577c478bd9Sstevel@tonic-gate 
47587c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
47597c478bd9Sstevel@tonic-gate }
47607c478bd9Sstevel@tonic-gate 
47617c478bd9Sstevel@tonic-gate /*
47627c478bd9Sstevel@tonic-gate  * cs_release_window - deallocates the window associated with the passed
47637c478bd9Sstevel@tonic-gate  *			window handle; this is ReleaseWindow
47647c478bd9Sstevel@tonic-gate  *
47657c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS if window handle is valid and window was
47667c478bd9Sstevel@tonic-gate  *			sucessfully deallocated
47677c478bd9Sstevel@tonic-gate  *		 CS_BAD_HANDLE if window handle is invalid or if window
47687c478bd9Sstevel@tonic-gate  *			handle is valid but window is not allocated
47697c478bd9Sstevel@tonic-gate  */
47707c478bd9Sstevel@tonic-gate static int
cs_release_window(window_handle_t wh)47717c478bd9Sstevel@tonic-gate cs_release_window(window_handle_t wh)
47727c478bd9Sstevel@tonic-gate {
47737c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
47747c478bd9Sstevel@tonic-gate 	cs_window_t *cw;
47757c478bd9Sstevel@tonic-gate 	client_t *client;
47767c478bd9Sstevel@tonic-gate 	int error;
47777c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
47787c478bd9Sstevel@tonic-gate 
47797c478bd9Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
47807c478bd9Sstevel@tonic-gate 
47817c478bd9Sstevel@tonic-gate 	if (!(cw = cs_find_window(wh))) {
47827c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
47837c478bd9Sstevel@tonic-gate 	    return (CS_BAD_HANDLE);
47847c478bd9Sstevel@tonic-gate 	}
47857c478bd9Sstevel@tonic-gate 
47867c478bd9Sstevel@tonic-gate 	/*
47877c478bd9Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
47887c478bd9Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
47897c478bd9Sstevel@tonic-gate 	 */
47907c478bd9Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(cw->client_handle)) {
47917c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
47927c478bd9Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
47937c478bd9Sstevel@tonic-gate 	}
47947c478bd9Sstevel@tonic-gate 
47957c478bd9Sstevel@tonic-gate 	/*
47967c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
47977c478bd9Sstevel@tonic-gate 	 */
47987c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(cw->client_handle))) == NULL)
47997c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
48007c478bd9Sstevel@tonic-gate 
48017c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
48027c478bd9Sstevel@tonic-gate 
48037c478bd9Sstevel@tonic-gate 	/*
48047c478bd9Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
48057c478bd9Sstevel@tonic-gate 	 */
48067c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(cw->client_handle, &error))) {
48077c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
48087c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
48097c478bd9Sstevel@tonic-gate 	    return (error);
48107c478bd9Sstevel@tonic-gate 	}
48117c478bd9Sstevel@tonic-gate 
48127c478bd9Sstevel@tonic-gate 	/*
48137c478bd9Sstevel@tonic-gate 	 * Mark this window as not in use anymore.
48147c478bd9Sstevel@tonic-gate 	 */
48157c478bd9Sstevel@tonic-gate 	cw->state &= ~CW_WIN_IN_USE;
48167c478bd9Sstevel@tonic-gate 
48177c478bd9Sstevel@tonic-gate 	/*
48187c478bd9Sstevel@tonic-gate 	 * Decrement the client's memory window count; this is how we know
48197c478bd9Sstevel@tonic-gate 	 *	when a client has any allocated memory windows.
48207c478bd9Sstevel@tonic-gate 	 */
48217c478bd9Sstevel@tonic-gate 	if (!(--(client->memwin_count)))
48227c478bd9Sstevel@tonic-gate 	    client->flags &= ~CLIENT_WIN_ALLOCATED;
48237c478bd9Sstevel@tonic-gate 
48247c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
48257c478bd9Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
48267c478bd9Sstevel@tonic-gate 
48277c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
48287c478bd9Sstevel@tonic-gate }
48297c478bd9Sstevel@tonic-gate 
48307c478bd9Sstevel@tonic-gate /*
48317c478bd9Sstevel@tonic-gate  * cs_modify_window - modifies a window's characteristics; this is ModifyWindow
48327c478bd9Sstevel@tonic-gate  */
48337c478bd9Sstevel@tonic-gate static int
cs_modify_window(window_handle_t wh,modify_win_t * mw)48347c478bd9Sstevel@tonic-gate cs_modify_window(window_handle_t wh, modify_win_t *mw)
48357c478bd9Sstevel@tonic-gate {
48367c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
48377c478bd9Sstevel@tonic-gate 	cs_window_t *cw;
48387c478bd9Sstevel@tonic-gate 	client_t *client;
48397c478bd9Sstevel@tonic-gate 	int error;
48407c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
48417c478bd9Sstevel@tonic-gate 
48427c478bd9Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
48437c478bd9Sstevel@tonic-gate 
48447c478bd9Sstevel@tonic-gate 	/*
48457c478bd9Sstevel@tonic-gate 	 * Do some sanity checking - make sure that we can find a pointer
48467c478bd9Sstevel@tonic-gate 	 *	to the window structure, and if we can, get the client that
48477c478bd9Sstevel@tonic-gate 	 *	has allocated that window.
48487c478bd9Sstevel@tonic-gate 	 */
48497c478bd9Sstevel@tonic-gate 	if (!(cw = cs_find_window(wh))) {
48507c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
48517c478bd9Sstevel@tonic-gate 	    return (CS_BAD_HANDLE);
48527c478bd9Sstevel@tonic-gate 	}
48537c478bd9Sstevel@tonic-gate 
48547c478bd9Sstevel@tonic-gate 	/*
48557c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
48567c478bd9Sstevel@tonic-gate 	 */
48577c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(cw->client_handle))) == NULL)
48587c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
48597c478bd9Sstevel@tonic-gate 
48607c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
48617c478bd9Sstevel@tonic-gate 
48627c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(cw->client_handle, &error))) {
48637c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
48647c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
48657c478bd9Sstevel@tonic-gate 	    return (error);
48667c478bd9Sstevel@tonic-gate 	}
48677c478bd9Sstevel@tonic-gate 
48687c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
48697c478bd9Sstevel@tonic-gate 
48707c478bd9Sstevel@tonic-gate 	/*
48717c478bd9Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
48727c478bd9Sstevel@tonic-gate 	 *	for this client, then return an error.
48737c478bd9Sstevel@tonic-gate 	 */
48747c478bd9Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
48757c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
48767c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
48777c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
48787c478bd9Sstevel@tonic-gate 	    return (CS_NO_CARD);
48797c478bd9Sstevel@tonic-gate 	}
48807c478bd9Sstevel@tonic-gate 
48817c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
48827c478bd9Sstevel@tonic-gate 
48837c478bd9Sstevel@tonic-gate 	mw->Attributes &= (
48847c478bd9Sstevel@tonic-gate 				WIN_MEMORY_TYPE_MASK |
48857c478bd9Sstevel@tonic-gate 				WIN_ENABLE |
48867c478bd9Sstevel@tonic-gate 				WIN_ACCESS_SPEED_VALID |
48877c478bd9Sstevel@tonic-gate 				WIN_ACC_ENDIAN_MASK |
48887c478bd9Sstevel@tonic-gate 				WIN_ACC_ORDER_MASK);
48897c478bd9Sstevel@tonic-gate 
48907c478bd9Sstevel@tonic-gate 	mw->Attributes &= ~WIN_DATA_WIDTH_VALID;
48917c478bd9Sstevel@tonic-gate 
4892*c48c3045SToomas Soome 	if ((error = cs_modify_mem_window(wh, mw, NULL, 0)) != CS_SUCCESS) {
48937c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
48947c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
48957c478bd9Sstevel@tonic-gate 	    return (error);
48967c478bd9Sstevel@tonic-gate 	}
48977c478bd9Sstevel@tonic-gate 
48987c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
48997c478bd9Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
49007c478bd9Sstevel@tonic-gate 
49017c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
49027c478bd9Sstevel@tonic-gate }
49037c478bd9Sstevel@tonic-gate 
49047c478bd9Sstevel@tonic-gate /*
49057c478bd9Sstevel@tonic-gate  * cs_modify_mem_window - modifies a window's characteristics; used internally
49067c478bd9Sstevel@tonic-gate  *				by Card Services
49077c478bd9Sstevel@tonic-gate  *
49087c478bd9Sstevel@tonic-gate  *    If *wr is NULL, it means that we're being called by ModifyWindow
49097c478bd9Sstevel@tonic-gate  *    If *wr is non-NULL, it means that we are being called by RequestWindow
49107c478bd9Sstevel@tonic-gate  *	and so we can't use SS_GetWindow.
49117c478bd9Sstevel@tonic-gate  */
49127c478bd9Sstevel@tonic-gate static int
cs_modify_mem_window(window_handle_t wh,modify_win_t * mw,win_req_t * wr,int sn)49137c478bd9Sstevel@tonic-gate cs_modify_mem_window(window_handle_t wh, modify_win_t *mw,
49147c478bd9Sstevel@tonic-gate 						win_req_t *wr, int sn)
49157c478bd9Sstevel@tonic-gate {
49167c478bd9Sstevel@tonic-gate 	get_window_t gw;
49177c478bd9Sstevel@tonic-gate 	set_window_t sw;
49187c478bd9Sstevel@tonic-gate 	set_page_t set_page;
49197c478bd9Sstevel@tonic-gate 	get_page_t get_page;
49207c478bd9Sstevel@tonic-gate 
49217c478bd9Sstevel@tonic-gate 	/*
49227c478bd9Sstevel@tonic-gate 	 * If the win_req_t struct pointer is NULL, it means that
49237c478bd9Sstevel@tonic-gate 	 *	we're being called by ModifyWindow, so get the
49247c478bd9Sstevel@tonic-gate 	 *	current window characteristics.
49257c478bd9Sstevel@tonic-gate 	 */
49267c478bd9Sstevel@tonic-gate 	if (!wr) {
49277c478bd9Sstevel@tonic-gate 	    gw.window = GET_WINDOW_NUMBER(wh);
49287c478bd9Sstevel@tonic-gate 	    if (SocketServices(SS_GetWindow, &gw) != SUCCESS)
49297c478bd9Sstevel@tonic-gate 		return (CS_BAD_WINDOW);
49307c478bd9Sstevel@tonic-gate 	    sw.state = gw.state;
49317c478bd9Sstevel@tonic-gate 	    sw.socket = gw.socket;
49327c478bd9Sstevel@tonic-gate 	    sw.WindowSize = gw.size;
49337c478bd9Sstevel@tonic-gate 	} else {
49347c478bd9Sstevel@tonic-gate 	    sw.state = 0;
49357c478bd9Sstevel@tonic-gate 	    sw.socket = sn;
49367c478bd9Sstevel@tonic-gate 	    sw.WindowSize = wr->Size;
49377c478bd9Sstevel@tonic-gate 	}
49387c478bd9Sstevel@tonic-gate 
49397c478bd9Sstevel@tonic-gate 	/*
49407c478bd9Sstevel@tonic-gate 	 * If we're being called by RequestWindow, we must always have
49417c478bd9Sstevel@tonic-gate 	 *	WIN_ACCESS_SPEED_VALID set since get_window_t is not
49427c478bd9Sstevel@tonic-gate 	 *	defined.
49437c478bd9Sstevel@tonic-gate 	 */
49447c478bd9Sstevel@tonic-gate 	if (mw->Attributes & WIN_ACCESS_SPEED_VALID) {
49457c478bd9Sstevel@tonic-gate 	    convert_speed_t convert_speed;
49467c478bd9Sstevel@tonic-gate 
49477c478bd9Sstevel@tonic-gate 	    convert_speed.Attributes = CONVERT_DEVSPEED_TO_NS;
49487c478bd9Sstevel@tonic-gate 	    convert_speed.devspeed = mw->AccessSpeed;
49497c478bd9Sstevel@tonic-gate 
49507c478bd9Sstevel@tonic-gate 	    if (cs_convert_speed(&convert_speed) != CS_SUCCESS)
49517c478bd9Sstevel@tonic-gate 		return (CS_BAD_SPEED);
49527c478bd9Sstevel@tonic-gate 
49537c478bd9Sstevel@tonic-gate 	    sw.speed = convert_speed.nS;
49547c478bd9Sstevel@tonic-gate 	} else {
49557c478bd9Sstevel@tonic-gate 	    sw.speed = gw.speed;
49567c478bd9Sstevel@tonic-gate 	}
49577c478bd9Sstevel@tonic-gate 
49587c478bd9Sstevel@tonic-gate 	if (!wr) {
49597c478bd9Sstevel@tonic-gate 	    get_page.window = GET_WINDOW_NUMBER(wh);
49607c478bd9Sstevel@tonic-gate 	    get_page.page = 0;
49617c478bd9Sstevel@tonic-gate 	    if (SocketServices(SS_GetPage, &get_page) != SUCCESS)
49627c478bd9Sstevel@tonic-gate 		return (CS_BAD_WINDOW);
49637c478bd9Sstevel@tonic-gate 	    set_page.state = get_page.state;
49647c478bd9Sstevel@tonic-gate 	    set_page.offset = get_page.offset;
49657c478bd9Sstevel@tonic-gate 	} else {
49667c478bd9Sstevel@tonic-gate 	    set_page.state = 0;
49677c478bd9Sstevel@tonic-gate 	    set_page.offset = 0;
49687c478bd9Sstevel@tonic-gate 	}
49697c478bd9Sstevel@tonic-gate 
49707c478bd9Sstevel@tonic-gate 	if (mw->Attributes & WIN_ENABLE) {
49717c478bd9Sstevel@tonic-gate 	    sw.state |= WS_ENABLED;
49727c478bd9Sstevel@tonic-gate 	    set_page.state |= PS_ENABLED;
49737c478bd9Sstevel@tonic-gate 	} else {
49747c478bd9Sstevel@tonic-gate 	    sw.state &= ~WS_ENABLED;
49757c478bd9Sstevel@tonic-gate 	    set_page.state &= ~PS_ENABLED;
49767c478bd9Sstevel@tonic-gate 	}
49777c478bd9Sstevel@tonic-gate 
49787c478bd9Sstevel@tonic-gate 	if (mw->Attributes & WIN_DATA_WIDTH_VALID) {
49797c478bd9Sstevel@tonic-gate 	    if (mw->Attributes & WIN_DATA_WIDTH_16)
49807c478bd9Sstevel@tonic-gate 		sw.state |= WS_16BIT;
49817c478bd9Sstevel@tonic-gate 	    else
49827c478bd9Sstevel@tonic-gate 		sw.state &= ~WS_16BIT;
49837c478bd9Sstevel@tonic-gate 	}
49847c478bd9Sstevel@tonic-gate 
49857c478bd9Sstevel@tonic-gate 	sw.window = GET_WINDOW_NUMBER(wh);
49867c478bd9Sstevel@tonic-gate 	sw.base = 0;
49877c478bd9Sstevel@tonic-gate 
49887c478bd9Sstevel@tonic-gate 	cs_set_acc_attributes(&sw, mw->Attributes);
49897c478bd9Sstevel@tonic-gate 
49907c478bd9Sstevel@tonic-gate 	if (SocketServices(SS_SetWindow, &sw) != SUCCESS)
49917c478bd9Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
49927c478bd9Sstevel@tonic-gate 
49937c478bd9Sstevel@tonic-gate 	if (mw->Attributes & WIN_MEMORY_TYPE_AM)
49947c478bd9Sstevel@tonic-gate 	    set_page.state |= PS_ATTRIBUTE;
49957c478bd9Sstevel@tonic-gate 	else
49967c478bd9Sstevel@tonic-gate 	    set_page.state &= ~PS_ATTRIBUTE;
49977c478bd9Sstevel@tonic-gate 
49987c478bd9Sstevel@tonic-gate 	set_page.window = GET_WINDOW_NUMBER(wh);
49997c478bd9Sstevel@tonic-gate 	set_page.page = 0;
50007c478bd9Sstevel@tonic-gate 	if (SocketServices(SS_SetPage, &set_page) != SUCCESS)
50017c478bd9Sstevel@tonic-gate 	    return (CS_BAD_OFFSET);
50027c478bd9Sstevel@tonic-gate 
50037c478bd9Sstevel@tonic-gate 	/*
50047c478bd9Sstevel@tonic-gate 	 * Return the current base address of this window
50057c478bd9Sstevel@tonic-gate 	 */
50067c478bd9Sstevel@tonic-gate 	if (wr) {
50077c478bd9Sstevel@tonic-gate 	    gw.window = GET_WINDOW_NUMBER(wh);
50087c478bd9Sstevel@tonic-gate 	    if (SocketServices(SS_GetWindow, &gw) != SUCCESS)
50097c478bd9Sstevel@tonic-gate 		return (CS_BAD_WINDOW);
50107c478bd9Sstevel@tonic-gate 
50117c478bd9Sstevel@tonic-gate 	    wr->Base.handle = (acc_handle_t)gw.handle;
50127c478bd9Sstevel@tonic-gate 	}
50137c478bd9Sstevel@tonic-gate 
50147c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
50157c478bd9Sstevel@tonic-gate }
50167c478bd9Sstevel@tonic-gate 
50177c478bd9Sstevel@tonic-gate /*
50187c478bd9Sstevel@tonic-gate  * cs_map_mem_page - sets the card offset of the mapped window
50197c478bd9Sstevel@tonic-gate  */
50207c478bd9Sstevel@tonic-gate static int
cs_map_mem_page(window_handle_t wh,map_mem_page_t * mmp)50217c478bd9Sstevel@tonic-gate cs_map_mem_page(window_handle_t wh, map_mem_page_t *mmp)
50227c478bd9Sstevel@tonic-gate {
50237c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
50247c478bd9Sstevel@tonic-gate 	cs_window_t *cw;
50257c478bd9Sstevel@tonic-gate 	client_t *client;
50267c478bd9Sstevel@tonic-gate 	inquire_window_t iw;
50277c478bd9Sstevel@tonic-gate 	get_window_t gw;
50287c478bd9Sstevel@tonic-gate 	set_page_t set_page;
50297c478bd9Sstevel@tonic-gate 	get_page_t get_page;
50307c478bd9Sstevel@tonic-gate 	int error;
50317c478bd9Sstevel@tonic-gate 	uint32_t size;
50327c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
50337c478bd9Sstevel@tonic-gate 
50347c478bd9Sstevel@tonic-gate 	/*
50357c478bd9Sstevel@tonic-gate 	 * We don't support paged windows, so never allow a page number
50367c478bd9Sstevel@tonic-gate 	 *	of other than 0
50377c478bd9Sstevel@tonic-gate 	 */
50387c478bd9Sstevel@tonic-gate 	if (mmp->Page)
50397c478bd9Sstevel@tonic-gate 	    return (CS_BAD_PAGE);
50407c478bd9Sstevel@tonic-gate 
50417c478bd9Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
50427c478bd9Sstevel@tonic-gate 
50437c478bd9Sstevel@tonic-gate 	/*
50447c478bd9Sstevel@tonic-gate 	 * Do some sanity checking - make sure that we can find a pointer
50457c478bd9Sstevel@tonic-gate 	 *	to the window structure, and if we can, get the client that
50467c478bd9Sstevel@tonic-gate 	 *	has allocated that window.
50477c478bd9Sstevel@tonic-gate 	 */
50487c478bd9Sstevel@tonic-gate 	if (!(cw = cs_find_window(wh))) {
50497c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
50507c478bd9Sstevel@tonic-gate 	    return (CS_BAD_HANDLE);
50517c478bd9Sstevel@tonic-gate 	}
50527c478bd9Sstevel@tonic-gate 
50537c478bd9Sstevel@tonic-gate 	/*
50547c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
50557c478bd9Sstevel@tonic-gate 	 */
50567c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(cw->client_handle))) == NULL)
50577c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
50587c478bd9Sstevel@tonic-gate 
50597c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
50607c478bd9Sstevel@tonic-gate 
50617c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(cw->client_handle, &error))) {
50627c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
50637c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
50647c478bd9Sstevel@tonic-gate 	    return (error);
50657c478bd9Sstevel@tonic-gate 	}
50667c478bd9Sstevel@tonic-gate 
50677c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
50687c478bd9Sstevel@tonic-gate 
50697c478bd9Sstevel@tonic-gate 	/*
50707c478bd9Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
50717c478bd9Sstevel@tonic-gate 	 *	for this client, then return an error.
50727c478bd9Sstevel@tonic-gate 	 */
50737c478bd9Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
50747c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
50757c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
50767c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
50777c478bd9Sstevel@tonic-gate 	    return (CS_NO_CARD);
50787c478bd9Sstevel@tonic-gate 	}
50797c478bd9Sstevel@tonic-gate 
50807c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
50817c478bd9Sstevel@tonic-gate 
50827c478bd9Sstevel@tonic-gate 	gw.window = GET_WINDOW_NUMBER(wh);
50837c478bd9Sstevel@tonic-gate 	SocketServices(SS_GetWindow, &gw);
50847c478bd9Sstevel@tonic-gate 
50857c478bd9Sstevel@tonic-gate 	iw.window = GET_WINDOW_NUMBER(wh);
50867c478bd9Sstevel@tonic-gate 	SocketServices(SS_InquireWindow, &iw);
50877c478bd9Sstevel@tonic-gate 
50887c478bd9Sstevel@tonic-gate 	if (iw.mem_win_char.MemWndCaps & WC_CALIGN)
50897c478bd9Sstevel@tonic-gate 	    size = gw.size;
50907c478bd9Sstevel@tonic-gate 	else
50917c478bd9Sstevel@tonic-gate 	    size = iw.mem_win_char.ReqOffset;
50927c478bd9Sstevel@tonic-gate 
50937c478bd9Sstevel@tonic-gate 	if (((mmp->CardOffset/size)*size) != mmp->CardOffset) {
50947c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
50957c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
50967c478bd9Sstevel@tonic-gate 	    return (CS_BAD_OFFSET);
50977c478bd9Sstevel@tonic-gate 	}
50987c478bd9Sstevel@tonic-gate 
50997c478bd9Sstevel@tonic-gate 	get_page.window = GET_WINDOW_NUMBER(wh);
51007c478bd9Sstevel@tonic-gate 	get_page.page = 0;
51017c478bd9Sstevel@tonic-gate 	SocketServices(SS_GetPage, &get_page);
51027c478bd9Sstevel@tonic-gate 
51037c478bd9Sstevel@tonic-gate 	set_page.window = GET_WINDOW_NUMBER(wh);
51047c478bd9Sstevel@tonic-gate 	set_page.page = 0;
51057c478bd9Sstevel@tonic-gate 	set_page.state = get_page.state;
51067c478bd9Sstevel@tonic-gate 	set_page.offset = mmp->CardOffset;
51077c478bd9Sstevel@tonic-gate 	if (SocketServices(SS_SetPage, &set_page) != SUCCESS) {
51087c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
51097c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
51107c478bd9Sstevel@tonic-gate 	    return (CS_BAD_OFFSET);
51117c478bd9Sstevel@tonic-gate 	}
51127c478bd9Sstevel@tonic-gate 
51137c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
51147c478bd9Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
51157c478bd9Sstevel@tonic-gate 
51167c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
51177c478bd9Sstevel@tonic-gate }
51187c478bd9Sstevel@tonic-gate 
51197c478bd9Sstevel@tonic-gate /*
51207c478bd9Sstevel@tonic-gate  * cs_find_window - finds the window associated with the passed window
51217c478bd9Sstevel@tonic-gate  *			handle; if the window handle is invalid or no
51227c478bd9Sstevel@tonic-gate  *			windows match the passed window handle, NULL
51237c478bd9Sstevel@tonic-gate  *			is returned.  Note that the window must be
51247c478bd9Sstevel@tonic-gate  *			allocated for this function to return a valid
51257c478bd9Sstevel@tonic-gate  *			window pointer.
51267c478bd9Sstevel@tonic-gate  *
51277c478bd9Sstevel@tonic-gate  *	returns: cs_window_t * pointer to the found window
51287c478bd9Sstevel@tonic-gate  *		 NULL if window handle invalid or window not allocated
51297c478bd9Sstevel@tonic-gate  */
51307c478bd9Sstevel@tonic-gate cs_window_t *
cs_find_window(window_handle_t wh)51317c478bd9Sstevel@tonic-gate cs_find_window(window_handle_t wh)
51327c478bd9Sstevel@tonic-gate {
51337c478bd9Sstevel@tonic-gate 	cs_window_t *cw;
51347c478bd9Sstevel@tonic-gate 
51357c478bd9Sstevel@tonic-gate 	if ((GET_WINDOW_NUMBER(wh) > cs_globals.num_windows) ||
51367c478bd9Sstevel@tonic-gate 			(GET_WINDOW_MAGIC(wh) != WINDOW_HANDLE_MAGIC))
51377c478bd9Sstevel@tonic-gate 	    return ((cs_window_t *)NULL);
51387c478bd9Sstevel@tonic-gate 
51397c478bd9Sstevel@tonic-gate 	if ((cw = cs_get_wp(GET_WINDOW_NUMBER(wh))) == NULL)
51407c478bd9Sstevel@tonic-gate 	    return (NULL);
51417c478bd9Sstevel@tonic-gate 
51427c478bd9Sstevel@tonic-gate 	if ((cw->state & CW_ALLOCATED) && (cw->state & CW_MEM))
51437c478bd9Sstevel@tonic-gate 	    return (cw);
51447c478bd9Sstevel@tonic-gate 
51457c478bd9Sstevel@tonic-gate 	return ((cs_window_t *)NULL);
51467c478bd9Sstevel@tonic-gate }
51477c478bd9Sstevel@tonic-gate 
51487c478bd9Sstevel@tonic-gate /*
51497c478bd9Sstevel@tonic-gate  * cs_create_window_handle - creates a unique window handle based on the
51507c478bd9Sstevel@tonic-gate  *				passed window number.
51517c478bd9Sstevel@tonic-gate  */
51527c478bd9Sstevel@tonic-gate static window_handle_t
cs_create_window_handle(uint32_t aw)51537c478bd9Sstevel@tonic-gate cs_create_window_handle(uint32_t aw)
51547c478bd9Sstevel@tonic-gate {
51557c478bd9Sstevel@tonic-gate 	return (WINDOW_HANDLE_MAGIC | (aw & WINDOW_HANDLE_MASK));
51567c478bd9Sstevel@tonic-gate }
51577c478bd9Sstevel@tonic-gate 
51587c478bd9Sstevel@tonic-gate /*
51597c478bd9Sstevel@tonic-gate  * cs_find_mem_window - tries to find a memory window matching the caller's
51607c478bd9Sstevel@tonic-gate  *			criteria
51617c478bd9Sstevel@tonic-gate  *
51627c478bd9Sstevel@tonic-gate  *	We return the first window that matches the requested criteria.
51637c478bd9Sstevel@tonic-gate  *
51647c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS - if memory window found
51657c478bd9Sstevel@tonic-gate  *		 CS_OUT_OF_RESOURCE - if no windows match requirements
51667c478bd9Sstevel@tonic-gate  *		 CS_BAD_SIZE - if requested size can not be met
51677c478bd9Sstevel@tonic-gate  *		 CS_BAD_WINDOW - if an internal error occured
51687c478bd9Sstevel@tonic-gate  */
51697c478bd9Sstevel@tonic-gate /* BEGIN CSTYLED */
51707c478bd9Sstevel@tonic-gate static int
cs_find_mem_window(uint32_t sn,win_req_t * rw,uint32_t * assigned_window)51717c478bd9Sstevel@tonic-gate cs_find_mem_window(uint32_t sn, win_req_t *rw, uint32_t *assigned_window)
51727c478bd9Sstevel@tonic-gate {
51737c478bd9Sstevel@tonic-gate 	uint32_t wn;
51747c478bd9Sstevel@tonic-gate 	int error = CS_OUT_OF_RESOURCE;
51757c478bd9Sstevel@tonic-gate 	uint32_t window_num = PCMCIA_MAX_WINDOWS;
51767c478bd9Sstevel@tonic-gate 	uint32_t min_size = UINT_MAX;
51777c478bd9Sstevel@tonic-gate 	inquire_window_t inquire_window, *iw;
51787c478bd9Sstevel@tonic-gate 	uint32_t MinSize, MaxSize, ReqGran, MemWndCaps, WndCaps;
51797c478bd9Sstevel@tonic-gate 	uint32_t tws;
51807c478bd9Sstevel@tonic-gate 
51817c478bd9Sstevel@tonic-gate 	iw = &inquire_window;
51827c478bd9Sstevel@tonic-gate 
51837c478bd9Sstevel@tonic-gate 	for (wn = 0; wn < cs_globals.num_windows; wn++) {
51847c478bd9Sstevel@tonic-gate 	    cs_window_t *cw;
51857c478bd9Sstevel@tonic-gate 
51867c478bd9Sstevel@tonic-gate 	    /*
51877c478bd9Sstevel@tonic-gate 	     * If we can't get a pointer to this window, we should contine
51887c478bd9Sstevel@tonic-gate 	     *	with scanning the next window, since this window might have
51897c478bd9Sstevel@tonic-gate 	     *	been dropped.
51907c478bd9Sstevel@tonic-gate 	     */
51917c478bd9Sstevel@tonic-gate 	    if ((cw = cs_get_wp(wn)) != NULL) {
51927c478bd9Sstevel@tonic-gate 	      iw->window = wn;
51937c478bd9Sstevel@tonic-gate 
51947c478bd9Sstevel@tonic-gate 	      if (SocketServices(SS_InquireWindow, iw) != SUCCESS)
51957c478bd9Sstevel@tonic-gate 		return (CS_BAD_WINDOW);
51967c478bd9Sstevel@tonic-gate 
51977c478bd9Sstevel@tonic-gate 	      MinSize = iw->mem_win_char.MinSize;
51987c478bd9Sstevel@tonic-gate 	      MaxSize = iw->mem_win_char.MaxSize;
51997c478bd9Sstevel@tonic-gate 	      ReqGran = iw->mem_win_char.ReqGran;
52007c478bd9Sstevel@tonic-gate 	      MemWndCaps = iw->mem_win_char.MemWndCaps;
52017c478bd9Sstevel@tonic-gate 	      WndCaps = iw->WndCaps;
52027c478bd9Sstevel@tonic-gate 
52037c478bd9Sstevel@tonic-gate 	      if (WINDOW_FOR_SOCKET(iw->Sockets, sn) &&
52047c478bd9Sstevel@tonic-gate 					WINDOW_AVAILABLE_FOR_MEM(cw) &&
52057c478bd9Sstevel@tonic-gate 					WndCaps & (WC_COMMON|WC_ATTRIBUTE)) {
52067c478bd9Sstevel@tonic-gate 		if ((error = cs_valid_window_speed(iw, rw->win_params.AccessSpeed)) ==
52077c478bd9Sstevel@tonic-gate 					CS_SUCCESS) {
52087c478bd9Sstevel@tonic-gate 		    error = CS_OUT_OF_RESOURCE;
52097c478bd9Sstevel@tonic-gate 		    if (cs_memwin_space_and_map_ok(iw, rw)) {
52107c478bd9Sstevel@tonic-gate 			error = CS_BAD_SIZE;
52117c478bd9Sstevel@tonic-gate 			if (!rw->Size) {
52127c478bd9Sstevel@tonic-gate 			    min_size = min(min_size, MinSize);
52137c478bd9Sstevel@tonic-gate 			    window_num = wn;
52147c478bd9Sstevel@tonic-gate 			    goto found_window;
52157c478bd9Sstevel@tonic-gate 			} else {
52167c478bd9Sstevel@tonic-gate 			    if (!(MemWndCaps & WC_SIZE)) {
52177c478bd9Sstevel@tonic-gate 				if (rw->Size == MinSize) {
52187c478bd9Sstevel@tonic-gate 				    min_size = MinSize;
52197c478bd9Sstevel@tonic-gate 				    window_num = wn;
52207c478bd9Sstevel@tonic-gate 				    goto found_window;
52217c478bd9Sstevel@tonic-gate 				}
52227c478bd9Sstevel@tonic-gate 			    } else { /* WC_SIZE */
52237c478bd9Sstevel@tonic-gate 			      if (!ReqGran) {
52247c478bd9Sstevel@tonic-gate 				error = CS_BAD_WINDOW;
52257c478bd9Sstevel@tonic-gate 			      } else {
52267c478bd9Sstevel@tonic-gate 				if ((rw->Size >= MinSize) &&
52277c478bd9Sstevel@tonic-gate 							(rw->Size <= MaxSize)) {
52287c478bd9Sstevel@tonic-gate 				    if (MemWndCaps & WC_POW2) {
52297c478bd9Sstevel@tonic-gate 				      unsigned rg = ReqGran;
52307c478bd9Sstevel@tonic-gate 					for (tws = MinSize; tws <= MaxSize;
52317c478bd9Sstevel@tonic-gate 								rg = (rg<<1)) {
52327c478bd9Sstevel@tonic-gate 					    if (rw->Size == tws) {
52337c478bd9Sstevel@tonic-gate 						min_size = tws;
52347c478bd9Sstevel@tonic-gate 						window_num = wn;
52357c478bd9Sstevel@tonic-gate 						goto found_window;
52367c478bd9Sstevel@tonic-gate 					    }
52377c478bd9Sstevel@tonic-gate 					    tws += rg;
52387c478bd9Sstevel@tonic-gate 					  } /* for (tws) */
52397c478bd9Sstevel@tonic-gate 				    } else {
52407c478bd9Sstevel@tonic-gate 					for (tws = MinSize; tws <= MaxSize;
52417c478bd9Sstevel@tonic-gate 							tws += ReqGran) {
52427c478bd9Sstevel@tonic-gate 					    if (rw->Size == tws) {
52437c478bd9Sstevel@tonic-gate 						min_size = tws;
52447c478bd9Sstevel@tonic-gate 						window_num = wn;
52457c478bd9Sstevel@tonic-gate 						goto found_window;
52467c478bd9Sstevel@tonic-gate 					    }
52477c478bd9Sstevel@tonic-gate 					  } /* for (tws) */
52487c478bd9Sstevel@tonic-gate 				    } /* if (!WC_POW2) */
52497c478bd9Sstevel@tonic-gate 				} /* if (Size >= MinSize) */
52507c478bd9Sstevel@tonic-gate 			      } /* if (!ReqGran) */
52517c478bd9Sstevel@tonic-gate 			    } /* if (WC_SIZE) */
52527c478bd9Sstevel@tonic-gate 			} /* if (rw->Size) */
52537c478bd9Sstevel@tonic-gate 		    } /* if (cs_space_and_map_ok) */
52547c478bd9Sstevel@tonic-gate 		} /* if (cs_valid_window_speed) */
52557c478bd9Sstevel@tonic-gate 	      } /* if (WINDOW_FOR_SOCKET) */
52567c478bd9Sstevel@tonic-gate 	    } /* if (cs_get_wp) */
52577c478bd9Sstevel@tonic-gate 	} /* for (wn) */
52587c478bd9Sstevel@tonic-gate 
52597c478bd9Sstevel@tonic-gate 	/*
52607c478bd9Sstevel@tonic-gate 	 * If we got here and the window_num wasn't set by any window
52617c478bd9Sstevel@tonic-gate 	 *	 matches in the above code, it means that we didn't
52627c478bd9Sstevel@tonic-gate 	 *	find a window matching the caller's criteria.
52637c478bd9Sstevel@tonic-gate 	 * If the error is CS_BAD_TYPE, it means that the last reason
52647c478bd9Sstevel@tonic-gate 	 *	that we couldn't match a window was because the caller's
52657c478bd9Sstevel@tonic-gate 	 *	requested speed was out of range of the last window that
52667c478bd9Sstevel@tonic-gate 	 *	we checked.  We convert this error code to CS_OUT_OF_RESOURCE
52677c478bd9Sstevel@tonic-gate 	 *	to conform to the RequestWindow section of the PCMCIA
52687c478bd9Sstevel@tonic-gate 	 *	Card Services spec.
52697c478bd9Sstevel@tonic-gate 	 */
52707c478bd9Sstevel@tonic-gate 	if (window_num == PCMCIA_MAX_WINDOWS) {
52717c478bd9Sstevel@tonic-gate 	    if (error == CS_BAD_TYPE)
52727c478bd9Sstevel@tonic-gate 		error = CS_OUT_OF_RESOURCE;
52737c478bd9Sstevel@tonic-gate 	    return (error);
52747c478bd9Sstevel@tonic-gate 	}
52757c478bd9Sstevel@tonic-gate 
52767c478bd9Sstevel@tonic-gate found_window:
52777c478bd9Sstevel@tonic-gate 	rw->Size = min_size;
52787c478bd9Sstevel@tonic-gate 	*assigned_window = window_num;
52797c478bd9Sstevel@tonic-gate 	iw->window = window_num;
52807c478bd9Sstevel@tonic-gate 	SocketServices(SS_InquireWindow, iw);
52817c478bd9Sstevel@tonic-gate 	MemWndCaps = iw->mem_win_char.MemWndCaps;
52827c478bd9Sstevel@tonic-gate 
52837c478bd9Sstevel@tonic-gate 	if (MemWndCaps & WC_CALIGN)
52847c478bd9Sstevel@tonic-gate 	    rw->Attributes |= WIN_OFFSET_SIZE;
52857c478bd9Sstevel@tonic-gate 	else
52867c478bd9Sstevel@tonic-gate 	    rw->Attributes &= ~WIN_OFFSET_SIZE;
52877c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
52887c478bd9Sstevel@tonic-gate }
52897c478bd9Sstevel@tonic-gate /* END CSTYLED */
52907c478bd9Sstevel@tonic-gate 
52917c478bd9Sstevel@tonic-gate /*
52927c478bd9Sstevel@tonic-gate  * cs_memwin_space_and_map_ok - checks to see if the passed window mapping
52937c478bd9Sstevel@tonic-gate  *				capabilities and window speeds are in the
52947c478bd9Sstevel@tonic-gate  *				range of the passed window.
52957c478bd9Sstevel@tonic-gate  *
52967c478bd9Sstevel@tonic-gate  *	returns: 0 - if the capabilities are out of range
52977c478bd9Sstevel@tonic-gate  *		 1 - if the capabilities are in range
52987c478bd9Sstevel@tonic-gate  */
52997c478bd9Sstevel@tonic-gate static int
cs_memwin_space_and_map_ok(inquire_window_t * iw,win_req_t * rw)53007c478bd9Sstevel@tonic-gate cs_memwin_space_and_map_ok(inquire_window_t *iw, win_req_t *rw)
53017c478bd9Sstevel@tonic-gate {
53027c478bd9Sstevel@tonic-gate 
53037c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
53047c478bd9Sstevel@tonic-gate 	if (cs_debug > 240)
53057c478bd9Sstevel@tonic-gate 	    printf("-> s&m_ok: Attributes 0x%x AccessSpeed 0x%x "
53067c478bd9Sstevel@tonic-gate 					"WndCaps 0x%x MemWndCaps 0x%x\n",
53077c478bd9Sstevel@tonic-gate 					(int)rw->Attributes,
53087c478bd9Sstevel@tonic-gate 					(int)rw->win_params.AccessSpeed,
53097c478bd9Sstevel@tonic-gate 					iw->WndCaps,
53107c478bd9Sstevel@tonic-gate 					iw->mem_win_char.MemWndCaps);
53117c478bd9Sstevel@tonic-gate #endif
53127c478bd9Sstevel@tonic-gate 
53137c478bd9Sstevel@tonic-gate 	if (rw->win_params.AccessSpeed & WIN_USE_WAIT) {
53147c478bd9Sstevel@tonic-gate 	    if (!(iw->WndCaps & WC_WAIT))
53157c478bd9Sstevel@tonic-gate 		return (0);
53167c478bd9Sstevel@tonic-gate 	}
53177c478bd9Sstevel@tonic-gate 
53187c478bd9Sstevel@tonic-gate 	if (rw->Attributes & WIN_DATA_WIDTH_16) {
53197c478bd9Sstevel@tonic-gate 	    if (!(iw->mem_win_char.MemWndCaps & WC_16BIT))
53207c478bd9Sstevel@tonic-gate 		return (0);
53217c478bd9Sstevel@tonic-gate 	} else {
53227c478bd9Sstevel@tonic-gate 	    if (!(iw->mem_win_char.MemWndCaps & WC_8BIT))
53237c478bd9Sstevel@tonic-gate 		return (0);
53247c478bd9Sstevel@tonic-gate 	}
53257c478bd9Sstevel@tonic-gate 
53267c478bd9Sstevel@tonic-gate 	if (rw->Attributes & WIN_MEMORY_TYPE_AM) {
53277c478bd9Sstevel@tonic-gate 	    if (!(iw->WndCaps & WC_ATTRIBUTE))
53287c478bd9Sstevel@tonic-gate 		return (0);
53297c478bd9Sstevel@tonic-gate 	}
53307c478bd9Sstevel@tonic-gate 
53317c478bd9Sstevel@tonic-gate 	if (rw->Attributes & WIN_MEMORY_TYPE_CM) {
53327c478bd9Sstevel@tonic-gate 	    if (!(iw->WndCaps & WC_COMMON))
53337c478bd9Sstevel@tonic-gate 		return (0);
53347c478bd9Sstevel@tonic-gate 	}
53357c478bd9Sstevel@tonic-gate 
53367c478bd9Sstevel@tonic-gate 	return (1);
53377c478bd9Sstevel@tonic-gate }
53387c478bd9Sstevel@tonic-gate 
53397c478bd9Sstevel@tonic-gate /*
53407c478bd9Sstevel@tonic-gate  * cs_valid_window_speed - checks to see if requested window speed
53417c478bd9Sstevel@tonic-gate  *				is in range of passed window
53427c478bd9Sstevel@tonic-gate  *
53437c478bd9Sstevel@tonic-gate  *	The inquire_window_t struct gives us speeds in nS, and we
53447c478bd9Sstevel@tonic-gate  *	get speeds in the AccessSpeed variable as a devspeed code.
53457c478bd9Sstevel@tonic-gate  *
53467c478bd9Sstevel@tonic-gate  *	returns: CS_BAD_SPEED - if AccessSpeed is invalid devspeed code
53477c478bd9Sstevel@tonic-gate  *		 CS_BAD_TYPE -	if AccessSpeed is not in range of valid
53487c478bd9Sstevel@tonic-gate  *				speed for this window
53497c478bd9Sstevel@tonic-gate  *		 CS_SUCCESS -	if window speed is in range
53507c478bd9Sstevel@tonic-gate  */
53517c478bd9Sstevel@tonic-gate static int
cs_valid_window_speed(inquire_window_t * iw,uint32_t AccessSpeed)53527c478bd9Sstevel@tonic-gate cs_valid_window_speed(inquire_window_t *iw, uint32_t AccessSpeed)
53537c478bd9Sstevel@tonic-gate {
53547c478bd9Sstevel@tonic-gate 	convert_speed_t convert_speed, *cs;
53557c478bd9Sstevel@tonic-gate 
53567c478bd9Sstevel@tonic-gate 	cs = &convert_speed;
53577c478bd9Sstevel@tonic-gate 
53587c478bd9Sstevel@tonic-gate 	cs->Attributes = CONVERT_DEVSPEED_TO_NS;
53597c478bd9Sstevel@tonic-gate 	cs->devspeed = AccessSpeed;
53607c478bd9Sstevel@tonic-gate 
53617c478bd9Sstevel@tonic-gate 	if (cs_convert_speed(cs) != CS_SUCCESS)
53627c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SPEED);
53637c478bd9Sstevel@tonic-gate 
53647c478bd9Sstevel@tonic-gate 	if ((cs->nS < iw->mem_win_char.Fastest) ||
53657c478bd9Sstevel@tonic-gate 		(cs->nS > iw->mem_win_char.Slowest))
53667c478bd9Sstevel@tonic-gate 	    return (CS_BAD_TYPE);
53677c478bd9Sstevel@tonic-gate 
53687c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
53697c478bd9Sstevel@tonic-gate }
53707c478bd9Sstevel@tonic-gate 
53717c478bd9Sstevel@tonic-gate /*
53727c478bd9Sstevel@tonic-gate  * ==== IO window handling section ====
53737c478bd9Sstevel@tonic-gate  */
53747c478bd9Sstevel@tonic-gate 
53757c478bd9Sstevel@tonic-gate /*
53767c478bd9Sstevel@tonic-gate  * cs_request_io - provides IO resources for clients; this is RequestIO
53777c478bd9Sstevel@tonic-gate  *
53787c478bd9Sstevel@tonic-gate  *	calling: cs_request_io(client_handle_t, io_req_t *)
53797c478bd9Sstevel@tonic-gate  *
53807c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS - if IO resources available for client
53817c478bd9Sstevel@tonic-gate  *		 CS_OUT_OF_RESOURCE - if no windows match requirements
53827c478bd9Sstevel@tonic-gate  *		 CS_BAD_HANDLE - client handle is invalid
53837c478bd9Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
53847c478bd9Sstevel@tonic-gate  *		 CS_NO_CARD - if no card is in socket
53857c478bd9Sstevel@tonic-gate  *		 CS_BAD_ATTRIBUTE - if any of the unsupported Attribute
53867c478bd9Sstevel@tonic-gate  *					flags are set
53877c478bd9Sstevel@tonic-gate  *		 CS_BAD_BASE - if either or both base port addresses
53887c478bd9Sstevel@tonic-gate  *					are invalid or out of range
53897c478bd9Sstevel@tonic-gate  *		 CS_CONFIGURATION_LOCKED - a RequestConfiguration has
53907c478bd9Sstevel@tonic-gate  *					already been done
53917c478bd9Sstevel@tonic-gate  *		 CS_IN_USE - IO ports already in use or function has
53927c478bd9Sstevel@tonic-gate  *					already been called
53937c478bd9Sstevel@tonic-gate  *		 CS_BAD_WINDOW - if failure while trying to set window
53947c478bd9Sstevel@tonic-gate  *					characteristics
53957c478bd9Sstevel@tonic-gate  */
53967c478bd9Sstevel@tonic-gate static int
cs_request_io(client_handle_t client_handle,io_req_t * ior)53977c478bd9Sstevel@tonic-gate cs_request_io(client_handle_t client_handle, io_req_t *ior)
53987c478bd9Sstevel@tonic-gate {
53997c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
54007c478bd9Sstevel@tonic-gate 	client_t *client;
54017c478bd9Sstevel@tonic-gate 	int error;
54027c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
54037c478bd9Sstevel@tonic-gate 	uint32_t socket_num;
54047c478bd9Sstevel@tonic-gate 
54057c478bd9Sstevel@tonic-gate 	/*
54067c478bd9Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
54077c478bd9Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
54087c478bd9Sstevel@tonic-gate 	 */
54097c478bd9Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
54107c478bd9Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
54117c478bd9Sstevel@tonic-gate 
54127c478bd9Sstevel@tonic-gate 	/*
54137c478bd9Sstevel@tonic-gate 	 * If the client has only requested one IO range, then make sure
54147c478bd9Sstevel@tonic-gate 	 *	that the Attributes2 filed is clear.
54157c478bd9Sstevel@tonic-gate 	 */
54167c478bd9Sstevel@tonic-gate 	if (!ior->NumPorts2)
54177c478bd9Sstevel@tonic-gate 	    ior->Attributes2 = 0;
54187c478bd9Sstevel@tonic-gate 
54197c478bd9Sstevel@tonic-gate 	/*
54207c478bd9Sstevel@tonic-gate 	 * Make sure that none of the unsupported or reserved flags are set.
54217c478bd9Sstevel@tonic-gate 	 */
54227c478bd9Sstevel@tonic-gate 	if ((ior->Attributes1 | ior->Attributes2) &    (IO_SHARED |
54237c478bd9Sstevel@tonic-gate 							IO_FIRST_SHARED |
54247c478bd9Sstevel@tonic-gate 							IO_FORCE_ALIAS_ACCESS |
54257c478bd9Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
54267c478bd9Sstevel@tonic-gate 							IO_DISABLE_WINDOW))
54277c478bd9Sstevel@tonic-gate 	    return (CS_BAD_ATTRIBUTE);
54287c478bd9Sstevel@tonic-gate 
54297c478bd9Sstevel@tonic-gate 	/*
54307c478bd9Sstevel@tonic-gate 	 * Make sure that we have a port count for the first region.
54317c478bd9Sstevel@tonic-gate 	 */
54327c478bd9Sstevel@tonic-gate 	if (!ior->NumPorts1)
54337c478bd9Sstevel@tonic-gate 	    return (CS_BAD_BASE);
54347c478bd9Sstevel@tonic-gate 
54357c478bd9Sstevel@tonic-gate 	/*
54367c478bd9Sstevel@tonic-gate 	 * If we're being asked for multiple IO ranges, then both base port
54377c478bd9Sstevel@tonic-gate 	 *	members must be non-zero.
54387c478bd9Sstevel@tonic-gate 	 */
54397c478bd9Sstevel@tonic-gate 	if ((ior->NumPorts2) && !(ior->BasePort1.base && ior->BasePort2.base))
54407c478bd9Sstevel@tonic-gate 	    return (CS_BAD_BASE);
54417c478bd9Sstevel@tonic-gate 
54427c478bd9Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
54437c478bd9Sstevel@tonic-gate 
54447c478bd9Sstevel@tonic-gate 	/*
54457c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
54467c478bd9Sstevel@tonic-gate 	 */
54477c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
54487c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
54497c478bd9Sstevel@tonic-gate 
54507c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
54517c478bd9Sstevel@tonic-gate 
54527c478bd9Sstevel@tonic-gate 	/*
54537c478bd9Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
54547c478bd9Sstevel@tonic-gate 	 */
54557c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
54567c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
54577c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
54587c478bd9Sstevel@tonic-gate 	    return (error);
54597c478bd9Sstevel@tonic-gate 	}
54607c478bd9Sstevel@tonic-gate 
54617c478bd9Sstevel@tonic-gate 	/*
54627c478bd9Sstevel@tonic-gate 	 * If RequestConfiguration has already been done, we don't allow
54637c478bd9Sstevel@tonic-gate 	 *	this call.
54647c478bd9Sstevel@tonic-gate 	 */
54657c478bd9Sstevel@tonic-gate 	if (client->flags & REQ_CONFIGURATION_DONE) {
54667c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
54677c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
54687c478bd9Sstevel@tonic-gate 	    return (CS_CONFIGURATION_LOCKED);
54697c478bd9Sstevel@tonic-gate 	}
54707c478bd9Sstevel@tonic-gate 
54717c478bd9Sstevel@tonic-gate 	/*
54727c478bd9Sstevel@tonic-gate 	 * If RequestIO has already been done, we don't allow this call.
54737c478bd9Sstevel@tonic-gate 	 */
54747c478bd9Sstevel@tonic-gate 	if (client->flags & REQ_IO_DONE) {
54757c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
54767c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
54777c478bd9Sstevel@tonic-gate 	    return (CS_IN_USE);
54787c478bd9Sstevel@tonic-gate 	}
54797c478bd9Sstevel@tonic-gate 
54807c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
54817c478bd9Sstevel@tonic-gate 
54827c478bd9Sstevel@tonic-gate 	/*
54837c478bd9Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
54847c478bd9Sstevel@tonic-gate 	 *	for this client, then return an error.
54857c478bd9Sstevel@tonic-gate 	 */
54867c478bd9Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
54877c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
54887c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
54897c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
54907c478bd9Sstevel@tonic-gate 	    return (CS_NO_CARD);
54917c478bd9Sstevel@tonic-gate 	}
54927c478bd9Sstevel@tonic-gate 
54937c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
54947c478bd9Sstevel@tonic-gate 
54957c478bd9Sstevel@tonic-gate 	/*
54967c478bd9Sstevel@tonic-gate 	 * If we're only being asked for one IO range, then set BasePort2 to
54977c478bd9Sstevel@tonic-gate 	 *	zero, since we use it later on.
54987c478bd9Sstevel@tonic-gate 	 */
54997c478bd9Sstevel@tonic-gate 	if (!ior->NumPorts2)
55007c478bd9Sstevel@tonic-gate 	    ior->BasePort2.base = 0;
55017c478bd9Sstevel@tonic-gate 
55027c478bd9Sstevel@tonic-gate 	/*
55037c478bd9Sstevel@tonic-gate 	 * See if we can allow Card Services to select the base address
55047c478bd9Sstevel@tonic-gate 	 *	value for this card; if the client has specified a non-zero
55057c478bd9Sstevel@tonic-gate 	 *	base IO address but the card doesn't decode enough IO
55067c478bd9Sstevel@tonic-gate 	 *	address lines to uniquely use that address, then we have
55077c478bd9Sstevel@tonic-gate 	 *	the flexibility to choose an alternative base address.
55087c478bd9Sstevel@tonic-gate 	 * Note that if the client specifies that the card decodes zero
55097c478bd9Sstevel@tonic-gate 	 *	IO address lines, then we have to use the NumPortsX
55107c478bd9Sstevel@tonic-gate 	 *	values to figure out how many address lines the card
55117c478bd9Sstevel@tonic-gate 	 *	actually decodes, and we have to round the NumPortsX
55127c478bd9Sstevel@tonic-gate 	 *	values up to the closest power of two.
55137c478bd9Sstevel@tonic-gate 	 */
55147c478bd9Sstevel@tonic-gate 	if (ior->IOAddrLines) {
55157c478bd9Sstevel@tonic-gate 	    ior->BasePort1.base = IOADDR_FROBNITZ(ior->BasePort1.base,
55167c478bd9Sstevel@tonic-gate 		ior->IOAddrLines);
55177c478bd9Sstevel@tonic-gate 	    ior->BasePort2.base = IOADDR_FROBNITZ(ior->BasePort2.base,
55187c478bd9Sstevel@tonic-gate 		ior->IOAddrLines);
55197c478bd9Sstevel@tonic-gate 	} else {
55207c478bd9Sstevel@tonic-gate 	    ior->BasePort1.base = ior->BasePort1.base &
55217c478bd9Sstevel@tonic-gate 				((IONUMPORTS_FROBNITZ(ior->NumPorts1) +
55227c478bd9Sstevel@tonic-gate 				IONUMPORTS_FROBNITZ(ior->NumPorts2)) - 1);
55237c478bd9Sstevel@tonic-gate 	    ior->BasePort2.base = ior->BasePort2.base &
55247c478bd9Sstevel@tonic-gate 				((IONUMPORTS_FROBNITZ(ior->NumPorts1) +
55257c478bd9Sstevel@tonic-gate 				IONUMPORTS_FROBNITZ(ior->NumPorts2)) - 1);
55267c478bd9Sstevel@tonic-gate 	}
55277c478bd9Sstevel@tonic-gate 
55287c478bd9Sstevel@tonic-gate 	socket_num = CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
55297c478bd9Sstevel@tonic-gate 	    GET_CLIENT_FUNCTION(client_handle));
55307c478bd9Sstevel@tonic-gate 
55317c478bd9Sstevel@tonic-gate 
55327c478bd9Sstevel@tonic-gate #ifdef	USE_IOMMAP_WINDOW
55337c478bd9Sstevel@tonic-gate 	/*
55347c478bd9Sstevel@tonic-gate 	 * Here is where the code diverges, depending on the type of IO windows
55357c478bd9Sstevel@tonic-gate 	 *	that this socket supports.  If this socket supportes memory
55367c478bd9Sstevel@tonic-gate 	 *	mapped IO windows, as determined by cs_init allocating an
55377c478bd9Sstevel@tonic-gate 	 *	io_mmap_window_t structure on the socket structure, then we
55387c478bd9Sstevel@tonic-gate 	 *	use one IO window for all the clients on this socket.  We can
55397c478bd9Sstevel@tonic-gate 	 *	do this safely since a memory mapped IO window implies that
55407c478bd9Sstevel@tonic-gate 	 *	only this socket shares the complete IO space of the card.
55417c478bd9Sstevel@tonic-gate 	 * See the next major block of code for a description of what we do
55427c478bd9Sstevel@tonic-gate 	 *	if a socket doesn't support memory mapped IO windows.
55437c478bd9Sstevel@tonic-gate 	 */
55447c478bd9Sstevel@tonic-gate 	if (sp->io_mmap_window) {
55457c478bd9Sstevel@tonic-gate 	    cs_window_t *cw;
55467c478bd9Sstevel@tonic-gate 	    io_mmap_window_t *imw = sp->io_mmap_window;
55477c478bd9Sstevel@tonic-gate 	    uint32_t offset;
55487c478bd9Sstevel@tonic-gate 
55497c478bd9Sstevel@tonic-gate 		/*
55507c478bd9Sstevel@tonic-gate 		 * If we haven't allocated an IO window yet, do it now.
55517c478bd9Sstevel@tonic-gate 		 * Try to allocate the IO window that cs_init found for us;
55527c478bd9Sstevel@tonic-gate 		 * if that fails, then call cs_find_io_win to find a window.
55537c478bd9Sstevel@tonic-gate 		 */
55547c478bd9Sstevel@tonic-gate 	    if (!imw->count) {
55557c478bd9Sstevel@tonic-gate 		set_window_t set_window;
55567c478bd9Sstevel@tonic-gate 
55577c478bd9Sstevel@tonic-gate 		if (!WINDOW_AVAILABLE_FOR_IO(imw->number)) {
55587c478bd9Sstevel@tonic-gate 		    iowin_char_t iowin_char;
55597c478bd9Sstevel@tonic-gate 
55607c478bd9Sstevel@tonic-gate 		    iowin_char.IOWndCaps = (WC_IO_RANGE_PER_WINDOW |
55617c478bd9Sstevel@tonic-gate 					    WC_8BIT |
55627c478bd9Sstevel@tonic-gate 					    WC_16BIT);
55637c478bd9Sstevel@tonic-gate 		    if ((error = cs_find_io_win(sp->socket_num, &iowin_char,
55647c478bd9Sstevel@tonic-gate 				    &imw->number, &imw->size)) != CS_SUCCESS) {
55657c478bd9Sstevel@tonic-gate 			EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
55667c478bd9Sstevel@tonic-gate 			mutex_exit(&cs_globals.window_lock);
55677c478bd9Sstevel@tonic-gate 		    } /* cs_find_io_win */
55687c478bd9Sstevel@tonic-gate 		} /* if (!WINDOW_AVAILABLE_FOR_IO) */
55697c478bd9Sstevel@tonic-gate 
55707c478bd9Sstevel@tonic-gate 		set_window.socket = socket_num;
55717c478bd9Sstevel@tonic-gate 		set_window.window = imw->number;
55727c478bd9Sstevel@tonic-gate 		set_window.speed = IO_WIN_SPEED;
55737c478bd9Sstevel@tonic-gate 		set_window.base.base = 0;
55747c478bd9Sstevel@tonic-gate 		set_window.WindowSize = imw->size;
55757c478bd9Sstevel@tonic-gate 		set_window.state = (WS_ENABLED | WS_16BIT |
55767c478bd9Sstevel@tonic-gate 				    WS_EXACT_MAPIN | WS_IO);
55777c478bd9Sstevel@tonic-gate 
55787c478bd9Sstevel@tonic-gate 		/* XXX - what to d here? XXX */
55797c478bd9Sstevel@tonic-gate 		cs_set_acc_attributes(&set_window, Attributes);
55807c478bd9Sstevel@tonic-gate 
55817c478bd9Sstevel@tonic-gate 		if (SocketServices(SS_SetWindow, &set_window) != SUCCESS) {
55827c478bd9Sstevel@tonic-gate 		    (void) cs_setup_io_win(socket_num, imw->number,
55837c478bd9Sstevel@tonic-gate 						NULL, NULL, NULL,
55847c478bd9Sstevel@tonic-gate 						(IO_DEALLOCATE_WINDOW |
55857c478bd9Sstevel@tonic-gate 						IO_DISABLE_WINDOW));
55867c478bd9Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
55877c478bd9Sstevel@tonic-gate 		    mutex_exit(&cs_globals.window_lock);
55887c478bd9Sstevel@tonic-gate 		    return (CS_BAD_WINDOW);
55897c478bd9Sstevel@tonic-gate 		}
55907c478bd9Sstevel@tonic-gate 
55917c478bd9Sstevel@tonic-gate 		imw->handle = set_window.base.handle;
55927c478bd9Sstevel@tonic-gate 		imw->size = set_window.WindowSize;
55937c478bd9Sstevel@tonic-gate 
55947c478bd9Sstevel@tonic-gate 		/*
55957c478bd9Sstevel@tonic-gate 		 * Check the caller's port requirements to be sure that they
55967c478bd9Sstevel@tonic-gate 		 *	fit within our found IO window.
55977c478bd9Sstevel@tonic-gate 		 */
55987c478bd9Sstevel@tonic-gate 		if ((ior->BasePort1.base + ior->NumPorts1 +
55997c478bd9Sstevel@tonic-gate 			ior->BasePort2.base + ior->NumPorts2) > imw->size) {
56007c478bd9Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
56017c478bd9Sstevel@tonic-gate 		    mutex_exit(&cs_globals.window_lock);
56027c478bd9Sstevel@tonic-gate 		    return (CS_BAD_BASE);
56037c478bd9Sstevel@tonic-gate 		}
56047c478bd9Sstevel@tonic-gate 
56057c478bd9Sstevel@tonic-gate 		if ((cw = cs_get_wp(imw->number)) == NULL) {
56067c478bd9Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
56077c478bd9Sstevel@tonic-gate 		    mutex_exit(&cs_globals.window_lock);
56087c478bd9Sstevel@tonic-gate 		    return (CS_BAD_WINDOW)
56097c478bd9Sstevel@tonic-gate 		}
56107c478bd9Sstevel@tonic-gate 		cw->state |= (CW_ALLOCATED | CW_IO);
56117c478bd9Sstevel@tonic-gate 
56127c478bd9Sstevel@tonic-gate 	    } /* if (!imw->count) */
56137c478bd9Sstevel@tonic-gate 
56147c478bd9Sstevel@tonic-gate 	    imw->count++;
56157c478bd9Sstevel@tonic-gate 
56167c478bd9Sstevel@tonic-gate 		/*
56177c478bd9Sstevel@tonic-gate 		 * All common access handles for this type of adapter are
56187c478bd9Sstevel@tonic-gate 		 * duped.  We never give the original back to the caller.
56197c478bd9Sstevel@tonic-gate 		 */
56207c478bd9Sstevel@tonic-gate 	    /* XXX need to set endianess and data ordering flags */
56217c478bd9Sstevel@tonic-gate 	    csx_DupHandle(imw->handle, &ior->BasePort1.handle, 0);
56227c478bd9Sstevel@tonic-gate 	    csx_GetHandleOffset(ior->BasePort1.handle, &offset);
56237c478bd9Sstevel@tonic-gate 	    csx_SetHandleOffset(ior->BasePort1.handle,
56247c478bd9Sstevel@tonic-gate 		ior->BasePort1.base + offset);
56257c478bd9Sstevel@tonic-gate 
56267c478bd9Sstevel@tonic-gate 	    if (ior->NumPorts2) {
56277c478bd9Sstevel@tonic-gate 		/* XXX need to set endianess and data ordering flags */
56287c478bd9Sstevel@tonic-gate 		csx_DupHandle(imw->handle, &ior->BasePort2.handle, 0);
56297c478bd9Sstevel@tonic-gate 		csx_GetHandleOffset(ior->BasePort2.handle, &offset);
56307c478bd9Sstevel@tonic-gate 		csx_SetHandleOffset(ior->BasePort2.handle,
56317c478bd9Sstevel@tonic-gate 		    ior->BasePort1.base + offset);
56327c478bd9Sstevel@tonic-gate 	    }
56337c478bd9Sstevel@tonic-gate 
56347c478bd9Sstevel@tonic-gate 		/*
56357c478bd9Sstevel@tonic-gate 		 * We don't really use these two values if we've got a memory
56367c478bd9Sstevel@tonic-gate 		 * mapped IO window since the assigned window number is stored
56377c478bd9Sstevel@tonic-gate 		 * in imw->number.
56387c478bd9Sstevel@tonic-gate 		 */
56397c478bd9Sstevel@tonic-gate 	    client->io_alloc.Window1 = imw->number;
56407c478bd9Sstevel@tonic-gate 	    client->io_alloc.Window2 = PCMCIA_MAX_WINDOWS;
56417c478bd9Sstevel@tonic-gate 
56427c478bd9Sstevel@tonic-gate 	/*
56437c478bd9Sstevel@tonic-gate 	 * This socket supports only IO port IO windows.
56447c478bd9Sstevel@tonic-gate 	 */
56457c478bd9Sstevel@tonic-gate 	} else {
56467c478bd9Sstevel@tonic-gate #else	/* USE_IOMMAP_WINDOW */
56477c478bd9Sstevel@tonic-gate 	{
56487c478bd9Sstevel@tonic-gate #endif	/* USE_IOMMAP_WINDOW */
56497c478bd9Sstevel@tonic-gate 	    baseaddru_t baseaddru;
56507c478bd9Sstevel@tonic-gate 
56517c478bd9Sstevel@tonic-gate 	    baseaddru.base = ior->BasePort1.base;
56527c478bd9Sstevel@tonic-gate 
56537c478bd9Sstevel@tonic-gate 	    if ((error = cs_allocate_io_win(sp->socket_num, ior->Attributes1,
56547c478bd9Sstevel@tonic-gate 		&client->io_alloc.Window1)) != CS_SUCCESS) {
56557c478bd9Sstevel@tonic-gate 
56567c478bd9Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
56577c478bd9Sstevel@tonic-gate 		mutex_exit(&cs_globals.window_lock);
56587c478bd9Sstevel@tonic-gate 		return (error);
56597c478bd9Sstevel@tonic-gate 	    } /* if (cs_allocate_io_win(1)) */
56607c478bd9Sstevel@tonic-gate 
56617c478bd9Sstevel@tonic-gate 		/*
56627c478bd9Sstevel@tonic-gate 		 * Setup the window hardware; if this fails, then we need to
56637c478bd9Sstevel@tonic-gate 		 *	deallocate the previously allocated window.
56647c478bd9Sstevel@tonic-gate 		 */
56657c478bd9Sstevel@tonic-gate 	    if ((error = cs_setup_io_win(socket_num,
56667c478bd9Sstevel@tonic-gate 						client->io_alloc.Window1,
56677c478bd9Sstevel@tonic-gate 						&baseaddru,
56687c478bd9Sstevel@tonic-gate 						&ior->NumPorts1,
56697c478bd9Sstevel@tonic-gate 						ior->IOAddrLines,
56707c478bd9Sstevel@tonic-gate 						ior->Attributes1)) !=
56717c478bd9Sstevel@tonic-gate 								CS_SUCCESS) {
56727c478bd9Sstevel@tonic-gate 		(void) cs_setup_io_win(socket_num, client->io_alloc.Window1,
5673*c48c3045SToomas Soome 					NULL, NULL, 0,
56747c478bd9Sstevel@tonic-gate 					(
56757c478bd9Sstevel@tonic-gate 						IO_DEALLOCATE_WINDOW |
56767c478bd9Sstevel@tonic-gate 						IO_DISABLE_WINDOW));
56777c478bd9Sstevel@tonic-gate 
56787c478bd9Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
56797c478bd9Sstevel@tonic-gate 		mutex_exit(&cs_globals.window_lock);
56807c478bd9Sstevel@tonic-gate 		return (error);
56817c478bd9Sstevel@tonic-gate 	    } /* if (cs_setup_io_win(1)) */
56827c478bd9Sstevel@tonic-gate 
56837c478bd9Sstevel@tonic-gate 	    ior->BasePort1.handle = (acc_handle_t)baseaddru.handle;
56847c478bd9Sstevel@tonic-gate 	    ior->BasePort1.base = baseaddru.base;
56857c478bd9Sstevel@tonic-gate 
56867c478bd9Sstevel@tonic-gate 		/*
56877c478bd9Sstevel@tonic-gate 		 * See if the client wants two IO ranges.
56887c478bd9Sstevel@tonic-gate 		 */
56897c478bd9Sstevel@tonic-gate 	    if (ior->NumPorts2) {
56907c478bd9Sstevel@tonic-gate 		baseaddru_t baseaddru;
56917c478bd9Sstevel@tonic-gate 
56927c478bd9Sstevel@tonic-gate 		baseaddru.base = ior->BasePort2.base;
56937c478bd9Sstevel@tonic-gate 
56947c478bd9Sstevel@tonic-gate 		/*
56957c478bd9Sstevel@tonic-gate 		 * If we fail to allocate this window, then we must deallocate
56967c478bd9Sstevel@tonic-gate 		 *	the previous IO window that is already allocated.
56977c478bd9Sstevel@tonic-gate 		 */
56987c478bd9Sstevel@tonic-gate 		if ((error = cs_allocate_io_win(sp->socket_num,
56997c478bd9Sstevel@tonic-gate 						ior->Attributes2,
57007c478bd9Sstevel@tonic-gate 						&client->io_alloc.Window2)) !=
57017c478bd9Sstevel@tonic-gate 								CS_SUCCESS) {
57027c478bd9Sstevel@tonic-gate 		    (void) cs_setup_io_win(socket_num,
57037c478bd9Sstevel@tonic-gate 						client->io_alloc.Window2,
5704*c48c3045SToomas Soome 						NULL, NULL, 0,
57057c478bd9Sstevel@tonic-gate 						(
57067c478bd9Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
57077c478bd9Sstevel@tonic-gate 							IO_DISABLE_WINDOW));
57087c478bd9Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
57097c478bd9Sstevel@tonic-gate 		    mutex_exit(&cs_globals.window_lock);
57107c478bd9Sstevel@tonic-gate 		    return (error);
57117c478bd9Sstevel@tonic-gate 		} /* if (cs_allocate_io_win(2)) */
57127c478bd9Sstevel@tonic-gate 		/*
57137c478bd9Sstevel@tonic-gate 		 * Setup the window hardware; if this fails, then we need to
57147c478bd9Sstevel@tonic-gate 		 *	deallocate the previously allocated window.
57157c478bd9Sstevel@tonic-gate 		 */
57167c478bd9Sstevel@tonic-gate 		if ((error = cs_setup_io_win(socket_num,
57177c478bd9Sstevel@tonic-gate 						client->io_alloc.Window2,
57187c478bd9Sstevel@tonic-gate 						&baseaddru,
57197c478bd9Sstevel@tonic-gate 						&ior->NumPorts2,
57207c478bd9Sstevel@tonic-gate 						ior->IOAddrLines,
57217c478bd9Sstevel@tonic-gate 						ior->Attributes2)) !=
57227c478bd9Sstevel@tonic-gate 								CS_SUCCESS) {
57237c478bd9Sstevel@tonic-gate 		    (void) cs_setup_io_win(socket_num,
57247c478bd9Sstevel@tonic-gate 						client->io_alloc.Window1,
5725*c48c3045SToomas Soome 						NULL, NULL, 0,
57267c478bd9Sstevel@tonic-gate 						(
57277c478bd9Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
57287c478bd9Sstevel@tonic-gate 							IO_DISABLE_WINDOW));
57297c478bd9Sstevel@tonic-gate 		    (void) cs_setup_io_win(socket_num,
57307c478bd9Sstevel@tonic-gate 						client->io_alloc.Window2,
5731*c48c3045SToomas Soome 						NULL, NULL, 0,
57327c478bd9Sstevel@tonic-gate 						(
57337c478bd9Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
57347c478bd9Sstevel@tonic-gate 							IO_DISABLE_WINDOW));
57357c478bd9Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
57367c478bd9Sstevel@tonic-gate 		    mutex_exit(&cs_globals.window_lock);
57377c478bd9Sstevel@tonic-gate 		    return (error);
57387c478bd9Sstevel@tonic-gate 		} /* if (cs_setup_io_win(2)) */
57397c478bd9Sstevel@tonic-gate 
57407c478bd9Sstevel@tonic-gate 		ior->BasePort2.handle = (acc_handle_t)baseaddru.handle;
57417c478bd9Sstevel@tonic-gate 		ior->BasePort2.base = baseaddru.base;
57427c478bd9Sstevel@tonic-gate 
57437c478bd9Sstevel@tonic-gate 	    } else {
57447c478bd9Sstevel@tonic-gate 		client->io_alloc.Window2 = PCMCIA_MAX_WINDOWS;
57457c478bd9Sstevel@tonic-gate 	    } /* if (ior->NumPorts2) */
57467c478bd9Sstevel@tonic-gate 	} /* if (sp->io_mmap_window) */
57477c478bd9Sstevel@tonic-gate 
57487c478bd9Sstevel@tonic-gate 	/*
57497c478bd9Sstevel@tonic-gate 	 * Save a copy of the client's port information so that we
57507c478bd9Sstevel@tonic-gate 	 *	can use it in the RequestConfiguration call.  We set
57517c478bd9Sstevel@tonic-gate 	 *	the IO window number(s) allocated in the respective
57527c478bd9Sstevel@tonic-gate 	 *	section of code, above.
57537c478bd9Sstevel@tonic-gate 	 */
57547c478bd9Sstevel@tonic-gate 	client->io_alloc.BasePort1.base = ior->BasePort1.base;
57557c478bd9Sstevel@tonic-gate 	client->io_alloc.BasePort1.handle = ior->BasePort1.handle;
57567c478bd9Sstevel@tonic-gate 	client->io_alloc.NumPorts1 = ior->NumPorts1;
57577c478bd9Sstevel@tonic-gate 	client->io_alloc.Attributes1 = ior->Attributes1;
57587c478bd9Sstevel@tonic-gate 	client->io_alloc.BasePort2.base = ior->BasePort2.base;
57597c478bd9Sstevel@tonic-gate 	client->io_alloc.BasePort2.handle = ior->BasePort2.handle;
57607c478bd9Sstevel@tonic-gate 	client->io_alloc.NumPorts2 = ior->NumPorts2;
57617c478bd9Sstevel@tonic-gate 	client->io_alloc.Attributes2 = ior->Attributes2;
57627c478bd9Sstevel@tonic-gate 	client->io_alloc.IOAddrLines = ior->IOAddrLines;
57637c478bd9Sstevel@tonic-gate 
57647c478bd9Sstevel@tonic-gate 	/*
57657c478bd9Sstevel@tonic-gate 	 * Mark this client as having done a successful RequestIO call.
57667c478bd9Sstevel@tonic-gate 	 */
57677c478bd9Sstevel@tonic-gate 	client->flags |= (REQ_IO_DONE | CLIENT_IO_ALLOCATED);
57687c478bd9Sstevel@tonic-gate 
57697c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
57707c478bd9Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
57717c478bd9Sstevel@tonic-gate 
57727c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
57737c478bd9Sstevel@tonic-gate }
57747c478bd9Sstevel@tonic-gate 
57757c478bd9Sstevel@tonic-gate /*
57767c478bd9Sstevel@tonic-gate  * cs_release_io - releases IO resources allocated by RequestIO; this is
57777c478bd9Sstevel@tonic-gate  *			ReleaseIO
57787c478bd9Sstevel@tonic-gate  *
57797c478bd9Sstevel@tonic-gate  *	calling: cs_release_io(client_handle_t, io_req_t *)
57807c478bd9Sstevel@tonic-gate  *
57817c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS - if IO resources sucessfully deallocated
57827c478bd9Sstevel@tonic-gate  *		 CS_BAD_HANDLE - client handle is invalid
57837c478bd9Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
57847c478bd9Sstevel@tonic-gate  *		 CS_CONFIGURATION_LOCKED - a RequestConfiguration has been
57857c478bd9Sstevel@tonic-gate  *				done without a ReleaseConfiguration
57867c478bd9Sstevel@tonic-gate  *		 CS_IN_USE - no RequestIO has been done
57877c478bd9Sstevel@tonic-gate  */
57887c478bd9Sstevel@tonic-gate static int
57897c478bd9Sstevel@tonic-gate cs_release_io(client_handle_t client_handle, io_req_t *ior)
57907c478bd9Sstevel@tonic-gate {
57917c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
57927c478bd9Sstevel@tonic-gate 	client_t *client;
57937c478bd9Sstevel@tonic-gate 	int error;
57947c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
57957c478bd9Sstevel@tonic-gate 	uint32_t socket_num;
57967c478bd9Sstevel@tonic-gate 
57977c478bd9Sstevel@tonic-gate #ifdef	lint
57987c478bd9Sstevel@tonic-gate 	ior = NULL;
57997c478bd9Sstevel@tonic-gate #endif
58007c478bd9Sstevel@tonic-gate 
58017c478bd9Sstevel@tonic-gate 	/*
58027c478bd9Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
58037c478bd9Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
58047c478bd9Sstevel@tonic-gate 	 */
58057c478bd9Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
58067c478bd9Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
58077c478bd9Sstevel@tonic-gate 
58087c478bd9Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
58097c478bd9Sstevel@tonic-gate 
58107c478bd9Sstevel@tonic-gate 	/*
58117c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
58127c478bd9Sstevel@tonic-gate 	 */
58137c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
58147c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
58157c478bd9Sstevel@tonic-gate 
58167c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
58177c478bd9Sstevel@tonic-gate 
58187c478bd9Sstevel@tonic-gate 	/*
58197c478bd9Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
58207c478bd9Sstevel@tonic-gate 	 */
58217c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
58227c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
58237c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
58247c478bd9Sstevel@tonic-gate 	    return (error);
58257c478bd9Sstevel@tonic-gate 	}
58267c478bd9Sstevel@tonic-gate 
58277c478bd9Sstevel@tonic-gate 	/*
58287c478bd9Sstevel@tonic-gate 	 * If RequestConfiguration has already been done, we don't allow
58297c478bd9Sstevel@tonic-gate 	 *	this call.
58307c478bd9Sstevel@tonic-gate 	 */
58317c478bd9Sstevel@tonic-gate 	if (client->flags & REQ_CONFIGURATION_DONE) {
58327c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
58337c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
58347c478bd9Sstevel@tonic-gate 	    return (CS_CONFIGURATION_LOCKED);
58357c478bd9Sstevel@tonic-gate 	}
58367c478bd9Sstevel@tonic-gate 
58377c478bd9Sstevel@tonic-gate 	/*
58387c478bd9Sstevel@tonic-gate 	 * If RequestIO has not been done, we don't allow this call.
58397c478bd9Sstevel@tonic-gate 	 */
58407c478bd9Sstevel@tonic-gate 	if (!(client->flags & REQ_IO_DONE)) {
58417c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
58427c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
58437c478bd9Sstevel@tonic-gate 	    return (CS_IN_USE);
58447c478bd9Sstevel@tonic-gate 	}
58457c478bd9Sstevel@tonic-gate 
58467c478bd9Sstevel@tonic-gate 	socket_num = CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
58477c478bd9Sstevel@tonic-gate 	    GET_CLIENT_FUNCTION(client_handle));
58487c478bd9Sstevel@tonic-gate 
58497c478bd9Sstevel@tonic-gate #ifdef	XXX
58507c478bd9Sstevel@tonic-gate 	/*
58517c478bd9Sstevel@tonic-gate 	 * Check the passed IO allocation with the stored allocation; if
58527c478bd9Sstevel@tonic-gate 	 *	they don't match, then return an error.
58537c478bd9Sstevel@tonic-gate 	 */
58547c478bd9Sstevel@tonic-gate 	if ((client->io_alloc.BasePort1 != ior->BasePort1) ||
58557c478bd9Sstevel@tonic-gate 	    (client->io_alloc.NumPorts1 != ior->NumPorts1) ||
58567c478bd9Sstevel@tonic-gate 	    (client->io_alloc.Attributes1 != ior->Attributes1) ||
58577c478bd9Sstevel@tonic-gate 	    (client->io_alloc.BasePort2 != ior->BasePort2) ||
58587c478bd9Sstevel@tonic-gate 	    (client->io_alloc.NumPorts2 != ior->NumPorts2) ||
58597c478bd9Sstevel@tonic-gate 	    (client->io_alloc.Attributes2 != ior->Attributes2) ||
58607c478bd9Sstevel@tonic-gate 	    (client->io_alloc.IOAddrLines != ior->IOAddrLines)) {
58617c478bd9Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
58627c478bd9Sstevel@tonic-gate 		mutex_exit(&cs_globals.window_lock);
58637c478bd9Sstevel@tonic-gate 		return (CS_BAD_ARGS);
58647c478bd9Sstevel@tonic-gate 	}
58657c478bd9Sstevel@tonic-gate #endif
58667c478bd9Sstevel@tonic-gate 
58677c478bd9Sstevel@tonic-gate #ifdef	USE_IOMMAP_WINDOW
58687c478bd9Sstevel@tonic-gate 	/*
58697c478bd9Sstevel@tonic-gate 	 * The code diverges here depending on if this socket supports
58707c478bd9Sstevel@tonic-gate 	 *	memory mapped IO windows or not.  See comments in the
58717c478bd9Sstevel@tonic-gate 	 *	cs_request_io function for a description of what's
58727c478bd9Sstevel@tonic-gate 	 *	going on here.
58737c478bd9Sstevel@tonic-gate 	 */
58747c478bd9Sstevel@tonic-gate 	if (sp->io_mmap_window) {
58757c478bd9Sstevel@tonic-gate 	    io_mmap_window_t *imw = sp->io_mmap_window;
58767c478bd9Sstevel@tonic-gate 
58777c478bd9Sstevel@tonic-gate 		/*
58787c478bd9Sstevel@tonic-gate 		 * We should never see this; if we do, it's an internal
58797c478bd9Sstevel@tonic-gate 		 *	consistency error.
58807c478bd9Sstevel@tonic-gate 		 */
58817c478bd9Sstevel@tonic-gate 	    if (!imw->count) {
58827c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_release_io: socket %d !imw->count\n",
58837c478bd9Sstevel@tonic-gate 							    sp->socket_num);
58847c478bd9Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
58857c478bd9Sstevel@tonic-gate 		mutex_exit(&cs_globals.window_lock);
58867c478bd9Sstevel@tonic-gate 		return (CS_GENERAL_FAILURE);
58877c478bd9Sstevel@tonic-gate 	    }
58887c478bd9Sstevel@tonic-gate 
58897c478bd9Sstevel@tonic-gate 		/*
58907c478bd9Sstevel@tonic-gate 		 * All common access handles for this type of adapter are
58917c478bd9Sstevel@tonic-gate 		 *	duped. We never give the original back to the caller,
58927c478bd9Sstevel@tonic-gate 		 *	so it's OK to unconditionally free the handle here.
58937c478bd9Sstevel@tonic-gate 		 */
58947c478bd9Sstevel@tonic-gate 	    csx_FreeHandle(&ior->BasePort1.handle);
58957c478bd9Sstevel@tonic-gate 
58967c478bd9Sstevel@tonic-gate 		/*
58977c478bd9Sstevel@tonic-gate 		 * If the IO window referance count is zero, then deallocate
58987c478bd9Sstevel@tonic-gate 		 * and disable this window.
58997c478bd9Sstevel@tonic-gate 		 */
59007c478bd9Sstevel@tonic-gate 	    if (!--(imw->count)) {
59017c478bd9Sstevel@tonic-gate 		(void) cs_setup_io_win(socket_num, imw->number, NULL,
59027c478bd9Sstevel@tonic-gate 								NULL, NULL,
59037c478bd9Sstevel@tonic-gate 						(
59047c478bd9Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
59057c478bd9Sstevel@tonic-gate 							IO_DISABLE_WINDOW));
59067c478bd9Sstevel@tonic-gate 	    } /* if (imw->count) */
59077c478bd9Sstevel@tonic-gate 	} else {
59087c478bd9Sstevel@tonic-gate #endif	/* USE_IOMMAP_WINDOW */
59097c478bd9Sstevel@tonic-gate 	    (void) cs_setup_io_win(socket_num, client->io_alloc.Window1,
5910*c48c3045SToomas Soome 						NULL, NULL, 0,
59117c478bd9Sstevel@tonic-gate 						(
59127c478bd9Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
59137c478bd9Sstevel@tonic-gate 							IO_DISABLE_WINDOW));
59147c478bd9Sstevel@tonic-gate 	    if (client->io_alloc.Window2 != PCMCIA_MAX_WINDOWS)
59157c478bd9Sstevel@tonic-gate 		(void) cs_setup_io_win(socket_num, client->io_alloc.Window2,
5916*c48c3045SToomas Soome 						NULL, NULL, 0,
59177c478bd9Sstevel@tonic-gate 						(
59187c478bd9Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
59197c478bd9Sstevel@tonic-gate 							IO_DISABLE_WINDOW));
59207c478bd9Sstevel@tonic-gate #ifdef	USE_IOMMAP_WINDOW
59217c478bd9Sstevel@tonic-gate 	} /* if (sp->io_mmap_window) */
59227c478bd9Sstevel@tonic-gate #endif	/* USE_IOMMAP_WINDOW */
59237c478bd9Sstevel@tonic-gate 
59247c478bd9Sstevel@tonic-gate 	/*
59257c478bd9Sstevel@tonic-gate 	 * Mark the client as not having any IO resources allocated.
59267c478bd9Sstevel@tonic-gate 	 */
59277c478bd9Sstevel@tonic-gate 	client->flags &= ~(REQ_IO_DONE | CLIENT_IO_ALLOCATED);
59287c478bd9Sstevel@tonic-gate 
59297c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
59307c478bd9Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
59317c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
59327c478bd9Sstevel@tonic-gate }
59337c478bd9Sstevel@tonic-gate 
59347c478bd9Sstevel@tonic-gate /*
59357c478bd9Sstevel@tonic-gate  * cs_find_io_win - finds an IO window that matches the parameters specified
59367c478bd9Sstevel@tonic-gate  *			in the flags argument
59377c478bd9Sstevel@tonic-gate  *
59387c478bd9Sstevel@tonic-gate  *	calling: sn - socket number to look for IO window on
59397c478bd9Sstevel@tonic-gate  *		 *iwc - other window characteristics to match
59407c478bd9Sstevel@tonic-gate  *		 *assigned_window - pointer to where we return the assigned
59417c478bd9Sstevel@tonic-gate  *					window number if we found a window or
59427c478bd9Sstevel@tonic-gate  *					undefined otherwise
59437c478bd9Sstevel@tonic-gate  *		 *size - if non-NULL, the found window size will be stored here
59447c478bd9Sstevel@tonic-gate  *
59457c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS - if IO window found
59467c478bd9Sstevel@tonic-gate  *		 CS_OUT_OF_RESOURCE - if no windows match requirements
59477c478bd9Sstevel@tonic-gate  */
59487c478bd9Sstevel@tonic-gate static int
59497c478bd9Sstevel@tonic-gate cs_find_io_win(uint32_t sn, iowin_char_t *iwc, uint32_t *assigned_window,
59507c478bd9Sstevel@tonic-gate     uint32_t *size)
59517c478bd9Sstevel@tonic-gate {
59527c478bd9Sstevel@tonic-gate 	inquire_window_t inquire_window, *iw;
59537c478bd9Sstevel@tonic-gate 	unsigned wn;
59547c478bd9Sstevel@tonic-gate 
59557c478bd9Sstevel@tonic-gate 	iw = &inquire_window;
59567c478bd9Sstevel@tonic-gate 
59577c478bd9Sstevel@tonic-gate 	for (wn = 0; wn < cs_globals.num_windows; wn++) {
59587c478bd9Sstevel@tonic-gate 	    iowin_char_t *iowc;
59597c478bd9Sstevel@tonic-gate 	    cs_window_t *cw;
59607c478bd9Sstevel@tonic-gate 
59617c478bd9Sstevel@tonic-gate 	    if ((cw = cs_get_wp(wn)) != NULL) {
59627c478bd9Sstevel@tonic-gate 
59637c478bd9Sstevel@tonic-gate 		iw->window = wn;
59647c478bd9Sstevel@tonic-gate 		SocketServices(SS_InquireWindow, iw);
59657c478bd9Sstevel@tonic-gate 
59667c478bd9Sstevel@tonic-gate 		iowc = &iw->iowin_char;
59677c478bd9Sstevel@tonic-gate 
59687c478bd9Sstevel@tonic-gate 		if (WINDOW_FOR_SOCKET(iw->Sockets, sn) &&
59697c478bd9Sstevel@tonic-gate 		    WINDOW_AVAILABLE_FOR_IO(cw) &&
59707c478bd9Sstevel@tonic-gate 		    (iw->WndCaps & WC_IO) &&
59717c478bd9Sstevel@tonic-gate 		    ((iowc->IOWndCaps & iwc->IOWndCaps) == iwc->IOWndCaps)) {
59727c478bd9Sstevel@tonic-gate 
59737c478bd9Sstevel@tonic-gate 			*assigned_window = wn;
59747c478bd9Sstevel@tonic-gate 
59757c478bd9Sstevel@tonic-gate 			if (size)
59767c478bd9Sstevel@tonic-gate 			    *size = iw->iowin_char.ReqGran;
59777c478bd9Sstevel@tonic-gate 			return (CS_SUCCESS);
59787c478bd9Sstevel@tonic-gate 		    } /* if (WINDOW_FOR_SOCKET) */
59797c478bd9Sstevel@tonic-gate 	    } /* cs_get_wp */
59807c478bd9Sstevel@tonic-gate 	} /* for (wn) */
59817c478bd9Sstevel@tonic-gate 
59827c478bd9Sstevel@tonic-gate 	return (CS_OUT_OF_RESOURCE);
59837c478bd9Sstevel@tonic-gate }
59847c478bd9Sstevel@tonic-gate 
59857c478bd9Sstevel@tonic-gate /*
59867c478bd9Sstevel@tonic-gate  * cs_allocate_io_win - finds and allocates an IO window
59877c478bd9Sstevel@tonic-gate  *
59887c478bd9Sstevel@tonic-gate  *	calling: sn - socket number to look for window on
59897c478bd9Sstevel@tonic-gate  *		 Attributes - window attributes in io_req_t.Attributes format
59907c478bd9Sstevel@tonic-gate  *		 *assigned_window - pointer to return assigned window number
59917c478bd9Sstevel@tonic-gate  *
59927c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS - IO window found and allocated
59937c478bd9Sstevel@tonic-gate  *		 CS_OUT_OF_RESOURCE - if cs_find_io_win couldn't find a
59947c478bd9Sstevel@tonic-gate  *				window that matches the passed criteria
59957c478bd9Sstevel@tonic-gate  *
59967c478bd9Sstevel@tonic-gate  * Note: This fucntion will find and allocate an IO window.  The caller is
59977c478bd9Sstevel@tonic-gate  *	responsible for deallocating the window.
59987c478bd9Sstevel@tonic-gate  */
59997c478bd9Sstevel@tonic-gate static int
60007c478bd9Sstevel@tonic-gate cs_allocate_io_win(uint32_t sn, uint32_t Attributes, uint32_t *assigned_window)
60017c478bd9Sstevel@tonic-gate {
60027c478bd9Sstevel@tonic-gate 	iowin_char_t iowin_char;
60037c478bd9Sstevel@tonic-gate 	cs_window_t *cw;
60047c478bd9Sstevel@tonic-gate 
60057c478bd9Sstevel@tonic-gate 	iowin_char.IOWndCaps =
60067c478bd9Sstevel@tonic-gate 		((Attributes & IO_DATA_PATH_WIDTH_16)?WC_16BIT:WC_8BIT);
60077c478bd9Sstevel@tonic-gate 
60087c478bd9Sstevel@tonic-gate 	if (cs_find_io_win(sn, &iowin_char, assigned_window, NULL) ==
60097c478bd9Sstevel@tonic-gate 								CS_SUCCESS) {
60107c478bd9Sstevel@tonic-gate 	    if ((cw = cs_get_wp(*assigned_window)) == NULL)
60117c478bd9Sstevel@tonic-gate 		return (CS_OUT_OF_RESOURCE);
60127c478bd9Sstevel@tonic-gate 
60137c478bd9Sstevel@tonic-gate 	    cw->state = (cw->state & CW_WINDOW_VALID) | (CW_ALLOCATED | CW_IO);
60147c478bd9Sstevel@tonic-gate 	    return (CS_SUCCESS);
60157c478bd9Sstevel@tonic-gate 	}
60167c478bd9Sstevel@tonic-gate 
60177c478bd9Sstevel@tonic-gate 	return (CS_OUT_OF_RESOURCE);
60187c478bd9Sstevel@tonic-gate }
60197c478bd9Sstevel@tonic-gate 
60207c478bd9Sstevel@tonic-gate /*
60217c478bd9Sstevel@tonic-gate  * cs_setup_io_win - setup and destroy an IO window
60227c478bd9Sstevel@tonic-gate  *
60237c478bd9Sstevel@tonic-gate  *	calling: sn - socket number
60247c478bd9Sstevel@tonic-gate  *		 wn - window number
60257c478bd9Sstevel@tonic-gate  * XXX Base - pointer to XXX
60267c478bd9Sstevel@tonic-gate  *		 *NumPorts - pointer to number of allocated ports to return
60277c478bd9Sstevel@tonic-gate  *		 IOAddrLines - number of IO address lines decoded by this card
60287c478bd9Sstevel@tonic-gate  *		 Attributes - either io_req_t attributes, or a combination of
60297c478bd9Sstevel@tonic-gate  *				the following flags:
60307c478bd9Sstevel@tonic-gate  *				    IO_DEALLOCATE_WINDOW - deallocate the window
60317c478bd9Sstevel@tonic-gate  *				    IO_DISABLE_WINDOW - disable the window
60327c478bd9Sstevel@tonic-gate  *				When either of these two flags are set, *Base
60337c478bd9Sstevel@tonic-gate  *				    and NumPorts should be NULL.
60347c478bd9Sstevel@tonic-gate  *
60357c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS - if no failure
60367c478bd9Sstevel@tonic-gate  *		 CS_BAD_WINDOW - if error while trying to configure window
60377c478bd9Sstevel@tonic-gate  *
60387c478bd9Sstevel@tonic-gate  * Note: We use the IOAddrLines value to determine what base address to pass
60397c478bd9Sstevel@tonic-gate  *		to Socket Services.
60407c478bd9Sstevel@tonic-gate  */
60417c478bd9Sstevel@tonic-gate static int
60427c478bd9Sstevel@tonic-gate cs_setup_io_win(uint32_t sn, uint32_t wn, baseaddru_t *Base, uint32_t *NumPorts,
60437c478bd9Sstevel@tonic-gate     uint32_t IOAddrLines, uint32_t Attributes)
60447c478bd9Sstevel@tonic-gate {
60457c478bd9Sstevel@tonic-gate 	set_window_t set_window;
60467c478bd9Sstevel@tonic-gate 
60477c478bd9Sstevel@tonic-gate 	if (Attributes & (IO_DEALLOCATE_WINDOW | IO_DISABLE_WINDOW)) {
60487c478bd9Sstevel@tonic-gate 
60497c478bd9Sstevel@tonic-gate 	    if (Attributes & IO_DEALLOCATE_WINDOW) {
60507c478bd9Sstevel@tonic-gate 		cs_window_t *cw;
60517c478bd9Sstevel@tonic-gate 
60527c478bd9Sstevel@tonic-gate 		if ((cw = cs_get_wp(wn)) == NULL)
60537c478bd9Sstevel@tonic-gate 		    return (CS_BAD_WINDOW);
60547c478bd9Sstevel@tonic-gate 		cw->state &= CW_WINDOW_VALID;
60557c478bd9Sstevel@tonic-gate 
60567c478bd9Sstevel@tonic-gate 	    } /* IO_DEALLOCATE_WINDOW */
60577c478bd9Sstevel@tonic-gate 
60587c478bd9Sstevel@tonic-gate 	    if (Attributes & IO_DISABLE_WINDOW) {
60597c478bd9Sstevel@tonic-gate 		get_window_t get_window;
60607c478bd9Sstevel@tonic-gate 
60617c478bd9Sstevel@tonic-gate 		get_window.window = wn;
60627c478bd9Sstevel@tonic-gate 
60637c478bd9Sstevel@tonic-gate 		SocketServices(SS_GetWindow, &get_window);
60647c478bd9Sstevel@tonic-gate 
60657c478bd9Sstevel@tonic-gate 		set_window.socket = get_window.socket;
60667c478bd9Sstevel@tonic-gate 		set_window.window = get_window.window;
60677c478bd9Sstevel@tonic-gate 		set_window.speed = get_window.speed;
60687c478bd9Sstevel@tonic-gate 		set_window.base = 0;
60697c478bd9Sstevel@tonic-gate 		set_window.WindowSize = get_window.size;
60707c478bd9Sstevel@tonic-gate 		set_window.state = get_window.state & ~WS_ENABLED;
60717c478bd9Sstevel@tonic-gate 
60727c478bd9Sstevel@tonic-gate 		cs_set_acc_attributes(&set_window, Attributes);
60737c478bd9Sstevel@tonic-gate 
60747c478bd9Sstevel@tonic-gate 		SocketServices(SS_SetWindow, &set_window);
60757c478bd9Sstevel@tonic-gate 	    } /* IO_DISABLE_WINDOW */
60767c478bd9Sstevel@tonic-gate 
60777c478bd9Sstevel@tonic-gate 	    return (CS_SUCCESS);
60787c478bd9Sstevel@tonic-gate 
60797c478bd9Sstevel@tonic-gate 	} /* if (IO_DEALLOCATE_WINDOW | IO_DISABLE_WINDOW) */
60807c478bd9Sstevel@tonic-gate 
60817c478bd9Sstevel@tonic-gate 	/*
60827c478bd9Sstevel@tonic-gate 	 * See if we can allow Socket Services to select the base address
60837c478bd9Sstevel@tonic-gate 	 *	value for this card; if the client has specified a non-zero
60847c478bd9Sstevel@tonic-gate 	 *	base IO address but the card doesn't decode enough IO
60857c478bd9Sstevel@tonic-gate 	 *	address lines to uniquely use that address, then we have
60867c478bd9Sstevel@tonic-gate 	 *	the flexibility to choose an alternative base address.
60877c478bd9Sstevel@tonic-gate 	 * XXX - Is this really correct in all cases?
60887c478bd9Sstevel@tonic-gate 	 */
60897c478bd9Sstevel@tonic-gate 	if (!IOAddrLines)
60907c478bd9Sstevel@tonic-gate 	    Base->base = 0;
60917c478bd9Sstevel@tonic-gate 	else
60927c478bd9Sstevel@tonic-gate 	    Base->base = IOADDR_FROBNITZ(Base->base, IOAddrLines);
60937c478bd9Sstevel@tonic-gate 
60947c478bd9Sstevel@tonic-gate 	set_window.socket = sn;
60957c478bd9Sstevel@tonic-gate 	set_window.window = wn;
60967c478bd9Sstevel@tonic-gate 	set_window.speed = IO_WIN_SPEED;
60977c478bd9Sstevel@tonic-gate 	set_window.base = Base->base;
60987c478bd9Sstevel@tonic-gate 	set_window.WindowSize = *NumPorts;
60997c478bd9Sstevel@tonic-gate 	set_window.state = (WS_ENABLED | WS_IO |
61007c478bd9Sstevel@tonic-gate 			((Attributes & IO_DATA_PATH_WIDTH_16)?WS_16BIT:0));
61017c478bd9Sstevel@tonic-gate 
61027c478bd9Sstevel@tonic-gate 	cs_set_acc_attributes(&set_window, Attributes);
61037c478bd9Sstevel@tonic-gate 
61047c478bd9Sstevel@tonic-gate 	if (SocketServices(SS_SetWindow, &set_window) != SUCCESS)
61057c478bd9Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
61067c478bd9Sstevel@tonic-gate 
61077c478bd9Sstevel@tonic-gate 	Base->base = set_window.base;
61087c478bd9Sstevel@tonic-gate 	Base->handle = set_window.handle;
61097c478bd9Sstevel@tonic-gate 	*NumPorts = set_window.WindowSize;
61107c478bd9Sstevel@tonic-gate 
61117c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
61127c478bd9Sstevel@tonic-gate }
61137c478bd9Sstevel@tonic-gate 
61147c478bd9Sstevel@tonic-gate /*
61157c478bd9Sstevel@tonic-gate  * ==== IRQ handling functions ====
61167c478bd9Sstevel@tonic-gate  */
61177c478bd9Sstevel@tonic-gate 
61187c478bd9Sstevel@tonic-gate /*
61197c478bd9Sstevel@tonic-gate  * cs_request_irq - add's client's IRQ handler; supports RequestIRQ
61207c478bd9Sstevel@tonic-gate  *
61217c478bd9Sstevel@tonic-gate  *	calling: irq_req_t.Attributes - must have the IRQ_TYPE_EXCLUSIVE
61227c478bd9Sstevel@tonic-gate  *			flag set, and all other flags clear, or
61237c478bd9Sstevel@tonic-gate  *			CS_BAD_ATTRIBUTE will be returned
61247c478bd9Sstevel@tonic-gate  *
61257c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS - if IRQ resources available for client
61267c478bd9Sstevel@tonic-gate  *		 CS_BAD_IRQ - if IRQ can not be allocated
61277c478bd9Sstevel@tonic-gate  *		 CS_BAD_HANDLE - client handle is invalid
61287c478bd9Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
61297c478bd9Sstevel@tonic-gate  *		 CS_NO_CARD - if no card is in socket
61307c478bd9Sstevel@tonic-gate  *		 CS_BAD_ATTRIBUTE - if any of the unsupported Attribute
61317c478bd9Sstevel@tonic-gate  *					flags are set
61327c478bd9Sstevel@tonic-gate  *		 CS_CONFIGURATION_LOCKED - a RequestConfiguration has
61337c478bd9Sstevel@tonic-gate  *					already been done
61347c478bd9Sstevel@tonic-gate  *		 CS_IN_USE - IRQ ports already in use or function has
61357c478bd9Sstevel@tonic-gate  *					already been called
61367c478bd9Sstevel@tonic-gate  *
61377c478bd9Sstevel@tonic-gate  * Note: We only allow level-mode interrupts.
61387c478bd9Sstevel@tonic-gate  */
61397c478bd9Sstevel@tonic-gate static int
61407c478bd9Sstevel@tonic-gate cs_request_irq(client_handle_t client_handle, irq_req_t *irqr)
61417c478bd9Sstevel@tonic-gate {
61427c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
61437c478bd9Sstevel@tonic-gate 	client_t *client;
61447c478bd9Sstevel@tonic-gate 	set_irq_handler_t set_irq_handler;
61457c478bd9Sstevel@tonic-gate 	int error;
61467c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
61477c478bd9Sstevel@tonic-gate 
61487c478bd9Sstevel@tonic-gate 	/*
61497c478bd9Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
61507c478bd9Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
61517c478bd9Sstevel@tonic-gate 	 */
61527c478bd9Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
61537c478bd9Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
61547c478bd9Sstevel@tonic-gate 
61557c478bd9Sstevel@tonic-gate 	/*
61567c478bd9Sstevel@tonic-gate 	 * Make sure that none of the unsupported or reserved flags are set.
61577c478bd9Sstevel@tonic-gate 	 */
61587c478bd9Sstevel@tonic-gate 	if ((irqr->Attributes &	(IRQ_TYPE_TIME | IRQ_TYPE_DYNAMIC_SHARING |
61597c478bd9Sstevel@tonic-gate 				IRQ_FIRST_SHARED | IRQ_PULSE_ALLOCATED |
61607c478bd9Sstevel@tonic-gate 				IRQ_FORCED_PULSE)) ||
61617c478bd9Sstevel@tonic-gate 		!(irqr->Attributes & IRQ_TYPE_EXCLUSIVE))
61627c478bd9Sstevel@tonic-gate 	    return (CS_BAD_ATTRIBUTE);
61637c478bd9Sstevel@tonic-gate 
61647c478bd9Sstevel@tonic-gate 	/*
61657c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
61667c478bd9Sstevel@tonic-gate 	 */
61677c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
61687c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
61697c478bd9Sstevel@tonic-gate 
61707c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
61717c478bd9Sstevel@tonic-gate 
61727c478bd9Sstevel@tonic-gate 	/*
61737c478bd9Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
61747c478bd9Sstevel@tonic-gate 	 */
61757c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
61767c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
61777c478bd9Sstevel@tonic-gate 	    return (error);
61787c478bd9Sstevel@tonic-gate 	}
61797c478bd9Sstevel@tonic-gate 
61807c478bd9Sstevel@tonic-gate 	/*
61817c478bd9Sstevel@tonic-gate 	 * If RequestConfiguration has already been done, we don't allow
61827c478bd9Sstevel@tonic-gate 	 *	this call.
61837c478bd9Sstevel@tonic-gate 	 */
61847c478bd9Sstevel@tonic-gate 	if (client->flags & REQ_CONFIGURATION_DONE) {
61857c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
61867c478bd9Sstevel@tonic-gate 	    return (CS_CONFIGURATION_LOCKED);
61877c478bd9Sstevel@tonic-gate 	}
61887c478bd9Sstevel@tonic-gate 
61897c478bd9Sstevel@tonic-gate 	/*
61907c478bd9Sstevel@tonic-gate 	 * If RequestIRQ has already been done, we don't allow this call.
61917c478bd9Sstevel@tonic-gate 	 */
61927c478bd9Sstevel@tonic-gate 	if (client->flags & REQ_IRQ_DONE) {
61937c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
61947c478bd9Sstevel@tonic-gate 	    return (CS_IN_USE);
61957c478bd9Sstevel@tonic-gate 	}
61967c478bd9Sstevel@tonic-gate 
61977c478bd9Sstevel@tonic-gate 	/*
61987c478bd9Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
61997c478bd9Sstevel@tonic-gate 	 *	for this client, then return an error.
62007c478bd9Sstevel@tonic-gate 	 */
62017c478bd9Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
62027c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
62037c478bd9Sstevel@tonic-gate 	    return (CS_NO_CARD);
62047c478bd9Sstevel@tonic-gate 	}
62057c478bd9Sstevel@tonic-gate 
62067c478bd9Sstevel@tonic-gate 	/*
62077c478bd9Sstevel@tonic-gate 	 * Set up the parameters and ask Socket Services to give us an IRQ
62087c478bd9Sstevel@tonic-gate 	 *	for this client.  We don't really do much, since the IRQ
62097c478bd9Sstevel@tonic-gate 	 *	resources are managed by SS and the kernel.  We also don't
62107c478bd9Sstevel@tonic-gate 	 *	care which IRQ level we are given.
62117c478bd9Sstevel@tonic-gate 	 */
62127c478bd9Sstevel@tonic-gate 	set_irq_handler.socket =
62137c478bd9Sstevel@tonic-gate 		CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
62147c478bd9Sstevel@tonic-gate 					GET_CLIENT_FUNCTION(client_handle));
62157c478bd9Sstevel@tonic-gate 	set_irq_handler.irq = IRQ_ANY;
62167c478bd9Sstevel@tonic-gate 
62177c478bd9Sstevel@tonic-gate 	set_irq_handler.handler_id = client_handle;
62187c478bd9Sstevel@tonic-gate 	set_irq_handler.handler = (f_t *)irqr->irq_handler;
62197c478bd9Sstevel@tonic-gate 	set_irq_handler.arg1 = irqr->irq_handler_arg;
62207c478bd9Sstevel@tonic-gate 	set_irq_handler.arg2 = NULL;
62217c478bd9Sstevel@tonic-gate 
62227c478bd9Sstevel@tonic-gate 	if ((error = SocketServices(SS_SetIRQHandler,
62237c478bd9Sstevel@tonic-gate 					&set_irq_handler)) != SUCCESS) {
62247c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
62257c478bd9Sstevel@tonic-gate 	    return (CS_BAD_IRQ);
62267c478bd9Sstevel@tonic-gate 	}
62277c478bd9Sstevel@tonic-gate 
62287c478bd9Sstevel@tonic-gate 	irqr->iblk_cookie = set_irq_handler.iblk_cookie;
62297c478bd9Sstevel@tonic-gate 	irqr->idev_cookie = set_irq_handler.idev_cookie;
62307c478bd9Sstevel@tonic-gate 
62317c478bd9Sstevel@tonic-gate 	/*
62327c478bd9Sstevel@tonic-gate 	 * Save the allocated IRQ information for this client.
62337c478bd9Sstevel@tonic-gate 	 */
62347c478bd9Sstevel@tonic-gate 	client->irq_alloc.Attributes = irqr->Attributes;
62357c478bd9Sstevel@tonic-gate 	client->irq_alloc.irq = set_irq_handler.irq;
62367c478bd9Sstevel@tonic-gate 	client->irq_alloc.handler_id = set_irq_handler.handler_id;
62377c478bd9Sstevel@tonic-gate 	client->irq_alloc.irq_handler = (f_t *)set_irq_handler.handler;
62387c478bd9Sstevel@tonic-gate 	client->irq_alloc.irq_handler_arg1 = set_irq_handler.arg1;
62397c478bd9Sstevel@tonic-gate 	client->irq_alloc.irq_handler_arg2 = set_irq_handler.arg2;
62407c478bd9Sstevel@tonic-gate 
62417c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
62427c478bd9Sstevel@tonic-gate 	if (cs_debug > 0)
62437c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_request_irq: socket %d irqr->Attributes 0x%x "
62447c478bd9Sstevel@tonic-gate 						"set_irq_handler.irq 0x%x\n",
62457c478bd9Sstevel@tonic-gate 						sp->socket_num,
62467c478bd9Sstevel@tonic-gate 						(int)irqr->Attributes,
62477c478bd9Sstevel@tonic-gate 						set_irq_handler.irq);
62487c478bd9Sstevel@tonic-gate #endif
62497c478bd9Sstevel@tonic-gate 
62507c478bd9Sstevel@tonic-gate 	/*
62517c478bd9Sstevel@tonic-gate 	 * Mark this client as having done a successful RequestIRQ call.
62527c478bd9Sstevel@tonic-gate 	 */
62537c478bd9Sstevel@tonic-gate 	client->flags |= (REQ_IRQ_DONE | CLIENT_IRQ_ALLOCATED);
62547c478bd9Sstevel@tonic-gate 
62557c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
62567c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
62577c478bd9Sstevel@tonic-gate }
62587c478bd9Sstevel@tonic-gate 
62597c478bd9Sstevel@tonic-gate /*
62607c478bd9Sstevel@tonic-gate  * cs_release_irq - releases IRQ resources allocated by RequestIRQ; this is
62617c478bd9Sstevel@tonic-gate  *			ReleaseIRQ
62627c478bd9Sstevel@tonic-gate  *
62637c478bd9Sstevel@tonic-gate  *	calling: cs_release_irq(client_handle_t, irq_req_t *)
62647c478bd9Sstevel@tonic-gate  *
62657c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS - if IRQ resources sucessfully deallocated
62667c478bd9Sstevel@tonic-gate  *		 CS_BAD_IRQ - if IRQ can not be deallocated
62677c478bd9Sstevel@tonic-gate  *		 CS_BAD_HANDLE - client handle is invalid
62687c478bd9Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
62697c478bd9Sstevel@tonic-gate  *		 CS_CONFIGURATION_LOCKED - a RequestConfiguration has been
62707c478bd9Sstevel@tonic-gate  *				done without a ReleaseConfiguration
62717c478bd9Sstevel@tonic-gate  *		 CS_IN_USE - no RequestIRQ has been done
62727c478bd9Sstevel@tonic-gate  */
62737c478bd9Sstevel@tonic-gate static int
62747c478bd9Sstevel@tonic-gate cs_release_irq(client_handle_t client_handle, irq_req_t *irqr)
62757c478bd9Sstevel@tonic-gate {
62767c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
62777c478bd9Sstevel@tonic-gate 	client_t *client;
62787c478bd9Sstevel@tonic-gate 	clear_irq_handler_t clear_irq_handler;
62797c478bd9Sstevel@tonic-gate 	int error;
62807c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
62817c478bd9Sstevel@tonic-gate 
62827c478bd9Sstevel@tonic-gate #ifdef	lint
62837c478bd9Sstevel@tonic-gate 	irqr = NULL;
62847c478bd9Sstevel@tonic-gate #endif
62857c478bd9Sstevel@tonic-gate 
62867c478bd9Sstevel@tonic-gate 	/*
62877c478bd9Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
62887c478bd9Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
62897c478bd9Sstevel@tonic-gate 	 */
62907c478bd9Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
62917c478bd9Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
62927c478bd9Sstevel@tonic-gate 
62937c478bd9Sstevel@tonic-gate 	/*
62947c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
62957c478bd9Sstevel@tonic-gate 	 */
62967c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
62977c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
62987c478bd9Sstevel@tonic-gate 
62997c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
63007c478bd9Sstevel@tonic-gate 
63017c478bd9Sstevel@tonic-gate 	/*
63027c478bd9Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
63037c478bd9Sstevel@tonic-gate 	 */
63047c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
63057c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
63067c478bd9Sstevel@tonic-gate 	    return (error);
63077c478bd9Sstevel@tonic-gate 	}
63087c478bd9Sstevel@tonic-gate 
63097c478bd9Sstevel@tonic-gate 	/*
63107c478bd9Sstevel@tonic-gate 	 * If RequestConfiguration has already been done, we don't allow
63117c478bd9Sstevel@tonic-gate 	 *	this call.
63127c478bd9Sstevel@tonic-gate 	 */
63137c478bd9Sstevel@tonic-gate 	if (client->flags & REQ_CONFIGURATION_DONE) {
63147c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
63157c478bd9Sstevel@tonic-gate 	    return (CS_CONFIGURATION_LOCKED);
63167c478bd9Sstevel@tonic-gate 	}
63177c478bd9Sstevel@tonic-gate 
63187c478bd9Sstevel@tonic-gate 	/*
63197c478bd9Sstevel@tonic-gate 	 * If RequestIRQ has not been done, we don't allow this call.
63207c478bd9Sstevel@tonic-gate 	 */
63217c478bd9Sstevel@tonic-gate 	if (!(client->flags & REQ_IRQ_DONE)) {
63227c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
63237c478bd9Sstevel@tonic-gate 	    return (CS_IN_USE);
63247c478bd9Sstevel@tonic-gate 	}
63257c478bd9Sstevel@tonic-gate 
63267c478bd9Sstevel@tonic-gate 	/*
63277c478bd9Sstevel@tonic-gate 	 * Tell Socket Services that we want to deregister this client's
63287c478bd9Sstevel@tonic-gate 	 *	IRQ handler.
63297c478bd9Sstevel@tonic-gate 	 */
63307c478bd9Sstevel@tonic-gate 	clear_irq_handler.socket =
63317c478bd9Sstevel@tonic-gate 		CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
63327c478bd9Sstevel@tonic-gate 				GET_CLIENT_FUNCTION(client_handle));
63337c478bd9Sstevel@tonic-gate 	clear_irq_handler.handler_id = client->irq_alloc.handler_id;
63347c478bd9Sstevel@tonic-gate 	clear_irq_handler.handler = (f_t *)client->irq_alloc.irq_handler;
63357c478bd9Sstevel@tonic-gate 
63367c478bd9Sstevel@tonic-gate 	/*
63377c478bd9Sstevel@tonic-gate 	 * At this point, we should never fail this SS call; if we do, it
63387c478bd9Sstevel@tonic-gate 	 *	means that there is an internal consistancy error in either
63397c478bd9Sstevel@tonic-gate 	 *	Card Services or Socket Services.
63407c478bd9Sstevel@tonic-gate 	 */
63417c478bd9Sstevel@tonic-gate 	if ((error = SocketServices(SS_ClearIRQHandler, &clear_irq_handler)) !=
63427c478bd9Sstevel@tonic-gate 								SUCCESS) {
63437c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
63447c478bd9Sstevel@tonic-gate 	    return (CS_BAD_IRQ);
63457c478bd9Sstevel@tonic-gate 	}
63467c478bd9Sstevel@tonic-gate 
63477c478bd9Sstevel@tonic-gate 	/*
63487c478bd9Sstevel@tonic-gate 	 * Mark the client as not having any IRQ resources allocated.
63497c478bd9Sstevel@tonic-gate 	 */
63507c478bd9Sstevel@tonic-gate 	client->flags &= ~(REQ_IRQ_DONE | CLIENT_IRQ_ALLOCATED);
63517c478bd9Sstevel@tonic-gate 
63527c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
63537c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
63547c478bd9Sstevel@tonic-gate }
63557c478bd9Sstevel@tonic-gate 
63567c478bd9Sstevel@tonic-gate /*
63577c478bd9Sstevel@tonic-gate  * ==== configuration handling functions ====
63587c478bd9Sstevel@tonic-gate  */
63597c478bd9Sstevel@tonic-gate 
63607c478bd9Sstevel@tonic-gate /*
63617c478bd9Sstevel@tonic-gate  * cs_request_configuration - sets up socket and card configuration on behalf
63627c478bd9Sstevel@tonic-gate  *		of the client; this is RequestConfiguration
63637c478bd9Sstevel@tonic-gate  *
63647c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS - if configuration sucessfully set
63657c478bd9Sstevel@tonic-gate  *		 CS_BAD_SOCKET - if Socket Services returns an error
63667c478bd9Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
63677c478bd9Sstevel@tonic-gate  *		 CS_BAD_ATTRIBUTE - if any unsupported or reserved flags
63687c478bd9Sstevel@tonic-gate  *					are set
63697c478bd9Sstevel@tonic-gate  *		 CS_BAD_TYPE - if the socket doesn't support a mem and IO
63707c478bd9Sstevel@tonic-gate  *				interface (SOCKET_INTERFACE_MEMORY_AND_IO set)
63717c478bd9Sstevel@tonic-gate  *		 CS_CONFIGURATION_LOCKED - a RequestConfiguration has
63727c478bd9Sstevel@tonic-gate  *					already been done
63737c478bd9Sstevel@tonic-gate  *		 CS_BAD_VCC - if Vcc value is not supported by socket
63747c478bd9Sstevel@tonic-gate  *		 CS_BAD_VPP1 - if Vpp1 value is not supported by socket
63757c478bd9Sstevel@tonic-gate  *		 CS_BAD_VPP2 - if Vpp2 value is not supported by socket
63767c478bd9Sstevel@tonic-gate  *
63777c478bd9Sstevel@tonic-gate  * Bug ID: 1193637 - Card Services RequestConfiguration does not conform
63787c478bd9Sstevel@tonic-gate  *	to PCMCIA standard
63797c478bd9Sstevel@tonic-gate  * We allow clients to do a RequestConfiguration even if they haven't
63807c478bd9Sstevel@tonic-gate  *	done a RequestIO or RequestIRQ.
63817c478bd9Sstevel@tonic-gate  */
63827c478bd9Sstevel@tonic-gate static int
63837c478bd9Sstevel@tonic-gate cs_request_configuration(client_handle_t client_handle, config_req_t *cr)
63847c478bd9Sstevel@tonic-gate {
63857c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
63867c478bd9Sstevel@tonic-gate 	client_t *client;
63877c478bd9Sstevel@tonic-gate 	volatile config_regs_t *crt;
63887c478bd9Sstevel@tonic-gate 	set_socket_t set_socket;
63897c478bd9Sstevel@tonic-gate 	get_socket_t get_socket;
63907c478bd9Sstevel@tonic-gate 	acc_handle_t cis_handle;
63917c478bd9Sstevel@tonic-gate 	int error;
63927c478bd9Sstevel@tonic-gate 	uint32_t newoffset;
63937c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
63947c478bd9Sstevel@tonic-gate 
63957c478bd9Sstevel@tonic-gate 	/*
63967c478bd9Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
63977c478bd9Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
63987c478bd9Sstevel@tonic-gate 	 */
63997c478bd9Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
64007c478bd9Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
64017c478bd9Sstevel@tonic-gate 
64027c478bd9Sstevel@tonic-gate #ifdef	XXX
64037c478bd9Sstevel@tonic-gate 	/*
64047c478bd9Sstevel@tonic-gate 	 * If the client specifies Vcc = 0 and any non-zero value for
64057c478bd9Sstevel@tonic-gate 	 *	either of the Vpp members, that's an illegal condition.
64067c478bd9Sstevel@tonic-gate 	 */
64077c478bd9Sstevel@tonic-gate 	if (!(cr->Vcc) && (cr->Vpp1 || cr->Vpp2))
64087c478bd9Sstevel@tonic-gate 	    return (CS_BAD_VCC);
64097c478bd9Sstevel@tonic-gate #endif
64107c478bd9Sstevel@tonic-gate 
64117c478bd9Sstevel@tonic-gate 	/*
64127c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
64137c478bd9Sstevel@tonic-gate 	 */
64147c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
64157c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
64167c478bd9Sstevel@tonic-gate 
64177c478bd9Sstevel@tonic-gate 	/*
64187c478bd9Sstevel@tonic-gate 	 * If the client is asking for a memory and IO interface on this
64197c478bd9Sstevel@tonic-gate 	 *	socket, then check the socket capabilities to be sure that
64207c478bd9Sstevel@tonic-gate 	 *	this socket supports this configuration.
64217c478bd9Sstevel@tonic-gate 	 */
64227c478bd9Sstevel@tonic-gate 	if (cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO) {
64237c478bd9Sstevel@tonic-gate 	    inquire_socket_t inquire_socket;
64247c478bd9Sstevel@tonic-gate 
64257c478bd9Sstevel@tonic-gate 	    inquire_socket.socket = sp->socket_num;
64267c478bd9Sstevel@tonic-gate 
64277c478bd9Sstevel@tonic-gate 	    if (SocketServices(SS_InquireSocket, &inquire_socket) != SUCCESS)
64287c478bd9Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
64297c478bd9Sstevel@tonic-gate 
64307c478bd9Sstevel@tonic-gate 	    if (!(inquire_socket.SocketCaps & IF_IO))
64317c478bd9Sstevel@tonic-gate 		return (CS_BAD_TYPE);
64327c478bd9Sstevel@tonic-gate 
64337c478bd9Sstevel@tonic-gate 	} /* if (SOCKET_INTERFACE_MEMORY_AND_IO) */
64347c478bd9Sstevel@tonic-gate 
64357c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
64367c478bd9Sstevel@tonic-gate 
64377c478bd9Sstevel@tonic-gate 	/*
64387c478bd9Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
64397c478bd9Sstevel@tonic-gate 	 */
64407c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
64417c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
64427c478bd9Sstevel@tonic-gate 	    return (error);
64437c478bd9Sstevel@tonic-gate 	}
64447c478bd9Sstevel@tonic-gate 
64457c478bd9Sstevel@tonic-gate 	/*
64467c478bd9Sstevel@tonic-gate 	 * If RequestConfiguration has already been done, we don't allow
64477c478bd9Sstevel@tonic-gate 	 *	this call.
64487c478bd9Sstevel@tonic-gate 	 */
64497c478bd9Sstevel@tonic-gate 	if (client->flags & REQ_CONFIGURATION_DONE) {
64507c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
64517c478bd9Sstevel@tonic-gate 	    return (CS_CONFIGURATION_LOCKED);
64527c478bd9Sstevel@tonic-gate 	}
64537c478bd9Sstevel@tonic-gate 
64547c478bd9Sstevel@tonic-gate 	/*
64557c478bd9Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
64567c478bd9Sstevel@tonic-gate 	 *	for this client, then return an error.
64577c478bd9Sstevel@tonic-gate 	 */
64587c478bd9Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
64597c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
64607c478bd9Sstevel@tonic-gate 	    return (CS_NO_CARD);
64617c478bd9Sstevel@tonic-gate 	}
64627c478bd9Sstevel@tonic-gate 
64637c478bd9Sstevel@tonic-gate 	/*
64647c478bd9Sstevel@tonic-gate 	 * At this point, most of the client's calling parameters have been
64657c478bd9Sstevel@tonic-gate 	 *	validated, so we can go ahead and configure the socket and
64667c478bd9Sstevel@tonic-gate 	 *	the card.
64677c478bd9Sstevel@tonic-gate 	 */
64687c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
64697c478bd9Sstevel@tonic-gate 
64707c478bd9Sstevel@tonic-gate 	/*
64717c478bd9Sstevel@tonic-gate 	 * Configure the socket with the interface type and voltages requested
64727c478bd9Sstevel@tonic-gate 	 *	by the client.
64737c478bd9Sstevel@tonic-gate 	 */
64747c478bd9Sstevel@tonic-gate 	get_socket.socket = sp->socket_num;
64757c478bd9Sstevel@tonic-gate 
64767c478bd9Sstevel@tonic-gate 	if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
64777c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
64787c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
64797c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
64807c478bd9Sstevel@tonic-gate 	}
64817c478bd9Sstevel@tonic-gate 
64827c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
64837c478bd9Sstevel@tonic-gate 	if (cs_debug > 0)
64847c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_request_configuration: socket %d "
64857c478bd9Sstevel@tonic-gate 					"client->irq_alloc.irq 0x%x "
64867c478bd9Sstevel@tonic-gate 					"get_socket.IRQRouting 0x%x\n",
64877c478bd9Sstevel@tonic-gate 						sp->socket_num,
64887c478bd9Sstevel@tonic-gate 						(int)client->irq_alloc.irq,
64897c478bd9Sstevel@tonic-gate 						get_socket.IRQRouting);
64907c478bd9Sstevel@tonic-gate #endif
64917c478bd9Sstevel@tonic-gate 
64927c478bd9Sstevel@tonic-gate 	bzero(&set_socket, sizeof (set_socket));
64937c478bd9Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
64947c478bd9Sstevel@tonic-gate 	set_socket.IREQRouting = client->irq_alloc.irq & ~IRQ_ENABLE;
64957c478bd9Sstevel@tonic-gate 
64967c478bd9Sstevel@tonic-gate 	set_socket.CtlInd = get_socket.CtlInd;
64977c478bd9Sstevel@tonic-gate 	set_socket.State = 0;	/* don't reset latched values */
64987c478bd9Sstevel@tonic-gate 
64997c478bd9Sstevel@tonic-gate 	if (cs_convert_powerlevel(sp->socket_num, cr->Vcc, VCC,
65007c478bd9Sstevel@tonic-gate 					&set_socket.VccLevel) != CS_SUCCESS) {
65017c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
65027c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
65037c478bd9Sstevel@tonic-gate 	    return (CS_BAD_VCC);
65047c478bd9Sstevel@tonic-gate 	}
65057c478bd9Sstevel@tonic-gate 
65067c478bd9Sstevel@tonic-gate 	if (cs_convert_powerlevel(sp->socket_num, cr->Vpp1, VPP1,
65077c478bd9Sstevel@tonic-gate 					&set_socket.Vpp1Level) != CS_SUCCESS) {
65087c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
65097c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
65107c478bd9Sstevel@tonic-gate 	    return (CS_BAD_VPP);
65117c478bd9Sstevel@tonic-gate 	}
65127c478bd9Sstevel@tonic-gate 
65137c478bd9Sstevel@tonic-gate 	if (cs_convert_powerlevel(sp->socket_num, cr->Vpp2, VPP2,
65147c478bd9Sstevel@tonic-gate 					&set_socket.Vpp2Level) != CS_SUCCESS) {
65157c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
65167c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
65177c478bd9Sstevel@tonic-gate 	    return (CS_BAD_VPP);
65187c478bd9Sstevel@tonic-gate 	}
65197c478bd9Sstevel@tonic-gate 
65207c478bd9Sstevel@tonic-gate 	if (!(cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO))
65217c478bd9Sstevel@tonic-gate 		set_socket.IFType = IF_MEMORY;
65227c478bd9Sstevel@tonic-gate 	else {
65237c478bd9Sstevel@tonic-gate 		set_socket.IFType = IF_IO;
65247c478bd9Sstevel@tonic-gate 
65257c478bd9Sstevel@tonic-gate 		/*
65267c478bd9Sstevel@tonic-gate 		 * The Cirrus Logic PD6710/672X/others? adapters will write
65277c478bd9Sstevel@tonic-gate 		 * protect the CIS if the socket is in MEMORY mode and the
65287c478bd9Sstevel@tonic-gate 		 * WP/IOCS16 pin is true.  When this happens, the CIS registers
65297c478bd9Sstevel@tonic-gate 		 * will fail to be written.  Go ahead and set the socket,
65307c478bd9Sstevel@tonic-gate 		 * even though the event mask isn't complete yet, so we can
65317c478bd9Sstevel@tonic-gate 		 * configure the adapter.  Afterwards, set the socket again
65327c478bd9Sstevel@tonic-gate 		 * to make sure the event mask is correct.
65337c478bd9Sstevel@tonic-gate 		 */
65347c478bd9Sstevel@tonic-gate 		if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
65357c478bd9Sstevel@tonic-gate 			sp->flags &= ~SOCKET_IS_IO;
65367c478bd9Sstevel@tonic-gate 			mutex_exit(&sp->cis_lock);
65377c478bd9Sstevel@tonic-gate 			EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
65387c478bd9Sstevel@tonic-gate 			return (CS_BAD_SOCKET);
65397c478bd9Sstevel@tonic-gate 		}
65407c478bd9Sstevel@tonic-gate 	}
65417c478bd9Sstevel@tonic-gate 
65427c478bd9Sstevel@tonic-gate 	if (cs_rc2_delay)
65437c478bd9Sstevel@tonic-gate 	    drv_usecwait(cs_rc2_delay * 1000);
65447c478bd9Sstevel@tonic-gate 
65457c478bd9Sstevel@tonic-gate 	/*
65467c478bd9Sstevel@tonic-gate 	 * Get a pointer to a window that contains the configuration
65477c478bd9Sstevel@tonic-gate 	 *	registers.
65487c478bd9Sstevel@tonic-gate 	 */
65497c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
65507c478bd9Sstevel@tonic-gate 	client->config_regs_offset = cr->ConfigBase;
65517c478bd9Sstevel@tonic-gate 	newoffset = client->config_regs_offset;
65527c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
65537c478bd9Sstevel@tonic-gate 	if (cs_init_cis_window(sp, &newoffset, &cis_handle,
65547c478bd9Sstevel@tonic-gate 					CISTPLF_AM_SPACE) != CS_SUCCESS) {
65557c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
65567c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
65577c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_request_configuration: socket %d can't init "
65587c478bd9Sstevel@tonic-gate 				"CIS window\n", sp->socket_num);
65597c478bd9Sstevel@tonic-gate 	    return (CS_GENERAL_FAILURE);
65607c478bd9Sstevel@tonic-gate 	}
65617c478bd9Sstevel@tonic-gate 
65627c478bd9Sstevel@tonic-gate 	/*
65637c478bd9Sstevel@tonic-gate 	 * Setup the config register pointers.
65647c478bd9Sstevel@tonic-gate 	 * Note that these pointers are not the complete virtual address;
65657c478bd9Sstevel@tonic-gate 	 *	the complete address is constructed each time the registers
65667c478bd9Sstevel@tonic-gate 	 *	are accessed.
65677c478bd9Sstevel@tonic-gate 	 */
65687c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
65697c478bd9Sstevel@tonic-gate 	crt = &client->config_regs;
65707c478bd9Sstevel@tonic-gate 	client->present = cr->Present;
65717c478bd9Sstevel@tonic-gate 
65727c478bd9Sstevel@tonic-gate 	bzero((char *)crt, sizeof (config_regs_t));
65737c478bd9Sstevel@tonic-gate 
65747c478bd9Sstevel@tonic-gate 	/* Configuration Option Register */
65757c478bd9Sstevel@tonic-gate 	if (client->present & CONFIG_OPTION_REG_PRESENT)
65767c478bd9Sstevel@tonic-gate 	    crt->cor_p = (newoffset + CONFIG_OPTION_REG_OFFSET);
65777c478bd9Sstevel@tonic-gate 
65787c478bd9Sstevel@tonic-gate 	/* Configuration and Status Register */
65797c478bd9Sstevel@tonic-gate 	if (client->present & CONFIG_STATUS_REG_PRESENT)
65807c478bd9Sstevel@tonic-gate 	    crt->ccsr_p = (newoffset + CONFIG_STATUS_REG_OFFSET);
65817c478bd9Sstevel@tonic-gate 
65827c478bd9Sstevel@tonic-gate 	/* Pin Replacement Register */
65837c478bd9Sstevel@tonic-gate 	if (client->present & CONFIG_PINREPL_REG_PRESENT)
65847c478bd9Sstevel@tonic-gate 	    crt->prr_p = (newoffset + CONFIG_PINREPL_REG_OFFSET);
65857c478bd9Sstevel@tonic-gate 
65867c478bd9Sstevel@tonic-gate 	/* Socket and Copy Register */
65877c478bd9Sstevel@tonic-gate 	if (client->present & CONFIG_COPY_REG_PRESENT)
65887c478bd9Sstevel@tonic-gate 	    crt->scr_p = (newoffset + CONFIG_COPY_REG_OFFSET);
65897c478bd9Sstevel@tonic-gate 
65907c478bd9Sstevel@tonic-gate 	/* Extended Status Register */
65917c478bd9Sstevel@tonic-gate 	if (client->present & CONFIG_EXSTAT_REG_PRESENT)
65927c478bd9Sstevel@tonic-gate 	    crt->exstat_p = (newoffset + CONFIG_EXSTAT_REG_OFFSET);
65937c478bd9Sstevel@tonic-gate 
65947c478bd9Sstevel@tonic-gate 	/* IO Base 0 Register */
65957c478bd9Sstevel@tonic-gate 	if (client->present & CONFIG_IOBASE0_REG_PRESENT)
65967c478bd9Sstevel@tonic-gate 	    crt->iobase0_p = (newoffset + CONFIG_IOBASE0_REG_OFFSET);
65977c478bd9Sstevel@tonic-gate 
65987c478bd9Sstevel@tonic-gate 	/* IO Base 1 Register */
65997c478bd9Sstevel@tonic-gate 	if (client->present & CONFIG_IOBASE1_REG_PRESENT)
66007c478bd9Sstevel@tonic-gate 	    crt->iobase1_p = (newoffset + CONFIG_IOBASE1_REG_OFFSET);
66017c478bd9Sstevel@tonic-gate 
66027c478bd9Sstevel@tonic-gate 	/* IO Base 2 Register */
66037c478bd9Sstevel@tonic-gate 	if (client->present & CONFIG_IOBASE2_REG_PRESENT)
66047c478bd9Sstevel@tonic-gate 	    crt->iobase2_p = (newoffset + CONFIG_IOBASE2_REG_OFFSET);
66057c478bd9Sstevel@tonic-gate 
66067c478bd9Sstevel@tonic-gate 	/* IO Base 3 Register */
66077c478bd9Sstevel@tonic-gate 	if (client->present & CONFIG_IOBASE3_REG_PRESENT)
66087c478bd9Sstevel@tonic-gate 	    crt->iobase3_p = (newoffset + CONFIG_IOBASE3_REG_OFFSET);
66097c478bd9Sstevel@tonic-gate 
66107c478bd9Sstevel@tonic-gate 	/* IO Limit Register */
66117c478bd9Sstevel@tonic-gate 	if (client->present & CONFIG_IOLIMIT_REG_PRESENT)
66127c478bd9Sstevel@tonic-gate 	    crt->iolimit_p = (newoffset + CONFIG_IOLIMIT_REG_OFFSET);
66137c478bd9Sstevel@tonic-gate 
66147c478bd9Sstevel@tonic-gate 	/*
66157c478bd9Sstevel@tonic-gate 	 * Setup the bits in the PRR mask that are valid; this is easy, just
66167c478bd9Sstevel@tonic-gate 	 *	copy the Pin value that the client gave us.  Note that for
66177c478bd9Sstevel@tonic-gate 	 *	this to work, the client must set both of the XXX_STATUS
66187c478bd9Sstevel@tonic-gate 	 *	and the XXX_EVENT bits in the Pin member.
66197c478bd9Sstevel@tonic-gate 	 */
66207c478bd9Sstevel@tonic-gate 	client->pin = cr->Pin;
66217c478bd9Sstevel@tonic-gate 
66227c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
66237c478bd9Sstevel@tonic-gate 	if (cs_debug > 128)
66247c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_request_configuration: client->pin 0x%x "
66257c478bd9Sstevel@tonic-gate 		"client->config_regs_offset 0x%x newoffset 0x%x cor_p 0x%x "
66267c478bd9Sstevel@tonic-gate 		"ccsr_p 0x%x prr_p 0x%x scr_p 0x%x\n",
66277c478bd9Sstevel@tonic-gate 		client->pin, (int)client->config_regs_offset, newoffset,
66287c478bd9Sstevel@tonic-gate 		(int)crt->cor_p, (int)crt->ccsr_p, (int)crt->prr_p,
66297c478bd9Sstevel@tonic-gate 		(int)crt->scr_p);
66307c478bd9Sstevel@tonic-gate #endif
66317c478bd9Sstevel@tonic-gate 
66327c478bd9Sstevel@tonic-gate 	/*
66337c478bd9Sstevel@tonic-gate 	 * If the socket isn't in IO mode, WP is asserted,  and we're going to
66347c478bd9Sstevel@tonic-gate 	 * write any of the config registers, issue a warning.
66357c478bd9Sstevel@tonic-gate 	 */
66367c478bd9Sstevel@tonic-gate 	if ((client->present != 0) &&
66377c478bd9Sstevel@tonic-gate 	    (!(cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO)) &&
66387c478bd9Sstevel@tonic-gate 	    (get_socket.state & SBM_WP)) {
66397c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "!cs_request_configuration: attempting to "
66407c478bd9Sstevel@tonic-gate 		    "write CIS config regs with WP set\n");
66417c478bd9Sstevel@tonic-gate 	}
66427c478bd9Sstevel@tonic-gate 
66437c478bd9Sstevel@tonic-gate 	/*
66447c478bd9Sstevel@tonic-gate 	 * Write any configuration registers that the client tells us are
66457c478bd9Sstevel@tonic-gate 	 *	present to the card; save a copy of what we wrote so that we
66467c478bd9Sstevel@tonic-gate 	 *	can return them if the client calls GetConfigurationInfo.
66477c478bd9Sstevel@tonic-gate 	 * The order in which we write the configuration registers is
66487c478bd9Sstevel@tonic-gate 	 *	specified by the PCMCIA spec; we must write the socket/copy
66497c478bd9Sstevel@tonic-gate 	 *	register first (if it exists), and then we can write the
66507c478bd9Sstevel@tonic-gate 	 *	registers in any arbitrary order.
66517c478bd9Sstevel@tonic-gate 	 */
66527c478bd9Sstevel@tonic-gate 	/* Socket and Copy Register */
66537c478bd9Sstevel@tonic-gate 	if (client->present & CONFIG_COPY_REG_PRESENT) {
66547c478bd9Sstevel@tonic-gate 	    crt->scr = cr->Copy;
66557c478bd9Sstevel@tonic-gate 	    csx_Put8(cis_handle, crt->scr_p, crt->scr);
66567c478bd9Sstevel@tonic-gate 	}
66577c478bd9Sstevel@tonic-gate 
66587c478bd9Sstevel@tonic-gate 	/* Pin Replacement Register */
66597c478bd9Sstevel@tonic-gate 	if (client->present & CONFIG_PINREPL_REG_PRESENT) {
66607c478bd9Sstevel@tonic-gate 	    crt->prr = cr->Pin;
66617c478bd9Sstevel@tonic-gate 	    csx_Put8(cis_handle, crt->prr_p, crt->prr);
66627c478bd9Sstevel@tonic-gate 	}
66637c478bd9Sstevel@tonic-gate 
66647c478bd9Sstevel@tonic-gate 	/* Configuration and Status Register */
66657c478bd9Sstevel@tonic-gate 	/* XXX should we set CCSR_SIG_CHG in the CCSR? XXX */
66667c478bd9Sstevel@tonic-gate 	if (client->present & CONFIG_STATUS_REG_PRESENT) {
66677c478bd9Sstevel@tonic-gate 	    crt->ccsr = cr->Status;
66687c478bd9Sstevel@tonic-gate 	    csx_Put8(cis_handle, crt->ccsr_p, crt->ccsr);
66697c478bd9Sstevel@tonic-gate 	}
66707c478bd9Sstevel@tonic-gate 
66717c478bd9Sstevel@tonic-gate 	/* Extended Status Register */
66727c478bd9Sstevel@tonic-gate 	if (client->present & CONFIG_EXSTAT_REG_PRESENT) {
66737c478bd9Sstevel@tonic-gate 	    crt->exstat = cr->ExtendedStatus;
66747c478bd9Sstevel@tonic-gate 	    csx_Put8(cis_handle, crt->exstat_p, crt->exstat);
66757c478bd9Sstevel@tonic-gate 	}
66767c478bd9Sstevel@tonic-gate 
66777c478bd9Sstevel@tonic-gate 	/*
66787c478bd9Sstevel@tonic-gate 	 * If any IO base and limit registers exist, and this client
66797c478bd9Sstevel@tonic-gate 	 *	has done a RequestIO, setup the IO Base and IO Limit
66807c478bd9Sstevel@tonic-gate 	 *	registers.
66817c478bd9Sstevel@tonic-gate 	 */
66827c478bd9Sstevel@tonic-gate 	if (client->flags & REQ_IO_DONE) {
66837c478bd9Sstevel@tonic-gate 	    if (client->present & CONFIG_IOBASE0_REG_PRESENT) {
66847c478bd9Sstevel@tonic-gate 		uint32_t base = client->io_alloc.BasePort1.base;
66857c478bd9Sstevel@tonic-gate 		uint32_t present = (client->present &
66867c478bd9Sstevel@tonic-gate 					CONFIG_IOBASE_REG_MASK) >>
66877c478bd9Sstevel@tonic-gate 						CONFIG_IOBASE_REG_SHIFT;
66887c478bd9Sstevel@tonic-gate 		uint32_t reg = crt->iobase0_p;
66897c478bd9Sstevel@tonic-gate 
66907c478bd9Sstevel@tonic-gate 		do {
66917c478bd9Sstevel@tonic-gate 		    csx_Put8(cis_handle, reg, base & 0x0ff);
66927c478bd9Sstevel@tonic-gate 		    reg = reg + 2;
66937c478bd9Sstevel@tonic-gate 		    base = base >> 8;
66947c478bd9Sstevel@tonic-gate 		    present = present >> 1;
66957c478bd9Sstevel@tonic-gate 		} while (present);
66967c478bd9Sstevel@tonic-gate 	    } /* CONFIG_IOBASE0_REG_PRESENT */
66977c478bd9Sstevel@tonic-gate 
66987c478bd9Sstevel@tonic-gate 	    if (client->present & CONFIG_IOLIMIT_REG_PRESENT) {
66997c478bd9Sstevel@tonic-gate 		uint32_t np = client->io_alloc.NumPorts1 +
67007c478bd9Sstevel@tonic-gate 					client->io_alloc.NumPorts2;
67017c478bd9Sstevel@tonic-gate 		uint32_t limit, do_bit = 0;
67027c478bd9Sstevel@tonic-gate 		int lm;
67037c478bd9Sstevel@tonic-gate 
67047c478bd9Sstevel@tonic-gate 		limit = (IONUMPORTS_FROBNITZ(np) - 1);
67057c478bd9Sstevel@tonic-gate 
67067c478bd9Sstevel@tonic-gate 		for (lm = 7; lm >= 0; lm--) {
67077c478bd9Sstevel@tonic-gate 		    if (limit & (1 << lm))
67087c478bd9Sstevel@tonic-gate 			do_bit = 1;
67097c478bd9Sstevel@tonic-gate 		    if (do_bit)
67107c478bd9Sstevel@tonic-gate 			limit |= (1 << lm);
67117c478bd9Sstevel@tonic-gate 		} /* for */
67127c478bd9Sstevel@tonic-gate 
67137c478bd9Sstevel@tonic-gate 		csx_Put8(cis_handle, crt->iolimit_p, limit);
67147c478bd9Sstevel@tonic-gate 	    } /* CONFIG_IOLIMIT_REG_PRESENT */
67157c478bd9Sstevel@tonic-gate 	} /* REQ_IO_DONE */
67167c478bd9Sstevel@tonic-gate 
67177c478bd9Sstevel@tonic-gate 	/*
67187c478bd9Sstevel@tonic-gate 	 * Mark the socket as being in IO mode.
67197c478bd9Sstevel@tonic-gate 	 */
67207c478bd9Sstevel@tonic-gate 	if (cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO)
67217c478bd9Sstevel@tonic-gate 	    sp->flags |= SOCKET_IS_IO;
67227c478bd9Sstevel@tonic-gate 
67237c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
67247c478bd9Sstevel@tonic-gate 
67257c478bd9Sstevel@tonic-gate 	/*
67267c478bd9Sstevel@tonic-gate 	 * Enable the interrupt if needed
67277c478bd9Sstevel@tonic-gate 	 */
67287c478bd9Sstevel@tonic-gate 	if (cr->Attributes & CONF_ENABLE_IRQ_STEERING)
67297c478bd9Sstevel@tonic-gate 	    set_socket.IREQRouting |= IRQ_ENABLE;
67307c478bd9Sstevel@tonic-gate 
67317c478bd9Sstevel@tonic-gate 	/*
67327c478bd9Sstevel@tonic-gate 	 * Now that we know if the PRR is present and if it is, which
67337c478bd9Sstevel@tonic-gate 	 *	bits in the PRR are valid, we can construct the correct
67347c478bd9Sstevel@tonic-gate 	 *	socket event mask.
67357c478bd9Sstevel@tonic-gate 	 */
67367c478bd9Sstevel@tonic-gate 	set_socket.SCIntMask = cs_merge_event_masks(sp, client);
67377c478bd9Sstevel@tonic-gate 
67387c478bd9Sstevel@tonic-gate 	/*
67397c478bd9Sstevel@tonic-gate 	 * Configuration Option Register - we handle this specially since
67407c478bd9Sstevel@tonic-gate 	 *	we don't allow the client to manipulate the RESET or
67417c478bd9Sstevel@tonic-gate 	 *	INTERRUPT bits (although a client can manipulate these
67427c478bd9Sstevel@tonic-gate 	 *	bits via an AccessConfigurationRegister call - explain
67437c478bd9Sstevel@tonic-gate 	 *	THAT logic to me).
67447c478bd9Sstevel@tonic-gate 	 * XXX - we force level-mode interrupts (COR_LEVEL_IRQ)
67457c478bd9Sstevel@tonic-gate 	 * XXX - we always enable the function on a multi-function card
67467c478bd9Sstevel@tonic-gate 	 */
67477c478bd9Sstevel@tonic-gate 	if (client->present & CONFIG_OPTION_REG_PRESENT) {
67487c478bd9Sstevel@tonic-gate 	    crt->cor = (cr->ConfigIndex & ~COR_SOFT_RESET) | COR_LEVEL_IRQ;
67497c478bd9Sstevel@tonic-gate 	    if (client->present & CONFIG_IOBASE0_REG_PRESENT)
67507c478bd9Sstevel@tonic-gate 		crt->cor |= COR_ENABLE_BASE_LIMIT;
67517c478bd9Sstevel@tonic-gate 	    if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
67527c478bd9Sstevel@tonic-gate 		crt->cor |= COR_ENABLE_FUNCTION;
67537c478bd9Sstevel@tonic-gate 		crt->cor &= ~COR_ENABLE_IREQ_ROUTING;
67547c478bd9Sstevel@tonic-gate 		if (cr->Attributes & CONF_ENABLE_IRQ_STEERING)
67557c478bd9Sstevel@tonic-gate 		    crt->cor |= COR_ENABLE_IREQ_ROUTING;
67567c478bd9Sstevel@tonic-gate 	    } /* CW_MULTI_FUNCTION_CIS */
67577c478bd9Sstevel@tonic-gate 
67587c478bd9Sstevel@tonic-gate #ifdef  CS_DEBUG
67597c478bd9Sstevel@tonic-gate 	if (cs_debug > 0)
67607c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_request_configuration "
67617c478bd9Sstevel@tonic-gate 		    "cor=x%x ConfigIndex=x%x Attributes=x%x flags=x%x\n"
67627c478bd9Sstevel@tonic-gate 		    "present=x%x cis_handle=%p cor_p=x%x\n",
67637c478bd9Sstevel@tonic-gate 		    crt->cor, cr->ConfigIndex, cr->Attributes, sp->cis_flags,
67647c478bd9Sstevel@tonic-gate 		    client->present, cis_handle, crt->cor_p);
67657c478bd9Sstevel@tonic-gate #endif
67667c478bd9Sstevel@tonic-gate 
67677c478bd9Sstevel@tonic-gate 	    csx_Put8(cis_handle, crt->cor_p, crt->cor);
67687c478bd9Sstevel@tonic-gate 	} /* CONFIG_OPTION_REG_PRESENT */
67697c478bd9Sstevel@tonic-gate 
67707c478bd9Sstevel@tonic-gate 	if (cs_rc1_delay)
67717c478bd9Sstevel@tonic-gate 	    drv_usecwait(cs_rc1_delay * 1000);
67727c478bd9Sstevel@tonic-gate 
67737c478bd9Sstevel@tonic-gate 	/*
67747c478bd9Sstevel@tonic-gate 	 * Set the socket to the parameters that the client requested.
67757c478bd9Sstevel@tonic-gate 	 */
67767c478bd9Sstevel@tonic-gate 	if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
67777c478bd9Sstevel@tonic-gate 	    if (client->present & CONFIG_OPTION_REG_PRESENT) {
67787c478bd9Sstevel@tonic-gate 		crt->cor = 0; /* XXX is 0 the right thing here? */
67797c478bd9Sstevel@tonic-gate 		csx_Put8(cis_handle, crt->cor_p, crt->cor);
67807c478bd9Sstevel@tonic-gate 	    }
67817c478bd9Sstevel@tonic-gate 	    sp->flags &= ~SOCKET_IS_IO;
67827c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
67837c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
67847c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
67857c478bd9Sstevel@tonic-gate 	}
67867c478bd9Sstevel@tonic-gate 
67877c478bd9Sstevel@tonic-gate 	if (cs_rc2_delay)
67887c478bd9Sstevel@tonic-gate 	    drv_usecwait(cs_rc2_delay * 1000);
67897c478bd9Sstevel@tonic-gate 
67907c478bd9Sstevel@tonic-gate 	/*
67917c478bd9Sstevel@tonic-gate 	 * Mark this client as having done a successful RequestConfiguration
67927c478bd9Sstevel@tonic-gate 	 *	call.
67937c478bd9Sstevel@tonic-gate 	 */
67947c478bd9Sstevel@tonic-gate 	client->flags |= REQ_CONFIGURATION_DONE;
67957c478bd9Sstevel@tonic-gate 
67967c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
67977c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
67987c478bd9Sstevel@tonic-gate 
67997c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
68007c478bd9Sstevel@tonic-gate }
68017c478bd9Sstevel@tonic-gate 
68027c478bd9Sstevel@tonic-gate /*
68037c478bd9Sstevel@tonic-gate  * cs_release_configuration - releases configuration previously set via the
68047c478bd9Sstevel@tonic-gate  *		RequestConfiguration call; this is ReleaseConfiguration
68057c478bd9Sstevel@tonic-gate  *
68067c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS - if configuration sucessfully released
68077c478bd9Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
68087c478bd9Sstevel@tonic-gate  *		 CS_BAD_SOCKET - if Socket Services returns an error
68097c478bd9Sstevel@tonic-gate  *		 CS_BAD_HANDLE - a RequestConfiguration has not been done
68107c478bd9Sstevel@tonic-gate  */
68117c478bd9Sstevel@tonic-gate /*ARGSUSED*/
68127c478bd9Sstevel@tonic-gate static int
68137c478bd9Sstevel@tonic-gate cs_release_configuration(client_handle_t client_handle, release_config_t *rcfg)
68147c478bd9Sstevel@tonic-gate {
68157c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
68167c478bd9Sstevel@tonic-gate 	client_t *client;
68177c478bd9Sstevel@tonic-gate 	volatile config_regs_t *crt;
68187c478bd9Sstevel@tonic-gate 	set_socket_t set_socket;
68197c478bd9Sstevel@tonic-gate 	get_socket_t get_socket;
68207c478bd9Sstevel@tonic-gate 	acc_handle_t cis_handle;
68217c478bd9Sstevel@tonic-gate 	int error;
68227c478bd9Sstevel@tonic-gate 	uint32_t newoffset;
68237c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
68247c478bd9Sstevel@tonic-gate 
68257c478bd9Sstevel@tonic-gate 	/*
68267c478bd9Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
68277c478bd9Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
68287c478bd9Sstevel@tonic-gate 	 */
68297c478bd9Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
68307c478bd9Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
68317c478bd9Sstevel@tonic-gate 
68327c478bd9Sstevel@tonic-gate 	/*
68337c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
68347c478bd9Sstevel@tonic-gate 	 */
68357c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
68367c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
68377c478bd9Sstevel@tonic-gate 
68387c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
68397c478bd9Sstevel@tonic-gate 
68407c478bd9Sstevel@tonic-gate 	/*
68417c478bd9Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
68427c478bd9Sstevel@tonic-gate 	 */
68437c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
68447c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
68457c478bd9Sstevel@tonic-gate 	    return (error);
68467c478bd9Sstevel@tonic-gate 	}
68477c478bd9Sstevel@tonic-gate 
68487c478bd9Sstevel@tonic-gate 	/*
68497c478bd9Sstevel@tonic-gate 	 * If RequestConfiguration has not been done, we don't allow
68507c478bd9Sstevel@tonic-gate 	 *	this call.
68517c478bd9Sstevel@tonic-gate 	 */
68527c478bd9Sstevel@tonic-gate 	if (!(client->flags & REQ_CONFIGURATION_DONE)) {
68537c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
68547c478bd9Sstevel@tonic-gate 	    return (CS_BAD_HANDLE);
68557c478bd9Sstevel@tonic-gate 	}
68567c478bd9Sstevel@tonic-gate 
68577c478bd9Sstevel@tonic-gate #ifdef  CS_DEBUG
68587c478bd9Sstevel@tonic-gate 	if (cs_debug > 0)
68597c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_release_configuration: "
68607c478bd9Sstevel@tonic-gate 		    "flags=0x%x CW_MULTI_FUNCTION_CIS =0x%x \n",
68617c478bd9Sstevel@tonic-gate 		    sp->cis_flags, CW_MULTI_FUNCTION_CIS);
68627c478bd9Sstevel@tonic-gate 
68637c478bd9Sstevel@tonic-gate #endif
68647c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
68657c478bd9Sstevel@tonic-gate 
68667c478bd9Sstevel@tonic-gate 	/*
68677c478bd9Sstevel@tonic-gate 	 * Set the card back to a memory-only interface byte writing a zero
68687c478bd9Sstevel@tonic-gate 	 *	to the COR.  Note that we don't update our soft copy of the
68697c478bd9Sstevel@tonic-gate 	 *	COR state since the PCMCIA spec only requires us to maintain
68707c478bd9Sstevel@tonic-gate 	 *	the last value that was written to that register during a
68717c478bd9Sstevel@tonic-gate 	 *	call to RequestConfiguration.
68727c478bd9Sstevel@tonic-gate 	 */
68737c478bd9Sstevel@tonic-gate 	crt = &client->config_regs;
68747c478bd9Sstevel@tonic-gate 
68757c478bd9Sstevel@tonic-gate 	newoffset = client->config_regs_offset;
68767c478bd9Sstevel@tonic-gate 	if (cs_init_cis_window(sp, &newoffset, &cis_handle,
68777c478bd9Sstevel@tonic-gate 					CISTPLF_AM_SPACE) != CS_SUCCESS) {
68787c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
68797c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
68807c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_release_configuration: socket %d can't init "
68817c478bd9Sstevel@tonic-gate 				"CIS window\n", sp->socket_num);
68827c478bd9Sstevel@tonic-gate 	    return (CS_GENERAL_FAILURE);
68837c478bd9Sstevel@tonic-gate 	}
68847c478bd9Sstevel@tonic-gate 
68857c478bd9Sstevel@tonic-gate 	if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
68867c478bd9Sstevel@tonic-gate 		/*
68877c478bd9Sstevel@tonic-gate 		 * For the Multifunction cards do not reset the socket
68887c478bd9Sstevel@tonic-gate 		 * to a memory only interface but do clear the
68897c478bd9Sstevel@tonic-gate 		 * Configuration Option Register and  mark this client
68907c478bd9Sstevel@tonic-gate 		 * as not having a configuration by clearing the
68917c478bd9Sstevel@tonic-gate 		 * REQ_CONFIGURATION_DONE flag.
68927c478bd9Sstevel@tonic-gate 		 */
68937c478bd9Sstevel@tonic-gate 		client->flags &= ~REQ_CONFIGURATION_DONE;
68947c478bd9Sstevel@tonic-gate 		csx_Put8(cis_handle, crt->cor_p, 0);
68957c478bd9Sstevel@tonic-gate 
68967c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
68977c478bd9Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
68987c478bd9Sstevel@tonic-gate 		return (CS_SUCCESS);
68997c478bd9Sstevel@tonic-gate 	}
69007c478bd9Sstevel@tonic-gate 
69017c478bd9Sstevel@tonic-gate 	/*
69027c478bd9Sstevel@tonic-gate 	 * Set the socket back to a memory-only interface; don't change
69037c478bd9Sstevel@tonic-gate 	 *	any other parameter of the socket.
69047c478bd9Sstevel@tonic-gate 	 */
69057c478bd9Sstevel@tonic-gate 	get_socket.socket = sp->socket_num;
69067c478bd9Sstevel@tonic-gate 
69077c478bd9Sstevel@tonic-gate 	if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
69087c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
69097c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
69107c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
69117c478bd9Sstevel@tonic-gate 	}
69127c478bd9Sstevel@tonic-gate 
69137c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
69147c478bd9Sstevel@tonic-gate 	sp->flags &= ~SOCKET_IS_IO;
69157c478bd9Sstevel@tonic-gate 	set_socket.SCIntMask = cs_merge_event_masks(sp, client);
69167c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
69177c478bd9Sstevel@tonic-gate 
69187c478bd9Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
69197c478bd9Sstevel@tonic-gate 	set_socket.IREQRouting = 0;
69207c478bd9Sstevel@tonic-gate 	set_socket.CtlInd = get_socket.CtlInd;
69217c478bd9Sstevel@tonic-gate 	set_socket.State = 0;	/* don't reset latched values */
69227c478bd9Sstevel@tonic-gate 	set_socket.VccLevel = get_socket.VccLevel;
69237c478bd9Sstevel@tonic-gate 	set_socket.Vpp1Level = get_socket.Vpp1Level;
69247c478bd9Sstevel@tonic-gate 	set_socket.Vpp2Level = get_socket.Vpp2Level;
69257c478bd9Sstevel@tonic-gate 	set_socket.IFType = IF_MEMORY;
69267c478bd9Sstevel@tonic-gate 
69277c478bd9Sstevel@tonic-gate 	if (client->present & CONFIG_OPTION_REG_PRESENT)
69287c478bd9Sstevel@tonic-gate 	    csx_Put8(cis_handle, crt->cor_p, 0);
69297c478bd9Sstevel@tonic-gate 
69307c478bd9Sstevel@tonic-gate 	if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
69317c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
69327c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
69337c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
69347c478bd9Sstevel@tonic-gate 	}
69357c478bd9Sstevel@tonic-gate 
69367c478bd9Sstevel@tonic-gate 	/*
69377c478bd9Sstevel@tonic-gate 	 * Mark this client as not having a configuration.
69387c478bd9Sstevel@tonic-gate 	 */
69397c478bd9Sstevel@tonic-gate 	client->flags &= ~REQ_CONFIGURATION_DONE;
69407c478bd9Sstevel@tonic-gate 
69417c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
69427c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
69437c478bd9Sstevel@tonic-gate 
69447c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
69457c478bd9Sstevel@tonic-gate }
69467c478bd9Sstevel@tonic-gate 
69477c478bd9Sstevel@tonic-gate /*
69487c478bd9Sstevel@tonic-gate  * cs_modify_configuration - modifies a configuration established by
69497c478bd9Sstevel@tonic-gate  *		RequestConfiguration; this is ModifyConfiguration
69507c478bd9Sstevel@tonic-gate  *
69517c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS - if configuration sucessfully modified
69527c478bd9Sstevel@tonic-gate  *		 CS_BAD_SOCKET - if Socket Services returns an error
69537c478bd9Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
69547c478bd9Sstevel@tonic-gate  *		 CS_BAD_HANDLE - a RequestConfiguration has not been done
69557c478bd9Sstevel@tonic-gate  *		 CS_NO_CARD - if no card in socket
69567c478bd9Sstevel@tonic-gate  *		 CS_BAD_ATTRIBUTE - if any unsupported or reserved flags
69577c478bd9Sstevel@tonic-gate  *					are set
69587c478bd9Sstevel@tonic-gate  *		 CS_BAD_VCC - if Vcc value is not supported by socket
69597c478bd9Sstevel@tonic-gate  *		 CS_BAD_VPP1 - if Vpp1 value is not supported by socket
69607c478bd9Sstevel@tonic-gate  *		 CS_BAD_VPP2 - if Vpp2 value is not supported by socket
69617c478bd9Sstevel@tonic-gate  */
69627c478bd9Sstevel@tonic-gate static int
69637c478bd9Sstevel@tonic-gate cs_modify_configuration(client_handle_t client_handle, modify_config_t *mc)
69647c478bd9Sstevel@tonic-gate {
69657c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
69667c478bd9Sstevel@tonic-gate 	client_t *client;
69677c478bd9Sstevel@tonic-gate 	set_socket_t set_socket;
69687c478bd9Sstevel@tonic-gate 	get_socket_t get_socket;
69697c478bd9Sstevel@tonic-gate 	int error;
69707c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
69717c478bd9Sstevel@tonic-gate 
69727c478bd9Sstevel@tonic-gate 	/*
69737c478bd9Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
69747c478bd9Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
69757c478bd9Sstevel@tonic-gate 	 */
69767c478bd9Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
69777c478bd9Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
69787c478bd9Sstevel@tonic-gate 
69797c478bd9Sstevel@tonic-gate 	/*
69807c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
69817c478bd9Sstevel@tonic-gate 	 */
69827c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
69837c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
69847c478bd9Sstevel@tonic-gate 
69857c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
69867c478bd9Sstevel@tonic-gate 
69877c478bd9Sstevel@tonic-gate 	/*
69887c478bd9Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
69897c478bd9Sstevel@tonic-gate 	 */
69907c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
69917c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
69927c478bd9Sstevel@tonic-gate 	    return (error);
69937c478bd9Sstevel@tonic-gate 	}
69947c478bd9Sstevel@tonic-gate 
69957c478bd9Sstevel@tonic-gate 	/*
69967c478bd9Sstevel@tonic-gate 	 * If RequestConfiguration has not been done, we don't allow
69977c478bd9Sstevel@tonic-gate 	 *	this call.
69987c478bd9Sstevel@tonic-gate 	 */
69997c478bd9Sstevel@tonic-gate 	if (!(client->flags & REQ_CONFIGURATION_DONE)) {
70007c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
70017c478bd9Sstevel@tonic-gate 	    return (CS_BAD_HANDLE);
70027c478bd9Sstevel@tonic-gate 	}
70037c478bd9Sstevel@tonic-gate 
70047c478bd9Sstevel@tonic-gate 	/*
70057c478bd9Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
70067c478bd9Sstevel@tonic-gate 	 *	for this client, then return an error.
70077c478bd9Sstevel@tonic-gate 	 */
70087c478bd9Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
70097c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
70107c478bd9Sstevel@tonic-gate 	    return (CS_NO_CARD);
70117c478bd9Sstevel@tonic-gate 	}
70127c478bd9Sstevel@tonic-gate 
70137c478bd9Sstevel@tonic-gate 	/*
70147c478bd9Sstevel@tonic-gate 	 * Get the current socket parameters so that we can modify them.
70157c478bd9Sstevel@tonic-gate 	 */
70167c478bd9Sstevel@tonic-gate 	get_socket.socket = sp->socket_num;
70177c478bd9Sstevel@tonic-gate 
70187c478bd9Sstevel@tonic-gate 	if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
70197c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
70207c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
70217c478bd9Sstevel@tonic-gate 	}
70227c478bd9Sstevel@tonic-gate 
70237c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
70247c478bd9Sstevel@tonic-gate 	if (cs_debug > 0)
70257c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_modify_configuration: socket %d "
70267c478bd9Sstevel@tonic-gate 				"client->irq_alloc.irq 0x%x "
70277c478bd9Sstevel@tonic-gate 				"get_socket.IRQRouting 0x%x\n",
70287c478bd9Sstevel@tonic-gate 				sp->socket_num, (int)client->irq_alloc.irq,
70297c478bd9Sstevel@tonic-gate 				get_socket.IRQRouting);
70307c478bd9Sstevel@tonic-gate #endif
70317c478bd9Sstevel@tonic-gate 
70327c478bd9Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
70337c478bd9Sstevel@tonic-gate 	set_socket.SCIntMask = get_socket.SCIntMask;
70347c478bd9Sstevel@tonic-gate 	set_socket.CtlInd = get_socket.CtlInd;
70357c478bd9Sstevel@tonic-gate 	set_socket.State = 0;	/* don't reset latched values */
70367c478bd9Sstevel@tonic-gate 	set_socket.IFType = get_socket.IFType;
70377c478bd9Sstevel@tonic-gate 
70387c478bd9Sstevel@tonic-gate 	set_socket.IREQRouting = get_socket.IRQRouting;
70397c478bd9Sstevel@tonic-gate 
70407c478bd9Sstevel@tonic-gate 	/*
70417c478bd9Sstevel@tonic-gate 	 * Modify the IRQ routing if the client wants it modified.
70427c478bd9Sstevel@tonic-gate 	 */
70437c478bd9Sstevel@tonic-gate 	if (mc->Attributes & CONF_IRQ_CHANGE_VALID) {
70447c478bd9Sstevel@tonic-gate 	    set_socket.IREQRouting &= ~IRQ_ENABLE;
70457c478bd9Sstevel@tonic-gate 
70467c478bd9Sstevel@tonic-gate 	    if ((sp->cis_flags & CW_MULTI_FUNCTION_CIS) &&
70477c478bd9Sstevel@tonic-gate 			(client->present & CONFIG_OPTION_REG_PRESENT)) {
70487c478bd9Sstevel@tonic-gate 		config_regs_t *crt = &client->config_regs;
70497c478bd9Sstevel@tonic-gate 		acc_handle_t cis_handle;
70507c478bd9Sstevel@tonic-gate 		uint32_t newoffset = client->config_regs_offset;
70517c478bd9Sstevel@tonic-gate 
70527c478bd9Sstevel@tonic-gate 		/*
70537c478bd9Sstevel@tonic-gate 		 * Get a pointer to a window that contains the configuration
70547c478bd9Sstevel@tonic-gate 		 *	registers.
70557c478bd9Sstevel@tonic-gate 		 */
70567c478bd9Sstevel@tonic-gate 		if (cs_init_cis_window(sp, &newoffset, &cis_handle,
70577c478bd9Sstevel@tonic-gate 					CISTPLF_AM_SPACE) != CS_SUCCESS) {
70587c478bd9Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
70597c478bd9Sstevel@tonic-gate 		    cmn_err(CE_CONT,
70607c478bd9Sstevel@tonic-gate 			"cs_modify_configuration: socket %d can't init "
70617c478bd9Sstevel@tonic-gate 			"CIS window\n", sp->socket_num);
70627c478bd9Sstevel@tonic-gate 		    return (CS_GENERAL_FAILURE);
70637c478bd9Sstevel@tonic-gate 		} /* cs_init_cis_window */
70647c478bd9Sstevel@tonic-gate 
70657c478bd9Sstevel@tonic-gate 		crt->cor &= ~COR_ENABLE_IREQ_ROUTING;
70667c478bd9Sstevel@tonic-gate 
70677c478bd9Sstevel@tonic-gate 		if (mc->Attributes & CONF_ENABLE_IRQ_STEERING)
70687c478bd9Sstevel@tonic-gate 		    crt->cor |= COR_ENABLE_IREQ_ROUTING;
70697c478bd9Sstevel@tonic-gate 
70707c478bd9Sstevel@tonic-gate #ifdef  CS_DEBUG
70717c478bd9Sstevel@tonic-gate 		if (cs_debug > 0)
70727c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_modify_configuration:"
70737c478bd9Sstevel@tonic-gate 			    " cor_p=0x%x cor=0x%x\n",
70747c478bd9Sstevel@tonic-gate 			    crt->cor_p, crt->cor);
70757c478bd9Sstevel@tonic-gate #endif
70767c478bd9Sstevel@tonic-gate 		csx_Put8(cis_handle, crt->cor_p, crt->cor);
70777c478bd9Sstevel@tonic-gate 
70787c478bd9Sstevel@tonic-gate 	    } /* CW_MULTI_FUNCTION_CIS */
70797c478bd9Sstevel@tonic-gate 
70807c478bd9Sstevel@tonic-gate 	    if (mc->Attributes & CONF_ENABLE_IRQ_STEERING)
70817c478bd9Sstevel@tonic-gate 		set_socket.IREQRouting |= IRQ_ENABLE;
70827c478bd9Sstevel@tonic-gate 
70837c478bd9Sstevel@tonic-gate 	} /* CONF_IRQ_CHANGE_VALID */
70847c478bd9Sstevel@tonic-gate 
70857c478bd9Sstevel@tonic-gate 	/*
70867c478bd9Sstevel@tonic-gate 	 * Modify the voltage levels that the client specifies.
70877c478bd9Sstevel@tonic-gate 	 */
70887c478bd9Sstevel@tonic-gate 	set_socket.VccLevel = get_socket.VccLevel;
70897c478bd9Sstevel@tonic-gate 
70907c478bd9Sstevel@tonic-gate 	if (mc->Attributes & CONF_VPP1_CHANGE_VALID) {
70917c478bd9Sstevel@tonic-gate 	    if (cs_convert_powerlevel(sp->socket_num, mc->Vpp1, VPP1,
70927c478bd9Sstevel@tonic-gate 					&set_socket.Vpp1Level) != CS_SUCCESS) {
70937c478bd9Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
70947c478bd9Sstevel@tonic-gate 		return (CS_BAD_VPP);
70957c478bd9Sstevel@tonic-gate 	    }
70967c478bd9Sstevel@tonic-gate 	} else {
70977c478bd9Sstevel@tonic-gate 	    set_socket.Vpp1Level = get_socket.Vpp1Level;
70987c478bd9Sstevel@tonic-gate 	}
70997c478bd9Sstevel@tonic-gate 
71007c478bd9Sstevel@tonic-gate 	if (mc->Attributes & CONF_VPP2_CHANGE_VALID) {
71017c478bd9Sstevel@tonic-gate 	    if (cs_convert_powerlevel(sp->socket_num, mc->Vpp2, VPP2,
71027c478bd9Sstevel@tonic-gate 					&set_socket.Vpp2Level) != CS_SUCCESS) {
71037c478bd9Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
71047c478bd9Sstevel@tonic-gate 		return (CS_BAD_VPP);
71057c478bd9Sstevel@tonic-gate 	    }
71067c478bd9Sstevel@tonic-gate 	} else {
71077c478bd9Sstevel@tonic-gate 	    set_socket.Vpp2Level = get_socket.Vpp2Level;
71087c478bd9Sstevel@tonic-gate 	}
71097c478bd9Sstevel@tonic-gate 
71107c478bd9Sstevel@tonic-gate 	/*
71117c478bd9Sstevel@tonic-gate 	 * Setup the modified socket configuration.
71127c478bd9Sstevel@tonic-gate 	 */
71137c478bd9Sstevel@tonic-gate 	if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
71147c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
71157c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
71167c478bd9Sstevel@tonic-gate 	}
71177c478bd9Sstevel@tonic-gate 
71187c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
71197c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
71207c478bd9Sstevel@tonic-gate }
71217c478bd9Sstevel@tonic-gate 
71227c478bd9Sstevel@tonic-gate /*
71237c478bd9Sstevel@tonic-gate  * cs_access_configuration_register - provides a client access to the card's
71247c478bd9Sstevel@tonic-gate  *		configuration registers; this is AccessConfigurationRegister
71257c478bd9Sstevel@tonic-gate  *
71267c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS - if register accessed successfully
71277c478bd9Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
71287c478bd9Sstevel@tonic-gate  *		 CS_BAD_ARGS - if arguments are out of range
71297c478bd9Sstevel@tonic-gate  *		 CS_NO_CARD - if no card in socket
71307c478bd9Sstevel@tonic-gate  *		 CS_BAD_BASE - if no config registers base address
71317c478bd9Sstevel@tonic-gate  *		 CS_UNSUPPORTED_MODE - if no RequestConfiguration has
71327c478bd9Sstevel@tonic-gate  *				been done yet
71337c478bd9Sstevel@tonic-gate  */
71347c478bd9Sstevel@tonic-gate static int
71357c478bd9Sstevel@tonic-gate cs_access_configuration_register(client_handle_t client_handle,
71367c478bd9Sstevel@tonic-gate 						access_config_reg_t *acr)
71377c478bd9Sstevel@tonic-gate {
71387c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
71397c478bd9Sstevel@tonic-gate 	client_t *client;
71407c478bd9Sstevel@tonic-gate 	acc_handle_t cis_handle;
71417c478bd9Sstevel@tonic-gate 	int error;
71427c478bd9Sstevel@tonic-gate 	uint32_t newoffset;
71437c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
71447c478bd9Sstevel@tonic-gate 
71457c478bd9Sstevel@tonic-gate 	/*
71467c478bd9Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
71477c478bd9Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
71487c478bd9Sstevel@tonic-gate 	 */
71497c478bd9Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
71507c478bd9Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
71517c478bd9Sstevel@tonic-gate 
71527c478bd9Sstevel@tonic-gate 	/*
71537c478bd9Sstevel@tonic-gate 	 * Make sure that the specifed offset is in range.
71547c478bd9Sstevel@tonic-gate 	 */
71557c478bd9Sstevel@tonic-gate 	if (acr->Offset > ((CISTPL_CONFIG_MAX_CONFIG_REGS * 2) - 2))
71567c478bd9Sstevel@tonic-gate 	    return (CS_BAD_ARGS);
71577c478bd9Sstevel@tonic-gate 
71587c478bd9Sstevel@tonic-gate 	/*
71597c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
71607c478bd9Sstevel@tonic-gate 	 */
71617c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
71627c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
71637c478bd9Sstevel@tonic-gate 
71647c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
71657c478bd9Sstevel@tonic-gate 
71667c478bd9Sstevel@tonic-gate 	/*
71677c478bd9Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
71687c478bd9Sstevel@tonic-gate 	 */
71697c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
71707c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
71717c478bd9Sstevel@tonic-gate 	    return (error);
71727c478bd9Sstevel@tonic-gate 	}
71737c478bd9Sstevel@tonic-gate 
71747c478bd9Sstevel@tonic-gate 	/*
71757c478bd9Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
71767c478bd9Sstevel@tonic-gate 	 *	for this client, then return an error.
71777c478bd9Sstevel@tonic-gate 	 */
71787c478bd9Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
71797c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
71807c478bd9Sstevel@tonic-gate 	    return (CS_NO_CARD);
71817c478bd9Sstevel@tonic-gate 	}
71827c478bd9Sstevel@tonic-gate 
71837c478bd9Sstevel@tonic-gate 	/*
71847c478bd9Sstevel@tonic-gate 	 * If RequestConfiguration has not been done, we don't allow
71857c478bd9Sstevel@tonic-gate 	 *	this call.
71867c478bd9Sstevel@tonic-gate 	 */
71877c478bd9Sstevel@tonic-gate 	if (!(client->flags & REQ_CONFIGURATION_DONE)) {
71887c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
71897c478bd9Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_MODE);
71907c478bd9Sstevel@tonic-gate 	}
71917c478bd9Sstevel@tonic-gate 
71927c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
71937c478bd9Sstevel@tonic-gate 
71947c478bd9Sstevel@tonic-gate 	/*
71957c478bd9Sstevel@tonic-gate 	 * Get a pointer to the CIS window
71967c478bd9Sstevel@tonic-gate 	 */
71977c478bd9Sstevel@tonic-gate 	newoffset = client->config_regs_offset + acr->Offset;
71987c478bd9Sstevel@tonic-gate 	if (cs_init_cis_window(sp, &newoffset, &cis_handle,
71997c478bd9Sstevel@tonic-gate 					CISTPLF_AM_SPACE) != CS_SUCCESS) {
72007c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
72017c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
72027c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_ACR: socket %d can't init CIS window\n",
72037c478bd9Sstevel@tonic-gate 							sp->socket_num);
72047c478bd9Sstevel@tonic-gate 	    return (CS_GENERAL_FAILURE);
72057c478bd9Sstevel@tonic-gate 	}
72067c478bd9Sstevel@tonic-gate 
72077c478bd9Sstevel@tonic-gate 	/*
72087c478bd9Sstevel@tonic-gate 	 * Create the address for the config register that the client
72097c478bd9Sstevel@tonic-gate 	 *	wants to access.
72107c478bd9Sstevel@tonic-gate 	 */
72117c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
72127c478bd9Sstevel@tonic-gate 
72137c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
72147c478bd9Sstevel@tonic-gate 	if (cs_debug > 1) {
72157c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_ACR: config_regs_offset 0x%x "
72167c478bd9Sstevel@tonic-gate 		"Offset 0x%x newoffset 0x%x\n",
72177c478bd9Sstevel@tonic-gate 		(int)client->config_regs_offset,
72187c478bd9Sstevel@tonic-gate 		(int)acr->Offset, newoffset);
72197c478bd9Sstevel@tonic-gate 	}
72207c478bd9Sstevel@tonic-gate #endif
72217c478bd9Sstevel@tonic-gate 
72227c478bd9Sstevel@tonic-gate 	/*
72237c478bd9Sstevel@tonic-gate 	 * Determine what the client wants us to do.  The client is
72247c478bd9Sstevel@tonic-gate 	 *	allowed to specify any valid offset, even if it would
72257c478bd9Sstevel@tonic-gate 	 *	cause an unimplemented configuration register to be
72267c478bd9Sstevel@tonic-gate 	 *	accessed.
72277c478bd9Sstevel@tonic-gate 	 */
72287c478bd9Sstevel@tonic-gate 	error = CS_SUCCESS;
72297c478bd9Sstevel@tonic-gate 	switch (acr->Action) {
72307c478bd9Sstevel@tonic-gate 	    case CONFIG_REG_READ:
72317c478bd9Sstevel@tonic-gate 		acr->Value = csx_Get8(cis_handle, newoffset);
72327c478bd9Sstevel@tonic-gate 		break;
72337c478bd9Sstevel@tonic-gate 	    case CONFIG_REG_WRITE:
72347c478bd9Sstevel@tonic-gate 		csx_Put8(cis_handle, newoffset, acr->Value);
72357c478bd9Sstevel@tonic-gate 		break;
72367c478bd9Sstevel@tonic-gate 	    default:
72377c478bd9Sstevel@tonic-gate 		error = CS_BAD_ARGS;
72387c478bd9Sstevel@tonic-gate 		break;
72397c478bd9Sstevel@tonic-gate 	} /* switch */
72407c478bd9Sstevel@tonic-gate 
72417c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
72427c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
72437c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
72447c478bd9Sstevel@tonic-gate 
72457c478bd9Sstevel@tonic-gate 	return (error);
72467c478bd9Sstevel@tonic-gate }
72477c478bd9Sstevel@tonic-gate 
72487c478bd9Sstevel@tonic-gate /*
72497c478bd9Sstevel@tonic-gate  * ==== RESET and general info functions ====
72507c478bd9Sstevel@tonic-gate  */
72517c478bd9Sstevel@tonic-gate 
72527c478bd9Sstevel@tonic-gate /*
72537c478bd9Sstevel@tonic-gate  * cs_reset_function - RESET the requested function on the card; this
72547c478bd9Sstevel@tonic-gate  *			is ResetFunction
72557c478bd9Sstevel@tonic-gate  *
72567c478bd9Sstevel@tonic-gate  *    Note: We don't support this functionality yet, and the standard
72577c478bd9Sstevel@tonic-gate  *		says it's OK to reutrn CS_IN_USE if we can't do this
72587c478bd9Sstevel@tonic-gate  *		operation.
72597c478bd9Sstevel@tonic-gate  */
72607c478bd9Sstevel@tonic-gate /*ARGSUSED*/
72617c478bd9Sstevel@tonic-gate static int
72627c478bd9Sstevel@tonic-gate cs_reset_function(client_handle_t ch, reset_function_t *rf)
72637c478bd9Sstevel@tonic-gate {
72647c478bd9Sstevel@tonic-gate 	return (CS_IN_USE);
72657c478bd9Sstevel@tonic-gate }
72667c478bd9Sstevel@tonic-gate 
72677c478bd9Sstevel@tonic-gate /*
72687c478bd9Sstevel@tonic-gate  * cs_get_configuration_info - return configuration info for the passed
72697c478bd9Sstevel@tonic-gate  *				socket and function number to the caller;
72707c478bd9Sstevel@tonic-gate  *				this is GetConfigurationInfo
72717c478bd9Sstevel@tonic-gate  */
72727c478bd9Sstevel@tonic-gate /*ARGSUSED*/
72737c478bd9Sstevel@tonic-gate static int
72747c478bd9Sstevel@tonic-gate cs_get_configuration_info(client_handle_t *chp, get_configuration_info_t *gci)
72757c478bd9Sstevel@tonic-gate {
72767c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
72777c478bd9Sstevel@tonic-gate 	uint32_t fn;
72787c478bd9Sstevel@tonic-gate 	client_t *client;
72797c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
72807c478bd9Sstevel@tonic-gate 
72817c478bd9Sstevel@tonic-gate 	/*
72827c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
72837c478bd9Sstevel@tonic-gate 	 */
72847c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(gci->Socket))) == NULL)
72857c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
72867c478bd9Sstevel@tonic-gate 
72877c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
72887c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
72897c478bd9Sstevel@tonic-gate 
72907c478bd9Sstevel@tonic-gate 	fn = CS_GET_FUNCTION_NUMBER(gci->Socket);
72917c478bd9Sstevel@tonic-gate 
72927c478bd9Sstevel@tonic-gate 	client = sp->client_list;
72937c478bd9Sstevel@tonic-gate 	while (client) {
72947c478bd9Sstevel@tonic-gate 
72957c478bd9Sstevel@tonic-gate 	    if (GET_CLIENT_FUNCTION(client->client_handle) == fn) {
72967c478bd9Sstevel@tonic-gate 
72977c478bd9Sstevel@tonic-gate 		/*
72987c478bd9Sstevel@tonic-gate 		 * If there's no card in the socket or the card in the
72997c478bd9Sstevel@tonic-gate 		 *	socket is not for this client, then return
73007c478bd9Sstevel@tonic-gate 		 *	an error.
73017c478bd9Sstevel@tonic-gate 		 */
73027c478bd9Sstevel@tonic-gate 		if (!(client->flags & CLIENT_CARD_INSERTED)) {
73037c478bd9Sstevel@tonic-gate 		    mutex_exit(&sp->lock);
73047c478bd9Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
73057c478bd9Sstevel@tonic-gate 		    return (CS_NO_CARD);
73067c478bd9Sstevel@tonic-gate 		}
73077c478bd9Sstevel@tonic-gate 
73087c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->lock);
73097c478bd9Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
73107c478bd9Sstevel@tonic-gate 		return (CS_SUCCESS);
73117c478bd9Sstevel@tonic-gate 
73127c478bd9Sstevel@tonic-gate 	    } /* GET_CLIENT_FUNCTION == fn */
73137c478bd9Sstevel@tonic-gate 
73147c478bd9Sstevel@tonic-gate 	    client = client->next;
73157c478bd9Sstevel@tonic-gate 	} /* while (client) */
73167c478bd9Sstevel@tonic-gate 
73177c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
73187c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
73197c478bd9Sstevel@tonic-gate 
73207c478bd9Sstevel@tonic-gate 	return (CS_BAD_SOCKET);
73217c478bd9Sstevel@tonic-gate }
73227c478bd9Sstevel@tonic-gate 
73237c478bd9Sstevel@tonic-gate /*
73247c478bd9Sstevel@tonic-gate  * cs_get_cardservices_info - return info about Card Services to the
73257c478bd9Sstevel@tonic-gate  *	caller; this is GetCardServicesInfo
73267c478bd9Sstevel@tonic-gate  */
73277c478bd9Sstevel@tonic-gate /*ARGSUSED*/
73287c478bd9Sstevel@tonic-gate static int
73297c478bd9Sstevel@tonic-gate cs_get_cardservices_info(client_handle_t ch, get_cardservices_info_t *gcsi)
73307c478bd9Sstevel@tonic-gate {
73317c478bd9Sstevel@tonic-gate 	gcsi->Signature[0] = 'C';
73327c478bd9Sstevel@tonic-gate 	gcsi->Signature[1] = 'S';
73337c478bd9Sstevel@tonic-gate 	gcsi->NumSockets = cs_globals.num_sockets;
73347c478bd9Sstevel@tonic-gate 	gcsi->Revision = CS_INTERNAL_REVISION_LEVEL;
73357c478bd9Sstevel@tonic-gate 	gcsi->CSLevel = CS_VERSION;
73367c478bd9Sstevel@tonic-gate 	gcsi->FuncsPerSocket = CIS_MAX_FUNCTIONS;
73377c478bd9Sstevel@tonic-gate 	(void) strncpy(gcsi->VendorString,
73387c478bd9Sstevel@tonic-gate 					CS_GET_CARDSERVICES_INFO_VENDOR_STRING,
73397c478bd9Sstevel@tonic-gate 					CS_GET_CARDSERVICES_INFO_MAX_VS_LEN);
73407c478bd9Sstevel@tonic-gate 
73417c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
73427c478bd9Sstevel@tonic-gate }
73437c478bd9Sstevel@tonic-gate 
73447c478bd9Sstevel@tonic-gate /*
73457c478bd9Sstevel@tonic-gate  * cs_get_physical_adapter_info - returns information about the requested
73467c478bd9Sstevel@tonic-gate  *					physical adapter; this is
73477c478bd9Sstevel@tonic-gate  *					GetPhysicalAdapterInfo
73487c478bd9Sstevel@tonic-gate  *
73497c478bd9Sstevel@tonic-gate  *	calling: client_handle_t:
73507c478bd9Sstevel@tonic-gate  *			NULL - use map_log_socket_t->LogSocket member
73517c478bd9Sstevel@tonic-gate  *				to specify logical socket number
73527c478bd9Sstevel@tonic-gate  *			!NULL - extract logical socket number from
73537c478bd9Sstevel@tonic-gate  *				client_handle_t
73547c478bd9Sstevel@tonic-gate  *
73557c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS
73567c478bd9Sstevel@tonic-gate  *		 CS_BAD_SOCKET - if client_handle_t is NULL and invalid
73577c478bd9Sstevel@tonic-gate  *					socket number is specified in
73587c478bd9Sstevel@tonic-gate  *					map_log_socket_t->LogSocket
73597c478bd9Sstevel@tonic-gate  *		 CS_BAD_HANDLE - if client_handle_t is !NULL and invalid
73607c478bd9Sstevel@tonic-gate  *					client handle is specified
73617c478bd9Sstevel@tonic-gate  */
73627c478bd9Sstevel@tonic-gate static int
73637c478bd9Sstevel@tonic-gate cs_get_physical_adapter_info(client_handle_t ch,
73647c478bd9Sstevel@tonic-gate 					get_physical_adapter_info_t *gpai)
73657c478bd9Sstevel@tonic-gate {
73667c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
73677c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
73687c478bd9Sstevel@tonic-gate 
7369*c48c3045SToomas Soome 	if (ch == 0)
73707c478bd9Sstevel@tonic-gate 	    gpai->PhySocket = CS_GET_SOCKET_NUMBER(gpai->LogSocket);
73717c478bd9Sstevel@tonic-gate 	else
73727c478bd9Sstevel@tonic-gate 	    gpai->PhySocket = GET_CLIENT_SOCKET(ch);
73737c478bd9Sstevel@tonic-gate 
73747c478bd9Sstevel@tonic-gate 	/*
73757c478bd9Sstevel@tonic-gate 	 * Determine if the passed socket number is valid or not.
73767c478bd9Sstevel@tonic-gate 	 */
73777c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(gpai->PhySocket))) == NULL)
7378*c48c3045SToomas Soome 	    return ((ch == 0) ? CS_BAD_SOCKET : CS_BAD_HANDLE);
73797c478bd9Sstevel@tonic-gate 
73807c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
73817c478bd9Sstevel@tonic-gate 
73827c478bd9Sstevel@tonic-gate 	/*
73837c478bd9Sstevel@tonic-gate 	 * If we were passed a client handle, determine if it's valid or not.
73847c478bd9Sstevel@tonic-gate 	 */
7385*c48c3045SToomas Soome 	if (ch != 0) {
73867c478bd9Sstevel@tonic-gate 	    if (cs_find_client(ch, NULL) == NULL) {
73877c478bd9Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
73887c478bd9Sstevel@tonic-gate 		return (CS_BAD_HANDLE);
73897c478bd9Sstevel@tonic-gate 	    } /* cs_find_client */
73907c478bd9Sstevel@tonic-gate 	} /* ch != NULL */
73917c478bd9Sstevel@tonic-gate 
73927c478bd9Sstevel@tonic-gate 	gpai->flags = sp->adapter.flags;
73937c478bd9Sstevel@tonic-gate 	(void) strcpy(gpai->name, sp->adapter.name);
73947c478bd9Sstevel@tonic-gate 	gpai->major = sp->adapter.major;
73957c478bd9Sstevel@tonic-gate 	gpai->minor = sp->adapter.minor;
73967c478bd9Sstevel@tonic-gate 	gpai->instance = sp->adapter.instance;
73977c478bd9Sstevel@tonic-gate 	gpai->number = sp->adapter.number;
73987c478bd9Sstevel@tonic-gate 	gpai->num_sockets = sp->adapter.num_sockets;
73997c478bd9Sstevel@tonic-gate 	gpai->first_socket = sp->adapter.first_socket;
74007c478bd9Sstevel@tonic-gate 
74017c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
74027c478bd9Sstevel@tonic-gate 
74037c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
74047c478bd9Sstevel@tonic-gate }
74057c478bd9Sstevel@tonic-gate 
74067c478bd9Sstevel@tonic-gate /*
74077c478bd9Sstevel@tonic-gate  * ==== general functions ====
74087c478bd9Sstevel@tonic-gate  */
74097c478bd9Sstevel@tonic-gate 
74107c478bd9Sstevel@tonic-gate /*
74117c478bd9Sstevel@tonic-gate  * cs_map_log_socket - returns the physical socket number associated with
74127c478bd9Sstevel@tonic-gate  *			either the passed client handle or the passed
74137c478bd9Sstevel@tonic-gate  *			logical socket number; this is MapLogSocket
74147c478bd9Sstevel@tonic-gate  *
74157c478bd9Sstevel@tonic-gate  *	calling: client_handle_t:
74167c478bd9Sstevel@tonic-gate  *			NULL - use map_log_socket_t->LogSocket member
74177c478bd9Sstevel@tonic-gate  *				to specify logical socket number
74187c478bd9Sstevel@tonic-gate  *			!NULL - extract logical socket number from
74197c478bd9Sstevel@tonic-gate  *				client_handle_t
74207c478bd9Sstevel@tonic-gate  *
74217c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS
74227c478bd9Sstevel@tonic-gate  *		 CS_BAD_SOCKET - if client_handle_t is NULL and invalid
74237c478bd9Sstevel@tonic-gate  *					socket number is specified in
74247c478bd9Sstevel@tonic-gate  *					map_log_socket_t->LogSocket
74257c478bd9Sstevel@tonic-gate  *		 CS_BAD_HANDLE - if client_handle_t is !NULL and invalid
74267c478bd9Sstevel@tonic-gate  *					client handle is specified
74277c478bd9Sstevel@tonic-gate  *
74287c478bd9Sstevel@tonic-gate  * Note: We provide this function since the instance number of a client
74297c478bd9Sstevel@tonic-gate  *		driver doesn't necessary correspond to the physical
74307c478bd9Sstevel@tonic-gate  *		socket number
74317c478bd9Sstevel@tonic-gate  */
74327c478bd9Sstevel@tonic-gate static int
74337c478bd9Sstevel@tonic-gate cs_map_log_socket(client_handle_t ch, map_log_socket_t *mls)
74347c478bd9Sstevel@tonic-gate {
74357c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
74367c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
74377c478bd9Sstevel@tonic-gate 
7438*c48c3045SToomas Soome 	if (ch == 0)
74397c478bd9Sstevel@tonic-gate 	    mls->PhySocket = CS_GET_SOCKET_NUMBER(mls->LogSocket);
74407c478bd9Sstevel@tonic-gate 	else
74417c478bd9Sstevel@tonic-gate 	    mls->PhySocket = GET_CLIENT_SOCKET(ch);
74427c478bd9Sstevel@tonic-gate 
74437c478bd9Sstevel@tonic-gate 	/*
74447c478bd9Sstevel@tonic-gate 	 * Determine if the passed socket number is valid or not.
74457c478bd9Sstevel@tonic-gate 	 */
74467c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(mls->PhySocket))) == NULL)
7447*c48c3045SToomas Soome 	    return ((ch == 0) ? CS_BAD_SOCKET : CS_BAD_HANDLE);
74487c478bd9Sstevel@tonic-gate 
74497c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
74507c478bd9Sstevel@tonic-gate 
74517c478bd9Sstevel@tonic-gate 	/*
74527c478bd9Sstevel@tonic-gate 	 * If we were passed a client handle, determine if it's valid or not.
74537c478bd9Sstevel@tonic-gate 	 */
7454*c48c3045SToomas Soome 	if (ch != 0) {
74557c478bd9Sstevel@tonic-gate 	    if (cs_find_client(ch, NULL) == NULL) {
74567c478bd9Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
74577c478bd9Sstevel@tonic-gate 		return (CS_BAD_HANDLE);
74587c478bd9Sstevel@tonic-gate 	    } /* cs_find_client */
74597c478bd9Sstevel@tonic-gate 	} /* ch != NULL */
74607c478bd9Sstevel@tonic-gate 
74617c478bd9Sstevel@tonic-gate 	mls->PhyAdapter = sp->adapter.number;
74627c478bd9Sstevel@tonic-gate 
74637c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
74647c478bd9Sstevel@tonic-gate 
74657c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
74667c478bd9Sstevel@tonic-gate }
74677c478bd9Sstevel@tonic-gate 
74687c478bd9Sstevel@tonic-gate /*
74697c478bd9Sstevel@tonic-gate  * cs_convert_speed - convers nS to devspeed and devspeed to nS
74707c478bd9Sstevel@tonic-gate  *
74717c478bd9Sstevel@tonic-gate  * The actual function is is in the CIS parser module; this
74727c478bd9Sstevel@tonic-gate  *	is only a wrapper.
74737c478bd9Sstevel@tonic-gate  */
74747c478bd9Sstevel@tonic-gate static int
74757c478bd9Sstevel@tonic-gate cs_convert_speed(convert_speed_t *cs)
74767c478bd9Sstevel@tonic-gate {
74777c478bd9Sstevel@tonic-gate 	return ((int)(uintptr_t)CIS_PARSER(CISP_CIS_CONV_DEVSPEED, cs));
74787c478bd9Sstevel@tonic-gate }
74797c478bd9Sstevel@tonic-gate 
74807c478bd9Sstevel@tonic-gate /*
74817c478bd9Sstevel@tonic-gate  * cs_convert_size - converts a devsize value to a size in bytes value
74827c478bd9Sstevel@tonic-gate  *			or a size in bytes value to a devsize value
74837c478bd9Sstevel@tonic-gate  *
74847c478bd9Sstevel@tonic-gate  * The actual function is is in the CIS parser module; this
74857c478bd9Sstevel@tonic-gate  *	is only a wrapper.
74867c478bd9Sstevel@tonic-gate  */
74877c478bd9Sstevel@tonic-gate static int
74887c478bd9Sstevel@tonic-gate cs_convert_size(convert_size_t *cs)
74897c478bd9Sstevel@tonic-gate {
74907c478bd9Sstevel@tonic-gate 	return ((int)(uintptr_t)CIS_PARSER(CISP_CIS_CONV_DEVSIZE, cs));
74917c478bd9Sstevel@tonic-gate }
74927c478bd9Sstevel@tonic-gate 
74937c478bd9Sstevel@tonic-gate /*
74947c478bd9Sstevel@tonic-gate  * cs_convert_powerlevel - converts a power level in tenths of a volt
74957c478bd9Sstevel@tonic-gate  *			to a power table entry for the specified socket
74967c478bd9Sstevel@tonic-gate  *
74977c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS - if volts converted to a valid power level
74987c478bd9Sstevel@tonic-gate  *		 CS_BAD_ADAPTER - if SS_InquireAdapter fails
74997c478bd9Sstevel@tonic-gate  *		 CS_BAD_ARGS - if volts are not supported on this socket
75007c478bd9Sstevel@tonic-gate  *				and adapter
75017c478bd9Sstevel@tonic-gate  */
75027c478bd9Sstevel@tonic-gate static int
75037c478bd9Sstevel@tonic-gate cs_convert_powerlevel(uint32_t sn, uint32_t volts, uint32_t flags, unsigned *pl)
75047c478bd9Sstevel@tonic-gate {
75057c478bd9Sstevel@tonic-gate 	inquire_adapter_t inquire_adapter;
75067c478bd9Sstevel@tonic-gate 	int i;
75077c478bd9Sstevel@tonic-gate 
75087c478bd9Sstevel@tonic-gate #ifdef	lint
75097c478bd9Sstevel@tonic-gate 	if (sn == 0)
75107c478bd9Sstevel@tonic-gate 	    panic("lint panic");
75117c478bd9Sstevel@tonic-gate #endif
75127c478bd9Sstevel@tonic-gate 
75137c478bd9Sstevel@tonic-gate 	*pl = 0;
75147c478bd9Sstevel@tonic-gate 
75157c478bd9Sstevel@tonic-gate 	if (SocketServices(SS_InquireAdapter, &inquire_adapter) != SUCCESS)
75167c478bd9Sstevel@tonic-gate 	    return (CS_BAD_ADAPTER);
75177c478bd9Sstevel@tonic-gate 
75187c478bd9Sstevel@tonic-gate 	for (i = 0; (i < inquire_adapter.NumPower); i++) {
75197c478bd9Sstevel@tonic-gate 	    if ((inquire_adapter.power_entry[i].ValidSignals & flags) &&
75207c478bd9Sstevel@tonic-gate 		(inquire_adapter.power_entry[i].PowerLevel == volts)) {
75217c478bd9Sstevel@tonic-gate 		*pl = i;
75227c478bd9Sstevel@tonic-gate 		return (CS_SUCCESS);
75237c478bd9Sstevel@tonic-gate 	    }
75247c478bd9Sstevel@tonic-gate 	}
75257c478bd9Sstevel@tonic-gate 
75267c478bd9Sstevel@tonic-gate 	return (CS_BAD_ARGS);
75277c478bd9Sstevel@tonic-gate }
75287c478bd9Sstevel@tonic-gate 
75297c478bd9Sstevel@tonic-gate /*
75307c478bd9Sstevel@tonic-gate  * cs_event2text - returns text string(s) associated with the event; this
75317c478bd9Sstevel@tonic-gate  *			function supports the Event2Text CS call.
75327c478bd9Sstevel@tonic-gate  *
75337c478bd9Sstevel@tonic-gate  *	calling: event2text_t * - pointer to event2text struct
75347c478bd9Sstevel@tonic-gate  *		 int event_source - specifies event type in event2text_t:
75357c478bd9Sstevel@tonic-gate  *					0 - SS event
75367c478bd9Sstevel@tonic-gate  *					1 - CS event
75377c478bd9Sstevel@tonic-gate  *
75387c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS
75397c478bd9Sstevel@tonic-gate  */
75407c478bd9Sstevel@tonic-gate static int
75417c478bd9Sstevel@tonic-gate cs_event2text(event2text_t *e2t, int event_source)
75427c478bd9Sstevel@tonic-gate {
75437c478bd9Sstevel@tonic-gate 	event_t event;
75447c478bd9Sstevel@tonic-gate 	char *sepchar = "|";
75457c478bd9Sstevel@tonic-gate 
75467c478bd9Sstevel@tonic-gate 	/*
75477c478bd9Sstevel@tonic-gate 	 * If event_source is 0, this is a SS event
75487c478bd9Sstevel@tonic-gate 	 */
75497c478bd9Sstevel@tonic-gate 	if (!event_source) {
75507c478bd9Sstevel@tonic-gate 	    for (event = 0; event < MAX_SS_EVENTS; event++) {
75517c478bd9Sstevel@tonic-gate 		if (cs_ss_event_text[event].ss_event == e2t->event) {
75527c478bd9Sstevel@tonic-gate 		    (void) strcpy(e2t->text, cs_ss_event_text[event].text);
75537c478bd9Sstevel@tonic-gate 		    return (CS_SUCCESS);
75547c478bd9Sstevel@tonic-gate 		}
75557c478bd9Sstevel@tonic-gate 	    }
75567c478bd9Sstevel@tonic-gate 	    (void) strcpy(e2t->text, cs_ss_event_text[MAX_CS_EVENTS].text);
75577c478bd9Sstevel@tonic-gate 	    return (CS_SUCCESS);
75587c478bd9Sstevel@tonic-gate 	} else {
75597c478bd9Sstevel@tonic-gate 		/*
75607c478bd9Sstevel@tonic-gate 		 * This is a CS event
75617c478bd9Sstevel@tonic-gate 		 */
75627c478bd9Sstevel@tonic-gate 	    e2t->text[0] = '\0';
75637c478bd9Sstevel@tonic-gate 	    for (event = 0; event < MAX_CS_EVENTS; event++) {
75647c478bd9Sstevel@tonic-gate 		if (cs_ss_event_text[event].cs_event & e2t->event) {
75657c478bd9Sstevel@tonic-gate 		    (void) strcat(e2t->text, cs_ss_event_text[event].text);
75667c478bd9Sstevel@tonic-gate 		    (void) strcat(e2t->text, sepchar);
75677c478bd9Sstevel@tonic-gate 		} /* if (cs_ss_event_text) */
75687c478bd9Sstevel@tonic-gate 	    } /* for (event) */
75697c478bd9Sstevel@tonic-gate 	    if (e2t->text[0])
7570*c48c3045SToomas Soome 		e2t->text[strlen(e2t->text)-1] = '\0';
75717c478bd9Sstevel@tonic-gate 	} /* if (!event_source) */
75727c478bd9Sstevel@tonic-gate 
75737c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
75747c478bd9Sstevel@tonic-gate }
75757c478bd9Sstevel@tonic-gate 
75767c478bd9Sstevel@tonic-gate /*
75777c478bd9Sstevel@tonic-gate  * cs_error2text - returns a pointer to a text string containing the name
75787c478bd9Sstevel@tonic-gate  *			of the passed Card Services function or return code
75797c478bd9Sstevel@tonic-gate  *
75807c478bd9Sstevel@tonic-gate  *	This function supports the Error2Text CS call.
75817c478bd9Sstevel@tonic-gate  */
75827c478bd9Sstevel@tonic-gate static char *
75837c478bd9Sstevel@tonic-gate cs_error2text(int function, int type)
75847c478bd9Sstevel@tonic-gate {
75857c478bd9Sstevel@tonic-gate 	cs_csfunc2text_strings_t *cfs;
75867c478bd9Sstevel@tonic-gate 	int end_marker;
75877c478bd9Sstevel@tonic-gate 
75887c478bd9Sstevel@tonic-gate 	if (type == CSFUN2TEXT_FUNCTION) {
75897c478bd9Sstevel@tonic-gate 	    cfs = cs_csfunc2text_funcstrings;
75907c478bd9Sstevel@tonic-gate 	    end_marker = CSFuncListEnd;
75917c478bd9Sstevel@tonic-gate 	} else {
75927c478bd9Sstevel@tonic-gate 	    cfs = cs_csfunc2text_returnstrings;
75937c478bd9Sstevel@tonic-gate 	    end_marker = CS_ERRORLIST_END;
75947c478bd9Sstevel@tonic-gate 	}
75957c478bd9Sstevel@tonic-gate 
75967c478bd9Sstevel@tonic-gate 	while (cfs->item != end_marker) {
75977c478bd9Sstevel@tonic-gate 	    if (cfs->item == function)
75987c478bd9Sstevel@tonic-gate 		return (cfs->text);
75997c478bd9Sstevel@tonic-gate 	    cfs++;
76007c478bd9Sstevel@tonic-gate 	}
76017c478bd9Sstevel@tonic-gate 
76027c478bd9Sstevel@tonic-gate 	return (cfs->text);
76037c478bd9Sstevel@tonic-gate }
76047c478bd9Sstevel@tonic-gate 
76057c478bd9Sstevel@tonic-gate /*
76067c478bd9Sstevel@tonic-gate  * cs_make_device_node - creates/removes device nodes on a client's behalf;
76077c478bd9Sstevel@tonic-gate  *				this is MakeDeviceNode and RemoveDeviceNode
76087c478bd9Sstevel@tonic-gate  *
76097c478bd9Sstevel@tonic-gate  *	returns: CS_SUCCESS - if all device nodes successfully created/removed
76107c478bd9Sstevel@tonic-gate  *		 CS_BAD_ATTRIBUTE - if NumDevNodes is not zero when Action
76117c478bd9Sstevel@tonic-gate  *				is REMOVAL_ALL_DEVICES
76127c478bd9Sstevel@tonic-gate  *		 CS_BAD_ARGS - if an invalid Action code is specified
76137c478bd9Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
76147c478bd9Sstevel@tonic-gate  *		 CS_OUT_OF_RESOURCE - if can't create/remove device node
76157c478bd9Sstevel@tonic-gate  */
76167c478bd9Sstevel@tonic-gate static int
76177c478bd9Sstevel@tonic-gate cs_make_device_node(client_handle_t client_handle, make_device_node_t *mdn)
76187c478bd9Sstevel@tonic-gate {
76197c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
76207c478bd9Sstevel@tonic-gate 	client_t *client;
76217c478bd9Sstevel@tonic-gate 	ss_make_device_node_t ss_make_device_node;
76227c478bd9Sstevel@tonic-gate 	int error, i;
76237c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
76247c478bd9Sstevel@tonic-gate 
76257c478bd9Sstevel@tonic-gate 	/*
76267c478bd9Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
76277c478bd9Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
76287c478bd9Sstevel@tonic-gate 	 */
76297c478bd9Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
76307c478bd9Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
76317c478bd9Sstevel@tonic-gate 
76327c478bd9Sstevel@tonic-gate 	/*
76337c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
76347c478bd9Sstevel@tonic-gate 	 */
76357c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
76367c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
76377c478bd9Sstevel@tonic-gate 
76387c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
76397c478bd9Sstevel@tonic-gate 
76407c478bd9Sstevel@tonic-gate 	/*
76417c478bd9Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
76427c478bd9Sstevel@tonic-gate 	 */
76437c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
76447c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
76457c478bd9Sstevel@tonic-gate 	    return (error);
76467c478bd9Sstevel@tonic-gate 	}
76477c478bd9Sstevel@tonic-gate 
76487c478bd9Sstevel@tonic-gate #ifdef	XXX
76497c478bd9Sstevel@tonic-gate 	/*
76507c478bd9Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
76517c478bd9Sstevel@tonic-gate 	 *	for this client, then return an error.
76527c478bd9Sstevel@tonic-gate 	 */
76537c478bd9Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
76547c478bd9Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
76557c478bd9Sstevel@tonic-gate 	    return (CS_NO_CARD);
76567c478bd9Sstevel@tonic-gate 	}
76577c478bd9Sstevel@tonic-gate #endif
76587c478bd9Sstevel@tonic-gate 
76597c478bd9Sstevel@tonic-gate 	/*
76607c478bd9Sstevel@tonic-gate 	 * Setup the client's dip, since we use it later on.
76617c478bd9Sstevel@tonic-gate 	 */
76627c478bd9Sstevel@tonic-gate 	ss_make_device_node.dip = client->dip;
76637c478bd9Sstevel@tonic-gate 
76647c478bd9Sstevel@tonic-gate 	/*
76657c478bd9Sstevel@tonic-gate 	 * Make sure that we're being given a valid Action.  Set the default
76667c478bd9Sstevel@tonic-gate 	 *	error code as well.
76677c478bd9Sstevel@tonic-gate 	 */
76687c478bd9Sstevel@tonic-gate 	error = CS_BAD_ARGS;	/* for default case */
76697c478bd9Sstevel@tonic-gate 	switch (mdn->Action) {
76707c478bd9Sstevel@tonic-gate 	    case CREATE_DEVICE_NODE:
76717c478bd9Sstevel@tonic-gate 	    case REMOVE_DEVICE_NODE:
76727c478bd9Sstevel@tonic-gate 		break;
76737c478bd9Sstevel@tonic-gate 	    case REMOVAL_ALL_DEVICE_NODES:
76747c478bd9Sstevel@tonic-gate 		if (mdn->NumDevNodes) {
76757c478bd9Sstevel@tonic-gate 		    error = CS_BAD_ATTRIBUTE;
76767c478bd9Sstevel@tonic-gate 		} else {
76777c478bd9Sstevel@tonic-gate 		    ss_make_device_node.flags = SS_CSINITDEV_REMOVE_DEVICE;
76787c478bd9Sstevel@tonic-gate 		    ss_make_device_node.name = NULL;
76797c478bd9Sstevel@tonic-gate 		    SocketServices(CSInitDev, &ss_make_device_node);
76807c478bd9Sstevel@tonic-gate 		    error = CS_SUCCESS;
76817c478bd9Sstevel@tonic-gate 		}
76826c125e4eSToomas Soome 		/* FALLTHROUGH */
76837c478bd9Sstevel@tonic-gate 	    default:
76847c478bd9Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
76857c478bd9Sstevel@tonic-gate 		return (error);
76867c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
76877c478bd9Sstevel@tonic-gate 	} /* switch */
76887c478bd9Sstevel@tonic-gate 
76897c478bd9Sstevel@tonic-gate 	/*
76907c478bd9Sstevel@tonic-gate 	 * Loop through the device node descriptions and create or destroy
76917c478bd9Sstevel@tonic-gate 	 *	the device node.
76927c478bd9Sstevel@tonic-gate 	 */
76937c478bd9Sstevel@tonic-gate 	for (i = 0; i < mdn->NumDevNodes; i++) {
76947c478bd9Sstevel@tonic-gate 	    devnode_desc_t *devnode_desc = &mdn->devnode_desc[i];
76957c478bd9Sstevel@tonic-gate 
76967c478bd9Sstevel@tonic-gate 	    ss_make_device_node.name = devnode_desc->name;
76977c478bd9Sstevel@tonic-gate 	    ss_make_device_node.spec_type = devnode_desc->spec_type;
76987c478bd9Sstevel@tonic-gate 	    ss_make_device_node.minor_num = devnode_desc->minor_num;
76997c478bd9Sstevel@tonic-gate 	    ss_make_device_node.node_type = devnode_desc->node_type;
77007c478bd9Sstevel@tonic-gate 
77017c478bd9Sstevel@tonic-gate 	/*
77027c478bd9Sstevel@tonic-gate 	 * Set the appropriate flag for the action that we want
77037c478bd9Sstevel@tonic-gate 	 *	SS to perform. Note that if we ever OR-in the flag
77047c478bd9Sstevel@tonic-gate 	 *	here, we need to be sure to clear the flags member
77057c478bd9Sstevel@tonic-gate 	 *	since we sometimes OR-in other flags below.
77067c478bd9Sstevel@tonic-gate 	 */
77077c478bd9Sstevel@tonic-gate 	    if (mdn->Action == CREATE_DEVICE_NODE) {
77087c478bd9Sstevel@tonic-gate 		ss_make_device_node.flags = SS_CSINITDEV_CREATE_DEVICE;
77097c478bd9Sstevel@tonic-gate 	    } else {
77107c478bd9Sstevel@tonic-gate 		ss_make_device_node.flags = SS_CSINITDEV_REMOVE_DEVICE;
77117c478bd9Sstevel@tonic-gate 	    }
77127c478bd9Sstevel@tonic-gate 
77137c478bd9Sstevel@tonic-gate 	/*
77147c478bd9Sstevel@tonic-gate 	 * If this is not the last device to process, then we need
77157c478bd9Sstevel@tonic-gate 	 *	to tell SS that more device process requests are on
77167c478bd9Sstevel@tonic-gate 	 *	their way after this one.
77177c478bd9Sstevel@tonic-gate 	 */
77187c478bd9Sstevel@tonic-gate 	    if (i < (mdn->NumDevNodes - 1))
77197c478bd9Sstevel@tonic-gate 		ss_make_device_node.flags |= SS_CSINITDEV_MORE_DEVICES;
77207c478bd9Sstevel@tonic-gate 
77217c478bd9Sstevel@tonic-gate 	    if (SocketServices(CSInitDev, &ss_make_device_node) != SUCCESS) {
77227c478bd9Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
77237c478bd9Sstevel@tonic-gate 		return (CS_OUT_OF_RESOURCE);
77247c478bd9Sstevel@tonic-gate 	    } /* CSInitDev */
77257c478bd9Sstevel@tonic-gate 	} /* for (mdn->NumDevNodes) */
77267c478bd9Sstevel@tonic-gate 
77277c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
77287c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
77297c478bd9Sstevel@tonic-gate }
77307c478bd9Sstevel@tonic-gate 
77317c478bd9Sstevel@tonic-gate /*
77327c478bd9Sstevel@tonic-gate  * cs_remove_device_node - removes device nodes
77337c478bd9Sstevel@tonic-gate  *
77347c478bd9Sstevel@tonic-gate  *	(see cs_make_device_node for a description of the calling
77357c478bd9Sstevel@tonic-gate  *		and return parameters)
77367c478bd9Sstevel@tonic-gate  */
77377c478bd9Sstevel@tonic-gate static int
77387c478bd9Sstevel@tonic-gate cs_remove_device_node(client_handle_t client_handle, remove_device_node_t *rdn)
77397c478bd9Sstevel@tonic-gate {
77407c478bd9Sstevel@tonic-gate 
77417c478bd9Sstevel@tonic-gate 	/*
77427c478bd9Sstevel@tonic-gate 	 * XXX - Note the assumption here that the make_device_node_t and
77437c478bd9Sstevel@tonic-gate 	 *	remove_device_node_t structures are identical.
77447c478bd9Sstevel@tonic-gate 	 */
77457c478bd9Sstevel@tonic-gate 	return (cs_make_device_node(client_handle, (make_device_node_t *)rdn));
77467c478bd9Sstevel@tonic-gate }
77477c478bd9Sstevel@tonic-gate 
77487c478bd9Sstevel@tonic-gate /*
77497c478bd9Sstevel@tonic-gate  * cs_ddi_info - this function is used by clients that need to support
77507c478bd9Sstevel@tonic-gate  *			the xxx_getinfo function; this is CS_DDI_Info
77517c478bd9Sstevel@tonic-gate  */
77527c478bd9Sstevel@tonic-gate static int
77537c478bd9Sstevel@tonic-gate cs_ddi_info(cs_ddi_info_t *cdi)
77547c478bd9Sstevel@tonic-gate {
77557c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
77567c478bd9Sstevel@tonic-gate 	client_t *client;
77577c478bd9Sstevel@tonic-gate 	int client_lock_acquired;
77587c478bd9Sstevel@tonic-gate 
77597c478bd9Sstevel@tonic-gate 	if (cdi->driver_name == NULL)
77607c478bd9Sstevel@tonic-gate 	    return (CS_BAD_ATTRIBUTE);
77617c478bd9Sstevel@tonic-gate 
77627c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
77637c478bd9Sstevel@tonic-gate 	if (cs_debug > 0) {
77647c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_ddi_info: socket %d client [%s]\n",
77657c478bd9Sstevel@tonic-gate 					(int)cdi->Socket, cdi->driver_name);
77667c478bd9Sstevel@tonic-gate 	}
77677c478bd9Sstevel@tonic-gate #endif
77687c478bd9Sstevel@tonic-gate 
77697c478bd9Sstevel@tonic-gate 	/*
77707c478bd9Sstevel@tonic-gate 	 * Check to see if the socket number is in range - the system
77717c478bd9Sstevel@tonic-gate 	 *	framework may cause a client driver to call us with
77727c478bd9Sstevel@tonic-gate 	 *	a socket number that used to be present but isn't
77737c478bd9Sstevel@tonic-gate 	 *	anymore. This is not a bug, and it's OK to return
77747c478bd9Sstevel@tonic-gate 	 *	an error if the socket number is out of range.
77757c478bd9Sstevel@tonic-gate 	 */
77767c478bd9Sstevel@tonic-gate 	if (!CHECK_SOCKET_NUM(cdi->Socket, cs_globals.max_socket_num)) {
77777c478bd9Sstevel@tonic-gate 
77787c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
77797c478bd9Sstevel@tonic-gate 	    if (cs_debug > 0) {
77807c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_ddi_info: socket %d client [%s] "
77817c478bd9Sstevel@tonic-gate 						"SOCKET IS OUT OF RANGE\n",
77827c478bd9Sstevel@tonic-gate 							(int)cdi->Socket,
77837c478bd9Sstevel@tonic-gate 							cdi->driver_name);
77847c478bd9Sstevel@tonic-gate 	    }
77857c478bd9Sstevel@tonic-gate #endif
77867c478bd9Sstevel@tonic-gate 
77877c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
77887c478bd9Sstevel@tonic-gate 	} /* if (!CHECK_SOCKET_NUM) */
77897c478bd9Sstevel@tonic-gate 
77907c478bd9Sstevel@tonic-gate 	/*
77917c478bd9Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
77927c478bd9Sstevel@tonic-gate 	 */
77937c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(cdi->Socket)) == NULL)
77947c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
77957c478bd9Sstevel@tonic-gate 
77967c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
77977c478bd9Sstevel@tonic-gate 
77987c478bd9Sstevel@tonic-gate 	client = sp->client_list;
77997c478bd9Sstevel@tonic-gate 	while (client) {
78007c478bd9Sstevel@tonic-gate 
78017c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
78027c478bd9Sstevel@tonic-gate 	    if (cs_debug > 0) {
78037c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_ddi_info: socket %d checking client [%s] "
78047c478bd9Sstevel@tonic-gate 							"handle 0x%x\n",
78057c478bd9Sstevel@tonic-gate 						(int)cdi->Socket,
78067c478bd9Sstevel@tonic-gate 						client->driver_name,
78077c478bd9Sstevel@tonic-gate 						(int)client->client_handle);
78087c478bd9Sstevel@tonic-gate 	    }
78097c478bd9Sstevel@tonic-gate #endif
78107c478bd9Sstevel@tonic-gate 
78117c478bd9Sstevel@tonic-gate 	    if (client->driver_name != NULL) {
78127c478bd9Sstevel@tonic-gate 		if (!(strcmp(client->driver_name, cdi->driver_name))) {
78137c478bd9Sstevel@tonic-gate 		    cdi->dip = client->dip;
78147c478bd9Sstevel@tonic-gate 		    cdi->instance = client->instance;
78157c478bd9Sstevel@tonic-gate 
78167c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
78177c478bd9Sstevel@tonic-gate 		    if (cs_debug > 0) {
78187c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_ddi_info: found client [%s] "
78197c478bd9Sstevel@tonic-gate 						"instance %d handle 0x%x\n",
78207c478bd9Sstevel@tonic-gate 					client->driver_name, client->instance,
78217c478bd9Sstevel@tonic-gate 					(int)client->client_handle);
78227c478bd9Sstevel@tonic-gate 		    }
78237c478bd9Sstevel@tonic-gate #endif
78247c478bd9Sstevel@tonic-gate 
78257c478bd9Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
78267c478bd9Sstevel@tonic-gate 		    return (CS_SUCCESS);
78277c478bd9Sstevel@tonic-gate 		} /* strcmp */
78287c478bd9Sstevel@tonic-gate 	    } /* driver_name != NULL */
78297c478bd9Sstevel@tonic-gate 	    client = client->next;
78307c478bd9Sstevel@tonic-gate 	} /* while (client) */
78317c478bd9Sstevel@tonic-gate 
78327c478bd9Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
78337c478bd9Sstevel@tonic-gate 	return (CS_BAD_SOCKET);
78347c478bd9Sstevel@tonic-gate }
78357c478bd9Sstevel@tonic-gate 
78367c478bd9Sstevel@tonic-gate /*
78377c478bd9Sstevel@tonic-gate  * cs_sys_ctl - Card Services system control; this is CS_Sys_Ctl
78387c478bd9Sstevel@tonic-gate  */
78397c478bd9Sstevel@tonic-gate static int
78407c478bd9Sstevel@tonic-gate cs_sys_ctl(cs_sys_ctl_t *csc)
78417c478bd9Sstevel@tonic-gate {
78427c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
78437c478bd9Sstevel@tonic-gate 	client_t *cp;
78447c478bd9Sstevel@tonic-gate 	int sn, ret = CS_UNSUPPORTED_MODE;
78457c478bd9Sstevel@tonic-gate 
78467c478bd9Sstevel@tonic-gate 	switch (csc->Action) {
78477c478bd9Sstevel@tonic-gate 	    case CS_SYS_CTL_SEND_EVENT:
78487c478bd9Sstevel@tonic-gate 		if (csc->Flags & CS_SYS_CTL_EVENT_SOCKET)
78497c478bd9Sstevel@tonic-gate 		    sn = CS_GET_SOCKET_NUMBER(csc->Socket);
78507c478bd9Sstevel@tonic-gate 		else
78517c478bd9Sstevel@tonic-gate 		    sn = GET_CLIENT_SOCKET(csc->client_handle);
78527c478bd9Sstevel@tonic-gate 		if ((sp = cs_get_sp(sn)) == NULL)
78537c478bd9Sstevel@tonic-gate 		    return (CS_BAD_SOCKET);
78547c478bd9Sstevel@tonic-gate 		mutex_enter(&sp->client_lock);
78557c478bd9Sstevel@tonic-gate 		mutex_enter(&sp->lock);
78567c478bd9Sstevel@tonic-gate 		csc->Events &= CS_EVENT_CLIENT_EVENTS_MASK;
78577c478bd9Sstevel@tonic-gate 		if (csc->Flags & CS_SYS_CTL_EVENT_SOCKET)
78587c478bd9Sstevel@tonic-gate 		    sp->events |= csc->Events;
78597c478bd9Sstevel@tonic-gate 		if (csc->Flags & CS_SYS_CTL_EVENT_CLIENT) {
78607c478bd9Sstevel@tonic-gate 		    if ((cp = cs_find_client(csc->client_handle, &ret)) ==
78617c478bd9Sstevel@tonic-gate 									NULL) {
78627c478bd9Sstevel@tonic-gate 			mutex_exit(&sp->lock);
78637c478bd9Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
78647c478bd9Sstevel@tonic-gate 			return (ret);
78657c478bd9Sstevel@tonic-gate 		    } /* cs_find_client */
78667c478bd9Sstevel@tonic-gate 			/*
78677c478bd9Sstevel@tonic-gate 			 * Setup the events that we want to send to the client.
78687c478bd9Sstevel@tonic-gate 			 */
78697c478bd9Sstevel@tonic-gate 		    cp->events |= (csc->Events &
78707c478bd9Sstevel@tonic-gate 					(cp->event_mask | cp->global_mask));
78717c478bd9Sstevel@tonic-gate 		} /* CS_SYS_CTL_EVENT_CLIENT */
78727c478bd9Sstevel@tonic-gate 
78737c478bd9Sstevel@tonic-gate 		if (csc->Flags & CS_SYS_CTL_WAIT_SYNC) {
78747c478bd9Sstevel@tonic-gate 		    sp->thread_state |= SOCKET_WAIT_SYNC;
78757c478bd9Sstevel@tonic-gate 		    mutex_exit(&sp->lock);
78767c478bd9Sstevel@tonic-gate 		    cv_broadcast(&sp->thread_cv);
78777c478bd9Sstevel@tonic-gate 		    cv_wait(&sp->caller_cv, &sp->client_lock);
78787c478bd9Sstevel@tonic-gate 		} else {
78797c478bd9Sstevel@tonic-gate 		    mutex_exit(&sp->lock);
78807c478bd9Sstevel@tonic-gate 		    cv_broadcast(&sp->thread_cv);
78817c478bd9Sstevel@tonic-gate 		} /* CS_SYS_CTL_WAIT_SYNC */
78827c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->client_lock);
78837c478bd9Sstevel@tonic-gate 		ret = CS_SUCCESS;
78847c478bd9Sstevel@tonic-gate 		break;
78857c478bd9Sstevel@tonic-gate 	    default:
78867c478bd9Sstevel@tonic-gate 		break;
78877c478bd9Sstevel@tonic-gate 	} /* switch */
78887c478bd9Sstevel@tonic-gate 
78897c478bd9Sstevel@tonic-gate 	return (ret);
78907c478bd9Sstevel@tonic-gate }
78917c478bd9Sstevel@tonic-gate 
78927c478bd9Sstevel@tonic-gate /*
78937c478bd9Sstevel@tonic-gate  * cs_get_sp - returns pointer to per-socket structure for passed
78947c478bd9Sstevel@tonic-gate  *		socket number
78957c478bd9Sstevel@tonic-gate  *
78967c478bd9Sstevel@tonic-gate  *	return:	(cs_socket_t *) - pointer to socket structure
78977c478bd9Sstevel@tonic-gate  *		NULL - invalid socket number passed in
78987c478bd9Sstevel@tonic-gate  */
78997c478bd9Sstevel@tonic-gate static cs_socket_t *
79007c478bd9Sstevel@tonic-gate cs_get_sp(uint32_t sn)
79017c478bd9Sstevel@tonic-gate {
79027c478bd9Sstevel@tonic-gate 	cs_socket_t *sp = cs_globals.sp;
79037c478bd9Sstevel@tonic-gate 
79047c478bd9Sstevel@tonic-gate 	if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY))
79057c478bd9Sstevel@tonic-gate 	    return (NULL);
79067c478bd9Sstevel@tonic-gate 
79077c478bd9Sstevel@tonic-gate 	if ((sp = cs_find_sp(sn)) == NULL)
79087c478bd9Sstevel@tonic-gate 	    return (NULL);
79097c478bd9Sstevel@tonic-gate 
79107c478bd9Sstevel@tonic-gate 	if (sp->flags & SOCKET_IS_VALID)
79117c478bd9Sstevel@tonic-gate 	    return (sp);
79127c478bd9Sstevel@tonic-gate 
79137c478bd9Sstevel@tonic-gate 	return (NULL);
79147c478bd9Sstevel@tonic-gate }
79157c478bd9Sstevel@tonic-gate 
79167c478bd9Sstevel@tonic-gate /*
79177c478bd9Sstevel@tonic-gate  * cs_find_sp - searches socket list and returns pointer to passed socket
79187c478bd9Sstevel@tonic-gate  *			number
79197c478bd9Sstevel@tonic-gate  *
79207c478bd9Sstevel@tonic-gate  *	return:	(cs_socket_t *) - pointer to socket structure if found
79217c478bd9Sstevel@tonic-gate  *		NULL - socket not found
79227c478bd9Sstevel@tonic-gate  */
79237c478bd9Sstevel@tonic-gate static cs_socket_t *
79247c478bd9Sstevel@tonic-gate cs_find_sp(uint32_t sn)
79257c478bd9Sstevel@tonic-gate {
79267c478bd9Sstevel@tonic-gate 	cs_socket_t *sp = cs_globals.sp;
79277c478bd9Sstevel@tonic-gate 
79287c478bd9Sstevel@tonic-gate 	while (sp) {
79297c478bd9Sstevel@tonic-gate 	    if (sp->socket_num == CS_GET_SOCKET_NUMBER(sn))
79307c478bd9Sstevel@tonic-gate 		return (sp);
79317c478bd9Sstevel@tonic-gate 	    sp = sp->next;
79327c478bd9Sstevel@tonic-gate 	} /* while */
79337c478bd9Sstevel@tonic-gate 
79347c478bd9Sstevel@tonic-gate 	return (NULL);
79357c478bd9Sstevel@tonic-gate }
79367c478bd9Sstevel@tonic-gate 
79377c478bd9Sstevel@tonic-gate /*
79387c478bd9Sstevel@tonic-gate  * cs_add_socket - add a socket
79397c478bd9Sstevel@tonic-gate  *
79407c478bd9Sstevel@tonic-gate  *	call:	sn - socket number to add
79417c478bd9Sstevel@tonic-gate  *
79427c478bd9Sstevel@tonic-gate  *	return:	CS_SUCCESS - operation sucessful
79437c478bd9Sstevel@tonic-gate  *		CS_BAD_SOCKET - unable to add socket
79447c478bd9Sstevel@tonic-gate  *		CS_BAD_WINDOW - unable to get CIS window for socket
79457c478bd9Sstevel@tonic-gate  *
79467c478bd9Sstevel@tonic-gate  * We get called here once for each socket that the framework wants to
79477c478bd9Sstevel@tonic-gate  *	add. When we are called, the framework guarentees that until we
79487c478bd9Sstevel@tonic-gate  *	complete this routine, no other adapter instances will be allowed
79497c478bd9Sstevel@tonic-gate  *	to attach and thus no other PCE_ADD_SOCKET events will occur.
79507c478bd9Sstevel@tonic-gate  *	It is safe to call SS_InquireAdapter to get the number of
79517c478bd9Sstevel@tonic-gate  *	windows that the framework currently knows about.
79527c478bd9Sstevel@tonic-gate  */
79537c478bd9Sstevel@tonic-gate static uint32_t
79547c478bd9Sstevel@tonic-gate cs_add_socket(uint32_t sn)
79557c478bd9Sstevel@tonic-gate {
79567c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
79577c478bd9Sstevel@tonic-gate 	sservice_t sservice;
79587c478bd9Sstevel@tonic-gate 	get_cookies_and_dip_t *gcad;
79597c478bd9Sstevel@tonic-gate 	win_req_t win_req;
79607c478bd9Sstevel@tonic-gate 	convert_speed_t convert_speed;
79617c478bd9Sstevel@tonic-gate 	set_socket_t set_socket;
79627c478bd9Sstevel@tonic-gate 	cs_window_t *cw;
79637c478bd9Sstevel@tonic-gate 	inquire_adapter_t inquire_adapter;
79647c478bd9Sstevel@tonic-gate 	inquire_window_t inquire_window;
79657c478bd9Sstevel@tonic-gate 	int ret, added_windows;
79667c478bd9Sstevel@tonic-gate 
79677c478bd9Sstevel@tonic-gate 	if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY))
79687c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
79697c478bd9Sstevel@tonic-gate 
79707c478bd9Sstevel@tonic-gate 	/*
79717c478bd9Sstevel@tonic-gate 	 * See if this socket has already been added - if it has, we
79727c478bd9Sstevel@tonic-gate 	 *	fail this. If we can't find the socket, then allocate
79737c478bd9Sstevel@tonic-gate 	 *	a new socket structure. If we do find the socket, then
79747c478bd9Sstevel@tonic-gate 	 *	check to see if it's already added; if it is, then
79757c478bd9Sstevel@tonic-gate 	 *	this is an error and return CS_BAD_SOCKET; if not,
79767c478bd9Sstevel@tonic-gate 	 *	then traverse the socket structure list and add this
79777c478bd9Sstevel@tonic-gate 	 *	next socket strcture to the end of the list.
79787c478bd9Sstevel@tonic-gate 	 * XXX What about locking this list while we update it? Is
79797c478bd9Sstevel@tonic-gate 	 *	that necessary since we're using the SOCKET_IS_VALID
79807c478bd9Sstevel@tonic-gate 	 *	flag and since we never delete a socket from the
79817c478bd9Sstevel@tonic-gate 	 *	list once it's been added?
79827c478bd9Sstevel@tonic-gate 	 */
79837c478bd9Sstevel@tonic-gate 	if ((sp = cs_find_sp(sn)) == NULL) {
79847c478bd9Sstevel@tonic-gate 	    cs_socket_t *spp = cs_globals.sp;
79857c478bd9Sstevel@tonic-gate 
79867c478bd9Sstevel@tonic-gate 	    sp = (cs_socket_t *)kmem_zalloc(sizeof (cs_socket_t), KM_SLEEP);
79877c478bd9Sstevel@tonic-gate 
79887c478bd9Sstevel@tonic-gate 	    if (cs_globals.sp == NULL)
79897c478bd9Sstevel@tonic-gate 		cs_globals.sp = sp;
79907c478bd9Sstevel@tonic-gate 	    else
79917c478bd9Sstevel@tonic-gate 		while (spp) {
79927c478bd9Sstevel@tonic-gate 		    if (spp->next == NULL) {
79937c478bd9Sstevel@tonic-gate 			spp->next = sp;
79947c478bd9Sstevel@tonic-gate 			break;
79957c478bd9Sstevel@tonic-gate 		    } /* if */
79967c478bd9Sstevel@tonic-gate 		    spp = spp->next;
79977c478bd9Sstevel@tonic-gate 		} /* while */
79987c478bd9Sstevel@tonic-gate 
79997c478bd9Sstevel@tonic-gate 	} else {
80007c478bd9Sstevel@tonic-gate 	    if (sp->flags & SOCKET_IS_VALID)
80017c478bd9Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
80027c478bd9Sstevel@tonic-gate 	} /* cs_find_sp */
80037c478bd9Sstevel@tonic-gate 
80047c478bd9Sstevel@tonic-gate 	/*
80057c478bd9Sstevel@tonic-gate 	 * Setup the socket number
80067c478bd9Sstevel@tonic-gate 	 */
80077c478bd9Sstevel@tonic-gate 	sp->socket_num = sn;
80087c478bd9Sstevel@tonic-gate 
80097c478bd9Sstevel@tonic-gate 	/*
80107c478bd9Sstevel@tonic-gate 	 * Find out how many windows the framework knows about
80117c478bd9Sstevel@tonic-gate 	 *	so far. If this number of windows is greater
80127c478bd9Sstevel@tonic-gate 	 *	than our current window count, bump up our
80137c478bd9Sstevel@tonic-gate 	 *	current window count.
80147c478bd9Sstevel@tonic-gate 	 * XXX Note that there is a BIG assumption here and that
80157c478bd9Sstevel@tonic-gate 	 *	is that once the framework tells us that it has
80167c478bd9Sstevel@tonic-gate 	 *	a window (as reflected in the NumWindows
80177c478bd9Sstevel@tonic-gate 	 *	value) it can NEVER remove that window.
80187c478bd9Sstevel@tonic-gate 	 *	When we really get the drop socket and drop
80197c478bd9Sstevel@tonic-gate 	 *	window mechanism working correctly, we'll have
80207c478bd9Sstevel@tonic-gate 	 *	to revisit this.
80217c478bd9Sstevel@tonic-gate 	 */
80227c478bd9Sstevel@tonic-gate 	SocketServices(SS_InquireAdapter, &inquire_adapter);
80237c478bd9Sstevel@tonic-gate 
80247c478bd9Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
80257c478bd9Sstevel@tonic-gate 	added_windows = inquire_adapter.NumWindows - cs_globals.num_windows;
80267c478bd9Sstevel@tonic-gate 	if (added_windows > 0) {
80277c478bd9Sstevel@tonic-gate 	    if (cs_add_windows(added_windows,
80287c478bd9Sstevel@tonic-gate 				cs_globals.num_windows) != CS_SUCCESS) {
80297c478bd9Sstevel@tonic-gate 		mutex_exit(&cs_globals.window_lock);
80307c478bd9Sstevel@tonic-gate 		return (CS_BAD_WINDOW);
80317c478bd9Sstevel@tonic-gate 	    } /* cs_add_windows */
80327c478bd9Sstevel@tonic-gate 
80337c478bd9Sstevel@tonic-gate 	    cs_globals.num_windows = inquire_adapter.NumWindows;
80347c478bd9Sstevel@tonic-gate 
80357c478bd9Sstevel@tonic-gate 	} /* if (added_windows) */
80367c478bd9Sstevel@tonic-gate 
80377c478bd9Sstevel@tonic-gate 	/*
80387c478bd9Sstevel@tonic-gate 	 * Find a window that we can use for this socket's CIS window.
80397c478bd9Sstevel@tonic-gate 	 */
80407c478bd9Sstevel@tonic-gate 	sp->cis_win_num = PCMCIA_MAX_WINDOWS;
80417c478bd9Sstevel@tonic-gate 
80427c478bd9Sstevel@tonic-gate 	convert_speed.Attributes = CONVERT_NS_TO_DEVSPEED;
80437c478bd9Sstevel@tonic-gate 	convert_speed.nS = CIS_DEFAULT_SPEED;
80447c478bd9Sstevel@tonic-gate 	(void) cs_convert_speed(&convert_speed);
80457c478bd9Sstevel@tonic-gate 
80467c478bd9Sstevel@tonic-gate 	win_req.win_params.AccessSpeed = convert_speed.devspeed;
80477c478bd9Sstevel@tonic-gate 	win_req.Attributes = (WIN_MEMORY_TYPE_AM | WIN_DATA_WIDTH_8);
80487c478bd9Sstevel@tonic-gate 	win_req.Attributes = (WIN_MEMORY_TYPE_AM | WIN_MEMORY_TYPE_CM);
80497c478bd9Sstevel@tonic-gate 	win_req.Base.base = 0;
80507c478bd9Sstevel@tonic-gate 	win_req.Size = 0;
80517c478bd9Sstevel@tonic-gate 
80527c478bd9Sstevel@tonic-gate 	if ((ret = cs_find_mem_window(sp->socket_num, &win_req,
80537c478bd9Sstevel@tonic-gate 					&sp->cis_win_num)) != CS_SUCCESS) {
80547c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
80557c478bd9Sstevel@tonic-gate 	    sp->cis_win_num = PCMCIA_MAX_WINDOWS;
80567c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_add_socket: socket %d can't get CIS "
80577c478bd9Sstevel@tonic-gate 						"window - error 0x%x\n",
80587c478bd9Sstevel@tonic-gate 						sp->socket_num, ret);
80597c478bd9Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
80607c478bd9Sstevel@tonic-gate 	} /* cs_find_mem_window */
80617c478bd9Sstevel@tonic-gate 
80627c478bd9Sstevel@tonic-gate 	if ((cw = cs_get_wp(sp->cis_win_num)) == NULL) {
80637c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
80647c478bd9Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
80657c478bd9Sstevel@tonic-gate 	}
80667c478bd9Sstevel@tonic-gate 
80677c478bd9Sstevel@tonic-gate 	inquire_window.window = sp->cis_win_num;
80687c478bd9Sstevel@tonic-gate 	SocketServices(SS_InquireWindow, &inquire_window);
80697c478bd9Sstevel@tonic-gate 
80707c478bd9Sstevel@tonic-gate 	/*
80717c478bd9Sstevel@tonic-gate 	 * If the CIS window is a variable sized window, then use
80727c478bd9Sstevel@tonic-gate 	 *	the size that cs_find_mem_window returned to us,
80737c478bd9Sstevel@tonic-gate 	 *	since this will be the minimum size that we can
80747c478bd9Sstevel@tonic-gate 	 *	set this window to. If the CIS window is a fixed
80757c478bd9Sstevel@tonic-gate 	 *	sized window, then use the system pagesize as the
80767c478bd9Sstevel@tonic-gate 	 *	CIS window size.
80777c478bd9Sstevel@tonic-gate 	 */
80787c478bd9Sstevel@tonic-gate 	if (inquire_window.mem_win_char.MemWndCaps & WC_SIZE) {
80797c478bd9Sstevel@tonic-gate 	    sp->cis_win_size = win_req.Size;
80807c478bd9Sstevel@tonic-gate 	} else {
80817c478bd9Sstevel@tonic-gate 	    sp->cis_win_size = PAGESIZE;
80827c478bd9Sstevel@tonic-gate 	}
80837c478bd9Sstevel@tonic-gate 
80847c478bd9Sstevel@tonic-gate 	cw->state |= (CW_CIS | CW_ALLOCATED);
80857c478bd9Sstevel@tonic-gate 	cw->socket_num = sp->socket_num;
80867c478bd9Sstevel@tonic-gate 
80877c478bd9Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
80887c478bd9Sstevel@tonic-gate 
80897c478bd9Sstevel@tonic-gate #if defined(CS_DEBUG)
80907c478bd9Sstevel@tonic-gate 	    if (cs_debug > 1) {
80917c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_add_socket: socket %d using CIS window %d "
80927c478bd9Sstevel@tonic-gate 					"size 0x%x\n", (int)sp->socket_num,
80937c478bd9Sstevel@tonic-gate 					(int)sp->cis_win_num,
80947c478bd9Sstevel@tonic-gate 					(int)sp->cis_win_size);
80957c478bd9Sstevel@tonic-gate 	    }
80967c478bd9Sstevel@tonic-gate #endif
80977c478bd9Sstevel@tonic-gate 
80987c478bd9Sstevel@tonic-gate 	/*
80997c478bd9Sstevel@tonic-gate 	 * Get the adapter information associated with this socket so
81007c478bd9Sstevel@tonic-gate 	 *	that we can initialize the mutexes, condition variables,
81017c478bd9Sstevel@tonic-gate 	 *	soft interrupt handler and per-socket adapter info.
81027c478bd9Sstevel@tonic-gate 	 */
81037c478bd9Sstevel@tonic-gate 	gcad = &sservice.get_cookies;
81047c478bd9Sstevel@tonic-gate 	gcad->socket = sp->socket_num;
81057c478bd9Sstevel@tonic-gate 	if (SocketServices(CSGetCookiesAndDip, &sservice) != SUCCESS) {
81067c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_add_socket: socket %d CSGetCookiesAndDip "
81077c478bd9Sstevel@tonic-gate 						"failure\n", sp->socket_num);
81087c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
81097c478bd9Sstevel@tonic-gate 	} /* CSGetCookiesAndDip */
81107c478bd9Sstevel@tonic-gate 
81117c478bd9Sstevel@tonic-gate 	/*
81127c478bd9Sstevel@tonic-gate 	 * Save the iblock and idev cookies for RegisterClient
81137c478bd9Sstevel@tonic-gate 	 */
81147c478bd9Sstevel@tonic-gate 	sp->iblk = gcad->iblock;
81157c478bd9Sstevel@tonic-gate 	sp->idev = gcad->idevice;
81167c478bd9Sstevel@tonic-gate 
81177c478bd9Sstevel@tonic-gate 	/*
81187c478bd9Sstevel@tonic-gate 	 * Setup the per-socket adapter info
81197c478bd9Sstevel@tonic-gate 	 */
81207c478bd9Sstevel@tonic-gate 	sp->adapter.flags = 0;
81217c478bd9Sstevel@tonic-gate 	(void) strcpy(sp->adapter.name, gcad->adapter_info.name);
81227c478bd9Sstevel@tonic-gate 	sp->adapter.major = gcad->adapter_info.major;
81237c478bd9Sstevel@tonic-gate 	sp->adapter.minor = gcad->adapter_info.minor;
81247c478bd9Sstevel@tonic-gate 	sp->adapter.instance = ddi_get_instance(gcad->dip);
81257c478bd9Sstevel@tonic-gate 	sp->adapter.number = gcad->adapter_info.number;
81267c478bd9Sstevel@tonic-gate 	sp->adapter.num_sockets = gcad->adapter_info.num_sockets;
81277c478bd9Sstevel@tonic-gate 	sp->adapter.first_socket = gcad->adapter_info.first_socket;
81287c478bd9Sstevel@tonic-gate 
81297c478bd9Sstevel@tonic-gate 	/* Setup for cs_event and cs_event_thread */
81307c478bd9Sstevel@tonic-gate 	mutex_init(&sp->lock, NULL, MUTEX_DRIVER, *(gcad->iblock));
81317c478bd9Sstevel@tonic-gate 	mutex_init(&sp->client_lock, NULL, MUTEX_DRIVER, NULL);
81327c478bd9Sstevel@tonic-gate 	mutex_init(&sp->cis_lock, NULL, MUTEX_DRIVER, NULL);
81337c478bd9Sstevel@tonic-gate 
81347c478bd9Sstevel@tonic-gate 	/* Setup for Socket Services work thread */
81357c478bd9Sstevel@tonic-gate 	mutex_init(&sp->ss_thread_lock, NULL, MUTEX_DRIVER, NULL);
81367c478bd9Sstevel@tonic-gate 
81377c478bd9Sstevel@tonic-gate 	sp->init_state |= SOCKET_INIT_STATE_MUTEX;
81387c478bd9Sstevel@tonic-gate 
81397c478bd9Sstevel@tonic-gate 	/* Setup for cs_event_thread */
81407c478bd9Sstevel@tonic-gate 	cv_init(&sp->thread_cv, NULL, CV_DRIVER, NULL);
81417c478bd9Sstevel@tonic-gate 	cv_init(&sp->caller_cv, NULL, CV_DRIVER, NULL);
81427c478bd9Sstevel@tonic-gate 	cv_init(&sp->reset_cv, NULL, CV_DRIVER, NULL);
81437c478bd9Sstevel@tonic-gate 
81447c478bd9Sstevel@tonic-gate 	/* Setup for Socket Services work thread */
81457c478bd9Sstevel@tonic-gate 	cv_init(&sp->ss_thread_cv, NULL, CV_DRIVER, NULL);
81467c478bd9Sstevel@tonic-gate 	cv_init(&sp->ss_caller_cv, NULL, CV_DRIVER, NULL);
81477c478bd9Sstevel@tonic-gate 
81487c478bd9Sstevel@tonic-gate 	sp->init_state |= SOCKET_INIT_STATE_CV;
81497c478bd9Sstevel@tonic-gate 
81507c478bd9Sstevel@tonic-gate 	/*
81517c478bd9Sstevel@tonic-gate 	 * If we haven't installed it yet, then install the soft interrupt
81527c478bd9Sstevel@tonic-gate 	 *	handler and save away the softint id.
81537c478bd9Sstevel@tonic-gate 	 */
81547c478bd9Sstevel@tonic-gate 	if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SOFTINTR)) {
81557c478bd9Sstevel@tonic-gate 	    if (ddi_add_softintr(gcad->dip, DDI_SOFTINT_HIGH,
81567c478bd9Sstevel@tonic-gate 						&sp->softint_id,
81577c478bd9Sstevel@tonic-gate 						NULL, NULL,
81587c478bd9Sstevel@tonic-gate 						cs_socket_event_softintr,
81597c478bd9Sstevel@tonic-gate 						(caddr_t)NULL) != DDI_SUCCESS) {
81607c478bd9Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_add_socket: socket %d can't add "
81617c478bd9Sstevel@tonic-gate 						"softintr\n", sp->socket_num);
81627c478bd9Sstevel@tonic-gate 		    return (CS_BAD_SOCKET);
81637c478bd9Sstevel@tonic-gate 	    } /* ddi_add_softintr */
81647c478bd9Sstevel@tonic-gate 
81657c478bd9Sstevel@tonic-gate 	    mutex_enter(&cs_globals.global_lock);
81667c478bd9Sstevel@tonic-gate 	    cs_globals.softint_id = sp->softint_id;
81677c478bd9Sstevel@tonic-gate 	    cs_globals.init_state |= GLOBAL_INIT_STATE_SOFTINTR;
81687c478bd9Sstevel@tonic-gate 	    /* XXX this timer is hokey at best... */
81697c478bd9Sstevel@tonic-gate 	    cs_globals.sotfint_tmo = timeout(cs_event_softintr_timeout,
81707c478bd9Sstevel@tonic-gate 		NULL, SOFTINT_TIMEOUT_TIME);
81717c478bd9Sstevel@tonic-gate 	    mutex_exit(&cs_globals.global_lock);
81727c478bd9Sstevel@tonic-gate 	} else {
81737c478bd9Sstevel@tonic-gate 		/*
81747c478bd9Sstevel@tonic-gate 		 * We've already added the soft interrupt handler, so just
81757c478bd9Sstevel@tonic-gate 		 *	store away the softint id.
81767c478bd9Sstevel@tonic-gate 		 */
81777c478bd9Sstevel@tonic-gate 	    sp->softint_id = cs_globals.softint_id;
81787c478bd9Sstevel@tonic-gate 	} /* if (!GLOBAL_INIT_STATE_SOFTINTR) */
81797c478bd9Sstevel@tonic-gate 
81807c478bd9Sstevel@tonic-gate 	/*
81817c478bd9Sstevel@tonic-gate 	 * While this next flag doesn't really describe a per-socket
81827c478bd9Sstevel@tonic-gate 	 *	resource, we still set it for each socket.  When the soft
81837c478bd9Sstevel@tonic-gate 	 *	interrupt handler finally gets removed in cs_deinit, this
81847c478bd9Sstevel@tonic-gate 	 *	flag will get cleared.
81857c478bd9Sstevel@tonic-gate 	 */
81867c478bd9Sstevel@tonic-gate 	sp->init_state |= SOCKET_INIT_STATE_SOFTINTR;
81877c478bd9Sstevel@tonic-gate 
81887c478bd9Sstevel@tonic-gate 	/*
81897c478bd9Sstevel@tonic-gate 	 * Socket Services defaults all sockets to power off and
81907c478bd9Sstevel@tonic-gate 	 *	clears all event masks.  We want to receive at least
81917c478bd9Sstevel@tonic-gate 	 *	card insertion events, so enable them.  Turn off power
81927c478bd9Sstevel@tonic-gate 	 *	to the socket as well.  We will turn it on again when
81937c478bd9Sstevel@tonic-gate 	 *	we get a card insertion event.
81947c478bd9Sstevel@tonic-gate 	 */
81957c478bd9Sstevel@tonic-gate 	sp->event_mask = CS_EVENT_CARD_INSERTION;
81967c478bd9Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
81977c478bd9Sstevel@tonic-gate 	set_socket.SCIntMask = SBM_CD;
81987c478bd9Sstevel@tonic-gate 	set_socket.IREQRouting = 0;
81997c478bd9Sstevel@tonic-gate 	set_socket.IFType = IF_MEMORY;
82007c478bd9Sstevel@tonic-gate 	set_socket.CtlInd = 0; /* turn off controls and indicators */
82017c478bd9Sstevel@tonic-gate 	set_socket.State = (unsigned)~0;	/* clear latched state bits */
82027c478bd9Sstevel@tonic-gate 
82037c478bd9Sstevel@tonic-gate 	(void) cs_convert_powerlevel(sp->socket_num, 0, VCC,
82047c478bd9Sstevel@tonic-gate 						&set_socket.VccLevel);
82057c478bd9Sstevel@tonic-gate 	(void) cs_convert_powerlevel(sp->socket_num, 0, VPP1,
82067c478bd9Sstevel@tonic-gate 						&set_socket.Vpp1Level);
82077c478bd9Sstevel@tonic-gate 	(void) cs_convert_powerlevel(sp->socket_num, 0, VPP2,
82087c478bd9Sstevel@tonic-gate 						&set_socket.Vpp2Level);
82097c478bd9Sstevel@tonic-gate 
82107c478bd9Sstevel@tonic-gate 	if ((ret = SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
82117c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_add_socket: socket %d SS_SetSocket "
82127c478bd9Sstevel@tonic-gate 					"failure %d\n", sp->socket_num, ret);
82137c478bd9Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
82147c478bd9Sstevel@tonic-gate 	} /* SS_SetSocket */
82157c478bd9Sstevel@tonic-gate 
82167c478bd9Sstevel@tonic-gate 	/*
82177c478bd9Sstevel@tonic-gate 	 * The various socket-specific variables are now set up, so
82187c478bd9Sstevel@tonic-gate 	 *	increment the global socket count and also mark the
82197c478bd9Sstevel@tonic-gate 	 *	socket as available. We need to set this before we
82207c478bd9Sstevel@tonic-gate 	 *	start any of the per-socket threads so that the threads
82217c478bd9Sstevel@tonic-gate 	 *	can get a valid socket pointer when they start.
82227c478bd9Sstevel@tonic-gate 	 */
82237c478bd9Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
82247c478bd9Sstevel@tonic-gate 	cs_globals.num_sockets++;
82257c478bd9Sstevel@tonic-gate 	cs_globals.max_socket_num =
82267c478bd9Sstevel@tonic-gate 			max(cs_globals.max_socket_num, sp->socket_num + 1);
82277c478bd9Sstevel@tonic-gate 	mutex_exit(&cs_globals.global_lock);
82287c478bd9Sstevel@tonic-gate 	sp->flags = SOCKET_IS_VALID;
82297c478bd9Sstevel@tonic-gate 
82307c478bd9Sstevel@tonic-gate 	/*
82317c478bd9Sstevel@tonic-gate 	 * Create the per-socket event handler thread.
82327c478bd9Sstevel@tonic-gate 	 */
82337c478bd9Sstevel@tonic-gate 	sp->event_thread = CREATE_SOCKET_EVENT_THREAD(cs_event_thread,
82347c478bd9Sstevel@tonic-gate 		(uintptr_t)sn);
82357c478bd9Sstevel@tonic-gate 
82367c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
82377c478bd9Sstevel@tonic-gate 	sp->init_state |= SOCKET_INIT_STATE_THREAD;
82387c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
82397c478bd9Sstevel@tonic-gate 
82407c478bd9Sstevel@tonic-gate 	/*
82417c478bd9Sstevel@tonic-gate 	 * Create the per-socket Socket Services work thread.
82427c478bd9Sstevel@tonic-gate 	 */
82437c478bd9Sstevel@tonic-gate 	sp->ss_thread = CREATE_SOCKET_EVENT_THREAD(cs_ss_thread,
82447c478bd9Sstevel@tonic-gate 		(uintptr_t)sn);
82457c478bd9Sstevel@tonic-gate 
82467c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
82477c478bd9Sstevel@tonic-gate 	sp->init_state |= (SOCKET_INIT_STATE_SS_THREAD |
82487c478bd9Sstevel@tonic-gate 						SOCKET_INIT_STATE_READY);
82497c478bd9Sstevel@tonic-gate 	sp->event_mask = CS_EVENT_CARD_INSERTION;
82507c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
82517c478bd9Sstevel@tonic-gate 
82527c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
82537c478bd9Sstevel@tonic-gate }
82547c478bd9Sstevel@tonic-gate 
82557c478bd9Sstevel@tonic-gate /*
82567c478bd9Sstevel@tonic-gate  * cs_drop_socket - drop a socket
82577c478bd9Sstevel@tonic-gate  *
82587c478bd9Sstevel@tonic-gate  *	call:	sn - socket number to drop
82597c478bd9Sstevel@tonic-gate  *
82607c478bd9Sstevel@tonic-gate  *	return:	CS_SUCCESS - operation sucessful
82617c478bd9Sstevel@tonic-gate  *		CS_BAD_SOCKET - unable to drop socket
82627c478bd9Sstevel@tonic-gate  */
82637c478bd9Sstevel@tonic-gate /*ARGSUSED*/
82647c478bd9Sstevel@tonic-gate static uint32_t
82657c478bd9Sstevel@tonic-gate cs_drop_socket(uint32_t sn)
82667c478bd9Sstevel@tonic-gate {
82677c478bd9Sstevel@tonic-gate #ifdef	XXX
82687c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
82697c478bd9Sstevel@tonic-gate 
82707c478bd9Sstevel@tonic-gate 	/*
82717c478bd9Sstevel@tonic-gate 	 * Tell the socket event thread to exit and then wait for it
82727c478bd9Sstevel@tonic-gate 	 *	to do so.
82737c478bd9Sstevel@tonic-gate 	 */
82747c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->client_lock);
82757c478bd9Sstevel@tonic-gate 	sp->thread_state |= SOCKET_THREAD_EXIT;
82767c478bd9Sstevel@tonic-gate 	cv_broadcast(&sp->thread_cv);
82777c478bd9Sstevel@tonic-gate 	cv_wait(&sp->caller_cv, &sp->client_lock);
82787c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->client_lock);
82797c478bd9Sstevel@tonic-gate 
82807c478bd9Sstevel@tonic-gate 	/*
82817c478bd9Sstevel@tonic-gate 	 * Tell the socket SS thread to exit and then wait for it
82827c478bd9Sstevel@tonic-gate 	 *	to do so.
82837c478bd9Sstevel@tonic-gate 	 */
82847c478bd9Sstevel@tonic-gate 
82857c478bd9Sstevel@tonic-gate 	/*
82867c478bd9Sstevel@tonic-gate 	 * Mark the socket as dropped.
82877c478bd9Sstevel@tonic-gate 	 */
82887c478bd9Sstevel@tonic-gate 	sp->flags &= ~SOCKET_IS_VALID;
82897c478bd9Sstevel@tonic-gate 
82907c478bd9Sstevel@tonic-gate #endif	/* XXX */
82917c478bd9Sstevel@tonic-gate 
82927c478bd9Sstevel@tonic-gate 	/* XXX for now don't allow dropping sockets XXX */
82937c478bd9Sstevel@tonic-gate 	return (CS_BAD_SOCKET);
82947c478bd9Sstevel@tonic-gate }
82957c478bd9Sstevel@tonic-gate 
82967c478bd9Sstevel@tonic-gate /*
82977c478bd9Sstevel@tonic-gate  * cs_get_socket - returns the socket and function numbers and a pointer
82987c478bd9Sstevel@tonic-gate  *			to the socket structure
82997c478bd9Sstevel@tonic-gate  *
83007c478bd9Sstevel@tonic-gate  * calling:	client_handle_t client_handle - client handle to extract
83017c478bd9Sstevel@tonic-gate  *						socket number from
83027c478bd9Sstevel@tonic-gate  *		uint32_t *socket -  pointer to socket number to use if
83037c478bd9Sstevel@tonic-gate  *					client_handle is for the SS client;
83047c478bd9Sstevel@tonic-gate  *					this value will be filled in on
83057c478bd9Sstevel@tonic-gate  *					return with the correct socket
83067c478bd9Sstevel@tonic-gate  *					and function numbers if we
83077c478bd9Sstevel@tonic-gate  *					return CS_SUCCESS
83087c478bd9Sstevel@tonic-gate  *		uint32_t *function - pointer to return function number into
83097c478bd9Sstevel@tonic-gate  *					if not NULL
83107c478bd9Sstevel@tonic-gate  *		cs_socket_t **sp - pointer to a pointer where a pointer
83117c478bd9Sstevel@tonic-gate  *					to the socket struct will be
83127c478bd9Sstevel@tonic-gate  *					placed if this is non-NULL
83137c478bd9Sstevel@tonic-gate  *		client_t **clp - pointer to a pointer where a pointer
83147c478bd9Sstevel@tonic-gate  *					to the client struct will be
83157c478bd9Sstevel@tonic-gate  *					placed if this is non-NULL
83167c478bd9Sstevel@tonic-gate  *
83177c478bd9Sstevel@tonic-gate  *    The socket and function numbers are derived as follows:
83187c478bd9Sstevel@tonic-gate  *
83197c478bd9Sstevel@tonic-gate  *	Client Type		Socket Number		Function Number
83207c478bd9Sstevel@tonic-gate  *	PC card client		From client_handle	From client_handle
83217c478bd9Sstevel@tonic-gate  *	Socket Services client	From *socket		From *socket
83227c478bd9Sstevel@tonic-gate  *	CSI client		From client_handle	From *socket
83237c478bd9Sstevel@tonic-gate  */
83247c478bd9Sstevel@tonic-gate static uint32_t
83257c478bd9Sstevel@tonic-gate cs_get_socket(client_handle_t client_handle, uint32_t *socket,
83267c478bd9Sstevel@tonic-gate     uint32_t *function, cs_socket_t **csp, client_t **clp)
83277c478bd9Sstevel@tonic-gate {
83287c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
83297c478bd9Sstevel@tonic-gate 	client_t *client;
83307c478bd9Sstevel@tonic-gate 	uint32_t sn, fn;
83317c478bd9Sstevel@tonic-gate 	int ret;
83327c478bd9Sstevel@tonic-gate 
83337c478bd9Sstevel@tonic-gate 	sn = *socket;
83347c478bd9Sstevel@tonic-gate 
83357c478bd9Sstevel@tonic-gate 	/*
83367c478bd9Sstevel@tonic-gate 	 * If this is the Socket Services client, then return the
83377c478bd9Sstevel@tonic-gate 	 *	socket and function numbers specified in the passed
83387c478bd9Sstevel@tonic-gate 	 *	socket number parameter, otherwise extract the socket
83397c478bd9Sstevel@tonic-gate 	 *	and function numbers from the client handle.
83407c478bd9Sstevel@tonic-gate 	 */
83417c478bd9Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle)) {
83427c478bd9Sstevel@tonic-gate 	    fn = CS_GET_FUNCTION_NUMBER(sn);
83437c478bd9Sstevel@tonic-gate 	    sn = CS_GET_SOCKET_NUMBER(sn);
83447c478bd9Sstevel@tonic-gate 	} else {
83457c478bd9Sstevel@tonic-gate 	    fn = GET_CLIENT_FUNCTION(client_handle);
83467c478bd9Sstevel@tonic-gate 	    sn = GET_CLIENT_SOCKET(client_handle);
83477c478bd9Sstevel@tonic-gate 	}
83487c478bd9Sstevel@tonic-gate 
83497c478bd9Sstevel@tonic-gate 	/*
83507c478bd9Sstevel@tonic-gate 	 * Check to be sure that the socket number is in range
83517c478bd9Sstevel@tonic-gate 	 */
83527c478bd9Sstevel@tonic-gate 	if (!(CHECK_SOCKET_NUM(sn, cs_globals.max_socket_num)))
83537c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
83547c478bd9Sstevel@tonic-gate 
83557c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(sn)) == NULL)
83567c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
83577c478bd9Sstevel@tonic-gate 
83587c478bd9Sstevel@tonic-gate 	/*
83597c478bd9Sstevel@tonic-gate 	 * If we were given a pointer, then fill it in with a pointer
83607c478bd9Sstevel@tonic-gate 	 *	to this socket.
83617c478bd9Sstevel@tonic-gate 	 */
83627c478bd9Sstevel@tonic-gate 	if (csp)
83637c478bd9Sstevel@tonic-gate 	    *csp = sp;
83647c478bd9Sstevel@tonic-gate 
83657c478bd9Sstevel@tonic-gate 	/*
83667c478bd9Sstevel@tonic-gate 	 * Search for the client; if it's not found, return an error.
83677c478bd9Sstevel@tonic-gate 	 */
83687c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
83697c478bd9Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &ret))) {
83707c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
83717c478bd9Sstevel@tonic-gate 	    return (ret);
83727c478bd9Sstevel@tonic-gate 	}
83737c478bd9Sstevel@tonic-gate 
83747c478bd9Sstevel@tonic-gate 	/*
83757c478bd9Sstevel@tonic-gate 	 * If we're a CIS client, then extract the function number
83767c478bd9Sstevel@tonic-gate 	 *	from the socket number.
83777c478bd9Sstevel@tonic-gate 	 */
83787c478bd9Sstevel@tonic-gate 	if (client->flags & CLIENT_CSI_CLIENT)
83797c478bd9Sstevel@tonic-gate 	    fn = CS_GET_FUNCTION_NUMBER(*socket);
83807c478bd9Sstevel@tonic-gate 
83817c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
83827c478bd9Sstevel@tonic-gate 
83837c478bd9Sstevel@tonic-gate 	/*
83847c478bd9Sstevel@tonic-gate 	 * Return the found client pointer if the caller wants it.
83857c478bd9Sstevel@tonic-gate 	 */
83867c478bd9Sstevel@tonic-gate 	if (clp)
83877c478bd9Sstevel@tonic-gate 	    *clp = client;
83887c478bd9Sstevel@tonic-gate 
83897c478bd9Sstevel@tonic-gate 	/*
83907c478bd9Sstevel@tonic-gate 	 * Return a socket number that is made up of the socket number
83917c478bd9Sstevel@tonic-gate 	 *	and the function number.
83927c478bd9Sstevel@tonic-gate 	 */
83937c478bd9Sstevel@tonic-gate 	*socket = CS_MAKE_SOCKET_NUMBER(sn, fn);
83947c478bd9Sstevel@tonic-gate 
83957c478bd9Sstevel@tonic-gate 	/*
83967c478bd9Sstevel@tonic-gate 	 * Return the function number if the caller wants it.
83977c478bd9Sstevel@tonic-gate 	 */
83987c478bd9Sstevel@tonic-gate 	if (function)
83997c478bd9Sstevel@tonic-gate 	    *function = fn;
84007c478bd9Sstevel@tonic-gate 
84017c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
84027c478bd9Sstevel@tonic-gate }
84037c478bd9Sstevel@tonic-gate 
84047c478bd9Sstevel@tonic-gate /*
84057c478bd9Sstevel@tonic-gate  * cs_get_wp - returns pointer to passed window number
84067c478bd9Sstevel@tonic-gate  *
84077c478bd9Sstevel@tonic-gate  *	return: (cs_window_t *) - pointer to window structure
84087c478bd9Sstevel@tonic-gate  *		NULL - if invalid window number passed in
84097c478bd9Sstevel@tonic-gate  */
84107c478bd9Sstevel@tonic-gate static cs_window_t *
84117c478bd9Sstevel@tonic-gate cs_get_wp(uint32_t wn)
84127c478bd9Sstevel@tonic-gate {
84137c478bd9Sstevel@tonic-gate 	cs_window_t *cw;
84147c478bd9Sstevel@tonic-gate 
84157c478bd9Sstevel@tonic-gate 	if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY))
84167c478bd9Sstevel@tonic-gate 	    return (NULL);
84177c478bd9Sstevel@tonic-gate 
84187c478bd9Sstevel@tonic-gate 	if ((cw = cs_find_wp(wn)) == NULL)
84197c478bd9Sstevel@tonic-gate 	    return (NULL);
84207c478bd9Sstevel@tonic-gate 
84217c478bd9Sstevel@tonic-gate 	if (cw->state & CW_WINDOW_VALID)
84227c478bd9Sstevel@tonic-gate 	    return (cw);
84237c478bd9Sstevel@tonic-gate 
84247c478bd9Sstevel@tonic-gate #ifdef  CS_DEBUG
84257c478bd9Sstevel@tonic-gate 	if (cs_debug > 0) {
84267c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_get_wp(): wn=%d  cw=%p\n",
84277c478bd9Sstevel@tonic-gate 		    (int)wn, (void *)cw);
84287c478bd9Sstevel@tonic-gate 	}
84297c478bd9Sstevel@tonic-gate #endif
84307c478bd9Sstevel@tonic-gate 
84317c478bd9Sstevel@tonic-gate 	return (NULL);
84327c478bd9Sstevel@tonic-gate }
84337c478bd9Sstevel@tonic-gate 
84347c478bd9Sstevel@tonic-gate /*
84357c478bd9Sstevel@tonic-gate  * cs_find_wp - searches window list and returns pointer to passed window
84367c478bd9Sstevel@tonic-gate  *			number
84377c478bd9Sstevel@tonic-gate  *
84387c478bd9Sstevel@tonic-gate  *	return: (cs_window_t *) - pointer to window structure
84397c478bd9Sstevel@tonic-gate  *		NULL - window not found
84407c478bd9Sstevel@tonic-gate  */
84417c478bd9Sstevel@tonic-gate static cs_window_t *
84427c478bd9Sstevel@tonic-gate cs_find_wp(uint32_t wn)
84437c478bd9Sstevel@tonic-gate {
84447c478bd9Sstevel@tonic-gate 	cs_window_t *cw = cs_globals.cw;
84457c478bd9Sstevel@tonic-gate 
84467c478bd9Sstevel@tonic-gate 	while (cw) {
84477c478bd9Sstevel@tonic-gate 	    if (cw->window_num == wn)
84487c478bd9Sstevel@tonic-gate 		return (cw);
84497c478bd9Sstevel@tonic-gate 	    cw = cw->next;
84507c478bd9Sstevel@tonic-gate 	} /* while */
84517c478bd9Sstevel@tonic-gate 
84527c478bd9Sstevel@tonic-gate #ifdef  CS_DEBUG
84537c478bd9Sstevel@tonic-gate 	if (cs_debug > 0) {
84547c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_find_wp(): wn=%d  window_num=%d cw=%p\n",
84557c478bd9Sstevel@tonic-gate 		    (int)wn, (int)cw->window_num, (void *)cw);
84567c478bd9Sstevel@tonic-gate 	}
84577c478bd9Sstevel@tonic-gate #endif
84587c478bd9Sstevel@tonic-gate 
84597c478bd9Sstevel@tonic-gate 	return (NULL);
84607c478bd9Sstevel@tonic-gate }
84617c478bd9Sstevel@tonic-gate 
84627c478bd9Sstevel@tonic-gate /*
84637c478bd9Sstevel@tonic-gate  * cs_add_windows - adds number of windows specified in "aw" to
84647c478bd9Sstevel@tonic-gate  *			the global window list; start the window
84657c478bd9Sstevel@tonic-gate  *			numbering at "bn"
84667c478bd9Sstevel@tonic-gate  *
84677c478bd9Sstevel@tonic-gate  *	return: CS_SUCCESS - if windows added sucessfully
84687c478bd9Sstevel@tonic-gate  *		CS_BAD_WINDOW - if unable to add windows
84697c478bd9Sstevel@tonic-gate  *
84707c478bd9Sstevel@tonic-gate  * Note: The window list must be protected by a lock by the caller.
84717c478bd9Sstevel@tonic-gate  */
84727c478bd9Sstevel@tonic-gate static int
84737c478bd9Sstevel@tonic-gate cs_add_windows(int aw, uint32_t bn)
84747c478bd9Sstevel@tonic-gate {
84757c478bd9Sstevel@tonic-gate 	cs_window_t *cwp = cs_globals.cw;
84767c478bd9Sstevel@tonic-gate 	cs_window_t *cw, *cwpp;
84777c478bd9Sstevel@tonic-gate 
84787c478bd9Sstevel@tonic-gate 	if (aw <= 0)
84797c478bd9Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
84807c478bd9Sstevel@tonic-gate 
84817c478bd9Sstevel@tonic-gate 	while (cwp) {
84827c478bd9Sstevel@tonic-gate 	    cwpp = cwp;
84837c478bd9Sstevel@tonic-gate 	    cwp = cwp->next;
84847c478bd9Sstevel@tonic-gate 	}
84857c478bd9Sstevel@tonic-gate 
84867c478bd9Sstevel@tonic-gate 	while (aw--) {
84877c478bd9Sstevel@tonic-gate 	    cw = (cs_window_t *)kmem_zalloc(sizeof (cs_window_t), KM_SLEEP);
84887c478bd9Sstevel@tonic-gate 
84897c478bd9Sstevel@tonic-gate 	    if (cs_globals.cw == NULL) {
84907c478bd9Sstevel@tonic-gate 		cs_globals.cw = cw;
84917c478bd9Sstevel@tonic-gate 		cwpp = cs_globals.cw;
84927c478bd9Sstevel@tonic-gate 	    } else {
84937c478bd9Sstevel@tonic-gate 		cwpp->next = cw;
84947c478bd9Sstevel@tonic-gate 		cwpp = cwpp->next;
84957c478bd9Sstevel@tonic-gate 	    }
84967c478bd9Sstevel@tonic-gate 
84977c478bd9Sstevel@tonic-gate 	    cwpp->window_num = bn++;
84987c478bd9Sstevel@tonic-gate 	    cwpp->state = CW_WINDOW_VALID;
84997c478bd9Sstevel@tonic-gate 
85007c478bd9Sstevel@tonic-gate 	} /* while (aw) */
85017c478bd9Sstevel@tonic-gate 
85027c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
85037c478bd9Sstevel@tonic-gate }
85047c478bd9Sstevel@tonic-gate 
85057c478bd9Sstevel@tonic-gate /*
85067c478bd9Sstevel@tonic-gate  * cs_ss_init - initialize CS items that need to wait until we receive
85077c478bd9Sstevel@tonic-gate  *			a PCE_SS_INIT_STATE/PCE_SS_STATE_INIT event
85087c478bd9Sstevel@tonic-gate  *
85097c478bd9Sstevel@tonic-gate  *	return: CS_SUCESS - if sucessfully initialized
85107c478bd9Sstevel@tonic-gate  *		(various) if error initializing
85117c478bd9Sstevel@tonic-gate  *
85127c478bd9Sstevel@tonic-gate  *	At this point, we expect that Socket Services has setup the
85137c478bd9Sstevel@tonic-gate  *	following global variables for us:
85147c478bd9Sstevel@tonic-gate  *
85157c478bd9Sstevel@tonic-gate  *		cs_socket_services - Socket Services entry point
85167c478bd9Sstevel@tonic-gate  *		cis_parser - CIS parser entry point
85177c478bd9Sstevel@tonic-gate  */
85187c478bd9Sstevel@tonic-gate static uint32_t
85197c478bd9Sstevel@tonic-gate cs_ss_init()
85207c478bd9Sstevel@tonic-gate {
85217c478bd9Sstevel@tonic-gate 	cs_register_cardservices_t rcs;
85227c478bd9Sstevel@tonic-gate 	csregister_t csr;
85237c478bd9Sstevel@tonic-gate 	uint32_t ret;
85247c478bd9Sstevel@tonic-gate 
85257c478bd9Sstevel@tonic-gate 	/*
85267c478bd9Sstevel@tonic-gate 	 * Fill out the parameters for CISP_CIS_SETUP
85277c478bd9Sstevel@tonic-gate 	 */
85287c478bd9Sstevel@tonic-gate 	csr.cs_magic = PCCS_MAGIC;
85297c478bd9Sstevel@tonic-gate 	csr.cs_version = PCCS_VERSION;
85307c478bd9Sstevel@tonic-gate 	csr.cs_card_services = CardServices;
85317c478bd9Sstevel@tonic-gate 	csr.cs_event = NULL;
85327c478bd9Sstevel@tonic-gate 
85337c478bd9Sstevel@tonic-gate 	/*
85347c478bd9Sstevel@tonic-gate 	 * Call into the CIS module and tell it what the private
85357c478bd9Sstevel@tonic-gate 	 *	Card Services entry point is. The CIS module will
85367c478bd9Sstevel@tonic-gate 	 *	call us back at CardServices(CISRegister, ...)
85377c478bd9Sstevel@tonic-gate 	 *	with the address of various CIS-specific global
85387c478bd9Sstevel@tonic-gate 	 *	data structures.
85397c478bd9Sstevel@tonic-gate 	 */
85407c478bd9Sstevel@tonic-gate 	CIS_PARSER(CISP_CIS_SETUP, &csr);
85417c478bd9Sstevel@tonic-gate 
85427c478bd9Sstevel@tonic-gate 	/*
85437c478bd9Sstevel@tonic-gate 	 * Register with the Card Services kernel stubs module
85447c478bd9Sstevel@tonic-gate 	 */
85457c478bd9Sstevel@tonic-gate 	rcs.magic = CS_STUBS_MAGIC;
85467c478bd9Sstevel@tonic-gate 	rcs.function = CS_ENTRY_REGISTER;
85477c478bd9Sstevel@tonic-gate 	rcs.cardservices = CardServices;
85487c478bd9Sstevel@tonic-gate 
85497c478bd9Sstevel@tonic-gate 	if ((ret = csx_register_cardservices(&rcs)) != CS_SUCCESS) {
85507c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_ss_init: can't register with "
85517c478bd9Sstevel@tonic-gate 					"cs_stubs, retcode = 0x%x\n", ret);
85527c478bd9Sstevel@tonic-gate 		return (ret);
85537c478bd9Sstevel@tonic-gate 	} /* csx_register_cardservices */
85547c478bd9Sstevel@tonic-gate 
85557c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
85567c478bd9Sstevel@tonic-gate }
85577c478bd9Sstevel@tonic-gate 
85587c478bd9Sstevel@tonic-gate /*
85597c478bd9Sstevel@tonic-gate  * cs_create_cis - reads CIS on card in socket and creates CIS lists
85607c478bd9Sstevel@tonic-gate  *
85617c478bd9Sstevel@tonic-gate  * Most of the work is done in the CIS module in the CISP_CIS_LIST_CREATE
85627c478bd9Sstevel@tonic-gate  *	function.
85637c478bd9Sstevel@tonic-gate  *
85647c478bd9Sstevel@tonic-gate  * This function returns:
85657c478bd9Sstevel@tonic-gate  *
85667c478bd9Sstevel@tonic-gate  *	CS_SUCCESS - if the CIS lists were created sucessfully
85677c478bd9Sstevel@tonic-gate  *	CS_BAD_WINDOW or CS_GENERAL_FAILURE - if CIS window could
85687c478bd9Sstevel@tonic-gate  *			not be setup
85697c478bd9Sstevel@tonic-gate  *	CS_BAD_CIS - if error creating CIS chains
85707c478bd9Sstevel@tonic-gate  *	CS_BAD_OFFSET - if the CIS parser tried to read past the
85717c478bd9Sstevel@tonic-gate  *			boundries of the allocated CIS window
85727c478bd9Sstevel@tonic-gate  */
85737c478bd9Sstevel@tonic-gate static int
85747c478bd9Sstevel@tonic-gate cs_create_cis(cs_socket_t *sp)
85757c478bd9Sstevel@tonic-gate {
85767c478bd9Sstevel@tonic-gate 	uint32_t ret;
85777c478bd9Sstevel@tonic-gate 
85787c478bd9Sstevel@tonic-gate 	ret = (uint32_t)(uintptr_t)CIS_PARSER(CISP_CIS_LIST_CREATE,
85797c478bd9Sstevel@tonic-gate 	    cis_cistpl_std_callout, sp);
85807c478bd9Sstevel@tonic-gate 
85817c478bd9Sstevel@tonic-gate #ifdef	CS_DEBUG
85827c478bd9Sstevel@tonic-gate 	if (ret == CS_NO_CIS) {
85837c478bd9Sstevel@tonic-gate 	    if (cs_debug > 0)
85847c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_create_cis: socket %d has no CIS\n",
85857c478bd9Sstevel@tonic-gate 								sp->socket_num);
85867c478bd9Sstevel@tonic-gate 	} else if (ret != CS_SUCCESS) {
85877c478bd9Sstevel@tonic-gate 	    if (cs_debug > 0)
85887c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_create_cis: socket %d ERROR = 0x%x\n",
85897c478bd9Sstevel@tonic-gate 							sp->socket_num, ret);
85907c478bd9Sstevel@tonic-gate 	    return (ret);
85917c478bd9Sstevel@tonic-gate 	}
85927c478bd9Sstevel@tonic-gate #else
85937c478bd9Sstevel@tonic-gate 	if (ret != CS_NO_CIS)
85947c478bd9Sstevel@tonic-gate 	    if (ret != CS_SUCCESS)
85957c478bd9Sstevel@tonic-gate 		return (ret);
85967c478bd9Sstevel@tonic-gate #endif
85977c478bd9Sstevel@tonic-gate 
85987c478bd9Sstevel@tonic-gate 	/*
85997c478bd9Sstevel@tonic-gate 	 * If this card didn't have any CIS at all, there's not much
86007c478bd9Sstevel@tonic-gate 	 *	else for us to do.
86017c478bd9Sstevel@tonic-gate 	 */
86027c478bd9Sstevel@tonic-gate 	if (!(sp->cis_flags & CW_VALID_CIS))
86037c478bd9Sstevel@tonic-gate 	    return (CS_SUCCESS);
86047c478bd9Sstevel@tonic-gate 
86057c478bd9Sstevel@tonic-gate 	/*
86067c478bd9Sstevel@tonic-gate 	 * If this is a single-function card, we need to move the CIS list
86077c478bd9Sstevel@tonic-gate 	 *	that is currently on CS_GLOBAL_CIS to the function zero
86087c478bd9Sstevel@tonic-gate 	 *	CIS list.
86097c478bd9Sstevel@tonic-gate 	 */
86107c478bd9Sstevel@tonic-gate 	if (!(sp->cis_flags & CW_MULTI_FUNCTION_CIS)) {
86117c478bd9Sstevel@tonic-gate 	    bcopy((caddr_t)&sp->cis[CS_GLOBAL_CIS],
86127c478bd9Sstevel@tonic-gate 				(caddr_t)&sp->cis[0], sizeof (cis_info_t));
86137c478bd9Sstevel@tonic-gate 	    bzero((caddr_t)&sp->cis[CS_GLOBAL_CIS], sizeof (cis_info_t));
86147c478bd9Sstevel@tonic-gate 	} /* !CW_MULTI_FUNCTION_CIS */
86157c478bd9Sstevel@tonic-gate 
86167c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
86177c478bd9Sstevel@tonic-gate }
86187c478bd9Sstevel@tonic-gate 
86197c478bd9Sstevel@tonic-gate /*
86207c478bd9Sstevel@tonic-gate  * cs_destroy_cis - destroys CIS list for socket
86217c478bd9Sstevel@tonic-gate  */
86227c478bd9Sstevel@tonic-gate static int
86237c478bd9Sstevel@tonic-gate cs_destroy_cis(cs_socket_t *sp)
86247c478bd9Sstevel@tonic-gate {
86257c478bd9Sstevel@tonic-gate 	CIS_PARSER(CISP_CIS_LIST_DESTROY, sp);
86267c478bd9Sstevel@tonic-gate 
86277c478bd9Sstevel@tonic-gate 	return (CS_SUCCESS);
86287c478bd9Sstevel@tonic-gate }
86297c478bd9Sstevel@tonic-gate 
86307c478bd9Sstevel@tonic-gate /*
86317c478bd9Sstevel@tonic-gate  * cs_get_client_info - This function is GetClientInfo.
86327c478bd9Sstevel@tonic-gate  *
86337c478bd9Sstevel@tonic-gate  *    calling:	client_handle_t - client handle to get client info on
86347c478bd9Sstevel@tonic-gate  *		client_info_t * - pointer to a client_info_t structure
86357c478bd9Sstevel@tonic-gate  *					to return client information in
86367c478bd9Sstevel@tonic-gate  *
86377c478bd9Sstevel@tonic-gate  *    returns:	CS_SUCCESS - if client info retreived from client
86387c478bd9Sstevel@tonic-gate  *		CS_BAD_SOCKET, CS_BAD_HANDLE - if invalid client
86397c478bd9Sstevel@tonic-gate  *					handle passed in
86407c478bd9Sstevel@tonic-gate  *		CS_NO_MORE_ITEMS - if client does not handle the
86417c478bd9Sstevel@tonic-gate  *					CS_EVENT_CLIENT_INFO event
86427c478bd9Sstevel@tonic-gate  *					or if invalid client info
86437c478bd9Sstevel@tonic-gate  *					retreived from client
86447c478bd9Sstevel@tonic-gate  */
86457c478bd9Sstevel@tonic-gate static int
86467c478bd9Sstevel@tonic-gate cs_get_client_info(client_handle_t client_handle, client_info_t *ci)
86477c478bd9Sstevel@tonic-gate {
86487c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
86497c478bd9Sstevel@tonic-gate 	client_t *client;
86507c478bd9Sstevel@tonic-gate 	client_info_t *cinfo;
86517c478bd9Sstevel@tonic-gate 	int ret = CS_SUCCESS;
86527c478bd9Sstevel@tonic-gate 
86537c478bd9Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle)) {
86547c478bd9Sstevel@tonic-gate 	    ci->Attributes = (CS_CLIENT_INFO_SOCKET_SERVICES |
86557c478bd9Sstevel@tonic-gate 						CS_CLIENT_INFO_VALID);
86567c478bd9Sstevel@tonic-gate 	    return (CS_SUCCESS);
86577c478bd9Sstevel@tonic-gate 	} /* CLIENT_HANDLE_IS_SS */
86587c478bd9Sstevel@tonic-gate 
86597c478bd9Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
86607c478bd9Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
86617c478bd9Sstevel@tonic-gate 
86627c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->client_lock);
86637c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->lock);
86647c478bd9Sstevel@tonic-gate 
86657c478bd9Sstevel@tonic-gate 	if ((client = cs_find_client(client_handle, &ret)) == NULL) {
86667c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
86677c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->client_lock);
86687c478bd9Sstevel@tonic-gate 	    return (ret);
86697c478bd9Sstevel@tonic-gate 	} /* cs_find_client */
86707c478bd9Sstevel@tonic-gate 
86717c478bd9Sstevel@tonic-gate 	/*
86727c478bd9Sstevel@tonic-gate 	 * If this client is not handling CS_EVENT_CLIENT_INFO events,
86737c478bd9Sstevel@tonic-gate 	 *	then don't bother to even wake up the event thread.
86747c478bd9Sstevel@tonic-gate 	 */
86757c478bd9Sstevel@tonic-gate 	if (!((client->event_mask | client->global_mask) &
86767c478bd9Sstevel@tonic-gate 					CS_EVENT_CLIENT_INFO)) {
86777c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
86787c478bd9Sstevel@tonic-gate 	    mutex_exit(&sp->client_lock);
86797c478bd9Sstevel@tonic-gate 	    return (CS_NO_MORE_ITEMS);
86807c478bd9Sstevel@tonic-gate 	} /* !CS_EVENT_CLIENT_INFO */
86817c478bd9Sstevel@tonic-gate 
86827c478bd9Sstevel@tonic-gate 	cinfo = &client->event_callback_args.client_info;
86837c478bd9Sstevel@tonic-gate 
86847c478bd9Sstevel@tonic-gate 	bzero((caddr_t)cinfo, sizeof (client_info_t));
86857c478bd9Sstevel@tonic-gate 	cinfo->Attributes = (ci->Attributes & CS_CLIENT_INFO_SUBSVC_MASK);
86867c478bd9Sstevel@tonic-gate 
86877c478bd9Sstevel@tonic-gate 	client->events |= CS_EVENT_CLIENT_INFO;
86887c478bd9Sstevel@tonic-gate 
86897c478bd9Sstevel@tonic-gate 	sp->thread_state |= SOCKET_WAIT_SYNC;
86907c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->lock);
86917c478bd9Sstevel@tonic-gate 	cv_broadcast(&sp->thread_cv);
86927c478bd9Sstevel@tonic-gate 	cv_wait(&sp->caller_cv, &sp->client_lock);
86937c478bd9Sstevel@tonic-gate 
86947c478bd9Sstevel@tonic-gate 	if (cinfo->Attributes & CS_CLIENT_INFO_VALID) {
86957c478bd9Sstevel@tonic-gate 	    bcopy((caddr_t)cinfo, (caddr_t)ci, sizeof (client_info_t));
86967c478bd9Sstevel@tonic-gate 	    ci->Attributes &= (CS_CLIENT_INFO_FLAGS_MASK |
86977c478bd9Sstevel@tonic-gate 					CS_CLIENT_INFO_SUBSVC_MASK);
86987c478bd9Sstevel@tonic-gate 	    ci->Attributes &= ~(CS_CLIENT_INFO_CLIENT_MASK |
86997c478bd9Sstevel@tonic-gate 						INFO_CARD_FLAGS_MASK |
87007c478bd9Sstevel@tonic-gate 						CS_CLIENT_INFO_CLIENT_ACTIVE);
87017c478bd9Sstevel@tonic-gate 	    ci->Attributes |= (client->flags & (CS_CLIENT_INFO_CLIENT_MASK |
87027c478bd9Sstevel@tonic-gate 						INFO_CARD_FLAGS_MASK));
87037c478bd9Sstevel@tonic-gate 	    (void) strcpy(ci->DriverName, client->driver_name);
87047c478bd9Sstevel@tonic-gate 	    if (cs_card_for_client(client))
87057c478bd9Sstevel@tonic-gate 		ci->Attributes |= CS_CLIENT_INFO_CLIENT_ACTIVE;
87067c478bd9Sstevel@tonic-gate 	} else {
87077c478bd9Sstevel@tonic-gate 	    ret = CS_NO_MORE_ITEMS;
87087c478bd9Sstevel@tonic-gate 	} /* CS_CLIENT_INFO_VALID */
87097c478bd9Sstevel@tonic-gate 
87107c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->client_lock);
87117c478bd9Sstevel@tonic-gate 
87127c478bd9Sstevel@tonic-gate 	return (ret);
87137c478bd9Sstevel@tonic-gate }
87147c478bd9Sstevel@tonic-gate 
87157c478bd9Sstevel@tonic-gate /*
87167c478bd9Sstevel@tonic-gate  * cs_get_firstnext_client - This function is GetFirstClient and
87177c478bd9Sstevel@tonic-gate  *				GetNextClient
87187c478bd9Sstevel@tonic-gate  *
87197c478bd9Sstevel@tonic-gate  *    calling:	get_firstnext_client_t * - pointer to a get_firstnext_client_t
87207c478bd9Sstevel@tonic-gate  *					structure to return client handle and
87217c478bd9Sstevel@tonic-gate  *					attributes in
87227c478bd9Sstevel@tonic-gate  *		flags - one of the following:
87237c478bd9Sstevel@tonic-gate  *				CS_GET_FIRST_FLAG - get first client handle
87247c478bd9Sstevel@tonic-gate  *				CS_GET_NEXT_FLAG - get next client handle
87257c478bd9Sstevel@tonic-gate  *
87267c478bd9Sstevel@tonic-gate  *    returns:	CS_SUCCESS - if client info retreived from client
87277c478bd9Sstevel@tonic-gate  *		CS_BAD_SOCKET, CS_BAD_HANDLE - if invalid client
87287c478bd9Sstevel@tonic-gate  *					handle passed in
87297c478bd9Sstevel@tonic-gate  *		CS_NO_MORE_ITEMS - if client does not handle the
87307c478bd9Sstevel@tonic-gate  *					CS_EVENT_CLIENT_INFO event
87317c478bd9Sstevel@tonic-gate  *					or if invalid client info
87327c478bd9Sstevel@tonic-gate  *					retreived from client
87337c478bd9Sstevel@tonic-gate  */
87347c478bd9Sstevel@tonic-gate static int
87357c478bd9Sstevel@tonic-gate cs_get_firstnext_client(get_firstnext_client_t *fnc, uint32_t flags)
87367c478bd9Sstevel@tonic-gate {
87377c478bd9Sstevel@tonic-gate 	cs_socket_t *sp;
87387c478bd9Sstevel@tonic-gate 	client_t *client;
87397c478bd9Sstevel@tonic-gate 	uint32_t sn = 0;
87407c478bd9Sstevel@tonic-gate 	int ret = CS_SUCCESS;
87417c478bd9Sstevel@tonic-gate 
87427c478bd9Sstevel@tonic-gate 	switch (flags) {
87437c478bd9Sstevel@tonic-gate 	    case CS_GET_FIRST_FLAG:
87447c478bd9Sstevel@tonic-gate 		if (fnc->Attributes & CS_GET_FIRSTNEXT_CLIENT_ALL_CLIENTS) {
87457c478bd9Sstevel@tonic-gate 		    while (sn < cs_globals.max_socket_num) {
87467c478bd9Sstevel@tonic-gate 			if ((sp = cs_get_sp(sn)) != NULL) {
87477c478bd9Sstevel@tonic-gate 			    mutex_enter(&sp->client_lock);
87487c478bd9Sstevel@tonic-gate 			    if ((client = sp->client_list) != NULL)
87497c478bd9Sstevel@tonic-gate 				break;
87507c478bd9Sstevel@tonic-gate 			    mutex_exit(&sp->client_lock);
87517c478bd9Sstevel@tonic-gate 			} /* if */
87527c478bd9Sstevel@tonic-gate 			sn++;
87537c478bd9Sstevel@tonic-gate 		    } /* while */
87547c478bd9Sstevel@tonic-gate 
87557c478bd9Sstevel@tonic-gate 		    if (sn == cs_globals.max_socket_num)
87567c478bd9Sstevel@tonic-gate 			return (CS_NO_MORE_ITEMS);
87577c478bd9Sstevel@tonic-gate 		} else if (fnc->Attributes &
87587c478bd9Sstevel@tonic-gate 					CS_GET_FIRSTNEXT_CLIENT_SOCKET_ONLY) {
87597c478bd9Sstevel@tonic-gate 		    if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(fnc->Socket))) ==
87607c478bd9Sstevel@tonic-gate 									NULL)
87617c478bd9Sstevel@tonic-gate 			return (CS_BAD_SOCKET);
87627c478bd9Sstevel@tonic-gate 		    mutex_enter(&sp->client_lock);
87637c478bd9Sstevel@tonic-gate 		    if ((client = sp->client_list) == NULL) {
87647c478bd9Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
87657c478bd9Sstevel@tonic-gate 			return (CS_NO_MORE_ITEMS);
87667c478bd9Sstevel@tonic-gate 		    }
87677c478bd9Sstevel@tonic-gate 		} else {
87687c478bd9Sstevel@tonic-gate 		    return (CS_BAD_ATTRIBUTE);
87697c478bd9Sstevel@tonic-gate 		}
87707c478bd9Sstevel@tonic-gate 
87717c478bd9Sstevel@tonic-gate 		fnc->client_handle = client->client_handle;
87727c478bd9Sstevel@tonic-gate 		fnc->num_clients = sp->num_clients;
87737c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->client_lock);
87747c478bd9Sstevel@tonic-gate 		break;
87757c478bd9Sstevel@tonic-gate 	    case CS_GET_NEXT_FLAG:
87767c478bd9Sstevel@tonic-gate 		if (fnc->Attributes & CS_GET_FIRSTNEXT_CLIENT_ALL_CLIENTS) {
87777c478bd9Sstevel@tonic-gate 		    sn = GET_CLIENT_SOCKET(fnc->client_handle);
87787c478bd9Sstevel@tonic-gate 
87797c478bd9Sstevel@tonic-gate 		    if ((sp = cs_get_sp(sn)) == NULL)
87807c478bd9Sstevel@tonic-gate 			return (CS_BAD_SOCKET);
87817c478bd9Sstevel@tonic-gate 
87827c478bd9Sstevel@tonic-gate 		    mutex_enter(&sp->client_lock);
87837c478bd9Sstevel@tonic-gate 		    if ((client = cs_find_client(fnc->client_handle,
87847c478bd9Sstevel@tonic-gate 				&ret)) == NULL) {
87857c478bd9Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
87867c478bd9Sstevel@tonic-gate 			return (ret);
87877c478bd9Sstevel@tonic-gate 		    }
87887c478bd9Sstevel@tonic-gate 		    if ((client = client->next) == NULL) {
87897c478bd9Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
87907c478bd9Sstevel@tonic-gate 			sn++;
87917c478bd9Sstevel@tonic-gate 			while (sn < cs_globals.max_socket_num) {
87927c478bd9Sstevel@tonic-gate 			    if ((sp = cs_get_sp(sn)) != NULL) {
87937c478bd9Sstevel@tonic-gate 				mutex_enter(&sp->client_lock);
87947c478bd9Sstevel@tonic-gate 				if ((client = sp->client_list) != NULL)
87957c478bd9Sstevel@tonic-gate 				    break;
87967c478bd9Sstevel@tonic-gate 				mutex_exit(&sp->client_lock);
87977c478bd9Sstevel@tonic-gate 			    } /* if */
87987c478bd9Sstevel@tonic-gate 			    sn++;
87997c478bd9Sstevel@tonic-gate 			} /* while */
88007c478bd9Sstevel@tonic-gate 
88017c478bd9Sstevel@tonic-gate 			if (sn == cs_globals.max_socket_num)
88027c478bd9Sstevel@tonic-gate 			    return (CS_NO_MORE_ITEMS);
88037c478bd9Sstevel@tonic-gate 		    } /* client = client->next */
88047c478bd9Sstevel@tonic-gate 
88057c478bd9Sstevel@tonic-gate 		} else if (fnc->Attributes &
88067c478bd9Sstevel@tonic-gate 					CS_GET_FIRSTNEXT_CLIENT_SOCKET_ONLY) {
88077c478bd9Sstevel@tonic-gate 		    sp = cs_get_sp(GET_CLIENT_SOCKET(fnc->client_handle));
88087c478bd9Sstevel@tonic-gate 		    if (sp == NULL)
88097c478bd9Sstevel@tonic-gate 			return (CS_BAD_SOCKET);
88107c478bd9Sstevel@tonic-gate 		    mutex_enter(&sp->client_lock);
88117c478bd9Sstevel@tonic-gate 		    if ((client = cs_find_client(fnc->client_handle,
88127c478bd9Sstevel@tonic-gate 				&ret)) == NULL) {
88137c478bd9Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
88147c478bd9Sstevel@tonic-gate 			return (ret);
88157c478bd9Sstevel@tonic-gate 		    }
88167c478bd9Sstevel@tonic-gate 		    if ((client = client->next) == NULL) {
88177c478bd9Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
88187c478bd9Sstevel@tonic-gate 			return (CS_NO_MORE_ITEMS);
88197c478bd9Sstevel@tonic-gate 		    }
88207c478bd9Sstevel@tonic-gate 		} else {
88217c478bd9Sstevel@tonic-gate 		    return (CS_BAD_ATTRIBUTE);
88227c478bd9Sstevel@tonic-gate 		}
88237c478bd9Sstevel@tonic-gate 
88247c478bd9Sstevel@tonic-gate 		fnc->client_handle = client->client_handle;
88257c478bd9Sstevel@tonic-gate 		fnc->num_clients = sp->num_clients;
88267c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->client_lock);
88277c478bd9Sstevel@tonic-gate 		break;
88287c478bd9Sstevel@tonic-gate 	    default:
88297c478bd9Sstevel@tonic-gate 		ret = CS_BAD_ATTRIBUTE;
88307c478bd9Sstevel@tonic-gate 		break;
88317c478bd9Sstevel@tonic-gate 
88327c478bd9Sstevel@tonic-gate 	} /* switch */
88337c478bd9Sstevel@tonic-gate 
88347c478bd9Sstevel@tonic-gate 	return (ret);
88357c478bd9Sstevel@tonic-gate }
88367c478bd9Sstevel@tonic-gate 
88377c478bd9Sstevel@tonic-gate /*
88387c478bd9Sstevel@tonic-gate  * cs_set_acc_attributes - converts Card Services endianness and
88397c478bd9Sstevel@tonic-gate  *				data ordering values to values
88407c478bd9Sstevel@tonic-gate  *				that Socket Services understands
88417c478bd9Sstevel@tonic-gate  *
88427c478bd9Sstevel@tonic-gate  *	calling: *sw - pointer to a set_window_t to set attributes in
88437c478bd9Sstevel@tonic-gate  *		 Attributes - CS attributes
88447c478bd9Sstevel@tonic-gate  */
88457c478bd9Sstevel@tonic-gate static void
88467c478bd9Sstevel@tonic-gate cs_set_acc_attributes(set_window_t *sw, uint32_t Attributes)
88477c478bd9Sstevel@tonic-gate {
88487c478bd9Sstevel@tonic-gate 	sw->attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
88497c478bd9Sstevel@tonic-gate 
88507c478bd9Sstevel@tonic-gate 	switch (Attributes & WIN_ACC_ENDIAN_MASK) {
88517c478bd9Sstevel@tonic-gate 	    case WIN_ACC_LITTLE_ENDIAN:
88527c478bd9Sstevel@tonic-gate 		sw->attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
88537c478bd9Sstevel@tonic-gate 		break;
88547c478bd9Sstevel@tonic-gate 	    case WIN_ACC_BIG_ENDIAN:
88557c478bd9Sstevel@tonic-gate 		sw->attr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC;
88567c478bd9Sstevel@tonic-gate 		break;
88577c478bd9Sstevel@tonic-gate 	    case WIN_ACC_NEVER_SWAP:
88587c478bd9Sstevel@tonic-gate 	    default:
88597c478bd9Sstevel@tonic-gate 		sw->attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
88607c478bd9Sstevel@tonic-gate 		break;
88617c478bd9Sstevel@tonic-gate 	} /* switch */
88627c478bd9Sstevel@tonic-gate 
88637c478bd9Sstevel@tonic-gate 	switch (Attributes & WIN_ACC_ORDER_MASK) {
88647c478bd9Sstevel@tonic-gate 	    case WIN_ACC_UNORDERED_OK:
88657c478bd9Sstevel@tonic-gate 		sw->attr.devacc_attr_dataorder = DDI_UNORDERED_OK_ACC;
88667c478bd9Sstevel@tonic-gate 		break;
88677c478bd9Sstevel@tonic-gate 	    case WIN_ACC_MERGING_OK:
88687c478bd9Sstevel@tonic-gate 		sw->attr.devacc_attr_dataorder = DDI_MERGING_OK_ACC;
88697c478bd9Sstevel@tonic-gate 		break;
88707c478bd9Sstevel@tonic-gate 	    case WIN_ACC_LOADCACHING_OK:
88717c478bd9Sstevel@tonic-gate 		sw->attr.devacc_attr_dataorder = DDI_LOADCACHING_OK_ACC;
88727c478bd9Sstevel@tonic-gate 		break;
88737c478bd9Sstevel@tonic-gate 	    case WIN_ACC_STORECACHING_OK:
88747c478bd9Sstevel@tonic-gate 		sw->attr.devacc_attr_dataorder = DDI_STORECACHING_OK_ACC;
88757c478bd9Sstevel@tonic-gate 		break;
88767c478bd9Sstevel@tonic-gate 	    case WIN_ACC_STRICT_ORDER:
88777c478bd9Sstevel@tonic-gate 	    default:
88787c478bd9Sstevel@tonic-gate 		sw->attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
88797c478bd9Sstevel@tonic-gate 		break;
88807c478bd9Sstevel@tonic-gate 	} /* switch */
88817c478bd9Sstevel@tonic-gate }
8882