1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * PCMCIA Card Services
31*0Sstevel@tonic-gate  *	The PCMCIA Card Services is a loadable module which
32*0Sstevel@tonic-gate  *	presents the Card Services interface to client device
33*0Sstevel@tonic-gate  *	drivers.
34*0Sstevel@tonic-gate  *
35*0Sstevel@tonic-gate  *	Card Services uses Socket Services-like calls into the
36*0Sstevel@tonic-gate  *	PCMCIA nexus driver to manipulate socket and adapter
37*0Sstevel@tonic-gate  *	resources.
38*0Sstevel@tonic-gate  *
39*0Sstevel@tonic-gate  * Note that a bunch of comments are not indented correctly with the
40*0Sstevel@tonic-gate  *	code that they are commenting on. This is because cstyle is
41*0Sstevel@tonic-gate  *	is inflexible concerning 4-column indenting.
42*0Sstevel@tonic-gate  */
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate #if defined(DEBUG)
45*0Sstevel@tonic-gate #define	CS_DEBUG
46*0Sstevel@tonic-gate #endif
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate #include <sys/types.h>
49*0Sstevel@tonic-gate #include <sys/systm.h>
50*0Sstevel@tonic-gate #include <sys/user.h>
51*0Sstevel@tonic-gate #include <sys/buf.h>
52*0Sstevel@tonic-gate #include <sys/file.h>
53*0Sstevel@tonic-gate #include <sys/uio.h>
54*0Sstevel@tonic-gate #include <sys/conf.h>
55*0Sstevel@tonic-gate #include <sys/stat.h>
56*0Sstevel@tonic-gate #include <sys/autoconf.h>
57*0Sstevel@tonic-gate #include <sys/vtoc.h>
58*0Sstevel@tonic-gate #include <sys/dkio.h>
59*0Sstevel@tonic-gate #include <sys/ddi.h>
60*0Sstevel@tonic-gate #include <sys/sunddi.h>
61*0Sstevel@tonic-gate #include <sys/debug.h>
62*0Sstevel@tonic-gate #include <sys/varargs.h>
63*0Sstevel@tonic-gate #include <sys/var.h>
64*0Sstevel@tonic-gate #include <sys/proc.h>
65*0Sstevel@tonic-gate #include <sys/thread.h>
66*0Sstevel@tonic-gate #include <sys/utsname.h>
67*0Sstevel@tonic-gate #include <sys/vtrace.h>
68*0Sstevel@tonic-gate #include <sys/kstat.h>
69*0Sstevel@tonic-gate #include <sys/kmem.h>
70*0Sstevel@tonic-gate #include <sys/modctl.h>
71*0Sstevel@tonic-gate #include <sys/kobj.h>
72*0Sstevel@tonic-gate #include <sys/callb.h>
73*0Sstevel@tonic-gate #include <sys/time.h>
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate #include <sys/pctypes.h>
76*0Sstevel@tonic-gate #include <pcmcia/sys/cs_types.h>
77*0Sstevel@tonic-gate #include <sys/pcmcia.h>
78*0Sstevel@tonic-gate #include <sys/sservice.h>
79*0Sstevel@tonic-gate #include <pcmcia/sys/cis.h>
80*0Sstevel@tonic-gate #include <pcmcia/sys/cis_handlers.h>
81*0Sstevel@tonic-gate #include <pcmcia/sys/cs.h>
82*0Sstevel@tonic-gate #include <pcmcia/sys/cs_priv.h>
83*0Sstevel@tonic-gate #include <pcmcia/sys/cs_stubs.h>
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate /*
86*0Sstevel@tonic-gate  * The cs_strings header file is where all of the major strings that
87*0Sstevel@tonic-gate  *	Card Services uses are located.
88*0Sstevel@tonic-gate  */
89*0Sstevel@tonic-gate #include <pcmcia/sys/cs_strings.h>
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate /*
93*0Sstevel@tonic-gate  * Function declarations
94*0Sstevel@tonic-gate  *
95*0Sstevel@tonic-gate  * The main Card Services entry point
96*0Sstevel@tonic-gate  */
97*0Sstevel@tonic-gate int CardServices(int function, ...);
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate /*
100*0Sstevel@tonic-gate  * functions and globals used by Socket Services
101*0Sstevel@tonic-gate  *
102*0Sstevel@tonic-gate  * WAS: void *(*cis_parser)(int, ...) = NULL;
103*0Sstevel@tonic-gate  */
104*0Sstevel@tonic-gate void *(*cis_parser)(int, ...) = NULL;
105*0Sstevel@tonic-gate csfunction_t *cs_socket_services = NULL;
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate /*
108*0Sstevel@tonic-gate  * event handling functions
109*0Sstevel@tonic-gate  */
110*0Sstevel@tonic-gate static event_t ss_to_cs_events(cs_socket_t *, event_t);
111*0Sstevel@tonic-gate static event_t cs_cse2sbm(event_t);
112*0Sstevel@tonic-gate static void cs_event_thread(uint32_t);
113*0Sstevel@tonic-gate static int cs_card_insertion(cs_socket_t *, event_t);
114*0Sstevel@tonic-gate static int cs_card_removal(cs_socket_t *);
115*0Sstevel@tonic-gate static void cs_ss_thread(uint32_t);
116*0Sstevel@tonic-gate void cs_ready_timeout(void *);
117*0Sstevel@tonic-gate static int cs_card_for_client(client_t *);
118*0Sstevel@tonic-gate static int cs_request_socket_mask(client_handle_t, request_socket_mask_t *);
119*0Sstevel@tonic-gate static int cs_release_socket_mask(client_handle_t, release_socket_mask_t *);
120*0Sstevel@tonic-gate static int cs_get_event_mask(client_handle_t, sockevent_t *);
121*0Sstevel@tonic-gate static int cs_set_event_mask(client_handle_t, sockevent_t *);
122*0Sstevel@tonic-gate static int cs_event2text(event2text_t *, int);
123*0Sstevel@tonic-gate static int cs_read_event_status(cs_socket_t *, client_t *, event_t *,
124*0Sstevel@tonic-gate 						get_ss_status_t *, int);
125*0Sstevel@tonic-gate uint32_t cs_socket_event_softintr(caddr_t);
126*0Sstevel@tonic-gate void cs_event_softintr_timeout(void *);
127*0Sstevel@tonic-gate static int cs_get_status(client_handle_t, get_status_t *);
128*0Sstevel@tonic-gate static uint32_t cs_sbm2cse(uint32_t);
129*0Sstevel@tonic-gate static unsigned cs_merge_event_masks(cs_socket_t *, client_t *);
130*0Sstevel@tonic-gate static int cs_set_socket_event_mask(cs_socket_t *, unsigned);
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate /*
133*0Sstevel@tonic-gate  * SS<->CS communication and internal socket and window  handling functions
134*0Sstevel@tonic-gate  */
135*0Sstevel@tonic-gate static uint32_t cs_add_socket(uint32_t);
136*0Sstevel@tonic-gate static uint32_t cs_drop_socket(uint32_t);
137*0Sstevel@tonic-gate static cs_socket_t *cs_get_sp(uint32_t);
138*0Sstevel@tonic-gate static cs_socket_t *cs_find_sp(uint32_t);
139*0Sstevel@tonic-gate static cs_window_t *cs_get_wp(uint32_t);
140*0Sstevel@tonic-gate static cs_window_t *cs_find_wp(uint32_t);
141*0Sstevel@tonic-gate static int cs_add_windows(int, uint32_t);
142*0Sstevel@tonic-gate static uint32_t cs_ss_init();
143*0Sstevel@tonic-gate static void cs_set_acc_attributes(set_window_t *, uint32_t);
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate /*
146*0Sstevel@tonic-gate  * CIS handling functions
147*0Sstevel@tonic-gate  */
148*0Sstevel@tonic-gate cistpl_callout_t *cis_cistpl_std_callout;
149*0Sstevel@tonic-gate static int cs_parse_tuple(client_handle_t,  tuple_t *, cisparse_t *, cisdata_t);
150*0Sstevel@tonic-gate static int cs_get_tuple_data(client_handle_t, tuple_t *);
151*0Sstevel@tonic-gate static int cs_validate_cis(client_handle_t, cisinfo_t *);
152*0Sstevel@tonic-gate static int cs_get_firstnext_tuple(client_handle_t, tuple_t *, uint32_t);
153*0Sstevel@tonic-gate static int cs_create_cis(cs_socket_t *);
154*0Sstevel@tonic-gate static int cs_destroy_cis(cs_socket_t *);
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate /*
157*0Sstevel@tonic-gate  * client handling functions
158*0Sstevel@tonic-gate  */
159*0Sstevel@tonic-gate unsigned cs_create_next_client_minor(unsigned, unsigned);
160*0Sstevel@tonic-gate static client_t *cs_find_client(client_handle_t, int *);
161*0Sstevel@tonic-gate static client_handle_t cs_create_client_handle(unsigned, client_t *);
162*0Sstevel@tonic-gate static int cs_destroy_client_handle(client_handle_t);
163*0Sstevel@tonic-gate static int cs_register_client(client_handle_t *, client_reg_t *);
164*0Sstevel@tonic-gate static int cs_deregister_client(client_handle_t);
165*0Sstevel@tonic-gate static int cs_deregister_mtd(client_handle_t);
166*0Sstevel@tonic-gate static void cs_clear_superclient_lock(int);
167*0Sstevel@tonic-gate static int cs_add_client_to_socket(unsigned, client_handle_t *,
168*0Sstevel@tonic-gate 						client_reg_t *, int);
169*0Sstevel@tonic-gate static int cs_get_client_info(client_handle_t, client_info_t *);
170*0Sstevel@tonic-gate static int cs_get_firstnext_client(get_firstnext_client_t *, uint32_t);
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate /*
173*0Sstevel@tonic-gate  * window handling functions
174*0Sstevel@tonic-gate  */
175*0Sstevel@tonic-gate static int cs_request_window(client_handle_t, window_handle_t *, win_req_t *);
176*0Sstevel@tonic-gate static int cs_release_window(window_handle_t);
177*0Sstevel@tonic-gate static int cs_modify_window(window_handle_t, modify_win_t *);
178*0Sstevel@tonic-gate static int cs_modify_mem_window(window_handle_t, modify_win_t *, win_req_t *,
179*0Sstevel@tonic-gate 									int);
180*0Sstevel@tonic-gate static int cs_map_mem_page(window_handle_t, map_mem_page_t *);
181*0Sstevel@tonic-gate static int cs_find_mem_window(uint32_t, win_req_t *, uint32_t *);
182*0Sstevel@tonic-gate static int cs_memwin_space_and_map_ok(inquire_window_t *, win_req_t *);
183*0Sstevel@tonic-gate static int cs_valid_window_speed(inquire_window_t *, uint32_t);
184*0Sstevel@tonic-gate static window_handle_t cs_create_window_handle(uint32_t);
185*0Sstevel@tonic-gate static cs_window_t *cs_find_window(window_handle_t);
186*0Sstevel@tonic-gate static int cs_find_io_win(uint32_t, iowin_char_t *, uint32_t *, uint32_t *);
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate /*
189*0Sstevel@tonic-gate  * IO, IRQ and configuration handling functions
190*0Sstevel@tonic-gate  */
191*0Sstevel@tonic-gate static int cs_request_io(client_handle_t, io_req_t *);
192*0Sstevel@tonic-gate static int cs_release_io(client_handle_t, io_req_t *);
193*0Sstevel@tonic-gate static int cs_allocate_io_win(uint32_t, uint32_t, uint32_t *);
194*0Sstevel@tonic-gate static int cs_setup_io_win(uint32_t, uint32_t, baseaddru_t *,
195*0Sstevel@tonic-gate 					uint32_t *, uint32_t, uint32_t);
196*0Sstevel@tonic-gate static int cs_request_irq(client_handle_t, irq_req_t *);
197*0Sstevel@tonic-gate static int cs_release_irq(client_handle_t, irq_req_t *);
198*0Sstevel@tonic-gate static int cs_request_configuration(client_handle_t, config_req_t *);
199*0Sstevel@tonic-gate static int cs_release_configuration(client_handle_t, release_config_t *);
200*0Sstevel@tonic-gate static int cs_modify_configuration(client_handle_t, modify_config_t *);
201*0Sstevel@tonic-gate static int cs_access_configuration_register(client_handle_t,
202*0Sstevel@tonic-gate 						access_config_reg_t *);
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate /*
205*0Sstevel@tonic-gate  * RESET and general info functions
206*0Sstevel@tonic-gate  */
207*0Sstevel@tonic-gate static int cs_reset_function(client_handle_t, reset_function_t *);
208*0Sstevel@tonic-gate static int cs_get_configuration_info(client_handle_t *,
209*0Sstevel@tonic-gate 						get_configuration_info_t *);
210*0Sstevel@tonic-gate static int cs_get_cardservices_info(client_handle_t,
211*0Sstevel@tonic-gate 						get_cardservices_info_t *);
212*0Sstevel@tonic-gate static int cs_get_physical_adapter_info(client_handle_t,
213*0Sstevel@tonic-gate 						get_physical_adapter_info_t *);
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate /*
216*0Sstevel@tonic-gate  * general functions
217*0Sstevel@tonic-gate  */
218*0Sstevel@tonic-gate static uint32_t cs_get_socket(client_handle_t, uint32_t *, uint32_t *,
219*0Sstevel@tonic-gate 					cs_socket_t **, client_t **);
220*0Sstevel@tonic-gate static int cs_convert_speed(convert_speed_t *);
221*0Sstevel@tonic-gate static int cs_convert_size(convert_size_t *);
222*0Sstevel@tonic-gate static char *cs_error2text(int, int);
223*0Sstevel@tonic-gate static int cs_map_log_socket(client_handle_t, map_log_socket_t *);
224*0Sstevel@tonic-gate static int cs_convert_powerlevel(uint32_t, uint32_t, uint32_t, unsigned *);
225*0Sstevel@tonic-gate static int cs_make_device_node(client_handle_t, make_device_node_t *);
226*0Sstevel@tonic-gate static int cs_remove_device_node(client_handle_t, remove_device_node_t *);
227*0Sstevel@tonic-gate static int cs_ddi_info(cs_ddi_info_t *);
228*0Sstevel@tonic-gate static int cs_init_cis_window(cs_socket_t *, uint32_t *, acc_handle_t *,
229*0Sstevel@tonic-gate 				uint32_t);
230*0Sstevel@tonic-gate static int cs_sys_ctl(cs_sys_ctl_t *);
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate /*
233*0Sstevel@tonic-gate  * global variables
234*0Sstevel@tonic-gate  */
235*0Sstevel@tonic-gate static int cs_max_client_handles = CS_MAX_CLIENTS;
236*0Sstevel@tonic-gate static client_t cs_socket_services_client;	/* global SS client */
237*0Sstevel@tonic-gate static client_types_t client_types[MAX_CLIENT_TYPES];
238*0Sstevel@tonic-gate static cs_globals_t cs_globals;
239*0Sstevel@tonic-gate int cs_reset_timeout_time = RESET_TIMEOUT_TIME;
240*0Sstevel@tonic-gate int cs_rc1_delay = CS_RC1_DELAY;
241*0Sstevel@tonic-gate int cs_rc2_delay = CS_RC2_DELAY;
242*0Sstevel@tonic-gate int cs_rq_delay = CS_RQ_DELAY;
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate #ifdef	CS_DEBUG
245*0Sstevel@tonic-gate int	cs_debug = 0;
246*0Sstevel@tonic-gate #endif
247*0Sstevel@tonic-gate 
248*0Sstevel@tonic-gate /*
249*0Sstevel@tonic-gate  * cs_init - Initialize CS internal structures, databases, and state,
250*0Sstevel@tonic-gate  *		and register with SS
251*0Sstevel@tonic-gate  *
252*0Sstevel@tonic-gate  * XXX - Need to make sure that if we fail at any point that we free
253*0Sstevel@tonic-gate  *		any resources that we allocated, as well as kill any
254*0Sstevel@tonic-gate  *		threads that may have been started.
255*0Sstevel@tonic-gate  */
256*0Sstevel@tonic-gate int
257*0Sstevel@tonic-gate cs_init()
258*0Sstevel@tonic-gate {
259*0Sstevel@tonic-gate 	client_types_t *ct;
260*0Sstevel@tonic-gate 	client_t *client;
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 	/*
263*0Sstevel@tonic-gate 	 * Initialize the CS global structure
264*0Sstevel@tonic-gate 	 */
265*0Sstevel@tonic-gate 	bzero((caddr_t)&cs_globals, sizeof (cs_globals_t));
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 	mutex_init(&cs_globals.global_lock, NULL, MUTEX_DRIVER, NULL);
268*0Sstevel@tonic-gate 	mutex_init(&cs_globals.window_lock, NULL, MUTEX_DRIVER, NULL);
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	cs_globals.init_state = GLOBAL_INIT_STATE_MUTEX;
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 	/*
273*0Sstevel@tonic-gate 	 * Set up the global Socket Services client, since we're going to
274*0Sstevel@tonic-gate 	 *	need it once we register with SS.
275*0Sstevel@tonic-gate 	 */
276*0Sstevel@tonic-gate 	client = &cs_socket_services_client;
277*0Sstevel@tonic-gate 	bzero((caddr_t)client, sizeof (client_t));
278*0Sstevel@tonic-gate 	client->client_handle = CS_SS_CLIENT_HANDLE;
279*0Sstevel@tonic-gate 	client->flags |= (INFO_SOCKET_SERVICES | CLIENT_CARD_INSERTED);
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate 	/*
282*0Sstevel@tonic-gate 	 * Setup the client type structure - this is used in the socket event
283*0Sstevel@tonic-gate 	 *	thread to sequence the delivery of events to all clients on
284*0Sstevel@tonic-gate 	 *	the socket.
285*0Sstevel@tonic-gate 	 */
286*0Sstevel@tonic-gate 	ct = &client_types[0];
287*0Sstevel@tonic-gate 	ct->type = INFO_IO_CLIENT;
288*0Sstevel@tonic-gate 	ct->order = CLIENT_EVENTS_LIFO;
289*0Sstevel@tonic-gate 	ct->next = &client_types[1];
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	ct = ct->next;
292*0Sstevel@tonic-gate 	ct->type = INFO_MTD_CLIENT;
293*0Sstevel@tonic-gate 	ct->order = CLIENT_EVENTS_FIFO;
294*0Sstevel@tonic-gate 	ct->next = &client_types[2];
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	ct = ct->next;
297*0Sstevel@tonic-gate 	ct->type = INFO_MEM_CLIENT;
298*0Sstevel@tonic-gate 	ct->order = CLIENT_EVENTS_FIFO;
299*0Sstevel@tonic-gate 	ct->next = NULL;
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 	return (CS_SUCCESS);
302*0Sstevel@tonic-gate }
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate /*
305*0Sstevel@tonic-gate  * cs_deinit - Deinitialize CS
306*0Sstevel@tonic-gate  *
307*0Sstevel@tonic-gate  * This function cleans up any allocated resources, stops any running threads,
308*0Sstevel@tonic-gate  *	destroys any mutexes and condition variables, and finally frees up the
309*0Sstevel@tonic-gate  *	global socket and window structure arrays.
310*0Sstevel@tonic-gate  */
311*0Sstevel@tonic-gate int
312*0Sstevel@tonic-gate cs_deinit()
313*0Sstevel@tonic-gate {
314*0Sstevel@tonic-gate 	cs_socket_t *sp;
315*0Sstevel@tonic-gate 	int sn, have_clients = 0, have_sockets = 0;
316*0Sstevel@tonic-gate 	cs_register_cardservices_t rcs;
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate #if defined(CS_DEBUG)
319*0Sstevel@tonic-gate 	if (cs_debug > 1)
320*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "CS: cs_deinit\n");
321*0Sstevel@tonic-gate #endif
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate 	/*
324*0Sstevel@tonic-gate 	 * Deregister with the Card Services kernel stubs module
325*0Sstevel@tonic-gate 	 */
326*0Sstevel@tonic-gate 	rcs.magic = CS_STUBS_MAGIC;
327*0Sstevel@tonic-gate 	rcs.function = CS_ENTRY_DEREGISTER;
328*0Sstevel@tonic-gate 	(void) csx_register_cardservices(&rcs);
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 	/*
331*0Sstevel@tonic-gate 	 * Set the GLOBAL_INIT_STATE_NO_CLIENTS flag to prevent new clients
332*0Sstevel@tonic-gate 	 *	from registering.
333*0Sstevel@tonic-gate 	 */
334*0Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
335*0Sstevel@tonic-gate 	cs_globals.init_state |= GLOBAL_INIT_STATE_NO_CLIENTS;
336*0Sstevel@tonic-gate 	mutex_exit(&cs_globals.global_lock);
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	/*
339*0Sstevel@tonic-gate 	 * Go through each socket and make sure that there are no clients
340*0Sstevel@tonic-gate 	 *	on any of the sockets.  If there are, we can't deinit until
341*0Sstevel@tonic-gate 	 *	all the clients for every socket are gone.
342*0Sstevel@tonic-gate 	 */
343*0Sstevel@tonic-gate 	for (sn = 0; sn < cs_globals.max_socket_num; sn++) {
344*0Sstevel@tonic-gate 	    if ((sp = cs_get_sp(sn)) != NULL) {
345*0Sstevel@tonic-gate 		have_sockets++;
346*0Sstevel@tonic-gate 		if (sp->client_list) {
347*0Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_deinit: cannot unload module since "
348*0Sstevel@tonic-gate 				"socket %d has registered clients\n", sn);
349*0Sstevel@tonic-gate 		    have_clients++;
350*0Sstevel@tonic-gate 		}
351*0Sstevel@tonic-gate 	    }
352*0Sstevel@tonic-gate 	}
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 	/*
355*0Sstevel@tonic-gate 	 * We don't allow unload if there are any clients registered
356*0Sstevel@tonic-gate 	 *	or if there are still sockets that are active.
357*0Sstevel@tonic-gate 	 */
358*0Sstevel@tonic-gate 	if ((have_clients > 0) || (have_sockets > 0))
359*0Sstevel@tonic-gate 	    return (BAD_FUNCTION);
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate #ifdef	XXX
362*0Sstevel@tonic-gate 	/*
363*0Sstevel@tonic-gate 	 * If one or more sockets have been added, we need to deallocate
364*0Sstevel@tonic-gate 	 *	the resources associated with those sockets.
365*0Sstevel@tonic-gate 	 */
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 	/*
368*0Sstevel@tonic-gate 	 * First, tell Socket Services that we're leaving, so that we
369*0Sstevel@tonic-gate 	 *	don't get any more event callbacks.
370*0Sstevel@tonic-gate 	 */
371*0Sstevel@tonic-gate 	SocketServices(CSUnregister);
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 	/*
374*0Sstevel@tonic-gate 	 * Wait for the soft int timer to tell us it's done
375*0Sstevel@tonic-gate 	 */
376*0Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
377*0Sstevel@tonic-gate 	cs_globals.init_state |= GLOBAL_INIT_STATE_UNLOADING;
378*0Sstevel@tonic-gate 	mutex_exit(&cs_globals.global_lock);
379*0Sstevel@tonic-gate 	UNTIMEOUT(cs_globals.sotfint_tmo);
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate 	/*
382*0Sstevel@tonic-gate 	 * Remove the soft interrupt handler.
383*0Sstevel@tonic-gate 	 */
384*0Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
385*0Sstevel@tonic-gate 	if (cs_globals.init_state & GLOBAL_INIT_STATE_SOFTINTR) {
386*0Sstevel@tonic-gate 	    ddi_remove_softintr(cs_globals.softint_id);
387*0Sstevel@tonic-gate 	    cs_globals.init_state &= ~GLOBAL_INIT_STATE_SOFTINTR;
388*0Sstevel@tonic-gate 	}
389*0Sstevel@tonic-gate 	mutex_exit(&cs_globals.global_lock);
390*0Sstevel@tonic-gate 
391*0Sstevel@tonic-gate 	return (CS_SUCCESS);
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate 	/*
394*0Sstevel@tonic-gate 	 * Go through each socket and free any resource allocated to that
395*0Sstevel@tonic-gate 	 *	socket, as well as any mutexs and condition variables.
396*0Sstevel@tonic-gate 	 */
397*0Sstevel@tonic-gate 	for (sn = 0; sn < cs_globals.max_socket_num; sn++) {
398*0Sstevel@tonic-gate 	    set_socket_t set_socket;
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate 	    if ((sp = cs_get_sp(sn)) != NULL) {
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 		/*
403*0Sstevel@tonic-gate 		 * untimeout possible pending ready/busy timer
404*0Sstevel@tonic-gate 		 */
405*0Sstevel@tonic-gate 		UNTIMEOUT(sp->rdybsy_tmo_id);
406*0Sstevel@tonic-gate 
407*0Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
408*0Sstevel@tonic-gate 		    mutex_enter(&sp->lock);
409*0Sstevel@tonic-gate 		sp->flags = SOCKET_UNLOAD_MODULE;
410*0Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_SOFTINTR)
411*0Sstevel@tonic-gate 		    sp->init_state &= ~SOCKET_INIT_STATE_SOFTINTR;
412*0Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
413*0Sstevel@tonic-gate 		    mutex_exit(&sp->lock);
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
416*0Sstevel@tonic-gate 		    mutex_enter(&sp->cis_lock);
417*0Sstevel@tonic-gate 		(void) cs_destroy_cis(sp);
418*0Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
419*0Sstevel@tonic-gate 		    mutex_exit(&sp->cis_lock);
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate 		/*
422*0Sstevel@tonic-gate 		 * Tell the event handler thread that we want it to exit, then
423*0Sstevel@tonic-gate 		 *	wait around until it tells us that it has exited.
424*0Sstevel@tonic-gate 		 */
425*0Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
426*0Sstevel@tonic-gate 		    mutex_enter(&sp->client_lock);
427*0Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_THREAD) {
428*0Sstevel@tonic-gate 		    sp->thread_state = SOCKET_THREAD_EXIT;
429*0Sstevel@tonic-gate 		    cv_broadcast(&sp->thread_cv);
430*0Sstevel@tonic-gate 		    cv_wait(&sp->caller_cv, &sp->client_lock);
431*0Sstevel@tonic-gate 		}
432*0Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
433*0Sstevel@tonic-gate 		    mutex_exit(&sp->client_lock);
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 		/*
436*0Sstevel@tonic-gate 		 * Tell the SS work thread that we want it to exit, then
437*0Sstevel@tonic-gate 		 *	wait around until it tells us that it has exited.
438*0Sstevel@tonic-gate 		 */
439*0Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
440*0Sstevel@tonic-gate 		    mutex_enter(&sp->ss_thread_lock);
441*0Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_SS_THREAD) {
442*0Sstevel@tonic-gate 		    sp->ss_thread_state = SOCKET_THREAD_EXIT;
443*0Sstevel@tonic-gate 		    cv_broadcast(&sp->ss_thread_cv);
444*0Sstevel@tonic-gate 		    cv_wait(&sp->ss_caller_cv, &sp->ss_thread_lock);
445*0Sstevel@tonic-gate 		}
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX)
448*0Sstevel@tonic-gate 		    mutex_exit(&sp->ss_thread_lock);
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 		/*
451*0Sstevel@tonic-gate 		 * Free the mutexii and condition variables that we used.
452*0Sstevel@tonic-gate 		 */
453*0Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_MUTEX) {
454*0Sstevel@tonic-gate 		    mutex_destroy(&sp->lock);
455*0Sstevel@tonic-gate 		    mutex_destroy(&sp->client_lock);
456*0Sstevel@tonic-gate 		    mutex_destroy(&sp->cis_lock);
457*0Sstevel@tonic-gate 		    mutex_destroy(&sp->ss_thread_lock);
458*0Sstevel@tonic-gate 		}
459*0Sstevel@tonic-gate 
460*0Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_CV) {
461*0Sstevel@tonic-gate 		    cv_destroy(&sp->thread_cv);
462*0Sstevel@tonic-gate 		    cv_destroy(&sp->caller_cv);
463*0Sstevel@tonic-gate 		    cv_destroy(&sp->reset_cv);
464*0Sstevel@tonic-gate 		    cv_destroy(&sp->ss_thread_cv);
465*0Sstevel@tonic-gate 		    cv_destroy(&sp->ss_caller_cv);
466*0Sstevel@tonic-gate 		}
467*0Sstevel@tonic-gate 
468*0Sstevel@tonic-gate #ifdef	USE_IOMMAP_WINDOW
469*0Sstevel@tonic-gate 		/*
470*0Sstevel@tonic-gate 		 * Free the memory-mapped IO structure if we allocated one.
471*0Sstevel@tonic-gate 		 */
472*0Sstevel@tonic-gate 		if (sp->io_mmap_window)
473*0Sstevel@tonic-gate 		    kmem_free(sp->io_mmap_window, sizeof (io_mmap_window_t));
474*0Sstevel@tonic-gate #endif	/* USE_IOMMAP_WINDOW */
475*0Sstevel@tonic-gate 
476*0Sstevel@tonic-gate 		/*
477*0Sstevel@tonic-gate 		 * Return the socket to memory-only mode and turn off the
478*0Sstevel@tonic-gate 		 *	socket power.
479*0Sstevel@tonic-gate 		 */
480*0Sstevel@tonic-gate 		sp->event_mask = 0;
481*0Sstevel@tonic-gate 		set_socket.socket = sp->socket_num;
482*0Sstevel@tonic-gate 		set_socket.SCIntMask = 0;
483*0Sstevel@tonic-gate 		set_socket.IREQRouting = 0;
484*0Sstevel@tonic-gate 		set_socket.IFType = IF_MEMORY;
485*0Sstevel@tonic-gate 		set_socket.CtlInd = 0; /* turn off controls and indicators */
486*0Sstevel@tonic-gate 		set_socket.State = (unsigned)~0; /* clear latched state bits */
487*0Sstevel@tonic-gate 
488*0Sstevel@tonic-gate 		(void) cs_convert_powerlevel(sp->socket_num, 0, VCC,
489*0Sstevel@tonic-gate 						&set_socket.VccLevel);
490*0Sstevel@tonic-gate 		(void) cs_convert_powerlevel(sp->socket_num, 0, VPP1,
491*0Sstevel@tonic-gate 						&set_socket.Vpp1Level);
492*0Sstevel@tonic-gate 		(void) cs_convert_powerlevel(sp->socket_num, 0, VPP2,
493*0Sstevel@tonic-gate 						&set_socket.Vpp2Level);
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate 		/*
496*0Sstevel@tonic-gate 		 * If we fail this call, there's not much we can do, so
497*0Sstevel@tonic-gate 		 *	just continue with the resource deallocation.
498*0Sstevel@tonic-gate 		 */
499*0Sstevel@tonic-gate 		if ((ret =
500*0Sstevel@tonic-gate 			SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
501*0Sstevel@tonic-gate 		    cmn_err(CE_CONT,
502*0Sstevel@tonic-gate 			"cs_deinit: socket %d SS_SetSocket failure %d\n",
503*0Sstevel@tonic-gate 							sp->socket_num, ret);
504*0Sstevel@tonic-gate 		}
505*0Sstevel@tonic-gate 	    } /* cs_get_sp */
506*0Sstevel@tonic-gate 	} /* for (sn) */
507*0Sstevel@tonic-gate #endif	/* XXX */
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate 	/*
510*0Sstevel@tonic-gate 	 * Destroy the global mutexii.
511*0Sstevel@tonic-gate 	 */
512*0Sstevel@tonic-gate 	mutex_destroy(&cs_globals.global_lock);
513*0Sstevel@tonic-gate 	mutex_destroy(&cs_globals.window_lock);
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate #ifdef	XXX
516*0Sstevel@tonic-gate 	/*
517*0Sstevel@tonic-gate 	 * Free the global "super-client" structure
518*0Sstevel@tonic-gate 	 */
519*0Sstevel@tonic-gate 	if (cs_globals.sclient_list)
520*0Sstevel@tonic-gate 	    kmem_free(cs_globals.sclient_list,
521*0Sstevel@tonic-gate 		(cs_globals.num_sockets * sizeof (struct sclient_list_t)));
522*0Sstevel@tonic-gate 	cs_globals.sclient_list = NULL;
523*0Sstevel@tonic-gate #endif	/* XXX */
524*0Sstevel@tonic-gate 
525*0Sstevel@tonic-gate 	return (CS_SUCCESS);
526*0Sstevel@tonic-gate }
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate /*
529*0Sstevel@tonic-gate  * ==== drip, drip, drip - the Card Services waterfall :-) ====
530*0Sstevel@tonic-gate  */
531*0Sstevel@tonic-gate 
532*0Sstevel@tonic-gate /*
533*0Sstevel@tonic-gate  * CardServices - general Card Services entry point for CS clients
534*0Sstevel@tonic-gate  *			and Socket Services; the address of this
535*0Sstevel@tonic-gate  *			function is handed to SS via the CSRegister
536*0Sstevel@tonic-gate  *			SS call
537*0Sstevel@tonic-gate  */
538*0Sstevel@tonic-gate int
539*0Sstevel@tonic-gate CardServices(int function, ...)
540*0Sstevel@tonic-gate {
541*0Sstevel@tonic-gate 	va_list arglist;
542*0Sstevel@tonic-gate 	int retcode = CS_UNSUPPORTED_FUNCTION;
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate 	cs_socket_t	*socp;
545*0Sstevel@tonic-gate 	uint32_t	*offp;
546*0Sstevel@tonic-gate 	acc_handle_t	*hp;
547*0Sstevel@tonic-gate 	client_handle_t	ch;
548*0Sstevel@tonic-gate 	client_handle_t	*chp;
549*0Sstevel@tonic-gate 	window_handle_t	wh;
550*0Sstevel@tonic-gate 	window_handle_t	*whp;
551*0Sstevel@tonic-gate 	tuple_t		*tuple;
552*0Sstevel@tonic-gate 	cisparse_t	*cisparse;
553*0Sstevel@tonic-gate 
554*0Sstevel@tonic-gate #ifdef	CS_DEBUG
555*0Sstevel@tonic-gate 	if (cs_debug > 127) {
556*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "CardServices: called for function %s (0x%x)\n",
557*0Sstevel@tonic-gate 				cs_error2text(function, CSFUN2TEXT_FUNCTION),
558*0Sstevel@tonic-gate 				function);
559*0Sstevel@tonic-gate 	}
560*0Sstevel@tonic-gate #endif
561*0Sstevel@tonic-gate 
562*0Sstevel@tonic-gate 	va_start(arglist, function);
563*0Sstevel@tonic-gate 
564*0Sstevel@tonic-gate 	/*
565*0Sstevel@tonic-gate 	 * Here's the Card Services waterfall
566*0Sstevel@tonic-gate 	 */
567*0Sstevel@tonic-gate 	switch (function) {
568*0Sstevel@tonic-gate 	/*
569*0Sstevel@tonic-gate 	 * We got here as a result of the CIS module calling us
570*0Sstevel@tonic-gate 	 *	in response to cs_ss_init() calling the CIS module
571*0Sstevel@tonic-gate 	 *	at CIS_PARSER(CISP_CIS_SETUP, ...)
572*0Sstevel@tonic-gate 	 */
573*0Sstevel@tonic-gate 	    case CISRegister: {
574*0Sstevel@tonic-gate 		cisregister_t *cisr;
575*0Sstevel@tonic-gate 
576*0Sstevel@tonic-gate 		    cisr = va_arg(arglist, cisregister_t *);
577*0Sstevel@tonic-gate 
578*0Sstevel@tonic-gate 		    if (cisr->cis_magic != PCCS_MAGIC ||
579*0Sstevel@tonic-gate 			cisr->cis_version != PCCS_VERSION) {
580*0Sstevel@tonic-gate 			    cmn_err(CE_WARN,
581*0Sstevel@tonic-gate 				"CS: CISRegister (%lx, %lx, %lx, %lx) *ERROR*",
582*0Sstevel@tonic-gate 					(long)cisr->cis_magic,
583*0Sstevel@tonic-gate 					(long)cisr->cis_version,
584*0Sstevel@tonic-gate 					(long)cisr->cis_parser,
585*0Sstevel@tonic-gate 					(long)cisr->cistpl_std_callout);
586*0Sstevel@tonic-gate 			retcode = CS_BAD_ARGS;
587*0Sstevel@tonic-gate 		    } else {
588*0Sstevel@tonic-gate 			/*
589*0Sstevel@tonic-gate 			 * Replace the CIS Parser entry point if
590*0Sstevel@tonic-gate 			 *	necessary.
591*0Sstevel@tonic-gate 			 */
592*0Sstevel@tonic-gate 			if (cisr->cis_parser != NULL)
593*0Sstevel@tonic-gate 			    cis_parser = cisr->cis_parser;
594*0Sstevel@tonic-gate 			cis_cistpl_std_callout = cisr->cistpl_std_callout;
595*0Sstevel@tonic-gate 			retcode = CS_SUCCESS;
596*0Sstevel@tonic-gate 		    }
597*0Sstevel@tonic-gate 		}
598*0Sstevel@tonic-gate 		break;
599*0Sstevel@tonic-gate 	    case CISUnregister:	/* XXX - should we do some more checking */
600*0Sstevel@tonic-gate 		/* XXX - need to protect this by a mutex */
601*0Sstevel@tonic-gate 		cis_parser = NULL;
602*0Sstevel@tonic-gate 		cis_cistpl_std_callout = NULL;
603*0Sstevel@tonic-gate 		retcode = CS_SUCCESS;
604*0Sstevel@tonic-gate 		break;
605*0Sstevel@tonic-gate 	    case InitCISWindow:
606*0Sstevel@tonic-gate 		socp	= va_arg(arglist, cs_socket_t *);
607*0Sstevel@tonic-gate 		offp	= va_arg(arglist, uint32_t *);
608*0Sstevel@tonic-gate 		hp	= va_arg(arglist, acc_handle_t *);
609*0Sstevel@tonic-gate 		retcode = cs_init_cis_window(socp, offp, hp,
610*0Sstevel@tonic-gate 				va_arg(arglist, uint32_t));
611*0Sstevel@tonic-gate 		break;
612*0Sstevel@tonic-gate 	    case RegisterClient:
613*0Sstevel@tonic-gate 		chp = va_arg(arglist, client_handle_t *),
614*0Sstevel@tonic-gate 		retcode = cs_register_client(chp,
615*0Sstevel@tonic-gate 				va_arg(arglist, client_reg_t *));
616*0Sstevel@tonic-gate 		break;
617*0Sstevel@tonic-gate 	    case DeregisterClient:
618*0Sstevel@tonic-gate 		retcode = cs_deregister_client(
619*0Sstevel@tonic-gate 				va_arg(arglist, client_handle_t));
620*0Sstevel@tonic-gate 		break;
621*0Sstevel@tonic-gate 	    case GetStatus:
622*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
623*0Sstevel@tonic-gate 		retcode = cs_get_status(ch,
624*0Sstevel@tonic-gate 				va_arg(arglist, get_status_t *));
625*0Sstevel@tonic-gate 		break;
626*0Sstevel@tonic-gate 	    case ResetFunction:
627*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
628*0Sstevel@tonic-gate 		retcode = cs_reset_function(ch,
629*0Sstevel@tonic-gate 				va_arg(arglist, reset_function_t *));
630*0Sstevel@tonic-gate 		break;
631*0Sstevel@tonic-gate 	    case SetEventMask:
632*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
633*0Sstevel@tonic-gate 		retcode = cs_set_event_mask(ch,
634*0Sstevel@tonic-gate 				va_arg(arglist, sockevent_t *));
635*0Sstevel@tonic-gate 		break;
636*0Sstevel@tonic-gate 	    case GetEventMask:
637*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
638*0Sstevel@tonic-gate 		retcode = cs_get_event_mask(ch,
639*0Sstevel@tonic-gate 				va_arg(arglist, sockevent_t *));
640*0Sstevel@tonic-gate 		break;
641*0Sstevel@tonic-gate 	    case RequestIO:
642*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
643*0Sstevel@tonic-gate 		retcode = cs_request_io(ch,
644*0Sstevel@tonic-gate 				va_arg(arglist, io_req_t *));
645*0Sstevel@tonic-gate 		break;
646*0Sstevel@tonic-gate 	    case ReleaseIO:
647*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
648*0Sstevel@tonic-gate 		retcode = cs_release_io(ch,
649*0Sstevel@tonic-gate 				va_arg(arglist, io_req_t *));
650*0Sstevel@tonic-gate 		break;
651*0Sstevel@tonic-gate 	    case RequestIRQ:
652*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
653*0Sstevel@tonic-gate 		retcode = cs_request_irq(ch,
654*0Sstevel@tonic-gate 				va_arg(arglist, irq_req_t *));
655*0Sstevel@tonic-gate 		break;
656*0Sstevel@tonic-gate 	    case ReleaseIRQ:
657*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
658*0Sstevel@tonic-gate 		retcode = cs_release_irq(ch,
659*0Sstevel@tonic-gate 				va_arg(arglist, irq_req_t *));
660*0Sstevel@tonic-gate 		break;
661*0Sstevel@tonic-gate 	    case RequestWindow:
662*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
663*0Sstevel@tonic-gate 		whp = va_arg(arglist, window_handle_t *);
664*0Sstevel@tonic-gate 		retcode = cs_request_window(ch, whp,
665*0Sstevel@tonic-gate 				va_arg(arglist, win_req_t *));
666*0Sstevel@tonic-gate 		break;
667*0Sstevel@tonic-gate 	    case ReleaseWindow:
668*0Sstevel@tonic-gate 		retcode = cs_release_window(
669*0Sstevel@tonic-gate 				va_arg(arglist, window_handle_t));
670*0Sstevel@tonic-gate 		break;
671*0Sstevel@tonic-gate 	    case ModifyWindow:
672*0Sstevel@tonic-gate 		wh = va_arg(arglist, window_handle_t);
673*0Sstevel@tonic-gate 		retcode = cs_modify_window(wh,
674*0Sstevel@tonic-gate 				va_arg(arglist, modify_win_t *));
675*0Sstevel@tonic-gate 		break;
676*0Sstevel@tonic-gate 	    case MapMemPage:
677*0Sstevel@tonic-gate 		wh = va_arg(arglist, window_handle_t);
678*0Sstevel@tonic-gate 		retcode = cs_map_mem_page(wh,
679*0Sstevel@tonic-gate 				va_arg(arglist, map_mem_page_t *));
680*0Sstevel@tonic-gate 		break;
681*0Sstevel@tonic-gate 	    case RequestSocketMask:
682*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
683*0Sstevel@tonic-gate 		retcode = cs_request_socket_mask(ch,
684*0Sstevel@tonic-gate 				va_arg(arglist, request_socket_mask_t *));
685*0Sstevel@tonic-gate 		break;
686*0Sstevel@tonic-gate 	    case ReleaseSocketMask:
687*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
688*0Sstevel@tonic-gate 		retcode = cs_release_socket_mask(ch,
689*0Sstevel@tonic-gate 				va_arg(arglist, release_socket_mask_t *));
690*0Sstevel@tonic-gate 		break;
691*0Sstevel@tonic-gate 	    case RequestConfiguration:
692*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
693*0Sstevel@tonic-gate 		retcode = cs_request_configuration(ch,
694*0Sstevel@tonic-gate 				va_arg(arglist, config_req_t *));
695*0Sstevel@tonic-gate 		break;
696*0Sstevel@tonic-gate 	    case GetPhysicalAdapterInfo:
697*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
698*0Sstevel@tonic-gate 		retcode = cs_get_physical_adapter_info(ch,
699*0Sstevel@tonic-gate 				va_arg(arglist, get_physical_adapter_info_t *));
700*0Sstevel@tonic-gate 		break;
701*0Sstevel@tonic-gate 	    case GetCardServicesInfo:
702*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
703*0Sstevel@tonic-gate 		retcode = cs_get_cardservices_info(ch,
704*0Sstevel@tonic-gate 				va_arg(arglist, get_cardservices_info_t *));
705*0Sstevel@tonic-gate 		break;
706*0Sstevel@tonic-gate 	    case GetConfigurationInfo:
707*0Sstevel@tonic-gate 		chp = va_arg(arglist, client_handle_t *);
708*0Sstevel@tonic-gate 		retcode = cs_get_configuration_info(chp,
709*0Sstevel@tonic-gate 				va_arg(arglist, get_configuration_info_t *));
710*0Sstevel@tonic-gate 		break;
711*0Sstevel@tonic-gate 	    case ModifyConfiguration:
712*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
713*0Sstevel@tonic-gate 		retcode = cs_modify_configuration(ch,
714*0Sstevel@tonic-gate 				va_arg(arglist, modify_config_t *));
715*0Sstevel@tonic-gate 		break;
716*0Sstevel@tonic-gate 	    case AccessConfigurationRegister:
717*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
718*0Sstevel@tonic-gate 		retcode = cs_access_configuration_register(ch,
719*0Sstevel@tonic-gate 				va_arg(arglist, access_config_reg_t *));
720*0Sstevel@tonic-gate 		break;
721*0Sstevel@tonic-gate 	    case ReleaseConfiguration:
722*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
723*0Sstevel@tonic-gate 		retcode = cs_release_configuration(ch,
724*0Sstevel@tonic-gate 				va_arg(arglist, release_config_t *));
725*0Sstevel@tonic-gate 		break;
726*0Sstevel@tonic-gate 	    case OpenMemory:
727*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: OpenMemory\n");
728*0Sstevel@tonic-gate 		break;
729*0Sstevel@tonic-gate 	    case ReadMemory:
730*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: ReadMemory\n");
731*0Sstevel@tonic-gate 		break;
732*0Sstevel@tonic-gate 	    case WriteMemory:
733*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: WriteMemory\n");
734*0Sstevel@tonic-gate 		break;
735*0Sstevel@tonic-gate 	    case CopyMemory:
736*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: CopyMemory\n");
737*0Sstevel@tonic-gate 		break;
738*0Sstevel@tonic-gate 	    case RegisterEraseQueue:
739*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: RegisterEraseQueue\n");
740*0Sstevel@tonic-gate 		break;
741*0Sstevel@tonic-gate 	    case CheckEraseQueue:
742*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: CheckEraseQueue\n");
743*0Sstevel@tonic-gate 		break;
744*0Sstevel@tonic-gate 	    case DeregisterEraseQueue:
745*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: DeregisterEraseQueue\n");
746*0Sstevel@tonic-gate 		break;
747*0Sstevel@tonic-gate 	    case CloseMemory:
748*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: CloseMemory\n");
749*0Sstevel@tonic-gate 		break;
750*0Sstevel@tonic-gate 	    case GetFirstRegion:
751*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: GetFirstRegion\n");
752*0Sstevel@tonic-gate 		break;
753*0Sstevel@tonic-gate 	    case GetNextRegion:
754*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: GetNextRegion\n");
755*0Sstevel@tonic-gate 		break;
756*0Sstevel@tonic-gate 	    case GetFirstPartition:
757*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: GetFirstPartition\n");
758*0Sstevel@tonic-gate 		break;
759*0Sstevel@tonic-gate 	    case GetNextPartition:
760*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: GetNextPartition\n");
761*0Sstevel@tonic-gate 		break;
762*0Sstevel@tonic-gate 	    case ReturnSSEntry:
763*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: ReturnSSEntry\n");
764*0Sstevel@tonic-gate 		break;
765*0Sstevel@tonic-gate 	    case MapLogSocket:
766*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
767*0Sstevel@tonic-gate 		retcode = cs_map_log_socket(ch,
768*0Sstevel@tonic-gate 				va_arg(arglist, map_log_socket_t *));
769*0Sstevel@tonic-gate 		break;
770*0Sstevel@tonic-gate 	    case MapPhySocket:
771*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: MapPhySocket\n");
772*0Sstevel@tonic-gate 		break;
773*0Sstevel@tonic-gate 	    case MapLogWindow:
774*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: MapLogWindow\n");
775*0Sstevel@tonic-gate 		break;
776*0Sstevel@tonic-gate 	    case MapPhyWindow:
777*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: MapPhyWindow\n");
778*0Sstevel@tonic-gate 		break;
779*0Sstevel@tonic-gate 	    case RegisterMTD:
780*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: RegisterMTD\n");
781*0Sstevel@tonic-gate 		break;
782*0Sstevel@tonic-gate 	    case RegisterTimer:
783*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: RegisterTimer\n");
784*0Sstevel@tonic-gate 		break;
785*0Sstevel@tonic-gate 	    case SetRegion:
786*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: SetRegion\n");
787*0Sstevel@tonic-gate 		break;
788*0Sstevel@tonic-gate 	    case RequestExclusive:
789*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: RequestExclusive\n");
790*0Sstevel@tonic-gate 		break;
791*0Sstevel@tonic-gate 	    case ReleaseExclusive:
792*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: ReleaseExclusive\n");
793*0Sstevel@tonic-gate 		break;
794*0Sstevel@tonic-gate 	    case GetFirstClient:
795*0Sstevel@tonic-gate 		retcode = cs_get_firstnext_client(
796*0Sstevel@tonic-gate 				va_arg(arglist, get_firstnext_client_t *),
797*0Sstevel@tonic-gate 				CS_GET_FIRST_FLAG);
798*0Sstevel@tonic-gate 		break;
799*0Sstevel@tonic-gate 	    case GetNextClient:
800*0Sstevel@tonic-gate 		retcode = cs_get_firstnext_client(
801*0Sstevel@tonic-gate 				va_arg(arglist, get_firstnext_client_t *),
802*0Sstevel@tonic-gate 				CS_GET_NEXT_FLAG);
803*0Sstevel@tonic-gate 		break;
804*0Sstevel@tonic-gate 	    case GetClientInfo:
805*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
806*0Sstevel@tonic-gate 		retcode = cs_get_client_info(ch,
807*0Sstevel@tonic-gate 				va_arg(arglist, client_info_t *));
808*0Sstevel@tonic-gate 		break;
809*0Sstevel@tonic-gate 	    case AddSocketServices:
810*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: AddSocketServices\n");
811*0Sstevel@tonic-gate 		break;
812*0Sstevel@tonic-gate 	    case ReplaceSocketServices:
813*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: ReplaceSocketServices\n");
814*0Sstevel@tonic-gate 		break;
815*0Sstevel@tonic-gate 	    case VendorSpecific:
816*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: VendorSpecific\n");
817*0Sstevel@tonic-gate 		break;
818*0Sstevel@tonic-gate 	    case AdjustResourceInfo:
819*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: AdjustResourceInfo\n");
820*0Sstevel@tonic-gate 		break;
821*0Sstevel@tonic-gate 	    case ValidateCIS:
822*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
823*0Sstevel@tonic-gate 		retcode = cs_validate_cis(ch,
824*0Sstevel@tonic-gate 				va_arg(arglist, cisinfo_t *));
825*0Sstevel@tonic-gate 		break;
826*0Sstevel@tonic-gate 	    case GetFirstTuple:
827*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
828*0Sstevel@tonic-gate 		retcode = cs_get_firstnext_tuple(ch,
829*0Sstevel@tonic-gate 				va_arg(arglist, tuple_t *),
830*0Sstevel@tonic-gate 				CS_GET_FIRST_FLAG);
831*0Sstevel@tonic-gate 		break;
832*0Sstevel@tonic-gate 	    case GetNextTuple:
833*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
834*0Sstevel@tonic-gate 		retcode = cs_get_firstnext_tuple(ch,
835*0Sstevel@tonic-gate 				va_arg(arglist, tuple_t *),
836*0Sstevel@tonic-gate 				CS_GET_NEXT_FLAG);
837*0Sstevel@tonic-gate 		break;
838*0Sstevel@tonic-gate 	    case GetTupleData:
839*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
840*0Sstevel@tonic-gate 		retcode = cs_get_tuple_data(ch,
841*0Sstevel@tonic-gate 				va_arg(arglist, tuple_t *));
842*0Sstevel@tonic-gate 		break;
843*0Sstevel@tonic-gate 	    case ParseTuple:
844*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
845*0Sstevel@tonic-gate 		tuple = va_arg(arglist, tuple_t *);
846*0Sstevel@tonic-gate 		cisparse = va_arg(arglist, cisparse_t *);
847*0Sstevel@tonic-gate 		retcode = cs_parse_tuple(ch, tuple, cisparse,
848*0Sstevel@tonic-gate 				va_arg(arglist, uint_t));
849*0Sstevel@tonic-gate 		break;
850*0Sstevel@tonic-gate 	    case MakeDeviceNode:
851*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
852*0Sstevel@tonic-gate 		retcode = cs_make_device_node(ch,
853*0Sstevel@tonic-gate 				va_arg(arglist, make_device_node_t *));
854*0Sstevel@tonic-gate 		break;
855*0Sstevel@tonic-gate 	    case RemoveDeviceNode:
856*0Sstevel@tonic-gate 		ch = va_arg(arglist, client_handle_t);
857*0Sstevel@tonic-gate 		retcode = cs_remove_device_node(ch,
858*0Sstevel@tonic-gate 				va_arg(arglist, remove_device_node_t *));
859*0Sstevel@tonic-gate 		break;
860*0Sstevel@tonic-gate 	    case ConvertSpeed:
861*0Sstevel@tonic-gate 		retcode = cs_convert_speed(
862*0Sstevel@tonic-gate 				va_arg(arglist, convert_speed_t *));
863*0Sstevel@tonic-gate 		break;
864*0Sstevel@tonic-gate 	    case ConvertSize:
865*0Sstevel@tonic-gate 		retcode = cs_convert_size(
866*0Sstevel@tonic-gate 				va_arg(arglist, convert_size_t *));
867*0Sstevel@tonic-gate 		break;
868*0Sstevel@tonic-gate 	    case Event2Text:
869*0Sstevel@tonic-gate 		retcode = cs_event2text(
870*0Sstevel@tonic-gate 				va_arg(arglist, event2text_t *), 1);
871*0Sstevel@tonic-gate 		break;
872*0Sstevel@tonic-gate 	    case Error2Text: {
873*0Sstevel@tonic-gate 		error2text_t *cft;
874*0Sstevel@tonic-gate 
875*0Sstevel@tonic-gate 		cft = va_arg(arglist, error2text_t *);
876*0Sstevel@tonic-gate 		(void) strcpy(cft->text,
877*0Sstevel@tonic-gate 				cs_error2text(cft->item, CSFUN2TEXT_RETURN));
878*0Sstevel@tonic-gate 		retcode = CS_SUCCESS;
879*0Sstevel@tonic-gate 		}
880*0Sstevel@tonic-gate 		break;
881*0Sstevel@tonic-gate 	    case CS_DDI_Info:
882*0Sstevel@tonic-gate 		retcode = cs_ddi_info(va_arg(arglist, cs_ddi_info_t *));
883*0Sstevel@tonic-gate 		break;
884*0Sstevel@tonic-gate 	    case CS_Sys_Ctl:
885*0Sstevel@tonic-gate 		retcode = cs_sys_ctl(va_arg(arglist, cs_sys_ctl_t *));
886*0Sstevel@tonic-gate 		break;
887*0Sstevel@tonic-gate 	    default:
888*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "CS: {unknown function %d}\n", function);
889*0Sstevel@tonic-gate 		break;
890*0Sstevel@tonic-gate 	} /* switch(function) */
891*0Sstevel@tonic-gate 
892*0Sstevel@tonic-gate 	va_end(arglist);
893*0Sstevel@tonic-gate 
894*0Sstevel@tonic-gate #ifdef	CS_DEBUG
895*0Sstevel@tonic-gate 	if (cs_debug > 127) {
896*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "CardServices: returning %s (0x%x)\n",
897*0Sstevel@tonic-gate 				cs_error2text(retcode, CSFUN2TEXT_RETURN),
898*0Sstevel@tonic-gate 				retcode);
899*0Sstevel@tonic-gate 	}
900*0Sstevel@tonic-gate #endif
901*0Sstevel@tonic-gate 
902*0Sstevel@tonic-gate 	return (retcode);
903*0Sstevel@tonic-gate }
904*0Sstevel@tonic-gate 
905*0Sstevel@tonic-gate /*
906*0Sstevel@tonic-gate  * ==== tuple and CIS handling section ====
907*0Sstevel@tonic-gate  */
908*0Sstevel@tonic-gate 
909*0Sstevel@tonic-gate /*
910*0Sstevel@tonic-gate  * cs_parse_tuple - This function supports the CS ParseTuple function call.
911*0Sstevel@tonic-gate  *
912*0Sstevel@tonic-gate  *    returns:	CS_SUCCESS - if tuple parsed sucessfully
913*0Sstevel@tonic-gate  *		CS_NO_CARD - if no card in socket
914*0Sstevel@tonic-gate  *		CS_BAD_ARGS - if passed CIS list pointer is NULL
915*0Sstevel@tonic-gate  *		CS_UNKNOWN_TUPLE - if unknown tuple passed to CIS parser
916*0Sstevel@tonic-gate  *		CS_BAD_CIS - if generic parser error
917*0Sstevel@tonic-gate  *		CS_NO_CIS - if no CIS for card/function
918*0Sstevel@tonic-gate  *
919*0Sstevel@tonic-gate  *    See notes for the cs_get_firstnext_tuple function.
920*0Sstevel@tonic-gate  */
921*0Sstevel@tonic-gate static int
922*0Sstevel@tonic-gate cs_parse_tuple(client_handle_t client_handle, tuple_t *tuple,
923*0Sstevel@tonic-gate 				cisparse_t *cisparse, cisdata_t cisdata)
924*0Sstevel@tonic-gate {
925*0Sstevel@tonic-gate 	cs_socket_t *sp;
926*0Sstevel@tonic-gate 	client_t *client;
927*0Sstevel@tonic-gate 	uint32_t fn;
928*0Sstevel@tonic-gate 	int ret;
929*0Sstevel@tonic-gate 
930*0Sstevel@tonic-gate 	if ((ret = cs_get_socket(client_handle, &tuple->Socket,
931*0Sstevel@tonic-gate 					&fn, &sp, &client)) != CS_SUCCESS)
932*0Sstevel@tonic-gate 	    return (ret);
933*0Sstevel@tonic-gate 
934*0Sstevel@tonic-gate 	/*
935*0Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
936*0Sstevel@tonic-gate 	 *	for this client, then return an error.
937*0Sstevel@tonic-gate 	 */
938*0Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED))
939*0Sstevel@tonic-gate 	    return (CS_NO_CARD);
940*0Sstevel@tonic-gate 
941*0Sstevel@tonic-gate 	/*
942*0Sstevel@tonic-gate 	 * Sanity check to be sure that we've got a non-NULL CIS list
943*0Sstevel@tonic-gate 	 *	pointer.
944*0Sstevel@tonic-gate 	 */
945*0Sstevel@tonic-gate 	if (!(tuple->CISOffset))
946*0Sstevel@tonic-gate 	    return (CS_BAD_ARGS);
947*0Sstevel@tonic-gate 
948*0Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
949*0Sstevel@tonic-gate 
950*0Sstevel@tonic-gate 	/*
951*0Sstevel@tonic-gate 	 * Check to see if there is a valid CIS for this function.
952*0Sstevel@tonic-gate 	 *	There is an implicit assumption here that if this
953*0Sstevel@tonic-gate 	 *	is a multi-function CIS and the specified function
954*0Sstevel@tonic-gate 	 *	number is not CS_GLOBAL_CIS that in order for there
955*0Sstevel@tonic-gate 	 *	to be a valid function-specific CIS, there also must
956*0Sstevel@tonic-gate 	 *	be a valid global CIS. This means that we don't need
957*0Sstevel@tonic-gate 	 *	to know whether this tuple came from the global CIS
958*0Sstevel@tonic-gate 	 *	or from the function-specific CIS.
959*0Sstevel@tonic-gate 	 */
960*0Sstevel@tonic-gate 	if ((sp->cis_flags & CW_VALID_CIS) &&
961*0Sstevel@tonic-gate 				(sp->cis[fn].flags & CW_VALID_CIS)) {
962*0Sstevel@tonic-gate 	    ret = (int)(uintptr_t)CIS_PARSER(CISP_CIS_PARSE_TUPLE,
963*0Sstevel@tonic-gate 				cis_cistpl_std_callout,
964*0Sstevel@tonic-gate 				tuple->CISOffset,
965*0Sstevel@tonic-gate 				(tuple->Attributes & TUPLE_RETURN_NAME)?
966*0Sstevel@tonic-gate 							HANDTPL_RETURN_NAME:
967*0Sstevel@tonic-gate 							HANDTPL_PARSE_LTUPLE,
968*0Sstevel@tonic-gate 				cisparse, cisdata);
969*0Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
970*0Sstevel@tonic-gate 	    if (ret == CISTPLF_UNKNOWN)
971*0Sstevel@tonic-gate 		return (CS_UNKNOWN_TUPLE);
972*0Sstevel@tonic-gate 	    if (ret != CISTPLF_NOERROR)
973*0Sstevel@tonic-gate 		return (CS_BAD_CIS);
974*0Sstevel@tonic-gate 	    ret = CS_SUCCESS;
975*0Sstevel@tonic-gate 	} else {
976*0Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
977*0Sstevel@tonic-gate 	    ret = CS_NO_CIS;
978*0Sstevel@tonic-gate 	} /* if (CW_VALID_CIS) */
979*0Sstevel@tonic-gate 
980*0Sstevel@tonic-gate 	return (ret);
981*0Sstevel@tonic-gate }
982*0Sstevel@tonic-gate 
983*0Sstevel@tonic-gate /*
984*0Sstevel@tonic-gate  * cs_get_firstnext_tuple - returns the first/next tuple of the specified type
985*0Sstevel@tonic-gate  *				this is to support the GetFirstTuple and
986*0Sstevel@tonic-gate  *				GetNextTuple function call
987*0Sstevel@tonic-gate  *
988*0Sstevel@tonic-gate  *    flags - one of:
989*0Sstevel@tonic-gate  *		CS_GET_FIRST_FLAG causes function to support GetFirstTuple
990*0Sstevel@tonic-gate  *		CS_GET_NEXT_FLAG causes function to support GetNextTuple
991*0Sstevel@tonic-gate  *
992*0Sstevel@tonic-gate  *	tuple_t->Attributes flags:
993*0Sstevel@tonic-gate  *		TUPLE_RETURN_LINK - XXX Not implemented, see notes below.
994*0Sstevel@tonic-gate  *		TUPLE_RETURN_IGNORED_TUPLES - return tuples with
995*0Sstevel@tonic-gate  *				CISTPLF_IGNORE_TUPLE set in the
996*0Sstevel@tonic-gate  *				cistpl_t->flags member.
997*0Sstevel@tonic-gate  *
998*0Sstevel@tonic-gate  *    Notes for regular PC card driver callers:
999*0Sstevel@tonic-gate  *
1000*0Sstevel@tonic-gate  *	On a single-function card, the caller will get back all the tuples in
1001*0Sstevel@tonic-gate  *	the CIS.
1002*0Sstevel@tonic-gate  *
1003*0Sstevel@tonic-gate  *	On a multi-function card, the caller will get the tuples from the
1004*0Sstevel@tonic-gate  *	global CIS followed by the tuples in the function-specific CIS. The
1005*0Sstevel@tonic-gate  *	caller will not get any tuples from a function-specific CIS that
1006*0Sstevel@tonic-gate  *	does not belong to the caller's function.
1007*0Sstevel@tonic-gate  *
1008*0Sstevel@tonic-gate  *    Notes for Socket Services, the "super-client" or CSI driver callers:
1009*0Sstevel@tonic-gate  *
1010*0Sstevel@tonic-gate  *	On a single-function card, the operation is the same as for regular
1011*0Sstevel@tonic-gate  *	PC card driver callers with the addition that if the function number
1012*0Sstevel@tonic-gate  *	is set to CS_GLOBAL_CIS this function will return CS_NO_CIS.
1013*0Sstevel@tonic-gate  *
1014*0Sstevel@tonic-gate  *	On a multi-function card, the operation is the same as for regular
1015*0Sstevel@tonic-gate  *	PC card driver callers with the addition that if the function number
1016*0Sstevel@tonic-gate  *	is set to CS_GLOBAL_CIS the caller will only get tuples from the
1017*0Sstevel@tonic-gate  *	global CIS. If a particular function nubmer does not exist, this
1018*0Sstevel@tonic-gate  *	function will return CS_NO_CIS for that function.
1019*0Sstevel@tonic-gate  *
1020*0Sstevel@tonic-gate  *    General notes:
1021*0Sstevel@tonic-gate  *
1022*0Sstevel@tonic-gate  *	On both a single-function card and a multi-function card, if the tuple
1023*0Sstevel@tonic-gate  *	comes from the global CIS chain, the CISTPLF_GLOBAL_CIS flag will be
1024*0Sstevel@tonic-gate  *	set in the tuple_t->flags member.
1025*0Sstevel@tonic-gate  *
1026*0Sstevel@tonic-gate  *	On a multi-function card, if the tuple comes from the function-specific
1027*0Sstevel@tonic-gate  *	CIS chain, the CISTPLF_MF_CIS flag will be set in the tuple_t->flags
1028*0Sstevel@tonic-gate  *	member.
1029*0Sstevel@tonic-gate  *
1030*0Sstevel@tonic-gate  *	For other flags that are set in the tuple_t->flags member, see the
1031*0Sstevel@tonic-gate  *	comments for the cis_list_lcreate function in the cis.c file.
1032*0Sstevel@tonic-gate  *
1033*0Sstevel@tonic-gate  *	The CIS parser may not include all the tuples that are in the CIS in
1034*0Sstevel@tonic-gate  *	the private CIS list that it creates and maintains. See the CIS
1035*0Sstevel@tonic-gate  *	parser documentation for a list of tuples that the parser does not
1036*0Sstevel@tonic-gate  *	include in the list.
1037*0Sstevel@tonic-gate  *
1038*0Sstevel@tonic-gate  *	If a tuple has the CISTPLF_IGNORE_TUPLE flag set and the flags
1039*0Sstevel@tonic-gate  *	parameter CIS_GET_LTUPLE_IGNORE is not set, that tuple will not
1040*0Sstevel@tonic-gate  *	be returned to the caller. Instead, the next tuple that matches
1041*0Sstevel@tonic-gate  *	the calling criteria will be returned (or NULL if no other tuples
1042*0Sstevel@tonic-gate  *	match the calling criteria). If CIS_GET_LTUPLE_IGNORE is set in
1043*0Sstevel@tonic-gate  *	the flags paramter, tuples in the CIS list that match the calling
1044*0Sstevel@tonic-gate  *	criteria will be returned.
1045*0Sstevel@tonic-gate  *
1046*0Sstevel@tonic-gate  * XXX The PC Card 95 Standard says that if the TUPLE_RETURN_LINK flag in
1047*0Sstevel@tonic-gate  *	the tuple_t->Attributes member is not set, then we don't return
1048*0Sstevel@tonic-gate  *	any of the link tuples. This function ignores this flag and always
1049*0Sstevel@tonic-gate  *	returns link tuples.
1050*0Sstevel@tonic-gate  *
1051*0Sstevel@tonic-gate  *    Return codes:
1052*0Sstevel@tonic-gate  *		CS_SUCCESS - if tuple sucessfully found and returned
1053*0Sstevel@tonic-gate  *		CS_NO_CARD - if no card inserted
1054*0Sstevel@tonic-gate  *		CS_NO_CIS - if no CIS for the specified card/function
1055*0Sstevel@tonic-gate  *		CS_NO_MORE_ITEMS - if tuple not found or no more tuples
1056*0Sstevel@tonic-gate  *					to return
1057*0Sstevel@tonic-gate  *
1058*0Sstevel@tonic-gate  *    See notes for cs_get_socket for a description of valid client, socket
1059*0Sstevel@tonic-gate  *	and function number combinations.
1060*0Sstevel@tonic-gate  */
1061*0Sstevel@tonic-gate static int
1062*0Sstevel@tonic-gate cs_get_firstnext_tuple(client_handle_t client_handle,
1063*0Sstevel@tonic-gate     tuple_t *tuple, uint32_t flags)
1064*0Sstevel@tonic-gate {
1065*0Sstevel@tonic-gate 	cs_socket_t *sp;
1066*0Sstevel@tonic-gate 	client_t *client;
1067*0Sstevel@tonic-gate 	uint32_t fn;
1068*0Sstevel@tonic-gate 	int ret;
1069*0Sstevel@tonic-gate 
1070*0Sstevel@tonic-gate 	if ((ret = cs_get_socket(client_handle, &tuple->Socket, &fn,
1071*0Sstevel@tonic-gate 						&sp, &client)) != CS_SUCCESS)
1072*0Sstevel@tonic-gate 	    return (ret);
1073*0Sstevel@tonic-gate 
1074*0Sstevel@tonic-gate 	/*
1075*0Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
1076*0Sstevel@tonic-gate 	 *	for this client, then return an error.
1077*0Sstevel@tonic-gate 	 */
1078*0Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED))
1079*0Sstevel@tonic-gate 	    return (CS_NO_CARD);
1080*0Sstevel@tonic-gate 
1081*0Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
1082*0Sstevel@tonic-gate 
1083*0Sstevel@tonic-gate 	/*
1084*0Sstevel@tonic-gate 	 * If there's no CIS on this card or no CIS for the specified
1085*0Sstevel@tonic-gate 	 *	function, then we can't do much.
1086*0Sstevel@tonic-gate 	 */
1087*0Sstevel@tonic-gate 	if ((!(sp->cis_flags & CW_VALID_CIS)) ||
1088*0Sstevel@tonic-gate 				(!(sp->cis[fn].flags & CW_VALID_CIS))) {
1089*0Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
1090*0Sstevel@tonic-gate 	    return (CS_NO_CIS);
1091*0Sstevel@tonic-gate 	}
1092*0Sstevel@tonic-gate 
1093*0Sstevel@tonic-gate 	/*
1094*0Sstevel@tonic-gate 	 * This will set the CIS_GET_LTUPLE_IGNORE flag if the
1095*0Sstevel@tonic-gate 	 *	TUPLE_RETURN_IGNORED_TUPLES flag is set. The
1096*0Sstevel@tonic-gate 	 *	assumption here is that the CIS_GET_LTUPLE_IGNORE
1097*0Sstevel@tonic-gate 	 *	flag and the TUPLE_RETURN_IGNORED_TUPLES flag
1098*0Sstevel@tonic-gate 	 *	shares the same bit position. If this ever changes,
1099*0Sstevel@tonic-gate 	 *	we'll ahve to re-work this section of code.
1100*0Sstevel@tonic-gate 	 */
1101*0Sstevel@tonic-gate 	if (tuple->Attributes & TUPLE_RETURN_IGNORED_TUPLES)
1102*0Sstevel@tonic-gate 	    flags |= CIS_GET_LTUPLE_IGNORE;
1103*0Sstevel@tonic-gate 
1104*0Sstevel@tonic-gate 	/*
1105*0Sstevel@tonic-gate 	 * Are we GetFirstTuple or GetNextTuple?
1106*0Sstevel@tonic-gate 	 */
1107*0Sstevel@tonic-gate 	if ((flags & CIS_GET_LTUPLE_OPMASK) & CS_GET_FIRST_FLAG) {
1108*0Sstevel@tonic-gate 	/*
1109*0Sstevel@tonic-gate 	 * Initialize the tuple structure; we need this information when
1110*0Sstevel@tonic-gate 	 *	we have to process a GetNextTuple or ParseTuple call.
1111*0Sstevel@tonic-gate 	 * If this card has a multi-function CIS, then we always start out
1112*0Sstevel@tonic-gate 	 *	delivering tuples from the global CIS chain. If this card does
1113*0Sstevel@tonic-gate 	 *	not have a multi-function CIS, then the function 0 CIS chain
1114*0Sstevel@tonic-gate 	 *	will contain the complete CIS list.
1115*0Sstevel@tonic-gate 	 * If this is a multi-function card, then use the GET_FIRST_LTUPLE
1116*0Sstevel@tonic-gate 	 *	macro to return the first tuple in the CIS list - we do this
1117*0Sstevel@tonic-gate 	 *	since we don't want to return tuples with CISTPLF_IGNORE_TUPLE
1118*0Sstevel@tonic-gate 	 *	set unless CIS_GET_LTUPLE_IGNORE is set in the flags parameter.
1119*0Sstevel@tonic-gate 	 * Note that we don't have to cross over into the fucntion-specific
1120*0Sstevel@tonic-gate 	 *	CIS chain if GET_FIRST_LTUPLE returns NULL, since a MF CIS will
1121*0Sstevel@tonic-gate 	 *	always have at least a CISTPL_LONGLINK_MFC tuple in the global
1122*0Sstevel@tonic-gate 	 *	CIS chain - the test for NULL is just a sanity check.
1123*0Sstevel@tonic-gate 	 */
1124*0Sstevel@tonic-gate 	    if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
1125*0Sstevel@tonic-gate 		if ((tuple->CISOffset =
1126*0Sstevel@tonic-gate 			GET_FIRST_LTUPLE(sp->cis[CS_GLOBAL_CIS].cis,
1127*0Sstevel@tonic-gate 							flags)) == NULL) {
1128*0Sstevel@tonic-gate 		    mutex_exit(&sp->cis_lock);
1129*0Sstevel@tonic-gate 		    return (CS_NO_MORE_ITEMS);
1130*0Sstevel@tonic-gate 		} /* GET_FIRST_LTUPLE */
1131*0Sstevel@tonic-gate 	    } else {
1132*0Sstevel@tonic-gate 		tuple->CISOffset = sp->cis[0].cis;
1133*0Sstevel@tonic-gate 	    } /* CW_MULTI_FUNCTION_CIS */
1134*0Sstevel@tonic-gate 	} else {
1135*0Sstevel@tonic-gate 	    cistpl_t *tp;
1136*0Sstevel@tonic-gate 
1137*0Sstevel@tonic-gate 		/*
1138*0Sstevel@tonic-gate 		 * Check to be sure that we have a non-NULL tuple list pointer.
1139*0Sstevel@tonic-gate 		 *	This is necessary in the case where the caller calls us
1140*0Sstevel@tonic-gate 		 *	with get next tuple requests but we don't have any more
1141*0Sstevel@tonic-gate 		 *	tuples to give back.
1142*0Sstevel@tonic-gate 		 */
1143*0Sstevel@tonic-gate 	    if (tuple->CISOffset == NULL) {
1144*0Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
1145*0Sstevel@tonic-gate 		return (CS_NO_MORE_ITEMS);
1146*0Sstevel@tonic-gate 	    }
1147*0Sstevel@tonic-gate 
1148*0Sstevel@tonic-gate 		/*
1149*0Sstevel@tonic-gate 		 * Point to the next tuple in the list.  If we're searching for
1150*0Sstevel@tonic-gate 		 *	a particular tuple, FIND_LTUPLE_FWD will find it.
1151*0Sstevel@tonic-gate 		 *
1152*0Sstevel@tonic-gate 		 * If there are no more tuples in the chain that we're looking
1153*0Sstevel@tonic-gate 		 *	at, then if we're looking at the global portion of a
1154*0Sstevel@tonic-gate 		 *	multi-function CIS, switch to the function-specific list
1155*0Sstevel@tonic-gate 		 *	and start looking there.
1156*0Sstevel@tonic-gate 		 */
1157*0Sstevel@tonic-gate 	    if ((tp = GET_NEXT_TUPLE(tuple->CISOffset, flags)) == NULL) {
1158*0Sstevel@tonic-gate 		if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
1159*0Sstevel@tonic-gate 		    if ((tuple->CISOffset->flags & CISTPLF_GLOBAL_CIS) &&
1160*0Sstevel@tonic-gate 							(fn != CS_GLOBAL_CIS)) {
1161*0Sstevel@tonic-gate 			tp = GET_FIRST_LTUPLE(sp->cis[fn].cis, flags);
1162*0Sstevel@tonic-gate 		    } /* CISTPLF_GLOBAL_CIS */
1163*0Sstevel@tonic-gate 		} /* CW_MULTI_FUNCTION_CIS */
1164*0Sstevel@tonic-gate 	    } /* GET_NEXT_TUPLE */
1165*0Sstevel@tonic-gate 
1166*0Sstevel@tonic-gate 		/*
1167*0Sstevel@tonic-gate 		 * If there are no more tuples in the chain, then return.
1168*0Sstevel@tonic-gate 		 */
1169*0Sstevel@tonic-gate 	    if ((tuple->CISOffset = tp) == NULL) {
1170*0Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
1171*0Sstevel@tonic-gate 		return (CS_NO_MORE_ITEMS);
1172*0Sstevel@tonic-gate 	    }
1173*0Sstevel@tonic-gate 	} /* CS_GET_FIRST_FLAG */
1174*0Sstevel@tonic-gate 
1175*0Sstevel@tonic-gate 	/*
1176*0Sstevel@tonic-gate 	 * Check if we want to get the first of a particular type of tuple
1177*0Sstevel@tonic-gate 	 *	or just the first tuple in the chain.
1178*0Sstevel@tonic-gate 	 * If there are no more tuples of the type we're searching for in
1179*0Sstevel@tonic-gate 	 *	the chain that we're looking at, then if we're looking at
1180*0Sstevel@tonic-gate 	 *	the global portion of a multi-function CIS, switch to the
1181*0Sstevel@tonic-gate 	 *	function-specific list and start looking there.
1182*0Sstevel@tonic-gate 	 */
1183*0Sstevel@tonic-gate 	if (tuple->DesiredTuple != RETURN_FIRST_TUPLE) {
1184*0Sstevel@tonic-gate 	    cistpl_t *tp;
1185*0Sstevel@tonic-gate 
1186*0Sstevel@tonic-gate 	    if ((tp = FIND_LTUPLE_FWD(tuple->CISOffset,
1187*0Sstevel@tonic-gate 					tuple->DesiredTuple, flags)) == NULL) {
1188*0Sstevel@tonic-gate 		if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
1189*0Sstevel@tonic-gate 		    if ((tuple->CISOffset->flags & CISTPLF_GLOBAL_CIS) &&
1190*0Sstevel@tonic-gate 							(fn != CS_GLOBAL_CIS)) {
1191*0Sstevel@tonic-gate 			tp = FIND_FIRST_LTUPLE(sp->cis[fn].cis,
1192*0Sstevel@tonic-gate 						tuple->DesiredTuple, flags);
1193*0Sstevel@tonic-gate 		    } /* CISTPLF_GLOBAL_CIS */
1194*0Sstevel@tonic-gate 		} /* CW_MULTI_FUNCTION_CIS */
1195*0Sstevel@tonic-gate 	    } /* FIND_LTUPLE_FWD */
1196*0Sstevel@tonic-gate 
1197*0Sstevel@tonic-gate 		/*
1198*0Sstevel@tonic-gate 		 * If there are no more tuples in the chain, then return.
1199*0Sstevel@tonic-gate 		 */
1200*0Sstevel@tonic-gate 	    if ((tuple->CISOffset = tp) == NULL) {
1201*0Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
1202*0Sstevel@tonic-gate 		return (CS_NO_MORE_ITEMS);
1203*0Sstevel@tonic-gate 	    }
1204*0Sstevel@tonic-gate 	} /* !RETURN_FIRST_TUPLE */
1205*0Sstevel@tonic-gate 
1206*0Sstevel@tonic-gate 	/*
1207*0Sstevel@tonic-gate 	 * We've got a tuple, now fill out the rest of the tuple_t
1208*0Sstevel@tonic-gate 	 *	structure.  Callers can use the flags member to
1209*0Sstevel@tonic-gate 	 *	determine whether or not the tuple data was copied
1210*0Sstevel@tonic-gate 	 *	to the linked list or if it's still on the card.
1211*0Sstevel@tonic-gate 	 */
1212*0Sstevel@tonic-gate 	tuple->Flags = tuple->CISOffset->flags;
1213*0Sstevel@tonic-gate 	tuple->TupleCode = tuple->CISOffset->type;
1214*0Sstevel@tonic-gate 	tuple->TupleLink = tuple->CISOffset->len;
1215*0Sstevel@tonic-gate 	tuple->TupleDataLen = tuple->CISOffset->len;
1216*0Sstevel@tonic-gate 
1217*0Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
1218*0Sstevel@tonic-gate 
1219*0Sstevel@tonic-gate 	return (CS_SUCCESS);
1220*0Sstevel@tonic-gate }
1221*0Sstevel@tonic-gate 
1222*0Sstevel@tonic-gate /*
1223*0Sstevel@tonic-gate  * cs_get_tuple_data - get the data portion of a tuple; this is to
1224*0Sstevel@tonic-gate  *	support the GetTupleData function call.
1225*0Sstevel@tonic-gate  *
1226*0Sstevel@tonic-gate  *    Note that if the data body of a tuple was not read from the CIS,
1227*0Sstevel@tonic-gate  *	then this function will return CS_NO_MORE_ITEMS.
1228*0Sstevel@tonic-gate  *
1229*0Sstevel@tonic-gate  *    For flags that are set in the tuple_t->flags member, see the
1230*0Sstevel@tonic-gate  *	comments for the cis_list_lcreate function in the cis.c file.
1231*0Sstevel@tonic-gate  *	These flags are copied into the tuple_t->flags member by the
1232*0Sstevel@tonic-gate  *	cs_get_firstnext_tuple function call.
1233*0Sstevel@tonic-gate  *
1234*0Sstevel@tonic-gate  *    See notes for the cs_get_firstnext_tuple function.
1235*0Sstevel@tonic-gate  */
1236*0Sstevel@tonic-gate static int
1237*0Sstevel@tonic-gate cs_get_tuple_data(client_handle_t client_handle, tuple_t *tuple)
1238*0Sstevel@tonic-gate {
1239*0Sstevel@tonic-gate 	cs_socket_t *sp;
1240*0Sstevel@tonic-gate 	client_t *client;
1241*0Sstevel@tonic-gate 	int ret, nbytes;
1242*0Sstevel@tonic-gate 	uint32_t fn, flags;
1243*0Sstevel@tonic-gate 	cisdata_t *tsd, *tdd;
1244*0Sstevel@tonic-gate 	uint32_t newoffset;
1245*0Sstevel@tonic-gate 	acc_handle_t cis_handle;
1246*0Sstevel@tonic-gate 
1247*0Sstevel@tonic-gate 	if ((ret = cs_get_socket(client_handle, &tuple->Socket, &fn,
1248*0Sstevel@tonic-gate 						&sp, &client)) != CS_SUCCESS)
1249*0Sstevel@tonic-gate 	    return (ret);
1250*0Sstevel@tonic-gate 
1251*0Sstevel@tonic-gate 	/*
1252*0Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
1253*0Sstevel@tonic-gate 	 *	for this client, then return an error.
1254*0Sstevel@tonic-gate 	 */
1255*0Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED))
1256*0Sstevel@tonic-gate 	    return (CS_NO_CARD);
1257*0Sstevel@tonic-gate 
1258*0Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
1259*0Sstevel@tonic-gate 
1260*0Sstevel@tonic-gate 	if ((sp->cis_flags & CW_VALID_CIS) &&
1261*0Sstevel@tonic-gate 				(sp->cis[fn].flags & CW_VALID_CIS)) {
1262*0Sstevel@tonic-gate 
1263*0Sstevel@tonic-gate 		/*
1264*0Sstevel@tonic-gate 		 * Check to be sure that we have a non-NULL pointer to
1265*0Sstevel@tonic-gate 		 *	a CIS list.
1266*0Sstevel@tonic-gate 		 */
1267*0Sstevel@tonic-gate 	    if (!(tuple->CISOffset)) {
1268*0Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
1269*0Sstevel@tonic-gate 		return (CS_NO_MORE_ITEMS);
1270*0Sstevel@tonic-gate 	    }
1271*0Sstevel@tonic-gate 
1272*0Sstevel@tonic-gate 	/*
1273*0Sstevel@tonic-gate 	 * Since the tuple data buffer that the caller calls us with
1274*0Sstevel@tonic-gate 	 *	is preallocated in the tuple_t structure, we ignore any
1275*0Sstevel@tonic-gate 	 *	TupleDataMax value that the caller has setup and use the
1276*0Sstevel@tonic-gate 	 *	actual size of the tuple data buffer in the structure.
1277*0Sstevel@tonic-gate 	 */
1278*0Sstevel@tonic-gate 	    tuple->TupleDataMax = sizeof (tuple->TupleData);
1279*0Sstevel@tonic-gate 
1280*0Sstevel@tonic-gate 	/*
1281*0Sstevel@tonic-gate 	 * Make sure the requested offset is not past the end of the
1282*0Sstevel@tonic-gate 	 *	tuple data body nor past the end of the user-supplied
1283*0Sstevel@tonic-gate 	 *	buffer.
1284*0Sstevel@tonic-gate 	 */
1285*0Sstevel@tonic-gate 	    if ((int)tuple->TupleOffset >= min((int)tuple->TupleLink,
1286*0Sstevel@tonic-gate 						(int)tuple->TupleDataMax)) {
1287*0Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
1288*0Sstevel@tonic-gate 		return (CS_NO_MORE_ITEMS);
1289*0Sstevel@tonic-gate 	    }
1290*0Sstevel@tonic-gate 
1291*0Sstevel@tonic-gate 	    tuple->TupleDataLen = tuple->TupleLink;
1292*0Sstevel@tonic-gate 
1293*0Sstevel@tonic-gate 	    if ((nbytes = min((int)tuple->TupleDataMax -
1294*0Sstevel@tonic-gate 						(int)tuple->TupleOffset,
1295*0Sstevel@tonic-gate 						(int)tuple->TupleDataLen -
1296*0Sstevel@tonic-gate 						(int)tuple->TupleOffset)) < 1) {
1297*0Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
1298*0Sstevel@tonic-gate 		return (CS_BAD_ARGS);
1299*0Sstevel@tonic-gate 	    }
1300*0Sstevel@tonic-gate 
1301*0Sstevel@tonic-gate 	/*
1302*0Sstevel@tonic-gate 	 * The tuple data destination is always the tuple_t->TupleData
1303*0Sstevel@tonic-gate 	 *	buffer in the tuple_t structure no matter where we read the
1304*0Sstevel@tonic-gate 	 *	tuple data from.
1305*0Sstevel@tonic-gate 	 */
1306*0Sstevel@tonic-gate 	    tdd = tuple->TupleData;
1307*0Sstevel@tonic-gate 	    bzero((caddr_t)tdd, sizeof (tuple->TupleData));
1308*0Sstevel@tonic-gate 
1309*0Sstevel@tonic-gate 	/*
1310*0Sstevel@tonic-gate 	 * Do we have a copy of the tuple data?  If not, we have to
1311*0Sstevel@tonic-gate 	 *	get a pointer to the CIS and read the tuple data from the
1312*0Sstevel@tonic-gate 	 *	card itself.
1313*0Sstevel@tonic-gate 	 */
1314*0Sstevel@tonic-gate 	    switch (tuple->CISOffset->flags & CISTPLF_SPACE_MASK) {
1315*0Sstevel@tonic-gate 		case CISTPLF_LM_SPACE:
1316*0Sstevel@tonic-gate 		    tsd = (tuple->CISOffset->data +
1317*0Sstevel@tonic-gate 					(unsigned)tuple->TupleOffset);
1318*0Sstevel@tonic-gate 		    while (nbytes--)
1319*0Sstevel@tonic-gate 			*tdd++ = *tsd++;
1320*0Sstevel@tonic-gate 		    break;
1321*0Sstevel@tonic-gate 		case CISTPLF_AM_SPACE:
1322*0Sstevel@tonic-gate 		case CISTPLF_CM_SPACE:
1323*0Sstevel@tonic-gate 		    newoffset = tuple->CISOffset->offset;
1324*0Sstevel@tonic-gate 
1325*0Sstevel@tonic-gate 		/*
1326*0Sstevel@tonic-gate 		 * Setup the proper space flags as well as setup the
1327*0Sstevel@tonic-gate 		 *	address offset to point to the start of the tuple
1328*0Sstevel@tonic-gate 		 *	data area; we need to do the latter since the
1329*0Sstevel@tonic-gate 		 *	cis_store_cis_addr function in cis.c sets up the
1330*0Sstevel@tonic-gate 		 *	tuple->CISOffset->offset offset to point to the
1331*0Sstevel@tonic-gate 		 *	start of the tuple.
1332*0Sstevel@tonic-gate 		 */
1333*0Sstevel@tonic-gate 		    if (tuple->CISOffset->flags & CISTPLF_AM_SPACE) {
1334*0Sstevel@tonic-gate 			flags = CISTPLF_AM_SPACE;
1335*0Sstevel@tonic-gate 			newoffset += ((tuple->TupleOffset * 2) + 4);
1336*0Sstevel@tonic-gate 		    } else {
1337*0Sstevel@tonic-gate 			flags = CISTPLF_CM_SPACE;
1338*0Sstevel@tonic-gate 			newoffset += (tuple->TupleOffset + 2);
1339*0Sstevel@tonic-gate 		    }
1340*0Sstevel@tonic-gate 
1341*0Sstevel@tonic-gate 		    if (cs_init_cis_window(sp, &newoffset, &cis_handle,
1342*0Sstevel@tonic-gate 							flags) != CS_SUCCESS) {
1343*0Sstevel@tonic-gate 			mutex_exit(&sp->cis_lock);
1344*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_get_tuple_data: socket %d "
1345*0Sstevel@tonic-gate 						"can't init CIS window\n",
1346*0Sstevel@tonic-gate 							sp->socket_num);
1347*0Sstevel@tonic-gate 			return (CS_GENERAL_FAILURE);
1348*0Sstevel@tonic-gate 		    } /* cs_init_cis_window */
1349*0Sstevel@tonic-gate 		    while (nbytes--) {
1350*0Sstevel@tonic-gate 			*tdd++ = csx_Get8(cis_handle, newoffset++);
1351*0Sstevel@tonic-gate 			if (tuple->CISOffset->flags & CISTPLF_AM_SPACE)
1352*0Sstevel@tonic-gate 			    newoffset++;
1353*0Sstevel@tonic-gate 		    } /* while */
1354*0Sstevel@tonic-gate 		    break;
1355*0Sstevel@tonic-gate 		default:
1356*0Sstevel@tonic-gate 		    mutex_exit(&sp->cis_lock);
1357*0Sstevel@tonic-gate 		    return (CS_GENERAL_FAILURE);
1358*0Sstevel@tonic-gate 	    } /* switch */
1359*0Sstevel@tonic-gate 
1360*0Sstevel@tonic-gate 	    ret = CS_SUCCESS;
1361*0Sstevel@tonic-gate 	} else {
1362*0Sstevel@tonic-gate 	    ret = CS_NO_CIS;
1363*0Sstevel@tonic-gate 	} /* if (CW_VALID_CIS) */
1364*0Sstevel@tonic-gate 
1365*0Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
1366*0Sstevel@tonic-gate 
1367*0Sstevel@tonic-gate 	return (ret);
1368*0Sstevel@tonic-gate }
1369*0Sstevel@tonic-gate 
1370*0Sstevel@tonic-gate /*
1371*0Sstevel@tonic-gate  * cs_validate_cis - validates the CIS on a card in the given socket; this
1372*0Sstevel@tonic-gate  *			is to support the ValidateCIS function call.
1373*0Sstevel@tonic-gate  *
1374*0Sstevel@tonic-gate  *    Notes for regular PC card driver callers:
1375*0Sstevel@tonic-gate  *
1376*0Sstevel@tonic-gate  *	Regular PC card drivers calling ValidateCIS will get the meaning of
1377*0Sstevel@tonic-gate  *	the structure members as specified in the standard.
1378*0Sstevel@tonic-gate  *
1379*0Sstevel@tonic-gate  *    Notes for Socket Services, the "super-client" or CSI driver callers:
1380*0Sstevel@tonic-gate  *
1381*0Sstevel@tonic-gate  *		with: Function Number = CS_GLOBAL_CIS
1382*0Sstevel@tonic-gate  *
1383*0Sstevel@tonic-gate  *	For a single-function card, CS_NO_CIS will be returned and the
1384*0Sstevel@tonic-gate  *	cisinfo_t->Chains and cisinfo_t->Tuples members will be set to 0.
1385*0Sstevel@tonic-gate  *
1386*0Sstevel@tonic-gate  *	For a multi-function card, cisinfo_t->Chains will contain a count of
1387*0Sstevel@tonic-gate  *	the number of CIS chains in the global portion of the CIS, and
1388*0Sstevel@tonic-gate  *	cisinfo_t->Tuples will contain a count of the number of tuples in
1389*0Sstevel@tonic-gate  *	the global portion of the CIS.
1390*0Sstevel@tonic-gate  *
1391*0Sstevel@tonic-gate  *		with: 0 <= Function Number < CIS_MAX_FUNCTIONS
1392*0Sstevel@tonic-gate  *
1393*0Sstevel@tonic-gate  *	For a single-function card, if the function number is equal to 0 and
1394*0Sstevel@tonic-gate  *	has a CIS, cisinfo_t->Chains will contain a count of the number of
1395*0Sstevel@tonic-gate  *	CIS chains in the CIS, and cisinfo_t->Tuples will contain a count of
1396*0Sstevel@tonic-gate  *	the number of tuples in the CIS. If the card does not have a CIS, or
1397*0Sstevel@tonic-gate  *	if the function number is not equal to 0, CS_NO_CIS will be returned
1398*0Sstevel@tonic-gate  *	and the cisinfo_t->Chains and cisinfo_t->Tuples members will be set
1399*0Sstevel@tonic-gate  *	to 0.
1400*0Sstevel@tonic-gate  *
1401*0Sstevel@tonic-gate  *	For a multi-function card, cisinfo_t->Chains will contain a count of
1402*0Sstevel@tonic-gate  *	the number of CIS chains in the global and function-specific
1403*0Sstevel@tonic-gate  *	portions of the CIS, and cisinfo_t->Tuples will contain a count of
1404*0Sstevel@tonic-gate  *	the number of tuples in the global and function-specific portions of
1405*0Sstevel@tonic-gate  *	the CIS. If the function does not exist or has no CIS, CS_NO_CIS
1406*0Sstevel@tonic-gate  *	will be returned and the cisinfo_t->Chains and cisinfo_t->Tuples
1407*0Sstevel@tonic-gate  *	members will be set to 0.
1408*0Sstevel@tonic-gate  *
1409*0Sstevel@tonic-gate  *    General notes:
1410*0Sstevel@tonic-gate  *
1411*0Sstevel@tonic-gate  *	If the card does not have a CIS, or if the function does not exist
1412*0Sstevel@tonic-gate  *	or has no CIS, CS_NO_CIS will be returned and the cisinfo_t->Chains
1413*0Sstevel@tonic-gate  *	and cisinfo_t->Tuples members will be set to 0.
1414*0Sstevel@tonic-gate  *
1415*0Sstevel@tonic-gate  *	Most of the work of validating the CIS has already been done by the
1416*0Sstevel@tonic-gate  *	CIS parser module, so we don't have to do much here except for
1417*0Sstevel@tonic-gate  *	looking at the various flags and tuple/chain counts that were already
1418*0Sstevel@tonic-gate  *	setup by the CIS parser.
1419*0Sstevel@tonic-gate  *
1420*0Sstevel@tonic-gate  *    See notes for the cs_get_firstnext_tuple function.
1421*0Sstevel@tonic-gate  */
1422*0Sstevel@tonic-gate static int
1423*0Sstevel@tonic-gate cs_validate_cis(client_handle_t client_handle, cisinfo_t *cisinfo)
1424*0Sstevel@tonic-gate {
1425*0Sstevel@tonic-gate 	cs_socket_t *sp;
1426*0Sstevel@tonic-gate 	client_t *client;
1427*0Sstevel@tonic-gate 	uint32_t fn;
1428*0Sstevel@tonic-gate 	int ret;
1429*0Sstevel@tonic-gate 
1430*0Sstevel@tonic-gate 	if ((ret = cs_get_socket(client_handle, &cisinfo->Socket, &fn,
1431*0Sstevel@tonic-gate 						&sp, &client)) != CS_SUCCESS)
1432*0Sstevel@tonic-gate 	    return (ret);
1433*0Sstevel@tonic-gate 
1434*0Sstevel@tonic-gate 	/*
1435*0Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
1436*0Sstevel@tonic-gate 	 *	for this client, then return an error.
1437*0Sstevel@tonic-gate 	 */
1438*0Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED))
1439*0Sstevel@tonic-gate 	    return (CS_NO_CARD);
1440*0Sstevel@tonic-gate 
1441*0Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
1442*0Sstevel@tonic-gate 	if ((sp->cis_flags & CW_VALID_CIS) &&
1443*0Sstevel@tonic-gate 				(sp->cis[fn].flags & CW_VALID_CIS)) {
1444*0Sstevel@tonic-gate 	    cisinfo->Chains = sp->cis[fn].nchains;
1445*0Sstevel@tonic-gate 	    cisinfo->Tuples = sp->cis[fn].ntuples;
1446*0Sstevel@tonic-gate 
1447*0Sstevel@tonic-gate 	    if ((fn != CS_GLOBAL_CIS) &&
1448*0Sstevel@tonic-gate 			(sp->cis[CS_GLOBAL_CIS].flags & CW_VALID_CIS)) {
1449*0Sstevel@tonic-gate 		cisinfo->Chains += sp->cis[CS_GLOBAL_CIS].nchains;
1450*0Sstevel@tonic-gate 		cisinfo->Tuples += sp->cis[CS_GLOBAL_CIS].ntuples;
1451*0Sstevel@tonic-gate 	    } /* !CS_GLOBAL_CIS */
1452*0Sstevel@tonic-gate 
1453*0Sstevel@tonic-gate 	    ret = CS_SUCCESS;
1454*0Sstevel@tonic-gate 	} else {
1455*0Sstevel@tonic-gate 	    cisinfo->Chains = 0;
1456*0Sstevel@tonic-gate 	    cisinfo->Tuples = 0;
1457*0Sstevel@tonic-gate 	    ret = CS_NO_CIS;
1458*0Sstevel@tonic-gate 	}
1459*0Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
1460*0Sstevel@tonic-gate 
1461*0Sstevel@tonic-gate 	return (ret);
1462*0Sstevel@tonic-gate }
1463*0Sstevel@tonic-gate 
1464*0Sstevel@tonic-gate /*
1465*0Sstevel@tonic-gate  * cs_init_cis_window - initializes the CIS window for the passed socket
1466*0Sstevel@tonic-gate  *
1467*0Sstevel@tonic-gate  *	calling: *sp - pointer to the per-socket structure
1468*0Sstevel@tonic-gate  *		 *offset - offset from start of AM or CM space
1469*0Sstevel@tonic-gate  *		 *hp - pointer to acc_handle_t to store modified
1470*0Sstevel@tonic-gate  *				window access handle in
1471*0Sstevel@tonic-gate  *		 flags - one of:
1472*0Sstevel@tonic-gate  *				CISTPLF_AM_SPACE - set window to AM space
1473*0Sstevel@tonic-gate  *				CISTPLF_CM_SPACE - set window to CM space
1474*0Sstevel@tonic-gate  *
1475*0Sstevel@tonic-gate  *	returns: CS_SUCCESS if CIS window was set up
1476*0Sstevel@tonic-gate  *		 *offset - contains adjusted offset to use to access
1477*0Sstevel@tonic-gate  *				requested space
1478*0Sstevel@tonic-gate  *		 CS_BAD_WINDOW if CIS window could not be setup
1479*0Sstevel@tonic-gate  *		 CS_GENERAL_FAILURE if socket has a CIS window number
1480*0Sstevel@tonic-gate  *					but the window flags are wrong
1481*0Sstevel@tonic-gate  *
1482*0Sstevel@tonic-gate  *	Note: This function will check to be sure that there is a valid
1483*0Sstevel@tonic-gate  *		CIS window allocated to this socket.
1484*0Sstevel@tonic-gate  *	      If there is an error in setting up the window hardware, the
1485*0Sstevel@tonic-gate  *		CIS window information for this socket is cleared.
1486*0Sstevel@tonic-gate  *	      This function is also used by routines that need to get
1487*0Sstevel@tonic-gate  *		a pointer to the base of AM space to access the card's
1488*0Sstevel@tonic-gate  *		configuration registers.
1489*0Sstevel@tonic-gate  *	      The passed offset is the un-window-size-aligned offset.
1490*0Sstevel@tonic-gate  */
1491*0Sstevel@tonic-gate int
1492*0Sstevel@tonic-gate cs_init_cis_window(cs_socket_t *sp, uint32_t *offset,
1493*0Sstevel@tonic-gate     acc_handle_t *hp, uint32_t flags)
1494*0Sstevel@tonic-gate {
1495*0Sstevel@tonic-gate 	set_window_t sw;
1496*0Sstevel@tonic-gate 	get_window_t gw;
1497*0Sstevel@tonic-gate 	inquire_window_t iw;
1498*0Sstevel@tonic-gate 	set_page_t set_page;
1499*0Sstevel@tonic-gate 	cs_window_t *cw;
1500*0Sstevel@tonic-gate 
1501*0Sstevel@tonic-gate 	/*
1502*0Sstevel@tonic-gate 	 * Check to be sure that we have a valid CIS window
1503*0Sstevel@tonic-gate 	 */
1504*0Sstevel@tonic-gate 	if (!SOCKET_HAS_CIS_WINDOW(sp)) {
1505*0Sstevel@tonic-gate 	    cmn_err(CE_CONT,
1506*0Sstevel@tonic-gate 			"cs_init_cis_window: socket %d has no CIS window\n",
1507*0Sstevel@tonic-gate 				sp->socket_num);
1508*0Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
1509*0Sstevel@tonic-gate 	}
1510*0Sstevel@tonic-gate 
1511*0Sstevel@tonic-gate 	/*
1512*0Sstevel@tonic-gate 	 * Check to be sure that this window is allocated for CIS use
1513*0Sstevel@tonic-gate 	 */
1514*0Sstevel@tonic-gate 	if ((cw = cs_get_wp(sp->cis_win_num)) == NULL)
1515*0Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
1516*0Sstevel@tonic-gate 
1517*0Sstevel@tonic-gate 	if (!(cw->state & CW_CIS)) {
1518*0Sstevel@tonic-gate 	    cmn_err(CE_CONT,
1519*0Sstevel@tonic-gate 		"cs_init_cis_window: socket %d invalid CIS window state 0x%x\n",
1520*0Sstevel@tonic-gate 				sp->socket_num, cw->state);
1521*0Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
1522*0Sstevel@tonic-gate 	}
1523*0Sstevel@tonic-gate 
1524*0Sstevel@tonic-gate 	/*
1525*0Sstevel@tonic-gate 	 * Get the characteristics of this window - we use this to
1526*0Sstevel@tonic-gate 	 *	determine whether we need to re-map the window or
1527*0Sstevel@tonic-gate 	 *	just move the window offset on the card.
1528*0Sstevel@tonic-gate 	 */
1529*0Sstevel@tonic-gate 	iw.window = sp->cis_win_num;
1530*0Sstevel@tonic-gate 	SocketServices(SS_InquireWindow, &iw);
1531*0Sstevel@tonic-gate 
1532*0Sstevel@tonic-gate 	/*
1533*0Sstevel@tonic-gate 	 * We've got a window, now set up the hardware. If we've got
1534*0Sstevel@tonic-gate 	 *	a variable sized window, then all we need to do is to
1535*0Sstevel@tonic-gate 	 *	get a valid mapping to the base of the window using
1536*0Sstevel@tonic-gate 	 *	the current window size; if we've got a fixed-size
1537*0Sstevel@tonic-gate 	 *	window, then we need to get a mapping to the window
1538*0Sstevel@tonic-gate 	 *	starting at offset zero of the window.
1539*0Sstevel@tonic-gate 	 */
1540*0Sstevel@tonic-gate 	if (iw.mem_win_char.MemWndCaps & WC_SIZE) {
1541*0Sstevel@tonic-gate 	    sw.WindowSize = sp->cis_win_size;
1542*0Sstevel@tonic-gate 	    set_page.offset = ((*offset / sp->cis_win_size) *
1543*0Sstevel@tonic-gate 						sp->cis_win_size);
1544*0Sstevel@tonic-gate 	} else {
1545*0Sstevel@tonic-gate 	    set_page.offset = ((*offset / iw.mem_win_char.MinSize) *
1546*0Sstevel@tonic-gate 						iw.mem_win_char.MinSize);
1547*0Sstevel@tonic-gate 	    sw.WindowSize = (((*offset & ~(PAGESIZE - 1)) &
1548*0Sstevel@tonic-gate 					(set_page.offset - 1)) + PAGESIZE);
1549*0Sstevel@tonic-gate 	}
1550*0Sstevel@tonic-gate 
1551*0Sstevel@tonic-gate 	/*
1552*0Sstevel@tonic-gate 	 * Return a normalized base offset; this takes care of the case
1553*0Sstevel@tonic-gate 	 *	where the required offset is greater than the window size.
1554*0Sstevel@tonic-gate 	 * BugID 1236404
1555*0Sstevel@tonic-gate 	 *	code was:
1556*0Sstevel@tonic-gate 	 *		*offset = *offset & (set_page.offset - 1);
1557*0Sstevel@tonic-gate 	 */
1558*0Sstevel@tonic-gate 	*offset = *offset - set_page.offset;
1559*0Sstevel@tonic-gate 
1560*0Sstevel@tonic-gate #ifdef	CS_DEBUG
1561*0Sstevel@tonic-gate 	if (cs_debug > 1)
1562*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_init_cis_window: WindowSize 0x%x "
1563*0Sstevel@tonic-gate 							"offset 0x%x\n",
1564*0Sstevel@tonic-gate 							(int)sw.WindowSize,
1565*0Sstevel@tonic-gate 							(int)set_page.offset);
1566*0Sstevel@tonic-gate 	if (cs_debug > 1)
1567*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "\t*offset = 0x%x space = %s\n",
1568*0Sstevel@tonic-gate 							(int)*offset,
1569*0Sstevel@tonic-gate 					(flags & CISTPLF_AM_SPACE)?
1570*0Sstevel@tonic-gate 					"CISTPLF_AM_SPACE":"CISTPLF_CM_SPACE");
1571*0Sstevel@tonic-gate #endif
1572*0Sstevel@tonic-gate 
1573*0Sstevel@tonic-gate 	sw.window = sp->cis_win_num;
1574*0Sstevel@tonic-gate 	sw.socket = sp->socket_num;
1575*0Sstevel@tonic-gate 	sw.state = (WS_ENABLED | WS_EXACT_MAPIN);
1576*0Sstevel@tonic-gate 	sw.attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1577*0Sstevel@tonic-gate 	sw.attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
1578*0Sstevel@tonic-gate 	sw.attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1579*0Sstevel@tonic-gate 
1580*0Sstevel@tonic-gate 	/*
1581*0Sstevel@tonic-gate 	 * The PCMCIA SS spec specifies this be expressed in
1582*0Sstevel@tonic-gate 	 *	a device speed format per 5.2.7.1.3 but
1583*0Sstevel@tonic-gate 	 *	our implementation of SS_SetWindow uses
1584*0Sstevel@tonic-gate 	 *	actual nanoseconds.
1585*0Sstevel@tonic-gate 	 */
1586*0Sstevel@tonic-gate 	sw.speed = CIS_DEFAULT_SPEED;
1587*0Sstevel@tonic-gate 	sw.base = 0;
1588*0Sstevel@tonic-gate 	/*
1589*0Sstevel@tonic-gate 	 * Set up the window - if this fails, then just set the
1590*0Sstevel@tonic-gate 	 *	CIS window number back to it's initialized value so
1591*0Sstevel@tonic-gate 	 *	that we'll fail when we break out of the loop.
1592*0Sstevel@tonic-gate 	 */
1593*0Sstevel@tonic-gate 	if (SocketServices(SS_SetWindow, &sw) != SUCCESS) {
1594*0Sstevel@tonic-gate 	    sp->cis_win_num = PCMCIA_MAX_WINDOWS;
1595*0Sstevel@tonic-gate 	    cw->state = 0; /* XXX do we really want to do this? */
1596*0Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
1597*0Sstevel@tonic-gate 	} else {
1598*0Sstevel@tonic-gate 		set_page.window = sp->cis_win_num;
1599*0Sstevel@tonic-gate 		set_page.page = 0;
1600*0Sstevel@tonic-gate 		set_page.state = PS_ENABLED;
1601*0Sstevel@tonic-gate 		if (flags & CISTPLF_AM_SPACE)
1602*0Sstevel@tonic-gate 		    set_page.state |= PS_ATTRIBUTE;
1603*0Sstevel@tonic-gate 
1604*0Sstevel@tonic-gate 		if (SocketServices(SS_SetPage, &set_page) != SUCCESS) {
1605*0Sstevel@tonic-gate 		    sp->cis_win_num = PCMCIA_MAX_WINDOWS;
1606*0Sstevel@tonic-gate 		    cw->state = 0; /* XXX do we really want to do this? */
1607*0Sstevel@tonic-gate 		    return (CS_BAD_WINDOW);
1608*0Sstevel@tonic-gate 		} /* if (SS_SetPage) */
1609*0Sstevel@tonic-gate 	} /* if (SS_SetWindow) */
1610*0Sstevel@tonic-gate 
1611*0Sstevel@tonic-gate 	/*
1612*0Sstevel@tonic-gate 	 * Get the window information for the CIS window for this socket.
1613*0Sstevel@tonic-gate 	 */
1614*0Sstevel@tonic-gate 	gw.window = sp->cis_win_num;
1615*0Sstevel@tonic-gate 	gw.socket = sp->socket_num; /* XXX - SS_GetWindow should set this */
1616*0Sstevel@tonic-gate 	if (SocketServices(SS_GetWindow, &gw) != SUCCESS)
1617*0Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
1618*0Sstevel@tonic-gate 
1619*0Sstevel@tonic-gate 	*hp = (acc_handle_t)gw.handle;
1620*0Sstevel@tonic-gate 
1621*0Sstevel@tonic-gate 	return (CS_SUCCESS);
1622*0Sstevel@tonic-gate }
1623*0Sstevel@tonic-gate 
1624*0Sstevel@tonic-gate /*
1625*0Sstevel@tonic-gate  * ==== client registration/deregistration section ====
1626*0Sstevel@tonic-gate  */
1627*0Sstevel@tonic-gate 
1628*0Sstevel@tonic-gate /*
1629*0Sstevel@tonic-gate  * cs_register_client - This supports the RegisterClient call.
1630*0Sstevel@tonic-gate  *
1631*0Sstevel@tonic-gate  * Upon successful registration, the client_handle_t * handle argument will
1632*0Sstevel@tonic-gate  *	contain the new client handle and we return CS_SUCCESS.
1633*0Sstevel@tonic-gate  */
1634*0Sstevel@tonic-gate static int
1635*0Sstevel@tonic-gate cs_register_client(client_handle_t *ch, client_reg_t *cr)
1636*0Sstevel@tonic-gate {
1637*0Sstevel@tonic-gate 	uint32_t sn;
1638*0Sstevel@tonic-gate 	int super_client = 0;
1639*0Sstevel@tonic-gate 	sclient_reg_t *scr = cr->priv;
1640*0Sstevel@tonic-gate 	struct sclient_list_t *scli;
1641*0Sstevel@tonic-gate 
1642*0Sstevel@tonic-gate 	/*
1643*0Sstevel@tonic-gate 	 * See if we're not supposed to register any new clients.
1644*0Sstevel@tonic-gate 	 */
1645*0Sstevel@tonic-gate 	if (cs_globals.init_state & GLOBAL_INIT_STATE_NO_CLIENTS)
1646*0Sstevel@tonic-gate 	    return (CS_OUT_OF_RESOURCE);
1647*0Sstevel@tonic-gate 
1648*0Sstevel@tonic-gate 	/*
1649*0Sstevel@tonic-gate 	 * Do a version check - if the client expects a later version of
1650*0Sstevel@tonic-gate 	 *	Card Services than what we are, return CS_BAD_VERSION.
1651*0Sstevel@tonic-gate 	 * XXX - How do we specify just a PARTICULAR version of CS??
1652*0Sstevel@tonic-gate 	 */
1653*0Sstevel@tonic-gate 	if (CS_VERSION < cr->Version)
1654*0Sstevel@tonic-gate 	    return (CS_BAD_VERSION);
1655*0Sstevel@tonic-gate 
1656*0Sstevel@tonic-gate 	/*
1657*0Sstevel@tonic-gate 	 * Check to be sure that the client has given us a valid set of
1658*0Sstevel@tonic-gate 	 *	client type flags.  We also use this opportunity to see
1659*0Sstevel@tonic-gate 	 *	if the registering client is Socket Services or is a
1660*0Sstevel@tonic-gate 	 *	"super-client" or a CSI client.
1661*0Sstevel@tonic-gate 	 *
1662*0Sstevel@tonic-gate 	 * Note that SS can not set any flag in the Attributes field other
1663*0Sstevel@tonic-gate 	 *	than the INFO_SOCKET_SERVICES flag.
1664*0Sstevel@tonic-gate 	 *
1665*0Sstevel@tonic-gate 	 * Valid combinations of cr->Attributes and cr->EventMask flags:
1666*0Sstevel@tonic-gate 	 *
1667*0Sstevel@tonic-gate 	 *  for Socket Services:
1668*0Sstevel@tonic-gate 	 *	cr->Attributes:
1669*0Sstevel@tonic-gate 	 *	    set:
1670*0Sstevel@tonic-gate 	 *		INFO_SOCKET_SERVICES
1671*0Sstevel@tonic-gate 	 *	    clear:
1672*0Sstevel@tonic-gate 	 *		{all other flags}
1673*0Sstevel@tonic-gate 	 *	cr->EventMask:
1674*0Sstevel@tonic-gate 	 *	    don't care:
1675*0Sstevel@tonic-gate 	 *		{all flags}
1676*0Sstevel@tonic-gate 	 *
1677*0Sstevel@tonic-gate 	 *  for regular clients:
1678*0Sstevel@tonic-gate 	 *	cr->Attributes:
1679*0Sstevel@tonic-gate 	 *	    only one of:
1680*0Sstevel@tonic-gate 	 *		INFO_IO_CLIENT
1681*0Sstevel@tonic-gate 	 *		INFO_MTD_CLIENT
1682*0Sstevel@tonic-gate 	 *		INFO_MEM_CLIENT
1683*0Sstevel@tonic-gate 	 *	    don't care:
1684*0Sstevel@tonic-gate 	 *		INFO_CARD_SHARE
1685*0Sstevel@tonic-gate 	 *		INFO_CARD_EXCL
1686*0Sstevel@tonic-gate 	 *	cr->EventMask:
1687*0Sstevel@tonic-gate 	 *	    clear:
1688*0Sstevel@tonic-gate 	 *		CS_EVENT_ALL_CLIENTS
1689*0Sstevel@tonic-gate 	 *	    don't care:
1690*0Sstevel@tonic-gate 	 *		{all other flags}
1691*0Sstevel@tonic-gate 	 *
1692*0Sstevel@tonic-gate 	 *  for CSI clients:
1693*0Sstevel@tonic-gate 	 *	cr->Attributes:
1694*0Sstevel@tonic-gate 	 *	    set:
1695*0Sstevel@tonic-gate 	 *		INFO_IO_CLIENT
1696*0Sstevel@tonic-gate 	 *		INFO_CSI_CLIENT
1697*0Sstevel@tonic-gate 	 *	    clear:
1698*0Sstevel@tonic-gate 	 *		INFO_MTD_CLIENT
1699*0Sstevel@tonic-gate 	 *		INFO_MEM_CLIENT
1700*0Sstevel@tonic-gate 	 *	    don't care:
1701*0Sstevel@tonic-gate 	 *		INFO_CARD_SHARE
1702*0Sstevel@tonic-gate 	 *		INFO_CARD_EXCL
1703*0Sstevel@tonic-gate 	 *	cr->EventMask:
1704*0Sstevel@tonic-gate 	 *	    don't care:
1705*0Sstevel@tonic-gate 	 *		{all flags}
1706*0Sstevel@tonic-gate 	 *
1707*0Sstevel@tonic-gate 	 *  for "super-clients":
1708*0Sstevel@tonic-gate 	 *	cr->Attributes:
1709*0Sstevel@tonic-gate 	 *	    set:
1710*0Sstevel@tonic-gate 	 *		INFO_IO_CLIENT
1711*0Sstevel@tonic-gate 	 *		INFO_MTD_CLIENT
1712*0Sstevel@tonic-gate 	 *		INFO_SOCKET_SERVICES
1713*0Sstevel@tonic-gate 	 *		INFO_CARD_SHARE
1714*0Sstevel@tonic-gate 	 *	    clear:
1715*0Sstevel@tonic-gate 	 *		INFO_MEM_CLIENT
1716*0Sstevel@tonic-gate 	 *		INFO_CARD_EXCL
1717*0Sstevel@tonic-gate 	 *	cr->EventMask:
1718*0Sstevel@tonic-gate 	 *	    don't care:
1719*0Sstevel@tonic-gate 	 *		{all flags}
1720*0Sstevel@tonic-gate 	 */
1721*0Sstevel@tonic-gate 	switch (cr->Attributes & INFO_CLIENT_TYPE_MASK) {
1722*0Sstevel@tonic-gate 	/*
1723*0Sstevel@tonic-gate 	 * Check first to see if this is Socket Services registering; if
1724*0Sstevel@tonic-gate 	 *	so, we don't do anything but return the client handle that is
1725*0Sstevel@tonic-gate 	 *	in the global SS client.
1726*0Sstevel@tonic-gate 	 */
1727*0Sstevel@tonic-gate 	    case INFO_SOCKET_SERVICES:
1728*0Sstevel@tonic-gate 		*ch = cs_socket_services_client.client_handle;
1729*0Sstevel@tonic-gate 		return (CS_SUCCESS);
1730*0Sstevel@tonic-gate 		/* NOTREACHED */
1731*0Sstevel@tonic-gate 	    /* CSI clients */
1732*0Sstevel@tonic-gate 	    case (INFO_CSI_CLIENT | INFO_IO_CLIENT):
1733*0Sstevel@tonic-gate 		break;
1734*0Sstevel@tonic-gate 	    /* regular clients */
1735*0Sstevel@tonic-gate 	    case INFO_IO_CLIENT:
1736*0Sstevel@tonic-gate 	    case INFO_MTD_CLIENT:
1737*0Sstevel@tonic-gate 	    case INFO_MEM_CLIENT:
1738*0Sstevel@tonic-gate 		if (cr->EventMask & CS_EVENT_ALL_CLIENTS)
1739*0Sstevel@tonic-gate 		    return (CS_BAD_ATTRIBUTE);
1740*0Sstevel@tonic-gate 		break;
1741*0Sstevel@tonic-gate 	    /* "super-client" clients */
1742*0Sstevel@tonic-gate 	    case (INFO_IO_CLIENT | INFO_MTD_CLIENT | INFO_SOCKET_SERVICES):
1743*0Sstevel@tonic-gate 		if ((!(cr->Attributes & INFO_CARD_SHARE)) ||
1744*0Sstevel@tonic-gate 				(cr->Attributes & INFO_CARD_EXCL))
1745*0Sstevel@tonic-gate 		    return (CS_BAD_ATTRIBUTE);
1746*0Sstevel@tonic-gate 		/*
1747*0Sstevel@tonic-gate 		 * We only allow one "super-client" per system.
1748*0Sstevel@tonic-gate 		 */
1749*0Sstevel@tonic-gate 		mutex_enter(&cs_globals.global_lock);
1750*0Sstevel@tonic-gate 		if (cs_globals.flags & GLOBAL_SUPER_CLIENT_REGISTERED) {
1751*0Sstevel@tonic-gate 		    mutex_exit(&cs_globals.global_lock);
1752*0Sstevel@tonic-gate 		    return (CS_NO_MORE_ITEMS);
1753*0Sstevel@tonic-gate 		}
1754*0Sstevel@tonic-gate 		cs_globals.flags |= GLOBAL_SUPER_CLIENT_REGISTERED;
1755*0Sstevel@tonic-gate 		mutex_exit(&cs_globals.global_lock);
1756*0Sstevel@tonic-gate 		super_client = CLIENT_SUPER_CLIENT;
1757*0Sstevel@tonic-gate 		break;
1758*0Sstevel@tonic-gate 	    default:
1759*0Sstevel@tonic-gate 		return (CS_BAD_ATTRIBUTE);
1760*0Sstevel@tonic-gate 	} /* switch (cr->Attributes) */
1761*0Sstevel@tonic-gate 
1762*0Sstevel@tonic-gate 	/*
1763*0Sstevel@tonic-gate 	 * Now, actually create the client node on the socket; this will
1764*0Sstevel@tonic-gate 	 *	also return the new client handle if there were no errors
1765*0Sstevel@tonic-gate 	 *	creating the client node.
1766*0Sstevel@tonic-gate 	 * The DIP2SOCKET_NUM macro will return the socket and function
1767*0Sstevel@tonic-gate 	 *	number using the encoding specified in the cs_priv.h file.
1768*0Sstevel@tonic-gate 	 */
1769*0Sstevel@tonic-gate 	if (super_client != CLIENT_SUPER_CLIENT) {
1770*0Sstevel@tonic-gate 	    if (cr->Attributes & INFO_CSI_CLIENT)
1771*0Sstevel@tonic-gate 		sn = (uint32_t)(uintptr_t)cr->priv;
1772*0Sstevel@tonic-gate 	    else
1773*0Sstevel@tonic-gate 		sn = DIP2SOCKET_NUM(cr->dip);
1774*0Sstevel@tonic-gate 	    return (cs_add_client_to_socket(sn, ch, cr, super_client));
1775*0Sstevel@tonic-gate 	} /* CLIENT_SUPER_CLIENT */
1776*0Sstevel@tonic-gate 
1777*0Sstevel@tonic-gate 	/*
1778*0Sstevel@tonic-gate 	 * This registering client is a "super-client", so we create one
1779*0Sstevel@tonic-gate 	 *	client node for each socket in the system.  We use the
1780*0Sstevel@tonic-gate 	 *	client_reg_t.priv structure member to point to a struct
1781*0Sstevel@tonic-gate 	 *	that the "super-client" client knows about.  The client
1782*0Sstevel@tonic-gate 	 *	handle pointer is not used in this case.
1783*0Sstevel@tonic-gate 	 * We return CS_SUCCESS if at least one client node could be
1784*0Sstevel@tonic-gate 	 *	created.  The client must check the error codes in the
1785*0Sstevel@tonic-gate 	 *	error code array to determine which clients could not
1786*0Sstevel@tonic-gate 	 *	be created on which sockets.
1787*0Sstevel@tonic-gate 	 * We return CS_BAD_HANDLE if no client nodes could be created.
1788*0Sstevel@tonic-gate 	 */
1789*0Sstevel@tonic-gate 	scr->num_clients = 0;
1790*0Sstevel@tonic-gate 	scr->max_socket_num = cs_globals.max_socket_num;
1791*0Sstevel@tonic-gate 	scr->num_sockets = cs_globals.num_sockets;
1792*0Sstevel@tonic-gate 	scr->num_windows = cs_globals.num_windows;
1793*0Sstevel@tonic-gate 
1794*0Sstevel@tonic-gate 	*(scr->sclient_list) = cs_globals.sclient_list;
1795*0Sstevel@tonic-gate 
1796*0Sstevel@tonic-gate 	for (sn = 0; sn < scr->num_sockets; sn++) {
1797*0Sstevel@tonic-gate 	    scli = scr->sclient_list[sn];
1798*0Sstevel@tonic-gate 	    if ((scli->error = cs_add_client_to_socket(sn, &scli->client_handle,
1799*0Sstevel@tonic-gate 					    cr, super_client)) == CS_SUCCESS) {
1800*0Sstevel@tonic-gate 		scr->num_clients++;
1801*0Sstevel@tonic-gate 	    }
1802*0Sstevel@tonic-gate 	}
1803*0Sstevel@tonic-gate 
1804*0Sstevel@tonic-gate 	/*
1805*0Sstevel@tonic-gate 	 * If we couldn't create any client nodes at all, then
1806*0Sstevel@tonic-gate 	 *	return an error.
1807*0Sstevel@tonic-gate 	 */
1808*0Sstevel@tonic-gate 	if (!scr->num_clients) {
1809*0Sstevel@tonic-gate 	/*
1810*0Sstevel@tonic-gate 	 * XXX - The global superclient lock now gets
1811*0Sstevel@tonic-gate 	 * cleared in cs_deregister_client
1812*0Sstevel@tonic-gate 	 */
1813*0Sstevel@tonic-gate 	    /* cs_clear_superclient_lock(super_client); */
1814*0Sstevel@tonic-gate 	    return (CS_BAD_HANDLE);
1815*0Sstevel@tonic-gate 	}
1816*0Sstevel@tonic-gate 
1817*0Sstevel@tonic-gate 	return (CS_SUCCESS);
1818*0Sstevel@tonic-gate }
1819*0Sstevel@tonic-gate 
1820*0Sstevel@tonic-gate /*
1821*0Sstevel@tonic-gate  * cs_add_client_to_socket - this function creates the client node on the
1822*0Sstevel@tonic-gate  *				requested socket.
1823*0Sstevel@tonic-gate  *
1824*0Sstevel@tonic-gate  * Note that if we return an error, there is no state that can be cleaned
1825*0Sstevel@tonic-gate  *	up.  The only way that we can return an error with allocated resources
1826*0Sstevel@tonic-gate  *	would be if one of the client handle functions had an internal error.
1827*0Sstevel@tonic-gate  *	Since we wouldn't get a valid client handle in this case anyway, there
1828*0Sstevel@tonic-gate  *	would be no way to find out what was allocated and what wasn't.
1829*0Sstevel@tonic-gate  */
1830*0Sstevel@tonic-gate static int
1831*0Sstevel@tonic-gate cs_add_client_to_socket(unsigned sn, client_handle_t *ch,
1832*0Sstevel@tonic-gate 					client_reg_t *cr, int super_client)
1833*0Sstevel@tonic-gate {
1834*0Sstevel@tonic-gate 	cs_socket_t *sp;
1835*0Sstevel@tonic-gate 	client_t *client, *cclp;
1836*0Sstevel@tonic-gate 	int error, cie = 1;
1837*0Sstevel@tonic-gate 	int client_lock_acquired;
1838*0Sstevel@tonic-gate 
1839*0Sstevel@tonic-gate 	if (cr->event_handler == NULL)
1840*0Sstevel@tonic-gate 	    return (CS_BAD_ARGS);
1841*0Sstevel@tonic-gate 
1842*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(sn)) == NULL)
1843*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
1844*0Sstevel@tonic-gate 
1845*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
1846*0Sstevel@tonic-gate 
1847*0Sstevel@tonic-gate 	/*
1848*0Sstevel@tonic-gate 	 * Run through all of the registered clients and compare the passed
1849*0Sstevel@tonic-gate 	 *	dip to the dip of each client to make sure that this client
1850*0Sstevel@tonic-gate 	 *	is not trying to register more than once.  If they are, then
1851*0Sstevel@tonic-gate 	 *	display a message and return an error.
1852*0Sstevel@tonic-gate 	 * XXX - we should really check all the sockets in case the client
1853*0Sstevel@tonic-gate 	 *	manipulates the instance number in the dip.
1854*0Sstevel@tonic-gate 	 * XXX - if we check each socket, we ned to also check for the
1855*0Sstevel@tonic-gate 	 *	"super-client" since it will use the same dip for all
1856*0Sstevel@tonic-gate 	 *	of it's client nodes.
1857*0Sstevel@tonic-gate 	 */
1858*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
1859*0Sstevel@tonic-gate 	client = sp->client_list;
1860*0Sstevel@tonic-gate 	while (client) {
1861*0Sstevel@tonic-gate 	    if (!(cr->Attributes & INFO_CSI_CLIENT) &&
1862*0Sstevel@tonic-gate 						(client->dip == cr->dip)) {
1863*0Sstevel@tonic-gate 		mutex_exit(&sp->lock);
1864*0Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
1865*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_add_client_to_socket: socket %d "
1866*0Sstevel@tonic-gate 					"function 0x%x\n"
1867*0Sstevel@tonic-gate 					"\tclient already registered with "
1868*0Sstevel@tonic-gate 					"handle 0x%x\n",
1869*0Sstevel@tonic-gate 						(int)CS_GET_SOCKET_NUMBER(sn),
1870*0Sstevel@tonic-gate 						(int)CS_GET_FUNCTION_NUMBER(sn),
1871*0Sstevel@tonic-gate 						(int)client->client_handle);
1872*0Sstevel@tonic-gate 		return (CS_BAD_HANDLE);
1873*0Sstevel@tonic-gate 	    }
1874*0Sstevel@tonic-gate 	    client = client->next;
1875*0Sstevel@tonic-gate 	} /* while (client) */
1876*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
1877*0Sstevel@tonic-gate 
1878*0Sstevel@tonic-gate 	/*
1879*0Sstevel@tonic-gate 	 * Create a unique client handle then make sure that we can find it.
1880*0Sstevel@tonic-gate 	 *	This has the side effect of getting us a pointer to the
1881*0Sstevel@tonic-gate 	 *	client structure as well.
1882*0Sstevel@tonic-gate 	 * Create a client list entry - cs_create_client_handle will use this
1883*0Sstevel@tonic-gate 	 *	as the new client node.
1884*0Sstevel@tonic-gate 	 * We do it here so that we can grab the sp->lock mutex for the
1885*0Sstevel@tonic-gate 	 *	duration of our manipulation of the client list.
1886*0Sstevel@tonic-gate 	 * If this function fails, then it will not have added the newly
1887*0Sstevel@tonic-gate 	 *	allocated client node to the client list on this socket,
1888*0Sstevel@tonic-gate 	 *	so we have to free the node that we allocated.
1889*0Sstevel@tonic-gate 	 */
1890*0Sstevel@tonic-gate 	cclp = (client_t *)kmem_zalloc(sizeof (client_t), KM_SLEEP);
1891*0Sstevel@tonic-gate 
1892*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
1893*0Sstevel@tonic-gate 	if (!(*ch = cs_create_client_handle(sn, cclp))) {
1894*0Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
1895*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
1896*0Sstevel@tonic-gate 	    kmem_free(cclp, sizeof (client_t));
1897*0Sstevel@tonic-gate 	    return (CS_OUT_OF_RESOURCE);
1898*0Sstevel@tonic-gate 	}
1899*0Sstevel@tonic-gate 
1900*0Sstevel@tonic-gate 	/*
1901*0Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.  We should never
1902*0Sstevel@tonic-gate 	 *	fail this since we just got a valid client handle.
1903*0Sstevel@tonic-gate 	 * If this fails, then we have an internal error so don't bother
1904*0Sstevel@tonic-gate 	 *	trying to clean up the allocated client handle since the
1905*0Sstevel@tonic-gate 	 *	whole system is probably hosed anyway and will shortly
1906*0Sstevel@tonic-gate 	 *	esplode.
1907*0Sstevel@tonic-gate 	 * It doesn't make sense to call cs_deregister_client at this point
1908*0Sstevel@tonic-gate 	 *	to clean up this broken client since the deregistration
1909*0Sstevel@tonic-gate 	 *	code will also call cs_find_client and most likely fail.
1910*0Sstevel@tonic-gate 	 */
1911*0Sstevel@tonic-gate 	if (!(client = cs_find_client(*ch, &error))) {
1912*0Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
1913*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
1914*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_add_client_to_socket: socket %d function 0x%x "
1915*0Sstevel@tonic-gate 				"invalid client handle created handle 0x%x\n",
1916*0Sstevel@tonic-gate 						(int)CS_GET_SOCKET_NUMBER(sn),
1917*0Sstevel@tonic-gate 						(int)CS_GET_FUNCTION_NUMBER(sn),
1918*0Sstevel@tonic-gate 						(int)*ch);
1919*0Sstevel@tonic-gate 	    return (error);
1920*0Sstevel@tonic-gate 	}
1921*0Sstevel@tonic-gate 
1922*0Sstevel@tonic-gate 	/*
1923*0Sstevel@tonic-gate 	 * Save the DDI information.
1924*0Sstevel@tonic-gate 	 */
1925*0Sstevel@tonic-gate 	client->dip = cr->dip;
1926*0Sstevel@tonic-gate 	cr->driver_name[MODMAXNAMELEN - 1] = NULL;
1927*0Sstevel@tonic-gate 	client->driver_name = (char *)kmem_zalloc(strlen(cr->driver_name) + 1,
1928*0Sstevel@tonic-gate 								KM_SLEEP);
1929*0Sstevel@tonic-gate 	(void) strcpy(client->driver_name, cr->driver_name);
1930*0Sstevel@tonic-gate 	client->instance = ddi_get_instance(cr->dip);
1931*0Sstevel@tonic-gate 
1932*0Sstevel@tonic-gate 	/*
1933*0Sstevel@tonic-gate 	 * Copy over the interesting items that the client gave us.
1934*0Sstevel@tonic-gate 	 */
1935*0Sstevel@tonic-gate 	client->flags = (cr->Attributes & INFO_CLIENT_TYPE_MASK);
1936*0Sstevel@tonic-gate 	client->event_callback_handler = cr->event_handler;
1937*0Sstevel@tonic-gate 	bcopy((caddr_t)&cr->event_callback_args,
1938*0Sstevel@tonic-gate 				(caddr_t)&client->event_callback_args,
1939*0Sstevel@tonic-gate 				sizeof (event_callback_args_t));
1940*0Sstevel@tonic-gate 	/*
1941*0Sstevel@tonic-gate 	 * Set the client handle since the client needs a client handle
1942*0Sstevel@tonic-gate 	 *	when they call us for their event handler.
1943*0Sstevel@tonic-gate 	 */
1944*0Sstevel@tonic-gate 	client->event_callback_args.client_handle = *ch;
1945*0Sstevel@tonic-gate 
1946*0Sstevel@tonic-gate 	/*
1947*0Sstevel@tonic-gate 	 * Initialize the IO window numbers; if an IO window number is equal
1948*0Sstevel@tonic-gate 	 *	to PCMCIA_MAX_WINDOWS it means that IO range is not in use.
1949*0Sstevel@tonic-gate 	 */
1950*0Sstevel@tonic-gate 	client->io_alloc.Window1 = PCMCIA_MAX_WINDOWS;
1951*0Sstevel@tonic-gate 	client->io_alloc.Window2 = PCMCIA_MAX_WINDOWS;
1952*0Sstevel@tonic-gate 
1953*0Sstevel@tonic-gate 	/*
1954*0Sstevel@tonic-gate 	 * Give the client the iblock and idevice cookies to use in
1955*0Sstevel@tonic-gate 	 *	the client's event handler high priority mutex.
1956*0Sstevel@tonic-gate 	 */
1957*0Sstevel@tonic-gate 	cr->iblk_cookie = sp->iblk;
1958*0Sstevel@tonic-gate 	cr->idev_cookie = sp->idev;
1959*0Sstevel@tonic-gate 
1960*0Sstevel@tonic-gate 	/*
1961*0Sstevel@tonic-gate 	 * Set up the global event mask information; we copy this directly
1962*0Sstevel@tonic-gate 	 *	from the client; since we are the only source of events,
1963*0Sstevel@tonic-gate 	 *	any bogus bits that the client puts in here won't matter
1964*0Sstevel@tonic-gate 	 *	because we'll never look at them.
1965*0Sstevel@tonic-gate 	 */
1966*0Sstevel@tonic-gate 	client->global_mask = cr->EventMask;
1967*0Sstevel@tonic-gate 
1968*0Sstevel@tonic-gate 	/*
1969*0Sstevel@tonic-gate 	 * If this client registered as a CSI client, set the appropriate
1970*0Sstevel@tonic-gate 	 *	flag in the client's flags area.
1971*0Sstevel@tonic-gate 	 */
1972*0Sstevel@tonic-gate 	if (cr->Attributes & INFO_CSI_CLIENT)
1973*0Sstevel@tonic-gate 	    client->flags |= CLIENT_CSI_CLIENT;
1974*0Sstevel@tonic-gate 
1975*0Sstevel@tonic-gate 	/*
1976*0Sstevel@tonic-gate 	 * If this client registered as a "super-client" set the appropriate
1977*0Sstevel@tonic-gate 	 *	flag in the client's flags area.
1978*0Sstevel@tonic-gate 	 */
1979*0Sstevel@tonic-gate 	if (super_client == CLIENT_SUPER_CLIENT)
1980*0Sstevel@tonic-gate 	    client->flags |= CLIENT_SUPER_CLIENT;
1981*0Sstevel@tonic-gate 
1982*0Sstevel@tonic-gate 	/*
1983*0Sstevel@tonic-gate 	 * Save other misc information that this client gave us - it is
1984*0Sstevel@tonic-gate 	 *	used in the GetClientInfo function.
1985*0Sstevel@tonic-gate 	 */
1986*0Sstevel@tonic-gate 	client->flags |= (cr->Attributes & INFO_CARD_FLAGS_MASK);
1987*0Sstevel@tonic-gate 
1988*0Sstevel@tonic-gate 	/*
1989*0Sstevel@tonic-gate 	 * Determine if we should give artificial card insertion events and
1990*0Sstevel@tonic-gate 	 *	a registration complete event. Since we don't differentiate
1991*0Sstevel@tonic-gate 	 *	between sharable and exclusive use cards when giving clients
1992*0Sstevel@tonic-gate 	 *	event notification, we modify the definition of the share/excl
1993*0Sstevel@tonic-gate 	 *	flags as follows:
1994*0Sstevel@tonic-gate 	 *
1995*0Sstevel@tonic-gate 	 *	    If either INFO_CARD_SHARE or INFO_CARD_EXCL is set,
1996*0Sstevel@tonic-gate 	 *	    the client will receive artificial card insertion
1997*0Sstevel@tonic-gate 	 *	    events (if the client's card is currently in the
1998*0Sstevel@tonic-gate 	 *	    socket) and a registration complete event.
1999*0Sstevel@tonic-gate 	 *
2000*0Sstevel@tonic-gate 	 *	    If neither of the INFO_CARD_SHARE or INFO_CARD_EXCL is
2001*0Sstevel@tonic-gate 	 *	    set, the client will not receive an artificial card
2002*0Sstevel@tonic-gate 	 *	    insertion event nor a registration complete event
2003*0Sstevel@tonic-gate 	 *	    due to the client's call to register client.
2004*0Sstevel@tonic-gate 	 *
2005*0Sstevel@tonic-gate 	 *	    The client's event mask is not affected by the setting
2006*0Sstevel@tonic-gate 	 *	    of these two bits.
2007*0Sstevel@tonic-gate 	 */
2008*0Sstevel@tonic-gate 	if (cr->Attributes & (INFO_CARD_SHARE | INFO_CARD_EXCL))
2009*0Sstevel@tonic-gate 	    client->pending_events = CS_EVENT_REGISTRATION_COMPLETE;
2010*0Sstevel@tonic-gate 
2011*0Sstevel@tonic-gate 	/*
2012*0Sstevel@tonic-gate 	 * Check to see if the card for this client is currently in
2013*0Sstevel@tonic-gate 	 *	the socket. If it is, then set CLIENT_CARD_INSERTED
2014*0Sstevel@tonic-gate 	 *	since clients that are calling GetStatus at attach
2015*0Sstevel@tonic-gate 	 *	time will typically check to see if their card is
2016*0Sstevel@tonic-gate 	 *	currently installed.
2017*0Sstevel@tonic-gate 	 * If this is the CSI client, we also need to check to see
2018*0Sstevel@tonic-gate 	 *	if there is any card inserted in the socket, since
2019*0Sstevel@tonic-gate 	 *	the cs_card_for_client function will always return
2020*0Sstevel@tonic-gate 	 *	TRUE for a CSI client.
2021*0Sstevel@tonic-gate 	 * XXX What about super-clients?
2022*0Sstevel@tonic-gate 	 */
2023*0Sstevel@tonic-gate 	if (client->flags & CLIENT_CSI_CLIENT) {
2024*0Sstevel@tonic-gate 	    get_ss_status_t get_ss_status;
2025*0Sstevel@tonic-gate 
2026*0Sstevel@tonic-gate 	    get_ss_status.socket = sp->socket_num;
2027*0Sstevel@tonic-gate 
2028*0Sstevel@tonic-gate 	    if (SocketServices(SS_GetStatus, &get_ss_status) != SUCCESS) {
2029*0Sstevel@tonic-gate 		mutex_exit(&sp->lock);
2030*0Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
2031*0Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
2032*0Sstevel@tonic-gate 	    } /* SS_GetStatus */
2033*0Sstevel@tonic-gate 
2034*0Sstevel@tonic-gate 	    if (!(cs_sbm2cse(get_ss_status.CardState) &
2035*0Sstevel@tonic-gate 			CS_EVENT_CARD_INSERTION))
2036*0Sstevel@tonic-gate 		cie = 0;
2037*0Sstevel@tonic-gate 
2038*0Sstevel@tonic-gate 	} /* CLIENT_CSI_CLIENT */
2039*0Sstevel@tonic-gate 
2040*0Sstevel@tonic-gate 	if (cs_card_for_client(client) && (cie != 0)) {
2041*0Sstevel@tonic-gate 	    client->pending_events |= CS_EVENT_CARD_INSERTION;
2042*0Sstevel@tonic-gate 	    client->flags |= CLIENT_CARD_INSERTED;
2043*0Sstevel@tonic-gate 	} /* cs_card_for_client */
2044*0Sstevel@tonic-gate 
2045*0Sstevel@tonic-gate 	sp->num_clients++;
2046*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
2047*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
2048*0Sstevel@tonic-gate 
2049*0Sstevel@tonic-gate 	return (CS_SUCCESS);
2050*0Sstevel@tonic-gate }
2051*0Sstevel@tonic-gate 
2052*0Sstevel@tonic-gate /*
2053*0Sstevel@tonic-gate  * cs_deregister_client - This supports the DeregisterClient call.
2054*0Sstevel@tonic-gate  */
2055*0Sstevel@tonic-gate static int
2056*0Sstevel@tonic-gate cs_deregister_client(client_handle_t client_handle)
2057*0Sstevel@tonic-gate {
2058*0Sstevel@tonic-gate 	cs_socket_t *sp;
2059*0Sstevel@tonic-gate 	client_t *client;
2060*0Sstevel@tonic-gate 	int error, super_client = 0;
2061*0Sstevel@tonic-gate 	int client_lock_acquired;
2062*0Sstevel@tonic-gate 
2063*0Sstevel@tonic-gate 	/*
2064*0Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
2065*0Sstevel@tonic-gate 	 *	is, we don't do anything except for return success.
2066*0Sstevel@tonic-gate 	 */
2067*0Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
2068*0Sstevel@tonic-gate 	    return (CS_SUCCESS);
2069*0Sstevel@tonic-gate 
2070*0Sstevel@tonic-gate 	/*
2071*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
2072*0Sstevel@tonic-gate 	 */
2073*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
2074*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
2075*0Sstevel@tonic-gate 
2076*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
2077*0Sstevel@tonic-gate 
2078*0Sstevel@tonic-gate 	/*
2079*0Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
2080*0Sstevel@tonic-gate 	 */
2081*0Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
2082*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
2083*0Sstevel@tonic-gate 	    return (error);
2084*0Sstevel@tonic-gate 	}
2085*0Sstevel@tonic-gate 
2086*0Sstevel@tonic-gate 	/*
2087*0Sstevel@tonic-gate 	 * Make sure that any resources allocated by this client are
2088*0Sstevel@tonic-gate 	 *	not still allocated, and that if this is an MTD that
2089*0Sstevel@tonic-gate 	 *	no MTD operations are still in progress.
2090*0Sstevel@tonic-gate 	 */
2091*0Sstevel@tonic-gate 	if (client->flags &    (CLIENT_IO_ALLOCATED	|
2092*0Sstevel@tonic-gate 				CLIENT_IRQ_ALLOCATED	|
2093*0Sstevel@tonic-gate 				CLIENT_WIN_ALLOCATED	|
2094*0Sstevel@tonic-gate 				REQ_CONFIGURATION_DONE	|
2095*0Sstevel@tonic-gate 				REQ_SOCKET_MASK_DONE	|
2096*0Sstevel@tonic-gate 				REQ_IO_DONE		|
2097*0Sstevel@tonic-gate 				REQ_IRQ_DONE)) {
2098*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
2099*0Sstevel@tonic-gate 	    return (CS_BUSY);
2100*0Sstevel@tonic-gate 	}
2101*0Sstevel@tonic-gate 
2102*0Sstevel@tonic-gate 	if (client->flags & CLIENT_MTD_IN_PROGRESS) {
2103*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
2104*0Sstevel@tonic-gate 	    return (CS_IN_USE);
2105*0Sstevel@tonic-gate 	}
2106*0Sstevel@tonic-gate 
2107*0Sstevel@tonic-gate 	/*
2108*0Sstevel@tonic-gate 	 * Any previously allocated resources are not allocated anymore, and
2109*0Sstevel@tonic-gate 	 *	no MTD operations are in progress, so if this is an MTD client
2110*0Sstevel@tonic-gate 	 *	then do any MTD-specific client deregistration, and then
2111*0Sstevel@tonic-gate 	 *	nuke this client.
2112*0Sstevel@tonic-gate 	 * We expect cs_deregister_mtd to never fail.
2113*0Sstevel@tonic-gate 	 */
2114*0Sstevel@tonic-gate 	if (client->flags & INFO_MTD_CLIENT)
2115*0Sstevel@tonic-gate 	    (void) cs_deregister_mtd(client_handle);
2116*0Sstevel@tonic-gate 
2117*0Sstevel@tonic-gate 	if (client->flags & CLIENT_SUPER_CLIENT)
2118*0Sstevel@tonic-gate 	    super_client = CLIENT_SUPER_CLIENT;
2119*0Sstevel@tonic-gate 
2120*0Sstevel@tonic-gate 	kmem_free(client->driver_name, strlen(client->driver_name) + 1);
2121*0Sstevel@tonic-gate 
2122*0Sstevel@tonic-gate 	error = cs_destroy_client_handle(client_handle);
2123*0Sstevel@tonic-gate 
2124*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
2125*0Sstevel@tonic-gate 
2126*0Sstevel@tonic-gate 	/*
2127*0Sstevel@tonic-gate 	 * If this was the "super-client" deregistering, then this
2128*0Sstevel@tonic-gate 	 *	will clear the global "super-client" lock.
2129*0Sstevel@tonic-gate 	 * XXX - move this outside the per-socket code.
2130*0Sstevel@tonic-gate 	 */
2131*0Sstevel@tonic-gate 	cs_clear_superclient_lock(super_client);
2132*0Sstevel@tonic-gate 
2133*0Sstevel@tonic-gate 	return (error);
2134*0Sstevel@tonic-gate }
2135*0Sstevel@tonic-gate 
2136*0Sstevel@tonic-gate /*
2137*0Sstevel@tonic-gate  * cs_create_next_client_minor - returns the next available client minor
2138*0Sstevel@tonic-gate  *					number or 0 if none available
2139*0Sstevel@tonic-gate  *
2140*0Sstevel@tonic-gate  * Note that cs_find_client will always return a valid pointer to the
2141*0Sstevel@tonic-gate  *	global Socket Services client which has a client minor number
2142*0Sstevel@tonic-gate  *	of 0; this means that this function can never return a 0 as the
2143*0Sstevel@tonic-gate  *	next valid available client minor number.
2144*0Sstevel@tonic-gate  */
2145*0Sstevel@tonic-gate unsigned
2146*0Sstevel@tonic-gate cs_create_next_client_minor(unsigned socket_num, unsigned next_minor)
2147*0Sstevel@tonic-gate {
2148*0Sstevel@tonic-gate 	unsigned max_client_handles = cs_max_client_handles;
2149*0Sstevel@tonic-gate 
2150*0Sstevel@tonic-gate 	do {
2151*0Sstevel@tonic-gate 	    next_minor &= CS_MAX_CLIENTS_MASK;
2152*0Sstevel@tonic-gate 	    if (!cs_find_client(MAKE_CLIENT_HANDLE(
2153*0Sstevel@tonic-gate 					CS_GET_SOCKET_NUMBER(socket_num),
2154*0Sstevel@tonic-gate 					CS_GET_FUNCTION_NUMBER(socket_num),
2155*0Sstevel@tonic-gate 							next_minor), NULL)) {
2156*0Sstevel@tonic-gate 		return (next_minor);
2157*0Sstevel@tonic-gate 	    }
2158*0Sstevel@tonic-gate 	    next_minor++;
2159*0Sstevel@tonic-gate 	} while (max_client_handles--);
2160*0Sstevel@tonic-gate 
2161*0Sstevel@tonic-gate 	return (0);
2162*0Sstevel@tonic-gate }
2163*0Sstevel@tonic-gate 
2164*0Sstevel@tonic-gate /*
2165*0Sstevel@tonic-gate  * cs_find_client - finds the client pointer associated with the client handle
2166*0Sstevel@tonic-gate  *			or NULL if client not found
2167*0Sstevel@tonic-gate  *
2168*0Sstevel@tonic-gate  * returns:	(client_t *)NULL - if client not found or an error occured
2169*0Sstevel@tonic-gate  *					If the error argument is not NULL,
2170*0Sstevel@tonic-gate  *					it is set to:
2171*0Sstevel@tonic-gate  *			CS_BAD_SOCKET - socket number in client_handle_t is
2172*0Sstevel@tonic-gate  *						invalid
2173*0Sstevel@tonic-gate  *			CS_BAD_HANDLE - client not found
2174*0Sstevel@tonic-gate  *			If no error, the error argument is not modified.
2175*0Sstevel@tonic-gate  *		(client_t *) - pointer to client_t structure
2176*0Sstevel@tonic-gate  *
2177*0Sstevel@tonic-gate  * Note that each socket always has a pseudo client with a client minor number
2178*0Sstevel@tonic-gate  *	of 0; this client minor number is used for Socket Services access to
2179*0Sstevel@tonic-gate  *	Card Services functions. The client pointer returned for client minor
2180*0Sstevel@tonic-gate  *	number 0 is the global Socket Services client pointer.
2181*0Sstevel@tonic-gate  */
2182*0Sstevel@tonic-gate static client_t *
2183*0Sstevel@tonic-gate cs_find_client(client_handle_t client_handle, int *error)
2184*0Sstevel@tonic-gate {
2185*0Sstevel@tonic-gate 	cs_socket_t *sp;
2186*0Sstevel@tonic-gate 	client_t *clp;
2187*0Sstevel@tonic-gate 
2188*0Sstevel@tonic-gate 	/*
2189*0Sstevel@tonic-gate 	 * If we are being asked to see if a client with a minor number
2190*0Sstevel@tonic-gate 	 *	of 0 exists, always return a pointer to the global Socket
2191*0Sstevel@tonic-gate 	 *	Services client, since this client always exists, and is
2192*0Sstevel@tonic-gate 	 *	only for use by Socket Services.  There is no socket
2193*0Sstevel@tonic-gate 	 *	associated with this special client handle.
2194*0Sstevel@tonic-gate 	 */
2195*0Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
2196*0Sstevel@tonic-gate 	    return (&cs_socket_services_client);
2197*0Sstevel@tonic-gate 
2198*0Sstevel@tonic-gate 	/*
2199*0Sstevel@tonic-gate 	 * Check to be sure that the socket number is in range
2200*0Sstevel@tonic-gate 	 */
2201*0Sstevel@tonic-gate 	if (!(CHECK_SOCKET_NUM(GET_CLIENT_SOCKET(client_handle),
2202*0Sstevel@tonic-gate 					cs_globals.max_socket_num))) {
2203*0Sstevel@tonic-gate 	    if (error)
2204*0Sstevel@tonic-gate 		*error = CS_BAD_SOCKET;
2205*0Sstevel@tonic-gate 	    return (NULL);
2206*0Sstevel@tonic-gate 	}
2207*0Sstevel@tonic-gate 
2208*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) {
2209*0Sstevel@tonic-gate 	    if (error)
2210*0Sstevel@tonic-gate 		*error = CS_BAD_SOCKET;
2211*0Sstevel@tonic-gate 	    return (NULL);
2212*0Sstevel@tonic-gate 	}
2213*0Sstevel@tonic-gate 
2214*0Sstevel@tonic-gate 	clp = sp->client_list;
2215*0Sstevel@tonic-gate 
2216*0Sstevel@tonic-gate 	while (clp) {
2217*0Sstevel@tonic-gate 	    if (clp->client_handle == client_handle)
2218*0Sstevel@tonic-gate 		return (clp);
2219*0Sstevel@tonic-gate 	    clp = clp->next;
2220*0Sstevel@tonic-gate 	}
2221*0Sstevel@tonic-gate 
2222*0Sstevel@tonic-gate 	if (error)
2223*0Sstevel@tonic-gate 	    *error = CS_BAD_HANDLE;
2224*0Sstevel@tonic-gate 
2225*0Sstevel@tonic-gate 	return (NULL);
2226*0Sstevel@tonic-gate }
2227*0Sstevel@tonic-gate 
2228*0Sstevel@tonic-gate /*
2229*0Sstevel@tonic-gate  * cs_destroy_client_handle - destroys client handle and client structure of
2230*0Sstevel@tonic-gate  *				passed client handle
2231*0Sstevel@tonic-gate  *
2232*0Sstevel@tonic-gate  * returns:	CS_SUCCESS - if client handle sucessfully destroyed
2233*0Sstevel@tonic-gate  *		CS_BAD_HANDLE - if client handle is invalid or if trying
2234*0Sstevel@tonic-gate  *					to destroy global SS client
2235*0Sstevel@tonic-gate  *		{other errors} - other errors from cs_find_client()
2236*0Sstevel@tonic-gate  */
2237*0Sstevel@tonic-gate static int
2238*0Sstevel@tonic-gate cs_destroy_client_handle(client_handle_t client_handle)
2239*0Sstevel@tonic-gate {
2240*0Sstevel@tonic-gate 	client_t *clp;
2241*0Sstevel@tonic-gate 	cs_socket_t *sp;
2242*0Sstevel@tonic-gate 	int error = CS_BAD_HANDLE;
2243*0Sstevel@tonic-gate 
2244*0Sstevel@tonic-gate 	/*
2245*0Sstevel@tonic-gate 	 * See if we were passed a valid client handle or if we're being asked
2246*0Sstevel@tonic-gate 	 *	to destroy the Socket Services client
2247*0Sstevel@tonic-gate 	 */
2248*0Sstevel@tonic-gate 	if ((!(clp = cs_find_client(client_handle, &error))) ||
2249*0Sstevel@tonic-gate 			(CLIENT_HANDLE_IS_SS(client_handle)))
2250*0Sstevel@tonic-gate 	    return (error);
2251*0Sstevel@tonic-gate 
2252*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
2253*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
2254*0Sstevel@tonic-gate 
2255*0Sstevel@tonic-gate 	/*
2256*0Sstevel@tonic-gate 	 * Recycle this client's minor number.  This will most likely
2257*0Sstevel@tonic-gate 	 *	be the next client minor number we use, but it is also
2258*0Sstevel@tonic-gate 	 *	a hint to cs_create_client_handle, and that function
2259*0Sstevel@tonic-gate 	 *	may actually create a new client handle using a minor
2260*0Sstevel@tonic-gate 	 *	number different that this number.
2261*0Sstevel@tonic-gate 	 */
2262*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
2263*0Sstevel@tonic-gate 	sp->next_cl_minor = GET_CLIENT_MINOR(client_handle);
2264*0Sstevel@tonic-gate 
2265*0Sstevel@tonic-gate 	/*
2266*0Sstevel@tonic-gate 	 * See if we're the first or not in the client list; if we're
2267*0Sstevel@tonic-gate 	 *	not first, then just adjust the client behind us to
2268*0Sstevel@tonic-gate 	 *	point to the client ahead of us; this could be NULL
2269*0Sstevel@tonic-gate 	 *	if we're the last client in the list.
2270*0Sstevel@tonic-gate 	 */
2271*0Sstevel@tonic-gate 	if (clp->prev) {
2272*0Sstevel@tonic-gate 	    clp->prev->next = clp->next;
2273*0Sstevel@tonic-gate 	} else {
2274*0Sstevel@tonic-gate 	/*
2275*0Sstevel@tonic-gate 	 * We are first, so adjust the client list head pointer
2276*0Sstevel@tonic-gate 	 *	in the socket to point to the client structure that
2277*0Sstevel@tonic-gate 	 *	follows us; this could turn out to be NULL if we're
2278*0Sstevel@tonic-gate 	 *	the only client on this socket.
2279*0Sstevel@tonic-gate 	 */
2280*0Sstevel@tonic-gate 	    sp->client_list = clp->next;
2281*0Sstevel@tonic-gate 	}
2282*0Sstevel@tonic-gate 
2283*0Sstevel@tonic-gate 	/*
2284*0Sstevel@tonic-gate 	 * If we're not the last client in the list, point the next
2285*0Sstevel@tonic-gate 	 *	client to the client behind us; this could turn out
2286*0Sstevel@tonic-gate 	 *	to be NULL if we're the first client on this socket.
2287*0Sstevel@tonic-gate 	 */
2288*0Sstevel@tonic-gate 	if (clp->next)
2289*0Sstevel@tonic-gate 	    clp->next->prev = clp->prev;
2290*0Sstevel@tonic-gate 
2291*0Sstevel@tonic-gate 	sp->num_clients--;
2292*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
2293*0Sstevel@tonic-gate 
2294*0Sstevel@tonic-gate 	/*
2295*0Sstevel@tonic-gate 	 * Free this client's memory.
2296*0Sstevel@tonic-gate 	 */
2297*0Sstevel@tonic-gate 	kmem_free(clp, sizeof (client_t));
2298*0Sstevel@tonic-gate 
2299*0Sstevel@tonic-gate 	return (CS_SUCCESS);
2300*0Sstevel@tonic-gate }
2301*0Sstevel@tonic-gate 
2302*0Sstevel@tonic-gate /*
2303*0Sstevel@tonic-gate  * cs_create_client_handle - create a new client handle for the passed
2304*0Sstevel@tonic-gate  *				socket and function number
2305*0Sstevel@tonic-gate  *
2306*0Sstevel@tonic-gate  * returns:	0 -  if can't create client for some reason
2307*0Sstevel@tonic-gate  *		client_handle_t - new client handle
2308*0Sstevel@tonic-gate  */
2309*0Sstevel@tonic-gate static client_handle_t
2310*0Sstevel@tonic-gate cs_create_client_handle(unsigned socket_num, client_t *cclp)
2311*0Sstevel@tonic-gate {
2312*0Sstevel@tonic-gate 	client_t *clp;
2313*0Sstevel@tonic-gate 	cs_socket_t *sp;
2314*0Sstevel@tonic-gate 	unsigned next_minor;
2315*0Sstevel@tonic-gate 	client_handle_t client_handle;
2316*0Sstevel@tonic-gate 
2317*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(socket_num)) == NULL)
2318*0Sstevel@tonic-gate 	    return (0);
2319*0Sstevel@tonic-gate 
2320*0Sstevel@tonic-gate 	/*
2321*0Sstevel@tonic-gate 	 * Get the next available minor number that we can use.  We use the
2322*0Sstevel@tonic-gate 	 *	next_cl_minor number as a hint to cs_create_next_client_minor
2323*0Sstevel@tonic-gate 	 *	and in most cases this will be the minor number we get back.
2324*0Sstevel@tonic-gate 	 * If for some reason we can't get a minor number, return an error.
2325*0Sstevel@tonic-gate 	 *	The only way we could get an error would be if there are
2326*0Sstevel@tonic-gate 	 *	already the maximum number of clients for this socket. Since
2327*0Sstevel@tonic-gate 	 *	the maximum number of clients per socket is pretty large,
2328*0Sstevel@tonic-gate 	 *	this error is unlikely to occur.
2329*0Sstevel@tonic-gate 	 */
2330*0Sstevel@tonic-gate 	if (!(next_minor =
2331*0Sstevel@tonic-gate 		cs_create_next_client_minor(socket_num, sp->next_cl_minor)))
2332*0Sstevel@tonic-gate 	    return (0);
2333*0Sstevel@tonic-gate 
2334*0Sstevel@tonic-gate 	/*
2335*0Sstevel@tonic-gate 	 * Got a new client minor number, now create a new client handle.
2336*0Sstevel@tonic-gate 	 */
2337*0Sstevel@tonic-gate 	client_handle = MAKE_CLIENT_HANDLE(CS_GET_SOCKET_NUMBER(socket_num),
2338*0Sstevel@tonic-gate 					CS_GET_FUNCTION_NUMBER(socket_num),
2339*0Sstevel@tonic-gate 					next_minor);
2340*0Sstevel@tonic-gate 
2341*0Sstevel@tonic-gate 	/*
2342*0Sstevel@tonic-gate 	 * If this client handle exists, then we have an internal
2343*0Sstevel@tonic-gate 	 *	error; this should never happen, BTW.  This is really
2344*0Sstevel@tonic-gate 	 *	a double-check on the cs_create_next_client_minor
2345*0Sstevel@tonic-gate 	 *	function, which also calls cs_find_client.
2346*0Sstevel@tonic-gate 	 */
2347*0Sstevel@tonic-gate 	if (cs_find_client(client_handle, NULL)) {
2348*0Sstevel@tonic-gate 	    cmn_err(CE_CONT,
2349*0Sstevel@tonic-gate 		"cs_create_client_handle: duplicate client handle 0x%x\n",
2350*0Sstevel@tonic-gate 							(int)client_handle);
2351*0Sstevel@tonic-gate 	    return (0);
2352*0Sstevel@tonic-gate 	}
2353*0Sstevel@tonic-gate 
2354*0Sstevel@tonic-gate 	/*
2355*0Sstevel@tonic-gate 	 * If we don't have any clients on this socket yet, create
2356*0Sstevel@tonic-gate 	 *	a new client and hang it on the socket client list.
2357*0Sstevel@tonic-gate 	 */
2358*0Sstevel@tonic-gate 	if (!sp->client_list) {
2359*0Sstevel@tonic-gate 	    sp->client_list = cclp;
2360*0Sstevel@tonic-gate 	    clp = sp->client_list;
2361*0Sstevel@tonic-gate 	} else {
2362*0Sstevel@tonic-gate 	/*
2363*0Sstevel@tonic-gate 	 * There are other clients on this socket, so look for
2364*0Sstevel@tonic-gate 	 *	the last client and add our new client after it.
2365*0Sstevel@tonic-gate 	 */
2366*0Sstevel@tonic-gate 	    clp = sp->client_list;
2367*0Sstevel@tonic-gate 	    while (clp->next) {
2368*0Sstevel@tonic-gate 		clp = clp->next;
2369*0Sstevel@tonic-gate 	    }
2370*0Sstevel@tonic-gate 
2371*0Sstevel@tonic-gate 	    clp->next = cclp;
2372*0Sstevel@tonic-gate 	    clp->next->prev = clp;
2373*0Sstevel@tonic-gate 	    clp = clp->next;
2374*0Sstevel@tonic-gate 	} /* if (!sp->client_list) */
2375*0Sstevel@tonic-gate 
2376*0Sstevel@tonic-gate 	/*
2377*0Sstevel@tonic-gate 	 * Assign the new client handle to this new client structure.
2378*0Sstevel@tonic-gate 	 */
2379*0Sstevel@tonic-gate 	clp->client_handle = client_handle;
2380*0Sstevel@tonic-gate 
2381*0Sstevel@tonic-gate 	/*
2382*0Sstevel@tonic-gate 	 * Create the next available client minor number for this socket
2383*0Sstevel@tonic-gate 	 *	and save it away.
2384*0Sstevel@tonic-gate 	 */
2385*0Sstevel@tonic-gate 	sp->next_cl_minor =
2386*0Sstevel@tonic-gate 		cs_create_next_client_minor(socket_num, sp->next_cl_minor);
2387*0Sstevel@tonic-gate 
2388*0Sstevel@tonic-gate 	return (client_handle);
2389*0Sstevel@tonic-gate }
2390*0Sstevel@tonic-gate 
2391*0Sstevel@tonic-gate /*
2392*0Sstevel@tonic-gate  * cs_clear_superclient_lock - clears the global "super-client" lock
2393*0Sstevel@tonic-gate  *
2394*0Sstevel@tonic-gate  * Note: this function uses the cs_globals.global_lock so observe proper
2395*0Sstevel@tonic-gate  *		nexting of locks!!
2396*0Sstevel@tonic-gate  */
2397*0Sstevel@tonic-gate static void
2398*0Sstevel@tonic-gate cs_clear_superclient_lock(int super_client)
2399*0Sstevel@tonic-gate {
2400*0Sstevel@tonic-gate 
2401*0Sstevel@tonic-gate 	/*
2402*0Sstevel@tonic-gate 	 * If this was a "super-client" registering then we need
2403*0Sstevel@tonic-gate 	 *	to clear the GLOBAL_SUPER_CLIENT_REGISTERED flag
2404*0Sstevel@tonic-gate 	 *	so that other "super-clients" can register.
2405*0Sstevel@tonic-gate 	 */
2406*0Sstevel@tonic-gate 	if (super_client == CLIENT_SUPER_CLIENT) {
2407*0Sstevel@tonic-gate 	    mutex_enter(&cs_globals.global_lock);
2408*0Sstevel@tonic-gate 	    cs_globals.flags &= ~GLOBAL_SUPER_CLIENT_REGISTERED;
2409*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.global_lock);
2410*0Sstevel@tonic-gate 	}
2411*0Sstevel@tonic-gate }
2412*0Sstevel@tonic-gate 
2413*0Sstevel@tonic-gate /*
2414*0Sstevel@tonic-gate  * ==== event handling section ====
2415*0Sstevel@tonic-gate  */
2416*0Sstevel@tonic-gate 
2417*0Sstevel@tonic-gate /*
2418*0Sstevel@tonic-gate  * cs_event - CS event hi-priority callback handler
2419*0Sstevel@tonic-gate  *
2420*0Sstevel@tonic-gate  *	This function gets called by SS and is passed the event type in
2421*0Sstevel@tonic-gate  *		the "event" argument, and the socket number in the "sn"
2422*0Sstevel@tonic-gate  *		argument. The "sn" argument is a valid logical socket
2423*0Sstevel@tonic-gate  *		number for all events except the PCE_SS_READY event.
2424*0Sstevel@tonic-gate  *
2425*0Sstevel@tonic-gate  *	The PCE_SS_INIT_STATE, PCE_ADD_SOCKET and PCE_DROP_SOCKET events
2426*0Sstevel@tonic-gate  *		are never called at high priority. These events return
2427*0Sstevel@tonic-gate  *		the following return codes:
2428*0Sstevel@tonic-gate  *
2429*0Sstevel@tonic-gate  *			CS_SUCCESS - operation sucessful
2430*0Sstevel@tonic-gate  *			CS_BAD_SOCKET - unable to complete operation
2431*0Sstevel@tonic-gate  *			CS_UNSUPPORTED_FUNCTION - bad subfunction of
2432*0Sstevel@tonic-gate  *							PCE_SS_INIT_STATE
2433*0Sstevel@tonic-gate  *
2434*0Sstevel@tonic-gate  *		The caller MUST look at these return codes!
2435*0Sstevel@tonic-gate  *
2436*0Sstevel@tonic-gate  *	This function is called at high-priority interrupt time for standard
2437*0Sstevel@tonic-gate  *		Card Services events, and the only standard Card Services
2438*0Sstevel@tonic-gate  *		event that it handles directly is the CS_EVENT_CARD_REMOVAL
2439*0Sstevel@tonic-gate  *		event, which gets shuttled right into the client's event
2440*0Sstevel@tonic-gate  *		handler.  All other events are just queued up and the socket
2441*0Sstevel@tonic-gate  *		event thread is woken up via the soft interrupt handler.
2442*0Sstevel@tonic-gate  *	Note that CS_EVENT_CARD_INSERTION events are not set in the clients'
2443*0Sstevel@tonic-gate  *		event field, since the CS card insertion/card ready processing
2444*0Sstevel@tonic-gate  *		code is responsible for setting this event in a client's
2445*0Sstevel@tonic-gate  *		event field.
2446*0Sstevel@tonic-gate  *
2447*0Sstevel@tonic-gate  */
2448*0Sstevel@tonic-gate /*ARGSUSED*/
2449*0Sstevel@tonic-gate uint32_t
2450*0Sstevel@tonic-gate cs_event(event_t event, uint32_t sn, uint32_t arg)
2451*0Sstevel@tonic-gate {
2452*0Sstevel@tonic-gate 	client_t *client;
2453*0Sstevel@tonic-gate 	cs_socket_t *sp;
2454*0Sstevel@tonic-gate 	client_types_t *ct;
2455*0Sstevel@tonic-gate 	uint32_t ret = CS_SUCCESS;
2456*0Sstevel@tonic-gate 
2457*0Sstevel@tonic-gate 	/*
2458*0Sstevel@tonic-gate 	 * Handle special SS<->CS events
2459*0Sstevel@tonic-gate 	 */
2460*0Sstevel@tonic-gate 	switch (event) {
2461*0Sstevel@tonic-gate 	    case PCE_SS_INIT_STATE:
2462*0Sstevel@tonic-gate 		mutex_enter(&cs_globals.global_lock);
2463*0Sstevel@tonic-gate 		switch (sn) {
2464*0Sstevel@tonic-gate 		    case PCE_SS_STATE_INIT:
2465*0Sstevel@tonic-gate 			if ((ret = cs_ss_init()) == CS_SUCCESS)
2466*0Sstevel@tonic-gate 			    cs_globals.init_state |= GLOBAL_INIT_STATE_SS_READY;
2467*0Sstevel@tonic-gate 			break;
2468*0Sstevel@tonic-gate 		    case PCE_SS_STATE_DEINIT:
2469*0Sstevel@tonic-gate 			cs_globals.init_state &= ~GLOBAL_INIT_STATE_SS_READY;
2470*0Sstevel@tonic-gate 			break;
2471*0Sstevel@tonic-gate 		    default:
2472*0Sstevel@tonic-gate 			ret = CS_UNSUPPORTED_FUNCTION;
2473*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_event: PCE_SS_INIT_STATE invalid "
2474*0Sstevel@tonic-gate 						"directive: 0x%x\n", sn);
2475*0Sstevel@tonic-gate 			break;
2476*0Sstevel@tonic-gate 		} /* switch (sn) */
2477*0Sstevel@tonic-gate 		mutex_exit(&cs_globals.global_lock);
2478*0Sstevel@tonic-gate 		return (ret);
2479*0Sstevel@tonic-gate 	    case PCE_ADD_SOCKET:
2480*0Sstevel@tonic-gate 		return (cs_add_socket(sn));
2481*0Sstevel@tonic-gate 	    case PCE_DROP_SOCKET:
2482*0Sstevel@tonic-gate 		return (cs_drop_socket(sn));
2483*0Sstevel@tonic-gate 	} /* switch (event) */
2484*0Sstevel@tonic-gate 
2485*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(sn)) == NULL)
2486*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
2487*0Sstevel@tonic-gate 
2488*0Sstevel@tonic-gate 	/*
2489*0Sstevel@tonic-gate 	 * Check to see if CS wants to unload - we do this since it's possible
2490*0Sstevel@tonic-gate 	 *	to disable certain sockets.  Do NOT acquire any locks yet.
2491*0Sstevel@tonic-gate 	 */
2492*0Sstevel@tonic-gate 	if (sp->flags & SOCKET_UNLOAD_MODULE) {
2493*0Sstevel@tonic-gate 	    if (event == PCE_CARD_INSERT)
2494*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "PCMCIA: socket %d disabled - please "
2495*0Sstevel@tonic-gate 							"remove card\n", sn);
2496*0Sstevel@tonic-gate 	    return (CS_SUCCESS);
2497*0Sstevel@tonic-gate 	}
2498*0Sstevel@tonic-gate 
2499*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
2500*0Sstevel@tonic-gate 
2501*0Sstevel@tonic-gate #ifdef	CS_DEBUG
2502*0Sstevel@tonic-gate 	if (cs_debug > 1) {
2503*0Sstevel@tonic-gate 	    event2text_t event2text;
2504*0Sstevel@tonic-gate 
2505*0Sstevel@tonic-gate 	    event2text.event = event;
2506*0Sstevel@tonic-gate 	    (void) cs_event2text(&event2text, 0);
2507*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_event: event=%s (x%x), socket=0x%x\n",
2508*0Sstevel@tonic-gate 				event2text.text, (int)event, (int)sn);
2509*0Sstevel@tonic-gate 	}
2510*0Sstevel@tonic-gate #endif
2511*0Sstevel@tonic-gate 
2512*0Sstevel@tonic-gate 	/*
2513*0Sstevel@tonic-gate 	 * Convert SS events to CS events; handle the PRR if necessary.
2514*0Sstevel@tonic-gate 	 */
2515*0Sstevel@tonic-gate 	sp->events |= ss_to_cs_events(sp, event);
2516*0Sstevel@tonic-gate 
2517*0Sstevel@tonic-gate 	/*
2518*0Sstevel@tonic-gate 	 * We want to maintain the required event dispatching order as
2519*0Sstevel@tonic-gate 	 *	specified in the PCMCIA spec, so we cycle through all
2520*0Sstevel@tonic-gate 	 *	clients on this socket to make sure that they are
2521*0Sstevel@tonic-gate 	 *	notified in the correct order of any high-priority
2522*0Sstevel@tonic-gate 	 *	events.
2523*0Sstevel@tonic-gate 	 */
2524*0Sstevel@tonic-gate 	ct = &client_types[0];
2525*0Sstevel@tonic-gate 	while (ct) {
2526*0Sstevel@tonic-gate 	/*
2527*0Sstevel@tonic-gate 	 * Point to the head of the client list for this socket, and go
2528*0Sstevel@tonic-gate 	 *	through each client to set up the client events as well as
2529*0Sstevel@tonic-gate 	 *	call the client's event handler directly if we have a high
2530*0Sstevel@tonic-gate 	 *	priority event that we need to tell the client about.
2531*0Sstevel@tonic-gate 	 */
2532*0Sstevel@tonic-gate 	    client = sp->client_list;
2533*0Sstevel@tonic-gate 
2534*0Sstevel@tonic-gate 	    if (ct->order & CLIENT_EVENTS_LIFO) {
2535*0Sstevel@tonic-gate 		client_t *clp = NULL;
2536*0Sstevel@tonic-gate 
2537*0Sstevel@tonic-gate 		while (client) {
2538*0Sstevel@tonic-gate 		    clp = client;
2539*0Sstevel@tonic-gate 		    client = client->next;
2540*0Sstevel@tonic-gate 		}
2541*0Sstevel@tonic-gate 		client = clp;
2542*0Sstevel@tonic-gate 	    }
2543*0Sstevel@tonic-gate 
2544*0Sstevel@tonic-gate 	    while (client) {
2545*0Sstevel@tonic-gate 		client->events |= ((sp->events & ~CS_EVENT_CARD_INSERTION) &
2546*0Sstevel@tonic-gate 				    (client->event_mask | client->global_mask));
2547*0Sstevel@tonic-gate 		if (client->flags & ct->type) {
2548*0Sstevel@tonic-gate #ifdef	CS_DEBUG
2549*0Sstevel@tonic-gate 		    if (cs_debug > 1) {
2550*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_event: socket %d client [%s] "
2551*0Sstevel@tonic-gate 						"events 0x%x flags 0x%x\n",
2552*0Sstevel@tonic-gate 						sn, client->driver_name,
2553*0Sstevel@tonic-gate 						(int)client->events,
2554*0Sstevel@tonic-gate 						(int)client->flags);
2555*0Sstevel@tonic-gate 		    }
2556*0Sstevel@tonic-gate #endif
2557*0Sstevel@tonic-gate 
2558*0Sstevel@tonic-gate 		/*
2559*0Sstevel@tonic-gate 		 * Handle the suspend and card removal events
2560*0Sstevel@tonic-gate 		 *	specially here so that the client can receive
2561*0Sstevel@tonic-gate 		 *	these events at high-priority.
2562*0Sstevel@tonic-gate 		 */
2563*0Sstevel@tonic-gate 		    if (client->events & CS_EVENT_PM_SUSPEND) {
2564*0Sstevel@tonic-gate 			if (client->flags & CLIENT_CARD_INSERTED) {
2565*0Sstevel@tonic-gate 			    CLIENT_EVENT_CALLBACK(client, CS_EVENT_PM_SUSPEND,
2566*0Sstevel@tonic-gate 							CS_EVENT_PRI_HIGH);
2567*0Sstevel@tonic-gate 			} /* if (CLIENT_CARD_INSERTED) */
2568*0Sstevel@tonic-gate 			client->events &= ~CS_EVENT_PM_SUSPEND;
2569*0Sstevel@tonic-gate 		    } /* if (CS_EVENT_PM_SUSPEND) */
2570*0Sstevel@tonic-gate 
2571*0Sstevel@tonic-gate 		    if (client->events & CS_EVENT_CARD_REMOVAL) {
2572*0Sstevel@tonic-gate 			if (client->flags & CLIENT_CARD_INSERTED) {
2573*0Sstevel@tonic-gate 			    client->flags &= ~(CLIENT_CARD_INSERTED |
2574*0Sstevel@tonic-gate 						CLIENT_SENT_INSERTION);
2575*0Sstevel@tonic-gate 			    CLIENT_EVENT_CALLBACK(client,
2576*0Sstevel@tonic-gate 							CS_EVENT_CARD_REMOVAL,
2577*0Sstevel@tonic-gate 							CS_EVENT_PRI_HIGH);
2578*0Sstevel@tonic-gate 			/*
2579*0Sstevel@tonic-gate 			 * Check to see if the client wants low priority
2580*0Sstevel@tonic-gate 			 *	removal events as well.
2581*0Sstevel@tonic-gate 			 */
2582*0Sstevel@tonic-gate 			    if ((client->event_mask | client->global_mask) &
2583*0Sstevel@tonic-gate 						CS_EVENT_CARD_REMOVAL_LOWP) {
2584*0Sstevel@tonic-gate 				client->events |= CS_EVENT_CARD_REMOVAL_LOWP;
2585*0Sstevel@tonic-gate 			    }
2586*0Sstevel@tonic-gate 			} /* if (CLIENT_CARD_INSERTED) */
2587*0Sstevel@tonic-gate 			client->events &= ~CS_EVENT_CARD_REMOVAL;
2588*0Sstevel@tonic-gate 		    } /* if (CS_EVENT_CARD_REMOVAL) */
2589*0Sstevel@tonic-gate 
2590*0Sstevel@tonic-gate 		} /* if (ct->type) */
2591*0Sstevel@tonic-gate 		if (ct->order & CLIENT_EVENTS_LIFO) {
2592*0Sstevel@tonic-gate 		    client = client->prev;
2593*0Sstevel@tonic-gate 		} else {
2594*0Sstevel@tonic-gate 		    client = client->next;
2595*0Sstevel@tonic-gate 		}
2596*0Sstevel@tonic-gate 	    } /* while (client) */
2597*0Sstevel@tonic-gate 
2598*0Sstevel@tonic-gate 	    ct = ct->next;
2599*0Sstevel@tonic-gate 	} /* while (ct) */
2600*0Sstevel@tonic-gate 
2601*0Sstevel@tonic-gate 	/*
2602*0Sstevel@tonic-gate 	 * Set the SOCKET_NEEDS_THREAD flag so that the soft interrupt
2603*0Sstevel@tonic-gate 	 *	handler will wakeup this socket's event thread.
2604*0Sstevel@tonic-gate 	 */
2605*0Sstevel@tonic-gate 	if (sp->events)
2606*0Sstevel@tonic-gate 	    sp->flags |= SOCKET_NEEDS_THREAD;
2607*0Sstevel@tonic-gate 
2608*0Sstevel@tonic-gate 	/*
2609*0Sstevel@tonic-gate 	 * Fire off a soft interrupt that will cause the socket thread
2610*0Sstevel@tonic-gate 	 *	to be woken up and any remaining events to be sent to
2611*0Sstevel@tonic-gate 	 *	the clients on this socket.
2612*0Sstevel@tonic-gate 	 */
2613*0Sstevel@tonic-gate 	if ((sp->init_state & SOCKET_INIT_STATE_SOFTINTR) &&
2614*0Sstevel@tonic-gate 			!(cs_globals.init_state & GLOBAL_INIT_STATE_UNLOADING))
2615*0Sstevel@tonic-gate 	    ddi_trigger_softintr(sp->softint_id);
2616*0Sstevel@tonic-gate 
2617*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
2618*0Sstevel@tonic-gate 
2619*0Sstevel@tonic-gate 	return (CS_SUCCESS);
2620*0Sstevel@tonic-gate }
2621*0Sstevel@tonic-gate 
2622*0Sstevel@tonic-gate /*
2623*0Sstevel@tonic-gate  * cs_card_insertion - handle card insertion and card ready events
2624*0Sstevel@tonic-gate  *
2625*0Sstevel@tonic-gate  * We read the CIS, if present, and store it away, then tell SS that
2626*0Sstevel@tonic-gate  *	we have read the CIS and it's ready to be parsed.  Since card
2627*0Sstevel@tonic-gate  *	insertion and card ready events are pretty closely intertwined,
2628*0Sstevel@tonic-gate  *	we handle both here.  For card ready events that are not the
2629*0Sstevel@tonic-gate  *	result of a card insertion event, we expect that the caller has
2630*0Sstevel@tonic-gate  *	already done the appropriate processing and that we will not be
2631*0Sstevel@tonic-gate  *	called unless we received a card ready event right after a card
2632*0Sstevel@tonic-gate  *	insertion event, i.e. that the SOCKET_WAIT_FOR_READY flag in
2633*0Sstevel@tonic-gate  *	sp->thread_state was set or if we get a CARD_READY event right
2634*0Sstevel@tonic-gate  *	after a CARD_INSERTION event.
2635*0Sstevel@tonic-gate  *
2636*0Sstevel@tonic-gate  *    calling:	sp - pointer to socket structure
2637*0Sstevel@tonic-gate  *		event - event to handle, one of:
2638*0Sstevel@tonic-gate  *				CS_EVENT_CARD_INSERTION
2639*0Sstevel@tonic-gate  *				CS_EVENT_CARD_READY
2640*0Sstevel@tonic-gate  *				CS_EVENT_SS_UPDATED
2641*0Sstevel@tonic-gate  */
2642*0Sstevel@tonic-gate static int
2643*0Sstevel@tonic-gate cs_card_insertion(cs_socket_t *sp, event_t event)
2644*0Sstevel@tonic-gate {
2645*0Sstevel@tonic-gate 	int ret;
2646*0Sstevel@tonic-gate 
2647*0Sstevel@tonic-gate 	/*
2648*0Sstevel@tonic-gate 	 * Since we're only called while waiting for the card insertion
2649*0Sstevel@tonic-gate 	 *	and card ready sequence to occur, we may have a pending
2650*0Sstevel@tonic-gate 	 *	card ready timer that hasn't gone off yet if we got a
2651*0Sstevel@tonic-gate 	 *	real card ready event.
2652*0Sstevel@tonic-gate 	 */
2653*0Sstevel@tonic-gate 	UNTIMEOUT(sp->rdybsy_tmo_id);
2654*0Sstevel@tonic-gate 
2655*0Sstevel@tonic-gate #ifdef	CS_DEBUG
2656*0Sstevel@tonic-gate 	if (cs_debug > 1) {
2657*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_card_insertion: event=0x%x, socket=0x%x\n",
2658*0Sstevel@tonic-gate 						(int)event, sp->socket_num);
2659*0Sstevel@tonic-gate 	}
2660*0Sstevel@tonic-gate #endif
2661*0Sstevel@tonic-gate 
2662*0Sstevel@tonic-gate 	/*
2663*0Sstevel@tonic-gate 	 * Handle card insertion processing
2664*0Sstevel@tonic-gate 	 */
2665*0Sstevel@tonic-gate 	if (event & CS_EVENT_CARD_INSERTION) {
2666*0Sstevel@tonic-gate 	    set_socket_t set_socket;
2667*0Sstevel@tonic-gate 	    get_ss_status_t gs;
2668*0Sstevel@tonic-gate 
2669*0Sstevel@tonic-gate 	/*
2670*0Sstevel@tonic-gate 	 * Check to be sure that we have a valid CIS window
2671*0Sstevel@tonic-gate 	 */
2672*0Sstevel@tonic-gate 	    if (!SOCKET_HAS_CIS_WINDOW(sp)) {
2673*0Sstevel@tonic-gate 		cmn_err(CE_CONT,
2674*0Sstevel@tonic-gate 			"cs_card_insertion: socket %d has no "
2675*0Sstevel@tonic-gate 							"CIS window\n",
2676*0Sstevel@tonic-gate 				sp->socket_num);
2677*0Sstevel@tonic-gate 		return (CS_GENERAL_FAILURE);
2678*0Sstevel@tonic-gate 	    }
2679*0Sstevel@tonic-gate 
2680*0Sstevel@tonic-gate 	/*
2681*0Sstevel@tonic-gate 	 * Apply power to the socket, enable card detect and card ready
2682*0Sstevel@tonic-gate 	 *	events, then reset the socket.
2683*0Sstevel@tonic-gate 	 */
2684*0Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
2685*0Sstevel@tonic-gate 	    sp->event_mask =   (CS_EVENT_CARD_REMOVAL   |
2686*0Sstevel@tonic-gate 				CS_EVENT_CARD_READY);
2687*0Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
2688*0Sstevel@tonic-gate 	    set_socket.socket = sp->socket_num;
2689*0Sstevel@tonic-gate 	    set_socket.SCIntMask = (SBM_CD | SBM_RDYBSY);
2690*0Sstevel@tonic-gate 	    set_socket.IREQRouting = 0;
2691*0Sstevel@tonic-gate 	    set_socket.IFType = IF_MEMORY;
2692*0Sstevel@tonic-gate 	    set_socket.CtlInd = 0; /* turn off controls and indicators */
2693*0Sstevel@tonic-gate 	    set_socket.State = (unsigned)~0;	/* clear latched state bits */
2694*0Sstevel@tonic-gate 
2695*0Sstevel@tonic-gate 	    (void) cs_convert_powerlevel(sp->socket_num, 50, VCC,
2696*0Sstevel@tonic-gate 						&set_socket.VccLevel);
2697*0Sstevel@tonic-gate 	    (void) cs_convert_powerlevel(sp->socket_num, 50, VPP1,
2698*0Sstevel@tonic-gate 						&set_socket.Vpp1Level);
2699*0Sstevel@tonic-gate 	    (void) cs_convert_powerlevel(sp->socket_num, 50, VPP2,
2700*0Sstevel@tonic-gate 						&set_socket.Vpp2Level);
2701*0Sstevel@tonic-gate 
2702*0Sstevel@tonic-gate 	    if ((ret = SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
2703*0Sstevel@tonic-gate 		cmn_err(CE_CONT,
2704*0Sstevel@tonic-gate 		    "cs_card_insertion: socket %d SS_SetSocket failure %d\n",
2705*0Sstevel@tonic-gate 				sp->socket_num, ret);
2706*0Sstevel@tonic-gate 		return (ret);
2707*0Sstevel@tonic-gate 	    }
2708*0Sstevel@tonic-gate 
2709*0Sstevel@tonic-gate 	/*
2710*0Sstevel@tonic-gate 	 * Clear the ready and ready_timeout events since they are now
2711*0Sstevel@tonic-gate 	 *	bogus since we're about to reset the socket.
2712*0Sstevel@tonic-gate 	 * XXX - should these be cleared right after the RESET??
2713*0Sstevel@tonic-gate 	 */
2714*0Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
2715*0Sstevel@tonic-gate 
2716*0Sstevel@tonic-gate 	    sp->events &= ~(CS_EVENT_CARD_READY | CS_EVENT_READY_TIMEOUT);
2717*0Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
2718*0Sstevel@tonic-gate 
2719*0Sstevel@tonic-gate 	    SocketServices(SS_ResetSocket, sp->socket_num,
2720*0Sstevel@tonic-gate 						RESET_MODE_CARD_ONLY);
2721*0Sstevel@tonic-gate 
2722*0Sstevel@tonic-gate 	/*
2723*0Sstevel@tonic-gate 	 * We are required by the PCMCIA spec to wait some number of
2724*0Sstevel@tonic-gate 	 *	milliseconds after reset before we access the card, so
2725*0Sstevel@tonic-gate 	 *	we set up a timer here that will wake us up and allow us
2726*0Sstevel@tonic-gate 	 *	to continue with our card initialization.
2727*0Sstevel@tonic-gate 	 */
2728*0Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
2729*0Sstevel@tonic-gate 	    sp->thread_state |= SOCKET_RESET_TIMER;
2730*0Sstevel@tonic-gate 	    (void) timeout(cs_ready_timeout, sp,
2731*0Sstevel@tonic-gate 		drv_usectohz(cs_reset_timeout_time * 1000));
2732*0Sstevel@tonic-gate 	    cv_wait(&sp->reset_cv, &sp->lock);
2733*0Sstevel@tonic-gate 	    sp->thread_state &= ~SOCKET_RESET_TIMER;
2734*0Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
2735*0Sstevel@tonic-gate 
2736*0Sstevel@tonic-gate #ifdef	CS_DEBUG
2737*0Sstevel@tonic-gate 	    if (cs_debug > 2) {
2738*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_card_insertion: socket %d out of RESET "
2739*0Sstevel@tonic-gate 		    "for %d mS sp->events 0x%x\n",
2740*0Sstevel@tonic-gate 		    sp->socket_num, cs_reset_timeout_time, (int)sp->events);
2741*0Sstevel@tonic-gate 	    }
2742*0Sstevel@tonic-gate #endif
2743*0Sstevel@tonic-gate 
2744*0Sstevel@tonic-gate 	/*
2745*0Sstevel@tonic-gate 	 * If we have a pending CS_EVENT_CARD_REMOVAL event it
2746*0Sstevel@tonic-gate 	 *	means that we likely got CD line bounce on the
2747*0Sstevel@tonic-gate 	 *	insertion, so terminate this processing.
2748*0Sstevel@tonic-gate 	 */
2749*0Sstevel@tonic-gate 	    if (sp->events & CS_EVENT_CARD_REMOVAL) {
2750*0Sstevel@tonic-gate #ifdef	CS_DEBUG
2751*0Sstevel@tonic-gate 		if (cs_debug > 0) {
2752*0Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_card_insertion: socket %d "
2753*0Sstevel@tonic-gate 						"CS_EVENT_CARD_REMOVAL event "
2754*0Sstevel@tonic-gate 						"terminating insertion "
2755*0Sstevel@tonic-gate 						"processing\n",
2756*0Sstevel@tonic-gate 							sp->socket_num);
2757*0Sstevel@tonic-gate 		}
2758*0Sstevel@tonic-gate #endif
2759*0Sstevel@tonic-gate 	    return (CS_SUCCESS);
2760*0Sstevel@tonic-gate 	    } /* if (CS_EVENT_CARD_REMOVAL) */
2761*0Sstevel@tonic-gate 
2762*0Sstevel@tonic-gate 	/*
2763*0Sstevel@tonic-gate 	 * If we got a card ready event after the reset, then don't
2764*0Sstevel@tonic-gate 	 *	bother setting up a card ready timer, since we'll blast
2765*0Sstevel@tonic-gate 	 *	right on through to the card ready processing.
2766*0Sstevel@tonic-gate 	 * Get the current card status to see if it's ready; if it
2767*0Sstevel@tonic-gate 	 *	is, we probably won't get a card ready event.
2768*0Sstevel@tonic-gate 	 */
2769*0Sstevel@tonic-gate 	    gs.socket = sp->socket_num;
2770*0Sstevel@tonic-gate 	    gs.CardState = 0;
2771*0Sstevel@tonic-gate 	    if ((ret = SocketServices(SS_GetStatus, &gs)) != SUCCESS) {
2772*0Sstevel@tonic-gate 		cmn_err(CE_CONT,
2773*0Sstevel@tonic-gate 		    "cs_card_insertion: socket %d SS_GetStatus failure %d\n",
2774*0Sstevel@tonic-gate 				sp->socket_num, ret);
2775*0Sstevel@tonic-gate 		return (ret);
2776*0Sstevel@tonic-gate 	    }
2777*0Sstevel@tonic-gate 
2778*0Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
2779*0Sstevel@tonic-gate 	    if ((sp->events & CS_EVENT_CARD_READY) ||
2780*0Sstevel@tonic-gate 					(gs.CardState & SBM_RDYBSY)) {
2781*0Sstevel@tonic-gate 		event = CS_EVENT_CARD_READY;
2782*0Sstevel@tonic-gate #ifdef	CS_DEBUG
2783*0Sstevel@tonic-gate 		if (cs_debug > 1) {
2784*0Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_card_insertion: socket %d card "
2785*0Sstevel@tonic-gate 						"READY\n", sp->socket_num);
2786*0Sstevel@tonic-gate 		}
2787*0Sstevel@tonic-gate #endif
2788*0Sstevel@tonic-gate 
2789*0Sstevel@tonic-gate 	    } else {
2790*0Sstevel@tonic-gate #ifdef	CS_DEBUG
2791*0Sstevel@tonic-gate 		if (cs_debug > 1) {
2792*0Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_card_insertion: socket %d setting "
2793*0Sstevel@tonic-gate 					"READY timer\n", sp->socket_num);
2794*0Sstevel@tonic-gate 		}
2795*0Sstevel@tonic-gate #endif
2796*0Sstevel@tonic-gate 
2797*0Sstevel@tonic-gate 		sp->rdybsy_tmo_id = timeout(cs_ready_timeout, sp,
2798*0Sstevel@tonic-gate 		    READY_TIMEOUT_TIME);
2799*0Sstevel@tonic-gate 		sp->thread_state |= SOCKET_WAIT_FOR_READY;
2800*0Sstevel@tonic-gate 
2801*0Sstevel@tonic-gate 	    } /* if (CS_EVENT_CARD_READY) */
2802*0Sstevel@tonic-gate 
2803*0Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
2804*0Sstevel@tonic-gate 
2805*0Sstevel@tonic-gate 	} /* if (CS_EVENT_CARD_INSERTION) */
2806*0Sstevel@tonic-gate 
2807*0Sstevel@tonic-gate 	/*
2808*0Sstevel@tonic-gate 	 * Handle card ready processing.  This is only card ready processing
2809*0Sstevel@tonic-gate 	 *	for card ready events in conjunction with a card insertion.
2810*0Sstevel@tonic-gate 	 */
2811*0Sstevel@tonic-gate 	if (event == CS_EVENT_CARD_READY) {
2812*0Sstevel@tonic-gate 	    get_socket_t get_socket;
2813*0Sstevel@tonic-gate 	    set_socket_t set_socket;
2814*0Sstevel@tonic-gate 
2815*0Sstevel@tonic-gate 	/*
2816*0Sstevel@tonic-gate 	 * The only events that we want to see now are card removal
2817*0Sstevel@tonic-gate 	 *	events.
2818*0Sstevel@tonic-gate 	 */
2819*0Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
2820*0Sstevel@tonic-gate 	    sp->event_mask = CS_EVENT_CARD_REMOVAL;
2821*0Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
2822*0Sstevel@tonic-gate 	    get_socket.socket = sp->socket_num;
2823*0Sstevel@tonic-gate 	    if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
2824*0Sstevel@tonic-gate 		cmn_err(CE_CONT,
2825*0Sstevel@tonic-gate 			"cs_card_insertion: socket %d SS_GetSocket failed\n",
2826*0Sstevel@tonic-gate 							sp->socket_num);
2827*0Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
2828*0Sstevel@tonic-gate 	    }
2829*0Sstevel@tonic-gate 
2830*0Sstevel@tonic-gate 	    set_socket.socket = sp->socket_num;
2831*0Sstevel@tonic-gate 	    set_socket.SCIntMask = SBM_CD;
2832*0Sstevel@tonic-gate 	    set_socket.VccLevel = get_socket.VccLevel;
2833*0Sstevel@tonic-gate 	    set_socket.Vpp1Level = get_socket.Vpp1Level;
2834*0Sstevel@tonic-gate 	    set_socket.Vpp2Level = get_socket.Vpp2Level;
2835*0Sstevel@tonic-gate 	    set_socket.IREQRouting = get_socket.IRQRouting;
2836*0Sstevel@tonic-gate 	    set_socket.IFType = get_socket.IFType;
2837*0Sstevel@tonic-gate 	    set_socket.CtlInd = get_socket.CtlInd;
2838*0Sstevel@tonic-gate 	    /* XXX (is ~0 correct here?) to reset latched values */
2839*0Sstevel@tonic-gate 	    set_socket.State = (unsigned)~0;
2840*0Sstevel@tonic-gate 
2841*0Sstevel@tonic-gate 	    if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
2842*0Sstevel@tonic-gate 		cmn_err(CE_CONT,
2843*0Sstevel@tonic-gate 			"cs_card_insertion: socket %d SS_SetSocket failed\n",
2844*0Sstevel@tonic-gate 							sp->socket_num);
2845*0Sstevel@tonic-gate 
2846*0Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
2847*0Sstevel@tonic-gate 	    }
2848*0Sstevel@tonic-gate 
2849*0Sstevel@tonic-gate 		/*
2850*0Sstevel@tonic-gate 		 * Grab the cis_lock mutex to protect the CIS-to-be and
2851*0Sstevel@tonic-gate 		 *	the CIS window, then fire off the CIS parser to
2852*0Sstevel@tonic-gate 		 *	create a local copy of the card's CIS.
2853*0Sstevel@tonic-gate 		 */
2854*0Sstevel@tonic-gate 		mutex_enter(&sp->cis_lock);
2855*0Sstevel@tonic-gate 
2856*0Sstevel@tonic-gate 		if ((ret = cs_create_cis(sp)) != CS_SUCCESS) {
2857*0Sstevel@tonic-gate 		    mutex_exit(&sp->cis_lock);
2858*0Sstevel@tonic-gate 		    return (ret);
2859*0Sstevel@tonic-gate 		}
2860*0Sstevel@tonic-gate 
2861*0Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
2862*0Sstevel@tonic-gate 
2863*0Sstevel@tonic-gate 		/*
2864*0Sstevel@tonic-gate 		 * If we have a pending CS_EVENT_CARD_REMOVAL event it
2865*0Sstevel@tonic-gate 		 *	means that we likely got CD line bounce on the
2866*0Sstevel@tonic-gate 		 *	insertion, so destroy the CIS and terminate this
2867*0Sstevel@tonic-gate 		 *	processing. We'll get called back to handle the
2868*0Sstevel@tonic-gate 		 *	insertion again later.
2869*0Sstevel@tonic-gate 		 */
2870*0Sstevel@tonic-gate 		if (sp->events & CS_EVENT_CARD_REMOVAL) {
2871*0Sstevel@tonic-gate 		    mutex_enter(&sp->cis_lock);
2872*0Sstevel@tonic-gate 		    (void) cs_destroy_cis(sp);
2873*0Sstevel@tonic-gate 		    mutex_exit(&sp->cis_lock);
2874*0Sstevel@tonic-gate 		} else {
2875*0Sstevel@tonic-gate 			/*
2876*0Sstevel@tonic-gate 			 * Schedule the call to the Socket Services work thread.
2877*0Sstevel@tonic-gate 			 */
2878*0Sstevel@tonic-gate 		    mutex_enter(&sp->ss_thread_lock);
2879*0Sstevel@tonic-gate 		    sp->ss_thread_state |= SOCKET_THREAD_CSCISInit;
2880*0Sstevel@tonic-gate 		    cv_broadcast(&sp->ss_thread_cv);
2881*0Sstevel@tonic-gate 		    mutex_exit(&sp->ss_thread_lock);
2882*0Sstevel@tonic-gate 		} /* if (CS_EVENT_CARD_REMOVAL) */
2883*0Sstevel@tonic-gate 	} /* if (CS_EVENT_CARD_READY) */
2884*0Sstevel@tonic-gate 
2885*0Sstevel@tonic-gate 	/*
2886*0Sstevel@tonic-gate 	 * Socket Services has parsed the CIS and has done any other
2887*0Sstevel@tonic-gate 	 *	work to get the client driver loaded and attached if
2888*0Sstevel@tonic-gate 	 *	necessary, so setup the per-client state.
2889*0Sstevel@tonic-gate 	 */
2890*0Sstevel@tonic-gate 	if (event == CS_EVENT_SS_UPDATED) {
2891*0Sstevel@tonic-gate 	    client_t *client;
2892*0Sstevel@tonic-gate 
2893*0Sstevel@tonic-gate 	/*
2894*0Sstevel@tonic-gate 	 * Now that we and SS are done handling the card insertion
2895*0Sstevel@tonic-gate 	 *	semantics, go through each client on this socket and set
2896*0Sstevel@tonic-gate 	 *	the CS_EVENT_CARD_INSERTION event in each client's event
2897*0Sstevel@tonic-gate 	 *	field.  We do this here instead of in cs_event so that
2898*0Sstevel@tonic-gate 	 *	when a client gets a CS_EVENT_CARD_INSERTION event, the
2899*0Sstevel@tonic-gate 	 *	card insertion and ready processing has already been done
2900*0Sstevel@tonic-gate 	 *	and SocketServices has had a chance to create a dip for
2901*0Sstevel@tonic-gate 	 *	the card in this socket.
2902*0Sstevel@tonic-gate 	 */
2903*0Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
2904*0Sstevel@tonic-gate 	    client = sp->client_list;
2905*0Sstevel@tonic-gate 	    while (client) {
2906*0Sstevel@tonic-gate 		client->events |= (CS_EVENT_CARD_INSERTION &
2907*0Sstevel@tonic-gate 				(client->event_mask | client->global_mask));
2908*0Sstevel@tonic-gate 		client = client->next;
2909*0Sstevel@tonic-gate 	    } /* while (client) */
2910*0Sstevel@tonic-gate 
2911*0Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
2912*0Sstevel@tonic-gate 
2913*0Sstevel@tonic-gate 	} /* if (CS_EVENT_SS_UPDATED) */
2914*0Sstevel@tonic-gate 
2915*0Sstevel@tonic-gate 	return (CS_SUCCESS);
2916*0Sstevel@tonic-gate }
2917*0Sstevel@tonic-gate 
2918*0Sstevel@tonic-gate /*
2919*0Sstevel@tonic-gate  * cs_card_removal - handle card removal events
2920*0Sstevel@tonic-gate  *
2921*0Sstevel@tonic-gate  * Destroy the CIS.
2922*0Sstevel@tonic-gate  *
2923*0Sstevel@tonic-gate  *    calling:	sp - pointer to socket structure
2924*0Sstevel@tonic-gate  *
2925*0Sstevel@tonic-gate  */
2926*0Sstevel@tonic-gate static int
2927*0Sstevel@tonic-gate cs_card_removal(cs_socket_t *sp)
2928*0Sstevel@tonic-gate {
2929*0Sstevel@tonic-gate 	set_socket_t set_socket;
2930*0Sstevel@tonic-gate 	int ret;
2931*0Sstevel@tonic-gate 
2932*0Sstevel@tonic-gate #ifdef	CS_DEBUG
2933*0Sstevel@tonic-gate 	if (cs_debug > 0) {
2934*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_card_removal: socket %d\n", sp->socket_num);
2935*0Sstevel@tonic-gate 	}
2936*0Sstevel@tonic-gate #endif
2937*0Sstevel@tonic-gate 
2938*0Sstevel@tonic-gate 	/*
2939*0Sstevel@tonic-gate 	 * Remove any pending card ready timer
2940*0Sstevel@tonic-gate 	 */
2941*0Sstevel@tonic-gate 	UNTIMEOUT(sp->rdybsy_tmo_id);
2942*0Sstevel@tonic-gate 
2943*0Sstevel@tonic-gate 	/*
2944*0Sstevel@tonic-gate 	 * Clear various flags so that everyone else knows that there's
2945*0Sstevel@tonic-gate 	 *	nothing on this socket anymore.  Note that we clear the
2946*0Sstevel@tonic-gate 	 *	SOCKET_CARD_INSERTED and SOCKET_IS_IO flags in the
2947*0Sstevel@tonic-gate 	 *	ss_to_cs_events event mapping function.
2948*0Sstevel@tonic-gate 	 */
2949*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
2950*0Sstevel@tonic-gate 	sp->thread_state &= ~(SOCKET_WAIT_FOR_READY | SOCKET_RESET_TIMER);
2951*0Sstevel@tonic-gate 
2952*0Sstevel@tonic-gate 	/*
2953*0Sstevel@tonic-gate 	 * Turn off socket power and set the socket back to memory mode.
2954*0Sstevel@tonic-gate 	 * Disable all socket events except for CARD_INSERTION events.
2955*0Sstevel@tonic-gate 	 */
2956*0Sstevel@tonic-gate 	sp->event_mask = CS_EVENT_CARD_INSERTION;
2957*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
2958*0Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
2959*0Sstevel@tonic-gate 	set_socket.SCIntMask = SBM_CD;
2960*0Sstevel@tonic-gate 	set_socket.IREQRouting = 0;
2961*0Sstevel@tonic-gate 	set_socket.IFType = IF_MEMORY;
2962*0Sstevel@tonic-gate 	set_socket.CtlInd = 0; /* turn off controls and indicators */
2963*0Sstevel@tonic-gate 	set_socket.State = (unsigned)~0;	/* clear latched state bits */
2964*0Sstevel@tonic-gate 
2965*0Sstevel@tonic-gate 	(void) cs_convert_powerlevel(sp->socket_num, 0, VCC,
2966*0Sstevel@tonic-gate 					&set_socket.VccLevel);
2967*0Sstevel@tonic-gate 	(void) cs_convert_powerlevel(sp->socket_num, 0, VPP1,
2968*0Sstevel@tonic-gate 					&set_socket.Vpp1Level);
2969*0Sstevel@tonic-gate 	(void) cs_convert_powerlevel(sp->socket_num, 0, VPP2,
2970*0Sstevel@tonic-gate 					&set_socket.Vpp2Level);
2971*0Sstevel@tonic-gate 
2972*0Sstevel@tonic-gate 	if ((ret = SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
2973*0Sstevel@tonic-gate 	    cmn_err(CE_CONT,
2974*0Sstevel@tonic-gate 		"cs_card_removal: socket %d SS_SetSocket failure %d\n",
2975*0Sstevel@tonic-gate 				sp->socket_num, ret);
2976*0Sstevel@tonic-gate 	    return (ret);
2977*0Sstevel@tonic-gate 	}
2978*0Sstevel@tonic-gate 
2979*0Sstevel@tonic-gate #ifdef	CS_DEBUG
2980*0Sstevel@tonic-gate 	if (cs_debug > 2) {
2981*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_card_removal: socket %d "
2982*0Sstevel@tonic-gate 					"calling cs_destroy_cis\n",
2983*0Sstevel@tonic-gate 							sp->socket_num);
2984*0Sstevel@tonic-gate 	}
2985*0Sstevel@tonic-gate #endif
2986*0Sstevel@tonic-gate 
2987*0Sstevel@tonic-gate 	/*
2988*0Sstevel@tonic-gate 	 * Destroy the CIS and tell Socket Services that we're done
2989*0Sstevel@tonic-gate 	 *	handling the card removal event.
2990*0Sstevel@tonic-gate 	 */
2991*0Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
2992*0Sstevel@tonic-gate 	(void) cs_destroy_cis(sp);
2993*0Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
2994*0Sstevel@tonic-gate 
2995*0Sstevel@tonic-gate #ifdef	CS_DEBUG
2996*0Sstevel@tonic-gate 	if (cs_debug > 2) {
2997*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_card_removal: calling CSCardRemoved\n");
2998*0Sstevel@tonic-gate 	}
2999*0Sstevel@tonic-gate #endif
3000*0Sstevel@tonic-gate 
3001*0Sstevel@tonic-gate 	SocketServices(CSCardRemoved, sp->socket_num);
3002*0Sstevel@tonic-gate 
3003*0Sstevel@tonic-gate 	return (CS_SUCCESS);
3004*0Sstevel@tonic-gate }
3005*0Sstevel@tonic-gate 
3006*0Sstevel@tonic-gate /*
3007*0Sstevel@tonic-gate  * ss_to_cs_events - convert Socket Services events to Card Services event
3008*0Sstevel@tonic-gate  *			masks; this function will not read the PRR if the
3009*0Sstevel@tonic-gate  *			socket is in IO mode; this happens in cs_event_thread
3010*0Sstevel@tonic-gate  *
3011*0Sstevel@tonic-gate  * This function returns a bit mask of events.
3012*0Sstevel@tonic-gate  *
3013*0Sstevel@tonic-gate  * Note that we do some simple hysterious on card insertion and card removal
3014*0Sstevel@tonic-gate  *	events to prevent spurious insertion and removal events from being
3015*0Sstevel@tonic-gate  *	propogated down the chain.
3016*0Sstevel@tonic-gate  */
3017*0Sstevel@tonic-gate static event_t
3018*0Sstevel@tonic-gate ss_to_cs_events(cs_socket_t *sp, event_t event)
3019*0Sstevel@tonic-gate {
3020*0Sstevel@tonic-gate 	event_t revent = 0;
3021*0Sstevel@tonic-gate 
3022*0Sstevel@tonic-gate 	switch (event) {
3023*0Sstevel@tonic-gate 	    case PCE_CARD_STATUS_CHANGE:
3024*0Sstevel@tonic-gate 		revent |= CS_EVENT_STATUS_CHANGE;
3025*0Sstevel@tonic-gate 		break;
3026*0Sstevel@tonic-gate 	    case PCE_CARD_REMOVAL:
3027*0Sstevel@tonic-gate 		if (sp->flags & SOCKET_CARD_INSERTED) {
3028*0Sstevel@tonic-gate 		    sp->flags &= ~(SOCKET_CARD_INSERTED | SOCKET_IS_IO);
3029*0Sstevel@tonic-gate 		    revent |= CS_EVENT_CARD_REMOVAL;
3030*0Sstevel@tonic-gate 			/*
3031*0Sstevel@tonic-gate 			 * If we're processing a removal event, it makes
3032*0Sstevel@tonic-gate 			 *	no sense to keep any insertion or ready events,
3033*0Sstevel@tonic-gate 			 *	so nuke them here.  This will not clear any
3034*0Sstevel@tonic-gate 			 *	insertion events in the per-client event field.
3035*0Sstevel@tonic-gate 			 */
3036*0Sstevel@tonic-gate 		    sp->events &= ~(CS_EVENT_CARD_INSERTION |
3037*0Sstevel@tonic-gate 				    CS_EVENT_CARD_READY |
3038*0Sstevel@tonic-gate 				    CS_EVENT_READY_TIMEOUT);
3039*0Sstevel@tonic-gate 
3040*0Sstevel@tonic-gate 		/*
3041*0Sstevel@tonic-gate 		 * We also don't need to wait for READY anymore since
3042*0Sstevel@tonic-gate 		 *	it probably won't show up, or if it does, it will
3043*0Sstevel@tonic-gate 		 *	be a bogus READY event as the card is sliding out
3044*0Sstevel@tonic-gate 		 *	of the socket.  Since we never do a cv_wait on the
3045*0Sstevel@tonic-gate 		 *	card ready timer, it's OK for that timer to either
3046*0Sstevel@tonic-gate 		 *	never go off (via an UNTIMEOUT in cs_card_removal)
3047*0Sstevel@tonic-gate 		 *	or to go off but not do a cv_broadcast (since the
3048*0Sstevel@tonic-gate 		 *	SOCKET_WAIT_FOR_READY flag is cleared here).
3049*0Sstevel@tonic-gate 		 */
3050*0Sstevel@tonic-gate 		    sp->thread_state &= ~SOCKET_WAIT_FOR_READY;
3051*0Sstevel@tonic-gate 
3052*0Sstevel@tonic-gate 		}
3053*0Sstevel@tonic-gate 		break;
3054*0Sstevel@tonic-gate 	    case PCE_CARD_INSERT:
3055*0Sstevel@tonic-gate 		if (!(sp->flags & SOCKET_CARD_INSERTED)) {
3056*0Sstevel@tonic-gate 		    sp->flags |= SOCKET_CARD_INSERTED;
3057*0Sstevel@tonic-gate 		    revent |= CS_EVENT_CARD_INSERTION;
3058*0Sstevel@tonic-gate 		}
3059*0Sstevel@tonic-gate 		break;
3060*0Sstevel@tonic-gate 	    case PCE_CARD_READY:
3061*0Sstevel@tonic-gate 		if (sp->flags & SOCKET_CARD_INSERTED)
3062*0Sstevel@tonic-gate 		    revent |= CS_EVENT_CARD_READY;
3063*0Sstevel@tonic-gate 		break;
3064*0Sstevel@tonic-gate 	    case PCE_CARD_BATTERY_WARN:
3065*0Sstevel@tonic-gate 		if (sp->flags & SOCKET_CARD_INSERTED)
3066*0Sstevel@tonic-gate 		    revent |= CS_EVENT_BATTERY_LOW;
3067*0Sstevel@tonic-gate 		break;
3068*0Sstevel@tonic-gate 	    case PCE_CARD_BATTERY_DEAD:
3069*0Sstevel@tonic-gate 		if (sp->flags & SOCKET_CARD_INSERTED)
3070*0Sstevel@tonic-gate 		    revent |= CS_EVENT_BATTERY_DEAD;
3071*0Sstevel@tonic-gate 		break;
3072*0Sstevel@tonic-gate 	    case PCE_CARD_WRITE_PROTECT:
3073*0Sstevel@tonic-gate 		if (sp->flags & SOCKET_CARD_INSERTED)
3074*0Sstevel@tonic-gate 		    revent |= CS_EVENT_WRITE_PROTECT;
3075*0Sstevel@tonic-gate 		break;
3076*0Sstevel@tonic-gate 	    case PCE_PM_RESUME:
3077*0Sstevel@tonic-gate 		revent |= CS_EVENT_PM_RESUME;
3078*0Sstevel@tonic-gate 		break;
3079*0Sstevel@tonic-gate 	    case PCE_PM_SUSPEND:
3080*0Sstevel@tonic-gate 		revent |= CS_EVENT_PM_SUSPEND;
3081*0Sstevel@tonic-gate 		break;
3082*0Sstevel@tonic-gate 	    default:
3083*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "ss_to_cs_events: unknown event 0x%x\n",
3084*0Sstevel@tonic-gate 								(int)event);
3085*0Sstevel@tonic-gate 		break;
3086*0Sstevel@tonic-gate 	} /* switch(event) */
3087*0Sstevel@tonic-gate 
3088*0Sstevel@tonic-gate 	return (revent);
3089*0Sstevel@tonic-gate }
3090*0Sstevel@tonic-gate 
3091*0Sstevel@tonic-gate /*
3092*0Sstevel@tonic-gate  * cs_ready_timeout - general purpose READY/BUSY and RESET timer
3093*0Sstevel@tonic-gate  *
3094*0Sstevel@tonic-gate  * Note that we really only expect one of the two events to be asserted when
3095*0Sstevel@tonic-gate  *	we are called.  XXX - Perhaps this might be a problem later on??
3096*0Sstevel@tonic-gate  *
3097*0Sstevel@tonic-gate  *	There is also the problem of cv_broadcast dropping the interrupt
3098*0Sstevel@tonic-gate  *	priority, even though we have our high-priority mutex held.  If
3099*0Sstevel@tonic-gate  *	we hold our high-priority mutex (sp->lock) over a cv_broadcast, and
3100*0Sstevel@tonic-gate  *	we get a high-priority interrupt during this time, the system will
3101*0Sstevel@tonic-gate  *	deadlock or panic.  Thanks to Andy Banta for finding this out in
3102*0Sstevel@tonic-gate  *	the SPC/S (stc.c) driver.
3103*0Sstevel@tonic-gate  *
3104*0Sstevel@tonic-gate  * This callback routine can not grab the sp->client_lock mutex or deadlock
3105*0Sstevel@tonic-gate  *	will result.
3106*0Sstevel@tonic-gate  */
3107*0Sstevel@tonic-gate void
3108*0Sstevel@tonic-gate cs_ready_timeout(void *arg)
3109*0Sstevel@tonic-gate {
3110*0Sstevel@tonic-gate 	cs_socket_t *sp = arg;
3111*0Sstevel@tonic-gate 	kcondvar_t *cvp = NULL;
3112*0Sstevel@tonic-gate 
3113*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
3114*0Sstevel@tonic-gate 
3115*0Sstevel@tonic-gate 	if (sp->thread_state & SOCKET_RESET_TIMER) {
3116*0Sstevel@tonic-gate #ifdef	CS_DEBUG
3117*0Sstevel@tonic-gate 	if (cs_debug > 1) {
3118*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_ready_timeout: SOCKET_RESET_TIMER socket %d\n",
3119*0Sstevel@tonic-gate 							sp->socket_num);
3120*0Sstevel@tonic-gate 	}
3121*0Sstevel@tonic-gate #endif
3122*0Sstevel@tonic-gate 
3123*0Sstevel@tonic-gate 	    cvp = &sp->reset_cv;
3124*0Sstevel@tonic-gate 	}
3125*0Sstevel@tonic-gate 
3126*0Sstevel@tonic-gate 	if (sp->thread_state & SOCKET_WAIT_FOR_READY) {
3127*0Sstevel@tonic-gate 	    sp->events |= CS_EVENT_READY_TIMEOUT;
3128*0Sstevel@tonic-gate 	    cvp = &sp->thread_cv;
3129*0Sstevel@tonic-gate 
3130*0Sstevel@tonic-gate #ifdef	CS_DEBUG
3131*0Sstevel@tonic-gate 	    if (cs_debug > 1) {
3132*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_ready_timeout: SOCKET_WAIT_FOR_READY "
3133*0Sstevel@tonic-gate 						"socket %d\n", sp->socket_num);
3134*0Sstevel@tonic-gate 	    }
3135*0Sstevel@tonic-gate #endif
3136*0Sstevel@tonic-gate 
3137*0Sstevel@tonic-gate 	}
3138*0Sstevel@tonic-gate 
3139*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
3140*0Sstevel@tonic-gate 
3141*0Sstevel@tonic-gate 	if (cvp)
3142*0Sstevel@tonic-gate 	    cv_broadcast(cvp);
3143*0Sstevel@tonic-gate }
3144*0Sstevel@tonic-gate 
3145*0Sstevel@tonic-gate /*
3146*0Sstevel@tonic-gate  * cs_event_softintr_timeout - wrapper function to call cs_socket_event_softintr
3147*0Sstevel@tonic-gate  */
3148*0Sstevel@tonic-gate /* ARGSUSED */
3149*0Sstevel@tonic-gate void
3150*0Sstevel@tonic-gate cs_event_softintr_timeout(void *arg)
3151*0Sstevel@tonic-gate {
3152*0Sstevel@tonic-gate 
3153*0Sstevel@tonic-gate 	/*
3154*0Sstevel@tonic-gate 	 * If we're trying to unload this module, then don't do
3155*0Sstevel@tonic-gate 	 *	anything but exit.
3156*0Sstevel@tonic-gate 	 * We acquire the cs_globals.global_lock mutex here so that
3157*0Sstevel@tonic-gate 	 *	we can correctly synchronize with cs_deinit when it
3158*0Sstevel@tonic-gate 	 *	is telling us to shut down. XXX - is this bogus??
3159*0Sstevel@tonic-gate 	 */
3160*0Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
3161*0Sstevel@tonic-gate 	if (!(cs_globals.init_state & GLOBAL_INIT_STATE_UNLOADING)) {
3162*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.global_lock);
3163*0Sstevel@tonic-gate 	    (void) cs_socket_event_softintr(NULL);
3164*0Sstevel@tonic-gate 	    cs_globals.sotfint_tmo = timeout(cs_event_softintr_timeout,
3165*0Sstevel@tonic-gate 		NULL, SOFTINT_TIMEOUT_TIME);
3166*0Sstevel@tonic-gate 	} else {
3167*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.global_lock);
3168*0Sstevel@tonic-gate 	}
3169*0Sstevel@tonic-gate }
3170*0Sstevel@tonic-gate 
3171*0Sstevel@tonic-gate /*
3172*0Sstevel@tonic-gate  * cs_socket_event_softintr - This function just does a cv_broadcast on behalf
3173*0Sstevel@tonic-gate  *				of the high-priority interrupt handler.
3174*0Sstevel@tonic-gate  *
3175*0Sstevel@tonic-gate  *	Note: There is no calling argument.
3176*0Sstevel@tonic-gate  */
3177*0Sstevel@tonic-gate /*ARGSUSED*/
3178*0Sstevel@tonic-gate uint32_t
3179*0Sstevel@tonic-gate cs_socket_event_softintr(caddr_t notused)
3180*0Sstevel@tonic-gate {
3181*0Sstevel@tonic-gate 	cs_socket_t *sp;
3182*0Sstevel@tonic-gate 	uint32_t sn;
3183*0Sstevel@tonic-gate 	int ret = DDI_INTR_UNCLAIMED;
3184*0Sstevel@tonic-gate 
3185*0Sstevel@tonic-gate 	/*
3186*0Sstevel@tonic-gate 	 * If the module is on it's way out, then don't bother
3187*0Sstevel@tonic-gate 	 *	to do anything else except return.
3188*0Sstevel@tonic-gate 	 */
3189*0Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
3190*0Sstevel@tonic-gate 	if ((cs_globals.init_state & GLOBAL_INIT_STATE_UNLOADING) ||
3191*0Sstevel@tonic-gate 				(cs_globals.init_state & GLOBAL_IN_SOFTINTR)) {
3192*0Sstevel@tonic-gate 		mutex_exit(&cs_globals.global_lock);
3193*0Sstevel@tonic-gate 
3194*0Sstevel@tonic-gate 		/*
3195*0Sstevel@tonic-gate 		 * Note that we return DDI_INTR_UNCLAIMED here
3196*0Sstevel@tonic-gate 		 *	since we don't want to be constantly
3197*0Sstevel@tonic-gate 		 *	called back.
3198*0Sstevel@tonic-gate 		 */
3199*0Sstevel@tonic-gate 		return (ret);
3200*0Sstevel@tonic-gate 	} else {
3201*0Sstevel@tonic-gate 	    cs_globals.init_state |= GLOBAL_IN_SOFTINTR;
3202*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.global_lock);
3203*0Sstevel@tonic-gate 	}
3204*0Sstevel@tonic-gate 
3205*0Sstevel@tonic-gate 	/*
3206*0Sstevel@tonic-gate 	 * Go through each socket and dispatch the appropriate events.
3207*0Sstevel@tonic-gate 	 *	We have to funnel everything through this one routine because
3208*0Sstevel@tonic-gate 	 *	we can't do a cv_broadcast from a high level interrupt handler
3209*0Sstevel@tonic-gate 	 *	and we also can't have more than one soft interrupt handler
3210*0Sstevel@tonic-gate 	 *	on a single dip and using the same handler address.
3211*0Sstevel@tonic-gate 	 */
3212*0Sstevel@tonic-gate 	for (sn = 0; sn < cs_globals.max_socket_num; sn++) {
3213*0Sstevel@tonic-gate 	    if ((sp = cs_get_sp(sn)) != NULL) {
3214*0Sstevel@tonic-gate 		if (sp->init_state & SOCKET_INIT_STATE_READY) {
3215*0Sstevel@tonic-gate 			/*
3216*0Sstevel@tonic-gate 			 * If we're being asked to unload CS, then don't bother
3217*0Sstevel@tonic-gate 			 *	waking up the socket event thread handler.
3218*0Sstevel@tonic-gate 			 */
3219*0Sstevel@tonic-gate 		    if (!(sp->flags & SOCKET_UNLOAD_MODULE) &&
3220*0Sstevel@tonic-gate 					(sp->flags & SOCKET_NEEDS_THREAD)) {
3221*0Sstevel@tonic-gate 			ret = DDI_INTR_CLAIMED;
3222*0Sstevel@tonic-gate 			mutex_enter(&sp->client_lock);
3223*0Sstevel@tonic-gate 			cv_broadcast(&sp->thread_cv);
3224*0Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
3225*0Sstevel@tonic-gate 		    } /* if (SOCKET_NEEDS_THREAD) */
3226*0Sstevel@tonic-gate 		} /* if (SOCKET_INIT_STATE_READY) */
3227*0Sstevel@tonic-gate 	    } /* cs_get_sp */
3228*0Sstevel@tonic-gate 	} /* for (sn) */
3229*0Sstevel@tonic-gate 
3230*0Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
3231*0Sstevel@tonic-gate 	cs_globals.init_state &= ~GLOBAL_IN_SOFTINTR;
3232*0Sstevel@tonic-gate 	mutex_exit(&cs_globals.global_lock);
3233*0Sstevel@tonic-gate 
3234*0Sstevel@tonic-gate 	return (ret);
3235*0Sstevel@tonic-gate }
3236*0Sstevel@tonic-gate 
3237*0Sstevel@tonic-gate /*
3238*0Sstevel@tonic-gate  * cs_event_thread - This is the per-socket event thread.
3239*0Sstevel@tonic-gate  */
3240*0Sstevel@tonic-gate static void
3241*0Sstevel@tonic-gate cs_event_thread(uint32_t sn)
3242*0Sstevel@tonic-gate {
3243*0Sstevel@tonic-gate 	cs_socket_t	*sp;
3244*0Sstevel@tonic-gate 	client_t	*client;
3245*0Sstevel@tonic-gate 	client_types_t	*ct;
3246*0Sstevel@tonic-gate 
3247*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(sn)) == NULL)
3248*0Sstevel@tonic-gate 	    return;
3249*0Sstevel@tonic-gate 
3250*0Sstevel@tonic-gate #ifdef	CS_DEBUG
3251*0Sstevel@tonic-gate 	if (cs_debug > 1) {
3252*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_event_thread: socket %d thread started\n",
3253*0Sstevel@tonic-gate 								sp->socket_num);
3254*0Sstevel@tonic-gate 	}
3255*0Sstevel@tonic-gate #endif
3256*0Sstevel@tonic-gate 
3257*0Sstevel@tonic-gate 	CALLB_CPR_INIT(&sp->cprinfo_cs, &sp->client_lock,
3258*0Sstevel@tonic-gate 					callb_generic_cpr, "cs_event_thread");
3259*0Sstevel@tonic-gate 
3260*0Sstevel@tonic-gate 	mutex_enter(&sp->client_lock);
3261*0Sstevel@tonic-gate 
3262*0Sstevel@tonic-gate 	for (;;) {
3263*0Sstevel@tonic-gate 
3264*0Sstevel@tonic-gate 	    CALLB_CPR_SAFE_BEGIN(&sp->cprinfo_cs);
3265*0Sstevel@tonic-gate 	    cv_wait(&sp->thread_cv, &sp->client_lock);
3266*0Sstevel@tonic-gate 	    CALLB_CPR_SAFE_END(&sp->cprinfo_cs, &sp->client_lock);
3267*0Sstevel@tonic-gate 
3268*0Sstevel@tonic-gate 	    mutex_enter(&sp->lock);
3269*0Sstevel@tonic-gate 	    sp->flags &= ~SOCKET_NEEDS_THREAD;
3270*0Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
3271*0Sstevel@tonic-gate 
3272*0Sstevel@tonic-gate 	/*
3273*0Sstevel@tonic-gate 	 * Check to see if there are any special thread operations that
3274*0Sstevel@tonic-gate 	 *	we are being asked to perform.
3275*0Sstevel@tonic-gate 	 */
3276*0Sstevel@tonic-gate 	    if (sp->thread_state & SOCKET_THREAD_EXIT) {
3277*0Sstevel@tonic-gate #ifdef	CS_DEBUG
3278*0Sstevel@tonic-gate 		if (cs_debug > 1) {
3279*0Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_event_thread: socket %d "
3280*0Sstevel@tonic-gate 							"SOCKET_THREAD_EXIT\n",
3281*0Sstevel@tonic-gate 							sp->socket_num);
3282*0Sstevel@tonic-gate 		}
3283*0Sstevel@tonic-gate #endif
3284*0Sstevel@tonic-gate 		CALLB_CPR_EXIT(&sp->cprinfo_cs);
3285*0Sstevel@tonic-gate 		cv_broadcast(&sp->caller_cv);	/* wakes up cs_deinit */
3286*0Sstevel@tonic-gate 		mutex_exit(&sp->client_lock);
3287*0Sstevel@tonic-gate 		return;
3288*0Sstevel@tonic-gate 	    } /* if (SOCKET_THREAD_EXIT) */
3289*0Sstevel@tonic-gate 
3290*0Sstevel@tonic-gate #ifdef	CS_DEBUG
3291*0Sstevel@tonic-gate 	    if (cs_debug > 1) {
3292*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_event_thread: socket %d sp->events 0x%x\n",
3293*0Sstevel@tonic-gate 							sp->socket_num,
3294*0Sstevel@tonic-gate 							(int)sp->events);
3295*0Sstevel@tonic-gate 	    }
3296*0Sstevel@tonic-gate #endif
3297*0Sstevel@tonic-gate 
3298*0Sstevel@tonic-gate 	/*
3299*0Sstevel@tonic-gate 	 * Handle CS_EVENT_CARD_INSERTION events
3300*0Sstevel@tonic-gate 	 */
3301*0Sstevel@tonic-gate 	    if (sp->events & CS_EVENT_CARD_INSERTION) {
3302*0Sstevel@tonic-gate 		mutex_enter(&sp->lock);
3303*0Sstevel@tonic-gate 		sp->events &= ~CS_EVENT_CARD_INSERTION;
3304*0Sstevel@tonic-gate 		mutex_exit(&sp->lock);
3305*0Sstevel@tonic-gate 
3306*0Sstevel@tonic-gate 		/*
3307*0Sstevel@tonic-gate 		 * If we have a pending CS_EVENT_CARD_REMOVAL event it
3308*0Sstevel@tonic-gate 		 *	means that we likely got CD line bounce on the
3309*0Sstevel@tonic-gate 		 *	insertion, so terminate this processing.
3310*0Sstevel@tonic-gate 		 */
3311*0Sstevel@tonic-gate 		if ((sp->events & CS_EVENT_CARD_REMOVAL) == 0) {
3312*0Sstevel@tonic-gate 		    (void) cs_card_insertion(sp, CS_EVENT_CARD_INSERTION);
3313*0Sstevel@tonic-gate 		}
3314*0Sstevel@tonic-gate #ifdef	CS_DEBUG
3315*0Sstevel@tonic-gate 		else if (cs_debug > 0) {
3316*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_event_thread: socket %d "
3317*0Sstevel@tonic-gate 					"CS_EVENT_CARD_REMOVAL event "
3318*0Sstevel@tonic-gate 					"terminating "
3319*0Sstevel@tonic-gate 					"CS_EVENT_CARD_INSERTION "
3320*0Sstevel@tonic-gate 					"processing\n", sp->socket_num);
3321*0Sstevel@tonic-gate 		    }
3322*0Sstevel@tonic-gate #endif
3323*0Sstevel@tonic-gate 	} /* if (CS_EVENT_CARD_INSERTION) */
3324*0Sstevel@tonic-gate 
3325*0Sstevel@tonic-gate 	/*
3326*0Sstevel@tonic-gate 	 * Handle CS_EVENT_CARD_READY and CS_EVENT_READY_TIMEOUT events
3327*0Sstevel@tonic-gate 	 */
3328*0Sstevel@tonic-gate 	    if (sp->events & (CS_EVENT_CARD_READY | CS_EVENT_READY_TIMEOUT)) {
3329*0Sstevel@tonic-gate 		mutex_enter(&sp->lock);
3330*0Sstevel@tonic-gate 		sp->events &= ~(CS_EVENT_CARD_READY | CS_EVENT_READY_TIMEOUT);
3331*0Sstevel@tonic-gate 		mutex_exit(&sp->lock);
3332*0Sstevel@tonic-gate 		if (sp->thread_state & SOCKET_WAIT_FOR_READY) {
3333*0Sstevel@tonic-gate 		    mutex_enter(&sp->lock);
3334*0Sstevel@tonic-gate 		    sp->thread_state &= ~SOCKET_WAIT_FOR_READY;
3335*0Sstevel@tonic-gate 		    mutex_exit(&sp->lock);
3336*0Sstevel@tonic-gate 		    (void) cs_card_insertion(sp, CS_EVENT_CARD_READY);
3337*0Sstevel@tonic-gate 		} /* if (SOCKET_WAIT_FOR_READY) */
3338*0Sstevel@tonic-gate 	    } /* if (CS_EVENT_CARD_READY) */
3339*0Sstevel@tonic-gate 
3340*0Sstevel@tonic-gate 	/*
3341*0Sstevel@tonic-gate 	 * Handle CS_EVENT_SS_UPDATED events
3342*0Sstevel@tonic-gate 	 */
3343*0Sstevel@tonic-gate 	    if (sp->events & CS_EVENT_SS_UPDATED) {
3344*0Sstevel@tonic-gate 		mutex_enter(&sp->lock);
3345*0Sstevel@tonic-gate 		sp->events &= ~CS_EVENT_SS_UPDATED;
3346*0Sstevel@tonic-gate 		mutex_exit(&sp->lock);
3347*0Sstevel@tonic-gate 		(void) cs_card_insertion(sp, CS_EVENT_SS_UPDATED);
3348*0Sstevel@tonic-gate 	    } /* if (CS_EVENT_SS_UPDATED) */
3349*0Sstevel@tonic-gate 
3350*0Sstevel@tonic-gate 	/*
3351*0Sstevel@tonic-gate 	 * Handle CS_EVENT_STATUS_CHANGE events
3352*0Sstevel@tonic-gate 	 */
3353*0Sstevel@tonic-gate 	    if (sp->events & CS_EVENT_STATUS_CHANGE) {
3354*0Sstevel@tonic-gate 		event_t revent;
3355*0Sstevel@tonic-gate 
3356*0Sstevel@tonic-gate 		mutex_enter(&sp->cis_lock);
3357*0Sstevel@tonic-gate 		mutex_enter(&sp->lock);
3358*0Sstevel@tonic-gate 		sp->events &= ~CS_EVENT_STATUS_CHANGE;
3359*0Sstevel@tonic-gate 
3360*0Sstevel@tonic-gate 		/*
3361*0Sstevel@tonic-gate 		 * Go through each client and add any events that we saw to
3362*0Sstevel@tonic-gate 		 *	the client's event list if the client has that event
3363*0Sstevel@tonic-gate 		 *	enabled in their event mask.
3364*0Sstevel@tonic-gate 		 * Remove any events that may be pending for this client if
3365*0Sstevel@tonic-gate 		 *	the client's event mask says that the client doesn't
3366*0Sstevel@tonic-gate 		 *	want to see those events anymore. This handles the
3367*0Sstevel@tonic-gate 		 *	case where the client had an event enabled in it's
3368*0Sstevel@tonic-gate 		 *	event mask when the event came in but between that
3369*0Sstevel@tonic-gate 		 *	time and the time we're called here the client
3370*0Sstevel@tonic-gate 		 *	disabled that event.
3371*0Sstevel@tonic-gate 		 */
3372*0Sstevel@tonic-gate 		client = sp->client_list;
3373*0Sstevel@tonic-gate 
3374*0Sstevel@tonic-gate 		while (client) {
3375*0Sstevel@tonic-gate 			/*
3376*0Sstevel@tonic-gate 			 * Read the PRR (if it exists) and check for any events.
3377*0Sstevel@tonic-gate 			 * The PRR will only be read if the socket is in IO
3378*0Sstevel@tonic-gate 			 * mode, if there is a card in the socket, and if there
3379*0Sstevel@tonic-gate 			 * is a PRR.
3380*0Sstevel@tonic-gate 			 * We don't have to clear revent before we call the
3381*0Sstevel@tonic-gate 			 * cs_read_event_status function since it will
3382*0Sstevel@tonic-gate 			 * clear it before adding any current events.
3383*0Sstevel@tonic-gate 			 */
3384*0Sstevel@tonic-gate 		    if (client->flags & CLIENT_CARD_INSERTED) {
3385*0Sstevel@tonic-gate 			(void) cs_read_event_status(sp, client,
3386*0Sstevel@tonic-gate 							&revent, NULL, 0);
3387*0Sstevel@tonic-gate 
3388*0Sstevel@tonic-gate 			client->events = ((client->events | revent) &
3389*0Sstevel@tonic-gate 						(client->event_mask |
3390*0Sstevel@tonic-gate 							client->global_mask));
3391*0Sstevel@tonic-gate 		    } /* CLIENT_CARD_INSERTED */
3392*0Sstevel@tonic-gate 		    client = client->next;
3393*0Sstevel@tonic-gate 		} /* while (client) */
3394*0Sstevel@tonic-gate 
3395*0Sstevel@tonic-gate 		mutex_exit(&sp->lock);
3396*0Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
3397*0Sstevel@tonic-gate 	    } /* if (CS_EVENT_STATUS_CHANGE) */
3398*0Sstevel@tonic-gate 
3399*0Sstevel@tonic-gate 	/*
3400*0Sstevel@tonic-gate 	 * We want to maintain the required event dispatching order as
3401*0Sstevel@tonic-gate 	 *	specified in the PCMCIA spec, so we cycle through all
3402*0Sstevel@tonic-gate 	 *	clients on this socket to make sure that they are
3403*0Sstevel@tonic-gate 	 *	notified in the correct order.
3404*0Sstevel@tonic-gate 	 */
3405*0Sstevel@tonic-gate 	    ct = &client_types[0];
3406*0Sstevel@tonic-gate 	    while (ct) {
3407*0Sstevel@tonic-gate 		/*
3408*0Sstevel@tonic-gate 		 * Point to the head of the client list for this socket, and go
3409*0Sstevel@tonic-gate 		 *	through each client to set up the client events as well
3410*0Sstevel@tonic-gate 		 *	as call the client's event handler directly if we have
3411*0Sstevel@tonic-gate 		 *	a high priority event that we need to tell the client
3412*0Sstevel@tonic-gate 		 *	about.
3413*0Sstevel@tonic-gate 		 */
3414*0Sstevel@tonic-gate 		client = sp->client_list;
3415*0Sstevel@tonic-gate 
3416*0Sstevel@tonic-gate 		if (ct->order & CLIENT_EVENTS_LIFO) {
3417*0Sstevel@tonic-gate 		    client_t *clp = NULL;
3418*0Sstevel@tonic-gate 
3419*0Sstevel@tonic-gate 		    while (client) {
3420*0Sstevel@tonic-gate 			clp = client;
3421*0Sstevel@tonic-gate 			client = client->next;
3422*0Sstevel@tonic-gate 		    }
3423*0Sstevel@tonic-gate 		    client = clp;
3424*0Sstevel@tonic-gate 		}
3425*0Sstevel@tonic-gate 
3426*0Sstevel@tonic-gate 		while (client) {
3427*0Sstevel@tonic-gate 		    if (client->flags & ct->type) {
3428*0Sstevel@tonic-gate 			    uint32_t bit = 0;
3429*0Sstevel@tonic-gate 			    event_t event;
3430*0Sstevel@tonic-gate 
3431*0Sstevel@tonic-gate 			while (client->events) {
3432*0Sstevel@tonic-gate 
3433*0Sstevel@tonic-gate 			    switch (event = CS_BIT_GET(client->events, bit)) {
3434*0Sstevel@tonic-gate 				/*
3435*0Sstevel@tonic-gate 				 * Clients always receive registration complete
3436*0Sstevel@tonic-gate 				 *	events, even if there is no card of
3437*0Sstevel@tonic-gate 				 *	their type currently in the socket.
3438*0Sstevel@tonic-gate 				 */
3439*0Sstevel@tonic-gate 				case CS_EVENT_REGISTRATION_COMPLETE:
3440*0Sstevel@tonic-gate 				    CLIENT_EVENT_CALLBACK(client, event,
3441*0Sstevel@tonic-gate 							CS_EVENT_PRI_LOW);
3442*0Sstevel@tonic-gate 				    break;
3443*0Sstevel@tonic-gate 				/*
3444*0Sstevel@tonic-gate 				 * The client only gets a card insertion event
3445*0Sstevel@tonic-gate 				 *	if there is currently a card in the
3446*0Sstevel@tonic-gate 				 *	socket that the client can control.
3447*0Sstevel@tonic-gate 				 *	The nexus determines this. We also
3448*0Sstevel@tonic-gate 				 *	prevent the client from receiving
3449*0Sstevel@tonic-gate 				 *	multiple CS_EVENT_CARD_INSERTION
3450*0Sstevel@tonic-gate 				 *	events without receiving intervening
3451*0Sstevel@tonic-gate 				 *	CS_EVENT_CARD_REMOVAL events.
3452*0Sstevel@tonic-gate 				 */
3453*0Sstevel@tonic-gate 				case CS_EVENT_CARD_INSERTION:
3454*0Sstevel@tonic-gate 				    if (cs_card_for_client(client)) {
3455*0Sstevel@tonic-gate 					int send_insertion;
3456*0Sstevel@tonic-gate 
3457*0Sstevel@tonic-gate 					mutex_enter(&sp->lock);
3458*0Sstevel@tonic-gate 					send_insertion = client->flags;
3459*0Sstevel@tonic-gate 					client->flags |=
3460*0Sstevel@tonic-gate 						(CLIENT_CARD_INSERTED |
3461*0Sstevel@tonic-gate 						CLIENT_SENT_INSERTION);
3462*0Sstevel@tonic-gate 					mutex_exit(&sp->lock);
3463*0Sstevel@tonic-gate 					if (!(send_insertion &
3464*0Sstevel@tonic-gate 						    CLIENT_SENT_INSERTION)) {
3465*0Sstevel@tonic-gate 					    CLIENT_EVENT_CALLBACK(client,
3466*0Sstevel@tonic-gate 						event, CS_EVENT_PRI_LOW);
3467*0Sstevel@tonic-gate 					} /* if (!CLIENT_SENT_INSERTION) */
3468*0Sstevel@tonic-gate 				    }
3469*0Sstevel@tonic-gate 				    break;
3470*0Sstevel@tonic-gate 				/*
3471*0Sstevel@tonic-gate 				 * The CS_EVENT_CARD_REMOVAL_LOWP is a low
3472*0Sstevel@tonic-gate 				 *	priority CS_EVENT_CARD_REMOVAL event.
3473*0Sstevel@tonic-gate 				 */
3474*0Sstevel@tonic-gate 				case CS_EVENT_CARD_REMOVAL_LOWP:
3475*0Sstevel@tonic-gate 				    mutex_enter(&sp->lock);
3476*0Sstevel@tonic-gate 				    client->flags &= ~CLIENT_SENT_INSERTION;
3477*0Sstevel@tonic-gate 				    mutex_exit(&sp->lock);
3478*0Sstevel@tonic-gate 				    CLIENT_EVENT_CALLBACK(client,
3479*0Sstevel@tonic-gate 							CS_EVENT_CARD_REMOVAL,
3480*0Sstevel@tonic-gate 							CS_EVENT_PRI_LOW);
3481*0Sstevel@tonic-gate 				    break;
3482*0Sstevel@tonic-gate 				/*
3483*0Sstevel@tonic-gate 				 * The hardware card removal events are handed
3484*0Sstevel@tonic-gate 				 *	to the client in cs_event at high
3485*0Sstevel@tonic-gate 				 *	priority interrupt time; this card
3486*0Sstevel@tonic-gate 				 *	removal event is a software-generated
3487*0Sstevel@tonic-gate 				 *	event.
3488*0Sstevel@tonic-gate 				 */
3489*0Sstevel@tonic-gate 				case CS_EVENT_CARD_REMOVAL:
3490*0Sstevel@tonic-gate 				    if (client->flags & CLIENT_CARD_INSERTED) {
3491*0Sstevel@tonic-gate 					mutex_enter(&sp->lock);
3492*0Sstevel@tonic-gate 					client->flags &=
3493*0Sstevel@tonic-gate 						~(CLIENT_CARD_INSERTED |
3494*0Sstevel@tonic-gate 						CLIENT_SENT_INSERTION);
3495*0Sstevel@tonic-gate 					mutex_exit(&sp->lock);
3496*0Sstevel@tonic-gate 					CLIENT_EVENT_CALLBACK(client, event,
3497*0Sstevel@tonic-gate 							CS_EVENT_PRI_LOW);
3498*0Sstevel@tonic-gate 				    }
3499*0Sstevel@tonic-gate 				    break;
3500*0Sstevel@tonic-gate 				/*
3501*0Sstevel@tonic-gate 				 * Write protect events require the info field
3502*0Sstevel@tonic-gate 				 *	of the client's event callback args to
3503*0Sstevel@tonic-gate 				 *	be zero if the card is not write
3504*0Sstevel@tonic-gate 				 *	protected and one if it is.
3505*0Sstevel@tonic-gate 				 */
3506*0Sstevel@tonic-gate 				case CS_EVENT_WRITE_PROTECT:
3507*0Sstevel@tonic-gate 				    if (client->flags & CLIENT_CARD_INSERTED) {
3508*0Sstevel@tonic-gate 					get_ss_status_t gs;
3509*0Sstevel@tonic-gate 
3510*0Sstevel@tonic-gate 					mutex_enter(&sp->cis_lock);
3511*0Sstevel@tonic-gate 					mutex_enter(&sp->lock);
3512*0Sstevel@tonic-gate 					(void) cs_read_event_status(sp, client,
3513*0Sstevel@tonic-gate 									NULL,
3514*0Sstevel@tonic-gate 									&gs, 0);
3515*0Sstevel@tonic-gate 					if (gs.CardState & SBM_WP) {
3516*0Sstevel@tonic-gate 					    client->event_callback_args.info =
3517*0Sstevel@tonic-gate 						(void *)
3518*0Sstevel@tonic-gate 						CS_EVENT_WRITE_PROTECT_WPON;
3519*0Sstevel@tonic-gate 					} else {
3520*0Sstevel@tonic-gate 					    client->event_callback_args.info =
3521*0Sstevel@tonic-gate 						(void *)
3522*0Sstevel@tonic-gate 						CS_EVENT_WRITE_PROTECT_WPOFF;
3523*0Sstevel@tonic-gate 					}
3524*0Sstevel@tonic-gate 					mutex_exit(&sp->lock);
3525*0Sstevel@tonic-gate 					mutex_exit(&sp->cis_lock);
3526*0Sstevel@tonic-gate 					CLIENT_EVENT_CALLBACK(client, event,
3527*0Sstevel@tonic-gate 							CS_EVENT_PRI_LOW);
3528*0Sstevel@tonic-gate 				    } /* CLIENT_CARD_INSERTED */
3529*0Sstevel@tonic-gate 				    break;
3530*0Sstevel@tonic-gate 				case CS_EVENT_CLIENT_INFO:
3531*0Sstevel@tonic-gate 				    CLIENT_EVENT_CALLBACK(client, event,
3532*0Sstevel@tonic-gate 							CS_EVENT_PRI_LOW);
3533*0Sstevel@tonic-gate 				    break;
3534*0Sstevel@tonic-gate 				case 0:
3535*0Sstevel@tonic-gate 				    break;
3536*0Sstevel@tonic-gate 				default:
3537*0Sstevel@tonic-gate 				    if (client->flags & CLIENT_CARD_INSERTED) {
3538*0Sstevel@tonic-gate 					CLIENT_EVENT_CALLBACK(client, event,
3539*0Sstevel@tonic-gate 							CS_EVENT_PRI_LOW);
3540*0Sstevel@tonic-gate 				    }
3541*0Sstevel@tonic-gate 				    break;
3542*0Sstevel@tonic-gate 			    } /* switch */
3543*0Sstevel@tonic-gate 			    mutex_enter(&sp->lock);
3544*0Sstevel@tonic-gate 			    CS_BIT_CLEAR(client->events, bit);
3545*0Sstevel@tonic-gate 			    mutex_exit(&sp->lock);
3546*0Sstevel@tonic-gate 			    bit++;
3547*0Sstevel@tonic-gate 			} /* while (client->events) */
3548*0Sstevel@tonic-gate 		    } /* if (ct->type) */
3549*0Sstevel@tonic-gate 		    if (ct->order & CLIENT_EVENTS_LIFO) {
3550*0Sstevel@tonic-gate 			client = client->prev;
3551*0Sstevel@tonic-gate 		    } else {
3552*0Sstevel@tonic-gate 			client = client->next;
3553*0Sstevel@tonic-gate 		    }
3554*0Sstevel@tonic-gate 		} /* while (client) */
3555*0Sstevel@tonic-gate 
3556*0Sstevel@tonic-gate 		ct = ct->next;
3557*0Sstevel@tonic-gate 	    } /* while (ct) */
3558*0Sstevel@tonic-gate 
3559*0Sstevel@tonic-gate 	/*
3560*0Sstevel@tonic-gate 	 * Handle CS_EVENT_CARD_REMOVAL events
3561*0Sstevel@tonic-gate 	 */
3562*0Sstevel@tonic-gate 	    if (sp->events & CS_EVENT_CARD_REMOVAL) {
3563*0Sstevel@tonic-gate 		mutex_enter(&sp->lock);
3564*0Sstevel@tonic-gate 		sp->events &= ~CS_EVENT_CARD_REMOVAL;
3565*0Sstevel@tonic-gate 		mutex_exit(&sp->lock);
3566*0Sstevel@tonic-gate 		(void) cs_card_removal(sp);
3567*0Sstevel@tonic-gate 	    } /* if (CS_EVENT_CARD_REMOVAL) */
3568*0Sstevel@tonic-gate 
3569*0Sstevel@tonic-gate 		/*
3570*0Sstevel@tonic-gate 		 * If someone is waiting for us to complete, signal them now.
3571*0Sstevel@tonic-gate 		 */
3572*0Sstevel@tonic-gate 	    if (sp->thread_state & SOCKET_WAIT_SYNC) {
3573*0Sstevel@tonic-gate 		mutex_enter(&sp->lock);
3574*0Sstevel@tonic-gate 		sp->thread_state &= ~SOCKET_WAIT_SYNC;
3575*0Sstevel@tonic-gate 		mutex_exit(&sp->lock);
3576*0Sstevel@tonic-gate 		cv_broadcast(&sp->caller_cv);
3577*0Sstevel@tonic-gate 	    } /* SOCKET_WAIT_SYNC */
3578*0Sstevel@tonic-gate 
3579*0Sstevel@tonic-gate 	} /* for (;;) */
3580*0Sstevel@tonic-gate }
3581*0Sstevel@tonic-gate 
3582*0Sstevel@tonic-gate /*
3583*0Sstevel@tonic-gate  * cs_card_for_client - checks to see if a card that the client can control
3584*0Sstevel@tonic-gate  *			is currently inserted in the socket.  Socket Services
3585*0Sstevel@tonic-gate  *			has to tell us if this is the case.
3586*0Sstevel@tonic-gate  */
3587*0Sstevel@tonic-gate static int
3588*0Sstevel@tonic-gate cs_card_for_client(client_t *client)
3589*0Sstevel@tonic-gate {
3590*0Sstevel@tonic-gate 
3591*0Sstevel@tonic-gate 	/*
3592*0Sstevel@tonic-gate 	 * If the client has set the CS_EVENT_ALL_CLIENTS it means that they
3593*0Sstevel@tonic-gate 	 *	want to get all events for all clients, irrespective of
3594*0Sstevel@tonic-gate 	 *	whether or not there is a card in the socket.  Such clients
3595*0Sstevel@tonic-gate 	 *	have to be very careful if they touch the card hardware in
3596*0Sstevel@tonic-gate 	 *	any way to prevent causing problems for other clients on the
3597*0Sstevel@tonic-gate 	 *	same socket.  This flag will typically only be set by the
3598*0Sstevel@tonic-gate 	 *	"super-client" or CSI types of clients that wish to get
3599*0Sstevel@tonic-gate 	 *	information on other clients or cards in the system.
3600*0Sstevel@tonic-gate 	 * Note that the CS_EVENT_ALL_CLIENTS must be set in either the
3601*0Sstevel@tonic-gate 	 *	client's global event mask or client event mask.
3602*0Sstevel@tonic-gate 	 * The client must also have registered as a "super-client" or as a
3603*0Sstevel@tonic-gate 	 *	CSI client for this socket.
3604*0Sstevel@tonic-gate 	 */
3605*0Sstevel@tonic-gate 	if ((client->flags & (CLIENT_SUPER_CLIENT | CLIENT_CSI_CLIENT)) &&
3606*0Sstevel@tonic-gate 			((client->global_mask | client->event_mask) &
3607*0Sstevel@tonic-gate 							CS_EVENT_ALL_CLIENTS))
3608*0Sstevel@tonic-gate 	    return (1);
3609*0Sstevel@tonic-gate 
3610*0Sstevel@tonic-gate 	/*
3611*0Sstevel@tonic-gate 	 * Look for the PCM_DEV_ACTIVE property on this client's dip; if
3612*0Sstevel@tonic-gate 	 *	it's found, it means that this client can control the card
3613*0Sstevel@tonic-gate 	 *	that is currently in the socket.  This is a boolean
3614*0Sstevel@tonic-gate 	 *	property managed by Socket Services.
3615*0Sstevel@tonic-gate 	 */
3616*0Sstevel@tonic-gate 	if (ddi_getprop(DDI_DEV_T_ANY, client->dip,    (DDI_PROP_CANSLEEP |
3617*0Sstevel@tonic-gate 							DDI_PROP_NOTPROM),
3618*0Sstevel@tonic-gate 							PCM_DEV_ACTIVE, NULL)) {
3619*0Sstevel@tonic-gate #ifdef	CS_DEBUG
3620*0Sstevel@tonic-gate 	    if (cs_debug > 1) {
3621*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_card_for_client: client handle 0x%x "
3622*0Sstevel@tonic-gate 					"driver [%s] says %s found\n",
3623*0Sstevel@tonic-gate 						(int)client->client_handle,
3624*0Sstevel@tonic-gate 						client->driver_name,
3625*0Sstevel@tonic-gate 						PCM_DEV_ACTIVE);
3626*0Sstevel@tonic-gate 	    }
3627*0Sstevel@tonic-gate #endif
3628*0Sstevel@tonic-gate 	    return (1);
3629*0Sstevel@tonic-gate 	}
3630*0Sstevel@tonic-gate 
3631*0Sstevel@tonic-gate 	return (0);
3632*0Sstevel@tonic-gate }
3633*0Sstevel@tonic-gate 
3634*0Sstevel@tonic-gate /*
3635*0Sstevel@tonic-gate  * cs_ss_thread - This is the Socket Services work thread. We fire off
3636*0Sstevel@tonic-gate  *			any calls to Socket Services here that we want
3637*0Sstevel@tonic-gate  *			to run on a thread that is seperate from the
3638*0Sstevel@tonic-gate  *			per-socket event thread.
3639*0Sstevel@tonic-gate  */
3640*0Sstevel@tonic-gate static void
3641*0Sstevel@tonic-gate cs_ss_thread(uint32_t sn)
3642*0Sstevel@tonic-gate {
3643*0Sstevel@tonic-gate 	cs_socket_t *sp;
3644*0Sstevel@tonic-gate 
3645*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(sn)) == NULL)
3646*0Sstevel@tonic-gate 	    return;
3647*0Sstevel@tonic-gate 
3648*0Sstevel@tonic-gate 	/*
3649*0Sstevel@tonic-gate 	 * Tell CPR that we've started a new thread.
3650*0Sstevel@tonic-gate 	 */
3651*0Sstevel@tonic-gate 	CALLB_CPR_INIT(&sp->cprinfo_ss, &sp->ss_thread_lock,
3652*0Sstevel@tonic-gate 					callb_generic_cpr, "cs_ss_thread");
3653*0Sstevel@tonic-gate 
3654*0Sstevel@tonic-gate 	mutex_enter(&sp->ss_thread_lock);
3655*0Sstevel@tonic-gate 
3656*0Sstevel@tonic-gate 	for (;;) {
3657*0Sstevel@tonic-gate 
3658*0Sstevel@tonic-gate 	    CALLB_CPR_SAFE_BEGIN(&sp->cprinfo_ss);
3659*0Sstevel@tonic-gate 	    cv_wait(&sp->ss_thread_cv, &sp->ss_thread_lock);
3660*0Sstevel@tonic-gate 	    CALLB_CPR_SAFE_END(&sp->cprinfo_ss, &sp->ss_thread_lock);
3661*0Sstevel@tonic-gate 
3662*0Sstevel@tonic-gate 		/*
3663*0Sstevel@tonic-gate 		 * Check to see if there are any special thread operations
3664*0Sstevel@tonic-gate 		 * that we are being asked to perform.
3665*0Sstevel@tonic-gate 		 */
3666*0Sstevel@tonic-gate 	    if (sp->ss_thread_state & SOCKET_THREAD_EXIT) {
3667*0Sstevel@tonic-gate #ifdef	CS_DEBUG
3668*0Sstevel@tonic-gate 		if (cs_debug > 1) {
3669*0Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_ss_thread: socket %d "
3670*0Sstevel@tonic-gate 					"SOCKET_THREAD_EXIT\n",
3671*0Sstevel@tonic-gate 						sp->socket_num);
3672*0Sstevel@tonic-gate 		}
3673*0Sstevel@tonic-gate #endif
3674*0Sstevel@tonic-gate 		CALLB_CPR_EXIT(&sp->cprinfo_ss);
3675*0Sstevel@tonic-gate 		cv_broadcast(&sp->ss_caller_cv);	/* wake up cs_deinit */
3676*0Sstevel@tonic-gate 		mutex_exit(&sp->ss_thread_lock);
3677*0Sstevel@tonic-gate 		return;
3678*0Sstevel@tonic-gate 	    } /* if (SOCKET_THREAD_EXIT) */
3679*0Sstevel@tonic-gate 
3680*0Sstevel@tonic-gate #ifdef	CS_DEBUG
3681*0Sstevel@tonic-gate 	    if (cs_debug > 1) {
3682*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_ss_thread: socket %d "
3683*0Sstevel@tonic-gate 					"ss_thread_state = 0x%x\n",
3684*0Sstevel@tonic-gate 						(int)sp->socket_num,
3685*0Sstevel@tonic-gate 						(int)sp->ss_thread_state);
3686*0Sstevel@tonic-gate 	    }
3687*0Sstevel@tonic-gate #endif
3688*0Sstevel@tonic-gate 
3689*0Sstevel@tonic-gate 		/*
3690*0Sstevel@tonic-gate 		 * Call SocketServices(CSCISInit) to have SS parse the
3691*0Sstevel@tonic-gate 		 *	CIS and load/attach any client drivers necessary.
3692*0Sstevel@tonic-gate 		 */
3693*0Sstevel@tonic-gate 	    if (sp->ss_thread_state & SOCKET_THREAD_CSCISInit) {
3694*0Sstevel@tonic-gate 
3695*0Sstevel@tonic-gate 		sp->ss_thread_state &= ~SOCKET_THREAD_CSCISInit;
3696*0Sstevel@tonic-gate 
3697*0Sstevel@tonic-gate 		if (!(sp->flags & SOCKET_CARD_INSERTED)) {
3698*0Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_ss_thread %d "
3699*0Sstevel@tonic-gate 					"card NOT inserted\n",
3700*0Sstevel@tonic-gate 					sp->socket_num);
3701*0Sstevel@tonic-gate 		}
3702*0Sstevel@tonic-gate 
3703*0Sstevel@tonic-gate #ifdef	CS_DEBUG
3704*0Sstevel@tonic-gate 		if (cs_debug > 1) {
3705*0Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_ss_thread: socket %d calling "
3706*0Sstevel@tonic-gate 						"CSCISInit\n", sp->socket_num);
3707*0Sstevel@tonic-gate 		}
3708*0Sstevel@tonic-gate #endif
3709*0Sstevel@tonic-gate 
3710*0Sstevel@tonic-gate 		/*
3711*0Sstevel@tonic-gate 		 * Tell SS that we have a complete CIS and that it can now
3712*0Sstevel@tonic-gate 		 *	be parsed.
3713*0Sstevel@tonic-gate 		 * Note that in some cases the client driver may block in
3714*0Sstevel@tonic-gate 		 *	their attach routine, causing this call to block until
3715*0Sstevel@tonic-gate 		 *	the client completes their attach.
3716*0Sstevel@tonic-gate 		 */
3717*0Sstevel@tonic-gate 		SocketServices(CSCISInit, sp->socket_num);
3718*0Sstevel@tonic-gate 
3719*0Sstevel@tonic-gate 		/*
3720*0Sstevel@tonic-gate 		 * Set the CS_EVENT_SS_UPDATED event for this socket so that the
3721*0Sstevel@tonic-gate 		 *	event thread can continue any card insertion processing
3722*0Sstevel@tonic-gate 		 *	that it has to do.
3723*0Sstevel@tonic-gate 		 */
3724*0Sstevel@tonic-gate 		mutex_enter(&sp->lock);
3725*0Sstevel@tonic-gate 		sp->events |= CS_EVENT_SS_UPDATED;
3726*0Sstevel@tonic-gate 		mutex_exit(&sp->lock);
3727*0Sstevel@tonic-gate 
3728*0Sstevel@tonic-gate 		/*
3729*0Sstevel@tonic-gate 		 * Wake up this socket's event thread so that clients can
3730*0Sstevel@tonic-gate 		 *	continue any card insertion or attach processing
3731*0Sstevel@tonic-gate 		 *	that they need to do.
3732*0Sstevel@tonic-gate 		 */
3733*0Sstevel@tonic-gate 		cv_broadcast(&sp->thread_cv);
3734*0Sstevel@tonic-gate 	    } /* if ST_CSCISInit */
3735*0Sstevel@tonic-gate 
3736*0Sstevel@tonic-gate 	} /* for (;;) */
3737*0Sstevel@tonic-gate }
3738*0Sstevel@tonic-gate 
3739*0Sstevel@tonic-gate /*
3740*0Sstevel@tonic-gate  * cs_request_socket_mask - set the client's event mask as well as causes
3741*0Sstevel@tonic-gate  *				any events pending from RegisterClient to
3742*0Sstevel@tonic-gate  *				be scheduled to be sent to the client
3743*0Sstevel@tonic-gate  */
3744*0Sstevel@tonic-gate static int
3745*0Sstevel@tonic-gate cs_request_socket_mask(client_handle_t client_handle,
3746*0Sstevel@tonic-gate 					request_socket_mask_t *se)
3747*0Sstevel@tonic-gate {
3748*0Sstevel@tonic-gate 	cs_socket_t *sp;
3749*0Sstevel@tonic-gate 	client_t *client;
3750*0Sstevel@tonic-gate 	int error;
3751*0Sstevel@tonic-gate 	int client_lock_acquired;
3752*0Sstevel@tonic-gate 
3753*0Sstevel@tonic-gate 	/*
3754*0Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
3755*0Sstevel@tonic-gate 	 *	is, we don't do anything except for return success.
3756*0Sstevel@tonic-gate 	 */
3757*0Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
3758*0Sstevel@tonic-gate 	    return (CS_SUCCESS);
3759*0Sstevel@tonic-gate 
3760*0Sstevel@tonic-gate 	/*
3761*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
3762*0Sstevel@tonic-gate 	 */
3763*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
3764*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
3765*0Sstevel@tonic-gate 
3766*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
3767*0Sstevel@tonic-gate 
3768*0Sstevel@tonic-gate 	/*
3769*0Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
3770*0Sstevel@tonic-gate 	 */
3771*0Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
3772*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
3773*0Sstevel@tonic-gate 	    return (error);
3774*0Sstevel@tonic-gate 	}
3775*0Sstevel@tonic-gate 
3776*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
3777*0Sstevel@tonic-gate 
3778*0Sstevel@tonic-gate 	/*
3779*0Sstevel@tonic-gate 	 * If this client has already done a RequestSocketMask without
3780*0Sstevel@tonic-gate 	 *	a corresponding ReleaseSocketMask, then return an error.
3781*0Sstevel@tonic-gate 	 */
3782*0Sstevel@tonic-gate 	if (client->flags & REQ_SOCKET_MASK_DONE) {
3783*0Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
3784*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
3785*0Sstevel@tonic-gate 	    return (CS_IN_USE);
3786*0Sstevel@tonic-gate 	}
3787*0Sstevel@tonic-gate 
3788*0Sstevel@tonic-gate 	/*
3789*0Sstevel@tonic-gate 	 * Set up the event mask information; we copy this directly from
3790*0Sstevel@tonic-gate 	 *	the client; since we are the only source of events, any
3791*0Sstevel@tonic-gate 	 *	bogus bits that the client puts in here won't matter
3792*0Sstevel@tonic-gate 	 *	because we'll never look at them.
3793*0Sstevel@tonic-gate 	 */
3794*0Sstevel@tonic-gate 	client->event_mask = se->EventMask;
3795*0Sstevel@tonic-gate 
3796*0Sstevel@tonic-gate 	/*
3797*0Sstevel@tonic-gate 	 * If RegisterClient left us some events to process, set these
3798*0Sstevel@tonic-gate 	 *	events up here.
3799*0Sstevel@tonic-gate 	 */
3800*0Sstevel@tonic-gate 	if (client->pending_events) {
3801*0Sstevel@tonic-gate 	    client->events |= client->pending_events;
3802*0Sstevel@tonic-gate 	    client->pending_events = 0;
3803*0Sstevel@tonic-gate #ifdef	CS_DEBUG
3804*0Sstevel@tonic-gate 	    if (cs_debug > 1) {
3805*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_request_socket_mask: client_handle = 0x%x "
3806*0Sstevel@tonic-gate 				"driver_name = [%s] events = 0x%x\n",
3807*0Sstevel@tonic-gate 					(int)client->client_handle,
3808*0Sstevel@tonic-gate 					client->driver_name,
3809*0Sstevel@tonic-gate 					(int)client->events);
3810*0Sstevel@tonic-gate 	    }
3811*0Sstevel@tonic-gate #endif
3812*0Sstevel@tonic-gate 	}
3813*0Sstevel@tonic-gate 
3814*0Sstevel@tonic-gate 	client->flags |= REQ_SOCKET_MASK_DONE;
3815*0Sstevel@tonic-gate 
3816*0Sstevel@tonic-gate 	/*
3817*0Sstevel@tonic-gate 	 * Merge all the clients' event masks and set the socket
3818*0Sstevel@tonic-gate 	 *	to generate the appropriate events.
3819*0Sstevel@tonic-gate 	 */
3820*0Sstevel@tonic-gate 	(void) cs_set_socket_event_mask(sp, cs_merge_event_masks(sp, client));
3821*0Sstevel@tonic-gate 
3822*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
3823*0Sstevel@tonic-gate 
3824*0Sstevel@tonic-gate 	/*
3825*0Sstevel@tonic-gate 	 * Wakeup the event thread if there are any client events to process.
3826*0Sstevel@tonic-gate 	 */
3827*0Sstevel@tonic-gate 	if (client->events) {
3828*0Sstevel@tonic-gate 	    cv_broadcast(&sp->thread_cv);
3829*0Sstevel@tonic-gate #ifdef	CS_DEBUG
3830*0Sstevel@tonic-gate 	    if (cs_debug > 1) {
3831*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_request_socket_mask: did cv_broadcast for "
3832*0Sstevel@tonic-gate 				"client_handle = 0x%x "
3833*0Sstevel@tonic-gate 				"driver_name = [%s] events = 0x%x\n",
3834*0Sstevel@tonic-gate 					(int)client->client_handle,
3835*0Sstevel@tonic-gate 					client->driver_name,
3836*0Sstevel@tonic-gate 					(int)client->events);
3837*0Sstevel@tonic-gate 	    }
3838*0Sstevel@tonic-gate #endif
3839*0Sstevel@tonic-gate 
3840*0Sstevel@tonic-gate 	}
3841*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
3842*0Sstevel@tonic-gate 
3843*0Sstevel@tonic-gate 	return (CS_SUCCESS);
3844*0Sstevel@tonic-gate }
3845*0Sstevel@tonic-gate 
3846*0Sstevel@tonic-gate /*
3847*0Sstevel@tonic-gate  * cs_release_socket_mask - clear the client's event mask
3848*0Sstevel@tonic-gate  *
3849*0Sstevel@tonic-gate  * Once this function returns, the client is guaranteed
3850*0Sstevel@tonic-gate  *	not to get any more event callbacks.
3851*0Sstevel@tonic-gate  */
3852*0Sstevel@tonic-gate /*ARGSUSED*/
3853*0Sstevel@tonic-gate static int
3854*0Sstevel@tonic-gate cs_release_socket_mask(client_handle_t client_handle,
3855*0Sstevel@tonic-gate 					release_socket_mask_t *rsm)
3856*0Sstevel@tonic-gate {
3857*0Sstevel@tonic-gate 	cs_socket_t *sp;
3858*0Sstevel@tonic-gate 	client_t *client;
3859*0Sstevel@tonic-gate 	int error;
3860*0Sstevel@tonic-gate 	int client_lock_acquired;
3861*0Sstevel@tonic-gate 
3862*0Sstevel@tonic-gate 	/*
3863*0Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
3864*0Sstevel@tonic-gate 	 *	is, we don't do anything except for return success.
3865*0Sstevel@tonic-gate 	 */
3866*0Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
3867*0Sstevel@tonic-gate 	    return (CS_SUCCESS);
3868*0Sstevel@tonic-gate 
3869*0Sstevel@tonic-gate 	/*
3870*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
3871*0Sstevel@tonic-gate 	 */
3872*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
3873*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
3874*0Sstevel@tonic-gate 
3875*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
3876*0Sstevel@tonic-gate 
3877*0Sstevel@tonic-gate 	/*
3878*0Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
3879*0Sstevel@tonic-gate 	 */
3880*0Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
3881*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
3882*0Sstevel@tonic-gate 	    return (error);
3883*0Sstevel@tonic-gate 	}
3884*0Sstevel@tonic-gate 
3885*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
3886*0Sstevel@tonic-gate 
3887*0Sstevel@tonic-gate 	/*
3888*0Sstevel@tonic-gate 	 * If this client has already done a RequestSocketMask without
3889*0Sstevel@tonic-gate 	 *	a corresponding ReleaseSocketMask, then return an error.
3890*0Sstevel@tonic-gate 	 */
3891*0Sstevel@tonic-gate 	if (!(client->flags & REQ_SOCKET_MASK_DONE)) {
3892*0Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
3893*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
3894*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
3895*0Sstevel@tonic-gate 	}
3896*0Sstevel@tonic-gate 
3897*0Sstevel@tonic-gate 	/*
3898*0Sstevel@tonic-gate 	 * Clear both the client event mask and the global event mask.
3899*0Sstevel@tonic-gate 	 *	We clear both since the semantics of this function are
3900*0Sstevel@tonic-gate 	 *	that once it returns, the client will not be called at
3901*0Sstevel@tonic-gate 	 *	it's event handler for any events until RequestSocketMask
3902*0Sstevel@tonic-gate 	 *	is called again.
3903*0Sstevel@tonic-gate 	 */
3904*0Sstevel@tonic-gate 	client->event_mask = 0;
3905*0Sstevel@tonic-gate 	client->global_mask = 0;
3906*0Sstevel@tonic-gate 	client->flags &= ~REQ_SOCKET_MASK_DONE;
3907*0Sstevel@tonic-gate 
3908*0Sstevel@tonic-gate 	/*
3909*0Sstevel@tonic-gate 	 * Merge all the clients' event masks and set the socket
3910*0Sstevel@tonic-gate 	 *	to generate the appropriate events.
3911*0Sstevel@tonic-gate 	 */
3912*0Sstevel@tonic-gate 	(void) cs_set_socket_event_mask(sp, cs_merge_event_masks(sp, client));
3913*0Sstevel@tonic-gate 
3914*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
3915*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
3916*0Sstevel@tonic-gate 
3917*0Sstevel@tonic-gate 	return (CS_SUCCESS);
3918*0Sstevel@tonic-gate }
3919*0Sstevel@tonic-gate 
3920*0Sstevel@tonic-gate /*
3921*0Sstevel@tonic-gate  * cs_get_event_mask - return the event mask for this client
3922*0Sstevel@tonic-gate  */
3923*0Sstevel@tonic-gate static int
3924*0Sstevel@tonic-gate cs_get_event_mask(client_handle_t client_handle, sockevent_t *se)
3925*0Sstevel@tonic-gate {
3926*0Sstevel@tonic-gate 	cs_socket_t *sp;
3927*0Sstevel@tonic-gate 	client_t *client;
3928*0Sstevel@tonic-gate 	int error;
3929*0Sstevel@tonic-gate 	int client_lock_acquired;
3930*0Sstevel@tonic-gate 
3931*0Sstevel@tonic-gate 	/*
3932*0Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
3933*0Sstevel@tonic-gate 	 *	is, we don't do anything except for return success.
3934*0Sstevel@tonic-gate 	 */
3935*0Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
3936*0Sstevel@tonic-gate 	    return (CS_SUCCESS);
3937*0Sstevel@tonic-gate 
3938*0Sstevel@tonic-gate 	/*
3939*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
3940*0Sstevel@tonic-gate 	 */
3941*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
3942*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
3943*0Sstevel@tonic-gate 
3944*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
3945*0Sstevel@tonic-gate 
3946*0Sstevel@tonic-gate 	/*
3947*0Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
3948*0Sstevel@tonic-gate 	 */
3949*0Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
3950*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
3951*0Sstevel@tonic-gate 	    return (error);
3952*0Sstevel@tonic-gate 	}
3953*0Sstevel@tonic-gate 
3954*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
3955*0Sstevel@tonic-gate 
3956*0Sstevel@tonic-gate #ifdef	XXX
3957*0Sstevel@tonic-gate 	/*
3958*0Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
3959*0Sstevel@tonic-gate 	 *	for this client, then return an error.
3960*0Sstevel@tonic-gate 	 * XXX - how can a client get their event masks if their card
3961*0Sstevel@tonic-gate 	 *	goes away?
3962*0Sstevel@tonic-gate 	 */
3963*0Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
3964*0Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
3965*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
3966*0Sstevel@tonic-gate 	    return (CS_NO_CARD);
3967*0Sstevel@tonic-gate 	}
3968*0Sstevel@tonic-gate #endif
3969*0Sstevel@tonic-gate 
3970*0Sstevel@tonic-gate 	/*
3971*0Sstevel@tonic-gate 	 * We are only allowed to get the client event mask if a
3972*0Sstevel@tonic-gate 	 *	RequestSocketMask has been called previously.  We
3973*0Sstevel@tonic-gate 	 *	are allowed to get the global event mask at any
3974*0Sstevel@tonic-gate 	 *	time.
3975*0Sstevel@tonic-gate 	 * The global event mask is initially set by the client
3976*0Sstevel@tonic-gate 	 *	in the call to RegisterClient.  The client event
3977*0Sstevel@tonic-gate 	 *	mask is set by the client in calls to SetEventMask
3978*0Sstevel@tonic-gate 	 *	and RequestSocketMask and gotten in calls to
3979*0Sstevel@tonic-gate 	 *	GetEventMask.
3980*0Sstevel@tonic-gate 	 */
3981*0Sstevel@tonic-gate 	if (se->Attributes & CONF_EVENT_MASK_CLIENT) {
3982*0Sstevel@tonic-gate 	    if (!(client->flags & REQ_SOCKET_MASK_DONE)) {
3983*0Sstevel@tonic-gate 		mutex_exit(&sp->lock);
3984*0Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
3985*0Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
3986*0Sstevel@tonic-gate 	    }
3987*0Sstevel@tonic-gate 	    se->EventMask = client->event_mask;
3988*0Sstevel@tonic-gate 	} else {
3989*0Sstevel@tonic-gate 	    se->EventMask = client->global_mask;
3990*0Sstevel@tonic-gate 	}
3991*0Sstevel@tonic-gate 
3992*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
3993*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
3994*0Sstevel@tonic-gate 
3995*0Sstevel@tonic-gate 	return (CS_SUCCESS);
3996*0Sstevel@tonic-gate }
3997*0Sstevel@tonic-gate 
3998*0Sstevel@tonic-gate /*
3999*0Sstevel@tonic-gate  * cs_set_event_mask - set the event mask for this client
4000*0Sstevel@tonic-gate  */
4001*0Sstevel@tonic-gate static int
4002*0Sstevel@tonic-gate cs_set_event_mask(client_handle_t client_handle, sockevent_t *se)
4003*0Sstevel@tonic-gate {
4004*0Sstevel@tonic-gate 	cs_socket_t *sp;
4005*0Sstevel@tonic-gate 	client_t *client;
4006*0Sstevel@tonic-gate 	int error;
4007*0Sstevel@tonic-gate 	int client_lock_acquired;
4008*0Sstevel@tonic-gate 
4009*0Sstevel@tonic-gate 	/*
4010*0Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
4011*0Sstevel@tonic-gate 	 *	is, we don't do anything except for return success.
4012*0Sstevel@tonic-gate 	 */
4013*0Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
4014*0Sstevel@tonic-gate 	    return (CS_SUCCESS);
4015*0Sstevel@tonic-gate 
4016*0Sstevel@tonic-gate 	/*
4017*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
4018*0Sstevel@tonic-gate 	 */
4019*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
4020*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
4021*0Sstevel@tonic-gate 
4022*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
4023*0Sstevel@tonic-gate 
4024*0Sstevel@tonic-gate 	/*
4025*0Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
4026*0Sstevel@tonic-gate 	 */
4027*0Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
4028*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4029*0Sstevel@tonic-gate 	    return (error);
4030*0Sstevel@tonic-gate 	}
4031*0Sstevel@tonic-gate 
4032*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
4033*0Sstevel@tonic-gate 
4034*0Sstevel@tonic-gate #ifdef	XXX
4035*0Sstevel@tonic-gate 	/*
4036*0Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
4037*0Sstevel@tonic-gate 	 *	for this client, then return an error.
4038*0Sstevel@tonic-gate 	 */
4039*0Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
4040*0Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
4041*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4042*0Sstevel@tonic-gate 	    return (CS_NO_CARD);
4043*0Sstevel@tonic-gate 	}
4044*0Sstevel@tonic-gate #endif
4045*0Sstevel@tonic-gate 
4046*0Sstevel@tonic-gate 	/*
4047*0Sstevel@tonic-gate 	 * We are only allowed to set the client event mask if a
4048*0Sstevel@tonic-gate 	 *	RequestSocketMask has been called previously.  We
4049*0Sstevel@tonic-gate 	 *	are allowed to set the global event mask at any
4050*0Sstevel@tonic-gate 	 *	time.
4051*0Sstevel@tonic-gate 	 * The global event mask is initially set by the client
4052*0Sstevel@tonic-gate 	 *	in the call to RegisterClient.  The client event
4053*0Sstevel@tonic-gate 	 *	mask is set by the client in calls to SetEventMask
4054*0Sstevel@tonic-gate 	 *	and RequestSocketMask and gotten in calls to
4055*0Sstevel@tonic-gate 	 *	GetEventMask.
4056*0Sstevel@tonic-gate 	 */
4057*0Sstevel@tonic-gate 	if (se->Attributes & CONF_EVENT_MASK_CLIENT) {
4058*0Sstevel@tonic-gate 	    if (!(client->flags & REQ_SOCKET_MASK_DONE)) {
4059*0Sstevel@tonic-gate 		mutex_exit(&sp->lock);
4060*0Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4061*0Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
4062*0Sstevel@tonic-gate 	    }
4063*0Sstevel@tonic-gate 	    client->event_mask = se->EventMask;
4064*0Sstevel@tonic-gate 	} else {
4065*0Sstevel@tonic-gate 	    client->global_mask = se->EventMask;
4066*0Sstevel@tonic-gate 	}
4067*0Sstevel@tonic-gate 
4068*0Sstevel@tonic-gate 	/*
4069*0Sstevel@tonic-gate 	 * Merge all the clients' event masks and set the socket
4070*0Sstevel@tonic-gate 	 *	to generate the appropriate events.
4071*0Sstevel@tonic-gate 	 */
4072*0Sstevel@tonic-gate 	(void) cs_set_socket_event_mask(sp, cs_merge_event_masks(sp, client));
4073*0Sstevel@tonic-gate 
4074*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
4075*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4076*0Sstevel@tonic-gate 
4077*0Sstevel@tonic-gate 	return (CS_SUCCESS);
4078*0Sstevel@tonic-gate }
4079*0Sstevel@tonic-gate 
4080*0Sstevel@tonic-gate /*
4081*0Sstevel@tonic-gate  * cs_read_event_status - handles PRR events and returns card status
4082*0Sstevel@tonic-gate  *
4083*0Sstevel@tonic-gate  *	calling: *sp - socket struct point
4084*0Sstevel@tonic-gate  *		 *client - client to check events on
4085*0Sstevel@tonic-gate  *		 *revent - pointer to event mask to update; if NULL, will
4086*0Sstevel@tonic-gate  *				not be updated, if non-NULL, will be updated
4087*0Sstevel@tonic-gate  *				with CS-format events; it is NOT necessary
4088*0Sstevel@tonic-gate  *				to clear this value before calling this
4089*0Sstevel@tonic-gate  *				function
4090*0Sstevel@tonic-gate  *		 *gs - pointer to a get_ss_status_t used for the SS GetStatus
4091*0Sstevel@tonic-gate  *				call; it is not necessary to initialize any
4092*0Sstevel@tonic-gate  *				members in this structure; set to NULL if
4093*0Sstevel@tonic-gate  *				not used
4094*0Sstevel@tonic-gate  *		flags - if CS_RES_IGNORE_NO_CARD is set, the check for a
4095*0Sstevel@tonic-gate  *				card present will not be done
4096*0Sstevel@tonic-gate  *
4097*0Sstevel@tonic-gate  *	returns: CS_SUCCESS
4098*0Sstevel@tonic-gate  *		 CS_NO_CARD - if no card is in the socket and the flags arg
4099*0Sstevel@tonic-gate  *				is not set to CS_RES_IGNORE_NO_CARD
4100*0Sstevel@tonic-gate  *		 CS_BAD_SOCKET - if the SS_GetStatus function returned an
4101*0Sstevel@tonic-gate  *					error
4102*0Sstevel@tonic-gate  *
4103*0Sstevel@tonic-gate  *	Note that if the client that configured this socket has told us that
4104*0Sstevel@tonic-gate  *		the READY pin in the PRR isn't valid and the socket is in IO
4105*0Sstevel@tonic-gate  *		mode, we always return that the card is READY.
4106*0Sstevel@tonic-gate  *
4107*0Sstevel@tonic-gate  *	Note that if gs is not NULL, the current card state will be returned
4108*0Sstevel@tonic-gate  *		in the gs->CardState member; this will always reflect the
4109*0Sstevel@tonic-gate  *		current card state and the state will come from both the
4110*0Sstevel@tonic-gate  *		SS_GetStatus call and the PRR, whichever is appropriate for
4111*0Sstevel@tonic-gate  *		the mode that the socket is currently in.
4112*0Sstevel@tonic-gate  */
4113*0Sstevel@tonic-gate static int
4114*0Sstevel@tonic-gate cs_read_event_status(cs_socket_t *sp, client_t *client, event_t *revent,
4115*0Sstevel@tonic-gate 						get_ss_status_t *gs, int flags)
4116*0Sstevel@tonic-gate {
4117*0Sstevel@tonic-gate 	cfg_regs_t prrd = 0;
4118*0Sstevel@tonic-gate 
4119*0Sstevel@tonic-gate 	/*
4120*0Sstevel@tonic-gate 	 * SOCKET_IS_IO will only be set if a RequestConfiguration
4121*0Sstevel@tonic-gate 	 *	has been done by at least one client on this socket.
4122*0Sstevel@tonic-gate 	 * If there isn't a card in the socket or the caller wants to ignore
4123*0Sstevel@tonic-gate 	 *	whether the card is in the socket or not, get the current
4124*0Sstevel@tonic-gate 	 *	card status.
4125*0Sstevel@tonic-gate 	 */
4126*0Sstevel@tonic-gate 	if ((sp->flags & SOCKET_CARD_INSERTED) ||
4127*0Sstevel@tonic-gate 					(flags & CS_RES_IGNORE_NO_CARD)) {
4128*0Sstevel@tonic-gate 	    if (sp->flags & SOCKET_IS_IO) {
4129*0Sstevel@tonic-gate 		if (client->present & CONFIG_PINREPL_REG_PRESENT) {
4130*0Sstevel@tonic-gate 		    acc_handle_t cis_handle;
4131*0Sstevel@tonic-gate 		    uint32_t newoffset = client->config_regs_offset;
4132*0Sstevel@tonic-gate 
4133*0Sstevel@tonic-gate 			/*
4134*0Sstevel@tonic-gate 			 * Get a handle to the CIS window
4135*0Sstevel@tonic-gate 			 */
4136*0Sstevel@tonic-gate 		    if (cs_init_cis_window(sp, &newoffset, &cis_handle,
4137*0Sstevel@tonic-gate 					CISTPLF_AM_SPACE) != CS_SUCCESS) {
4138*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_read_event_status: socket %d "
4139*0Sstevel@tonic-gate 					    "can't init CIS window\n",
4140*0Sstevel@tonic-gate 							sp->socket_num);
4141*0Sstevel@tonic-gate 			return (CS_GENERAL_FAILURE);
4142*0Sstevel@tonic-gate 		    } /* cs_init_cis_window */
4143*0Sstevel@tonic-gate 
4144*0Sstevel@tonic-gate 		    prrd = csx_Get8(cis_handle, client->config_regs.prr_p);
4145*0Sstevel@tonic-gate 		    prrd &= client->pin;
4146*0Sstevel@tonic-gate 
4147*0Sstevel@tonic-gate #ifdef	CS_DEBUG
4148*0Sstevel@tonic-gate 		    if (cs_debug > 1) {
4149*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_read_event_status: "
4150*0Sstevel@tonic-gate 						"prrd 0x%x client->pin 0x%x\n",
4151*0Sstevel@tonic-gate 								(int)prrd,
4152*0Sstevel@tonic-gate 								client->pin);
4153*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "PRR(1) = [%s%s%s%s%s%s%s%s]\n",
4154*0Sstevel@tonic-gate 						((prrd & PRR_WP_STATUS)?
4155*0Sstevel@tonic-gate 							"PRR_WP_STATUS ":""),
4156*0Sstevel@tonic-gate 						((prrd & PRR_READY_STATUS)?
4157*0Sstevel@tonic-gate 							"PRR_READY_STATUS ":""),
4158*0Sstevel@tonic-gate 						((prrd & PRR_BVD2_STATUS)?
4159*0Sstevel@tonic-gate 							"PRR_BVD2_STATUS ":""),
4160*0Sstevel@tonic-gate 						((prrd & PRR_BVD1_STATUS)?
4161*0Sstevel@tonic-gate 							"PRR_BVD1_STATUS ":""),
4162*0Sstevel@tonic-gate 						((prrd & PRR_WP_EVENT)?
4163*0Sstevel@tonic-gate 							"PRR_WP_EVENT ":""),
4164*0Sstevel@tonic-gate 						((prrd & PRR_READY_EVENT)?
4165*0Sstevel@tonic-gate 							"PRR_READY_EVENT ":""),
4166*0Sstevel@tonic-gate 						((prrd & PRR_BVD2_EVENT)?
4167*0Sstevel@tonic-gate 							"PRR_BVD2_EVENT ":""),
4168*0Sstevel@tonic-gate 						((prrd & PRR_BVD1_EVENT)?
4169*0Sstevel@tonic-gate 							"PRR_BVD1_EVENT ":""));
4170*0Sstevel@tonic-gate 		    }
4171*0Sstevel@tonic-gate #endif
4172*0Sstevel@tonic-gate 
4173*0Sstevel@tonic-gate 			/*
4174*0Sstevel@tonic-gate 			 * The caller wants the event changes sent back and
4175*0Sstevel@tonic-gate 			 * the PRR event change bits cleared.
4176*0Sstevel@tonic-gate 			 */
4177*0Sstevel@tonic-gate 		    if (revent) {
4178*0Sstevel@tonic-gate 			get_socket_t get_socket;
4179*0Sstevel@tonic-gate 			set_socket_t set_socket;
4180*0Sstevel@tonic-gate 
4181*0Sstevel@tonic-gate 			/*
4182*0Sstevel@tonic-gate 			 * Bug ID: 1193636 - Card Services sends bogus
4183*0Sstevel@tonic-gate 			 *	events on CS_EVENT_STATUS_CHANGE events
4184*0Sstevel@tonic-gate 			 * Clear this before we OR-in any values.
4185*0Sstevel@tonic-gate 			 */
4186*0Sstevel@tonic-gate 			*revent = 0;
4187*0Sstevel@tonic-gate 
4188*0Sstevel@tonic-gate 			PRR_EVENT(prrd, PRR_WP_EVENT, PRR_WP_STATUS,
4189*0Sstevel@tonic-gate 					CS_EVENT_WRITE_PROTECT, *revent);
4190*0Sstevel@tonic-gate 
4191*0Sstevel@tonic-gate 			PRR_EVENT(prrd, PRR_READY_EVENT, PRR_READY_STATUS,
4192*0Sstevel@tonic-gate 					CS_EVENT_CARD_READY, *revent);
4193*0Sstevel@tonic-gate 
4194*0Sstevel@tonic-gate 			PRR_EVENT(prrd, PRR_BVD2_EVENT, PRR_BVD2_STATUS,
4195*0Sstevel@tonic-gate 					CS_EVENT_BATTERY_LOW, *revent);
4196*0Sstevel@tonic-gate 
4197*0Sstevel@tonic-gate 			PRR_EVENT(prrd, PRR_BVD1_EVENT, PRR_BVD1_STATUS,
4198*0Sstevel@tonic-gate 					CS_EVENT_BATTERY_DEAD, *revent);
4199*0Sstevel@tonic-gate 
4200*0Sstevel@tonic-gate 
4201*0Sstevel@tonic-gate #ifdef	CS_DEBUG
4202*0Sstevel@tonic-gate 			if (cs_debug > 1) {
4203*0Sstevel@tonic-gate 
4204*0Sstevel@tonic-gate 			    cmn_err(CE_CONT, "PRR() = [%s%s%s%s%s%s%s%s]\n",
4205*0Sstevel@tonic-gate 						((prrd & PRR_WP_STATUS)?
4206*0Sstevel@tonic-gate 							"PRR_WP_STATUS ":""),
4207*0Sstevel@tonic-gate 						((prrd & PRR_READY_STATUS)?
4208*0Sstevel@tonic-gate 							"PRR_READY_STATUS ":""),
4209*0Sstevel@tonic-gate 						((prrd & PRR_BVD2_STATUS)?
4210*0Sstevel@tonic-gate 							"PRR_BVD2_STATUS ":""),
4211*0Sstevel@tonic-gate 						((prrd & PRR_BVD1_STATUS)?
4212*0Sstevel@tonic-gate 							"PRR_BVD1_STATUS ":""),
4213*0Sstevel@tonic-gate 						((prrd & PRR_WP_EVENT)?
4214*0Sstevel@tonic-gate 							"PRR_WP_EVENT ":""),
4215*0Sstevel@tonic-gate 						((prrd & PRR_READY_EVENT)?
4216*0Sstevel@tonic-gate 							"PRR_READY_EVENT ":""),
4217*0Sstevel@tonic-gate 						((prrd & PRR_BVD2_EVENT)?
4218*0Sstevel@tonic-gate 							"PRR_BVD2_EVENT ":""),
4219*0Sstevel@tonic-gate 						((prrd & PRR_BVD1_EVENT)?
4220*0Sstevel@tonic-gate 							"PRR_BVD1_EVENT ":""));
4221*0Sstevel@tonic-gate 			}
4222*0Sstevel@tonic-gate #endif
4223*0Sstevel@tonic-gate 
4224*0Sstevel@tonic-gate 			if (prrd)
4225*0Sstevel@tonic-gate 			    csx_Put8(cis_handle, client->config_regs.prr_p,
4226*0Sstevel@tonic-gate 				prrd);
4227*0Sstevel@tonic-gate 
4228*0Sstevel@tonic-gate 			/*
4229*0Sstevel@tonic-gate 			 * We now have to reenable the status change interrupts
4230*0Sstevel@tonic-gate 			 *	if there are any valid bits in the PRR. Since
4231*0Sstevel@tonic-gate 			 *	the BVD1 signal becomes the STATUS_CHANGE
4232*0Sstevel@tonic-gate 			 *	signal when the socket is in IO mode, we just
4233*0Sstevel@tonic-gate 			 *	have to set the SBM_BVD1 enable bit in the
4234*0Sstevel@tonic-gate 			 *	event mask.
4235*0Sstevel@tonic-gate 			 */
4236*0Sstevel@tonic-gate 			if (client->pin) {
4237*0Sstevel@tonic-gate 			    get_socket.socket = sp->socket_num;
4238*0Sstevel@tonic-gate 			    SocketServices(SS_GetSocket, &get_socket);
4239*0Sstevel@tonic-gate 			    set_socket.socket = sp->socket_num;
4240*0Sstevel@tonic-gate 			    set_socket.SCIntMask =
4241*0Sstevel@tonic-gate 					get_socket.SCIntMask | SBM_BVD1;
4242*0Sstevel@tonic-gate 			    set_socket.VccLevel = get_socket.VccLevel;
4243*0Sstevel@tonic-gate 			    set_socket.Vpp1Level = get_socket.Vpp1Level;
4244*0Sstevel@tonic-gate 			    set_socket.Vpp2Level = get_socket.Vpp2Level;
4245*0Sstevel@tonic-gate 			    set_socket.IREQRouting = get_socket.IRQRouting;
4246*0Sstevel@tonic-gate 			    set_socket.IFType = get_socket.IFType;
4247*0Sstevel@tonic-gate 			    set_socket.CtlInd = get_socket.CtlInd;
4248*0Sstevel@tonic-gate 			    set_socket.State = get_socket.state;
4249*0Sstevel@tonic-gate 			    SocketServices(SS_SetSocket, &set_socket);
4250*0Sstevel@tonic-gate 			} /* if (client->pin) */
4251*0Sstevel@tonic-gate 		    } /* if (revent) */
4252*0Sstevel@tonic-gate 
4253*0Sstevel@tonic-gate 		} /* if (CONFIG_PINREPL_REG_PRESENT) */
4254*0Sstevel@tonic-gate 	    } /* if (SOCKET_IS_IO) */
4255*0Sstevel@tonic-gate 
4256*0Sstevel@tonic-gate 	/*
4257*0Sstevel@tonic-gate 	 * The caller wants the current card state; we just read
4258*0Sstevel@tonic-gate 	 *	it and return a copy of it but do not clear any of
4259*0Sstevel@tonic-gate 	 *	the event changed bits (if we're reading the PRR).
4260*0Sstevel@tonic-gate 	 */
4261*0Sstevel@tonic-gate 	    if (gs) {
4262*0Sstevel@tonic-gate 		gs->socket = sp->socket_num;
4263*0Sstevel@tonic-gate 		gs->CardState = 0;
4264*0Sstevel@tonic-gate 		if (SocketServices(SS_GetStatus, gs) != SUCCESS)
4265*0Sstevel@tonic-gate 		    return (CS_BAD_SOCKET);
4266*0Sstevel@tonic-gate 		if (sp->flags & SOCKET_IS_IO) {
4267*0Sstevel@tonic-gate 		/*
4268*0Sstevel@tonic-gate 		 * If the socket is in IO mode, then clear the
4269*0Sstevel@tonic-gate 		 *	gs->CardState bits that are now in the PRR
4270*0Sstevel@tonic-gate 		 */
4271*0Sstevel@tonic-gate 		    gs->CardState &= ~(SBM_WP | SBM_BVD1 |
4272*0Sstevel@tonic-gate 						SBM_BVD2 | SBM_RDYBSY);
4273*0Sstevel@tonic-gate 
4274*0Sstevel@tonic-gate 		/*
4275*0Sstevel@tonic-gate 		 * Convert PRR status to SS_GetStatus status
4276*0Sstevel@tonic-gate 		 */
4277*0Sstevel@tonic-gate 		    if (prrd & PRR_WP_STATUS)
4278*0Sstevel@tonic-gate 			gs->CardState |= SBM_WP;
4279*0Sstevel@tonic-gate 		    if (prrd & PRR_BVD2_STATUS)
4280*0Sstevel@tonic-gate 			gs->CardState |= SBM_BVD2;
4281*0Sstevel@tonic-gate 		    if (prrd & PRR_BVD1_STATUS)
4282*0Sstevel@tonic-gate 			gs->CardState |= SBM_BVD1;
4283*0Sstevel@tonic-gate 
4284*0Sstevel@tonic-gate 		/*
4285*0Sstevel@tonic-gate 		 * If the client has indicated that there is no
4286*0Sstevel@tonic-gate 		 *	PRR or that the READY bit in the PRR isn't
4287*0Sstevel@tonic-gate 		 *	valid, then we simulate the READY bit by
4288*0Sstevel@tonic-gate 		 *	always returning READY.
4289*0Sstevel@tonic-gate 		 */
4290*0Sstevel@tonic-gate 		    if (!(client->present & CONFIG_PINREPL_REG_PRESENT) ||
4291*0Sstevel@tonic-gate 			((client->present & CONFIG_PINREPL_REG_PRESENT) &&
4292*0Sstevel@tonic-gate 			!((client->pin &
4293*0Sstevel@tonic-gate 			    (PRR_READY_STATUS | PRR_READY_EVENT)) ==
4294*0Sstevel@tonic-gate 				(PRR_READY_STATUS | PRR_READY_EVENT))) ||
4295*0Sstevel@tonic-gate 				(prrd & PRR_READY_STATUS))
4296*0Sstevel@tonic-gate 			gs->CardState |= SBM_RDYBSY;
4297*0Sstevel@tonic-gate 
4298*0Sstevel@tonic-gate #ifdef	CS_DEBUG
4299*0Sstevel@tonic-gate 			if (cs_debug > 1) {
4300*0Sstevel@tonic-gate 			    cmn_err(CE_CONT, "cs_read_event_status: prrd 0x%x "
4301*0Sstevel@tonic-gate 				"client->pin 0x%x "
4302*0Sstevel@tonic-gate 				"gs->CardState 0x%x\n",
4303*0Sstevel@tonic-gate 				prrd, client->pin, gs->CardState);
4304*0Sstevel@tonic-gate 			}
4305*0Sstevel@tonic-gate #endif
4306*0Sstevel@tonic-gate 
4307*0Sstevel@tonic-gate 		} /* if (SOCKET_IS_IO) */
4308*0Sstevel@tonic-gate 	    } /* if (gs) */
4309*0Sstevel@tonic-gate 	    return (CS_SUCCESS);
4310*0Sstevel@tonic-gate 	} /* if (SOCKET_CARD_INSERTED) */
4311*0Sstevel@tonic-gate 
4312*0Sstevel@tonic-gate 	return (CS_NO_CARD);
4313*0Sstevel@tonic-gate }
4314*0Sstevel@tonic-gate 
4315*0Sstevel@tonic-gate /*
4316*0Sstevel@tonic-gate  * cs_get_status - gets live card status and latched card status changes
4317*0Sstevel@tonic-gate  *			supports the GetStatus CS call
4318*0Sstevel@tonic-gate  *
4319*0Sstevel@tonic-gate  *	returns: CS_SUCCESS
4320*0Sstevel@tonic-gate  *		 CS_BAD_HANDLE if the passed client handle is invalid
4321*0Sstevel@tonic-gate  *
4322*0Sstevel@tonic-gate  *	Note: This function resets the latched status values maintained
4323*0Sstevel@tonic-gate  *		by Socket Services
4324*0Sstevel@tonic-gate  */
4325*0Sstevel@tonic-gate static int
4326*0Sstevel@tonic-gate cs_get_status(client_handle_t client_handle, get_status_t *gs)
4327*0Sstevel@tonic-gate {
4328*0Sstevel@tonic-gate 	cs_socket_t *sp;
4329*0Sstevel@tonic-gate 	client_t *client;
4330*0Sstevel@tonic-gate 	get_ss_status_t get_ss_status;
4331*0Sstevel@tonic-gate 	get_socket_t get_socket;
4332*0Sstevel@tonic-gate 	set_socket_t set_socket;
4333*0Sstevel@tonic-gate 	int error;
4334*0Sstevel@tonic-gate 	int client_lock_acquired;
4335*0Sstevel@tonic-gate 
4336*0Sstevel@tonic-gate 	/*
4337*0Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
4338*0Sstevel@tonic-gate 	 *	is, we don't do anything except for return success.
4339*0Sstevel@tonic-gate 	 */
4340*0Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
4341*0Sstevel@tonic-gate 	    return (CS_SUCCESS);
4342*0Sstevel@tonic-gate 
4343*0Sstevel@tonic-gate 	/*
4344*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
4345*0Sstevel@tonic-gate 	 */
4346*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
4347*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
4348*0Sstevel@tonic-gate 
4349*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
4350*0Sstevel@tonic-gate 
4351*0Sstevel@tonic-gate 	/*
4352*0Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
4353*0Sstevel@tonic-gate 	 */
4354*0Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
4355*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4356*0Sstevel@tonic-gate 	    return (error);
4357*0Sstevel@tonic-gate 	}
4358*0Sstevel@tonic-gate 
4359*0Sstevel@tonic-gate 	/*
4360*0Sstevel@tonic-gate 	 * Get the current card status as well as the latched card
4361*0Sstevel@tonic-gate 	 *	state.  Set the CS_RES_IGNORE_NO_CARD so that even
4362*0Sstevel@tonic-gate 	 *	if there is no card in the socket we'll still get
4363*0Sstevel@tonic-gate 	 *	a valid status.
4364*0Sstevel@tonic-gate 	 * Note that it is not necessary to initialize any values
4365*0Sstevel@tonic-gate 	 *	in the get_ss_status structure.
4366*0Sstevel@tonic-gate 	 */
4367*0Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
4368*0Sstevel@tonic-gate 	if ((error = cs_read_event_status(sp, client, NULL, &get_ss_status,
4369*0Sstevel@tonic-gate 					CS_RES_IGNORE_NO_CARD)) != CS_SUCCESS) {
4370*0Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
4371*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4372*0Sstevel@tonic-gate 	    return (error);
4373*0Sstevel@tonic-gate 	}
4374*0Sstevel@tonic-gate 
4375*0Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
4376*0Sstevel@tonic-gate 
4377*0Sstevel@tonic-gate 	gs->raw_CardState = cs_sbm2cse(get_ss_status.CardState);
4378*0Sstevel@tonic-gate 
4379*0Sstevel@tonic-gate 	/*
4380*0Sstevel@tonic-gate 	 * Assign the "live" card state to the "real" card state. If there's
4381*0Sstevel@tonic-gate 	 *	no card in the socket or the card in the socket is not
4382*0Sstevel@tonic-gate 	 *	for this client, then we lie and tell the caller that the
4383*0Sstevel@tonic-gate 	 *	card is not inserted.
4384*0Sstevel@tonic-gate 	 */
4385*0Sstevel@tonic-gate 	gs->CardState = gs->raw_CardState;
4386*0Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED))
4387*0Sstevel@tonic-gate 	    gs->CardState &= ~CS_EVENT_CARD_INSERTION;
4388*0Sstevel@tonic-gate 
4389*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4390*0Sstevel@tonic-gate 
4391*0Sstevel@tonic-gate 	get_socket.socket = sp->socket_num;
4392*0Sstevel@tonic-gate 	if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS)
4393*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
4394*0Sstevel@tonic-gate 
4395*0Sstevel@tonic-gate 	gs->SocketState = cs_sbm2cse(get_socket.state);
4396*0Sstevel@tonic-gate 
4397*0Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
4398*0Sstevel@tonic-gate 	set_socket.SCIntMask = get_socket.SCIntMask;
4399*0Sstevel@tonic-gate 	set_socket.VccLevel = get_socket.VccLevel;
4400*0Sstevel@tonic-gate 	set_socket.Vpp1Level = get_socket.Vpp1Level;
4401*0Sstevel@tonic-gate 	set_socket.Vpp2Level = get_socket.Vpp2Level;
4402*0Sstevel@tonic-gate 	set_socket.IREQRouting = get_socket.IRQRouting;
4403*0Sstevel@tonic-gate 	set_socket.IFType = get_socket.IFType;
4404*0Sstevel@tonic-gate 	set_socket.CtlInd = get_socket.CtlInd;
4405*0Sstevel@tonic-gate 	/* XXX (is ~0 correct here?) reset latched values */
4406*0Sstevel@tonic-gate 	set_socket.State = (unsigned)~0;
4407*0Sstevel@tonic-gate 
4408*0Sstevel@tonic-gate 	if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS)
4409*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
4410*0Sstevel@tonic-gate 
4411*0Sstevel@tonic-gate 	return (CS_SUCCESS);
4412*0Sstevel@tonic-gate }
4413*0Sstevel@tonic-gate 
4414*0Sstevel@tonic-gate /*
4415*0Sstevel@tonic-gate  * cs_cse2sbm - converts a CS event mask to an SS (SBM_XXX) event mask
4416*0Sstevel@tonic-gate  */
4417*0Sstevel@tonic-gate static event_t
4418*0Sstevel@tonic-gate cs_cse2sbm(event_t event_mask)
4419*0Sstevel@tonic-gate {
4420*0Sstevel@tonic-gate 	event_t sbm_event = 0;
4421*0Sstevel@tonic-gate 
4422*0Sstevel@tonic-gate 	/*
4423*0Sstevel@tonic-gate 	 * XXX - we need to handle PM_CHANGE and RESET here as well
4424*0Sstevel@tonic-gate 	 */
4425*0Sstevel@tonic-gate 	if (event_mask & CS_EVENT_WRITE_PROTECT)
4426*0Sstevel@tonic-gate 	    sbm_event |= SBM_WP;
4427*0Sstevel@tonic-gate 	if (event_mask & CS_EVENT_BATTERY_DEAD)
4428*0Sstevel@tonic-gate 	    sbm_event |= SBM_BVD1;
4429*0Sstevel@tonic-gate 	if (event_mask & CS_EVENT_BATTERY_LOW)
4430*0Sstevel@tonic-gate 	    sbm_event |= SBM_BVD2;
4431*0Sstevel@tonic-gate 	if (event_mask & CS_EVENT_CARD_READY)
4432*0Sstevel@tonic-gate 	    sbm_event |= SBM_RDYBSY;
4433*0Sstevel@tonic-gate 	if (event_mask & CS_EVENT_CARD_LOCK)
4434*0Sstevel@tonic-gate 	    sbm_event |= SBM_LOCKED;
4435*0Sstevel@tonic-gate 	if (event_mask & CS_EVENT_EJECTION_REQUEST)
4436*0Sstevel@tonic-gate 	    sbm_event |= SBM_EJECT;
4437*0Sstevel@tonic-gate 	if (event_mask & CS_EVENT_INSERTION_REQUEST)
4438*0Sstevel@tonic-gate 	    sbm_event |= SBM_INSERT;
4439*0Sstevel@tonic-gate 	if (event_mask & (CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL))
4440*0Sstevel@tonic-gate 	    sbm_event |= SBM_CD;
4441*0Sstevel@tonic-gate 
4442*0Sstevel@tonic-gate 	return (sbm_event);
4443*0Sstevel@tonic-gate }
4444*0Sstevel@tonic-gate 
4445*0Sstevel@tonic-gate /*
4446*0Sstevel@tonic-gate  * cs_sbm2cse - converts SBM_xxx state to CS event bits
4447*0Sstevel@tonic-gate  *
4448*0Sstevel@tonic-gate  * This function should never set any of the following bits:
4449*0Sstevel@tonic-gate  *
4450*0Sstevel@tonic-gate  *		CS_EVENT_MTD_REQUEST
4451*0Sstevel@tonic-gate  *		CS_EVENT_CLIENT_INFO
4452*0Sstevel@tonic-gate  *		CS_EVENT_TIMER_EXPIRED
4453*0Sstevel@tonic-gate  *		CS_EVENT_CARD_REMOVAL
4454*0Sstevel@tonic-gate  *		CS_EVENT_CARD_REMOVAL_LOWP
4455*0Sstevel@tonic-gate  *		CS_EVENT_ALL_CLIENTS
4456*0Sstevel@tonic-gate  *		CS_EVENT_READY_TIMEOUT
4457*0Sstevel@tonic-gate  *
4458*0Sstevel@tonic-gate  *	These bits are defined in the CS_STATUS_XXX series and are
4459*0Sstevel@tonic-gate  *	used by GetStatus.
4460*0Sstevel@tonic-gate  */
4461*0Sstevel@tonic-gate static uint32_t
4462*0Sstevel@tonic-gate cs_sbm2cse(uint32_t state)
4463*0Sstevel@tonic-gate {
4464*0Sstevel@tonic-gate 	uint32_t rstate = 0;
4465*0Sstevel@tonic-gate 
4466*0Sstevel@tonic-gate 	/*
4467*0Sstevel@tonic-gate 	 * XXX - we need to handle PM_CHANGE and RESET here as well
4468*0Sstevel@tonic-gate 	 */
4469*0Sstevel@tonic-gate 	if (state & SBM_WP)
4470*0Sstevel@tonic-gate 	    rstate |= CS_EVENT_WRITE_PROTECT;
4471*0Sstevel@tonic-gate 	if (state & SBM_BVD1)
4472*0Sstevel@tonic-gate 	    rstate |= CS_EVENT_BATTERY_DEAD;
4473*0Sstevel@tonic-gate 	if (state & SBM_BVD2)
4474*0Sstevel@tonic-gate 	    rstate |= CS_EVENT_BATTERY_LOW;
4475*0Sstevel@tonic-gate 	if (state & SBM_RDYBSY)
4476*0Sstevel@tonic-gate 	    rstate |= CS_EVENT_CARD_READY;
4477*0Sstevel@tonic-gate 	if (state & SBM_LOCKED)
4478*0Sstevel@tonic-gate 	    rstate |= CS_EVENT_CARD_LOCK;
4479*0Sstevel@tonic-gate 	if (state & SBM_EJECT)
4480*0Sstevel@tonic-gate 	    rstate |= CS_EVENT_EJECTION_REQUEST;
4481*0Sstevel@tonic-gate 	if (state & SBM_INSERT)
4482*0Sstevel@tonic-gate 	    rstate |= CS_EVENT_INSERTION_REQUEST;
4483*0Sstevel@tonic-gate 	if (state & SBM_CD)
4484*0Sstevel@tonic-gate 	    rstate |= CS_EVENT_CARD_INSERTION;
4485*0Sstevel@tonic-gate 
4486*0Sstevel@tonic-gate 	return (rstate);
4487*0Sstevel@tonic-gate }
4488*0Sstevel@tonic-gate 
4489*0Sstevel@tonic-gate /*
4490*0Sstevel@tonic-gate  * cs_merge_event_masks - merge the CS global socket event mask with the
4491*0Sstevel@tonic-gate  *				passed client's event masks
4492*0Sstevel@tonic-gate  */
4493*0Sstevel@tonic-gate static unsigned
4494*0Sstevel@tonic-gate cs_merge_event_masks(cs_socket_t *sp, client_t *client)
4495*0Sstevel@tonic-gate {
4496*0Sstevel@tonic-gate 	unsigned SCIntMask;
4497*0Sstevel@tonic-gate 	uint32_t event_mask;
4498*0Sstevel@tonic-gate 
4499*0Sstevel@tonic-gate 	/*
4500*0Sstevel@tonic-gate 	 * We always want to see card detect and status change events.
4501*0Sstevel@tonic-gate 	 */
4502*0Sstevel@tonic-gate 	SCIntMask = SBM_CD;
4503*0Sstevel@tonic-gate 
4504*0Sstevel@tonic-gate 	event_mask = client->event_mask | client->global_mask |
4505*0Sstevel@tonic-gate 							sp->event_mask;
4506*0Sstevel@tonic-gate 
4507*0Sstevel@tonic-gate 	if (!(sp->flags & SOCKET_IS_IO)) {
4508*0Sstevel@tonic-gate 	    SCIntMask |= cs_cse2sbm(event_mask);
4509*0Sstevel@tonic-gate 	} else {
4510*0Sstevel@tonic-gate 		/*
4511*0Sstevel@tonic-gate 		 * If the socket is in IO mode and there is a PRR present,
4512*0Sstevel@tonic-gate 		 *	then we may need to enable PCE_CARD_STATUS_CHANGE
4513*0Sstevel@tonic-gate 		 *	events.
4514*0Sstevel@tonic-gate 		 */
4515*0Sstevel@tonic-gate 	    if (client->present & CONFIG_PINREPL_REG_PRESENT) {
4516*0Sstevel@tonic-gate 
4517*0Sstevel@tonic-gate 		SCIntMask |= (cs_cse2sbm(event_mask) &
4518*0Sstevel@tonic-gate 				~(SBM_WP | SBM_BVD1 | SBM_BVD2 | SBM_RDYBSY));
4519*0Sstevel@tonic-gate 
4520*0Sstevel@tonic-gate 		if ((client->pin & (PRR_WP_STATUS | PRR_WP_EVENT)) ==
4521*0Sstevel@tonic-gate 					(PRR_WP_STATUS | PRR_WP_EVENT))
4522*0Sstevel@tonic-gate 		    if (event_mask & CS_EVENT_WRITE_PROTECT)
4523*0Sstevel@tonic-gate 			SCIntMask |= SBM_BVD1;
4524*0Sstevel@tonic-gate 
4525*0Sstevel@tonic-gate 		if ((client->pin & (PRR_READY_STATUS | PRR_READY_EVENT)) ==
4526*0Sstevel@tonic-gate 					(PRR_READY_STATUS | PRR_READY_EVENT))
4527*0Sstevel@tonic-gate 		    if (event_mask & CS_EVENT_CARD_READY)
4528*0Sstevel@tonic-gate 			    SCIntMask |= SBM_BVD1;
4529*0Sstevel@tonic-gate 
4530*0Sstevel@tonic-gate 		if ((client->pin & (PRR_BVD2_STATUS | PRR_BVD2_EVENT)) ==
4531*0Sstevel@tonic-gate 					(PRR_BVD2_STATUS | PRR_BVD2_EVENT))
4532*0Sstevel@tonic-gate 		    if (event_mask & CS_EVENT_BATTERY_LOW)
4533*0Sstevel@tonic-gate 			    SCIntMask |= SBM_BVD1;
4534*0Sstevel@tonic-gate 
4535*0Sstevel@tonic-gate 		if ((client->pin & (PRR_BVD1_STATUS | PRR_BVD1_EVENT)) ==
4536*0Sstevel@tonic-gate 					(PRR_BVD1_STATUS | PRR_BVD1_EVENT))
4537*0Sstevel@tonic-gate 		    if (event_mask & CS_EVENT_BATTERY_DEAD)
4538*0Sstevel@tonic-gate 			    SCIntMask |= SBM_BVD1;
4539*0Sstevel@tonic-gate 
4540*0Sstevel@tonic-gate 	    } /* if (CONFIG_PINREPL_REG_PRESENT) */
4541*0Sstevel@tonic-gate 	} /* if (!SOCKET_IS_IO) */
4542*0Sstevel@tonic-gate 
4543*0Sstevel@tonic-gate 	return (SCIntMask);
4544*0Sstevel@tonic-gate }
4545*0Sstevel@tonic-gate 
4546*0Sstevel@tonic-gate /*
4547*0Sstevel@tonic-gate  * cs_set_socket_event_mask - set the event mask for the socket
4548*0Sstevel@tonic-gate  */
4549*0Sstevel@tonic-gate static int
4550*0Sstevel@tonic-gate cs_set_socket_event_mask(cs_socket_t *sp, unsigned event_mask)
4551*0Sstevel@tonic-gate {
4552*0Sstevel@tonic-gate 	get_socket_t get_socket;
4553*0Sstevel@tonic-gate 	set_socket_t set_socket;
4554*0Sstevel@tonic-gate 
4555*0Sstevel@tonic-gate 	get_socket.socket = sp->socket_num;
4556*0Sstevel@tonic-gate 	if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS)
4557*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
4558*0Sstevel@tonic-gate 
4559*0Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
4560*0Sstevel@tonic-gate 	set_socket.SCIntMask = event_mask;
4561*0Sstevel@tonic-gate 	set_socket.VccLevel = get_socket.VccLevel;
4562*0Sstevel@tonic-gate 	set_socket.Vpp1Level = get_socket.Vpp1Level;
4563*0Sstevel@tonic-gate 	set_socket.Vpp2Level = get_socket.Vpp2Level;
4564*0Sstevel@tonic-gate 	set_socket.IREQRouting = get_socket.IRQRouting;
4565*0Sstevel@tonic-gate 	set_socket.IFType = get_socket.IFType;
4566*0Sstevel@tonic-gate 	set_socket.CtlInd = get_socket.CtlInd;
4567*0Sstevel@tonic-gate 	/* XXX (is ~0 correct here?) reset latched values */
4568*0Sstevel@tonic-gate 	set_socket.State = (unsigned)~0;
4569*0Sstevel@tonic-gate 
4570*0Sstevel@tonic-gate 	if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS)
4571*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
4572*0Sstevel@tonic-gate 
4573*0Sstevel@tonic-gate 	return (CS_SUCCESS);
4574*0Sstevel@tonic-gate }
4575*0Sstevel@tonic-gate 
4576*0Sstevel@tonic-gate /*
4577*0Sstevel@tonic-gate  * ==== MTD handling section ====
4578*0Sstevel@tonic-gate  */
4579*0Sstevel@tonic-gate static int
4580*0Sstevel@tonic-gate cs_deregister_mtd(client_handle_t client_handle)
4581*0Sstevel@tonic-gate {
4582*0Sstevel@tonic-gate 
4583*0Sstevel@tonic-gate 	cmn_err(CE_CONT, "cs_deregister_mtd: client_handle 0x%x\n",
4584*0Sstevel@tonic-gate 							(int)client_handle);
4585*0Sstevel@tonic-gate 
4586*0Sstevel@tonic-gate 	return (CS_SUCCESS);
4587*0Sstevel@tonic-gate }
4588*0Sstevel@tonic-gate 
4589*0Sstevel@tonic-gate /*
4590*0Sstevel@tonic-gate  * ==== memory window handling section ====
4591*0Sstevel@tonic-gate  */
4592*0Sstevel@tonic-gate 
4593*0Sstevel@tonic-gate /*
4594*0Sstevel@tonic-gate  * cs_request_window  - searches through window list for the socket to find a
4595*0Sstevel@tonic-gate  *			memory window that matches the requested criteria;
4596*0Sstevel@tonic-gate  *			this is RequestWindow
4597*0Sstevel@tonic-gate  *
4598*0Sstevel@tonic-gate  * calling:  cs_request_window(client_handle_t, *window_handle_t, win_req_t *)
4599*0Sstevel@tonic-gate  *
4600*0Sstevel@tonic-gate  *	On sucessful return, the window_handle_t * pointed to will
4601*0Sstevel@tonic-gate  *		contain a valid window handle for this window.
4602*0Sstevel@tonic-gate  *
4603*0Sstevel@tonic-gate  *	returns: CS_SUCCESS - if window found
4604*0Sstevel@tonic-gate  *		 CS_OUT_OF_RESOURCE - if no windows match requirements
4605*0Sstevel@tonic-gate  *		 CS_BAD_HANDLE - client handle is invalid
4606*0Sstevel@tonic-gate  *		 CS_BAD_SIZE - if requested size can not be met
4607*0Sstevel@tonic-gate  *		 CS_BAD_WINDOW - if an internal error occured
4608*0Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
4609*0Sstevel@tonic-gate  *		 CS_NO_CARD - if no card is in socket
4610*0Sstevel@tonic-gate  *		 CS_BAD_ATTRIBUTE - if any of the unsupported Attrbute
4611*0Sstevel@tonic-gate  *					flags are set
4612*0Sstevel@tonic-gate  */
4613*0Sstevel@tonic-gate static int
4614*0Sstevel@tonic-gate cs_request_window(client_handle_t client_handle,
4615*0Sstevel@tonic-gate 				window_handle_t *wh,
4616*0Sstevel@tonic-gate 				win_req_t *rw)
4617*0Sstevel@tonic-gate {
4618*0Sstevel@tonic-gate 	cs_socket_t *sp;
4619*0Sstevel@tonic-gate 	cs_window_t *cw;
4620*0Sstevel@tonic-gate 	client_t *client;
4621*0Sstevel@tonic-gate 	modify_win_t mw;
4622*0Sstevel@tonic-gate 	inquire_window_t iw;
4623*0Sstevel@tonic-gate 	uint32_t aw;
4624*0Sstevel@tonic-gate 	int error;
4625*0Sstevel@tonic-gate 	int client_lock_acquired;
4626*0Sstevel@tonic-gate 	uint32_t socket_num;
4627*0Sstevel@tonic-gate 
4628*0Sstevel@tonic-gate 	/*
4629*0Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
4630*0Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
4631*0Sstevel@tonic-gate 	 */
4632*0Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
4633*0Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
4634*0Sstevel@tonic-gate 
4635*0Sstevel@tonic-gate 	/*
4636*0Sstevel@tonic-gate 	 * Make sure that none of the unsupported flags are set.
4637*0Sstevel@tonic-gate 	 */
4638*0Sstevel@tonic-gate 	if (rw->Attributes &   (/* Compatability */
4639*0Sstevel@tonic-gate 				WIN_PAGED |
4640*0Sstevel@tonic-gate 				WIN_SHARED |
4641*0Sstevel@tonic-gate 				WIN_FIRST_SHARED |
4642*0Sstevel@tonic-gate 				WIN_BINDING_SPECIFIC |
4643*0Sstevel@tonic-gate 				/* CS internal */
4644*0Sstevel@tonic-gate 				WIN_DATA_WIDTH_VALID |
4645*0Sstevel@tonic-gate 				/* IO window flags */
4646*0Sstevel@tonic-gate 				WIN_MEMORY_TYPE_IO |
4647*0Sstevel@tonic-gate 				/* CardBus flags */
4648*0Sstevel@tonic-gate 				WIN_DATA_WIDTH_32 |
4649*0Sstevel@tonic-gate 				WIN_PREFETCH_CACHE_MASK |
4650*0Sstevel@tonic-gate 				WIN_BAR_MASK))
4651*0Sstevel@tonic-gate 	    return (CS_BAD_ATTRIBUTE);
4652*0Sstevel@tonic-gate 
4653*0Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
4654*0Sstevel@tonic-gate 
4655*0Sstevel@tonic-gate 	/*
4656*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
4657*0Sstevel@tonic-gate 	 */
4658*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
4659*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
4660*0Sstevel@tonic-gate 
4661*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
4662*0Sstevel@tonic-gate 
4663*0Sstevel@tonic-gate 	/*
4664*0Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
4665*0Sstevel@tonic-gate 	 */
4666*0Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
4667*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4668*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
4669*0Sstevel@tonic-gate 	    return (error);
4670*0Sstevel@tonic-gate 	}
4671*0Sstevel@tonic-gate 
4672*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
4673*0Sstevel@tonic-gate 
4674*0Sstevel@tonic-gate 	/*
4675*0Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
4676*0Sstevel@tonic-gate 	 *	for this client, then return an error.
4677*0Sstevel@tonic-gate 	 */
4678*0Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
4679*0Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
4680*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4681*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
4682*0Sstevel@tonic-gate 	    return (CS_NO_CARD);
4683*0Sstevel@tonic-gate 	}
4684*0Sstevel@tonic-gate 
4685*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
4686*0Sstevel@tonic-gate 
4687*0Sstevel@tonic-gate 	socket_num = CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
4688*0Sstevel@tonic-gate 	    GET_CLIENT_FUNCTION(client_handle));
4689*0Sstevel@tonic-gate 
4690*0Sstevel@tonic-gate 
4691*0Sstevel@tonic-gate 	/*
4692*0Sstevel@tonic-gate 	 * See if we can find a window that matches the caller's criteria.
4693*0Sstevel@tonic-gate 	 *	If we can't, then thre's not much more that we can do except
4694*0Sstevel@tonic-gate 	 *	for return an error.
4695*0Sstevel@tonic-gate 	 */
4696*0Sstevel@tonic-gate 	if ((error = cs_find_mem_window(sp->socket_num, rw, &aw)) !=
4697*0Sstevel@tonic-gate 								CS_SUCCESS) {
4698*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4699*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
4700*0Sstevel@tonic-gate 	    return (error);
4701*0Sstevel@tonic-gate 	}
4702*0Sstevel@tonic-gate 
4703*0Sstevel@tonic-gate 	/*
4704*0Sstevel@tonic-gate 	 * We got a window, now synthesize a new window handle for this
4705*0Sstevel@tonic-gate 	 *	client and get a pointer to the global window structs
4706*0Sstevel@tonic-gate 	 *	and assign this window to this client.
4707*0Sstevel@tonic-gate 	 * We don't have to check for errors from cs_create_window_handle
4708*0Sstevel@tonic-gate 	 *	since that function always returns a valid window handle
4709*0Sstevel@tonic-gate 	 *	if it is given a valid window number.
4710*0Sstevel@tonic-gate 	 */
4711*0Sstevel@tonic-gate 	*wh = cs_create_window_handle(aw);
4712*0Sstevel@tonic-gate 	if ((cw = cs_get_wp(aw)) == NULL) {
4713*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4714*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
4715*0Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
4716*0Sstevel@tonic-gate 	}
4717*0Sstevel@tonic-gate 
4718*0Sstevel@tonic-gate 	cw->window_handle = *wh;
4719*0Sstevel@tonic-gate 	cw->client_handle = client_handle;
4720*0Sstevel@tonic-gate 	cw->socket_num = sp->socket_num;
4721*0Sstevel@tonic-gate 	cw->state |= (CW_ALLOCATED | CW_MEM);
4722*0Sstevel@tonic-gate 
4723*0Sstevel@tonic-gate 	mw.Attributes = (
4724*0Sstevel@tonic-gate 				rw->Attributes |
4725*0Sstevel@tonic-gate 				WIN_DATA_WIDTH_VALID |
4726*0Sstevel@tonic-gate 				WIN_ACCESS_SPEED_VALID);
4727*0Sstevel@tonic-gate 	mw.AccessSpeed = rw->win_params.AccessSpeed;
4728*0Sstevel@tonic-gate 
4729*0Sstevel@tonic-gate 	if ((error = cs_modify_mem_window(*wh, &mw, rw, socket_num)) !=
4730*0Sstevel@tonic-gate 	    CS_SUCCESS) {
4731*0Sstevel@tonic-gate 	    cw->state = 0;
4732*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4733*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
4734*0Sstevel@tonic-gate 	    return (error);
4735*0Sstevel@tonic-gate 	}
4736*0Sstevel@tonic-gate 
4737*0Sstevel@tonic-gate 	/*
4738*0Sstevel@tonic-gate 	 * Get any required card offset and pass it back to the client.
4739*0Sstevel@tonic-gate 	 *	This is not defined in the current PCMCIA spec.  It is
4740*0Sstevel@tonic-gate 	 *	an aid to clients that want to use it to generate an
4741*0Sstevel@tonic-gate 	 *	optimum card offset.
4742*0Sstevel@tonic-gate 	 */
4743*0Sstevel@tonic-gate 	iw.window = GET_WINDOW_NUMBER(*wh);
4744*0Sstevel@tonic-gate 	SocketServices(SS_InquireWindow, &iw);
4745*0Sstevel@tonic-gate 
4746*0Sstevel@tonic-gate 	if (iw.mem_win_char.MemWndCaps & WC_CALIGN)
4747*0Sstevel@tonic-gate 	    rw->ReqOffset = rw->Size;
4748*0Sstevel@tonic-gate 	else
4749*0Sstevel@tonic-gate 	    rw->ReqOffset = iw.mem_win_char.ReqOffset;
4750*0Sstevel@tonic-gate 
4751*0Sstevel@tonic-gate 	/*
4752*0Sstevel@tonic-gate 	 * Increment the client's memory window count; this is how we know
4753*0Sstevel@tonic-gate 	 *	when a client has any allocated memory windows.
4754*0Sstevel@tonic-gate 	 */
4755*0Sstevel@tonic-gate 	client->memwin_count++;
4756*0Sstevel@tonic-gate 
4757*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4758*0Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
4759*0Sstevel@tonic-gate 
4760*0Sstevel@tonic-gate 	return (CS_SUCCESS);
4761*0Sstevel@tonic-gate }
4762*0Sstevel@tonic-gate 
4763*0Sstevel@tonic-gate /*
4764*0Sstevel@tonic-gate  * cs_release_window - deallocates the window associated with the passed
4765*0Sstevel@tonic-gate  *			window handle; this is ReleaseWindow
4766*0Sstevel@tonic-gate  *
4767*0Sstevel@tonic-gate  *	returns: CS_SUCCESS if window handle is valid and window was
4768*0Sstevel@tonic-gate  *			sucessfully deallocated
4769*0Sstevel@tonic-gate  *		 CS_BAD_HANDLE if window handle is invalid or if window
4770*0Sstevel@tonic-gate  *			handle is valid but window is not allocated
4771*0Sstevel@tonic-gate  */
4772*0Sstevel@tonic-gate static int
4773*0Sstevel@tonic-gate cs_release_window(window_handle_t wh)
4774*0Sstevel@tonic-gate {
4775*0Sstevel@tonic-gate 	cs_socket_t *sp;
4776*0Sstevel@tonic-gate 	cs_window_t *cw;
4777*0Sstevel@tonic-gate 	client_t *client;
4778*0Sstevel@tonic-gate 	int error;
4779*0Sstevel@tonic-gate 	int client_lock_acquired;
4780*0Sstevel@tonic-gate 
4781*0Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
4782*0Sstevel@tonic-gate 
4783*0Sstevel@tonic-gate 	if (!(cw = cs_find_window(wh))) {
4784*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
4785*0Sstevel@tonic-gate 	    return (CS_BAD_HANDLE);
4786*0Sstevel@tonic-gate 	}
4787*0Sstevel@tonic-gate 
4788*0Sstevel@tonic-gate 	/*
4789*0Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
4790*0Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
4791*0Sstevel@tonic-gate 	 */
4792*0Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(cw->client_handle)) {
4793*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
4794*0Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
4795*0Sstevel@tonic-gate 	}
4796*0Sstevel@tonic-gate 
4797*0Sstevel@tonic-gate 	/*
4798*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
4799*0Sstevel@tonic-gate 	 */
4800*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(cw->client_handle))) == NULL)
4801*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
4802*0Sstevel@tonic-gate 
4803*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
4804*0Sstevel@tonic-gate 
4805*0Sstevel@tonic-gate 	/*
4806*0Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
4807*0Sstevel@tonic-gate 	 */
4808*0Sstevel@tonic-gate 	if (!(client = cs_find_client(cw->client_handle, &error))) {
4809*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4810*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
4811*0Sstevel@tonic-gate 	    return (error);
4812*0Sstevel@tonic-gate 	}
4813*0Sstevel@tonic-gate 
4814*0Sstevel@tonic-gate 	/*
4815*0Sstevel@tonic-gate 	 * Mark this window as not in use anymore.
4816*0Sstevel@tonic-gate 	 */
4817*0Sstevel@tonic-gate 	cw->state &= ~CW_WIN_IN_USE;
4818*0Sstevel@tonic-gate 
4819*0Sstevel@tonic-gate 	/*
4820*0Sstevel@tonic-gate 	 * Decrement the client's memory window count; this is how we know
4821*0Sstevel@tonic-gate 	 *	when a client has any allocated memory windows.
4822*0Sstevel@tonic-gate 	 */
4823*0Sstevel@tonic-gate 	if (!(--(client->memwin_count)))
4824*0Sstevel@tonic-gate 	    client->flags &= ~CLIENT_WIN_ALLOCATED;
4825*0Sstevel@tonic-gate 
4826*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4827*0Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
4828*0Sstevel@tonic-gate 
4829*0Sstevel@tonic-gate 	return (CS_SUCCESS);
4830*0Sstevel@tonic-gate }
4831*0Sstevel@tonic-gate 
4832*0Sstevel@tonic-gate /*
4833*0Sstevel@tonic-gate  * cs_modify_window - modifies a window's characteristics; this is ModifyWindow
4834*0Sstevel@tonic-gate  */
4835*0Sstevel@tonic-gate static int
4836*0Sstevel@tonic-gate cs_modify_window(window_handle_t wh, modify_win_t *mw)
4837*0Sstevel@tonic-gate {
4838*0Sstevel@tonic-gate 	cs_socket_t *sp;
4839*0Sstevel@tonic-gate 	cs_window_t *cw;
4840*0Sstevel@tonic-gate 	client_t *client;
4841*0Sstevel@tonic-gate 	int error;
4842*0Sstevel@tonic-gate 	int client_lock_acquired;
4843*0Sstevel@tonic-gate 
4844*0Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
4845*0Sstevel@tonic-gate 
4846*0Sstevel@tonic-gate 	/*
4847*0Sstevel@tonic-gate 	 * Do some sanity checking - make sure that we can find a pointer
4848*0Sstevel@tonic-gate 	 *	to the window structure, and if we can, get the client that
4849*0Sstevel@tonic-gate 	 *	has allocated that window.
4850*0Sstevel@tonic-gate 	 */
4851*0Sstevel@tonic-gate 	if (!(cw = cs_find_window(wh))) {
4852*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
4853*0Sstevel@tonic-gate 	    return (CS_BAD_HANDLE);
4854*0Sstevel@tonic-gate 	}
4855*0Sstevel@tonic-gate 
4856*0Sstevel@tonic-gate 	/*
4857*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
4858*0Sstevel@tonic-gate 	 */
4859*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(cw->client_handle))) == NULL)
4860*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
4861*0Sstevel@tonic-gate 
4862*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
4863*0Sstevel@tonic-gate 
4864*0Sstevel@tonic-gate 	if (!(client = cs_find_client(cw->client_handle, &error))) {
4865*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4866*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
4867*0Sstevel@tonic-gate 	    return (error);
4868*0Sstevel@tonic-gate 	}
4869*0Sstevel@tonic-gate 
4870*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
4871*0Sstevel@tonic-gate 
4872*0Sstevel@tonic-gate 	/*
4873*0Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
4874*0Sstevel@tonic-gate 	 *	for this client, then return an error.
4875*0Sstevel@tonic-gate 	 */
4876*0Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
4877*0Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
4878*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4879*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
4880*0Sstevel@tonic-gate 	    return (CS_NO_CARD);
4881*0Sstevel@tonic-gate 	}
4882*0Sstevel@tonic-gate 
4883*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
4884*0Sstevel@tonic-gate 
4885*0Sstevel@tonic-gate 	mw->Attributes &= (
4886*0Sstevel@tonic-gate 				WIN_MEMORY_TYPE_MASK |
4887*0Sstevel@tonic-gate 				WIN_ENABLE |
4888*0Sstevel@tonic-gate 				WIN_ACCESS_SPEED_VALID |
4889*0Sstevel@tonic-gate 				WIN_ACC_ENDIAN_MASK |
4890*0Sstevel@tonic-gate 				WIN_ACC_ORDER_MASK);
4891*0Sstevel@tonic-gate 
4892*0Sstevel@tonic-gate 	mw->Attributes &= ~WIN_DATA_WIDTH_VALID;
4893*0Sstevel@tonic-gate 
4894*0Sstevel@tonic-gate 	if ((error = cs_modify_mem_window(wh, mw, NULL, NULL)) != CS_SUCCESS) {
4895*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4896*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
4897*0Sstevel@tonic-gate 	    return (error);
4898*0Sstevel@tonic-gate 	}
4899*0Sstevel@tonic-gate 
4900*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
4901*0Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
4902*0Sstevel@tonic-gate 
4903*0Sstevel@tonic-gate 	return (CS_SUCCESS);
4904*0Sstevel@tonic-gate }
4905*0Sstevel@tonic-gate 
4906*0Sstevel@tonic-gate /*
4907*0Sstevel@tonic-gate  * cs_modify_mem_window - modifies a window's characteristics; used internally
4908*0Sstevel@tonic-gate  *				by Card Services
4909*0Sstevel@tonic-gate  *
4910*0Sstevel@tonic-gate  *    If *wr is NULL, it means that we're being called by ModifyWindow
4911*0Sstevel@tonic-gate  *    If *wr is non-NULL, it means that we are being called by RequestWindow
4912*0Sstevel@tonic-gate  *	and so we can't use SS_GetWindow.
4913*0Sstevel@tonic-gate  */
4914*0Sstevel@tonic-gate static int
4915*0Sstevel@tonic-gate cs_modify_mem_window(window_handle_t wh, modify_win_t *mw,
4916*0Sstevel@tonic-gate 						win_req_t *wr, int sn)
4917*0Sstevel@tonic-gate {
4918*0Sstevel@tonic-gate 	get_window_t gw;
4919*0Sstevel@tonic-gate 	set_window_t sw;
4920*0Sstevel@tonic-gate 	set_page_t set_page;
4921*0Sstevel@tonic-gate 	get_page_t get_page;
4922*0Sstevel@tonic-gate 
4923*0Sstevel@tonic-gate 	/*
4924*0Sstevel@tonic-gate 	 * If the win_req_t struct pointer is NULL, it means that
4925*0Sstevel@tonic-gate 	 *	we're being called by ModifyWindow, so get the
4926*0Sstevel@tonic-gate 	 *	current window characteristics.
4927*0Sstevel@tonic-gate 	 */
4928*0Sstevel@tonic-gate 	if (!wr) {
4929*0Sstevel@tonic-gate 	    gw.window = GET_WINDOW_NUMBER(wh);
4930*0Sstevel@tonic-gate 	    if (SocketServices(SS_GetWindow, &gw) != SUCCESS)
4931*0Sstevel@tonic-gate 		return (CS_BAD_WINDOW);
4932*0Sstevel@tonic-gate 	    sw.state = gw.state;
4933*0Sstevel@tonic-gate 	    sw.socket = gw.socket;
4934*0Sstevel@tonic-gate 	    sw.WindowSize = gw.size;
4935*0Sstevel@tonic-gate 	} else {
4936*0Sstevel@tonic-gate 	    sw.state = 0;
4937*0Sstevel@tonic-gate 	    sw.socket = sn;
4938*0Sstevel@tonic-gate 	    sw.WindowSize = wr->Size;
4939*0Sstevel@tonic-gate 	}
4940*0Sstevel@tonic-gate 
4941*0Sstevel@tonic-gate 	/*
4942*0Sstevel@tonic-gate 	 * If we're being called by RequestWindow, we must always have
4943*0Sstevel@tonic-gate 	 *	WIN_ACCESS_SPEED_VALID set since get_window_t is not
4944*0Sstevel@tonic-gate 	 *	defined.
4945*0Sstevel@tonic-gate 	 */
4946*0Sstevel@tonic-gate 	if (mw->Attributes & WIN_ACCESS_SPEED_VALID) {
4947*0Sstevel@tonic-gate 	    convert_speed_t convert_speed;
4948*0Sstevel@tonic-gate 
4949*0Sstevel@tonic-gate 	    convert_speed.Attributes = CONVERT_DEVSPEED_TO_NS;
4950*0Sstevel@tonic-gate 	    convert_speed.devspeed = mw->AccessSpeed;
4951*0Sstevel@tonic-gate 
4952*0Sstevel@tonic-gate 	    if (cs_convert_speed(&convert_speed) != CS_SUCCESS)
4953*0Sstevel@tonic-gate 		return (CS_BAD_SPEED);
4954*0Sstevel@tonic-gate 
4955*0Sstevel@tonic-gate 	    sw.speed = convert_speed.nS;
4956*0Sstevel@tonic-gate 	} else {
4957*0Sstevel@tonic-gate 	    sw.speed = gw.speed;
4958*0Sstevel@tonic-gate 	}
4959*0Sstevel@tonic-gate 
4960*0Sstevel@tonic-gate 	if (!wr) {
4961*0Sstevel@tonic-gate 	    get_page.window = GET_WINDOW_NUMBER(wh);
4962*0Sstevel@tonic-gate 	    get_page.page = 0;
4963*0Sstevel@tonic-gate 	    if (SocketServices(SS_GetPage, &get_page) != SUCCESS)
4964*0Sstevel@tonic-gate 		return (CS_BAD_WINDOW);
4965*0Sstevel@tonic-gate 	    set_page.state = get_page.state;
4966*0Sstevel@tonic-gate 	    set_page.offset = get_page.offset;
4967*0Sstevel@tonic-gate 	} else {
4968*0Sstevel@tonic-gate 	    set_page.state = 0;
4969*0Sstevel@tonic-gate 	    set_page.offset = 0;
4970*0Sstevel@tonic-gate 	}
4971*0Sstevel@tonic-gate 
4972*0Sstevel@tonic-gate 	if (mw->Attributes & WIN_ENABLE) {
4973*0Sstevel@tonic-gate 	    sw.state |= WS_ENABLED;
4974*0Sstevel@tonic-gate 	    set_page.state |= PS_ENABLED;
4975*0Sstevel@tonic-gate 	} else {
4976*0Sstevel@tonic-gate 	    sw.state &= ~WS_ENABLED;
4977*0Sstevel@tonic-gate 	    set_page.state &= ~PS_ENABLED;
4978*0Sstevel@tonic-gate 	}
4979*0Sstevel@tonic-gate 
4980*0Sstevel@tonic-gate 	if (mw->Attributes & WIN_DATA_WIDTH_VALID) {
4981*0Sstevel@tonic-gate 	    if (mw->Attributes & WIN_DATA_WIDTH_16)
4982*0Sstevel@tonic-gate 		sw.state |= WS_16BIT;
4983*0Sstevel@tonic-gate 	    else
4984*0Sstevel@tonic-gate 		sw.state &= ~WS_16BIT;
4985*0Sstevel@tonic-gate 	}
4986*0Sstevel@tonic-gate 
4987*0Sstevel@tonic-gate 	sw.window = GET_WINDOW_NUMBER(wh);
4988*0Sstevel@tonic-gate 	sw.base = 0;
4989*0Sstevel@tonic-gate 
4990*0Sstevel@tonic-gate 	cs_set_acc_attributes(&sw, mw->Attributes);
4991*0Sstevel@tonic-gate 
4992*0Sstevel@tonic-gate 	if (SocketServices(SS_SetWindow, &sw) != SUCCESS)
4993*0Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
4994*0Sstevel@tonic-gate 
4995*0Sstevel@tonic-gate 	if (mw->Attributes & WIN_MEMORY_TYPE_AM)
4996*0Sstevel@tonic-gate 	    set_page.state |= PS_ATTRIBUTE;
4997*0Sstevel@tonic-gate 	else
4998*0Sstevel@tonic-gate 	    set_page.state &= ~PS_ATTRIBUTE;
4999*0Sstevel@tonic-gate 
5000*0Sstevel@tonic-gate 	set_page.window = GET_WINDOW_NUMBER(wh);
5001*0Sstevel@tonic-gate 	set_page.page = 0;
5002*0Sstevel@tonic-gate 	if (SocketServices(SS_SetPage, &set_page) != SUCCESS)
5003*0Sstevel@tonic-gate 	    return (CS_BAD_OFFSET);
5004*0Sstevel@tonic-gate 
5005*0Sstevel@tonic-gate 	/*
5006*0Sstevel@tonic-gate 	 * Return the current base address of this window
5007*0Sstevel@tonic-gate 	 */
5008*0Sstevel@tonic-gate 	if (wr) {
5009*0Sstevel@tonic-gate 	    gw.window = GET_WINDOW_NUMBER(wh);
5010*0Sstevel@tonic-gate 	    if (SocketServices(SS_GetWindow, &gw) != SUCCESS)
5011*0Sstevel@tonic-gate 		return (CS_BAD_WINDOW);
5012*0Sstevel@tonic-gate 
5013*0Sstevel@tonic-gate 	    wr->Base.handle = (acc_handle_t)gw.handle;
5014*0Sstevel@tonic-gate 	}
5015*0Sstevel@tonic-gate 
5016*0Sstevel@tonic-gate 	return (CS_SUCCESS);
5017*0Sstevel@tonic-gate }
5018*0Sstevel@tonic-gate 
5019*0Sstevel@tonic-gate /*
5020*0Sstevel@tonic-gate  * cs_map_mem_page - sets the card offset of the mapped window
5021*0Sstevel@tonic-gate  */
5022*0Sstevel@tonic-gate static int
5023*0Sstevel@tonic-gate cs_map_mem_page(window_handle_t wh, map_mem_page_t *mmp)
5024*0Sstevel@tonic-gate {
5025*0Sstevel@tonic-gate 	cs_socket_t *sp;
5026*0Sstevel@tonic-gate 	cs_window_t *cw;
5027*0Sstevel@tonic-gate 	client_t *client;
5028*0Sstevel@tonic-gate 	inquire_window_t iw;
5029*0Sstevel@tonic-gate 	get_window_t gw;
5030*0Sstevel@tonic-gate 	set_page_t set_page;
5031*0Sstevel@tonic-gate 	get_page_t get_page;
5032*0Sstevel@tonic-gate 	int error;
5033*0Sstevel@tonic-gate 	uint32_t size;
5034*0Sstevel@tonic-gate 	int client_lock_acquired;
5035*0Sstevel@tonic-gate 
5036*0Sstevel@tonic-gate 	/*
5037*0Sstevel@tonic-gate 	 * We don't support paged windows, so never allow a page number
5038*0Sstevel@tonic-gate 	 *	of other than 0
5039*0Sstevel@tonic-gate 	 */
5040*0Sstevel@tonic-gate 	if (mmp->Page)
5041*0Sstevel@tonic-gate 	    return (CS_BAD_PAGE);
5042*0Sstevel@tonic-gate 
5043*0Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
5044*0Sstevel@tonic-gate 
5045*0Sstevel@tonic-gate 	/*
5046*0Sstevel@tonic-gate 	 * Do some sanity checking - make sure that we can find a pointer
5047*0Sstevel@tonic-gate 	 *	to the window structure, and if we can, get the client that
5048*0Sstevel@tonic-gate 	 *	has allocated that window.
5049*0Sstevel@tonic-gate 	 */
5050*0Sstevel@tonic-gate 	if (!(cw = cs_find_window(wh))) {
5051*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
5052*0Sstevel@tonic-gate 	    return (CS_BAD_HANDLE);
5053*0Sstevel@tonic-gate 	}
5054*0Sstevel@tonic-gate 
5055*0Sstevel@tonic-gate 	/*
5056*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
5057*0Sstevel@tonic-gate 	 */
5058*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(cw->client_handle))) == NULL)
5059*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
5060*0Sstevel@tonic-gate 
5061*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
5062*0Sstevel@tonic-gate 
5063*0Sstevel@tonic-gate 	if (!(client = cs_find_client(cw->client_handle, &error))) {
5064*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5065*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
5066*0Sstevel@tonic-gate 	    return (error);
5067*0Sstevel@tonic-gate 	}
5068*0Sstevel@tonic-gate 
5069*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
5070*0Sstevel@tonic-gate 
5071*0Sstevel@tonic-gate 	/*
5072*0Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
5073*0Sstevel@tonic-gate 	 *	for this client, then return an error.
5074*0Sstevel@tonic-gate 	 */
5075*0Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
5076*0Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
5077*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5078*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
5079*0Sstevel@tonic-gate 	    return (CS_NO_CARD);
5080*0Sstevel@tonic-gate 	}
5081*0Sstevel@tonic-gate 
5082*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
5083*0Sstevel@tonic-gate 
5084*0Sstevel@tonic-gate 	gw.window = GET_WINDOW_NUMBER(wh);
5085*0Sstevel@tonic-gate 	SocketServices(SS_GetWindow, &gw);
5086*0Sstevel@tonic-gate 
5087*0Sstevel@tonic-gate 	iw.window = GET_WINDOW_NUMBER(wh);
5088*0Sstevel@tonic-gate 	SocketServices(SS_InquireWindow, &iw);
5089*0Sstevel@tonic-gate 
5090*0Sstevel@tonic-gate 	if (iw.mem_win_char.MemWndCaps & WC_CALIGN)
5091*0Sstevel@tonic-gate 	    size = gw.size;
5092*0Sstevel@tonic-gate 	else
5093*0Sstevel@tonic-gate 	    size = iw.mem_win_char.ReqOffset;
5094*0Sstevel@tonic-gate 
5095*0Sstevel@tonic-gate 	if (((mmp->CardOffset/size)*size) != mmp->CardOffset) {
5096*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5097*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
5098*0Sstevel@tonic-gate 	    return (CS_BAD_OFFSET);
5099*0Sstevel@tonic-gate 	}
5100*0Sstevel@tonic-gate 
5101*0Sstevel@tonic-gate 	get_page.window = GET_WINDOW_NUMBER(wh);
5102*0Sstevel@tonic-gate 	get_page.page = 0;
5103*0Sstevel@tonic-gate 	SocketServices(SS_GetPage, &get_page);
5104*0Sstevel@tonic-gate 
5105*0Sstevel@tonic-gate 	set_page.window = GET_WINDOW_NUMBER(wh);
5106*0Sstevel@tonic-gate 	set_page.page = 0;
5107*0Sstevel@tonic-gate 	set_page.state = get_page.state;
5108*0Sstevel@tonic-gate 	set_page.offset = mmp->CardOffset;
5109*0Sstevel@tonic-gate 	if (SocketServices(SS_SetPage, &set_page) != SUCCESS) {
5110*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5111*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
5112*0Sstevel@tonic-gate 	    return (CS_BAD_OFFSET);
5113*0Sstevel@tonic-gate 	}
5114*0Sstevel@tonic-gate 
5115*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5116*0Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
5117*0Sstevel@tonic-gate 
5118*0Sstevel@tonic-gate 	return (CS_SUCCESS);
5119*0Sstevel@tonic-gate }
5120*0Sstevel@tonic-gate 
5121*0Sstevel@tonic-gate /*
5122*0Sstevel@tonic-gate  * cs_find_window - finds the window associated with the passed window
5123*0Sstevel@tonic-gate  *			handle; if the window handle is invalid or no
5124*0Sstevel@tonic-gate  *			windows match the passed window handle, NULL
5125*0Sstevel@tonic-gate  *			is returned.  Note that the window must be
5126*0Sstevel@tonic-gate  *			allocated for this function to return a valid
5127*0Sstevel@tonic-gate  *			window pointer.
5128*0Sstevel@tonic-gate  *
5129*0Sstevel@tonic-gate  *	returns: cs_window_t * pointer to the found window
5130*0Sstevel@tonic-gate  *		 NULL if window handle invalid or window not allocated
5131*0Sstevel@tonic-gate  */
5132*0Sstevel@tonic-gate cs_window_t *
5133*0Sstevel@tonic-gate cs_find_window(window_handle_t wh)
5134*0Sstevel@tonic-gate {
5135*0Sstevel@tonic-gate 	cs_window_t *cw;
5136*0Sstevel@tonic-gate 
5137*0Sstevel@tonic-gate 	if ((GET_WINDOW_NUMBER(wh) > cs_globals.num_windows) ||
5138*0Sstevel@tonic-gate 			(GET_WINDOW_MAGIC(wh) != WINDOW_HANDLE_MAGIC))
5139*0Sstevel@tonic-gate 	    return ((cs_window_t *)NULL);
5140*0Sstevel@tonic-gate 
5141*0Sstevel@tonic-gate 	if ((cw = cs_get_wp(GET_WINDOW_NUMBER(wh))) == NULL)
5142*0Sstevel@tonic-gate 	    return (NULL);
5143*0Sstevel@tonic-gate 
5144*0Sstevel@tonic-gate 	if ((cw->state & CW_ALLOCATED) && (cw->state & CW_MEM))
5145*0Sstevel@tonic-gate 	    return (cw);
5146*0Sstevel@tonic-gate 
5147*0Sstevel@tonic-gate 	return ((cs_window_t *)NULL);
5148*0Sstevel@tonic-gate }
5149*0Sstevel@tonic-gate 
5150*0Sstevel@tonic-gate /*
5151*0Sstevel@tonic-gate  * cs_create_window_handle - creates a unique window handle based on the
5152*0Sstevel@tonic-gate  *				passed window number.
5153*0Sstevel@tonic-gate  */
5154*0Sstevel@tonic-gate static window_handle_t
5155*0Sstevel@tonic-gate cs_create_window_handle(uint32_t aw)
5156*0Sstevel@tonic-gate {
5157*0Sstevel@tonic-gate 	return (WINDOW_HANDLE_MAGIC | (aw & WINDOW_HANDLE_MASK));
5158*0Sstevel@tonic-gate }
5159*0Sstevel@tonic-gate 
5160*0Sstevel@tonic-gate /*
5161*0Sstevel@tonic-gate  * cs_find_mem_window - tries to find a memory window matching the caller's
5162*0Sstevel@tonic-gate  *			criteria
5163*0Sstevel@tonic-gate  *
5164*0Sstevel@tonic-gate  *	We return the first window that matches the requested criteria.
5165*0Sstevel@tonic-gate  *
5166*0Sstevel@tonic-gate  *	returns: CS_SUCCESS - if memory window found
5167*0Sstevel@tonic-gate  *		 CS_OUT_OF_RESOURCE - if no windows match requirements
5168*0Sstevel@tonic-gate  *		 CS_BAD_SIZE - if requested size can not be met
5169*0Sstevel@tonic-gate  *		 CS_BAD_WINDOW - if an internal error occured
5170*0Sstevel@tonic-gate  */
5171*0Sstevel@tonic-gate /* BEGIN CSTYLED */
5172*0Sstevel@tonic-gate static int
5173*0Sstevel@tonic-gate cs_find_mem_window(uint32_t sn, win_req_t *rw, uint32_t *assigned_window)
5174*0Sstevel@tonic-gate {
5175*0Sstevel@tonic-gate 	uint32_t wn;
5176*0Sstevel@tonic-gate 	int error = CS_OUT_OF_RESOURCE;
5177*0Sstevel@tonic-gate 	uint32_t window_num = PCMCIA_MAX_WINDOWS;
5178*0Sstevel@tonic-gate 	uint32_t min_size = UINT_MAX;
5179*0Sstevel@tonic-gate 	inquire_window_t inquire_window, *iw;
5180*0Sstevel@tonic-gate 	uint32_t MinSize, MaxSize, ReqGran, MemWndCaps, WndCaps;
5181*0Sstevel@tonic-gate 	uint32_t tws;
5182*0Sstevel@tonic-gate 
5183*0Sstevel@tonic-gate 	iw = &inquire_window;
5184*0Sstevel@tonic-gate 
5185*0Sstevel@tonic-gate 	for (wn = 0; wn < cs_globals.num_windows; wn++) {
5186*0Sstevel@tonic-gate 	    cs_window_t *cw;
5187*0Sstevel@tonic-gate 
5188*0Sstevel@tonic-gate 	    /*
5189*0Sstevel@tonic-gate 	     * If we can't get a pointer to this window, we should contine
5190*0Sstevel@tonic-gate 	     *	with scanning the next window, since this window might have
5191*0Sstevel@tonic-gate 	     *	been dropped.
5192*0Sstevel@tonic-gate 	     */
5193*0Sstevel@tonic-gate 	    if ((cw = cs_get_wp(wn)) != NULL) {
5194*0Sstevel@tonic-gate 	      iw->window = wn;
5195*0Sstevel@tonic-gate 
5196*0Sstevel@tonic-gate 	      if (SocketServices(SS_InquireWindow, iw) != SUCCESS)
5197*0Sstevel@tonic-gate 		return (CS_BAD_WINDOW);
5198*0Sstevel@tonic-gate 
5199*0Sstevel@tonic-gate 	      MinSize = iw->mem_win_char.MinSize;
5200*0Sstevel@tonic-gate 	      MaxSize = iw->mem_win_char.MaxSize;
5201*0Sstevel@tonic-gate 	      ReqGran = iw->mem_win_char.ReqGran;
5202*0Sstevel@tonic-gate 	      MemWndCaps = iw->mem_win_char.MemWndCaps;
5203*0Sstevel@tonic-gate 	      WndCaps = iw->WndCaps;
5204*0Sstevel@tonic-gate 
5205*0Sstevel@tonic-gate 	      if (WINDOW_FOR_SOCKET(iw->Sockets, sn) &&
5206*0Sstevel@tonic-gate 					WINDOW_AVAILABLE_FOR_MEM(cw) &&
5207*0Sstevel@tonic-gate 					WndCaps & (WC_COMMON|WC_ATTRIBUTE)) {
5208*0Sstevel@tonic-gate 		if ((error = cs_valid_window_speed(iw, rw->win_params.AccessSpeed)) ==
5209*0Sstevel@tonic-gate 					CS_SUCCESS) {
5210*0Sstevel@tonic-gate 		    error = CS_OUT_OF_RESOURCE;
5211*0Sstevel@tonic-gate 		    if (cs_memwin_space_and_map_ok(iw, rw)) {
5212*0Sstevel@tonic-gate 			error = CS_BAD_SIZE;
5213*0Sstevel@tonic-gate 			if (!rw->Size) {
5214*0Sstevel@tonic-gate 			    min_size = min(min_size, MinSize);
5215*0Sstevel@tonic-gate 			    window_num = wn;
5216*0Sstevel@tonic-gate 			    goto found_window;
5217*0Sstevel@tonic-gate 			} else {
5218*0Sstevel@tonic-gate 			    if (!(MemWndCaps & WC_SIZE)) {
5219*0Sstevel@tonic-gate 				if (rw->Size == MinSize) {
5220*0Sstevel@tonic-gate 				    min_size = MinSize;
5221*0Sstevel@tonic-gate 				    window_num = wn;
5222*0Sstevel@tonic-gate 				    goto found_window;
5223*0Sstevel@tonic-gate 				}
5224*0Sstevel@tonic-gate 			    } else { /* WC_SIZE */
5225*0Sstevel@tonic-gate 			      if (!ReqGran) {
5226*0Sstevel@tonic-gate 				error = CS_BAD_WINDOW;
5227*0Sstevel@tonic-gate 			      } else {
5228*0Sstevel@tonic-gate 				if ((rw->Size >= MinSize) &&
5229*0Sstevel@tonic-gate 							(rw->Size <= MaxSize)) {
5230*0Sstevel@tonic-gate 				    if (MemWndCaps & WC_POW2) {
5231*0Sstevel@tonic-gate 				      unsigned rg = ReqGran;
5232*0Sstevel@tonic-gate 					for (tws = MinSize; tws <= MaxSize;
5233*0Sstevel@tonic-gate 								rg = (rg<<1)) {
5234*0Sstevel@tonic-gate 					    if (rw->Size == tws) {
5235*0Sstevel@tonic-gate 						min_size = tws;
5236*0Sstevel@tonic-gate 						window_num = wn;
5237*0Sstevel@tonic-gate 						goto found_window;
5238*0Sstevel@tonic-gate 					    }
5239*0Sstevel@tonic-gate 					    tws += rg;
5240*0Sstevel@tonic-gate 					  } /* for (tws) */
5241*0Sstevel@tonic-gate 				    } else {
5242*0Sstevel@tonic-gate 					for (tws = MinSize; tws <= MaxSize;
5243*0Sstevel@tonic-gate 							tws += ReqGran) {
5244*0Sstevel@tonic-gate 					    if (rw->Size == tws) {
5245*0Sstevel@tonic-gate 						min_size = tws;
5246*0Sstevel@tonic-gate 						window_num = wn;
5247*0Sstevel@tonic-gate 						goto found_window;
5248*0Sstevel@tonic-gate 					    }
5249*0Sstevel@tonic-gate 					  } /* for (tws) */
5250*0Sstevel@tonic-gate 				    } /* if (!WC_POW2) */
5251*0Sstevel@tonic-gate 				} /* if (Size >= MinSize) */
5252*0Sstevel@tonic-gate 			      } /* if (!ReqGran) */
5253*0Sstevel@tonic-gate 			    } /* if (WC_SIZE) */
5254*0Sstevel@tonic-gate 			} /* if (rw->Size) */
5255*0Sstevel@tonic-gate 		    } /* if (cs_space_and_map_ok) */
5256*0Sstevel@tonic-gate 		} /* if (cs_valid_window_speed) */
5257*0Sstevel@tonic-gate 	      } /* if (WINDOW_FOR_SOCKET) */
5258*0Sstevel@tonic-gate 	    } /* if (cs_get_wp) */
5259*0Sstevel@tonic-gate 	} /* for (wn) */
5260*0Sstevel@tonic-gate 
5261*0Sstevel@tonic-gate 	/*
5262*0Sstevel@tonic-gate 	 * If we got here and the window_num wasn't set by any window
5263*0Sstevel@tonic-gate 	 *	 matches in the above code, it means that we didn't
5264*0Sstevel@tonic-gate 	 *	find a window matching the caller's criteria.
5265*0Sstevel@tonic-gate 	 * If the error is CS_BAD_TYPE, it means that the last reason
5266*0Sstevel@tonic-gate 	 *	that we couldn't match a window was because the caller's
5267*0Sstevel@tonic-gate 	 *	requested speed was out of range of the last window that
5268*0Sstevel@tonic-gate 	 *	we checked.  We convert this error code to CS_OUT_OF_RESOURCE
5269*0Sstevel@tonic-gate 	 *	to conform to the RequestWindow section of the PCMCIA
5270*0Sstevel@tonic-gate 	 *	Card Services spec.
5271*0Sstevel@tonic-gate 	 */
5272*0Sstevel@tonic-gate 	if (window_num == PCMCIA_MAX_WINDOWS) {
5273*0Sstevel@tonic-gate 	    if (error == CS_BAD_TYPE)
5274*0Sstevel@tonic-gate 		error = CS_OUT_OF_RESOURCE;
5275*0Sstevel@tonic-gate 	    return (error);
5276*0Sstevel@tonic-gate 	}
5277*0Sstevel@tonic-gate 
5278*0Sstevel@tonic-gate found_window:
5279*0Sstevel@tonic-gate 	rw->Size = min_size;
5280*0Sstevel@tonic-gate 	*assigned_window = window_num;
5281*0Sstevel@tonic-gate 	iw->window = window_num;
5282*0Sstevel@tonic-gate 	SocketServices(SS_InquireWindow, iw);
5283*0Sstevel@tonic-gate 	MemWndCaps = iw->mem_win_char.MemWndCaps;
5284*0Sstevel@tonic-gate 
5285*0Sstevel@tonic-gate 	if (MemWndCaps & WC_CALIGN)
5286*0Sstevel@tonic-gate 	    rw->Attributes |= WIN_OFFSET_SIZE;
5287*0Sstevel@tonic-gate 	else
5288*0Sstevel@tonic-gate 	    rw->Attributes &= ~WIN_OFFSET_SIZE;
5289*0Sstevel@tonic-gate 	return (CS_SUCCESS);
5290*0Sstevel@tonic-gate }
5291*0Sstevel@tonic-gate /* END CSTYLED */
5292*0Sstevel@tonic-gate 
5293*0Sstevel@tonic-gate /*
5294*0Sstevel@tonic-gate  * cs_memwin_space_and_map_ok - checks to see if the passed window mapping
5295*0Sstevel@tonic-gate  *				capabilities and window speeds are in the
5296*0Sstevel@tonic-gate  *				range of the passed window.
5297*0Sstevel@tonic-gate  *
5298*0Sstevel@tonic-gate  *	returns: 0 - if the capabilities are out of range
5299*0Sstevel@tonic-gate  *		 1 - if the capabilities are in range
5300*0Sstevel@tonic-gate  */
5301*0Sstevel@tonic-gate static int
5302*0Sstevel@tonic-gate cs_memwin_space_and_map_ok(inquire_window_t *iw, win_req_t *rw)
5303*0Sstevel@tonic-gate {
5304*0Sstevel@tonic-gate 
5305*0Sstevel@tonic-gate #ifdef	CS_DEBUG
5306*0Sstevel@tonic-gate 	if (cs_debug > 240)
5307*0Sstevel@tonic-gate 	    printf("-> s&m_ok: Attributes 0x%x AccessSpeed 0x%x "
5308*0Sstevel@tonic-gate 					"WndCaps 0x%x MemWndCaps 0x%x\n",
5309*0Sstevel@tonic-gate 					(int)rw->Attributes,
5310*0Sstevel@tonic-gate 					(int)rw->win_params.AccessSpeed,
5311*0Sstevel@tonic-gate 					iw->WndCaps,
5312*0Sstevel@tonic-gate 					iw->mem_win_char.MemWndCaps);
5313*0Sstevel@tonic-gate #endif
5314*0Sstevel@tonic-gate 
5315*0Sstevel@tonic-gate 	if (rw->win_params.AccessSpeed & WIN_USE_WAIT) {
5316*0Sstevel@tonic-gate 	    if (!(iw->WndCaps & WC_WAIT))
5317*0Sstevel@tonic-gate 		return (0);
5318*0Sstevel@tonic-gate 	}
5319*0Sstevel@tonic-gate 
5320*0Sstevel@tonic-gate 	if (rw->Attributes & WIN_DATA_WIDTH_16) {
5321*0Sstevel@tonic-gate 	    if (!(iw->mem_win_char.MemWndCaps & WC_16BIT))
5322*0Sstevel@tonic-gate 		return (0);
5323*0Sstevel@tonic-gate 	} else {
5324*0Sstevel@tonic-gate 	    if (!(iw->mem_win_char.MemWndCaps & WC_8BIT))
5325*0Sstevel@tonic-gate 		return (0);
5326*0Sstevel@tonic-gate 	}
5327*0Sstevel@tonic-gate 
5328*0Sstevel@tonic-gate 	if (rw->Attributes & WIN_MEMORY_TYPE_AM) {
5329*0Sstevel@tonic-gate 	    if (!(iw->WndCaps & WC_ATTRIBUTE))
5330*0Sstevel@tonic-gate 		return (0);
5331*0Sstevel@tonic-gate 	}
5332*0Sstevel@tonic-gate 
5333*0Sstevel@tonic-gate 	if (rw->Attributes & WIN_MEMORY_TYPE_CM) {
5334*0Sstevel@tonic-gate 	    if (!(iw->WndCaps & WC_COMMON))
5335*0Sstevel@tonic-gate 		return (0);
5336*0Sstevel@tonic-gate 	}
5337*0Sstevel@tonic-gate 
5338*0Sstevel@tonic-gate 	return (1);
5339*0Sstevel@tonic-gate }
5340*0Sstevel@tonic-gate 
5341*0Sstevel@tonic-gate /*
5342*0Sstevel@tonic-gate  * cs_valid_window_speed - checks to see if requested window speed
5343*0Sstevel@tonic-gate  *				is in range of passed window
5344*0Sstevel@tonic-gate  *
5345*0Sstevel@tonic-gate  *	The inquire_window_t struct gives us speeds in nS, and we
5346*0Sstevel@tonic-gate  *	get speeds in the AccessSpeed variable as a devspeed code.
5347*0Sstevel@tonic-gate  *
5348*0Sstevel@tonic-gate  *	returns: CS_BAD_SPEED - if AccessSpeed is invalid devspeed code
5349*0Sstevel@tonic-gate  *		 CS_BAD_TYPE -	if AccessSpeed is not in range of valid
5350*0Sstevel@tonic-gate  *				speed for this window
5351*0Sstevel@tonic-gate  *		 CS_SUCCESS -	if window speed is in range
5352*0Sstevel@tonic-gate  */
5353*0Sstevel@tonic-gate static int
5354*0Sstevel@tonic-gate cs_valid_window_speed(inquire_window_t *iw, uint32_t AccessSpeed)
5355*0Sstevel@tonic-gate {
5356*0Sstevel@tonic-gate 	convert_speed_t convert_speed, *cs;
5357*0Sstevel@tonic-gate 
5358*0Sstevel@tonic-gate 	cs = &convert_speed;
5359*0Sstevel@tonic-gate 
5360*0Sstevel@tonic-gate 	cs->Attributes = CONVERT_DEVSPEED_TO_NS;
5361*0Sstevel@tonic-gate 	cs->devspeed = AccessSpeed;
5362*0Sstevel@tonic-gate 
5363*0Sstevel@tonic-gate 	if (cs_convert_speed(cs) != CS_SUCCESS)
5364*0Sstevel@tonic-gate 	    return (CS_BAD_SPEED);
5365*0Sstevel@tonic-gate 
5366*0Sstevel@tonic-gate 	if ((cs->nS < iw->mem_win_char.Fastest) ||
5367*0Sstevel@tonic-gate 		(cs->nS > iw->mem_win_char.Slowest))
5368*0Sstevel@tonic-gate 	    return (CS_BAD_TYPE);
5369*0Sstevel@tonic-gate 
5370*0Sstevel@tonic-gate 	return (CS_SUCCESS);
5371*0Sstevel@tonic-gate }
5372*0Sstevel@tonic-gate 
5373*0Sstevel@tonic-gate /*
5374*0Sstevel@tonic-gate  * ==== IO window handling section ====
5375*0Sstevel@tonic-gate  */
5376*0Sstevel@tonic-gate 
5377*0Sstevel@tonic-gate /*
5378*0Sstevel@tonic-gate  * cs_request_io - provides IO resources for clients; this is RequestIO
5379*0Sstevel@tonic-gate  *
5380*0Sstevel@tonic-gate  *	calling: cs_request_io(client_handle_t, io_req_t *)
5381*0Sstevel@tonic-gate  *
5382*0Sstevel@tonic-gate  *	returns: CS_SUCCESS - if IO resources available for client
5383*0Sstevel@tonic-gate  *		 CS_OUT_OF_RESOURCE - if no windows match requirements
5384*0Sstevel@tonic-gate  *		 CS_BAD_HANDLE - client handle is invalid
5385*0Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
5386*0Sstevel@tonic-gate  *		 CS_NO_CARD - if no card is in socket
5387*0Sstevel@tonic-gate  *		 CS_BAD_ATTRIBUTE - if any of the unsupported Attribute
5388*0Sstevel@tonic-gate  *					flags are set
5389*0Sstevel@tonic-gate  *		 CS_BAD_BASE - if either or both base port addresses
5390*0Sstevel@tonic-gate  *					are invalid or out of range
5391*0Sstevel@tonic-gate  *		 CS_CONFIGURATION_LOCKED - a RequestConfiguration has
5392*0Sstevel@tonic-gate  *					already been done
5393*0Sstevel@tonic-gate  *		 CS_IN_USE - IO ports already in use or function has
5394*0Sstevel@tonic-gate  *					already been called
5395*0Sstevel@tonic-gate  *		 CS_BAD_WINDOW - if failure while trying to set window
5396*0Sstevel@tonic-gate  *					characteristics
5397*0Sstevel@tonic-gate  */
5398*0Sstevel@tonic-gate static int
5399*0Sstevel@tonic-gate cs_request_io(client_handle_t client_handle, io_req_t *ior)
5400*0Sstevel@tonic-gate {
5401*0Sstevel@tonic-gate 	cs_socket_t *sp;
5402*0Sstevel@tonic-gate 	client_t *client;
5403*0Sstevel@tonic-gate 	int error;
5404*0Sstevel@tonic-gate 	int client_lock_acquired;
5405*0Sstevel@tonic-gate 	uint32_t socket_num;
5406*0Sstevel@tonic-gate 
5407*0Sstevel@tonic-gate 	/*
5408*0Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
5409*0Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
5410*0Sstevel@tonic-gate 	 */
5411*0Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
5412*0Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
5413*0Sstevel@tonic-gate 
5414*0Sstevel@tonic-gate 	/*
5415*0Sstevel@tonic-gate 	 * If the client has only requested one IO range, then make sure
5416*0Sstevel@tonic-gate 	 *	that the Attributes2 filed is clear.
5417*0Sstevel@tonic-gate 	 */
5418*0Sstevel@tonic-gate 	if (!ior->NumPorts2)
5419*0Sstevel@tonic-gate 	    ior->Attributes2 = 0;
5420*0Sstevel@tonic-gate 
5421*0Sstevel@tonic-gate 	/*
5422*0Sstevel@tonic-gate 	 * Make sure that none of the unsupported or reserved flags are set.
5423*0Sstevel@tonic-gate 	 */
5424*0Sstevel@tonic-gate 	if ((ior->Attributes1 | ior->Attributes2) &    (IO_SHARED |
5425*0Sstevel@tonic-gate 							IO_FIRST_SHARED |
5426*0Sstevel@tonic-gate 							IO_FORCE_ALIAS_ACCESS |
5427*0Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
5428*0Sstevel@tonic-gate 							IO_DISABLE_WINDOW))
5429*0Sstevel@tonic-gate 	    return (CS_BAD_ATTRIBUTE);
5430*0Sstevel@tonic-gate 
5431*0Sstevel@tonic-gate 	/*
5432*0Sstevel@tonic-gate 	 * Make sure that we have a port count for the first region.
5433*0Sstevel@tonic-gate 	 */
5434*0Sstevel@tonic-gate 	if (!ior->NumPorts1)
5435*0Sstevel@tonic-gate 	    return (CS_BAD_BASE);
5436*0Sstevel@tonic-gate 
5437*0Sstevel@tonic-gate 	/*
5438*0Sstevel@tonic-gate 	 * If we're being asked for multiple IO ranges, then both base port
5439*0Sstevel@tonic-gate 	 *	members must be non-zero.
5440*0Sstevel@tonic-gate 	 */
5441*0Sstevel@tonic-gate 	if ((ior->NumPorts2) && !(ior->BasePort1.base && ior->BasePort2.base))
5442*0Sstevel@tonic-gate 	    return (CS_BAD_BASE);
5443*0Sstevel@tonic-gate 
5444*0Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
5445*0Sstevel@tonic-gate 
5446*0Sstevel@tonic-gate 	/*
5447*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
5448*0Sstevel@tonic-gate 	 */
5449*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
5450*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
5451*0Sstevel@tonic-gate 
5452*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
5453*0Sstevel@tonic-gate 
5454*0Sstevel@tonic-gate 	/*
5455*0Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
5456*0Sstevel@tonic-gate 	 */
5457*0Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
5458*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5459*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
5460*0Sstevel@tonic-gate 	    return (error);
5461*0Sstevel@tonic-gate 	}
5462*0Sstevel@tonic-gate 
5463*0Sstevel@tonic-gate 	/*
5464*0Sstevel@tonic-gate 	 * If RequestConfiguration has already been done, we don't allow
5465*0Sstevel@tonic-gate 	 *	this call.
5466*0Sstevel@tonic-gate 	 */
5467*0Sstevel@tonic-gate 	if (client->flags & REQ_CONFIGURATION_DONE) {
5468*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5469*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
5470*0Sstevel@tonic-gate 	    return (CS_CONFIGURATION_LOCKED);
5471*0Sstevel@tonic-gate 	}
5472*0Sstevel@tonic-gate 
5473*0Sstevel@tonic-gate 	/*
5474*0Sstevel@tonic-gate 	 * If RequestIO has already been done, we don't allow this call.
5475*0Sstevel@tonic-gate 	 */
5476*0Sstevel@tonic-gate 	if (client->flags & REQ_IO_DONE) {
5477*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5478*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
5479*0Sstevel@tonic-gate 	    return (CS_IN_USE);
5480*0Sstevel@tonic-gate 	}
5481*0Sstevel@tonic-gate 
5482*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
5483*0Sstevel@tonic-gate 
5484*0Sstevel@tonic-gate 	/*
5485*0Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
5486*0Sstevel@tonic-gate 	 *	for this client, then return an error.
5487*0Sstevel@tonic-gate 	 */
5488*0Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
5489*0Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
5490*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5491*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
5492*0Sstevel@tonic-gate 	    return (CS_NO_CARD);
5493*0Sstevel@tonic-gate 	}
5494*0Sstevel@tonic-gate 
5495*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
5496*0Sstevel@tonic-gate 
5497*0Sstevel@tonic-gate 	/*
5498*0Sstevel@tonic-gate 	 * If we're only being asked for one IO range, then set BasePort2 to
5499*0Sstevel@tonic-gate 	 *	zero, since we use it later on.
5500*0Sstevel@tonic-gate 	 */
5501*0Sstevel@tonic-gate 	if (!ior->NumPorts2)
5502*0Sstevel@tonic-gate 	    ior->BasePort2.base = 0;
5503*0Sstevel@tonic-gate 
5504*0Sstevel@tonic-gate 	/*
5505*0Sstevel@tonic-gate 	 * See if we can allow Card Services to select the base address
5506*0Sstevel@tonic-gate 	 *	value for this card; if the client has specified a non-zero
5507*0Sstevel@tonic-gate 	 *	base IO address but the card doesn't decode enough IO
5508*0Sstevel@tonic-gate 	 *	address lines to uniquely use that address, then we have
5509*0Sstevel@tonic-gate 	 *	the flexibility to choose an alternative base address.
5510*0Sstevel@tonic-gate 	 * Note that if the client specifies that the card decodes zero
5511*0Sstevel@tonic-gate 	 *	IO address lines, then we have to use the NumPortsX
5512*0Sstevel@tonic-gate 	 *	values to figure out how many address lines the card
5513*0Sstevel@tonic-gate 	 *	actually decodes, and we have to round the NumPortsX
5514*0Sstevel@tonic-gate 	 *	values up to the closest power of two.
5515*0Sstevel@tonic-gate 	 */
5516*0Sstevel@tonic-gate 	if (ior->IOAddrLines) {
5517*0Sstevel@tonic-gate 	    ior->BasePort1.base = IOADDR_FROBNITZ(ior->BasePort1.base,
5518*0Sstevel@tonic-gate 		ior->IOAddrLines);
5519*0Sstevel@tonic-gate 	    ior->BasePort2.base = IOADDR_FROBNITZ(ior->BasePort2.base,
5520*0Sstevel@tonic-gate 		ior->IOAddrLines);
5521*0Sstevel@tonic-gate 	} else {
5522*0Sstevel@tonic-gate 	    ior->BasePort1.base = ior->BasePort1.base &
5523*0Sstevel@tonic-gate 				((IONUMPORTS_FROBNITZ(ior->NumPorts1) +
5524*0Sstevel@tonic-gate 				IONUMPORTS_FROBNITZ(ior->NumPorts2)) - 1);
5525*0Sstevel@tonic-gate 	    ior->BasePort2.base = ior->BasePort2.base &
5526*0Sstevel@tonic-gate 				((IONUMPORTS_FROBNITZ(ior->NumPorts1) +
5527*0Sstevel@tonic-gate 				IONUMPORTS_FROBNITZ(ior->NumPorts2)) - 1);
5528*0Sstevel@tonic-gate 	}
5529*0Sstevel@tonic-gate 
5530*0Sstevel@tonic-gate 	socket_num = CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
5531*0Sstevel@tonic-gate 	    GET_CLIENT_FUNCTION(client_handle));
5532*0Sstevel@tonic-gate 
5533*0Sstevel@tonic-gate 
5534*0Sstevel@tonic-gate #ifdef	USE_IOMMAP_WINDOW
5535*0Sstevel@tonic-gate 	/*
5536*0Sstevel@tonic-gate 	 * Here is where the code diverges, depending on the type of IO windows
5537*0Sstevel@tonic-gate 	 *	that this socket supports.  If this socket supportes memory
5538*0Sstevel@tonic-gate 	 *	mapped IO windows, as determined by cs_init allocating an
5539*0Sstevel@tonic-gate 	 *	io_mmap_window_t structure on the socket structure, then we
5540*0Sstevel@tonic-gate 	 *	use one IO window for all the clients on this socket.  We can
5541*0Sstevel@tonic-gate 	 *	do this safely since a memory mapped IO window implies that
5542*0Sstevel@tonic-gate 	 *	only this socket shares the complete IO space of the card.
5543*0Sstevel@tonic-gate 	 * See the next major block of code for a description of what we do
5544*0Sstevel@tonic-gate 	 *	if a socket doesn't support memory mapped IO windows.
5545*0Sstevel@tonic-gate 	 */
5546*0Sstevel@tonic-gate 	if (sp->io_mmap_window) {
5547*0Sstevel@tonic-gate 	    cs_window_t *cw;
5548*0Sstevel@tonic-gate 	    io_mmap_window_t *imw = sp->io_mmap_window;
5549*0Sstevel@tonic-gate 	    uint32_t offset;
5550*0Sstevel@tonic-gate 
5551*0Sstevel@tonic-gate 		/*
5552*0Sstevel@tonic-gate 		 * If we haven't allocated an IO window yet, do it now.
5553*0Sstevel@tonic-gate 		 * Try to allocate the IO window that cs_init found for us;
5554*0Sstevel@tonic-gate 		 * if that fails, then call cs_find_io_win to find a window.
5555*0Sstevel@tonic-gate 		 */
5556*0Sstevel@tonic-gate 	    if (!imw->count) {
5557*0Sstevel@tonic-gate 		set_window_t set_window;
5558*0Sstevel@tonic-gate 
5559*0Sstevel@tonic-gate 		if (!WINDOW_AVAILABLE_FOR_IO(imw->number)) {
5560*0Sstevel@tonic-gate 		    iowin_char_t iowin_char;
5561*0Sstevel@tonic-gate 
5562*0Sstevel@tonic-gate 		    iowin_char.IOWndCaps = (WC_IO_RANGE_PER_WINDOW |
5563*0Sstevel@tonic-gate 					    WC_8BIT |
5564*0Sstevel@tonic-gate 					    WC_16BIT);
5565*0Sstevel@tonic-gate 		    if ((error = cs_find_io_win(sp->socket_num, &iowin_char,
5566*0Sstevel@tonic-gate 				    &imw->number, &imw->size)) != CS_SUCCESS) {
5567*0Sstevel@tonic-gate 			EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5568*0Sstevel@tonic-gate 			mutex_exit(&cs_globals.window_lock);
5569*0Sstevel@tonic-gate 		    } /* cs_find_io_win */
5570*0Sstevel@tonic-gate 		} /* if (!WINDOW_AVAILABLE_FOR_IO) */
5571*0Sstevel@tonic-gate 
5572*0Sstevel@tonic-gate 		set_window.socket = socket_num;
5573*0Sstevel@tonic-gate 		set_window.window = imw->number;
5574*0Sstevel@tonic-gate 		set_window.speed = IO_WIN_SPEED;
5575*0Sstevel@tonic-gate 		set_window.base.base = 0;
5576*0Sstevel@tonic-gate 		set_window.WindowSize = imw->size;
5577*0Sstevel@tonic-gate 		set_window.state = (WS_ENABLED | WS_16BIT |
5578*0Sstevel@tonic-gate 				    WS_EXACT_MAPIN | WS_IO);
5579*0Sstevel@tonic-gate 
5580*0Sstevel@tonic-gate 		/* XXX - what to d here? XXX */
5581*0Sstevel@tonic-gate 		cs_set_acc_attributes(&set_window, Attributes);
5582*0Sstevel@tonic-gate 
5583*0Sstevel@tonic-gate 		if (SocketServices(SS_SetWindow, &set_window) != SUCCESS) {
5584*0Sstevel@tonic-gate 		    (void) cs_setup_io_win(socket_num, imw->number,
5585*0Sstevel@tonic-gate 						NULL, NULL, NULL,
5586*0Sstevel@tonic-gate 						(IO_DEALLOCATE_WINDOW |
5587*0Sstevel@tonic-gate 						IO_DISABLE_WINDOW));
5588*0Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5589*0Sstevel@tonic-gate 		    mutex_exit(&cs_globals.window_lock);
5590*0Sstevel@tonic-gate 		    return (CS_BAD_WINDOW);
5591*0Sstevel@tonic-gate 		}
5592*0Sstevel@tonic-gate 
5593*0Sstevel@tonic-gate 		imw->handle = set_window.base.handle;
5594*0Sstevel@tonic-gate 		imw->size = set_window.WindowSize;
5595*0Sstevel@tonic-gate 
5596*0Sstevel@tonic-gate 		/*
5597*0Sstevel@tonic-gate 		 * Check the caller's port requirements to be sure that they
5598*0Sstevel@tonic-gate 		 *	fit within our found IO window.
5599*0Sstevel@tonic-gate 		 */
5600*0Sstevel@tonic-gate 		if ((ior->BasePort1.base + ior->NumPorts1 +
5601*0Sstevel@tonic-gate 			ior->BasePort2.base + ior->NumPorts2) > imw->size) {
5602*0Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5603*0Sstevel@tonic-gate 		    mutex_exit(&cs_globals.window_lock);
5604*0Sstevel@tonic-gate 		    return (CS_BAD_BASE);
5605*0Sstevel@tonic-gate 		}
5606*0Sstevel@tonic-gate 
5607*0Sstevel@tonic-gate 		if ((cw = cs_get_wp(imw->number)) == NULL) {
5608*0Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5609*0Sstevel@tonic-gate 		    mutex_exit(&cs_globals.window_lock);
5610*0Sstevel@tonic-gate 		    return (CS_BAD_WINDOW)
5611*0Sstevel@tonic-gate 		}
5612*0Sstevel@tonic-gate 		cw->state |= (CW_ALLOCATED | CW_IO);
5613*0Sstevel@tonic-gate 
5614*0Sstevel@tonic-gate 	    } /* if (!imw->count) */
5615*0Sstevel@tonic-gate 
5616*0Sstevel@tonic-gate 	    imw->count++;
5617*0Sstevel@tonic-gate 
5618*0Sstevel@tonic-gate 		/*
5619*0Sstevel@tonic-gate 		 * All common access handles for this type of adapter are
5620*0Sstevel@tonic-gate 		 * duped.  We never give the original back to the caller.
5621*0Sstevel@tonic-gate 		 */
5622*0Sstevel@tonic-gate 	    /* XXX need to set endianess and data ordering flags */
5623*0Sstevel@tonic-gate 	    csx_DupHandle(imw->handle, &ior->BasePort1.handle, 0);
5624*0Sstevel@tonic-gate 	    csx_GetHandleOffset(ior->BasePort1.handle, &offset);
5625*0Sstevel@tonic-gate 	    csx_SetHandleOffset(ior->BasePort1.handle,
5626*0Sstevel@tonic-gate 		ior->BasePort1.base + offset);
5627*0Sstevel@tonic-gate 
5628*0Sstevel@tonic-gate 	    if (ior->NumPorts2) {
5629*0Sstevel@tonic-gate 		/* XXX need to set endianess and data ordering flags */
5630*0Sstevel@tonic-gate 		csx_DupHandle(imw->handle, &ior->BasePort2.handle, 0);
5631*0Sstevel@tonic-gate 		csx_GetHandleOffset(ior->BasePort2.handle, &offset);
5632*0Sstevel@tonic-gate 		csx_SetHandleOffset(ior->BasePort2.handle,
5633*0Sstevel@tonic-gate 		    ior->BasePort1.base + offset);
5634*0Sstevel@tonic-gate 	    }
5635*0Sstevel@tonic-gate 
5636*0Sstevel@tonic-gate 		/*
5637*0Sstevel@tonic-gate 		 * We don't really use these two values if we've got a memory
5638*0Sstevel@tonic-gate 		 * mapped IO window since the assigned window number is stored
5639*0Sstevel@tonic-gate 		 * in imw->number.
5640*0Sstevel@tonic-gate 		 */
5641*0Sstevel@tonic-gate 	    client->io_alloc.Window1 = imw->number;
5642*0Sstevel@tonic-gate 	    client->io_alloc.Window2 = PCMCIA_MAX_WINDOWS;
5643*0Sstevel@tonic-gate 
5644*0Sstevel@tonic-gate 	/*
5645*0Sstevel@tonic-gate 	 * This socket supports only IO port IO windows.
5646*0Sstevel@tonic-gate 	 */
5647*0Sstevel@tonic-gate 	} else {
5648*0Sstevel@tonic-gate #else	/* USE_IOMMAP_WINDOW */
5649*0Sstevel@tonic-gate 	{
5650*0Sstevel@tonic-gate #endif	/* USE_IOMMAP_WINDOW */
5651*0Sstevel@tonic-gate 	    baseaddru_t baseaddru;
5652*0Sstevel@tonic-gate 
5653*0Sstevel@tonic-gate 	    baseaddru.base = ior->BasePort1.base;
5654*0Sstevel@tonic-gate 
5655*0Sstevel@tonic-gate 	    if ((error = cs_allocate_io_win(sp->socket_num, ior->Attributes1,
5656*0Sstevel@tonic-gate 		&client->io_alloc.Window1)) != CS_SUCCESS) {
5657*0Sstevel@tonic-gate 
5658*0Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5659*0Sstevel@tonic-gate 		mutex_exit(&cs_globals.window_lock);
5660*0Sstevel@tonic-gate 		return (error);
5661*0Sstevel@tonic-gate 	    } /* if (cs_allocate_io_win(1)) */
5662*0Sstevel@tonic-gate 
5663*0Sstevel@tonic-gate 		/*
5664*0Sstevel@tonic-gate 		 * Setup the window hardware; if this fails, then we need to
5665*0Sstevel@tonic-gate 		 *	deallocate the previously allocated window.
5666*0Sstevel@tonic-gate 		 */
5667*0Sstevel@tonic-gate 	    if ((error = cs_setup_io_win(socket_num,
5668*0Sstevel@tonic-gate 						client->io_alloc.Window1,
5669*0Sstevel@tonic-gate 						&baseaddru,
5670*0Sstevel@tonic-gate 						&ior->NumPorts1,
5671*0Sstevel@tonic-gate 						ior->IOAddrLines,
5672*0Sstevel@tonic-gate 						ior->Attributes1)) !=
5673*0Sstevel@tonic-gate 								CS_SUCCESS) {
5674*0Sstevel@tonic-gate 		(void) cs_setup_io_win(socket_num, client->io_alloc.Window1,
5675*0Sstevel@tonic-gate 					NULL, NULL, NULL,
5676*0Sstevel@tonic-gate 					(
5677*0Sstevel@tonic-gate 						IO_DEALLOCATE_WINDOW |
5678*0Sstevel@tonic-gate 						IO_DISABLE_WINDOW));
5679*0Sstevel@tonic-gate 
5680*0Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5681*0Sstevel@tonic-gate 		mutex_exit(&cs_globals.window_lock);
5682*0Sstevel@tonic-gate 		return (error);
5683*0Sstevel@tonic-gate 	    } /* if (cs_setup_io_win(1)) */
5684*0Sstevel@tonic-gate 
5685*0Sstevel@tonic-gate 	    ior->BasePort1.handle = (acc_handle_t)baseaddru.handle;
5686*0Sstevel@tonic-gate 	    ior->BasePort1.base = baseaddru.base;
5687*0Sstevel@tonic-gate 
5688*0Sstevel@tonic-gate 		/*
5689*0Sstevel@tonic-gate 		 * See if the client wants two IO ranges.
5690*0Sstevel@tonic-gate 		 */
5691*0Sstevel@tonic-gate 	    if (ior->NumPorts2) {
5692*0Sstevel@tonic-gate 		baseaddru_t baseaddru;
5693*0Sstevel@tonic-gate 
5694*0Sstevel@tonic-gate 		baseaddru.base = ior->BasePort2.base;
5695*0Sstevel@tonic-gate 
5696*0Sstevel@tonic-gate 		/*
5697*0Sstevel@tonic-gate 		 * If we fail to allocate this window, then we must deallocate
5698*0Sstevel@tonic-gate 		 *	the previous IO window that is already allocated.
5699*0Sstevel@tonic-gate 		 */
5700*0Sstevel@tonic-gate 		if ((error = cs_allocate_io_win(sp->socket_num,
5701*0Sstevel@tonic-gate 						ior->Attributes2,
5702*0Sstevel@tonic-gate 						&client->io_alloc.Window2)) !=
5703*0Sstevel@tonic-gate 								CS_SUCCESS) {
5704*0Sstevel@tonic-gate 		    (void) cs_setup_io_win(socket_num,
5705*0Sstevel@tonic-gate 						client->io_alloc.Window2,
5706*0Sstevel@tonic-gate 						NULL, NULL, NULL,
5707*0Sstevel@tonic-gate 						(
5708*0Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
5709*0Sstevel@tonic-gate 							IO_DISABLE_WINDOW));
5710*0Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5711*0Sstevel@tonic-gate 		    mutex_exit(&cs_globals.window_lock);
5712*0Sstevel@tonic-gate 		    return (error);
5713*0Sstevel@tonic-gate 		} /* if (cs_allocate_io_win(2)) */
5714*0Sstevel@tonic-gate 		/*
5715*0Sstevel@tonic-gate 		 * Setup the window hardware; if this fails, then we need to
5716*0Sstevel@tonic-gate 		 *	deallocate the previously allocated window.
5717*0Sstevel@tonic-gate 		 */
5718*0Sstevel@tonic-gate 		if ((error = cs_setup_io_win(socket_num,
5719*0Sstevel@tonic-gate 						client->io_alloc.Window2,
5720*0Sstevel@tonic-gate 						&baseaddru,
5721*0Sstevel@tonic-gate 						&ior->NumPorts2,
5722*0Sstevel@tonic-gate 						ior->IOAddrLines,
5723*0Sstevel@tonic-gate 						ior->Attributes2)) !=
5724*0Sstevel@tonic-gate 								CS_SUCCESS) {
5725*0Sstevel@tonic-gate 		    (void) cs_setup_io_win(socket_num,
5726*0Sstevel@tonic-gate 						client->io_alloc.Window1,
5727*0Sstevel@tonic-gate 						NULL, NULL, NULL,
5728*0Sstevel@tonic-gate 						(
5729*0Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
5730*0Sstevel@tonic-gate 							IO_DISABLE_WINDOW));
5731*0Sstevel@tonic-gate 		    (void) cs_setup_io_win(socket_num,
5732*0Sstevel@tonic-gate 						client->io_alloc.Window2,
5733*0Sstevel@tonic-gate 						NULL, NULL, NULL,
5734*0Sstevel@tonic-gate 						(
5735*0Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
5736*0Sstevel@tonic-gate 							IO_DISABLE_WINDOW));
5737*0Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5738*0Sstevel@tonic-gate 		    mutex_exit(&cs_globals.window_lock);
5739*0Sstevel@tonic-gate 		    return (error);
5740*0Sstevel@tonic-gate 		} /* if (cs_setup_io_win(2)) */
5741*0Sstevel@tonic-gate 
5742*0Sstevel@tonic-gate 		ior->BasePort2.handle = (acc_handle_t)baseaddru.handle;
5743*0Sstevel@tonic-gate 		ior->BasePort2.base = baseaddru.base;
5744*0Sstevel@tonic-gate 
5745*0Sstevel@tonic-gate 	    } else {
5746*0Sstevel@tonic-gate 		client->io_alloc.Window2 = PCMCIA_MAX_WINDOWS;
5747*0Sstevel@tonic-gate 	    } /* if (ior->NumPorts2) */
5748*0Sstevel@tonic-gate 	} /* if (sp->io_mmap_window) */
5749*0Sstevel@tonic-gate 
5750*0Sstevel@tonic-gate 	/*
5751*0Sstevel@tonic-gate 	 * Save a copy of the client's port information so that we
5752*0Sstevel@tonic-gate 	 *	can use it in the RequestConfiguration call.  We set
5753*0Sstevel@tonic-gate 	 *	the IO window number(s) allocated in the respective
5754*0Sstevel@tonic-gate 	 *	section of code, above.
5755*0Sstevel@tonic-gate 	 */
5756*0Sstevel@tonic-gate 	client->io_alloc.BasePort1.base = ior->BasePort1.base;
5757*0Sstevel@tonic-gate 	client->io_alloc.BasePort1.handle = ior->BasePort1.handle;
5758*0Sstevel@tonic-gate 	client->io_alloc.NumPorts1 = ior->NumPorts1;
5759*0Sstevel@tonic-gate 	client->io_alloc.Attributes1 = ior->Attributes1;
5760*0Sstevel@tonic-gate 	client->io_alloc.BasePort2.base = ior->BasePort2.base;
5761*0Sstevel@tonic-gate 	client->io_alloc.BasePort2.handle = ior->BasePort2.handle;
5762*0Sstevel@tonic-gate 	client->io_alloc.NumPorts2 = ior->NumPorts2;
5763*0Sstevel@tonic-gate 	client->io_alloc.Attributes2 = ior->Attributes2;
5764*0Sstevel@tonic-gate 	client->io_alloc.IOAddrLines = ior->IOAddrLines;
5765*0Sstevel@tonic-gate 
5766*0Sstevel@tonic-gate 	/*
5767*0Sstevel@tonic-gate 	 * Mark this client as having done a successful RequestIO call.
5768*0Sstevel@tonic-gate 	 */
5769*0Sstevel@tonic-gate 	client->flags |= (REQ_IO_DONE | CLIENT_IO_ALLOCATED);
5770*0Sstevel@tonic-gate 
5771*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5772*0Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
5773*0Sstevel@tonic-gate 
5774*0Sstevel@tonic-gate 	return (CS_SUCCESS);
5775*0Sstevel@tonic-gate }
5776*0Sstevel@tonic-gate 
5777*0Sstevel@tonic-gate /*
5778*0Sstevel@tonic-gate  * cs_release_io - releases IO resources allocated by RequestIO; this is
5779*0Sstevel@tonic-gate  *			ReleaseIO
5780*0Sstevel@tonic-gate  *
5781*0Sstevel@tonic-gate  *	calling: cs_release_io(client_handle_t, io_req_t *)
5782*0Sstevel@tonic-gate  *
5783*0Sstevel@tonic-gate  *	returns: CS_SUCCESS - if IO resources sucessfully deallocated
5784*0Sstevel@tonic-gate  *		 CS_BAD_HANDLE - client handle is invalid
5785*0Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
5786*0Sstevel@tonic-gate  *		 CS_CONFIGURATION_LOCKED - a RequestConfiguration has been
5787*0Sstevel@tonic-gate  *				done without a ReleaseConfiguration
5788*0Sstevel@tonic-gate  *		 CS_IN_USE - no RequestIO has been done
5789*0Sstevel@tonic-gate  */
5790*0Sstevel@tonic-gate static int
5791*0Sstevel@tonic-gate cs_release_io(client_handle_t client_handle, io_req_t *ior)
5792*0Sstevel@tonic-gate {
5793*0Sstevel@tonic-gate 	cs_socket_t *sp;
5794*0Sstevel@tonic-gate 	client_t *client;
5795*0Sstevel@tonic-gate 	int error;
5796*0Sstevel@tonic-gate 	int client_lock_acquired;
5797*0Sstevel@tonic-gate 	uint32_t socket_num;
5798*0Sstevel@tonic-gate 
5799*0Sstevel@tonic-gate #ifdef	lint
5800*0Sstevel@tonic-gate 	ior = NULL;
5801*0Sstevel@tonic-gate #endif
5802*0Sstevel@tonic-gate 
5803*0Sstevel@tonic-gate 	/*
5804*0Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
5805*0Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
5806*0Sstevel@tonic-gate 	 */
5807*0Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
5808*0Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
5809*0Sstevel@tonic-gate 
5810*0Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
5811*0Sstevel@tonic-gate 
5812*0Sstevel@tonic-gate 	/*
5813*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
5814*0Sstevel@tonic-gate 	 */
5815*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
5816*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
5817*0Sstevel@tonic-gate 
5818*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
5819*0Sstevel@tonic-gate 
5820*0Sstevel@tonic-gate 	/*
5821*0Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
5822*0Sstevel@tonic-gate 	 */
5823*0Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
5824*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5825*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
5826*0Sstevel@tonic-gate 	    return (error);
5827*0Sstevel@tonic-gate 	}
5828*0Sstevel@tonic-gate 
5829*0Sstevel@tonic-gate 	/*
5830*0Sstevel@tonic-gate 	 * If RequestConfiguration has already been done, we don't allow
5831*0Sstevel@tonic-gate 	 *	this call.
5832*0Sstevel@tonic-gate 	 */
5833*0Sstevel@tonic-gate 	if (client->flags & REQ_CONFIGURATION_DONE) {
5834*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5835*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
5836*0Sstevel@tonic-gate 	    return (CS_CONFIGURATION_LOCKED);
5837*0Sstevel@tonic-gate 	}
5838*0Sstevel@tonic-gate 
5839*0Sstevel@tonic-gate 	/*
5840*0Sstevel@tonic-gate 	 * If RequestIO has not been done, we don't allow this call.
5841*0Sstevel@tonic-gate 	 */
5842*0Sstevel@tonic-gate 	if (!(client->flags & REQ_IO_DONE)) {
5843*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5844*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
5845*0Sstevel@tonic-gate 	    return (CS_IN_USE);
5846*0Sstevel@tonic-gate 	}
5847*0Sstevel@tonic-gate 
5848*0Sstevel@tonic-gate 	socket_num = CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
5849*0Sstevel@tonic-gate 	    GET_CLIENT_FUNCTION(client_handle));
5850*0Sstevel@tonic-gate 
5851*0Sstevel@tonic-gate #ifdef	XXX
5852*0Sstevel@tonic-gate 	/*
5853*0Sstevel@tonic-gate 	 * Check the passed IO allocation with the stored allocation; if
5854*0Sstevel@tonic-gate 	 *	they don't match, then return an error.
5855*0Sstevel@tonic-gate 	 */
5856*0Sstevel@tonic-gate 	if ((client->io_alloc.BasePort1 != ior->BasePort1) ||
5857*0Sstevel@tonic-gate 	    (client->io_alloc.NumPorts1 != ior->NumPorts1) ||
5858*0Sstevel@tonic-gate 	    (client->io_alloc.Attributes1 != ior->Attributes1) ||
5859*0Sstevel@tonic-gate 	    (client->io_alloc.BasePort2 != ior->BasePort2) ||
5860*0Sstevel@tonic-gate 	    (client->io_alloc.NumPorts2 != ior->NumPorts2) ||
5861*0Sstevel@tonic-gate 	    (client->io_alloc.Attributes2 != ior->Attributes2) ||
5862*0Sstevel@tonic-gate 	    (client->io_alloc.IOAddrLines != ior->IOAddrLines)) {
5863*0Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5864*0Sstevel@tonic-gate 		mutex_exit(&cs_globals.window_lock);
5865*0Sstevel@tonic-gate 		return (CS_BAD_ARGS);
5866*0Sstevel@tonic-gate 	}
5867*0Sstevel@tonic-gate #endif
5868*0Sstevel@tonic-gate 
5869*0Sstevel@tonic-gate #ifdef	USE_IOMMAP_WINDOW
5870*0Sstevel@tonic-gate 	/*
5871*0Sstevel@tonic-gate 	 * The code diverges here depending on if this socket supports
5872*0Sstevel@tonic-gate 	 *	memory mapped IO windows or not.  See comments in the
5873*0Sstevel@tonic-gate 	 *	cs_request_io function for a description of what's
5874*0Sstevel@tonic-gate 	 *	going on here.
5875*0Sstevel@tonic-gate 	 */
5876*0Sstevel@tonic-gate 	if (sp->io_mmap_window) {
5877*0Sstevel@tonic-gate 	    io_mmap_window_t *imw = sp->io_mmap_window;
5878*0Sstevel@tonic-gate 
5879*0Sstevel@tonic-gate 		/*
5880*0Sstevel@tonic-gate 		 * We should never see this; if we do, it's an internal
5881*0Sstevel@tonic-gate 		 *	consistency error.
5882*0Sstevel@tonic-gate 		 */
5883*0Sstevel@tonic-gate 	    if (!imw->count) {
5884*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_release_io: socket %d !imw->count\n",
5885*0Sstevel@tonic-gate 							    sp->socket_num);
5886*0Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5887*0Sstevel@tonic-gate 		mutex_exit(&cs_globals.window_lock);
5888*0Sstevel@tonic-gate 		return (CS_GENERAL_FAILURE);
5889*0Sstevel@tonic-gate 	    }
5890*0Sstevel@tonic-gate 
5891*0Sstevel@tonic-gate 		/*
5892*0Sstevel@tonic-gate 		 * All common access handles for this type of adapter are
5893*0Sstevel@tonic-gate 		 *	duped. We never give the original back to the caller,
5894*0Sstevel@tonic-gate 		 *	so it's OK to unconditionally free the handle here.
5895*0Sstevel@tonic-gate 		 */
5896*0Sstevel@tonic-gate 	    csx_FreeHandle(&ior->BasePort1.handle);
5897*0Sstevel@tonic-gate 
5898*0Sstevel@tonic-gate 		/*
5899*0Sstevel@tonic-gate 		 * If the IO window referance count is zero, then deallocate
5900*0Sstevel@tonic-gate 		 * and disable this window.
5901*0Sstevel@tonic-gate 		 */
5902*0Sstevel@tonic-gate 	    if (!--(imw->count)) {
5903*0Sstevel@tonic-gate 		(void) cs_setup_io_win(socket_num, imw->number, NULL,
5904*0Sstevel@tonic-gate 								NULL, NULL,
5905*0Sstevel@tonic-gate 						(
5906*0Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
5907*0Sstevel@tonic-gate 							IO_DISABLE_WINDOW));
5908*0Sstevel@tonic-gate 	    } /* if (imw->count) */
5909*0Sstevel@tonic-gate 	} else {
5910*0Sstevel@tonic-gate #endif	/* USE_IOMMAP_WINDOW */
5911*0Sstevel@tonic-gate 	    (void) cs_setup_io_win(socket_num, client->io_alloc.Window1,
5912*0Sstevel@tonic-gate 						NULL, NULL, NULL,
5913*0Sstevel@tonic-gate 						(
5914*0Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
5915*0Sstevel@tonic-gate 							IO_DISABLE_WINDOW));
5916*0Sstevel@tonic-gate 	    if (client->io_alloc.Window2 != PCMCIA_MAX_WINDOWS)
5917*0Sstevel@tonic-gate 		(void) cs_setup_io_win(socket_num, client->io_alloc.Window2,
5918*0Sstevel@tonic-gate 						NULL, NULL, NULL,
5919*0Sstevel@tonic-gate 						(
5920*0Sstevel@tonic-gate 							IO_DEALLOCATE_WINDOW |
5921*0Sstevel@tonic-gate 							IO_DISABLE_WINDOW));
5922*0Sstevel@tonic-gate #ifdef	USE_IOMMAP_WINDOW
5923*0Sstevel@tonic-gate 	} /* if (sp->io_mmap_window) */
5924*0Sstevel@tonic-gate #endif	/* USE_IOMMAP_WINDOW */
5925*0Sstevel@tonic-gate 
5926*0Sstevel@tonic-gate 	/*
5927*0Sstevel@tonic-gate 	 * Mark the client as not having any IO resources allocated.
5928*0Sstevel@tonic-gate 	 */
5929*0Sstevel@tonic-gate 	client->flags &= ~(REQ_IO_DONE | CLIENT_IO_ALLOCATED);
5930*0Sstevel@tonic-gate 
5931*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
5932*0Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
5933*0Sstevel@tonic-gate 	return (CS_SUCCESS);
5934*0Sstevel@tonic-gate }
5935*0Sstevel@tonic-gate 
5936*0Sstevel@tonic-gate /*
5937*0Sstevel@tonic-gate  * cs_find_io_win - finds an IO window that matches the parameters specified
5938*0Sstevel@tonic-gate  *			in the flags argument
5939*0Sstevel@tonic-gate  *
5940*0Sstevel@tonic-gate  *	calling: sn - socket number to look for IO window on
5941*0Sstevel@tonic-gate  *		 *iwc - other window characteristics to match
5942*0Sstevel@tonic-gate  *		 *assigned_window - pointer to where we return the assigned
5943*0Sstevel@tonic-gate  *					window number if we found a window or
5944*0Sstevel@tonic-gate  *					undefined otherwise
5945*0Sstevel@tonic-gate  *		 *size - if non-NULL, the found window size will be stored here
5946*0Sstevel@tonic-gate  *
5947*0Sstevel@tonic-gate  *	returns: CS_SUCCESS - if IO window found
5948*0Sstevel@tonic-gate  *		 CS_OUT_OF_RESOURCE - if no windows match requirements
5949*0Sstevel@tonic-gate  */
5950*0Sstevel@tonic-gate static int
5951*0Sstevel@tonic-gate cs_find_io_win(uint32_t sn, iowin_char_t *iwc, uint32_t *assigned_window,
5952*0Sstevel@tonic-gate     uint32_t *size)
5953*0Sstevel@tonic-gate {
5954*0Sstevel@tonic-gate 	inquire_window_t inquire_window, *iw;
5955*0Sstevel@tonic-gate 	unsigned wn;
5956*0Sstevel@tonic-gate 
5957*0Sstevel@tonic-gate 	iw = &inquire_window;
5958*0Sstevel@tonic-gate 
5959*0Sstevel@tonic-gate 	for (wn = 0; wn < cs_globals.num_windows; wn++) {
5960*0Sstevel@tonic-gate 	    iowin_char_t *iowc;
5961*0Sstevel@tonic-gate 	    cs_window_t *cw;
5962*0Sstevel@tonic-gate 
5963*0Sstevel@tonic-gate 	    if ((cw = cs_get_wp(wn)) != NULL) {
5964*0Sstevel@tonic-gate 
5965*0Sstevel@tonic-gate 		iw->window = wn;
5966*0Sstevel@tonic-gate 		SocketServices(SS_InquireWindow, iw);
5967*0Sstevel@tonic-gate 
5968*0Sstevel@tonic-gate 		iowc = &iw->iowin_char;
5969*0Sstevel@tonic-gate 
5970*0Sstevel@tonic-gate 		if (WINDOW_FOR_SOCKET(iw->Sockets, sn) &&
5971*0Sstevel@tonic-gate 		    WINDOW_AVAILABLE_FOR_IO(cw) &&
5972*0Sstevel@tonic-gate 		    (iw->WndCaps & WC_IO) &&
5973*0Sstevel@tonic-gate 		    ((iowc->IOWndCaps & iwc->IOWndCaps) == iwc->IOWndCaps)) {
5974*0Sstevel@tonic-gate 
5975*0Sstevel@tonic-gate 			*assigned_window = wn;
5976*0Sstevel@tonic-gate 
5977*0Sstevel@tonic-gate 			if (size)
5978*0Sstevel@tonic-gate 			    *size = iw->iowin_char.ReqGran;
5979*0Sstevel@tonic-gate 			return (CS_SUCCESS);
5980*0Sstevel@tonic-gate 		    } /* if (WINDOW_FOR_SOCKET) */
5981*0Sstevel@tonic-gate 	    } /* cs_get_wp */
5982*0Sstevel@tonic-gate 	} /* for (wn) */
5983*0Sstevel@tonic-gate 
5984*0Sstevel@tonic-gate 	return (CS_OUT_OF_RESOURCE);
5985*0Sstevel@tonic-gate }
5986*0Sstevel@tonic-gate 
5987*0Sstevel@tonic-gate /*
5988*0Sstevel@tonic-gate  * cs_allocate_io_win - finds and allocates an IO window
5989*0Sstevel@tonic-gate  *
5990*0Sstevel@tonic-gate  *	calling: sn - socket number to look for window on
5991*0Sstevel@tonic-gate  *		 Attributes - window attributes in io_req_t.Attributes format
5992*0Sstevel@tonic-gate  *		 *assigned_window - pointer to return assigned window number
5993*0Sstevel@tonic-gate  *
5994*0Sstevel@tonic-gate  *	returns: CS_SUCCESS - IO window found and allocated
5995*0Sstevel@tonic-gate  *		 CS_OUT_OF_RESOURCE - if cs_find_io_win couldn't find a
5996*0Sstevel@tonic-gate  *				window that matches the passed criteria
5997*0Sstevel@tonic-gate  *
5998*0Sstevel@tonic-gate  * Note: This fucntion will find and allocate an IO window.  The caller is
5999*0Sstevel@tonic-gate  *	responsible for deallocating the window.
6000*0Sstevel@tonic-gate  */
6001*0Sstevel@tonic-gate static int
6002*0Sstevel@tonic-gate cs_allocate_io_win(uint32_t sn, uint32_t Attributes, uint32_t *assigned_window)
6003*0Sstevel@tonic-gate {
6004*0Sstevel@tonic-gate 	iowin_char_t iowin_char;
6005*0Sstevel@tonic-gate 	cs_window_t *cw;
6006*0Sstevel@tonic-gate 
6007*0Sstevel@tonic-gate 	iowin_char.IOWndCaps =
6008*0Sstevel@tonic-gate 		((Attributes & IO_DATA_PATH_WIDTH_16)?WC_16BIT:WC_8BIT);
6009*0Sstevel@tonic-gate 
6010*0Sstevel@tonic-gate 	if (cs_find_io_win(sn, &iowin_char, assigned_window, NULL) ==
6011*0Sstevel@tonic-gate 								CS_SUCCESS) {
6012*0Sstevel@tonic-gate 	    if ((cw = cs_get_wp(*assigned_window)) == NULL)
6013*0Sstevel@tonic-gate 		return (CS_OUT_OF_RESOURCE);
6014*0Sstevel@tonic-gate 
6015*0Sstevel@tonic-gate 	    cw->state = (cw->state & CW_WINDOW_VALID) | (CW_ALLOCATED | CW_IO);
6016*0Sstevel@tonic-gate 	    return (CS_SUCCESS);
6017*0Sstevel@tonic-gate 	}
6018*0Sstevel@tonic-gate 
6019*0Sstevel@tonic-gate 	return (CS_OUT_OF_RESOURCE);
6020*0Sstevel@tonic-gate }
6021*0Sstevel@tonic-gate 
6022*0Sstevel@tonic-gate /*
6023*0Sstevel@tonic-gate  * cs_setup_io_win - setup and destroy an IO window
6024*0Sstevel@tonic-gate  *
6025*0Sstevel@tonic-gate  *	calling: sn - socket number
6026*0Sstevel@tonic-gate  *		 wn - window number
6027*0Sstevel@tonic-gate  * XXX Base - pointer to XXX
6028*0Sstevel@tonic-gate  *		 *NumPorts - pointer to number of allocated ports to return
6029*0Sstevel@tonic-gate  *		 IOAddrLines - number of IO address lines decoded by this card
6030*0Sstevel@tonic-gate  *		 Attributes - either io_req_t attributes, or a combination of
6031*0Sstevel@tonic-gate  *				the following flags:
6032*0Sstevel@tonic-gate  *				    IO_DEALLOCATE_WINDOW - deallocate the window
6033*0Sstevel@tonic-gate  *				    IO_DISABLE_WINDOW - disable the window
6034*0Sstevel@tonic-gate  *				When either of these two flags are set, *Base
6035*0Sstevel@tonic-gate  *				    and NumPorts should be NULL.
6036*0Sstevel@tonic-gate  *
6037*0Sstevel@tonic-gate  *	returns: CS_SUCCESS - if no failure
6038*0Sstevel@tonic-gate  *		 CS_BAD_WINDOW - if error while trying to configure window
6039*0Sstevel@tonic-gate  *
6040*0Sstevel@tonic-gate  * Note: We use the IOAddrLines value to determine what base address to pass
6041*0Sstevel@tonic-gate  *		to Socket Services.
6042*0Sstevel@tonic-gate  */
6043*0Sstevel@tonic-gate static int
6044*0Sstevel@tonic-gate cs_setup_io_win(uint32_t sn, uint32_t wn, baseaddru_t *Base, uint32_t *NumPorts,
6045*0Sstevel@tonic-gate     uint32_t IOAddrLines, uint32_t Attributes)
6046*0Sstevel@tonic-gate {
6047*0Sstevel@tonic-gate 	set_window_t set_window;
6048*0Sstevel@tonic-gate 
6049*0Sstevel@tonic-gate 	if (Attributes & (IO_DEALLOCATE_WINDOW | IO_DISABLE_WINDOW)) {
6050*0Sstevel@tonic-gate 
6051*0Sstevel@tonic-gate 	    if (Attributes & IO_DEALLOCATE_WINDOW) {
6052*0Sstevel@tonic-gate 		cs_window_t *cw;
6053*0Sstevel@tonic-gate 
6054*0Sstevel@tonic-gate 		if ((cw = cs_get_wp(wn)) == NULL)
6055*0Sstevel@tonic-gate 		    return (CS_BAD_WINDOW);
6056*0Sstevel@tonic-gate 		cw->state &= CW_WINDOW_VALID;
6057*0Sstevel@tonic-gate 
6058*0Sstevel@tonic-gate 	    } /* IO_DEALLOCATE_WINDOW */
6059*0Sstevel@tonic-gate 
6060*0Sstevel@tonic-gate 	    if (Attributes & IO_DISABLE_WINDOW) {
6061*0Sstevel@tonic-gate 		get_window_t get_window;
6062*0Sstevel@tonic-gate 
6063*0Sstevel@tonic-gate 		get_window.window = wn;
6064*0Sstevel@tonic-gate 
6065*0Sstevel@tonic-gate 		SocketServices(SS_GetWindow, &get_window);
6066*0Sstevel@tonic-gate 
6067*0Sstevel@tonic-gate 		set_window.socket = get_window.socket;
6068*0Sstevel@tonic-gate 		set_window.window = get_window.window;
6069*0Sstevel@tonic-gate 		set_window.speed = get_window.speed;
6070*0Sstevel@tonic-gate 		set_window.base = 0;
6071*0Sstevel@tonic-gate 		set_window.WindowSize = get_window.size;
6072*0Sstevel@tonic-gate 		set_window.state = get_window.state & ~WS_ENABLED;
6073*0Sstevel@tonic-gate 
6074*0Sstevel@tonic-gate 		cs_set_acc_attributes(&set_window, Attributes);
6075*0Sstevel@tonic-gate 
6076*0Sstevel@tonic-gate 		SocketServices(SS_SetWindow, &set_window);
6077*0Sstevel@tonic-gate 	    } /* IO_DISABLE_WINDOW */
6078*0Sstevel@tonic-gate 
6079*0Sstevel@tonic-gate 	    return (CS_SUCCESS);
6080*0Sstevel@tonic-gate 
6081*0Sstevel@tonic-gate 	} /* if (IO_DEALLOCATE_WINDOW | IO_DISABLE_WINDOW) */
6082*0Sstevel@tonic-gate 
6083*0Sstevel@tonic-gate 	/*
6084*0Sstevel@tonic-gate 	 * See if we can allow Socket Services to select the base address
6085*0Sstevel@tonic-gate 	 *	value for this card; if the client has specified a non-zero
6086*0Sstevel@tonic-gate 	 *	base IO address but the card doesn't decode enough IO
6087*0Sstevel@tonic-gate 	 *	address lines to uniquely use that address, then we have
6088*0Sstevel@tonic-gate 	 *	the flexibility to choose an alternative base address.
6089*0Sstevel@tonic-gate 	 * XXX - Is this really correct in all cases?
6090*0Sstevel@tonic-gate 	 */
6091*0Sstevel@tonic-gate 	if (!IOAddrLines)
6092*0Sstevel@tonic-gate 	    Base->base = 0;
6093*0Sstevel@tonic-gate 	else
6094*0Sstevel@tonic-gate 	    Base->base = IOADDR_FROBNITZ(Base->base, IOAddrLines);
6095*0Sstevel@tonic-gate 
6096*0Sstevel@tonic-gate 	set_window.socket = sn;
6097*0Sstevel@tonic-gate 	set_window.window = wn;
6098*0Sstevel@tonic-gate 	set_window.speed = IO_WIN_SPEED;
6099*0Sstevel@tonic-gate 	set_window.base = Base->base;
6100*0Sstevel@tonic-gate 	set_window.WindowSize = *NumPorts;
6101*0Sstevel@tonic-gate 	set_window.state = (WS_ENABLED | WS_IO |
6102*0Sstevel@tonic-gate 			((Attributes & IO_DATA_PATH_WIDTH_16)?WS_16BIT:0));
6103*0Sstevel@tonic-gate 
6104*0Sstevel@tonic-gate 	cs_set_acc_attributes(&set_window, Attributes);
6105*0Sstevel@tonic-gate 
6106*0Sstevel@tonic-gate 	if (SocketServices(SS_SetWindow, &set_window) != SUCCESS)
6107*0Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
6108*0Sstevel@tonic-gate 
6109*0Sstevel@tonic-gate 	Base->base = set_window.base;
6110*0Sstevel@tonic-gate 	Base->handle = set_window.handle;
6111*0Sstevel@tonic-gate 	*NumPorts = set_window.WindowSize;
6112*0Sstevel@tonic-gate 
6113*0Sstevel@tonic-gate 	return (CS_SUCCESS);
6114*0Sstevel@tonic-gate }
6115*0Sstevel@tonic-gate 
6116*0Sstevel@tonic-gate /*
6117*0Sstevel@tonic-gate  * ==== IRQ handling functions ====
6118*0Sstevel@tonic-gate  */
6119*0Sstevel@tonic-gate 
6120*0Sstevel@tonic-gate /*
6121*0Sstevel@tonic-gate  * cs_request_irq - add's client's IRQ handler; supports RequestIRQ
6122*0Sstevel@tonic-gate  *
6123*0Sstevel@tonic-gate  *	calling: irq_req_t.Attributes - must have the IRQ_TYPE_EXCLUSIVE
6124*0Sstevel@tonic-gate  *			flag set, and all other flags clear, or
6125*0Sstevel@tonic-gate  *			CS_BAD_ATTRIBUTE will be returned
6126*0Sstevel@tonic-gate  *
6127*0Sstevel@tonic-gate  *	returns: CS_SUCCESS - if IRQ resources available for client
6128*0Sstevel@tonic-gate  *		 CS_BAD_IRQ - if IRQ can not be allocated
6129*0Sstevel@tonic-gate  *		 CS_BAD_HANDLE - client handle is invalid
6130*0Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
6131*0Sstevel@tonic-gate  *		 CS_NO_CARD - if no card is in socket
6132*0Sstevel@tonic-gate  *		 CS_BAD_ATTRIBUTE - if any of the unsupported Attribute
6133*0Sstevel@tonic-gate  *					flags are set
6134*0Sstevel@tonic-gate  *		 CS_CONFIGURATION_LOCKED - a RequestConfiguration has
6135*0Sstevel@tonic-gate  *					already been done
6136*0Sstevel@tonic-gate  *		 CS_IN_USE - IRQ ports already in use or function has
6137*0Sstevel@tonic-gate  *					already been called
6138*0Sstevel@tonic-gate  *
6139*0Sstevel@tonic-gate  * Note: We only allow level-mode interrupts.
6140*0Sstevel@tonic-gate  */
6141*0Sstevel@tonic-gate static int
6142*0Sstevel@tonic-gate cs_request_irq(client_handle_t client_handle, irq_req_t *irqr)
6143*0Sstevel@tonic-gate {
6144*0Sstevel@tonic-gate 	cs_socket_t *sp;
6145*0Sstevel@tonic-gate 	client_t *client;
6146*0Sstevel@tonic-gate 	set_irq_handler_t set_irq_handler;
6147*0Sstevel@tonic-gate 	int error;
6148*0Sstevel@tonic-gate 	int client_lock_acquired;
6149*0Sstevel@tonic-gate 
6150*0Sstevel@tonic-gate 	/*
6151*0Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
6152*0Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
6153*0Sstevel@tonic-gate 	 */
6154*0Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
6155*0Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
6156*0Sstevel@tonic-gate 
6157*0Sstevel@tonic-gate 	/*
6158*0Sstevel@tonic-gate 	 * Make sure that none of the unsupported or reserved flags are set.
6159*0Sstevel@tonic-gate 	 */
6160*0Sstevel@tonic-gate 	if ((irqr->Attributes &	(IRQ_TYPE_TIME | IRQ_TYPE_DYNAMIC_SHARING |
6161*0Sstevel@tonic-gate 				IRQ_FIRST_SHARED | IRQ_PULSE_ALLOCATED |
6162*0Sstevel@tonic-gate 				IRQ_FORCED_PULSE)) ||
6163*0Sstevel@tonic-gate 		!(irqr->Attributes & IRQ_TYPE_EXCLUSIVE))
6164*0Sstevel@tonic-gate 	    return (CS_BAD_ATTRIBUTE);
6165*0Sstevel@tonic-gate 
6166*0Sstevel@tonic-gate 	/*
6167*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
6168*0Sstevel@tonic-gate 	 */
6169*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
6170*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
6171*0Sstevel@tonic-gate 
6172*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
6173*0Sstevel@tonic-gate 
6174*0Sstevel@tonic-gate 	/*
6175*0Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
6176*0Sstevel@tonic-gate 	 */
6177*0Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
6178*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6179*0Sstevel@tonic-gate 	    return (error);
6180*0Sstevel@tonic-gate 	}
6181*0Sstevel@tonic-gate 
6182*0Sstevel@tonic-gate 	/*
6183*0Sstevel@tonic-gate 	 * If RequestConfiguration has already been done, we don't allow
6184*0Sstevel@tonic-gate 	 *	this call.
6185*0Sstevel@tonic-gate 	 */
6186*0Sstevel@tonic-gate 	if (client->flags & REQ_CONFIGURATION_DONE) {
6187*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6188*0Sstevel@tonic-gate 	    return (CS_CONFIGURATION_LOCKED);
6189*0Sstevel@tonic-gate 	}
6190*0Sstevel@tonic-gate 
6191*0Sstevel@tonic-gate 	/*
6192*0Sstevel@tonic-gate 	 * If RequestIRQ has already been done, we don't allow this call.
6193*0Sstevel@tonic-gate 	 */
6194*0Sstevel@tonic-gate 	if (client->flags & REQ_IRQ_DONE) {
6195*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6196*0Sstevel@tonic-gate 	    return (CS_IN_USE);
6197*0Sstevel@tonic-gate 	}
6198*0Sstevel@tonic-gate 
6199*0Sstevel@tonic-gate 	/*
6200*0Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
6201*0Sstevel@tonic-gate 	 *	for this client, then return an error.
6202*0Sstevel@tonic-gate 	 */
6203*0Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
6204*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6205*0Sstevel@tonic-gate 	    return (CS_NO_CARD);
6206*0Sstevel@tonic-gate 	}
6207*0Sstevel@tonic-gate 
6208*0Sstevel@tonic-gate 	/*
6209*0Sstevel@tonic-gate 	 * Set up the parameters and ask Socket Services to give us an IRQ
6210*0Sstevel@tonic-gate 	 *	for this client.  We don't really do much, since the IRQ
6211*0Sstevel@tonic-gate 	 *	resources are managed by SS and the kernel.  We also don't
6212*0Sstevel@tonic-gate 	 *	care which IRQ level we are given.
6213*0Sstevel@tonic-gate 	 */
6214*0Sstevel@tonic-gate 	set_irq_handler.socket =
6215*0Sstevel@tonic-gate 		CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
6216*0Sstevel@tonic-gate 					GET_CLIENT_FUNCTION(client_handle));
6217*0Sstevel@tonic-gate 	set_irq_handler.irq = IRQ_ANY;
6218*0Sstevel@tonic-gate 
6219*0Sstevel@tonic-gate 	set_irq_handler.handler_id = client_handle;
6220*0Sstevel@tonic-gate 	set_irq_handler.handler = (f_t *)irqr->irq_handler;
6221*0Sstevel@tonic-gate 	set_irq_handler.arg1 = irqr->irq_handler_arg;
6222*0Sstevel@tonic-gate 	set_irq_handler.arg2 = NULL;
6223*0Sstevel@tonic-gate 
6224*0Sstevel@tonic-gate 	if ((error = SocketServices(SS_SetIRQHandler,
6225*0Sstevel@tonic-gate 					&set_irq_handler)) != SUCCESS) {
6226*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6227*0Sstevel@tonic-gate 	    return (CS_BAD_IRQ);
6228*0Sstevel@tonic-gate 	}
6229*0Sstevel@tonic-gate 
6230*0Sstevel@tonic-gate 	irqr->iblk_cookie = set_irq_handler.iblk_cookie;
6231*0Sstevel@tonic-gate 	irqr->idev_cookie = set_irq_handler.idev_cookie;
6232*0Sstevel@tonic-gate 
6233*0Sstevel@tonic-gate 	/*
6234*0Sstevel@tonic-gate 	 * Save the allocated IRQ information for this client.
6235*0Sstevel@tonic-gate 	 */
6236*0Sstevel@tonic-gate 	client->irq_alloc.Attributes = irqr->Attributes;
6237*0Sstevel@tonic-gate 	client->irq_alloc.irq = set_irq_handler.irq;
6238*0Sstevel@tonic-gate 	client->irq_alloc.handler_id = set_irq_handler.handler_id;
6239*0Sstevel@tonic-gate 	client->irq_alloc.irq_handler = (f_t *)set_irq_handler.handler;
6240*0Sstevel@tonic-gate 	client->irq_alloc.irq_handler_arg1 = set_irq_handler.arg1;
6241*0Sstevel@tonic-gate 	client->irq_alloc.irq_handler_arg2 = set_irq_handler.arg2;
6242*0Sstevel@tonic-gate 
6243*0Sstevel@tonic-gate #ifdef	CS_DEBUG
6244*0Sstevel@tonic-gate 	if (cs_debug > 0)
6245*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_request_irq: socket %d irqr->Attributes 0x%x "
6246*0Sstevel@tonic-gate 						"set_irq_handler.irq 0x%x\n",
6247*0Sstevel@tonic-gate 						sp->socket_num,
6248*0Sstevel@tonic-gate 						(int)irqr->Attributes,
6249*0Sstevel@tonic-gate 						set_irq_handler.irq);
6250*0Sstevel@tonic-gate #endif
6251*0Sstevel@tonic-gate 
6252*0Sstevel@tonic-gate 	/*
6253*0Sstevel@tonic-gate 	 * Mark this client as having done a successful RequestIRQ call.
6254*0Sstevel@tonic-gate 	 */
6255*0Sstevel@tonic-gate 	client->flags |= (REQ_IRQ_DONE | CLIENT_IRQ_ALLOCATED);
6256*0Sstevel@tonic-gate 
6257*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6258*0Sstevel@tonic-gate 	return (CS_SUCCESS);
6259*0Sstevel@tonic-gate }
6260*0Sstevel@tonic-gate 
6261*0Sstevel@tonic-gate /*
6262*0Sstevel@tonic-gate  * cs_release_irq - releases IRQ resources allocated by RequestIRQ; this is
6263*0Sstevel@tonic-gate  *			ReleaseIRQ
6264*0Sstevel@tonic-gate  *
6265*0Sstevel@tonic-gate  *	calling: cs_release_irq(client_handle_t, irq_req_t *)
6266*0Sstevel@tonic-gate  *
6267*0Sstevel@tonic-gate  *	returns: CS_SUCCESS - if IRQ resources sucessfully deallocated
6268*0Sstevel@tonic-gate  *		 CS_BAD_IRQ - if IRQ can not be deallocated
6269*0Sstevel@tonic-gate  *		 CS_BAD_HANDLE - client handle is invalid
6270*0Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
6271*0Sstevel@tonic-gate  *		 CS_CONFIGURATION_LOCKED - a RequestConfiguration has been
6272*0Sstevel@tonic-gate  *				done without a ReleaseConfiguration
6273*0Sstevel@tonic-gate  *		 CS_IN_USE - no RequestIRQ has been done
6274*0Sstevel@tonic-gate  */
6275*0Sstevel@tonic-gate static int
6276*0Sstevel@tonic-gate cs_release_irq(client_handle_t client_handle, irq_req_t *irqr)
6277*0Sstevel@tonic-gate {
6278*0Sstevel@tonic-gate 	cs_socket_t *sp;
6279*0Sstevel@tonic-gate 	client_t *client;
6280*0Sstevel@tonic-gate 	clear_irq_handler_t clear_irq_handler;
6281*0Sstevel@tonic-gate 	int error;
6282*0Sstevel@tonic-gate 	int client_lock_acquired;
6283*0Sstevel@tonic-gate 
6284*0Sstevel@tonic-gate #ifdef	lint
6285*0Sstevel@tonic-gate 	irqr = NULL;
6286*0Sstevel@tonic-gate #endif
6287*0Sstevel@tonic-gate 
6288*0Sstevel@tonic-gate 	/*
6289*0Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
6290*0Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
6291*0Sstevel@tonic-gate 	 */
6292*0Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
6293*0Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
6294*0Sstevel@tonic-gate 
6295*0Sstevel@tonic-gate 	/*
6296*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
6297*0Sstevel@tonic-gate 	 */
6298*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
6299*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
6300*0Sstevel@tonic-gate 
6301*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
6302*0Sstevel@tonic-gate 
6303*0Sstevel@tonic-gate 	/*
6304*0Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
6305*0Sstevel@tonic-gate 	 */
6306*0Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
6307*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6308*0Sstevel@tonic-gate 	    return (error);
6309*0Sstevel@tonic-gate 	}
6310*0Sstevel@tonic-gate 
6311*0Sstevel@tonic-gate 	/*
6312*0Sstevel@tonic-gate 	 * If RequestConfiguration has already been done, we don't allow
6313*0Sstevel@tonic-gate 	 *	this call.
6314*0Sstevel@tonic-gate 	 */
6315*0Sstevel@tonic-gate 	if (client->flags & REQ_CONFIGURATION_DONE) {
6316*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6317*0Sstevel@tonic-gate 	    return (CS_CONFIGURATION_LOCKED);
6318*0Sstevel@tonic-gate 	}
6319*0Sstevel@tonic-gate 
6320*0Sstevel@tonic-gate 	/*
6321*0Sstevel@tonic-gate 	 * If RequestIRQ has not been done, we don't allow this call.
6322*0Sstevel@tonic-gate 	 */
6323*0Sstevel@tonic-gate 	if (!(client->flags & REQ_IRQ_DONE)) {
6324*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6325*0Sstevel@tonic-gate 	    return (CS_IN_USE);
6326*0Sstevel@tonic-gate 	}
6327*0Sstevel@tonic-gate 
6328*0Sstevel@tonic-gate 	/*
6329*0Sstevel@tonic-gate 	 * Tell Socket Services that we want to deregister this client's
6330*0Sstevel@tonic-gate 	 *	IRQ handler.
6331*0Sstevel@tonic-gate 	 */
6332*0Sstevel@tonic-gate 	clear_irq_handler.socket =
6333*0Sstevel@tonic-gate 		CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle),
6334*0Sstevel@tonic-gate 				GET_CLIENT_FUNCTION(client_handle));
6335*0Sstevel@tonic-gate 	clear_irq_handler.handler_id = client->irq_alloc.handler_id;
6336*0Sstevel@tonic-gate 	clear_irq_handler.handler = (f_t *)client->irq_alloc.irq_handler;
6337*0Sstevel@tonic-gate 
6338*0Sstevel@tonic-gate 	/*
6339*0Sstevel@tonic-gate 	 * At this point, we should never fail this SS call; if we do, it
6340*0Sstevel@tonic-gate 	 *	means that there is an internal consistancy error in either
6341*0Sstevel@tonic-gate 	 *	Card Services or Socket Services.
6342*0Sstevel@tonic-gate 	 */
6343*0Sstevel@tonic-gate 	if ((error = SocketServices(SS_ClearIRQHandler, &clear_irq_handler)) !=
6344*0Sstevel@tonic-gate 								SUCCESS) {
6345*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6346*0Sstevel@tonic-gate 	    return (CS_BAD_IRQ);
6347*0Sstevel@tonic-gate 	}
6348*0Sstevel@tonic-gate 
6349*0Sstevel@tonic-gate 	/*
6350*0Sstevel@tonic-gate 	 * Mark the client as not having any IRQ resources allocated.
6351*0Sstevel@tonic-gate 	 */
6352*0Sstevel@tonic-gate 	client->flags &= ~(REQ_IRQ_DONE | CLIENT_IRQ_ALLOCATED);
6353*0Sstevel@tonic-gate 
6354*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6355*0Sstevel@tonic-gate 	return (CS_SUCCESS);
6356*0Sstevel@tonic-gate }
6357*0Sstevel@tonic-gate 
6358*0Sstevel@tonic-gate /*
6359*0Sstevel@tonic-gate  * ==== configuration handling functions ====
6360*0Sstevel@tonic-gate  */
6361*0Sstevel@tonic-gate 
6362*0Sstevel@tonic-gate /*
6363*0Sstevel@tonic-gate  * cs_request_configuration - sets up socket and card configuration on behalf
6364*0Sstevel@tonic-gate  *		of the client; this is RequestConfiguration
6365*0Sstevel@tonic-gate  *
6366*0Sstevel@tonic-gate  *	returns: CS_SUCCESS - if configuration sucessfully set
6367*0Sstevel@tonic-gate  *		 CS_BAD_SOCKET - if Socket Services returns an error
6368*0Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
6369*0Sstevel@tonic-gate  *		 CS_BAD_ATTRIBUTE - if any unsupported or reserved flags
6370*0Sstevel@tonic-gate  *					are set
6371*0Sstevel@tonic-gate  *		 CS_BAD_TYPE - if the socket doesn't support a mem and IO
6372*0Sstevel@tonic-gate  *				interface (SOCKET_INTERFACE_MEMORY_AND_IO set)
6373*0Sstevel@tonic-gate  *		 CS_CONFIGURATION_LOCKED - a RequestConfiguration has
6374*0Sstevel@tonic-gate  *					already been done
6375*0Sstevel@tonic-gate  *		 CS_BAD_VCC - if Vcc value is not supported by socket
6376*0Sstevel@tonic-gate  *		 CS_BAD_VPP1 - if Vpp1 value is not supported by socket
6377*0Sstevel@tonic-gate  *		 CS_BAD_VPP2 - if Vpp2 value is not supported by socket
6378*0Sstevel@tonic-gate  *
6379*0Sstevel@tonic-gate  * Bug ID: 1193637 - Card Services RequestConfiguration does not conform
6380*0Sstevel@tonic-gate  *	to PCMCIA standard
6381*0Sstevel@tonic-gate  * We allow clients to do a RequestConfiguration even if they haven't
6382*0Sstevel@tonic-gate  *	done a RequestIO or RequestIRQ.
6383*0Sstevel@tonic-gate  */
6384*0Sstevel@tonic-gate static int
6385*0Sstevel@tonic-gate cs_request_configuration(client_handle_t client_handle, config_req_t *cr)
6386*0Sstevel@tonic-gate {
6387*0Sstevel@tonic-gate 	cs_socket_t *sp;
6388*0Sstevel@tonic-gate 	client_t *client;
6389*0Sstevel@tonic-gate 	volatile config_regs_t *crt;
6390*0Sstevel@tonic-gate 	set_socket_t set_socket;
6391*0Sstevel@tonic-gate 	get_socket_t get_socket;
6392*0Sstevel@tonic-gate 	acc_handle_t cis_handle;
6393*0Sstevel@tonic-gate 	int error;
6394*0Sstevel@tonic-gate 	uint32_t newoffset;
6395*0Sstevel@tonic-gate 	int client_lock_acquired;
6396*0Sstevel@tonic-gate 
6397*0Sstevel@tonic-gate 	/*
6398*0Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
6399*0Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
6400*0Sstevel@tonic-gate 	 */
6401*0Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
6402*0Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
6403*0Sstevel@tonic-gate 
6404*0Sstevel@tonic-gate #ifdef	XXX
6405*0Sstevel@tonic-gate 	/*
6406*0Sstevel@tonic-gate 	 * If the client specifies Vcc = 0 and any non-zero value for
6407*0Sstevel@tonic-gate 	 *	either of the Vpp members, that's an illegal condition.
6408*0Sstevel@tonic-gate 	 */
6409*0Sstevel@tonic-gate 	if (!(cr->Vcc) && (cr->Vpp1 || cr->Vpp2))
6410*0Sstevel@tonic-gate 	    return (CS_BAD_VCC);
6411*0Sstevel@tonic-gate #endif
6412*0Sstevel@tonic-gate 
6413*0Sstevel@tonic-gate 	/*
6414*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
6415*0Sstevel@tonic-gate 	 */
6416*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
6417*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
6418*0Sstevel@tonic-gate 
6419*0Sstevel@tonic-gate 	/*
6420*0Sstevel@tonic-gate 	 * If the client is asking for a memory and IO interface on this
6421*0Sstevel@tonic-gate 	 *	socket, then check the socket capabilities to be sure that
6422*0Sstevel@tonic-gate 	 *	this socket supports this configuration.
6423*0Sstevel@tonic-gate 	 */
6424*0Sstevel@tonic-gate 	if (cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO) {
6425*0Sstevel@tonic-gate 	    inquire_socket_t inquire_socket;
6426*0Sstevel@tonic-gate 
6427*0Sstevel@tonic-gate 	    inquire_socket.socket = sp->socket_num;
6428*0Sstevel@tonic-gate 
6429*0Sstevel@tonic-gate 	    if (SocketServices(SS_InquireSocket, &inquire_socket) != SUCCESS)
6430*0Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
6431*0Sstevel@tonic-gate 
6432*0Sstevel@tonic-gate 	    if (!(inquire_socket.SocketCaps & IF_IO))
6433*0Sstevel@tonic-gate 		return (CS_BAD_TYPE);
6434*0Sstevel@tonic-gate 
6435*0Sstevel@tonic-gate 	} /* if (SOCKET_INTERFACE_MEMORY_AND_IO) */
6436*0Sstevel@tonic-gate 
6437*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
6438*0Sstevel@tonic-gate 
6439*0Sstevel@tonic-gate 	/*
6440*0Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
6441*0Sstevel@tonic-gate 	 */
6442*0Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
6443*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6444*0Sstevel@tonic-gate 	    return (error);
6445*0Sstevel@tonic-gate 	}
6446*0Sstevel@tonic-gate 
6447*0Sstevel@tonic-gate 	/*
6448*0Sstevel@tonic-gate 	 * If RequestConfiguration has already been done, we don't allow
6449*0Sstevel@tonic-gate 	 *	this call.
6450*0Sstevel@tonic-gate 	 */
6451*0Sstevel@tonic-gate 	if (client->flags & REQ_CONFIGURATION_DONE) {
6452*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6453*0Sstevel@tonic-gate 	    return (CS_CONFIGURATION_LOCKED);
6454*0Sstevel@tonic-gate 	}
6455*0Sstevel@tonic-gate 
6456*0Sstevel@tonic-gate 	/*
6457*0Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
6458*0Sstevel@tonic-gate 	 *	for this client, then return an error.
6459*0Sstevel@tonic-gate 	 */
6460*0Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
6461*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6462*0Sstevel@tonic-gate 	    return (CS_NO_CARD);
6463*0Sstevel@tonic-gate 	}
6464*0Sstevel@tonic-gate 
6465*0Sstevel@tonic-gate 	/*
6466*0Sstevel@tonic-gate 	 * At this point, most of the client's calling parameters have been
6467*0Sstevel@tonic-gate 	 *	validated, so we can go ahead and configure the socket and
6468*0Sstevel@tonic-gate 	 *	the card.
6469*0Sstevel@tonic-gate 	 */
6470*0Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
6471*0Sstevel@tonic-gate 
6472*0Sstevel@tonic-gate 	/*
6473*0Sstevel@tonic-gate 	 * Configure the socket with the interface type and voltages requested
6474*0Sstevel@tonic-gate 	 *	by the client.
6475*0Sstevel@tonic-gate 	 */
6476*0Sstevel@tonic-gate 	get_socket.socket = sp->socket_num;
6477*0Sstevel@tonic-gate 
6478*0Sstevel@tonic-gate 	if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
6479*0Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
6480*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6481*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
6482*0Sstevel@tonic-gate 	}
6483*0Sstevel@tonic-gate 
6484*0Sstevel@tonic-gate #ifdef	CS_DEBUG
6485*0Sstevel@tonic-gate 	if (cs_debug > 0)
6486*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_request_configuration: socket %d "
6487*0Sstevel@tonic-gate 					"client->irq_alloc.irq 0x%x "
6488*0Sstevel@tonic-gate 					"get_socket.IRQRouting 0x%x\n",
6489*0Sstevel@tonic-gate 						sp->socket_num,
6490*0Sstevel@tonic-gate 						(int)client->irq_alloc.irq,
6491*0Sstevel@tonic-gate 						get_socket.IRQRouting);
6492*0Sstevel@tonic-gate #endif
6493*0Sstevel@tonic-gate 
6494*0Sstevel@tonic-gate 	bzero(&set_socket, sizeof (set_socket));
6495*0Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
6496*0Sstevel@tonic-gate 	set_socket.IREQRouting = client->irq_alloc.irq & ~IRQ_ENABLE;
6497*0Sstevel@tonic-gate 
6498*0Sstevel@tonic-gate 	set_socket.CtlInd = get_socket.CtlInd;
6499*0Sstevel@tonic-gate 	set_socket.State = 0;	/* don't reset latched values */
6500*0Sstevel@tonic-gate 
6501*0Sstevel@tonic-gate 	if (cs_convert_powerlevel(sp->socket_num, cr->Vcc, VCC,
6502*0Sstevel@tonic-gate 					&set_socket.VccLevel) != CS_SUCCESS) {
6503*0Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
6504*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6505*0Sstevel@tonic-gate 	    return (CS_BAD_VCC);
6506*0Sstevel@tonic-gate 	}
6507*0Sstevel@tonic-gate 
6508*0Sstevel@tonic-gate 	if (cs_convert_powerlevel(sp->socket_num, cr->Vpp1, VPP1,
6509*0Sstevel@tonic-gate 					&set_socket.Vpp1Level) != CS_SUCCESS) {
6510*0Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
6511*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6512*0Sstevel@tonic-gate 	    return (CS_BAD_VPP);
6513*0Sstevel@tonic-gate 	}
6514*0Sstevel@tonic-gate 
6515*0Sstevel@tonic-gate 	if (cs_convert_powerlevel(sp->socket_num, cr->Vpp2, VPP2,
6516*0Sstevel@tonic-gate 					&set_socket.Vpp2Level) != CS_SUCCESS) {
6517*0Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
6518*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6519*0Sstevel@tonic-gate 	    return (CS_BAD_VPP);
6520*0Sstevel@tonic-gate 	}
6521*0Sstevel@tonic-gate 
6522*0Sstevel@tonic-gate 	if (!(cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO))
6523*0Sstevel@tonic-gate 		set_socket.IFType = IF_MEMORY;
6524*0Sstevel@tonic-gate 	else {
6525*0Sstevel@tonic-gate 		set_socket.IFType = IF_IO;
6526*0Sstevel@tonic-gate 
6527*0Sstevel@tonic-gate 		/*
6528*0Sstevel@tonic-gate 		 * The Cirrus Logic PD6710/672X/others? adapters will write
6529*0Sstevel@tonic-gate 		 * protect the CIS if the socket is in MEMORY mode and the
6530*0Sstevel@tonic-gate 		 * WP/IOCS16 pin is true.  When this happens, the CIS registers
6531*0Sstevel@tonic-gate 		 * will fail to be written.  Go ahead and set the socket,
6532*0Sstevel@tonic-gate 		 * even though the event mask isn't complete yet, so we can
6533*0Sstevel@tonic-gate 		 * configure the adapter.  Afterwards, set the socket again
6534*0Sstevel@tonic-gate 		 * to make sure the event mask is correct.
6535*0Sstevel@tonic-gate 		 */
6536*0Sstevel@tonic-gate 		if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
6537*0Sstevel@tonic-gate 			sp->flags &= ~SOCKET_IS_IO;
6538*0Sstevel@tonic-gate 			mutex_exit(&sp->cis_lock);
6539*0Sstevel@tonic-gate 			EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6540*0Sstevel@tonic-gate 			return (CS_BAD_SOCKET);
6541*0Sstevel@tonic-gate 		}
6542*0Sstevel@tonic-gate 	}
6543*0Sstevel@tonic-gate 
6544*0Sstevel@tonic-gate 	if (cs_rc2_delay)
6545*0Sstevel@tonic-gate 	    drv_usecwait(cs_rc2_delay * 1000);
6546*0Sstevel@tonic-gate 
6547*0Sstevel@tonic-gate 	/*
6548*0Sstevel@tonic-gate 	 * Get a pointer to a window that contains the configuration
6549*0Sstevel@tonic-gate 	 *	registers.
6550*0Sstevel@tonic-gate 	 */
6551*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
6552*0Sstevel@tonic-gate 	client->config_regs_offset = cr->ConfigBase;
6553*0Sstevel@tonic-gate 	newoffset = client->config_regs_offset;
6554*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
6555*0Sstevel@tonic-gate 	if (cs_init_cis_window(sp, &newoffset, &cis_handle,
6556*0Sstevel@tonic-gate 					CISTPLF_AM_SPACE) != CS_SUCCESS) {
6557*0Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
6558*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6559*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_request_configuration: socket %d can't init "
6560*0Sstevel@tonic-gate 				"CIS window\n", sp->socket_num);
6561*0Sstevel@tonic-gate 	    return (CS_GENERAL_FAILURE);
6562*0Sstevel@tonic-gate 	}
6563*0Sstevel@tonic-gate 
6564*0Sstevel@tonic-gate 	/*
6565*0Sstevel@tonic-gate 	 * Setup the config register pointers.
6566*0Sstevel@tonic-gate 	 * Note that these pointers are not the complete virtual address;
6567*0Sstevel@tonic-gate 	 *	the complete address is constructed each time the registers
6568*0Sstevel@tonic-gate 	 *	are accessed.
6569*0Sstevel@tonic-gate 	 */
6570*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
6571*0Sstevel@tonic-gate 	crt = &client->config_regs;
6572*0Sstevel@tonic-gate 	client->present = cr->Present;
6573*0Sstevel@tonic-gate 
6574*0Sstevel@tonic-gate 	bzero((char *)crt, sizeof (config_regs_t));
6575*0Sstevel@tonic-gate 
6576*0Sstevel@tonic-gate 	/* Configuration Option Register */
6577*0Sstevel@tonic-gate 	if (client->present & CONFIG_OPTION_REG_PRESENT)
6578*0Sstevel@tonic-gate 	    crt->cor_p = (newoffset + CONFIG_OPTION_REG_OFFSET);
6579*0Sstevel@tonic-gate 
6580*0Sstevel@tonic-gate 	/* Configuration and Status Register */
6581*0Sstevel@tonic-gate 	if (client->present & CONFIG_STATUS_REG_PRESENT)
6582*0Sstevel@tonic-gate 	    crt->ccsr_p = (newoffset + CONFIG_STATUS_REG_OFFSET);
6583*0Sstevel@tonic-gate 
6584*0Sstevel@tonic-gate 	/* Pin Replacement Register */
6585*0Sstevel@tonic-gate 	if (client->present & CONFIG_PINREPL_REG_PRESENT)
6586*0Sstevel@tonic-gate 	    crt->prr_p = (newoffset + CONFIG_PINREPL_REG_OFFSET);
6587*0Sstevel@tonic-gate 
6588*0Sstevel@tonic-gate 	/* Socket and Copy Register */
6589*0Sstevel@tonic-gate 	if (client->present & CONFIG_COPY_REG_PRESENT)
6590*0Sstevel@tonic-gate 	    crt->scr_p = (newoffset + CONFIG_COPY_REG_OFFSET);
6591*0Sstevel@tonic-gate 
6592*0Sstevel@tonic-gate 	/* Extended Status Register */
6593*0Sstevel@tonic-gate 	if (client->present & CONFIG_EXSTAT_REG_PRESENT)
6594*0Sstevel@tonic-gate 	    crt->exstat_p = (newoffset + CONFIG_EXSTAT_REG_OFFSET);
6595*0Sstevel@tonic-gate 
6596*0Sstevel@tonic-gate 	/* IO Base 0 Register */
6597*0Sstevel@tonic-gate 	if (client->present & CONFIG_IOBASE0_REG_PRESENT)
6598*0Sstevel@tonic-gate 	    crt->iobase0_p = (newoffset + CONFIG_IOBASE0_REG_OFFSET);
6599*0Sstevel@tonic-gate 
6600*0Sstevel@tonic-gate 	/* IO Base 1 Register */
6601*0Sstevel@tonic-gate 	if (client->present & CONFIG_IOBASE1_REG_PRESENT)
6602*0Sstevel@tonic-gate 	    crt->iobase1_p = (newoffset + CONFIG_IOBASE1_REG_OFFSET);
6603*0Sstevel@tonic-gate 
6604*0Sstevel@tonic-gate 	/* IO Base 2 Register */
6605*0Sstevel@tonic-gate 	if (client->present & CONFIG_IOBASE2_REG_PRESENT)
6606*0Sstevel@tonic-gate 	    crt->iobase2_p = (newoffset + CONFIG_IOBASE2_REG_OFFSET);
6607*0Sstevel@tonic-gate 
6608*0Sstevel@tonic-gate 	/* IO Base 3 Register */
6609*0Sstevel@tonic-gate 	if (client->present & CONFIG_IOBASE3_REG_PRESENT)
6610*0Sstevel@tonic-gate 	    crt->iobase3_p = (newoffset + CONFIG_IOBASE3_REG_OFFSET);
6611*0Sstevel@tonic-gate 
6612*0Sstevel@tonic-gate 	/* IO Limit Register */
6613*0Sstevel@tonic-gate 	if (client->present & CONFIG_IOLIMIT_REG_PRESENT)
6614*0Sstevel@tonic-gate 	    crt->iolimit_p = (newoffset + CONFIG_IOLIMIT_REG_OFFSET);
6615*0Sstevel@tonic-gate 
6616*0Sstevel@tonic-gate 	/*
6617*0Sstevel@tonic-gate 	 * Setup the bits in the PRR mask that are valid; this is easy, just
6618*0Sstevel@tonic-gate 	 *	copy the Pin value that the client gave us.  Note that for
6619*0Sstevel@tonic-gate 	 *	this to work, the client must set both of the XXX_STATUS
6620*0Sstevel@tonic-gate 	 *	and the XXX_EVENT bits in the Pin member.
6621*0Sstevel@tonic-gate 	 */
6622*0Sstevel@tonic-gate 	client->pin = cr->Pin;
6623*0Sstevel@tonic-gate 
6624*0Sstevel@tonic-gate #ifdef	CS_DEBUG
6625*0Sstevel@tonic-gate 	if (cs_debug > 128)
6626*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_request_configuration: client->pin 0x%x "
6627*0Sstevel@tonic-gate 		"client->config_regs_offset 0x%x newoffset 0x%x cor_p 0x%x "
6628*0Sstevel@tonic-gate 		"ccsr_p 0x%x prr_p 0x%x scr_p 0x%x\n",
6629*0Sstevel@tonic-gate 		client->pin, (int)client->config_regs_offset, newoffset,
6630*0Sstevel@tonic-gate 		(int)crt->cor_p, (int)crt->ccsr_p, (int)crt->prr_p,
6631*0Sstevel@tonic-gate 		(int)crt->scr_p);
6632*0Sstevel@tonic-gate #endif
6633*0Sstevel@tonic-gate 
6634*0Sstevel@tonic-gate 	/*
6635*0Sstevel@tonic-gate 	 * If the socket isn't in IO mode, WP is asserted,  and we're going to
6636*0Sstevel@tonic-gate 	 * write any of the config registers, issue a warning.
6637*0Sstevel@tonic-gate 	 */
6638*0Sstevel@tonic-gate 	if ((client->present != 0) &&
6639*0Sstevel@tonic-gate 	    (!(cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO)) &&
6640*0Sstevel@tonic-gate 	    (get_socket.state & SBM_WP)) {
6641*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "!cs_request_configuration: attempting to "
6642*0Sstevel@tonic-gate 		    "write CIS config regs with WP set\n");
6643*0Sstevel@tonic-gate 	}
6644*0Sstevel@tonic-gate 
6645*0Sstevel@tonic-gate 	/*
6646*0Sstevel@tonic-gate 	 * Write any configuration registers that the client tells us are
6647*0Sstevel@tonic-gate 	 *	present to the card; save a copy of what we wrote so that we
6648*0Sstevel@tonic-gate 	 *	can return them if the client calls GetConfigurationInfo.
6649*0Sstevel@tonic-gate 	 * The order in which we write the configuration registers is
6650*0Sstevel@tonic-gate 	 *	specified by the PCMCIA spec; we must write the socket/copy
6651*0Sstevel@tonic-gate 	 *	register first (if it exists), and then we can write the
6652*0Sstevel@tonic-gate 	 *	registers in any arbitrary order.
6653*0Sstevel@tonic-gate 	 */
6654*0Sstevel@tonic-gate 	/* Socket and Copy Register */
6655*0Sstevel@tonic-gate 	if (client->present & CONFIG_COPY_REG_PRESENT) {
6656*0Sstevel@tonic-gate 	    crt->scr = cr->Copy;
6657*0Sstevel@tonic-gate 	    csx_Put8(cis_handle, crt->scr_p, crt->scr);
6658*0Sstevel@tonic-gate 	}
6659*0Sstevel@tonic-gate 
6660*0Sstevel@tonic-gate 	/* Pin Replacement Register */
6661*0Sstevel@tonic-gate 	if (client->present & CONFIG_PINREPL_REG_PRESENT) {
6662*0Sstevel@tonic-gate 	    crt->prr = cr->Pin;
6663*0Sstevel@tonic-gate 	    csx_Put8(cis_handle, crt->prr_p, crt->prr);
6664*0Sstevel@tonic-gate 	}
6665*0Sstevel@tonic-gate 
6666*0Sstevel@tonic-gate 	/* Configuration and Status Register */
6667*0Sstevel@tonic-gate 	/* XXX should we set CCSR_SIG_CHG in the CCSR? XXX */
6668*0Sstevel@tonic-gate 	if (client->present & CONFIG_STATUS_REG_PRESENT) {
6669*0Sstevel@tonic-gate 	    crt->ccsr = cr->Status;
6670*0Sstevel@tonic-gate 	    csx_Put8(cis_handle, crt->ccsr_p, crt->ccsr);
6671*0Sstevel@tonic-gate 	}
6672*0Sstevel@tonic-gate 
6673*0Sstevel@tonic-gate 	/* Extended Status Register */
6674*0Sstevel@tonic-gate 	if (client->present & CONFIG_EXSTAT_REG_PRESENT) {
6675*0Sstevel@tonic-gate 	    crt->exstat = cr->ExtendedStatus;
6676*0Sstevel@tonic-gate 	    csx_Put8(cis_handle, crt->exstat_p, crt->exstat);
6677*0Sstevel@tonic-gate 	}
6678*0Sstevel@tonic-gate 
6679*0Sstevel@tonic-gate 	/*
6680*0Sstevel@tonic-gate 	 * If any IO base and limit registers exist, and this client
6681*0Sstevel@tonic-gate 	 *	has done a RequestIO, setup the IO Base and IO Limit
6682*0Sstevel@tonic-gate 	 *	registers.
6683*0Sstevel@tonic-gate 	 */
6684*0Sstevel@tonic-gate 	if (client->flags & REQ_IO_DONE) {
6685*0Sstevel@tonic-gate 	    if (client->present & CONFIG_IOBASE0_REG_PRESENT) {
6686*0Sstevel@tonic-gate 		uint32_t base = client->io_alloc.BasePort1.base;
6687*0Sstevel@tonic-gate 		uint32_t present = (client->present &
6688*0Sstevel@tonic-gate 					CONFIG_IOBASE_REG_MASK) >>
6689*0Sstevel@tonic-gate 						CONFIG_IOBASE_REG_SHIFT;
6690*0Sstevel@tonic-gate 		uint32_t reg = crt->iobase0_p;
6691*0Sstevel@tonic-gate 
6692*0Sstevel@tonic-gate 		do {
6693*0Sstevel@tonic-gate 		    csx_Put8(cis_handle, reg, base & 0x0ff);
6694*0Sstevel@tonic-gate 		    reg = reg + 2;
6695*0Sstevel@tonic-gate 		    base = base >> 8;
6696*0Sstevel@tonic-gate 		    present = present >> 1;
6697*0Sstevel@tonic-gate 		} while (present);
6698*0Sstevel@tonic-gate 	    } /* CONFIG_IOBASE0_REG_PRESENT */
6699*0Sstevel@tonic-gate 
6700*0Sstevel@tonic-gate 	    if (client->present & CONFIG_IOLIMIT_REG_PRESENT) {
6701*0Sstevel@tonic-gate 		uint32_t np = client->io_alloc.NumPorts1 +
6702*0Sstevel@tonic-gate 					client->io_alloc.NumPorts2;
6703*0Sstevel@tonic-gate 		uint32_t limit, do_bit = 0;
6704*0Sstevel@tonic-gate 		int lm;
6705*0Sstevel@tonic-gate 
6706*0Sstevel@tonic-gate 		limit = (IONUMPORTS_FROBNITZ(np) - 1);
6707*0Sstevel@tonic-gate 
6708*0Sstevel@tonic-gate 		for (lm = 7; lm >= 0; lm--) {
6709*0Sstevel@tonic-gate 		    if (limit & (1 << lm))
6710*0Sstevel@tonic-gate 			do_bit = 1;
6711*0Sstevel@tonic-gate 		    if (do_bit)
6712*0Sstevel@tonic-gate 			limit |= (1 << lm);
6713*0Sstevel@tonic-gate 		} /* for */
6714*0Sstevel@tonic-gate 
6715*0Sstevel@tonic-gate 		csx_Put8(cis_handle, crt->iolimit_p, limit);
6716*0Sstevel@tonic-gate 	    } /* CONFIG_IOLIMIT_REG_PRESENT */
6717*0Sstevel@tonic-gate 	} /* REQ_IO_DONE */
6718*0Sstevel@tonic-gate 
6719*0Sstevel@tonic-gate 	/*
6720*0Sstevel@tonic-gate 	 * Mark the socket as being in IO mode.
6721*0Sstevel@tonic-gate 	 */
6722*0Sstevel@tonic-gate 	if (cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO)
6723*0Sstevel@tonic-gate 	    sp->flags |= SOCKET_IS_IO;
6724*0Sstevel@tonic-gate 
6725*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
6726*0Sstevel@tonic-gate 
6727*0Sstevel@tonic-gate 	/*
6728*0Sstevel@tonic-gate 	 * Enable the interrupt if needed
6729*0Sstevel@tonic-gate 	 */
6730*0Sstevel@tonic-gate 	if (cr->Attributes & CONF_ENABLE_IRQ_STEERING)
6731*0Sstevel@tonic-gate 	    set_socket.IREQRouting |= IRQ_ENABLE;
6732*0Sstevel@tonic-gate 
6733*0Sstevel@tonic-gate 	/*
6734*0Sstevel@tonic-gate 	 * Now that we know if the PRR is present and if it is, which
6735*0Sstevel@tonic-gate 	 *	bits in the PRR are valid, we can construct the correct
6736*0Sstevel@tonic-gate 	 *	socket event mask.
6737*0Sstevel@tonic-gate 	 */
6738*0Sstevel@tonic-gate 	set_socket.SCIntMask = cs_merge_event_masks(sp, client);
6739*0Sstevel@tonic-gate 
6740*0Sstevel@tonic-gate 	/*
6741*0Sstevel@tonic-gate 	 * Configuration Option Register - we handle this specially since
6742*0Sstevel@tonic-gate 	 *	we don't allow the client to manipulate the RESET or
6743*0Sstevel@tonic-gate 	 *	INTERRUPT bits (although a client can manipulate these
6744*0Sstevel@tonic-gate 	 *	bits via an AccessConfigurationRegister call - explain
6745*0Sstevel@tonic-gate 	 *	THAT logic to me).
6746*0Sstevel@tonic-gate 	 * XXX - we force level-mode interrupts (COR_LEVEL_IRQ)
6747*0Sstevel@tonic-gate 	 * XXX - we always enable the function on a multi-function card
6748*0Sstevel@tonic-gate 	 */
6749*0Sstevel@tonic-gate 	if (client->present & CONFIG_OPTION_REG_PRESENT) {
6750*0Sstevel@tonic-gate 	    crt->cor = (cr->ConfigIndex & ~COR_SOFT_RESET) | COR_LEVEL_IRQ;
6751*0Sstevel@tonic-gate 	    if (client->present & CONFIG_IOBASE0_REG_PRESENT)
6752*0Sstevel@tonic-gate 		crt->cor |= COR_ENABLE_BASE_LIMIT;
6753*0Sstevel@tonic-gate 	    if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
6754*0Sstevel@tonic-gate 		crt->cor |= COR_ENABLE_FUNCTION;
6755*0Sstevel@tonic-gate 		crt->cor &= ~COR_ENABLE_IREQ_ROUTING;
6756*0Sstevel@tonic-gate 		if (cr->Attributes & CONF_ENABLE_IRQ_STEERING)
6757*0Sstevel@tonic-gate 		    crt->cor |= COR_ENABLE_IREQ_ROUTING;
6758*0Sstevel@tonic-gate 	    } /* CW_MULTI_FUNCTION_CIS */
6759*0Sstevel@tonic-gate 
6760*0Sstevel@tonic-gate #ifdef  CS_DEBUG
6761*0Sstevel@tonic-gate 	if (cs_debug > 0)
6762*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_request_configuration "
6763*0Sstevel@tonic-gate 		    "cor=x%x ConfigIndex=x%x Attributes=x%x flags=x%x\n"
6764*0Sstevel@tonic-gate 		    "present=x%x cis_handle=%p cor_p=x%x\n",
6765*0Sstevel@tonic-gate 		    crt->cor, cr->ConfigIndex, cr->Attributes, sp->cis_flags,
6766*0Sstevel@tonic-gate 		    client->present, cis_handle, crt->cor_p);
6767*0Sstevel@tonic-gate #endif
6768*0Sstevel@tonic-gate 
6769*0Sstevel@tonic-gate 	    csx_Put8(cis_handle, crt->cor_p, crt->cor);
6770*0Sstevel@tonic-gate 	} /* CONFIG_OPTION_REG_PRESENT */
6771*0Sstevel@tonic-gate 
6772*0Sstevel@tonic-gate 	if (cs_rc1_delay)
6773*0Sstevel@tonic-gate 	    drv_usecwait(cs_rc1_delay * 1000);
6774*0Sstevel@tonic-gate 
6775*0Sstevel@tonic-gate 	/*
6776*0Sstevel@tonic-gate 	 * Set the socket to the parameters that the client requested.
6777*0Sstevel@tonic-gate 	 */
6778*0Sstevel@tonic-gate 	if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
6779*0Sstevel@tonic-gate 	    if (client->present & CONFIG_OPTION_REG_PRESENT) {
6780*0Sstevel@tonic-gate 		crt->cor = 0; /* XXX is 0 the right thing here? */
6781*0Sstevel@tonic-gate 		csx_Put8(cis_handle, crt->cor_p, crt->cor);
6782*0Sstevel@tonic-gate 	    }
6783*0Sstevel@tonic-gate 	    sp->flags &= ~SOCKET_IS_IO;
6784*0Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
6785*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6786*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
6787*0Sstevel@tonic-gate 	}
6788*0Sstevel@tonic-gate 
6789*0Sstevel@tonic-gate 	if (cs_rc2_delay)
6790*0Sstevel@tonic-gate 	    drv_usecwait(cs_rc2_delay * 1000);
6791*0Sstevel@tonic-gate 
6792*0Sstevel@tonic-gate 	/*
6793*0Sstevel@tonic-gate 	 * Mark this client as having done a successful RequestConfiguration
6794*0Sstevel@tonic-gate 	 *	call.
6795*0Sstevel@tonic-gate 	 */
6796*0Sstevel@tonic-gate 	client->flags |= REQ_CONFIGURATION_DONE;
6797*0Sstevel@tonic-gate 
6798*0Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
6799*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6800*0Sstevel@tonic-gate 
6801*0Sstevel@tonic-gate 	return (CS_SUCCESS);
6802*0Sstevel@tonic-gate }
6803*0Sstevel@tonic-gate 
6804*0Sstevel@tonic-gate /*
6805*0Sstevel@tonic-gate  * cs_release_configuration - releases configuration previously set via the
6806*0Sstevel@tonic-gate  *		RequestConfiguration call; this is ReleaseConfiguration
6807*0Sstevel@tonic-gate  *
6808*0Sstevel@tonic-gate  *	returns: CS_SUCCESS - if configuration sucessfully released
6809*0Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
6810*0Sstevel@tonic-gate  *		 CS_BAD_SOCKET - if Socket Services returns an error
6811*0Sstevel@tonic-gate  *		 CS_BAD_HANDLE - a RequestConfiguration has not been done
6812*0Sstevel@tonic-gate  */
6813*0Sstevel@tonic-gate /*ARGSUSED*/
6814*0Sstevel@tonic-gate static int
6815*0Sstevel@tonic-gate cs_release_configuration(client_handle_t client_handle, release_config_t *rcfg)
6816*0Sstevel@tonic-gate {
6817*0Sstevel@tonic-gate 	cs_socket_t *sp;
6818*0Sstevel@tonic-gate 	client_t *client;
6819*0Sstevel@tonic-gate 	volatile config_regs_t *crt;
6820*0Sstevel@tonic-gate 	set_socket_t set_socket;
6821*0Sstevel@tonic-gate 	get_socket_t get_socket;
6822*0Sstevel@tonic-gate 	acc_handle_t cis_handle;
6823*0Sstevel@tonic-gate 	int error;
6824*0Sstevel@tonic-gate 	uint32_t newoffset;
6825*0Sstevel@tonic-gate 	int client_lock_acquired;
6826*0Sstevel@tonic-gate 
6827*0Sstevel@tonic-gate 	/*
6828*0Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
6829*0Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
6830*0Sstevel@tonic-gate 	 */
6831*0Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
6832*0Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
6833*0Sstevel@tonic-gate 
6834*0Sstevel@tonic-gate 	/*
6835*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
6836*0Sstevel@tonic-gate 	 */
6837*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
6838*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
6839*0Sstevel@tonic-gate 
6840*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
6841*0Sstevel@tonic-gate 
6842*0Sstevel@tonic-gate 	/*
6843*0Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
6844*0Sstevel@tonic-gate 	 */
6845*0Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
6846*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6847*0Sstevel@tonic-gate 	    return (error);
6848*0Sstevel@tonic-gate 	}
6849*0Sstevel@tonic-gate 
6850*0Sstevel@tonic-gate 	/*
6851*0Sstevel@tonic-gate 	 * If RequestConfiguration has not been done, we don't allow
6852*0Sstevel@tonic-gate 	 *	this call.
6853*0Sstevel@tonic-gate 	 */
6854*0Sstevel@tonic-gate 	if (!(client->flags & REQ_CONFIGURATION_DONE)) {
6855*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6856*0Sstevel@tonic-gate 	    return (CS_BAD_HANDLE);
6857*0Sstevel@tonic-gate 	}
6858*0Sstevel@tonic-gate 
6859*0Sstevel@tonic-gate #ifdef  CS_DEBUG
6860*0Sstevel@tonic-gate 	if (cs_debug > 0)
6861*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_release_configuration: "
6862*0Sstevel@tonic-gate 		    "flags=0x%x CW_MULTI_FUNCTION_CIS =0x%x \n",
6863*0Sstevel@tonic-gate 		    sp->cis_flags, CW_MULTI_FUNCTION_CIS);
6864*0Sstevel@tonic-gate 
6865*0Sstevel@tonic-gate #endif
6866*0Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
6867*0Sstevel@tonic-gate 
6868*0Sstevel@tonic-gate 	/*
6869*0Sstevel@tonic-gate 	 * Set the card back to a memory-only interface byte writing a zero
6870*0Sstevel@tonic-gate 	 *	to the COR.  Note that we don't update our soft copy of the
6871*0Sstevel@tonic-gate 	 *	COR state since the PCMCIA spec only requires us to maintain
6872*0Sstevel@tonic-gate 	 *	the last value that was written to that register during a
6873*0Sstevel@tonic-gate 	 *	call to RequestConfiguration.
6874*0Sstevel@tonic-gate 	 */
6875*0Sstevel@tonic-gate 	crt = &client->config_regs;
6876*0Sstevel@tonic-gate 
6877*0Sstevel@tonic-gate 	newoffset = client->config_regs_offset;
6878*0Sstevel@tonic-gate 	if (cs_init_cis_window(sp, &newoffset, &cis_handle,
6879*0Sstevel@tonic-gate 					CISTPLF_AM_SPACE) != CS_SUCCESS) {
6880*0Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
6881*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6882*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_release_configuration: socket %d can't init "
6883*0Sstevel@tonic-gate 				"CIS window\n", sp->socket_num);
6884*0Sstevel@tonic-gate 	    return (CS_GENERAL_FAILURE);
6885*0Sstevel@tonic-gate 	}
6886*0Sstevel@tonic-gate 
6887*0Sstevel@tonic-gate 	if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) {
6888*0Sstevel@tonic-gate 		/*
6889*0Sstevel@tonic-gate 		 * For the Multifunction cards do not reset the socket
6890*0Sstevel@tonic-gate 		 * to a memory only interface but do clear the
6891*0Sstevel@tonic-gate 		 * Configuration Option Register and  mark this client
6892*0Sstevel@tonic-gate 		 * as not having a configuration by clearing the
6893*0Sstevel@tonic-gate 		 * REQ_CONFIGURATION_DONE flag.
6894*0Sstevel@tonic-gate 		 */
6895*0Sstevel@tonic-gate 		client->flags &= ~REQ_CONFIGURATION_DONE;
6896*0Sstevel@tonic-gate 		csx_Put8(cis_handle, crt->cor_p, 0);
6897*0Sstevel@tonic-gate 
6898*0Sstevel@tonic-gate 		mutex_exit(&sp->cis_lock);
6899*0Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6900*0Sstevel@tonic-gate 		return (CS_SUCCESS);
6901*0Sstevel@tonic-gate 	}
6902*0Sstevel@tonic-gate 
6903*0Sstevel@tonic-gate 	/*
6904*0Sstevel@tonic-gate 	 * Set the socket back to a memory-only interface; don't change
6905*0Sstevel@tonic-gate 	 *	any other parameter of the socket.
6906*0Sstevel@tonic-gate 	 */
6907*0Sstevel@tonic-gate 	get_socket.socket = sp->socket_num;
6908*0Sstevel@tonic-gate 
6909*0Sstevel@tonic-gate 	if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
6910*0Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
6911*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6912*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
6913*0Sstevel@tonic-gate 	}
6914*0Sstevel@tonic-gate 
6915*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
6916*0Sstevel@tonic-gate 	sp->flags &= ~SOCKET_IS_IO;
6917*0Sstevel@tonic-gate 	set_socket.SCIntMask = cs_merge_event_masks(sp, client);
6918*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
6919*0Sstevel@tonic-gate 
6920*0Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
6921*0Sstevel@tonic-gate 	set_socket.IREQRouting = 0;
6922*0Sstevel@tonic-gate 	set_socket.CtlInd = get_socket.CtlInd;
6923*0Sstevel@tonic-gate 	set_socket.State = 0;	/* don't reset latched values */
6924*0Sstevel@tonic-gate 	set_socket.VccLevel = get_socket.VccLevel;
6925*0Sstevel@tonic-gate 	set_socket.Vpp1Level = get_socket.Vpp1Level;
6926*0Sstevel@tonic-gate 	set_socket.Vpp2Level = get_socket.Vpp2Level;
6927*0Sstevel@tonic-gate 	set_socket.IFType = IF_MEMORY;
6928*0Sstevel@tonic-gate 
6929*0Sstevel@tonic-gate #if defined(__i386) || defined(__amd64)
6930*0Sstevel@tonic-gate 	/*
6931*0Sstevel@tonic-gate 	 * Some adapters (PD67xx) can write-protect the CIS when the
6932*0Sstevel@tonic-gate 	 * socket is in memory mode
6933*0Sstevel@tonic-gate 	 */
6934*0Sstevel@tonic-gate 	if (client->present & CONFIG_OPTION_REG_PRESENT)
6935*0Sstevel@tonic-gate 	    csx_Put8(cis_handle, crt->cor_p, COR_SOFT_RESET);
6936*0Sstevel@tonic-gate 
6937*0Sstevel@tonic-gate 	if (cs_rq_delay)
6938*0Sstevel@tonic-gate 	    drv_usecwait(cs_rq_delay * 1000);
6939*0Sstevel@tonic-gate #endif
6940*0Sstevel@tonic-gate 
6941*0Sstevel@tonic-gate 	if (client->present & CONFIG_OPTION_REG_PRESENT)
6942*0Sstevel@tonic-gate 	    csx_Put8(cis_handle, crt->cor_p, 0);
6943*0Sstevel@tonic-gate 
6944*0Sstevel@tonic-gate 	if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
6945*0Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
6946*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6947*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
6948*0Sstevel@tonic-gate 	}
6949*0Sstevel@tonic-gate 
6950*0Sstevel@tonic-gate 	/*
6951*0Sstevel@tonic-gate 	 * Mark this client as not having a configuration.
6952*0Sstevel@tonic-gate 	 */
6953*0Sstevel@tonic-gate 	client->flags &= ~REQ_CONFIGURATION_DONE;
6954*0Sstevel@tonic-gate 
6955*0Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
6956*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
6957*0Sstevel@tonic-gate 
6958*0Sstevel@tonic-gate 	return (CS_SUCCESS);
6959*0Sstevel@tonic-gate }
6960*0Sstevel@tonic-gate 
6961*0Sstevel@tonic-gate /*
6962*0Sstevel@tonic-gate  * cs_modify_configuration - modifies a configuration established by
6963*0Sstevel@tonic-gate  *		RequestConfiguration; this is ModifyConfiguration
6964*0Sstevel@tonic-gate  *
6965*0Sstevel@tonic-gate  *	returns: CS_SUCCESS - if configuration sucessfully modified
6966*0Sstevel@tonic-gate  *		 CS_BAD_SOCKET - if Socket Services returns an error
6967*0Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
6968*0Sstevel@tonic-gate  *		 CS_BAD_HANDLE - a RequestConfiguration has not been done
6969*0Sstevel@tonic-gate  *		 CS_NO_CARD - if no card in socket
6970*0Sstevel@tonic-gate  *		 CS_BAD_ATTRIBUTE - if any unsupported or reserved flags
6971*0Sstevel@tonic-gate  *					are set
6972*0Sstevel@tonic-gate  *		 CS_BAD_VCC - if Vcc value is not supported by socket
6973*0Sstevel@tonic-gate  *		 CS_BAD_VPP1 - if Vpp1 value is not supported by socket
6974*0Sstevel@tonic-gate  *		 CS_BAD_VPP2 - if Vpp2 value is not supported by socket
6975*0Sstevel@tonic-gate  */
6976*0Sstevel@tonic-gate static int
6977*0Sstevel@tonic-gate cs_modify_configuration(client_handle_t client_handle, modify_config_t *mc)
6978*0Sstevel@tonic-gate {
6979*0Sstevel@tonic-gate 	cs_socket_t *sp;
6980*0Sstevel@tonic-gate 	client_t *client;
6981*0Sstevel@tonic-gate 	set_socket_t set_socket;
6982*0Sstevel@tonic-gate 	get_socket_t get_socket;
6983*0Sstevel@tonic-gate 	int error;
6984*0Sstevel@tonic-gate 	int client_lock_acquired;
6985*0Sstevel@tonic-gate 
6986*0Sstevel@tonic-gate 	/*
6987*0Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
6988*0Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
6989*0Sstevel@tonic-gate 	 */
6990*0Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
6991*0Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
6992*0Sstevel@tonic-gate 
6993*0Sstevel@tonic-gate 	/*
6994*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
6995*0Sstevel@tonic-gate 	 */
6996*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
6997*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
6998*0Sstevel@tonic-gate 
6999*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
7000*0Sstevel@tonic-gate 
7001*0Sstevel@tonic-gate 	/*
7002*0Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
7003*0Sstevel@tonic-gate 	 */
7004*0Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
7005*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7006*0Sstevel@tonic-gate 	    return (error);
7007*0Sstevel@tonic-gate 	}
7008*0Sstevel@tonic-gate 
7009*0Sstevel@tonic-gate 	/*
7010*0Sstevel@tonic-gate 	 * If RequestConfiguration has not been done, we don't allow
7011*0Sstevel@tonic-gate 	 *	this call.
7012*0Sstevel@tonic-gate 	 */
7013*0Sstevel@tonic-gate 	if (!(client->flags & REQ_CONFIGURATION_DONE)) {
7014*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7015*0Sstevel@tonic-gate 	    return (CS_BAD_HANDLE);
7016*0Sstevel@tonic-gate 	}
7017*0Sstevel@tonic-gate 
7018*0Sstevel@tonic-gate 	/*
7019*0Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
7020*0Sstevel@tonic-gate 	 *	for this client, then return an error.
7021*0Sstevel@tonic-gate 	 */
7022*0Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
7023*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7024*0Sstevel@tonic-gate 	    return (CS_NO_CARD);
7025*0Sstevel@tonic-gate 	}
7026*0Sstevel@tonic-gate 
7027*0Sstevel@tonic-gate 	/*
7028*0Sstevel@tonic-gate 	 * Get the current socket parameters so that we can modify them.
7029*0Sstevel@tonic-gate 	 */
7030*0Sstevel@tonic-gate 	get_socket.socket = sp->socket_num;
7031*0Sstevel@tonic-gate 
7032*0Sstevel@tonic-gate 	if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) {
7033*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7034*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
7035*0Sstevel@tonic-gate 	}
7036*0Sstevel@tonic-gate 
7037*0Sstevel@tonic-gate #ifdef	CS_DEBUG
7038*0Sstevel@tonic-gate 	if (cs_debug > 0)
7039*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_modify_configuration: socket %d "
7040*0Sstevel@tonic-gate 				"client->irq_alloc.irq 0x%x "
7041*0Sstevel@tonic-gate 				"get_socket.IRQRouting 0x%x\n",
7042*0Sstevel@tonic-gate 				sp->socket_num, (int)client->irq_alloc.irq,
7043*0Sstevel@tonic-gate 				get_socket.IRQRouting);
7044*0Sstevel@tonic-gate #endif
7045*0Sstevel@tonic-gate 
7046*0Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
7047*0Sstevel@tonic-gate 	set_socket.SCIntMask = get_socket.SCIntMask;
7048*0Sstevel@tonic-gate 	set_socket.CtlInd = get_socket.CtlInd;
7049*0Sstevel@tonic-gate 	set_socket.State = 0;	/* don't reset latched values */
7050*0Sstevel@tonic-gate 	set_socket.IFType = get_socket.IFType;
7051*0Sstevel@tonic-gate 
7052*0Sstevel@tonic-gate 	set_socket.IREQRouting = get_socket.IRQRouting;
7053*0Sstevel@tonic-gate 
7054*0Sstevel@tonic-gate 	/*
7055*0Sstevel@tonic-gate 	 * Modify the IRQ routing if the client wants it modified.
7056*0Sstevel@tonic-gate 	 */
7057*0Sstevel@tonic-gate 	if (mc->Attributes & CONF_IRQ_CHANGE_VALID) {
7058*0Sstevel@tonic-gate 	    set_socket.IREQRouting &= ~IRQ_ENABLE;
7059*0Sstevel@tonic-gate 
7060*0Sstevel@tonic-gate 	    if ((sp->cis_flags & CW_MULTI_FUNCTION_CIS) &&
7061*0Sstevel@tonic-gate 			(client->present & CONFIG_OPTION_REG_PRESENT)) {
7062*0Sstevel@tonic-gate 		config_regs_t *crt = &client->config_regs;
7063*0Sstevel@tonic-gate 		acc_handle_t cis_handle;
7064*0Sstevel@tonic-gate 		uint32_t newoffset = client->config_regs_offset;
7065*0Sstevel@tonic-gate 
7066*0Sstevel@tonic-gate 		/*
7067*0Sstevel@tonic-gate 		 * Get a pointer to a window that contains the configuration
7068*0Sstevel@tonic-gate 		 *	registers.
7069*0Sstevel@tonic-gate 		 */
7070*0Sstevel@tonic-gate 		if (cs_init_cis_window(sp, &newoffset, &cis_handle,
7071*0Sstevel@tonic-gate 					CISTPLF_AM_SPACE) != CS_SUCCESS) {
7072*0Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7073*0Sstevel@tonic-gate 		    cmn_err(CE_CONT,
7074*0Sstevel@tonic-gate 			"cs_modify_configuration: socket %d can't init "
7075*0Sstevel@tonic-gate 			"CIS window\n", sp->socket_num);
7076*0Sstevel@tonic-gate 		    return (CS_GENERAL_FAILURE);
7077*0Sstevel@tonic-gate 		} /* cs_init_cis_window */
7078*0Sstevel@tonic-gate 
7079*0Sstevel@tonic-gate 		crt->cor &= ~COR_ENABLE_IREQ_ROUTING;
7080*0Sstevel@tonic-gate 
7081*0Sstevel@tonic-gate 		if (mc->Attributes & CONF_ENABLE_IRQ_STEERING)
7082*0Sstevel@tonic-gate 		    crt->cor |= COR_ENABLE_IREQ_ROUTING;
7083*0Sstevel@tonic-gate 
7084*0Sstevel@tonic-gate #ifdef  CS_DEBUG
7085*0Sstevel@tonic-gate 		if (cs_debug > 0)
7086*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_modify_configuration:"
7087*0Sstevel@tonic-gate 			    " cor_p=0x%x cor=0x%x\n",
7088*0Sstevel@tonic-gate 			    crt->cor_p, crt->cor);
7089*0Sstevel@tonic-gate #endif
7090*0Sstevel@tonic-gate 		csx_Put8(cis_handle, crt->cor_p, crt->cor);
7091*0Sstevel@tonic-gate 
7092*0Sstevel@tonic-gate 	    } /* CW_MULTI_FUNCTION_CIS */
7093*0Sstevel@tonic-gate 
7094*0Sstevel@tonic-gate 	    if (mc->Attributes & CONF_ENABLE_IRQ_STEERING)
7095*0Sstevel@tonic-gate 		set_socket.IREQRouting |= IRQ_ENABLE;
7096*0Sstevel@tonic-gate 
7097*0Sstevel@tonic-gate 	} /* CONF_IRQ_CHANGE_VALID */
7098*0Sstevel@tonic-gate 
7099*0Sstevel@tonic-gate 	/*
7100*0Sstevel@tonic-gate 	 * Modify the voltage levels that the client specifies.
7101*0Sstevel@tonic-gate 	 */
7102*0Sstevel@tonic-gate 	set_socket.VccLevel = get_socket.VccLevel;
7103*0Sstevel@tonic-gate 
7104*0Sstevel@tonic-gate 	if (mc->Attributes & CONF_VPP1_CHANGE_VALID) {
7105*0Sstevel@tonic-gate 	    if (cs_convert_powerlevel(sp->socket_num, mc->Vpp1, VPP1,
7106*0Sstevel@tonic-gate 					&set_socket.Vpp1Level) != CS_SUCCESS) {
7107*0Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7108*0Sstevel@tonic-gate 		return (CS_BAD_VPP);
7109*0Sstevel@tonic-gate 	    }
7110*0Sstevel@tonic-gate 	} else {
7111*0Sstevel@tonic-gate 	    set_socket.Vpp1Level = get_socket.Vpp1Level;
7112*0Sstevel@tonic-gate 	}
7113*0Sstevel@tonic-gate 
7114*0Sstevel@tonic-gate 	if (mc->Attributes & CONF_VPP2_CHANGE_VALID) {
7115*0Sstevel@tonic-gate 	    if (cs_convert_powerlevel(sp->socket_num, mc->Vpp2, VPP2,
7116*0Sstevel@tonic-gate 					&set_socket.Vpp2Level) != CS_SUCCESS) {
7117*0Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7118*0Sstevel@tonic-gate 		return (CS_BAD_VPP);
7119*0Sstevel@tonic-gate 	    }
7120*0Sstevel@tonic-gate 	} else {
7121*0Sstevel@tonic-gate 	    set_socket.Vpp2Level = get_socket.Vpp2Level;
7122*0Sstevel@tonic-gate 	}
7123*0Sstevel@tonic-gate 
7124*0Sstevel@tonic-gate 	/*
7125*0Sstevel@tonic-gate 	 * Setup the modified socket configuration.
7126*0Sstevel@tonic-gate 	 */
7127*0Sstevel@tonic-gate 	if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) {
7128*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7129*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
7130*0Sstevel@tonic-gate 	}
7131*0Sstevel@tonic-gate 
7132*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7133*0Sstevel@tonic-gate 	return (CS_SUCCESS);
7134*0Sstevel@tonic-gate }
7135*0Sstevel@tonic-gate 
7136*0Sstevel@tonic-gate /*
7137*0Sstevel@tonic-gate  * cs_access_configuration_register - provides a client access to the card's
7138*0Sstevel@tonic-gate  *		configuration registers; this is AccessConfigurationRegister
7139*0Sstevel@tonic-gate  *
7140*0Sstevel@tonic-gate  *	returns: CS_SUCCESS - if register accessed successfully
7141*0Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
7142*0Sstevel@tonic-gate  *		 CS_BAD_ARGS - if arguments are out of range
7143*0Sstevel@tonic-gate  *		 CS_NO_CARD - if no card in socket
7144*0Sstevel@tonic-gate  *		 CS_BAD_BASE - if no config registers base address
7145*0Sstevel@tonic-gate  *		 CS_UNSUPPORTED_MODE - if no RequestConfiguration has
7146*0Sstevel@tonic-gate  *				been done yet
7147*0Sstevel@tonic-gate  */
7148*0Sstevel@tonic-gate static int
7149*0Sstevel@tonic-gate cs_access_configuration_register(client_handle_t client_handle,
7150*0Sstevel@tonic-gate 						access_config_reg_t *acr)
7151*0Sstevel@tonic-gate {
7152*0Sstevel@tonic-gate 	cs_socket_t *sp;
7153*0Sstevel@tonic-gate 	client_t *client;
7154*0Sstevel@tonic-gate 	acc_handle_t cis_handle;
7155*0Sstevel@tonic-gate 	int error;
7156*0Sstevel@tonic-gate 	uint32_t newoffset;
7157*0Sstevel@tonic-gate 	int client_lock_acquired;
7158*0Sstevel@tonic-gate 
7159*0Sstevel@tonic-gate 	/*
7160*0Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
7161*0Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
7162*0Sstevel@tonic-gate 	 */
7163*0Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
7164*0Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
7165*0Sstevel@tonic-gate 
7166*0Sstevel@tonic-gate 	/*
7167*0Sstevel@tonic-gate 	 * Make sure that the specifed offset is in range.
7168*0Sstevel@tonic-gate 	 */
7169*0Sstevel@tonic-gate 	if (acr->Offset > ((CISTPL_CONFIG_MAX_CONFIG_REGS * 2) - 2))
7170*0Sstevel@tonic-gate 	    return (CS_BAD_ARGS);
7171*0Sstevel@tonic-gate 
7172*0Sstevel@tonic-gate 	/*
7173*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
7174*0Sstevel@tonic-gate 	 */
7175*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
7176*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
7177*0Sstevel@tonic-gate 
7178*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
7179*0Sstevel@tonic-gate 
7180*0Sstevel@tonic-gate 	/*
7181*0Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
7182*0Sstevel@tonic-gate 	 */
7183*0Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
7184*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7185*0Sstevel@tonic-gate 	    return (error);
7186*0Sstevel@tonic-gate 	}
7187*0Sstevel@tonic-gate 
7188*0Sstevel@tonic-gate 	/*
7189*0Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
7190*0Sstevel@tonic-gate 	 *	for this client, then return an error.
7191*0Sstevel@tonic-gate 	 */
7192*0Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
7193*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7194*0Sstevel@tonic-gate 	    return (CS_NO_CARD);
7195*0Sstevel@tonic-gate 	}
7196*0Sstevel@tonic-gate 
7197*0Sstevel@tonic-gate 	/*
7198*0Sstevel@tonic-gate 	 * If RequestConfiguration has not been done, we don't allow
7199*0Sstevel@tonic-gate 	 *	this call.
7200*0Sstevel@tonic-gate 	 */
7201*0Sstevel@tonic-gate 	if (!(client->flags & REQ_CONFIGURATION_DONE)) {
7202*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7203*0Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_MODE);
7204*0Sstevel@tonic-gate 	}
7205*0Sstevel@tonic-gate 
7206*0Sstevel@tonic-gate 	mutex_enter(&sp->cis_lock);
7207*0Sstevel@tonic-gate 
7208*0Sstevel@tonic-gate 	/*
7209*0Sstevel@tonic-gate 	 * Get a pointer to the CIS window
7210*0Sstevel@tonic-gate 	 */
7211*0Sstevel@tonic-gate 	newoffset = client->config_regs_offset + acr->Offset;
7212*0Sstevel@tonic-gate 	if (cs_init_cis_window(sp, &newoffset, &cis_handle,
7213*0Sstevel@tonic-gate 					CISTPLF_AM_SPACE) != CS_SUCCESS) {
7214*0Sstevel@tonic-gate 	    mutex_exit(&sp->cis_lock);
7215*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7216*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_ACR: socket %d can't init CIS window\n",
7217*0Sstevel@tonic-gate 							sp->socket_num);
7218*0Sstevel@tonic-gate 	    return (CS_GENERAL_FAILURE);
7219*0Sstevel@tonic-gate 	}
7220*0Sstevel@tonic-gate 
7221*0Sstevel@tonic-gate 	/*
7222*0Sstevel@tonic-gate 	 * Create the address for the config register that the client
7223*0Sstevel@tonic-gate 	 *	wants to access.
7224*0Sstevel@tonic-gate 	 */
7225*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
7226*0Sstevel@tonic-gate 
7227*0Sstevel@tonic-gate #ifdef	CS_DEBUG
7228*0Sstevel@tonic-gate 	if (cs_debug > 1) {
7229*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_ACR: config_regs_offset 0x%x "
7230*0Sstevel@tonic-gate 		"Offset 0x%x newoffset 0x%x\n",
7231*0Sstevel@tonic-gate 		(int)client->config_regs_offset,
7232*0Sstevel@tonic-gate 		(int)acr->Offset, newoffset);
7233*0Sstevel@tonic-gate 	}
7234*0Sstevel@tonic-gate #endif
7235*0Sstevel@tonic-gate 
7236*0Sstevel@tonic-gate 	/*
7237*0Sstevel@tonic-gate 	 * Determine what the client wants us to do.  The client is
7238*0Sstevel@tonic-gate 	 *	allowed to specify any valid offset, even if it would
7239*0Sstevel@tonic-gate 	 *	cause an unimplemented configuration register to be
7240*0Sstevel@tonic-gate 	 *	accessed.
7241*0Sstevel@tonic-gate 	 */
7242*0Sstevel@tonic-gate 	error = CS_SUCCESS;
7243*0Sstevel@tonic-gate 	switch (acr->Action) {
7244*0Sstevel@tonic-gate 	    case CONFIG_REG_READ:
7245*0Sstevel@tonic-gate 		acr->Value = csx_Get8(cis_handle, newoffset);
7246*0Sstevel@tonic-gate 		break;
7247*0Sstevel@tonic-gate 	    case CONFIG_REG_WRITE:
7248*0Sstevel@tonic-gate 		csx_Put8(cis_handle, newoffset, acr->Value);
7249*0Sstevel@tonic-gate 		break;
7250*0Sstevel@tonic-gate 	    default:
7251*0Sstevel@tonic-gate 		error = CS_BAD_ARGS;
7252*0Sstevel@tonic-gate 		break;
7253*0Sstevel@tonic-gate 	} /* switch */
7254*0Sstevel@tonic-gate 
7255*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
7256*0Sstevel@tonic-gate 	mutex_exit(&sp->cis_lock);
7257*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7258*0Sstevel@tonic-gate 
7259*0Sstevel@tonic-gate 	return (error);
7260*0Sstevel@tonic-gate }
7261*0Sstevel@tonic-gate 
7262*0Sstevel@tonic-gate /*
7263*0Sstevel@tonic-gate  * ==== RESET and general info functions ====
7264*0Sstevel@tonic-gate  */
7265*0Sstevel@tonic-gate 
7266*0Sstevel@tonic-gate /*
7267*0Sstevel@tonic-gate  * cs_reset_function - RESET the requested function on the card; this
7268*0Sstevel@tonic-gate  *			is ResetFunction
7269*0Sstevel@tonic-gate  *
7270*0Sstevel@tonic-gate  *    Note: We don't support this functionality yet, and the standard
7271*0Sstevel@tonic-gate  *		says it's OK to reutrn CS_IN_USE if we can't do this
7272*0Sstevel@tonic-gate  *		operation.
7273*0Sstevel@tonic-gate  */
7274*0Sstevel@tonic-gate /*ARGSUSED*/
7275*0Sstevel@tonic-gate static int
7276*0Sstevel@tonic-gate cs_reset_function(client_handle_t ch, reset_function_t *rf)
7277*0Sstevel@tonic-gate {
7278*0Sstevel@tonic-gate 	return (CS_IN_USE);
7279*0Sstevel@tonic-gate }
7280*0Sstevel@tonic-gate 
7281*0Sstevel@tonic-gate /*
7282*0Sstevel@tonic-gate  * cs_get_configuration_info - return configuration info for the passed
7283*0Sstevel@tonic-gate  *				socket and function number to the caller;
7284*0Sstevel@tonic-gate  *				this is GetConfigurationInfo
7285*0Sstevel@tonic-gate  */
7286*0Sstevel@tonic-gate /*ARGSUSED*/
7287*0Sstevel@tonic-gate static int
7288*0Sstevel@tonic-gate cs_get_configuration_info(client_handle_t *chp, get_configuration_info_t *gci)
7289*0Sstevel@tonic-gate {
7290*0Sstevel@tonic-gate 	cs_socket_t *sp;
7291*0Sstevel@tonic-gate 	uint32_t fn;
7292*0Sstevel@tonic-gate 	client_t *client;
7293*0Sstevel@tonic-gate 	int client_lock_acquired;
7294*0Sstevel@tonic-gate 
7295*0Sstevel@tonic-gate 	/*
7296*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
7297*0Sstevel@tonic-gate 	 */
7298*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(gci->Socket))) == NULL)
7299*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
7300*0Sstevel@tonic-gate 
7301*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
7302*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
7303*0Sstevel@tonic-gate 
7304*0Sstevel@tonic-gate 	fn = CS_GET_FUNCTION_NUMBER(gci->Socket);
7305*0Sstevel@tonic-gate 
7306*0Sstevel@tonic-gate 	client = sp->client_list;
7307*0Sstevel@tonic-gate 	while (client) {
7308*0Sstevel@tonic-gate 
7309*0Sstevel@tonic-gate 	    if (GET_CLIENT_FUNCTION(client->client_handle) == fn) {
7310*0Sstevel@tonic-gate 
7311*0Sstevel@tonic-gate 		/*
7312*0Sstevel@tonic-gate 		 * If there's no card in the socket or the card in the
7313*0Sstevel@tonic-gate 		 *	socket is not for this client, then return
7314*0Sstevel@tonic-gate 		 *	an error.
7315*0Sstevel@tonic-gate 		 */
7316*0Sstevel@tonic-gate 		if (!(client->flags & CLIENT_CARD_INSERTED)) {
7317*0Sstevel@tonic-gate 		    mutex_exit(&sp->lock);
7318*0Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7319*0Sstevel@tonic-gate 		    return (CS_NO_CARD);
7320*0Sstevel@tonic-gate 		}
7321*0Sstevel@tonic-gate 
7322*0Sstevel@tonic-gate 		mutex_exit(&sp->lock);
7323*0Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7324*0Sstevel@tonic-gate 		return (CS_SUCCESS);
7325*0Sstevel@tonic-gate 
7326*0Sstevel@tonic-gate 	    } /* GET_CLIENT_FUNCTION == fn */
7327*0Sstevel@tonic-gate 
7328*0Sstevel@tonic-gate 	    client = client->next;
7329*0Sstevel@tonic-gate 	} /* while (client) */
7330*0Sstevel@tonic-gate 
7331*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
7332*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7333*0Sstevel@tonic-gate 
7334*0Sstevel@tonic-gate 	return (CS_BAD_SOCKET);
7335*0Sstevel@tonic-gate }
7336*0Sstevel@tonic-gate 
7337*0Sstevel@tonic-gate /*
7338*0Sstevel@tonic-gate  * cs_get_cardservices_info - return info about Card Services to the
7339*0Sstevel@tonic-gate  *	caller; this is GetCardServicesInfo
7340*0Sstevel@tonic-gate  */
7341*0Sstevel@tonic-gate /*ARGSUSED*/
7342*0Sstevel@tonic-gate static int
7343*0Sstevel@tonic-gate cs_get_cardservices_info(client_handle_t ch, get_cardservices_info_t *gcsi)
7344*0Sstevel@tonic-gate {
7345*0Sstevel@tonic-gate 	gcsi->Signature[0] = 'C';
7346*0Sstevel@tonic-gate 	gcsi->Signature[1] = 'S';
7347*0Sstevel@tonic-gate 	gcsi->NumSockets = cs_globals.num_sockets;
7348*0Sstevel@tonic-gate 	gcsi->Revision = CS_INTERNAL_REVISION_LEVEL;
7349*0Sstevel@tonic-gate 	gcsi->CSLevel = CS_VERSION;
7350*0Sstevel@tonic-gate 	gcsi->FuncsPerSocket = CIS_MAX_FUNCTIONS;
7351*0Sstevel@tonic-gate 	(void) strncpy(gcsi->VendorString,
7352*0Sstevel@tonic-gate 					CS_GET_CARDSERVICES_INFO_VENDOR_STRING,
7353*0Sstevel@tonic-gate 					CS_GET_CARDSERVICES_INFO_MAX_VS_LEN);
7354*0Sstevel@tonic-gate 
7355*0Sstevel@tonic-gate 	return (CS_SUCCESS);
7356*0Sstevel@tonic-gate }
7357*0Sstevel@tonic-gate 
7358*0Sstevel@tonic-gate /*
7359*0Sstevel@tonic-gate  * cs_get_physical_adapter_info - returns information about the requested
7360*0Sstevel@tonic-gate  *					physical adapter; this is
7361*0Sstevel@tonic-gate  *					GetPhysicalAdapterInfo
7362*0Sstevel@tonic-gate  *
7363*0Sstevel@tonic-gate  *	calling: client_handle_t:
7364*0Sstevel@tonic-gate  *			NULL - use map_log_socket_t->LogSocket member
7365*0Sstevel@tonic-gate  *				to specify logical socket number
7366*0Sstevel@tonic-gate  *			!NULL - extract logical socket number from
7367*0Sstevel@tonic-gate  *				client_handle_t
7368*0Sstevel@tonic-gate  *
7369*0Sstevel@tonic-gate  *	returns: CS_SUCCESS
7370*0Sstevel@tonic-gate  *		 CS_BAD_SOCKET - if client_handle_t is NULL and invalid
7371*0Sstevel@tonic-gate  *					socket number is specified in
7372*0Sstevel@tonic-gate  *					map_log_socket_t->LogSocket
7373*0Sstevel@tonic-gate  *		 CS_BAD_HANDLE - if client_handle_t is !NULL and invalid
7374*0Sstevel@tonic-gate  *					client handle is specified
7375*0Sstevel@tonic-gate  */
7376*0Sstevel@tonic-gate static int
7377*0Sstevel@tonic-gate cs_get_physical_adapter_info(client_handle_t ch,
7378*0Sstevel@tonic-gate 					get_physical_adapter_info_t *gpai)
7379*0Sstevel@tonic-gate {
7380*0Sstevel@tonic-gate 	cs_socket_t *sp;
7381*0Sstevel@tonic-gate 	int client_lock_acquired;
7382*0Sstevel@tonic-gate 
7383*0Sstevel@tonic-gate 	if (ch == NULL)
7384*0Sstevel@tonic-gate 	    gpai->PhySocket = CS_GET_SOCKET_NUMBER(gpai->LogSocket);
7385*0Sstevel@tonic-gate 	else
7386*0Sstevel@tonic-gate 	    gpai->PhySocket = GET_CLIENT_SOCKET(ch);
7387*0Sstevel@tonic-gate 
7388*0Sstevel@tonic-gate 	/*
7389*0Sstevel@tonic-gate 	 * Determine if the passed socket number is valid or not.
7390*0Sstevel@tonic-gate 	 */
7391*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(gpai->PhySocket))) == NULL)
7392*0Sstevel@tonic-gate 	    return ((ch == NULL) ? CS_BAD_SOCKET : CS_BAD_HANDLE);
7393*0Sstevel@tonic-gate 
7394*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
7395*0Sstevel@tonic-gate 
7396*0Sstevel@tonic-gate 	/*
7397*0Sstevel@tonic-gate 	 * If we were passed a client handle, determine if it's valid or not.
7398*0Sstevel@tonic-gate 	 */
7399*0Sstevel@tonic-gate 	if (ch != NULL) {
7400*0Sstevel@tonic-gate 	    if (cs_find_client(ch, NULL) == NULL) {
7401*0Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7402*0Sstevel@tonic-gate 		return (CS_BAD_HANDLE);
7403*0Sstevel@tonic-gate 	    } /* cs_find_client */
7404*0Sstevel@tonic-gate 	} /* ch != NULL */
7405*0Sstevel@tonic-gate 
7406*0Sstevel@tonic-gate 	gpai->flags = sp->adapter.flags;
7407*0Sstevel@tonic-gate 	(void) strcpy(gpai->name, sp->adapter.name);
7408*0Sstevel@tonic-gate 	gpai->major = sp->adapter.major;
7409*0Sstevel@tonic-gate 	gpai->minor = sp->adapter.minor;
7410*0Sstevel@tonic-gate 	gpai->instance = sp->adapter.instance;
7411*0Sstevel@tonic-gate 	gpai->number = sp->adapter.number;
7412*0Sstevel@tonic-gate 	gpai->num_sockets = sp->adapter.num_sockets;
7413*0Sstevel@tonic-gate 	gpai->first_socket = sp->adapter.first_socket;
7414*0Sstevel@tonic-gate 
7415*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7416*0Sstevel@tonic-gate 
7417*0Sstevel@tonic-gate 	return (CS_SUCCESS);
7418*0Sstevel@tonic-gate }
7419*0Sstevel@tonic-gate 
7420*0Sstevel@tonic-gate /*
7421*0Sstevel@tonic-gate  * ==== general functions ====
7422*0Sstevel@tonic-gate  */
7423*0Sstevel@tonic-gate 
7424*0Sstevel@tonic-gate /*
7425*0Sstevel@tonic-gate  * cs_map_log_socket - returns the physical socket number associated with
7426*0Sstevel@tonic-gate  *			either the passed client handle or the passed
7427*0Sstevel@tonic-gate  *			logical socket number; this is MapLogSocket
7428*0Sstevel@tonic-gate  *
7429*0Sstevel@tonic-gate  *	calling: client_handle_t:
7430*0Sstevel@tonic-gate  *			NULL - use map_log_socket_t->LogSocket member
7431*0Sstevel@tonic-gate  *				to specify logical socket number
7432*0Sstevel@tonic-gate  *			!NULL - extract logical socket number from
7433*0Sstevel@tonic-gate  *				client_handle_t
7434*0Sstevel@tonic-gate  *
7435*0Sstevel@tonic-gate  *	returns: CS_SUCCESS
7436*0Sstevel@tonic-gate  *		 CS_BAD_SOCKET - if client_handle_t is NULL and invalid
7437*0Sstevel@tonic-gate  *					socket number is specified in
7438*0Sstevel@tonic-gate  *					map_log_socket_t->LogSocket
7439*0Sstevel@tonic-gate  *		 CS_BAD_HANDLE - if client_handle_t is !NULL and invalid
7440*0Sstevel@tonic-gate  *					client handle is specified
7441*0Sstevel@tonic-gate  *
7442*0Sstevel@tonic-gate  * Note: We provide this function since the instance number of a client
7443*0Sstevel@tonic-gate  *		driver doesn't necessary correspond to the physical
7444*0Sstevel@tonic-gate  *		socket number
7445*0Sstevel@tonic-gate  */
7446*0Sstevel@tonic-gate static int
7447*0Sstevel@tonic-gate cs_map_log_socket(client_handle_t ch, map_log_socket_t *mls)
7448*0Sstevel@tonic-gate {
7449*0Sstevel@tonic-gate 	cs_socket_t *sp;
7450*0Sstevel@tonic-gate 	int client_lock_acquired;
7451*0Sstevel@tonic-gate 
7452*0Sstevel@tonic-gate 	if (ch == NULL)
7453*0Sstevel@tonic-gate 	    mls->PhySocket = CS_GET_SOCKET_NUMBER(mls->LogSocket);
7454*0Sstevel@tonic-gate 	else
7455*0Sstevel@tonic-gate 	    mls->PhySocket = GET_CLIENT_SOCKET(ch);
7456*0Sstevel@tonic-gate 
7457*0Sstevel@tonic-gate 	/*
7458*0Sstevel@tonic-gate 	 * Determine if the passed socket number is valid or not.
7459*0Sstevel@tonic-gate 	 */
7460*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(mls->PhySocket))) == NULL)
7461*0Sstevel@tonic-gate 	    return ((ch == NULL) ? CS_BAD_SOCKET : CS_BAD_HANDLE);
7462*0Sstevel@tonic-gate 
7463*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
7464*0Sstevel@tonic-gate 
7465*0Sstevel@tonic-gate 	/*
7466*0Sstevel@tonic-gate 	 * If we were passed a client handle, determine if it's valid or not.
7467*0Sstevel@tonic-gate 	 */
7468*0Sstevel@tonic-gate 	if (ch != NULL) {
7469*0Sstevel@tonic-gate 	    if (cs_find_client(ch, NULL) == NULL) {
7470*0Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7471*0Sstevel@tonic-gate 		return (CS_BAD_HANDLE);
7472*0Sstevel@tonic-gate 	    } /* cs_find_client */
7473*0Sstevel@tonic-gate 	} /* ch != NULL */
7474*0Sstevel@tonic-gate 
7475*0Sstevel@tonic-gate 	mls->PhyAdapter = sp->adapter.number;
7476*0Sstevel@tonic-gate 
7477*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7478*0Sstevel@tonic-gate 
7479*0Sstevel@tonic-gate 	return (CS_SUCCESS);
7480*0Sstevel@tonic-gate }
7481*0Sstevel@tonic-gate 
7482*0Sstevel@tonic-gate /*
7483*0Sstevel@tonic-gate  * cs_convert_speed - convers nS to devspeed and devspeed to nS
7484*0Sstevel@tonic-gate  *
7485*0Sstevel@tonic-gate  * The actual function is is in the CIS parser module; this
7486*0Sstevel@tonic-gate  *	is only a wrapper.
7487*0Sstevel@tonic-gate  */
7488*0Sstevel@tonic-gate static int
7489*0Sstevel@tonic-gate cs_convert_speed(convert_speed_t *cs)
7490*0Sstevel@tonic-gate {
7491*0Sstevel@tonic-gate 	return ((int)(uintptr_t)CIS_PARSER(CISP_CIS_CONV_DEVSPEED, cs));
7492*0Sstevel@tonic-gate }
7493*0Sstevel@tonic-gate 
7494*0Sstevel@tonic-gate /*
7495*0Sstevel@tonic-gate  * cs_convert_size - converts a devsize value to a size in bytes value
7496*0Sstevel@tonic-gate  *			or a size in bytes value to a devsize value
7497*0Sstevel@tonic-gate  *
7498*0Sstevel@tonic-gate  * The actual function is is in the CIS parser module; this
7499*0Sstevel@tonic-gate  *	is only a wrapper.
7500*0Sstevel@tonic-gate  */
7501*0Sstevel@tonic-gate static int
7502*0Sstevel@tonic-gate cs_convert_size(convert_size_t *cs)
7503*0Sstevel@tonic-gate {
7504*0Sstevel@tonic-gate 	return ((int)(uintptr_t)CIS_PARSER(CISP_CIS_CONV_DEVSIZE, cs));
7505*0Sstevel@tonic-gate }
7506*0Sstevel@tonic-gate 
7507*0Sstevel@tonic-gate /*
7508*0Sstevel@tonic-gate  * cs_convert_powerlevel - converts a power level in tenths of a volt
7509*0Sstevel@tonic-gate  *			to a power table entry for the specified socket
7510*0Sstevel@tonic-gate  *
7511*0Sstevel@tonic-gate  *	returns: CS_SUCCESS - if volts converted to a valid power level
7512*0Sstevel@tonic-gate  *		 CS_BAD_ADAPTER - if SS_InquireAdapter fails
7513*0Sstevel@tonic-gate  *		 CS_BAD_ARGS - if volts are not supported on this socket
7514*0Sstevel@tonic-gate  *				and adapter
7515*0Sstevel@tonic-gate  */
7516*0Sstevel@tonic-gate static int
7517*0Sstevel@tonic-gate cs_convert_powerlevel(uint32_t sn, uint32_t volts, uint32_t flags, unsigned *pl)
7518*0Sstevel@tonic-gate {
7519*0Sstevel@tonic-gate 	inquire_adapter_t inquire_adapter;
7520*0Sstevel@tonic-gate 	int i;
7521*0Sstevel@tonic-gate 
7522*0Sstevel@tonic-gate #ifdef	lint
7523*0Sstevel@tonic-gate 	if (sn == 0)
7524*0Sstevel@tonic-gate 	    panic("lint panic");
7525*0Sstevel@tonic-gate #endif
7526*0Sstevel@tonic-gate 
7527*0Sstevel@tonic-gate 	*pl = 0;
7528*0Sstevel@tonic-gate 
7529*0Sstevel@tonic-gate 	if (SocketServices(SS_InquireAdapter, &inquire_adapter) != SUCCESS)
7530*0Sstevel@tonic-gate 	    return (CS_BAD_ADAPTER);
7531*0Sstevel@tonic-gate 
7532*0Sstevel@tonic-gate 	for (i = 0; (i < inquire_adapter.NumPower); i++) {
7533*0Sstevel@tonic-gate 	    if ((inquire_adapter.power_entry[i].ValidSignals & flags) &&
7534*0Sstevel@tonic-gate 		(inquire_adapter.power_entry[i].PowerLevel == volts)) {
7535*0Sstevel@tonic-gate 		*pl = i;
7536*0Sstevel@tonic-gate 		return (CS_SUCCESS);
7537*0Sstevel@tonic-gate 	    }
7538*0Sstevel@tonic-gate 	}
7539*0Sstevel@tonic-gate 
7540*0Sstevel@tonic-gate 	return (CS_BAD_ARGS);
7541*0Sstevel@tonic-gate }
7542*0Sstevel@tonic-gate 
7543*0Sstevel@tonic-gate /*
7544*0Sstevel@tonic-gate  * cs_event2text - returns text string(s) associated with the event; this
7545*0Sstevel@tonic-gate  *			function supports the Event2Text CS call.
7546*0Sstevel@tonic-gate  *
7547*0Sstevel@tonic-gate  *	calling: event2text_t * - pointer to event2text struct
7548*0Sstevel@tonic-gate  *		 int event_source - specifies event type in event2text_t:
7549*0Sstevel@tonic-gate  *					0 - SS event
7550*0Sstevel@tonic-gate  *					1 - CS event
7551*0Sstevel@tonic-gate  *
7552*0Sstevel@tonic-gate  *	returns: CS_SUCCESS
7553*0Sstevel@tonic-gate  */
7554*0Sstevel@tonic-gate static int
7555*0Sstevel@tonic-gate cs_event2text(event2text_t *e2t, int event_source)
7556*0Sstevel@tonic-gate {
7557*0Sstevel@tonic-gate 	event_t event;
7558*0Sstevel@tonic-gate 	char *sepchar = "|";
7559*0Sstevel@tonic-gate 
7560*0Sstevel@tonic-gate 	/*
7561*0Sstevel@tonic-gate 	 * If event_source is 0, this is a SS event
7562*0Sstevel@tonic-gate 	 */
7563*0Sstevel@tonic-gate 	if (!event_source) {
7564*0Sstevel@tonic-gate 	    for (event = 0; event < MAX_SS_EVENTS; event++) {
7565*0Sstevel@tonic-gate 		if (cs_ss_event_text[event].ss_event == e2t->event) {
7566*0Sstevel@tonic-gate 		    (void) strcpy(e2t->text, cs_ss_event_text[event].text);
7567*0Sstevel@tonic-gate 		    return (CS_SUCCESS);
7568*0Sstevel@tonic-gate 		}
7569*0Sstevel@tonic-gate 	    }
7570*0Sstevel@tonic-gate 	    (void) strcpy(e2t->text, cs_ss_event_text[MAX_CS_EVENTS].text);
7571*0Sstevel@tonic-gate 	    return (CS_SUCCESS);
7572*0Sstevel@tonic-gate 	} else {
7573*0Sstevel@tonic-gate 		/*
7574*0Sstevel@tonic-gate 		 * This is a CS event
7575*0Sstevel@tonic-gate 		 */
7576*0Sstevel@tonic-gate 	    e2t->text[0] = '\0';
7577*0Sstevel@tonic-gate 	    for (event = 0; event < MAX_CS_EVENTS; event++) {
7578*0Sstevel@tonic-gate 		if (cs_ss_event_text[event].cs_event & e2t->event) {
7579*0Sstevel@tonic-gate 		    (void) strcat(e2t->text, cs_ss_event_text[event].text);
7580*0Sstevel@tonic-gate 		    (void) strcat(e2t->text, sepchar);
7581*0Sstevel@tonic-gate 		} /* if (cs_ss_event_text) */
7582*0Sstevel@tonic-gate 	    } /* for (event) */
7583*0Sstevel@tonic-gate 	    if (e2t->text[0])
7584*0Sstevel@tonic-gate 		e2t->text[strlen(e2t->text)-1] = NULL;
7585*0Sstevel@tonic-gate 	} /* if (!event_source) */
7586*0Sstevel@tonic-gate 
7587*0Sstevel@tonic-gate 	return (CS_SUCCESS);
7588*0Sstevel@tonic-gate }
7589*0Sstevel@tonic-gate 
7590*0Sstevel@tonic-gate /*
7591*0Sstevel@tonic-gate  * cs_error2text - returns a pointer to a text string containing the name
7592*0Sstevel@tonic-gate  *			of the passed Card Services function or return code
7593*0Sstevel@tonic-gate  *
7594*0Sstevel@tonic-gate  *	This function supports the Error2Text CS call.
7595*0Sstevel@tonic-gate  */
7596*0Sstevel@tonic-gate static char *
7597*0Sstevel@tonic-gate cs_error2text(int function, int type)
7598*0Sstevel@tonic-gate {
7599*0Sstevel@tonic-gate 	cs_csfunc2text_strings_t *cfs;
7600*0Sstevel@tonic-gate 	int end_marker;
7601*0Sstevel@tonic-gate 
7602*0Sstevel@tonic-gate 	if (type == CSFUN2TEXT_FUNCTION) {
7603*0Sstevel@tonic-gate 	    cfs = cs_csfunc2text_funcstrings;
7604*0Sstevel@tonic-gate 	    end_marker = CSFuncListEnd;
7605*0Sstevel@tonic-gate 	} else {
7606*0Sstevel@tonic-gate 	    cfs = cs_csfunc2text_returnstrings;
7607*0Sstevel@tonic-gate 	    end_marker = CS_ERRORLIST_END;
7608*0Sstevel@tonic-gate 	}
7609*0Sstevel@tonic-gate 
7610*0Sstevel@tonic-gate 	while (cfs->item != end_marker) {
7611*0Sstevel@tonic-gate 	    if (cfs->item == function)
7612*0Sstevel@tonic-gate 		return (cfs->text);
7613*0Sstevel@tonic-gate 	    cfs++;
7614*0Sstevel@tonic-gate 	}
7615*0Sstevel@tonic-gate 
7616*0Sstevel@tonic-gate 	return (cfs->text);
7617*0Sstevel@tonic-gate }
7618*0Sstevel@tonic-gate 
7619*0Sstevel@tonic-gate /*
7620*0Sstevel@tonic-gate  * cs_make_device_node - creates/removes device nodes on a client's behalf;
7621*0Sstevel@tonic-gate  *				this is MakeDeviceNode and RemoveDeviceNode
7622*0Sstevel@tonic-gate  *
7623*0Sstevel@tonic-gate  *	returns: CS_SUCCESS - if all device nodes successfully created/removed
7624*0Sstevel@tonic-gate  *		 CS_BAD_ATTRIBUTE - if NumDevNodes is not zero when Action
7625*0Sstevel@tonic-gate  *				is REMOVAL_ALL_DEVICES
7626*0Sstevel@tonic-gate  *		 CS_BAD_ARGS - if an invalid Action code is specified
7627*0Sstevel@tonic-gate  *		 CS_UNSUPPORTED_FUNCTION - if SS is trying to call us
7628*0Sstevel@tonic-gate  *		 CS_OUT_OF_RESOURCE - if can't create/remove device node
7629*0Sstevel@tonic-gate  */
7630*0Sstevel@tonic-gate static int
7631*0Sstevel@tonic-gate cs_make_device_node(client_handle_t client_handle, make_device_node_t *mdn)
7632*0Sstevel@tonic-gate {
7633*0Sstevel@tonic-gate 	cs_socket_t *sp;
7634*0Sstevel@tonic-gate 	client_t *client;
7635*0Sstevel@tonic-gate 	ss_make_device_node_t ss_make_device_node;
7636*0Sstevel@tonic-gate 	int error, i;
7637*0Sstevel@tonic-gate 	int client_lock_acquired;
7638*0Sstevel@tonic-gate 
7639*0Sstevel@tonic-gate 	/*
7640*0Sstevel@tonic-gate 	 * Check to see if this is the Socket Services client handle; if it
7641*0Sstevel@tonic-gate 	 *	is, we don't support SS using this call.
7642*0Sstevel@tonic-gate 	 */
7643*0Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle))
7644*0Sstevel@tonic-gate 	    return (CS_UNSUPPORTED_FUNCTION);
7645*0Sstevel@tonic-gate 
7646*0Sstevel@tonic-gate 	/*
7647*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
7648*0Sstevel@tonic-gate 	 */
7649*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
7650*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
7651*0Sstevel@tonic-gate 
7652*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
7653*0Sstevel@tonic-gate 
7654*0Sstevel@tonic-gate 	/*
7655*0Sstevel@tonic-gate 	 *  Make sure that this is a valid client handle.
7656*0Sstevel@tonic-gate 	 */
7657*0Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &error))) {
7658*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7659*0Sstevel@tonic-gate 	    return (error);
7660*0Sstevel@tonic-gate 	}
7661*0Sstevel@tonic-gate 
7662*0Sstevel@tonic-gate #ifdef	XXX
7663*0Sstevel@tonic-gate 	/*
7664*0Sstevel@tonic-gate 	 * If there's no card in the socket or the card in the socket is not
7665*0Sstevel@tonic-gate 	 *	for this client, then return an error.
7666*0Sstevel@tonic-gate 	 */
7667*0Sstevel@tonic-gate 	if (!(client->flags & CLIENT_CARD_INSERTED)) {
7668*0Sstevel@tonic-gate 	    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7669*0Sstevel@tonic-gate 	    return (CS_NO_CARD);
7670*0Sstevel@tonic-gate 	}
7671*0Sstevel@tonic-gate #endif
7672*0Sstevel@tonic-gate 
7673*0Sstevel@tonic-gate 	/*
7674*0Sstevel@tonic-gate 	 * Setup the client's dip, since we use it later on.
7675*0Sstevel@tonic-gate 	 */
7676*0Sstevel@tonic-gate 	ss_make_device_node.dip = client->dip;
7677*0Sstevel@tonic-gate 
7678*0Sstevel@tonic-gate 	/*
7679*0Sstevel@tonic-gate 	 * Make sure that we're being given a valid Action.  Set the default
7680*0Sstevel@tonic-gate 	 *	error code as well.
7681*0Sstevel@tonic-gate 	 */
7682*0Sstevel@tonic-gate 	error = CS_BAD_ARGS;	/* for default case */
7683*0Sstevel@tonic-gate 	switch (mdn->Action) {
7684*0Sstevel@tonic-gate 	    case CREATE_DEVICE_NODE:
7685*0Sstevel@tonic-gate 	    case REMOVE_DEVICE_NODE:
7686*0Sstevel@tonic-gate 		break;
7687*0Sstevel@tonic-gate 	    case REMOVAL_ALL_DEVICE_NODES:
7688*0Sstevel@tonic-gate 		if (mdn->NumDevNodes) {
7689*0Sstevel@tonic-gate 		    error = CS_BAD_ATTRIBUTE;
7690*0Sstevel@tonic-gate 		} else {
7691*0Sstevel@tonic-gate 		    ss_make_device_node.flags = SS_CSINITDEV_REMOVE_DEVICE;
7692*0Sstevel@tonic-gate 		    ss_make_device_node.name = NULL;
7693*0Sstevel@tonic-gate 		    SocketServices(CSInitDev, &ss_make_device_node);
7694*0Sstevel@tonic-gate 		    error = CS_SUCCESS;
7695*0Sstevel@tonic-gate 		}
7696*0Sstevel@tonic-gate 		/* fall-through case */
7697*0Sstevel@tonic-gate 	    default:
7698*0Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7699*0Sstevel@tonic-gate 		return (error);
7700*0Sstevel@tonic-gate 		/* NOTREACHED */
7701*0Sstevel@tonic-gate 	} /* switch */
7702*0Sstevel@tonic-gate 
7703*0Sstevel@tonic-gate 	/*
7704*0Sstevel@tonic-gate 	 * Loop through the device node descriptions and create or destroy
7705*0Sstevel@tonic-gate 	 *	the device node.
7706*0Sstevel@tonic-gate 	 */
7707*0Sstevel@tonic-gate 	for (i = 0; i < mdn->NumDevNodes; i++) {
7708*0Sstevel@tonic-gate 	    devnode_desc_t *devnode_desc = &mdn->devnode_desc[i];
7709*0Sstevel@tonic-gate 
7710*0Sstevel@tonic-gate 	    ss_make_device_node.name = devnode_desc->name;
7711*0Sstevel@tonic-gate 	    ss_make_device_node.spec_type = devnode_desc->spec_type;
7712*0Sstevel@tonic-gate 	    ss_make_device_node.minor_num = devnode_desc->minor_num;
7713*0Sstevel@tonic-gate 	    ss_make_device_node.node_type = devnode_desc->node_type;
7714*0Sstevel@tonic-gate 
7715*0Sstevel@tonic-gate 	/*
7716*0Sstevel@tonic-gate 	 * Set the appropriate flag for the action that we want
7717*0Sstevel@tonic-gate 	 *	SS to perform. Note that if we ever OR-in the flag
7718*0Sstevel@tonic-gate 	 *	here, we need to be sure to clear the flags member
7719*0Sstevel@tonic-gate 	 *	since we sometimes OR-in other flags below.
7720*0Sstevel@tonic-gate 	 */
7721*0Sstevel@tonic-gate 	    if (mdn->Action == CREATE_DEVICE_NODE) {
7722*0Sstevel@tonic-gate 		ss_make_device_node.flags = SS_CSINITDEV_CREATE_DEVICE;
7723*0Sstevel@tonic-gate 	    } else {
7724*0Sstevel@tonic-gate 		ss_make_device_node.flags = SS_CSINITDEV_REMOVE_DEVICE;
7725*0Sstevel@tonic-gate 	    }
7726*0Sstevel@tonic-gate 
7727*0Sstevel@tonic-gate 	/*
7728*0Sstevel@tonic-gate 	 * If this is not the last device to process, then we need
7729*0Sstevel@tonic-gate 	 *	to tell SS that more device process requests are on
7730*0Sstevel@tonic-gate 	 *	their way after this one.
7731*0Sstevel@tonic-gate 	 */
7732*0Sstevel@tonic-gate 	    if (i < (mdn->NumDevNodes - 1))
7733*0Sstevel@tonic-gate 		ss_make_device_node.flags |= SS_CSINITDEV_MORE_DEVICES;
7734*0Sstevel@tonic-gate 
7735*0Sstevel@tonic-gate 	    if (SocketServices(CSInitDev, &ss_make_device_node) != SUCCESS) {
7736*0Sstevel@tonic-gate 		EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7737*0Sstevel@tonic-gate 		return (CS_OUT_OF_RESOURCE);
7738*0Sstevel@tonic-gate 	    } /* CSInitDev */
7739*0Sstevel@tonic-gate 	} /* for (mdn->NumDevNodes) */
7740*0Sstevel@tonic-gate 
7741*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7742*0Sstevel@tonic-gate 	return (CS_SUCCESS);
7743*0Sstevel@tonic-gate }
7744*0Sstevel@tonic-gate 
7745*0Sstevel@tonic-gate /*
7746*0Sstevel@tonic-gate  * cs_remove_device_node - removes device nodes
7747*0Sstevel@tonic-gate  *
7748*0Sstevel@tonic-gate  *	(see cs_make_device_node for a description of the calling
7749*0Sstevel@tonic-gate  *		and return parameters)
7750*0Sstevel@tonic-gate  */
7751*0Sstevel@tonic-gate static int
7752*0Sstevel@tonic-gate cs_remove_device_node(client_handle_t client_handle, remove_device_node_t *rdn)
7753*0Sstevel@tonic-gate {
7754*0Sstevel@tonic-gate 
7755*0Sstevel@tonic-gate 	/*
7756*0Sstevel@tonic-gate 	 * XXX - Note the assumption here that the make_device_node_t and
7757*0Sstevel@tonic-gate 	 *	remove_device_node_t structures are identical.
7758*0Sstevel@tonic-gate 	 */
7759*0Sstevel@tonic-gate 	return (cs_make_device_node(client_handle, (make_device_node_t *)rdn));
7760*0Sstevel@tonic-gate }
7761*0Sstevel@tonic-gate 
7762*0Sstevel@tonic-gate /*
7763*0Sstevel@tonic-gate  * cs_ddi_info - this function is used by clients that need to support
7764*0Sstevel@tonic-gate  *			the xxx_getinfo function; this is CS_DDI_Info
7765*0Sstevel@tonic-gate  */
7766*0Sstevel@tonic-gate static int
7767*0Sstevel@tonic-gate cs_ddi_info(cs_ddi_info_t *cdi)
7768*0Sstevel@tonic-gate {
7769*0Sstevel@tonic-gate 	cs_socket_t *sp;
7770*0Sstevel@tonic-gate 	client_t *client;
7771*0Sstevel@tonic-gate 	int client_lock_acquired;
7772*0Sstevel@tonic-gate 
7773*0Sstevel@tonic-gate 	if (cdi->driver_name == NULL)
7774*0Sstevel@tonic-gate 	    return (CS_BAD_ATTRIBUTE);
7775*0Sstevel@tonic-gate 
7776*0Sstevel@tonic-gate #ifdef	CS_DEBUG
7777*0Sstevel@tonic-gate 	if (cs_debug > 0) {
7778*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_ddi_info: socket %d client [%s]\n",
7779*0Sstevel@tonic-gate 					(int)cdi->Socket, cdi->driver_name);
7780*0Sstevel@tonic-gate 	}
7781*0Sstevel@tonic-gate #endif
7782*0Sstevel@tonic-gate 
7783*0Sstevel@tonic-gate 	/*
7784*0Sstevel@tonic-gate 	 * Check to see if the socket number is in range - the system
7785*0Sstevel@tonic-gate 	 *	framework may cause a client driver to call us with
7786*0Sstevel@tonic-gate 	 *	a socket number that used to be present but isn't
7787*0Sstevel@tonic-gate 	 *	anymore. This is not a bug, and it's OK to return
7788*0Sstevel@tonic-gate 	 *	an error if the socket number is out of range.
7789*0Sstevel@tonic-gate 	 */
7790*0Sstevel@tonic-gate 	if (!CHECK_SOCKET_NUM(cdi->Socket, cs_globals.max_socket_num)) {
7791*0Sstevel@tonic-gate 
7792*0Sstevel@tonic-gate #ifdef	CS_DEBUG
7793*0Sstevel@tonic-gate 	    if (cs_debug > 0) {
7794*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_ddi_info: socket %d client [%s] "
7795*0Sstevel@tonic-gate 						"SOCKET IS OUT OF RANGE\n",
7796*0Sstevel@tonic-gate 							(int)cdi->Socket,
7797*0Sstevel@tonic-gate 							cdi->driver_name);
7798*0Sstevel@tonic-gate 	    }
7799*0Sstevel@tonic-gate #endif
7800*0Sstevel@tonic-gate 
7801*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
7802*0Sstevel@tonic-gate 	} /* if (!CHECK_SOCKET_NUM) */
7803*0Sstevel@tonic-gate 
7804*0Sstevel@tonic-gate 	/*
7805*0Sstevel@tonic-gate 	 * Get a pointer to this client's socket structure.
7806*0Sstevel@tonic-gate 	 */
7807*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(cdi->Socket)) == NULL)
7808*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
7809*0Sstevel@tonic-gate 
7810*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp);
7811*0Sstevel@tonic-gate 
7812*0Sstevel@tonic-gate 	client = sp->client_list;
7813*0Sstevel@tonic-gate 	while (client) {
7814*0Sstevel@tonic-gate 
7815*0Sstevel@tonic-gate #ifdef	CS_DEBUG
7816*0Sstevel@tonic-gate 	    if (cs_debug > 0) {
7817*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_ddi_info: socket %d checking client [%s] "
7818*0Sstevel@tonic-gate 							"handle 0x%x\n",
7819*0Sstevel@tonic-gate 						(int)cdi->Socket,
7820*0Sstevel@tonic-gate 						client->driver_name,
7821*0Sstevel@tonic-gate 						(int)client->client_handle);
7822*0Sstevel@tonic-gate 	    }
7823*0Sstevel@tonic-gate #endif
7824*0Sstevel@tonic-gate 
7825*0Sstevel@tonic-gate 	    if (client->driver_name != NULL) {
7826*0Sstevel@tonic-gate 		if (!(strcmp(client->driver_name, cdi->driver_name))) {
7827*0Sstevel@tonic-gate 		    cdi->dip = client->dip;
7828*0Sstevel@tonic-gate 		    cdi->instance = client->instance;
7829*0Sstevel@tonic-gate 
7830*0Sstevel@tonic-gate #ifdef	CS_DEBUG
7831*0Sstevel@tonic-gate 		    if (cs_debug > 0) {
7832*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "cs_ddi_info: found client [%s] "
7833*0Sstevel@tonic-gate 						"instance %d handle 0x%x\n",
7834*0Sstevel@tonic-gate 					client->driver_name, client->instance,
7835*0Sstevel@tonic-gate 					(int)client->client_handle);
7836*0Sstevel@tonic-gate 		    }
7837*0Sstevel@tonic-gate #endif
7838*0Sstevel@tonic-gate 
7839*0Sstevel@tonic-gate 		    EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7840*0Sstevel@tonic-gate 		    return (CS_SUCCESS);
7841*0Sstevel@tonic-gate 		} /* strcmp */
7842*0Sstevel@tonic-gate 	    } /* driver_name != NULL */
7843*0Sstevel@tonic-gate 	    client = client->next;
7844*0Sstevel@tonic-gate 	} /* while (client) */
7845*0Sstevel@tonic-gate 
7846*0Sstevel@tonic-gate 	EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp);
7847*0Sstevel@tonic-gate 	return (CS_BAD_SOCKET);
7848*0Sstevel@tonic-gate }
7849*0Sstevel@tonic-gate 
7850*0Sstevel@tonic-gate /*
7851*0Sstevel@tonic-gate  * cs_sys_ctl - Card Services system control; this is CS_Sys_Ctl
7852*0Sstevel@tonic-gate  */
7853*0Sstevel@tonic-gate static int
7854*0Sstevel@tonic-gate cs_sys_ctl(cs_sys_ctl_t *csc)
7855*0Sstevel@tonic-gate {
7856*0Sstevel@tonic-gate 	cs_socket_t *sp;
7857*0Sstevel@tonic-gate 	client_t *cp;
7858*0Sstevel@tonic-gate 	int sn, ret = CS_UNSUPPORTED_MODE;
7859*0Sstevel@tonic-gate 
7860*0Sstevel@tonic-gate 	switch (csc->Action) {
7861*0Sstevel@tonic-gate 	    case CS_SYS_CTL_SEND_EVENT:
7862*0Sstevel@tonic-gate 		if (csc->Flags & CS_SYS_CTL_EVENT_SOCKET)
7863*0Sstevel@tonic-gate 		    sn = CS_GET_SOCKET_NUMBER(csc->Socket);
7864*0Sstevel@tonic-gate 		else
7865*0Sstevel@tonic-gate 		    sn = GET_CLIENT_SOCKET(csc->client_handle);
7866*0Sstevel@tonic-gate 		if ((sp = cs_get_sp(sn)) == NULL)
7867*0Sstevel@tonic-gate 		    return (CS_BAD_SOCKET);
7868*0Sstevel@tonic-gate 		mutex_enter(&sp->client_lock);
7869*0Sstevel@tonic-gate 		mutex_enter(&sp->lock);
7870*0Sstevel@tonic-gate 		csc->Events &= CS_EVENT_CLIENT_EVENTS_MASK;
7871*0Sstevel@tonic-gate 		if (csc->Flags & CS_SYS_CTL_EVENT_SOCKET)
7872*0Sstevel@tonic-gate 		    sp->events |= csc->Events;
7873*0Sstevel@tonic-gate 		if (csc->Flags & CS_SYS_CTL_EVENT_CLIENT) {
7874*0Sstevel@tonic-gate 		    if ((cp = cs_find_client(csc->client_handle, &ret)) ==
7875*0Sstevel@tonic-gate 									NULL) {
7876*0Sstevel@tonic-gate 			mutex_exit(&sp->lock);
7877*0Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
7878*0Sstevel@tonic-gate 			return (ret);
7879*0Sstevel@tonic-gate 		    } /* cs_find_client */
7880*0Sstevel@tonic-gate 			/*
7881*0Sstevel@tonic-gate 			 * Setup the events that we want to send to the client.
7882*0Sstevel@tonic-gate 			 */
7883*0Sstevel@tonic-gate 		    cp->events |= (csc->Events &
7884*0Sstevel@tonic-gate 					(cp->event_mask | cp->global_mask));
7885*0Sstevel@tonic-gate 		} /* CS_SYS_CTL_EVENT_CLIENT */
7886*0Sstevel@tonic-gate 
7887*0Sstevel@tonic-gate 		if (csc->Flags & CS_SYS_CTL_WAIT_SYNC) {
7888*0Sstevel@tonic-gate 		    sp->thread_state |= SOCKET_WAIT_SYNC;
7889*0Sstevel@tonic-gate 		    mutex_exit(&sp->lock);
7890*0Sstevel@tonic-gate 		    cv_broadcast(&sp->thread_cv);
7891*0Sstevel@tonic-gate 		    cv_wait(&sp->caller_cv, &sp->client_lock);
7892*0Sstevel@tonic-gate 		} else {
7893*0Sstevel@tonic-gate 		    mutex_exit(&sp->lock);
7894*0Sstevel@tonic-gate 		    cv_broadcast(&sp->thread_cv);
7895*0Sstevel@tonic-gate 		} /* CS_SYS_CTL_WAIT_SYNC */
7896*0Sstevel@tonic-gate 		mutex_exit(&sp->client_lock);
7897*0Sstevel@tonic-gate 		ret = CS_SUCCESS;
7898*0Sstevel@tonic-gate 		break;
7899*0Sstevel@tonic-gate 	    default:
7900*0Sstevel@tonic-gate 		break;
7901*0Sstevel@tonic-gate 	} /* switch */
7902*0Sstevel@tonic-gate 
7903*0Sstevel@tonic-gate 	return (ret);
7904*0Sstevel@tonic-gate }
7905*0Sstevel@tonic-gate 
7906*0Sstevel@tonic-gate /*
7907*0Sstevel@tonic-gate  * cs_get_sp - returns pointer to per-socket structure for passed
7908*0Sstevel@tonic-gate  *		socket number
7909*0Sstevel@tonic-gate  *
7910*0Sstevel@tonic-gate  *	return:	(cs_socket_t *) - pointer to socket structure
7911*0Sstevel@tonic-gate  *		NULL - invalid socket number passed in
7912*0Sstevel@tonic-gate  */
7913*0Sstevel@tonic-gate static cs_socket_t *
7914*0Sstevel@tonic-gate cs_get_sp(uint32_t sn)
7915*0Sstevel@tonic-gate {
7916*0Sstevel@tonic-gate 	cs_socket_t *sp = cs_globals.sp;
7917*0Sstevel@tonic-gate 
7918*0Sstevel@tonic-gate 	if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY))
7919*0Sstevel@tonic-gate 	    return (NULL);
7920*0Sstevel@tonic-gate 
7921*0Sstevel@tonic-gate 	if ((sp = cs_find_sp(sn)) == NULL)
7922*0Sstevel@tonic-gate 	    return (NULL);
7923*0Sstevel@tonic-gate 
7924*0Sstevel@tonic-gate 	if (sp->flags & SOCKET_IS_VALID)
7925*0Sstevel@tonic-gate 	    return (sp);
7926*0Sstevel@tonic-gate 
7927*0Sstevel@tonic-gate 	return (NULL);
7928*0Sstevel@tonic-gate }
7929*0Sstevel@tonic-gate 
7930*0Sstevel@tonic-gate /*
7931*0Sstevel@tonic-gate  * cs_find_sp - searches socket list and returns pointer to passed socket
7932*0Sstevel@tonic-gate  *			number
7933*0Sstevel@tonic-gate  *
7934*0Sstevel@tonic-gate  *	return:	(cs_socket_t *) - pointer to socket structure if found
7935*0Sstevel@tonic-gate  *		NULL - socket not found
7936*0Sstevel@tonic-gate  */
7937*0Sstevel@tonic-gate static cs_socket_t *
7938*0Sstevel@tonic-gate cs_find_sp(uint32_t sn)
7939*0Sstevel@tonic-gate {
7940*0Sstevel@tonic-gate 	cs_socket_t *sp = cs_globals.sp;
7941*0Sstevel@tonic-gate 
7942*0Sstevel@tonic-gate 	while (sp) {
7943*0Sstevel@tonic-gate 	    if (sp->socket_num == CS_GET_SOCKET_NUMBER(sn))
7944*0Sstevel@tonic-gate 		return (sp);
7945*0Sstevel@tonic-gate 	    sp = sp->next;
7946*0Sstevel@tonic-gate 	} /* while */
7947*0Sstevel@tonic-gate 
7948*0Sstevel@tonic-gate 	return (NULL);
7949*0Sstevel@tonic-gate }
7950*0Sstevel@tonic-gate 
7951*0Sstevel@tonic-gate /*
7952*0Sstevel@tonic-gate  * cs_add_socket - add a socket
7953*0Sstevel@tonic-gate  *
7954*0Sstevel@tonic-gate  *	call:	sn - socket number to add
7955*0Sstevel@tonic-gate  *
7956*0Sstevel@tonic-gate  *	return:	CS_SUCCESS - operation sucessful
7957*0Sstevel@tonic-gate  *		CS_BAD_SOCKET - unable to add socket
7958*0Sstevel@tonic-gate  *		CS_BAD_WINDOW - unable to get CIS window for socket
7959*0Sstevel@tonic-gate  *
7960*0Sstevel@tonic-gate  * We get called here once for each socket that the framework wants to
7961*0Sstevel@tonic-gate  *	add. When we are called, the framework guarentees that until we
7962*0Sstevel@tonic-gate  *	complete this routine, no other adapter instances will be allowed
7963*0Sstevel@tonic-gate  *	to attach and thus no other PCE_ADD_SOCKET events will occur.
7964*0Sstevel@tonic-gate  *	It is safe to call SS_InquireAdapter to get the number of
7965*0Sstevel@tonic-gate  *	windows that the framework currently knows about.
7966*0Sstevel@tonic-gate  */
7967*0Sstevel@tonic-gate static uint32_t
7968*0Sstevel@tonic-gate cs_add_socket(uint32_t sn)
7969*0Sstevel@tonic-gate {
7970*0Sstevel@tonic-gate 	cs_socket_t *sp;
7971*0Sstevel@tonic-gate 	sservice_t sservice;
7972*0Sstevel@tonic-gate 	get_cookies_and_dip_t *gcad;
7973*0Sstevel@tonic-gate 	win_req_t win_req;
7974*0Sstevel@tonic-gate 	convert_speed_t convert_speed;
7975*0Sstevel@tonic-gate 	set_socket_t set_socket;
7976*0Sstevel@tonic-gate 	cs_window_t *cw;
7977*0Sstevel@tonic-gate 	inquire_adapter_t inquire_adapter;
7978*0Sstevel@tonic-gate 	inquire_window_t inquire_window;
7979*0Sstevel@tonic-gate 	int ret, added_windows;
7980*0Sstevel@tonic-gate 
7981*0Sstevel@tonic-gate 	if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY))
7982*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
7983*0Sstevel@tonic-gate 
7984*0Sstevel@tonic-gate 	/*
7985*0Sstevel@tonic-gate 	 * See if this socket has already been added - if it has, we
7986*0Sstevel@tonic-gate 	 *	fail this. If we can't find the socket, then allocate
7987*0Sstevel@tonic-gate 	 *	a new socket structure. If we do find the socket, then
7988*0Sstevel@tonic-gate 	 *	check to see if it's already added; if it is, then
7989*0Sstevel@tonic-gate 	 *	this is an error and return CS_BAD_SOCKET; if not,
7990*0Sstevel@tonic-gate 	 *	then traverse the socket structure list and add this
7991*0Sstevel@tonic-gate 	 *	next socket strcture to the end of the list.
7992*0Sstevel@tonic-gate 	 * XXX What about locking this list while we update it? Is
7993*0Sstevel@tonic-gate 	 *	that necessary since we're using the SOCKET_IS_VALID
7994*0Sstevel@tonic-gate 	 *	flag and since we never delete a socket from the
7995*0Sstevel@tonic-gate 	 *	list once it's been added?
7996*0Sstevel@tonic-gate 	 */
7997*0Sstevel@tonic-gate 	if ((sp = cs_find_sp(sn)) == NULL) {
7998*0Sstevel@tonic-gate 	    cs_socket_t *spp = cs_globals.sp;
7999*0Sstevel@tonic-gate 
8000*0Sstevel@tonic-gate 	    sp = (cs_socket_t *)kmem_zalloc(sizeof (cs_socket_t), KM_SLEEP);
8001*0Sstevel@tonic-gate 
8002*0Sstevel@tonic-gate 	    if (cs_globals.sp == NULL)
8003*0Sstevel@tonic-gate 		cs_globals.sp = sp;
8004*0Sstevel@tonic-gate 	    else
8005*0Sstevel@tonic-gate 		while (spp) {
8006*0Sstevel@tonic-gate 		    if (spp->next == NULL) {
8007*0Sstevel@tonic-gate 			spp->next = sp;
8008*0Sstevel@tonic-gate 			break;
8009*0Sstevel@tonic-gate 		    } /* if */
8010*0Sstevel@tonic-gate 		    spp = spp->next;
8011*0Sstevel@tonic-gate 		} /* while */
8012*0Sstevel@tonic-gate 
8013*0Sstevel@tonic-gate 	} else {
8014*0Sstevel@tonic-gate 	    if (sp->flags & SOCKET_IS_VALID)
8015*0Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
8016*0Sstevel@tonic-gate 	} /* cs_find_sp */
8017*0Sstevel@tonic-gate 
8018*0Sstevel@tonic-gate 	/*
8019*0Sstevel@tonic-gate 	 * Setup the socket number
8020*0Sstevel@tonic-gate 	 */
8021*0Sstevel@tonic-gate 	sp->socket_num = sn;
8022*0Sstevel@tonic-gate 
8023*0Sstevel@tonic-gate 	/*
8024*0Sstevel@tonic-gate 	 * Find out how many windows the framework knows about
8025*0Sstevel@tonic-gate 	 *	so far. If this number of windows is greater
8026*0Sstevel@tonic-gate 	 *	than our current window count, bump up our
8027*0Sstevel@tonic-gate 	 *	current window count.
8028*0Sstevel@tonic-gate 	 * XXX Note that there is a BIG assumption here and that
8029*0Sstevel@tonic-gate 	 *	is that once the framework tells us that it has
8030*0Sstevel@tonic-gate 	 *	a window (as reflected in the NumWindows
8031*0Sstevel@tonic-gate 	 *	value) it can NEVER remove that window.
8032*0Sstevel@tonic-gate 	 *	When we really get the drop socket and drop
8033*0Sstevel@tonic-gate 	 *	window mechanism working correctly, we'll have
8034*0Sstevel@tonic-gate 	 *	to revisit this.
8035*0Sstevel@tonic-gate 	 */
8036*0Sstevel@tonic-gate 	SocketServices(SS_InquireAdapter, &inquire_adapter);
8037*0Sstevel@tonic-gate 
8038*0Sstevel@tonic-gate 	mutex_enter(&cs_globals.window_lock);
8039*0Sstevel@tonic-gate 	added_windows = inquire_adapter.NumWindows - cs_globals.num_windows;
8040*0Sstevel@tonic-gate 	if (added_windows > 0) {
8041*0Sstevel@tonic-gate 	    if (cs_add_windows(added_windows,
8042*0Sstevel@tonic-gate 				cs_globals.num_windows) != CS_SUCCESS) {
8043*0Sstevel@tonic-gate 		mutex_exit(&cs_globals.window_lock);
8044*0Sstevel@tonic-gate 		return (CS_BAD_WINDOW);
8045*0Sstevel@tonic-gate 	    } /* cs_add_windows */
8046*0Sstevel@tonic-gate 
8047*0Sstevel@tonic-gate 	    cs_globals.num_windows = inquire_adapter.NumWindows;
8048*0Sstevel@tonic-gate 
8049*0Sstevel@tonic-gate 	} /* if (added_windows) */
8050*0Sstevel@tonic-gate 
8051*0Sstevel@tonic-gate 	/*
8052*0Sstevel@tonic-gate 	 * Find a window that we can use for this socket's CIS window.
8053*0Sstevel@tonic-gate 	 */
8054*0Sstevel@tonic-gate 	sp->cis_win_num = PCMCIA_MAX_WINDOWS;
8055*0Sstevel@tonic-gate 
8056*0Sstevel@tonic-gate 	convert_speed.Attributes = CONVERT_NS_TO_DEVSPEED;
8057*0Sstevel@tonic-gate 	convert_speed.nS = CIS_DEFAULT_SPEED;
8058*0Sstevel@tonic-gate 	(void) cs_convert_speed(&convert_speed);
8059*0Sstevel@tonic-gate 
8060*0Sstevel@tonic-gate 	win_req.win_params.AccessSpeed = convert_speed.devspeed;
8061*0Sstevel@tonic-gate 	win_req.Attributes = (WIN_MEMORY_TYPE_AM | WIN_DATA_WIDTH_8);
8062*0Sstevel@tonic-gate 	win_req.Attributes = (WIN_MEMORY_TYPE_AM | WIN_MEMORY_TYPE_CM);
8063*0Sstevel@tonic-gate 	win_req.Base.base = 0;
8064*0Sstevel@tonic-gate 	win_req.Size = 0;
8065*0Sstevel@tonic-gate 
8066*0Sstevel@tonic-gate 	if ((ret = cs_find_mem_window(sp->socket_num, &win_req,
8067*0Sstevel@tonic-gate 					&sp->cis_win_num)) != CS_SUCCESS) {
8068*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
8069*0Sstevel@tonic-gate 	    sp->cis_win_num = PCMCIA_MAX_WINDOWS;
8070*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_add_socket: socket %d can't get CIS "
8071*0Sstevel@tonic-gate 						"window - error 0x%x\n",
8072*0Sstevel@tonic-gate 						sp->socket_num, ret);
8073*0Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
8074*0Sstevel@tonic-gate 	} /* cs_find_mem_window */
8075*0Sstevel@tonic-gate 
8076*0Sstevel@tonic-gate 	if ((cw = cs_get_wp(sp->cis_win_num)) == NULL) {
8077*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.window_lock);
8078*0Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
8079*0Sstevel@tonic-gate 	}
8080*0Sstevel@tonic-gate 
8081*0Sstevel@tonic-gate 	inquire_window.window = sp->cis_win_num;
8082*0Sstevel@tonic-gate 	SocketServices(SS_InquireWindow, &inquire_window);
8083*0Sstevel@tonic-gate 
8084*0Sstevel@tonic-gate 	/*
8085*0Sstevel@tonic-gate 	 * If the CIS window is a variable sized window, then use
8086*0Sstevel@tonic-gate 	 *	the size that cs_find_mem_window returned to us,
8087*0Sstevel@tonic-gate 	 *	since this will be the minimum size that we can
8088*0Sstevel@tonic-gate 	 *	set this window to. If the CIS window is a fixed
8089*0Sstevel@tonic-gate 	 *	sized window, then use the system pagesize as the
8090*0Sstevel@tonic-gate 	 *	CIS window size.
8091*0Sstevel@tonic-gate 	 */
8092*0Sstevel@tonic-gate 	if (inquire_window.mem_win_char.MemWndCaps & WC_SIZE) {
8093*0Sstevel@tonic-gate 	    sp->cis_win_size = win_req.Size;
8094*0Sstevel@tonic-gate 	} else {
8095*0Sstevel@tonic-gate 	    sp->cis_win_size = PAGESIZE;
8096*0Sstevel@tonic-gate 	}
8097*0Sstevel@tonic-gate 
8098*0Sstevel@tonic-gate 	cw->state |= (CW_CIS | CW_ALLOCATED);
8099*0Sstevel@tonic-gate 	cw->socket_num = sp->socket_num;
8100*0Sstevel@tonic-gate 
8101*0Sstevel@tonic-gate 	mutex_exit(&cs_globals.window_lock);
8102*0Sstevel@tonic-gate 
8103*0Sstevel@tonic-gate #if defined(CS_DEBUG)
8104*0Sstevel@tonic-gate 	    if (cs_debug > 1) {
8105*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_add_socket: socket %d using CIS window %d "
8106*0Sstevel@tonic-gate 					"size 0x%x\n", (int)sp->socket_num,
8107*0Sstevel@tonic-gate 					(int)sp->cis_win_num,
8108*0Sstevel@tonic-gate 					(int)sp->cis_win_size);
8109*0Sstevel@tonic-gate 	    }
8110*0Sstevel@tonic-gate #endif
8111*0Sstevel@tonic-gate 
8112*0Sstevel@tonic-gate 	/*
8113*0Sstevel@tonic-gate 	 * Get the adapter information associated with this socket so
8114*0Sstevel@tonic-gate 	 *	that we can initialize the mutexes, condition variables,
8115*0Sstevel@tonic-gate 	 *	soft interrupt handler and per-socket adapter info.
8116*0Sstevel@tonic-gate 	 */
8117*0Sstevel@tonic-gate 	gcad = &sservice.get_cookies;
8118*0Sstevel@tonic-gate 	gcad->socket = sp->socket_num;
8119*0Sstevel@tonic-gate 	if (SocketServices(CSGetCookiesAndDip, &sservice) != SUCCESS) {
8120*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_add_socket: socket %d CSGetCookiesAndDip "
8121*0Sstevel@tonic-gate 						"failure\n", sp->socket_num);
8122*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
8123*0Sstevel@tonic-gate 	} /* CSGetCookiesAndDip */
8124*0Sstevel@tonic-gate 
8125*0Sstevel@tonic-gate 	/*
8126*0Sstevel@tonic-gate 	 * Save the iblock and idev cookies for RegisterClient
8127*0Sstevel@tonic-gate 	 */
8128*0Sstevel@tonic-gate 	sp->iblk = gcad->iblock;
8129*0Sstevel@tonic-gate 	sp->idev = gcad->idevice;
8130*0Sstevel@tonic-gate 
8131*0Sstevel@tonic-gate 	/*
8132*0Sstevel@tonic-gate 	 * Setup the per-socket adapter info
8133*0Sstevel@tonic-gate 	 */
8134*0Sstevel@tonic-gate 	sp->adapter.flags = 0;
8135*0Sstevel@tonic-gate 	(void) strcpy(sp->adapter.name, gcad->adapter_info.name);
8136*0Sstevel@tonic-gate 	sp->adapter.major = gcad->adapter_info.major;
8137*0Sstevel@tonic-gate 	sp->adapter.minor = gcad->adapter_info.minor;
8138*0Sstevel@tonic-gate 	sp->adapter.instance = ddi_get_instance(gcad->dip);
8139*0Sstevel@tonic-gate 	sp->adapter.number = gcad->adapter_info.number;
8140*0Sstevel@tonic-gate 	sp->adapter.num_sockets = gcad->adapter_info.num_sockets;
8141*0Sstevel@tonic-gate 	sp->adapter.first_socket = gcad->adapter_info.first_socket;
8142*0Sstevel@tonic-gate 
8143*0Sstevel@tonic-gate 	/* Setup for cs_event and cs_event_thread */
8144*0Sstevel@tonic-gate 	mutex_init(&sp->lock, NULL, MUTEX_DRIVER, *(gcad->iblock));
8145*0Sstevel@tonic-gate 	mutex_init(&sp->client_lock, NULL, MUTEX_DRIVER, NULL);
8146*0Sstevel@tonic-gate 	mutex_init(&sp->cis_lock, NULL, MUTEX_DRIVER, NULL);
8147*0Sstevel@tonic-gate 
8148*0Sstevel@tonic-gate 	/* Setup for Socket Services work thread */
8149*0Sstevel@tonic-gate 	mutex_init(&sp->ss_thread_lock, NULL, MUTEX_DRIVER, NULL);
8150*0Sstevel@tonic-gate 
8151*0Sstevel@tonic-gate 	sp->init_state |= SOCKET_INIT_STATE_MUTEX;
8152*0Sstevel@tonic-gate 
8153*0Sstevel@tonic-gate 	/* Setup for cs_event_thread */
8154*0Sstevel@tonic-gate 	cv_init(&sp->thread_cv, NULL, CV_DRIVER, NULL);
8155*0Sstevel@tonic-gate 	cv_init(&sp->caller_cv, NULL, CV_DRIVER, NULL);
8156*0Sstevel@tonic-gate 	cv_init(&sp->reset_cv, NULL, CV_DRIVER, NULL);
8157*0Sstevel@tonic-gate 
8158*0Sstevel@tonic-gate 	/* Setup for Socket Services work thread */
8159*0Sstevel@tonic-gate 	cv_init(&sp->ss_thread_cv, NULL, CV_DRIVER, NULL);
8160*0Sstevel@tonic-gate 	cv_init(&sp->ss_caller_cv, NULL, CV_DRIVER, NULL);
8161*0Sstevel@tonic-gate 
8162*0Sstevel@tonic-gate 	sp->init_state |= SOCKET_INIT_STATE_CV;
8163*0Sstevel@tonic-gate 
8164*0Sstevel@tonic-gate 	/*
8165*0Sstevel@tonic-gate 	 * If we haven't installed it yet, then install the soft interrupt
8166*0Sstevel@tonic-gate 	 *	handler and save away the softint id.
8167*0Sstevel@tonic-gate 	 */
8168*0Sstevel@tonic-gate 	if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SOFTINTR)) {
8169*0Sstevel@tonic-gate 	    if (ddi_add_softintr(gcad->dip, DDI_SOFTINT_HIGH,
8170*0Sstevel@tonic-gate 						&sp->softint_id,
8171*0Sstevel@tonic-gate 						NULL, NULL,
8172*0Sstevel@tonic-gate 						cs_socket_event_softintr,
8173*0Sstevel@tonic-gate 						(caddr_t)NULL) != DDI_SUCCESS) {
8174*0Sstevel@tonic-gate 		    cmn_err(CE_CONT, "cs_add_socket: socket %d can't add "
8175*0Sstevel@tonic-gate 						"softintr\n", sp->socket_num);
8176*0Sstevel@tonic-gate 		    return (CS_BAD_SOCKET);
8177*0Sstevel@tonic-gate 	    } /* ddi_add_softintr */
8178*0Sstevel@tonic-gate 
8179*0Sstevel@tonic-gate 	    mutex_enter(&cs_globals.global_lock);
8180*0Sstevel@tonic-gate 	    cs_globals.softint_id = sp->softint_id;
8181*0Sstevel@tonic-gate 	    cs_globals.init_state |= GLOBAL_INIT_STATE_SOFTINTR;
8182*0Sstevel@tonic-gate 	    /* XXX this timer is hokey at best... */
8183*0Sstevel@tonic-gate 	    cs_globals.sotfint_tmo = timeout(cs_event_softintr_timeout,
8184*0Sstevel@tonic-gate 		NULL, SOFTINT_TIMEOUT_TIME);
8185*0Sstevel@tonic-gate 	    mutex_exit(&cs_globals.global_lock);
8186*0Sstevel@tonic-gate 	} else {
8187*0Sstevel@tonic-gate 		/*
8188*0Sstevel@tonic-gate 		 * We've already added the soft interrupt handler, so just
8189*0Sstevel@tonic-gate 		 *	store away the softint id.
8190*0Sstevel@tonic-gate 		 */
8191*0Sstevel@tonic-gate 	    sp->softint_id = cs_globals.softint_id;
8192*0Sstevel@tonic-gate 	} /* if (!GLOBAL_INIT_STATE_SOFTINTR) */
8193*0Sstevel@tonic-gate 
8194*0Sstevel@tonic-gate 	/*
8195*0Sstevel@tonic-gate 	 * While this next flag doesn't really describe a per-socket
8196*0Sstevel@tonic-gate 	 *	resource, we still set it for each socket.  When the soft
8197*0Sstevel@tonic-gate 	 *	interrupt handler finally gets removed in cs_deinit, this
8198*0Sstevel@tonic-gate 	 *	flag will get cleared.
8199*0Sstevel@tonic-gate 	 */
8200*0Sstevel@tonic-gate 	sp->init_state |= SOCKET_INIT_STATE_SOFTINTR;
8201*0Sstevel@tonic-gate 
8202*0Sstevel@tonic-gate 	/*
8203*0Sstevel@tonic-gate 	 * Socket Services defaults all sockets to power off and
8204*0Sstevel@tonic-gate 	 *	clears all event masks.  We want to receive at least
8205*0Sstevel@tonic-gate 	 *	card insertion events, so enable them.  Turn off power
8206*0Sstevel@tonic-gate 	 *	to the socket as well.  We will turn it on again when
8207*0Sstevel@tonic-gate 	 *	we get a card insertion event.
8208*0Sstevel@tonic-gate 	 */
8209*0Sstevel@tonic-gate 	sp->event_mask = CS_EVENT_CARD_INSERTION;
8210*0Sstevel@tonic-gate 	set_socket.socket = sp->socket_num;
8211*0Sstevel@tonic-gate 	set_socket.SCIntMask = SBM_CD;
8212*0Sstevel@tonic-gate 	set_socket.IREQRouting = 0;
8213*0Sstevel@tonic-gate 	set_socket.IFType = IF_MEMORY;
8214*0Sstevel@tonic-gate 	set_socket.CtlInd = 0; /* turn off controls and indicators */
8215*0Sstevel@tonic-gate 	set_socket.State = (unsigned)~0;	/* clear latched state bits */
8216*0Sstevel@tonic-gate 
8217*0Sstevel@tonic-gate 	(void) cs_convert_powerlevel(sp->socket_num, 0, VCC,
8218*0Sstevel@tonic-gate 						&set_socket.VccLevel);
8219*0Sstevel@tonic-gate 	(void) cs_convert_powerlevel(sp->socket_num, 0, VPP1,
8220*0Sstevel@tonic-gate 						&set_socket.Vpp1Level);
8221*0Sstevel@tonic-gate 	(void) cs_convert_powerlevel(sp->socket_num, 0, VPP2,
8222*0Sstevel@tonic-gate 						&set_socket.Vpp2Level);
8223*0Sstevel@tonic-gate 
8224*0Sstevel@tonic-gate 	if ((ret = SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) {
8225*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_add_socket: socket %d SS_SetSocket "
8226*0Sstevel@tonic-gate 					"failure %d\n", sp->socket_num, ret);
8227*0Sstevel@tonic-gate 		return (CS_BAD_SOCKET);
8228*0Sstevel@tonic-gate 	} /* SS_SetSocket */
8229*0Sstevel@tonic-gate 
8230*0Sstevel@tonic-gate 	/*
8231*0Sstevel@tonic-gate 	 * The various socket-specific variables are now set up, so
8232*0Sstevel@tonic-gate 	 *	increment the global socket count and also mark the
8233*0Sstevel@tonic-gate 	 *	socket as available. We need to set this before we
8234*0Sstevel@tonic-gate 	 *	start any of the per-socket threads so that the threads
8235*0Sstevel@tonic-gate 	 *	can get a valid socket pointer when they start.
8236*0Sstevel@tonic-gate 	 */
8237*0Sstevel@tonic-gate 	mutex_enter(&cs_globals.global_lock);
8238*0Sstevel@tonic-gate 	cs_globals.num_sockets++;
8239*0Sstevel@tonic-gate 	cs_globals.max_socket_num =
8240*0Sstevel@tonic-gate 			max(cs_globals.max_socket_num, sp->socket_num + 1);
8241*0Sstevel@tonic-gate 	mutex_exit(&cs_globals.global_lock);
8242*0Sstevel@tonic-gate 	sp->flags = SOCKET_IS_VALID;
8243*0Sstevel@tonic-gate 
8244*0Sstevel@tonic-gate 	/*
8245*0Sstevel@tonic-gate 	 * Create the per-socket event handler thread.
8246*0Sstevel@tonic-gate 	 */
8247*0Sstevel@tonic-gate 	sp->event_thread = CREATE_SOCKET_EVENT_THREAD(cs_event_thread,
8248*0Sstevel@tonic-gate 		(uintptr_t)sn);
8249*0Sstevel@tonic-gate 
8250*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
8251*0Sstevel@tonic-gate 	sp->init_state |= SOCKET_INIT_STATE_THREAD;
8252*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
8253*0Sstevel@tonic-gate 
8254*0Sstevel@tonic-gate 	/*
8255*0Sstevel@tonic-gate 	 * Create the per-socket Socket Services work thread.
8256*0Sstevel@tonic-gate 	 */
8257*0Sstevel@tonic-gate 	sp->ss_thread = CREATE_SOCKET_EVENT_THREAD(cs_ss_thread,
8258*0Sstevel@tonic-gate 		(uintptr_t)sn);
8259*0Sstevel@tonic-gate 
8260*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
8261*0Sstevel@tonic-gate 	sp->init_state |= (SOCKET_INIT_STATE_SS_THREAD |
8262*0Sstevel@tonic-gate 						SOCKET_INIT_STATE_READY);
8263*0Sstevel@tonic-gate 	sp->event_mask = CS_EVENT_CARD_INSERTION;
8264*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
8265*0Sstevel@tonic-gate 
8266*0Sstevel@tonic-gate 	return (CS_SUCCESS);
8267*0Sstevel@tonic-gate }
8268*0Sstevel@tonic-gate 
8269*0Sstevel@tonic-gate /*
8270*0Sstevel@tonic-gate  * cs_drop_socket - drop a socket
8271*0Sstevel@tonic-gate  *
8272*0Sstevel@tonic-gate  *	call:	sn - socket number to drop
8273*0Sstevel@tonic-gate  *
8274*0Sstevel@tonic-gate  *	return:	CS_SUCCESS - operation sucessful
8275*0Sstevel@tonic-gate  *		CS_BAD_SOCKET - unable to drop socket
8276*0Sstevel@tonic-gate  */
8277*0Sstevel@tonic-gate /*ARGSUSED*/
8278*0Sstevel@tonic-gate static uint32_t
8279*0Sstevel@tonic-gate cs_drop_socket(uint32_t sn)
8280*0Sstevel@tonic-gate {
8281*0Sstevel@tonic-gate #ifdef	XXX
8282*0Sstevel@tonic-gate 	cs_socket_t *sp;
8283*0Sstevel@tonic-gate 
8284*0Sstevel@tonic-gate 	/*
8285*0Sstevel@tonic-gate 	 * Tell the socket event thread to exit and then wait for it
8286*0Sstevel@tonic-gate 	 *	to do so.
8287*0Sstevel@tonic-gate 	 */
8288*0Sstevel@tonic-gate 	mutex_enter(&sp->client_lock);
8289*0Sstevel@tonic-gate 	sp->thread_state |= SOCKET_THREAD_EXIT;
8290*0Sstevel@tonic-gate 	cv_broadcast(&sp->thread_cv);
8291*0Sstevel@tonic-gate 	cv_wait(&sp->caller_cv, &sp->client_lock);
8292*0Sstevel@tonic-gate 	mutex_exit(&sp->client_lock);
8293*0Sstevel@tonic-gate 
8294*0Sstevel@tonic-gate 	/*
8295*0Sstevel@tonic-gate 	 * Tell the socket SS thread to exit and then wait for it
8296*0Sstevel@tonic-gate 	 *	to do so.
8297*0Sstevel@tonic-gate 	 */
8298*0Sstevel@tonic-gate 
8299*0Sstevel@tonic-gate 	/*
8300*0Sstevel@tonic-gate 	 * Mark the socket as dropped.
8301*0Sstevel@tonic-gate 	 */
8302*0Sstevel@tonic-gate 	sp->flags &= ~SOCKET_IS_VALID;
8303*0Sstevel@tonic-gate 
8304*0Sstevel@tonic-gate #endif	/* XXX */
8305*0Sstevel@tonic-gate 
8306*0Sstevel@tonic-gate 	/* XXX for now don't allow dropping sockets XXX */
8307*0Sstevel@tonic-gate 	return (CS_BAD_SOCKET);
8308*0Sstevel@tonic-gate }
8309*0Sstevel@tonic-gate 
8310*0Sstevel@tonic-gate /*
8311*0Sstevel@tonic-gate  * cs_get_socket - returns the socket and function numbers and a pointer
8312*0Sstevel@tonic-gate  *			to the socket structure
8313*0Sstevel@tonic-gate  *
8314*0Sstevel@tonic-gate  * calling:	client_handle_t client_handle - client handle to extract
8315*0Sstevel@tonic-gate  *						socket number from
8316*0Sstevel@tonic-gate  *		uint32_t *socket -  pointer to socket number to use if
8317*0Sstevel@tonic-gate  *					client_handle is for the SS client;
8318*0Sstevel@tonic-gate  *					this value will be filled in on
8319*0Sstevel@tonic-gate  *					return with the correct socket
8320*0Sstevel@tonic-gate  *					and function numbers if we
8321*0Sstevel@tonic-gate  *					return CS_SUCCESS
8322*0Sstevel@tonic-gate  *		uint32_t *function - pointer to return function number into
8323*0Sstevel@tonic-gate  *					if not NULL
8324*0Sstevel@tonic-gate  *		cs_socket_t **sp - pointer to a pointer where a pointer
8325*0Sstevel@tonic-gate  *					to the socket struct will be
8326*0Sstevel@tonic-gate  *					placed if this is non-NULL
8327*0Sstevel@tonic-gate  *		client_t **clp - pointer to a pointer where a pointer
8328*0Sstevel@tonic-gate  *					to the client struct will be
8329*0Sstevel@tonic-gate  *					placed if this is non-NULL
8330*0Sstevel@tonic-gate  *
8331*0Sstevel@tonic-gate  *    The socket and function numbers are derived as follows:
8332*0Sstevel@tonic-gate  *
8333*0Sstevel@tonic-gate  *	Client Type		Socket Number		Function Number
8334*0Sstevel@tonic-gate  *	PC card client		From client_handle	From client_handle
8335*0Sstevel@tonic-gate  *	Socket Services client	From *socket		From *socket
8336*0Sstevel@tonic-gate  *	CSI client		From client_handle	From *socket
8337*0Sstevel@tonic-gate  */
8338*0Sstevel@tonic-gate static uint32_t
8339*0Sstevel@tonic-gate cs_get_socket(client_handle_t client_handle, uint32_t *socket,
8340*0Sstevel@tonic-gate     uint32_t *function, cs_socket_t **csp, client_t **clp)
8341*0Sstevel@tonic-gate {
8342*0Sstevel@tonic-gate 	cs_socket_t *sp;
8343*0Sstevel@tonic-gate 	client_t *client;
8344*0Sstevel@tonic-gate 	uint32_t sn, fn;
8345*0Sstevel@tonic-gate 	int ret;
8346*0Sstevel@tonic-gate 
8347*0Sstevel@tonic-gate 	sn = *socket;
8348*0Sstevel@tonic-gate 
8349*0Sstevel@tonic-gate 	/*
8350*0Sstevel@tonic-gate 	 * If this is the Socket Services client, then return the
8351*0Sstevel@tonic-gate 	 *	socket and function numbers specified in the passed
8352*0Sstevel@tonic-gate 	 *	socket number parameter, otherwise extract the socket
8353*0Sstevel@tonic-gate 	 *	and function numbers from the client handle.
8354*0Sstevel@tonic-gate 	 */
8355*0Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle)) {
8356*0Sstevel@tonic-gate 	    fn = CS_GET_FUNCTION_NUMBER(sn);
8357*0Sstevel@tonic-gate 	    sn = CS_GET_SOCKET_NUMBER(sn);
8358*0Sstevel@tonic-gate 	} else {
8359*0Sstevel@tonic-gate 	    fn = GET_CLIENT_FUNCTION(client_handle);
8360*0Sstevel@tonic-gate 	    sn = GET_CLIENT_SOCKET(client_handle);
8361*0Sstevel@tonic-gate 	}
8362*0Sstevel@tonic-gate 
8363*0Sstevel@tonic-gate 	/*
8364*0Sstevel@tonic-gate 	 * Check to be sure that the socket number is in range
8365*0Sstevel@tonic-gate 	 */
8366*0Sstevel@tonic-gate 	if (!(CHECK_SOCKET_NUM(sn, cs_globals.max_socket_num)))
8367*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
8368*0Sstevel@tonic-gate 
8369*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(sn)) == NULL)
8370*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
8371*0Sstevel@tonic-gate 
8372*0Sstevel@tonic-gate 	/*
8373*0Sstevel@tonic-gate 	 * If we were given a pointer, then fill it in with a pointer
8374*0Sstevel@tonic-gate 	 *	to this socket.
8375*0Sstevel@tonic-gate 	 */
8376*0Sstevel@tonic-gate 	if (csp)
8377*0Sstevel@tonic-gate 	    *csp = sp;
8378*0Sstevel@tonic-gate 
8379*0Sstevel@tonic-gate 	/*
8380*0Sstevel@tonic-gate 	 * Search for the client; if it's not found, return an error.
8381*0Sstevel@tonic-gate 	 */
8382*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
8383*0Sstevel@tonic-gate 	if (!(client = cs_find_client(client_handle, &ret))) {
8384*0Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
8385*0Sstevel@tonic-gate 	    return (ret);
8386*0Sstevel@tonic-gate 	}
8387*0Sstevel@tonic-gate 
8388*0Sstevel@tonic-gate 	/*
8389*0Sstevel@tonic-gate 	 * If we're a CIS client, then extract the function number
8390*0Sstevel@tonic-gate 	 *	from the socket number.
8391*0Sstevel@tonic-gate 	 */
8392*0Sstevel@tonic-gate 	if (client->flags & CLIENT_CSI_CLIENT)
8393*0Sstevel@tonic-gate 	    fn = CS_GET_FUNCTION_NUMBER(*socket);
8394*0Sstevel@tonic-gate 
8395*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
8396*0Sstevel@tonic-gate 
8397*0Sstevel@tonic-gate 	/*
8398*0Sstevel@tonic-gate 	 * Return the found client pointer if the caller wants it.
8399*0Sstevel@tonic-gate 	 */
8400*0Sstevel@tonic-gate 	if (clp)
8401*0Sstevel@tonic-gate 	    *clp = client;
8402*0Sstevel@tonic-gate 
8403*0Sstevel@tonic-gate 	/*
8404*0Sstevel@tonic-gate 	 * Return a socket number that is made up of the socket number
8405*0Sstevel@tonic-gate 	 *	and the function number.
8406*0Sstevel@tonic-gate 	 */
8407*0Sstevel@tonic-gate 	*socket = CS_MAKE_SOCKET_NUMBER(sn, fn);
8408*0Sstevel@tonic-gate 
8409*0Sstevel@tonic-gate 	/*
8410*0Sstevel@tonic-gate 	 * Return the function number if the caller wants it.
8411*0Sstevel@tonic-gate 	 */
8412*0Sstevel@tonic-gate 	if (function)
8413*0Sstevel@tonic-gate 	    *function = fn;
8414*0Sstevel@tonic-gate 
8415*0Sstevel@tonic-gate 	return (CS_SUCCESS);
8416*0Sstevel@tonic-gate }
8417*0Sstevel@tonic-gate 
8418*0Sstevel@tonic-gate /*
8419*0Sstevel@tonic-gate  * cs_get_wp - returns pointer to passed window number
8420*0Sstevel@tonic-gate  *
8421*0Sstevel@tonic-gate  *	return: (cs_window_t *) - pointer to window structure
8422*0Sstevel@tonic-gate  *		NULL - if invalid window number passed in
8423*0Sstevel@tonic-gate  */
8424*0Sstevel@tonic-gate static cs_window_t *
8425*0Sstevel@tonic-gate cs_get_wp(uint32_t wn)
8426*0Sstevel@tonic-gate {
8427*0Sstevel@tonic-gate 	cs_window_t *cw;
8428*0Sstevel@tonic-gate 
8429*0Sstevel@tonic-gate 	if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY))
8430*0Sstevel@tonic-gate 	    return (NULL);
8431*0Sstevel@tonic-gate 
8432*0Sstevel@tonic-gate 	if ((cw = cs_find_wp(wn)) == NULL)
8433*0Sstevel@tonic-gate 	    return (NULL);
8434*0Sstevel@tonic-gate 
8435*0Sstevel@tonic-gate 	if (cw->state & CW_WINDOW_VALID)
8436*0Sstevel@tonic-gate 	    return (cw);
8437*0Sstevel@tonic-gate 
8438*0Sstevel@tonic-gate #ifdef  CS_DEBUG
8439*0Sstevel@tonic-gate 	if (cs_debug > 0) {
8440*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_get_wp(): wn=%d  cw=%p\n",
8441*0Sstevel@tonic-gate 		    (int)wn, (void *)cw);
8442*0Sstevel@tonic-gate 	}
8443*0Sstevel@tonic-gate #endif
8444*0Sstevel@tonic-gate 
8445*0Sstevel@tonic-gate 	return (NULL);
8446*0Sstevel@tonic-gate }
8447*0Sstevel@tonic-gate 
8448*0Sstevel@tonic-gate /*
8449*0Sstevel@tonic-gate  * cs_find_wp - searches window list and returns pointer to passed window
8450*0Sstevel@tonic-gate  *			number
8451*0Sstevel@tonic-gate  *
8452*0Sstevel@tonic-gate  *	return: (cs_window_t *) - pointer to window structure
8453*0Sstevel@tonic-gate  *		NULL - window not found
8454*0Sstevel@tonic-gate  */
8455*0Sstevel@tonic-gate static cs_window_t *
8456*0Sstevel@tonic-gate cs_find_wp(uint32_t wn)
8457*0Sstevel@tonic-gate {
8458*0Sstevel@tonic-gate 	cs_window_t *cw = cs_globals.cw;
8459*0Sstevel@tonic-gate 
8460*0Sstevel@tonic-gate 	while (cw) {
8461*0Sstevel@tonic-gate 	    if (cw->window_num == wn)
8462*0Sstevel@tonic-gate 		return (cw);
8463*0Sstevel@tonic-gate 	    cw = cw->next;
8464*0Sstevel@tonic-gate 	} /* while */
8465*0Sstevel@tonic-gate 
8466*0Sstevel@tonic-gate #ifdef  CS_DEBUG
8467*0Sstevel@tonic-gate 	if (cs_debug > 0) {
8468*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_find_wp(): wn=%d  window_num=%d cw=%p\n",
8469*0Sstevel@tonic-gate 		    (int)wn, (int)cw->window_num, (void *)cw);
8470*0Sstevel@tonic-gate 	}
8471*0Sstevel@tonic-gate #endif
8472*0Sstevel@tonic-gate 
8473*0Sstevel@tonic-gate 	return (NULL);
8474*0Sstevel@tonic-gate }
8475*0Sstevel@tonic-gate 
8476*0Sstevel@tonic-gate /*
8477*0Sstevel@tonic-gate  * cs_add_windows - adds number of windows specified in "aw" to
8478*0Sstevel@tonic-gate  *			the global window list; start the window
8479*0Sstevel@tonic-gate  *			numbering at "bn"
8480*0Sstevel@tonic-gate  *
8481*0Sstevel@tonic-gate  *	return: CS_SUCCESS - if windows added sucessfully
8482*0Sstevel@tonic-gate  *		CS_BAD_WINDOW - if unable to add windows
8483*0Sstevel@tonic-gate  *
8484*0Sstevel@tonic-gate  * Note: The window list must be protected by a lock by the caller.
8485*0Sstevel@tonic-gate  */
8486*0Sstevel@tonic-gate static int
8487*0Sstevel@tonic-gate cs_add_windows(int aw, uint32_t bn)
8488*0Sstevel@tonic-gate {
8489*0Sstevel@tonic-gate 	cs_window_t *cwp = cs_globals.cw;
8490*0Sstevel@tonic-gate 	cs_window_t *cw, *cwpp;
8491*0Sstevel@tonic-gate 
8492*0Sstevel@tonic-gate 	if (aw <= 0)
8493*0Sstevel@tonic-gate 	    return (CS_BAD_WINDOW);
8494*0Sstevel@tonic-gate 
8495*0Sstevel@tonic-gate 	while (cwp) {
8496*0Sstevel@tonic-gate 	    cwpp = cwp;
8497*0Sstevel@tonic-gate 	    cwp = cwp->next;
8498*0Sstevel@tonic-gate 	}
8499*0Sstevel@tonic-gate 
8500*0Sstevel@tonic-gate 	while (aw--) {
8501*0Sstevel@tonic-gate 	    cw = (cs_window_t *)kmem_zalloc(sizeof (cs_window_t), KM_SLEEP);
8502*0Sstevel@tonic-gate 
8503*0Sstevel@tonic-gate 	    if (cs_globals.cw == NULL) {
8504*0Sstevel@tonic-gate 		cs_globals.cw = cw;
8505*0Sstevel@tonic-gate 		cwpp = cs_globals.cw;
8506*0Sstevel@tonic-gate 	    } else {
8507*0Sstevel@tonic-gate 		cwpp->next = cw;
8508*0Sstevel@tonic-gate 		cwpp = cwpp->next;
8509*0Sstevel@tonic-gate 	    }
8510*0Sstevel@tonic-gate 
8511*0Sstevel@tonic-gate 	    cwpp->window_num = bn++;
8512*0Sstevel@tonic-gate 	    cwpp->state = CW_WINDOW_VALID;
8513*0Sstevel@tonic-gate 
8514*0Sstevel@tonic-gate 	} /* while (aw) */
8515*0Sstevel@tonic-gate 
8516*0Sstevel@tonic-gate 	return (CS_SUCCESS);
8517*0Sstevel@tonic-gate }
8518*0Sstevel@tonic-gate 
8519*0Sstevel@tonic-gate /*
8520*0Sstevel@tonic-gate  * cs_ss_init - initialize CS items that need to wait until we receive
8521*0Sstevel@tonic-gate  *			a PCE_SS_INIT_STATE/PCE_SS_STATE_INIT event
8522*0Sstevel@tonic-gate  *
8523*0Sstevel@tonic-gate  *	return: CS_SUCESS - if sucessfully initialized
8524*0Sstevel@tonic-gate  *		(various) if error initializing
8525*0Sstevel@tonic-gate  *
8526*0Sstevel@tonic-gate  *	At this point, we expect that Socket Services has setup the
8527*0Sstevel@tonic-gate  *	following global variables for us:
8528*0Sstevel@tonic-gate  *
8529*0Sstevel@tonic-gate  *		cs_socket_services - Socket Services entry point
8530*0Sstevel@tonic-gate  *		cis_parser - CIS parser entry point
8531*0Sstevel@tonic-gate  */
8532*0Sstevel@tonic-gate static uint32_t
8533*0Sstevel@tonic-gate cs_ss_init()
8534*0Sstevel@tonic-gate {
8535*0Sstevel@tonic-gate 	cs_register_cardservices_t rcs;
8536*0Sstevel@tonic-gate 	csregister_t csr;
8537*0Sstevel@tonic-gate 	uint32_t ret;
8538*0Sstevel@tonic-gate 
8539*0Sstevel@tonic-gate 	/*
8540*0Sstevel@tonic-gate 	 * Fill out the parameters for CISP_CIS_SETUP
8541*0Sstevel@tonic-gate 	 */
8542*0Sstevel@tonic-gate 	csr.cs_magic = PCCS_MAGIC;
8543*0Sstevel@tonic-gate 	csr.cs_version = PCCS_VERSION;
8544*0Sstevel@tonic-gate 	csr.cs_card_services = CardServices;
8545*0Sstevel@tonic-gate 	csr.cs_event = NULL;
8546*0Sstevel@tonic-gate 
8547*0Sstevel@tonic-gate 	/*
8548*0Sstevel@tonic-gate 	 * Call into the CIS module and tell it what the private
8549*0Sstevel@tonic-gate 	 *	Card Services entry point is. The CIS module will
8550*0Sstevel@tonic-gate 	 *	call us back at CardServices(CISRegister, ...)
8551*0Sstevel@tonic-gate 	 *	with the address of various CIS-specific global
8552*0Sstevel@tonic-gate 	 *	data structures.
8553*0Sstevel@tonic-gate 	 */
8554*0Sstevel@tonic-gate 	CIS_PARSER(CISP_CIS_SETUP, &csr);
8555*0Sstevel@tonic-gate 
8556*0Sstevel@tonic-gate 	/*
8557*0Sstevel@tonic-gate 	 * Register with the Card Services kernel stubs module
8558*0Sstevel@tonic-gate 	 */
8559*0Sstevel@tonic-gate 	rcs.magic = CS_STUBS_MAGIC;
8560*0Sstevel@tonic-gate 	rcs.function = CS_ENTRY_REGISTER;
8561*0Sstevel@tonic-gate 	rcs.cardservices = CardServices;
8562*0Sstevel@tonic-gate 
8563*0Sstevel@tonic-gate 	if ((ret = csx_register_cardservices(&rcs)) != CS_SUCCESS) {
8564*0Sstevel@tonic-gate 	    cmn_err(CE_CONT, "cs_ss_init: can't register with "
8565*0Sstevel@tonic-gate 					"cs_stubs, retcode = 0x%x\n", ret);
8566*0Sstevel@tonic-gate 		return (ret);
8567*0Sstevel@tonic-gate 	} /* csx_register_cardservices */
8568*0Sstevel@tonic-gate 
8569*0Sstevel@tonic-gate 	return (CS_SUCCESS);
8570*0Sstevel@tonic-gate }
8571*0Sstevel@tonic-gate 
8572*0Sstevel@tonic-gate /*
8573*0Sstevel@tonic-gate  * cs_create_cis - reads CIS on card in socket and creates CIS lists
8574*0Sstevel@tonic-gate  *
8575*0Sstevel@tonic-gate  * Most of the work is done in the CIS module in the CISP_CIS_LIST_CREATE
8576*0Sstevel@tonic-gate  *	function.
8577*0Sstevel@tonic-gate  *
8578*0Sstevel@tonic-gate  * This function returns:
8579*0Sstevel@tonic-gate  *
8580*0Sstevel@tonic-gate  *	CS_SUCCESS - if the CIS lists were created sucessfully
8581*0Sstevel@tonic-gate  *	CS_BAD_WINDOW or CS_GENERAL_FAILURE - if CIS window could
8582*0Sstevel@tonic-gate  *			not be setup
8583*0Sstevel@tonic-gate  *	CS_BAD_CIS - if error creating CIS chains
8584*0Sstevel@tonic-gate  *	CS_BAD_OFFSET - if the CIS parser tried to read past the
8585*0Sstevel@tonic-gate  *			boundries of the allocated CIS window
8586*0Sstevel@tonic-gate  */
8587*0Sstevel@tonic-gate static int
8588*0Sstevel@tonic-gate cs_create_cis(cs_socket_t *sp)
8589*0Sstevel@tonic-gate {
8590*0Sstevel@tonic-gate 	uint32_t ret;
8591*0Sstevel@tonic-gate 
8592*0Sstevel@tonic-gate 	ret = (uint32_t)(uintptr_t)CIS_PARSER(CISP_CIS_LIST_CREATE,
8593*0Sstevel@tonic-gate 	    cis_cistpl_std_callout, sp);
8594*0Sstevel@tonic-gate 
8595*0Sstevel@tonic-gate #ifdef	CS_DEBUG
8596*0Sstevel@tonic-gate 	if (ret == CS_NO_CIS) {
8597*0Sstevel@tonic-gate 	    if (cs_debug > 0)
8598*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_create_cis: socket %d has no CIS\n",
8599*0Sstevel@tonic-gate 								sp->socket_num);
8600*0Sstevel@tonic-gate 	} else if (ret != CS_SUCCESS) {
8601*0Sstevel@tonic-gate 	    if (cs_debug > 0)
8602*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "cs_create_cis: socket %d ERROR = 0x%x\n",
8603*0Sstevel@tonic-gate 							sp->socket_num, ret);
8604*0Sstevel@tonic-gate 	    return (ret);
8605*0Sstevel@tonic-gate 	}
8606*0Sstevel@tonic-gate #else
8607*0Sstevel@tonic-gate 	if (ret != CS_NO_CIS)
8608*0Sstevel@tonic-gate 	    if (ret != CS_SUCCESS)
8609*0Sstevel@tonic-gate 		return (ret);
8610*0Sstevel@tonic-gate #endif
8611*0Sstevel@tonic-gate 
8612*0Sstevel@tonic-gate 	/*
8613*0Sstevel@tonic-gate 	 * If this card didn't have any CIS at all, there's not much
8614*0Sstevel@tonic-gate 	 *	else for us to do.
8615*0Sstevel@tonic-gate 	 */
8616*0Sstevel@tonic-gate 	if (!(sp->cis_flags & CW_VALID_CIS))
8617*0Sstevel@tonic-gate 	    return (CS_SUCCESS);
8618*0Sstevel@tonic-gate 
8619*0Sstevel@tonic-gate 	/*
8620*0Sstevel@tonic-gate 	 * If this is a single-function card, we need to move the CIS list
8621*0Sstevel@tonic-gate 	 *	that is currently on CS_GLOBAL_CIS to the function zero
8622*0Sstevel@tonic-gate 	 *	CIS list.
8623*0Sstevel@tonic-gate 	 */
8624*0Sstevel@tonic-gate 	if (!(sp->cis_flags & CW_MULTI_FUNCTION_CIS)) {
8625*0Sstevel@tonic-gate 	    bcopy((caddr_t)&sp->cis[CS_GLOBAL_CIS],
8626*0Sstevel@tonic-gate 				(caddr_t)&sp->cis[0], sizeof (cis_info_t));
8627*0Sstevel@tonic-gate 	    bzero((caddr_t)&sp->cis[CS_GLOBAL_CIS], sizeof (cis_info_t));
8628*0Sstevel@tonic-gate 	} /* !CW_MULTI_FUNCTION_CIS */
8629*0Sstevel@tonic-gate 
8630*0Sstevel@tonic-gate 	return (CS_SUCCESS);
8631*0Sstevel@tonic-gate }
8632*0Sstevel@tonic-gate 
8633*0Sstevel@tonic-gate /*
8634*0Sstevel@tonic-gate  * cs_destroy_cis - destroys CIS list for socket
8635*0Sstevel@tonic-gate  */
8636*0Sstevel@tonic-gate static int
8637*0Sstevel@tonic-gate cs_destroy_cis(cs_socket_t *sp)
8638*0Sstevel@tonic-gate {
8639*0Sstevel@tonic-gate 	CIS_PARSER(CISP_CIS_LIST_DESTROY, sp);
8640*0Sstevel@tonic-gate 
8641*0Sstevel@tonic-gate 	return (CS_SUCCESS);
8642*0Sstevel@tonic-gate }
8643*0Sstevel@tonic-gate 
8644*0Sstevel@tonic-gate /*
8645*0Sstevel@tonic-gate  * cs_get_client_info - This function is GetClientInfo.
8646*0Sstevel@tonic-gate  *
8647*0Sstevel@tonic-gate  *    calling:	client_handle_t - client handle to get client info on
8648*0Sstevel@tonic-gate  *		client_info_t * - pointer to a client_info_t structure
8649*0Sstevel@tonic-gate  *					to return client information in
8650*0Sstevel@tonic-gate  *
8651*0Sstevel@tonic-gate  *    returns:	CS_SUCCESS - if client info retreived from client
8652*0Sstevel@tonic-gate  *		CS_BAD_SOCKET, CS_BAD_HANDLE - if invalid client
8653*0Sstevel@tonic-gate  *					handle passed in
8654*0Sstevel@tonic-gate  *		CS_NO_MORE_ITEMS - if client does not handle the
8655*0Sstevel@tonic-gate  *					CS_EVENT_CLIENT_INFO event
8656*0Sstevel@tonic-gate  *					or if invalid client info
8657*0Sstevel@tonic-gate  *					retreived from client
8658*0Sstevel@tonic-gate  */
8659*0Sstevel@tonic-gate static int
8660*0Sstevel@tonic-gate cs_get_client_info(client_handle_t client_handle, client_info_t *ci)
8661*0Sstevel@tonic-gate {
8662*0Sstevel@tonic-gate 	cs_socket_t *sp;
8663*0Sstevel@tonic-gate 	client_t *client;
8664*0Sstevel@tonic-gate 	client_info_t *cinfo;
8665*0Sstevel@tonic-gate 	int ret = CS_SUCCESS;
8666*0Sstevel@tonic-gate 
8667*0Sstevel@tonic-gate 	if (CLIENT_HANDLE_IS_SS(client_handle)) {
8668*0Sstevel@tonic-gate 	    ci->Attributes = (CS_CLIENT_INFO_SOCKET_SERVICES |
8669*0Sstevel@tonic-gate 						CS_CLIENT_INFO_VALID);
8670*0Sstevel@tonic-gate 	    return (CS_SUCCESS);
8671*0Sstevel@tonic-gate 	} /* CLIENT_HANDLE_IS_SS */
8672*0Sstevel@tonic-gate 
8673*0Sstevel@tonic-gate 	if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL)
8674*0Sstevel@tonic-gate 	    return (CS_BAD_SOCKET);
8675*0Sstevel@tonic-gate 
8676*0Sstevel@tonic-gate 	mutex_enter(&sp->client_lock);
8677*0Sstevel@tonic-gate 	mutex_enter(&sp->lock);
8678*0Sstevel@tonic-gate 
8679*0Sstevel@tonic-gate 	if ((client = cs_find_client(client_handle, &ret)) == NULL) {
8680*0Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
8681*0Sstevel@tonic-gate 	    mutex_exit(&sp->client_lock);
8682*0Sstevel@tonic-gate 	    return (ret);
8683*0Sstevel@tonic-gate 	} /* cs_find_client */
8684*0Sstevel@tonic-gate 
8685*0Sstevel@tonic-gate 	/*
8686*0Sstevel@tonic-gate 	 * If this client is not handling CS_EVENT_CLIENT_INFO events,
8687*0Sstevel@tonic-gate 	 *	then don't bother to even wake up the event thread.
8688*0Sstevel@tonic-gate 	 */
8689*0Sstevel@tonic-gate 	if (!((client->event_mask | client->global_mask) &
8690*0Sstevel@tonic-gate 					CS_EVENT_CLIENT_INFO)) {
8691*0Sstevel@tonic-gate 	    mutex_exit(&sp->lock);
8692*0Sstevel@tonic-gate 	    mutex_exit(&sp->client_lock);
8693*0Sstevel@tonic-gate 	    return (CS_NO_MORE_ITEMS);
8694*0Sstevel@tonic-gate 	} /* !CS_EVENT_CLIENT_INFO */
8695*0Sstevel@tonic-gate 
8696*0Sstevel@tonic-gate 	cinfo = &client->event_callback_args.client_info;
8697*0Sstevel@tonic-gate 
8698*0Sstevel@tonic-gate 	bzero((caddr_t)cinfo, sizeof (client_info_t));
8699*0Sstevel@tonic-gate 	cinfo->Attributes = (ci->Attributes & CS_CLIENT_INFO_SUBSVC_MASK);
8700*0Sstevel@tonic-gate 
8701*0Sstevel@tonic-gate 	client->events |= CS_EVENT_CLIENT_INFO;
8702*0Sstevel@tonic-gate 
8703*0Sstevel@tonic-gate 	sp->thread_state |= SOCKET_WAIT_SYNC;
8704*0Sstevel@tonic-gate 	mutex_exit(&sp->lock);
8705*0Sstevel@tonic-gate 	cv_broadcast(&sp->thread_cv);
8706*0Sstevel@tonic-gate 	cv_wait(&sp->caller_cv, &sp->client_lock);
8707*0Sstevel@tonic-gate 
8708*0Sstevel@tonic-gate 	if (cinfo->Attributes & CS_CLIENT_INFO_VALID) {
8709*0Sstevel@tonic-gate 	    bcopy((caddr_t)cinfo, (caddr_t)ci, sizeof (client_info_t));
8710*0Sstevel@tonic-gate 	    ci->Attributes &= (CS_CLIENT_INFO_FLAGS_MASK |
8711*0Sstevel@tonic-gate 					CS_CLIENT_INFO_SUBSVC_MASK);
8712*0Sstevel@tonic-gate 	    ci->Attributes &= ~(CS_CLIENT_INFO_CLIENT_MASK |
8713*0Sstevel@tonic-gate 						INFO_CARD_FLAGS_MASK |
8714*0Sstevel@tonic-gate 						CS_CLIENT_INFO_CLIENT_ACTIVE);
8715*0Sstevel@tonic-gate 	    ci->Attributes |= (client->flags & (CS_CLIENT_INFO_CLIENT_MASK |
8716*0Sstevel@tonic-gate 						INFO_CARD_FLAGS_MASK));
8717*0Sstevel@tonic-gate 	    (void) strcpy(ci->DriverName, client->driver_name);
8718*0Sstevel@tonic-gate 	    if (cs_card_for_client(client))
8719*0Sstevel@tonic-gate 		ci->Attributes |= CS_CLIENT_INFO_CLIENT_ACTIVE;
8720*0Sstevel@tonic-gate 	} else {
8721*0Sstevel@tonic-gate 	    ret = CS_NO_MORE_ITEMS;
8722*0Sstevel@tonic-gate 	} /* CS_CLIENT_INFO_VALID */
8723*0Sstevel@tonic-gate 
8724*0Sstevel@tonic-gate 	mutex_exit(&sp->client_lock);
8725*0Sstevel@tonic-gate 
8726*0Sstevel@tonic-gate 	return (ret);
8727*0Sstevel@tonic-gate }
8728*0Sstevel@tonic-gate 
8729*0Sstevel@tonic-gate /*
8730*0Sstevel@tonic-gate  * cs_get_firstnext_client - This function is GetFirstClient and
8731*0Sstevel@tonic-gate  *				GetNextClient
8732*0Sstevel@tonic-gate  *
8733*0Sstevel@tonic-gate  *    calling:	get_firstnext_client_t * - pointer to a get_firstnext_client_t
8734*0Sstevel@tonic-gate  *					structure to return client handle and
8735*0Sstevel@tonic-gate  *					attributes in
8736*0Sstevel@tonic-gate  *		flags - one of the following:
8737*0Sstevel@tonic-gate  *				CS_GET_FIRST_FLAG - get first client handle
8738*0Sstevel@tonic-gate  *				CS_GET_NEXT_FLAG - get next client handle
8739*0Sstevel@tonic-gate  *
8740*0Sstevel@tonic-gate  *    returns:	CS_SUCCESS - if client info retreived from client
8741*0Sstevel@tonic-gate  *		CS_BAD_SOCKET, CS_BAD_HANDLE - if invalid client
8742*0Sstevel@tonic-gate  *					handle passed in
8743*0Sstevel@tonic-gate  *		CS_NO_MORE_ITEMS - if client does not handle the
8744*0Sstevel@tonic-gate  *					CS_EVENT_CLIENT_INFO event
8745*0Sstevel@tonic-gate  *					or if invalid client info
8746*0Sstevel@tonic-gate  *					retreived from client
8747*0Sstevel@tonic-gate  */
8748*0Sstevel@tonic-gate static int
8749*0Sstevel@tonic-gate cs_get_firstnext_client(get_firstnext_client_t *fnc, uint32_t flags)
8750*0Sstevel@tonic-gate {
8751*0Sstevel@tonic-gate 	cs_socket_t *sp;
8752*0Sstevel@tonic-gate 	client_t *client;
8753*0Sstevel@tonic-gate 	uint32_t sn = 0;
8754*0Sstevel@tonic-gate 	int ret = CS_SUCCESS;
8755*0Sstevel@tonic-gate 
8756*0Sstevel@tonic-gate 	switch (flags) {
8757*0Sstevel@tonic-gate 	    case CS_GET_FIRST_FLAG:
8758*0Sstevel@tonic-gate 		if (fnc->Attributes & CS_GET_FIRSTNEXT_CLIENT_ALL_CLIENTS) {
8759*0Sstevel@tonic-gate 		    while (sn < cs_globals.max_socket_num) {
8760*0Sstevel@tonic-gate 			if ((sp = cs_get_sp(sn)) != NULL) {
8761*0Sstevel@tonic-gate 			    mutex_enter(&sp->client_lock);
8762*0Sstevel@tonic-gate 			    if ((client = sp->client_list) != NULL)
8763*0Sstevel@tonic-gate 				break;
8764*0Sstevel@tonic-gate 			    mutex_exit(&sp->client_lock);
8765*0Sstevel@tonic-gate 			} /* if */
8766*0Sstevel@tonic-gate 			sn++;
8767*0Sstevel@tonic-gate 		    } /* while */
8768*0Sstevel@tonic-gate 
8769*0Sstevel@tonic-gate 		    if (sn == cs_globals.max_socket_num)
8770*0Sstevel@tonic-gate 			return (CS_NO_MORE_ITEMS);
8771*0Sstevel@tonic-gate 		} else if (fnc->Attributes &
8772*0Sstevel@tonic-gate 					CS_GET_FIRSTNEXT_CLIENT_SOCKET_ONLY) {
8773*0Sstevel@tonic-gate 		    if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(fnc->Socket))) ==
8774*0Sstevel@tonic-gate 									NULL)
8775*0Sstevel@tonic-gate 			return (CS_BAD_SOCKET);
8776*0Sstevel@tonic-gate 		    mutex_enter(&sp->client_lock);
8777*0Sstevel@tonic-gate 		    if ((client = sp->client_list) == NULL) {
8778*0Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
8779*0Sstevel@tonic-gate 			return (CS_NO_MORE_ITEMS);
8780*0Sstevel@tonic-gate 		    }
8781*0Sstevel@tonic-gate 		} else {
8782*0Sstevel@tonic-gate 		    return (CS_BAD_ATTRIBUTE);
8783*0Sstevel@tonic-gate 		}
8784*0Sstevel@tonic-gate 
8785*0Sstevel@tonic-gate 		fnc->client_handle = client->client_handle;
8786*0Sstevel@tonic-gate 		fnc->num_clients = sp->num_clients;
8787*0Sstevel@tonic-gate 		mutex_exit(&sp->client_lock);
8788*0Sstevel@tonic-gate 		break;
8789*0Sstevel@tonic-gate 	    case CS_GET_NEXT_FLAG:
8790*0Sstevel@tonic-gate 		if (fnc->Attributes & CS_GET_FIRSTNEXT_CLIENT_ALL_CLIENTS) {
8791*0Sstevel@tonic-gate 		    sn = GET_CLIENT_SOCKET(fnc->client_handle);
8792*0Sstevel@tonic-gate 
8793*0Sstevel@tonic-gate 		    if ((sp = cs_get_sp(sn)) == NULL)
8794*0Sstevel@tonic-gate 			return (CS_BAD_SOCKET);
8795*0Sstevel@tonic-gate 
8796*0Sstevel@tonic-gate 		    mutex_enter(&sp->client_lock);
8797*0Sstevel@tonic-gate 		    if ((client = cs_find_client(fnc->client_handle,
8798*0Sstevel@tonic-gate 				&ret)) == NULL) {
8799*0Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
8800*0Sstevel@tonic-gate 			return (ret);
8801*0Sstevel@tonic-gate 		    }
8802*0Sstevel@tonic-gate 		    if ((client = client->next) == NULL) {
8803*0Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
8804*0Sstevel@tonic-gate 			sn++;
8805*0Sstevel@tonic-gate 			while (sn < cs_globals.max_socket_num) {
8806*0Sstevel@tonic-gate 			    if ((sp = cs_get_sp(sn)) != NULL) {
8807*0Sstevel@tonic-gate 				mutex_enter(&sp->client_lock);
8808*0Sstevel@tonic-gate 				if ((client = sp->client_list) != NULL)
8809*0Sstevel@tonic-gate 				    break;
8810*0Sstevel@tonic-gate 				mutex_exit(&sp->client_lock);
8811*0Sstevel@tonic-gate 			    } /* if */
8812*0Sstevel@tonic-gate 			    sn++;
8813*0Sstevel@tonic-gate 			} /* while */
8814*0Sstevel@tonic-gate 
8815*0Sstevel@tonic-gate 			if (sn == cs_globals.max_socket_num)
8816*0Sstevel@tonic-gate 			    return (CS_NO_MORE_ITEMS);
8817*0Sstevel@tonic-gate 		    } /* client = client->next */
8818*0Sstevel@tonic-gate 
8819*0Sstevel@tonic-gate 		} else if (fnc->Attributes &
8820*0Sstevel@tonic-gate 					CS_GET_FIRSTNEXT_CLIENT_SOCKET_ONLY) {
8821*0Sstevel@tonic-gate 		    sp = cs_get_sp(GET_CLIENT_SOCKET(fnc->client_handle));
8822*0Sstevel@tonic-gate 		    if (sp == NULL)
8823*0Sstevel@tonic-gate 			return (CS_BAD_SOCKET);
8824*0Sstevel@tonic-gate 		    mutex_enter(&sp->client_lock);
8825*0Sstevel@tonic-gate 		    if ((client = cs_find_client(fnc->client_handle,
8826*0Sstevel@tonic-gate 				&ret)) == NULL) {
8827*0Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
8828*0Sstevel@tonic-gate 			return (ret);
8829*0Sstevel@tonic-gate 		    }
8830*0Sstevel@tonic-gate 		    if ((client = client->next) == NULL) {
8831*0Sstevel@tonic-gate 			mutex_exit(&sp->client_lock);
8832*0Sstevel@tonic-gate 			return (CS_NO_MORE_ITEMS);
8833*0Sstevel@tonic-gate 		    }
8834*0Sstevel@tonic-gate 		} else {
8835*0Sstevel@tonic-gate 		    return (CS_BAD_ATTRIBUTE);
8836*0Sstevel@tonic-gate 		}
8837*0Sstevel@tonic-gate 
8838*0Sstevel@tonic-gate 		fnc->client_handle = client->client_handle;
8839*0Sstevel@tonic-gate 		fnc->num_clients = sp->num_clients;
8840*0Sstevel@tonic-gate 		mutex_exit(&sp->client_lock);
8841*0Sstevel@tonic-gate 		break;
8842*0Sstevel@tonic-gate 	    default:
8843*0Sstevel@tonic-gate 		ret = CS_BAD_ATTRIBUTE;
8844*0Sstevel@tonic-gate 		break;
8845*0Sstevel@tonic-gate 
8846*0Sstevel@tonic-gate 	} /* switch */
8847*0Sstevel@tonic-gate 
8848*0Sstevel@tonic-gate 	return (ret);
8849*0Sstevel@tonic-gate }
8850*0Sstevel@tonic-gate 
8851*0Sstevel@tonic-gate /*
8852*0Sstevel@tonic-gate  * cs_set_acc_attributes - converts Card Services endianness and
8853*0Sstevel@tonic-gate  *				data ordering values to values
8854*0Sstevel@tonic-gate  *				that Socket Services understands
8855*0Sstevel@tonic-gate  *
8856*0Sstevel@tonic-gate  *	calling: *sw - pointer to a set_window_t to set attributes in
8857*0Sstevel@tonic-gate  *		 Attributes - CS attributes
8858*0Sstevel@tonic-gate  */
8859*0Sstevel@tonic-gate static void
8860*0Sstevel@tonic-gate cs_set_acc_attributes(set_window_t *sw, uint32_t Attributes)
8861*0Sstevel@tonic-gate {
8862*0Sstevel@tonic-gate 	sw->attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
8863*0Sstevel@tonic-gate 
8864*0Sstevel@tonic-gate 	switch (Attributes & WIN_ACC_ENDIAN_MASK) {
8865*0Sstevel@tonic-gate 	    case WIN_ACC_LITTLE_ENDIAN:
8866*0Sstevel@tonic-gate 		sw->attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
8867*0Sstevel@tonic-gate 		break;
8868*0Sstevel@tonic-gate 	    case WIN_ACC_BIG_ENDIAN:
8869*0Sstevel@tonic-gate 		sw->attr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC;
8870*0Sstevel@tonic-gate 		break;
8871*0Sstevel@tonic-gate 	    case WIN_ACC_NEVER_SWAP:
8872*0Sstevel@tonic-gate 	    default:
8873*0Sstevel@tonic-gate 		sw->attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
8874*0Sstevel@tonic-gate 		break;
8875*0Sstevel@tonic-gate 	} /* switch */
8876*0Sstevel@tonic-gate 
8877*0Sstevel@tonic-gate 	switch (Attributes & WIN_ACC_ORDER_MASK) {
8878*0Sstevel@tonic-gate 	    case WIN_ACC_UNORDERED_OK:
8879*0Sstevel@tonic-gate 		sw->attr.devacc_attr_dataorder = DDI_UNORDERED_OK_ACC;
8880*0Sstevel@tonic-gate 		break;
8881*0Sstevel@tonic-gate 	    case WIN_ACC_MERGING_OK:
8882*0Sstevel@tonic-gate 		sw->attr.devacc_attr_dataorder = DDI_MERGING_OK_ACC;
8883*0Sstevel@tonic-gate 		break;
8884*0Sstevel@tonic-gate 	    case WIN_ACC_LOADCACHING_OK:
8885*0Sstevel@tonic-gate 		sw->attr.devacc_attr_dataorder = DDI_LOADCACHING_OK_ACC;
8886*0Sstevel@tonic-gate 		break;
8887*0Sstevel@tonic-gate 	    case WIN_ACC_STORECACHING_OK:
8888*0Sstevel@tonic-gate 		sw->attr.devacc_attr_dataorder = DDI_STORECACHING_OK_ACC;
8889*0Sstevel@tonic-gate 		break;
8890*0Sstevel@tonic-gate 	    case WIN_ACC_STRICT_ORDER:
8891*0Sstevel@tonic-gate 	    default:
8892*0Sstevel@tonic-gate 		sw->attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
8893*0Sstevel@tonic-gate 		break;
8894*0Sstevel@tonic-gate 	} /* switch */
8895*0Sstevel@tonic-gate }
8896