xref: /onnv-gate/usr/src/uts/common/pcmcia/cs/cs.c (revision 1278:cccbfe741e06)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*1278Shx147065  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * PCMCIA Card Services
310Sstevel@tonic-gate  *	The PCMCIA Card Services is a loadable module which
320Sstevel@tonic-gate  *	presents the Card Services interface to client device
330Sstevel@tonic-gate  *	drivers.
340Sstevel@tonic-gate  *
350Sstevel@tonic-gate  *	Card Services uses Socket Services-like calls into the
360Sstevel@tonic-gate  *	PCMCIA nexus driver to manipulate socket and adapter
370Sstevel@tonic-gate  *	resources.
380Sstevel@tonic-gate  *
390Sstevel@tonic-gate  * Note that a bunch of comments are not indented correctly with the
400Sstevel@tonic-gate  *	code that they are commenting on. This is because cstyle is
410Sstevel@tonic-gate  *	is inflexible concerning 4-column indenting.
420Sstevel@tonic-gate  */
430Sstevel@tonic-gate 
440Sstevel@tonic-gate #if defined(DEBUG)
450Sstevel@tonic-gate #define	CS_DEBUG
460Sstevel@tonic-gate #endif
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #include <sys/types.h>
490Sstevel@tonic-gate #include <sys/systm.h>
500Sstevel@tonic-gate #include <sys/user.h>
510Sstevel@tonic-gate #include <sys/buf.h>
520Sstevel@tonic-gate #include <sys/file.h>
530Sstevel@tonic-gate #include <sys/uio.h>
540Sstevel@tonic-gate #include <sys/conf.h>
550Sstevel@tonic-gate #include <sys/stat.h>
560Sstevel@tonic-gate #include <sys/autoconf.h>
570Sstevel@tonic-gate #include <sys/vtoc.h>
580Sstevel@tonic-gate #include <sys/dkio.h>
590Sstevel@tonic-gate #include <sys/ddi.h>
600Sstevel@tonic-gate #include <sys/sunddi.h>
610Sstevel@tonic-gate #include <sys/debug.h>
620Sstevel@tonic-gate #include <sys/varargs.h>
630Sstevel@tonic-gate #include <sys/var.h>
640Sstevel@tonic-gate #include <sys/proc.h>
650Sstevel@tonic-gate #include <sys/thread.h>
660Sstevel@tonic-gate #include <sys/utsname.h>
670Sstevel@tonic-gate #include <sys/vtrace.h>
680Sstevel@tonic-gate #include <sys/kstat.h>
690Sstevel@tonic-gate #include <sys/kmem.h>
700Sstevel@tonic-gate #include <sys/modctl.h>
710Sstevel@tonic-gate #include <sys/kobj.h>
720Sstevel@tonic-gate #include <sys/callb.h>
730Sstevel@tonic-gate #include <sys/time.h>
740Sstevel@tonic-gate 
750Sstevel@tonic-gate #include <sys/pctypes.h>
760Sstevel@tonic-gate #include <pcmcia/sys/cs_types.h>
770Sstevel@tonic-gate #include <sys/pcmcia.h>
780Sstevel@tonic-gate #include <sys/sservice.h>
790Sstevel@tonic-gate #include <pcmcia/sys/cis.h>
800Sstevel@tonic-gate #include <pcmcia/sys/cis_handlers.h>
810Sstevel@tonic-gate #include <pcmcia/sys/cs.h>
820Sstevel@tonic-gate #include <pcmcia/sys/cs_priv.h>
830Sstevel@tonic-gate #include <pcmcia/sys/cs_stubs.h>
840Sstevel@tonic-gate 
850Sstevel@tonic-gate /*
860Sstevel@tonic-gate  * The cs_strings header file is where all of the major strings that
870Sstevel@tonic-gate  *	Card Services uses are located.
880Sstevel@tonic-gate  */
890Sstevel@tonic-gate #include <pcmcia/sys/cs_strings.h>
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 
920Sstevel@tonic-gate /*
930Sstevel@tonic-gate  * Function declarations
940Sstevel@tonic-gate  *
950Sstevel@tonic-gate  * The main Card Services entry point
960Sstevel@tonic-gate  */
970Sstevel@tonic-gate int CardServices(int function, ...);
980Sstevel@tonic-gate 
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate  * functions and globals used by Socket Services
1010Sstevel@tonic-gate  *
1020Sstevel@tonic-gate  * WAS: void *(*cis_parser)(int, ...) = NULL;
1030Sstevel@tonic-gate  */
1040Sstevel@tonic-gate void *(*cis_parser)(int, ...) = NULL;
1050Sstevel@tonic-gate csfunction_t *cs_socket_services = NULL;
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate /*
1080Sstevel@tonic-gate  * event handling functions
1090Sstevel@tonic-gate  */
1100Sstevel@tonic-gate static event_t ss_to_cs_events(cs_socket_t *, event_t);
1110Sstevel@tonic-gate static event_t cs_cse2sbm(event_t);
1120Sstevel@tonic-gate static void cs_event_thread(uint32_t);
1130Sstevel@tonic-gate static int cs_card_insertion(cs_socket_t *, event_t);
1140Sstevel@tonic-gate static int cs_card_removal(cs_socket_t *);
1150Sstevel@tonic-gate static void cs_ss_thread(uint32_t);
1160Sstevel@tonic-gate void cs_ready_timeout(void *);
1170Sstevel@tonic-gate static int cs_card_for_client(client_t *);
1180Sstevel@tonic-gate static int cs_request_socket_mask(client_handle_t, request_socket_mask_t *);
1190Sstevel@tonic-gate static int cs_release_socket_mask(client_handle_t, release_socket_mask_t *);
1200Sstevel@tonic-gate static int cs_get_event_mask(client_handle_t, sockevent_t *);
1210Sstevel@tonic-gate static int cs_set_event_mask(client_handle_t, sockevent_t *);
1220Sstevel@tonic-gate static int cs_event2text(event2text_t *, int);
1230Sstevel@tonic-gate static int cs_read_event_status(cs_socket_t *, client_t *, event_t *,
1240Sstevel@tonic-gate 						get_ss_status_t *, int);
1250Sstevel@tonic-gate uint32_t cs_socket_event_softintr(caddr_t);
1260Sstevel@tonic-gate void cs_event_softintr_timeout(void *);
1270Sstevel@tonic-gate static int cs_get_status(client_handle_t, get_status_t *);
1280Sstevel@tonic-gate static uint32_t cs_sbm2cse(uint32_t);
1290Sstevel@tonic-gate static unsigned cs_merge_event_masks(cs_socket_t *, client_t *);
1300Sstevel@tonic-gate static int cs_set_socket_event_mask(cs_socket_t *, unsigned);
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate /*
1330Sstevel@tonic-gate  * SS<->CS communication and internal socket and window  handling functions
1340Sstevel@tonic-gate  */
1350Sstevel@tonic-gate static uint32_t cs_add_socket(uint32_t);
1360Sstevel@tonic-gate static uint32_t cs_drop_socket(uint32_t);
1370Sstevel@tonic-gate static cs_socket_t *cs_get_sp(uint32_t);
1380Sstevel@tonic-gate static cs_socket_t *cs_find_sp(uint32_t);
1390Sstevel@tonic-gate static cs_window_t *cs_get_wp(uint32_t);
1400Sstevel@tonic-gate static cs_window_t *cs_find_wp(uint32_t);
1410Sstevel@tonic-gate static int cs_add_windows(int, uint32_t);
1420Sstevel@tonic-gate static uint32_t cs_ss_init();
1430Sstevel@tonic-gate static void cs_set_acc_attributes(set_window_t *, uint32_t);
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate /*
1460Sstevel@tonic-gate  * CIS handling functions
1470Sstevel@tonic-gate  */
1480Sstevel@tonic-gate cistpl_callout_t *cis_cistpl_std_callout;
1490Sstevel@tonic-gate static int cs_parse_tuple(client_handle_t,  tuple_t *, cisparse_t *, cisdata_t);
1500Sstevel@tonic-gate static int cs_get_tuple_data(client_handle_t, tuple_t *);
1510Sstevel@tonic-gate static int cs_validate_cis(client_handle_t, cisinfo_t *);
1520Sstevel@tonic-gate static int cs_get_firstnext_tuple(client_handle_t, tuple_t *, uint32_t);
1530Sstevel@tonic-gate static int cs_create_cis(cs_socket_t *);
1540Sstevel@tonic-gate static int cs_destroy_cis(cs_socket_t *);
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate /*
1570Sstevel@tonic-gate  * client handling functions
1580Sstevel@tonic-gate  */
1590Sstevel@tonic-gate unsigned cs_create_next_client_minor(unsigned, unsigned);
1600Sstevel@tonic-gate static client_t *cs_find_client(client_handle_t, int *);
1610Sstevel@tonic-gate static client_handle_t cs_create_client_handle(unsigned, client_t *);
1620Sstevel@tonic-gate static int cs_destroy_client_handle(client_handle_t);
1630Sstevel@tonic-gate static int cs_register_client(client_handle_t *, client_reg_t *);
1640Sstevel@tonic-gate static int cs_deregister_client(client_handle_t);
1650Sstevel@tonic-gate static int cs_deregister_mtd(client_handle_t);
1660Sstevel@tonic-gate static void cs_clear_superclient_lock(int);
1670Sstevel@tonic-gate static int cs_add_client_to_socket(unsigned, client_handle_t *,
1680Sstevel@tonic-gate 						client_reg_t *, int);
1690Sstevel@tonic-gate static int cs_get_client_info(client_handle_t, client_info_t *);
1700Sstevel@tonic-gate static int cs_get_firstnext_client(get_firstnext_client_t *, uint32_t);
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate /*
1730Sstevel@tonic-gate  * window handling functions
1740Sstevel@tonic-gate  */
1750Sstevel@tonic-gate static int cs_request_window(client_handle_t, window_handle_t *, win_req_t *);
1760Sstevel@tonic-gate static int cs_release_window(window_handle_t);
1770Sstevel@tonic-gate static int cs_modify_window(window_handle_t, modify_win_t *);
1780Sstevel@tonic-gate static int cs_modify_mem_window(window_handle_t, modify_win_t *, win_req_t *,
1790Sstevel@tonic-gate 									int);
1800Sstevel@tonic-gate static int cs_map_mem_page(window_handle_t, map_mem_page_t *);
1810Sstevel@tonic-gate static int cs_find_mem_window(uint32_t, win_req_t *, uint32_t *);
1820Sstevel@tonic-gate static int cs_memwin_space_and_map_ok(inquire_window_t *, win_req_t *);
1830Sstevel@tonic-gate static int cs_valid_window_speed(inquire_window_t *, uint32_t);
1840Sstevel@tonic-gate static window_handle_t cs_create_window_handle(uint32_t);
1850Sstevel@tonic-gate static cs_window_t *cs_find_window(window_handle_t);
1860Sstevel@tonic-gate static int cs_find_io_win(uint32_t, iowin_char_t *, uint32_t *, uint32_t *);
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate /*
1890Sstevel@tonic-gate  * IO, IRQ and configuration handling functions
1900Sstevel@tonic-gate  */
1910Sstevel@tonic-gate static int cs_request_io(client_handle_t, io_req_t *);
1920Sstevel@tonic-gate static int cs_release_io(client_handle_t, io_req_t *);
1930Sstevel@tonic-gate static int cs_allocate_io_win(uint32_t, uint32_t, uint32_t *);
1940Sstevel@tonic-gate static int cs_setup_io_win(uint32_t, uint32_t, baseaddru_t *,
1950Sstevel@tonic-gate 					uint32_t *, uint32_t, uint32_t);
1960Sstevel@tonic-gate static int cs_request_irq(client_handle_t, irq_req_t *);
1970Sstevel@tonic-gate static int cs_release_irq(client_handle_t, irq_req_t *);
1980Sstevel@tonic-gate static int cs_request_configuration(client_handle_t, config_req_t *);
1990Sstevel@tonic-gate static int cs_release_configuration(client_handle_t, release_config_t *);
2000Sstevel@tonic-gate static int cs_modify_configuration(client_handle_t, modify_config_t *);
2010Sstevel@tonic-gate static int cs_access_configuration_register(client_handle_t,
2020Sstevel@tonic-gate 						access_config_reg_t *);
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate /*
2050Sstevel@tonic-gate  * RESET and general info functions
2060Sstevel@tonic-gate  */
2070Sstevel@tonic-gate static int cs_reset_function(client_handle_t, reset_function_t *);
2080Sstevel@tonic-gate static int cs_get_configuration_info(client_handle_t *,
2090Sstevel@tonic-gate 						get_configuration_info_t *);
2100Sstevel@tonic-gate static int cs_get_cardservices_info(client_handle_t,
2110Sstevel@tonic-gate 						get_cardservices_info_t *);
2120Sstevel@tonic-gate static int cs_get_physical_adapter_info(client_handle_t,
2130Sstevel@tonic-gate 						get_physical_adapter_info_t *);
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate /*
2160Sstevel@tonic-gate  * general functions
2170Sstevel@tonic-gate  */
2180Sstevel@tonic-gate static uint32_t cs_get_socket(client_handle_t, uint32_t *, uint32_t *,
2190Sstevel@tonic-gate 					cs_socket_t **, client_t **);
2200Sstevel@tonic-gate static int cs_convert_speed(convert_speed_t *);
2210Sstevel@tonic-gate static int cs_convert_size(convert_size_t *);
2220Sstevel@tonic-gate static char *cs_error2text(int, int);
2230Sstevel@tonic-gate static int cs_map_log_socket(client_handle_t, map_log_socket_t *);
2240Sstevel@tonic-gate static int cs_convert_powerlevel(uint32_t, uint32_t, uint32_t, unsigned *);
2250Sstevel@tonic-gate static int cs_make_device_node(client_handle_t, make_device_node_t *);
2260Sstevel@tonic-gate static int cs_remove_device_node(client_handle_t, remove_device_node_t *);
2270Sstevel@tonic-gate static int cs_ddi_info(cs_ddi_info_t *);
2280Sstevel@tonic-gate static int cs_init_cis_window(cs_socket_t *, uint32_t *, acc_handle_t *,
2290Sstevel@tonic-gate 				uint32_t);
2300Sstevel@tonic-gate static int cs_sys_ctl(cs_sys_ctl_t *);
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate /*
2330Sstevel@tonic-gate  * global variables
2340Sstevel@tonic-gate  */
2350Sstevel@tonic-gate static int cs_max_client_handles = CS_MAX_CLIENTS;
2360Sstevel@tonic-gate static client_t cs_socket_services_client;	/* global SS client */
2370Sstevel@tonic-gate static client_types_t client_types[MAX_CLIENT_TYPES];
2380Sstevel@tonic-gate static cs_globals_t cs_globals;
2390Sstevel@tonic-gate int cs_reset_timeout_time = RESET_TIMEOUT_TIME;
2400Sstevel@tonic-gate int cs_rc1_delay = CS_RC1_DELAY;
2410Sstevel@tonic-gate int cs_rc2_delay = CS_RC2_DELAY;
2420Sstevel@tonic-gate int cs_rq_delay = CS_RQ_DELAY;
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate #ifdef	CS_DEBUG
2450Sstevel@tonic-gate int	cs_debug = 0;
2460Sstevel@tonic-gate #endif
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate /*
2490Sstevel@tonic-gate  * cs_init - Initialize CS internal structures, databases, and state,
2500Sstevel@tonic-gate  *		and register with SS
2510Sstevel@tonic-gate  *
2520Sstevel@tonic-gate  * XXX - Need to make sure that if we fail at any point that we free
2530Sstevel@tonic-gate  *		any resources that we allocated, as well as kill any
2540Sstevel@tonic-gate  *		threads that may have been started.
2550Sstevel@tonic-gate  */
2560Sstevel@tonic-gate int
cs_init()2570Sstevel@tonic-gate cs_init()
2580Sstevel@tonic-gate {
2590Sstevel@tonic-gate 	client_types_t *ct;
2600Sstevel@tonic-gate 	client_t *client;
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	/*
2630Sstevel@tonic-gate 	 * Initialize the CS global structure
2640Sstevel@tonic-gate 	 */
2650Sstevel@tonic-gate 	bzero((caddr_t)&cs_globals, sizeof (cs_globals_t));
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	mutex_init(&cs_globals.global_lock, NULL, MUTEX_DRIVER, NULL);
2680Sstevel@tonic-gate 	mutex_init(&cs_globals.window_lock, NULL, MUTEX_DRIVER, NULL);
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	cs_globals.init_state = GLOBAL_INIT_STATE_MUTEX;
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	/*
2730Sstevel@tonic-gate 	 * Set up the global Socket Services client, since we're going to
2740Sstevel@tonic-gate 	 *	need it once we register with SS.
2750Sstevel@tonic-gate 	 */
2760Sstevel@tonic-gate 	client = &cs_socket_services_client;
2770Sstevel@tonic-gate 	bzero((caddr_t)client, sizeof (client_t));
2780Sstevel@tonic-gate 	client->client_handle = CS_SS_CLIENT_HANDLE;
2790Sstevel@tonic-gate 	client->flags |= (INFO_SOCKET_SERVICES | CLIENT_CARD_INSERTED);
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	/*
2820Sstevel@tonic-gate 	 * Setup the client type structure - this is used in the socket event
2830Sstevel@tonic-gate 	 *	thread to sequence the delivery of events to all clients on
2840Sstevel@tonic-gate 	 *	the socket.
2850Sstevel@tonic-gate 	 */
2860Sstevel@tonic-gate 	ct = &client_types[0];
2870Sstevel@tonic-gate 	ct->type = INFO_IO_CLIENT;
2880Sstevel@tonic-gate 	ct->order = CLIENT_EVENTS_LIFO;
2890Sstevel@tonic-gate 	ct->next = &client_types[1];
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	ct = ct->next;
2920Sstevel@tonic-gate 	ct->type = INFO_MTD_CLIENT;
2930Sstevel@tonic-gate 	ct->order = CLIENT_EVENTS_FIFO;
2940Sstevel@tonic-gate 	ct->next = &client_types[2];
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	ct = ct->next;
2970Sstevel@tonic-gate 	ct->type = INFO_MEM_CLIENT;
2980Sstevel@tonic-gate 	ct->order = CLIENT_EVENTS_FIFO;
2990Sstevel@tonic-gate 	ct->next = NULL;
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	return (CS_SUCCESS);
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate /*
3050Sstevel@tonic-gate  * cs_deinit - Deinitialize CS
3060Sstevel@tonic-gate  *
3070Sstevel@tonic-gate  * This function cleans up any allocated resources, stops any running threads,
3080Sstevel@tonic-gate  *	destroys any mutexes and condition variables, and finally frees up the
3090Sstevel@tonic-gate  *	global socket and window structure arrays.
3100Sstevel@tonic-gate  */
3110Sstevel@tonic-gate int
cs_deinit()3120Sstevel@tonic-gate cs_deinit()
3130Sstevel@tonic-gate {
3140Sstevel@tonic-gate 	cs_socket_t *sp;
3150Sstevel@tonic-gate 	int sn, have_clients = 0, have_sockets = 0;
3160Sstevel@tonic-gate 	cs_register_cardservices_t rcs;
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate #if defined(CS_DEBUG)
3190Sstevel@tonic-gate 	if (cs_debug > 1)
3200Sstevel@tonic-gate 	    cmn_err(CE_CONT, "CS: cs_deinit\n");
3210Sstevel@tonic-gate #endif
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	/*
3240Sstevel@tonic-gate 	 * Deregister with the Card Services kernel stubs module
3250Sstevel@tonic-gate 	 */
3260Sstevel@tonic-gate 	rcs.magic = CS_STUBS_MAGIC;
3270Sstevel@tonic-gate 	rcs.function = CS_ENTRY_DEREGISTER;
3280Sstevel@tonic-gate 	(void) csx_register_cardservices(&rcs);
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	/*
3310Sstevel@tonic-gate 	 * Set the GLOBAL_INIT_STATE_NO_CLIENTS flag to prevent new clients
3320Sstevel@tonic-gate 	 *	from registering.
3330Sstevel@tonic-gate 	 */
3340Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
3350Sstevel@tonic-gate 	cs_globals.init_state |= GLOBAL_INIT_STATE_NO_CLIENTS;
3360Sstevel@tonic-gate 	mutex_exit(&cs_globals.global_lock);
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	/*
3390Sstevel@tonic-gate 	 * Go through each socket and make sure that there are no clients
3400Sstevel@tonic-gate 	 *	on any of the sockets.  If there are, we can't deinit until
3410Sstevel@tonic-gate 	 *	all the clients for every socket are gone.
3420Sstevel@tonic-gate 	 */
3430Sstevel@tonic-gate 	for (sn = 0; sn < cs_globals.max_socket_num; sn++) {
3440Sstevel@tonic-gate 	    if ((sp = cs_get_sp(sn)) != NULL) {
3450Sstevel@tonic-gate 		have_sockets++;
3460Sstevel@tonic-gate 		if (sp->client_list) {
3470Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_deinit: cannot unload module since "
3480Sstevel@tonic-gate 				"socket %d has registered clients\n", sn);
3490Sstevel@tonic-gate 		    have_clients++;
3500Sstevel@tonic-gate 		}
3510Sstevel@tonic-gate 	    }
3520Sstevel@tonic-gate 	}
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 	/*
3550Sstevel@tonic-gate 	 * We don't allow unload if there are any clients registered
3560Sstevel@tonic-gate 	 *	or if there are still sockets that are active.
3570Sstevel@tonic-gate 	 */
3580Sstevel@tonic-gate 	if ((have_clients > 0) || (have_sockets > 0))
3590Sstevel@tonic-gate 	    return (BAD_FUNCTION);
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate #ifdef	XXX
3620Sstevel@tonic-gate 	/*
3630Sstevel@tonic-gate 	 * If one or more sockets have been added, we need to deallocate
3640Sstevel@tonic-gate 	 *	the resources associated with those sockets.
3650Sstevel@tonic-gate 	 */
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	/*
3680Sstevel@tonic-gate 	 * First, tell Socket Services that we're leaving, so that we
3690Sstevel@tonic-gate 	 *	don't get any more event callbacks.
3700Sstevel@tonic-gate 	 */
3710Sstevel@tonic-gate 	SocketServices(CSUnregister);
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	/*
3740Sstevel@tonic-gate 	 * Wait for the soft int timer to tell us it's done
3750Sstevel@tonic-gate 	 */
3760Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
3770Sstevel@tonic-gate 	cs_globals.init_state |= GLOBAL_INIT_STATE_UNLOADING;
3780Sstevel@tonic-gate 	mutex_exit(&cs_globals.global_lock);
3790Sstevel@tonic-gate 	UNTIMEOUT(cs_globals.sotfint_tmo);
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	/*
3820Sstevel@tonic-gate 	 * Remove the soft interrupt handler.
3830Sstevel@tonic-gate 	 */
3840Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
3850Sstevel@tonic-gate 	if (cs_globals.init_state & GLOBAL_INIT_STATE_SOFTINTR) {
3860Sstevel@tonic-gate 	    ddi_remove_softintr(cs_globals.softint_id);
3870Sstevel@tonic-gate 	    cs_globals.init_state &= ~GLOBAL_INIT_STATE_SOFTINTR;
3880Sstevel@tonic-gate 	}
3890Sstevel@tonic-gate 	mutex_exit(&cs_globals.global_lock);
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	return (CS_SUCCESS);
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	/*
3940Sstevel@tonic-gate 	 * Go through each socket and free any resource allocated to that
3950Sstevel@tonic-gate 	 *	socket, as well as any mutexs and condition variables.
3960Sstevel@tonic-gate 	 */
3970Sstevel@tonic-gate 	for (sn = 0; sn < cs_globals.max_socket_num; sn++) {
3980Sstevel@tonic-gate 	    set_socket_t set_socket;
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	    if ((sp = cs_get_sp(sn)) != NULL) {
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 		/*
4030Sstevel@tonic-gate 		 * untimeout possible pending ready/busy timer
4040Sstevel@tonic-gate 		 */
4050Sstevel@tonic-gate 		UNTIMEOUT(sp->rdybsy_tmo_id);
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4080Sstevel@tonic-gate 		    mutex_enter(&sp->lock);
4090Sstevel@tonic-gate 		sp->flags = SOCKET_UNLOAD_MODULE;
4100Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_SOFTINTR)
4110Sstevel@tonic-gate 		    sp->init_state &= ~SOCKET_INIT_STATE_SOFTINTR;
4120Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4130Sstevel@tonic-gate 		    mutex_exit(&sp->lock);
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4160Sstevel@tonic-gate 		    mutex_enter(&sp->cis_lock);
4170Sstevel@tonic-gate 		(void) cs_destroy_cis(sp);
4180Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4190Sstevel@tonic-gate 		    mutex_exit(&sp->cis_lock);
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 		/*
4220Sstevel@tonic-gate 		 * Tell the event handler thread that we want it to exit, then
4230Sstevel@tonic-gate 		 *	wait around until it tells us that it has exited.
4240Sstevel@tonic-gate 		 */
4250Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4260Sstevel@tonic-gate 		    mutex_enter(&sp->client_lock);
4270Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_THREAD) {
4280Sstevel@tonic-gate 		    sp->thread_state = SOCKET_THREAD_EXIT;
4290Sstevel@tonic-gate 		    cv_broadcast(&sp->thread_cv);
4300Sstevel@tonic-gate 		    cv_wait(&sp->caller_cv, &sp->client_lock);
4310Sstevel@tonic-gate 		}
4320Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4330Sstevel@tonic-gate 		    mutex_exit(&sp->client_lock);
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 		/*
4360Sstevel@tonic-gate 		 * Tell the SS work thread that we want it to exit, then
4370Sstevel@tonic-gate 		 *	wait around until it tells us that it has exited.
4380Sstevel@tonic-gate 		 */
4390Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4400Sstevel@tonic-gate 		    mutex_enter(&sp->ss_thread_lock);
4410Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_SS_THREAD) {
4420Sstevel@tonic-gate 		    sp->ss_thread_state = SOCKET_THREAD_EXIT;
4430Sstevel@tonic-gate 		    cv_broadcast(&sp->ss_thread_cv);
4440Sstevel@tonic-gate 		    cv_wait(&sp->ss_caller_cv, &sp->ss_thread_lock);
4450Sstevel@tonic-gate 		}
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
4480Sstevel@tonic-gate 		    mutex_exit(&sp->ss_thread_lock);
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 		/*
4510Sstevel@tonic-gate 		 * Free the mutexii and condition variables that we used.
4520Sstevel@tonic-gate 		 */
4530Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX) {
4540Sstevel@tonic-gate 		    mutex_destroy(&sp->lock);
4550Sstevel@tonic-gate 		    mutex_destroy(&sp->client_lock);
4560Sstevel@tonic-gate 		    mutex_destroy(&sp->cis_lock);
4570Sstevel@tonic-gate 		    mutex_destroy(&sp->ss_thread_lock);
4580Sstevel@tonic-gate 		}
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_CV) {
4610Sstevel@tonic-gate 		    cv_destroy(&sp->thread_cv);
4620Sstevel@tonic-gate 		    cv_destroy(&sp->caller_cv);
4630Sstevel@tonic-gate 		    cv_destroy(&sp->reset_cv);
4640Sstevel@tonic-gate 		    cv_destroy(&sp->ss_thread_cv);
4650Sstevel@tonic-gate 		    cv_destroy(&sp->ss_caller_cv);
4660Sstevel@tonic-gate 		}
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate #ifdef	USE_IOMMAP_WINDOW
4690Sstevel@tonic-gate 		/*
4700Sstevel@tonic-gate 		 * Free the memory-mapped IO structure if we allocated one.
4710Sstevel@tonic-gate 		 */
4720Sstevel@tonic-gate 		if (sp->io_mmap_window)
4730Sstevel@tonic-gate 		    kmem_free(sp->io_mmap_window, sizeof (io_mmap_window_t));
4740Sstevel@tonic-gate #endif	/* USE_IOMMAP_WINDOW */
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 		/*
4770Sstevel@tonic-gate 		 * Return the socket to memory-only mode and turn off the
4780Sstevel@tonic-gate 		 *	socket power.
4790Sstevel@tonic-gate 		 */
4800Sstevel@tonic-gate 		sp->event_mask = 0;
4810Sstevel@tonic-gate 		set_socket.socket = sp->socket_num;
4820Sstevel@tonic-gate 		set_socket.SCIntMask = 0;
4830Sstevel@tonic-gate 		set_socket.IREQRouting = 0;
4840Sstevel@tonic-gate 		set_socket.IFType = IF_MEMORY;
4850Sstevel@tonic-gate 		set_socket.CtlInd = 0; /* turn off controls and indicators */
4860Sstevel@tonic-gate 		set_socket.State = (unsigned)~0; /* clear latched state bits */
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 		(void) cs_convert_powerlevel(sp->socket_num, 0, VCC,
4890Sstevel@tonic-gate 						&set_socket.VccLevel);
4900Sstevel@tonic-gate 		(void) cs_convert_powerlevel(sp->socket_num, 0, VPP1,
4910Sstevel@tonic-gate 						&set_socket.Vpp1Level);
4920Sstevel@tonic-gate 		(void) cs_convert_powerlevel(sp->socket_num, 0, VPP2,
4930Sstevel@tonic-gate 						&set_socket.Vpp2Level);
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 		/*
4960Sstevel@tonic-gate 		 * If we fail this call, there's not much we can do, so
4970Sstevel@tonic-gate 		 *	just continue with the resource deallocation.
4980Sstevel@tonic-gate 		 */
4990Sstevel@tonic-gate 		if ((ret =
5000Sstevel@tonic-gate 			SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
5010Sstevel@tonic-gate 		    cmn_err(CE_CONT,
5020Sstevel@tonic-gate 			"cs_deinit: socket %d SS_SetSocket failure %d\n",
5030Sstevel@tonic-gate 							sp->socket_num, ret);
5040Sstevel@tonic-gate 		}
5050Sstevel@tonic-gate 	    } /* cs_get_sp */
5060Sstevel@tonic-gate 	} /* for (sn) */
5070Sstevel@tonic-gate #endif	/* XXX */
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	/*
5100Sstevel@tonic-gate 	 * Destroy the global mutexii.
5110Sstevel@tonic-gate 	 */
5120Sstevel@tonic-gate 	mutex_destroy(&cs_globals.global_lock);
5130Sstevel@tonic-gate 	mutex_destroy(&cs_globals.window_lock);
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate #ifdef	XXX
5160Sstevel@tonic-gate 	/*
5170Sstevel@tonic-gate 	 * Free the global "super-client" structure
5180Sstevel@tonic-gate 	 */
5190Sstevel@tonic-gate 	if (cs_globals.sclient_list)
5200Sstevel@tonic-gate 	    kmem_free(cs_globals.sclient_list,
5210Sstevel@tonic-gate 		(cs_globals.num_sockets * sizeof (struct sclient_list_t)));
5220Sstevel@tonic-gate 	cs_globals.sclient_list = NULL;
5230Sstevel@tonic-gate #endif	/* XXX */
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	return (CS_SUCCESS);
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate /*
5290Sstevel@tonic-gate  * ==== drip, drip, drip - the Card Services waterfall :-) ====
5300Sstevel@tonic-gate  */
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate /*
5330Sstevel@tonic-gate  * CardServices - general Card Services entry point for CS clients
5340Sstevel@tonic-gate  *			and Socket Services; the address of this
5350Sstevel@tonic-gate  *			function is handed to SS via the CSRegister
5360Sstevel@tonic-gate  *			SS call
5370Sstevel@tonic-gate  */
5380Sstevel@tonic-gate int
CardServices(int function,...)5390Sstevel@tonic-gate CardServices(int function, ...)
5400Sstevel@tonic-gate {
5410Sstevel@tonic-gate 	va_list arglist;
5420Sstevel@tonic-gate 	int retcode = CS_UNSUPPORTED_FUNCTION;
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 	cs_socket_t	*socp;
5450Sstevel@tonic-gate 	uint32_t	*offp;
5460Sstevel@tonic-gate 	acc_handle_t	*hp;
5470Sstevel@tonic-gate 	client_handle_t	ch;
5480Sstevel@tonic-gate 	client_handle_t	*chp;
5490Sstevel@tonic-gate 	window_handle_t	wh;
5500Sstevel@tonic-gate 	window_handle_t	*whp;
5510Sstevel@tonic-gate 	tuple_t		*tuple;
5520Sstevel@tonic-gate 	cisparse_t	*cisparse;
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate #ifdef	CS_DEBUG
5550Sstevel@tonic-gate 	if (cs_debug > 127) {
5560Sstevel@tonic-gate 	    cmn_err(CE_CONT, "CardServices: called for function %s (0x%x)\n",
5570Sstevel@tonic-gate 				cs_error2text(function, CSFUN2TEXT_FUNCTION),
5580Sstevel@tonic-gate 				function);
5590Sstevel@tonic-gate 	}
5600Sstevel@tonic-gate #endif
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	va_start(arglist, function);
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	/*
5650Sstevel@tonic-gate 	 * Here's the Card Services waterfall
5660Sstevel@tonic-gate 	 */
5670Sstevel@tonic-gate 	switch (function) {
5680Sstevel@tonic-gate 	/*
5690Sstevel@tonic-gate 	 * We got here as a result of the CIS module calling us
5700Sstevel@tonic-gate 	 *	in response to cs_ss_init() calling the CIS module
5710Sstevel@tonic-gate 	 *	at CIS_PARSER(CISP_CIS_SETUP, ...)
5720Sstevel@tonic-gate 	 */
5730Sstevel@tonic-gate 	    case CISRegister: {
5740Sstevel@tonic-gate 		cisregister_t *cisr;
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 		    cisr = va_arg(arglist, cisregister_t *);
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 		    if (cisr->cis_magic != PCCS_MAGIC ||
5790Sstevel@tonic-gate 			cisr->cis_version != PCCS_VERSION) {
5800Sstevel@tonic-gate 			    cmn_err(CE_WARN,
5810Sstevel@tonic-gate 				"CS: CISRegister (%lx, %lx, %lx, %lx) *ERROR*",
5820Sstevel@tonic-gate 					(long)cisr->cis_magic,
5830Sstevel@tonic-gate 					(long)cisr->cis_version,
5840Sstevel@tonic-gate 					(long)cisr->cis_parser,
5850Sstevel@tonic-gate 					(long)cisr->cistpl_std_callout);
5860Sstevel@tonic-gate 			retcode = CS_BAD_ARGS;
5870Sstevel@tonic-gate 		    } else {
5880Sstevel@tonic-gate 			/*
5890Sstevel@tonic-gate 			 * Replace the CIS Parser entry point if
5900Sstevel@tonic-gate 			 *	necessary.
5910Sstevel@tonic-gate 			 */
5920Sstevel@tonic-gate 			if (cisr->cis_parser != NULL)
5930Sstevel@tonic-gate 			    cis_parser = cisr->cis_parser;
5940Sstevel@tonic-gate 			cis_cistpl_std_callout = cisr->cistpl_std_callout;
5950Sstevel@tonic-gate 			retcode = CS_SUCCESS;
5960Sstevel@tonic-gate 		    }
5970Sstevel@tonic-gate 		}
5980Sstevel@tonic-gate 		break;
5990Sstevel@tonic-gate 	    case CISUnregister:	/* XXX - should we do some more checking */
6000Sstevel@tonic-gate 		/* XXX - need to protect this by a mutex */
6010Sstevel@tonic-gate 		cis_parser = NULL;
6020Sstevel@tonic-gate 		cis_cistpl_std_callout = NULL;
6030Sstevel@tonic-gate 		retcode = CS_SUCCESS;
6040Sstevel@tonic-gate 		break;
6050Sstevel@tonic-gate 	    case InitCISWindow:
6060Sstevel@tonic-gate 		socp	= va_arg(arglist, cs_socket_t *);
6070Sstevel@tonic-gate 		offp	= va_arg(arglist, uint32_t *);
6080Sstevel@tonic-gate 		hp	= va_arg(arglist, acc_handle_t *);
6090Sstevel@tonic-gate 		retcode = cs_init_cis_window(socp, offp, hp,
6100Sstevel@tonic-gate 				va_arg(arglist, uint32_t));
6110Sstevel@tonic-gate 		break;
6120Sstevel@tonic-gate 	    case RegisterClient:
6130Sstevel@tonic-gate 		chp = va_arg(arglist, client_handle_t *),
6140Sstevel@tonic-gate 		retcode = cs_register_client(chp,
6150Sstevel@tonic-gate 				va_arg(arglist, client_reg_t *));
6160Sstevel@tonic-gate 		break;
6170Sstevel@tonic-gate 	    case DeregisterClient:
6180Sstevel@tonic-gate 		retcode = cs_deregister_client(
6190Sstevel@tonic-gate 				va_arg(arglist, client_handle_t));
6200Sstevel@tonic-gate 		break;
6210Sstevel@tonic-gate 	    case GetStatus:
6220Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6230Sstevel@tonic-gate 		retcode = cs_get_status(ch,
6240Sstevel@tonic-gate 				va_arg(arglist, get_status_t *));
6250Sstevel@tonic-gate 		break;
6260Sstevel@tonic-gate 	    case ResetFunction:
6270Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6280Sstevel@tonic-gate 		retcode = cs_reset_function(ch,
6290Sstevel@tonic-gate 				va_arg(arglist, reset_function_t *));
6300Sstevel@tonic-gate 		break;
6310Sstevel@tonic-gate 	    case SetEventMask:
6320Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6330Sstevel@tonic-gate 		retcode = cs_set_event_mask(ch,
6340Sstevel@tonic-gate 				va_arg(arglist, sockevent_t *));
6350Sstevel@tonic-gate 		break;
6360Sstevel@tonic-gate 	    case GetEventMask:
6370Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6380Sstevel@tonic-gate 		retcode = cs_get_event_mask(ch,
6390Sstevel@tonic-gate 				va_arg(arglist, sockevent_t *));
6400Sstevel@tonic-gate 		break;
6410Sstevel@tonic-gate 	    case RequestIO:
6420Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6430Sstevel@tonic-gate 		retcode = cs_request_io(ch,
6440Sstevel@tonic-gate 				va_arg(arglist, io_req_t *));
6450Sstevel@tonic-gate 		break;
6460Sstevel@tonic-gate 	    case ReleaseIO:
6470Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6480Sstevel@tonic-gate 		retcode = cs_release_io(ch,
6490Sstevel@tonic-gate 				va_arg(arglist, io_req_t *));
6500Sstevel@tonic-gate 		break;
6510Sstevel@tonic-gate 	    case RequestIRQ:
6520Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6530Sstevel@tonic-gate 		retcode = cs_request_irq(ch,
6540Sstevel@tonic-gate 				va_arg(arglist, irq_req_t *));
6550Sstevel@tonic-gate 		break;
6560Sstevel@tonic-gate 	    case ReleaseIRQ:
6570Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6580Sstevel@tonic-gate 		retcode = cs_release_irq(ch,
6590Sstevel@tonic-gate 				va_arg(arglist, irq_req_t *));
6600Sstevel@tonic-gate 		break;
6610Sstevel@tonic-gate 	    case RequestWindow:
6620Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6630Sstevel@tonic-gate 		whp = va_arg(arglist, window_handle_t *);
6640Sstevel@tonic-gate 		retcode = cs_request_window(ch, whp,
6650Sstevel@tonic-gate 				va_arg(arglist, win_req_t *));
6660Sstevel@tonic-gate 		break;
6670Sstevel@tonic-gate 	    case ReleaseWindow:
6680Sstevel@tonic-gate 		retcode = cs_release_window(
6690Sstevel@tonic-gate 				va_arg(arglist, window_handle_t));
6700Sstevel@tonic-gate 		break;
6710Sstevel@tonic-gate 	    case ModifyWindow:
6720Sstevel@tonic-gate 		wh = va_arg(arglist, window_handle_t);
6730Sstevel@tonic-gate 		retcode = cs_modify_window(wh,
6740Sstevel@tonic-gate 				va_arg(arglist, modify_win_t *));
6750Sstevel@tonic-gate 		break;
6760Sstevel@tonic-gate 	    case MapMemPage:
6770Sstevel@tonic-gate 		wh = va_arg(arglist, window_handle_t);
6780Sstevel@tonic-gate 		retcode = cs_map_mem_page(wh,
6790Sstevel@tonic-gate 				va_arg(arglist, map_mem_page_t *));
6800Sstevel@tonic-gate 		break;
6810Sstevel@tonic-gate 	    case RequestSocketMask:
6820Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6830Sstevel@tonic-gate 		retcode = cs_request_socket_mask(ch,
6840Sstevel@tonic-gate 				va_arg(arglist, request_socket_mask_t *));
6850Sstevel@tonic-gate 		break;
6860Sstevel@tonic-gate 	    case ReleaseSocketMask:
6870Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6880Sstevel@tonic-gate 		retcode = cs_release_socket_mask(ch,
6890Sstevel@tonic-gate 				va_arg(arglist, release_socket_mask_t *));
6900Sstevel@tonic-gate 		break;
6910Sstevel@tonic-gate 	    case RequestConfiguration:
6920Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6930Sstevel@tonic-gate 		retcode = cs_request_configuration(ch,
6940Sstevel@tonic-gate 				va_arg(arglist, config_req_t *));
6950Sstevel@tonic-gate 		break;
6960Sstevel@tonic-gate 	    case GetPhysicalAdapterInfo:
6970Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
6980Sstevel@tonic-gate 		retcode = cs_get_physical_adapter_info(ch,
6990Sstevel@tonic-gate 				va_arg(arglist, get_physical_adapter_info_t *));
7000Sstevel@tonic-gate 		break;
7010Sstevel@tonic-gate 	    case GetCardServicesInfo:
7020Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
7030Sstevel@tonic-gate 		retcode = cs_get_cardservices_info(ch,
7040Sstevel@tonic-gate 				va_arg(arglist, get_cardservices_info_t *));
7050Sstevel@tonic-gate 		break;
7060Sstevel@tonic-gate 	    case GetConfigurationInfo:
7070Sstevel@tonic-gate 		chp = va_arg(arglist, client_handle_t *);
7080Sstevel@tonic-gate 		retcode = cs_get_configuration_info(chp,
7090Sstevel@tonic-gate 				va_arg(arglist, get_configuration_info_t *));
7100Sstevel@tonic-gate 		break;
7110Sstevel@tonic-gate 	    case ModifyConfiguration:
7120Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
7130Sstevel@tonic-gate 		retcode = cs_modify_configuration(ch,
7140Sstevel@tonic-gate 				va_arg(arglist, modify_config_t *));
7150Sstevel@tonic-gate 		break;
7160Sstevel@tonic-gate 	    case AccessConfigurationRegister:
7170Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
7180Sstevel@tonic-gate 		retcode = cs_access_configuration_register(ch,
7190Sstevel@tonic-gate 				va_arg(arglist, access_config_reg_t *));
7200Sstevel@tonic-gate 		break;
7210Sstevel@tonic-gate 	    case ReleaseConfiguration:
7220Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
7230Sstevel@tonic-gate 		retcode = cs_release_configuration(ch,
7240Sstevel@tonic-gate 				va_arg(arglist, release_config_t *));
7250Sstevel@tonic-gate 		break;
7260Sstevel@tonic-gate 	    case OpenMemory:
7270Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: OpenMemory\n");
7280Sstevel@tonic-gate 		break;
7290Sstevel@tonic-gate 	    case ReadMemory:
7300Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: ReadMemory\n");
7310Sstevel@tonic-gate 		break;
7320Sstevel@tonic-gate 	    case WriteMemory:
7330Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: WriteMemory\n");
7340Sstevel@tonic-gate 		break;
7350Sstevel@tonic-gate 	    case CopyMemory:
7360Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: CopyMemory\n");
7370Sstevel@tonic-gate 		break;
7380Sstevel@tonic-gate 	    case RegisterEraseQueue:
7390Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: RegisterEraseQueue\n");
7400Sstevel@tonic-gate 		break;
7410Sstevel@tonic-gate 	    case CheckEraseQueue:
7420Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: CheckEraseQueue\n");
7430Sstevel@tonic-gate 		break;
7440Sstevel@tonic-gate 	    case DeregisterEraseQueue:
7450Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: DeregisterEraseQueue\n");
7460Sstevel@tonic-gate 		break;
7470Sstevel@tonic-gate 	    case CloseMemory:
7480Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: CloseMemory\n");
7490Sstevel@tonic-gate 		break;
7500Sstevel@tonic-gate 	    case GetFirstRegion:
7510Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: GetFirstRegion\n");
7520Sstevel@tonic-gate 		break;
7530Sstevel@tonic-gate 	    case GetNextRegion:
7540Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: GetNextRegion\n");
7550Sstevel@tonic-gate 		break;
7560Sstevel@tonic-gate 	    case GetFirstPartition:
7570Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: GetFirstPartition\n");
7580Sstevel@tonic-gate 		break;
7590Sstevel@tonic-gate 	    case GetNextPartition:
7600Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: GetNextPartition\n");
7610Sstevel@tonic-gate 		break;
7620Sstevel@tonic-gate 	    case ReturnSSEntry:
7630Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: ReturnSSEntry\n");
7640Sstevel@tonic-gate 		break;
7650Sstevel@tonic-gate 	    case MapLogSocket:
7660Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
7670Sstevel@tonic-gate 		retcode = cs_map_log_socket(ch,
7680Sstevel@tonic-gate 				va_arg(arglist, map_log_socket_t *));
7690Sstevel@tonic-gate 		break;
7700Sstevel@tonic-gate 	    case MapPhySocket:
7710Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: MapPhySocket\n");
7720Sstevel@tonic-gate 		break;
7730Sstevel@tonic-gate 	    case MapLogWindow:
7740Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: MapLogWindow\n");
7750Sstevel@tonic-gate 		break;
7760Sstevel@tonic-gate 	    case MapPhyWindow:
7770Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: MapPhyWindow\n");
7780Sstevel@tonic-gate 		break;
7790Sstevel@tonic-gate 	    case RegisterMTD:
7800Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: RegisterMTD\n");
7810Sstevel@tonic-gate 		break;
7820Sstevel@tonic-gate 	    case RegisterTimer:
7830Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: RegisterTimer\n");
7840Sstevel@tonic-gate 		break;
7850Sstevel@tonic-gate 	    case SetRegion:
7860Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: SetRegion\n");
7870Sstevel@tonic-gate 		break;
7880Sstevel@tonic-gate 	    case RequestExclusive:
7890Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: RequestExclusive\n");
7900Sstevel@tonic-gate 		break;
7910Sstevel@tonic-gate 	    case ReleaseExclusive:
7920Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: ReleaseExclusive\n");
7930Sstevel@tonic-gate 		break;
7940Sstevel@tonic-gate 	    case GetFirstClient:
7950Sstevel@tonic-gate 		retcode = cs_get_firstnext_client(
7960Sstevel@tonic-gate 				va_arg(arglist, get_firstnext_client_t *),
7970Sstevel@tonic-gate 				CS_GET_FIRST_FLAG);
7980Sstevel@tonic-gate 		break;
7990Sstevel@tonic-gate 	    case GetNextClient:
8000Sstevel@tonic-gate 		retcode = cs_get_firstnext_client(
8010Sstevel@tonic-gate 				va_arg(arglist, get_firstnext_client_t *),
8020Sstevel@tonic-gate 				CS_GET_NEXT_FLAG);
8030Sstevel@tonic-gate 		break;
8040Sstevel@tonic-gate 	    case GetClientInfo:
8050Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
8060Sstevel@tonic-gate 		retcode = cs_get_client_info(ch,
8070Sstevel@tonic-gate 				va_arg(arglist, client_info_t *));
8080Sstevel@tonic-gate 		break;
8090Sstevel@tonic-gate 	    case AddSocketServices:
8100Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: AddSocketServices\n");
8110Sstevel@tonic-gate 		break;
8120Sstevel@tonic-gate 	    case ReplaceSocketServices:
8130Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: ReplaceSocketServices\n");
8140Sstevel@tonic-gate 		break;
8150Sstevel@tonic-gate 	    case VendorSpecific:
8160Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: VendorSpecific\n");
8170Sstevel@tonic-gate 		break;
8180Sstevel@tonic-gate 	    case AdjustResourceInfo:
8190Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: AdjustResourceInfo\n");
8200Sstevel@tonic-gate 		break;
8210Sstevel@tonic-gate 	    case ValidateCIS:
8220Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
8230Sstevel@tonic-gate 		retcode = cs_validate_cis(ch,
8240Sstevel@tonic-gate 				va_arg(arglist, cisinfo_t *));
8250Sstevel@tonic-gate 		break;
8260Sstevel@tonic-gate 	    case GetFirstTuple:
8270Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
8280Sstevel@tonic-gate 		retcode = cs_get_firstnext_tuple(ch,
8290Sstevel@tonic-gate 				va_arg(arglist, tuple_t *),
8300Sstevel@tonic-gate 				CS_GET_FIRST_FLAG);
8310Sstevel@tonic-gate 		break;
8320Sstevel@tonic-gate 	    case GetNextTuple:
8330Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
8340Sstevel@tonic-gate 		retcode = cs_get_firstnext_tuple(ch,
8350Sstevel@tonic-gate 				va_arg(arglist, tuple_t *),
8360Sstevel@tonic-gate 				CS_GET_NEXT_FLAG);
8370Sstevel@tonic-gate 		break;
8380Sstevel@tonic-gate 	    case GetTupleData:
8390Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
8400Sstevel@tonic-gate 		retcode = cs_get_tuple_data(ch,
8410Sstevel@tonic-gate 				va_arg(arglist, tuple_t *));
8420Sstevel@tonic-gate 		break;
8430Sstevel@tonic-gate 	    case ParseTuple:
8440Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
8450Sstevel@tonic-gate 		tuple = va_arg(arglist, tuple_t *);
8460Sstevel@tonic-gate 		cisparse = va_arg(arglist, cisparse_t *);
8470Sstevel@tonic-gate 		retcode = cs_parse_tuple(ch, tuple, cisparse,
8480Sstevel@tonic-gate 				va_arg(arglist, uint_t));
8490Sstevel@tonic-gate 		break;
8500Sstevel@tonic-gate 	    case MakeDeviceNode:
8510Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
8520Sstevel@tonic-gate 		retcode = cs_make_device_node(ch,
8530Sstevel@tonic-gate 				va_arg(arglist, make_device_node_t *));
8540Sstevel@tonic-gate 		break;
8550Sstevel@tonic-gate 	    case RemoveDeviceNode:
8560Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
8570Sstevel@tonic-gate 		retcode = cs_remove_device_node(ch,
8580Sstevel@tonic-gate 				va_arg(arglist, remove_device_node_t *));
8590Sstevel@tonic-gate 		break;
8600Sstevel@tonic-gate 	    case ConvertSpeed:
8610Sstevel@tonic-gate 		retcode = cs_convert_speed(
8620Sstevel@tonic-gate 				va_arg(arglist, convert_speed_t *));
8630Sstevel@tonic-gate 		break;
8640Sstevel@tonic-gate 	    case ConvertSize:
8650Sstevel@tonic-gate 		retcode = cs_convert_size(
8660Sstevel@tonic-gate 				va_arg(arglist, convert_size_t *));
8670Sstevel@tonic-gate 		break;
8680Sstevel@tonic-gate 	    case Event2Text:
8690Sstevel@tonic-gate 		retcode = cs_event2text(
8700Sstevel@tonic-gate 				va_arg(arglist, event2text_t *), 1);
8710Sstevel@tonic-gate 		break;
8720Sstevel@tonic-gate 	    case Error2Text: {
8730Sstevel@tonic-gate 		error2text_t *cft;
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 		cft = va_arg(arglist, error2text_t *);
8760Sstevel@tonic-gate 		(void) strcpy(cft->text,
8770Sstevel@tonic-gate 				cs_error2text(cft->item, CSFUN2TEXT_RETURN));
8780Sstevel@tonic-gate 		retcode = CS_SUCCESS;
8790Sstevel@tonic-gate 		}
8800Sstevel@tonic-gate 		break;
8810Sstevel@tonic-gate 	    case CS_DDI_Info:
8820Sstevel@tonic-gate 		retcode = cs_ddi_info(va_arg(arglist, cs_ddi_info_t *));
8830Sstevel@tonic-gate 		break;
8840Sstevel@tonic-gate 	    case CS_Sys_Ctl:
8850Sstevel@tonic-gate 		retcode = cs_sys_ctl(va_arg(arglist, cs_sys_ctl_t *));
8860Sstevel@tonic-gate 		break;
8870Sstevel@tonic-gate 	    default:
8880Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: {unknown function %d}\n", function);
8890Sstevel@tonic-gate 		break;
8900Sstevel@tonic-gate 	} /* switch(function) */
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 	va_end(arglist);
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate #ifdef	CS_DEBUG
8950Sstevel@tonic-gate 	if (cs_debug > 127) {
8960Sstevel@tonic-gate 	    cmn_err(CE_CONT, "CardServices: returning %s (0x%x)\n",
8970Sstevel@tonic-gate 				cs_error2text(retcode, CSFUN2TEXT_RETURN),
8980Sstevel@tonic-gate 				retcode);
8990Sstevel@tonic-gate 	}
9000Sstevel@tonic-gate #endif
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	return (retcode);
9030Sstevel@tonic-gate }
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate /*
9060Sstevel@tonic-gate  * ==== tuple and CIS handling section ====
9070Sstevel@tonic-gate  */
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate /*
9100Sstevel@tonic-gate  * cs_parse_tuple - This function supports the CS ParseTuple function call.
9110Sstevel@tonic-gate  *
9120Sstevel@tonic-gate  *    returns:	CS_SUCCESS - if tuple parsed sucessfully
9130Sstevel@tonic-gate  *		CS_NO_CARD - if no card in socket
9140Sstevel@tonic-gate  *		CS_BAD_ARGS - if passed CIS list pointer is NULL
9150Sstevel@tonic-gate  *		CS_UNKNOWN_TUPLE - if unknown tuple passed to CIS parser
9160Sstevel@tonic-gate  *		CS_BAD_CIS - if generic parser error
9170Sstevel@tonic-gate  *		CS_NO_CIS - if no CIS for card/function
9180Sstevel@tonic-gate  *
9190Sstevel@tonic-gate  *    See notes for the cs_get_firstnext_tuple function.
9200Sstevel@tonic-gate  */
9210Sstevel@tonic-gate static int
cs_parse_tuple(client_handle_t client_handle,tuple_t * tuple,cisparse_t * cisparse,cisdata_t cisdata)9220Sstevel@tonic-gate cs_parse_tuple(client_handle_t client_handle, tuple_t *tuple,
9230Sstevel@tonic-gate 				cisparse_t *cisparse, cisdata_t cisdata)
9240Sstevel@tonic-gate {
9250Sstevel@tonic-gate 	cs_socket_t *sp;
9260Sstevel@tonic-gate 	client_t *client;
9270Sstevel@tonic-gate 	uint32_t fn;
9280Sstevel@tonic-gate 	int ret;
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 	if ((ret = cs_get_socket(client_handle, &tuple->Socket,
9310Sstevel@tonic-gate 					&fn, &sp, &client)) != CS_SUCCESS)
9320Sstevel@tonic-gate 	    return (ret);
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 	/*
9350Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
9360Sstevel@tonic-gate 	 *	for this client, then return an error.
9370Sstevel@tonic-gate 	 */
9380Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED))
9390Sstevel@tonic-gate 	    return (CS_NO_CARD);
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 	/*
9420Sstevel@tonic-gate 	 * Sanity check to be sure that we've got a non-NULL CIS list
9430Sstevel@tonic-gate 	 *	pointer.
9440Sstevel@tonic-gate 	 */
9450Sstevel@tonic-gate 	if (!(tuple->CISOffset))
9460Sstevel@tonic-gate 	    return (CS_BAD_ARGS);
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	/*
9510Sstevel@tonic-gate 	 * Check to see if there is a valid CIS for this function.
9520Sstevel@tonic-gate 	 *	There is an implicit assumption here that if this
9530Sstevel@tonic-gate 	 *	is a multi-function CIS and the specified function
9540Sstevel@tonic-gate 	 *	number is not CS_GLOBAL_CIS that in order for there
9550Sstevel@tonic-gate 	 *	to be a valid function-specific CIS, there also must
9560Sstevel@tonic-gate 	 *	be a valid global CIS. This means that we don't need
9570Sstevel@tonic-gate 	 *	to know whether this tuple came from the global CIS
9580Sstevel@tonic-gate 	 *	or from the function-specific CIS.
9590Sstevel@tonic-gate 	 */
9600Sstevel@tonic-gate 	if ((sp->cis_flags & CW_VALID_CIS) &&
9610Sstevel@tonic-gate 				(sp->cis[fn].flags & CW_VALID_CIS)) {
9620Sstevel@tonic-gate 	    ret = (int)(uintptr_t)CIS_PARSER(CISP_CIS_PARSE_TUPLE,
9630Sstevel@tonic-gate 				cis_cistpl_std_callout,
9640Sstevel@tonic-gate 				tuple->CISOffset,
9650Sstevel@tonic-gate 				(tuple->Attributes & TUPLE_RETURN_NAME)?
9660Sstevel@tonic-gate 							HANDTPL_RETURN_NAME:
9670Sstevel@tonic-gate 							HANDTPL_PARSE_LTUPLE,
9680Sstevel@tonic-gate 				cisparse, cisdata);
9690Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
9700Sstevel@tonic-gate 	    if (ret == CISTPLF_UNKNOWN)
9710Sstevel@tonic-gate 		return (CS_UNKNOWN_TUPLE);
9720Sstevel@tonic-gate 	    if (ret != CISTPLF_NOERROR)
9730Sstevel@tonic-gate 		return (CS_BAD_CIS);
9740Sstevel@tonic-gate 	    ret = CS_SUCCESS;
9750Sstevel@tonic-gate 	} else {
9760Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
9770Sstevel@tonic-gate 	    ret = CS_NO_CIS;
9780Sstevel@tonic-gate 	} /* if (CW_VALID_CIS) */
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	return (ret);
9810Sstevel@tonic-gate }
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate /*
9840Sstevel@tonic-gate  * cs_get_firstnext_tuple - returns the first/next tuple of the specified type
9850Sstevel@tonic-gate  *				this is to support the GetFirstTuple and
9860Sstevel@tonic-gate  *				GetNextTuple function call
9870Sstevel@tonic-gate  *
9880Sstevel@tonic-gate  *    flags - one of:
9890Sstevel@tonic-gate  *		CS_GET_FIRST_FLAG causes function to support GetFirstTuple
9900Sstevel@tonic-gate  *		CS_GET_NEXT_FLAG causes function to support GetNextTuple
9910Sstevel@tonic-gate  *
9920Sstevel@tonic-gate  *	tuple_t->Attributes flags:
9930Sstevel@tonic-gate  *		TUPLE_RETURN_LINK - XXX Not implemented, see notes below.
9940Sstevel@tonic-gate  *		TUPLE_RETURN_IGNORED_TUPLES - return tuples with
9950Sstevel@tonic-gate  *				CISTPLF_IGNORE_TUPLE set in the
9960Sstevel@tonic-gate  *				cistpl_t->flags member.
9970Sstevel@tonic-gate  *
9980Sstevel@tonic-gate  *    Notes for regular PC card driver callers:
9990Sstevel@tonic-gate  *
10000Sstevel@tonic-gate  *	On a single-function card, the caller will get back all the tuples in
10010Sstevel@tonic-gate  *	the CIS.
10020Sstevel@tonic-gate  *
10030Sstevel@tonic-gate  *	On a multi-function card, the caller will get the tuples from the
10040Sstevel@tonic-gate  *	global CIS followed by the tuples in the function-specific CIS. The
10050Sstevel@tonic-gate  *	caller will not get any tuples from a function-specific CIS that
10060Sstevel@tonic-gate  *	does not belong to the caller's function.
10070Sstevel@tonic-gate  *
10080Sstevel@tonic-gate  *    Notes for Socket Services, the "super-client" or CSI driver callers:
10090Sstevel@tonic-gate  *
10100Sstevel@tonic-gate  *	On a single-function card, the operation is the same as for regular
10110Sstevel@tonic-gate  *	PC card driver callers with the addition that if the function number
10120Sstevel@tonic-gate  *	is set to CS_GLOBAL_CIS this function will return CS_NO_CIS.
10130Sstevel@tonic-gate  *
10140Sstevel@tonic-gate  *	On a multi-function card, the operation is the same as for regular
10150Sstevel@tonic-gate  *	PC card driver callers with the addition that if the function number
10160Sstevel@tonic-gate  *	is set to CS_GLOBAL_CIS the caller will only get tuples from the
10170Sstevel@tonic-gate  *	global CIS. If a particular function nubmer does not exist, this
10180Sstevel@tonic-gate  *	function will return CS_NO_CIS for that function.
10190Sstevel@tonic-gate  *
10200Sstevel@tonic-gate  *    General notes:
10210Sstevel@tonic-gate  *
10220Sstevel@tonic-gate  *	On both a single-function card and a multi-function card, if the tuple
10230Sstevel@tonic-gate  *	comes from the global CIS chain, the CISTPLF_GLOBAL_CIS flag will be
10240Sstevel@tonic-gate  *	set in the tuple_t->flags member.
10250Sstevel@tonic-gate  *
10260Sstevel@tonic-gate  *	On a multi-function card, if the tuple comes from the function-specific
10270Sstevel@tonic-gate  *	CIS chain, the CISTPLF_MF_CIS flag will be set in the tuple_t->flags
10280Sstevel@tonic-gate  *	member.
10290Sstevel@tonic-gate  *
10300Sstevel@tonic-gate  *	For other flags that are set in the tuple_t->flags member, see the
10310Sstevel@tonic-gate  *	comments for the cis_list_lcreate function in the cis.c file.
10320Sstevel@tonic-gate  *
10330Sstevel@tonic-gate  *	The CIS parser may not include all the tuples that are in the CIS in
10340Sstevel@tonic-gate  *	the private CIS list that it creates and maintains. See the CIS
10350Sstevel@tonic-gate  *	parser documentation for a list of tuples that the parser does not
10360Sstevel@tonic-gate  *	include in the list.
10370Sstevel@tonic-gate  *
10380Sstevel@tonic-gate  *	If a tuple has the CISTPLF_IGNORE_TUPLE flag set and the flags
10390Sstevel@tonic-gate  *	parameter CIS_GET_LTUPLE_IGNORE is not set, that tuple will not
10400Sstevel@tonic-gate  *	be returned to the caller. Instead, the next tuple that matches
10410Sstevel@tonic-gate  *	the calling criteria will be returned (or NULL if no other tuples
10420Sstevel@tonic-gate  *	match the calling criteria). If CIS_GET_LTUPLE_IGNORE is set in
10430Sstevel@tonic-gate  *	the flags paramter, tuples in the CIS list that match the calling
10440Sstevel@tonic-gate  *	criteria will be returned.
10450Sstevel@tonic-gate  *
10460Sstevel@tonic-gate  * XXX The PC Card 95 Standard says that if the TUPLE_RETURN_LINK flag in
10470Sstevel@tonic-gate  *	the tuple_t->Attributes member is not set, then we don't return
10480Sstevel@tonic-gate  *	any of the link tuples. This function ignores this flag and always
10490Sstevel@tonic-gate  *	returns link tuples.
10500Sstevel@tonic-gate  *
10510Sstevel@tonic-gate  *    Return codes:
10520Sstevel@tonic-gate  *		CS_SUCCESS - if tuple sucessfully found and returned
10530Sstevel@tonic-gate  *		CS_NO_CARD - if no card inserted
10540Sstevel@tonic-gate  *		CS_NO_CIS - if no CIS for the specified card/function
10550Sstevel@tonic-gate  *		CS_NO_MORE_ITEMS - if tuple not found or no more tuples
10560Sstevel@tonic-gate  *					to return
10570Sstevel@tonic-gate  *
10580Sstevel@tonic-gate  *    See notes for cs_get_socket for a description of valid client, socket
10590Sstevel@tonic-gate  *	and function number combinations.
10600Sstevel@tonic-gate  */
10610Sstevel@tonic-gate static int
cs_get_firstnext_tuple(client_handle_t client_handle,tuple_t * tuple,uint32_t flags)10620Sstevel@tonic-gate cs_get_firstnext_tuple(client_handle_t client_handle,
10630Sstevel@tonic-gate     tuple_t *tuple, uint32_t flags)
10640Sstevel@tonic-gate {
10650Sstevel@tonic-gate 	cs_socket_t *sp;
10660Sstevel@tonic-gate 	client_t *client;
10670Sstevel@tonic-gate 	uint32_t fn;
10680Sstevel@tonic-gate 	int ret;
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate 	if ((ret = cs_get_socket(client_handle, &tuple->Socket, &fn,
10710Sstevel@tonic-gate 						&sp, &client)) != CS_SUCCESS)
10720Sstevel@tonic-gate 	    return (ret);
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate 	/*
10750Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
10760Sstevel@tonic-gate 	 *	for this client, then return an error.
10770Sstevel@tonic-gate 	 */
10780Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED))
10790Sstevel@tonic-gate 	    return (CS_NO_CARD);
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 	/*
10840Sstevel@tonic-gate 	 * If there's no CIS on this card or no CIS for the specified
10850Sstevel@tonic-gate 	 *	function, then we can't do much.
10860Sstevel@tonic-gate 	 */
10870Sstevel@tonic-gate 	if ((!(sp->cis_flags & CW_VALID_CIS)) ||
10880Sstevel@tonic-gate 				(!(sp->cis[fn].flags & CW_VALID_CIS))) {
10890Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
10900Sstevel@tonic-gate 	    return (CS_NO_CIS);
10910Sstevel@tonic-gate 	}
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate 	/*
10940Sstevel@tonic-gate 	 * This will set the CIS_GET_LTUPLE_IGNORE flag if the
10950Sstevel@tonic-gate 	 *	TUPLE_RETURN_IGNORED_TUPLES flag is set. The
10960Sstevel@tonic-gate 	 *	assumption here is that the CIS_GET_LTUPLE_IGNORE
10970Sstevel@tonic-gate 	 *	flag and the TUPLE_RETURN_IGNORED_TUPLES flag
10980Sstevel@tonic-gate 	 *	shares the same bit position. If this ever changes,
10990Sstevel@tonic-gate 	 *	we'll ahve to re-work this section of code.
11000Sstevel@tonic-gate 	 */
11010Sstevel@tonic-gate 	if (tuple->Attributes & TUPLE_RETURN_IGNORED_TUPLES)
11020Sstevel@tonic-gate 	    flags |= CIS_GET_LTUPLE_IGNORE;
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 	/*
11050Sstevel@tonic-gate 	 * Are we GetFirstTuple or GetNextTuple?
11060Sstevel@tonic-gate 	 */
11070Sstevel@tonic-gate 	if ((flags & CIS_GET_LTUPLE_OPMASK) & CS_GET_FIRST_FLAG) {
11080Sstevel@tonic-gate 	/*
11090Sstevel@tonic-gate 	 * Initialize the tuple structure; we need this information when
11100Sstevel@tonic-gate 	 *	we have to process a GetNextTuple or ParseTuple call.
11110Sstevel@tonic-gate 	 * If this card has a multi-function CIS, then we always start out
11120Sstevel@tonic-gate 	 *	delivering tuples from the global CIS chain. If this card does
11130Sstevel@tonic-gate 	 *	not have a multi-function CIS, then the function 0 CIS chain
11140Sstevel@tonic-gate 	 *	will contain the complete CIS list.
11150Sstevel@tonic-gate 	 * If this is a multi-function card, then use the GET_FIRST_LTUPLE
11160Sstevel@tonic-gate 	 *	macro to return the first tuple in the CIS list - we do this
11170Sstevel@tonic-gate 	 *	since we don't want to return tuples with CISTPLF_IGNORE_TUPLE
11180Sstevel@tonic-gate 	 *	set unless CIS_GET_LTUPLE_IGNORE is set in the flags parameter.
11190Sstevel@tonic-gate 	 * Note that we don't have to cross over into the fucntion-specific
11200Sstevel@tonic-gate 	 *	CIS chain if GET_FIRST_LTUPLE returns NULL, since a MF CIS will
11210Sstevel@tonic-gate 	 *	always have at least a CISTPL_LONGLINK_MFC tuple in the global
11220Sstevel@tonic-gate 	 *	CIS chain - the test for NULL is just a sanity check.
11230Sstevel@tonic-gate 	 */
11240Sstevel@tonic-gate 	    if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
11250Sstevel@tonic-gate 		if ((tuple->CISOffset =
11260Sstevel@tonic-gate 			GET_FIRST_LTUPLE(sp->cis[CS_GLOBAL_CIS].cis,
11270Sstevel@tonic-gate 							flags)) == NULL) {
11280Sstevel@tonic-gate 		    mutex_exit(&sp->cis_lock);
11290Sstevel@tonic-gate 		    return (CS_NO_MORE_ITEMS);
11300Sstevel@tonic-gate 		} /* GET_FIRST_LTUPLE */
11310Sstevel@tonic-gate 	    } else {
11320Sstevel@tonic-gate 		tuple->CISOffset = sp->cis[0].cis;
11330Sstevel@tonic-gate 	    } /* CW_MULTI_FUNCTION_CIS */
11340Sstevel@tonic-gate 	} else {
11350Sstevel@tonic-gate 	    cistpl_t *tp;
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate 		/*
11380Sstevel@tonic-gate 		 * Check to be sure that we have a non-NULL tuple list pointer.
11390Sstevel@tonic-gate 		 *	This is necessary in the case where the caller calls us
11400Sstevel@tonic-gate 		 *	with get next tuple requests but we don't have any more
11410Sstevel@tonic-gate 		 *	tuples to give back.
11420Sstevel@tonic-gate 		 */
11430Sstevel@tonic-gate 	    if (tuple->CISOffset == NULL) {
11440Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
11450Sstevel@tonic-gate 		return (CS_NO_MORE_ITEMS);
11460Sstevel@tonic-gate 	    }
11470Sstevel@tonic-gate 
11480Sstevel@tonic-gate 		/*
11490Sstevel@tonic-gate 		 * Point to the next tuple in the list.  If we're searching for
11500Sstevel@tonic-gate 		 *	a particular tuple, FIND_LTUPLE_FWD will find it.
11510Sstevel@tonic-gate 		 *
11520Sstevel@tonic-gate 		 * If there are no more tuples in the chain that we're looking
11530Sstevel@tonic-gate 		 *	at, then if we're looking at the global portion of a
11540Sstevel@tonic-gate 		 *	multi-function CIS, switch to the function-specific list
11550Sstevel@tonic-gate 		 *	and start looking there.
11560Sstevel@tonic-gate 		 */
11570Sstevel@tonic-gate 	    if ((tp = GET_NEXT_TUPLE(tuple->CISOffset, flags)) == NULL) {
11580Sstevel@tonic-gate 		if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
11590Sstevel@tonic-gate 		    if ((tuple->CISOffset->flags & CISTPLF_GLOBAL_CIS) &&
11600Sstevel@tonic-gate 							(fn != CS_GLOBAL_CIS)) {
11610Sstevel@tonic-gate 			tp = GET_FIRST_LTUPLE(sp->cis[fn].cis, flags);
11620Sstevel@tonic-gate 		    } /* CISTPLF_GLOBAL_CIS */
11630Sstevel@tonic-gate 		} /* CW_MULTI_FUNCTION_CIS */
11640Sstevel@tonic-gate 	    } /* GET_NEXT_TUPLE */
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 		/*
11670Sstevel@tonic-gate 		 * If there are no more tuples in the chain, then return.
11680Sstevel@tonic-gate 		 */
11690Sstevel@tonic-gate 	    if ((tuple->CISOffset = tp) == NULL) {
11700Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
11710Sstevel@tonic-gate 		return (CS_NO_MORE_ITEMS);
11720Sstevel@tonic-gate 	    }
11730Sstevel@tonic-gate 	} /* CS_GET_FIRST_FLAG */
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate 	/*
11760Sstevel@tonic-gate 	 * Check if we want to get the first of a particular type of tuple
11770Sstevel@tonic-gate 	 *	or just the first tuple in the chain.
11780Sstevel@tonic-gate 	 * If there are no more tuples of the type we're searching for in
11790Sstevel@tonic-gate 	 *	the chain that we're looking at, then if we're looking at
11800Sstevel@tonic-gate 	 *	the global portion of a multi-function CIS, switch to the
11810Sstevel@tonic-gate 	 *	function-specific list and start looking there.
11820Sstevel@tonic-gate 	 */
11830Sstevel@tonic-gate 	if (tuple->DesiredTuple != RETURN_FIRST_TUPLE) {
11840Sstevel@tonic-gate 	    cistpl_t *tp;
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 	    if ((tp = FIND_LTUPLE_FWD(tuple->CISOffset,
11870Sstevel@tonic-gate 					tuple->DesiredTuple, flags)) == NULL) {
11880Sstevel@tonic-gate 		if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
11890Sstevel@tonic-gate 		    if ((tuple->CISOffset->flags & CISTPLF_GLOBAL_CIS) &&
11900Sstevel@tonic-gate 							(fn != CS_GLOBAL_CIS)) {
11910Sstevel@tonic-gate 			tp = FIND_FIRST_LTUPLE(sp->cis[fn].cis,
11920Sstevel@tonic-gate 						tuple->DesiredTuple, flags);
11930Sstevel@tonic-gate 		    } /* CISTPLF_GLOBAL_CIS */
11940Sstevel@tonic-gate 		} /* CW_MULTI_FUNCTION_CIS */
11950Sstevel@tonic-gate 	    } /* FIND_LTUPLE_FWD */
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate 		/*
11980Sstevel@tonic-gate 		 * If there are no more tuples in the chain, then return.
11990Sstevel@tonic-gate 		 */
12000Sstevel@tonic-gate 	    if ((tuple->CISOffset = tp) == NULL) {
12010Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
12020Sstevel@tonic-gate 		return (CS_NO_MORE_ITEMS);
12030Sstevel@tonic-gate 	    }
12040Sstevel@tonic-gate 	} /* !RETURN_FIRST_TUPLE */
12050Sstevel@tonic-gate 
12060Sstevel@tonic-gate 	/*
12070Sstevel@tonic-gate 	 * We've got a tuple, now fill out the rest of the tuple_t
12080Sstevel@tonic-gate 	 *	structure.  Callers can use the flags member to
12090Sstevel@tonic-gate 	 *	determine whether or not the tuple data was copied
12100Sstevel@tonic-gate 	 *	to the linked list or if it's still on the card.
12110Sstevel@tonic-gate 	 */
12120Sstevel@tonic-gate 	tuple->Flags = tuple->CISOffset->flags;
12130Sstevel@tonic-gate 	tuple->TupleCode = tuple->CISOffset->type;
12140Sstevel@tonic-gate 	tuple->TupleLink = tuple->CISOffset->len;
12150Sstevel@tonic-gate 	tuple->TupleDataLen = tuple->CISOffset->len;
12160Sstevel@tonic-gate 
12170Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate 	return (CS_SUCCESS);
12200Sstevel@tonic-gate }
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate /*
12230Sstevel@tonic-gate  * cs_get_tuple_data - get the data portion of a tuple; this is to
12240Sstevel@tonic-gate  *	support the GetTupleData function call.
12250Sstevel@tonic-gate  *
12260Sstevel@tonic-gate  *    Note that if the data body of a tuple was not read from the CIS,
12270Sstevel@tonic-gate  *	then this function will return CS_NO_MORE_ITEMS.
12280Sstevel@tonic-gate  *
12290Sstevel@tonic-gate  *    For flags that are set in the tuple_t->flags member, see the
12300Sstevel@tonic-gate  *	comments for the cis_list_lcreate function in the cis.c file.
12310Sstevel@tonic-gate  *	These flags are copied into the tuple_t->flags member by the
12320Sstevel@tonic-gate  *	cs_get_firstnext_tuple function call.
12330Sstevel@tonic-gate  *
12340Sstevel@tonic-gate  *    See notes for the cs_get_firstnext_tuple function.
12350Sstevel@tonic-gate  */
12360Sstevel@tonic-gate static int
cs_get_tuple_data(client_handle_t client_handle,tuple_t * tuple)12370Sstevel@tonic-gate cs_get_tuple_data(client_handle_t client_handle, tuple_t *tuple)
12380Sstevel@tonic-gate {
12390Sstevel@tonic-gate 	cs_socket_t *sp;
12400Sstevel@tonic-gate 	client_t *client;
12410Sstevel@tonic-gate 	int ret, nbytes;
12420Sstevel@tonic-gate 	uint32_t fn, flags;
12430Sstevel@tonic-gate 	cisdata_t *tsd, *tdd;
12440Sstevel@tonic-gate 	uint32_t newoffset;
12450Sstevel@tonic-gate 	acc_handle_t cis_handle;
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 	if ((ret = cs_get_socket(client_handle, &tuple->Socket, &fn,
12480Sstevel@tonic-gate 						&sp, &client)) != CS_SUCCESS)
12490Sstevel@tonic-gate 	    return (ret);
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate 	/*
12520Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
12530Sstevel@tonic-gate 	 *	for this client, then return an error.
12540Sstevel@tonic-gate 	 */
12550Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED))
12560Sstevel@tonic-gate 	    return (CS_NO_CARD);
12570Sstevel@tonic-gate 
12580Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
12590Sstevel@tonic-gate 
12600Sstevel@tonic-gate 	if ((sp->cis_flags & CW_VALID_CIS) &&
12610Sstevel@tonic-gate 				(sp->cis[fn].flags & CW_VALID_CIS)) {
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate 		/*
12640Sstevel@tonic-gate 		 * Check to be sure that we have a non-NULL pointer to
12650Sstevel@tonic-gate 		 *	a CIS list.
12660Sstevel@tonic-gate 		 */
12670Sstevel@tonic-gate 	    if (!(tuple->CISOffset)) {
12680Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
12690Sstevel@tonic-gate 		return (CS_NO_MORE_ITEMS);
12700Sstevel@tonic-gate 	    }
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 	/*
12730Sstevel@tonic-gate 	 * Since the tuple data buffer that the caller calls us with
12740Sstevel@tonic-gate 	 *	is preallocated in the tuple_t structure, we ignore any
12750Sstevel@tonic-gate 	 *	TupleDataMax value that the caller has setup and use the
12760Sstevel@tonic-gate 	 *	actual size of the tuple data buffer in the structure.
12770Sstevel@tonic-gate 	 */
12780Sstevel@tonic-gate 	    tuple->TupleDataMax = sizeof (tuple->TupleData);
12790Sstevel@tonic-gate 
12800Sstevel@tonic-gate 	/*
12810Sstevel@tonic-gate 	 * Make sure the requested offset is not past the end of the
12820Sstevel@tonic-gate 	 *	tuple data body nor past the end of the user-supplied
12830Sstevel@tonic-gate 	 *	buffer.
12840Sstevel@tonic-gate 	 */
12850Sstevel@tonic-gate 	    if ((int)tuple->TupleOffset >= min((int)tuple->TupleLink,
12860Sstevel@tonic-gate 						(int)tuple->TupleDataMax)) {
12870Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
12880Sstevel@tonic-gate 		return (CS_NO_MORE_ITEMS);
12890Sstevel@tonic-gate 	    }
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate 	    tuple->TupleDataLen = tuple->TupleLink;
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate 	    if ((nbytes = min((int)tuple->TupleDataMax -
12940Sstevel@tonic-gate 						(int)tuple->TupleOffset,
12950Sstevel@tonic-gate 						(int)tuple->TupleDataLen -
12960Sstevel@tonic-gate 						(int)tuple->TupleOffset)) < 1) {
12970Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
12980Sstevel@tonic-gate 		return (CS_BAD_ARGS);
12990Sstevel@tonic-gate 	    }
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate 	/*
13020Sstevel@tonic-gate 	 * The tuple data destination is always the tuple_t->TupleData
13030Sstevel@tonic-gate 	 *	buffer in the tuple_t structure no matter where we read the
13040Sstevel@tonic-gate 	 *	tuple data from.
13050Sstevel@tonic-gate 	 */
13060Sstevel@tonic-gate 	    tdd = tuple->TupleData;
13070Sstevel@tonic-gate 	    bzero((caddr_t)tdd, sizeof (tuple->TupleData));
13080Sstevel@tonic-gate 
13090Sstevel@tonic-gate 	/*
13100Sstevel@tonic-gate 	 * Do we have a copy of the tuple data?  If not, we have to
13110Sstevel@tonic-gate 	 *	get a pointer to the CIS and read the tuple data from the
13120Sstevel@tonic-gate 	 *	card itself.
13130Sstevel@tonic-gate 	 */
13140Sstevel@tonic-gate 	    switch (tuple->CISOffset->flags & CISTPLF_SPACE_MASK) {
13150Sstevel@tonic-gate 		case CISTPLF_LM_SPACE:
13160Sstevel@tonic-gate 		    tsd = (tuple->CISOffset->data +
13170Sstevel@tonic-gate 					(unsigned)tuple->TupleOffset);
13180Sstevel@tonic-gate 		    while (nbytes--)
13190Sstevel@tonic-gate 			*tdd++ = *tsd++;
13200Sstevel@tonic-gate 		    break;
13210Sstevel@tonic-gate 		case CISTPLF_AM_SPACE:
13220Sstevel@tonic-gate 		case CISTPLF_CM_SPACE:
13230Sstevel@tonic-gate 		    newoffset = tuple->CISOffset->offset;
13240Sstevel@tonic-gate 
13250Sstevel@tonic-gate 		/*
13260Sstevel@tonic-gate 		 * Setup the proper space flags as well as setup the
13270Sstevel@tonic-gate 		 *	address offset to point to the start of the tuple
13280Sstevel@tonic-gate 		 *	data area; we need to do the latter since the
13290Sstevel@tonic-gate 		 *	cis_store_cis_addr function in cis.c sets up the
13300Sstevel@tonic-gate 		 *	tuple->CISOffset->offset offset to point to the
13310Sstevel@tonic-gate 		 *	start of the tuple.
13320Sstevel@tonic-gate 		 */
13330Sstevel@tonic-gate 		    if (tuple->CISOffset->flags & CISTPLF_AM_SPACE) {
13340Sstevel@tonic-gate 			flags = CISTPLF_AM_SPACE;
13350Sstevel@tonic-gate 			newoffset += ((tuple->TupleOffset * 2) + 4);
13360Sstevel@tonic-gate 		    } else {
13370Sstevel@tonic-gate 			flags = CISTPLF_CM_SPACE;
13380Sstevel@tonic-gate 			newoffset += (tuple->TupleOffset + 2);
13390Sstevel@tonic-gate 		    }
13400Sstevel@tonic-gate 
13410Sstevel@tonic-gate 		    if (cs_init_cis_window(sp, &newoffset, &cis_handle,
13420Sstevel@tonic-gate 							flags) != CS_SUCCESS) {
13430Sstevel@tonic-gate 			mutex_exit(&sp->cis_lock);
13440Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_get_tuple_data: socket %d "
13450Sstevel@tonic-gate 						"can't init CIS window\n",
13460Sstevel@tonic-gate 							sp->socket_num);
13470Sstevel@tonic-gate 			return (CS_GENERAL_FAILURE);
13480Sstevel@tonic-gate 		    } /* cs_init_cis_window */
13490Sstevel@tonic-gate 		    while (nbytes--) {
13500Sstevel@tonic-gate 			*tdd++ = csx_Get8(cis_handle, newoffset++);
13510Sstevel@tonic-gate 			if (tuple->CISOffset->flags & CISTPLF_AM_SPACE)
13520Sstevel@tonic-gate 			    newoffset++;
13530Sstevel@tonic-gate 		    } /* while */
13540Sstevel@tonic-gate 		    break;
13550Sstevel@tonic-gate 		default:
13560Sstevel@tonic-gate 		    mutex_exit(&sp->cis_lock);
13570Sstevel@tonic-gate 		    return (CS_GENERAL_FAILURE);
13580Sstevel@tonic-gate 	    } /* switch */
13590Sstevel@tonic-gate 
13600Sstevel@tonic-gate 	    ret = CS_SUCCESS;
13610Sstevel@tonic-gate 	} else {
13620Sstevel@tonic-gate 	    ret = CS_NO_CIS;
13630Sstevel@tonic-gate 	} /* if (CW_VALID_CIS) */
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate 	return (ret);
13680Sstevel@tonic-gate }
13690Sstevel@tonic-gate 
13700Sstevel@tonic-gate /*
13710Sstevel@tonic-gate  * cs_validate_cis - validates the CIS on a card in the given socket; this
13720Sstevel@tonic-gate  *			is to support the ValidateCIS function call.
13730Sstevel@tonic-gate  *
13740Sstevel@tonic-gate  *    Notes for regular PC card driver callers:
13750Sstevel@tonic-gate  *
13760Sstevel@tonic-gate  *	Regular PC card drivers calling ValidateCIS will get the meaning of
13770Sstevel@tonic-gate  *	the structure members as specified in the standard.
13780Sstevel@tonic-gate  *
13790Sstevel@tonic-gate  *    Notes for Socket Services, the "super-client" or CSI driver callers:
13800Sstevel@tonic-gate  *
13810Sstevel@tonic-gate  *		with: Function Number = CS_GLOBAL_CIS
13820Sstevel@tonic-gate  *
13830Sstevel@tonic-gate  *	For a single-function card, CS_NO_CIS will be returned and the
13840Sstevel@tonic-gate  *	cisinfo_t->Chains and cisinfo_t->Tuples members will be set to 0.
13850Sstevel@tonic-gate  *
13860Sstevel@tonic-gate  *	For a multi-function card, cisinfo_t->Chains will contain a count of
13870Sstevel@tonic-gate  *	the number of CIS chains in the global portion of the CIS, and
13880Sstevel@tonic-gate  *	cisinfo_t->Tuples will contain a count of the number of tuples in
13890Sstevel@tonic-gate  *	the global portion of the CIS.
13900Sstevel@tonic-gate  *
13910Sstevel@tonic-gate  *		with: 0 <= Function Number < CIS_MAX_FUNCTIONS
13920Sstevel@tonic-gate  *
13930Sstevel@tonic-gate  *	For a single-function card, if the function number is equal to 0 and
13940Sstevel@tonic-gate  *	has a CIS, cisinfo_t->Chains will contain a count of the number of
13950Sstevel@tonic-gate  *	CIS chains in the CIS, and cisinfo_t->Tuples will contain a count of
13960Sstevel@tonic-gate  *	the number of tuples in the CIS. If the card does not have a CIS, or
13970Sstevel@tonic-gate  *	if the function number is not equal to 0, CS_NO_CIS will be returned
13980Sstevel@tonic-gate  *	and the cisinfo_t->Chains and cisinfo_t->Tuples members will be set
13990Sstevel@tonic-gate  *	to 0.
14000Sstevel@tonic-gate  *
14010Sstevel@tonic-gate  *	For a multi-function card, cisinfo_t->Chains will contain a count of
14020Sstevel@tonic-gate  *	the number of CIS chains in the global and function-specific
14030Sstevel@tonic-gate  *	portions of the CIS, and cisinfo_t->Tuples will contain a count of
14040Sstevel@tonic-gate  *	the number of tuples in the global and function-specific portions of
14050Sstevel@tonic-gate  *	the CIS. If the function does not exist or has no CIS, CS_NO_CIS
14060Sstevel@tonic-gate  *	will be returned and the cisinfo_t->Chains and cisinfo_t->Tuples
14070Sstevel@tonic-gate  *	members will be set to 0.
14080Sstevel@tonic-gate  *
14090Sstevel@tonic-gate  *    General notes:
14100Sstevel@tonic-gate  *
14110Sstevel@tonic-gate  *	If the card does not have a CIS, or if the function does not exist
14120Sstevel@tonic-gate  *	or has no CIS, CS_NO_CIS will be returned and the cisinfo_t->Chains
14130Sstevel@tonic-gate  *	and cisinfo_t->Tuples members will be set to 0.
14140Sstevel@tonic-gate  *
14150Sstevel@tonic-gate  *	Most of the work of validating the CIS has already been done by the
14160Sstevel@tonic-gate  *	CIS parser module, so we don't have to do much here except for
14170Sstevel@tonic-gate  *	looking at the various flags and tuple/chain counts that were already
14180Sstevel@tonic-gate  *	setup by the CIS parser.
14190Sstevel@tonic-gate  *
14200Sstevel@tonic-gate  *    See notes for the cs_get_firstnext_tuple function.
14210Sstevel@tonic-gate  */
14220Sstevel@tonic-gate static int
cs_validate_cis(client_handle_t client_handle,cisinfo_t * cisinfo)14230Sstevel@tonic-gate cs_validate_cis(client_handle_t client_handle, cisinfo_t *cisinfo)
14240Sstevel@tonic-gate {
14250Sstevel@tonic-gate 	cs_socket_t *sp;
14260Sstevel@tonic-gate 	client_t *client;
14270Sstevel@tonic-gate 	uint32_t fn;
14280Sstevel@tonic-gate 	int ret;
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate 	if ((ret = cs_get_socket(client_handle, &cisinfo->Socket, &fn,
14310Sstevel@tonic-gate 						&sp, &client)) != CS_SUCCESS)
14320Sstevel@tonic-gate 	    return (ret);
14330Sstevel@tonic-gate 
14340Sstevel@tonic-gate 	/*
14350Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
14360Sstevel@tonic-gate 	 *	for this client, then return an error.
14370Sstevel@tonic-gate 	 */
14380Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED))
14390Sstevel@tonic-gate 	    return (CS_NO_CARD);
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
14420Sstevel@tonic-gate 	if ((sp->cis_flags & CW_VALID_CIS) &&
14430Sstevel@tonic-gate 				(sp->cis[fn].flags & CW_VALID_CIS)) {
14440Sstevel@tonic-gate 	    cisinfo->Chains = sp->cis[fn].nchains;
14450Sstevel@tonic-gate 	    cisinfo->Tuples = sp->cis[fn].ntuples;
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 	    if ((fn != CS_GLOBAL_CIS) &&
14480Sstevel@tonic-gate 			(sp->cis[CS_GLOBAL_CIS].flags & CW_VALID_CIS)) {
14490Sstevel@tonic-gate 		cisinfo->Chains += sp->cis[CS_GLOBAL_CIS].nchains;
14500Sstevel@tonic-gate 		cisinfo->Tuples += sp->cis[CS_GLOBAL_CIS].ntuples;
14510Sstevel@tonic-gate 	    } /* !CS_GLOBAL_CIS */
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate 	    ret = CS_SUCCESS;
14540Sstevel@tonic-gate 	} else {
14550Sstevel@tonic-gate 	    cisinfo->Chains = 0;
14560Sstevel@tonic-gate 	    cisinfo->Tuples = 0;
14570Sstevel@tonic-gate 	    ret = CS_NO_CIS;
14580Sstevel@tonic-gate 	}
14590Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
14600Sstevel@tonic-gate 
14610Sstevel@tonic-gate 	return (ret);
14620Sstevel@tonic-gate }
14630Sstevel@tonic-gate 
14640Sstevel@tonic-gate /*
14650Sstevel@tonic-gate  * cs_init_cis_window - initializes the CIS window for the passed socket
14660Sstevel@tonic-gate  *
14670Sstevel@tonic-gate  *	calling: *sp - pointer to the per-socket structure
14680Sstevel@tonic-gate  *		 *offset - offset from start of AM or CM space
14690Sstevel@tonic-gate  *		 *hp - pointer to acc_handle_t to store modified
14700Sstevel@tonic-gate  *				window access handle in
14710Sstevel@tonic-gate  *		 flags - one of:
14720Sstevel@tonic-gate  *				CISTPLF_AM_SPACE - set window to AM space
14730Sstevel@tonic-gate  *				CISTPLF_CM_SPACE - set window to CM space
14740Sstevel@tonic-gate  *
14750Sstevel@tonic-gate  *	returns: CS_SUCCESS if CIS window was set up
14760Sstevel@tonic-gate  *		 *offset - contains adjusted offset to use to access
14770Sstevel@tonic-gate  *				requested space
14780Sstevel@tonic-gate  *		 CS_BAD_WINDOW if CIS window could not be setup
14790Sstevel@tonic-gate  *		 CS_GENERAL_FAILURE if socket has a CIS window number
14800Sstevel@tonic-gate  *					but the window flags are wrong
14810Sstevel@tonic-gate  *
14820Sstevel@tonic-gate  *	Note: This function will check to be sure that there is a valid
14830Sstevel@tonic-gate  *		CIS window allocated to this socket.
14840Sstevel@tonic-gate  *	      If there is an error in setting up the window hardware, the
14850Sstevel@tonic-gate  *		CIS window information for this socket is cleared.
14860Sstevel@tonic-gate  *	      This function is also used by routines that need to get
14870Sstevel@tonic-gate  *		a pointer to the base of AM space to access the card's
14880Sstevel@tonic-gate  *		configuration registers.
14890Sstevel@tonic-gate  *	      The passed offset is the un-window-size-aligned offset.
14900Sstevel@tonic-gate  */
14910Sstevel@tonic-gate int
cs_init_cis_window(cs_socket_t * sp,uint32_t * offset,acc_handle_t * hp,uint32_t flags)14920Sstevel@tonic-gate cs_init_cis_window(cs_socket_t *sp, uint32_t *offset,
14930Sstevel@tonic-gate     acc_handle_t *hp, uint32_t flags)
14940Sstevel@tonic-gate {
14950Sstevel@tonic-gate 	set_window_t sw;
14960Sstevel@tonic-gate 	get_window_t gw;
14970Sstevel@tonic-gate 	inquire_window_t iw;
14980Sstevel@tonic-gate 	set_page_t set_page;
14990Sstevel@tonic-gate 	cs_window_t *cw;
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 	/*
15020Sstevel@tonic-gate 	 * Check to be sure that we have a valid CIS window
15030Sstevel@tonic-gate 	 */
15040Sstevel@tonic-gate 	if (!SOCKET_HAS_CIS_WINDOW(sp)) {
15050Sstevel@tonic-gate 	    cmn_err(CE_CONT,
15060Sstevel@tonic-gate 			"cs_init_cis_window: socket %d has no CIS window\n",
15070Sstevel@tonic-gate 				sp->socket_num);
15080Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
15090Sstevel@tonic-gate 	}
15100Sstevel@tonic-gate 
15110Sstevel@tonic-gate 	/*
15120Sstevel@tonic-gate 	 * Check to be sure that this window is allocated for CIS use
15130Sstevel@tonic-gate 	 */
15140Sstevel@tonic-gate 	if ((cw = cs_get_wp(sp->cis_win_num)) == NULL)
15150Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate 	if (!(cw->state & CW_CIS)) {
15180Sstevel@tonic-gate 	    cmn_err(CE_CONT,
15190Sstevel@tonic-gate 		"cs_init_cis_window: socket %d invalid CIS window state 0x%x\n",
15200Sstevel@tonic-gate 				sp->socket_num, cw->state);
15210Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
15220Sstevel@tonic-gate 	}
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate 	/*
15250Sstevel@tonic-gate 	 * Get the characteristics of this window - we use this to
15260Sstevel@tonic-gate 	 *	determine whether we need to re-map the window or
15270Sstevel@tonic-gate 	 *	just move the window offset on the card.
15280Sstevel@tonic-gate 	 */
15290Sstevel@tonic-gate 	iw.window = sp->cis_win_num;
15300Sstevel@tonic-gate 	SocketServices(SS_InquireWindow, &iw);
15310Sstevel@tonic-gate 
15320Sstevel@tonic-gate 	/*
15330Sstevel@tonic-gate 	 * We've got a window, now set up the hardware. If we've got
15340Sstevel@tonic-gate 	 *	a variable sized window, then all we need to do is to
15350Sstevel@tonic-gate 	 *	get a valid mapping to the base of the window using
15360Sstevel@tonic-gate 	 *	the current window size; if we've got a fixed-size
15370Sstevel@tonic-gate 	 *	window, then we need to get a mapping to the window
15380Sstevel@tonic-gate 	 *	starting at offset zero of the window.
15390Sstevel@tonic-gate 	 */
15400Sstevel@tonic-gate 	if (iw.mem_win_char.MemWndCaps & WC_SIZE) {
15410Sstevel@tonic-gate 	    sw.WindowSize = sp->cis_win_size;
15420Sstevel@tonic-gate 	    set_page.offset = ((*offset / sp->cis_win_size) *
15430Sstevel@tonic-gate 						sp->cis_win_size);
15440Sstevel@tonic-gate 	} else {
15450Sstevel@tonic-gate 	    set_page.offset = ((*offset / iw.mem_win_char.MinSize) *
15460Sstevel@tonic-gate 						iw.mem_win_char.MinSize);
15470Sstevel@tonic-gate 	    sw.WindowSize = (((*offset & ~(PAGESIZE - 1)) &
15480Sstevel@tonic-gate 					(set_page.offset - 1)) + PAGESIZE);
15490Sstevel@tonic-gate 	}
15500Sstevel@tonic-gate 
15510Sstevel@tonic-gate 	/*
15520Sstevel@tonic-gate 	 * Return a normalized base offset; this takes care of the case
15530Sstevel@tonic-gate 	 *	where the required offset is greater than the window size.
15540Sstevel@tonic-gate 	 * BugID 1236404
15550Sstevel@tonic-gate 	 *	code was:
15560Sstevel@tonic-gate 	 *		*offset = *offset & (set_page.offset - 1);
15570Sstevel@tonic-gate 	 */
15580Sstevel@tonic-gate 	*offset = *offset - set_page.offset;
15590Sstevel@tonic-gate 
15600Sstevel@tonic-gate #ifdef	CS_DEBUG
15610Sstevel@tonic-gate 	if (cs_debug > 1)
15620Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_init_cis_window: WindowSize 0x%x "
15630Sstevel@tonic-gate 							"offset 0x%x\n",
15640Sstevel@tonic-gate 							(int)sw.WindowSize,
15650Sstevel@tonic-gate 							(int)set_page.offset);
15660Sstevel@tonic-gate 	if (cs_debug > 1)
15670Sstevel@tonic-gate 	    cmn_err(CE_CONT, "\t*offset = 0x%x space = %s\n",
15680Sstevel@tonic-gate 							(int)*offset,
15690Sstevel@tonic-gate 					(flags & CISTPLF_AM_SPACE)?
15700Sstevel@tonic-gate 					"CISTPLF_AM_SPACE":"CISTPLF_CM_SPACE");
15710Sstevel@tonic-gate #endif
15720Sstevel@tonic-gate 
15730Sstevel@tonic-gate 	sw.window = sp->cis_win_num;
15740Sstevel@tonic-gate 	sw.socket = sp->socket_num;
15750Sstevel@tonic-gate 	sw.state = (WS_ENABLED | WS_EXACT_MAPIN);
15760Sstevel@tonic-gate 	sw.attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
15770Sstevel@tonic-gate 	sw.attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
15780Sstevel@tonic-gate 	sw.attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
15790Sstevel@tonic-gate 
15800Sstevel@tonic-gate 	/*
15810Sstevel@tonic-gate 	 * The PCMCIA SS spec specifies this be expressed in
15820Sstevel@tonic-gate 	 *	a device speed format per 5.2.7.1.3 but
15830Sstevel@tonic-gate 	 *	our implementation of SS_SetWindow uses
15840Sstevel@tonic-gate 	 *	actual nanoseconds.
15850Sstevel@tonic-gate 	 */
15860Sstevel@tonic-gate 	sw.speed = CIS_DEFAULT_SPEED;
15870Sstevel@tonic-gate 	sw.base = 0;
15880Sstevel@tonic-gate 	/*
15890Sstevel@tonic-gate 	 * Set up the window - if this fails, then just set the
15900Sstevel@tonic-gate 	 *	CIS window number back to it's initialized value so
15910Sstevel@tonic-gate 	 *	that we'll fail when we break out of the loop.
15920Sstevel@tonic-gate 	 */
15930Sstevel@tonic-gate 	if (SocketServices(SS_SetWindow, &sw) != SUCCESS) {
15940Sstevel@tonic-gate 	    sp->cis_win_num = PCMCIA_MAX_WINDOWS;
15950Sstevel@tonic-gate 	    cw->state = 0; /* XXX do we really want to do this? */
15960Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
15970Sstevel@tonic-gate 	} else {
15980Sstevel@tonic-gate 		set_page.window = sp->cis_win_num;
15990Sstevel@tonic-gate 		set_page.page = 0;
16000Sstevel@tonic-gate 		set_page.state = PS_ENABLED;
16010Sstevel@tonic-gate 		if (flags & CISTPLF_AM_SPACE)
16020Sstevel@tonic-gate 		    set_page.state |= PS_ATTRIBUTE;
16030Sstevel@tonic-gate 
16040Sstevel@tonic-gate 		if (SocketServices(SS_SetPage, &set_page) != SUCCESS) {
16050Sstevel@tonic-gate 		    sp->cis_win_num = PCMCIA_MAX_WINDOWS;
16060Sstevel@tonic-gate 		    cw->state = 0; /* XXX do we really want to do this? */
16070Sstevel@tonic-gate 		    return (CS_BAD_WINDOW);
16080Sstevel@tonic-gate 		} /* if (SS_SetPage) */
16090Sstevel@tonic-gate 	} /* if (SS_SetWindow) */
16100Sstevel@tonic-gate 
16110Sstevel@tonic-gate 	/*
16120Sstevel@tonic-gate 	 * Get the window information for the CIS window for this socket.
16130Sstevel@tonic-gate 	 */
16140Sstevel@tonic-gate 	gw.window = sp->cis_win_num;
16150Sstevel@tonic-gate 	gw.socket = sp->socket_num; /* XXX - SS_GetWindow should set this */
16160Sstevel@tonic-gate 	if (SocketServices(SS_GetWindow, &gw) != SUCCESS)
16170Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
16180Sstevel@tonic-gate 
16190Sstevel@tonic-gate 	*hp = (acc_handle_t)gw.handle;
16200Sstevel@tonic-gate 
16210Sstevel@tonic-gate 	return (CS_SUCCESS);
16220Sstevel@tonic-gate }
16230Sstevel@tonic-gate 
16240Sstevel@tonic-gate /*
16250Sstevel@tonic-gate  * ==== client registration/deregistration section ====
16260Sstevel@tonic-gate  */
16270Sstevel@tonic-gate 
16280Sstevel@tonic-gate /*
16290Sstevel@tonic-gate  * cs_register_client - This supports the RegisterClient call.
16300Sstevel@tonic-gate  *
16310Sstevel@tonic-gate  * Upon successful registration, the client_handle_t * handle argument will
16320Sstevel@tonic-gate  *	contain the new client handle and we return CS_SUCCESS.
16330Sstevel@tonic-gate  */
16340Sstevel@tonic-gate static int
cs_register_client(client_handle_t * ch,client_reg_t * cr)16350Sstevel@tonic-gate cs_register_client(client_handle_t *ch, client_reg_t *cr)
16360Sstevel@tonic-gate {
16370Sstevel@tonic-gate 	uint32_t sn;
16380Sstevel@tonic-gate 	int super_client = 0;
16390Sstevel@tonic-gate 	sclient_reg_t *scr = cr->priv;
16400Sstevel@tonic-gate 	struct sclient_list_t *scli;
16410Sstevel@tonic-gate 
16420Sstevel@tonic-gate 	/*
16430Sstevel@tonic-gate 	 * See if we're not supposed to register any new clients.
16440Sstevel@tonic-gate 	 */
16450Sstevel@tonic-gate 	if (cs_globals.init_state & GLOBAL_INIT_STATE_NO_CLIENTS)
16460Sstevel@tonic-gate 	    return (CS_OUT_OF_RESOURCE);
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate 	/*
16490Sstevel@tonic-gate 	 * Do a version check - if the client expects a later version of
16500Sstevel@tonic-gate 	 *	Card Services than what we are, return CS_BAD_VERSION.
16510Sstevel@tonic-gate 	 * XXX - How do we specify just a PARTICULAR version of CS??
16520Sstevel@tonic-gate 	 */
16530Sstevel@tonic-gate 	if (CS_VERSION < cr->Version)
16540Sstevel@tonic-gate 	    return (CS_BAD_VERSION);
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate 	/*
16570Sstevel@tonic-gate 	 * Check to be sure that the client has given us a valid set of
16580Sstevel@tonic-gate 	 *	client type flags.  We also use this opportunity to see
16590Sstevel@tonic-gate 	 *	if the registering client is Socket Services or is a
16600Sstevel@tonic-gate 	 *	"super-client" or a CSI client.
16610Sstevel@tonic-gate 	 *
16620Sstevel@tonic-gate 	 * Note that SS can not set any flag in the Attributes field other
16630Sstevel@tonic-gate 	 *	than the INFO_SOCKET_SERVICES flag.
16640Sstevel@tonic-gate 	 *
16650Sstevel@tonic-gate 	 * Valid combinations of cr->Attributes and cr->EventMask flags:
16660Sstevel@tonic-gate 	 *
16670Sstevel@tonic-gate 	 *  for Socket Services:
16680Sstevel@tonic-gate 	 *	cr->Attributes:
16690Sstevel@tonic-gate 	 *	    set:
16700Sstevel@tonic-gate 	 *		INFO_SOCKET_SERVICES
16710Sstevel@tonic-gate 	 *	    clear:
16720Sstevel@tonic-gate 	 *		{all other flags}
16730Sstevel@tonic-gate 	 *	cr->EventMask:
16740Sstevel@tonic-gate 	 *	    don't care:
16750Sstevel@tonic-gate 	 *		{all flags}
16760Sstevel@tonic-gate 	 *
16770Sstevel@tonic-gate 	 *  for regular clients:
16780Sstevel@tonic-gate 	 *	cr->Attributes:
16790Sstevel@tonic-gate 	 *	    only one of:
16800Sstevel@tonic-gate 	 *		INFO_IO_CLIENT
16810Sstevel@tonic-gate 	 *		INFO_MTD_CLIENT
16820Sstevel@tonic-gate 	 *		INFO_MEM_CLIENT
16830Sstevel@tonic-gate 	 *	    don't care:
16840Sstevel@tonic-gate 	 *		INFO_CARD_SHARE
16850Sstevel@tonic-gate 	 *		INFO_CARD_EXCL
16860Sstevel@tonic-gate 	 *	cr->EventMask:
16870Sstevel@tonic-gate 	 *	    clear:
16880Sstevel@tonic-gate 	 *		CS_EVENT_ALL_CLIENTS
16890Sstevel@tonic-gate 	 *	    don't care:
16900Sstevel@tonic-gate 	 *		{all other flags}
16910Sstevel@tonic-gate 	 *
16920Sstevel@tonic-gate 	 *  for CSI clients:
16930Sstevel@tonic-gate 	 *	cr->Attributes:
16940Sstevel@tonic-gate 	 *	    set:
16950Sstevel@tonic-gate 	 *		INFO_IO_CLIENT
16960Sstevel@tonic-gate 	 *		INFO_CSI_CLIENT
16970Sstevel@tonic-gate 	 *	    clear:
16980Sstevel@tonic-gate 	 *		INFO_MTD_CLIENT
16990Sstevel@tonic-gate 	 *		INFO_MEM_CLIENT
17000Sstevel@tonic-gate 	 *	    don't care:
17010Sstevel@tonic-gate 	 *		INFO_CARD_SHARE
17020Sstevel@tonic-gate 	 *		INFO_CARD_EXCL
17030Sstevel@tonic-gate 	 *	cr->EventMask:
17040Sstevel@tonic-gate 	 *	    don't care:
17050Sstevel@tonic-gate 	 *		{all flags}
17060Sstevel@tonic-gate 	 *
17070Sstevel@tonic-gate 	 *  for "super-clients":
17080Sstevel@tonic-gate 	 *	cr->Attributes:
17090Sstevel@tonic-gate 	 *	    set:
17100Sstevel@tonic-gate 	 *		INFO_IO_CLIENT
17110Sstevel@tonic-gate 	 *		INFO_MTD_CLIENT
17120Sstevel@tonic-gate 	 *		INFO_SOCKET_SERVICES
17130Sstevel@tonic-gate 	 *		INFO_CARD_SHARE
17140Sstevel@tonic-gate 	 *	    clear:
17150Sstevel@tonic-gate 	 *		INFO_MEM_CLIENT
17160Sstevel@tonic-gate 	 *		INFO_CARD_EXCL
17170Sstevel@tonic-gate 	 *	cr->EventMask:
17180Sstevel@tonic-gate 	 *	    don't care:
17190Sstevel@tonic-gate 	 *		{all flags}
17200Sstevel@tonic-gate 	 */
17210Sstevel@tonic-gate 	switch (cr->Attributes & INFO_CLIENT_TYPE_MASK) {
17220Sstevel@tonic-gate 	/*
17230Sstevel@tonic-gate 	 * Check first to see if this is Socket Services registering; if
17240Sstevel@tonic-gate 	 *	so, we don't do anything but return the client handle that is
17250Sstevel@tonic-gate 	 *	in the global SS client.
17260Sstevel@tonic-gate 	 */
17270Sstevel@tonic-gate 	    case INFO_SOCKET_SERVICES:
17280Sstevel@tonic-gate 		*ch = cs_socket_services_client.client_handle;
17290Sstevel@tonic-gate 		return (CS_SUCCESS);
17300Sstevel@tonic-gate 		/* NOTREACHED */
17310Sstevel@tonic-gate 	    /* CSI clients */
17320Sstevel@tonic-gate 	    case (INFO_CSI_CLIENT | INFO_IO_CLIENT):
17330Sstevel@tonic-gate 		break;
17340Sstevel@tonic-gate 	    /* regular clients */
17350Sstevel@tonic-gate 	    case INFO_IO_CLIENT:
17360Sstevel@tonic-gate 	    case INFO_MTD_CLIENT:
17370Sstevel@tonic-gate 	    case INFO_MEM_CLIENT:
17380Sstevel@tonic-gate 		if (cr->EventMask & CS_EVENT_ALL_CLIENTS)
17390Sstevel@tonic-gate 		    return (CS_BAD_ATTRIBUTE);
17400Sstevel@tonic-gate 		break;
17410Sstevel@tonic-gate 	    /* "super-client" clients */
17420Sstevel@tonic-gate 	    case (INFO_IO_CLIENT | INFO_MTD_CLIENT | INFO_SOCKET_SERVICES):
17430Sstevel@tonic-gate 		if ((!(cr->Attributes & INFO_CARD_SHARE)) ||
17440Sstevel@tonic-gate 				(cr->Attributes & INFO_CARD_EXCL))
17450Sstevel@tonic-gate 		    return (CS_BAD_ATTRIBUTE);
17460Sstevel@tonic-gate 		/*
17470Sstevel@tonic-gate 		 * We only allow one "super-client" per system.
17480Sstevel@tonic-gate 		 */
17490Sstevel@tonic-gate 		mutex_enter(&cs_globals.global_lock);
17500Sstevel@tonic-gate 		if (cs_globals.flags & GLOBAL_SUPER_CLIENT_REGISTERED) {
17510Sstevel@tonic-gate 		    mutex_exit(&cs_globals.global_lock);
17520Sstevel@tonic-gate 		    return (CS_NO_MORE_ITEMS);
17530Sstevel@tonic-gate 		}
17540Sstevel@tonic-gate 		cs_globals.flags |= GLOBAL_SUPER_CLIENT_REGISTERED;
17550Sstevel@tonic-gate 		mutex_exit(&cs_globals.global_lock);
17560Sstevel@tonic-gate 		super_client = CLIENT_SUPER_CLIENT;
17570Sstevel@tonic-gate 		break;
17580Sstevel@tonic-gate 	    default:
17590Sstevel@tonic-gate 		return (CS_BAD_ATTRIBUTE);
17600Sstevel@tonic-gate 	} /* switch (cr->Attributes) */
17610Sstevel@tonic-gate 
17620Sstevel@tonic-gate 	/*
17630Sstevel@tonic-gate 	 * Now, actually create the client node on the socket; this will
17640Sstevel@tonic-gate 	 *	also return the new client handle if there were no errors
17650Sstevel@tonic-gate 	 *	creating the client node.
17660Sstevel@tonic-gate 	 * The DIP2SOCKET_NUM macro will return the socket and function
17670Sstevel@tonic-gate 	 *	number using the encoding specified in the cs_priv.h file.
17680Sstevel@tonic-gate 	 */
17690Sstevel@tonic-gate 	if (super_client != CLIENT_SUPER_CLIENT) {
17700Sstevel@tonic-gate 	    if (cr->Attributes & INFO_CSI_CLIENT)
17710Sstevel@tonic-gate 		sn = (uint32_t)(uintptr_t)cr->priv;
17720Sstevel@tonic-gate 	    else
17730Sstevel@tonic-gate 		sn = DIP2SOCKET_NUM(cr->dip);
17740Sstevel@tonic-gate 	    return (cs_add_client_to_socket(sn, ch, cr, super_client));
17750Sstevel@tonic-gate 	} /* CLIENT_SUPER_CLIENT */
17760Sstevel@tonic-gate 
17770Sstevel@tonic-gate 	/*
17780Sstevel@tonic-gate 	 * This registering client is a "super-client", so we create one
17790Sstevel@tonic-gate 	 *	client node for each socket in the system.  We use the
17800Sstevel@tonic-gate 	 *	client_reg_t.priv structure member to point to a struct
17810Sstevel@tonic-gate 	 *	that the "super-client" client knows about.  The client
17820Sstevel@tonic-gate 	 *	handle pointer is not used in this case.
17830Sstevel@tonic-gate 	 * We return CS_SUCCESS if at least one client node could be
17840Sstevel@tonic-gate 	 *	created.  The client must check the error codes in the
17850Sstevel@tonic-gate 	 *	error code array to determine which clients could not
17860Sstevel@tonic-gate 	 *	be created on which sockets.
17870Sstevel@tonic-gate 	 * We return CS_BAD_HANDLE if no client nodes could be created.
17880Sstevel@tonic-gate 	 */
17890Sstevel@tonic-gate 	scr->num_clients = 0;
17900Sstevel@tonic-gate 	scr->max_socket_num = cs_globals.max_socket_num;
17910Sstevel@tonic-gate 	scr->num_sockets = cs_globals.num_sockets;
17920Sstevel@tonic-gate 	scr->num_windows = cs_globals.num_windows;
17930Sstevel@tonic-gate 
17940Sstevel@tonic-gate 	*(scr->sclient_list) = cs_globals.sclient_list;
17950Sstevel@tonic-gate 
17960Sstevel@tonic-gate 	for (sn = 0; sn < scr->num_sockets; sn++) {
17970Sstevel@tonic-gate 	    scli = scr->sclient_list[sn];
17980Sstevel@tonic-gate 	    if ((scli->error = cs_add_client_to_socket(sn, &scli->client_handle,
17990Sstevel@tonic-gate 					    cr, super_client)) == CS_SUCCESS) {
18000Sstevel@tonic-gate 		scr->num_clients++;
18010Sstevel@tonic-gate 	    }
18020Sstevel@tonic-gate 	}
18030Sstevel@tonic-gate 
18040Sstevel@tonic-gate 	/*
18050Sstevel@tonic-gate 	 * If we couldn't create any client nodes at all, then
18060Sstevel@tonic-gate 	 *	return an error.
18070Sstevel@tonic-gate 	 */
18080Sstevel@tonic-gate 	if (!scr->num_clients) {
18090Sstevel@tonic-gate 	/*
18100Sstevel@tonic-gate 	 * XXX - The global superclient lock now gets
18110Sstevel@tonic-gate 	 * cleared in cs_deregister_client
18120Sstevel@tonic-gate 	 */
18130Sstevel@tonic-gate 	    /* cs_clear_superclient_lock(super_client); */
18140Sstevel@tonic-gate 	    return (CS_BAD_HANDLE);
18150Sstevel@tonic-gate 	}
18160Sstevel@tonic-gate 
18170Sstevel@tonic-gate 	return (CS_SUCCESS);
18180Sstevel@tonic-gate }
18190Sstevel@tonic-gate 
18200Sstevel@tonic-gate /*
18210Sstevel@tonic-gate  * cs_add_client_to_socket - this function creates the client node on the
18220Sstevel@tonic-gate  *				requested socket.
18230Sstevel@tonic-gate  *
18240Sstevel@tonic-gate  * Note that if we return an error, there is no state that can be cleaned
18250Sstevel@tonic-gate  *	up.  The only way that we can return an error with allocated resources
18260Sstevel@tonic-gate  *	would be if one of the client handle functions had an internal error.
18270Sstevel@tonic-gate  *	Since we wouldn't get a valid client handle in this case anyway, there
18280Sstevel@tonic-gate  *	would be no way to find out what was allocated and what wasn't.
18290Sstevel@tonic-gate  */
18300Sstevel@tonic-gate static int
cs_add_client_to_socket(unsigned sn,client_handle_t * ch,client_reg_t * cr,int super_client)18310Sstevel@tonic-gate cs_add_client_to_socket(unsigned sn, client_handle_t *ch,
18320Sstevel@tonic-gate 					client_reg_t *cr, int super_client)
18330Sstevel@tonic-gate {
18340Sstevel@tonic-gate 	cs_socket_t *sp;
18350Sstevel@tonic-gate 	client_t *client, *cclp;
18360Sstevel@tonic-gate 	int error, cie = 1;
18370Sstevel@tonic-gate 	int client_lock_acquired;
18380Sstevel@tonic-gate 
18390Sstevel@tonic-gate 	if (cr->event_handler == NULL)
18400Sstevel@tonic-gate 	    return (CS_BAD_ARGS);
18410Sstevel@tonic-gate 
18420Sstevel@tonic-gate 	if ((sp = cs_get_sp(sn)) == NULL)
18430Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
18440Sstevel@tonic-gate 
18450Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
18460Sstevel@tonic-gate 
18470Sstevel@tonic-gate 	/*
18480Sstevel@tonic-gate 	 * Run through all of the registered clients and compare the passed
18490Sstevel@tonic-gate 	 *	dip to the dip of each client to make sure that this client
18500Sstevel@tonic-gate 	 *	is not trying to register more than once.  If they are, then
18510Sstevel@tonic-gate 	 *	display a message and return an error.
18520Sstevel@tonic-gate 	 * XXX - we should really check all the sockets in case the client
18530Sstevel@tonic-gate 	 *	manipulates the instance number in the dip.
18540Sstevel@tonic-gate 	 * XXX - if we check each socket, we ned to also check for the
18550Sstevel@tonic-gate 	 *	"super-client" since it will use the same dip for all
18560Sstevel@tonic-gate 	 *	of it's client nodes.
18570Sstevel@tonic-gate 	 */
18580Sstevel@tonic-gate 	mutex_enter(&sp->lock);
18590Sstevel@tonic-gate 	client = sp->client_list;
18600Sstevel@tonic-gate 	while (client) {
18610Sstevel@tonic-gate 	    if (!(cr->Attributes & INFO_CSI_CLIENT) &&
18620Sstevel@tonic-gate 						(client->dip == cr->dip)) {
18630Sstevel@tonic-gate 		mutex_exit(&sp->lock);
18640Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
18650Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_add_client_to_socket: socket %d "
18660Sstevel@tonic-gate 					"function 0x%x\n"
18670Sstevel@tonic-gate 					"\tclient already registered with "
18680Sstevel@tonic-gate 					"handle 0x%x\n",
18690Sstevel@tonic-gate 						(int)CS_GET_SOCKET_NUMBER(sn),
18700Sstevel@tonic-gate 						(int)CS_GET_FUNCTION_NUMBER(sn),
18710Sstevel@tonic-gate 						(int)client->client_handle);
18720Sstevel@tonic-gate 		return (CS_BAD_HANDLE);
18730Sstevel@tonic-gate 	    }
18740Sstevel@tonic-gate 	    client = client->next;
18750Sstevel@tonic-gate 	} /* while (client) */
18760Sstevel@tonic-gate 	mutex_exit(&sp->lock);
18770Sstevel@tonic-gate 
18780Sstevel@tonic-gate 	/*
18790Sstevel@tonic-gate 	 * Create a unique client handle then make sure that we can find it.
18800Sstevel@tonic-gate 	 *	This has the side effect of getting us a pointer to the
18810Sstevel@tonic-gate 	 *	client structure as well.
18820Sstevel@tonic-gate 	 * Create a client list entry - cs_create_client_handle will use this
18830Sstevel@tonic-gate 	 *	as the new client node.
18840Sstevel@tonic-gate 	 * We do it here so that we can grab the sp->lock mutex for the
18850Sstevel@tonic-gate 	 *	duration of our manipulation of the client list.
18860Sstevel@tonic-gate 	 * If this function fails, then it will not have added the newly
18870Sstevel@tonic-gate 	 *	allocated client node to the client list on this socket,
18880Sstevel@tonic-gate 	 *	so we have to free the node that we allocated.
18890Sstevel@tonic-gate 	 */
18900Sstevel@tonic-gate 	cclp = (client_t *)kmem_zalloc(sizeof (client_t), KM_SLEEP);
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 	mutex_enter(&sp->lock);
18930Sstevel@tonic-gate 	if (!(*ch = cs_create_client_handle(sn, cclp))) {
18940Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
18950Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
18960Sstevel@tonic-gate 	    kmem_free(cclp, sizeof (client_t));
18970Sstevel@tonic-gate 	    return (CS_OUT_OF_RESOURCE);
18980Sstevel@tonic-gate 	}
18990Sstevel@tonic-gate 
19000Sstevel@tonic-gate 	/*
19010Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.  We should never
19020Sstevel@tonic-gate 	 *	fail this since we just got a valid client handle.
19030Sstevel@tonic-gate 	 * If this fails, then we have an internal error so don't bother
19040Sstevel@tonic-gate 	 *	trying to clean up the allocated client handle since the
19050Sstevel@tonic-gate 	 *	whole system is probably hosed anyway and will shortly
19060Sstevel@tonic-gate 	 *	esplode.
19070Sstevel@tonic-gate 	 * It doesn't make sense to call cs_deregister_client at this point
19080Sstevel@tonic-gate 	 *	to clean up this broken client since the deregistration
19090Sstevel@tonic-gate 	 *	code will also call cs_find_client and most likely fail.
19100Sstevel@tonic-gate 	 */
19110Sstevel@tonic-gate 	if (!(client = cs_find_client(*ch, &error))) {
19120Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
19130Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
19140Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_add_client_to_socket: socket %d function 0x%x "
19150Sstevel@tonic-gate 				"invalid client handle created handle 0x%x\n",
19160Sstevel@tonic-gate 						(int)CS_GET_SOCKET_NUMBER(sn),
19170Sstevel@tonic-gate 						(int)CS_GET_FUNCTION_NUMBER(sn),
19180Sstevel@tonic-gate 						(int)*ch);
19190Sstevel@tonic-gate 	    return (error);
19200Sstevel@tonic-gate 	}
19210Sstevel@tonic-gate 
19220Sstevel@tonic-gate 	/*
19230Sstevel@tonic-gate 	 * Save the DDI information.
19240Sstevel@tonic-gate 	 */
19250Sstevel@tonic-gate 	client->dip = cr->dip;
19260Sstevel@tonic-gate 	cr->driver_name[MODMAXNAMELEN - 1] = NULL;
19270Sstevel@tonic-gate 	client->driver_name = (char *)kmem_zalloc(strlen(cr->driver_name) + 1,
19280Sstevel@tonic-gate 								KM_SLEEP);
19290Sstevel@tonic-gate 	(void) strcpy(client->driver_name, cr->driver_name);
19300Sstevel@tonic-gate 	client->instance = ddi_get_instance(cr->dip);
19310Sstevel@tonic-gate 
19320Sstevel@tonic-gate 	/*
19330Sstevel@tonic-gate 	 * Copy over the interesting items that the client gave us.
19340Sstevel@tonic-gate 	 */
19350Sstevel@tonic-gate 	client->flags = (cr->Attributes & INFO_CLIENT_TYPE_MASK);
19360Sstevel@tonic-gate 	client->event_callback_handler = cr->event_handler;
19370Sstevel@tonic-gate 	bcopy((caddr_t)&cr->event_callback_args,
19380Sstevel@tonic-gate 				(caddr_t)&client->event_callback_args,
19390Sstevel@tonic-gate 				sizeof (event_callback_args_t));
19400Sstevel@tonic-gate 	/*
19410Sstevel@tonic-gate 	 * Set the client handle since the client needs a client handle
19420Sstevel@tonic-gate 	 *	when they call us for their event handler.
19430Sstevel@tonic-gate 	 */
19440Sstevel@tonic-gate 	client->event_callback_args.client_handle = *ch;
19450Sstevel@tonic-gate 
19460Sstevel@tonic-gate 	/*
19470Sstevel@tonic-gate 	 * Initialize the IO window numbers; if an IO window number is equal
19480Sstevel@tonic-gate 	 *	to PCMCIA_MAX_WINDOWS it means that IO range is not in use.
19490Sstevel@tonic-gate 	 */
19500Sstevel@tonic-gate 	client->io_alloc.Window1 = PCMCIA_MAX_WINDOWS;
19510Sstevel@tonic-gate 	client->io_alloc.Window2 = PCMCIA_MAX_WINDOWS;
19520Sstevel@tonic-gate 
19530Sstevel@tonic-gate 	/*
19540Sstevel@tonic-gate 	 * Give the client the iblock and idevice cookies to use in
19550Sstevel@tonic-gate 	 *	the client's event handler high priority mutex.
19560Sstevel@tonic-gate 	 */
19570Sstevel@tonic-gate 	cr->iblk_cookie = sp->iblk;
19580Sstevel@tonic-gate 	cr->idev_cookie = sp->idev;
19590Sstevel@tonic-gate 
19600Sstevel@tonic-gate 	/*
19610Sstevel@tonic-gate 	 * Set up the global event mask information; we copy this directly
19620Sstevel@tonic-gate 	 *	from the client; since we are the only source of events,
19630Sstevel@tonic-gate 	 *	any bogus bits that the client puts in here won't matter
19640Sstevel@tonic-gate 	 *	because we'll never look at them.
19650Sstevel@tonic-gate 	 */
19660Sstevel@tonic-gate 	client->global_mask = cr->EventMask;
19670Sstevel@tonic-gate 
19680Sstevel@tonic-gate 	/*
19690Sstevel@tonic-gate 	 * If this client registered as a CSI client, set the appropriate
19700Sstevel@tonic-gate 	 *	flag in the client's flags area.
19710Sstevel@tonic-gate 	 */
19720Sstevel@tonic-gate 	if (cr->Attributes & INFO_CSI_CLIENT)
19730Sstevel@tonic-gate 	    client->flags |= CLIENT_CSI_CLIENT;
19740Sstevel@tonic-gate 
19750Sstevel@tonic-gate 	/*
19760Sstevel@tonic-gate 	 * If this client registered as a "super-client" set the appropriate
19770Sstevel@tonic-gate 	 *	flag in the client's flags area.
19780Sstevel@tonic-gate 	 */
19790Sstevel@tonic-gate 	if (super_client == CLIENT_SUPER_CLIENT)
19800Sstevel@tonic-gate 	    client->flags |= CLIENT_SUPER_CLIENT;
19810Sstevel@tonic-gate 
19820Sstevel@tonic-gate 	/*
19830Sstevel@tonic-gate 	 * Save other misc information that this client gave us - it is
19840Sstevel@tonic-gate 	 *	used in the GetClientInfo function.
19850Sstevel@tonic-gate 	 */
19860Sstevel@tonic-gate 	client->flags |= (cr->Attributes & INFO_CARD_FLAGS_MASK);
19870Sstevel@tonic-gate 
19880Sstevel@tonic-gate 	/*
19890Sstevel@tonic-gate 	 * Determine if we should give artificial card insertion events and
19900Sstevel@tonic-gate 	 *	a registration complete event. Since we don't differentiate
19910Sstevel@tonic-gate 	 *	between sharable and exclusive use cards when giving clients
19920Sstevel@tonic-gate 	 *	event notification, we modify the definition of the share/excl
19930Sstevel@tonic-gate 	 *	flags as follows:
19940Sstevel@tonic-gate 	 *
19950Sstevel@tonic-gate 	 *	    If either INFO_CARD_SHARE or INFO_CARD_EXCL is set,
19960Sstevel@tonic-gate 	 *	    the client will receive artificial card insertion
19970Sstevel@tonic-gate 	 *	    events (if the client's card is currently in the
19980Sstevel@tonic-gate 	 *	    socket) and a registration complete event.
19990Sstevel@tonic-gate 	 *
20000Sstevel@tonic-gate 	 *	    If neither of the INFO_CARD_SHARE or INFO_CARD_EXCL is
20010Sstevel@tonic-gate 	 *	    set, the client will not receive an artificial card
20020Sstevel@tonic-gate 	 *	    insertion event nor a registration complete event
20030Sstevel@tonic-gate 	 *	    due to the client's call to register client.
20040Sstevel@tonic-gate 	 *
20050Sstevel@tonic-gate 	 *	    The client's event mask is not affected by the setting
20060Sstevel@tonic-gate 	 *	    of these two bits.
20070Sstevel@tonic-gate 	 */
20080Sstevel@tonic-gate 	if (cr->Attributes & (INFO_CARD_SHARE | INFO_CARD_EXCL))
20090Sstevel@tonic-gate 	    client->pending_events = CS_EVENT_REGISTRATION_COMPLETE;
20100Sstevel@tonic-gate 
20110Sstevel@tonic-gate 	/*
20120Sstevel@tonic-gate 	 * Check to see if the card for this client is currently in
20130Sstevel@tonic-gate 	 *	the socket. If it is, then set CLIENT_CARD_INSERTED
20140Sstevel@tonic-gate 	 *	since clients that are calling GetStatus at attach
20150Sstevel@tonic-gate 	 *	time will typically check to see if their card is
20160Sstevel@tonic-gate 	 *	currently installed.
20170Sstevel@tonic-gate 	 * If this is the CSI client, we also need to check to see
20180Sstevel@tonic-gate 	 *	if there is any card inserted in the socket, since
20190Sstevel@tonic-gate 	 *	the cs_card_for_client function will always return
20200Sstevel@tonic-gate 	 *	TRUE for a CSI client.
20210Sstevel@tonic-gate 	 * XXX What about super-clients?
20220Sstevel@tonic-gate 	 */
20230Sstevel@tonic-gate 	if (client->flags & CLIENT_CSI_CLIENT) {
20240Sstevel@tonic-gate 	    get_ss_status_t get_ss_status;
20250Sstevel@tonic-gate 
20260Sstevel@tonic-gate 	    get_ss_status.socket = sp->socket_num;
20270Sstevel@tonic-gate 
20280Sstevel@tonic-gate 	    if (SocketServices(SS_GetStatus, &get_ss_status) != SUCCESS) {
20290Sstevel@tonic-gate 		mutex_exit(&sp->lock);
20300Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
20310Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
20320Sstevel@tonic-gate 	    } /* SS_GetStatus */
20330Sstevel@tonic-gate 
20340Sstevel@tonic-gate 	    if (!(cs_sbm2cse(get_ss_status.CardState) &
20350Sstevel@tonic-gate 			CS_EVENT_CARD_INSERTION))
20360Sstevel@tonic-gate 		cie = 0;
20370Sstevel@tonic-gate 
20380Sstevel@tonic-gate 	} /* CLIENT_CSI_CLIENT */
20390Sstevel@tonic-gate 
20400Sstevel@tonic-gate 	if (cs_card_for_client(client) && (cie != 0)) {
20410Sstevel@tonic-gate 	    client->pending_events |= CS_EVENT_CARD_INSERTION;
20420Sstevel@tonic-gate 	    client->flags |= CLIENT_CARD_INSERTED;
20430Sstevel@tonic-gate 	} /* cs_card_for_client */
20440Sstevel@tonic-gate 
20450Sstevel@tonic-gate 	sp->num_clients++;
20460Sstevel@tonic-gate 	mutex_exit(&sp->lock);
20470Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
20480Sstevel@tonic-gate 
20490Sstevel@tonic-gate 	return (CS_SUCCESS);
20500Sstevel@tonic-gate }
20510Sstevel@tonic-gate 
20520Sstevel@tonic-gate /*
20530Sstevel@tonic-gate  * cs_deregister_client - This supports the DeregisterClient call.
20540Sstevel@tonic-gate  */
20550Sstevel@tonic-gate static int
cs_deregister_client(client_handle_t client_handle)20560Sstevel@tonic-gate cs_deregister_client(client_handle_t client_handle)
20570Sstevel@tonic-gate {
20580Sstevel@tonic-gate 	cs_socket_t *sp;
20590Sstevel@tonic-gate 	client_t *client;
20600Sstevel@tonic-gate 	int error, super_client = 0;
20610Sstevel@tonic-gate 	int client_lock_acquired;
20620Sstevel@tonic-gate 
20630Sstevel@tonic-gate 	/*
20640Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
20650Sstevel@tonic-gate 	 *	is, we don't do anything except for return success.
20660Sstevel@tonic-gate 	 */
20670Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
20680Sstevel@tonic-gate 	    return (CS_SUCCESS);
20690Sstevel@tonic-gate 
20700Sstevel@tonic-gate 	/*
20710Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
20720Sstevel@tonic-gate 	 */
20730Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
20740Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
20750Sstevel@tonic-gate 
20760Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
20770Sstevel@tonic-gate 
20780Sstevel@tonic-gate 	/*
20790Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
20800Sstevel@tonic-gate 	 */
20810Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
20820Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
20830Sstevel@tonic-gate 	    return (error);
20840Sstevel@tonic-gate 	}
20850Sstevel@tonic-gate 
20860Sstevel@tonic-gate 	/*
20870Sstevel@tonic-gate 	 * Make sure that any resources allocated by this client are
20880Sstevel@tonic-gate 	 *	not still allocated, and that if this is an MTD that
20890Sstevel@tonic-gate 	 *	no MTD operations are still in progress.
20900Sstevel@tonic-gate 	 */
20910Sstevel@tonic-gate 	if (client->flags &    (CLIENT_IO_ALLOCATED	|
20920Sstevel@tonic-gate 				CLIENT_IRQ_ALLOCATED	|
20930Sstevel@tonic-gate 				CLIENT_WIN_ALLOCATED	|
20940Sstevel@tonic-gate 				REQ_CONFIGURATION_DONE	|
20950Sstevel@tonic-gate 				REQ_SOCKET_MASK_DONE	|
20960Sstevel@tonic-gate 				REQ_IO_DONE		|
20970Sstevel@tonic-gate 				REQ_IRQ_DONE)) {
20980Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
20990Sstevel@tonic-gate 	    return (CS_BUSY);
21000Sstevel@tonic-gate 	}
21010Sstevel@tonic-gate 
21020Sstevel@tonic-gate 	if (client->flags & CLIENT_MTD_IN_PROGRESS) {
21030Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
21040Sstevel@tonic-gate 	    return (CS_IN_USE);
21050Sstevel@tonic-gate 	}
21060Sstevel@tonic-gate 
21070Sstevel@tonic-gate 	/*
21080Sstevel@tonic-gate 	 * Any previously allocated resources are not allocated anymore, and
21090Sstevel@tonic-gate 	 *	no MTD operations are in progress, so if this is an MTD client
21100Sstevel@tonic-gate 	 *	then do any MTD-specific client deregistration, and then
21110Sstevel@tonic-gate 	 *	nuke this client.
21120Sstevel@tonic-gate 	 * We expect cs_deregister_mtd to never fail.
21130Sstevel@tonic-gate 	 */
21140Sstevel@tonic-gate 	if (client->flags & INFO_MTD_CLIENT)
21150Sstevel@tonic-gate 	    (void) cs_deregister_mtd(client_handle);
21160Sstevel@tonic-gate 
21170Sstevel@tonic-gate 	if (client->flags & CLIENT_SUPER_CLIENT)
21180Sstevel@tonic-gate 	    super_client = CLIENT_SUPER_CLIENT;
21190Sstevel@tonic-gate 
21200Sstevel@tonic-gate 	kmem_free(client->driver_name, strlen(client->driver_name) + 1);
21210Sstevel@tonic-gate 
21220Sstevel@tonic-gate 	error = cs_destroy_client_handle(client_handle);
21230Sstevel@tonic-gate 
21240Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
21250Sstevel@tonic-gate 
21260Sstevel@tonic-gate 	/*
21270Sstevel@tonic-gate 	 * If this was the "super-client" deregistering, then this
21280Sstevel@tonic-gate 	 *	will clear the global "super-client" lock.
21290Sstevel@tonic-gate 	 * XXX - move this outside the per-socket code.
21300Sstevel@tonic-gate 	 */
21310Sstevel@tonic-gate 	cs_clear_superclient_lock(super_client);
21320Sstevel@tonic-gate 
21330Sstevel@tonic-gate 	return (error);
21340Sstevel@tonic-gate }
21350Sstevel@tonic-gate 
21360Sstevel@tonic-gate /*
21370Sstevel@tonic-gate  * cs_create_next_client_minor - returns the next available client minor
21380Sstevel@tonic-gate  *					number or 0 if none available
21390Sstevel@tonic-gate  *
21400Sstevel@tonic-gate  * Note that cs_find_client will always return a valid pointer to the
21410Sstevel@tonic-gate  *	global Socket Services client which has a client minor number
21420Sstevel@tonic-gate  *	of 0; this means that this function can never return a 0 as the
21430Sstevel@tonic-gate  *	next valid available client minor number.
21440Sstevel@tonic-gate  */
21450Sstevel@tonic-gate unsigned
cs_create_next_client_minor(unsigned socket_num,unsigned next_minor)21460Sstevel@tonic-gate cs_create_next_client_minor(unsigned socket_num, unsigned next_minor)
21470Sstevel@tonic-gate {
21480Sstevel@tonic-gate 	unsigned max_client_handles = cs_max_client_handles;
21490Sstevel@tonic-gate 
21500Sstevel@tonic-gate 	do {
21510Sstevel@tonic-gate 	    next_minor &= CS_MAX_CLIENTS_MASK;
21520Sstevel@tonic-gate 	    if (!cs_find_client(MAKE_CLIENT_HANDLE(
21530Sstevel@tonic-gate 					CS_GET_SOCKET_NUMBER(socket_num),
21540Sstevel@tonic-gate 					CS_GET_FUNCTION_NUMBER(socket_num),
21550Sstevel@tonic-gate 							next_minor), NULL)) {
21560Sstevel@tonic-gate 		return (next_minor);
21570Sstevel@tonic-gate 	    }
21580Sstevel@tonic-gate 	    next_minor++;
21590Sstevel@tonic-gate 	} while (max_client_handles--);
21600Sstevel@tonic-gate 
21610Sstevel@tonic-gate 	return (0);
21620Sstevel@tonic-gate }
21630Sstevel@tonic-gate 
21640Sstevel@tonic-gate /*
21650Sstevel@tonic-gate  * cs_find_client - finds the client pointer associated with the client handle
21660Sstevel@tonic-gate  *			or NULL if client not found
21670Sstevel@tonic-gate  *
21680Sstevel@tonic-gate  * returns:	(client_t *)NULL - if client not found or an error occured
21690Sstevel@tonic-gate  *					If the error argument is not NULL,
21700Sstevel@tonic-gate  *					it is set to:
21710Sstevel@tonic-gate  *			CS_BAD_SOCKET - socket number in client_handle_t is
21720Sstevel@tonic-gate  *						invalid
21730Sstevel@tonic-gate  *			CS_BAD_HANDLE - client not found
21740Sstevel@tonic-gate  *			If no error, the error argument is not modified.
21750Sstevel@tonic-gate  *		(client_t *) - pointer to client_t structure
21760Sstevel@tonic-gate  *
21770Sstevel@tonic-gate  * Note that each socket always has a pseudo client with a client minor number
21780Sstevel@tonic-gate  *	of 0; this client minor number is used for Socket Services access to
21790Sstevel@tonic-gate  *	Card Services functions. The client pointer returned for client minor
21800Sstevel@tonic-gate  *	number 0 is the global Socket Services client pointer.
21810Sstevel@tonic-gate  */
21820Sstevel@tonic-gate static client_t *
cs_find_client(client_handle_t client_handle,int * error)21830Sstevel@tonic-gate cs_find_client(client_handle_t client_handle, int *error)
21840Sstevel@tonic-gate {
21850Sstevel@tonic-gate 	cs_socket_t *sp;
21860Sstevel@tonic-gate 	client_t *clp;
21870Sstevel@tonic-gate 
21880Sstevel@tonic-gate 	/*
21890Sstevel@tonic-gate 	 * If we are being asked to see if a client with a minor number
21900Sstevel@tonic-gate 	 *	of 0 exists, always return a pointer to the global Socket
21910Sstevel@tonic-gate 	 *	Services client, since this client always exists, and is
21920Sstevel@tonic-gate 	 *	only for use by Socket Services.  There is no socket
21930Sstevel@tonic-gate 	 *	associated with this special client handle.
21940Sstevel@tonic-gate 	 */
21950Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
21960Sstevel@tonic-gate 	    return (&cs_socket_services_client);
21970Sstevel@tonic-gate 
21980Sstevel@tonic-gate 	/*
21990Sstevel@tonic-gate 	 * Check to be sure that the socket number is in range
22000Sstevel@tonic-gate 	 */
22010Sstevel@tonic-gate 	if (!(CHECK_SOCKET_NUM(GET_CLIENT_SOCKET(client_handle),
22020Sstevel@tonic-gate 					cs_globals.max_socket_num))) {
22030Sstevel@tonic-gate 	    if (error)
22040Sstevel@tonic-gate 		*error = CS_BAD_SOCKET;
22050Sstevel@tonic-gate 	    return (NULL);
22060Sstevel@tonic-gate 	}
22070Sstevel@tonic-gate 
22080Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) {
22090Sstevel@tonic-gate 	    if (error)
22100Sstevel@tonic-gate 		*error = CS_BAD_SOCKET;
22110Sstevel@tonic-gate 	    return (NULL);
22120Sstevel@tonic-gate 	}
22130Sstevel@tonic-gate 
22140Sstevel@tonic-gate 	clp = sp->client_list;
22150Sstevel@tonic-gate 
22160Sstevel@tonic-gate 	while (clp) {
22170Sstevel@tonic-gate 	    if (clp->client_handle == client_handle)
22180Sstevel@tonic-gate 		return (clp);
22190Sstevel@tonic-gate 	    clp = clp->next;
22200Sstevel@tonic-gate 	}
22210Sstevel@tonic-gate 
22220Sstevel@tonic-gate 	if (error)
22230Sstevel@tonic-gate 	    *error = CS_BAD_HANDLE;
22240Sstevel@tonic-gate 
22250Sstevel@tonic-gate 	return (NULL);
22260Sstevel@tonic-gate }
22270Sstevel@tonic-gate 
22280Sstevel@tonic-gate /*
22290Sstevel@tonic-gate  * cs_destroy_client_handle - destroys client handle and client structure of
22300Sstevel@tonic-gate  *				passed client handle
22310Sstevel@tonic-gate  *
22320Sstevel@tonic-gate  * returns:	CS_SUCCESS - if client handle sucessfully destroyed
22330Sstevel@tonic-gate  *		CS_BAD_HANDLE - if client handle is invalid or if trying
22340Sstevel@tonic-gate  *					to destroy global SS client
22350Sstevel@tonic-gate  *		{other errors} - other errors from cs_find_client()
22360Sstevel@tonic-gate  */
22370Sstevel@tonic-gate static int
cs_destroy_client_handle(client_handle_t client_handle)22380Sstevel@tonic-gate cs_destroy_client_handle(client_handle_t client_handle)
22390Sstevel@tonic-gate {
22400Sstevel@tonic-gate 	client_t *clp;
22410Sstevel@tonic-gate 	cs_socket_t *sp;
22420Sstevel@tonic-gate 	int error = CS_BAD_HANDLE;
22430Sstevel@tonic-gate 
22440Sstevel@tonic-gate 	/*
22450Sstevel@tonic-gate 	 * See if we were passed a valid client handle or if we're being asked
22460Sstevel@tonic-gate 	 *	to destroy the Socket Services client
22470Sstevel@tonic-gate 	 */
22480Sstevel@tonic-gate 	if ((!(clp = cs_find_client(client_handle, &error))) ||
22490Sstevel@tonic-gate 			(CLIENT_HANDLE_IS_SS(client_handle)))
22500Sstevel@tonic-gate 	    return (error);
22510Sstevel@tonic-gate 
22520Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
22530Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
22540Sstevel@tonic-gate 
22550Sstevel@tonic-gate 	/*
22560Sstevel@tonic-gate 	 * Recycle this client's minor number.  This will most likely
22570Sstevel@tonic-gate 	 *	be the next client minor number we use, but it is also
22580Sstevel@tonic-gate 	 *	a hint to cs_create_client_handle, and that function
22590Sstevel@tonic-gate 	 *	may actually create a new client handle using a minor
22600Sstevel@tonic-gate 	 *	number different that this number.
22610Sstevel@tonic-gate 	 */
22620Sstevel@tonic-gate 	mutex_enter(&sp->lock);
22630Sstevel@tonic-gate 	sp->next_cl_minor = GET_CLIENT_MINOR(client_handle);
22640Sstevel@tonic-gate 
22650Sstevel@tonic-gate 	/*
22660Sstevel@tonic-gate 	 * See if we're the first or not in the client list; if we're
22670Sstevel@tonic-gate 	 *	not first, then just adjust the client behind us to
22680Sstevel@tonic-gate 	 *	point to the client ahead of us; this could be NULL
22690Sstevel@tonic-gate 	 *	if we're the last client in the list.
22700Sstevel@tonic-gate 	 */
22710Sstevel@tonic-gate 	if (clp->prev) {
22720Sstevel@tonic-gate 	    clp->prev->next = clp->next;
22730Sstevel@tonic-gate 	} else {
22740Sstevel@tonic-gate 	/*
22750Sstevel@tonic-gate 	 * We are first, so adjust the client list head pointer
22760Sstevel@tonic-gate 	 *	in the socket to point to the client structure that
22770Sstevel@tonic-gate 	 *	follows us; this could turn out to be NULL if we're
22780Sstevel@tonic-gate 	 *	the only client on this socket.
22790Sstevel@tonic-gate 	 */
22800Sstevel@tonic-gate 	    sp->client_list = clp->next;
22810Sstevel@tonic-gate 	}
22820Sstevel@tonic-gate 
22830Sstevel@tonic-gate 	/*
22840Sstevel@tonic-gate 	 * If we're not the last client in the list, point the next
22850Sstevel@tonic-gate 	 *	client to the client behind us; this could turn out
22860Sstevel@tonic-gate 	 *	to be NULL if we're the first client on this socket.
22870Sstevel@tonic-gate 	 */
22880Sstevel@tonic-gate 	if (clp->next)
22890Sstevel@tonic-gate 	    clp->next->prev = clp->prev;
22900Sstevel@tonic-gate 
22910Sstevel@tonic-gate 	sp->num_clients--;
22920Sstevel@tonic-gate 	mutex_exit(&sp->lock);
22930Sstevel@tonic-gate 
22940Sstevel@tonic-gate 	/*
22950Sstevel@tonic-gate 	 * Free this client's memory.
22960Sstevel@tonic-gate 	 */
22970Sstevel@tonic-gate 	kmem_free(clp, sizeof (client_t));
22980Sstevel@tonic-gate 
22990Sstevel@tonic-gate 	return (CS_SUCCESS);
23000Sstevel@tonic-gate }
23010Sstevel@tonic-gate 
23020Sstevel@tonic-gate /*
23030Sstevel@tonic-gate  * cs_create_client_handle - create a new client handle for the passed
23040Sstevel@tonic-gate  *				socket and function number
23050Sstevel@tonic-gate  *
23060Sstevel@tonic-gate  * returns:	0 -  if can't create client for some reason
23070Sstevel@tonic-gate  *		client_handle_t - new client handle
23080Sstevel@tonic-gate  */
23090Sstevel@tonic-gate static client_handle_t
cs_create_client_handle(unsigned socket_num,client_t * cclp)23100Sstevel@tonic-gate cs_create_client_handle(unsigned socket_num, client_t *cclp)
23110Sstevel@tonic-gate {
23120Sstevel@tonic-gate 	client_t *clp;
23130Sstevel@tonic-gate 	cs_socket_t *sp;
23140Sstevel@tonic-gate 	unsigned next_minor;
23150Sstevel@tonic-gate 	client_handle_t client_handle;
23160Sstevel@tonic-gate 
23170Sstevel@tonic-gate 	if ((sp = cs_get_sp(socket_num)) == NULL)
23180Sstevel@tonic-gate 	    return (0);
23190Sstevel@tonic-gate 
23200Sstevel@tonic-gate 	/*
23210Sstevel@tonic-gate 	 * Get the next available minor number that we can use.  We use the
23220Sstevel@tonic-gate 	 *	next_cl_minor number as a hint to cs_create_next_client_minor
23230Sstevel@tonic-gate 	 *	and in most cases this will be the minor number we get back.
23240Sstevel@tonic-gate 	 * If for some reason we can't get a minor number, return an error.
23250Sstevel@tonic-gate 	 *	The only way we could get an error would be if there are
23260Sstevel@tonic-gate 	 *	already the maximum number of clients for this socket. Since
23270Sstevel@tonic-gate 	 *	the maximum number of clients per socket is pretty large,
23280Sstevel@tonic-gate 	 *	this error is unlikely to occur.
23290Sstevel@tonic-gate 	 */
23300Sstevel@tonic-gate 	if (!(next_minor =
23310Sstevel@tonic-gate 		cs_create_next_client_minor(socket_num, sp->next_cl_minor)))
23320Sstevel@tonic-gate 	    return (0);
23330Sstevel@tonic-gate 
23340Sstevel@tonic-gate 	/*
23350Sstevel@tonic-gate 	 * Got a new client minor number, now create a new client handle.
23360Sstevel@tonic-gate 	 */
23370Sstevel@tonic-gate 	client_handle = MAKE_CLIENT_HANDLE(CS_GET_SOCKET_NUMBER(socket_num),
23380Sstevel@tonic-gate 					CS_GET_FUNCTION_NUMBER(socket_num),
23390Sstevel@tonic-gate 					next_minor);
23400Sstevel@tonic-gate 
23410Sstevel@tonic-gate 	/*
23420Sstevel@tonic-gate 	 * If this client handle exists, then we have an internal
23430Sstevel@tonic-gate 	 *	error; this should never happen, BTW.  This is really
23440Sstevel@tonic-gate 	 *	a double-check on the cs_create_next_client_minor
23450Sstevel@tonic-gate 	 *	function, which also calls cs_find_client.
23460Sstevel@tonic-gate 	 */
23470Sstevel@tonic-gate 	if (cs_find_client(client_handle, NULL)) {
23480Sstevel@tonic-gate 	    cmn_err(CE_CONT,
23490Sstevel@tonic-gate 		"cs_create_client_handle: duplicate client handle 0x%x\n",
23500Sstevel@tonic-gate 							(int)client_handle);
23510Sstevel@tonic-gate 	    return (0);
23520Sstevel@tonic-gate 	}
23530Sstevel@tonic-gate 
23540Sstevel@tonic-gate 	/*
23550Sstevel@tonic-gate 	 * If we don't have any clients on this socket yet, create
23560Sstevel@tonic-gate 	 *	a new client and hang it on the socket client list.
23570Sstevel@tonic-gate 	 */
23580Sstevel@tonic-gate 	if (!sp->client_list) {
23590Sstevel@tonic-gate 	    sp->client_list = cclp;
23600Sstevel@tonic-gate 	    clp = sp->client_list;
23610Sstevel@tonic-gate 	} else {
23620Sstevel@tonic-gate 	/*
23630Sstevel@tonic-gate 	 * There are other clients on this socket, so look for
23640Sstevel@tonic-gate 	 *	the last client and add our new client after it.
23650Sstevel@tonic-gate 	 */
23660Sstevel@tonic-gate 	    clp = sp->client_list;
23670Sstevel@tonic-gate 	    while (clp->next) {
23680Sstevel@tonic-gate 		clp = clp->next;
23690Sstevel@tonic-gate 	    }
23700Sstevel@tonic-gate 
23710Sstevel@tonic-gate 	    clp->next = cclp;
23720Sstevel@tonic-gate 	    clp->next->prev = clp;
23730Sstevel@tonic-gate 	    clp = clp->next;
23740Sstevel@tonic-gate 	} /* if (!sp->client_list) */
23750Sstevel@tonic-gate 
23760Sstevel@tonic-gate 	/*
23770Sstevel@tonic-gate 	 * Assign the new client handle to this new client structure.
23780Sstevel@tonic-gate 	 */
23790Sstevel@tonic-gate 	clp->client_handle = client_handle;
23800Sstevel@tonic-gate 
23810Sstevel@tonic-gate 	/*
23820Sstevel@tonic-gate 	 * Create the next available client minor number for this socket
23830Sstevel@tonic-gate 	 *	and save it away.
23840Sstevel@tonic-gate 	 */
23850Sstevel@tonic-gate 	sp->next_cl_minor =
23860Sstevel@tonic-gate 		cs_create_next_client_minor(socket_num, sp->next_cl_minor);
23870Sstevel@tonic-gate 
23880Sstevel@tonic-gate 	return (client_handle);
23890Sstevel@tonic-gate }
23900Sstevel@tonic-gate 
23910Sstevel@tonic-gate /*
23920Sstevel@tonic-gate  * cs_clear_superclient_lock - clears the global "super-client" lock
23930Sstevel@tonic-gate  *
23940Sstevel@tonic-gate  * Note: this function uses the cs_globals.global_lock so observe proper
23950Sstevel@tonic-gate  *		nexting of locks!!
23960Sstevel@tonic-gate  */
23970Sstevel@tonic-gate static void
cs_clear_superclient_lock(int super_client)23980Sstevel@tonic-gate cs_clear_superclient_lock(int super_client)
23990Sstevel@tonic-gate {
24000Sstevel@tonic-gate 
24010Sstevel@tonic-gate 	/*
24020Sstevel@tonic-gate 	 * If this was a "super-client" registering then we need
24030Sstevel@tonic-gate 	 *	to clear the GLOBAL_SUPER_CLIENT_REGISTERED flag
24040Sstevel@tonic-gate 	 *	so that other "super-clients" can register.
24050Sstevel@tonic-gate 	 */
24060Sstevel@tonic-gate 	if (super_client == CLIENT_SUPER_CLIENT) {
24070Sstevel@tonic-gate 	    mutex_enter(&cs_globals.global_lock);
24080Sstevel@tonic-gate 	    cs_globals.flags &= ~GLOBAL_SUPER_CLIENT_REGISTERED;
24090Sstevel@tonic-gate 	    mutex_exit(&cs_globals.global_lock);
24100Sstevel@tonic-gate 	}
24110Sstevel@tonic-gate }
24120Sstevel@tonic-gate 
24130Sstevel@tonic-gate /*
24140Sstevel@tonic-gate  * ==== event handling section ====
24150Sstevel@tonic-gate  */
24160Sstevel@tonic-gate 
24170Sstevel@tonic-gate /*
24180Sstevel@tonic-gate  * cs_event - CS event hi-priority callback handler
24190Sstevel@tonic-gate  *
24200Sstevel@tonic-gate  *	This function gets called by SS and is passed the event type in
24210Sstevel@tonic-gate  *		the "event" argument, and the socket number in the "sn"
24220Sstevel@tonic-gate  *		argument. The "sn" argument is a valid logical socket
24230Sstevel@tonic-gate  *		number for all events except the PCE_SS_READY event.
24240Sstevel@tonic-gate  *
24250Sstevel@tonic-gate  *	The PCE_SS_INIT_STATE, PCE_ADD_SOCKET and PCE_DROP_SOCKET events
24260Sstevel@tonic-gate  *		are never called at high priority. These events return
24270Sstevel@tonic-gate  *		the following return codes:
24280Sstevel@tonic-gate  *
24290Sstevel@tonic-gate  *			CS_SUCCESS - operation sucessful
24300Sstevel@tonic-gate  *			CS_BAD_SOCKET - unable to complete operation
24310Sstevel@tonic-gate  *			CS_UNSUPPORTED_FUNCTION - bad subfunction of
24320Sstevel@tonic-gate  *							PCE_SS_INIT_STATE
24330Sstevel@tonic-gate  *
24340Sstevel@tonic-gate  *		The caller MUST look at these return codes!
24350Sstevel@tonic-gate  *
24360Sstevel@tonic-gate  *	This function is called at high-priority interrupt time for standard
24370Sstevel@tonic-gate  *		Card Services events, and the only standard Card Services
24380Sstevel@tonic-gate  *		event that it handles directly is the CS_EVENT_CARD_REMOVAL
24390Sstevel@tonic-gate  *		event, which gets shuttled right into the client's event
24400Sstevel@tonic-gate  *		handler.  All other events are just queued up and the socket
24410Sstevel@tonic-gate  *		event thread is woken up via the soft interrupt handler.
24420Sstevel@tonic-gate  *	Note that CS_EVENT_CARD_INSERTION events are not set in the clients'
24430Sstevel@tonic-gate  *		event field, since the CS card insertion/card ready processing
24440Sstevel@tonic-gate  *		code is responsible for setting this event in a client's
24450Sstevel@tonic-gate  *		event field.
24460Sstevel@tonic-gate  *
24470Sstevel@tonic-gate  */
24480Sstevel@tonic-gate /*ARGSUSED*/
24490Sstevel@tonic-gate uint32_t
cs_event(event_t event,uint32_t sn,uint32_t arg)24500Sstevel@tonic-gate cs_event(event_t event, uint32_t sn, uint32_t arg)
24510Sstevel@tonic-gate {
24520Sstevel@tonic-gate 	client_t *client;
24530Sstevel@tonic-gate 	cs_socket_t *sp;
24540Sstevel@tonic-gate 	client_types_t *ct;
24550Sstevel@tonic-gate 	uint32_t ret = CS_SUCCESS;
24560Sstevel@tonic-gate 
24570Sstevel@tonic-gate 	/*
24580Sstevel@tonic-gate 	 * Handle special SS<->CS events
24590Sstevel@tonic-gate 	 */
24600Sstevel@tonic-gate 	switch (event) {
24610Sstevel@tonic-gate 	    case PCE_SS_INIT_STATE:
24620Sstevel@tonic-gate 		mutex_enter(&cs_globals.global_lock);
24630Sstevel@tonic-gate 		switch (sn) {
24640Sstevel@tonic-gate 		    case PCE_SS_STATE_INIT:
24650Sstevel@tonic-gate 			if ((ret = cs_ss_init()) == CS_SUCCESS)
24660Sstevel@tonic-gate 			    cs_globals.init_state |= GLOBAL_INIT_STATE_SS_READY;
24670Sstevel@tonic-gate 			break;
24680Sstevel@tonic-gate 		    case PCE_SS_STATE_DEINIT:
24690Sstevel@tonic-gate 			cs_globals.init_state &= ~GLOBAL_INIT_STATE_SS_READY;
24700Sstevel@tonic-gate 			break;
24710Sstevel@tonic-gate 		    default:
24720Sstevel@tonic-gate 			ret = CS_UNSUPPORTED_FUNCTION;
24730Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_event: PCE_SS_INIT_STATE invalid "
24740Sstevel@tonic-gate 						"directive: 0x%x\n", sn);
24750Sstevel@tonic-gate 			break;
24760Sstevel@tonic-gate 		} /* switch (sn) */
24770Sstevel@tonic-gate 		mutex_exit(&cs_globals.global_lock);
24780Sstevel@tonic-gate 		return (ret);
24790Sstevel@tonic-gate 	    case PCE_ADD_SOCKET:
24800Sstevel@tonic-gate 		return (cs_add_socket(sn));
24810Sstevel@tonic-gate 	    case PCE_DROP_SOCKET:
24820Sstevel@tonic-gate 		return (cs_drop_socket(sn));
24830Sstevel@tonic-gate 	} /* switch (event) */
24840Sstevel@tonic-gate 
24850Sstevel@tonic-gate 	if ((sp = cs_get_sp(sn)) == NULL)
24860Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
24870Sstevel@tonic-gate 
24880Sstevel@tonic-gate 	/*
24890Sstevel@tonic-gate 	 * Check to see if CS wants to unload - we do this since it's possible
24900Sstevel@tonic-gate 	 *	to disable certain sockets.  Do NOT acquire any locks yet.
24910Sstevel@tonic-gate 	 */
24920Sstevel@tonic-gate 	if (sp->flags & SOCKET_UNLOAD_MODULE) {
24930Sstevel@tonic-gate 	    if (event == PCE_CARD_INSERT)
24940Sstevel@tonic-gate 		cmn_err(CE_CONT, "PCMCIA: socket %d disabled - please "
24950Sstevel@tonic-gate 							"remove card\n", sn);
24960Sstevel@tonic-gate 	    return (CS_SUCCESS);
24970Sstevel@tonic-gate 	}
24980Sstevel@tonic-gate 
24990Sstevel@tonic-gate 	mutex_enter(&sp->lock);
25000Sstevel@tonic-gate 
25010Sstevel@tonic-gate #ifdef	CS_DEBUG
25020Sstevel@tonic-gate 	if (cs_debug > 1) {
25030Sstevel@tonic-gate 	    event2text_t event2text;
25040Sstevel@tonic-gate 
25050Sstevel@tonic-gate 	    event2text.event = event;
25060Sstevel@tonic-gate 	    (void) cs_event2text(&event2text, 0);
25070Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_event: event=%s (x%x), socket=0x%x\n",
25080Sstevel@tonic-gate 				event2text.text, (int)event, (int)sn);
25090Sstevel@tonic-gate 	}
25100Sstevel@tonic-gate #endif
25110Sstevel@tonic-gate 
25120Sstevel@tonic-gate 	/*
25130Sstevel@tonic-gate 	 * Convert SS events to CS events; handle the PRR if necessary.
25140Sstevel@tonic-gate 	 */
25150Sstevel@tonic-gate 	sp->events |= ss_to_cs_events(sp, event);
25160Sstevel@tonic-gate 
25170Sstevel@tonic-gate 	/*
25180Sstevel@tonic-gate 	 * We want to maintain the required event dispatching order as
25190Sstevel@tonic-gate 	 *	specified in the PCMCIA spec, so we cycle through all
25200Sstevel@tonic-gate 	 *	clients on this socket to make sure that they are
25210Sstevel@tonic-gate 	 *	notified in the correct order of any high-priority
25220Sstevel@tonic-gate 	 *	events.
25230Sstevel@tonic-gate 	 */
25240Sstevel@tonic-gate 	ct = &client_types[0];
25250Sstevel@tonic-gate 	while (ct) {
25260Sstevel@tonic-gate 	/*
25270Sstevel@tonic-gate 	 * Point to the head of the client list for this socket, and go
25280Sstevel@tonic-gate 	 *	through each client to set up the client events as well as
25290Sstevel@tonic-gate 	 *	call the client's event handler directly if we have a high
25300Sstevel@tonic-gate 	 *	priority event that we need to tell the client about.
25310Sstevel@tonic-gate 	 */
25320Sstevel@tonic-gate 	    client = sp->client_list;
25330Sstevel@tonic-gate 
25340Sstevel@tonic-gate 	    if (ct->order & CLIENT_EVENTS_LIFO) {
25350Sstevel@tonic-gate 		client_t *clp = NULL;
25360Sstevel@tonic-gate 
25370Sstevel@tonic-gate 		while (client) {
25380Sstevel@tonic-gate 		    clp = client;
25390Sstevel@tonic-gate 		    client = client->next;
25400Sstevel@tonic-gate 		}
25410Sstevel@tonic-gate 		client = clp;
25420Sstevel@tonic-gate 	    }
25430Sstevel@tonic-gate 
25440Sstevel@tonic-gate 	    while (client) {
25450Sstevel@tonic-gate 		client->events |= ((sp->events & ~CS_EVENT_CARD_INSERTION) &
25460Sstevel@tonic-gate 				    (client->event_mask | client->global_mask));
25470Sstevel@tonic-gate 		if (client->flags & ct->type) {
25480Sstevel@tonic-gate #ifdef	CS_DEBUG
25490Sstevel@tonic-gate 		    if (cs_debug > 1) {
25500Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_event: socket %d client [%s] "
25510Sstevel@tonic-gate 						"events 0x%x flags 0x%x\n",
25520Sstevel@tonic-gate 						sn, client->driver_name,
25530Sstevel@tonic-gate 						(int)client->events,
25540Sstevel@tonic-gate 						(int)client->flags);
25550Sstevel@tonic-gate 		    }
25560Sstevel@tonic-gate #endif
25570Sstevel@tonic-gate 
25580Sstevel@tonic-gate 		/*
25590Sstevel@tonic-gate 		 * Handle the suspend and card removal events
25600Sstevel@tonic-gate 		 *	specially here so that the client can receive
25610Sstevel@tonic-gate 		 *	these events at high-priority.
25620Sstevel@tonic-gate 		 */
25630Sstevel@tonic-gate 		    if (client->events & CS_EVENT_PM_SUSPEND) {
25640Sstevel@tonic-gate 			if (client->flags & CLIENT_CARD_INSERTED) {
25650Sstevel@tonic-gate 			    CLIENT_EVENT_CALLBACK(client, CS_EVENT_PM_SUSPEND,
25660Sstevel@tonic-gate 							CS_EVENT_PRI_HIGH);
25670Sstevel@tonic-gate 			} /* if (CLIENT_CARD_INSERTED) */
25680Sstevel@tonic-gate 			client->events &= ~CS_EVENT_PM_SUSPEND;
25690Sstevel@tonic-gate 		    } /* if (CS_EVENT_PM_SUSPEND) */
25700Sstevel@tonic-gate 
25710Sstevel@tonic-gate 		    if (client->events & CS_EVENT_CARD_REMOVAL) {
25720Sstevel@tonic-gate 			if (client->flags & CLIENT_CARD_INSERTED) {
25730Sstevel@tonic-gate 			    client->flags &= ~(CLIENT_CARD_INSERTED |
25740Sstevel@tonic-gate 						CLIENT_SENT_INSERTION);
25750Sstevel@tonic-gate 			    CLIENT_EVENT_CALLBACK(client,
25760Sstevel@tonic-gate 							CS_EVENT_CARD_REMOVAL,
25770Sstevel@tonic-gate 							CS_EVENT_PRI_HIGH);
25780Sstevel@tonic-gate 			/*
25790Sstevel@tonic-gate 			 * Check to see if the client wants low priority
25800Sstevel@tonic-gate 			 *	removal events as well.
25810Sstevel@tonic-gate 			 */
25820Sstevel@tonic-gate 			    if ((client->event_mask | client->global_mask) &
25830Sstevel@tonic-gate 						CS_EVENT_CARD_REMOVAL_LOWP) {
25840Sstevel@tonic-gate 				client->events |= CS_EVENT_CARD_REMOVAL_LOWP;
25850Sstevel@tonic-gate 			    }
25860Sstevel@tonic-gate 			} /* if (CLIENT_CARD_INSERTED) */
25870Sstevel@tonic-gate 			client->events &= ~CS_EVENT_CARD_REMOVAL;
25880Sstevel@tonic-gate 		    } /* if (CS_EVENT_CARD_REMOVAL) */
25890Sstevel@tonic-gate 
25900Sstevel@tonic-gate 		} /* if (ct->type) */
25910Sstevel@tonic-gate 		if (ct->order & CLIENT_EVENTS_LIFO) {
25920Sstevel@tonic-gate 		    client = client->prev;
25930Sstevel@tonic-gate 		} else {
25940Sstevel@tonic-gate 		    client = client->next;
25950Sstevel@tonic-gate 		}
25960Sstevel@tonic-gate 	    } /* while (client) */
25970Sstevel@tonic-gate 
25980Sstevel@tonic-gate 	    ct = ct->next;
25990Sstevel@tonic-gate 	} /* while (ct) */
26000Sstevel@tonic-gate 
26010Sstevel@tonic-gate 	/*
26020Sstevel@tonic-gate 	 * Set the SOCKET_NEEDS_THREAD flag so that the soft interrupt
26030Sstevel@tonic-gate 	 *	handler will wakeup this socket's event thread.
26040Sstevel@tonic-gate 	 */
26050Sstevel@tonic-gate 	if (sp->events)
26060Sstevel@tonic-gate 	    sp->flags |= SOCKET_NEEDS_THREAD;
26070Sstevel@tonic-gate 
26080Sstevel@tonic-gate 	/*
26090Sstevel@tonic-gate 	 * Fire off a soft interrupt that will cause the socket thread
26100Sstevel@tonic-gate 	 *	to be woken up and any remaining events to be sent to
26110Sstevel@tonic-gate 	 *	the clients on this socket.
26120Sstevel@tonic-gate 	 */
26130Sstevel@tonic-gate 	if ((sp->init_state & SOCKET_INIT_STATE_SOFTINTR) &&
26140Sstevel@tonic-gate 			!(cs_globals.init_state & GLOBAL_INIT_STATE_UNLOADING))
26150Sstevel@tonic-gate 	    ddi_trigger_softintr(sp->softint_id);
26160Sstevel@tonic-gate 
26170Sstevel@tonic-gate 	mutex_exit(&sp->lock);
26180Sstevel@tonic-gate 
26190Sstevel@tonic-gate 	return (CS_SUCCESS);
26200Sstevel@tonic-gate }
26210Sstevel@tonic-gate 
26220Sstevel@tonic-gate /*
26230Sstevel@tonic-gate  * cs_card_insertion - handle card insertion and card ready events
26240Sstevel@tonic-gate  *
26250Sstevel@tonic-gate  * We read the CIS, if present, and store it away, then tell SS that
26260Sstevel@tonic-gate  *	we have read the CIS and it's ready to be parsed.  Since card
26270Sstevel@tonic-gate  *	insertion and card ready events are pretty closely intertwined,
26280Sstevel@tonic-gate  *	we handle both here.  For card ready events that are not the
26290Sstevel@tonic-gate  *	result of a card insertion event, we expect that the caller has
26300Sstevel@tonic-gate  *	already done the appropriate processing and that we will not be
26310Sstevel@tonic-gate  *	called unless we received a card ready event right after a card
26320Sstevel@tonic-gate  *	insertion event, i.e. that the SOCKET_WAIT_FOR_READY flag in
26330Sstevel@tonic-gate  *	sp->thread_state was set or if we get a CARD_READY event right
26340Sstevel@tonic-gate  *	after a CARD_INSERTION event.
26350Sstevel@tonic-gate  *
26360Sstevel@tonic-gate  *    calling:	sp - pointer to socket structure
26370Sstevel@tonic-gate  *		event - event to handle, one of:
26380Sstevel@tonic-gate  *				CS_EVENT_CARD_INSERTION
26390Sstevel@tonic-gate  *				CS_EVENT_CARD_READY
26400Sstevel@tonic-gate  *				CS_EVENT_SS_UPDATED
26410Sstevel@tonic-gate  */
26420Sstevel@tonic-gate static int
cs_card_insertion(cs_socket_t * sp,event_t event)26430Sstevel@tonic-gate cs_card_insertion(cs_socket_t *sp, event_t event)
26440Sstevel@tonic-gate {
26450Sstevel@tonic-gate 	int ret;
26460Sstevel@tonic-gate 
26470Sstevel@tonic-gate 	/*
26480Sstevel@tonic-gate 	 * Since we're only called while waiting for the card insertion
26490Sstevel@tonic-gate 	 *	and card ready sequence to occur, we may have a pending
26500Sstevel@tonic-gate 	 *	card ready timer that hasn't gone off yet if we got a
26510Sstevel@tonic-gate 	 *	real card ready event.
26520Sstevel@tonic-gate 	 */
26530Sstevel@tonic-gate 	UNTIMEOUT(sp->rdybsy_tmo_id);
26540Sstevel@tonic-gate 
26550Sstevel@tonic-gate #ifdef	CS_DEBUG
26560Sstevel@tonic-gate 	if (cs_debug > 1) {
26570Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_card_insertion: event=0x%x, socket=0x%x\n",
26580Sstevel@tonic-gate 						(int)event, sp->socket_num);
26590Sstevel@tonic-gate 	}
26600Sstevel@tonic-gate #endif
26610Sstevel@tonic-gate 
26620Sstevel@tonic-gate 	/*
26630Sstevel@tonic-gate 	 * Handle card insertion processing
26640Sstevel@tonic-gate 	 */
26650Sstevel@tonic-gate 	if (event & CS_EVENT_CARD_INSERTION) {
26660Sstevel@tonic-gate 	    set_socket_t set_socket;
26670Sstevel@tonic-gate 	    get_ss_status_t gs;
26680Sstevel@tonic-gate 
26690Sstevel@tonic-gate 	/*
26700Sstevel@tonic-gate 	 * Check to be sure that we have a valid CIS window
26710Sstevel@tonic-gate 	 */
26720Sstevel@tonic-gate 	    if (!SOCKET_HAS_CIS_WINDOW(sp)) {
26730Sstevel@tonic-gate 		cmn_err(CE_CONT,
26740Sstevel@tonic-gate 			"cs_card_insertion: socket %d has no "
26750Sstevel@tonic-gate 							"CIS window\n",
26760Sstevel@tonic-gate 				sp->socket_num);
26770Sstevel@tonic-gate 		return (CS_GENERAL_FAILURE);
26780Sstevel@tonic-gate 	    }
26790Sstevel@tonic-gate 
26800Sstevel@tonic-gate 	/*
26810Sstevel@tonic-gate 	 * Apply power to the socket, enable card detect and card ready
26820Sstevel@tonic-gate 	 *	events, then reset the socket.
26830Sstevel@tonic-gate 	 */
26840Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
26850Sstevel@tonic-gate 	    sp->event_mask =   (CS_EVENT_CARD_REMOVAL   |
26860Sstevel@tonic-gate 				CS_EVENT_CARD_READY);
26870Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
26880Sstevel@tonic-gate 	    set_socket.socket = sp->socket_num;
26890Sstevel@tonic-gate 	    set_socket.SCIntMask = (SBM_CD | SBM_RDYBSY);
26900Sstevel@tonic-gate 	    set_socket.IREQRouting = 0;
26910Sstevel@tonic-gate 	    set_socket.IFType = IF_MEMORY;
26920Sstevel@tonic-gate 	    set_socket.CtlInd = 0; /* turn off controls and indicators */
26930Sstevel@tonic-gate 	    set_socket.State = (unsigned)~0;	/* clear latched state bits */
26940Sstevel@tonic-gate 
26950Sstevel@tonic-gate 	    (void) cs_convert_powerlevel(sp->socket_num, 50, VCC,
26960Sstevel@tonic-gate 						&set_socket.VccLevel);
26970Sstevel@tonic-gate 	    (void) cs_convert_powerlevel(sp->socket_num, 50, VPP1,
26980Sstevel@tonic-gate 						&set_socket.Vpp1Level);
26990Sstevel@tonic-gate 	    (void) cs_convert_powerlevel(sp->socket_num, 50, VPP2,
27000Sstevel@tonic-gate 						&set_socket.Vpp2Level);
27010Sstevel@tonic-gate 
27020Sstevel@tonic-gate 	    if ((ret = SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
27030Sstevel@tonic-gate 		cmn_err(CE_CONT,
27040Sstevel@tonic-gate 		    "cs_card_insertion: socket %d SS_SetSocket failure %d\n",
27050Sstevel@tonic-gate 				sp->socket_num, ret);
27060Sstevel@tonic-gate 		return (ret);
27070Sstevel@tonic-gate 	    }
27080Sstevel@tonic-gate 
27090Sstevel@tonic-gate 	/*
27100Sstevel@tonic-gate 	 * Clear the ready and ready_timeout events since they are now
27110Sstevel@tonic-gate 	 *	bogus since we're about to reset the socket.
27120Sstevel@tonic-gate 	 * XXX - should these be cleared right after the RESET??
27130Sstevel@tonic-gate 	 */
27140Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
27150Sstevel@tonic-gate 
27160Sstevel@tonic-gate 	    sp->events &= ~(CS_EVENT_CARD_READY | CS_EVENT_READY_TIMEOUT);
27170Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
27180Sstevel@tonic-gate 
27190Sstevel@tonic-gate 	    SocketServices(SS_ResetSocket, sp->socket_num,
27200Sstevel@tonic-gate 						RESET_MODE_CARD_ONLY);
27210Sstevel@tonic-gate 
27220Sstevel@tonic-gate 	/*
27230Sstevel@tonic-gate 	 * We are required by the PCMCIA spec to wait some number of
27240Sstevel@tonic-gate 	 *	milliseconds after reset before we access the card, so
27250Sstevel@tonic-gate 	 *	we set up a timer here that will wake us up and allow us
27260Sstevel@tonic-gate 	 *	to continue with our card initialization.
27270Sstevel@tonic-gate 	 */
27280Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
27290Sstevel@tonic-gate 	    sp->thread_state |= SOCKET_RESET_TIMER;
27300Sstevel@tonic-gate 	    (void) timeout(cs_ready_timeout, sp,
27310Sstevel@tonic-gate 		drv_usectohz(cs_reset_timeout_time * 1000));
27320Sstevel@tonic-gate 	    cv_wait(&sp->reset_cv, &sp->lock);
27330Sstevel@tonic-gate 	    sp->thread_state &= ~SOCKET_RESET_TIMER;
27340Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
27350Sstevel@tonic-gate 
27360Sstevel@tonic-gate #ifdef	CS_DEBUG
27370Sstevel@tonic-gate 	    if (cs_debug > 2) {
27380Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_card_insertion: socket %d out of RESET "
27390Sstevel@tonic-gate 		    "for %d mS sp->events 0x%x\n",
27400Sstevel@tonic-gate 		    sp->socket_num, cs_reset_timeout_time, (int)sp->events);
27410Sstevel@tonic-gate 	    }
27420Sstevel@tonic-gate #endif
27430Sstevel@tonic-gate 
27440Sstevel@tonic-gate 	/*
27450Sstevel@tonic-gate 	 * If we have a pending CS_EVENT_CARD_REMOVAL event it
27460Sstevel@tonic-gate 	 *	means that we likely got CD line bounce on the
27470Sstevel@tonic-gate 	 *	insertion, so terminate this processing.
27480Sstevel@tonic-gate 	 */
27490Sstevel@tonic-gate 	    if (sp->events & CS_EVENT_CARD_REMOVAL) {
27500Sstevel@tonic-gate #ifdef	CS_DEBUG
27510Sstevel@tonic-gate 		if (cs_debug > 0) {
27520Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_card_insertion: socket %d "
27530Sstevel@tonic-gate 						"CS_EVENT_CARD_REMOVAL event "
27540Sstevel@tonic-gate 						"terminating insertion "
27550Sstevel@tonic-gate 						"processing\n",
27560Sstevel@tonic-gate 							sp->socket_num);
27570Sstevel@tonic-gate 		}
27580Sstevel@tonic-gate #endif
27590Sstevel@tonic-gate 	    return (CS_SUCCESS);
27600Sstevel@tonic-gate 	    } /* if (CS_EVENT_CARD_REMOVAL) */
27610Sstevel@tonic-gate 
27620Sstevel@tonic-gate 	/*
27630Sstevel@tonic-gate 	 * If we got a card ready event after the reset, then don't
27640Sstevel@tonic-gate 	 *	bother setting up a card ready timer, since we'll blast
27650Sstevel@tonic-gate 	 *	right on through to the card ready processing.
27660Sstevel@tonic-gate 	 * Get the current card status to see if it's ready; if it
27670Sstevel@tonic-gate 	 *	is, we probably won't get a card ready event.
27680Sstevel@tonic-gate 	 */
27690Sstevel@tonic-gate 	    gs.socket = sp->socket_num;
27700Sstevel@tonic-gate 	    gs.CardState = 0;
27710Sstevel@tonic-gate 	    if ((ret = SocketServices(SS_GetStatus, &gs)) != SUCCESS) {
27720Sstevel@tonic-gate 		cmn_err(CE_CONT,
27730Sstevel@tonic-gate 		    "cs_card_insertion: socket %d SS_GetStatus failure %d\n",
27740Sstevel@tonic-gate 				sp->socket_num, ret);
27750Sstevel@tonic-gate 		return (ret);
27760Sstevel@tonic-gate 	    }
27770Sstevel@tonic-gate 
27780Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
27790Sstevel@tonic-gate 	    if ((sp->events & CS_EVENT_CARD_READY) ||
27800Sstevel@tonic-gate 					(gs.CardState & SBM_RDYBSY)) {
27810Sstevel@tonic-gate 		event = CS_EVENT_CARD_READY;
27820Sstevel@tonic-gate #ifdef	CS_DEBUG
27830Sstevel@tonic-gate 		if (cs_debug > 1) {
27840Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_card_insertion: socket %d card "
27850Sstevel@tonic-gate 						"READY\n", sp->socket_num);
27860Sstevel@tonic-gate 		}
27870Sstevel@tonic-gate #endif
27880Sstevel@tonic-gate 
27890Sstevel@tonic-gate 	    } else {
27900Sstevel@tonic-gate #ifdef	CS_DEBUG
27910Sstevel@tonic-gate 		if (cs_debug > 1) {
27920Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_card_insertion: socket %d setting "
27930Sstevel@tonic-gate 					"READY timer\n", sp->socket_num);
27940Sstevel@tonic-gate 		}
27950Sstevel@tonic-gate #endif
27960Sstevel@tonic-gate 
27970Sstevel@tonic-gate 		sp->rdybsy_tmo_id = timeout(cs_ready_timeout, sp,
27980Sstevel@tonic-gate 		    READY_TIMEOUT_TIME);
27990Sstevel@tonic-gate 		sp->thread_state |= SOCKET_WAIT_FOR_READY;
28000Sstevel@tonic-gate 
28010Sstevel@tonic-gate 	    } /* if (CS_EVENT_CARD_READY) */
28020Sstevel@tonic-gate 
28030Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
28040Sstevel@tonic-gate 
28050Sstevel@tonic-gate 	} /* if (CS_EVENT_CARD_INSERTION) */
28060Sstevel@tonic-gate 
28070Sstevel@tonic-gate 	/*
28080Sstevel@tonic-gate 	 * Handle card ready processing.  This is only card ready processing
28090Sstevel@tonic-gate 	 *	for card ready events in conjunction with a card insertion.
28100Sstevel@tonic-gate 	 */
28110Sstevel@tonic-gate 	if (event == CS_EVENT_CARD_READY) {
28120Sstevel@tonic-gate 	    get_socket_t get_socket;
28130Sstevel@tonic-gate 	    set_socket_t set_socket;
28140Sstevel@tonic-gate 
28150Sstevel@tonic-gate 	/*
28160Sstevel@tonic-gate 	 * The only events that we want to see now are card removal
28170Sstevel@tonic-gate 	 *	events.
28180Sstevel@tonic-gate 	 */
28190Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
28200Sstevel@tonic-gate 	    sp->event_mask = CS_EVENT_CARD_REMOVAL;
28210Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
28220Sstevel@tonic-gate 	    get_socket.socket = sp->socket_num;
28230Sstevel@tonic-gate 	    if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
28240Sstevel@tonic-gate 		cmn_err(CE_CONT,
28250Sstevel@tonic-gate 			"cs_card_insertion: socket %d SS_GetSocket failed\n",
28260Sstevel@tonic-gate 							sp->socket_num);
28270Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
28280Sstevel@tonic-gate 	    }
28290Sstevel@tonic-gate 
28300Sstevel@tonic-gate 	    set_socket.socket = sp->socket_num;
28310Sstevel@tonic-gate 	    set_socket.SCIntMask = SBM_CD;
28320Sstevel@tonic-gate 	    set_socket.VccLevel = get_socket.VccLevel;
28330Sstevel@tonic-gate 	    set_socket.Vpp1Level = get_socket.Vpp1Level;
28340Sstevel@tonic-gate 	    set_socket.Vpp2Level = get_socket.Vpp2Level;
28350Sstevel@tonic-gate 	    set_socket.IREQRouting = get_socket.IRQRouting;
28360Sstevel@tonic-gate 	    set_socket.IFType = get_socket.IFType;
28370Sstevel@tonic-gate 	    set_socket.CtlInd = get_socket.CtlInd;
28380Sstevel@tonic-gate 	    /* XXX (is ~0 correct here?) to reset latched values */
28390Sstevel@tonic-gate 	    set_socket.State = (unsigned)~0;
28400Sstevel@tonic-gate 
28410Sstevel@tonic-gate 	    if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
28420Sstevel@tonic-gate 		cmn_err(CE_CONT,
28430Sstevel@tonic-gate 			"cs_card_insertion: socket %d SS_SetSocket failed\n",
28440Sstevel@tonic-gate 							sp->socket_num);
28450Sstevel@tonic-gate 
28460Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
28470Sstevel@tonic-gate 	    }
28480Sstevel@tonic-gate 
28490Sstevel@tonic-gate 		/*
28500Sstevel@tonic-gate 		 * Grab the cis_lock mutex to protect the CIS-to-be and
28510Sstevel@tonic-gate 		 *	the CIS window, then fire off the CIS parser to
28520Sstevel@tonic-gate 		 *	create a local copy of the card's CIS.
28530Sstevel@tonic-gate 		 */
28540Sstevel@tonic-gate 		mutex_enter(&sp->cis_lock);
28550Sstevel@tonic-gate 
28560Sstevel@tonic-gate 		if ((ret = cs_create_cis(sp)) != CS_SUCCESS) {
28570Sstevel@tonic-gate 		    mutex_exit(&sp->cis_lock);
28580Sstevel@tonic-gate 		    return (ret);
28590Sstevel@tonic-gate 		}
28600Sstevel@tonic-gate 
28610Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
28620Sstevel@tonic-gate 
28630Sstevel@tonic-gate 		/*
28640Sstevel@tonic-gate 		 * If we have a pending CS_EVENT_CARD_REMOVAL event it
28650Sstevel@tonic-gate 		 *	means that we likely got CD line bounce on the
28660Sstevel@tonic-gate 		 *	insertion, so destroy the CIS and terminate this
28670Sstevel@tonic-gate 		 *	processing. We'll get called back to handle the
28680Sstevel@tonic-gate 		 *	insertion again later.
28690Sstevel@tonic-gate 		 */
28700Sstevel@tonic-gate 		if (sp->events & CS_EVENT_CARD_REMOVAL) {
28710Sstevel@tonic-gate 		    mutex_enter(&sp->cis_lock);
28720Sstevel@tonic-gate 		    (void) cs_destroy_cis(sp);
28730Sstevel@tonic-gate 		    mutex_exit(&sp->cis_lock);
28740Sstevel@tonic-gate 		} else {
28750Sstevel@tonic-gate 			/*
28760Sstevel@tonic-gate 			 * Schedule the call to the Socket Services work thread.
28770Sstevel@tonic-gate 			 */
28780Sstevel@tonic-gate 		    mutex_enter(&sp->ss_thread_lock);
28790Sstevel@tonic-gate 		    sp->ss_thread_state |= SOCKET_THREAD_CSCISInit;
28800Sstevel@tonic-gate 		    cv_broadcast(&sp->ss_thread_cv);
28810Sstevel@tonic-gate 		    mutex_exit(&sp->ss_thread_lock);
28820Sstevel@tonic-gate 		} /* if (CS_EVENT_CARD_REMOVAL) */
28830Sstevel@tonic-gate 	} /* if (CS_EVENT_CARD_READY) */
28840Sstevel@tonic-gate 
28850Sstevel@tonic-gate 	/*
28860Sstevel@tonic-gate 	 * Socket Services has parsed the CIS and has done any other
28870Sstevel@tonic-gate 	 *	work to get the client driver loaded and attached if
28880Sstevel@tonic-gate 	 *	necessary, so setup the per-client state.
28890Sstevel@tonic-gate 	 */
28900Sstevel@tonic-gate 	if (event == CS_EVENT_SS_UPDATED) {
28910Sstevel@tonic-gate 	    client_t *client;
28920Sstevel@tonic-gate 
28930Sstevel@tonic-gate 	/*
28940Sstevel@tonic-gate 	 * Now that we and SS are done handling the card insertion
28950Sstevel@tonic-gate 	 *	semantics, go through each client on this socket and set
28960Sstevel@tonic-gate 	 *	the CS_EVENT_CARD_INSERTION event in each client's event
28970Sstevel@tonic-gate 	 *	field.  We do this here instead of in cs_event so that
28980Sstevel@tonic-gate 	 *	when a client gets a CS_EVENT_CARD_INSERTION event, the
28990Sstevel@tonic-gate 	 *	card insertion and ready processing has already been done
29000Sstevel@tonic-gate 	 *	and SocketServices has had a chance to create a dip for
29010Sstevel@tonic-gate 	 *	the card in this socket.
29020Sstevel@tonic-gate 	 */
29030Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
29040Sstevel@tonic-gate 	    client = sp->client_list;
29050Sstevel@tonic-gate 	    while (client) {
29060Sstevel@tonic-gate 		client->events |= (CS_EVENT_CARD_INSERTION &
29070Sstevel@tonic-gate 				(client->event_mask | client->global_mask));
29080Sstevel@tonic-gate 		client = client->next;
29090Sstevel@tonic-gate 	    } /* while (client) */
29100Sstevel@tonic-gate 
29110Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
29120Sstevel@tonic-gate 
29130Sstevel@tonic-gate 	} /* if (CS_EVENT_SS_UPDATED) */
29140Sstevel@tonic-gate 
29150Sstevel@tonic-gate 	return (CS_SUCCESS);
29160Sstevel@tonic-gate }
29170Sstevel@tonic-gate 
29180Sstevel@tonic-gate /*
29190Sstevel@tonic-gate  * cs_card_removal - handle card removal events
29200Sstevel@tonic-gate  *
29210Sstevel@tonic-gate  * Destroy the CIS.
29220Sstevel@tonic-gate  *
29230Sstevel@tonic-gate  *    calling:	sp - pointer to socket structure
29240Sstevel@tonic-gate  *
29250Sstevel@tonic-gate  */
29260Sstevel@tonic-gate static int
cs_card_removal(cs_socket_t * sp)29270Sstevel@tonic-gate cs_card_removal(cs_socket_t *sp)
29280Sstevel@tonic-gate {
29290Sstevel@tonic-gate 	set_socket_t set_socket;
29300Sstevel@tonic-gate 	int ret;
29310Sstevel@tonic-gate 
29320Sstevel@tonic-gate #ifdef	CS_DEBUG
29330Sstevel@tonic-gate 	if (cs_debug > 0) {
29340Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_card_removal: socket %d\n", sp->socket_num);
29350Sstevel@tonic-gate 	}
29360Sstevel@tonic-gate #endif
29370Sstevel@tonic-gate 
29380Sstevel@tonic-gate 	/*
29390Sstevel@tonic-gate 	 * Remove any pending card ready timer
29400Sstevel@tonic-gate 	 */
29410Sstevel@tonic-gate 	UNTIMEOUT(sp->rdybsy_tmo_id);
29420Sstevel@tonic-gate 
29430Sstevel@tonic-gate 	/*
29440Sstevel@tonic-gate 	 * Clear various flags so that everyone else knows that there's
29450Sstevel@tonic-gate 	 *	nothing on this socket anymore.  Note that we clear the
29460Sstevel@tonic-gate 	 *	SOCKET_CARD_INSERTED and SOCKET_IS_IO flags in the
29470Sstevel@tonic-gate 	 *	ss_to_cs_events event mapping function.
29480Sstevel@tonic-gate 	 */
29490Sstevel@tonic-gate 	mutex_enter(&sp->lock);
29500Sstevel@tonic-gate 	sp->thread_state &= ~(SOCKET_WAIT_FOR_READY | SOCKET_RESET_TIMER);
29510Sstevel@tonic-gate 
29520Sstevel@tonic-gate 	/*
29530Sstevel@tonic-gate 	 * Turn off socket power and set the socket back to memory mode.
29540Sstevel@tonic-gate 	 * Disable all socket events except for CARD_INSERTION events.
29550Sstevel@tonic-gate 	 */
29560Sstevel@tonic-gate 	sp->event_mask = CS_EVENT_CARD_INSERTION;
29570Sstevel@tonic-gate 	mutex_exit(&sp->lock);
29580Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
29590Sstevel@tonic-gate 	set_socket.SCIntMask = SBM_CD;
29600Sstevel@tonic-gate 	set_socket.IREQRouting = 0;
29610Sstevel@tonic-gate 	set_socket.IFType = IF_MEMORY;
29620Sstevel@tonic-gate 	set_socket.CtlInd = 0; /* turn off controls and indicators */
29630Sstevel@tonic-gate 	set_socket.State = (unsigned)~0;	/* clear latched state bits */
29640Sstevel@tonic-gate 
29650Sstevel@tonic-gate 	(void) cs_convert_powerlevel(sp->socket_num, 0, VCC,
29660Sstevel@tonic-gate 					&set_socket.VccLevel);
29670Sstevel@tonic-gate 	(void) cs_convert_powerlevel(sp->socket_num, 0, VPP1,
29680Sstevel@tonic-gate 					&set_socket.Vpp1Level);
29690Sstevel@tonic-gate 	(void) cs_convert_powerlevel(sp->socket_num, 0, VPP2,
29700Sstevel@tonic-gate 					&set_socket.Vpp2Level);
29710Sstevel@tonic-gate 
29720Sstevel@tonic-gate 	if ((ret = SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
29730Sstevel@tonic-gate 	    cmn_err(CE_CONT,
29740Sstevel@tonic-gate 		"cs_card_removal: socket %d SS_SetSocket failure %d\n",
29750Sstevel@tonic-gate 				sp->socket_num, ret);
29760Sstevel@tonic-gate 	    return (ret);
29770Sstevel@tonic-gate 	}
29780Sstevel@tonic-gate 
29790Sstevel@tonic-gate #ifdef	CS_DEBUG
29800Sstevel@tonic-gate 	if (cs_debug > 2) {
29810Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_card_removal: socket %d "
29820Sstevel@tonic-gate 					"calling cs_destroy_cis\n",
29830Sstevel@tonic-gate 							sp->socket_num);
29840Sstevel@tonic-gate 	}
29850Sstevel@tonic-gate #endif
29860Sstevel@tonic-gate 
29870Sstevel@tonic-gate 	/*
29880Sstevel@tonic-gate 	 * Destroy the CIS and tell Socket Services that we're done
29890Sstevel@tonic-gate 	 *	handling the card removal event.
29900Sstevel@tonic-gate 	 */
29910Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
29920Sstevel@tonic-gate 	(void) cs_destroy_cis(sp);
29930Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
29940Sstevel@tonic-gate 
29950Sstevel@tonic-gate #ifdef	CS_DEBUG
29960Sstevel@tonic-gate 	if (cs_debug > 2) {
29970Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_card_removal: calling CSCardRemoved\n");
29980Sstevel@tonic-gate 	}
29990Sstevel@tonic-gate #endif
30000Sstevel@tonic-gate 
30010Sstevel@tonic-gate 	SocketServices(CSCardRemoved, sp->socket_num);
30020Sstevel@tonic-gate 
30030Sstevel@tonic-gate 	return (CS_SUCCESS);
30040Sstevel@tonic-gate }
30050Sstevel@tonic-gate 
30060Sstevel@tonic-gate /*
30070Sstevel@tonic-gate  * ss_to_cs_events - convert Socket Services events to Card Services event
30080Sstevel@tonic-gate  *			masks; this function will not read the PRR if the
30090Sstevel@tonic-gate  *			socket is in IO mode; this happens in cs_event_thread
30100Sstevel@tonic-gate  *
30110Sstevel@tonic-gate  * This function returns a bit mask of events.
30120Sstevel@tonic-gate  *
30130Sstevel@tonic-gate  * Note that we do some simple hysterious on card insertion and card removal
30140Sstevel@tonic-gate  *	events to prevent spurious insertion and removal events from being
30150Sstevel@tonic-gate  *	propogated down the chain.
30160Sstevel@tonic-gate  */
30170Sstevel@tonic-gate static event_t
ss_to_cs_events(cs_socket_t * sp,event_t event)30180Sstevel@tonic-gate ss_to_cs_events(cs_socket_t *sp, event_t event)
30190Sstevel@tonic-gate {
30200Sstevel@tonic-gate 	event_t revent = 0;
30210Sstevel@tonic-gate 
30220Sstevel@tonic-gate 	switch (event) {
30230Sstevel@tonic-gate 	    case PCE_CARD_STATUS_CHANGE:
30240Sstevel@tonic-gate 		revent |= CS_EVENT_STATUS_CHANGE;
30250Sstevel@tonic-gate 		break;
30260Sstevel@tonic-gate 	    case PCE_CARD_REMOVAL:
30270Sstevel@tonic-gate 		if (sp->flags & SOCKET_CARD_INSERTED) {
30280Sstevel@tonic-gate 		    sp->flags &= ~(SOCKET_CARD_INSERTED | SOCKET_IS_IO);
30290Sstevel@tonic-gate 		    revent |= CS_EVENT_CARD_REMOVAL;
30300Sstevel@tonic-gate 			/*
30310Sstevel@tonic-gate 			 * If we're processing a removal event, it makes
30320Sstevel@tonic-gate 			 *	no sense to keep any insertion or ready events,
30330Sstevel@tonic-gate 			 *	so nuke them here.  This will not clear any
30340Sstevel@tonic-gate 			 *	insertion events in the per-client event field.
30350Sstevel@tonic-gate 			 */
30360Sstevel@tonic-gate 		    sp->events &= ~(CS_EVENT_CARD_INSERTION |
30370Sstevel@tonic-gate 				    CS_EVENT_CARD_READY |
30380Sstevel@tonic-gate 				    CS_EVENT_READY_TIMEOUT);
30390Sstevel@tonic-gate 
30400Sstevel@tonic-gate 		/*
30410Sstevel@tonic-gate 		 * We also don't need to wait for READY anymore since
30420Sstevel@tonic-gate 		 *	it probably won't show up, or if it does, it will
30430Sstevel@tonic-gate 		 *	be a bogus READY event as the card is sliding out
30440Sstevel@tonic-gate 		 *	of the socket.  Since we never do a cv_wait on the
30450Sstevel@tonic-gate 		 *	card ready timer, it's OK for that timer to either
30460Sstevel@tonic-gate 		 *	never go off (via an UNTIMEOUT in cs_card_removal)
30470Sstevel@tonic-gate 		 *	or to go off but not do a cv_broadcast (since the
30480Sstevel@tonic-gate 		 *	SOCKET_WAIT_FOR_READY flag is cleared here).
30490Sstevel@tonic-gate 		 */
30500Sstevel@tonic-gate 		    sp->thread_state &= ~SOCKET_WAIT_FOR_READY;
30510Sstevel@tonic-gate 
30520Sstevel@tonic-gate 		}
30530Sstevel@tonic-gate 		break;
30540Sstevel@tonic-gate 	    case PCE_CARD_INSERT:
30550Sstevel@tonic-gate 		if (!(sp->flags & SOCKET_CARD_INSERTED)) {
30560Sstevel@tonic-gate 		    sp->flags |= SOCKET_CARD_INSERTED;
30570Sstevel@tonic-gate 		    revent |= CS_EVENT_CARD_INSERTION;
30580Sstevel@tonic-gate 		}
30590Sstevel@tonic-gate 		break;
30600Sstevel@tonic-gate 	    case PCE_CARD_READY:
30610Sstevel@tonic-gate 		if (sp->flags & SOCKET_CARD_INSERTED)
30620Sstevel@tonic-gate 		    revent |= CS_EVENT_CARD_READY;
30630Sstevel@tonic-gate 		break;
30640Sstevel@tonic-gate 	    case PCE_CARD_BATTERY_WARN:
30650Sstevel@tonic-gate 		if (sp->flags & SOCKET_CARD_INSERTED)
30660Sstevel@tonic-gate 		    revent |= CS_EVENT_BATTERY_LOW;
30670Sstevel@tonic-gate 		break;
30680Sstevel@tonic-gate 	    case PCE_CARD_BATTERY_DEAD:
30690Sstevel@tonic-gate 		if (sp->flags & SOCKET_CARD_INSERTED)
30700Sstevel@tonic-gate 		    revent |= CS_EVENT_BATTERY_DEAD;
30710Sstevel@tonic-gate 		break;
30720Sstevel@tonic-gate 	    case PCE_CARD_WRITE_PROTECT:
30730Sstevel@tonic-gate 		if (sp->flags & SOCKET_CARD_INSERTED)
30740Sstevel@tonic-gate 		    revent |= CS_EVENT_WRITE_PROTECT;
30750Sstevel@tonic-gate 		break;
30760Sstevel@tonic-gate 	    case PCE_PM_RESUME:
30770Sstevel@tonic-gate 		revent |= CS_EVENT_PM_RESUME;
30780Sstevel@tonic-gate 		break;
30790Sstevel@tonic-gate 	    case PCE_PM_SUSPEND:
30800Sstevel@tonic-gate 		revent |= CS_EVENT_PM_SUSPEND;
30810Sstevel@tonic-gate 		break;
30820Sstevel@tonic-gate 	    default:
30830Sstevel@tonic-gate 		cmn_err(CE_CONT, "ss_to_cs_events: unknown event 0x%x\n",
30840Sstevel@tonic-gate 								(int)event);
30850Sstevel@tonic-gate 		break;
30860Sstevel@tonic-gate 	} /* switch(event) */
30870Sstevel@tonic-gate 
30880Sstevel@tonic-gate 	return (revent);
30890Sstevel@tonic-gate }
30900Sstevel@tonic-gate 
30910Sstevel@tonic-gate /*
30920Sstevel@tonic-gate  * cs_ready_timeout - general purpose READY/BUSY and RESET timer
30930Sstevel@tonic-gate  *
30940Sstevel@tonic-gate  * Note that we really only expect one of the two events to be asserted when
30950Sstevel@tonic-gate  *	we are called.  XXX - Perhaps this might be a problem later on??
30960Sstevel@tonic-gate  *
30970Sstevel@tonic-gate  *	There is also the problem of cv_broadcast dropping the interrupt
30980Sstevel@tonic-gate  *	priority, even though we have our high-priority mutex held.  If
30990Sstevel@tonic-gate  *	we hold our high-priority mutex (sp->lock) over a cv_broadcast, and
31000Sstevel@tonic-gate  *	we get a high-priority interrupt during this time, the system will
31010Sstevel@tonic-gate  *	deadlock or panic.  Thanks to Andy Banta for finding this out in
31020Sstevel@tonic-gate  *	the SPC/S (stc.c) driver.
31030Sstevel@tonic-gate  *
31040Sstevel@tonic-gate  * This callback routine can not grab the sp->client_lock mutex or deadlock
31050Sstevel@tonic-gate  *	will result.
31060Sstevel@tonic-gate  */
31070Sstevel@tonic-gate void
cs_ready_timeout(void * arg)31080Sstevel@tonic-gate cs_ready_timeout(void *arg)
31090Sstevel@tonic-gate {
31100Sstevel@tonic-gate 	cs_socket_t *sp = arg;
31110Sstevel@tonic-gate 	kcondvar_t *cvp = NULL;
31120Sstevel@tonic-gate 
31130Sstevel@tonic-gate 	mutex_enter(&sp->lock);
31140Sstevel@tonic-gate 
31150Sstevel@tonic-gate 	if (sp->thread_state & SOCKET_RESET_TIMER) {
31160Sstevel@tonic-gate #ifdef	CS_DEBUG
31170Sstevel@tonic-gate 	if (cs_debug > 1) {
31180Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_ready_timeout: SOCKET_RESET_TIMER socket %d\n",
31190Sstevel@tonic-gate 							sp->socket_num);
31200Sstevel@tonic-gate 	}
31210Sstevel@tonic-gate #endif
31220Sstevel@tonic-gate 
31230Sstevel@tonic-gate 	    cvp = &sp->reset_cv;
31240Sstevel@tonic-gate 	}
31250Sstevel@tonic-gate 
31260Sstevel@tonic-gate 	if (sp->thread_state & SOCKET_WAIT_FOR_READY) {
31270Sstevel@tonic-gate 	    sp->events |= CS_EVENT_READY_TIMEOUT;
31280Sstevel@tonic-gate 	    cvp = &sp->thread_cv;
31290Sstevel@tonic-gate 
31300Sstevel@tonic-gate #ifdef	CS_DEBUG
31310Sstevel@tonic-gate 	    if (cs_debug > 1) {
31320Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_ready_timeout: SOCKET_WAIT_FOR_READY "
31330Sstevel@tonic-gate 						"socket %d\n", sp->socket_num);
31340Sstevel@tonic-gate 	    }
31350Sstevel@tonic-gate #endif
31360Sstevel@tonic-gate 
31370Sstevel@tonic-gate 	}
31380Sstevel@tonic-gate 
31390Sstevel@tonic-gate 	mutex_exit(&sp->lock);
31400Sstevel@tonic-gate 
31410Sstevel@tonic-gate 	if (cvp)
31420Sstevel@tonic-gate 	    cv_broadcast(cvp);
31430Sstevel@tonic-gate }
31440Sstevel@tonic-gate 
31450Sstevel@tonic-gate /*
31460Sstevel@tonic-gate  * cs_event_softintr_timeout - wrapper function to call cs_socket_event_softintr
31470Sstevel@tonic-gate  */
31480Sstevel@tonic-gate /* ARGSUSED */
31490Sstevel@tonic-gate void
cs_event_softintr_timeout(void * arg)31500Sstevel@tonic-gate cs_event_softintr_timeout(void *arg)
31510Sstevel@tonic-gate {
31520Sstevel@tonic-gate 
31530Sstevel@tonic-gate 	/*
31540Sstevel@tonic-gate 	 * If we're trying to unload this module, then don't do
31550Sstevel@tonic-gate 	 *	anything but exit.
31560Sstevel@tonic-gate 	 * We acquire the cs_globals.global_lock mutex here so that
31570Sstevel@tonic-gate 	 *	we can correctly synchronize with cs_deinit when it
31580Sstevel@tonic-gate 	 *	is telling us to shut down. XXX - is this bogus??
31590Sstevel@tonic-gate 	 */
31600Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
31610Sstevel@tonic-gate 	if (!(cs_globals.init_state & GLOBAL_INIT_STATE_UNLOADING)) {
31620Sstevel@tonic-gate 	    mutex_exit(&cs_globals.global_lock);
31630Sstevel@tonic-gate 	    (void) cs_socket_event_softintr(NULL);
31640Sstevel@tonic-gate 	    cs_globals.sotfint_tmo = timeout(cs_event_softintr_timeout,
31650Sstevel@tonic-gate 		NULL, SOFTINT_TIMEOUT_TIME);
31660Sstevel@tonic-gate 	} else {
31670Sstevel@tonic-gate 	    mutex_exit(&cs_globals.global_lock);
31680Sstevel@tonic-gate 	}
31690Sstevel@tonic-gate }
31700Sstevel@tonic-gate 
31710Sstevel@tonic-gate /*
31720Sstevel@tonic-gate  * cs_socket_event_softintr - This function just does a cv_broadcast on behalf
31730Sstevel@tonic-gate  *				of the high-priority interrupt handler.
31740Sstevel@tonic-gate  *
31750Sstevel@tonic-gate  *	Note: There is no calling argument.
31760Sstevel@tonic-gate  */
31770Sstevel@tonic-gate /*ARGSUSED*/
31780Sstevel@tonic-gate uint32_t
cs_socket_event_softintr(caddr_t notused)31790Sstevel@tonic-gate cs_socket_event_softintr(caddr_t notused)
31800Sstevel@tonic-gate {
31810Sstevel@tonic-gate 	cs_socket_t *sp;
31820Sstevel@tonic-gate 	uint32_t sn;
31830Sstevel@tonic-gate 	int ret = DDI_INTR_UNCLAIMED;
31840Sstevel@tonic-gate 
31850Sstevel@tonic-gate 	/*
31860Sstevel@tonic-gate 	 * If the module is on it's way out, then don't bother
31870Sstevel@tonic-gate 	 *	to do anything else except return.
31880Sstevel@tonic-gate 	 */
31890Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
31900Sstevel@tonic-gate 	if ((cs_globals.init_state & GLOBAL_INIT_STATE_UNLOADING) ||
31910Sstevel@tonic-gate 				(cs_globals.init_state & GLOBAL_IN_SOFTINTR)) {
31920Sstevel@tonic-gate 		mutex_exit(&cs_globals.global_lock);
31930Sstevel@tonic-gate 
31940Sstevel@tonic-gate 		/*
31950Sstevel@tonic-gate 		 * Note that we return DDI_INTR_UNCLAIMED here
31960Sstevel@tonic-gate 		 *	since we don't want to be constantly
31970Sstevel@tonic-gate 		 *	called back.
31980Sstevel@tonic-gate 		 */
31990Sstevel@tonic-gate 		return (ret);
32000Sstevel@tonic-gate 	} else {
32010Sstevel@tonic-gate 	    cs_globals.init_state |= GLOBAL_IN_SOFTINTR;
32020Sstevel@tonic-gate 	    mutex_exit(&cs_globals.global_lock);
32030Sstevel@tonic-gate 	}
32040Sstevel@tonic-gate 
32050Sstevel@tonic-gate 	/*
32060Sstevel@tonic-gate 	 * Go through each socket and dispatch the appropriate events.
32070Sstevel@tonic-gate 	 *	We have to funnel everything through this one routine because
32080Sstevel@tonic-gate 	 *	we can't do a cv_broadcast from a high level interrupt handler
32090Sstevel@tonic-gate 	 *	and we also can't have more than one soft interrupt handler
32100Sstevel@tonic-gate 	 *	on a single dip and using the same handler address.
32110Sstevel@tonic-gate 	 */
32120Sstevel@tonic-gate 	for (sn = 0; sn < cs_globals.max_socket_num; sn++) {
32130Sstevel@tonic-gate 	    if ((sp = cs_get_sp(sn)) != NULL) {
32140Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_READY) {
32150Sstevel@tonic-gate 			/*
32160Sstevel@tonic-gate 			 * If we're being asked to unload CS, then don't bother
32170Sstevel@tonic-gate 			 *	waking up the socket event thread handler.
32180Sstevel@tonic-gate 			 */
32190Sstevel@tonic-gate 		    if (!(sp->flags & SOCKET_UNLOAD_MODULE) &&
32200Sstevel@tonic-gate 					(sp->flags & SOCKET_NEEDS_THREAD)) {
32210Sstevel@tonic-gate 			ret = DDI_INTR_CLAIMED;
32220Sstevel@tonic-gate 			mutex_enter(&sp->client_lock);
32230Sstevel@tonic-gate 			cv_broadcast(&sp->thread_cv);
32240Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
32250Sstevel@tonic-gate 		    } /* if (SOCKET_NEEDS_THREAD) */
32260Sstevel@tonic-gate 		} /* if (SOCKET_INIT_STATE_READY) */
32270Sstevel@tonic-gate 	    } /* cs_get_sp */
32280Sstevel@tonic-gate 	} /* for (sn) */
32290Sstevel@tonic-gate 
32300Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
32310Sstevel@tonic-gate 	cs_globals.init_state &= ~GLOBAL_IN_SOFTINTR;
32320Sstevel@tonic-gate 	mutex_exit(&cs_globals.global_lock);
32330Sstevel@tonic-gate 
32340Sstevel@tonic-gate 	return (ret);
32350Sstevel@tonic-gate }
32360Sstevel@tonic-gate 
32370Sstevel@tonic-gate /*
32380Sstevel@tonic-gate  * cs_event_thread - This is the per-socket event thread.
32390Sstevel@tonic-gate  */
32400Sstevel@tonic-gate static void
cs_event_thread(uint32_t sn)32410Sstevel@tonic-gate cs_event_thread(uint32_t sn)
32420Sstevel@tonic-gate {
32430Sstevel@tonic-gate 	cs_socket_t	*sp;
32440Sstevel@tonic-gate 	client_t	*client;
32450Sstevel@tonic-gate 	client_types_t	*ct;
32460Sstevel@tonic-gate 
32470Sstevel@tonic-gate 	if ((sp = cs_get_sp(sn)) == NULL)
32480Sstevel@tonic-gate 	    return;
32490Sstevel@tonic-gate 
32500Sstevel@tonic-gate #ifdef	CS_DEBUG
32510Sstevel@tonic-gate 	if (cs_debug > 1) {
32520Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_event_thread: socket %d thread started\n",
32530Sstevel@tonic-gate 								sp->socket_num);
32540Sstevel@tonic-gate 	}
32550Sstevel@tonic-gate #endif
32560Sstevel@tonic-gate 
32570Sstevel@tonic-gate 	CALLB_CPR_INIT(&sp->cprinfo_cs, &sp->client_lock,
32580Sstevel@tonic-gate 					callb_generic_cpr, "cs_event_thread");
32590Sstevel@tonic-gate 
32600Sstevel@tonic-gate 	mutex_enter(&sp->client_lock);
32610Sstevel@tonic-gate 
32620Sstevel@tonic-gate 	for (;;) {
32630Sstevel@tonic-gate 
32640Sstevel@tonic-gate 	    CALLB_CPR_SAFE_BEGIN(&sp->cprinfo_cs);
32650Sstevel@tonic-gate 	    cv_wait(&sp->thread_cv, &sp->client_lock);
32660Sstevel@tonic-gate 	    CALLB_CPR_SAFE_END(&sp->cprinfo_cs, &sp->client_lock);
32670Sstevel@tonic-gate 
32680Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
32690Sstevel@tonic-gate 	    sp->flags &= ~SOCKET_NEEDS_THREAD;
32700Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
32710Sstevel@tonic-gate 
32720Sstevel@tonic-gate 	/*
32730Sstevel@tonic-gate 	 * Check to see if there are any special thread operations that
32740Sstevel@tonic-gate 	 *	we are being asked to perform.
32750Sstevel@tonic-gate 	 */
32760Sstevel@tonic-gate 	    if (sp->thread_state & SOCKET_THREAD_EXIT) {
32770Sstevel@tonic-gate #ifdef	CS_DEBUG
32780Sstevel@tonic-gate 		if (cs_debug > 1) {
32790Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_event_thread: socket %d "
32800Sstevel@tonic-gate 							"SOCKET_THREAD_EXIT\n",
32810Sstevel@tonic-gate 							sp->socket_num);
32820Sstevel@tonic-gate 		}
32830Sstevel@tonic-gate #endif
32840Sstevel@tonic-gate 		CALLB_CPR_EXIT(&sp->cprinfo_cs);
32850Sstevel@tonic-gate 		cv_broadcast(&sp->caller_cv);	/* wakes up cs_deinit */
32860Sstevel@tonic-gate 		mutex_exit(&sp->client_lock);
32870Sstevel@tonic-gate 		return;
32880Sstevel@tonic-gate 	    } /* if (SOCKET_THREAD_EXIT) */
32890Sstevel@tonic-gate 
32900Sstevel@tonic-gate #ifdef	CS_DEBUG
32910Sstevel@tonic-gate 	    if (cs_debug > 1) {
32920Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_event_thread: socket %d sp->events 0x%x\n",
32930Sstevel@tonic-gate 							sp->socket_num,
32940Sstevel@tonic-gate 							(int)sp->events);
32950Sstevel@tonic-gate 	    }
32960Sstevel@tonic-gate #endif
32970Sstevel@tonic-gate 
32980Sstevel@tonic-gate 	/*
32990Sstevel@tonic-gate 	 * Handle CS_EVENT_CARD_INSERTION events
33000Sstevel@tonic-gate 	 */
33010Sstevel@tonic-gate 	    if (sp->events & CS_EVENT_CARD_INSERTION) {
33020Sstevel@tonic-gate 		mutex_enter(&sp->lock);
33030Sstevel@tonic-gate 		sp->events &= ~CS_EVENT_CARD_INSERTION;
33040Sstevel@tonic-gate 		mutex_exit(&sp->lock);
33050Sstevel@tonic-gate 
33060Sstevel@tonic-gate 		/*
33070Sstevel@tonic-gate 		 * If we have a pending CS_EVENT_CARD_REMOVAL event it
33080Sstevel@tonic-gate 		 *	means that we likely got CD line bounce on the
33090Sstevel@tonic-gate 		 *	insertion, so terminate this processing.
33100Sstevel@tonic-gate 		 */
33110Sstevel@tonic-gate 		if ((sp->events & CS_EVENT_CARD_REMOVAL) == 0) {
33120Sstevel@tonic-gate 		    (void) cs_card_insertion(sp, CS_EVENT_CARD_INSERTION);
33130Sstevel@tonic-gate 		}
33140Sstevel@tonic-gate #ifdef	CS_DEBUG
33150Sstevel@tonic-gate 		else if (cs_debug > 0) {
33160Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_event_thread: socket %d "
33170Sstevel@tonic-gate 					"CS_EVENT_CARD_REMOVAL event "
33180Sstevel@tonic-gate 					"terminating "
33190Sstevel@tonic-gate 					"CS_EVENT_CARD_INSERTION "
33200Sstevel@tonic-gate 					"processing\n", sp->socket_num);
33210Sstevel@tonic-gate 		    }
33220Sstevel@tonic-gate #endif
33230Sstevel@tonic-gate 	} /* if (CS_EVENT_CARD_INSERTION) */
33240Sstevel@tonic-gate 
33250Sstevel@tonic-gate 	/*
33260Sstevel@tonic-gate 	 * Handle CS_EVENT_CARD_READY and CS_EVENT_READY_TIMEOUT events
33270Sstevel@tonic-gate 	 */
33280Sstevel@tonic-gate 	    if (sp->events & (CS_EVENT_CARD_READY | CS_EVENT_READY_TIMEOUT)) {
33290Sstevel@tonic-gate 		mutex_enter(&sp->lock);
33300Sstevel@tonic-gate 		sp->events &= ~(CS_EVENT_CARD_READY | CS_EVENT_READY_TIMEOUT);
33310Sstevel@tonic-gate 		mutex_exit(&sp->lock);
33320Sstevel@tonic-gate 		if (sp->thread_state & SOCKET_WAIT_FOR_READY) {
33330Sstevel@tonic-gate 		    mutex_enter(&sp->lock);
33340Sstevel@tonic-gate 		    sp->thread_state &= ~SOCKET_WAIT_FOR_READY;
33350Sstevel@tonic-gate 		    mutex_exit(&sp->lock);
33360Sstevel@tonic-gate 		    (void) cs_card_insertion(sp, CS_EVENT_CARD_READY);
33370Sstevel@tonic-gate 		} /* if (SOCKET_WAIT_FOR_READY) */
33380Sstevel@tonic-gate 	    } /* if (CS_EVENT_CARD_READY) */
33390Sstevel@tonic-gate 
33400Sstevel@tonic-gate 	/*
33410Sstevel@tonic-gate 	 * Handle CS_EVENT_SS_UPDATED events
33420Sstevel@tonic-gate 	 */
33430Sstevel@tonic-gate 	    if (sp->events & CS_EVENT_SS_UPDATED) {
33440Sstevel@tonic-gate 		mutex_enter(&sp->lock);
33450Sstevel@tonic-gate 		sp->events &= ~CS_EVENT_SS_UPDATED;
33460Sstevel@tonic-gate 		mutex_exit(&sp->lock);
33470Sstevel@tonic-gate 		(void) cs_card_insertion(sp, CS_EVENT_SS_UPDATED);
33480Sstevel@tonic-gate 	    } /* if (CS_EVENT_SS_UPDATED) */
33490Sstevel@tonic-gate 
33500Sstevel@tonic-gate 	/*
33510Sstevel@tonic-gate 	 * Handle CS_EVENT_STATUS_CHANGE events
33520Sstevel@tonic-gate 	 */
33530Sstevel@tonic-gate 	    if (sp->events & CS_EVENT_STATUS_CHANGE) {
33540Sstevel@tonic-gate 		event_t revent;
33550Sstevel@tonic-gate 
33560Sstevel@tonic-gate 		mutex_enter(&sp->cis_lock);
33570Sstevel@tonic-gate 		mutex_enter(&sp->lock);
33580Sstevel@tonic-gate 		sp->events &= ~CS_EVENT_STATUS_CHANGE;
33590Sstevel@tonic-gate 
33600Sstevel@tonic-gate 		/*
33610Sstevel@tonic-gate 		 * Go through each client and add any events that we saw to
33620Sstevel@tonic-gate 		 *	the client's event list if the client has that event
33630Sstevel@tonic-gate 		 *	enabled in their event mask.
33640Sstevel@tonic-gate 		 * Remove any events that may be pending for this client if
33650Sstevel@tonic-gate 		 *	the client's event mask says that the client doesn't
33660Sstevel@tonic-gate 		 *	want to see those events anymore. This handles the
33670Sstevel@tonic-gate 		 *	case where the client had an event enabled in it's
33680Sstevel@tonic-gate 		 *	event mask when the event came in but between that
33690Sstevel@tonic-gate 		 *	time and the time we're called here the client
33700Sstevel@tonic-gate 		 *	disabled that event.
33710Sstevel@tonic-gate 		 */
33720Sstevel@tonic-gate 		client = sp->client_list;
33730Sstevel@tonic-gate 
33740Sstevel@tonic-gate 		while (client) {
33750Sstevel@tonic-gate 			/*
33760Sstevel@tonic-gate 			 * Read the PRR (if it exists) and check for any events.
33770Sstevel@tonic-gate 			 * The PRR will only be read if the socket is in IO
33780Sstevel@tonic-gate 			 * mode, if there is a card in the socket, and if there
33790Sstevel@tonic-gate 			 * is a PRR.
33800Sstevel@tonic-gate 			 * We don't have to clear revent before we call the
33810Sstevel@tonic-gate 			 * cs_read_event_status function since it will
33820Sstevel@tonic-gate 			 * clear it before adding any current events.
33830Sstevel@tonic-gate 			 */
33840Sstevel@tonic-gate 		    if (client->flags & CLIENT_CARD_INSERTED) {
33850Sstevel@tonic-gate 			(void) cs_read_event_status(sp, client,
33860Sstevel@tonic-gate 							&revent, NULL, 0);
33870Sstevel@tonic-gate 
33880Sstevel@tonic-gate 			client->events = ((client->events | revent) &
33890Sstevel@tonic-gate 						(client->event_mask |
33900Sstevel@tonic-gate 							client->global_mask));
33910Sstevel@tonic-gate 		    } /* CLIENT_CARD_INSERTED */
33920Sstevel@tonic-gate 		    client = client->next;
33930Sstevel@tonic-gate 		} /* while (client) */
33940Sstevel@tonic-gate 
33950Sstevel@tonic-gate 		mutex_exit(&sp->lock);
33960Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
33970Sstevel@tonic-gate 	    } /* if (CS_EVENT_STATUS_CHANGE) */
33980Sstevel@tonic-gate 
33990Sstevel@tonic-gate 	/*
34000Sstevel@tonic-gate 	 * We want to maintain the required event dispatching order as
34010Sstevel@tonic-gate 	 *	specified in the PCMCIA spec, so we cycle through all
34020Sstevel@tonic-gate 	 *	clients on this socket to make sure that they are
34030Sstevel@tonic-gate 	 *	notified in the correct order.
34040Sstevel@tonic-gate 	 */
34050Sstevel@tonic-gate 	    ct = &client_types[0];
34060Sstevel@tonic-gate 	    while (ct) {
34070Sstevel@tonic-gate 		/*
34080Sstevel@tonic-gate 		 * Point to the head of the client list for this socket, and go
34090Sstevel@tonic-gate 		 *	through each client to set up the client events as well
34100Sstevel@tonic-gate 		 *	as call the client's event handler directly if we have
34110Sstevel@tonic-gate 		 *	a high priority event that we need to tell the client
34120Sstevel@tonic-gate 		 *	about.
34130Sstevel@tonic-gate 		 */
34140Sstevel@tonic-gate 		client = sp->client_list;
34150Sstevel@tonic-gate 
34160Sstevel@tonic-gate 		if (ct->order & CLIENT_EVENTS_LIFO) {
34170Sstevel@tonic-gate 		    client_t *clp = NULL;
34180Sstevel@tonic-gate 
34190Sstevel@tonic-gate 		    while (client) {
34200Sstevel@tonic-gate 			clp = client;
34210Sstevel@tonic-gate 			client = client->next;
34220Sstevel@tonic-gate 		    }
34230Sstevel@tonic-gate 		    client = clp;
34240Sstevel@tonic-gate 		}
34250Sstevel@tonic-gate 
34260Sstevel@tonic-gate 		while (client) {
34270Sstevel@tonic-gate 		    if (client->flags & ct->type) {
34280Sstevel@tonic-gate 			    uint32_t bit = 0;
34290Sstevel@tonic-gate 			    event_t event;
34300Sstevel@tonic-gate 
34310Sstevel@tonic-gate 			while (client->events) {
34320Sstevel@tonic-gate 
34330Sstevel@tonic-gate 			    switch (event = CS_BIT_GET(client->events, bit)) {
34340Sstevel@tonic-gate 				/*
34350Sstevel@tonic-gate 				 * Clients always receive registration complete
34360Sstevel@tonic-gate 				 *	events, even if there is no card of
34370Sstevel@tonic-gate 				 *	their type currently in the socket.
34380Sstevel@tonic-gate 				 */
34390Sstevel@tonic-gate 				case CS_EVENT_REGISTRATION_COMPLETE:
34400Sstevel@tonic-gate 				    CLIENT_EVENT_CALLBACK(client, event,
34410Sstevel@tonic-gate 							CS_EVENT_PRI_LOW);
34420Sstevel@tonic-gate 				    break;
34430Sstevel@tonic-gate 				/*
34440Sstevel@tonic-gate 				 * The client only gets a card insertion event
34450Sstevel@tonic-gate 				 *	if there is currently a card in the
34460Sstevel@tonic-gate 				 *	socket that the client can control.
34470Sstevel@tonic-gate 				 *	The nexus determines this. We also
34480Sstevel@tonic-gate 				 *	prevent the client from receiving
34490Sstevel@tonic-gate 				 *	multiple CS_EVENT_CARD_INSERTION
34500Sstevel@tonic-gate 				 *	events without receiving intervening
34510Sstevel@tonic-gate 				 *	CS_EVENT_CARD_REMOVAL events.
34520Sstevel@tonic-gate 				 */
34530Sstevel@tonic-gate 				case CS_EVENT_CARD_INSERTION:
34540Sstevel@tonic-gate 				    if (cs_card_for_client(client)) {
34550Sstevel@tonic-gate 					int send_insertion;
34560Sstevel@tonic-gate 
34570Sstevel@tonic-gate 					mutex_enter(&sp->lock);
34580Sstevel@tonic-gate 					send_insertion = client->flags;
34590Sstevel@tonic-gate 					client->flags |=
34600Sstevel@tonic-gate 						(CLIENT_CARD_INSERTED |
34610Sstevel@tonic-gate 						CLIENT_SENT_INSERTION);
34620Sstevel@tonic-gate 					mutex_exit(&sp->lock);
34630Sstevel@tonic-gate 					if (!(send_insertion &
34640Sstevel@tonic-gate 						    CLIENT_SENT_INSERTION)) {
34650Sstevel@tonic-gate 					    CLIENT_EVENT_CALLBACK(client,
34660Sstevel@tonic-gate 						event, CS_EVENT_PRI_LOW);
34670Sstevel@tonic-gate 					} /* if (!CLIENT_SENT_INSERTION) */
34680Sstevel@tonic-gate 				    }
34690Sstevel@tonic-gate 				    break;
34700Sstevel@tonic-gate 				/*
34710Sstevel@tonic-gate 				 * The CS_EVENT_CARD_REMOVAL_LOWP is a low
34720Sstevel@tonic-gate 				 *	priority CS_EVENT_CARD_REMOVAL event.
34730Sstevel@tonic-gate 				 */
34740Sstevel@tonic-gate 				case CS_EVENT_CARD_REMOVAL_LOWP:
34750Sstevel@tonic-gate 				    mutex_enter(&sp->lock);
34760Sstevel@tonic-gate 				    client->flags &= ~CLIENT_SENT_INSERTION;
34770Sstevel@tonic-gate 				    mutex_exit(&sp->lock);
34780Sstevel@tonic-gate 				    CLIENT_EVENT_CALLBACK(client,
34790Sstevel@tonic-gate 							CS_EVENT_CARD_REMOVAL,
34800Sstevel@tonic-gate 							CS_EVENT_PRI_LOW);
34810Sstevel@tonic-gate 				    break;
34820Sstevel@tonic-gate 				/*
34830Sstevel@tonic-gate 				 * The hardware card removal events are handed
34840Sstevel@tonic-gate 				 *	to the client in cs_event at high
34850Sstevel@tonic-gate 				 *	priority interrupt time; this card
34860Sstevel@tonic-gate 				 *	removal event is a software-generated
34870Sstevel@tonic-gate 				 *	event.
34880Sstevel@tonic-gate 				 */
34890Sstevel@tonic-gate 				case CS_EVENT_CARD_REMOVAL:
34900Sstevel@tonic-gate 				    if (client->flags & CLIENT_CARD_INSERTED) {
34910Sstevel@tonic-gate 					mutex_enter(&sp->lock);
34920Sstevel@tonic-gate 					client->flags &=
34930Sstevel@tonic-gate 						~(CLIENT_CARD_INSERTED |
34940Sstevel@tonic-gate 						CLIENT_SENT_INSERTION);
34950Sstevel@tonic-gate 					mutex_exit(&sp->lock);
34960Sstevel@tonic-gate 					CLIENT_EVENT_CALLBACK(client, event,
34970Sstevel@tonic-gate 							CS_EVENT_PRI_LOW);
34980Sstevel@tonic-gate 				    }
34990Sstevel@tonic-gate 				    break;
35000Sstevel@tonic-gate 				/*
35010Sstevel@tonic-gate 				 * Write protect events require the info field
35020Sstevel@tonic-gate 				 *	of the client's event callback args to
35030Sstevel@tonic-gate 				 *	be zero if the card is not write
35040Sstevel@tonic-gate 				 *	protected and one if it is.
35050Sstevel@tonic-gate 				 */
35060Sstevel@tonic-gate 				case CS_EVENT_WRITE_PROTECT:
35070Sstevel@tonic-gate 				    if (client->flags & CLIENT_CARD_INSERTED) {
35080Sstevel@tonic-gate 					get_ss_status_t gs;
35090Sstevel@tonic-gate 
35100Sstevel@tonic-gate 					mutex_enter(&sp->cis_lock);
35110Sstevel@tonic-gate 					mutex_enter(&sp->lock);
35120Sstevel@tonic-gate 					(void) cs_read_event_status(sp, client,
35130Sstevel@tonic-gate 									NULL,
35140Sstevel@tonic-gate 									&gs, 0);
35150Sstevel@tonic-gate 					if (gs.CardState & SBM_WP) {
35160Sstevel@tonic-gate 					    client->event_callback_args.info =
35170Sstevel@tonic-gate 						(void *)
35180Sstevel@tonic-gate 						CS_EVENT_WRITE_PROTECT_WPON;
35190Sstevel@tonic-gate 					} else {
35200Sstevel@tonic-gate 					    client->event_callback_args.info =
35210Sstevel@tonic-gate 						(void *)
35220Sstevel@tonic-gate 						CS_EVENT_WRITE_PROTECT_WPOFF;
35230Sstevel@tonic-gate 					}
35240Sstevel@tonic-gate 					mutex_exit(&sp->lock);
35250Sstevel@tonic-gate 					mutex_exit(&sp->cis_lock);
35260Sstevel@tonic-gate 					CLIENT_EVENT_CALLBACK(client, event,
35270Sstevel@tonic-gate 							CS_EVENT_PRI_LOW);
35280Sstevel@tonic-gate 				    } /* CLIENT_CARD_INSERTED */
35290Sstevel@tonic-gate 				    break;
35300Sstevel@tonic-gate 				case CS_EVENT_CLIENT_INFO:
35310Sstevel@tonic-gate 				    CLIENT_EVENT_CALLBACK(client, event,
35320Sstevel@tonic-gate 							CS_EVENT_PRI_LOW);
35330Sstevel@tonic-gate 				    break;
35340Sstevel@tonic-gate 				case 0:
35350Sstevel@tonic-gate 				    break;
35360Sstevel@tonic-gate 				default:
35370Sstevel@tonic-gate 				    if (client->flags & CLIENT_CARD_INSERTED) {
35380Sstevel@tonic-gate 					CLIENT_EVENT_CALLBACK(client, event,
35390Sstevel@tonic-gate 							CS_EVENT_PRI_LOW);
35400Sstevel@tonic-gate 				    }
35410Sstevel@tonic-gate 				    break;
35420Sstevel@tonic-gate 			    } /* switch */
35430Sstevel@tonic-gate 			    mutex_enter(&sp->lock);
35440Sstevel@tonic-gate 			    CS_BIT_CLEAR(client->events, bit);
35450Sstevel@tonic-gate 			    mutex_exit(&sp->lock);
35460Sstevel@tonic-gate 			    bit++;
35470Sstevel@tonic-gate 			} /* while (client->events) */
35480Sstevel@tonic-gate 		    } /* if (ct->type) */
35490Sstevel@tonic-gate 		    if (ct->order & CLIENT_EVENTS_LIFO) {
35500Sstevel@tonic-gate 			client = client->prev;
35510Sstevel@tonic-gate 		    } else {
35520Sstevel@tonic-gate 			client = client->next;
35530Sstevel@tonic-gate 		    }
35540Sstevel@tonic-gate 		} /* while (client) */
35550Sstevel@tonic-gate 
35560Sstevel@tonic-gate 		ct = ct->next;
35570Sstevel@tonic-gate 	    } /* while (ct) */
35580Sstevel@tonic-gate 
35590Sstevel@tonic-gate 	/*
35600Sstevel@tonic-gate 	 * Handle CS_EVENT_CARD_REMOVAL events
35610Sstevel@tonic-gate 	 */
35620Sstevel@tonic-gate 	    if (sp->events & CS_EVENT_CARD_REMOVAL) {
35630Sstevel@tonic-gate 		mutex_enter(&sp->lock);
35640Sstevel@tonic-gate 		sp->events &= ~CS_EVENT_CARD_REMOVAL;
35650Sstevel@tonic-gate 		mutex_exit(&sp->lock);
35660Sstevel@tonic-gate 		(void) cs_card_removal(sp);
35670Sstevel@tonic-gate 	    } /* if (CS_EVENT_CARD_REMOVAL) */
35680Sstevel@tonic-gate 
35690Sstevel@tonic-gate 		/*
35700Sstevel@tonic-gate 		 * If someone is waiting for us to complete, signal them now.
35710Sstevel@tonic-gate 		 */
35720Sstevel@tonic-gate 	    if (sp->thread_state & SOCKET_WAIT_SYNC) {
35730Sstevel@tonic-gate 		mutex_enter(&sp->lock);
35740Sstevel@tonic-gate 		sp->thread_state &= ~SOCKET_WAIT_SYNC;
35750Sstevel@tonic-gate 		mutex_exit(&sp->lock);
35760Sstevel@tonic-gate 		cv_broadcast(&sp->caller_cv);
35770Sstevel@tonic-gate 	    } /* SOCKET_WAIT_SYNC */
35780Sstevel@tonic-gate 
35790Sstevel@tonic-gate 	} /* for (;;) */
35800Sstevel@tonic-gate }
35810Sstevel@tonic-gate 
35820Sstevel@tonic-gate /*
35830Sstevel@tonic-gate  * cs_card_for_client - checks to see if a card that the client can control
35840Sstevel@tonic-gate  *			is currently inserted in the socket.  Socket Services
35850Sstevel@tonic-gate  *			has to tell us if this is the case.
35860Sstevel@tonic-gate  */
35870Sstevel@tonic-gate static int
cs_card_for_client(client_t * client)35880Sstevel@tonic-gate cs_card_for_client(client_t *client)
35890Sstevel@tonic-gate {
35900Sstevel@tonic-gate 
35910Sstevel@tonic-gate 	/*
35920Sstevel@tonic-gate 	 * If the client has set the CS_EVENT_ALL_CLIENTS it means that they
35930Sstevel@tonic-gate 	 *	want to get all events for all clients, irrespective of
35940Sstevel@tonic-gate 	 *	whether or not there is a card in the socket.  Such clients
35950Sstevel@tonic-gate 	 *	have to be very careful if they touch the card hardware in
35960Sstevel@tonic-gate 	 *	any way to prevent causing problems for other clients on the
35970Sstevel@tonic-gate 	 *	same socket.  This flag will typically only be set by the
35980Sstevel@tonic-gate 	 *	"super-client" or CSI types of clients that wish to get
35990Sstevel@tonic-gate 	 *	information on other clients or cards in the system.
36000Sstevel@tonic-gate 	 * Note that the CS_EVENT_ALL_CLIENTS must be set in either the
36010Sstevel@tonic-gate 	 *	client's global event mask or client event mask.
36020Sstevel@tonic-gate 	 * The client must also have registered as a "super-client" or as a
36030Sstevel@tonic-gate 	 *	CSI client for this socket.
36040Sstevel@tonic-gate 	 */
36050Sstevel@tonic-gate 	if ((client->flags & (CLIENT_SUPER_CLIENT | CLIENT_CSI_CLIENT)) &&
36060Sstevel@tonic-gate 			((client->global_mask | client->event_mask) &
36070Sstevel@tonic-gate 							CS_EVENT_ALL_CLIENTS))
36080Sstevel@tonic-gate 	    return (1);
36090Sstevel@tonic-gate 
36100Sstevel@tonic-gate 	/*
36110Sstevel@tonic-gate 	 * Look for the PCM_DEV_ACTIVE property on this client's dip; if
36120Sstevel@tonic-gate 	 *	it's found, it means that this client can control the card
36130Sstevel@tonic-gate 	 *	that is currently in the socket.  This is a boolean
36140Sstevel@tonic-gate 	 *	property managed by Socket Services.
36150Sstevel@tonic-gate 	 */
36160Sstevel@tonic-gate 	if (ddi_getprop(DDI_DEV_T_ANY, client->dip,    (DDI_PROP_CANSLEEP |
36170Sstevel@tonic-gate 							DDI_PROP_NOTPROM),
36180Sstevel@tonic-gate 							PCM_DEV_ACTIVE, NULL)) {
36190Sstevel@tonic-gate #ifdef	CS_DEBUG
36200Sstevel@tonic-gate 	    if (cs_debug > 1) {
36210Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_card_for_client: client handle 0x%x "
36220Sstevel@tonic-gate 					"driver [%s] says %s found\n",
36230Sstevel@tonic-gate 						(int)client->client_handle,
36240Sstevel@tonic-gate 						client->driver_name,
36250Sstevel@tonic-gate 						PCM_DEV_ACTIVE);
36260Sstevel@tonic-gate 	    }
36270Sstevel@tonic-gate #endif
36280Sstevel@tonic-gate 	    return (1);
36290Sstevel@tonic-gate 	}
36300Sstevel@tonic-gate 
36310Sstevel@tonic-gate 	return (0);
36320Sstevel@tonic-gate }
36330Sstevel@tonic-gate 
36340Sstevel@tonic-gate /*
36350Sstevel@tonic-gate  * cs_ss_thread - This is the Socket Services work thread. We fire off
36360Sstevel@tonic-gate  *			any calls to Socket Services here that we want
36370Sstevel@tonic-gate  *			to run on a thread that is seperate from the
36380Sstevel@tonic-gate  *			per-socket event thread.
36390Sstevel@tonic-gate  */
36400Sstevel@tonic-gate static void
cs_ss_thread(uint32_t sn)36410Sstevel@tonic-gate cs_ss_thread(uint32_t sn)
36420Sstevel@tonic-gate {
36430Sstevel@tonic-gate 	cs_socket_t *sp;
36440Sstevel@tonic-gate 
36450Sstevel@tonic-gate 	if ((sp = cs_get_sp(sn)) == NULL)
36460Sstevel@tonic-gate 	    return;
36470Sstevel@tonic-gate 
36480Sstevel@tonic-gate 	/*
36490Sstevel@tonic-gate 	 * Tell CPR that we've started a new thread.
36500Sstevel@tonic-gate 	 */
36510Sstevel@tonic-gate 	CALLB_CPR_INIT(&sp->cprinfo_ss, &sp->ss_thread_lock,
36520Sstevel@tonic-gate 					callb_generic_cpr, "cs_ss_thread");
36530Sstevel@tonic-gate 
36540Sstevel@tonic-gate 	mutex_enter(&sp->ss_thread_lock);
36550Sstevel@tonic-gate 
36560Sstevel@tonic-gate 	for (;;) {
36570Sstevel@tonic-gate 
36580Sstevel@tonic-gate 	    CALLB_CPR_SAFE_BEGIN(&sp->cprinfo_ss);
36590Sstevel@tonic-gate 	    cv_wait(&sp->ss_thread_cv, &sp->ss_thread_lock);
36600Sstevel@tonic-gate 	    CALLB_CPR_SAFE_END(&sp->cprinfo_ss, &sp->ss_thread_lock);
36610Sstevel@tonic-gate 
36620Sstevel@tonic-gate 		/*
36630Sstevel@tonic-gate 		 * Check to see if there are any special thread operations
36640Sstevel@tonic-gate 		 * that we are being asked to perform.
36650Sstevel@tonic-gate 		 */
36660Sstevel@tonic-gate 	    if (sp->ss_thread_state & SOCKET_THREAD_EXIT) {
36670Sstevel@tonic-gate #ifdef	CS_DEBUG
36680Sstevel@tonic-gate 		if (cs_debug > 1) {
36690Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_ss_thread: socket %d "
36700Sstevel@tonic-gate 					"SOCKET_THREAD_EXIT\n",
36710Sstevel@tonic-gate 						sp->socket_num);
36720Sstevel@tonic-gate 		}
36730Sstevel@tonic-gate #endif
36740Sstevel@tonic-gate 		CALLB_CPR_EXIT(&sp->cprinfo_ss);
36750Sstevel@tonic-gate 		cv_broadcast(&sp->ss_caller_cv);	/* wake up cs_deinit */
36760Sstevel@tonic-gate 		mutex_exit(&sp->ss_thread_lock);
36770Sstevel@tonic-gate 		return;
36780Sstevel@tonic-gate 	    } /* if (SOCKET_THREAD_EXIT) */
36790Sstevel@tonic-gate 
36800Sstevel@tonic-gate #ifdef	CS_DEBUG
36810Sstevel@tonic-gate 	    if (cs_debug > 1) {
36820Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_ss_thread: socket %d "
36830Sstevel@tonic-gate 					"ss_thread_state = 0x%x\n",
36840Sstevel@tonic-gate 						(int)sp->socket_num,
36850Sstevel@tonic-gate 						(int)sp->ss_thread_state);
36860Sstevel@tonic-gate 	    }
36870Sstevel@tonic-gate #endif
36880Sstevel@tonic-gate 
36890Sstevel@tonic-gate 		/*
36900Sstevel@tonic-gate 		 * Call SocketServices(CSCISInit) to have SS parse the
36910Sstevel@tonic-gate 		 *	CIS and load/attach any client drivers necessary.
36920Sstevel@tonic-gate 		 */
36930Sstevel@tonic-gate 	    if (sp->ss_thread_state & SOCKET_THREAD_CSCISInit) {
36940Sstevel@tonic-gate 
36950Sstevel@tonic-gate 		sp->ss_thread_state &= ~SOCKET_THREAD_CSCISInit;
36960Sstevel@tonic-gate 
36970Sstevel@tonic-gate 		if (!(sp->flags & SOCKET_CARD_INSERTED)) {
36980Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_ss_thread %d "
36990Sstevel@tonic-gate 					"card NOT inserted\n",
37000Sstevel@tonic-gate 					sp->socket_num);
37010Sstevel@tonic-gate 		}
37020Sstevel@tonic-gate 
37030Sstevel@tonic-gate #ifdef	CS_DEBUG
37040Sstevel@tonic-gate 		if (cs_debug > 1) {
37050Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_ss_thread: socket %d calling "
37060Sstevel@tonic-gate 						"CSCISInit\n", sp->socket_num);
37070Sstevel@tonic-gate 		}
37080Sstevel@tonic-gate #endif
37090Sstevel@tonic-gate 
37100Sstevel@tonic-gate 		/*
37110Sstevel@tonic-gate 		 * Tell SS that we have a complete CIS and that it can now
37120Sstevel@tonic-gate 		 *	be parsed.
37130Sstevel@tonic-gate 		 * Note that in some cases the client driver may block in
37140Sstevel@tonic-gate 		 *	their attach routine, causing this call to block until
37150Sstevel@tonic-gate 		 *	the client completes their attach.
37160Sstevel@tonic-gate 		 */
37170Sstevel@tonic-gate 		SocketServices(CSCISInit, sp->socket_num);
37180Sstevel@tonic-gate 
37190Sstevel@tonic-gate 		/*
37200Sstevel@tonic-gate 		 * Set the CS_EVENT_SS_UPDATED event for this socket so that the
37210Sstevel@tonic-gate 		 *	event thread can continue any card insertion processing
37220Sstevel@tonic-gate 		 *	that it has to do.
37230Sstevel@tonic-gate 		 */
37240Sstevel@tonic-gate 		mutex_enter(&sp->lock);
37250Sstevel@tonic-gate 		sp->events |= CS_EVENT_SS_UPDATED;
37260Sstevel@tonic-gate 		mutex_exit(&sp->lock);
37270Sstevel@tonic-gate 
37280Sstevel@tonic-gate 		/*
37290Sstevel@tonic-gate 		 * Wake up this socket's event thread so that clients can
37300Sstevel@tonic-gate 		 *	continue any card insertion or attach processing
37310Sstevel@tonic-gate 		 *	that they need to do.
37320Sstevel@tonic-gate 		 */
37330Sstevel@tonic-gate 		cv_broadcast(&sp->thread_cv);
37340Sstevel@tonic-gate 	    } /* if ST_CSCISInit */
37350Sstevel@tonic-gate 
37360Sstevel@tonic-gate 	} /* for (;;) */
37370Sstevel@tonic-gate }
37380Sstevel@tonic-gate 
37390Sstevel@tonic-gate /*
37400Sstevel@tonic-gate  * cs_request_socket_mask - set the client's event mask as well as causes
37410Sstevel@tonic-gate  *				any events pending from RegisterClient to
37420Sstevel@tonic-gate  *				be scheduled to be sent to the client
37430Sstevel@tonic-gate  */
37440Sstevel@tonic-gate static int
cs_request_socket_mask(client_handle_t client_handle,request_socket_mask_t * se)37450Sstevel@tonic-gate cs_request_socket_mask(client_handle_t client_handle,
37460Sstevel@tonic-gate 					request_socket_mask_t *se)
37470Sstevel@tonic-gate {
37480Sstevel@tonic-gate 	cs_socket_t *sp;
37490Sstevel@tonic-gate 	client_t *client;
37500Sstevel@tonic-gate 	int error;
37510Sstevel@tonic-gate 	int client_lock_acquired;
37520Sstevel@tonic-gate 
37530Sstevel@tonic-gate 	/*
37540Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
37550Sstevel@tonic-gate 	 *	is, we don't do anything except for return success.
37560Sstevel@tonic-gate 	 */
37570Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
37580Sstevel@tonic-gate 	    return (CS_SUCCESS);
37590Sstevel@tonic-gate 
37600Sstevel@tonic-gate 	/*
37610Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
37620Sstevel@tonic-gate 	 */
37630Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
37640Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
37650Sstevel@tonic-gate 
37660Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
37670Sstevel@tonic-gate 
37680Sstevel@tonic-gate 	/*
37690Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
37700Sstevel@tonic-gate 	 */
37710Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
37720Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
37730Sstevel@tonic-gate 	    return (error);
37740Sstevel@tonic-gate 	}
37750Sstevel@tonic-gate 
37760Sstevel@tonic-gate 	mutex_enter(&sp->lock);
37770Sstevel@tonic-gate 
37780Sstevel@tonic-gate 	/*
37790Sstevel@tonic-gate 	 * If this client has already done a RequestSocketMask without
37800Sstevel@tonic-gate 	 *	a corresponding ReleaseSocketMask, then return an error.
37810Sstevel@tonic-gate 	 */
37820Sstevel@tonic-gate 	if (client->flags & REQ_SOCKET_MASK_DONE) {
37830Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
37840Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
37850Sstevel@tonic-gate 	    return (CS_IN_USE);
37860Sstevel@tonic-gate 	}
37870Sstevel@tonic-gate 
37880Sstevel@tonic-gate 	/*
37890Sstevel@tonic-gate 	 * Set up the event mask information; we copy this directly from
37900Sstevel@tonic-gate 	 *	the client; since we are the only source of events, any
37910Sstevel@tonic-gate 	 *	bogus bits that the client puts in here won't matter
37920Sstevel@tonic-gate 	 *	because we'll never look at them.
37930Sstevel@tonic-gate 	 */
37940Sstevel@tonic-gate 	client->event_mask = se->EventMask;
37950Sstevel@tonic-gate 
37960Sstevel@tonic-gate 	/*
37970Sstevel@tonic-gate 	 * If RegisterClient left us some events to process, set these
37980Sstevel@tonic-gate 	 *	events up here.
37990Sstevel@tonic-gate 	 */
38000Sstevel@tonic-gate 	if (client->pending_events) {
38010Sstevel@tonic-gate 	    client->events |= client->pending_events;
38020Sstevel@tonic-gate 	    client->pending_events = 0;
38030Sstevel@tonic-gate #ifdef	CS_DEBUG
38040Sstevel@tonic-gate 	    if (cs_debug > 1) {
38050Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_request_socket_mask: client_handle = 0x%x "
38060Sstevel@tonic-gate 				"driver_name = [%s] events = 0x%x\n",
38070Sstevel@tonic-gate 					(int)client->client_handle,
38080Sstevel@tonic-gate 					client->driver_name,
38090Sstevel@tonic-gate 					(int)client->events);
38100Sstevel@tonic-gate 	    }
38110Sstevel@tonic-gate #endif
38120Sstevel@tonic-gate 	}
38130Sstevel@tonic-gate 
38140Sstevel@tonic-gate 	client->flags |= REQ_SOCKET_MASK_DONE;
38150Sstevel@tonic-gate 
38160Sstevel@tonic-gate 	/*
38170Sstevel@tonic-gate 	 * Merge all the clients' event masks and set the socket
38180Sstevel@tonic-gate 	 *	to generate the appropriate events.
38190Sstevel@tonic-gate 	 */
38200Sstevel@tonic-gate 	(void) cs_set_socket_event_mask(sp, cs_merge_event_masks(sp, client));
38210Sstevel@tonic-gate 
38220Sstevel@tonic-gate 	mutex_exit(&sp->lock);
38230Sstevel@tonic-gate 
38240Sstevel@tonic-gate 	/*
38250Sstevel@tonic-gate 	 * Wakeup the event thread if there are any client events to process.
38260Sstevel@tonic-gate 	 */
38270Sstevel@tonic-gate 	if (client->events) {
38280Sstevel@tonic-gate 	    cv_broadcast(&sp->thread_cv);
38290Sstevel@tonic-gate #ifdef	CS_DEBUG
38300Sstevel@tonic-gate 	    if (cs_debug > 1) {
38310Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_request_socket_mask: did cv_broadcast for "
38320Sstevel@tonic-gate 				"client_handle = 0x%x "
38330Sstevel@tonic-gate 				"driver_name = [%s] events = 0x%x\n",
38340Sstevel@tonic-gate 					(int)client->client_handle,
38350Sstevel@tonic-gate 					client->driver_name,
38360Sstevel@tonic-gate 					(int)client->events);
38370Sstevel@tonic-gate 	    }
38380Sstevel@tonic-gate #endif
38390Sstevel@tonic-gate 
38400Sstevel@tonic-gate 	}
38410Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
38420Sstevel@tonic-gate 
38430Sstevel@tonic-gate 	return (CS_SUCCESS);
38440Sstevel@tonic-gate }
38450Sstevel@tonic-gate 
38460Sstevel@tonic-gate /*
38470Sstevel@tonic-gate  * cs_release_socket_mask - clear the client's event mask
38480Sstevel@tonic-gate  *
38490Sstevel@tonic-gate  * Once this function returns, the client is guaranteed
38500Sstevel@tonic-gate  *	not to get any more event callbacks.
38510Sstevel@tonic-gate  */
38520Sstevel@tonic-gate /*ARGSUSED*/
38530Sstevel@tonic-gate static int
cs_release_socket_mask(client_handle_t client_handle,release_socket_mask_t * rsm)38540Sstevel@tonic-gate cs_release_socket_mask(client_handle_t client_handle,
38550Sstevel@tonic-gate 					release_socket_mask_t *rsm)
38560Sstevel@tonic-gate {
38570Sstevel@tonic-gate 	cs_socket_t *sp;
38580Sstevel@tonic-gate 	client_t *client;
38590Sstevel@tonic-gate 	int error;
38600Sstevel@tonic-gate 	int client_lock_acquired;
38610Sstevel@tonic-gate 
38620Sstevel@tonic-gate 	/*
38630Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
38640Sstevel@tonic-gate 	 *	is, we don't do anything except for return success.
38650Sstevel@tonic-gate 	 */
38660Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
38670Sstevel@tonic-gate 	    return (CS_SUCCESS);
38680Sstevel@tonic-gate 
38690Sstevel@tonic-gate 	/*
38700Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
38710Sstevel@tonic-gate 	 */
38720Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
38730Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
38740Sstevel@tonic-gate 
38750Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
38760Sstevel@tonic-gate 
38770Sstevel@tonic-gate 	/*
38780Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
38790Sstevel@tonic-gate 	 */
38800Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
38810Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
38820Sstevel@tonic-gate 	    return (error);
38830Sstevel@tonic-gate 	}
38840Sstevel@tonic-gate 
38850Sstevel@tonic-gate 	mutex_enter(&sp->lock);
38860Sstevel@tonic-gate 
38870Sstevel@tonic-gate 	/*
38880Sstevel@tonic-gate 	 * If this client has already done a RequestSocketMask without
38890Sstevel@tonic-gate 	 *	a corresponding ReleaseSocketMask, then return an error.
38900Sstevel@tonic-gate 	 */
38910Sstevel@tonic-gate 	if (!(client->flags & REQ_SOCKET_MASK_DONE)) {
38920Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
38930Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
38940Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
38950Sstevel@tonic-gate 	}
38960Sstevel@tonic-gate 
38970Sstevel@tonic-gate 	/*
38980Sstevel@tonic-gate 	 * Clear both the client event mask and the global event mask.
38990Sstevel@tonic-gate 	 *	We clear both since the semantics of this function are
39000Sstevel@tonic-gate 	 *	that once it returns, the client will not be called at
39010Sstevel@tonic-gate 	 *	it's event handler for any events until RequestSocketMask
39020Sstevel@tonic-gate 	 *	is called again.
39030Sstevel@tonic-gate 	 */
39040Sstevel@tonic-gate 	client->event_mask = 0;
39050Sstevel@tonic-gate 	client->global_mask = 0;
39060Sstevel@tonic-gate 	client->flags &= ~REQ_SOCKET_MASK_DONE;
39070Sstevel@tonic-gate 
39080Sstevel@tonic-gate 	/*
39090Sstevel@tonic-gate 	 * Merge all the clients' event masks and set the socket
39100Sstevel@tonic-gate 	 *	to generate the appropriate events.
39110Sstevel@tonic-gate 	 */
39120Sstevel@tonic-gate 	(void) cs_set_socket_event_mask(sp, cs_merge_event_masks(sp, client));
39130Sstevel@tonic-gate 
39140Sstevel@tonic-gate 	mutex_exit(&sp->lock);
39150Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
39160Sstevel@tonic-gate 
39170Sstevel@tonic-gate 	return (CS_SUCCESS);
39180Sstevel@tonic-gate }
39190Sstevel@tonic-gate 
39200Sstevel@tonic-gate /*
39210Sstevel@tonic-gate  * cs_get_event_mask - return the event mask for this client
39220Sstevel@tonic-gate  */
39230Sstevel@tonic-gate static int
cs_get_event_mask(client_handle_t client_handle,sockevent_t * se)39240Sstevel@tonic-gate cs_get_event_mask(client_handle_t client_handle, sockevent_t *se)
39250Sstevel@tonic-gate {
39260Sstevel@tonic-gate 	cs_socket_t *sp;
39270Sstevel@tonic-gate 	client_t *client;
39280Sstevel@tonic-gate 	int error;
39290Sstevel@tonic-gate 	int client_lock_acquired;
39300Sstevel@tonic-gate 
39310Sstevel@tonic-gate 	/*
39320Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
39330Sstevel@tonic-gate 	 *	is, we don't do anything except for return success.
39340Sstevel@tonic-gate 	 */
39350Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
39360Sstevel@tonic-gate 	    return (CS_SUCCESS);
39370Sstevel@tonic-gate 
39380Sstevel@tonic-gate 	/*
39390Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
39400Sstevel@tonic-gate 	 */
39410Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
39420Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
39430Sstevel@tonic-gate 
39440Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
39450Sstevel@tonic-gate 
39460Sstevel@tonic-gate 	/*
39470Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
39480Sstevel@tonic-gate 	 */
39490Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
39500Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
39510Sstevel@tonic-gate 	    return (error);
39520Sstevel@tonic-gate 	}
39530Sstevel@tonic-gate 
39540Sstevel@tonic-gate 	mutex_enter(&sp->lock);
39550Sstevel@tonic-gate 
39560Sstevel@tonic-gate #ifdef	XXX
39570Sstevel@tonic-gate 	/*
39580Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
39590Sstevel@tonic-gate 	 *	for this client, then return an error.
39600Sstevel@tonic-gate 	 * XXX - how can a client get their event masks if their card
39610Sstevel@tonic-gate 	 *	goes away?
39620Sstevel@tonic-gate 	 */
39630Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
39640Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
39650Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
39660Sstevel@tonic-gate 	    return (CS_NO_CARD);
39670Sstevel@tonic-gate 	}
39680Sstevel@tonic-gate #endif
39690Sstevel@tonic-gate 
39700Sstevel@tonic-gate 	/*
39710Sstevel@tonic-gate 	 * We are only allowed to get the client event mask if a
39720Sstevel@tonic-gate 	 *	RequestSocketMask has been called previously.  We
39730Sstevel@tonic-gate 	 *	are allowed to get the global event mask at any
39740Sstevel@tonic-gate 	 *	time.
39750Sstevel@tonic-gate 	 * The global event mask is initially set by the client
39760Sstevel@tonic-gate 	 *	in the call to RegisterClient.  The client event
39770Sstevel@tonic-gate 	 *	mask is set by the client in calls to SetEventMask
39780Sstevel@tonic-gate 	 *	and RequestSocketMask and gotten in calls to
39790Sstevel@tonic-gate 	 *	GetEventMask.
39800Sstevel@tonic-gate 	 */
39810Sstevel@tonic-gate 	if (se->Attributes & CONF_EVENT_MASK_CLIENT) {
39820Sstevel@tonic-gate 	    if (!(client->flags & REQ_SOCKET_MASK_DONE)) {
39830Sstevel@tonic-gate 		mutex_exit(&sp->lock);
39840Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
39850Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
39860Sstevel@tonic-gate 	    }
39870Sstevel@tonic-gate 	    se->EventMask = client->event_mask;
39880Sstevel@tonic-gate 	} else {
39890Sstevel@tonic-gate 	    se->EventMask = client->global_mask;
39900Sstevel@tonic-gate 	}
39910Sstevel@tonic-gate 
39920Sstevel@tonic-gate 	mutex_exit(&sp->lock);
39930Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
39940Sstevel@tonic-gate 
39950Sstevel@tonic-gate 	return (CS_SUCCESS);
39960Sstevel@tonic-gate }
39970Sstevel@tonic-gate 
39980Sstevel@tonic-gate /*
39990Sstevel@tonic-gate  * cs_set_event_mask - set the event mask for this client
40000Sstevel@tonic-gate  */
40010Sstevel@tonic-gate static int
cs_set_event_mask(client_handle_t client_handle,sockevent_t * se)40020Sstevel@tonic-gate cs_set_event_mask(client_handle_t client_handle, sockevent_t *se)
40030Sstevel@tonic-gate {
40040Sstevel@tonic-gate 	cs_socket_t *sp;
40050Sstevel@tonic-gate 	client_t *client;
40060Sstevel@tonic-gate 	int error;
40070Sstevel@tonic-gate 	int client_lock_acquired;
40080Sstevel@tonic-gate 
40090Sstevel@tonic-gate 	/*
40100Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
40110Sstevel@tonic-gate 	 *	is, we don't do anything except for return success.
40120Sstevel@tonic-gate 	 */
40130Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
40140Sstevel@tonic-gate 	    return (CS_SUCCESS);
40150Sstevel@tonic-gate 
40160Sstevel@tonic-gate 	/*
40170Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
40180Sstevel@tonic-gate 	 */
40190Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
40200Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
40210Sstevel@tonic-gate 
40220Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
40230Sstevel@tonic-gate 
40240Sstevel@tonic-gate 	/*
40250Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
40260Sstevel@tonic-gate 	 */
40270Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
40280Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
40290Sstevel@tonic-gate 	    return (error);
40300Sstevel@tonic-gate 	}
40310Sstevel@tonic-gate 
40320Sstevel@tonic-gate 	mutex_enter(&sp->lock);
40330Sstevel@tonic-gate 
40340Sstevel@tonic-gate #ifdef	XXX
40350Sstevel@tonic-gate 	/*
40360Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
40370Sstevel@tonic-gate 	 *	for this client, then return an error.
40380Sstevel@tonic-gate 	 */
40390Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
40400Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
40410Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
40420Sstevel@tonic-gate 	    return (CS_NO_CARD);
40430Sstevel@tonic-gate 	}
40440Sstevel@tonic-gate #endif
40450Sstevel@tonic-gate 
40460Sstevel@tonic-gate 	/*
40470Sstevel@tonic-gate 	 * We are only allowed to set the client event mask if a
40480Sstevel@tonic-gate 	 *	RequestSocketMask has been called previously.  We
40490Sstevel@tonic-gate 	 *	are allowed to set the global event mask at any
40500Sstevel@tonic-gate 	 *	time.
40510Sstevel@tonic-gate 	 * The global event mask is initially set by the client
40520Sstevel@tonic-gate 	 *	in the call to RegisterClient.  The client event
40530Sstevel@tonic-gate 	 *	mask is set by the client in calls to SetEventMask
40540Sstevel@tonic-gate 	 *	and RequestSocketMask and gotten in calls to
40550Sstevel@tonic-gate 	 *	GetEventMask.
40560Sstevel@tonic-gate 	 */
40570Sstevel@tonic-gate 	if (se->Attributes & CONF_EVENT_MASK_CLIENT) {
40580Sstevel@tonic-gate 	    if (!(client->flags & REQ_SOCKET_MASK_DONE)) {
40590Sstevel@tonic-gate 		mutex_exit(&sp->lock);
40600Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
40610Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
40620Sstevel@tonic-gate 	    }
40630Sstevel@tonic-gate 	    client->event_mask = se->EventMask;
40640Sstevel@tonic-gate 	} else {
40650Sstevel@tonic-gate 	    client->global_mask = se->EventMask;
40660Sstevel@tonic-gate 	}
40670Sstevel@tonic-gate 
40680Sstevel@tonic-gate 	/*
40690Sstevel@tonic-gate 	 * Merge all the clients' event masks and set the socket
40700Sstevel@tonic-gate 	 *	to generate the appropriate events.
40710Sstevel@tonic-gate 	 */
40720Sstevel@tonic-gate 	(void) cs_set_socket_event_mask(sp, cs_merge_event_masks(sp, client));
40730Sstevel@tonic-gate 
40740Sstevel@tonic-gate 	mutex_exit(&sp->lock);
40750Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
40760Sstevel@tonic-gate 
40770Sstevel@tonic-gate 	return (CS_SUCCESS);
40780Sstevel@tonic-gate }
40790Sstevel@tonic-gate 
40800Sstevel@tonic-gate /*
40810Sstevel@tonic-gate  * cs_read_event_status - handles PRR events and returns card status
40820Sstevel@tonic-gate  *
40830Sstevel@tonic-gate  *	calling: *sp - socket struct point
40840Sstevel@tonic-gate  *		 *client - client to check events on
40850Sstevel@tonic-gate  *		 *revent - pointer to event mask to update; if NULL, will
40860Sstevel@tonic-gate  *				not be updated, if non-NULL, will be updated
40870Sstevel@tonic-gate  *				with CS-format events; it is NOT necessary
40880Sstevel@tonic-gate  *				to clear this value before calling this
40890Sstevel@tonic-gate  *				function
40900Sstevel@tonic-gate  *		 *gs - pointer to a get_ss_status_t used for the SS GetStatus
40910Sstevel@tonic-gate  *				call; it is not necessary to initialize any
40920Sstevel@tonic-gate  *				members in this structure; set to NULL if
40930Sstevel@tonic-gate  *				not used
40940Sstevel@tonic-gate  *		flags - if CS_RES_IGNORE_NO_CARD is set, the check for a
40950Sstevel@tonic-gate  *				card present will not be done
40960Sstevel@tonic-gate  *
40970Sstevel@tonic-gate  *	returns: CS_SUCCESS
40980Sstevel@tonic-gate  *		 CS_NO_CARD - if no card is in the socket and the flags arg
40990Sstevel@tonic-gate  *				is not set to CS_RES_IGNORE_NO_CARD
41000Sstevel@tonic-gate  *		 CS_BAD_SOCKET - if the SS_GetStatus function returned an
41010Sstevel@tonic-gate  *					error
41020Sstevel@tonic-gate  *
41030Sstevel@tonic-gate  *	Note that if the client that configured this socket has told us that
41040Sstevel@tonic-gate  *		the READY pin in the PRR isn't valid and the socket is in IO
41050Sstevel@tonic-gate  *		mode, we always return that the card is READY.
41060Sstevel@tonic-gate  *
41070Sstevel@tonic-gate  *	Note that if gs is not NULL, the current card state will be returned
41080Sstevel@tonic-gate  *		in the gs->CardState member; this will always reflect the
41090Sstevel@tonic-gate  *		current card state and the state will come from both the
41100Sstevel@tonic-gate  *		SS_GetStatus call and the PRR, whichever is appropriate for
41110Sstevel@tonic-gate  *		the mode that the socket is currently in.
41120Sstevel@tonic-gate  */
41130Sstevel@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)41140Sstevel@tonic-gate cs_read_event_status(cs_socket_t *sp, client_t *client, event_t *revent,
41150Sstevel@tonic-gate 						get_ss_status_t *gs, int flags)
41160Sstevel@tonic-gate {
41170Sstevel@tonic-gate 	cfg_regs_t prrd = 0;
41180Sstevel@tonic-gate 
41190Sstevel@tonic-gate 	/*
41200Sstevel@tonic-gate 	 * SOCKET_IS_IO will only be set if a RequestConfiguration
41210Sstevel@tonic-gate 	 *	has been done by at least one client on this socket.
41220Sstevel@tonic-gate 	 * If there isn't a card in the socket or the caller wants to ignore
41230Sstevel@tonic-gate 	 *	whether the card is in the socket or not, get the current
41240Sstevel@tonic-gate 	 *	card status.
41250Sstevel@tonic-gate 	 */
41260Sstevel@tonic-gate 	if ((sp->flags & SOCKET_CARD_INSERTED) ||
41270Sstevel@tonic-gate 					(flags & CS_RES_IGNORE_NO_CARD)) {
41280Sstevel@tonic-gate 	    if (sp->flags & SOCKET_IS_IO) {
41290Sstevel@tonic-gate 		if (client->present & CONFIG_PINREPL_REG_PRESENT) {
41300Sstevel@tonic-gate 		    acc_handle_t cis_handle;
41310Sstevel@tonic-gate 		    uint32_t newoffset = client->config_regs_offset;
41320Sstevel@tonic-gate 
41330Sstevel@tonic-gate 			/*
41340Sstevel@tonic-gate 			 * Get a handle to the CIS window
41350Sstevel@tonic-gate 			 */
41360Sstevel@tonic-gate 		    if (cs_init_cis_window(sp, &newoffset, &cis_handle,
41370Sstevel@tonic-gate 					CISTPLF_AM_SPACE) != CS_SUCCESS) {
41380Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_read_event_status: socket %d "
41390Sstevel@tonic-gate 					    "can't init CIS window\n",
41400Sstevel@tonic-gate 							sp->socket_num);
41410Sstevel@tonic-gate 			return (CS_GENERAL_FAILURE);
41420Sstevel@tonic-gate 		    } /* cs_init_cis_window */
41430Sstevel@tonic-gate 
41440Sstevel@tonic-gate 		    prrd = csx_Get8(cis_handle, client->config_regs.prr_p);
41450Sstevel@tonic-gate 		    prrd &= client->pin;
41460Sstevel@tonic-gate 
41470Sstevel@tonic-gate #ifdef	CS_DEBUG
41480Sstevel@tonic-gate 		    if (cs_debug > 1) {
41490Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_read_event_status: "
41500Sstevel@tonic-gate 						"prrd 0x%x client->pin 0x%x\n",
41510Sstevel@tonic-gate 								(int)prrd,
41520Sstevel@tonic-gate 								client->pin);
41530Sstevel@tonic-gate 			cmn_err(CE_CONT, "PRR(1) = [%s%s%s%s%s%s%s%s]\n",
41540Sstevel@tonic-gate 						((prrd & PRR_WP_STATUS)?
41550Sstevel@tonic-gate 							"PRR_WP_STATUS ":""),
41560Sstevel@tonic-gate 						((prrd & PRR_READY_STATUS)?
41570Sstevel@tonic-gate 							"PRR_READY_STATUS ":""),
41580Sstevel@tonic-gate 						((prrd & PRR_BVD2_STATUS)?
41590Sstevel@tonic-gate 							"PRR_BVD2_STATUS ":""),
41600Sstevel@tonic-gate 						((prrd & PRR_BVD1_STATUS)?
41610Sstevel@tonic-gate 							"PRR_BVD1_STATUS ":""),
41620Sstevel@tonic-gate 						((prrd & PRR_WP_EVENT)?
41630Sstevel@tonic-gate 							"PRR_WP_EVENT ":""),
41640Sstevel@tonic-gate 						((prrd & PRR_READY_EVENT)?
41650Sstevel@tonic-gate 							"PRR_READY_EVENT ":""),
41660Sstevel@tonic-gate 						((prrd & PRR_BVD2_EVENT)?
41670Sstevel@tonic-gate 							"PRR_BVD2_EVENT ":""),
41680Sstevel@tonic-gate 						((prrd & PRR_BVD1_EVENT)?
41690Sstevel@tonic-gate 							"PRR_BVD1_EVENT ":""));
41700Sstevel@tonic-gate 		    }
41710Sstevel@tonic-gate #endif
41720Sstevel@tonic-gate 
41730Sstevel@tonic-gate 			/*
41740Sstevel@tonic-gate 			 * The caller wants the event changes sent back and
41750Sstevel@tonic-gate 			 * the PRR event change bits cleared.
41760Sstevel@tonic-gate 			 */
41770Sstevel@tonic-gate 		    if (revent) {
41780Sstevel@tonic-gate 			get_socket_t get_socket;
41790Sstevel@tonic-gate 			set_socket_t set_socket;
41800Sstevel@tonic-gate 
41810Sstevel@tonic-gate 			/*
41820Sstevel@tonic-gate 			 * Bug ID: 1193636 - Card Services sends bogus
41830Sstevel@tonic-gate 			 *	events on CS_EVENT_STATUS_CHANGE events
41840Sstevel@tonic-gate 			 * Clear this before we OR-in any values.
41850Sstevel@tonic-gate 			 */
41860Sstevel@tonic-gate 			*revent = 0;
41870Sstevel@tonic-gate 
41880Sstevel@tonic-gate 			PRR_EVENT(prrd, PRR_WP_EVENT, PRR_WP_STATUS,
41890Sstevel@tonic-gate 					CS_EVENT_WRITE_PROTECT, *revent);
41900Sstevel@tonic-gate 
41910Sstevel@tonic-gate 			PRR_EVENT(prrd, PRR_READY_EVENT, PRR_READY_STATUS,
41920Sstevel@tonic-gate 					CS_EVENT_CARD_READY, *revent);
41930Sstevel@tonic-gate 
41940Sstevel@tonic-gate 			PRR_EVENT(prrd, PRR_BVD2_EVENT, PRR_BVD2_STATUS,
41950Sstevel@tonic-gate 					CS_EVENT_BATTERY_LOW, *revent);
41960Sstevel@tonic-gate 
41970Sstevel@tonic-gate 			PRR_EVENT(prrd, PRR_BVD1_EVENT, PRR_BVD1_STATUS,
41980Sstevel@tonic-gate 					CS_EVENT_BATTERY_DEAD, *revent);
41990Sstevel@tonic-gate 
42000Sstevel@tonic-gate 
42010Sstevel@tonic-gate #ifdef	CS_DEBUG
42020Sstevel@tonic-gate 			if (cs_debug > 1) {
42030Sstevel@tonic-gate 
42040Sstevel@tonic-gate 			    cmn_err(CE_CONT, "PRR() = [%s%s%s%s%s%s%s%s]\n",
42050Sstevel@tonic-gate 						((prrd & PRR_WP_STATUS)?
42060Sstevel@tonic-gate 							"PRR_WP_STATUS ":""),
42070Sstevel@tonic-gate 						((prrd & PRR_READY_STATUS)?
42080Sstevel@tonic-gate 							"PRR_READY_STATUS ":""),
42090Sstevel@tonic-gate 						((prrd & PRR_BVD2_STATUS)?
42100Sstevel@tonic-gate 							"PRR_BVD2_STATUS ":""),
42110Sstevel@tonic-gate 						((prrd & PRR_BVD1_STATUS)?
42120Sstevel@tonic-gate 							"PRR_BVD1_STATUS ":""),
42130Sstevel@tonic-gate 						((prrd & PRR_WP_EVENT)?
42140Sstevel@tonic-gate 							"PRR_WP_EVENT ":""),
42150Sstevel@tonic-gate 						((prrd & PRR_READY_EVENT)?
42160Sstevel@tonic-gate 							"PRR_READY_EVENT ":""),
42170Sstevel@tonic-gate 						((prrd & PRR_BVD2_EVENT)?
42180Sstevel@tonic-gate 							"PRR_BVD2_EVENT ":""),
42190Sstevel@tonic-gate 						((prrd & PRR_BVD1_EVENT)?
42200Sstevel@tonic-gate 							"PRR_BVD1_EVENT ":""));
42210Sstevel@tonic-gate 			}
42220Sstevel@tonic-gate #endif
42230Sstevel@tonic-gate 
42240Sstevel@tonic-gate 			if (prrd)
42250Sstevel@tonic-gate 			    csx_Put8(cis_handle, client->config_regs.prr_p,
42260Sstevel@tonic-gate 				prrd);
42270Sstevel@tonic-gate 
42280Sstevel@tonic-gate 			/*
42290Sstevel@tonic-gate 			 * We now have to reenable the status change interrupts
42300Sstevel@tonic-gate 			 *	if there are any valid bits in the PRR. Since
42310Sstevel@tonic-gate 			 *	the BVD1 signal becomes the STATUS_CHANGE
42320Sstevel@tonic-gate 			 *	signal when the socket is in IO mode, we just
42330Sstevel@tonic-gate 			 *	have to set the SBM_BVD1 enable bit in the
42340Sstevel@tonic-gate 			 *	event mask.
42350Sstevel@tonic-gate 			 */
42360Sstevel@tonic-gate 			if (client->pin) {
42370Sstevel@tonic-gate 			    get_socket.socket = sp->socket_num;
42380Sstevel@tonic-gate 			    SocketServices(SS_GetSocket, &get_socket);
42390Sstevel@tonic-gate 			    set_socket.socket = sp->socket_num;
42400Sstevel@tonic-gate 			    set_socket.SCIntMask =
42410Sstevel@tonic-gate 					get_socket.SCIntMask | SBM_BVD1;
42420Sstevel@tonic-gate 			    set_socket.VccLevel = get_socket.VccLevel;
42430Sstevel@tonic-gate 			    set_socket.Vpp1Level = get_socket.Vpp1Level;
42440Sstevel@tonic-gate 			    set_socket.Vpp2Level = get_socket.Vpp2Level;
42450Sstevel@tonic-gate 			    set_socket.IREQRouting = get_socket.IRQRouting;
42460Sstevel@tonic-gate 			    set_socket.IFType = get_socket.IFType;
42470Sstevel@tonic-gate 			    set_socket.CtlInd = get_socket.CtlInd;
42480Sstevel@tonic-gate 			    set_socket.State = get_socket.state;
42490Sstevel@tonic-gate 			    SocketServices(SS_SetSocket, &set_socket);
42500Sstevel@tonic-gate 			} /* if (client->pin) */
42510Sstevel@tonic-gate 		    } /* if (revent) */
42520Sstevel@tonic-gate 
42530Sstevel@tonic-gate 		} /* if (CONFIG_PINREPL_REG_PRESENT) */
42540Sstevel@tonic-gate 	    } /* if (SOCKET_IS_IO) */
42550Sstevel@tonic-gate 
42560Sstevel@tonic-gate 	/*
42570Sstevel@tonic-gate 	 * The caller wants the current card state; we just read
42580Sstevel@tonic-gate 	 *	it and return a copy of it but do not clear any of
42590Sstevel@tonic-gate 	 *	the event changed bits (if we're reading the PRR).
42600Sstevel@tonic-gate 	 */
42610Sstevel@tonic-gate 	    if (gs) {
42620Sstevel@tonic-gate 		gs->socket = sp->socket_num;
42630Sstevel@tonic-gate 		gs->CardState = 0;
42640Sstevel@tonic-gate 		if (SocketServices(SS_GetStatus, gs) != SUCCESS)
42650Sstevel@tonic-gate 		    return (CS_BAD_SOCKET);
42660Sstevel@tonic-gate 		if (sp->flags & SOCKET_IS_IO) {
42670Sstevel@tonic-gate 		/*
42680Sstevel@tonic-gate 		 * If the socket is in IO mode, then clear the
42690Sstevel@tonic-gate 		 *	gs->CardState bits that are now in the PRR
42700Sstevel@tonic-gate 		 */
42710Sstevel@tonic-gate 		    gs->CardState &= ~(SBM_WP | SBM_BVD1 |
42720Sstevel@tonic-gate 						SBM_BVD2 | SBM_RDYBSY);
42730Sstevel@tonic-gate 
42740Sstevel@tonic-gate 		/*
42750Sstevel@tonic-gate 		 * Convert PRR status to SS_GetStatus status
42760Sstevel@tonic-gate 		 */
42770Sstevel@tonic-gate 		    if (prrd & PRR_WP_STATUS)
42780Sstevel@tonic-gate 			gs->CardState |= SBM_WP;
42790Sstevel@tonic-gate 		    if (prrd & PRR_BVD2_STATUS)
42800Sstevel@tonic-gate 			gs->CardState |= SBM_BVD2;
42810Sstevel@tonic-gate 		    if (prrd & PRR_BVD1_STATUS)
42820Sstevel@tonic-gate 			gs->CardState |= SBM_BVD1;
42830Sstevel@tonic-gate 
42840Sstevel@tonic-gate 		/*
42850Sstevel@tonic-gate 		 * If the client has indicated that there is no
42860Sstevel@tonic-gate 		 *	PRR or that the READY bit in the PRR isn't
42870Sstevel@tonic-gate 		 *	valid, then we simulate the READY bit by
42880Sstevel@tonic-gate 		 *	always returning READY.
42890Sstevel@tonic-gate 		 */
42900Sstevel@tonic-gate 		    if (!(client->present & CONFIG_PINREPL_REG_PRESENT) ||
42910Sstevel@tonic-gate 			((client->present & CONFIG_PINREPL_REG_PRESENT) &&
42920Sstevel@tonic-gate 			!((client->pin &
42930Sstevel@tonic-gate 			    (PRR_READY_STATUS | PRR_READY_EVENT)) ==
42940Sstevel@tonic-gate 				(PRR_READY_STATUS | PRR_READY_EVENT))) ||
42950Sstevel@tonic-gate 				(prrd & PRR_READY_STATUS))
42960Sstevel@tonic-gate 			gs->CardState |= SBM_RDYBSY;
42970Sstevel@tonic-gate 
42980Sstevel@tonic-gate #ifdef	CS_DEBUG
42990Sstevel@tonic-gate 			if (cs_debug > 1) {
43000Sstevel@tonic-gate 			    cmn_err(CE_CONT, "cs_read_event_status: prrd 0x%x "
43010Sstevel@tonic-gate 				"client->pin 0x%x "
43020Sstevel@tonic-gate 				"gs->CardState 0x%x\n",
43030Sstevel@tonic-gate 				prrd, client->pin, gs->CardState);
43040Sstevel@tonic-gate 			}
43050Sstevel@tonic-gate #endif
43060Sstevel@tonic-gate 
43070Sstevel@tonic-gate 		} /* if (SOCKET_IS_IO) */
43080Sstevel@tonic-gate 	    } /* if (gs) */
43090Sstevel@tonic-gate 	    return (CS_SUCCESS);
43100Sstevel@tonic-gate 	} /* if (SOCKET_CARD_INSERTED) */
43110Sstevel@tonic-gate 
43120Sstevel@tonic-gate 	return (CS_NO_CARD);
43130Sstevel@tonic-gate }
43140Sstevel@tonic-gate 
43150Sstevel@tonic-gate /*
43160Sstevel@tonic-gate  * cs_get_status - gets live card status and latched card status changes
43170Sstevel@tonic-gate  *			supports the GetStatus CS call
43180Sstevel@tonic-gate  *
43190Sstevel@tonic-gate  *	returns: CS_SUCCESS
43200Sstevel@tonic-gate  *		 CS_BAD_HANDLE if the passed client handle is invalid
43210Sstevel@tonic-gate  *
43220Sstevel@tonic-gate  *	Note: This function resets the latched status values maintained
43230Sstevel@tonic-gate  *		by Socket Services
43240Sstevel@tonic-gate  */
43250Sstevel@tonic-gate static int
cs_get_status(client_handle_t client_handle,get_status_t * gs)43260Sstevel@tonic-gate cs_get_status(client_handle_t client_handle, get_status_t *gs)
43270Sstevel@tonic-gate {
43280Sstevel@tonic-gate 	cs_socket_t *sp;
43290Sstevel@tonic-gate 	client_t *client;
43300Sstevel@tonic-gate 	get_ss_status_t get_ss_status;
43310Sstevel@tonic-gate 	get_socket_t get_socket;
43320Sstevel@tonic-gate 	set_socket_t set_socket;
43330Sstevel@tonic-gate 	int error;
43340Sstevel@tonic-gate 	int client_lock_acquired;
43350Sstevel@tonic-gate 
43360Sstevel@tonic-gate 	/*
43370Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
43380Sstevel@tonic-gate 	 *	is, we don't do anything except for return success.
43390Sstevel@tonic-gate 	 */
43400Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
43410Sstevel@tonic-gate 	    return (CS_SUCCESS);
43420Sstevel@tonic-gate 
43430Sstevel@tonic-gate 	/*
43440Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
43450Sstevel@tonic-gate 	 */
43460Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
43470Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
43480Sstevel@tonic-gate 
43490Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
43500Sstevel@tonic-gate 
43510Sstevel@tonic-gate 	/*
43520Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
43530Sstevel@tonic-gate 	 */
43540Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
43550Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
43560Sstevel@tonic-gate 	    return (error);
43570Sstevel@tonic-gate 	}
43580Sstevel@tonic-gate 
43590Sstevel@tonic-gate 	/*
43600Sstevel@tonic-gate 	 * Get the current card status as well as the latched card
43610Sstevel@tonic-gate 	 *	state.  Set the CS_RES_IGNORE_NO_CARD so that even
43620Sstevel@tonic-gate 	 *	if there is no card in the socket we'll still get
43630Sstevel@tonic-gate 	 *	a valid status.
43640Sstevel@tonic-gate 	 * Note that it is not necessary to initialize any values
43650Sstevel@tonic-gate 	 *	in the get_ss_status structure.
43660Sstevel@tonic-gate 	 */
43670Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
43680Sstevel@tonic-gate 	if ((error = cs_read_event_status(sp, client, NULL, &get_ss_status,
43690Sstevel@tonic-gate 					CS_RES_IGNORE_NO_CARD)) != CS_SUCCESS) {
43700Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
43710Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
43720Sstevel@tonic-gate 	    return (error);
43730Sstevel@tonic-gate 	}
43740Sstevel@tonic-gate 
43750Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
43760Sstevel@tonic-gate 
43770Sstevel@tonic-gate 	gs->raw_CardState = cs_sbm2cse(get_ss_status.CardState);
43780Sstevel@tonic-gate 
43790Sstevel@tonic-gate 	/*
43800Sstevel@tonic-gate 	 * Assign the "live" card state to the "real" card state. If there's
43810Sstevel@tonic-gate 	 *	no card in the socket or the card in the socket is not
43820Sstevel@tonic-gate 	 *	for this client, then we lie and tell the caller that the
43830Sstevel@tonic-gate 	 *	card is not inserted.
43840Sstevel@tonic-gate 	 */
43850Sstevel@tonic-gate 	gs->CardState = gs->raw_CardState;
43860Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED))
43870Sstevel@tonic-gate 	    gs->CardState &= ~CS_EVENT_CARD_INSERTION;
43880Sstevel@tonic-gate 
43890Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
43900Sstevel@tonic-gate 
43910Sstevel@tonic-gate 	get_socket.socket = sp->socket_num;
43920Sstevel@tonic-gate 	if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS)
43930Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
43940Sstevel@tonic-gate 
43950Sstevel@tonic-gate 	gs->SocketState = cs_sbm2cse(get_socket.state);
43960Sstevel@tonic-gate 
43970Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
43980Sstevel@tonic-gate 	set_socket.SCIntMask = get_socket.SCIntMask;
43990Sstevel@tonic-gate 	set_socket.VccLevel = get_socket.VccLevel;
44000Sstevel@tonic-gate 	set_socket.Vpp1Level = get_socket.Vpp1Level;
44010Sstevel@tonic-gate 	set_socket.Vpp2Level = get_socket.Vpp2Level;
44020Sstevel@tonic-gate 	set_socket.IREQRouting = get_socket.IRQRouting;
44030Sstevel@tonic-gate 	set_socket.IFType = get_socket.IFType;
44040Sstevel@tonic-gate 	set_socket.CtlInd = get_socket.CtlInd;
44050Sstevel@tonic-gate 	/* XXX (is ~0 correct here?) reset latched values */
44060Sstevel@tonic-gate 	set_socket.State = (unsigned)~0;
44070Sstevel@tonic-gate 
44080Sstevel@tonic-gate 	if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS)
44090Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
44100Sstevel@tonic-gate 
44110Sstevel@tonic-gate 	return (CS_SUCCESS);
44120Sstevel@tonic-gate }
44130Sstevel@tonic-gate 
44140Sstevel@tonic-gate /*
44150Sstevel@tonic-gate  * cs_cse2sbm - converts a CS event mask to an SS (SBM_XXX) event mask
44160Sstevel@tonic-gate  */
44170Sstevel@tonic-gate static event_t
cs_cse2sbm(event_t event_mask)44180Sstevel@tonic-gate cs_cse2sbm(event_t event_mask)
44190Sstevel@tonic-gate {
44200Sstevel@tonic-gate 	event_t sbm_event = 0;
44210Sstevel@tonic-gate 
44220Sstevel@tonic-gate 	/*
44230Sstevel@tonic-gate 	 * XXX - we need to handle PM_CHANGE and RESET here as well
44240Sstevel@tonic-gate 	 */
44250Sstevel@tonic-gate 	if (event_mask & CS_EVENT_WRITE_PROTECT)
44260Sstevel@tonic-gate 	    sbm_event |= SBM_WP;
44270Sstevel@tonic-gate 	if (event_mask & CS_EVENT_BATTERY_DEAD)
44280Sstevel@tonic-gate 	    sbm_event |= SBM_BVD1;
44290Sstevel@tonic-gate 	if (event_mask & CS_EVENT_BATTERY_LOW)
44300Sstevel@tonic-gate 	    sbm_event |= SBM_BVD2;
44310Sstevel@tonic-gate 	if (event_mask & CS_EVENT_CARD_READY)
44320Sstevel@tonic-gate 	    sbm_event |= SBM_RDYBSY;
44330Sstevel@tonic-gate 	if (event_mask & CS_EVENT_CARD_LOCK)
44340Sstevel@tonic-gate 	    sbm_event |= SBM_LOCKED;
44350Sstevel@tonic-gate 	if (event_mask & CS_EVENT_EJECTION_REQUEST)
44360Sstevel@tonic-gate 	    sbm_event |= SBM_EJECT;
44370Sstevel@tonic-gate 	if (event_mask & CS_EVENT_INSERTION_REQUEST)
44380Sstevel@tonic-gate 	    sbm_event |= SBM_INSERT;
44390Sstevel@tonic-gate 	if (event_mask & (CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL))
44400Sstevel@tonic-gate 	    sbm_event |= SBM_CD;
44410Sstevel@tonic-gate 
44420Sstevel@tonic-gate 	return (sbm_event);
44430Sstevel@tonic-gate }
44440Sstevel@tonic-gate 
44450Sstevel@tonic-gate /*
44460Sstevel@tonic-gate  * cs_sbm2cse - converts SBM_xxx state to CS event bits
44470Sstevel@tonic-gate  *
44480Sstevel@tonic-gate  * This function should never set any of the following bits:
44490Sstevel@tonic-gate  *
44500Sstevel@tonic-gate  *		CS_EVENT_MTD_REQUEST
44510Sstevel@tonic-gate  *		CS_EVENT_CLIENT_INFO
44520Sstevel@tonic-gate  *		CS_EVENT_TIMER_EXPIRED
44530Sstevel@tonic-gate  *		CS_EVENT_CARD_REMOVAL
44540Sstevel@tonic-gate  *		CS_EVENT_CARD_REMOVAL_LOWP
44550Sstevel@tonic-gate  *		CS_EVENT_ALL_CLIENTS
44560Sstevel@tonic-gate  *		CS_EVENT_READY_TIMEOUT
44570Sstevel@tonic-gate  *
44580Sstevel@tonic-gate  *	These bits are defined in the CS_STATUS_XXX series and are
44590Sstevel@tonic-gate  *	used by GetStatus.
44600Sstevel@tonic-gate  */
44610Sstevel@tonic-gate static uint32_t
cs_sbm2cse(uint32_t state)44620Sstevel@tonic-gate cs_sbm2cse(uint32_t state)
44630Sstevel@tonic-gate {
44640Sstevel@tonic-gate 	uint32_t rstate = 0;
44650Sstevel@tonic-gate 
44660Sstevel@tonic-gate 	/*
44670Sstevel@tonic-gate 	 * XXX - we need to handle PM_CHANGE and RESET here as well
44680Sstevel@tonic-gate 	 */
44690Sstevel@tonic-gate 	if (state & SBM_WP)
44700Sstevel@tonic-gate 	    rstate |= CS_EVENT_WRITE_PROTECT;
44710Sstevel@tonic-gate 	if (state & SBM_BVD1)
44720Sstevel@tonic-gate 	    rstate |= CS_EVENT_BATTERY_DEAD;
44730Sstevel@tonic-gate 	if (state & SBM_BVD2)
44740Sstevel@tonic-gate 	    rstate |= CS_EVENT_BATTERY_LOW;
44750Sstevel@tonic-gate 	if (state & SBM_RDYBSY)
44760Sstevel@tonic-gate 	    rstate |= CS_EVENT_CARD_READY;
44770Sstevel@tonic-gate 	if (state & SBM_LOCKED)
44780Sstevel@tonic-gate 	    rstate |= CS_EVENT_CARD_LOCK;
44790Sstevel@tonic-gate 	if (state & SBM_EJECT)
44800Sstevel@tonic-gate 	    rstate |= CS_EVENT_EJECTION_REQUEST;
44810Sstevel@tonic-gate 	if (state & SBM_INSERT)
44820Sstevel@tonic-gate 	    rstate |= CS_EVENT_INSERTION_REQUEST;
44830Sstevel@tonic-gate 	if (state & SBM_CD)
44840Sstevel@tonic-gate 	    rstate |= CS_EVENT_CARD_INSERTION;
44850Sstevel@tonic-gate 
44860Sstevel@tonic-gate 	return (rstate);
44870Sstevel@tonic-gate }
44880Sstevel@tonic-gate 
44890Sstevel@tonic-gate /*
44900Sstevel@tonic-gate  * cs_merge_event_masks - merge the CS global socket event mask with the
44910Sstevel@tonic-gate  *				passed client's event masks
44920Sstevel@tonic-gate  */
44930Sstevel@tonic-gate static unsigned
cs_merge_event_masks(cs_socket_t * sp,client_t * client)44940Sstevel@tonic-gate cs_merge_event_masks(cs_socket_t *sp, client_t *client)
44950Sstevel@tonic-gate {
44960Sstevel@tonic-gate 	unsigned SCIntMask;
44970Sstevel@tonic-gate 	uint32_t event_mask;
44980Sstevel@tonic-gate 
44990Sstevel@tonic-gate 	/*
45000Sstevel@tonic-gate 	 * We always want to see card detect and status change events.
45010Sstevel@tonic-gate 	 */
45020Sstevel@tonic-gate 	SCIntMask = SBM_CD;
45030Sstevel@tonic-gate 
45040Sstevel@tonic-gate 	event_mask = client->event_mask | client->global_mask |
45050Sstevel@tonic-gate 							sp->event_mask;
45060Sstevel@tonic-gate 
45070Sstevel@tonic-gate 	if (!(sp->flags & SOCKET_IS_IO)) {
45080Sstevel@tonic-gate 	    SCIntMask |= cs_cse2sbm(event_mask);
45090Sstevel@tonic-gate 	} else {
45100Sstevel@tonic-gate 		/*
45110Sstevel@tonic-gate 		 * If the socket is in IO mode and there is a PRR present,
45120Sstevel@tonic-gate 		 *	then we may need to enable PCE_CARD_STATUS_CHANGE
45130Sstevel@tonic-gate 		 *	events.
45140Sstevel@tonic-gate 		 */
45150Sstevel@tonic-gate 	    if (client->present & CONFIG_PINREPL_REG_PRESENT) {
45160Sstevel@tonic-gate 
45170Sstevel@tonic-gate 		SCIntMask |= (cs_cse2sbm(event_mask) &
45180Sstevel@tonic-gate 				~(SBM_WP | SBM_BVD1 | SBM_BVD2 | SBM_RDYBSY));
45190Sstevel@tonic-gate 
45200Sstevel@tonic-gate 		if ((client->pin & (PRR_WP_STATUS | PRR_WP_EVENT)) ==
45210Sstevel@tonic-gate 					(PRR_WP_STATUS | PRR_WP_EVENT))
45220Sstevel@tonic-gate 		    if (event_mask & CS_EVENT_WRITE_PROTECT)
45230Sstevel@tonic-gate 			SCIntMask |= SBM_BVD1;
45240Sstevel@tonic-gate 
45250Sstevel@tonic-gate 		if ((client->pin & (PRR_READY_STATUS | PRR_READY_EVENT)) ==
45260Sstevel@tonic-gate 					(PRR_READY_STATUS | PRR_READY_EVENT))
45270Sstevel@tonic-gate 		    if (event_mask & CS_EVENT_CARD_READY)
45280Sstevel@tonic-gate 			    SCIntMask |= SBM_BVD1;
45290Sstevel@tonic-gate 
45300Sstevel@tonic-gate 		if ((client->pin & (PRR_BVD2_STATUS | PRR_BVD2_EVENT)) ==
45310Sstevel@tonic-gate 					(PRR_BVD2_STATUS | PRR_BVD2_EVENT))
45320Sstevel@tonic-gate 		    if (event_mask & CS_EVENT_BATTERY_LOW)
45330Sstevel@tonic-gate 			    SCIntMask |= SBM_BVD1;
45340Sstevel@tonic-gate 
45350Sstevel@tonic-gate 		if ((client->pin & (PRR_BVD1_STATUS | PRR_BVD1_EVENT)) ==
45360Sstevel@tonic-gate 					(PRR_BVD1_STATUS | PRR_BVD1_EVENT))
45370Sstevel@tonic-gate 		    if (event_mask & CS_EVENT_BATTERY_DEAD)
45380Sstevel@tonic-gate 			    SCIntMask |= SBM_BVD1;
45390Sstevel@tonic-gate 
45400Sstevel@tonic-gate 	    } /* if (CONFIG_PINREPL_REG_PRESENT) */
45410Sstevel@tonic-gate 	} /* if (!SOCKET_IS_IO) */
45420Sstevel@tonic-gate 
45430Sstevel@tonic-gate 	return (SCIntMask);
45440Sstevel@tonic-gate }
45450Sstevel@tonic-gate 
45460Sstevel@tonic-gate /*
45470Sstevel@tonic-gate  * cs_set_socket_event_mask - set the event mask for the socket
45480Sstevel@tonic-gate  */
45490Sstevel@tonic-gate static int
cs_set_socket_event_mask(cs_socket_t * sp,unsigned event_mask)45500Sstevel@tonic-gate cs_set_socket_event_mask(cs_socket_t *sp, unsigned event_mask)
45510Sstevel@tonic-gate {
45520Sstevel@tonic-gate 	get_socket_t get_socket;
45530Sstevel@tonic-gate 	set_socket_t set_socket;
45540Sstevel@tonic-gate 
45550Sstevel@tonic-gate 	get_socket.socket = sp->socket_num;
45560Sstevel@tonic-gate 	if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS)
45570Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
45580Sstevel@tonic-gate 
45590Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
45600Sstevel@tonic-gate 	set_socket.SCIntMask = event_mask;
45610Sstevel@tonic-gate 	set_socket.VccLevel = get_socket.VccLevel;
45620Sstevel@tonic-gate 	set_socket.Vpp1Level = get_socket.Vpp1Level;
45630Sstevel@tonic-gate 	set_socket.Vpp2Level = get_socket.Vpp2Level;
45640Sstevel@tonic-gate 	set_socket.IREQRouting = get_socket.IRQRouting;
45650Sstevel@tonic-gate 	set_socket.IFType = get_socket.IFType;
45660Sstevel@tonic-gate 	set_socket.CtlInd = get_socket.CtlInd;
45670Sstevel@tonic-gate 	/* XXX (is ~0 correct here?) reset latched values */
45680Sstevel@tonic-gate 	set_socket.State = (unsigned)~0;
45690Sstevel@tonic-gate 
45700Sstevel@tonic-gate 	if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS)
45710Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
45720Sstevel@tonic-gate 
45730Sstevel@tonic-gate 	return (CS_SUCCESS);
45740Sstevel@tonic-gate }
45750Sstevel@tonic-gate 
45760Sstevel@tonic-gate /*
45770Sstevel@tonic-gate  * ==== MTD handling section ====
45780Sstevel@tonic-gate  */
45790Sstevel@tonic-gate static int
cs_deregister_mtd(client_handle_t client_handle)45800Sstevel@tonic-gate cs_deregister_mtd(client_handle_t client_handle)
45810Sstevel@tonic-gate {
45820Sstevel@tonic-gate 
45830Sstevel@tonic-gate 	cmn_err(CE_CONT, "cs_deregister_mtd: client_handle 0x%x\n",
45840Sstevel@tonic-gate 							(int)client_handle);
45850Sstevel@tonic-gate 
45860Sstevel@tonic-gate 	return (CS_SUCCESS);
45870Sstevel@tonic-gate }
45880Sstevel@tonic-gate 
45890Sstevel@tonic-gate /*
45900Sstevel@tonic-gate  * ==== memory window handling section ====
45910Sstevel@tonic-gate  */
45920Sstevel@tonic-gate 
45930Sstevel@tonic-gate /*
45940Sstevel@tonic-gate  * cs_request_window  - searches through window list for the socket to find a
45950Sstevel@tonic-gate  *			memory window that matches the requested criteria;
45960Sstevel@tonic-gate  *			this is RequestWindow
45970Sstevel@tonic-gate  *
45980Sstevel@tonic-gate  * calling:  cs_request_window(client_handle_t, *window_handle_t, win_req_t *)
45990Sstevel@tonic-gate  *
46000Sstevel@tonic-gate  *	On sucessful return, the window_handle_t * pointed to will
46010Sstevel@tonic-gate  *		contain a valid window handle for this window.
46020Sstevel@tonic-gate  *
46030Sstevel@tonic-gate  *	returns: CS_SUCCESS - if window found
46040Sstevel@tonic-gate  *		 CS_OUT_OF_RESOURCE - if no windows match requirements
46050Sstevel@tonic-gate  *		 CS_BAD_HANDLE - client handle is invalid
46060Sstevel@tonic-gate  *		 CS_BAD_SIZE - if requested size can not be met
46070Sstevel@tonic-gate  *		 CS_BAD_WINDOW - if an internal error occured
46080Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
46090Sstevel@tonic-gate  *		 CS_NO_CARD - if no card is in socket
46100Sstevel@tonic-gate  *		 CS_BAD_ATTRIBUTE - if any of the unsupported Attrbute
46110Sstevel@tonic-gate  *					flags are set
46120Sstevel@tonic-gate  */
46130Sstevel@tonic-gate static int
cs_request_window(client_handle_t client_handle,window_handle_t * wh,win_req_t * rw)46140Sstevel@tonic-gate cs_request_window(client_handle_t client_handle,
46150Sstevel@tonic-gate 				window_handle_t *wh,
46160Sstevel@tonic-gate 				win_req_t *rw)
46170Sstevel@tonic-gate {
46180Sstevel@tonic-gate 	cs_socket_t *sp;
46190Sstevel@tonic-gate 	cs_window_t *cw;
46200Sstevel@tonic-gate 	client_t *client;
46210Sstevel@tonic-gate 	modify_win_t mw;
46220Sstevel@tonic-gate 	inquire_window_t iw;
46230Sstevel@tonic-gate 	uint32_t aw;
46240Sstevel@tonic-gate 	int error;
46250Sstevel@tonic-gate 	int client_lock_acquired;
46260Sstevel@tonic-gate 	uint32_t socket_num;
46270Sstevel@tonic-gate 
46280Sstevel@tonic-gate 	/*
46290Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
46300Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
46310Sstevel@tonic-gate 	 */
46320Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
46330Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
46340Sstevel@tonic-gate 
46350Sstevel@tonic-gate 	/*
46360Sstevel@tonic-gate 	 * Make sure that none of the unsupported flags are set.
46370Sstevel@tonic-gate 	 */
46380Sstevel@tonic-gate 	if (rw->Attributes &   (/* Compatability */
46390Sstevel@tonic-gate 				WIN_PAGED |
46400Sstevel@tonic-gate 				WIN_SHARED |
46410Sstevel@tonic-gate 				WIN_FIRST_SHARED |
46420Sstevel@tonic-gate 				WIN_BINDING_SPECIFIC |
46430Sstevel@tonic-gate 				/* CS internal */
46440Sstevel@tonic-gate 				WIN_DATA_WIDTH_VALID |
46450Sstevel@tonic-gate 				/* IO window flags */
46460Sstevel@tonic-gate 				WIN_MEMORY_TYPE_IO |
46470Sstevel@tonic-gate 				/* CardBus flags */
46480Sstevel@tonic-gate 				WIN_DATA_WIDTH_32 |
46490Sstevel@tonic-gate 				WIN_PREFETCH_CACHE_MASK |
46500Sstevel@tonic-gate 				WIN_BAR_MASK))
46510Sstevel@tonic-gate 	    return (CS_BAD_ATTRIBUTE);
46520Sstevel@tonic-gate 
46530Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
46540Sstevel@tonic-gate 
46550Sstevel@tonic-gate 	/*
46560Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
46570Sstevel@tonic-gate 	 */
46580Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
46590Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
46600Sstevel@tonic-gate 
46610Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
46620Sstevel@tonic-gate 
46630Sstevel@tonic-gate 	/*
46640Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
46650Sstevel@tonic-gate 	 */
46660Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
46670Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
46680Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
46690Sstevel@tonic-gate 	    return (error);
46700Sstevel@tonic-gate 	}
46710Sstevel@tonic-gate 
46720Sstevel@tonic-gate 	mutex_enter(&sp->lock);
46730Sstevel@tonic-gate 
46740Sstevel@tonic-gate 	/*
46750Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
46760Sstevel@tonic-gate 	 *	for this client, then return an error.
46770Sstevel@tonic-gate 	 */
46780Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
46790Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
46800Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
46810Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
46820Sstevel@tonic-gate 	    return (CS_NO_CARD);
46830Sstevel@tonic-gate 	}
46840Sstevel@tonic-gate 
46850Sstevel@tonic-gate 	mutex_exit(&sp->lock);
46860Sstevel@tonic-gate 
46870Sstevel@tonic-gate 	socket_num = CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
46880Sstevel@tonic-gate 	    GET_CLIENT_FUNCTION(client_handle));
46890Sstevel@tonic-gate 
46900Sstevel@tonic-gate 
46910Sstevel@tonic-gate 	/*
46920Sstevel@tonic-gate 	 * See if we can find a window that matches the caller's criteria.
46930Sstevel@tonic-gate 	 *	If we can't, then thre's not much more that we can do except
46940Sstevel@tonic-gate 	 *	for return an error.
46950Sstevel@tonic-gate 	 */
46960Sstevel@tonic-gate 	if ((error = cs_find_mem_window(sp->socket_num, rw, &aw)) !=
46970Sstevel@tonic-gate 								CS_SUCCESS) {
46980Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
46990Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
47000Sstevel@tonic-gate 	    return (error);
47010Sstevel@tonic-gate 	}
47020Sstevel@tonic-gate 
47030Sstevel@tonic-gate 	/*
47040Sstevel@tonic-gate 	 * We got a window, now synthesize a new window handle for this
47050Sstevel@tonic-gate 	 *	client and get a pointer to the global window structs
47060Sstevel@tonic-gate 	 *	and assign this window to this client.
47070Sstevel@tonic-gate 	 * We don't have to check for errors from cs_create_window_handle
47080Sstevel@tonic-gate 	 *	since that function always returns a valid window handle
47090Sstevel@tonic-gate 	 *	if it is given a valid window number.
47100Sstevel@tonic-gate 	 */
47110Sstevel@tonic-gate 	*wh = cs_create_window_handle(aw);
47120Sstevel@tonic-gate 	if ((cw = cs_get_wp(aw)) == NULL) {
47130Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
47140Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
47150Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
47160Sstevel@tonic-gate 	}
47170Sstevel@tonic-gate 
47180Sstevel@tonic-gate 	cw->window_handle = *wh;
47190Sstevel@tonic-gate 	cw->client_handle = client_handle;
47200Sstevel@tonic-gate 	cw->socket_num = sp->socket_num;
47210Sstevel@tonic-gate 	cw->state |= (CW_ALLOCATED | CW_MEM);
47220Sstevel@tonic-gate 
47230Sstevel@tonic-gate 	mw.Attributes = (
47240Sstevel@tonic-gate 				rw->Attributes |
47250Sstevel@tonic-gate 				WIN_DATA_WIDTH_VALID |
47260Sstevel@tonic-gate 				WIN_ACCESS_SPEED_VALID);
47270Sstevel@tonic-gate 	mw.AccessSpeed = rw->win_params.AccessSpeed;
47280Sstevel@tonic-gate 
47290Sstevel@tonic-gate 	if ((error = cs_modify_mem_window(*wh, &mw, rw, socket_num)) !=
47300Sstevel@tonic-gate 	    CS_SUCCESS) {
47310Sstevel@tonic-gate 	    cw->state = 0;
47320Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
47330Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
47340Sstevel@tonic-gate 	    return (error);
47350Sstevel@tonic-gate 	}
47360Sstevel@tonic-gate 
47370Sstevel@tonic-gate 	/*
47380Sstevel@tonic-gate 	 * Get any required card offset and pass it back to the client.
47390Sstevel@tonic-gate 	 *	This is not defined in the current PCMCIA spec.  It is
47400Sstevel@tonic-gate 	 *	an aid to clients that want to use it to generate an
47410Sstevel@tonic-gate 	 *	optimum card offset.
47420Sstevel@tonic-gate 	 */
47430Sstevel@tonic-gate 	iw.window = GET_WINDOW_NUMBER(*wh);
47440Sstevel@tonic-gate 	SocketServices(SS_InquireWindow, &iw);
47450Sstevel@tonic-gate 
47460Sstevel@tonic-gate 	if (iw.mem_win_char.MemWndCaps & WC_CALIGN)
47470Sstevel@tonic-gate 	    rw->ReqOffset = rw->Size;
47480Sstevel@tonic-gate 	else
47490Sstevel@tonic-gate 	    rw->ReqOffset = iw.mem_win_char.ReqOffset;
47500Sstevel@tonic-gate 
47510Sstevel@tonic-gate 	/*
47520Sstevel@tonic-gate 	 * Increment the client's memory window count; this is how we know
47530Sstevel@tonic-gate 	 *	when a client has any allocated memory windows.
47540Sstevel@tonic-gate 	 */
47550Sstevel@tonic-gate 	client->memwin_count++;
47560Sstevel@tonic-gate 
47570Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
47580Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
47590Sstevel@tonic-gate 
47600Sstevel@tonic-gate 	return (CS_SUCCESS);
47610Sstevel@tonic-gate }
47620Sstevel@tonic-gate 
47630Sstevel@tonic-gate /*
47640Sstevel@tonic-gate  * cs_release_window - deallocates the window associated with the passed
47650Sstevel@tonic-gate  *			window handle; this is ReleaseWindow
47660Sstevel@tonic-gate  *
47670Sstevel@tonic-gate  *	returns: CS_SUCCESS if window handle is valid and window was
47680Sstevel@tonic-gate  *			sucessfully deallocated
47690Sstevel@tonic-gate  *		 CS_BAD_HANDLE if window handle is invalid or if window
47700Sstevel@tonic-gate  *			handle is valid but window is not allocated
47710Sstevel@tonic-gate  */
47720Sstevel@tonic-gate static int
cs_release_window(window_handle_t wh)47730Sstevel@tonic-gate cs_release_window(window_handle_t wh)
47740Sstevel@tonic-gate {
47750Sstevel@tonic-gate 	cs_socket_t *sp;
47760Sstevel@tonic-gate 	cs_window_t *cw;
47770Sstevel@tonic-gate 	client_t *client;
47780Sstevel@tonic-gate 	int error;
47790Sstevel@tonic-gate 	int client_lock_acquired;
47800Sstevel@tonic-gate 
47810Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
47820Sstevel@tonic-gate 
47830Sstevel@tonic-gate 	if (!(cw = cs_find_window(wh))) {
47840Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
47850Sstevel@tonic-gate 	    return (CS_BAD_HANDLE);
47860Sstevel@tonic-gate 	}
47870Sstevel@tonic-gate 
47880Sstevel@tonic-gate 	/*
47890Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
47900Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
47910Sstevel@tonic-gate 	 */
47920Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(cw->client_handle)) {
47930Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
47940Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
47950Sstevel@tonic-gate 	}
47960Sstevel@tonic-gate 
47970Sstevel@tonic-gate 	/*
47980Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
47990Sstevel@tonic-gate 	 */
48000Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(cw->client_handle))) == NULL)
48010Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
48020Sstevel@tonic-gate 
48030Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
48040Sstevel@tonic-gate 
48050Sstevel@tonic-gate 	/*
48060Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
48070Sstevel@tonic-gate 	 */
48080Sstevel@tonic-gate 	if (!(client = cs_find_client(cw->client_handle, &error))) {
48090Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
48100Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
48110Sstevel@tonic-gate 	    return (error);
48120Sstevel@tonic-gate 	}
48130Sstevel@tonic-gate 
48140Sstevel@tonic-gate 	/*
48150Sstevel@tonic-gate 	 * Mark this window as not in use anymore.
48160Sstevel@tonic-gate 	 */
48170Sstevel@tonic-gate 	cw->state &= ~CW_WIN_IN_USE;
48180Sstevel@tonic-gate 
48190Sstevel@tonic-gate 	/*
48200Sstevel@tonic-gate 	 * Decrement the client's memory window count; this is how we know
48210Sstevel@tonic-gate 	 *	when a client has any allocated memory windows.
48220Sstevel@tonic-gate 	 */
48230Sstevel@tonic-gate 	if (!(--(client->memwin_count)))
48240Sstevel@tonic-gate 	    client->flags &= ~CLIENT_WIN_ALLOCATED;
48250Sstevel@tonic-gate 
48260Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
48270Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
48280Sstevel@tonic-gate 
48290Sstevel@tonic-gate 	return (CS_SUCCESS);
48300Sstevel@tonic-gate }
48310Sstevel@tonic-gate 
48320Sstevel@tonic-gate /*
48330Sstevel@tonic-gate  * cs_modify_window - modifies a window's characteristics; this is ModifyWindow
48340Sstevel@tonic-gate  */
48350Sstevel@tonic-gate static int
cs_modify_window(window_handle_t wh,modify_win_t * mw)48360Sstevel@tonic-gate cs_modify_window(window_handle_t wh, modify_win_t *mw)
48370Sstevel@tonic-gate {
48380Sstevel@tonic-gate 	cs_socket_t *sp;
48390Sstevel@tonic-gate 	cs_window_t *cw;
48400Sstevel@tonic-gate 	client_t *client;
48410Sstevel@tonic-gate 	int error;
48420Sstevel@tonic-gate 	int client_lock_acquired;
48430Sstevel@tonic-gate 
48440Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
48450Sstevel@tonic-gate 
48460Sstevel@tonic-gate 	/*
48470Sstevel@tonic-gate 	 * Do some sanity checking - make sure that we can find a pointer
48480Sstevel@tonic-gate 	 *	to the window structure, and if we can, get the client that
48490Sstevel@tonic-gate 	 *	has allocated that window.
48500Sstevel@tonic-gate 	 */
48510Sstevel@tonic-gate 	if (!(cw = cs_find_window(wh))) {
48520Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
48530Sstevel@tonic-gate 	    return (CS_BAD_HANDLE);
48540Sstevel@tonic-gate 	}
48550Sstevel@tonic-gate 
48560Sstevel@tonic-gate 	/*
48570Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
48580Sstevel@tonic-gate 	 */
48590Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(cw->client_handle))) == NULL)
48600Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
48610Sstevel@tonic-gate 
48620Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
48630Sstevel@tonic-gate 
48640Sstevel@tonic-gate 	if (!(client = cs_find_client(cw->client_handle, &error))) {
48650Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
48660Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
48670Sstevel@tonic-gate 	    return (error);
48680Sstevel@tonic-gate 	}
48690Sstevel@tonic-gate 
48700Sstevel@tonic-gate 	mutex_enter(&sp->lock);
48710Sstevel@tonic-gate 
48720Sstevel@tonic-gate 	/*
48730Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
48740Sstevel@tonic-gate 	 *	for this client, then return an error.
48750Sstevel@tonic-gate 	 */
48760Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
48770Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
48780Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
48790Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
48800Sstevel@tonic-gate 	    return (CS_NO_CARD);
48810Sstevel@tonic-gate 	}
48820Sstevel@tonic-gate 
48830Sstevel@tonic-gate 	mutex_exit(&sp->lock);
48840Sstevel@tonic-gate 
48850Sstevel@tonic-gate 	mw->Attributes &= (
48860Sstevel@tonic-gate 				WIN_MEMORY_TYPE_MASK |
48870Sstevel@tonic-gate 				WIN_ENABLE |
48880Sstevel@tonic-gate 				WIN_ACCESS_SPEED_VALID |
48890Sstevel@tonic-gate 				WIN_ACC_ENDIAN_MASK |
48900Sstevel@tonic-gate 				WIN_ACC_ORDER_MASK);
48910Sstevel@tonic-gate 
48920Sstevel@tonic-gate 	mw->Attributes &= ~WIN_DATA_WIDTH_VALID;
48930Sstevel@tonic-gate 
48940Sstevel@tonic-gate 	if ((error = cs_modify_mem_window(wh, mw, NULL, NULL)) != CS_SUCCESS) {
48950Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
48960Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
48970Sstevel@tonic-gate 	    return (error);
48980Sstevel@tonic-gate 	}
48990Sstevel@tonic-gate 
49000Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
49010Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
49020Sstevel@tonic-gate 
49030Sstevel@tonic-gate 	return (CS_SUCCESS);
49040Sstevel@tonic-gate }
49050Sstevel@tonic-gate 
49060Sstevel@tonic-gate /*
49070Sstevel@tonic-gate  * cs_modify_mem_window - modifies a window's characteristics; used internally
49080Sstevel@tonic-gate  *				by Card Services
49090Sstevel@tonic-gate  *
49100Sstevel@tonic-gate  *    If *wr is NULL, it means that we're being called by ModifyWindow
49110Sstevel@tonic-gate  *    If *wr is non-NULL, it means that we are being called by RequestWindow
49120Sstevel@tonic-gate  *	and so we can't use SS_GetWindow.
49130Sstevel@tonic-gate  */
49140Sstevel@tonic-gate static int
cs_modify_mem_window(window_handle_t wh,modify_win_t * mw,win_req_t * wr,int sn)49150Sstevel@tonic-gate cs_modify_mem_window(window_handle_t wh, modify_win_t *mw,
49160Sstevel@tonic-gate 						win_req_t *wr, int sn)
49170Sstevel@tonic-gate {
49180Sstevel@tonic-gate 	get_window_t gw;
49190Sstevel@tonic-gate 	set_window_t sw;
49200Sstevel@tonic-gate 	set_page_t set_page;
49210Sstevel@tonic-gate 	get_page_t get_page;
49220Sstevel@tonic-gate 
49230Sstevel@tonic-gate 	/*
49240Sstevel@tonic-gate 	 * If the win_req_t struct pointer is NULL, it means that
49250Sstevel@tonic-gate 	 *	we're being called by ModifyWindow, so get the
49260Sstevel@tonic-gate 	 *	current window characteristics.
49270Sstevel@tonic-gate 	 */
49280Sstevel@tonic-gate 	if (!wr) {
49290Sstevel@tonic-gate 	    gw.window = GET_WINDOW_NUMBER(wh);
49300Sstevel@tonic-gate 	    if (SocketServices(SS_GetWindow, &gw) != SUCCESS)
49310Sstevel@tonic-gate 		return (CS_BAD_WINDOW);
49320Sstevel@tonic-gate 	    sw.state = gw.state;
49330Sstevel@tonic-gate 	    sw.socket = gw.socket;
49340Sstevel@tonic-gate 	    sw.WindowSize = gw.size;
49350Sstevel@tonic-gate 	} else {
49360Sstevel@tonic-gate 	    sw.state = 0;
49370Sstevel@tonic-gate 	    sw.socket = sn;
49380Sstevel@tonic-gate 	    sw.WindowSize = wr->Size;
49390Sstevel@tonic-gate 	}
49400Sstevel@tonic-gate 
49410Sstevel@tonic-gate 	/*
49420Sstevel@tonic-gate 	 * If we're being called by RequestWindow, we must always have
49430Sstevel@tonic-gate 	 *	WIN_ACCESS_SPEED_VALID set since get_window_t is not
49440Sstevel@tonic-gate 	 *	defined.
49450Sstevel@tonic-gate 	 */
49460Sstevel@tonic-gate 	if (mw->Attributes & WIN_ACCESS_SPEED_VALID) {
49470Sstevel@tonic-gate 	    convert_speed_t convert_speed;
49480Sstevel@tonic-gate 
49490Sstevel@tonic-gate 	    convert_speed.Attributes = CONVERT_DEVSPEED_TO_NS;
49500Sstevel@tonic-gate 	    convert_speed.devspeed = mw->AccessSpeed;
49510Sstevel@tonic-gate 
49520Sstevel@tonic-gate 	    if (cs_convert_speed(&convert_speed) != CS_SUCCESS)
49530Sstevel@tonic-gate 		return (CS_BAD_SPEED);
49540Sstevel@tonic-gate 
49550Sstevel@tonic-gate 	    sw.speed = convert_speed.nS;
49560Sstevel@tonic-gate 	} else {
49570Sstevel@tonic-gate 	    sw.speed = gw.speed;
49580Sstevel@tonic-gate 	}
49590Sstevel@tonic-gate 
49600Sstevel@tonic-gate 	if (!wr) {
49610Sstevel@tonic-gate 	    get_page.window = GET_WINDOW_NUMBER(wh);
49620Sstevel@tonic-gate 	    get_page.page = 0;
49630Sstevel@tonic-gate 	    if (SocketServices(SS_GetPage, &get_page) != SUCCESS)
49640Sstevel@tonic-gate 		return (CS_BAD_WINDOW);
49650Sstevel@tonic-gate 	    set_page.state = get_page.state;
49660Sstevel@tonic-gate 	    set_page.offset = get_page.offset;
49670Sstevel@tonic-gate 	} else {
49680Sstevel@tonic-gate 	    set_page.state = 0;
49690Sstevel@tonic-gate 	    set_page.offset = 0;
49700Sstevel@tonic-gate 	}
49710Sstevel@tonic-gate 
49720Sstevel@tonic-gate 	if (mw->Attributes & WIN_ENABLE) {
49730Sstevel@tonic-gate 	    sw.state |= WS_ENABLED;
49740Sstevel@tonic-gate 	    set_page.state |= PS_ENABLED;
49750Sstevel@tonic-gate 	} else {
49760Sstevel@tonic-gate 	    sw.state &= ~WS_ENABLED;
49770Sstevel@tonic-gate 	    set_page.state &= ~PS_ENABLED;
49780Sstevel@tonic-gate 	}
49790Sstevel@tonic-gate 
49800Sstevel@tonic-gate 	if (mw->Attributes & WIN_DATA_WIDTH_VALID) {
49810Sstevel@tonic-gate 	    if (mw->Attributes & WIN_DATA_WIDTH_16)
49820Sstevel@tonic-gate 		sw.state |= WS_16BIT;
49830Sstevel@tonic-gate 	    else
49840Sstevel@tonic-gate 		sw.state &= ~WS_16BIT;
49850Sstevel@tonic-gate 	}
49860Sstevel@tonic-gate 
49870Sstevel@tonic-gate 	sw.window = GET_WINDOW_NUMBER(wh);
49880Sstevel@tonic-gate 	sw.base = 0;
49890Sstevel@tonic-gate 
49900Sstevel@tonic-gate 	cs_set_acc_attributes(&sw, mw->Attributes);
49910Sstevel@tonic-gate 
49920Sstevel@tonic-gate 	if (SocketServices(SS_SetWindow, &sw) != SUCCESS)
49930Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
49940Sstevel@tonic-gate 
49950Sstevel@tonic-gate 	if (mw->Attributes & WIN_MEMORY_TYPE_AM)
49960Sstevel@tonic-gate 	    set_page.state |= PS_ATTRIBUTE;
49970Sstevel@tonic-gate 	else
49980Sstevel@tonic-gate 	    set_page.state &= ~PS_ATTRIBUTE;
49990Sstevel@tonic-gate 
50000Sstevel@tonic-gate 	set_page.window = GET_WINDOW_NUMBER(wh);
50010Sstevel@tonic-gate 	set_page.page = 0;
50020Sstevel@tonic-gate 	if (SocketServices(SS_SetPage, &set_page) != SUCCESS)
50030Sstevel@tonic-gate 	    return (CS_BAD_OFFSET);
50040Sstevel@tonic-gate 
50050Sstevel@tonic-gate 	/*
50060Sstevel@tonic-gate 	 * Return the current base address of this window
50070Sstevel@tonic-gate 	 */
50080Sstevel@tonic-gate 	if (wr) {
50090Sstevel@tonic-gate 	    gw.window = GET_WINDOW_NUMBER(wh);
50100Sstevel@tonic-gate 	    if (SocketServices(SS_GetWindow, &gw) != SUCCESS)
50110Sstevel@tonic-gate 		return (CS_BAD_WINDOW);
50120Sstevel@tonic-gate 
50130Sstevel@tonic-gate 	    wr->Base.handle = (acc_handle_t)gw.handle;
50140Sstevel@tonic-gate 	}
50150Sstevel@tonic-gate 
50160Sstevel@tonic-gate 	return (CS_SUCCESS);
50170Sstevel@tonic-gate }
50180Sstevel@tonic-gate 
50190Sstevel@tonic-gate /*
50200Sstevel@tonic-gate  * cs_map_mem_page - sets the card offset of the mapped window
50210Sstevel@tonic-gate  */
50220Sstevel@tonic-gate static int
cs_map_mem_page(window_handle_t wh,map_mem_page_t * mmp)50230Sstevel@tonic-gate cs_map_mem_page(window_handle_t wh, map_mem_page_t *mmp)
50240Sstevel@tonic-gate {
50250Sstevel@tonic-gate 	cs_socket_t *sp;
50260Sstevel@tonic-gate 	cs_window_t *cw;
50270Sstevel@tonic-gate 	client_t *client;
50280Sstevel@tonic-gate 	inquire_window_t iw;
50290Sstevel@tonic-gate 	get_window_t gw;
50300Sstevel@tonic-gate 	set_page_t set_page;
50310Sstevel@tonic-gate 	get_page_t get_page;
50320Sstevel@tonic-gate 	int error;
50330Sstevel@tonic-gate 	uint32_t size;
50340Sstevel@tonic-gate 	int client_lock_acquired;
50350Sstevel@tonic-gate 
50360Sstevel@tonic-gate 	/*
50370Sstevel@tonic-gate 	 * We don't support paged windows, so never allow a page number
50380Sstevel@tonic-gate 	 *	of other than 0
50390Sstevel@tonic-gate 	 */
50400Sstevel@tonic-gate 	if (mmp->Page)
50410Sstevel@tonic-gate 	    return (CS_BAD_PAGE);
50420Sstevel@tonic-gate 
50430Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
50440Sstevel@tonic-gate 
50450Sstevel@tonic-gate 	/*
50460Sstevel@tonic-gate 	 * Do some sanity checking - make sure that we can find a pointer
50470Sstevel@tonic-gate 	 *	to the window structure, and if we can, get the client that
50480Sstevel@tonic-gate 	 *	has allocated that window.
50490Sstevel@tonic-gate 	 */
50500Sstevel@tonic-gate 	if (!(cw = cs_find_window(wh))) {
50510Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
50520Sstevel@tonic-gate 	    return (CS_BAD_HANDLE);
50530Sstevel@tonic-gate 	}
50540Sstevel@tonic-gate 
50550Sstevel@tonic-gate 	/*
50560Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
50570Sstevel@tonic-gate 	 */
50580Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(cw->client_handle))) == NULL)
50590Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
50600Sstevel@tonic-gate 
50610Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
50620Sstevel@tonic-gate 
50630Sstevel@tonic-gate 	if (!(client = cs_find_client(cw->client_handle, &error))) {
50640Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
50650Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
50660Sstevel@tonic-gate 	    return (error);
50670Sstevel@tonic-gate 	}
50680Sstevel@tonic-gate 
50690Sstevel@tonic-gate 	mutex_enter(&sp->lock);
50700Sstevel@tonic-gate 
50710Sstevel@tonic-gate 	/*
50720Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
50730Sstevel@tonic-gate 	 *	for this client, then return an error.
50740Sstevel@tonic-gate 	 */
50750Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
50760Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
50770Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
50780Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
50790Sstevel@tonic-gate 	    return (CS_NO_CARD);
50800Sstevel@tonic-gate 	}
50810Sstevel@tonic-gate 
50820Sstevel@tonic-gate 	mutex_exit(&sp->lock);
50830Sstevel@tonic-gate 
50840Sstevel@tonic-gate 	gw.window = GET_WINDOW_NUMBER(wh);
50850Sstevel@tonic-gate 	SocketServices(SS_GetWindow, &gw);
50860Sstevel@tonic-gate 
50870Sstevel@tonic-gate 	iw.window = GET_WINDOW_NUMBER(wh);
50880Sstevel@tonic-gate 	SocketServices(SS_InquireWindow, &iw);
50890Sstevel@tonic-gate 
50900Sstevel@tonic-gate 	if (iw.mem_win_char.MemWndCaps & WC_CALIGN)
50910Sstevel@tonic-gate 	    size = gw.size;
50920Sstevel@tonic-gate 	else
50930Sstevel@tonic-gate 	    size = iw.mem_win_char.ReqOffset;
50940Sstevel@tonic-gate 
50950Sstevel@tonic-gate 	if (((mmp->CardOffset/size)*size) != mmp->CardOffset) {
50960Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
50970Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
50980Sstevel@tonic-gate 	    return (CS_BAD_OFFSET);
50990Sstevel@tonic-gate 	}
51000Sstevel@tonic-gate 
51010Sstevel@tonic-gate 	get_page.window = GET_WINDOW_NUMBER(wh);
51020Sstevel@tonic-gate 	get_page.page = 0;
51030Sstevel@tonic-gate 	SocketServices(SS_GetPage, &get_page);
51040Sstevel@tonic-gate 
51050Sstevel@tonic-gate 	set_page.window = GET_WINDOW_NUMBER(wh);
51060Sstevel@tonic-gate 	set_page.page = 0;
51070Sstevel@tonic-gate 	set_page.state = get_page.state;
51080Sstevel@tonic-gate 	set_page.offset = mmp->CardOffset;
51090Sstevel@tonic-gate 	if (SocketServices(SS_SetPage, &set_page) != SUCCESS) {
51100Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
51110Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
51120Sstevel@tonic-gate 	    return (CS_BAD_OFFSET);
51130Sstevel@tonic-gate 	}
51140Sstevel@tonic-gate 
51150Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
51160Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
51170Sstevel@tonic-gate 
51180Sstevel@tonic-gate 	return (CS_SUCCESS);
51190Sstevel@tonic-gate }
51200Sstevel@tonic-gate 
51210Sstevel@tonic-gate /*
51220Sstevel@tonic-gate  * cs_find_window - finds the window associated with the passed window
51230Sstevel@tonic-gate  *			handle; if the window handle is invalid or no
51240Sstevel@tonic-gate  *			windows match the passed window handle, NULL
51250Sstevel@tonic-gate  *			is returned.  Note that the window must be
51260Sstevel@tonic-gate  *			allocated for this function to return a valid
51270Sstevel@tonic-gate  *			window pointer.
51280Sstevel@tonic-gate  *
51290Sstevel@tonic-gate  *	returns: cs_window_t * pointer to the found window
51300Sstevel@tonic-gate  *		 NULL if window handle invalid or window not allocated
51310Sstevel@tonic-gate  */
51320Sstevel@tonic-gate cs_window_t *
cs_find_window(window_handle_t wh)51330Sstevel@tonic-gate cs_find_window(window_handle_t wh)
51340Sstevel@tonic-gate {
51350Sstevel@tonic-gate 	cs_window_t *cw;
51360Sstevel@tonic-gate 
51370Sstevel@tonic-gate 	if ((GET_WINDOW_NUMBER(wh) > cs_globals.num_windows) ||
51380Sstevel@tonic-gate 			(GET_WINDOW_MAGIC(wh) != WINDOW_HANDLE_MAGIC))
51390Sstevel@tonic-gate 	    return ((cs_window_t *)NULL);
51400Sstevel@tonic-gate 
51410Sstevel@tonic-gate 	if ((cw = cs_get_wp(GET_WINDOW_NUMBER(wh))) == NULL)
51420Sstevel@tonic-gate 	    return (NULL);
51430Sstevel@tonic-gate 
51440Sstevel@tonic-gate 	if ((cw->state & CW_ALLOCATED) && (cw->state & CW_MEM))
51450Sstevel@tonic-gate 	    return (cw);
51460Sstevel@tonic-gate 
51470Sstevel@tonic-gate 	return ((cs_window_t *)NULL);
51480Sstevel@tonic-gate }
51490Sstevel@tonic-gate 
51500Sstevel@tonic-gate /*
51510Sstevel@tonic-gate  * cs_create_window_handle - creates a unique window handle based on the
51520Sstevel@tonic-gate  *				passed window number.
51530Sstevel@tonic-gate  */
51540Sstevel@tonic-gate static window_handle_t
cs_create_window_handle(uint32_t aw)51550Sstevel@tonic-gate cs_create_window_handle(uint32_t aw)
51560Sstevel@tonic-gate {
51570Sstevel@tonic-gate 	return (WINDOW_HANDLE_MAGIC | (aw & WINDOW_HANDLE_MASK));
51580Sstevel@tonic-gate }
51590Sstevel@tonic-gate 
51600Sstevel@tonic-gate /*
51610Sstevel@tonic-gate  * cs_find_mem_window - tries to find a memory window matching the caller's
51620Sstevel@tonic-gate  *			criteria
51630Sstevel@tonic-gate  *
51640Sstevel@tonic-gate  *	We return the first window that matches the requested criteria.
51650Sstevel@tonic-gate  *
51660Sstevel@tonic-gate  *	returns: CS_SUCCESS - if memory window found
51670Sstevel@tonic-gate  *		 CS_OUT_OF_RESOURCE - if no windows match requirements
51680Sstevel@tonic-gate  *		 CS_BAD_SIZE - if requested size can not be met
51690Sstevel@tonic-gate  *		 CS_BAD_WINDOW - if an internal error occured
51700Sstevel@tonic-gate  */
51710Sstevel@tonic-gate /* BEGIN CSTYLED */
51720Sstevel@tonic-gate static int
cs_find_mem_window(uint32_t sn,win_req_t * rw,uint32_t * assigned_window)51730Sstevel@tonic-gate cs_find_mem_window(uint32_t sn, win_req_t *rw, uint32_t *assigned_window)
51740Sstevel@tonic-gate {
51750Sstevel@tonic-gate 	uint32_t wn;
51760Sstevel@tonic-gate 	int error = CS_OUT_OF_RESOURCE;
51770Sstevel@tonic-gate 	uint32_t window_num = PCMCIA_MAX_WINDOWS;
51780Sstevel@tonic-gate 	uint32_t min_size = UINT_MAX;
51790Sstevel@tonic-gate 	inquire_window_t inquire_window, *iw;
51800Sstevel@tonic-gate 	uint32_t MinSize, MaxSize, ReqGran, MemWndCaps, WndCaps;
51810Sstevel@tonic-gate 	uint32_t tws;
51820Sstevel@tonic-gate 
51830Sstevel@tonic-gate 	iw = &inquire_window;
51840Sstevel@tonic-gate 
51850Sstevel@tonic-gate 	for (wn = 0; wn < cs_globals.num_windows; wn++) {
51860Sstevel@tonic-gate 	    cs_window_t *cw;
51870Sstevel@tonic-gate 
51880Sstevel@tonic-gate 	    /*
51890Sstevel@tonic-gate 	     * If we can't get a pointer to this window, we should contine
51900Sstevel@tonic-gate 	     *	with scanning the next window, since this window might have
51910Sstevel@tonic-gate 	     *	been dropped.
51920Sstevel@tonic-gate 	     */
51930Sstevel@tonic-gate 	    if ((cw = cs_get_wp(wn)) != NULL) {
51940Sstevel@tonic-gate 	      iw->window = wn;
51950Sstevel@tonic-gate 
51960Sstevel@tonic-gate 	      if (SocketServices(SS_InquireWindow, iw) != SUCCESS)
51970Sstevel@tonic-gate 		return (CS_BAD_WINDOW);
51980Sstevel@tonic-gate 
51990Sstevel@tonic-gate 	      MinSize = iw->mem_win_char.MinSize;
52000Sstevel@tonic-gate 	      MaxSize = iw->mem_win_char.MaxSize;
52010Sstevel@tonic-gate 	      ReqGran = iw->mem_win_char.ReqGran;
52020Sstevel@tonic-gate 	      MemWndCaps = iw->mem_win_char.MemWndCaps;
52030Sstevel@tonic-gate 	      WndCaps = iw->WndCaps;
52040Sstevel@tonic-gate 
52050Sstevel@tonic-gate 	      if (WINDOW_FOR_SOCKET(iw->Sockets, sn) &&
52060Sstevel@tonic-gate 					WINDOW_AVAILABLE_FOR_MEM(cw) &&
52070Sstevel@tonic-gate 					WndCaps & (WC_COMMON|WC_ATTRIBUTE)) {
52080Sstevel@tonic-gate 		if ((error = cs_valid_window_speed(iw, rw->win_params.AccessSpeed)) ==
52090Sstevel@tonic-gate 					CS_SUCCESS) {
52100Sstevel@tonic-gate 		    error = CS_OUT_OF_RESOURCE;
52110Sstevel@tonic-gate 		    if (cs_memwin_space_and_map_ok(iw, rw)) {
52120Sstevel@tonic-gate 			error = CS_BAD_SIZE;
52130Sstevel@tonic-gate 			if (!rw->Size) {
52140Sstevel@tonic-gate 			    min_size = min(min_size, MinSize);
52150Sstevel@tonic-gate 			    window_num = wn;
52160Sstevel@tonic-gate 			    goto found_window;
52170Sstevel@tonic-gate 			} else {
52180Sstevel@tonic-gate 			    if (!(MemWndCaps & WC_SIZE)) {
52190Sstevel@tonic-gate 				if (rw->Size == MinSize) {
52200Sstevel@tonic-gate 				    min_size = MinSize;
52210Sstevel@tonic-gate 				    window_num = wn;
52220Sstevel@tonic-gate 				    goto found_window;
52230Sstevel@tonic-gate 				}
52240Sstevel@tonic-gate 			    } else { /* WC_SIZE */
52250Sstevel@tonic-gate 			      if (!ReqGran) {
52260Sstevel@tonic-gate 				error = CS_BAD_WINDOW;
52270Sstevel@tonic-gate 			      } else {
52280Sstevel@tonic-gate 				if ((rw->Size >= MinSize) &&
52290Sstevel@tonic-gate 							(rw->Size <= MaxSize)) {
52300Sstevel@tonic-gate 				    if (MemWndCaps & WC_POW2) {
52310Sstevel@tonic-gate 				      unsigned rg = ReqGran;
52320Sstevel@tonic-gate 					for (tws = MinSize; tws <= MaxSize;
52330Sstevel@tonic-gate 								rg = (rg<<1)) {
52340Sstevel@tonic-gate 					    if (rw->Size == tws) {
52350Sstevel@tonic-gate 						min_size = tws;
52360Sstevel@tonic-gate 						window_num = wn;
52370Sstevel@tonic-gate 						goto found_window;
52380Sstevel@tonic-gate 					    }
52390Sstevel@tonic-gate 					    tws += rg;
52400Sstevel@tonic-gate 					  } /* for (tws) */
52410Sstevel@tonic-gate 				    } else {
52420Sstevel@tonic-gate 					for (tws = MinSize; tws <= MaxSize;
52430Sstevel@tonic-gate 							tws += ReqGran) {
52440Sstevel@tonic-gate 					    if (rw->Size == tws) {
52450Sstevel@tonic-gate 						min_size = tws;
52460Sstevel@tonic-gate 						window_num = wn;
52470Sstevel@tonic-gate 						goto found_window;
52480Sstevel@tonic-gate 					    }
52490Sstevel@tonic-gate 					  } /* for (tws) */
52500Sstevel@tonic-gate 				    } /* if (!WC_POW2) */
52510Sstevel@tonic-gate 				} /* if (Size >= MinSize) */
52520Sstevel@tonic-gate 			      } /* if (!ReqGran) */
52530Sstevel@tonic-gate 			    } /* if (WC_SIZE) */
52540Sstevel@tonic-gate 			} /* if (rw->Size) */
52550Sstevel@tonic-gate 		    } /* if (cs_space_and_map_ok) */
52560Sstevel@tonic-gate 		} /* if (cs_valid_window_speed) */
52570Sstevel@tonic-gate 	      } /* if (WINDOW_FOR_SOCKET) */
52580Sstevel@tonic-gate 	    } /* if (cs_get_wp) */
52590Sstevel@tonic-gate 	} /* for (wn) */
52600Sstevel@tonic-gate 
52610Sstevel@tonic-gate 	/*
52620Sstevel@tonic-gate 	 * If we got here and the window_num wasn't set by any window
52630Sstevel@tonic-gate 	 *	 matches in the above code, it means that we didn't
52640Sstevel@tonic-gate 	 *	find a window matching the caller's criteria.
52650Sstevel@tonic-gate 	 * If the error is CS_BAD_TYPE, it means that the last reason
52660Sstevel@tonic-gate 	 *	that we couldn't match a window was because the caller's
52670Sstevel@tonic-gate 	 *	requested speed was out of range of the last window that
52680Sstevel@tonic-gate 	 *	we checked.  We convert this error code to CS_OUT_OF_RESOURCE
52690Sstevel@tonic-gate 	 *	to conform to the RequestWindow section of the PCMCIA
52700Sstevel@tonic-gate 	 *	Card Services spec.
52710Sstevel@tonic-gate 	 */
52720Sstevel@tonic-gate 	if (window_num == PCMCIA_MAX_WINDOWS) {
52730Sstevel@tonic-gate 	    if (error == CS_BAD_TYPE)
52740Sstevel@tonic-gate 		error = CS_OUT_OF_RESOURCE;
52750Sstevel@tonic-gate 	    return (error);
52760Sstevel@tonic-gate 	}
52770Sstevel@tonic-gate 
52780Sstevel@tonic-gate found_window:
52790Sstevel@tonic-gate 	rw->Size = min_size;
52800Sstevel@tonic-gate 	*assigned_window = window_num;
52810Sstevel@tonic-gate 	iw->window = window_num;
52820Sstevel@tonic-gate 	SocketServices(SS_InquireWindow, iw);
52830Sstevel@tonic-gate 	MemWndCaps = iw->mem_win_char.MemWndCaps;
52840Sstevel@tonic-gate 
52850Sstevel@tonic-gate 	if (MemWndCaps & WC_CALIGN)
52860Sstevel@tonic-gate 	    rw->Attributes |= WIN_OFFSET_SIZE;
52870Sstevel@tonic-gate 	else
52880Sstevel@tonic-gate 	    rw->Attributes &= ~WIN_OFFSET_SIZE;
52890Sstevel@tonic-gate 	return (CS_SUCCESS);
52900Sstevel@tonic-gate }
52910Sstevel@tonic-gate /* END CSTYLED */
52920Sstevel@tonic-gate 
52930Sstevel@tonic-gate /*
52940Sstevel@tonic-gate  * cs_memwin_space_and_map_ok - checks to see if the passed window mapping
52950Sstevel@tonic-gate  *				capabilities and window speeds are in the
52960Sstevel@tonic-gate  *				range of the passed window.
52970Sstevel@tonic-gate  *
52980Sstevel@tonic-gate  *	returns: 0 - if the capabilities are out of range
52990Sstevel@tonic-gate  *		 1 - if the capabilities are in range
53000Sstevel@tonic-gate  */
53010Sstevel@tonic-gate static int
cs_memwin_space_and_map_ok(inquire_window_t * iw,win_req_t * rw)53020Sstevel@tonic-gate cs_memwin_space_and_map_ok(inquire_window_t *iw, win_req_t *rw)
53030Sstevel@tonic-gate {
53040Sstevel@tonic-gate 
53050Sstevel@tonic-gate #ifdef	CS_DEBUG
53060Sstevel@tonic-gate 	if (cs_debug > 240)
53070Sstevel@tonic-gate 	    printf("-> s&m_ok: Attributes 0x%x AccessSpeed 0x%x "
53080Sstevel@tonic-gate 					"WndCaps 0x%x MemWndCaps 0x%x\n",
53090Sstevel@tonic-gate 					(int)rw->Attributes,
53100Sstevel@tonic-gate 					(int)rw->win_params.AccessSpeed,
53110Sstevel@tonic-gate 					iw->WndCaps,
53120Sstevel@tonic-gate 					iw->mem_win_char.MemWndCaps);
53130Sstevel@tonic-gate #endif
53140Sstevel@tonic-gate 
53150Sstevel@tonic-gate 	if (rw->win_params.AccessSpeed & WIN_USE_WAIT) {
53160Sstevel@tonic-gate 	    if (!(iw->WndCaps & WC_WAIT))
53170Sstevel@tonic-gate 		return (0);
53180Sstevel@tonic-gate 	}
53190Sstevel@tonic-gate 
53200Sstevel@tonic-gate 	if (rw->Attributes & WIN_DATA_WIDTH_16) {
53210Sstevel@tonic-gate 	    if (!(iw->mem_win_char.MemWndCaps & WC_16BIT))
53220Sstevel@tonic-gate 		return (0);
53230Sstevel@tonic-gate 	} else {
53240Sstevel@tonic-gate 	    if (!(iw->mem_win_char.MemWndCaps & WC_8BIT))
53250Sstevel@tonic-gate 		return (0);
53260Sstevel@tonic-gate 	}
53270Sstevel@tonic-gate 
53280Sstevel@tonic-gate 	if (rw->Attributes & WIN_MEMORY_TYPE_AM) {
53290Sstevel@tonic-gate 	    if (!(iw->WndCaps & WC_ATTRIBUTE))
53300Sstevel@tonic-gate 		return (0);
53310Sstevel@tonic-gate 	}
53320Sstevel@tonic-gate 
53330Sstevel@tonic-gate 	if (rw->Attributes & WIN_MEMORY_TYPE_CM) {
53340Sstevel@tonic-gate 	    if (!(iw->WndCaps & WC_COMMON))
53350Sstevel@tonic-gate 		return (0);
53360Sstevel@tonic-gate 	}
53370Sstevel@tonic-gate 
53380Sstevel@tonic-gate 	return (1);
53390Sstevel@tonic-gate }
53400Sstevel@tonic-gate 
53410Sstevel@tonic-gate /*
53420Sstevel@tonic-gate  * cs_valid_window_speed - checks to see if requested window speed
53430Sstevel@tonic-gate  *				is in range of passed window
53440Sstevel@tonic-gate  *
53450Sstevel@tonic-gate  *	The inquire_window_t struct gives us speeds in nS, and we
53460Sstevel@tonic-gate  *	get speeds in the AccessSpeed variable as a devspeed code.
53470Sstevel@tonic-gate  *
53480Sstevel@tonic-gate  *	returns: CS_BAD_SPEED - if AccessSpeed is invalid devspeed code
53490Sstevel@tonic-gate  *		 CS_BAD_TYPE -	if AccessSpeed is not in range of valid
53500Sstevel@tonic-gate  *				speed for this window
53510Sstevel@tonic-gate  *		 CS_SUCCESS -	if window speed is in range
53520Sstevel@tonic-gate  */
53530Sstevel@tonic-gate static int
cs_valid_window_speed(inquire_window_t * iw,uint32_t AccessSpeed)53540Sstevel@tonic-gate cs_valid_window_speed(inquire_window_t *iw, uint32_t AccessSpeed)
53550Sstevel@tonic-gate {
53560Sstevel@tonic-gate 	convert_speed_t convert_speed, *cs;
53570Sstevel@tonic-gate 
53580Sstevel@tonic-gate 	cs = &convert_speed;
53590Sstevel@tonic-gate 
53600Sstevel@tonic-gate 	cs->Attributes = CONVERT_DEVSPEED_TO_NS;
53610Sstevel@tonic-gate 	cs->devspeed = AccessSpeed;
53620Sstevel@tonic-gate 
53630Sstevel@tonic-gate 	if (cs_convert_speed(cs) != CS_SUCCESS)
53640Sstevel@tonic-gate 	    return (CS_BAD_SPEED);
53650Sstevel@tonic-gate 
53660Sstevel@tonic-gate 	if ((cs->nS < iw->mem_win_char.Fastest) ||
53670Sstevel@tonic-gate 		(cs->nS > iw->mem_win_char.Slowest))
53680Sstevel@tonic-gate 	    return (CS_BAD_TYPE);
53690Sstevel@tonic-gate 
53700Sstevel@tonic-gate 	return (CS_SUCCESS);
53710Sstevel@tonic-gate }
53720Sstevel@tonic-gate 
53730Sstevel@tonic-gate /*
53740Sstevel@tonic-gate  * ==== IO window handling section ====
53750Sstevel@tonic-gate  */
53760Sstevel@tonic-gate 
53770Sstevel@tonic-gate /*
53780Sstevel@tonic-gate  * cs_request_io - provides IO resources for clients; this is RequestIO
53790Sstevel@tonic-gate  *
53800Sstevel@tonic-gate  *	calling: cs_request_io(client_handle_t, io_req_t *)
53810Sstevel@tonic-gate  *
53820Sstevel@tonic-gate  *	returns: CS_SUCCESS - if IO resources available for client
53830Sstevel@tonic-gate  *		 CS_OUT_OF_RESOURCE - if no windows match requirements
53840Sstevel@tonic-gate  *		 CS_BAD_HANDLE - client handle is invalid
53850Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
53860Sstevel@tonic-gate  *		 CS_NO_CARD - if no card is in socket
53870Sstevel@tonic-gate  *		 CS_BAD_ATTRIBUTE - if any of the unsupported Attribute
53880Sstevel@tonic-gate  *					flags are set
53890Sstevel@tonic-gate  *		 CS_BAD_BASE - if either or both base port addresses
53900Sstevel@tonic-gate  *					are invalid or out of range
53910Sstevel@tonic-gate  *		 CS_CONFIGURATION_LOCKED - a RequestConfiguration has
53920Sstevel@tonic-gate  *					already been done
53930Sstevel@tonic-gate  *		 CS_IN_USE - IO ports already in use or function has
53940Sstevel@tonic-gate  *					already been called
53950Sstevel@tonic-gate  *		 CS_BAD_WINDOW - if failure while trying to set window
53960Sstevel@tonic-gate  *					characteristics
53970Sstevel@tonic-gate  */
53980Sstevel@tonic-gate static int
cs_request_io(client_handle_t client_handle,io_req_t * ior)53990Sstevel@tonic-gate cs_request_io(client_handle_t client_handle, io_req_t *ior)
54000Sstevel@tonic-gate {
54010Sstevel@tonic-gate 	cs_socket_t *sp;
54020Sstevel@tonic-gate 	client_t *client;
54030Sstevel@tonic-gate 	int error;
54040Sstevel@tonic-gate 	int client_lock_acquired;
54050Sstevel@tonic-gate 	uint32_t socket_num;
54060Sstevel@tonic-gate 
54070Sstevel@tonic-gate 	/*
54080Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
54090Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
54100Sstevel@tonic-gate 	 */
54110Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
54120Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
54130Sstevel@tonic-gate 
54140Sstevel@tonic-gate 	/*
54150Sstevel@tonic-gate 	 * If the client has only requested one IO range, then make sure
54160Sstevel@tonic-gate 	 *	that the Attributes2 filed is clear.
54170Sstevel@tonic-gate 	 */
54180Sstevel@tonic-gate 	if (!ior->NumPorts2)
54190Sstevel@tonic-gate 	    ior->Attributes2 = 0;
54200Sstevel@tonic-gate 
54210Sstevel@tonic-gate 	/*
54220Sstevel@tonic-gate 	 * Make sure that none of the unsupported or reserved flags are set.
54230Sstevel@tonic-gate 	 */
54240Sstevel@tonic-gate 	if ((ior->Attributes1 | ior->Attributes2) &    (IO_SHARED |
54250Sstevel@tonic-gate 							IO_FIRST_SHARED |
54260Sstevel@tonic-gate 							IO_FORCE_ALIAS_ACCESS |
54270Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
54280Sstevel@tonic-gate 							IO_DISABLE_WINDOW))
54290Sstevel@tonic-gate 	    return (CS_BAD_ATTRIBUTE);
54300Sstevel@tonic-gate 
54310Sstevel@tonic-gate 	/*
54320Sstevel@tonic-gate 	 * Make sure that we have a port count for the first region.
54330Sstevel@tonic-gate 	 */
54340Sstevel@tonic-gate 	if (!ior->NumPorts1)
54350Sstevel@tonic-gate 	    return (CS_BAD_BASE);
54360Sstevel@tonic-gate 
54370Sstevel@tonic-gate 	/*
54380Sstevel@tonic-gate 	 * If we're being asked for multiple IO ranges, then both base port
54390Sstevel@tonic-gate 	 *	members must be non-zero.
54400Sstevel@tonic-gate 	 */
54410Sstevel@tonic-gate 	if ((ior->NumPorts2) && !(ior->BasePort1.base && ior->BasePort2.base))
54420Sstevel@tonic-gate 	    return (CS_BAD_BASE);
54430Sstevel@tonic-gate 
54440Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
54450Sstevel@tonic-gate 
54460Sstevel@tonic-gate 	/*
54470Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
54480Sstevel@tonic-gate 	 */
54490Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
54500Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
54510Sstevel@tonic-gate 
54520Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
54530Sstevel@tonic-gate 
54540Sstevel@tonic-gate 	/*
54550Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
54560Sstevel@tonic-gate 	 */
54570Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
54580Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
54590Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
54600Sstevel@tonic-gate 	    return (error);
54610Sstevel@tonic-gate 	}
54620Sstevel@tonic-gate 
54630Sstevel@tonic-gate 	/*
54640Sstevel@tonic-gate 	 * If RequestConfiguration has already been done, we don't allow
54650Sstevel@tonic-gate 	 *	this call.
54660Sstevel@tonic-gate 	 */
54670Sstevel@tonic-gate 	if (client->flags & REQ_CONFIGURATION_DONE) {
54680Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
54690Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
54700Sstevel@tonic-gate 	    return (CS_CONFIGURATION_LOCKED);
54710Sstevel@tonic-gate 	}
54720Sstevel@tonic-gate 
54730Sstevel@tonic-gate 	/*
54740Sstevel@tonic-gate 	 * If RequestIO has already been done, we don't allow this call.
54750Sstevel@tonic-gate 	 */
54760Sstevel@tonic-gate 	if (client->flags & REQ_IO_DONE) {
54770Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
54780Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
54790Sstevel@tonic-gate 	    return (CS_IN_USE);
54800Sstevel@tonic-gate 	}
54810Sstevel@tonic-gate 
54820Sstevel@tonic-gate 	mutex_enter(&sp->lock);
54830Sstevel@tonic-gate 
54840Sstevel@tonic-gate 	/*
54850Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
54860Sstevel@tonic-gate 	 *	for this client, then return an error.
54870Sstevel@tonic-gate 	 */
54880Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
54890Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
54900Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
54910Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
54920Sstevel@tonic-gate 	    return (CS_NO_CARD);
54930Sstevel@tonic-gate 	}
54940Sstevel@tonic-gate 
54950Sstevel@tonic-gate 	mutex_exit(&sp->lock);
54960Sstevel@tonic-gate 
54970Sstevel@tonic-gate 	/*
54980Sstevel@tonic-gate 	 * If we're only being asked for one IO range, then set BasePort2 to
54990Sstevel@tonic-gate 	 *	zero, since we use it later on.
55000Sstevel@tonic-gate 	 */
55010Sstevel@tonic-gate 	if (!ior->NumPorts2)
55020Sstevel@tonic-gate 	    ior->BasePort2.base = 0;
55030Sstevel@tonic-gate 
55040Sstevel@tonic-gate 	/*
55050Sstevel@tonic-gate 	 * See if we can allow Card Services to select the base address
55060Sstevel@tonic-gate 	 *	value for this card; if the client has specified a non-zero
55070Sstevel@tonic-gate 	 *	base IO address but the card doesn't decode enough IO
55080Sstevel@tonic-gate 	 *	address lines to uniquely use that address, then we have
55090Sstevel@tonic-gate 	 *	the flexibility to choose an alternative base address.
55100Sstevel@tonic-gate 	 * Note that if the client specifies that the card decodes zero
55110Sstevel@tonic-gate 	 *	IO address lines, then we have to use the NumPortsX
55120Sstevel@tonic-gate 	 *	values to figure out how many address lines the card
55130Sstevel@tonic-gate 	 *	actually decodes, and we have to round the NumPortsX
55140Sstevel@tonic-gate 	 *	values up to the closest power of two.
55150Sstevel@tonic-gate 	 */
55160Sstevel@tonic-gate 	if (ior->IOAddrLines) {
55170Sstevel@tonic-gate 	    ior->BasePort1.base = IOADDR_FROBNITZ(ior->BasePort1.base,
55180Sstevel@tonic-gate 		ior->IOAddrLines);
55190Sstevel@tonic-gate 	    ior->BasePort2.base = IOADDR_FROBNITZ(ior->BasePort2.base,
55200Sstevel@tonic-gate 		ior->IOAddrLines);
55210Sstevel@tonic-gate 	} else {
55220Sstevel@tonic-gate 	    ior->BasePort1.base = ior->BasePort1.base &
55230Sstevel@tonic-gate 				((IONUMPORTS_FROBNITZ(ior->NumPorts1) +
55240Sstevel@tonic-gate 				IONUMPORTS_FROBNITZ(ior->NumPorts2)) - 1);
55250Sstevel@tonic-gate 	    ior->BasePort2.base = ior->BasePort2.base &
55260Sstevel@tonic-gate 				((IONUMPORTS_FROBNITZ(ior->NumPorts1) +
55270Sstevel@tonic-gate 				IONUMPORTS_FROBNITZ(ior->NumPorts2)) - 1);
55280Sstevel@tonic-gate 	}
55290Sstevel@tonic-gate 
55300Sstevel@tonic-gate 	socket_num = CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
55310Sstevel@tonic-gate 	    GET_CLIENT_FUNCTION(client_handle));
55320Sstevel@tonic-gate 
55330Sstevel@tonic-gate 
55340Sstevel@tonic-gate #ifdef	USE_IOMMAP_WINDOW
55350Sstevel@tonic-gate 	/*
55360Sstevel@tonic-gate 	 * Here is where the code diverges, depending on the type of IO windows
55370Sstevel@tonic-gate 	 *	that this socket supports.  If this socket supportes memory
55380Sstevel@tonic-gate 	 *	mapped IO windows, as determined by cs_init allocating an
55390Sstevel@tonic-gate 	 *	io_mmap_window_t structure on the socket structure, then we
55400Sstevel@tonic-gate 	 *	use one IO window for all the clients on this socket.  We can
55410Sstevel@tonic-gate 	 *	do this safely since a memory mapped IO window implies that
55420Sstevel@tonic-gate 	 *	only this socket shares the complete IO space of the card.
55430Sstevel@tonic-gate 	 * See the next major block of code for a description of what we do
55440Sstevel@tonic-gate 	 *	if a socket doesn't support memory mapped IO windows.
55450Sstevel@tonic-gate 	 */
55460Sstevel@tonic-gate 	if (sp->io_mmap_window) {
55470Sstevel@tonic-gate 	    cs_window_t *cw;
55480Sstevel@tonic-gate 	    io_mmap_window_t *imw = sp->io_mmap_window;
55490Sstevel@tonic-gate 	    uint32_t offset;
55500Sstevel@tonic-gate 
55510Sstevel@tonic-gate 		/*
55520Sstevel@tonic-gate 		 * If we haven't allocated an IO window yet, do it now.
55530Sstevel@tonic-gate 		 * Try to allocate the IO window that cs_init found for us;
55540Sstevel@tonic-gate 		 * if that fails, then call cs_find_io_win to find a window.
55550Sstevel@tonic-gate 		 */
55560Sstevel@tonic-gate 	    if (!imw->count) {
55570Sstevel@tonic-gate 		set_window_t set_window;
55580Sstevel@tonic-gate 
55590Sstevel@tonic-gate 		if (!WINDOW_AVAILABLE_FOR_IO(imw->number)) {
55600Sstevel@tonic-gate 		    iowin_char_t iowin_char;
55610Sstevel@tonic-gate 
55620Sstevel@tonic-gate 		    iowin_char.IOWndCaps = (WC_IO_RANGE_PER_WINDOW |
55630Sstevel@tonic-gate 					    WC_8BIT |
55640Sstevel@tonic-gate 					    WC_16BIT);
55650Sstevel@tonic-gate 		    if ((error = cs_find_io_win(sp->socket_num, &iowin_char,
55660Sstevel@tonic-gate 				    &imw->number, &imw->size)) != CS_SUCCESS) {
55670Sstevel@tonic-gate 			EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
55680Sstevel@tonic-gate 			mutex_exit(&cs_globals.window_lock);
55690Sstevel@tonic-gate 		    } /* cs_find_io_win */
55700Sstevel@tonic-gate 		} /* if (!WINDOW_AVAILABLE_FOR_IO) */
55710Sstevel@tonic-gate 
55720Sstevel@tonic-gate 		set_window.socket = socket_num;
55730Sstevel@tonic-gate 		set_window.window = imw->number;
55740Sstevel@tonic-gate 		set_window.speed = IO_WIN_SPEED;
55750Sstevel@tonic-gate 		set_window.base.base = 0;
55760Sstevel@tonic-gate 		set_window.WindowSize = imw->size;
55770Sstevel@tonic-gate 		set_window.state = (WS_ENABLED | WS_16BIT |
55780Sstevel@tonic-gate 				    WS_EXACT_MAPIN | WS_IO);
55790Sstevel@tonic-gate 
55800Sstevel@tonic-gate 		/* XXX - what to d here? XXX */
55810Sstevel@tonic-gate 		cs_set_acc_attributes(&set_window, Attributes);
55820Sstevel@tonic-gate 
55830Sstevel@tonic-gate 		if (SocketServices(SS_SetWindow, &set_window) != SUCCESS) {
55840Sstevel@tonic-gate 		    (void) cs_setup_io_win(socket_num, imw->number,
55850Sstevel@tonic-gate 						NULL, NULL, NULL,
55860Sstevel@tonic-gate 						(IO_DEALLOCATE_WINDOW |
55870Sstevel@tonic-gate 						IO_DISABLE_WINDOW));
55880Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
55890Sstevel@tonic-gate 		    mutex_exit(&cs_globals.window_lock);
55900Sstevel@tonic-gate 		    return (CS_BAD_WINDOW);
55910Sstevel@tonic-gate 		}
55920Sstevel@tonic-gate 
55930Sstevel@tonic-gate 		imw->handle = set_window.base.handle;
55940Sstevel@tonic-gate 		imw->size = set_window.WindowSize;
55950Sstevel@tonic-gate 
55960Sstevel@tonic-gate 		/*
55970Sstevel@tonic-gate 		 * Check the caller's port requirements to be sure that they
55980Sstevel@tonic-gate 		 *	fit within our found IO window.
55990Sstevel@tonic-gate 		 */
56000Sstevel@tonic-gate 		if ((ior->BasePort1.base + ior->NumPorts1 +
56010Sstevel@tonic-gate 			ior->BasePort2.base + ior->NumPorts2) > imw->size) {
56020Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
56030Sstevel@tonic-gate 		    mutex_exit(&cs_globals.window_lock);
56040Sstevel@tonic-gate 		    return (CS_BAD_BASE);
56050Sstevel@tonic-gate 		}
56060Sstevel@tonic-gate 
56070Sstevel@tonic-gate 		if ((cw = cs_get_wp(imw->number)) == NULL) {
56080Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
56090Sstevel@tonic-gate 		    mutex_exit(&cs_globals.window_lock);
56100Sstevel@tonic-gate 		    return (CS_BAD_WINDOW)
56110Sstevel@tonic-gate 		}
56120Sstevel@tonic-gate 		cw->state |= (CW_ALLOCATED | CW_IO);
56130Sstevel@tonic-gate 
56140Sstevel@tonic-gate 	    } /* if (!imw->count) */
56150Sstevel@tonic-gate 
56160Sstevel@tonic-gate 	    imw->count++;
56170Sstevel@tonic-gate 
56180Sstevel@tonic-gate 		/*
56190Sstevel@tonic-gate 		 * All common access handles for this type of adapter are
56200Sstevel@tonic-gate 		 * duped.  We never give the original back to the caller.
56210Sstevel@tonic-gate 		 */
56220Sstevel@tonic-gate 	    /* XXX need to set endianess and data ordering flags */
56230Sstevel@tonic-gate 	    csx_DupHandle(imw->handle, &ior->BasePort1.handle, 0);
56240Sstevel@tonic-gate 	    csx_GetHandleOffset(ior->BasePort1.handle, &offset);
56250Sstevel@tonic-gate 	    csx_SetHandleOffset(ior->BasePort1.handle,
56260Sstevel@tonic-gate 		ior->BasePort1.base + offset);
56270Sstevel@tonic-gate 
56280Sstevel@tonic-gate 	    if (ior->NumPorts2) {
56290Sstevel@tonic-gate 		/* XXX need to set endianess and data ordering flags */
56300Sstevel@tonic-gate 		csx_DupHandle(imw->handle, &ior->BasePort2.handle, 0);
56310Sstevel@tonic-gate 		csx_GetHandleOffset(ior->BasePort2.handle, &offset);
56320Sstevel@tonic-gate 		csx_SetHandleOffset(ior->BasePort2.handle,
56330Sstevel@tonic-gate 		    ior->BasePort1.base + offset);
56340Sstevel@tonic-gate 	    }
56350Sstevel@tonic-gate 
56360Sstevel@tonic-gate 		/*
56370Sstevel@tonic-gate 		 * We don't really use these two values if we've got a memory
56380Sstevel@tonic-gate 		 * mapped IO window since the assigned window number is stored
56390Sstevel@tonic-gate 		 * in imw->number.
56400Sstevel@tonic-gate 		 */
56410Sstevel@tonic-gate 	    client->io_alloc.Window1 = imw->number;
56420Sstevel@tonic-gate 	    client->io_alloc.Window2 = PCMCIA_MAX_WINDOWS;
56430Sstevel@tonic-gate 
56440Sstevel@tonic-gate 	/*
56450Sstevel@tonic-gate 	 * This socket supports only IO port IO windows.
56460Sstevel@tonic-gate 	 */
56470Sstevel@tonic-gate 	} else {
56480Sstevel@tonic-gate #else	/* USE_IOMMAP_WINDOW */
56490Sstevel@tonic-gate 	{
56500Sstevel@tonic-gate #endif	/* USE_IOMMAP_WINDOW */
56510Sstevel@tonic-gate 	    baseaddru_t baseaddru;
56520Sstevel@tonic-gate 
56530Sstevel@tonic-gate 	    baseaddru.base = ior->BasePort1.base;
56540Sstevel@tonic-gate 
56550Sstevel@tonic-gate 	    if ((error = cs_allocate_io_win(sp->socket_num, ior->Attributes1,
56560Sstevel@tonic-gate 		&client->io_alloc.Window1)) != CS_SUCCESS) {
56570Sstevel@tonic-gate 
56580Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
56590Sstevel@tonic-gate 		mutex_exit(&cs_globals.window_lock);
56600Sstevel@tonic-gate 		return (error);
56610Sstevel@tonic-gate 	    } /* if (cs_allocate_io_win(1)) */
56620Sstevel@tonic-gate 
56630Sstevel@tonic-gate 		/*
56640Sstevel@tonic-gate 		 * Setup the window hardware; if this fails, then we need to
56650Sstevel@tonic-gate 		 *	deallocate the previously allocated window.
56660Sstevel@tonic-gate 		 */
56670Sstevel@tonic-gate 	    if ((error = cs_setup_io_win(socket_num,
56680Sstevel@tonic-gate 						client->io_alloc.Window1,
56690Sstevel@tonic-gate 						&baseaddru,
56700Sstevel@tonic-gate 						&ior->NumPorts1,
56710Sstevel@tonic-gate 						ior->IOAddrLines,
56720Sstevel@tonic-gate 						ior->Attributes1)) !=
56730Sstevel@tonic-gate 								CS_SUCCESS) {
56740Sstevel@tonic-gate 		(void) cs_setup_io_win(socket_num, client->io_alloc.Window1,
56750Sstevel@tonic-gate 					NULL, NULL, NULL,
56760Sstevel@tonic-gate 					(
56770Sstevel@tonic-gate 						IO_DEALLOCATE_WINDOW |
56780Sstevel@tonic-gate 						IO_DISABLE_WINDOW));
56790Sstevel@tonic-gate 
56800Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
56810Sstevel@tonic-gate 		mutex_exit(&cs_globals.window_lock);
56820Sstevel@tonic-gate 		return (error);
56830Sstevel@tonic-gate 	    } /* if (cs_setup_io_win(1)) */
56840Sstevel@tonic-gate 
56850Sstevel@tonic-gate 	    ior->BasePort1.handle = (acc_handle_t)baseaddru.handle;
56860Sstevel@tonic-gate 	    ior->BasePort1.base = baseaddru.base;
56870Sstevel@tonic-gate 
56880Sstevel@tonic-gate 		/*
56890Sstevel@tonic-gate 		 * See if the client wants two IO ranges.
56900Sstevel@tonic-gate 		 */
56910Sstevel@tonic-gate 	    if (ior->NumPorts2) {
56920Sstevel@tonic-gate 		baseaddru_t baseaddru;
56930Sstevel@tonic-gate 
56940Sstevel@tonic-gate 		baseaddru.base = ior->BasePort2.base;
56950Sstevel@tonic-gate 
56960Sstevel@tonic-gate 		/*
56970Sstevel@tonic-gate 		 * If we fail to allocate this window, then we must deallocate
56980Sstevel@tonic-gate 		 *	the previous IO window that is already allocated.
56990Sstevel@tonic-gate 		 */
57000Sstevel@tonic-gate 		if ((error = cs_allocate_io_win(sp->socket_num,
57010Sstevel@tonic-gate 						ior->Attributes2,
57020Sstevel@tonic-gate 						&client->io_alloc.Window2)) !=
57030Sstevel@tonic-gate 								CS_SUCCESS) {
57040Sstevel@tonic-gate 		    (void) cs_setup_io_win(socket_num,
57050Sstevel@tonic-gate 						client->io_alloc.Window2,
57060Sstevel@tonic-gate 						NULL, NULL, NULL,
57070Sstevel@tonic-gate 						(
57080Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
57090Sstevel@tonic-gate 							IO_DISABLE_WINDOW));
57100Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
57110Sstevel@tonic-gate 		    mutex_exit(&cs_globals.window_lock);
57120Sstevel@tonic-gate 		    return (error);
57130Sstevel@tonic-gate 		} /* if (cs_allocate_io_win(2)) */
57140Sstevel@tonic-gate 		/*
57150Sstevel@tonic-gate 		 * Setup the window hardware; if this fails, then we need to
57160Sstevel@tonic-gate 		 *	deallocate the previously allocated window.
57170Sstevel@tonic-gate 		 */
57180Sstevel@tonic-gate 		if ((error = cs_setup_io_win(socket_num,
57190Sstevel@tonic-gate 						client->io_alloc.Window2,
57200Sstevel@tonic-gate 						&baseaddru,
57210Sstevel@tonic-gate 						&ior->NumPorts2,
57220Sstevel@tonic-gate 						ior->IOAddrLines,
57230Sstevel@tonic-gate 						ior->Attributes2)) !=
57240Sstevel@tonic-gate 								CS_SUCCESS) {
57250Sstevel@tonic-gate 		    (void) cs_setup_io_win(socket_num,
57260Sstevel@tonic-gate 						client->io_alloc.Window1,
57270Sstevel@tonic-gate 						NULL, NULL, NULL,
57280Sstevel@tonic-gate 						(
57290Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
57300Sstevel@tonic-gate 							IO_DISABLE_WINDOW));
57310Sstevel@tonic-gate 		    (void) cs_setup_io_win(socket_num,
57320Sstevel@tonic-gate 						client->io_alloc.Window2,
57330Sstevel@tonic-gate 						NULL, NULL, NULL,
57340Sstevel@tonic-gate 						(
57350Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
57360Sstevel@tonic-gate 							IO_DISABLE_WINDOW));
57370Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
57380Sstevel@tonic-gate 		    mutex_exit(&cs_globals.window_lock);
57390Sstevel@tonic-gate 		    return (error);
57400Sstevel@tonic-gate 		} /* if (cs_setup_io_win(2)) */
57410Sstevel@tonic-gate 
57420Sstevel@tonic-gate 		ior->BasePort2.handle = (acc_handle_t)baseaddru.handle;
57430Sstevel@tonic-gate 		ior->BasePort2.base = baseaddru.base;
57440Sstevel@tonic-gate 
57450Sstevel@tonic-gate 	    } else {
57460Sstevel@tonic-gate 		client->io_alloc.Window2 = PCMCIA_MAX_WINDOWS;
57470Sstevel@tonic-gate 	    } /* if (ior->NumPorts2) */
57480Sstevel@tonic-gate 	} /* if (sp->io_mmap_window) */
57490Sstevel@tonic-gate 
57500Sstevel@tonic-gate 	/*
57510Sstevel@tonic-gate 	 * Save a copy of the client's port information so that we
57520Sstevel@tonic-gate 	 *	can use it in the RequestConfiguration call.  We set
57530Sstevel@tonic-gate 	 *	the IO window number(s) allocated in the respective
57540Sstevel@tonic-gate 	 *	section of code, above.
57550Sstevel@tonic-gate 	 */
57560Sstevel@tonic-gate 	client->io_alloc.BasePort1.base = ior->BasePort1.base;
57570Sstevel@tonic-gate 	client->io_alloc.BasePort1.handle = ior->BasePort1.handle;
57580Sstevel@tonic-gate 	client->io_alloc.NumPorts1 = ior->NumPorts1;
57590Sstevel@tonic-gate 	client->io_alloc.Attributes1 = ior->Attributes1;
57600Sstevel@tonic-gate 	client->io_alloc.BasePort2.base = ior->BasePort2.base;
57610Sstevel@tonic-gate 	client->io_alloc.BasePort2.handle = ior->BasePort2.handle;
57620Sstevel@tonic-gate 	client->io_alloc.NumPorts2 = ior->NumPorts2;
57630Sstevel@tonic-gate 	client->io_alloc.Attributes2 = ior->Attributes2;
57640Sstevel@tonic-gate 	client->io_alloc.IOAddrLines = ior->IOAddrLines;
57650Sstevel@tonic-gate 
57660Sstevel@tonic-gate 	/*
57670Sstevel@tonic-gate 	 * Mark this client as having done a successful RequestIO call.
57680Sstevel@tonic-gate 	 */
57690Sstevel@tonic-gate 	client->flags |= (REQ_IO_DONE | CLIENT_IO_ALLOCATED);
57700Sstevel@tonic-gate 
57710Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
57720Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
57730Sstevel@tonic-gate 
57740Sstevel@tonic-gate 	return (CS_SUCCESS);
57750Sstevel@tonic-gate }
57760Sstevel@tonic-gate 
57770Sstevel@tonic-gate /*
57780Sstevel@tonic-gate  * cs_release_io - releases IO resources allocated by RequestIO; this is
57790Sstevel@tonic-gate  *			ReleaseIO
57800Sstevel@tonic-gate  *
57810Sstevel@tonic-gate  *	calling: cs_release_io(client_handle_t, io_req_t *)
57820Sstevel@tonic-gate  *
57830Sstevel@tonic-gate  *	returns: CS_SUCCESS - if IO resources sucessfully deallocated
57840Sstevel@tonic-gate  *		 CS_BAD_HANDLE - client handle is invalid
57850Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
57860Sstevel@tonic-gate  *		 CS_CONFIGURATION_LOCKED - a RequestConfiguration has been
57870Sstevel@tonic-gate  *				done without a ReleaseConfiguration
57880Sstevel@tonic-gate  *		 CS_IN_USE - no RequestIO has been done
57890Sstevel@tonic-gate  */
57900Sstevel@tonic-gate static int
57910Sstevel@tonic-gate cs_release_io(client_handle_t client_handle, io_req_t *ior)
57920Sstevel@tonic-gate {
57930Sstevel@tonic-gate 	cs_socket_t *sp;
57940Sstevel@tonic-gate 	client_t *client;
57950Sstevel@tonic-gate 	int error;
57960Sstevel@tonic-gate 	int client_lock_acquired;
57970Sstevel@tonic-gate 	uint32_t socket_num;
57980Sstevel@tonic-gate 
57990Sstevel@tonic-gate #ifdef	lint
58000Sstevel@tonic-gate 	ior = NULL;
58010Sstevel@tonic-gate #endif
58020Sstevel@tonic-gate 
58030Sstevel@tonic-gate 	/*
58040Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
58050Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
58060Sstevel@tonic-gate 	 */
58070Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
58080Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
58090Sstevel@tonic-gate 
58100Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
58110Sstevel@tonic-gate 
58120Sstevel@tonic-gate 	/*
58130Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
58140Sstevel@tonic-gate 	 */
58150Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
58160Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
58170Sstevel@tonic-gate 
58180Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
58190Sstevel@tonic-gate 
58200Sstevel@tonic-gate 	/*
58210Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
58220Sstevel@tonic-gate 	 */
58230Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
58240Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
58250Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
58260Sstevel@tonic-gate 	    return (error);
58270Sstevel@tonic-gate 	}
58280Sstevel@tonic-gate 
58290Sstevel@tonic-gate 	/*
58300Sstevel@tonic-gate 	 * If RequestConfiguration has already been done, we don't allow
58310Sstevel@tonic-gate 	 *	this call.
58320Sstevel@tonic-gate 	 */
58330Sstevel@tonic-gate 	if (client->flags & REQ_CONFIGURATION_DONE) {
58340Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
58350Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
58360Sstevel@tonic-gate 	    return (CS_CONFIGURATION_LOCKED);
58370Sstevel@tonic-gate 	}
58380Sstevel@tonic-gate 
58390Sstevel@tonic-gate 	/*
58400Sstevel@tonic-gate 	 * If RequestIO has not been done, we don't allow this call.
58410Sstevel@tonic-gate 	 */
58420Sstevel@tonic-gate 	if (!(client->flags & REQ_IO_DONE)) {
58430Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
58440Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
58450Sstevel@tonic-gate 	    return (CS_IN_USE);
58460Sstevel@tonic-gate 	}
58470Sstevel@tonic-gate 
58480Sstevel@tonic-gate 	socket_num = CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
58490Sstevel@tonic-gate 	    GET_CLIENT_FUNCTION(client_handle));
58500Sstevel@tonic-gate 
58510Sstevel@tonic-gate #ifdef	XXX
58520Sstevel@tonic-gate 	/*
58530Sstevel@tonic-gate 	 * Check the passed IO allocation with the stored allocation; if
58540Sstevel@tonic-gate 	 *	they don't match, then return an error.
58550Sstevel@tonic-gate 	 */
58560Sstevel@tonic-gate 	if ((client->io_alloc.BasePort1 != ior->BasePort1) ||
58570Sstevel@tonic-gate 	    (client->io_alloc.NumPorts1 != ior->NumPorts1) ||
58580Sstevel@tonic-gate 	    (client->io_alloc.Attributes1 != ior->Attributes1) ||
58590Sstevel@tonic-gate 	    (client->io_alloc.BasePort2 != ior->BasePort2) ||
58600Sstevel@tonic-gate 	    (client->io_alloc.NumPorts2 != ior->NumPorts2) ||
58610Sstevel@tonic-gate 	    (client->io_alloc.Attributes2 != ior->Attributes2) ||
58620Sstevel@tonic-gate 	    (client->io_alloc.IOAddrLines != ior->IOAddrLines)) {
58630Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
58640Sstevel@tonic-gate 		mutex_exit(&cs_globals.window_lock);
58650Sstevel@tonic-gate 		return (CS_BAD_ARGS);
58660Sstevel@tonic-gate 	}
58670Sstevel@tonic-gate #endif
58680Sstevel@tonic-gate 
58690Sstevel@tonic-gate #ifdef	USE_IOMMAP_WINDOW
58700Sstevel@tonic-gate 	/*
58710Sstevel@tonic-gate 	 * The code diverges here depending on if this socket supports
58720Sstevel@tonic-gate 	 *	memory mapped IO windows or not.  See comments in the
58730Sstevel@tonic-gate 	 *	cs_request_io function for a description of what's
58740Sstevel@tonic-gate 	 *	going on here.
58750Sstevel@tonic-gate 	 */
58760Sstevel@tonic-gate 	if (sp->io_mmap_window) {
58770Sstevel@tonic-gate 	    io_mmap_window_t *imw = sp->io_mmap_window;
58780Sstevel@tonic-gate 
58790Sstevel@tonic-gate 		/*
58800Sstevel@tonic-gate 		 * We should never see this; if we do, it's an internal
58810Sstevel@tonic-gate 		 *	consistency error.
58820Sstevel@tonic-gate 		 */
58830Sstevel@tonic-gate 	    if (!imw->count) {
58840Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_release_io: socket %d !imw->count\n",
58850Sstevel@tonic-gate 							    sp->socket_num);
58860Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
58870Sstevel@tonic-gate 		mutex_exit(&cs_globals.window_lock);
58880Sstevel@tonic-gate 		return (CS_GENERAL_FAILURE);
58890Sstevel@tonic-gate 	    }
58900Sstevel@tonic-gate 
58910Sstevel@tonic-gate 		/*
58920Sstevel@tonic-gate 		 * All common access handles for this type of adapter are
58930Sstevel@tonic-gate 		 *	duped. We never give the original back to the caller,
58940Sstevel@tonic-gate 		 *	so it's OK to unconditionally free the handle here.
58950Sstevel@tonic-gate 		 */
58960Sstevel@tonic-gate 	    csx_FreeHandle(&ior->BasePort1.handle);
58970Sstevel@tonic-gate 
58980Sstevel@tonic-gate 		/*
58990Sstevel@tonic-gate 		 * If the IO window referance count is zero, then deallocate
59000Sstevel@tonic-gate 		 * and disable this window.
59010Sstevel@tonic-gate 		 */
59020Sstevel@tonic-gate 	    if (!--(imw->count)) {
59030Sstevel@tonic-gate 		(void) cs_setup_io_win(socket_num, imw->number, NULL,
59040Sstevel@tonic-gate 								NULL, NULL,
59050Sstevel@tonic-gate 						(
59060Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
59070Sstevel@tonic-gate 							IO_DISABLE_WINDOW));
59080Sstevel@tonic-gate 	    } /* if (imw->count) */
59090Sstevel@tonic-gate 	} else {
59100Sstevel@tonic-gate #endif	/* USE_IOMMAP_WINDOW */
59110Sstevel@tonic-gate 	    (void) cs_setup_io_win(socket_num, client->io_alloc.Window1,
59120Sstevel@tonic-gate 						NULL, NULL, NULL,
59130Sstevel@tonic-gate 						(
59140Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
59150Sstevel@tonic-gate 							IO_DISABLE_WINDOW));
59160Sstevel@tonic-gate 	    if (client->io_alloc.Window2 != PCMCIA_MAX_WINDOWS)
59170Sstevel@tonic-gate 		(void) cs_setup_io_win(socket_num, client->io_alloc.Window2,
59180Sstevel@tonic-gate 						NULL, NULL, NULL,
59190Sstevel@tonic-gate 						(
59200Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
59210Sstevel@tonic-gate 							IO_DISABLE_WINDOW));
59220Sstevel@tonic-gate #ifdef	USE_IOMMAP_WINDOW
59230Sstevel@tonic-gate 	} /* if (sp->io_mmap_window) */
59240Sstevel@tonic-gate #endif	/* USE_IOMMAP_WINDOW */
59250Sstevel@tonic-gate 
59260Sstevel@tonic-gate 	/*
59270Sstevel@tonic-gate 	 * Mark the client as not having any IO resources allocated.
59280Sstevel@tonic-gate 	 */
59290Sstevel@tonic-gate 	client->flags &= ~(REQ_IO_DONE | CLIENT_IO_ALLOCATED);
59300Sstevel@tonic-gate 
59310Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
59320Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
59330Sstevel@tonic-gate 	return (CS_SUCCESS);
59340Sstevel@tonic-gate }
59350Sstevel@tonic-gate 
59360Sstevel@tonic-gate /*
59370Sstevel@tonic-gate  * cs_find_io_win - finds an IO window that matches the parameters specified
59380Sstevel@tonic-gate  *			in the flags argument
59390Sstevel@tonic-gate  *
59400Sstevel@tonic-gate  *	calling: sn - socket number to look for IO window on
59410Sstevel@tonic-gate  *		 *iwc - other window characteristics to match
59420Sstevel@tonic-gate  *		 *assigned_window - pointer to where we return the assigned
59430Sstevel@tonic-gate  *					window number if we found a window or
59440Sstevel@tonic-gate  *					undefined otherwise
59450Sstevel@tonic-gate  *		 *size - if non-NULL, the found window size will be stored here
59460Sstevel@tonic-gate  *
59470Sstevel@tonic-gate  *	returns: CS_SUCCESS - if IO window found
59480Sstevel@tonic-gate  *		 CS_OUT_OF_RESOURCE - if no windows match requirements
59490Sstevel@tonic-gate  */
59500Sstevel@tonic-gate static int
59510Sstevel@tonic-gate cs_find_io_win(uint32_t sn, iowin_char_t *iwc, uint32_t *assigned_window,
59520Sstevel@tonic-gate     uint32_t *size)
59530Sstevel@tonic-gate {
59540Sstevel@tonic-gate 	inquire_window_t inquire_window, *iw;
59550Sstevel@tonic-gate 	unsigned wn;
59560Sstevel@tonic-gate 
59570Sstevel@tonic-gate 	iw = &inquire_window;
59580Sstevel@tonic-gate 
59590Sstevel@tonic-gate 	for (wn = 0; wn < cs_globals.num_windows; wn++) {
59600Sstevel@tonic-gate 	    iowin_char_t *iowc;
59610Sstevel@tonic-gate 	    cs_window_t *cw;
59620Sstevel@tonic-gate 
59630Sstevel@tonic-gate 	    if ((cw = cs_get_wp(wn)) != NULL) {
59640Sstevel@tonic-gate 
59650Sstevel@tonic-gate 		iw->window = wn;
59660Sstevel@tonic-gate 		SocketServices(SS_InquireWindow, iw);
59670Sstevel@tonic-gate 
59680Sstevel@tonic-gate 		iowc = &iw->iowin_char;
59690Sstevel@tonic-gate 
59700Sstevel@tonic-gate 		if (WINDOW_FOR_SOCKET(iw->Sockets, sn) &&
59710Sstevel@tonic-gate 		    WINDOW_AVAILABLE_FOR_IO(cw) &&
59720Sstevel@tonic-gate 		    (iw->WndCaps & WC_IO) &&
59730Sstevel@tonic-gate 		    ((iowc->IOWndCaps & iwc->IOWndCaps) == iwc->IOWndCaps)) {
59740Sstevel@tonic-gate 
59750Sstevel@tonic-gate 			*assigned_window = wn;
59760Sstevel@tonic-gate 
59770Sstevel@tonic-gate 			if (size)
59780Sstevel@tonic-gate 			    *size = iw->iowin_char.ReqGran;
59790Sstevel@tonic-gate 			return (CS_SUCCESS);
59800Sstevel@tonic-gate 		    } /* if (WINDOW_FOR_SOCKET) */
59810Sstevel@tonic-gate 	    } /* cs_get_wp */
59820Sstevel@tonic-gate 	} /* for (wn) */
59830Sstevel@tonic-gate 
59840Sstevel@tonic-gate 	return (CS_OUT_OF_RESOURCE);
59850Sstevel@tonic-gate }
59860Sstevel@tonic-gate 
59870Sstevel@tonic-gate /*
59880Sstevel@tonic-gate  * cs_allocate_io_win - finds and allocates an IO window
59890Sstevel@tonic-gate  *
59900Sstevel@tonic-gate  *	calling: sn - socket number to look for window on
59910Sstevel@tonic-gate  *		 Attributes - window attributes in io_req_t.Attributes format
59920Sstevel@tonic-gate  *		 *assigned_window - pointer to return assigned window number
59930Sstevel@tonic-gate  *
59940Sstevel@tonic-gate  *	returns: CS_SUCCESS - IO window found and allocated
59950Sstevel@tonic-gate  *		 CS_OUT_OF_RESOURCE - if cs_find_io_win couldn't find a
59960Sstevel@tonic-gate  *				window that matches the passed criteria
59970Sstevel@tonic-gate  *
59980Sstevel@tonic-gate  * Note: This fucntion will find and allocate an IO window.  The caller is
59990Sstevel@tonic-gate  *	responsible for deallocating the window.
60000Sstevel@tonic-gate  */
60010Sstevel@tonic-gate static int
60020Sstevel@tonic-gate cs_allocate_io_win(uint32_t sn, uint32_t Attributes, uint32_t *assigned_window)
60030Sstevel@tonic-gate {
60040Sstevel@tonic-gate 	iowin_char_t iowin_char;
60050Sstevel@tonic-gate 	cs_window_t *cw;
60060Sstevel@tonic-gate 
60070Sstevel@tonic-gate 	iowin_char.IOWndCaps =
60080Sstevel@tonic-gate 		((Attributes & IO_DATA_PATH_WIDTH_16)?WC_16BIT:WC_8BIT);
60090Sstevel@tonic-gate 
60100Sstevel@tonic-gate 	if (cs_find_io_win(sn, &iowin_char, assigned_window, NULL) ==
60110Sstevel@tonic-gate 								CS_SUCCESS) {
60120Sstevel@tonic-gate 	    if ((cw = cs_get_wp(*assigned_window)) == NULL)
60130Sstevel@tonic-gate 		return (CS_OUT_OF_RESOURCE);
60140Sstevel@tonic-gate 
60150Sstevel@tonic-gate 	    cw->state = (cw->state & CW_WINDOW_VALID) | (CW_ALLOCATED | CW_IO);
60160Sstevel@tonic-gate 	    return (CS_SUCCESS);
60170Sstevel@tonic-gate 	}
60180Sstevel@tonic-gate 
60190Sstevel@tonic-gate 	return (CS_OUT_OF_RESOURCE);
60200Sstevel@tonic-gate }
60210Sstevel@tonic-gate 
60220Sstevel@tonic-gate /*
60230Sstevel@tonic-gate  * cs_setup_io_win - setup and destroy an IO window
60240Sstevel@tonic-gate  *
60250Sstevel@tonic-gate  *	calling: sn - socket number
60260Sstevel@tonic-gate  *		 wn - window number
60270Sstevel@tonic-gate  * XXX Base - pointer to XXX
60280Sstevel@tonic-gate  *		 *NumPorts - pointer to number of allocated ports to return
60290Sstevel@tonic-gate  *		 IOAddrLines - number of IO address lines decoded by this card
60300Sstevel@tonic-gate  *		 Attributes - either io_req_t attributes, or a combination of
60310Sstevel@tonic-gate  *				the following flags:
60320Sstevel@tonic-gate  *				    IO_DEALLOCATE_WINDOW - deallocate the window
60330Sstevel@tonic-gate  *				    IO_DISABLE_WINDOW - disable the window
60340Sstevel@tonic-gate  *				When either of these two flags are set, *Base
60350Sstevel@tonic-gate  *				    and NumPorts should be NULL.
60360Sstevel@tonic-gate  *
60370Sstevel@tonic-gate  *	returns: CS_SUCCESS - if no failure
60380Sstevel@tonic-gate  *		 CS_BAD_WINDOW - if error while trying to configure window
60390Sstevel@tonic-gate  *
60400Sstevel@tonic-gate  * Note: We use the IOAddrLines value to determine what base address to pass
60410Sstevel@tonic-gate  *		to Socket Services.
60420Sstevel@tonic-gate  */
60430Sstevel@tonic-gate static int
60440Sstevel@tonic-gate cs_setup_io_win(uint32_t sn, uint32_t wn, baseaddru_t *Base, uint32_t *NumPorts,
60450Sstevel@tonic-gate     uint32_t IOAddrLines, uint32_t Attributes)
60460Sstevel@tonic-gate {
60470Sstevel@tonic-gate 	set_window_t set_window;
60480Sstevel@tonic-gate 
60490Sstevel@tonic-gate 	if (Attributes & (IO_DEALLOCATE_WINDOW | IO_DISABLE_WINDOW)) {
60500Sstevel@tonic-gate 
60510Sstevel@tonic-gate 	    if (Attributes & IO_DEALLOCATE_WINDOW) {
60520Sstevel@tonic-gate 		cs_window_t *cw;
60530Sstevel@tonic-gate 
60540Sstevel@tonic-gate 		if ((cw = cs_get_wp(wn)) == NULL)
60550Sstevel@tonic-gate 		    return (CS_BAD_WINDOW);
60560Sstevel@tonic-gate 		cw->state &= CW_WINDOW_VALID;
60570Sstevel@tonic-gate 
60580Sstevel@tonic-gate 	    } /* IO_DEALLOCATE_WINDOW */
60590Sstevel@tonic-gate 
60600Sstevel@tonic-gate 	    if (Attributes & IO_DISABLE_WINDOW) {
60610Sstevel@tonic-gate 		get_window_t get_window;
60620Sstevel@tonic-gate 
60630Sstevel@tonic-gate 		get_window.window = wn;
60640Sstevel@tonic-gate 
60650Sstevel@tonic-gate 		SocketServices(SS_GetWindow, &get_window);
60660Sstevel@tonic-gate 
60670Sstevel@tonic-gate 		set_window.socket = get_window.socket;
60680Sstevel@tonic-gate 		set_window.window = get_window.window;
60690Sstevel@tonic-gate 		set_window.speed = get_window.speed;
60700Sstevel@tonic-gate 		set_window.base = 0;
60710Sstevel@tonic-gate 		set_window.WindowSize = get_window.size;
60720Sstevel@tonic-gate 		set_window.state = get_window.state & ~WS_ENABLED;
60730Sstevel@tonic-gate 
60740Sstevel@tonic-gate 		cs_set_acc_attributes(&set_window, Attributes);
60750Sstevel@tonic-gate 
60760Sstevel@tonic-gate 		SocketServices(SS_SetWindow, &set_window);
60770Sstevel@tonic-gate 	    } /* IO_DISABLE_WINDOW */
60780Sstevel@tonic-gate 
60790Sstevel@tonic-gate 	    return (CS_SUCCESS);
60800Sstevel@tonic-gate 
60810Sstevel@tonic-gate 	} /* if (IO_DEALLOCATE_WINDOW | IO_DISABLE_WINDOW) */
60820Sstevel@tonic-gate 
60830Sstevel@tonic-gate 	/*
60840Sstevel@tonic-gate 	 * See if we can allow Socket Services to select the base address
60850Sstevel@tonic-gate 	 *	value for this card; if the client has specified a non-zero
60860Sstevel@tonic-gate 	 *	base IO address but the card doesn't decode enough IO
60870Sstevel@tonic-gate 	 *	address lines to uniquely use that address, then we have
60880Sstevel@tonic-gate 	 *	the flexibility to choose an alternative base address.
60890Sstevel@tonic-gate 	 * XXX - Is this really correct in all cases?
60900Sstevel@tonic-gate 	 */
60910Sstevel@tonic-gate 	if (!IOAddrLines)
60920Sstevel@tonic-gate 	    Base->base = 0;
60930Sstevel@tonic-gate 	else
60940Sstevel@tonic-gate 	    Base->base = IOADDR_FROBNITZ(Base->base, IOAddrLines);
60950Sstevel@tonic-gate 
60960Sstevel@tonic-gate 	set_window.socket = sn;
60970Sstevel@tonic-gate 	set_window.window = wn;
60980Sstevel@tonic-gate 	set_window.speed = IO_WIN_SPEED;
60990Sstevel@tonic-gate 	set_window.base = Base->base;
61000Sstevel@tonic-gate 	set_window.WindowSize = *NumPorts;
61010Sstevel@tonic-gate 	set_window.state = (WS_ENABLED | WS_IO |
61020Sstevel@tonic-gate 			((Attributes & IO_DATA_PATH_WIDTH_16)?WS_16BIT:0));
61030Sstevel@tonic-gate 
61040Sstevel@tonic-gate 	cs_set_acc_attributes(&set_window, Attributes);
61050Sstevel@tonic-gate 
61060Sstevel@tonic-gate 	if (SocketServices(SS_SetWindow, &set_window) != SUCCESS)
61070Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
61080Sstevel@tonic-gate 
61090Sstevel@tonic-gate 	Base->base = set_window.base;
61100Sstevel@tonic-gate 	Base->handle = set_window.handle;
61110Sstevel@tonic-gate 	*NumPorts = set_window.WindowSize;
61120Sstevel@tonic-gate 
61130Sstevel@tonic-gate 	return (CS_SUCCESS);
61140Sstevel@tonic-gate }
61150Sstevel@tonic-gate 
61160Sstevel@tonic-gate /*
61170Sstevel@tonic-gate  * ==== IRQ handling functions ====
61180Sstevel@tonic-gate  */
61190Sstevel@tonic-gate 
61200Sstevel@tonic-gate /*
61210Sstevel@tonic-gate  * cs_request_irq - add's client's IRQ handler; supports RequestIRQ
61220Sstevel@tonic-gate  *
61230Sstevel@tonic-gate  *	calling: irq_req_t.Attributes - must have the IRQ_TYPE_EXCLUSIVE
61240Sstevel@tonic-gate  *			flag set, and all other flags clear, or
61250Sstevel@tonic-gate  *			CS_BAD_ATTRIBUTE will be returned
61260Sstevel@tonic-gate  *
61270Sstevel@tonic-gate  *	returns: CS_SUCCESS - if IRQ resources available for client
61280Sstevel@tonic-gate  *		 CS_BAD_IRQ - if IRQ can not be allocated
61290Sstevel@tonic-gate  *		 CS_BAD_HANDLE - client handle is invalid
61300Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
61310Sstevel@tonic-gate  *		 CS_NO_CARD - if no card is in socket
61320Sstevel@tonic-gate  *		 CS_BAD_ATTRIBUTE - if any of the unsupported Attribute
61330Sstevel@tonic-gate  *					flags are set
61340Sstevel@tonic-gate  *		 CS_CONFIGURATION_LOCKED - a RequestConfiguration has
61350Sstevel@tonic-gate  *					already been done
61360Sstevel@tonic-gate  *		 CS_IN_USE - IRQ ports already in use or function has
61370Sstevel@tonic-gate  *					already been called
61380Sstevel@tonic-gate  *
61390Sstevel@tonic-gate  * Note: We only allow level-mode interrupts.
61400Sstevel@tonic-gate  */
61410Sstevel@tonic-gate static int
61420Sstevel@tonic-gate cs_request_irq(client_handle_t client_handle, irq_req_t *irqr)
61430Sstevel@tonic-gate {
61440Sstevel@tonic-gate 	cs_socket_t *sp;
61450Sstevel@tonic-gate 	client_t *client;
61460Sstevel@tonic-gate 	set_irq_handler_t set_irq_handler;
61470Sstevel@tonic-gate 	int error;
61480Sstevel@tonic-gate 	int client_lock_acquired;
61490Sstevel@tonic-gate 
61500Sstevel@tonic-gate 	/*
61510Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
61520Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
61530Sstevel@tonic-gate 	 */
61540Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
61550Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
61560Sstevel@tonic-gate 
61570Sstevel@tonic-gate 	/*
61580Sstevel@tonic-gate 	 * Make sure that none of the unsupported or reserved flags are set.
61590Sstevel@tonic-gate 	 */
61600Sstevel@tonic-gate 	if ((irqr->Attributes &	(IRQ_TYPE_TIME | IRQ_TYPE_DYNAMIC_SHARING |
61610Sstevel@tonic-gate 				IRQ_FIRST_SHARED | IRQ_PULSE_ALLOCATED |
61620Sstevel@tonic-gate 				IRQ_FORCED_PULSE)) ||
61630Sstevel@tonic-gate 		!(irqr->Attributes & IRQ_TYPE_EXCLUSIVE))
61640Sstevel@tonic-gate 	    return (CS_BAD_ATTRIBUTE);
61650Sstevel@tonic-gate 
61660Sstevel@tonic-gate 	/*
61670Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
61680Sstevel@tonic-gate 	 */
61690Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
61700Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
61710Sstevel@tonic-gate 
61720Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
61730Sstevel@tonic-gate 
61740Sstevel@tonic-gate 	/*
61750Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
61760Sstevel@tonic-gate 	 */
61770Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
61780Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
61790Sstevel@tonic-gate 	    return (error);
61800Sstevel@tonic-gate 	}
61810Sstevel@tonic-gate 
61820Sstevel@tonic-gate 	/*
61830Sstevel@tonic-gate 	 * If RequestConfiguration has already been done, we don't allow
61840Sstevel@tonic-gate 	 *	this call.
61850Sstevel@tonic-gate 	 */
61860Sstevel@tonic-gate 	if (client->flags & REQ_CONFIGURATION_DONE) {
61870Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
61880Sstevel@tonic-gate 	    return (CS_CONFIGURATION_LOCKED);
61890Sstevel@tonic-gate 	}
61900Sstevel@tonic-gate 
61910Sstevel@tonic-gate 	/*
61920Sstevel@tonic-gate 	 * If RequestIRQ has already been done, we don't allow this call.
61930Sstevel@tonic-gate 	 */
61940Sstevel@tonic-gate 	if (client->flags & REQ_IRQ_DONE) {
61950Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
61960Sstevel@tonic-gate 	    return (CS_IN_USE);
61970Sstevel@tonic-gate 	}
61980Sstevel@tonic-gate 
61990Sstevel@tonic-gate 	/*
62000Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
62010Sstevel@tonic-gate 	 *	for this client, then return an error.
62020Sstevel@tonic-gate 	 */
62030Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
62040Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
62050Sstevel@tonic-gate 	    return (CS_NO_CARD);
62060Sstevel@tonic-gate 	}
62070Sstevel@tonic-gate 
62080Sstevel@tonic-gate 	/*
62090Sstevel@tonic-gate 	 * Set up the parameters and ask Socket Services to give us an IRQ
62100Sstevel@tonic-gate 	 *	for this client.  We don't really do much, since the IRQ
62110Sstevel@tonic-gate 	 *	resources are managed by SS and the kernel.  We also don't
62120Sstevel@tonic-gate 	 *	care which IRQ level we are given.
62130Sstevel@tonic-gate 	 */
62140Sstevel@tonic-gate 	set_irq_handler.socket =
62150Sstevel@tonic-gate 		CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
62160Sstevel@tonic-gate 					GET_CLIENT_FUNCTION(client_handle));
62170Sstevel@tonic-gate 	set_irq_handler.irq = IRQ_ANY;
62180Sstevel@tonic-gate 
62190Sstevel@tonic-gate 	set_irq_handler.handler_id = client_handle;
62200Sstevel@tonic-gate 	set_irq_handler.handler = (f_t *)irqr->irq_handler;
62210Sstevel@tonic-gate 	set_irq_handler.arg1 = irqr->irq_handler_arg;
62220Sstevel@tonic-gate 	set_irq_handler.arg2 = NULL;
62230Sstevel@tonic-gate 
62240Sstevel@tonic-gate 	if ((error = SocketServices(SS_SetIRQHandler,
62250Sstevel@tonic-gate 					&set_irq_handler)) != SUCCESS) {
62260Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
62270Sstevel@tonic-gate 	    return (CS_BAD_IRQ);
62280Sstevel@tonic-gate 	}
62290Sstevel@tonic-gate 
62300Sstevel@tonic-gate 	irqr->iblk_cookie = set_irq_handler.iblk_cookie;
62310Sstevel@tonic-gate 	irqr->idev_cookie = set_irq_handler.idev_cookie;
62320Sstevel@tonic-gate 
62330Sstevel@tonic-gate 	/*
62340Sstevel@tonic-gate 	 * Save the allocated IRQ information for this client.
62350Sstevel@tonic-gate 	 */
62360Sstevel@tonic-gate 	client->irq_alloc.Attributes = irqr->Attributes;
62370Sstevel@tonic-gate 	client->irq_alloc.irq = set_irq_handler.irq;
62380Sstevel@tonic-gate 	client->irq_alloc.handler_id = set_irq_handler.handler_id;
62390Sstevel@tonic-gate 	client->irq_alloc.irq_handler = (f_t *)set_irq_handler.handler;
62400Sstevel@tonic-gate 	client->irq_alloc.irq_handler_arg1 = set_irq_handler.arg1;
62410Sstevel@tonic-gate 	client->irq_alloc.irq_handler_arg2 = set_irq_handler.arg2;
62420Sstevel@tonic-gate 
62430Sstevel@tonic-gate #ifdef	CS_DEBUG
62440Sstevel@tonic-gate 	if (cs_debug > 0)
62450Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_request_irq: socket %d irqr->Attributes 0x%x "
62460Sstevel@tonic-gate 						"set_irq_handler.irq 0x%x\n",
62470Sstevel@tonic-gate 						sp->socket_num,
62480Sstevel@tonic-gate 						(int)irqr->Attributes,
62490Sstevel@tonic-gate 						set_irq_handler.irq);
62500Sstevel@tonic-gate #endif
62510Sstevel@tonic-gate 
62520Sstevel@tonic-gate 	/*
62530Sstevel@tonic-gate 	 * Mark this client as having done a successful RequestIRQ call.
62540Sstevel@tonic-gate 	 */
62550Sstevel@tonic-gate 	client->flags |= (REQ_IRQ_DONE | CLIENT_IRQ_ALLOCATED);
62560Sstevel@tonic-gate 
62570Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
62580Sstevel@tonic-gate 	return (CS_SUCCESS);
62590Sstevel@tonic-gate }
62600Sstevel@tonic-gate 
62610Sstevel@tonic-gate /*
62620Sstevel@tonic-gate  * cs_release_irq - releases IRQ resources allocated by RequestIRQ; this is
62630Sstevel@tonic-gate  *			ReleaseIRQ
62640Sstevel@tonic-gate  *
62650Sstevel@tonic-gate  *	calling: cs_release_irq(client_handle_t, irq_req_t *)
62660Sstevel@tonic-gate  *
62670Sstevel@tonic-gate  *	returns: CS_SUCCESS - if IRQ resources sucessfully deallocated
62680Sstevel@tonic-gate  *		 CS_BAD_IRQ - if IRQ can not be deallocated
62690Sstevel@tonic-gate  *		 CS_BAD_HANDLE - client handle is invalid
62700Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
62710Sstevel@tonic-gate  *		 CS_CONFIGURATION_LOCKED - a RequestConfiguration has been
62720Sstevel@tonic-gate  *				done without a ReleaseConfiguration
62730Sstevel@tonic-gate  *		 CS_IN_USE - no RequestIRQ has been done
62740Sstevel@tonic-gate  */
62750Sstevel@tonic-gate static int
62760Sstevel@tonic-gate cs_release_irq(client_handle_t client_handle, irq_req_t *irqr)
62770Sstevel@tonic-gate {
62780Sstevel@tonic-gate 	cs_socket_t *sp;
62790Sstevel@tonic-gate 	client_t *client;
62800Sstevel@tonic-gate 	clear_irq_handler_t clear_irq_handler;
62810Sstevel@tonic-gate 	int error;
62820Sstevel@tonic-gate 	int client_lock_acquired;
62830Sstevel@tonic-gate 
62840Sstevel@tonic-gate #ifdef	lint
62850Sstevel@tonic-gate 	irqr = NULL;
62860Sstevel@tonic-gate #endif
62870Sstevel@tonic-gate 
62880Sstevel@tonic-gate 	/*
62890Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
62900Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
62910Sstevel@tonic-gate 	 */
62920Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
62930Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
62940Sstevel@tonic-gate 
62950Sstevel@tonic-gate 	/*
62960Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
62970Sstevel@tonic-gate 	 */
62980Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
62990Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
63000Sstevel@tonic-gate 
63010Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
63020Sstevel@tonic-gate 
63030Sstevel@tonic-gate 	/*
63040Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
63050Sstevel@tonic-gate 	 */
63060Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
63070Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
63080Sstevel@tonic-gate 	    return (error);
63090Sstevel@tonic-gate 	}
63100Sstevel@tonic-gate 
63110Sstevel@tonic-gate 	/*
63120Sstevel@tonic-gate 	 * If RequestConfiguration has already been done, we don't allow
63130Sstevel@tonic-gate 	 *	this call.
63140Sstevel@tonic-gate 	 */
63150Sstevel@tonic-gate 	if (client->flags & REQ_CONFIGURATION_DONE) {
63160Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
63170Sstevel@tonic-gate 	    return (CS_CONFIGURATION_LOCKED);
63180Sstevel@tonic-gate 	}
63190Sstevel@tonic-gate 
63200Sstevel@tonic-gate 	/*
63210Sstevel@tonic-gate 	 * If RequestIRQ has not been done, we don't allow this call.
63220Sstevel@tonic-gate 	 */
63230Sstevel@tonic-gate 	if (!(client->flags & REQ_IRQ_DONE)) {
63240Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
63250Sstevel@tonic-gate 	    return (CS_IN_USE);
63260Sstevel@tonic-gate 	}
63270Sstevel@tonic-gate 
63280Sstevel@tonic-gate 	/*
63290Sstevel@tonic-gate 	 * Tell Socket Services that we want to deregister this client's
63300Sstevel@tonic-gate 	 *	IRQ handler.
63310Sstevel@tonic-gate 	 */
63320Sstevel@tonic-gate 	clear_irq_handler.socket =
63330Sstevel@tonic-gate 		CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
63340Sstevel@tonic-gate 				GET_CLIENT_FUNCTION(client_handle));
63350Sstevel@tonic-gate 	clear_irq_handler.handler_id = client->irq_alloc.handler_id;
63360Sstevel@tonic-gate 	clear_irq_handler.handler = (f_t *)client->irq_alloc.irq_handler;
63370Sstevel@tonic-gate 
63380Sstevel@tonic-gate 	/*
63390Sstevel@tonic-gate 	 * At this point, we should never fail this SS call; if we do, it
63400Sstevel@tonic-gate 	 *	means that there is an internal consistancy error in either
63410Sstevel@tonic-gate 	 *	Card Services or Socket Services.
63420Sstevel@tonic-gate 	 */
63430Sstevel@tonic-gate 	if ((error = SocketServices(SS_ClearIRQHandler, &clear_irq_handler)) !=
63440Sstevel@tonic-gate 								SUCCESS) {
63450Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
63460Sstevel@tonic-gate 	    return (CS_BAD_IRQ);
63470Sstevel@tonic-gate 	}
63480Sstevel@tonic-gate 
63490Sstevel@tonic-gate 	/*
63500Sstevel@tonic-gate 	 * Mark the client as not having any IRQ resources allocated.
63510Sstevel@tonic-gate 	 */
63520Sstevel@tonic-gate 	client->flags &= ~(REQ_IRQ_DONE | CLIENT_IRQ_ALLOCATED);
63530Sstevel@tonic-gate 
63540Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
63550Sstevel@tonic-gate 	return (CS_SUCCESS);
63560Sstevel@tonic-gate }
63570Sstevel@tonic-gate 
63580Sstevel@tonic-gate /*
63590Sstevel@tonic-gate  * ==== configuration handling functions ====
63600Sstevel@tonic-gate  */
63610Sstevel@tonic-gate 
63620Sstevel@tonic-gate /*
63630Sstevel@tonic-gate  * cs_request_configuration - sets up socket and card configuration on behalf
63640Sstevel@tonic-gate  *		of the client; this is RequestConfiguration
63650Sstevel@tonic-gate  *
63660Sstevel@tonic-gate  *	returns: CS_SUCCESS - if configuration sucessfully set
63670Sstevel@tonic-gate  *		 CS_BAD_SOCKET - if Socket Services returns an error
63680Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
63690Sstevel@tonic-gate  *		 CS_BAD_ATTRIBUTE - if any unsupported or reserved flags
63700Sstevel@tonic-gate  *					are set
63710Sstevel@tonic-gate  *		 CS_BAD_TYPE - if the socket doesn't support a mem and IO
63720Sstevel@tonic-gate  *				interface (SOCKET_INTERFACE_MEMORY_AND_IO set)
63730Sstevel@tonic-gate  *		 CS_CONFIGURATION_LOCKED - a RequestConfiguration has
63740Sstevel@tonic-gate  *					already been done
63750Sstevel@tonic-gate  *		 CS_BAD_VCC - if Vcc value is not supported by socket
63760Sstevel@tonic-gate  *		 CS_BAD_VPP1 - if Vpp1 value is not supported by socket
63770Sstevel@tonic-gate  *		 CS_BAD_VPP2 - if Vpp2 value is not supported by socket
63780Sstevel@tonic-gate  *
63790Sstevel@tonic-gate  * Bug ID: 1193637 - Card Services RequestConfiguration does not conform
63800Sstevel@tonic-gate  *	to PCMCIA standard
63810Sstevel@tonic-gate  * We allow clients to do a RequestConfiguration even if they haven't
63820Sstevel@tonic-gate  *	done a RequestIO or RequestIRQ.
63830Sstevel@tonic-gate  */
63840Sstevel@tonic-gate static int
63850Sstevel@tonic-gate cs_request_configuration(client_handle_t client_handle, config_req_t *cr)
63860Sstevel@tonic-gate {
63870Sstevel@tonic-gate 	cs_socket_t *sp;
63880Sstevel@tonic-gate 	client_t *client;
63890Sstevel@tonic-gate 	volatile config_regs_t *crt;
63900Sstevel@tonic-gate 	set_socket_t set_socket;
63910Sstevel@tonic-gate 	get_socket_t get_socket;
63920Sstevel@tonic-gate 	acc_handle_t cis_handle;
63930Sstevel@tonic-gate 	int error;
63940Sstevel@tonic-gate 	uint32_t newoffset;
63950Sstevel@tonic-gate 	int client_lock_acquired;
63960Sstevel@tonic-gate 
63970Sstevel@tonic-gate 	/*
63980Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
63990Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
64000Sstevel@tonic-gate 	 */
64010Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
64020Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
64030Sstevel@tonic-gate 
64040Sstevel@tonic-gate #ifdef	XXX
64050Sstevel@tonic-gate 	/*
64060Sstevel@tonic-gate 	 * If the client specifies Vcc = 0 and any non-zero value for
64070Sstevel@tonic-gate 	 *	either of the Vpp members, that's an illegal condition.
64080Sstevel@tonic-gate 	 */
64090Sstevel@tonic-gate 	if (!(cr->Vcc) && (cr->Vpp1 || cr->Vpp2))
64100Sstevel@tonic-gate 	    return (CS_BAD_VCC);
64110Sstevel@tonic-gate #endif
64120Sstevel@tonic-gate 
64130Sstevel@tonic-gate 	/*
64140Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
64150Sstevel@tonic-gate 	 */
64160Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
64170Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
64180Sstevel@tonic-gate 
64190Sstevel@tonic-gate 	/*
64200Sstevel@tonic-gate 	 * If the client is asking for a memory and IO interface on this
64210Sstevel@tonic-gate 	 *	socket, then check the socket capabilities to be sure that
64220Sstevel@tonic-gate 	 *	this socket supports this configuration.
64230Sstevel@tonic-gate 	 */
64240Sstevel@tonic-gate 	if (cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO) {
64250Sstevel@tonic-gate 	    inquire_socket_t inquire_socket;
64260Sstevel@tonic-gate 
64270Sstevel@tonic-gate 	    inquire_socket.socket = sp->socket_num;
64280Sstevel@tonic-gate 
64290Sstevel@tonic-gate 	    if (SocketServices(SS_InquireSocket, &inquire_socket) != SUCCESS)
64300Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
64310Sstevel@tonic-gate 
64320Sstevel@tonic-gate 	    if (!(inquire_socket.SocketCaps & IF_IO))
64330Sstevel@tonic-gate 		return (CS_BAD_TYPE);
64340Sstevel@tonic-gate 
64350Sstevel@tonic-gate 	} /* if (SOCKET_INTERFACE_MEMORY_AND_IO) */
64360Sstevel@tonic-gate 
64370Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
64380Sstevel@tonic-gate 
64390Sstevel@tonic-gate 	/*
64400Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
64410Sstevel@tonic-gate 	 */
64420Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
64430Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
64440Sstevel@tonic-gate 	    return (error);
64450Sstevel@tonic-gate 	}
64460Sstevel@tonic-gate 
64470Sstevel@tonic-gate 	/*
64480Sstevel@tonic-gate 	 * If RequestConfiguration has already been done, we don't allow
64490Sstevel@tonic-gate 	 *	this call.
64500Sstevel@tonic-gate 	 */
64510Sstevel@tonic-gate 	if (client->flags & REQ_CONFIGURATION_DONE) {
64520Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
64530Sstevel@tonic-gate 	    return (CS_CONFIGURATION_LOCKED);
64540Sstevel@tonic-gate 	}
64550Sstevel@tonic-gate 
64560Sstevel@tonic-gate 	/*
64570Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
64580Sstevel@tonic-gate 	 *	for this client, then return an error.
64590Sstevel@tonic-gate 	 */
64600Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
64610Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
64620Sstevel@tonic-gate 	    return (CS_NO_CARD);
64630Sstevel@tonic-gate 	}
64640Sstevel@tonic-gate 
64650Sstevel@tonic-gate 	/*
64660Sstevel@tonic-gate 	 * At this point, most of the client's calling parameters have been
64670Sstevel@tonic-gate 	 *	validated, so we can go ahead and configure the socket and
64680Sstevel@tonic-gate 	 *	the card.
64690Sstevel@tonic-gate 	 */
64700Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
64710Sstevel@tonic-gate 
64720Sstevel@tonic-gate 	/*
64730Sstevel@tonic-gate 	 * Configure the socket with the interface type and voltages requested
64740Sstevel@tonic-gate 	 *	by the client.
64750Sstevel@tonic-gate 	 */
64760Sstevel@tonic-gate 	get_socket.socket = sp->socket_num;
64770Sstevel@tonic-gate 
64780Sstevel@tonic-gate 	if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
64790Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
64800Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
64810Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
64820Sstevel@tonic-gate 	}
64830Sstevel@tonic-gate 
64840Sstevel@tonic-gate #ifdef	CS_DEBUG
64850Sstevel@tonic-gate 	if (cs_debug > 0)
64860Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_request_configuration: socket %d "
64870Sstevel@tonic-gate 					"client->irq_alloc.irq 0x%x "
64880Sstevel@tonic-gate 					"get_socket.IRQRouting 0x%x\n",
64890Sstevel@tonic-gate 						sp->socket_num,
64900Sstevel@tonic-gate 						(int)client->irq_alloc.irq,
64910Sstevel@tonic-gate 						get_socket.IRQRouting);
64920Sstevel@tonic-gate #endif
64930Sstevel@tonic-gate 
64940Sstevel@tonic-gate 	bzero(&set_socket, sizeof (set_socket));
64950Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
64960Sstevel@tonic-gate 	set_socket.IREQRouting = client->irq_alloc.irq & ~IRQ_ENABLE;
64970Sstevel@tonic-gate 
64980Sstevel@tonic-gate 	set_socket.CtlInd = get_socket.CtlInd;
64990Sstevel@tonic-gate 	set_socket.State = 0;	/* don't reset latched values */
65000Sstevel@tonic-gate 
65010Sstevel@tonic-gate 	if (cs_convert_powerlevel(sp->socket_num, cr->Vcc, VCC,
65020Sstevel@tonic-gate 					&set_socket.VccLevel) != CS_SUCCESS) {
65030Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
65040Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
65050Sstevel@tonic-gate 	    return (CS_BAD_VCC);
65060Sstevel@tonic-gate 	}
65070Sstevel@tonic-gate 
65080Sstevel@tonic-gate 	if (cs_convert_powerlevel(sp->socket_num, cr->Vpp1, VPP1,
65090Sstevel@tonic-gate 					&set_socket.Vpp1Level) != CS_SUCCESS) {
65100Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
65110Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
65120Sstevel@tonic-gate 	    return (CS_BAD_VPP);
65130Sstevel@tonic-gate 	}
65140Sstevel@tonic-gate 
65150Sstevel@tonic-gate 	if (cs_convert_powerlevel(sp->socket_num, cr->Vpp2, VPP2,
65160Sstevel@tonic-gate 					&set_socket.Vpp2Level) != CS_SUCCESS) {
65170Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
65180Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
65190Sstevel@tonic-gate 	    return (CS_BAD_VPP);
65200Sstevel@tonic-gate 	}
65210Sstevel@tonic-gate 
65220Sstevel@tonic-gate 	if (!(cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO))
65230Sstevel@tonic-gate 		set_socket.IFType = IF_MEMORY;
65240Sstevel@tonic-gate 	else {
65250Sstevel@tonic-gate 		set_socket.IFType = IF_IO;
65260Sstevel@tonic-gate 
65270Sstevel@tonic-gate 		/*
65280Sstevel@tonic-gate 		 * The Cirrus Logic PD6710/672X/others? adapters will write
65290Sstevel@tonic-gate 		 * protect the CIS if the socket is in MEMORY mode and the
65300Sstevel@tonic-gate 		 * WP/IOCS16 pin is true.  When this happens, the CIS registers
65310Sstevel@tonic-gate 		 * will fail to be written.  Go ahead and set the socket,
65320Sstevel@tonic-gate 		 * even though the event mask isn't complete yet, so we can
65330Sstevel@tonic-gate 		 * configure the adapter.  Afterwards, set the socket again
65340Sstevel@tonic-gate 		 * to make sure the event mask is correct.
65350Sstevel@tonic-gate 		 */
65360Sstevel@tonic-gate 		if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
65370Sstevel@tonic-gate 			sp->flags &= ~SOCKET_IS_IO;
65380Sstevel@tonic-gate 			mutex_exit(&sp->cis_lock);
65390Sstevel@tonic-gate 			EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
65400Sstevel@tonic-gate 			return (CS_BAD_SOCKET);
65410Sstevel@tonic-gate 		}
65420Sstevel@tonic-gate 	}
65430Sstevel@tonic-gate 
65440Sstevel@tonic-gate 	if (cs_rc2_delay)
65450Sstevel@tonic-gate 	    drv_usecwait(cs_rc2_delay * 1000);
65460Sstevel@tonic-gate 
65470Sstevel@tonic-gate 	/*
65480Sstevel@tonic-gate 	 * Get a pointer to a window that contains the configuration
65490Sstevel@tonic-gate 	 *	registers.
65500Sstevel@tonic-gate 	 */
65510Sstevel@tonic-gate 	mutex_enter(&sp->lock);
65520Sstevel@tonic-gate 	client->config_regs_offset = cr->ConfigBase;
65530Sstevel@tonic-gate 	newoffset = client->config_regs_offset;
65540Sstevel@tonic-gate 	mutex_exit(&sp->lock);
65550Sstevel@tonic-gate 	if (cs_init_cis_window(sp, &newoffset, &cis_handle,
65560Sstevel@tonic-gate 					CISTPLF_AM_SPACE) != CS_SUCCESS) {
65570Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
65580Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
65590Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_request_configuration: socket %d can't init "
65600Sstevel@tonic-gate 				"CIS window\n", sp->socket_num);
65610Sstevel@tonic-gate 	    return (CS_GENERAL_FAILURE);
65620Sstevel@tonic-gate 	}
65630Sstevel@tonic-gate 
65640Sstevel@tonic-gate 	/*
65650Sstevel@tonic-gate 	 * Setup the config register pointers.
65660Sstevel@tonic-gate 	 * Note that these pointers are not the complete virtual address;
65670Sstevel@tonic-gate 	 *	the complete address is constructed each time the registers
65680Sstevel@tonic-gate 	 *	are accessed.
65690Sstevel@tonic-gate 	 */
65700Sstevel@tonic-gate 	mutex_enter(&sp->lock);
65710Sstevel@tonic-gate 	crt = &client->config_regs;
65720Sstevel@tonic-gate 	client->present = cr->Present;
65730Sstevel@tonic-gate 
65740Sstevel@tonic-gate 	bzero((char *)crt, sizeof (config_regs_t));
65750Sstevel@tonic-gate 
65760Sstevel@tonic-gate 	/* Configuration Option Register */
65770Sstevel@tonic-gate 	if (client->present & CONFIG_OPTION_REG_PRESENT)
65780Sstevel@tonic-gate 	    crt->cor_p = (newoffset + CONFIG_OPTION_REG_OFFSET);
65790Sstevel@tonic-gate 
65800Sstevel@tonic-gate 	/* Configuration and Status Register */
65810Sstevel@tonic-gate 	if (client->present & CONFIG_STATUS_REG_PRESENT)
65820Sstevel@tonic-gate 	    crt->ccsr_p = (newoffset + CONFIG_STATUS_REG_OFFSET);
65830Sstevel@tonic-gate 
65840Sstevel@tonic-gate 	/* Pin Replacement Register */
65850Sstevel@tonic-gate 	if (client->present & CONFIG_PINREPL_REG_PRESENT)
65860Sstevel@tonic-gate 	    crt->prr_p = (newoffset + CONFIG_PINREPL_REG_OFFSET);
65870Sstevel@tonic-gate 
65880Sstevel@tonic-gate 	/* Socket and Copy Register */
65890Sstevel@tonic-gate 	if (client->present & CONFIG_COPY_REG_PRESENT)
65900Sstevel@tonic-gate 	    crt->scr_p = (newoffset + CONFIG_COPY_REG_OFFSET);
65910Sstevel@tonic-gate 
65920Sstevel@tonic-gate 	/* Extended Status Register */
65930Sstevel@tonic-gate 	if (client->present & CONFIG_EXSTAT_REG_PRESENT)
65940Sstevel@tonic-gate 	    crt->exstat_p = (newoffset + CONFIG_EXSTAT_REG_OFFSET);
65950Sstevel@tonic-gate 
65960Sstevel@tonic-gate 	/* IO Base 0 Register */
65970Sstevel@tonic-gate 	if (client->present & CONFIG_IOBASE0_REG_PRESENT)
65980Sstevel@tonic-gate 	    crt->iobase0_p = (newoffset + CONFIG_IOBASE0_REG_OFFSET);
65990Sstevel@tonic-gate 
66000Sstevel@tonic-gate 	/* IO Base 1 Register */
66010Sstevel@tonic-gate 	if (client->present & CONFIG_IOBASE1_REG_PRESENT)
66020Sstevel@tonic-gate 	    crt->iobase1_p = (newoffset + CONFIG_IOBASE1_REG_OFFSET);
66030Sstevel@tonic-gate 
66040Sstevel@tonic-gate 	/* IO Base 2 Register */
66050Sstevel@tonic-gate 	if (client->present & CONFIG_IOBASE2_REG_PRESENT)
66060Sstevel@tonic-gate 	    crt->iobase2_p = (newoffset + CONFIG_IOBASE2_REG_OFFSET);
66070Sstevel@tonic-gate 
66080Sstevel@tonic-gate 	/* IO Base 3 Register */
66090Sstevel@tonic-gate 	if (client->present & CONFIG_IOBASE3_REG_PRESENT)
66100Sstevel@tonic-gate 	    crt->iobase3_p = (newoffset + CONFIG_IOBASE3_REG_OFFSET);
66110Sstevel@tonic-gate 
66120Sstevel@tonic-gate 	/* IO Limit Register */
66130Sstevel@tonic-gate 	if (client->present & CONFIG_IOLIMIT_REG_PRESENT)
66140Sstevel@tonic-gate 	    crt->iolimit_p = (newoffset + CONFIG_IOLIMIT_REG_OFFSET);
66150Sstevel@tonic-gate 
66160Sstevel@tonic-gate 	/*
66170Sstevel@tonic-gate 	 * Setup the bits in the PRR mask that are valid; this is easy, just
66180Sstevel@tonic-gate 	 *	copy the Pin value that the client gave us.  Note that for
66190Sstevel@tonic-gate 	 *	this to work, the client must set both of the XXX_STATUS
66200Sstevel@tonic-gate 	 *	and the XXX_EVENT bits in the Pin member.
66210Sstevel@tonic-gate 	 */
66220Sstevel@tonic-gate 	client->pin = cr->Pin;
66230Sstevel@tonic-gate 
66240Sstevel@tonic-gate #ifdef	CS_DEBUG
66250Sstevel@tonic-gate 	if (cs_debug > 128)
66260Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_request_configuration: client->pin 0x%x "
66270Sstevel@tonic-gate 		"client->config_regs_offset 0x%x newoffset 0x%x cor_p 0x%x "
66280Sstevel@tonic-gate 		"ccsr_p 0x%x prr_p 0x%x scr_p 0x%x\n",
66290Sstevel@tonic-gate 		client->pin, (int)client->config_regs_offset, newoffset,
66300Sstevel@tonic-gate 		(int)crt->cor_p, (int)crt->ccsr_p, (int)crt->prr_p,
66310Sstevel@tonic-gate 		(int)crt->scr_p);
66320Sstevel@tonic-gate #endif
66330Sstevel@tonic-gate 
66340Sstevel@tonic-gate 	/*
66350Sstevel@tonic-gate 	 * If the socket isn't in IO mode, WP is asserted,  and we're going to
66360Sstevel@tonic-gate 	 * write any of the config registers, issue a warning.
66370Sstevel@tonic-gate 	 */
66380Sstevel@tonic-gate 	if ((client->present != 0) &&
66390Sstevel@tonic-gate 	    (!(cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO)) &&
66400Sstevel@tonic-gate 	    (get_socket.state & SBM_WP)) {
66410Sstevel@tonic-gate 		cmn_err(CE_NOTE, "!cs_request_configuration: attempting to "
66420Sstevel@tonic-gate 		    "write CIS config regs with WP set\n");
66430Sstevel@tonic-gate 	}
66440Sstevel@tonic-gate 
66450Sstevel@tonic-gate 	/*
66460Sstevel@tonic-gate 	 * Write any configuration registers that the client tells us are
66470Sstevel@tonic-gate 	 *	present to the card; save a copy of what we wrote so that we
66480Sstevel@tonic-gate 	 *	can return them if the client calls GetConfigurationInfo.
66490Sstevel@tonic-gate 	 * The order in which we write the configuration registers is
66500Sstevel@tonic-gate 	 *	specified by the PCMCIA spec; we must write the socket/copy
66510Sstevel@tonic-gate 	 *	register first (if it exists), and then we can write the
66520Sstevel@tonic-gate 	 *	registers in any arbitrary order.
66530Sstevel@tonic-gate 	 */
66540Sstevel@tonic-gate 	/* Socket and Copy Register */
66550Sstevel@tonic-gate 	if (client->present & CONFIG_COPY_REG_PRESENT) {
66560Sstevel@tonic-gate 	    crt->scr = cr->Copy;
66570Sstevel@tonic-gate 	    csx_Put8(cis_handle, crt->scr_p, crt->scr);
66580Sstevel@tonic-gate 	}
66590Sstevel@tonic-gate 
66600Sstevel@tonic-gate 	/* Pin Replacement Register */
66610Sstevel@tonic-gate 	if (client->present & CONFIG_PINREPL_REG_PRESENT) {
66620Sstevel@tonic-gate 	    crt->prr = cr->Pin;
66630Sstevel@tonic-gate 	    csx_Put8(cis_handle, crt->prr_p, crt->prr);
66640Sstevel@tonic-gate 	}
66650Sstevel@tonic-gate 
66660Sstevel@tonic-gate 	/* Configuration and Status Register */
66670Sstevel@tonic-gate 	/* XXX should we set CCSR_SIG_CHG in the CCSR? XXX */
66680Sstevel@tonic-gate 	if (client->present & CONFIG_STATUS_REG_PRESENT) {
66690Sstevel@tonic-gate 	    crt->ccsr = cr->Status;
66700Sstevel@tonic-gate 	    csx_Put8(cis_handle, crt->ccsr_p, crt->ccsr);
66710Sstevel@tonic-gate 	}
66720Sstevel@tonic-gate 
66730Sstevel@tonic-gate 	/* Extended Status Register */
66740Sstevel@tonic-gate 	if (client->present & CONFIG_EXSTAT_REG_PRESENT) {
66750Sstevel@tonic-gate 	    crt->exstat = cr->ExtendedStatus;
66760Sstevel@tonic-gate 	    csx_Put8(cis_handle, crt->exstat_p, crt->exstat);
66770Sstevel@tonic-gate 	}
66780Sstevel@tonic-gate 
66790Sstevel@tonic-gate 	/*
66800Sstevel@tonic-gate 	 * If any IO base and limit registers exist, and this client
66810Sstevel@tonic-gate 	 *	has done a RequestIO, setup the IO Base and IO Limit
66820Sstevel@tonic-gate 	 *	registers.
66830Sstevel@tonic-gate 	 */
66840Sstevel@tonic-gate 	if (client->flags & REQ_IO_DONE) {
66850Sstevel@tonic-gate 	    if (client->present & CONFIG_IOBASE0_REG_PRESENT) {
66860Sstevel@tonic-gate 		uint32_t base = client->io_alloc.BasePort1.base;
66870Sstevel@tonic-gate 		uint32_t present = (client->present &
66880Sstevel@tonic-gate 					CONFIG_IOBASE_REG_MASK) >>
66890Sstevel@tonic-gate 						CONFIG_IOBASE_REG_SHIFT;
66900Sstevel@tonic-gate 		uint32_t reg = crt->iobase0_p;
66910Sstevel@tonic-gate 
66920Sstevel@tonic-gate 		do {
66930Sstevel@tonic-gate 		    csx_Put8(cis_handle, reg, base & 0x0ff);
66940Sstevel@tonic-gate 		    reg = reg + 2;
66950Sstevel@tonic-gate 		    base = base >> 8;
66960Sstevel@tonic-gate 		    present = present >> 1;
66970Sstevel@tonic-gate 		} while (present);
66980Sstevel@tonic-gate 	    } /* CONFIG_IOBASE0_REG_PRESENT */
66990Sstevel@tonic-gate 
67000Sstevel@tonic-gate 	    if (client->present & CONFIG_IOLIMIT_REG_PRESENT) {
67010Sstevel@tonic-gate 		uint32_t np = client->io_alloc.NumPorts1 +
67020Sstevel@tonic-gate 					client->io_alloc.NumPorts2;
67030Sstevel@tonic-gate 		uint32_t limit, do_bit = 0;
67040Sstevel@tonic-gate 		int lm;
67050Sstevel@tonic-gate 
67060Sstevel@tonic-gate 		limit = (IONUMPORTS_FROBNITZ(np) - 1);
67070Sstevel@tonic-gate 
67080Sstevel@tonic-gate 		for (lm = 7; lm >= 0; lm--) {
67090Sstevel@tonic-gate 		    if (limit & (1 << lm))
67100Sstevel@tonic-gate 			do_bit = 1;
67110Sstevel@tonic-gate 		    if (do_bit)
67120Sstevel@tonic-gate 			limit |= (1 << lm);
67130Sstevel@tonic-gate 		} /* for */
67140Sstevel@tonic-gate 
67150Sstevel@tonic-gate 		csx_Put8(cis_handle, crt->iolimit_p, limit);
67160Sstevel@tonic-gate 	    } /* CONFIG_IOLIMIT_REG_PRESENT */
67170Sstevel@tonic-gate 	} /* REQ_IO_DONE */
67180Sstevel@tonic-gate 
67190Sstevel@tonic-gate 	/*
67200Sstevel@tonic-gate 	 * Mark the socket as being in IO mode.
67210Sstevel@tonic-gate 	 */
67220Sstevel@tonic-gate 	if (cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO)
67230Sstevel@tonic-gate 	    sp->flags |= SOCKET_IS_IO;
67240Sstevel@tonic-gate 
67250Sstevel@tonic-gate 	mutex_exit(&sp->lock);
67260Sstevel@tonic-gate 
67270Sstevel@tonic-gate 	/*
67280Sstevel@tonic-gate 	 * Enable the interrupt if needed
67290Sstevel@tonic-gate 	 */
67300Sstevel@tonic-gate 	if (cr->Attributes & CONF_ENABLE_IRQ_STEERING)
67310Sstevel@tonic-gate 	    set_socket.IREQRouting |= IRQ_ENABLE;
67320Sstevel@tonic-gate 
67330Sstevel@tonic-gate 	/*
67340Sstevel@tonic-gate 	 * Now that we know if the PRR is present and if it is, which
67350Sstevel@tonic-gate 	 *	bits in the PRR are valid, we can construct the correct
67360Sstevel@tonic-gate 	 *	socket event mask.
67370Sstevel@tonic-gate 	 */
67380Sstevel@tonic-gate 	set_socket.SCIntMask = cs_merge_event_masks(sp, client);
67390Sstevel@tonic-gate 
67400Sstevel@tonic-gate 	/*
67410Sstevel@tonic-gate 	 * Configuration Option Register - we handle this specially since
67420Sstevel@tonic-gate 	 *	we don't allow the client to manipulate the RESET or
67430Sstevel@tonic-gate 	 *	INTERRUPT bits (although a client can manipulate these
67440Sstevel@tonic-gate 	 *	bits via an AccessConfigurationRegister call - explain
67450Sstevel@tonic-gate 	 *	THAT logic to me).
67460Sstevel@tonic-gate 	 * XXX - we force level-mode interrupts (COR_LEVEL_IRQ)
67470Sstevel@tonic-gate 	 * XXX - we always enable the function on a multi-function card
67480Sstevel@tonic-gate 	 */
67490Sstevel@tonic-gate 	if (client->present & CONFIG_OPTION_REG_PRESENT) {
67500Sstevel@tonic-gate 	    crt->cor = (cr->ConfigIndex & ~COR_SOFT_RESET) | COR_LEVEL_IRQ;
67510Sstevel@tonic-gate 	    if (client->present & CONFIG_IOBASE0_REG_PRESENT)
67520Sstevel@tonic-gate 		crt->cor |= COR_ENABLE_BASE_LIMIT;
67530Sstevel@tonic-gate 	    if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
67540Sstevel@tonic-gate 		crt->cor |= COR_ENABLE_FUNCTION;
67550Sstevel@tonic-gate 		crt->cor &= ~COR_ENABLE_IREQ_ROUTING;
67560Sstevel@tonic-gate 		if (cr->Attributes & CONF_ENABLE_IRQ_STEERING)
67570Sstevel@tonic-gate 		    crt->cor |= COR_ENABLE_IREQ_ROUTING;
67580Sstevel@tonic-gate 	    } /* CW_MULTI_FUNCTION_CIS */
67590Sstevel@tonic-gate 
67600Sstevel@tonic-gate #ifdef  CS_DEBUG
67610Sstevel@tonic-gate 	if (cs_debug > 0)
67620Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_request_configuration "
67630Sstevel@tonic-gate 		    "cor=x%x ConfigIndex=x%x Attributes=x%x flags=x%x\n"
67640Sstevel@tonic-gate 		    "present=x%x cis_handle=%p cor_p=x%x\n",
67650Sstevel@tonic-gate 		    crt->cor, cr->ConfigIndex, cr->Attributes, sp->cis_flags,
67660Sstevel@tonic-gate 		    client->present, cis_handle, crt->cor_p);
67670Sstevel@tonic-gate #endif
67680Sstevel@tonic-gate 
67690Sstevel@tonic-gate 	    csx_Put8(cis_handle, crt->cor_p, crt->cor);
67700Sstevel@tonic-gate 	} /* CONFIG_OPTION_REG_PRESENT */
67710Sstevel@tonic-gate 
67720Sstevel@tonic-gate 	if (cs_rc1_delay)
67730Sstevel@tonic-gate 	    drv_usecwait(cs_rc1_delay * 1000);
67740Sstevel@tonic-gate 
67750Sstevel@tonic-gate 	/*
67760Sstevel@tonic-gate 	 * Set the socket to the parameters that the client requested.
67770Sstevel@tonic-gate 	 */
67780Sstevel@tonic-gate 	if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
67790Sstevel@tonic-gate 	    if (client->present & CONFIG_OPTION_REG_PRESENT) {
67800Sstevel@tonic-gate 		crt->cor = 0; /* XXX is 0 the right thing here? */
67810Sstevel@tonic-gate 		csx_Put8(cis_handle, crt->cor_p, crt->cor);
67820Sstevel@tonic-gate 	    }
67830Sstevel@tonic-gate 	    sp->flags &= ~SOCKET_IS_IO;
67840Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
67850Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
67860Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
67870Sstevel@tonic-gate 	}
67880Sstevel@tonic-gate 
67890Sstevel@tonic-gate 	if (cs_rc2_delay)
67900Sstevel@tonic-gate 	    drv_usecwait(cs_rc2_delay * 1000);
67910Sstevel@tonic-gate 
67920Sstevel@tonic-gate 	/*
67930Sstevel@tonic-gate 	 * Mark this client as having done a successful RequestConfiguration
67940Sstevel@tonic-gate 	 *	call.
67950Sstevel@tonic-gate 	 */
67960Sstevel@tonic-gate 	client->flags |= REQ_CONFIGURATION_DONE;
67970Sstevel@tonic-gate 
67980Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
67990Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
68000Sstevel@tonic-gate 
68010Sstevel@tonic-gate 	return (CS_SUCCESS);
68020Sstevel@tonic-gate }
68030Sstevel@tonic-gate 
68040Sstevel@tonic-gate /*
68050Sstevel@tonic-gate  * cs_release_configuration - releases configuration previously set via the
68060Sstevel@tonic-gate  *		RequestConfiguration call; this is ReleaseConfiguration
68070Sstevel@tonic-gate  *
68080Sstevel@tonic-gate  *	returns: CS_SUCCESS - if configuration sucessfully released
68090Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
68100Sstevel@tonic-gate  *		 CS_BAD_SOCKET - if Socket Services returns an error
68110Sstevel@tonic-gate  *		 CS_BAD_HANDLE - a RequestConfiguration has not been done
68120Sstevel@tonic-gate  */
68130Sstevel@tonic-gate /*ARGSUSED*/
68140Sstevel@tonic-gate static int
68150Sstevel@tonic-gate cs_release_configuration(client_handle_t client_handle, release_config_t *rcfg)
68160Sstevel@tonic-gate {
68170Sstevel@tonic-gate 	cs_socket_t *sp;
68180Sstevel@tonic-gate 	client_t *client;
68190Sstevel@tonic-gate 	volatile config_regs_t *crt;
68200Sstevel@tonic-gate 	set_socket_t set_socket;
68210Sstevel@tonic-gate 	get_socket_t get_socket;
68220Sstevel@tonic-gate 	acc_handle_t cis_handle;
68230Sstevel@tonic-gate 	int error;
68240Sstevel@tonic-gate 	uint32_t newoffset;
68250Sstevel@tonic-gate 	int client_lock_acquired;
68260Sstevel@tonic-gate 
68270Sstevel@tonic-gate 	/*
68280Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
68290Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
68300Sstevel@tonic-gate 	 */
68310Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
68320Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
68330Sstevel@tonic-gate 
68340Sstevel@tonic-gate 	/*
68350Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
68360Sstevel@tonic-gate 	 */
68370Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
68380Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
68390Sstevel@tonic-gate 
68400Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
68410Sstevel@tonic-gate 
68420Sstevel@tonic-gate 	/*
68430Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
68440Sstevel@tonic-gate 	 */
68450Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
68460Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
68470Sstevel@tonic-gate 	    return (error);
68480Sstevel@tonic-gate 	}
68490Sstevel@tonic-gate 
68500Sstevel@tonic-gate 	/*
68510Sstevel@tonic-gate 	 * If RequestConfiguration has not been done, we don't allow
68520Sstevel@tonic-gate 	 *	this call.
68530Sstevel@tonic-gate 	 */
68540Sstevel@tonic-gate 	if (!(client->flags & REQ_CONFIGURATION_DONE)) {
68550Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
68560Sstevel@tonic-gate 	    return (CS_BAD_HANDLE);
68570Sstevel@tonic-gate 	}
68580Sstevel@tonic-gate 
68590Sstevel@tonic-gate #ifdef  CS_DEBUG
68600Sstevel@tonic-gate 	if (cs_debug > 0)
68610Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_release_configuration: "
68620Sstevel@tonic-gate 		    "flags=0x%x CW_MULTI_FUNCTION_CIS =0x%x \n",
68630Sstevel@tonic-gate 		    sp->cis_flags, CW_MULTI_FUNCTION_CIS);
68640Sstevel@tonic-gate 
68650Sstevel@tonic-gate #endif
68660Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
68670Sstevel@tonic-gate 
68680Sstevel@tonic-gate 	/*
68690Sstevel@tonic-gate 	 * Set the card back to a memory-only interface byte writing a zero
68700Sstevel@tonic-gate 	 *	to the COR.  Note that we don't update our soft copy of the
68710Sstevel@tonic-gate 	 *	COR state since the PCMCIA spec only requires us to maintain
68720Sstevel@tonic-gate 	 *	the last value that was written to that register during a
68730Sstevel@tonic-gate 	 *	call to RequestConfiguration.
68740Sstevel@tonic-gate 	 */
68750Sstevel@tonic-gate 	crt = &client->config_regs;
68760Sstevel@tonic-gate 
68770Sstevel@tonic-gate 	newoffset = client->config_regs_offset;
68780Sstevel@tonic-gate 	if (cs_init_cis_window(sp, &newoffset, &cis_handle,
68790Sstevel@tonic-gate 					CISTPLF_AM_SPACE) != CS_SUCCESS) {
68800Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
68810Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
68820Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_release_configuration: socket %d can't init "
68830Sstevel@tonic-gate 				"CIS window\n", sp->socket_num);
68840Sstevel@tonic-gate 	    return (CS_GENERAL_FAILURE);
68850Sstevel@tonic-gate 	}
68860Sstevel@tonic-gate 
68870Sstevel@tonic-gate 	if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
68880Sstevel@tonic-gate 		/*
68890Sstevel@tonic-gate 		 * For the Multifunction cards do not reset the socket
68900Sstevel@tonic-gate 		 * to a memory only interface but do clear the
68910Sstevel@tonic-gate 		 * Configuration Option Register and  mark this client
68920Sstevel@tonic-gate 		 * as not having a configuration by clearing the
68930Sstevel@tonic-gate 		 * REQ_CONFIGURATION_DONE flag.
68940Sstevel@tonic-gate 		 */
68950Sstevel@tonic-gate 		client->flags &= ~REQ_CONFIGURATION_DONE;
68960Sstevel@tonic-gate 		csx_Put8(cis_handle, crt->cor_p, 0);
68970Sstevel@tonic-gate 
68980Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
68990Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
69000Sstevel@tonic-gate 		return (CS_SUCCESS);
69010Sstevel@tonic-gate 	}
69020Sstevel@tonic-gate 
69030Sstevel@tonic-gate 	/*
69040Sstevel@tonic-gate 	 * Set the socket back to a memory-only interface; don't change
69050Sstevel@tonic-gate 	 *	any other parameter of the socket.
69060Sstevel@tonic-gate 	 */
69070Sstevel@tonic-gate 	get_socket.socket = sp->socket_num;
69080Sstevel@tonic-gate 
69090Sstevel@tonic-gate 	if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
69100Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
69110Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
69120Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
69130Sstevel@tonic-gate 	}
69140Sstevel@tonic-gate 
69150Sstevel@tonic-gate 	mutex_enter(&sp->lock);
69160Sstevel@tonic-gate 	sp->flags &= ~SOCKET_IS_IO;
69170Sstevel@tonic-gate 	set_socket.SCIntMask = cs_merge_event_masks(sp, client);
69180Sstevel@tonic-gate 	mutex_exit(&sp->lock);
69190Sstevel@tonic-gate 
69200Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
69210Sstevel@tonic-gate 	set_socket.IREQRouting = 0;
69220Sstevel@tonic-gate 	set_socket.CtlInd = get_socket.CtlInd;
69230Sstevel@tonic-gate 	set_socket.State = 0;	/* don't reset latched values */
69240Sstevel@tonic-gate 	set_socket.VccLevel = get_socket.VccLevel;
69250Sstevel@tonic-gate 	set_socket.Vpp1Level = get_socket.Vpp1Level;
69260Sstevel@tonic-gate 	set_socket.Vpp2Level = get_socket.Vpp2Level;
69270Sstevel@tonic-gate 	set_socket.IFType = IF_MEMORY;
69280Sstevel@tonic-gate 
69290Sstevel@tonic-gate 	if (client->present & CONFIG_OPTION_REG_PRESENT)
69300Sstevel@tonic-gate 	    csx_Put8(cis_handle, crt->cor_p, 0);
69310Sstevel@tonic-gate 
69320Sstevel@tonic-gate 	if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
69330Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
69340Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
69350Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
69360Sstevel@tonic-gate 	}
69370Sstevel@tonic-gate 
69380Sstevel@tonic-gate 	/*
69390Sstevel@tonic-gate 	 * Mark this client as not having a configuration.
69400Sstevel@tonic-gate 	 */
69410Sstevel@tonic-gate 	client->flags &= ~REQ_CONFIGURATION_DONE;
69420Sstevel@tonic-gate 
69430Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
69440Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
69450Sstevel@tonic-gate 
69460Sstevel@tonic-gate 	return (CS_SUCCESS);
69470Sstevel@tonic-gate }
69480Sstevel@tonic-gate 
69490Sstevel@tonic-gate /*
69500Sstevel@tonic-gate  * cs_modify_configuration - modifies a configuration established by
69510Sstevel@tonic-gate  *		RequestConfiguration; this is ModifyConfiguration
69520Sstevel@tonic-gate  *
69530Sstevel@tonic-gate  *	returns: CS_SUCCESS - if configuration sucessfully modified
69540Sstevel@tonic-gate  *		 CS_BAD_SOCKET - if Socket Services returns an error
69550Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
69560Sstevel@tonic-gate  *		 CS_BAD_HANDLE - a RequestConfiguration has not been done
69570Sstevel@tonic-gate  *		 CS_NO_CARD - if no card in socket
69580Sstevel@tonic-gate  *		 CS_BAD_ATTRIBUTE - if any unsupported or reserved flags
69590Sstevel@tonic-gate  *					are set
69600Sstevel@tonic-gate  *		 CS_BAD_VCC - if Vcc value is not supported by socket
69610Sstevel@tonic-gate  *		 CS_BAD_VPP1 - if Vpp1 value is not supported by socket
69620Sstevel@tonic-gate  *		 CS_BAD_VPP2 - if Vpp2 value is not supported by socket
69630Sstevel@tonic-gate  */
69640Sstevel@tonic-gate static int
69650Sstevel@tonic-gate cs_modify_configuration(client_handle_t client_handle, modify_config_t *mc)
69660Sstevel@tonic-gate {
69670Sstevel@tonic-gate 	cs_socket_t *sp;
69680Sstevel@tonic-gate 	client_t *client;
69690Sstevel@tonic-gate 	set_socket_t set_socket;
69700Sstevel@tonic-gate 	get_socket_t get_socket;
69710Sstevel@tonic-gate 	int error;
69720Sstevel@tonic-gate 	int client_lock_acquired;
69730Sstevel@tonic-gate 
69740Sstevel@tonic-gate 	/*
69750Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
69760Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
69770Sstevel@tonic-gate 	 */
69780Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
69790Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
69800Sstevel@tonic-gate 
69810Sstevel@tonic-gate 	/*
69820Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
69830Sstevel@tonic-gate 	 */
69840Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
69850Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
69860Sstevel@tonic-gate 
69870Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
69880Sstevel@tonic-gate 
69890Sstevel@tonic-gate 	/*
69900Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
69910Sstevel@tonic-gate 	 */
69920Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
69930Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
69940Sstevel@tonic-gate 	    return (error);
69950Sstevel@tonic-gate 	}
69960Sstevel@tonic-gate 
69970Sstevel@tonic-gate 	/*
69980Sstevel@tonic-gate 	 * If RequestConfiguration has not been done, we don't allow
69990Sstevel@tonic-gate 	 *	this call.
70000Sstevel@tonic-gate 	 */
70010Sstevel@tonic-gate 	if (!(client->flags & REQ_CONFIGURATION_DONE)) {
70020Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
70030Sstevel@tonic-gate 	    return (CS_BAD_HANDLE);
70040Sstevel@tonic-gate 	}
70050Sstevel@tonic-gate 
70060Sstevel@tonic-gate 	/*
70070Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
70080Sstevel@tonic-gate 	 *	for this client, then return an error.
70090Sstevel@tonic-gate 	 */
70100Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
70110Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
70120Sstevel@tonic-gate 	    return (CS_NO_CARD);
70130Sstevel@tonic-gate 	}
70140Sstevel@tonic-gate 
70150Sstevel@tonic-gate 	/*
70160Sstevel@tonic-gate 	 * Get the current socket parameters so that we can modify them.
70170Sstevel@tonic-gate 	 */
70180Sstevel@tonic-gate 	get_socket.socket = sp->socket_num;
70190Sstevel@tonic-gate 
70200Sstevel@tonic-gate 	if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
70210Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
70220Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
70230Sstevel@tonic-gate 	}
70240Sstevel@tonic-gate 
70250Sstevel@tonic-gate #ifdef	CS_DEBUG
70260Sstevel@tonic-gate 	if (cs_debug > 0)
70270Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_modify_configuration: socket %d "
70280Sstevel@tonic-gate 				"client->irq_alloc.irq 0x%x "
70290Sstevel@tonic-gate 				"get_socket.IRQRouting 0x%x\n",
70300Sstevel@tonic-gate 				sp->socket_num, (int)client->irq_alloc.irq,
70310Sstevel@tonic-gate 				get_socket.IRQRouting);
70320Sstevel@tonic-gate #endif
70330Sstevel@tonic-gate 
70340Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
70350Sstevel@tonic-gate 	set_socket.SCIntMask = get_socket.SCIntMask;
70360Sstevel@tonic-gate 	set_socket.CtlInd = get_socket.CtlInd;
70370Sstevel@tonic-gate 	set_socket.State = 0;	/* don't reset latched values */
70380Sstevel@tonic-gate 	set_socket.IFType = get_socket.IFType;
70390Sstevel@tonic-gate 
70400Sstevel@tonic-gate 	set_socket.IREQRouting = get_socket.IRQRouting;
70410Sstevel@tonic-gate 
70420Sstevel@tonic-gate 	/*
70430Sstevel@tonic-gate 	 * Modify the IRQ routing if the client wants it modified.
70440Sstevel@tonic-gate 	 */
70450Sstevel@tonic-gate 	if (mc->Attributes & CONF_IRQ_CHANGE_VALID) {
70460Sstevel@tonic-gate 	    set_socket.IREQRouting &= ~IRQ_ENABLE;
70470Sstevel@tonic-gate 
70480Sstevel@tonic-gate 	    if ((sp->cis_flags & CW_MULTI_FUNCTION_CIS) &&
70490Sstevel@tonic-gate 			(client->present & CONFIG_OPTION_REG_PRESENT)) {
70500Sstevel@tonic-gate 		config_regs_t *crt = &client->config_regs;
70510Sstevel@tonic-gate 		acc_handle_t cis_handle;
70520Sstevel@tonic-gate 		uint32_t newoffset = client->config_regs_offset;
70530Sstevel@tonic-gate 
70540Sstevel@tonic-gate 		/*
70550Sstevel@tonic-gate 		 * Get a pointer to a window that contains the configuration
70560Sstevel@tonic-gate 		 *	registers.
70570Sstevel@tonic-gate 		 */
70580Sstevel@tonic-gate 		if (cs_init_cis_window(sp, &newoffset, &cis_handle,
70590Sstevel@tonic-gate 					CISTPLF_AM_SPACE) != CS_SUCCESS) {
70600Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
70610Sstevel@tonic-gate 		    cmn_err(CE_CONT,
70620Sstevel@tonic-gate 			"cs_modify_configuration: socket %d can't init "
70630Sstevel@tonic-gate 			"CIS window\n", sp->socket_num);
70640Sstevel@tonic-gate 		    return (CS_GENERAL_FAILURE);
70650Sstevel@tonic-gate 		} /* cs_init_cis_window */
70660Sstevel@tonic-gate 
70670Sstevel@tonic-gate 		crt->cor &= ~COR_ENABLE_IREQ_ROUTING;
70680Sstevel@tonic-gate 
70690Sstevel@tonic-gate 		if (mc->Attributes & CONF_ENABLE_IRQ_STEERING)
70700Sstevel@tonic-gate 		    crt->cor |= COR_ENABLE_IREQ_ROUTING;
70710Sstevel@tonic-gate 
70720Sstevel@tonic-gate #ifdef  CS_DEBUG
70730Sstevel@tonic-gate 		if (cs_debug > 0)
70740Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_modify_configuration:"
70750Sstevel@tonic-gate 			    " cor_p=0x%x cor=0x%x\n",
70760Sstevel@tonic-gate 			    crt->cor_p, crt->cor);
70770Sstevel@tonic-gate #endif
70780Sstevel@tonic-gate 		csx_Put8(cis_handle, crt->cor_p, crt->cor);
70790Sstevel@tonic-gate 
70800Sstevel@tonic-gate 	    } /* CW_MULTI_FUNCTION_CIS */
70810Sstevel@tonic-gate 
70820Sstevel@tonic-gate 	    if (mc->Attributes & CONF_ENABLE_IRQ_STEERING)
70830Sstevel@tonic-gate 		set_socket.IREQRouting |= IRQ_ENABLE;
70840Sstevel@tonic-gate 
70850Sstevel@tonic-gate 	} /* CONF_IRQ_CHANGE_VALID */
70860Sstevel@tonic-gate 
70870Sstevel@tonic-gate 	/*
70880Sstevel@tonic-gate 	 * Modify the voltage levels that the client specifies.
70890Sstevel@tonic-gate 	 */
70900Sstevel@tonic-gate 	set_socket.VccLevel = get_socket.VccLevel;
70910Sstevel@tonic-gate 
70920Sstevel@tonic-gate 	if (mc->Attributes & CONF_VPP1_CHANGE_VALID) {
70930Sstevel@tonic-gate 	    if (cs_convert_powerlevel(sp->socket_num, mc->Vpp1, VPP1,
70940Sstevel@tonic-gate 					&set_socket.Vpp1Level) != CS_SUCCESS) {
70950Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
70960Sstevel@tonic-gate 		return (CS_BAD_VPP);
70970Sstevel@tonic-gate 	    }
70980Sstevel@tonic-gate 	} else {
70990Sstevel@tonic-gate 	    set_socket.Vpp1Level = get_socket.Vpp1Level;
71000Sstevel@tonic-gate 	}
71010Sstevel@tonic-gate 
71020Sstevel@tonic-gate 	if (mc->Attributes & CONF_VPP2_CHANGE_VALID) {
71030Sstevel@tonic-gate 	    if (cs_convert_powerlevel(sp->socket_num, mc->Vpp2, VPP2,
71040Sstevel@tonic-gate 					&set_socket.Vpp2Level) != CS_SUCCESS) {
71050Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
71060Sstevel@tonic-gate 		return (CS_BAD_VPP);
71070Sstevel@tonic-gate 	    }
71080Sstevel@tonic-gate 	} else {
71090Sstevel@tonic-gate 	    set_socket.Vpp2Level = get_socket.Vpp2Level;
71100Sstevel@tonic-gate 	}
71110Sstevel@tonic-gate 
71120Sstevel@tonic-gate 	/*
71130Sstevel@tonic-gate 	 * Setup the modified socket configuration.
71140Sstevel@tonic-gate 	 */
71150Sstevel@tonic-gate 	if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
71160Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
71170Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
71180Sstevel@tonic-gate 	}
71190Sstevel@tonic-gate 
71200Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
71210Sstevel@tonic-gate 	return (CS_SUCCESS);
71220Sstevel@tonic-gate }
71230Sstevel@tonic-gate 
71240Sstevel@tonic-gate /*
71250Sstevel@tonic-gate  * cs_access_configuration_register - provides a client access to the card's
71260Sstevel@tonic-gate  *		configuration registers; this is AccessConfigurationRegister
71270Sstevel@tonic-gate  *
71280Sstevel@tonic-gate  *	returns: CS_SUCCESS - if register accessed successfully
71290Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
71300Sstevel@tonic-gate  *		 CS_BAD_ARGS - if arguments are out of range
71310Sstevel@tonic-gate  *		 CS_NO_CARD - if no card in socket
71320Sstevel@tonic-gate  *		 CS_BAD_BASE - if no config registers base address
71330Sstevel@tonic-gate  *		 CS_UNSUPPORTED_MODE - if no RequestConfiguration has
71340Sstevel@tonic-gate  *				been done yet
71350Sstevel@tonic-gate  */
71360Sstevel@tonic-gate static int
71370Sstevel@tonic-gate cs_access_configuration_register(client_handle_t client_handle,
71380Sstevel@tonic-gate 						access_config_reg_t *acr)
71390Sstevel@tonic-gate {
71400Sstevel@tonic-gate 	cs_socket_t *sp;
71410Sstevel@tonic-gate 	client_t *client;
71420Sstevel@tonic-gate 	acc_handle_t cis_handle;
71430Sstevel@tonic-gate 	int error;
71440Sstevel@tonic-gate 	uint32_t newoffset;
71450Sstevel@tonic-gate 	int client_lock_acquired;
71460Sstevel@tonic-gate 
71470Sstevel@tonic-gate 	/*
71480Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
71490Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
71500Sstevel@tonic-gate 	 */
71510Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
71520Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
71530Sstevel@tonic-gate 
71540Sstevel@tonic-gate 	/*
71550Sstevel@tonic-gate 	 * Make sure that the specifed offset is in range.
71560Sstevel@tonic-gate 	 */
71570Sstevel@tonic-gate 	if (acr->Offset > ((CISTPL_CONFIG_MAX_CONFIG_REGS * 2) - 2))
71580Sstevel@tonic-gate 	    return (CS_BAD_ARGS);
71590Sstevel@tonic-gate 
71600Sstevel@tonic-gate 	/*
71610Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
71620Sstevel@tonic-gate 	 */
71630Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
71640Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
71650Sstevel@tonic-gate 
71660Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
71670Sstevel@tonic-gate 
71680Sstevel@tonic-gate 	/*
71690Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
71700Sstevel@tonic-gate 	 */
71710Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
71720Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
71730Sstevel@tonic-gate 	    return (error);
71740Sstevel@tonic-gate 	}
71750Sstevel@tonic-gate 
71760Sstevel@tonic-gate 	/*
71770Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
71780Sstevel@tonic-gate 	 *	for this client, then return an error.
71790Sstevel@tonic-gate 	 */
71800Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
71810Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
71820Sstevel@tonic-gate 	    return (CS_NO_CARD);
71830Sstevel@tonic-gate 	}
71840Sstevel@tonic-gate 
71850Sstevel@tonic-gate 	/*
71860Sstevel@tonic-gate 	 * If RequestConfiguration has not been done, we don't allow
71870Sstevel@tonic-gate 	 *	this call.
71880Sstevel@tonic-gate 	 */
71890Sstevel@tonic-gate 	if (!(client->flags & REQ_CONFIGURATION_DONE)) {
71900Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
71910Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_MODE);
71920Sstevel@tonic-gate 	}
71930Sstevel@tonic-gate 
71940Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
71950Sstevel@tonic-gate 
71960Sstevel@tonic-gate 	/*
71970Sstevel@tonic-gate 	 * Get a pointer to the CIS window
71980Sstevel@tonic-gate 	 */
71990Sstevel@tonic-gate 	newoffset = client->config_regs_offset + acr->Offset;
72000Sstevel@tonic-gate 	if (cs_init_cis_window(sp, &newoffset, &cis_handle,
72010Sstevel@tonic-gate 					CISTPLF_AM_SPACE) != CS_SUCCESS) {
72020Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
72030Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
72040Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_ACR: socket %d can't init CIS window\n",
72050Sstevel@tonic-gate 							sp->socket_num);
72060Sstevel@tonic-gate 	    return (CS_GENERAL_FAILURE);
72070Sstevel@tonic-gate 	}
72080Sstevel@tonic-gate 
72090Sstevel@tonic-gate 	/*
72100Sstevel@tonic-gate 	 * Create the address for the config register that the client
72110Sstevel@tonic-gate 	 *	wants to access.
72120Sstevel@tonic-gate 	 */
72130Sstevel@tonic-gate 	mutex_enter(&sp->lock);
72140Sstevel@tonic-gate 
72150Sstevel@tonic-gate #ifdef	CS_DEBUG
72160Sstevel@tonic-gate 	if (cs_debug > 1) {
72170Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_ACR: config_regs_offset 0x%x "
72180Sstevel@tonic-gate 		"Offset 0x%x newoffset 0x%x\n",
72190Sstevel@tonic-gate 		(int)client->config_regs_offset,
72200Sstevel@tonic-gate 		(int)acr->Offset, newoffset);
72210Sstevel@tonic-gate 	}
72220Sstevel@tonic-gate #endif
72230Sstevel@tonic-gate 
72240Sstevel@tonic-gate 	/*
72250Sstevel@tonic-gate 	 * Determine what the client wants us to do.  The client is
72260Sstevel@tonic-gate 	 *	allowed to specify any valid offset, even if it would
72270Sstevel@tonic-gate 	 *	cause an unimplemented configuration register to be
72280Sstevel@tonic-gate 	 *	accessed.
72290Sstevel@tonic-gate 	 */
72300Sstevel@tonic-gate 	error = CS_SUCCESS;
72310Sstevel@tonic-gate 	switch (acr->Action) {
72320Sstevel@tonic-gate 	    case CONFIG_REG_READ:
72330Sstevel@tonic-gate 		acr->Value = csx_Get8(cis_handle, newoffset);
72340Sstevel@tonic-gate 		break;
72350Sstevel@tonic-gate 	    case CONFIG_REG_WRITE:
72360Sstevel@tonic-gate 		csx_Put8(cis_handle, newoffset, acr->Value);
72370Sstevel@tonic-gate 		break;
72380Sstevel@tonic-gate 	    default:
72390Sstevel@tonic-gate 		error = CS_BAD_ARGS;
72400Sstevel@tonic-gate 		break;
72410Sstevel@tonic-gate 	} /* switch */
72420Sstevel@tonic-gate 
72430Sstevel@tonic-gate 	mutex_exit(&sp->lock);
72440Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
72450Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
72460Sstevel@tonic-gate 
72470Sstevel@tonic-gate 	return (error);
72480Sstevel@tonic-gate }
72490Sstevel@tonic-gate 
72500Sstevel@tonic-gate /*
72510Sstevel@tonic-gate  * ==== RESET and general info functions ====
72520Sstevel@tonic-gate  */
72530Sstevel@tonic-gate 
72540Sstevel@tonic-gate /*
72550Sstevel@tonic-gate  * cs_reset_function - RESET the requested function on the card; this
72560Sstevel@tonic-gate  *			is ResetFunction
72570Sstevel@tonic-gate  *
72580Sstevel@tonic-gate  *    Note: We don't support this functionality yet, and the standard
72590Sstevel@tonic-gate  *		says it's OK to reutrn CS_IN_USE if we can't do this
72600Sstevel@tonic-gate  *		operation.
72610Sstevel@tonic-gate  */
72620Sstevel@tonic-gate /*ARGSUSED*/
72630Sstevel@tonic-gate static int
72640Sstevel@tonic-gate cs_reset_function(client_handle_t ch, reset_function_t *rf)
72650Sstevel@tonic-gate {
72660Sstevel@tonic-gate 	return (CS_IN_USE);
72670Sstevel@tonic-gate }
72680Sstevel@tonic-gate 
72690Sstevel@tonic-gate /*
72700Sstevel@tonic-gate  * cs_get_configuration_info - return configuration info for the passed
72710Sstevel@tonic-gate  *				socket and function number to the caller;
72720Sstevel@tonic-gate  *				this is GetConfigurationInfo
72730Sstevel@tonic-gate  */
72740Sstevel@tonic-gate /*ARGSUSED*/
72750Sstevel@tonic-gate static int
72760Sstevel@tonic-gate cs_get_configuration_info(client_handle_t *chp, get_configuration_info_t *gci)
72770Sstevel@tonic-gate {
72780Sstevel@tonic-gate 	cs_socket_t *sp;
72790Sstevel@tonic-gate 	uint32_t fn;
72800Sstevel@tonic-gate 	client_t *client;
72810Sstevel@tonic-gate 	int client_lock_acquired;
72820Sstevel@tonic-gate 
72830Sstevel@tonic-gate 	/*
72840Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
72850Sstevel@tonic-gate 	 */
72860Sstevel@tonic-gate 	if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(gci->Socket))) == NULL)
72870Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
72880Sstevel@tonic-gate 
72890Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
72900Sstevel@tonic-gate 	mutex_enter(&sp->lock);
72910Sstevel@tonic-gate 
72920Sstevel@tonic-gate 	fn = CS_GET_FUNCTION_NUMBER(gci->Socket);
72930Sstevel@tonic-gate 
72940Sstevel@tonic-gate 	client = sp->client_list;
72950Sstevel@tonic-gate 	while (client) {
72960Sstevel@tonic-gate 
72970Sstevel@tonic-gate 	    if (GET_CLIENT_FUNCTION(client->client_handle) == fn) {
72980Sstevel@tonic-gate 
72990Sstevel@tonic-gate 		/*
73000Sstevel@tonic-gate 		 * If there's no card in the socket or the card in the
73010Sstevel@tonic-gate 		 *	socket is not for this client, then return
73020Sstevel@tonic-gate 		 *	an error.
73030Sstevel@tonic-gate 		 */
73040Sstevel@tonic-gate 		if (!(client->flags & CLIENT_CARD_INSERTED)) {
73050Sstevel@tonic-gate 		    mutex_exit(&sp->lock);
73060Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
73070Sstevel@tonic-gate 		    return (CS_NO_CARD);
73080Sstevel@tonic-gate 		}
73090Sstevel@tonic-gate 
73100Sstevel@tonic-gate 		mutex_exit(&sp->lock);
73110Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
73120Sstevel@tonic-gate 		return (CS_SUCCESS);
73130Sstevel@tonic-gate 
73140Sstevel@tonic-gate 	    } /* GET_CLIENT_FUNCTION == fn */
73150Sstevel@tonic-gate 
73160Sstevel@tonic-gate 	    client = client->next;
73170Sstevel@tonic-gate 	} /* while (client) */
73180Sstevel@tonic-gate 
73190Sstevel@tonic-gate 	mutex_exit(&sp->lock);
73200Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
73210Sstevel@tonic-gate 
73220Sstevel@tonic-gate 	return (CS_BAD_SOCKET);
73230Sstevel@tonic-gate }
73240Sstevel@tonic-gate 
73250Sstevel@tonic-gate /*
73260Sstevel@tonic-gate  * cs_get_cardservices_info - return info about Card Services to the
73270Sstevel@tonic-gate  *	caller; this is GetCardServicesInfo
73280Sstevel@tonic-gate  */
73290Sstevel@tonic-gate /*ARGSUSED*/
73300Sstevel@tonic-gate static int
73310Sstevel@tonic-gate cs_get_cardservices_info(client_handle_t ch, get_cardservices_info_t *gcsi)
73320Sstevel@tonic-gate {
73330Sstevel@tonic-gate 	gcsi->Signature[0] = 'C';
73340Sstevel@tonic-gate 	gcsi->Signature[1] = 'S';
73350Sstevel@tonic-gate 	gcsi->NumSockets = cs_globals.num_sockets;
73360Sstevel@tonic-gate 	gcsi->Revision = CS_INTERNAL_REVISION_LEVEL;
73370Sstevel@tonic-gate 	gcsi->CSLevel = CS_VERSION;
73380Sstevel@tonic-gate 	gcsi->FuncsPerSocket = CIS_MAX_FUNCTIONS;
73390Sstevel@tonic-gate 	(void) strncpy(gcsi->VendorString,
73400Sstevel@tonic-gate 					CS_GET_CARDSERVICES_INFO_VENDOR_STRING,
73410Sstevel@tonic-gate 					CS_GET_CARDSERVICES_INFO_MAX_VS_LEN);
73420Sstevel@tonic-gate 
73430Sstevel@tonic-gate 	return (CS_SUCCESS);
73440Sstevel@tonic-gate }
73450Sstevel@tonic-gate 
73460Sstevel@tonic-gate /*
73470Sstevel@tonic-gate  * cs_get_physical_adapter_info - returns information about the requested
73480Sstevel@tonic-gate  *					physical adapter; this is
73490Sstevel@tonic-gate  *					GetPhysicalAdapterInfo
73500Sstevel@tonic-gate  *
73510Sstevel@tonic-gate  *	calling: client_handle_t:
73520Sstevel@tonic-gate  *			NULL - use map_log_socket_t->LogSocket member
73530Sstevel@tonic-gate  *				to specify logical socket number
73540Sstevel@tonic-gate  *			!NULL - extract logical socket number from
73550Sstevel@tonic-gate  *				client_handle_t
73560Sstevel@tonic-gate  *
73570Sstevel@tonic-gate  *	returns: CS_SUCCESS
73580Sstevel@tonic-gate  *		 CS_BAD_SOCKET - if client_handle_t is NULL and invalid
73590Sstevel@tonic-gate  *					socket number is specified in
73600Sstevel@tonic-gate  *					map_log_socket_t->LogSocket
73610Sstevel@tonic-gate  *		 CS_BAD_HANDLE - if client_handle_t is !NULL and invalid
73620Sstevel@tonic-gate  *					client handle is specified
73630Sstevel@tonic-gate  */
73640Sstevel@tonic-gate static int
73650Sstevel@tonic-gate cs_get_physical_adapter_info(client_handle_t ch,
73660Sstevel@tonic-gate 					get_physical_adapter_info_t *gpai)
73670Sstevel@tonic-gate {
73680Sstevel@tonic-gate 	cs_socket_t *sp;
73690Sstevel@tonic-gate 	int client_lock_acquired;
73700Sstevel@tonic-gate 
73710Sstevel@tonic-gate 	if (ch == NULL)
73720Sstevel@tonic-gate 	    gpai->PhySocket = CS_GET_SOCKET_NUMBER(gpai->LogSocket);
73730Sstevel@tonic-gate 	else
73740Sstevel@tonic-gate 	    gpai->PhySocket = GET_CLIENT_SOCKET(ch);
73750Sstevel@tonic-gate 
73760Sstevel@tonic-gate 	/*
73770Sstevel@tonic-gate 	 * Determine if the passed socket number is valid or not.
73780Sstevel@tonic-gate 	 */
73790Sstevel@tonic-gate 	if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(gpai->PhySocket))) == NULL)
73800Sstevel@tonic-gate 	    return ((ch == NULL) ? CS_BAD_SOCKET : CS_BAD_HANDLE);
73810Sstevel@tonic-gate 
73820Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
73830Sstevel@tonic-gate 
73840Sstevel@tonic-gate 	/*
73850Sstevel@tonic-gate 	 * If we were passed a client handle, determine if it's valid or not.
73860Sstevel@tonic-gate 	 */
73870Sstevel@tonic-gate 	if (ch != NULL) {
73880Sstevel@tonic-gate 	    if (cs_find_client(ch, NULL) == NULL) {
73890Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
73900Sstevel@tonic-gate 		return (CS_BAD_HANDLE);
73910Sstevel@tonic-gate 	    } /* cs_find_client */
73920Sstevel@tonic-gate 	} /* ch != NULL */
73930Sstevel@tonic-gate 
73940Sstevel@tonic-gate 	gpai->flags = sp->adapter.flags;
73950Sstevel@tonic-gate 	(void) strcpy(gpai->name, sp->adapter.name);
73960Sstevel@tonic-gate 	gpai->major = sp->adapter.major;
73970Sstevel@tonic-gate 	gpai->minor = sp->adapter.minor;
73980Sstevel@tonic-gate 	gpai->instance = sp->adapter.instance;
73990Sstevel@tonic-gate 	gpai->number = sp->adapter.number;
74000Sstevel@tonic-gate 	gpai->num_sockets = sp->adapter.num_sockets;
74010Sstevel@tonic-gate 	gpai->first_socket = sp->adapter.first_socket;
74020Sstevel@tonic-gate 
74030Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
74040Sstevel@tonic-gate 
74050Sstevel@tonic-gate 	return (CS_SUCCESS);
74060Sstevel@tonic-gate }
74070Sstevel@tonic-gate 
74080Sstevel@tonic-gate /*
74090Sstevel@tonic-gate  * ==== general functions ====
74100Sstevel@tonic-gate  */
74110Sstevel@tonic-gate 
74120Sstevel@tonic-gate /*
74130Sstevel@tonic-gate  * cs_map_log_socket - returns the physical socket number associated with
74140Sstevel@tonic-gate  *			either the passed client handle or the passed
74150Sstevel@tonic-gate  *			logical socket number; this is MapLogSocket
74160Sstevel@tonic-gate  *
74170Sstevel@tonic-gate  *	calling: client_handle_t:
74180Sstevel@tonic-gate  *			NULL - use map_log_socket_t->LogSocket member
74190Sstevel@tonic-gate  *				to specify logical socket number
74200Sstevel@tonic-gate  *			!NULL - extract logical socket number from
74210Sstevel@tonic-gate  *				client_handle_t
74220Sstevel@tonic-gate  *
74230Sstevel@tonic-gate  *	returns: CS_SUCCESS
74240Sstevel@tonic-gate  *		 CS_BAD_SOCKET - if client_handle_t is NULL and invalid
74250Sstevel@tonic-gate  *					socket number is specified in
74260Sstevel@tonic-gate  *					map_log_socket_t->LogSocket
74270Sstevel@tonic-gate  *		 CS_BAD_HANDLE - if client_handle_t is !NULL and invalid
74280Sstevel@tonic-gate  *					client handle is specified
74290Sstevel@tonic-gate  *
74300Sstevel@tonic-gate  * Note: We provide this function since the instance number of a client
74310Sstevel@tonic-gate  *		driver doesn't necessary correspond to the physical
74320Sstevel@tonic-gate  *		socket number
74330Sstevel@tonic-gate  */
74340Sstevel@tonic-gate static int
74350Sstevel@tonic-gate cs_map_log_socket(client_handle_t ch, map_log_socket_t *mls)
74360Sstevel@tonic-gate {
74370Sstevel@tonic-gate 	cs_socket_t *sp;
74380Sstevel@tonic-gate 	int client_lock_acquired;
74390Sstevel@tonic-gate 
74400Sstevel@tonic-gate 	if (ch == NULL)
74410Sstevel@tonic-gate 	    mls->PhySocket = CS_GET_SOCKET_NUMBER(mls->LogSocket);
74420Sstevel@tonic-gate 	else
74430Sstevel@tonic-gate 	    mls->PhySocket = GET_CLIENT_SOCKET(ch);
74440Sstevel@tonic-gate 
74450Sstevel@tonic-gate 	/*
74460Sstevel@tonic-gate 	 * Determine if the passed socket number is valid or not.
74470Sstevel@tonic-gate 	 */
74480Sstevel@tonic-gate 	if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(mls->PhySocket))) == NULL)
74490Sstevel@tonic-gate 	    return ((ch == NULL) ? CS_BAD_SOCKET : CS_BAD_HANDLE);
74500Sstevel@tonic-gate 
74510Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
74520Sstevel@tonic-gate 
74530Sstevel@tonic-gate 	/*
74540Sstevel@tonic-gate 	 * If we were passed a client handle, determine if it's valid or not.
74550Sstevel@tonic-gate 	 */
74560Sstevel@tonic-gate 	if (ch != NULL) {
74570Sstevel@tonic-gate 	    if (cs_find_client(ch, NULL) == NULL) {
74580Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
74590Sstevel@tonic-gate 		return (CS_BAD_HANDLE);
74600Sstevel@tonic-gate 	    } /* cs_find_client */
74610Sstevel@tonic-gate 	} /* ch != NULL */
74620Sstevel@tonic-gate 
74630Sstevel@tonic-gate 	mls->PhyAdapter = sp->adapter.number;
74640Sstevel@tonic-gate 
74650Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
74660Sstevel@tonic-gate 
74670Sstevel@tonic-gate 	return (CS_SUCCESS);
74680Sstevel@tonic-gate }
74690Sstevel@tonic-gate 
74700Sstevel@tonic-gate /*
74710Sstevel@tonic-gate  * cs_convert_speed - convers nS to devspeed and devspeed to nS
74720Sstevel@tonic-gate  *
74730Sstevel@tonic-gate  * The actual function is is in the CIS parser module; this
74740Sstevel@tonic-gate  *	is only a wrapper.
74750Sstevel@tonic-gate  */
74760Sstevel@tonic-gate static int
74770Sstevel@tonic-gate cs_convert_speed(convert_speed_t *cs)
74780Sstevel@tonic-gate {
74790Sstevel@tonic-gate 	return ((int)(uintptr_t)CIS_PARSER(CISP_CIS_CONV_DEVSPEED, cs));
74800Sstevel@tonic-gate }
74810Sstevel@tonic-gate 
74820Sstevel@tonic-gate /*
74830Sstevel@tonic-gate  * cs_convert_size - converts a devsize value to a size in bytes value
74840Sstevel@tonic-gate  *			or a size in bytes value to a devsize value
74850Sstevel@tonic-gate  *
74860Sstevel@tonic-gate  * The actual function is is in the CIS parser module; this
74870Sstevel@tonic-gate  *	is only a wrapper.
74880Sstevel@tonic-gate  */
74890Sstevel@tonic-gate static int
74900Sstevel@tonic-gate cs_convert_size(convert_size_t *cs)
74910Sstevel@tonic-gate {
74920Sstevel@tonic-gate 	return ((int)(uintptr_t)CIS_PARSER(CISP_CIS_CONV_DEVSIZE, cs));
74930Sstevel@tonic-gate }
74940Sstevel@tonic-gate 
74950Sstevel@tonic-gate /*
74960Sstevel@tonic-gate  * cs_convert_powerlevel - converts a power level in tenths of a volt
74970Sstevel@tonic-gate  *			to a power table entry for the specified socket
74980Sstevel@tonic-gate  *
74990Sstevel@tonic-gate  *	returns: CS_SUCCESS - if volts converted to a valid power level
75000Sstevel@tonic-gate  *		 CS_BAD_ADAPTER - if SS_InquireAdapter fails
75010Sstevel@tonic-gate  *		 CS_BAD_ARGS - if volts are not supported on this socket
75020Sstevel@tonic-gate  *				and adapter
75030Sstevel@tonic-gate  */
75040Sstevel@tonic-gate static int
75050Sstevel@tonic-gate cs_convert_powerlevel(uint32_t sn, uint32_t volts, uint32_t flags, unsigned *pl)
75060Sstevel@tonic-gate {
75070Sstevel@tonic-gate 	inquire_adapter_t inquire_adapter;
75080Sstevel@tonic-gate 	int i;
75090Sstevel@tonic-gate 
75100Sstevel@tonic-gate #ifdef	lint
75110Sstevel@tonic-gate 	if (sn == 0)
75120Sstevel@tonic-gate 	    panic("lint panic");
75130Sstevel@tonic-gate #endif
75140Sstevel@tonic-gate 
75150Sstevel@tonic-gate 	*pl = 0;
75160Sstevel@tonic-gate 
75170Sstevel@tonic-gate 	if (SocketServices(SS_InquireAdapter, &inquire_adapter) != SUCCESS)
75180Sstevel@tonic-gate 	    return (CS_BAD_ADAPTER);
75190Sstevel@tonic-gate 
75200Sstevel@tonic-gate 	for (i = 0; (i < inquire_adapter.NumPower); i++) {
75210Sstevel@tonic-gate 	    if ((inquire_adapter.power_entry[i].ValidSignals & flags) &&
75220Sstevel@tonic-gate 		(inquire_adapter.power_entry[i].PowerLevel == volts)) {
75230Sstevel@tonic-gate 		*pl = i;
75240Sstevel@tonic-gate 		return (CS_SUCCESS);
75250Sstevel@tonic-gate 	    }
75260Sstevel@tonic-gate 	}
75270Sstevel@tonic-gate 
75280Sstevel@tonic-gate 	return (CS_BAD_ARGS);
75290Sstevel@tonic-gate }
75300Sstevel@tonic-gate 
75310Sstevel@tonic-gate /*
75320Sstevel@tonic-gate  * cs_event2text - returns text string(s) associated with the event; this
75330Sstevel@tonic-gate  *			function supports the Event2Text CS call.
75340Sstevel@tonic-gate  *
75350Sstevel@tonic-gate  *	calling: event2text_t * - pointer to event2text struct
75360Sstevel@tonic-gate  *		 int event_source - specifies event type in event2text_t:
75370Sstevel@tonic-gate  *					0 - SS event
75380Sstevel@tonic-gate  *					1 - CS event
75390Sstevel@tonic-gate  *
75400Sstevel@tonic-gate  *	returns: CS_SUCCESS
75410Sstevel@tonic-gate  */
75420Sstevel@tonic-gate static int
75430Sstevel@tonic-gate cs_event2text(event2text_t *e2t, int event_source)
75440Sstevel@tonic-gate {
75450Sstevel@tonic-gate 	event_t event;
75460Sstevel@tonic-gate 	char *sepchar = "|";
75470Sstevel@tonic-gate 
75480Sstevel@tonic-gate 	/*
75490Sstevel@tonic-gate 	 * If event_source is 0, this is a SS event
75500Sstevel@tonic-gate 	 */
75510Sstevel@tonic-gate 	if (!event_source) {
75520Sstevel@tonic-gate 	    for (event = 0; event < MAX_SS_EVENTS; event++) {
75530Sstevel@tonic-gate 		if (cs_ss_event_text[event].ss_event == e2t->event) {
75540Sstevel@tonic-gate 		    (void) strcpy(e2t->text, cs_ss_event_text[event].text);
75550Sstevel@tonic-gate 		    return (CS_SUCCESS);
75560Sstevel@tonic-gate 		}
75570Sstevel@tonic-gate 	    }
75580Sstevel@tonic-gate 	    (void) strcpy(e2t->text, cs_ss_event_text[MAX_CS_EVENTS].text);
75590Sstevel@tonic-gate 	    return (CS_SUCCESS);
75600Sstevel@tonic-gate 	} else {
75610Sstevel@tonic-gate 		/*
75620Sstevel@tonic-gate 		 * This is a CS event
75630Sstevel@tonic-gate 		 */
75640Sstevel@tonic-gate 	    e2t->text[0] = '\0';
75650Sstevel@tonic-gate 	    for (event = 0; event < MAX_CS_EVENTS; event++) {
75660Sstevel@tonic-gate 		if (cs_ss_event_text[event].cs_event & e2t->event) {
75670Sstevel@tonic-gate 		    (void) strcat(e2t->text, cs_ss_event_text[event].text);
75680Sstevel@tonic-gate 		    (void) strcat(e2t->text, sepchar);
75690Sstevel@tonic-gate 		} /* if (cs_ss_event_text) */
75700Sstevel@tonic-gate 	    } /* for (event) */
75710Sstevel@tonic-gate 	    if (e2t->text[0])
75720Sstevel@tonic-gate 		e2t->text[strlen(e2t->text)-1] = NULL;
75730Sstevel@tonic-gate 	} /* if (!event_source) */
75740Sstevel@tonic-gate 
75750Sstevel@tonic-gate 	return (CS_SUCCESS);
75760Sstevel@tonic-gate }
75770Sstevel@tonic-gate 
75780Sstevel@tonic-gate /*
75790Sstevel@tonic-gate  * cs_error2text - returns a pointer to a text string containing the name
75800Sstevel@tonic-gate  *			of the passed Card Services function or return code
75810Sstevel@tonic-gate  *
75820Sstevel@tonic-gate  *	This function supports the Error2Text CS call.
75830Sstevel@tonic-gate  */
75840Sstevel@tonic-gate static char *
75850Sstevel@tonic-gate cs_error2text(int function, int type)
75860Sstevel@tonic-gate {
75870Sstevel@tonic-gate 	cs_csfunc2text_strings_t *cfs;
75880Sstevel@tonic-gate 	int end_marker;
75890Sstevel@tonic-gate 
75900Sstevel@tonic-gate 	if (type == CSFUN2TEXT_FUNCTION) {
75910Sstevel@tonic-gate 	    cfs = cs_csfunc2text_funcstrings;
75920Sstevel@tonic-gate 	    end_marker = CSFuncListEnd;
75930Sstevel@tonic-gate 	} else {
75940Sstevel@tonic-gate 	    cfs = cs_csfunc2text_returnstrings;
75950Sstevel@tonic-gate 	    end_marker = CS_ERRORLIST_END;
75960Sstevel@tonic-gate 	}
75970Sstevel@tonic-gate 
75980Sstevel@tonic-gate 	while (cfs->item != end_marker) {
75990Sstevel@tonic-gate 	    if (cfs->item == function)
76000Sstevel@tonic-gate 		return (cfs->text);
76010Sstevel@tonic-gate 	    cfs++;
76020Sstevel@tonic-gate 	}
76030Sstevel@tonic-gate 
76040Sstevel@tonic-gate 	return (cfs->text);
76050Sstevel@tonic-gate }
76060Sstevel@tonic-gate 
76070Sstevel@tonic-gate /*
76080Sstevel@tonic-gate  * cs_make_device_node - creates/removes device nodes on a client's behalf;
76090Sstevel@tonic-gate  *				this is MakeDeviceNode and RemoveDeviceNode
76100Sstevel@tonic-gate  *
76110Sstevel@tonic-gate  *	returns: CS_SUCCESS - if all device nodes successfully created/removed
76120Sstevel@tonic-gate  *		 CS_BAD_ATTRIBUTE - if NumDevNodes is not zero when Action
76130Sstevel@tonic-gate  *				is REMOVAL_ALL_DEVICES
76140Sstevel@tonic-gate  *		 CS_BAD_ARGS - if an invalid Action code is specified
76150Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
76160Sstevel@tonic-gate  *		 CS_OUT_OF_RESOURCE - if can't create/remove device node
76170Sstevel@tonic-gate  */
76180Sstevel@tonic-gate static int
76190Sstevel@tonic-gate cs_make_device_node(client_handle_t client_handle, make_device_node_t *mdn)
76200Sstevel@tonic-gate {
76210Sstevel@tonic-gate 	cs_socket_t *sp;
76220Sstevel@tonic-gate 	client_t *client;
76230Sstevel@tonic-gate 	ss_make_device_node_t ss_make_device_node;
76240Sstevel@tonic-gate 	int error, i;
76250Sstevel@tonic-gate 	int client_lock_acquired;
76260Sstevel@tonic-gate 
76270Sstevel@tonic-gate 	/*
76280Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
76290Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
76300Sstevel@tonic-gate 	 */
76310Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
76320Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
76330Sstevel@tonic-gate 
76340Sstevel@tonic-gate 	/*
76350Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
76360Sstevel@tonic-gate 	 */
76370Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
76380Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
76390Sstevel@tonic-gate 
76400Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
76410Sstevel@tonic-gate 
76420Sstevel@tonic-gate 	/*
76430Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
76440Sstevel@tonic-gate 	 */
76450Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
76460Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
76470Sstevel@tonic-gate 	    return (error);
76480Sstevel@tonic-gate 	}
76490Sstevel@tonic-gate 
76500Sstevel@tonic-gate #ifdef	XXX
76510Sstevel@tonic-gate 	/*
76520Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
76530Sstevel@tonic-gate 	 *	for this client, then return an error.
76540Sstevel@tonic-gate 	 */
76550Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
76560Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
76570Sstevel@tonic-gate 	    return (CS_NO_CARD);
76580Sstevel@tonic-gate 	}
76590Sstevel@tonic-gate #endif
76600Sstevel@tonic-gate 
76610Sstevel@tonic-gate 	/*
76620Sstevel@tonic-gate 	 * Setup the client's dip, since we use it later on.
76630Sstevel@tonic-gate 	 */
76640Sstevel@tonic-gate 	ss_make_device_node.dip = client->dip;
76650Sstevel@tonic-gate 
76660Sstevel@tonic-gate 	/*
76670Sstevel@tonic-gate 	 * Make sure that we're being given a valid Action.  Set the default
76680Sstevel@tonic-gate 	 *	error code as well.
76690Sstevel@tonic-gate 	 */
76700Sstevel@tonic-gate 	error = CS_BAD_ARGS;	/* for default case */
76710Sstevel@tonic-gate 	switch (mdn->Action) {
76720Sstevel@tonic-gate 	    case CREATE_DEVICE_NODE:
76730Sstevel@tonic-gate 	    case REMOVE_DEVICE_NODE:
76740Sstevel@tonic-gate 		break;
76750Sstevel@tonic-gate 	    case REMOVAL_ALL_DEVICE_NODES:
76760Sstevel@tonic-gate 		if (mdn->NumDevNodes) {
76770Sstevel@tonic-gate 		    error = CS_BAD_ATTRIBUTE;
76780Sstevel@tonic-gate 		} else {
76790Sstevel@tonic-gate 		    ss_make_device_node.flags = SS_CSINITDEV_REMOVE_DEVICE;
76800Sstevel@tonic-gate 		    ss_make_device_node.name = NULL;
76810Sstevel@tonic-gate 		    SocketServices(CSInitDev, &ss_make_device_node);
76820Sstevel@tonic-gate 		    error = CS_SUCCESS;
76830Sstevel@tonic-gate 		}
76840Sstevel@tonic-gate 		/* fall-through case */
76850Sstevel@tonic-gate 	    default:
76860Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
76870Sstevel@tonic-gate 		return (error);
76880Sstevel@tonic-gate 		/* NOTREACHED */
76890Sstevel@tonic-gate 	} /* switch */
76900Sstevel@tonic-gate 
76910Sstevel@tonic-gate 	/*
76920Sstevel@tonic-gate 	 * Loop through the device node descriptions and create or destroy
76930Sstevel@tonic-gate 	 *	the device node.
76940Sstevel@tonic-gate 	 */
76950Sstevel@tonic-gate 	for (i = 0; i < mdn->NumDevNodes; i++) {
76960Sstevel@tonic-gate 	    devnode_desc_t *devnode_desc = &mdn->devnode_desc[i];
76970Sstevel@tonic-gate 
76980Sstevel@tonic-gate 	    ss_make_device_node.name = devnode_desc->name;
76990Sstevel@tonic-gate 	    ss_make_device_node.spec_type = devnode_desc->spec_type;
77000Sstevel@tonic-gate 	    ss_make_device_node.minor_num = devnode_desc->minor_num;
77010Sstevel@tonic-gate 	    ss_make_device_node.node_type = devnode_desc->node_type;
77020Sstevel@tonic-gate 
77030Sstevel@tonic-gate 	/*
77040Sstevel@tonic-gate 	 * Set the appropriate flag for the action that we want
77050Sstevel@tonic-gate 	 *	SS to perform. Note that if we ever OR-in the flag
77060Sstevel@tonic-gate 	 *	here, we need to be sure to clear the flags member
77070Sstevel@tonic-gate 	 *	since we sometimes OR-in other flags below.
77080Sstevel@tonic-gate 	 */
77090Sstevel@tonic-gate 	    if (mdn->Action == CREATE_DEVICE_NODE) {
77100Sstevel@tonic-gate 		ss_make_device_node.flags = SS_CSINITDEV_CREATE_DEVICE;
77110Sstevel@tonic-gate 	    } else {
77120Sstevel@tonic-gate 		ss_make_device_node.flags = SS_CSINITDEV_REMOVE_DEVICE;
77130Sstevel@tonic-gate 	    }
77140Sstevel@tonic-gate 
77150Sstevel@tonic-gate 	/*
77160Sstevel@tonic-gate 	 * If this is not the last device to process, then we need
77170Sstevel@tonic-gate 	 *	to tell SS that more device process requests are on
77180Sstevel@tonic-gate 	 *	their way after this one.
77190Sstevel@tonic-gate 	 */
77200Sstevel@tonic-gate 	    if (i < (mdn->NumDevNodes - 1))
77210Sstevel@tonic-gate 		ss_make_device_node.flags |= SS_CSINITDEV_MORE_DEVICES;
77220Sstevel@tonic-gate 
77230Sstevel@tonic-gate 	    if (SocketServices(CSInitDev, &ss_make_device_node) != SUCCESS) {
77240Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
77250Sstevel@tonic-gate 		return (CS_OUT_OF_RESOURCE);
77260Sstevel@tonic-gate 	    } /* CSInitDev */
77270Sstevel@tonic-gate 	} /* for (mdn->NumDevNodes) */
77280Sstevel@tonic-gate 
77290Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
77300Sstevel@tonic-gate 	return (CS_SUCCESS);
77310Sstevel@tonic-gate }
77320Sstevel@tonic-gate 
77330Sstevel@tonic-gate /*
77340Sstevel@tonic-gate  * cs_remove_device_node - removes device nodes
77350Sstevel@tonic-gate  *
77360Sstevel@tonic-gate  *	(see cs_make_device_node for a description of the calling
77370Sstevel@tonic-gate  *		and return parameters)
77380Sstevel@tonic-gate  */
77390Sstevel@tonic-gate static int
77400Sstevel@tonic-gate cs_remove_device_node(client_handle_t client_handle, remove_device_node_t *rdn)
77410Sstevel@tonic-gate {
77420Sstevel@tonic-gate 
77430Sstevel@tonic-gate 	/*
77440Sstevel@tonic-gate 	 * XXX - Note the assumption here that the make_device_node_t and
77450Sstevel@tonic-gate 	 *	remove_device_node_t structures are identical.
77460Sstevel@tonic-gate 	 */
77470Sstevel@tonic-gate 	return (cs_make_device_node(client_handle, (make_device_node_t *)rdn));
77480Sstevel@tonic-gate }
77490Sstevel@tonic-gate 
77500Sstevel@tonic-gate /*
77510Sstevel@tonic-gate  * cs_ddi_info - this function is used by clients that need to support
77520Sstevel@tonic-gate  *			the xxx_getinfo function; this is CS_DDI_Info
77530Sstevel@tonic-gate  */
77540Sstevel@tonic-gate static int
77550Sstevel@tonic-gate cs_ddi_info(cs_ddi_info_t *cdi)
77560Sstevel@tonic-gate {
77570Sstevel@tonic-gate 	cs_socket_t *sp;
77580Sstevel@tonic-gate 	client_t *client;
77590Sstevel@tonic-gate 	int client_lock_acquired;
77600Sstevel@tonic-gate 
77610Sstevel@tonic-gate 	if (cdi->driver_name == NULL)
77620Sstevel@tonic-gate 	    return (CS_BAD_ATTRIBUTE);
77630Sstevel@tonic-gate 
77640Sstevel@tonic-gate #ifdef	CS_DEBUG
77650Sstevel@tonic-gate 	if (cs_debug > 0) {
77660Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_ddi_info: socket %d client [%s]\n",
77670Sstevel@tonic-gate 					(int)cdi->Socket, cdi->driver_name);
77680Sstevel@tonic-gate 	}
77690Sstevel@tonic-gate #endif
77700Sstevel@tonic-gate 
77710Sstevel@tonic-gate 	/*
77720Sstevel@tonic-gate 	 * Check to see if the socket number is in range - the system
77730Sstevel@tonic-gate 	 *	framework may cause a client driver to call us with
77740Sstevel@tonic-gate 	 *	a socket number that used to be present but isn't
77750Sstevel@tonic-gate 	 *	anymore. This is not a bug, and it's OK to return
77760Sstevel@tonic-gate 	 *	an error if the socket number is out of range.
77770Sstevel@tonic-gate 	 */
77780Sstevel@tonic-gate 	if (!CHECK_SOCKET_NUM(cdi->Socket, cs_globals.max_socket_num)) {
77790Sstevel@tonic-gate 
77800Sstevel@tonic-gate #ifdef	CS_DEBUG
77810Sstevel@tonic-gate 	    if (cs_debug > 0) {
77820Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_ddi_info: socket %d client [%s] "
77830Sstevel@tonic-gate 						"SOCKET IS OUT OF RANGE\n",
77840Sstevel@tonic-gate 							(int)cdi->Socket,
77850Sstevel@tonic-gate 							cdi->driver_name);
77860Sstevel@tonic-gate 	    }
77870Sstevel@tonic-gate #endif
77880Sstevel@tonic-gate 
77890Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
77900Sstevel@tonic-gate 	} /* if (!CHECK_SOCKET_NUM) */
77910Sstevel@tonic-gate 
77920Sstevel@tonic-gate 	/*
77930Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
77940Sstevel@tonic-gate 	 */
77950Sstevel@tonic-gate 	if ((sp = cs_get_sp(cdi->Socket)) == NULL)
77960Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
77970Sstevel@tonic-gate 
77980Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
77990Sstevel@tonic-gate 
78000Sstevel@tonic-gate 	client = sp->client_list;
78010Sstevel@tonic-gate 	while (client) {
78020Sstevel@tonic-gate 
78030Sstevel@tonic-gate #ifdef	CS_DEBUG
78040Sstevel@tonic-gate 	    if (cs_debug > 0) {
78050Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_ddi_info: socket %d checking client [%s] "
78060Sstevel@tonic-gate 							"handle 0x%x\n",
78070Sstevel@tonic-gate 						(int)cdi->Socket,
78080Sstevel@tonic-gate 						client->driver_name,
78090Sstevel@tonic-gate 						(int)client->client_handle);
78100Sstevel@tonic-gate 	    }
78110Sstevel@tonic-gate #endif
78120Sstevel@tonic-gate 
78130Sstevel@tonic-gate 	    if (client->driver_name != NULL) {
78140Sstevel@tonic-gate 		if (!(strcmp(client->driver_name, cdi->driver_name))) {
78150Sstevel@tonic-gate 		    cdi->dip = client->dip;
78160Sstevel@tonic-gate 		    cdi->instance = client->instance;
78170Sstevel@tonic-gate 
78180Sstevel@tonic-gate #ifdef	CS_DEBUG
78190Sstevel@tonic-gate 		    if (cs_debug > 0) {
78200Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_ddi_info: found client [%s] "
78210Sstevel@tonic-gate 						"instance %d handle 0x%x\n",
78220Sstevel@tonic-gate 					client->driver_name, client->instance,
78230Sstevel@tonic-gate 					(int)client->client_handle);
78240Sstevel@tonic-gate 		    }
78250Sstevel@tonic-gate #endif
78260Sstevel@tonic-gate 
78270Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
78280Sstevel@tonic-gate 		    return (CS_SUCCESS);
78290Sstevel@tonic-gate 		} /* strcmp */
78300Sstevel@tonic-gate 	    } /* driver_name != NULL */
78310Sstevel@tonic-gate 	    client = client->next;
78320Sstevel@tonic-gate 	} /* while (client) */
78330Sstevel@tonic-gate 
78340Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
78350Sstevel@tonic-gate 	return (CS_BAD_SOCKET);
78360Sstevel@tonic-gate }
78370Sstevel@tonic-gate 
78380Sstevel@tonic-gate /*
78390Sstevel@tonic-gate  * cs_sys_ctl - Card Services system control; this is CS_Sys_Ctl
78400Sstevel@tonic-gate  */
78410Sstevel@tonic-gate static int
78420Sstevel@tonic-gate cs_sys_ctl(cs_sys_ctl_t *csc)
78430Sstevel@tonic-gate {
78440Sstevel@tonic-gate 	cs_socket_t *sp;
78450Sstevel@tonic-gate 	client_t *cp;
78460Sstevel@tonic-gate 	int sn, ret = CS_UNSUPPORTED_MODE;
78470Sstevel@tonic-gate 
78480Sstevel@tonic-gate 	switch (csc->Action) {
78490Sstevel@tonic-gate 	    case CS_SYS_CTL_SEND_EVENT:
78500Sstevel@tonic-gate 		if (csc->Flags & CS_SYS_CTL_EVENT_SOCKET)
78510Sstevel@tonic-gate 		    sn = CS_GET_SOCKET_NUMBER(csc->Socket);
78520Sstevel@tonic-gate 		else
78530Sstevel@tonic-gate 		    sn = GET_CLIENT_SOCKET(csc->client_handle);
78540Sstevel@tonic-gate 		if ((sp = cs_get_sp(sn)) == NULL)
78550Sstevel@tonic-gate 		    return (CS_BAD_SOCKET);
78560Sstevel@tonic-gate 		mutex_enter(&sp->client_lock);
78570Sstevel@tonic-gate 		mutex_enter(&sp->lock);
78580Sstevel@tonic-gate 		csc->Events &= CS_EVENT_CLIENT_EVENTS_MASK;
78590Sstevel@tonic-gate 		if (csc->Flags & CS_SYS_CTL_EVENT_SOCKET)
78600Sstevel@tonic-gate 		    sp->events |= csc->Events;
78610Sstevel@tonic-gate 		if (csc->Flags & CS_SYS_CTL_EVENT_CLIENT) {
78620Sstevel@tonic-gate 		    if ((cp = cs_find_client(csc->client_handle, &ret)) ==
78630Sstevel@tonic-gate 									NULL) {
78640Sstevel@tonic-gate 			mutex_exit(&sp->lock);
78650Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
78660Sstevel@tonic-gate 			return (ret);
78670Sstevel@tonic-gate 		    } /* cs_find_client */
78680Sstevel@tonic-gate 			/*
78690Sstevel@tonic-gate 			 * Setup the events that we want to send to the client.
78700Sstevel@tonic-gate 			 */
78710Sstevel@tonic-gate 		    cp->events |= (csc->Events &
78720Sstevel@tonic-gate 					(cp->event_mask | cp->global_mask));
78730Sstevel@tonic-gate 		} /* CS_SYS_CTL_EVENT_CLIENT */
78740Sstevel@tonic-gate 
78750Sstevel@tonic-gate 		if (csc->Flags & CS_SYS_CTL_WAIT_SYNC) {
78760Sstevel@tonic-gate 		    sp->thread_state |= SOCKET_WAIT_SYNC;
78770Sstevel@tonic-gate 		    mutex_exit(&sp->lock);
78780Sstevel@tonic-gate 		    cv_broadcast(&sp->thread_cv);
78790Sstevel@tonic-gate 		    cv_wait(&sp->caller_cv, &sp->client_lock);
78800Sstevel@tonic-gate 		} else {
78810Sstevel@tonic-gate 		    mutex_exit(&sp->lock);
78820Sstevel@tonic-gate 		    cv_broadcast(&sp->thread_cv);
78830Sstevel@tonic-gate 		} /* CS_SYS_CTL_WAIT_SYNC */
78840Sstevel@tonic-gate 		mutex_exit(&sp->client_lock);
78850Sstevel@tonic-gate 		ret = CS_SUCCESS;
78860Sstevel@tonic-gate 		break;
78870Sstevel@tonic-gate 	    default:
78880Sstevel@tonic-gate 		break;
78890Sstevel@tonic-gate 	} /* switch */
78900Sstevel@tonic-gate 
78910Sstevel@tonic-gate 	return (ret);
78920Sstevel@tonic-gate }
78930Sstevel@tonic-gate 
78940Sstevel@tonic-gate /*
78950Sstevel@tonic-gate  * cs_get_sp - returns pointer to per-socket structure for passed
78960Sstevel@tonic-gate  *		socket number
78970Sstevel@tonic-gate  *
78980Sstevel@tonic-gate  *	return:	(cs_socket_t *) - pointer to socket structure
78990Sstevel@tonic-gate  *		NULL - invalid socket number passed in
79000Sstevel@tonic-gate  */
79010Sstevel@tonic-gate static cs_socket_t *
79020Sstevel@tonic-gate cs_get_sp(uint32_t sn)
79030Sstevel@tonic-gate {
79040Sstevel@tonic-gate 	cs_socket_t *sp = cs_globals.sp;
79050Sstevel@tonic-gate 
79060Sstevel@tonic-gate 	if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY))
79070Sstevel@tonic-gate 	    return (NULL);
79080Sstevel@tonic-gate 
79090Sstevel@tonic-gate 	if ((sp = cs_find_sp(sn)) == NULL)
79100Sstevel@tonic-gate 	    return (NULL);
79110Sstevel@tonic-gate 
79120Sstevel@tonic-gate 	if (sp->flags & SOCKET_IS_VALID)
79130Sstevel@tonic-gate 	    return (sp);
79140Sstevel@tonic-gate 
79150Sstevel@tonic-gate 	return (NULL);
79160Sstevel@tonic-gate }
79170Sstevel@tonic-gate 
79180Sstevel@tonic-gate /*
79190Sstevel@tonic-gate  * cs_find_sp - searches socket list and returns pointer to passed socket
79200Sstevel@tonic-gate  *			number
79210Sstevel@tonic-gate  *
79220Sstevel@tonic-gate  *	return:	(cs_socket_t *) - pointer to socket structure if found
79230Sstevel@tonic-gate  *		NULL - socket not found
79240Sstevel@tonic-gate  */
79250Sstevel@tonic-gate static cs_socket_t *
79260Sstevel@tonic-gate cs_find_sp(uint32_t sn)
79270Sstevel@tonic-gate {
79280Sstevel@tonic-gate 	cs_socket_t *sp = cs_globals.sp;
79290Sstevel@tonic-gate 
79300Sstevel@tonic-gate 	while (sp) {
79310Sstevel@tonic-gate 	    if (sp->socket_num == CS_GET_SOCKET_NUMBER(sn))
79320Sstevel@tonic-gate 		return (sp);
79330Sstevel@tonic-gate 	    sp = sp->next;
79340Sstevel@tonic-gate 	} /* while */
79350Sstevel@tonic-gate 
79360Sstevel@tonic-gate 	return (NULL);
79370Sstevel@tonic-gate }
79380Sstevel@tonic-gate 
79390Sstevel@tonic-gate /*
79400Sstevel@tonic-gate  * cs_add_socket - add a socket
79410Sstevel@tonic-gate  *
79420Sstevel@tonic-gate  *	call:	sn - socket number to add
79430Sstevel@tonic-gate  *
79440Sstevel@tonic-gate  *	return:	CS_SUCCESS - operation sucessful
79450Sstevel@tonic-gate  *		CS_BAD_SOCKET - unable to add socket
79460Sstevel@tonic-gate  *		CS_BAD_WINDOW - unable to get CIS window for socket
79470Sstevel@tonic-gate  *
79480Sstevel@tonic-gate  * We get called here once for each socket that the framework wants to
79490Sstevel@tonic-gate  *	add. When we are called, the framework guarentees that until we
79500Sstevel@tonic-gate  *	complete this routine, no other adapter instances will be allowed
79510Sstevel@tonic-gate  *	to attach and thus no other PCE_ADD_SOCKET events will occur.
79520Sstevel@tonic-gate  *	It is safe to call SS_InquireAdapter to get the number of
79530Sstevel@tonic-gate  *	windows that the framework currently knows about.
79540Sstevel@tonic-gate  */
79550Sstevel@tonic-gate static uint32_t
79560Sstevel@tonic-gate cs_add_socket(uint32_t sn)
79570Sstevel@tonic-gate {
79580Sstevel@tonic-gate 	cs_socket_t *sp;
79590Sstevel@tonic-gate 	sservice_t sservice;
79600Sstevel@tonic-gate 	get_cookies_and_dip_t *gcad;
79610Sstevel@tonic-gate 	win_req_t win_req;
79620Sstevel@tonic-gate 	convert_speed_t convert_speed;
79630Sstevel@tonic-gate 	set_socket_t set_socket;
79640Sstevel@tonic-gate 	cs_window_t *cw;
79650Sstevel@tonic-gate 	inquire_adapter_t inquire_adapter;
79660Sstevel@tonic-gate 	inquire_window_t inquire_window;
79670Sstevel@tonic-gate 	int ret, added_windows;
79680Sstevel@tonic-gate 
79690Sstevel@tonic-gate 	if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY))
79700Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
79710Sstevel@tonic-gate 
79720Sstevel@tonic-gate 	/*
79730Sstevel@tonic-gate 	 * See if this socket has already been added - if it has, we
79740Sstevel@tonic-gate 	 *	fail this. If we can't find the socket, then allocate
79750Sstevel@tonic-gate 	 *	a new socket structure. If we do find the socket, then
79760Sstevel@tonic-gate 	 *	check to see if it's already added; if it is, then
79770Sstevel@tonic-gate 	 *	this is an error and return CS_BAD_SOCKET; if not,
79780Sstevel@tonic-gate 	 *	then traverse the socket structure list and add this
79790Sstevel@tonic-gate 	 *	next socket strcture to the end of the list.
79800Sstevel@tonic-gate 	 * XXX What about locking this list while we update it? Is
79810Sstevel@tonic-gate 	 *	that necessary since we're using the SOCKET_IS_VALID
79820Sstevel@tonic-gate 	 *	flag and since we never delete a socket from the
79830Sstevel@tonic-gate 	 *	list once it's been added?
79840Sstevel@tonic-gate 	 */
79850Sstevel@tonic-gate 	if ((sp = cs_find_sp(sn)) == NULL) {
79860Sstevel@tonic-gate 	    cs_socket_t *spp = cs_globals.sp;
79870Sstevel@tonic-gate 
79880Sstevel@tonic-gate 	    sp = (cs_socket_t *)kmem_zalloc(sizeof (cs_socket_t), KM_SLEEP);
79890Sstevel@tonic-gate 
79900Sstevel@tonic-gate 	    if (cs_globals.sp == NULL)
79910Sstevel@tonic-gate 		cs_globals.sp = sp;
79920Sstevel@tonic-gate 	    else
79930Sstevel@tonic-gate 		while (spp) {
79940Sstevel@tonic-gate 		    if (spp->next == NULL) {
79950Sstevel@tonic-gate 			spp->next = sp;
79960Sstevel@tonic-gate 			break;
79970Sstevel@tonic-gate 		    } /* if */
79980Sstevel@tonic-gate 		    spp = spp->next;
79990Sstevel@tonic-gate 		} /* while */
80000Sstevel@tonic-gate 
80010Sstevel@tonic-gate 	} else {
80020Sstevel@tonic-gate 	    if (sp->flags & SOCKET_IS_VALID)
80030Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
80040Sstevel@tonic-gate 	} /* cs_find_sp */
80050Sstevel@tonic-gate 
80060Sstevel@tonic-gate 	/*
80070Sstevel@tonic-gate 	 * Setup the socket number
80080Sstevel@tonic-gate 	 */
80090Sstevel@tonic-gate 	sp->socket_num = sn;
80100Sstevel@tonic-gate 
80110Sstevel@tonic-gate 	/*
80120Sstevel@tonic-gate 	 * Find out how many windows the framework knows about
80130Sstevel@tonic-gate 	 *	so far. If this number of windows is greater
80140Sstevel@tonic-gate 	 *	than our current window count, bump up our
80150Sstevel@tonic-gate 	 *	current window count.
80160Sstevel@tonic-gate 	 * XXX Note that there is a BIG assumption here and that
80170Sstevel@tonic-gate 	 *	is that once the framework tells us that it has
80180Sstevel@tonic-gate 	 *	a window (as reflected in the NumWindows
80190Sstevel@tonic-gate 	 *	value) it can NEVER remove that window.
80200Sstevel@tonic-gate 	 *	When we really get the drop socket and drop
80210Sstevel@tonic-gate 	 *	window mechanism working correctly, we'll have
80220Sstevel@tonic-gate 	 *	to revisit this.
80230Sstevel@tonic-gate 	 */
80240Sstevel@tonic-gate 	SocketServices(SS_InquireAdapter, &inquire_adapter);
80250Sstevel@tonic-gate 
80260Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
80270Sstevel@tonic-gate 	added_windows = inquire_adapter.NumWindows - cs_globals.num_windows;
80280Sstevel@tonic-gate 	if (added_windows > 0) {
80290Sstevel@tonic-gate 	    if (cs_add_windows(added_windows,
80300Sstevel@tonic-gate 				cs_globals.num_windows) != CS_SUCCESS) {
80310Sstevel@tonic-gate 		mutex_exit(&cs_globals.window_lock);
80320Sstevel@tonic-gate 		return (CS_BAD_WINDOW);
80330Sstevel@tonic-gate 	    } /* cs_add_windows */
80340Sstevel@tonic-gate 
80350Sstevel@tonic-gate 	    cs_globals.num_windows = inquire_adapter.NumWindows;
80360Sstevel@tonic-gate 
80370Sstevel@tonic-gate 	} /* if (added_windows) */
80380Sstevel@tonic-gate 
80390Sstevel@tonic-gate 	/*
80400Sstevel@tonic-gate 	 * Find a window that we can use for this socket's CIS window.
80410Sstevel@tonic-gate 	 */
80420Sstevel@tonic-gate 	sp->cis_win_num = PCMCIA_MAX_WINDOWS;
80430Sstevel@tonic-gate 
80440Sstevel@tonic-gate 	convert_speed.Attributes = CONVERT_NS_TO_DEVSPEED;
80450Sstevel@tonic-gate 	convert_speed.nS = CIS_DEFAULT_SPEED;
80460Sstevel@tonic-gate 	(void) cs_convert_speed(&convert_speed);
80470Sstevel@tonic-gate 
80480Sstevel@tonic-gate 	win_req.win_params.AccessSpeed = convert_speed.devspeed;
80490Sstevel@tonic-gate 	win_req.Attributes = (WIN_MEMORY_TYPE_AM | WIN_DATA_WIDTH_8);
80500Sstevel@tonic-gate 	win_req.Attributes = (WIN_MEMORY_TYPE_AM | WIN_MEMORY_TYPE_CM);
80510Sstevel@tonic-gate 	win_req.Base.base = 0;
80520Sstevel@tonic-gate 	win_req.Size = 0;
80530Sstevel@tonic-gate 
80540Sstevel@tonic-gate 	if ((ret = cs_find_mem_window(sp->socket_num, &win_req,
80550Sstevel@tonic-gate 					&sp->cis_win_num)) != CS_SUCCESS) {
80560Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
80570Sstevel@tonic-gate 	    sp->cis_win_num = PCMCIA_MAX_WINDOWS;
80580Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_add_socket: socket %d can't get CIS "
80590Sstevel@tonic-gate 						"window - error 0x%x\n",
80600Sstevel@tonic-gate 						sp->socket_num, ret);
80610Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
80620Sstevel@tonic-gate 	} /* cs_find_mem_window */
80630Sstevel@tonic-gate 
80640Sstevel@tonic-gate 	if ((cw = cs_get_wp(sp->cis_win_num)) == NULL) {
80650Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
80660Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
80670Sstevel@tonic-gate 	}
80680Sstevel@tonic-gate 
80690Sstevel@tonic-gate 	inquire_window.window = sp->cis_win_num;
80700Sstevel@tonic-gate 	SocketServices(SS_InquireWindow, &inquire_window);
80710Sstevel@tonic-gate 
80720Sstevel@tonic-gate 	/*
80730Sstevel@tonic-gate 	 * If the CIS window is a variable sized window, then use
80740Sstevel@tonic-gate 	 *	the size that cs_find_mem_window returned to us,
80750Sstevel@tonic-gate 	 *	since this will be the minimum size that we can
80760Sstevel@tonic-gate 	 *	set this window to. If the CIS window is a fixed
80770Sstevel@tonic-gate 	 *	sized window, then use the system pagesize as the
80780Sstevel@tonic-gate 	 *	CIS window size.
80790Sstevel@tonic-gate 	 */
80800Sstevel@tonic-gate 	if (inquire_window.mem_win_char.MemWndCaps & WC_SIZE) {
80810Sstevel@tonic-gate 	    sp->cis_win_size = win_req.Size;
80820Sstevel@tonic-gate 	} else {
80830Sstevel@tonic-gate 	    sp->cis_win_size = PAGESIZE;
80840Sstevel@tonic-gate 	}
80850Sstevel@tonic-gate 
80860Sstevel@tonic-gate 	cw->state |= (CW_CIS | CW_ALLOCATED);
80870Sstevel@tonic-gate 	cw->socket_num = sp->socket_num;
80880Sstevel@tonic-gate 
80890Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
80900Sstevel@tonic-gate 
80910Sstevel@tonic-gate #if defined(CS_DEBUG)
80920Sstevel@tonic-gate 	    if (cs_debug > 1) {
80930Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_add_socket: socket %d using CIS window %d "
80940Sstevel@tonic-gate 					"size 0x%x\n", (int)sp->socket_num,
80950Sstevel@tonic-gate 					(int)sp->cis_win_num,
80960Sstevel@tonic-gate 					(int)sp->cis_win_size);
80970Sstevel@tonic-gate 	    }
80980Sstevel@tonic-gate #endif
80990Sstevel@tonic-gate 
81000Sstevel@tonic-gate 	/*
81010Sstevel@tonic-gate 	 * Get the adapter information associated with this socket so
81020Sstevel@tonic-gate 	 *	that we can initialize the mutexes, condition variables,
81030Sstevel@tonic-gate 	 *	soft interrupt handler and per-socket adapter info.
81040Sstevel@tonic-gate 	 */
81050Sstevel@tonic-gate 	gcad = &sservice.get_cookies;
81060Sstevel@tonic-gate 	gcad->socket = sp->socket_num;
81070Sstevel@tonic-gate 	if (SocketServices(CSGetCookiesAndDip, &sservice) != SUCCESS) {
81080Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_add_socket: socket %d CSGetCookiesAndDip "
81090Sstevel@tonic-gate 						"failure\n", sp->socket_num);
81100Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
81110Sstevel@tonic-gate 	} /* CSGetCookiesAndDip */
81120Sstevel@tonic-gate 
81130Sstevel@tonic-gate 	/*
81140Sstevel@tonic-gate 	 * Save the iblock and idev cookies for RegisterClient
81150Sstevel@tonic-gate 	 */
81160Sstevel@tonic-gate 	sp->iblk = gcad->iblock;
81170Sstevel@tonic-gate 	sp->idev = gcad->idevice;
81180Sstevel@tonic-gate 
81190Sstevel@tonic-gate 	/*
81200Sstevel@tonic-gate 	 * Setup the per-socket adapter info
81210Sstevel@tonic-gate 	 */
81220Sstevel@tonic-gate 	sp->adapter.flags = 0;
81230Sstevel@tonic-gate 	(void) strcpy(sp->adapter.name, gcad->adapter_info.name);
81240Sstevel@tonic-gate 	sp->adapter.major = gcad->adapter_info.major;
81250Sstevel@tonic-gate 	sp->adapter.minor = gcad->adapter_info.minor;
81260Sstevel@tonic-gate 	sp->adapter.instance = ddi_get_instance(gcad->dip);
81270Sstevel@tonic-gate 	sp->adapter.number = gcad->adapter_info.number;
81280Sstevel@tonic-gate 	sp->adapter.num_sockets = gcad->adapter_info.num_sockets;
81290Sstevel@tonic-gate 	sp->adapter.first_socket = gcad->adapter_info.first_socket;
81300Sstevel@tonic-gate 
81310Sstevel@tonic-gate 	/* Setup for cs_event and cs_event_thread */
81320Sstevel@tonic-gate 	mutex_init(&sp->lock, NULL, MUTEX_DRIVER, *(gcad->iblock));
81330Sstevel@tonic-gate 	mutex_init(&sp->client_lock, NULL, MUTEX_DRIVER, NULL);
81340Sstevel@tonic-gate 	mutex_init(&sp->cis_lock, NULL, MUTEX_DRIVER, NULL);
81350Sstevel@tonic-gate 
81360Sstevel@tonic-gate 	/* Setup for Socket Services work thread */
81370Sstevel@tonic-gate 	mutex_init(&sp->ss_thread_lock, NULL, MUTEX_DRIVER, NULL);
81380Sstevel@tonic-gate 
81390Sstevel@tonic-gate 	sp->init_state |= SOCKET_INIT_STATE_MUTEX;
81400Sstevel@tonic-gate 
81410Sstevel@tonic-gate 	/* Setup for cs_event_thread */
81420Sstevel@tonic-gate 	cv_init(&sp->thread_cv, NULL, CV_DRIVER, NULL);
81430Sstevel@tonic-gate 	cv_init(&sp->caller_cv, NULL, CV_DRIVER, NULL);
81440Sstevel@tonic-gate 	cv_init(&sp->reset_cv, NULL, CV_DRIVER, NULL);
81450Sstevel@tonic-gate 
81460Sstevel@tonic-gate 	/* Setup for Socket Services work thread */
81470Sstevel@tonic-gate 	cv_init(&sp->ss_thread_cv, NULL, CV_DRIVER, NULL);
81480Sstevel@tonic-gate 	cv_init(&sp->ss_caller_cv, NULL, CV_DRIVER, NULL);
81490Sstevel@tonic-gate 
81500Sstevel@tonic-gate 	sp->init_state |= SOCKET_INIT_STATE_CV;
81510Sstevel@tonic-gate 
81520Sstevel@tonic-gate 	/*
81530Sstevel@tonic-gate 	 * If we haven't installed it yet, then install the soft interrupt
81540Sstevel@tonic-gate 	 *	handler and save away the softint id.
81550Sstevel@tonic-gate 	 */
81560Sstevel@tonic-gate 	if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SOFTINTR)) {
81570Sstevel@tonic-gate 	    if (ddi_add_softintr(gcad->dip, DDI_SOFTINT_HIGH,
81580Sstevel@tonic-gate 						&sp->softint_id,
81590Sstevel@tonic-gate 						NULL, NULL,
81600Sstevel@tonic-gate 						cs_socket_event_softintr,
81610Sstevel@tonic-gate 						(caddr_t)NULL) != DDI_SUCCESS) {
81620Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_add_socket: socket %d can't add "
81630Sstevel@tonic-gate 						"softintr\n", sp->socket_num);
81640Sstevel@tonic-gate 		    return (CS_BAD_SOCKET);
81650Sstevel@tonic-gate 	    } /* ddi_add_softintr */
81660Sstevel@tonic-gate 
81670Sstevel@tonic-gate 	    mutex_enter(&cs_globals.global_lock);
81680Sstevel@tonic-gate 	    cs_globals.softint_id = sp->softint_id;
81690Sstevel@tonic-gate 	    cs_globals.init_state |= GLOBAL_INIT_STATE_SOFTINTR;
81700Sstevel@tonic-gate 	    /* XXX this timer is hokey at best... */
81710Sstevel@tonic-gate 	    cs_globals.sotfint_tmo = timeout(cs_event_softintr_timeout,
81720Sstevel@tonic-gate 		NULL, SOFTINT_TIMEOUT_TIME);
81730Sstevel@tonic-gate 	    mutex_exit(&cs_globals.global_lock);
81740Sstevel@tonic-gate 	} else {
81750Sstevel@tonic-gate 		/*
81760Sstevel@tonic-gate 		 * We've already added the soft interrupt handler, so just
81770Sstevel@tonic-gate 		 *	store away the softint id.
81780Sstevel@tonic-gate 		 */
81790Sstevel@tonic-gate 	    sp->softint_id = cs_globals.softint_id;
81800Sstevel@tonic-gate 	} /* if (!GLOBAL_INIT_STATE_SOFTINTR) */
81810Sstevel@tonic-gate 
81820Sstevel@tonic-gate 	/*
81830Sstevel@tonic-gate 	 * While this next flag doesn't really describe a per-socket
81840Sstevel@tonic-gate 	 *	resource, we still set it for each socket.  When the soft
81850Sstevel@tonic-gate 	 *	interrupt handler finally gets removed in cs_deinit, this
81860Sstevel@tonic-gate 	 *	flag will get cleared.
81870Sstevel@tonic-gate 	 */
81880Sstevel@tonic-gate 	sp->init_state |= SOCKET_INIT_STATE_SOFTINTR;
81890Sstevel@tonic-gate 
81900Sstevel@tonic-gate 	/*
81910Sstevel@tonic-gate 	 * Socket Services defaults all sockets to power off and
81920Sstevel@tonic-gate 	 *	clears all event masks.  We want to receive at least
81930Sstevel@tonic-gate 	 *	card insertion events, so enable them.  Turn off power
81940Sstevel@tonic-gate 	 *	to the socket as well.  We will turn it on again when
81950Sstevel@tonic-gate 	 *	we get a card insertion event.
81960Sstevel@tonic-gate 	 */
81970Sstevel@tonic-gate 	sp->event_mask = CS_EVENT_CARD_INSERTION;
81980Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
81990Sstevel@tonic-gate 	set_socket.SCIntMask = SBM_CD;
82000Sstevel@tonic-gate 	set_socket.IREQRouting = 0;
82010Sstevel@tonic-gate 	set_socket.IFType = IF_MEMORY;
82020Sstevel@tonic-gate 	set_socket.CtlInd = 0; /* turn off controls and indicators */
82030Sstevel@tonic-gate 	set_socket.State = (unsigned)~0;	/* clear latched state bits */
82040Sstevel@tonic-gate 
82050Sstevel@tonic-gate 	(void) cs_convert_powerlevel(sp->socket_num, 0, VCC,
82060Sstevel@tonic-gate 						&set_socket.VccLevel);
82070Sstevel@tonic-gate 	(void) cs_convert_powerlevel(sp->socket_num, 0, VPP1,
82080Sstevel@tonic-gate 						&set_socket.Vpp1Level);
82090Sstevel@tonic-gate 	(void) cs_convert_powerlevel(sp->socket_num, 0, VPP2,
82100Sstevel@tonic-gate 						&set_socket.Vpp2Level);
82110Sstevel@tonic-gate 
82120Sstevel@tonic-gate 	if ((ret = SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
82130Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_add_socket: socket %d SS_SetSocket "
82140Sstevel@tonic-gate 					"failure %d\n", sp->socket_num, ret);
82150Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
82160Sstevel@tonic-gate 	} /* SS_SetSocket */
82170Sstevel@tonic-gate 
82180Sstevel@tonic-gate 	/*
82190Sstevel@tonic-gate 	 * The various socket-specific variables are now set up, so
82200Sstevel@tonic-gate 	 *	increment the global socket count and also mark the
82210Sstevel@tonic-gate 	 *	socket as available. We need to set this before we
82220Sstevel@tonic-gate 	 *	start any of the per-socket threads so that the threads
82230Sstevel@tonic-gate 	 *	can get a valid socket pointer when they start.
82240Sstevel@tonic-gate 	 */
82250Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
82260Sstevel@tonic-gate 	cs_globals.num_sockets++;
82270Sstevel@tonic-gate 	cs_globals.max_socket_num =
82280Sstevel@tonic-gate 			max(cs_globals.max_socket_num, sp->socket_num + 1);
82290Sstevel@tonic-gate 	mutex_exit(&cs_globals.global_lock);
82300Sstevel@tonic-gate 	sp->flags = SOCKET_IS_VALID;
82310Sstevel@tonic-gate 
82320Sstevel@tonic-gate 	/*
82330Sstevel@tonic-gate 	 * Create the per-socket event handler thread.
82340Sstevel@tonic-gate 	 */
82350Sstevel@tonic-gate 	sp->event_thread = CREATE_SOCKET_EVENT_THREAD(cs_event_thread,
82360Sstevel@tonic-gate 		(uintptr_t)sn);
82370Sstevel@tonic-gate 
82380Sstevel@tonic-gate 	mutex_enter(&sp->lock);
82390Sstevel@tonic-gate 	sp->init_state |= SOCKET_INIT_STATE_THREAD;
82400Sstevel@tonic-gate 	mutex_exit(&sp->lock);
82410Sstevel@tonic-gate 
82420Sstevel@tonic-gate 	/*
82430Sstevel@tonic-gate 	 * Create the per-socket Socket Services work thread.
82440Sstevel@tonic-gate 	 */
82450Sstevel@tonic-gate 	sp->ss_thread = CREATE_SOCKET_EVENT_THREAD(cs_ss_thread,
82460Sstevel@tonic-gate 		(uintptr_t)sn);
82470Sstevel@tonic-gate 
82480Sstevel@tonic-gate 	mutex_enter(&sp->lock);
82490Sstevel@tonic-gate 	sp->init_state |= (SOCKET_INIT_STATE_SS_THREAD |
82500Sstevel@tonic-gate 						SOCKET_INIT_STATE_READY);
82510Sstevel@tonic-gate 	sp->event_mask = CS_EVENT_CARD_INSERTION;
82520Sstevel@tonic-gate 	mutex_exit(&sp->lock);
82530Sstevel@tonic-gate 
82540Sstevel@tonic-gate 	return (CS_SUCCESS);
82550Sstevel@tonic-gate }
82560Sstevel@tonic-gate 
82570Sstevel@tonic-gate /*
82580Sstevel@tonic-gate  * cs_drop_socket - drop a socket
82590Sstevel@tonic-gate  *
82600Sstevel@tonic-gate  *	call:	sn - socket number to drop
82610Sstevel@tonic-gate  *
82620Sstevel@tonic-gate  *	return:	CS_SUCCESS - operation sucessful
82630Sstevel@tonic-gate  *		CS_BAD_SOCKET - unable to drop socket
82640Sstevel@tonic-gate  */
82650Sstevel@tonic-gate /*ARGSUSED*/
82660Sstevel@tonic-gate static uint32_t
82670Sstevel@tonic-gate cs_drop_socket(uint32_t sn)
82680Sstevel@tonic-gate {
82690Sstevel@tonic-gate #ifdef	XXX
82700Sstevel@tonic-gate 	cs_socket_t *sp;
82710Sstevel@tonic-gate 
82720Sstevel@tonic-gate 	/*
82730Sstevel@tonic-gate 	 * Tell the socket event thread to exit and then wait for it
82740Sstevel@tonic-gate 	 *	to do so.
82750Sstevel@tonic-gate 	 */
82760Sstevel@tonic-gate 	mutex_enter(&sp->client_lock);
82770Sstevel@tonic-gate 	sp->thread_state |= SOCKET_THREAD_EXIT;
82780Sstevel@tonic-gate 	cv_broadcast(&sp->thread_cv);
82790Sstevel@tonic-gate 	cv_wait(&sp->caller_cv, &sp->client_lock);
82800Sstevel@tonic-gate 	mutex_exit(&sp->client_lock);
82810Sstevel@tonic-gate 
82820Sstevel@tonic-gate 	/*
82830Sstevel@tonic-gate 	 * Tell the socket SS thread to exit and then wait for it
82840Sstevel@tonic-gate 	 *	to do so.
82850Sstevel@tonic-gate 	 */
82860Sstevel@tonic-gate 
82870Sstevel@tonic-gate 	/*
82880Sstevel@tonic-gate 	 * Mark the socket as dropped.
82890Sstevel@tonic-gate 	 */
82900Sstevel@tonic-gate 	sp->flags &= ~SOCKET_IS_VALID;
82910Sstevel@tonic-gate 
82920Sstevel@tonic-gate #endif	/* XXX */
82930Sstevel@tonic-gate 
82940Sstevel@tonic-gate 	/* XXX for now don't allow dropping sockets XXX */
82950Sstevel@tonic-gate 	return (CS_BAD_SOCKET);
82960Sstevel@tonic-gate }
82970Sstevel@tonic-gate 
82980Sstevel@tonic-gate /*
82990Sstevel@tonic-gate  * cs_get_socket - returns the socket and function numbers and a pointer
83000Sstevel@tonic-gate  *			to the socket structure
83010Sstevel@tonic-gate  *
83020Sstevel@tonic-gate  * calling:	client_handle_t client_handle - client handle to extract
83030Sstevel@tonic-gate  *						socket number from
83040Sstevel@tonic-gate  *		uint32_t *socket -  pointer to socket number to use if
83050Sstevel@tonic-gate  *					client_handle is for the SS client;
83060Sstevel@tonic-gate  *					this value will be filled in on
83070Sstevel@tonic-gate  *					return with the correct socket
83080Sstevel@tonic-gate  *					and function numbers if we
83090Sstevel@tonic-gate  *					return CS_SUCCESS
83100Sstevel@tonic-gate  *		uint32_t *function - pointer to return function number into
83110Sstevel@tonic-gate  *					if not NULL
83120Sstevel@tonic-gate  *		cs_socket_t **sp - pointer to a pointer where a pointer
83130Sstevel@tonic-gate  *					to the socket struct will be
83140Sstevel@tonic-gate  *					placed if this is non-NULL
83150Sstevel@tonic-gate  *		client_t **clp - pointer to a pointer where a pointer
83160Sstevel@tonic-gate  *					to the client struct will be
83170Sstevel@tonic-gate  *					placed if this is non-NULL
83180Sstevel@tonic-gate  *
83190Sstevel@tonic-gate  *    The socket and function numbers are derived as follows:
83200Sstevel@tonic-gate  *
83210Sstevel@tonic-gate  *	Client Type		Socket Number		Function Number
83220Sstevel@tonic-gate  *	PC card client		From client_handle	From client_handle
83230Sstevel@tonic-gate  *	Socket Services client	From *socket		From *socket
83240Sstevel@tonic-gate  *	CSI client		From client_handle	From *socket
83250Sstevel@tonic-gate  */
83260Sstevel@tonic-gate static uint32_t
83270Sstevel@tonic-gate cs_get_socket(client_handle_t client_handle, uint32_t *socket,
83280Sstevel@tonic-gate     uint32_t *function, cs_socket_t **csp, client_t **clp)
83290Sstevel@tonic-gate {
83300Sstevel@tonic-gate 	cs_socket_t *sp;
83310Sstevel@tonic-gate 	client_t *client;
83320Sstevel@tonic-gate 	uint32_t sn, fn;
83330Sstevel@tonic-gate 	int ret;
83340Sstevel@tonic-gate 
83350Sstevel@tonic-gate 	sn = *socket;
83360Sstevel@tonic-gate 
83370Sstevel@tonic-gate 	/*
83380Sstevel@tonic-gate 	 * If this is the Socket Services client, then return the
83390Sstevel@tonic-gate 	 *	socket and function numbers specified in the passed
83400Sstevel@tonic-gate 	 *	socket number parameter, otherwise extract the socket
83410Sstevel@tonic-gate 	 *	and function numbers from the client handle.
83420Sstevel@tonic-gate 	 */
83430Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle)) {
83440Sstevel@tonic-gate 	    fn = CS_GET_FUNCTION_NUMBER(sn);
83450Sstevel@tonic-gate 	    sn = CS_GET_SOCKET_NUMBER(sn);
83460Sstevel@tonic-gate 	} else {
83470Sstevel@tonic-gate 	    fn = GET_CLIENT_FUNCTION(client_handle);
83480Sstevel@tonic-gate 	    sn = GET_CLIENT_SOCKET(client_handle);
83490Sstevel@tonic-gate 	}
83500Sstevel@tonic-gate 
83510Sstevel@tonic-gate 	/*
83520Sstevel@tonic-gate 	 * Check to be sure that the socket number is in range
83530Sstevel@tonic-gate 	 */
83540Sstevel@tonic-gate 	if (!(CHECK_SOCKET_NUM(sn, cs_globals.max_socket_num)))
83550Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
83560Sstevel@tonic-gate 
83570Sstevel@tonic-gate 	if ((sp = cs_get_sp(sn)) == NULL)
83580Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
83590Sstevel@tonic-gate 
83600Sstevel@tonic-gate 	/*
83610Sstevel@tonic-gate 	 * If we were given a pointer, then fill it in with a pointer
83620Sstevel@tonic-gate 	 *	to this socket.
83630Sstevel@tonic-gate 	 */
83640Sstevel@tonic-gate 	if (csp)
83650Sstevel@tonic-gate 	    *csp = sp;
83660Sstevel@tonic-gate 
83670Sstevel@tonic-gate 	/*
83680Sstevel@tonic-gate 	 * Search for the client; if it's not found, return an error.
83690Sstevel@tonic-gate 	 */
83700Sstevel@tonic-gate 	mutex_enter(&sp->lock);
83710Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &ret))) {
83720Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
83730Sstevel@tonic-gate 	    return (ret);
83740Sstevel@tonic-gate 	}
83750Sstevel@tonic-gate 
83760Sstevel@tonic-gate 	/*
83770Sstevel@tonic-gate 	 * If we're a CIS client, then extract the function number
83780Sstevel@tonic-gate 	 *	from the socket number.
83790Sstevel@tonic-gate 	 */
83800Sstevel@tonic-gate 	if (client->flags & CLIENT_CSI_CLIENT)
83810Sstevel@tonic-gate 	    fn = CS_GET_FUNCTION_NUMBER(*socket);
83820Sstevel@tonic-gate 
83830Sstevel@tonic-gate 	mutex_exit(&sp->lock);
83840Sstevel@tonic-gate 
83850Sstevel@tonic-gate 	/*
83860Sstevel@tonic-gate 	 * Return the found client pointer if the caller wants it.
83870Sstevel@tonic-gate 	 */
83880Sstevel@tonic-gate 	if (clp)
83890Sstevel@tonic-gate 	    *clp = client;
83900Sstevel@tonic-gate 
83910Sstevel@tonic-gate 	/*
83920Sstevel@tonic-gate 	 * Return a socket number that is made up of the socket number
83930Sstevel@tonic-gate 	 *	and the function number.
83940Sstevel@tonic-gate 	 */
83950Sstevel@tonic-gate 	*socket = CS_MAKE_SOCKET_NUMBER(sn, fn);
83960Sstevel@tonic-gate 
83970Sstevel@tonic-gate 	/*
83980Sstevel@tonic-gate 	 * Return the function number if the caller wants it.
83990Sstevel@tonic-gate 	 */
84000Sstevel@tonic-gate 	if (function)
84010Sstevel@tonic-gate 	    *function = fn;
84020Sstevel@tonic-gate 
84030Sstevel@tonic-gate 	return (CS_SUCCESS);
84040Sstevel@tonic-gate }
84050Sstevel@tonic-gate 
84060Sstevel@tonic-gate /*
84070Sstevel@tonic-gate  * cs_get_wp - returns pointer to passed window number
84080Sstevel@tonic-gate  *
84090Sstevel@tonic-gate  *	return: (cs_window_t *) - pointer to window structure
84100Sstevel@tonic-gate  *		NULL - if invalid window number passed in
84110Sstevel@tonic-gate  */
84120Sstevel@tonic-gate static cs_window_t *
84130Sstevel@tonic-gate cs_get_wp(uint32_t wn)
84140Sstevel@tonic-gate {
84150Sstevel@tonic-gate 	cs_window_t *cw;
84160Sstevel@tonic-gate 
84170Sstevel@tonic-gate 	if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY))
84180Sstevel@tonic-gate 	    return (NULL);
84190Sstevel@tonic-gate 
84200Sstevel@tonic-gate 	if ((cw = cs_find_wp(wn)) == NULL)
84210Sstevel@tonic-gate 	    return (NULL);
84220Sstevel@tonic-gate 
84230Sstevel@tonic-gate 	if (cw->state & CW_WINDOW_VALID)
84240Sstevel@tonic-gate 	    return (cw);
84250Sstevel@tonic-gate 
84260Sstevel@tonic-gate #ifdef  CS_DEBUG
84270Sstevel@tonic-gate 	if (cs_debug > 0) {
84280Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_get_wp(): wn=%d  cw=%p\n",
84290Sstevel@tonic-gate 		    (int)wn, (void *)cw);
84300Sstevel@tonic-gate 	}
84310Sstevel@tonic-gate #endif
84320Sstevel@tonic-gate 
84330Sstevel@tonic-gate 	return (NULL);
84340Sstevel@tonic-gate }
84350Sstevel@tonic-gate 
84360Sstevel@tonic-gate /*
84370Sstevel@tonic-gate  * cs_find_wp - searches window list and returns pointer to passed window
84380Sstevel@tonic-gate  *			number
84390Sstevel@tonic-gate  *
84400Sstevel@tonic-gate  *	return: (cs_window_t *) - pointer to window structure
84410Sstevel@tonic-gate  *		NULL - window not found
84420Sstevel@tonic-gate  */
84430Sstevel@tonic-gate static cs_window_t *
84440Sstevel@tonic-gate cs_find_wp(uint32_t wn)
84450Sstevel@tonic-gate {
84460Sstevel@tonic-gate 	cs_window_t *cw = cs_globals.cw;
84470Sstevel@tonic-gate 
84480Sstevel@tonic-gate 	while (cw) {
84490Sstevel@tonic-gate 	    if (cw->window_num == wn)
84500Sstevel@tonic-gate 		return (cw);
84510Sstevel@tonic-gate 	    cw = cw->next;
84520Sstevel@tonic-gate 	} /* while */
84530Sstevel@tonic-gate 
84540Sstevel@tonic-gate #ifdef  CS_DEBUG
84550Sstevel@tonic-gate 	if (cs_debug > 0) {
84560Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_find_wp(): wn=%d  window_num=%d cw=%p\n",
84570Sstevel@tonic-gate 		    (int)wn, (int)cw->window_num, (void *)cw);
84580Sstevel@tonic-gate 	}
84590Sstevel@tonic-gate #endif
84600Sstevel@tonic-gate 
84610Sstevel@tonic-gate 	return (NULL);
84620Sstevel@tonic-gate }
84630Sstevel@tonic-gate 
84640Sstevel@tonic-gate /*
84650Sstevel@tonic-gate  * cs_add_windows - adds number of windows specified in "aw" to
84660Sstevel@tonic-gate  *			the global window list; start the window
84670Sstevel@tonic-gate  *			numbering at "bn"
84680Sstevel@tonic-gate  *
84690Sstevel@tonic-gate  *	return: CS_SUCCESS - if windows added sucessfully
84700Sstevel@tonic-gate  *		CS_BAD_WINDOW - if unable to add windows
84710Sstevel@tonic-gate  *
84720Sstevel@tonic-gate  * Note: The window list must be protected by a lock by the caller.
84730Sstevel@tonic-gate  */
84740Sstevel@tonic-gate static int
84750Sstevel@tonic-gate cs_add_windows(int aw, uint32_t bn)
84760Sstevel@tonic-gate {
84770Sstevel@tonic-gate 	cs_window_t *cwp = cs_globals.cw;
84780Sstevel@tonic-gate 	cs_window_t *cw, *cwpp;
84790Sstevel@tonic-gate 
84800Sstevel@tonic-gate 	if (aw <= 0)
84810Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
84820Sstevel@tonic-gate 
84830Sstevel@tonic-gate 	while (cwp) {
84840Sstevel@tonic-gate 	    cwpp = cwp;
84850Sstevel@tonic-gate 	    cwp = cwp->next;
84860Sstevel@tonic-gate 	}
84870Sstevel@tonic-gate 
84880Sstevel@tonic-gate 	while (aw--) {
84890Sstevel@tonic-gate 	    cw = (cs_window_t *)kmem_zalloc(sizeof (cs_window_t), KM_SLEEP);
84900Sstevel@tonic-gate 
84910Sstevel@tonic-gate 	    if (cs_globals.cw == NULL) {
84920Sstevel@tonic-gate 		cs_globals.cw = cw;
84930Sstevel@tonic-gate 		cwpp = cs_globals.cw;
84940Sstevel@tonic-gate 	    } else {
84950Sstevel@tonic-gate 		cwpp->next = cw;
84960Sstevel@tonic-gate 		cwpp = cwpp->next;
84970Sstevel@tonic-gate 	    }
84980Sstevel@tonic-gate 
84990Sstevel@tonic-gate 	    cwpp->window_num = bn++;
85000Sstevel@tonic-gate 	    cwpp->state = CW_WINDOW_VALID;
85010Sstevel@tonic-gate 
85020Sstevel@tonic-gate 	} /* while (aw) */
85030Sstevel@tonic-gate 
85040Sstevel@tonic-gate 	return (CS_SUCCESS);
85050Sstevel@tonic-gate }
85060Sstevel@tonic-gate 
85070Sstevel@tonic-gate /*
85080Sstevel@tonic-gate  * cs_ss_init - initialize CS items that need to wait until we receive
85090Sstevel@tonic-gate  *			a PCE_SS_INIT_STATE/PCE_SS_STATE_INIT event
85100Sstevel@tonic-gate  *
85110Sstevel@tonic-gate  *	return: CS_SUCESS - if sucessfully initialized
85120Sstevel@tonic-gate  *		(various) if error initializing
85130Sstevel@tonic-gate  *
85140Sstevel@tonic-gate  *	At this point, we expect that Socket Services has setup the
85150Sstevel@tonic-gate  *	following global variables for us:
85160Sstevel@tonic-gate  *
85170Sstevel@tonic-gate  *		cs_socket_services - Socket Services entry point
85180Sstevel@tonic-gate  *		cis_parser - CIS parser entry point
85190Sstevel@tonic-gate  */
85200Sstevel@tonic-gate static uint32_t
85210Sstevel@tonic-gate cs_ss_init()
85220Sstevel@tonic-gate {
85230Sstevel@tonic-gate 	cs_register_cardservices_t rcs;
85240Sstevel@tonic-gate 	csregister_t csr;
85250Sstevel@tonic-gate 	uint32_t ret;
85260Sstevel@tonic-gate 
85270Sstevel@tonic-gate 	/*
85280Sstevel@tonic-gate 	 * Fill out the parameters for CISP_CIS_SETUP
85290Sstevel@tonic-gate 	 */
85300Sstevel@tonic-gate 	csr.cs_magic = PCCS_MAGIC;
85310Sstevel@tonic-gate 	csr.cs_version = PCCS_VERSION;
85320Sstevel@tonic-gate 	csr.cs_card_services = CardServices;
85330Sstevel@tonic-gate 	csr.cs_event = NULL;
85340Sstevel@tonic-gate 
85350Sstevel@tonic-gate 	/*
85360Sstevel@tonic-gate 	 * Call into the CIS module and tell it what the private
85370Sstevel@tonic-gate 	 *	Card Services entry point is. The CIS module will
85380Sstevel@tonic-gate 	 *	call us back at CardServices(CISRegister, ...)
85390Sstevel@tonic-gate 	 *	with the address of various CIS-specific global
85400Sstevel@tonic-gate 	 *	data structures.
85410Sstevel@tonic-gate 	 */
85420Sstevel@tonic-gate 	CIS_PARSER(CISP_CIS_SETUP, &csr);
85430Sstevel@tonic-gate 
85440Sstevel@tonic-gate 	/*
85450Sstevel@tonic-gate 	 * Register with the Card Services kernel stubs module
85460Sstevel@tonic-gate 	 */
85470Sstevel@tonic-gate 	rcs.magic = CS_STUBS_MAGIC;
85480Sstevel@tonic-gate 	rcs.function = CS_ENTRY_REGISTER;
85490Sstevel@tonic-gate 	rcs.cardservices = CardServices;
85500Sstevel@tonic-gate 
85510Sstevel@tonic-gate 	if ((ret = csx_register_cardservices(&rcs)) != CS_SUCCESS) {
85520Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_ss_init: can't register with "
85530Sstevel@tonic-gate 					"cs_stubs, retcode = 0x%x\n", ret);
85540Sstevel@tonic-gate 		return (ret);
85550Sstevel@tonic-gate 	} /* csx_register_cardservices */
85560Sstevel@tonic-gate 
85570Sstevel@tonic-gate 	return (CS_SUCCESS);
85580Sstevel@tonic-gate }
85590Sstevel@tonic-gate 
85600Sstevel@tonic-gate /*
85610Sstevel@tonic-gate  * cs_create_cis - reads CIS on card in socket and creates CIS lists
85620Sstevel@tonic-gate  *
85630Sstevel@tonic-gate  * Most of the work is done in the CIS module in the CISP_CIS_LIST_CREATE
85640Sstevel@tonic-gate  *	function.
85650Sstevel@tonic-gate  *
85660Sstevel@tonic-gate  * This function returns:
85670Sstevel@tonic-gate  *
85680Sstevel@tonic-gate  *	CS_SUCCESS - if the CIS lists were created sucessfully
85690Sstevel@tonic-gate  *	CS_BAD_WINDOW or CS_GENERAL_FAILURE - if CIS window could
85700Sstevel@tonic-gate  *			not be setup
85710Sstevel@tonic-gate  *	CS_BAD_CIS - if error creating CIS chains
85720Sstevel@tonic-gate  *	CS_BAD_OFFSET - if the CIS parser tried to read past the
85730Sstevel@tonic-gate  *			boundries of the allocated CIS window
85740Sstevel@tonic-gate  */
85750Sstevel@tonic-gate static int
85760Sstevel@tonic-gate cs_create_cis(cs_socket_t *sp)
85770Sstevel@tonic-gate {
85780Sstevel@tonic-gate 	uint32_t ret;
85790Sstevel@tonic-gate 
85800Sstevel@tonic-gate 	ret = (uint32_t)(uintptr_t)CIS_PARSER(CISP_CIS_LIST_CREATE,
85810Sstevel@tonic-gate 	    cis_cistpl_std_callout, sp);
85820Sstevel@tonic-gate 
85830Sstevel@tonic-gate #ifdef	CS_DEBUG
85840Sstevel@tonic-gate 	if (ret == CS_NO_CIS) {
85850Sstevel@tonic-gate 	    if (cs_debug > 0)
85860Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_create_cis: socket %d has no CIS\n",
85870Sstevel@tonic-gate 								sp->socket_num);
85880Sstevel@tonic-gate 	} else if (ret != CS_SUCCESS) {
85890Sstevel@tonic-gate 	    if (cs_debug > 0)
85900Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_create_cis: socket %d ERROR = 0x%x\n",
85910Sstevel@tonic-gate 							sp->socket_num, ret);
85920Sstevel@tonic-gate 	    return (ret);
85930Sstevel@tonic-gate 	}
85940Sstevel@tonic-gate #else
85950Sstevel@tonic-gate 	if (ret != CS_NO_CIS)
85960Sstevel@tonic-gate 	    if (ret != CS_SUCCESS)
85970Sstevel@tonic-gate 		return (ret);
85980Sstevel@tonic-gate #endif
85990Sstevel@tonic-gate 
86000Sstevel@tonic-gate 	/*
86010Sstevel@tonic-gate 	 * If this card didn't have any CIS at all, there's not much
86020Sstevel@tonic-gate 	 *	else for us to do.
86030Sstevel@tonic-gate 	 */
86040Sstevel@tonic-gate 	if (!(sp->cis_flags & CW_VALID_CIS))
86050Sstevel@tonic-gate 	    return (CS_SUCCESS);
86060Sstevel@tonic-gate 
86070Sstevel@tonic-gate 	/*
86080Sstevel@tonic-gate 	 * If this is a single-function card, we need to move the CIS list
86090Sstevel@tonic-gate 	 *	that is currently on CS_GLOBAL_CIS to the function zero
86100Sstevel@tonic-gate 	 *	CIS list.
86110Sstevel@tonic-gate 	 */
86120Sstevel@tonic-gate 	if (!(sp->cis_flags & CW_MULTI_FUNCTION_CIS)) {
86130Sstevel@tonic-gate 	    bcopy((caddr_t)&sp->cis[CS_GLOBAL_CIS],
86140Sstevel@tonic-gate 				(caddr_t)&sp->cis[0], sizeof (cis_info_t));
86150Sstevel@tonic-gate 	    bzero((caddr_t)&sp->cis[CS_GLOBAL_CIS], sizeof (cis_info_t));
86160Sstevel@tonic-gate 	} /* !CW_MULTI_FUNCTION_CIS */
86170Sstevel@tonic-gate 
86180Sstevel@tonic-gate 	return (CS_SUCCESS);
86190Sstevel@tonic-gate }
86200Sstevel@tonic-gate 
86210Sstevel@tonic-gate /*
86220Sstevel@tonic-gate  * cs_destroy_cis - destroys CIS list for socket
86230Sstevel@tonic-gate  */
86240Sstevel@tonic-gate static int
86250Sstevel@tonic-gate cs_destroy_cis(cs_socket_t *sp)
86260Sstevel@tonic-gate {
86270Sstevel@tonic-gate 	CIS_PARSER(CISP_CIS_LIST_DESTROY, sp);
86280Sstevel@tonic-gate 
86290Sstevel@tonic-gate 	return (CS_SUCCESS);
86300Sstevel@tonic-gate }
86310Sstevel@tonic-gate 
86320Sstevel@tonic-gate /*
86330Sstevel@tonic-gate  * cs_get_client_info - This function is GetClientInfo.
86340Sstevel@tonic-gate  *
86350Sstevel@tonic-gate  *    calling:	client_handle_t - client handle to get client info on
86360Sstevel@tonic-gate  *		client_info_t * - pointer to a client_info_t structure
86370Sstevel@tonic-gate  *					to return client information in
86380Sstevel@tonic-gate  *
86390Sstevel@tonic-gate  *    returns:	CS_SUCCESS - if client info retreived from client
86400Sstevel@tonic-gate  *		CS_BAD_SOCKET, CS_BAD_HANDLE - if invalid client
86410Sstevel@tonic-gate  *					handle passed in
86420Sstevel@tonic-gate  *		CS_NO_MORE_ITEMS - if client does not handle the
86430Sstevel@tonic-gate  *					CS_EVENT_CLIENT_INFO event
86440Sstevel@tonic-gate  *					or if invalid client info
86450Sstevel@tonic-gate  *					retreived from client
86460Sstevel@tonic-gate  */
86470Sstevel@tonic-gate static int
86480Sstevel@tonic-gate cs_get_client_info(client_handle_t client_handle, client_info_t *ci)
86490Sstevel@tonic-gate {
86500Sstevel@tonic-gate 	cs_socket_t *sp;
86510Sstevel@tonic-gate 	client_t *client;
86520Sstevel@tonic-gate 	client_info_t *cinfo;
86530Sstevel@tonic-gate 	int ret = CS_SUCCESS;
86540Sstevel@tonic-gate 
86550Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle)) {
86560Sstevel@tonic-gate 	    ci->Attributes = (CS_CLIENT_INFO_SOCKET_SERVICES |
86570Sstevel@tonic-gate 						CS_CLIENT_INFO_VALID);
86580Sstevel@tonic-gate 	    return (CS_SUCCESS);
86590Sstevel@tonic-gate 	} /* CLIENT_HANDLE_IS_SS */
86600Sstevel@tonic-gate 
86610Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
86620Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
86630Sstevel@tonic-gate 
86640Sstevel@tonic-gate 	mutex_enter(&sp->client_lock);
86650Sstevel@tonic-gate 	mutex_enter(&sp->lock);
86660Sstevel@tonic-gate 
86670Sstevel@tonic-gate 	if ((client = cs_find_client(client_handle, &ret)) == NULL) {
86680Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
86690Sstevel@tonic-gate 	    mutex_exit(&sp->client_lock);
86700Sstevel@tonic-gate 	    return (ret);
86710Sstevel@tonic-gate 	} /* cs_find_client */
86720Sstevel@tonic-gate 
86730Sstevel@tonic-gate 	/*
86740Sstevel@tonic-gate 	 * If this client is not handling CS_EVENT_CLIENT_INFO events,
86750Sstevel@tonic-gate 	 *	then don't bother to even wake up the event thread.
86760Sstevel@tonic-gate 	 */
86770Sstevel@tonic-gate 	if (!((client->event_mask | client->global_mask) &
86780Sstevel@tonic-gate 					CS_EVENT_CLIENT_INFO)) {
86790Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
86800Sstevel@tonic-gate 	    mutex_exit(&sp->client_lock);
86810Sstevel@tonic-gate 	    return (CS_NO_MORE_ITEMS);
86820Sstevel@tonic-gate 	} /* !CS_EVENT_CLIENT_INFO */
86830Sstevel@tonic-gate 
86840Sstevel@tonic-gate 	cinfo = &client->event_callback_args.client_info;
86850Sstevel@tonic-gate 
86860Sstevel@tonic-gate 	bzero((caddr_t)cinfo, sizeof (client_info_t));
86870Sstevel@tonic-gate 	cinfo->Attributes = (ci->Attributes & CS_CLIENT_INFO_SUBSVC_MASK);
86880Sstevel@tonic-gate 
86890Sstevel@tonic-gate 	client->events |= CS_EVENT_CLIENT_INFO;
86900Sstevel@tonic-gate 
86910Sstevel@tonic-gate 	sp->thread_state |= SOCKET_WAIT_SYNC;
86920Sstevel@tonic-gate 	mutex_exit(&sp->lock);
86930Sstevel@tonic-gate 	cv_broadcast(&sp->thread_cv);
86940Sstevel@tonic-gate 	cv_wait(&sp->caller_cv, &sp->client_lock);
86950Sstevel@tonic-gate 
86960Sstevel@tonic-gate 	if (cinfo->Attributes & CS_CLIENT_INFO_VALID) {
86970Sstevel@tonic-gate 	    bcopy((caddr_t)cinfo, (caddr_t)ci, sizeof (client_info_t));
86980Sstevel@tonic-gate 	    ci->Attributes &= (CS_CLIENT_INFO_FLAGS_MASK |
86990Sstevel@tonic-gate 					CS_CLIENT_INFO_SUBSVC_MASK);
87000Sstevel@tonic-gate 	    ci->Attributes &= ~(CS_CLIENT_INFO_CLIENT_MASK |
87010Sstevel@tonic-gate 						INFO_CARD_FLAGS_MASK |
87020Sstevel@tonic-gate 						CS_CLIENT_INFO_CLIENT_ACTIVE);
87030Sstevel@tonic-gate 	    ci->Attributes |= (client->flags & (CS_CLIENT_INFO_CLIENT_MASK |
87040Sstevel@tonic-gate 						INFO_CARD_FLAGS_MASK));
87050Sstevel@tonic-gate 	    (void) strcpy(ci->DriverName, client->driver_name);
87060Sstevel@tonic-gate 	    if (cs_card_for_client(client))
87070Sstevel@tonic-gate 		ci->Attributes |= CS_CLIENT_INFO_CLIENT_ACTIVE;
87080Sstevel@tonic-gate 	} else {
87090Sstevel@tonic-gate 	    ret = CS_NO_MORE_ITEMS;
87100Sstevel@tonic-gate 	} /* CS_CLIENT_INFO_VALID */
87110Sstevel@tonic-gate 
87120Sstevel@tonic-gate 	mutex_exit(&sp->client_lock);
87130Sstevel@tonic-gate 
87140Sstevel@tonic-gate 	return (ret);
87150Sstevel@tonic-gate }
87160Sstevel@tonic-gate 
87170Sstevel@tonic-gate /*
87180Sstevel@tonic-gate  * cs_get_firstnext_client - This function is GetFirstClient and
87190Sstevel@tonic-gate  *				GetNextClient
87200Sstevel@tonic-gate  *
87210Sstevel@tonic-gate  *    calling:	get_firstnext_client_t * - pointer to a get_firstnext_client_t
87220Sstevel@tonic-gate  *					structure to return client handle and
87230Sstevel@tonic-gate  *					attributes in
87240Sstevel@tonic-gate  *		flags - one of the following:
87250Sstevel@tonic-gate  *				CS_GET_FIRST_FLAG - get first client handle
87260Sstevel@tonic-gate  *				CS_GET_NEXT_FLAG - get next client handle
87270Sstevel@tonic-gate  *
87280Sstevel@tonic-gate  *    returns:	CS_SUCCESS - if client info retreived from client
87290Sstevel@tonic-gate  *		CS_BAD_SOCKET, CS_BAD_HANDLE - if invalid client
87300Sstevel@tonic-gate  *					handle passed in
87310Sstevel@tonic-gate  *		CS_NO_MORE_ITEMS - if client does not handle the
87320Sstevel@tonic-gate  *					CS_EVENT_CLIENT_INFO event
87330Sstevel@tonic-gate  *					or if invalid client info
87340Sstevel@tonic-gate  *					retreived from client
87350Sstevel@tonic-gate  */
87360Sstevel@tonic-gate static int
87370Sstevel@tonic-gate cs_get_firstnext_client(get_firstnext_client_t *fnc, uint32_t flags)
87380Sstevel@tonic-gate {
87390Sstevel@tonic-gate 	cs_socket_t *sp;
87400Sstevel@tonic-gate 	client_t *client;
87410Sstevel@tonic-gate 	uint32_t sn = 0;
87420Sstevel@tonic-gate 	int ret = CS_SUCCESS;
87430Sstevel@tonic-gate 
87440Sstevel@tonic-gate 	switch (flags) {
87450Sstevel@tonic-gate 	    case CS_GET_FIRST_FLAG:
87460Sstevel@tonic-gate 		if (fnc->Attributes & CS_GET_FIRSTNEXT_CLIENT_ALL_CLIENTS) {
87470Sstevel@tonic-gate 		    while (sn < cs_globals.max_socket_num) {
87480Sstevel@tonic-gate 			if ((sp = cs_get_sp(sn)) != NULL) {
87490Sstevel@tonic-gate 			    mutex_enter(&sp->client_lock);
87500Sstevel@tonic-gate 			    if ((client = sp->client_list) != NULL)
87510Sstevel@tonic-gate 				break;
87520Sstevel@tonic-gate 			    mutex_exit(&sp->client_lock);
87530Sstevel@tonic-gate 			} /* if */
87540Sstevel@tonic-gate 			sn++;
87550Sstevel@tonic-gate 		    } /* while */
87560Sstevel@tonic-gate 
87570Sstevel@tonic-gate 		    if (sn == cs_globals.max_socket_num)
87580Sstevel@tonic-gate 			return (CS_NO_MORE_ITEMS);
87590Sstevel@tonic-gate 		} else if (fnc->Attributes &
87600Sstevel@tonic-gate 					CS_GET_FIRSTNEXT_CLIENT_SOCKET_ONLY) {
87610Sstevel@tonic-gate 		    if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(fnc->Socket))) ==
87620Sstevel@tonic-gate 									NULL)
87630Sstevel@tonic-gate 			return (CS_BAD_SOCKET);
87640Sstevel@tonic-gate 		    mutex_enter(&sp->client_lock);
87650Sstevel@tonic-gate 		    if ((client = sp->client_list) == NULL) {
87660Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
87670Sstevel@tonic-gate 			return (CS_NO_MORE_ITEMS);
87680Sstevel@tonic-gate 		    }
87690Sstevel@tonic-gate 		} else {
87700Sstevel@tonic-gate 		    return (CS_BAD_ATTRIBUTE);
87710Sstevel@tonic-gate 		}
87720Sstevel@tonic-gate 
87730Sstevel@tonic-gate 		fnc->client_handle = client->client_handle;
87740Sstevel@tonic-gate 		fnc->num_clients = sp->num_clients;
87750Sstevel@tonic-gate 		mutex_exit(&sp->client_lock);
87760Sstevel@tonic-gate 		break;
87770Sstevel@tonic-gate 	    case CS_GET_NEXT_FLAG:
87780Sstevel@tonic-gate 		if (fnc->Attributes & CS_GET_FIRSTNEXT_CLIENT_ALL_CLIENTS) {
87790Sstevel@tonic-gate 		    sn = GET_CLIENT_SOCKET(fnc->client_handle);
87800Sstevel@tonic-gate 
87810Sstevel@tonic-gate 		    if ((sp = cs_get_sp(sn)) == NULL)
87820Sstevel@tonic-gate 			return (CS_BAD_SOCKET);
87830Sstevel@tonic-gate 
87840Sstevel@tonic-gate 		    mutex_enter(&sp->client_lock);
87850Sstevel@tonic-gate 		    if ((client = cs_find_client(fnc->client_handle,
87860Sstevel@tonic-gate 				&ret)) == NULL) {
87870Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
87880Sstevel@tonic-gate 			return (ret);
87890Sstevel@tonic-gate 		    }
87900Sstevel@tonic-gate 		    if ((client = client->next) == NULL) {
87910Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
87920Sstevel@tonic-gate 			sn++;
87930Sstevel@tonic-gate 			while (sn < cs_globals.max_socket_num) {
87940Sstevel@tonic-gate 			    if ((sp = cs_get_sp(sn)) != NULL) {
87950Sstevel@tonic-gate 				mutex_enter(&sp->client_lock);
87960Sstevel@tonic-gate 				if ((client = sp->client_list) != NULL)
87970Sstevel@tonic-gate 				    break;
87980Sstevel@tonic-gate 				mutex_exit(&sp->client_lock);
87990Sstevel@tonic-gate 			    } /* if */
88000Sstevel@tonic-gate 			    sn++;
88010Sstevel@tonic-gate 			} /* while */
88020Sstevel@tonic-gate 
88030Sstevel@tonic-gate 			if (sn == cs_globals.max_socket_num)
88040Sstevel@tonic-gate 			    return (CS_NO_MORE_ITEMS);
88050Sstevel@tonic-gate 		    } /* client = client->next */
88060Sstevel@tonic-gate 
88070Sstevel@tonic-gate 		} else if (fnc->Attributes &
88080Sstevel@tonic-gate 					CS_GET_FIRSTNEXT_CLIENT_SOCKET_ONLY) {
88090Sstevel@tonic-gate 		    sp = cs_get_sp(GET_CLIENT_SOCKET(fnc->client_handle));
88100Sstevel@tonic-gate 		    if (sp == NULL)
88110Sstevel@tonic-gate 			return (CS_BAD_SOCKET);
88120Sstevel@tonic-gate 		    mutex_enter(&sp->client_lock);
88130Sstevel@tonic-gate 		    if ((client = cs_find_client(fnc->client_handle,
88140Sstevel@tonic-gate 				&ret)) == NULL) {
88150Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
88160Sstevel@tonic-gate 			return (ret);
88170Sstevel@tonic-gate 		    }
88180Sstevel@tonic-gate 		    if ((client = client->next) == NULL) {
88190Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
88200Sstevel@tonic-gate 			return (CS_NO_MORE_ITEMS);
88210Sstevel@tonic-gate 		    }
88220Sstevel@tonic-gate 		} else {
88230Sstevel@tonic-gate 		    return (CS_BAD_ATTRIBUTE);
88240Sstevel@tonic-gate 		}
88250Sstevel@tonic-gate 
88260Sstevel@tonic-gate 		fnc->client_handle = client->client_handle;
88270Sstevel@tonic-gate 		fnc->num_clients = sp->num_clients;
88280Sstevel@tonic-gate 		mutex_exit(&sp->client_lock);
88290Sstevel@tonic-gate 		break;
88300Sstevel@tonic-gate 	    default:
88310Sstevel@tonic-gate 		ret = CS_BAD_ATTRIBUTE;
88320Sstevel@tonic-gate 		break;
88330Sstevel@tonic-gate 
88340Sstevel@tonic-gate 	} /* switch */
88350Sstevel@tonic-gate 
88360Sstevel@tonic-gate 	return (ret);
88370Sstevel@tonic-gate }
88380Sstevel@tonic-gate 
88390Sstevel@tonic-gate /*
88400Sstevel@tonic-gate  * cs_set_acc_attributes - converts Card Services endianness and
88410Sstevel@tonic-gate  *				data ordering values to values
88420Sstevel@tonic-gate  *				that Socket Services understands
88430Sstevel@tonic-gate  *
88440Sstevel@tonic-gate  *	calling: *sw - pointer to a set_window_t to set attributes in
88450Sstevel@tonic-gate  *		 Attributes - CS attributes
88460Sstevel@tonic-gate  */
88470Sstevel@tonic-gate static void
88480Sstevel@tonic-gate cs_set_acc_attributes(set_window_t *sw, uint32_t Attributes)
88490Sstevel@tonic-gate {
88500Sstevel@tonic-gate 	sw->attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
88510Sstevel@tonic-gate 
88520Sstevel@tonic-gate 	switch (Attributes & WIN_ACC_ENDIAN_MASK) {
88530Sstevel@tonic-gate 	    case WIN_ACC_LITTLE_ENDIAN:
88540Sstevel@tonic-gate 		sw->attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
88550Sstevel@tonic-gate 		break;
88560Sstevel@tonic-gate 	    case WIN_ACC_BIG_ENDIAN:
88570Sstevel@tonic-gate 		sw->attr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC;
88580Sstevel@tonic-gate 		break;
88590Sstevel@tonic-gate 	    case WIN_ACC_NEVER_SWAP:
88600Sstevel@tonic-gate 	    default:
88610Sstevel@tonic-gate 		sw->attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
88620Sstevel@tonic-gate 		break;
88630Sstevel@tonic-gate 	} /* switch */
88640Sstevel@tonic-gate 
88650Sstevel@tonic-gate 	switch (Attributes & WIN_ACC_ORDER_MASK) {
88660Sstevel@tonic-gate 	    case WIN_ACC_UNORDERED_OK:
88670Sstevel@tonic-gate 		sw->attr.devacc_attr_dataorder = DDI_UNORDERED_OK_ACC;
88680Sstevel@tonic-gate 		break;
88690Sstevel@tonic-gate 	    case WIN_ACC_MERGING_OK:
88700Sstevel@tonic-gate 		sw->attr.devacc_attr_dataorder = DDI_MERGING_OK_ACC;
88710Sstevel@tonic-gate 		break;
88720Sstevel@tonic-gate 	    case WIN_ACC_LOADCACHING_OK:
88730Sstevel@tonic-gate 		sw->attr.devacc_attr_dataorder = DDI_LOADCACHING_OK_ACC;
88740Sstevel@tonic-gate 		break;
88750Sstevel@tonic-gate 	    case WIN_ACC_STORECACHING_OK:
88760Sstevel@tonic-gate 		sw->attr.devacc_attr_dataorder = DDI_STORECACHING_OK_ACC;
88770Sstevel@tonic-gate 		break;
88780Sstevel@tonic-gate 	    case WIN_ACC_STRICT_ORDER:
88790Sstevel@tonic-gate 	    default:
88800Sstevel@tonic-gate 		sw->attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
88810Sstevel@tonic-gate 		break;
88820Sstevel@tonic-gate 	} /* switch */
88830Sstevel@tonic-gate }
8884