10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 23*1278Shx147065 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * PCMCIA Card Services 310Sstevel@tonic-gate * The PCMCIA Card Services is a loadable module which 320Sstevel@tonic-gate * presents the Card Services interface to client device 330Sstevel@tonic-gate * drivers. 340Sstevel@tonic-gate * 350Sstevel@tonic-gate * Card Services uses Socket Services-like calls into the 360Sstevel@tonic-gate * PCMCIA nexus driver to manipulate socket and adapter 370Sstevel@tonic-gate * resources. 380Sstevel@tonic-gate * 390Sstevel@tonic-gate * Note that a bunch of comments are not indented correctly with the 400Sstevel@tonic-gate * code that they are commenting on. This is because cstyle is 410Sstevel@tonic-gate * is inflexible concerning 4-column indenting. 420Sstevel@tonic-gate */ 430Sstevel@tonic-gate 440Sstevel@tonic-gate #if defined(DEBUG) 450Sstevel@tonic-gate #define CS_DEBUG 460Sstevel@tonic-gate #endif 470Sstevel@tonic-gate 480Sstevel@tonic-gate #include <sys/types.h> 490Sstevel@tonic-gate #include <sys/systm.h> 500Sstevel@tonic-gate #include <sys/user.h> 510Sstevel@tonic-gate #include <sys/buf.h> 520Sstevel@tonic-gate #include <sys/file.h> 530Sstevel@tonic-gate #include <sys/uio.h> 540Sstevel@tonic-gate #include <sys/conf.h> 550Sstevel@tonic-gate #include <sys/stat.h> 560Sstevel@tonic-gate #include <sys/autoconf.h> 570Sstevel@tonic-gate #include <sys/vtoc.h> 580Sstevel@tonic-gate #include <sys/dkio.h> 590Sstevel@tonic-gate #include <sys/ddi.h> 600Sstevel@tonic-gate #include <sys/sunddi.h> 610Sstevel@tonic-gate #include <sys/debug.h> 620Sstevel@tonic-gate #include <sys/varargs.h> 630Sstevel@tonic-gate #include <sys/var.h> 640Sstevel@tonic-gate #include <sys/proc.h> 650Sstevel@tonic-gate #include <sys/thread.h> 660Sstevel@tonic-gate #include <sys/utsname.h> 670Sstevel@tonic-gate #include <sys/vtrace.h> 680Sstevel@tonic-gate #include <sys/kstat.h> 690Sstevel@tonic-gate #include <sys/kmem.h> 700Sstevel@tonic-gate #include <sys/modctl.h> 710Sstevel@tonic-gate #include <sys/kobj.h> 720Sstevel@tonic-gate #include <sys/callb.h> 730Sstevel@tonic-gate #include <sys/time.h> 740Sstevel@tonic-gate 750Sstevel@tonic-gate #include <sys/pctypes.h> 760Sstevel@tonic-gate #include <pcmcia/sys/cs_types.h> 770Sstevel@tonic-gate #include <sys/pcmcia.h> 780Sstevel@tonic-gate #include <sys/sservice.h> 790Sstevel@tonic-gate #include <pcmcia/sys/cis.h> 800Sstevel@tonic-gate #include <pcmcia/sys/cis_handlers.h> 810Sstevel@tonic-gate #include <pcmcia/sys/cs.h> 820Sstevel@tonic-gate #include <pcmcia/sys/cs_priv.h> 830Sstevel@tonic-gate #include <pcmcia/sys/cs_stubs.h> 840Sstevel@tonic-gate 850Sstevel@tonic-gate /* 860Sstevel@tonic-gate * The cs_strings header file is where all of the major strings that 870Sstevel@tonic-gate * Card Services uses are located. 880Sstevel@tonic-gate */ 890Sstevel@tonic-gate #include <pcmcia/sys/cs_strings.h> 900Sstevel@tonic-gate 910Sstevel@tonic-gate 920Sstevel@tonic-gate /* 930Sstevel@tonic-gate * Function declarations 940Sstevel@tonic-gate * 950Sstevel@tonic-gate * The main Card Services entry point 960Sstevel@tonic-gate */ 970Sstevel@tonic-gate int CardServices(int function, ...); 980Sstevel@tonic-gate 990Sstevel@tonic-gate /* 1000Sstevel@tonic-gate * functions and globals used by Socket Services 1010Sstevel@tonic-gate * 1020Sstevel@tonic-gate * WAS: void *(*cis_parser)(int, ...) = NULL; 1030Sstevel@tonic-gate */ 1040Sstevel@tonic-gate void *(*cis_parser)(int, ...) = NULL; 1050Sstevel@tonic-gate csfunction_t *cs_socket_services = NULL; 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate /* 1080Sstevel@tonic-gate * event handling functions 1090Sstevel@tonic-gate */ 1100Sstevel@tonic-gate static event_t ss_to_cs_events(cs_socket_t *, event_t); 1110Sstevel@tonic-gate static event_t cs_cse2sbm(event_t); 1120Sstevel@tonic-gate static void cs_event_thread(uint32_t); 1130Sstevel@tonic-gate static int cs_card_insertion(cs_socket_t *, event_t); 1140Sstevel@tonic-gate static int cs_card_removal(cs_socket_t *); 1150Sstevel@tonic-gate static void cs_ss_thread(uint32_t); 1160Sstevel@tonic-gate void cs_ready_timeout(void *); 1170Sstevel@tonic-gate static int cs_card_for_client(client_t *); 1180Sstevel@tonic-gate static int cs_request_socket_mask(client_handle_t, request_socket_mask_t *); 1190Sstevel@tonic-gate static int cs_release_socket_mask(client_handle_t, release_socket_mask_t *); 1200Sstevel@tonic-gate static int cs_get_event_mask(client_handle_t, sockevent_t *); 1210Sstevel@tonic-gate static int cs_set_event_mask(client_handle_t, sockevent_t *); 1220Sstevel@tonic-gate static int cs_event2text(event2text_t *, int); 1230Sstevel@tonic-gate static int cs_read_event_status(cs_socket_t *, client_t *, event_t *, 1240Sstevel@tonic-gate get_ss_status_t *, int); 1250Sstevel@tonic-gate uint32_t cs_socket_event_softintr(caddr_t); 1260Sstevel@tonic-gate void cs_event_softintr_timeout(void *); 1270Sstevel@tonic-gate static int cs_get_status(client_handle_t, get_status_t *); 1280Sstevel@tonic-gate static uint32_t cs_sbm2cse(uint32_t); 1290Sstevel@tonic-gate static unsigned cs_merge_event_masks(cs_socket_t *, client_t *); 1300Sstevel@tonic-gate static int cs_set_socket_event_mask(cs_socket_t *, unsigned); 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate /* 1330Sstevel@tonic-gate * SS<->CS communication and internal socket and window handling functions 1340Sstevel@tonic-gate */ 1350Sstevel@tonic-gate static uint32_t cs_add_socket(uint32_t); 1360Sstevel@tonic-gate static uint32_t cs_drop_socket(uint32_t); 1370Sstevel@tonic-gate static cs_socket_t *cs_get_sp(uint32_t); 1380Sstevel@tonic-gate static cs_socket_t *cs_find_sp(uint32_t); 1390Sstevel@tonic-gate static cs_window_t *cs_get_wp(uint32_t); 1400Sstevel@tonic-gate static cs_window_t *cs_find_wp(uint32_t); 1410Sstevel@tonic-gate static int cs_add_windows(int, uint32_t); 1420Sstevel@tonic-gate static uint32_t cs_ss_init(); 1430Sstevel@tonic-gate static void cs_set_acc_attributes(set_window_t *, uint32_t); 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate /* 1460Sstevel@tonic-gate * CIS handling functions 1470Sstevel@tonic-gate */ 1480Sstevel@tonic-gate cistpl_callout_t *cis_cistpl_std_callout; 1490Sstevel@tonic-gate static int cs_parse_tuple(client_handle_t, tuple_t *, cisparse_t *, cisdata_t); 1500Sstevel@tonic-gate static int cs_get_tuple_data(client_handle_t, tuple_t *); 1510Sstevel@tonic-gate static int cs_validate_cis(client_handle_t, cisinfo_t *); 1520Sstevel@tonic-gate static int cs_get_firstnext_tuple(client_handle_t, tuple_t *, uint32_t); 1530Sstevel@tonic-gate static int cs_create_cis(cs_socket_t *); 1540Sstevel@tonic-gate static int cs_destroy_cis(cs_socket_t *); 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate /* 1570Sstevel@tonic-gate * client handling functions 1580Sstevel@tonic-gate */ 1590Sstevel@tonic-gate unsigned cs_create_next_client_minor(unsigned, unsigned); 1600Sstevel@tonic-gate static client_t *cs_find_client(client_handle_t, int *); 1610Sstevel@tonic-gate static client_handle_t cs_create_client_handle(unsigned, client_t *); 1620Sstevel@tonic-gate static int cs_destroy_client_handle(client_handle_t); 1630Sstevel@tonic-gate static int cs_register_client(client_handle_t *, client_reg_t *); 1640Sstevel@tonic-gate static int cs_deregister_client(client_handle_t); 1650Sstevel@tonic-gate static int cs_deregister_mtd(client_handle_t); 1660Sstevel@tonic-gate static void cs_clear_superclient_lock(int); 1670Sstevel@tonic-gate static int cs_add_client_to_socket(unsigned, client_handle_t *, 1680Sstevel@tonic-gate client_reg_t *, int); 1690Sstevel@tonic-gate static int cs_get_client_info(client_handle_t, client_info_t *); 1700Sstevel@tonic-gate static int cs_get_firstnext_client(get_firstnext_client_t *, uint32_t); 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate /* 1730Sstevel@tonic-gate * window handling functions 1740Sstevel@tonic-gate */ 1750Sstevel@tonic-gate static int cs_request_window(client_handle_t, window_handle_t *, win_req_t *); 1760Sstevel@tonic-gate static int cs_release_window(window_handle_t); 1770Sstevel@tonic-gate static int cs_modify_window(window_handle_t, modify_win_t *); 1780Sstevel@tonic-gate static int cs_modify_mem_window(window_handle_t, modify_win_t *, win_req_t *, 1790Sstevel@tonic-gate int); 1800Sstevel@tonic-gate static int cs_map_mem_page(window_handle_t, map_mem_page_t *); 1810Sstevel@tonic-gate static int cs_find_mem_window(uint32_t, win_req_t *, uint32_t *); 1820Sstevel@tonic-gate static int cs_memwin_space_and_map_ok(inquire_window_t *, win_req_t *); 1830Sstevel@tonic-gate static int cs_valid_window_speed(inquire_window_t *, uint32_t); 1840Sstevel@tonic-gate static window_handle_t cs_create_window_handle(uint32_t); 1850Sstevel@tonic-gate static cs_window_t *cs_find_window(window_handle_t); 1860Sstevel@tonic-gate static int cs_find_io_win(uint32_t, iowin_char_t *, uint32_t *, uint32_t *); 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate /* 1890Sstevel@tonic-gate * IO, IRQ and configuration handling functions 1900Sstevel@tonic-gate */ 1910Sstevel@tonic-gate static int cs_request_io(client_handle_t, io_req_t *); 1920Sstevel@tonic-gate static int cs_release_io(client_handle_t, io_req_t *); 1930Sstevel@tonic-gate static int cs_allocate_io_win(uint32_t, uint32_t, uint32_t *); 1940Sstevel@tonic-gate static int cs_setup_io_win(uint32_t, uint32_t, baseaddru_t *, 1950Sstevel@tonic-gate uint32_t *, uint32_t, uint32_t); 1960Sstevel@tonic-gate static int cs_request_irq(client_handle_t, irq_req_t *); 1970Sstevel@tonic-gate static int cs_release_irq(client_handle_t, irq_req_t *); 1980Sstevel@tonic-gate static int cs_request_configuration(client_handle_t, config_req_t *); 1990Sstevel@tonic-gate static int cs_release_configuration(client_handle_t, release_config_t *); 2000Sstevel@tonic-gate static int cs_modify_configuration(client_handle_t, modify_config_t *); 2010Sstevel@tonic-gate static int cs_access_configuration_register(client_handle_t, 2020Sstevel@tonic-gate access_config_reg_t *); 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate /* 2050Sstevel@tonic-gate * RESET and general info functions 2060Sstevel@tonic-gate */ 2070Sstevel@tonic-gate static int cs_reset_function(client_handle_t, reset_function_t *); 2080Sstevel@tonic-gate static int cs_get_configuration_info(client_handle_t *, 2090Sstevel@tonic-gate get_configuration_info_t *); 2100Sstevel@tonic-gate static int cs_get_cardservices_info(client_handle_t, 2110Sstevel@tonic-gate get_cardservices_info_t *); 2120Sstevel@tonic-gate static int cs_get_physical_adapter_info(client_handle_t, 2130Sstevel@tonic-gate get_physical_adapter_info_t *); 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate /* 2160Sstevel@tonic-gate * general functions 2170Sstevel@tonic-gate */ 2180Sstevel@tonic-gate static uint32_t cs_get_socket(client_handle_t, uint32_t *, uint32_t *, 2190Sstevel@tonic-gate cs_socket_t **, client_t **); 2200Sstevel@tonic-gate static int cs_convert_speed(convert_speed_t *); 2210Sstevel@tonic-gate static int cs_convert_size(convert_size_t *); 2220Sstevel@tonic-gate static char *cs_error2text(int, int); 2230Sstevel@tonic-gate static int cs_map_log_socket(client_handle_t, map_log_socket_t *); 2240Sstevel@tonic-gate static int cs_convert_powerlevel(uint32_t, uint32_t, uint32_t, unsigned *); 2250Sstevel@tonic-gate static int cs_make_device_node(client_handle_t, make_device_node_t *); 2260Sstevel@tonic-gate static int cs_remove_device_node(client_handle_t, remove_device_node_t *); 2270Sstevel@tonic-gate static int cs_ddi_info(cs_ddi_info_t *); 2280Sstevel@tonic-gate static int cs_init_cis_window(cs_socket_t *, uint32_t *, acc_handle_t *, 2290Sstevel@tonic-gate uint32_t); 2300Sstevel@tonic-gate static int cs_sys_ctl(cs_sys_ctl_t *); 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate /* 2330Sstevel@tonic-gate * global variables 2340Sstevel@tonic-gate */ 2350Sstevel@tonic-gate static int cs_max_client_handles = CS_MAX_CLIENTS; 2360Sstevel@tonic-gate static client_t cs_socket_services_client; /* global SS client */ 2370Sstevel@tonic-gate static client_types_t client_types[MAX_CLIENT_TYPES]; 2380Sstevel@tonic-gate static cs_globals_t cs_globals; 2390Sstevel@tonic-gate int cs_reset_timeout_time = RESET_TIMEOUT_TIME; 2400Sstevel@tonic-gate int cs_rc1_delay = CS_RC1_DELAY; 2410Sstevel@tonic-gate int cs_rc2_delay = CS_RC2_DELAY; 2420Sstevel@tonic-gate int cs_rq_delay = CS_RQ_DELAY; 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate #ifdef CS_DEBUG 2450Sstevel@tonic-gate int cs_debug = 0; 2460Sstevel@tonic-gate #endif 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate /* 2490Sstevel@tonic-gate * cs_init - Initialize CS internal structures, databases, and state, 2500Sstevel@tonic-gate * and register with SS 2510Sstevel@tonic-gate * 2520Sstevel@tonic-gate * XXX - Need to make sure that if we fail at any point that we free 2530Sstevel@tonic-gate * any resources that we allocated, as well as kill any 2540Sstevel@tonic-gate * threads that may have been started. 2550Sstevel@tonic-gate */ 2560Sstevel@tonic-gate int 2570Sstevel@tonic-gate cs_init() 2580Sstevel@tonic-gate { 2590Sstevel@tonic-gate client_types_t *ct; 2600Sstevel@tonic-gate client_t *client; 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate /* 2630Sstevel@tonic-gate * Initialize the CS global structure 2640Sstevel@tonic-gate */ 2650Sstevel@tonic-gate bzero((caddr_t)&cs_globals, sizeof (cs_globals_t)); 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate mutex_init(&cs_globals.global_lock, NULL, MUTEX_DRIVER, NULL); 2680Sstevel@tonic-gate mutex_init(&cs_globals.window_lock, NULL, MUTEX_DRIVER, NULL); 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate cs_globals.init_state = GLOBAL_INIT_STATE_MUTEX; 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate /* 2730Sstevel@tonic-gate * Set up the global Socket Services client, since we're going to 2740Sstevel@tonic-gate * need it once we register with SS. 2750Sstevel@tonic-gate */ 2760Sstevel@tonic-gate client = &cs_socket_services_client; 2770Sstevel@tonic-gate bzero((caddr_t)client, sizeof (client_t)); 2780Sstevel@tonic-gate client->client_handle = CS_SS_CLIENT_HANDLE; 2790Sstevel@tonic-gate client->flags |= (INFO_SOCKET_SERVICES | CLIENT_CARD_INSERTED); 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate /* 2820Sstevel@tonic-gate * Setup the client type structure - this is used in the socket event 2830Sstevel@tonic-gate * thread to sequence the delivery of events to all clients on 2840Sstevel@tonic-gate * the socket. 2850Sstevel@tonic-gate */ 2860Sstevel@tonic-gate ct = &client_types[0]; 2870Sstevel@tonic-gate ct->type = INFO_IO_CLIENT; 2880Sstevel@tonic-gate ct->order = CLIENT_EVENTS_LIFO; 2890Sstevel@tonic-gate ct->next = &client_types[1]; 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate ct = ct->next; 2920Sstevel@tonic-gate ct->type = INFO_MTD_CLIENT; 2930Sstevel@tonic-gate ct->order = CLIENT_EVENTS_FIFO; 2940Sstevel@tonic-gate ct->next = &client_types[2]; 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate ct = ct->next; 2970Sstevel@tonic-gate ct->type = INFO_MEM_CLIENT; 2980Sstevel@tonic-gate ct->order = CLIENT_EVENTS_FIFO; 2990Sstevel@tonic-gate ct->next = NULL; 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate return (CS_SUCCESS); 3020Sstevel@tonic-gate } 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate /* 3050Sstevel@tonic-gate * cs_deinit - Deinitialize CS 3060Sstevel@tonic-gate * 3070Sstevel@tonic-gate * This function cleans up any allocated resources, stops any running threads, 3080Sstevel@tonic-gate * destroys any mutexes and condition variables, and finally frees up the 3090Sstevel@tonic-gate * global socket and window structure arrays. 3100Sstevel@tonic-gate */ 3110Sstevel@tonic-gate int 3120Sstevel@tonic-gate cs_deinit() 3130Sstevel@tonic-gate { 3140Sstevel@tonic-gate cs_socket_t *sp; 3150Sstevel@tonic-gate int sn, have_clients = 0, have_sockets = 0; 3160Sstevel@tonic-gate cs_register_cardservices_t rcs; 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate #if defined(CS_DEBUG) 3190Sstevel@tonic-gate if (cs_debug > 1) 3200Sstevel@tonic-gate cmn_err(CE_CONT, "CS: cs_deinit\n"); 3210Sstevel@tonic-gate #endif 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate /* 3240Sstevel@tonic-gate * Deregister with the Card Services kernel stubs module 3250Sstevel@tonic-gate */ 3260Sstevel@tonic-gate rcs.magic = CS_STUBS_MAGIC; 3270Sstevel@tonic-gate rcs.function = CS_ENTRY_DEREGISTER; 3280Sstevel@tonic-gate (void) csx_register_cardservices(&rcs); 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate /* 3310Sstevel@tonic-gate * Set the GLOBAL_INIT_STATE_NO_CLIENTS flag to prevent new clients 3320Sstevel@tonic-gate * from registering. 3330Sstevel@tonic-gate */ 3340Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock); 3350Sstevel@tonic-gate cs_globals.init_state |= GLOBAL_INIT_STATE_NO_CLIENTS; 3360Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock); 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate /* 3390Sstevel@tonic-gate * Go through each socket and make sure that there are no clients 3400Sstevel@tonic-gate * on any of the sockets. If there are, we can't deinit until 3410Sstevel@tonic-gate * all the clients for every socket are gone. 3420Sstevel@tonic-gate */ 3430Sstevel@tonic-gate for (sn = 0; sn < cs_globals.max_socket_num; sn++) { 3440Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) != NULL) { 3450Sstevel@tonic-gate have_sockets++; 3460Sstevel@tonic-gate if (sp->client_list) { 3470Sstevel@tonic-gate cmn_err(CE_CONT, "cs_deinit: cannot unload module since " 3480Sstevel@tonic-gate "socket %d has registered clients\n", sn); 3490Sstevel@tonic-gate have_clients++; 3500Sstevel@tonic-gate } 3510Sstevel@tonic-gate } 3520Sstevel@tonic-gate } 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate /* 3550Sstevel@tonic-gate * We don't allow unload if there are any clients registered 3560Sstevel@tonic-gate * or if there are still sockets that are active. 3570Sstevel@tonic-gate */ 3580Sstevel@tonic-gate if ((have_clients > 0) || (have_sockets > 0)) 3590Sstevel@tonic-gate return (BAD_FUNCTION); 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate #ifdef XXX 3620Sstevel@tonic-gate /* 3630Sstevel@tonic-gate * If one or more sockets have been added, we need to deallocate 3640Sstevel@tonic-gate * the resources associated with those sockets. 3650Sstevel@tonic-gate */ 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate /* 3680Sstevel@tonic-gate * First, tell Socket Services that we're leaving, so that we 3690Sstevel@tonic-gate * don't get any more event callbacks. 3700Sstevel@tonic-gate */ 3710Sstevel@tonic-gate SocketServices(CSUnregister); 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate /* 3740Sstevel@tonic-gate * Wait for the soft int timer to tell us it's done 3750Sstevel@tonic-gate */ 3760Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock); 3770Sstevel@tonic-gate cs_globals.init_state |= GLOBAL_INIT_STATE_UNLOADING; 3780Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock); 3790Sstevel@tonic-gate UNTIMEOUT(cs_globals.sotfint_tmo); 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate /* 3820Sstevel@tonic-gate * Remove the soft interrupt handler. 3830Sstevel@tonic-gate */ 3840Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock); 3850Sstevel@tonic-gate if (cs_globals.init_state & GLOBAL_INIT_STATE_SOFTINTR) { 3860Sstevel@tonic-gate ddi_remove_softintr(cs_globals.softint_id); 3870Sstevel@tonic-gate cs_globals.init_state &= ~GLOBAL_INIT_STATE_SOFTINTR; 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock); 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate return (CS_SUCCESS); 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate /* 3940Sstevel@tonic-gate * Go through each socket and free any resource allocated to that 3950Sstevel@tonic-gate * socket, as well as any mutexs and condition variables. 3960Sstevel@tonic-gate */ 3970Sstevel@tonic-gate for (sn = 0; sn < cs_globals.max_socket_num; sn++) { 3980Sstevel@tonic-gate set_socket_t set_socket; 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) != NULL) { 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate /* 4030Sstevel@tonic-gate * untimeout possible pending ready/busy timer 4040Sstevel@tonic-gate */ 4050Sstevel@tonic-gate UNTIMEOUT(sp->rdybsy_tmo_id); 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_MUTEX) 4080Sstevel@tonic-gate mutex_enter(&sp->lock); 4090Sstevel@tonic-gate sp->flags = SOCKET_UNLOAD_MODULE; 4100Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_SOFTINTR) 4110Sstevel@tonic-gate sp->init_state &= ~SOCKET_INIT_STATE_SOFTINTR; 4120Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_MUTEX) 4130Sstevel@tonic-gate mutex_exit(&sp->lock); 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_MUTEX) 4160Sstevel@tonic-gate mutex_enter(&sp->cis_lock); 4170Sstevel@tonic-gate (void) cs_destroy_cis(sp); 4180Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_MUTEX) 4190Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate /* 4220Sstevel@tonic-gate * Tell the event handler thread that we want it to exit, then 4230Sstevel@tonic-gate * wait around until it tells us that it has exited. 4240Sstevel@tonic-gate */ 4250Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_MUTEX) 4260Sstevel@tonic-gate mutex_enter(&sp->client_lock); 4270Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_THREAD) { 4280Sstevel@tonic-gate sp->thread_state = SOCKET_THREAD_EXIT; 4290Sstevel@tonic-gate cv_broadcast(&sp->thread_cv); 4300Sstevel@tonic-gate cv_wait(&sp->caller_cv, &sp->client_lock); 4310Sstevel@tonic-gate } 4320Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_MUTEX) 4330Sstevel@tonic-gate mutex_exit(&sp->client_lock); 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate /* 4360Sstevel@tonic-gate * Tell the SS work thread that we want it to exit, then 4370Sstevel@tonic-gate * wait around until it tells us that it has exited. 4380Sstevel@tonic-gate */ 4390Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_MUTEX) 4400Sstevel@tonic-gate mutex_enter(&sp->ss_thread_lock); 4410Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_SS_THREAD) { 4420Sstevel@tonic-gate sp->ss_thread_state = SOCKET_THREAD_EXIT; 4430Sstevel@tonic-gate cv_broadcast(&sp->ss_thread_cv); 4440Sstevel@tonic-gate cv_wait(&sp->ss_caller_cv, &sp->ss_thread_lock); 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_MUTEX) 4480Sstevel@tonic-gate mutex_exit(&sp->ss_thread_lock); 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate /* 4510Sstevel@tonic-gate * Free the mutexii and condition variables that we used. 4520Sstevel@tonic-gate */ 4530Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_MUTEX) { 4540Sstevel@tonic-gate mutex_destroy(&sp->lock); 4550Sstevel@tonic-gate mutex_destroy(&sp->client_lock); 4560Sstevel@tonic-gate mutex_destroy(&sp->cis_lock); 4570Sstevel@tonic-gate mutex_destroy(&sp->ss_thread_lock); 4580Sstevel@tonic-gate } 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_CV) { 4610Sstevel@tonic-gate cv_destroy(&sp->thread_cv); 4620Sstevel@tonic-gate cv_destroy(&sp->caller_cv); 4630Sstevel@tonic-gate cv_destroy(&sp->reset_cv); 4640Sstevel@tonic-gate cv_destroy(&sp->ss_thread_cv); 4650Sstevel@tonic-gate cv_destroy(&sp->ss_caller_cv); 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate 4680Sstevel@tonic-gate #ifdef USE_IOMMAP_WINDOW 4690Sstevel@tonic-gate /* 4700Sstevel@tonic-gate * Free the memory-mapped IO structure if we allocated one. 4710Sstevel@tonic-gate */ 4720Sstevel@tonic-gate if (sp->io_mmap_window) 4730Sstevel@tonic-gate kmem_free(sp->io_mmap_window, sizeof (io_mmap_window_t)); 4740Sstevel@tonic-gate #endif /* USE_IOMMAP_WINDOW */ 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate /* 4770Sstevel@tonic-gate * Return the socket to memory-only mode and turn off the 4780Sstevel@tonic-gate * socket power. 4790Sstevel@tonic-gate */ 4800Sstevel@tonic-gate sp->event_mask = 0; 4810Sstevel@tonic-gate set_socket.socket = sp->socket_num; 4820Sstevel@tonic-gate set_socket.SCIntMask = 0; 4830Sstevel@tonic-gate set_socket.IREQRouting = 0; 4840Sstevel@tonic-gate set_socket.IFType = IF_MEMORY; 4850Sstevel@tonic-gate set_socket.CtlInd = 0; /* turn off controls and indicators */ 4860Sstevel@tonic-gate set_socket.State = (unsigned)~0; /* clear latched state bits */ 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 0, VCC, 4890Sstevel@tonic-gate &set_socket.VccLevel); 4900Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 0, VPP1, 4910Sstevel@tonic-gate &set_socket.Vpp1Level); 4920Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 0, VPP2, 4930Sstevel@tonic-gate &set_socket.Vpp2Level); 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate /* 4960Sstevel@tonic-gate * If we fail this call, there's not much we can do, so 4970Sstevel@tonic-gate * just continue with the resource deallocation. 4980Sstevel@tonic-gate */ 4990Sstevel@tonic-gate if ((ret = 5000Sstevel@tonic-gate SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) { 5010Sstevel@tonic-gate cmn_err(CE_CONT, 5020Sstevel@tonic-gate "cs_deinit: socket %d SS_SetSocket failure %d\n", 5030Sstevel@tonic-gate sp->socket_num, ret); 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate } /* cs_get_sp */ 5060Sstevel@tonic-gate } /* for (sn) */ 5070Sstevel@tonic-gate #endif /* XXX */ 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate /* 5100Sstevel@tonic-gate * Destroy the global mutexii. 5110Sstevel@tonic-gate */ 5120Sstevel@tonic-gate mutex_destroy(&cs_globals.global_lock); 5130Sstevel@tonic-gate mutex_destroy(&cs_globals.window_lock); 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate #ifdef XXX 5160Sstevel@tonic-gate /* 5170Sstevel@tonic-gate * Free the global "super-client" structure 5180Sstevel@tonic-gate */ 5190Sstevel@tonic-gate if (cs_globals.sclient_list) 5200Sstevel@tonic-gate kmem_free(cs_globals.sclient_list, 5210Sstevel@tonic-gate (cs_globals.num_sockets * sizeof (struct sclient_list_t))); 5220Sstevel@tonic-gate cs_globals.sclient_list = NULL; 5230Sstevel@tonic-gate #endif /* XXX */ 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate return (CS_SUCCESS); 5260Sstevel@tonic-gate } 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate /* 5290Sstevel@tonic-gate * ==== drip, drip, drip - the Card Services waterfall :-) ==== 5300Sstevel@tonic-gate */ 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate /* 5330Sstevel@tonic-gate * CardServices - general Card Services entry point for CS clients 5340Sstevel@tonic-gate * and Socket Services; the address of this 5350Sstevel@tonic-gate * function is handed to SS via the CSRegister 5360Sstevel@tonic-gate * SS call 5370Sstevel@tonic-gate */ 5380Sstevel@tonic-gate int 5390Sstevel@tonic-gate CardServices(int function, ...) 5400Sstevel@tonic-gate { 5410Sstevel@tonic-gate va_list arglist; 5420Sstevel@tonic-gate int retcode = CS_UNSUPPORTED_FUNCTION; 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate cs_socket_t *socp; 5450Sstevel@tonic-gate uint32_t *offp; 5460Sstevel@tonic-gate acc_handle_t *hp; 5470Sstevel@tonic-gate client_handle_t ch; 5480Sstevel@tonic-gate client_handle_t *chp; 5490Sstevel@tonic-gate window_handle_t wh; 5500Sstevel@tonic-gate window_handle_t *whp; 5510Sstevel@tonic-gate tuple_t *tuple; 5520Sstevel@tonic-gate cisparse_t *cisparse; 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate #ifdef CS_DEBUG 5550Sstevel@tonic-gate if (cs_debug > 127) { 5560Sstevel@tonic-gate cmn_err(CE_CONT, "CardServices: called for function %s (0x%x)\n", 5570Sstevel@tonic-gate cs_error2text(function, CSFUN2TEXT_FUNCTION), 5580Sstevel@tonic-gate function); 5590Sstevel@tonic-gate } 5600Sstevel@tonic-gate #endif 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate va_start(arglist, function); 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate /* 5650Sstevel@tonic-gate * Here's the Card Services waterfall 5660Sstevel@tonic-gate */ 5670Sstevel@tonic-gate switch (function) { 5680Sstevel@tonic-gate /* 5690Sstevel@tonic-gate * We got here as a result of the CIS module calling us 5700Sstevel@tonic-gate * in response to cs_ss_init() calling the CIS module 5710Sstevel@tonic-gate * at CIS_PARSER(CISP_CIS_SETUP, ...) 5720Sstevel@tonic-gate */ 5730Sstevel@tonic-gate case CISRegister: { 5740Sstevel@tonic-gate cisregister_t *cisr; 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate cisr = va_arg(arglist, cisregister_t *); 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate if (cisr->cis_magic != PCCS_MAGIC || 5790Sstevel@tonic-gate cisr->cis_version != PCCS_VERSION) { 5800Sstevel@tonic-gate cmn_err(CE_WARN, 5810Sstevel@tonic-gate "CS: CISRegister (%lx, %lx, %lx, %lx) *ERROR*", 5820Sstevel@tonic-gate (long)cisr->cis_magic, 5830Sstevel@tonic-gate (long)cisr->cis_version, 5840Sstevel@tonic-gate (long)cisr->cis_parser, 5850Sstevel@tonic-gate (long)cisr->cistpl_std_callout); 5860Sstevel@tonic-gate retcode = CS_BAD_ARGS; 5870Sstevel@tonic-gate } else { 5880Sstevel@tonic-gate /* 5890Sstevel@tonic-gate * Replace the CIS Parser entry point if 5900Sstevel@tonic-gate * necessary. 5910Sstevel@tonic-gate */ 5920Sstevel@tonic-gate if (cisr->cis_parser != NULL) 5930Sstevel@tonic-gate cis_parser = cisr->cis_parser; 5940Sstevel@tonic-gate cis_cistpl_std_callout = cisr->cistpl_std_callout; 5950Sstevel@tonic-gate retcode = CS_SUCCESS; 5960Sstevel@tonic-gate } 5970Sstevel@tonic-gate } 5980Sstevel@tonic-gate break; 5990Sstevel@tonic-gate case CISUnregister: /* XXX - should we do some more checking */ 6000Sstevel@tonic-gate /* XXX - need to protect this by a mutex */ 6010Sstevel@tonic-gate cis_parser = NULL; 6020Sstevel@tonic-gate cis_cistpl_std_callout = NULL; 6030Sstevel@tonic-gate retcode = CS_SUCCESS; 6040Sstevel@tonic-gate break; 6050Sstevel@tonic-gate case InitCISWindow: 6060Sstevel@tonic-gate socp = va_arg(arglist, cs_socket_t *); 6070Sstevel@tonic-gate offp = va_arg(arglist, uint32_t *); 6080Sstevel@tonic-gate hp = va_arg(arglist, acc_handle_t *); 6090Sstevel@tonic-gate retcode = cs_init_cis_window(socp, offp, hp, 6100Sstevel@tonic-gate va_arg(arglist, uint32_t)); 6110Sstevel@tonic-gate break; 6120Sstevel@tonic-gate case RegisterClient: 6130Sstevel@tonic-gate chp = va_arg(arglist, client_handle_t *), 6140Sstevel@tonic-gate retcode = cs_register_client(chp, 6150Sstevel@tonic-gate va_arg(arglist, client_reg_t *)); 6160Sstevel@tonic-gate break; 6170Sstevel@tonic-gate case DeregisterClient: 6180Sstevel@tonic-gate retcode = cs_deregister_client( 6190Sstevel@tonic-gate va_arg(arglist, client_handle_t)); 6200Sstevel@tonic-gate break; 6210Sstevel@tonic-gate case GetStatus: 6220Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 6230Sstevel@tonic-gate retcode = cs_get_status(ch, 6240Sstevel@tonic-gate va_arg(arglist, get_status_t *)); 6250Sstevel@tonic-gate break; 6260Sstevel@tonic-gate case ResetFunction: 6270Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 6280Sstevel@tonic-gate retcode = cs_reset_function(ch, 6290Sstevel@tonic-gate va_arg(arglist, reset_function_t *)); 6300Sstevel@tonic-gate break; 6310Sstevel@tonic-gate case SetEventMask: 6320Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 6330Sstevel@tonic-gate retcode = cs_set_event_mask(ch, 6340Sstevel@tonic-gate va_arg(arglist, sockevent_t *)); 6350Sstevel@tonic-gate break; 6360Sstevel@tonic-gate case GetEventMask: 6370Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 6380Sstevel@tonic-gate retcode = cs_get_event_mask(ch, 6390Sstevel@tonic-gate va_arg(arglist, sockevent_t *)); 6400Sstevel@tonic-gate break; 6410Sstevel@tonic-gate case RequestIO: 6420Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 6430Sstevel@tonic-gate retcode = cs_request_io(ch, 6440Sstevel@tonic-gate va_arg(arglist, io_req_t *)); 6450Sstevel@tonic-gate break; 6460Sstevel@tonic-gate case ReleaseIO: 6470Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 6480Sstevel@tonic-gate retcode = cs_release_io(ch, 6490Sstevel@tonic-gate va_arg(arglist, io_req_t *)); 6500Sstevel@tonic-gate break; 6510Sstevel@tonic-gate case RequestIRQ: 6520Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 6530Sstevel@tonic-gate retcode = cs_request_irq(ch, 6540Sstevel@tonic-gate va_arg(arglist, irq_req_t *)); 6550Sstevel@tonic-gate break; 6560Sstevel@tonic-gate case ReleaseIRQ: 6570Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 6580Sstevel@tonic-gate retcode = cs_release_irq(ch, 6590Sstevel@tonic-gate va_arg(arglist, irq_req_t *)); 6600Sstevel@tonic-gate break; 6610Sstevel@tonic-gate case RequestWindow: 6620Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 6630Sstevel@tonic-gate whp = va_arg(arglist, window_handle_t *); 6640Sstevel@tonic-gate retcode = cs_request_window(ch, whp, 6650Sstevel@tonic-gate va_arg(arglist, win_req_t *)); 6660Sstevel@tonic-gate break; 6670Sstevel@tonic-gate case ReleaseWindow: 6680Sstevel@tonic-gate retcode = cs_release_window( 6690Sstevel@tonic-gate va_arg(arglist, window_handle_t)); 6700Sstevel@tonic-gate break; 6710Sstevel@tonic-gate case ModifyWindow: 6720Sstevel@tonic-gate wh = va_arg(arglist, window_handle_t); 6730Sstevel@tonic-gate retcode = cs_modify_window(wh, 6740Sstevel@tonic-gate va_arg(arglist, modify_win_t *)); 6750Sstevel@tonic-gate break; 6760Sstevel@tonic-gate case MapMemPage: 6770Sstevel@tonic-gate wh = va_arg(arglist, window_handle_t); 6780Sstevel@tonic-gate retcode = cs_map_mem_page(wh, 6790Sstevel@tonic-gate va_arg(arglist, map_mem_page_t *)); 6800Sstevel@tonic-gate break; 6810Sstevel@tonic-gate case RequestSocketMask: 6820Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 6830Sstevel@tonic-gate retcode = cs_request_socket_mask(ch, 6840Sstevel@tonic-gate va_arg(arglist, request_socket_mask_t *)); 6850Sstevel@tonic-gate break; 6860Sstevel@tonic-gate case ReleaseSocketMask: 6870Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 6880Sstevel@tonic-gate retcode = cs_release_socket_mask(ch, 6890Sstevel@tonic-gate va_arg(arglist, release_socket_mask_t *)); 6900Sstevel@tonic-gate break; 6910Sstevel@tonic-gate case RequestConfiguration: 6920Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 6930Sstevel@tonic-gate retcode = cs_request_configuration(ch, 6940Sstevel@tonic-gate va_arg(arglist, config_req_t *)); 6950Sstevel@tonic-gate break; 6960Sstevel@tonic-gate case GetPhysicalAdapterInfo: 6970Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 6980Sstevel@tonic-gate retcode = cs_get_physical_adapter_info(ch, 6990Sstevel@tonic-gate va_arg(arglist, get_physical_adapter_info_t *)); 7000Sstevel@tonic-gate break; 7010Sstevel@tonic-gate case GetCardServicesInfo: 7020Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 7030Sstevel@tonic-gate retcode = cs_get_cardservices_info(ch, 7040Sstevel@tonic-gate va_arg(arglist, get_cardservices_info_t *)); 7050Sstevel@tonic-gate break; 7060Sstevel@tonic-gate case GetConfigurationInfo: 7070Sstevel@tonic-gate chp = va_arg(arglist, client_handle_t *); 7080Sstevel@tonic-gate retcode = cs_get_configuration_info(chp, 7090Sstevel@tonic-gate va_arg(arglist, get_configuration_info_t *)); 7100Sstevel@tonic-gate break; 7110Sstevel@tonic-gate case ModifyConfiguration: 7120Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 7130Sstevel@tonic-gate retcode = cs_modify_configuration(ch, 7140Sstevel@tonic-gate va_arg(arglist, modify_config_t *)); 7150Sstevel@tonic-gate break; 7160Sstevel@tonic-gate case AccessConfigurationRegister: 7170Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 7180Sstevel@tonic-gate retcode = cs_access_configuration_register(ch, 7190Sstevel@tonic-gate va_arg(arglist, access_config_reg_t *)); 7200Sstevel@tonic-gate break; 7210Sstevel@tonic-gate case ReleaseConfiguration: 7220Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 7230Sstevel@tonic-gate retcode = cs_release_configuration(ch, 7240Sstevel@tonic-gate va_arg(arglist, release_config_t *)); 7250Sstevel@tonic-gate break; 7260Sstevel@tonic-gate case OpenMemory: 7270Sstevel@tonic-gate cmn_err(CE_CONT, "CS: OpenMemory\n"); 7280Sstevel@tonic-gate break; 7290Sstevel@tonic-gate case ReadMemory: 7300Sstevel@tonic-gate cmn_err(CE_CONT, "CS: ReadMemory\n"); 7310Sstevel@tonic-gate break; 7320Sstevel@tonic-gate case WriteMemory: 7330Sstevel@tonic-gate cmn_err(CE_CONT, "CS: WriteMemory\n"); 7340Sstevel@tonic-gate break; 7350Sstevel@tonic-gate case CopyMemory: 7360Sstevel@tonic-gate cmn_err(CE_CONT, "CS: CopyMemory\n"); 7370Sstevel@tonic-gate break; 7380Sstevel@tonic-gate case RegisterEraseQueue: 7390Sstevel@tonic-gate cmn_err(CE_CONT, "CS: RegisterEraseQueue\n"); 7400Sstevel@tonic-gate break; 7410Sstevel@tonic-gate case CheckEraseQueue: 7420Sstevel@tonic-gate cmn_err(CE_CONT, "CS: CheckEraseQueue\n"); 7430Sstevel@tonic-gate break; 7440Sstevel@tonic-gate case DeregisterEraseQueue: 7450Sstevel@tonic-gate cmn_err(CE_CONT, "CS: DeregisterEraseQueue\n"); 7460Sstevel@tonic-gate break; 7470Sstevel@tonic-gate case CloseMemory: 7480Sstevel@tonic-gate cmn_err(CE_CONT, "CS: CloseMemory\n"); 7490Sstevel@tonic-gate break; 7500Sstevel@tonic-gate case GetFirstRegion: 7510Sstevel@tonic-gate cmn_err(CE_CONT, "CS: GetFirstRegion\n"); 7520Sstevel@tonic-gate break; 7530Sstevel@tonic-gate case GetNextRegion: 7540Sstevel@tonic-gate cmn_err(CE_CONT, "CS: GetNextRegion\n"); 7550Sstevel@tonic-gate break; 7560Sstevel@tonic-gate case GetFirstPartition: 7570Sstevel@tonic-gate cmn_err(CE_CONT, "CS: GetFirstPartition\n"); 7580Sstevel@tonic-gate break; 7590Sstevel@tonic-gate case GetNextPartition: 7600Sstevel@tonic-gate cmn_err(CE_CONT, "CS: GetNextPartition\n"); 7610Sstevel@tonic-gate break; 7620Sstevel@tonic-gate case ReturnSSEntry: 7630Sstevel@tonic-gate cmn_err(CE_CONT, "CS: ReturnSSEntry\n"); 7640Sstevel@tonic-gate break; 7650Sstevel@tonic-gate case MapLogSocket: 7660Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 7670Sstevel@tonic-gate retcode = cs_map_log_socket(ch, 7680Sstevel@tonic-gate va_arg(arglist, map_log_socket_t *)); 7690Sstevel@tonic-gate break; 7700Sstevel@tonic-gate case MapPhySocket: 7710Sstevel@tonic-gate cmn_err(CE_CONT, "CS: MapPhySocket\n"); 7720Sstevel@tonic-gate break; 7730Sstevel@tonic-gate case MapLogWindow: 7740Sstevel@tonic-gate cmn_err(CE_CONT, "CS: MapLogWindow\n"); 7750Sstevel@tonic-gate break; 7760Sstevel@tonic-gate case MapPhyWindow: 7770Sstevel@tonic-gate cmn_err(CE_CONT, "CS: MapPhyWindow\n"); 7780Sstevel@tonic-gate break; 7790Sstevel@tonic-gate case RegisterMTD: 7800Sstevel@tonic-gate cmn_err(CE_CONT, "CS: RegisterMTD\n"); 7810Sstevel@tonic-gate break; 7820Sstevel@tonic-gate case RegisterTimer: 7830Sstevel@tonic-gate cmn_err(CE_CONT, "CS: RegisterTimer\n"); 7840Sstevel@tonic-gate break; 7850Sstevel@tonic-gate case SetRegion: 7860Sstevel@tonic-gate cmn_err(CE_CONT, "CS: SetRegion\n"); 7870Sstevel@tonic-gate break; 7880Sstevel@tonic-gate case RequestExclusive: 7890Sstevel@tonic-gate cmn_err(CE_CONT, "CS: RequestExclusive\n"); 7900Sstevel@tonic-gate break; 7910Sstevel@tonic-gate case ReleaseExclusive: 7920Sstevel@tonic-gate cmn_err(CE_CONT, "CS: ReleaseExclusive\n"); 7930Sstevel@tonic-gate break; 7940Sstevel@tonic-gate case GetFirstClient: 7950Sstevel@tonic-gate retcode = cs_get_firstnext_client( 7960Sstevel@tonic-gate va_arg(arglist, get_firstnext_client_t *), 7970Sstevel@tonic-gate CS_GET_FIRST_FLAG); 7980Sstevel@tonic-gate break; 7990Sstevel@tonic-gate case GetNextClient: 8000Sstevel@tonic-gate retcode = cs_get_firstnext_client( 8010Sstevel@tonic-gate va_arg(arglist, get_firstnext_client_t *), 8020Sstevel@tonic-gate CS_GET_NEXT_FLAG); 8030Sstevel@tonic-gate break; 8040Sstevel@tonic-gate case GetClientInfo: 8050Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 8060Sstevel@tonic-gate retcode = cs_get_client_info(ch, 8070Sstevel@tonic-gate va_arg(arglist, client_info_t *)); 8080Sstevel@tonic-gate break; 8090Sstevel@tonic-gate case AddSocketServices: 8100Sstevel@tonic-gate cmn_err(CE_CONT, "CS: AddSocketServices\n"); 8110Sstevel@tonic-gate break; 8120Sstevel@tonic-gate case ReplaceSocketServices: 8130Sstevel@tonic-gate cmn_err(CE_CONT, "CS: ReplaceSocketServices\n"); 8140Sstevel@tonic-gate break; 8150Sstevel@tonic-gate case VendorSpecific: 8160Sstevel@tonic-gate cmn_err(CE_CONT, "CS: VendorSpecific\n"); 8170Sstevel@tonic-gate break; 8180Sstevel@tonic-gate case AdjustResourceInfo: 8190Sstevel@tonic-gate cmn_err(CE_CONT, "CS: AdjustResourceInfo\n"); 8200Sstevel@tonic-gate break; 8210Sstevel@tonic-gate case ValidateCIS: 8220Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 8230Sstevel@tonic-gate retcode = cs_validate_cis(ch, 8240Sstevel@tonic-gate va_arg(arglist, cisinfo_t *)); 8250Sstevel@tonic-gate break; 8260Sstevel@tonic-gate case GetFirstTuple: 8270Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 8280Sstevel@tonic-gate retcode = cs_get_firstnext_tuple(ch, 8290Sstevel@tonic-gate va_arg(arglist, tuple_t *), 8300Sstevel@tonic-gate CS_GET_FIRST_FLAG); 8310Sstevel@tonic-gate break; 8320Sstevel@tonic-gate case GetNextTuple: 8330Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 8340Sstevel@tonic-gate retcode = cs_get_firstnext_tuple(ch, 8350Sstevel@tonic-gate va_arg(arglist, tuple_t *), 8360Sstevel@tonic-gate CS_GET_NEXT_FLAG); 8370Sstevel@tonic-gate break; 8380Sstevel@tonic-gate case GetTupleData: 8390Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 8400Sstevel@tonic-gate retcode = cs_get_tuple_data(ch, 8410Sstevel@tonic-gate va_arg(arglist, tuple_t *)); 8420Sstevel@tonic-gate break; 8430Sstevel@tonic-gate case ParseTuple: 8440Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 8450Sstevel@tonic-gate tuple = va_arg(arglist, tuple_t *); 8460Sstevel@tonic-gate cisparse = va_arg(arglist, cisparse_t *); 8470Sstevel@tonic-gate retcode = cs_parse_tuple(ch, tuple, cisparse, 8480Sstevel@tonic-gate va_arg(arglist, uint_t)); 8490Sstevel@tonic-gate break; 8500Sstevel@tonic-gate case MakeDeviceNode: 8510Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 8520Sstevel@tonic-gate retcode = cs_make_device_node(ch, 8530Sstevel@tonic-gate va_arg(arglist, make_device_node_t *)); 8540Sstevel@tonic-gate break; 8550Sstevel@tonic-gate case RemoveDeviceNode: 8560Sstevel@tonic-gate ch = va_arg(arglist, client_handle_t); 8570Sstevel@tonic-gate retcode = cs_remove_device_node(ch, 8580Sstevel@tonic-gate va_arg(arglist, remove_device_node_t *)); 8590Sstevel@tonic-gate break; 8600Sstevel@tonic-gate case ConvertSpeed: 8610Sstevel@tonic-gate retcode = cs_convert_speed( 8620Sstevel@tonic-gate va_arg(arglist, convert_speed_t *)); 8630Sstevel@tonic-gate break; 8640Sstevel@tonic-gate case ConvertSize: 8650Sstevel@tonic-gate retcode = cs_convert_size( 8660Sstevel@tonic-gate va_arg(arglist, convert_size_t *)); 8670Sstevel@tonic-gate break; 8680Sstevel@tonic-gate case Event2Text: 8690Sstevel@tonic-gate retcode = cs_event2text( 8700Sstevel@tonic-gate va_arg(arglist, event2text_t *), 1); 8710Sstevel@tonic-gate break; 8720Sstevel@tonic-gate case Error2Text: { 8730Sstevel@tonic-gate error2text_t *cft; 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate cft = va_arg(arglist, error2text_t *); 8760Sstevel@tonic-gate (void) strcpy(cft->text, 8770Sstevel@tonic-gate cs_error2text(cft->item, CSFUN2TEXT_RETURN)); 8780Sstevel@tonic-gate retcode = CS_SUCCESS; 8790Sstevel@tonic-gate } 8800Sstevel@tonic-gate break; 8810Sstevel@tonic-gate case CS_DDI_Info: 8820Sstevel@tonic-gate retcode = cs_ddi_info(va_arg(arglist, cs_ddi_info_t *)); 8830Sstevel@tonic-gate break; 8840Sstevel@tonic-gate case CS_Sys_Ctl: 8850Sstevel@tonic-gate retcode = cs_sys_ctl(va_arg(arglist, cs_sys_ctl_t *)); 8860Sstevel@tonic-gate break; 8870Sstevel@tonic-gate default: 8880Sstevel@tonic-gate cmn_err(CE_CONT, "CS: {unknown function %d}\n", function); 8890Sstevel@tonic-gate break; 8900Sstevel@tonic-gate } /* switch(function) */ 8910Sstevel@tonic-gate 8920Sstevel@tonic-gate va_end(arglist); 8930Sstevel@tonic-gate 8940Sstevel@tonic-gate #ifdef CS_DEBUG 8950Sstevel@tonic-gate if (cs_debug > 127) { 8960Sstevel@tonic-gate cmn_err(CE_CONT, "CardServices: returning %s (0x%x)\n", 8970Sstevel@tonic-gate cs_error2text(retcode, CSFUN2TEXT_RETURN), 8980Sstevel@tonic-gate retcode); 8990Sstevel@tonic-gate } 9000Sstevel@tonic-gate #endif 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate return (retcode); 9030Sstevel@tonic-gate } 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate /* 9060Sstevel@tonic-gate * ==== tuple and CIS handling section ==== 9070Sstevel@tonic-gate */ 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate /* 9100Sstevel@tonic-gate * cs_parse_tuple - This function supports the CS ParseTuple function call. 9110Sstevel@tonic-gate * 9120Sstevel@tonic-gate * returns: CS_SUCCESS - if tuple parsed sucessfully 9130Sstevel@tonic-gate * CS_NO_CARD - if no card in socket 9140Sstevel@tonic-gate * CS_BAD_ARGS - if passed CIS list pointer is NULL 9150Sstevel@tonic-gate * CS_UNKNOWN_TUPLE - if unknown tuple passed to CIS parser 9160Sstevel@tonic-gate * CS_BAD_CIS - if generic parser error 9170Sstevel@tonic-gate * CS_NO_CIS - if no CIS for card/function 9180Sstevel@tonic-gate * 9190Sstevel@tonic-gate * See notes for the cs_get_firstnext_tuple function. 9200Sstevel@tonic-gate */ 9210Sstevel@tonic-gate static int 9220Sstevel@tonic-gate cs_parse_tuple(client_handle_t client_handle, tuple_t *tuple, 9230Sstevel@tonic-gate cisparse_t *cisparse, cisdata_t cisdata) 9240Sstevel@tonic-gate { 9250Sstevel@tonic-gate cs_socket_t *sp; 9260Sstevel@tonic-gate client_t *client; 9270Sstevel@tonic-gate uint32_t fn; 9280Sstevel@tonic-gate int ret; 9290Sstevel@tonic-gate 9300Sstevel@tonic-gate if ((ret = cs_get_socket(client_handle, &tuple->Socket, 9310Sstevel@tonic-gate &fn, &sp, &client)) != CS_SUCCESS) 9320Sstevel@tonic-gate return (ret); 9330Sstevel@tonic-gate 9340Sstevel@tonic-gate /* 9350Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not 9360Sstevel@tonic-gate * for this client, then return an error. 9370Sstevel@tonic-gate */ 9380Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) 9390Sstevel@tonic-gate return (CS_NO_CARD); 9400Sstevel@tonic-gate 9410Sstevel@tonic-gate /* 9420Sstevel@tonic-gate * Sanity check to be sure that we've got a non-NULL CIS list 9430Sstevel@tonic-gate * pointer. 9440Sstevel@tonic-gate */ 9450Sstevel@tonic-gate if (!(tuple->CISOffset)) 9460Sstevel@tonic-gate return (CS_BAD_ARGS); 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate mutex_enter(&sp->cis_lock); 9490Sstevel@tonic-gate 9500Sstevel@tonic-gate /* 9510Sstevel@tonic-gate * Check to see if there is a valid CIS for this function. 9520Sstevel@tonic-gate * There is an implicit assumption here that if this 9530Sstevel@tonic-gate * is a multi-function CIS and the specified function 9540Sstevel@tonic-gate * number is not CS_GLOBAL_CIS that in order for there 9550Sstevel@tonic-gate * to be a valid function-specific CIS, there also must 9560Sstevel@tonic-gate * be a valid global CIS. This means that we don't need 9570Sstevel@tonic-gate * to know whether this tuple came from the global CIS 9580Sstevel@tonic-gate * or from the function-specific CIS. 9590Sstevel@tonic-gate */ 9600Sstevel@tonic-gate if ((sp->cis_flags & CW_VALID_CIS) && 9610Sstevel@tonic-gate (sp->cis[fn].flags & CW_VALID_CIS)) { 9620Sstevel@tonic-gate ret = (int)(uintptr_t)CIS_PARSER(CISP_CIS_PARSE_TUPLE, 9630Sstevel@tonic-gate cis_cistpl_std_callout, 9640Sstevel@tonic-gate tuple->CISOffset, 9650Sstevel@tonic-gate (tuple->Attributes & TUPLE_RETURN_NAME)? 9660Sstevel@tonic-gate HANDTPL_RETURN_NAME: 9670Sstevel@tonic-gate HANDTPL_PARSE_LTUPLE, 9680Sstevel@tonic-gate cisparse, cisdata); 9690Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 9700Sstevel@tonic-gate if (ret == CISTPLF_UNKNOWN) 9710Sstevel@tonic-gate return (CS_UNKNOWN_TUPLE); 9720Sstevel@tonic-gate if (ret != CISTPLF_NOERROR) 9730Sstevel@tonic-gate return (CS_BAD_CIS); 9740Sstevel@tonic-gate ret = CS_SUCCESS; 9750Sstevel@tonic-gate } else { 9760Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 9770Sstevel@tonic-gate ret = CS_NO_CIS; 9780Sstevel@tonic-gate } /* if (CW_VALID_CIS) */ 9790Sstevel@tonic-gate 9800Sstevel@tonic-gate return (ret); 9810Sstevel@tonic-gate } 9820Sstevel@tonic-gate 9830Sstevel@tonic-gate /* 9840Sstevel@tonic-gate * cs_get_firstnext_tuple - returns the first/next tuple of the specified type 9850Sstevel@tonic-gate * this is to support the GetFirstTuple and 9860Sstevel@tonic-gate * GetNextTuple function call 9870Sstevel@tonic-gate * 9880Sstevel@tonic-gate * flags - one of: 9890Sstevel@tonic-gate * CS_GET_FIRST_FLAG causes function to support GetFirstTuple 9900Sstevel@tonic-gate * CS_GET_NEXT_FLAG causes function to support GetNextTuple 9910Sstevel@tonic-gate * 9920Sstevel@tonic-gate * tuple_t->Attributes flags: 9930Sstevel@tonic-gate * TUPLE_RETURN_LINK - XXX Not implemented, see notes below. 9940Sstevel@tonic-gate * TUPLE_RETURN_IGNORED_TUPLES - return tuples with 9950Sstevel@tonic-gate * CISTPLF_IGNORE_TUPLE set in the 9960Sstevel@tonic-gate * cistpl_t->flags member. 9970Sstevel@tonic-gate * 9980Sstevel@tonic-gate * Notes for regular PC card driver callers: 9990Sstevel@tonic-gate * 10000Sstevel@tonic-gate * On a single-function card, the caller will get back all the tuples in 10010Sstevel@tonic-gate * the CIS. 10020Sstevel@tonic-gate * 10030Sstevel@tonic-gate * On a multi-function card, the caller will get the tuples from the 10040Sstevel@tonic-gate * global CIS followed by the tuples in the function-specific CIS. The 10050Sstevel@tonic-gate * caller will not get any tuples from a function-specific CIS that 10060Sstevel@tonic-gate * does not belong to the caller's function. 10070Sstevel@tonic-gate * 10080Sstevel@tonic-gate * Notes for Socket Services, the "super-client" or CSI driver callers: 10090Sstevel@tonic-gate * 10100Sstevel@tonic-gate * On a single-function card, the operation is the same as for regular 10110Sstevel@tonic-gate * PC card driver callers with the addition that if the function number 10120Sstevel@tonic-gate * is set to CS_GLOBAL_CIS this function will return CS_NO_CIS. 10130Sstevel@tonic-gate * 10140Sstevel@tonic-gate * On a multi-function card, the operation is the same as for regular 10150Sstevel@tonic-gate * PC card driver callers with the addition that if the function number 10160Sstevel@tonic-gate * is set to CS_GLOBAL_CIS the caller will only get tuples from the 10170Sstevel@tonic-gate * global CIS. If a particular function nubmer does not exist, this 10180Sstevel@tonic-gate * function will return CS_NO_CIS for that function. 10190Sstevel@tonic-gate * 10200Sstevel@tonic-gate * General notes: 10210Sstevel@tonic-gate * 10220Sstevel@tonic-gate * On both a single-function card and a multi-function card, if the tuple 10230Sstevel@tonic-gate * comes from the global CIS chain, the CISTPLF_GLOBAL_CIS flag will be 10240Sstevel@tonic-gate * set in the tuple_t->flags member. 10250Sstevel@tonic-gate * 10260Sstevel@tonic-gate * On a multi-function card, if the tuple comes from the function-specific 10270Sstevel@tonic-gate * CIS chain, the CISTPLF_MF_CIS flag will be set in the tuple_t->flags 10280Sstevel@tonic-gate * member. 10290Sstevel@tonic-gate * 10300Sstevel@tonic-gate * For other flags that are set in the tuple_t->flags member, see the 10310Sstevel@tonic-gate * comments for the cis_list_lcreate function in the cis.c file. 10320Sstevel@tonic-gate * 10330Sstevel@tonic-gate * The CIS parser may not include all the tuples that are in the CIS in 10340Sstevel@tonic-gate * the private CIS list that it creates and maintains. See the CIS 10350Sstevel@tonic-gate * parser documentation for a list of tuples that the parser does not 10360Sstevel@tonic-gate * include in the list. 10370Sstevel@tonic-gate * 10380Sstevel@tonic-gate * If a tuple has the CISTPLF_IGNORE_TUPLE flag set and the flags 10390Sstevel@tonic-gate * parameter CIS_GET_LTUPLE_IGNORE is not set, that tuple will not 10400Sstevel@tonic-gate * be returned to the caller. Instead, the next tuple that matches 10410Sstevel@tonic-gate * the calling criteria will be returned (or NULL if no other tuples 10420Sstevel@tonic-gate * match the calling criteria). If CIS_GET_LTUPLE_IGNORE is set in 10430Sstevel@tonic-gate * the flags paramter, tuples in the CIS list that match the calling 10440Sstevel@tonic-gate * criteria will be returned. 10450Sstevel@tonic-gate * 10460Sstevel@tonic-gate * XXX The PC Card 95 Standard says that if the TUPLE_RETURN_LINK flag in 10470Sstevel@tonic-gate * the tuple_t->Attributes member is not set, then we don't return 10480Sstevel@tonic-gate * any of the link tuples. This function ignores this flag and always 10490Sstevel@tonic-gate * returns link tuples. 10500Sstevel@tonic-gate * 10510Sstevel@tonic-gate * Return codes: 10520Sstevel@tonic-gate * CS_SUCCESS - if tuple sucessfully found and returned 10530Sstevel@tonic-gate * CS_NO_CARD - if no card inserted 10540Sstevel@tonic-gate * CS_NO_CIS - if no CIS for the specified card/function 10550Sstevel@tonic-gate * CS_NO_MORE_ITEMS - if tuple not found or no more tuples 10560Sstevel@tonic-gate * to return 10570Sstevel@tonic-gate * 10580Sstevel@tonic-gate * See notes for cs_get_socket for a description of valid client, socket 10590Sstevel@tonic-gate * and function number combinations. 10600Sstevel@tonic-gate */ 10610Sstevel@tonic-gate static int 10620Sstevel@tonic-gate cs_get_firstnext_tuple(client_handle_t client_handle, 10630Sstevel@tonic-gate tuple_t *tuple, uint32_t flags) 10640Sstevel@tonic-gate { 10650Sstevel@tonic-gate cs_socket_t *sp; 10660Sstevel@tonic-gate client_t *client; 10670Sstevel@tonic-gate uint32_t fn; 10680Sstevel@tonic-gate int ret; 10690Sstevel@tonic-gate 10700Sstevel@tonic-gate if ((ret = cs_get_socket(client_handle, &tuple->Socket, &fn, 10710Sstevel@tonic-gate &sp, &client)) != CS_SUCCESS) 10720Sstevel@tonic-gate return (ret); 10730Sstevel@tonic-gate 10740Sstevel@tonic-gate /* 10750Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not 10760Sstevel@tonic-gate * for this client, then return an error. 10770Sstevel@tonic-gate */ 10780Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) 10790Sstevel@tonic-gate return (CS_NO_CARD); 10800Sstevel@tonic-gate 10810Sstevel@tonic-gate mutex_enter(&sp->cis_lock); 10820Sstevel@tonic-gate 10830Sstevel@tonic-gate /* 10840Sstevel@tonic-gate * If there's no CIS on this card or no CIS for the specified 10850Sstevel@tonic-gate * function, then we can't do much. 10860Sstevel@tonic-gate */ 10870Sstevel@tonic-gate if ((!(sp->cis_flags & CW_VALID_CIS)) || 10880Sstevel@tonic-gate (!(sp->cis[fn].flags & CW_VALID_CIS))) { 10890Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 10900Sstevel@tonic-gate return (CS_NO_CIS); 10910Sstevel@tonic-gate } 10920Sstevel@tonic-gate 10930Sstevel@tonic-gate /* 10940Sstevel@tonic-gate * This will set the CIS_GET_LTUPLE_IGNORE flag if the 10950Sstevel@tonic-gate * TUPLE_RETURN_IGNORED_TUPLES flag is set. The 10960Sstevel@tonic-gate * assumption here is that the CIS_GET_LTUPLE_IGNORE 10970Sstevel@tonic-gate * flag and the TUPLE_RETURN_IGNORED_TUPLES flag 10980Sstevel@tonic-gate * shares the same bit position. If this ever changes, 10990Sstevel@tonic-gate * we'll ahve to re-work this section of code. 11000Sstevel@tonic-gate */ 11010Sstevel@tonic-gate if (tuple->Attributes & TUPLE_RETURN_IGNORED_TUPLES) 11020Sstevel@tonic-gate flags |= CIS_GET_LTUPLE_IGNORE; 11030Sstevel@tonic-gate 11040Sstevel@tonic-gate /* 11050Sstevel@tonic-gate * Are we GetFirstTuple or GetNextTuple? 11060Sstevel@tonic-gate */ 11070Sstevel@tonic-gate if ((flags & CIS_GET_LTUPLE_OPMASK) & CS_GET_FIRST_FLAG) { 11080Sstevel@tonic-gate /* 11090Sstevel@tonic-gate * Initialize the tuple structure; we need this information when 11100Sstevel@tonic-gate * we have to process a GetNextTuple or ParseTuple call. 11110Sstevel@tonic-gate * If this card has a multi-function CIS, then we always start out 11120Sstevel@tonic-gate * delivering tuples from the global CIS chain. If this card does 11130Sstevel@tonic-gate * not have a multi-function CIS, then the function 0 CIS chain 11140Sstevel@tonic-gate * will contain the complete CIS list. 11150Sstevel@tonic-gate * If this is a multi-function card, then use the GET_FIRST_LTUPLE 11160Sstevel@tonic-gate * macro to return the first tuple in the CIS list - we do this 11170Sstevel@tonic-gate * since we don't want to return tuples with CISTPLF_IGNORE_TUPLE 11180Sstevel@tonic-gate * set unless CIS_GET_LTUPLE_IGNORE is set in the flags parameter. 11190Sstevel@tonic-gate * Note that we don't have to cross over into the fucntion-specific 11200Sstevel@tonic-gate * CIS chain if GET_FIRST_LTUPLE returns NULL, since a MF CIS will 11210Sstevel@tonic-gate * always have at least a CISTPL_LONGLINK_MFC tuple in the global 11220Sstevel@tonic-gate * CIS chain - the test for NULL is just a sanity check. 11230Sstevel@tonic-gate */ 11240Sstevel@tonic-gate if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) { 11250Sstevel@tonic-gate if ((tuple->CISOffset = 11260Sstevel@tonic-gate GET_FIRST_LTUPLE(sp->cis[CS_GLOBAL_CIS].cis, 11270Sstevel@tonic-gate flags)) == NULL) { 11280Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 11290Sstevel@tonic-gate return (CS_NO_MORE_ITEMS); 11300Sstevel@tonic-gate } /* GET_FIRST_LTUPLE */ 11310Sstevel@tonic-gate } else { 11320Sstevel@tonic-gate tuple->CISOffset = sp->cis[0].cis; 11330Sstevel@tonic-gate } /* CW_MULTI_FUNCTION_CIS */ 11340Sstevel@tonic-gate } else { 11350Sstevel@tonic-gate cistpl_t *tp; 11360Sstevel@tonic-gate 11370Sstevel@tonic-gate /* 11380Sstevel@tonic-gate * Check to be sure that we have a non-NULL tuple list pointer. 11390Sstevel@tonic-gate * This is necessary in the case where the caller calls us 11400Sstevel@tonic-gate * with get next tuple requests but we don't have any more 11410Sstevel@tonic-gate * tuples to give back. 11420Sstevel@tonic-gate */ 11430Sstevel@tonic-gate if (tuple->CISOffset == NULL) { 11440Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 11450Sstevel@tonic-gate return (CS_NO_MORE_ITEMS); 11460Sstevel@tonic-gate } 11470Sstevel@tonic-gate 11480Sstevel@tonic-gate /* 11490Sstevel@tonic-gate * Point to the next tuple in the list. If we're searching for 11500Sstevel@tonic-gate * a particular tuple, FIND_LTUPLE_FWD will find it. 11510Sstevel@tonic-gate * 11520Sstevel@tonic-gate * If there are no more tuples in the chain that we're looking 11530Sstevel@tonic-gate * at, then if we're looking at the global portion of a 11540Sstevel@tonic-gate * multi-function CIS, switch to the function-specific list 11550Sstevel@tonic-gate * and start looking there. 11560Sstevel@tonic-gate */ 11570Sstevel@tonic-gate if ((tp = GET_NEXT_TUPLE(tuple->CISOffset, flags)) == NULL) { 11580Sstevel@tonic-gate if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) { 11590Sstevel@tonic-gate if ((tuple->CISOffset->flags & CISTPLF_GLOBAL_CIS) && 11600Sstevel@tonic-gate (fn != CS_GLOBAL_CIS)) { 11610Sstevel@tonic-gate tp = GET_FIRST_LTUPLE(sp->cis[fn].cis, flags); 11620Sstevel@tonic-gate } /* CISTPLF_GLOBAL_CIS */ 11630Sstevel@tonic-gate } /* CW_MULTI_FUNCTION_CIS */ 11640Sstevel@tonic-gate } /* GET_NEXT_TUPLE */ 11650Sstevel@tonic-gate 11660Sstevel@tonic-gate /* 11670Sstevel@tonic-gate * If there are no more tuples in the chain, then return. 11680Sstevel@tonic-gate */ 11690Sstevel@tonic-gate if ((tuple->CISOffset = tp) == NULL) { 11700Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 11710Sstevel@tonic-gate return (CS_NO_MORE_ITEMS); 11720Sstevel@tonic-gate } 11730Sstevel@tonic-gate } /* CS_GET_FIRST_FLAG */ 11740Sstevel@tonic-gate 11750Sstevel@tonic-gate /* 11760Sstevel@tonic-gate * Check if we want to get the first of a particular type of tuple 11770Sstevel@tonic-gate * or just the first tuple in the chain. 11780Sstevel@tonic-gate * If there are no more tuples of the type we're searching for in 11790Sstevel@tonic-gate * the chain that we're looking at, then if we're looking at 11800Sstevel@tonic-gate * the global portion of a multi-function CIS, switch to the 11810Sstevel@tonic-gate * function-specific list and start looking there. 11820Sstevel@tonic-gate */ 11830Sstevel@tonic-gate if (tuple->DesiredTuple != RETURN_FIRST_TUPLE) { 11840Sstevel@tonic-gate cistpl_t *tp; 11850Sstevel@tonic-gate 11860Sstevel@tonic-gate if ((tp = FIND_LTUPLE_FWD(tuple->CISOffset, 11870Sstevel@tonic-gate tuple->DesiredTuple, flags)) == NULL) { 11880Sstevel@tonic-gate if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) { 11890Sstevel@tonic-gate if ((tuple->CISOffset->flags & CISTPLF_GLOBAL_CIS) && 11900Sstevel@tonic-gate (fn != CS_GLOBAL_CIS)) { 11910Sstevel@tonic-gate tp = FIND_FIRST_LTUPLE(sp->cis[fn].cis, 11920Sstevel@tonic-gate tuple->DesiredTuple, flags); 11930Sstevel@tonic-gate } /* CISTPLF_GLOBAL_CIS */ 11940Sstevel@tonic-gate } /* CW_MULTI_FUNCTION_CIS */ 11950Sstevel@tonic-gate } /* FIND_LTUPLE_FWD */ 11960Sstevel@tonic-gate 11970Sstevel@tonic-gate /* 11980Sstevel@tonic-gate * If there are no more tuples in the chain, then return. 11990Sstevel@tonic-gate */ 12000Sstevel@tonic-gate if ((tuple->CISOffset = tp) == NULL) { 12010Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 12020Sstevel@tonic-gate return (CS_NO_MORE_ITEMS); 12030Sstevel@tonic-gate } 12040Sstevel@tonic-gate } /* !RETURN_FIRST_TUPLE */ 12050Sstevel@tonic-gate 12060Sstevel@tonic-gate /* 12070Sstevel@tonic-gate * We've got a tuple, now fill out the rest of the tuple_t 12080Sstevel@tonic-gate * structure. Callers can use the flags member to 12090Sstevel@tonic-gate * determine whether or not the tuple data was copied 12100Sstevel@tonic-gate * to the linked list or if it's still on the card. 12110Sstevel@tonic-gate */ 12120Sstevel@tonic-gate tuple->Flags = tuple->CISOffset->flags; 12130Sstevel@tonic-gate tuple->TupleCode = tuple->CISOffset->type; 12140Sstevel@tonic-gate tuple->TupleLink = tuple->CISOffset->len; 12150Sstevel@tonic-gate tuple->TupleDataLen = tuple->CISOffset->len; 12160Sstevel@tonic-gate 12170Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 12180Sstevel@tonic-gate 12190Sstevel@tonic-gate return (CS_SUCCESS); 12200Sstevel@tonic-gate } 12210Sstevel@tonic-gate 12220Sstevel@tonic-gate /* 12230Sstevel@tonic-gate * cs_get_tuple_data - get the data portion of a tuple; this is to 12240Sstevel@tonic-gate * support the GetTupleData function call. 12250Sstevel@tonic-gate * 12260Sstevel@tonic-gate * Note that if the data body of a tuple was not read from the CIS, 12270Sstevel@tonic-gate * then this function will return CS_NO_MORE_ITEMS. 12280Sstevel@tonic-gate * 12290Sstevel@tonic-gate * For flags that are set in the tuple_t->flags member, see the 12300Sstevel@tonic-gate * comments for the cis_list_lcreate function in the cis.c file. 12310Sstevel@tonic-gate * These flags are copied into the tuple_t->flags member by the 12320Sstevel@tonic-gate * cs_get_firstnext_tuple function call. 12330Sstevel@tonic-gate * 12340Sstevel@tonic-gate * See notes for the cs_get_firstnext_tuple function. 12350Sstevel@tonic-gate */ 12360Sstevel@tonic-gate static int 12370Sstevel@tonic-gate cs_get_tuple_data(client_handle_t client_handle, tuple_t *tuple) 12380Sstevel@tonic-gate { 12390Sstevel@tonic-gate cs_socket_t *sp; 12400Sstevel@tonic-gate client_t *client; 12410Sstevel@tonic-gate int ret, nbytes; 12420Sstevel@tonic-gate uint32_t fn, flags; 12430Sstevel@tonic-gate cisdata_t *tsd, *tdd; 12440Sstevel@tonic-gate uint32_t newoffset; 12450Sstevel@tonic-gate acc_handle_t cis_handle; 12460Sstevel@tonic-gate 12470Sstevel@tonic-gate if ((ret = cs_get_socket(client_handle, &tuple->Socket, &fn, 12480Sstevel@tonic-gate &sp, &client)) != CS_SUCCESS) 12490Sstevel@tonic-gate return (ret); 12500Sstevel@tonic-gate 12510Sstevel@tonic-gate /* 12520Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not 12530Sstevel@tonic-gate * for this client, then return an error. 12540Sstevel@tonic-gate */ 12550Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) 12560Sstevel@tonic-gate return (CS_NO_CARD); 12570Sstevel@tonic-gate 12580Sstevel@tonic-gate mutex_enter(&sp->cis_lock); 12590Sstevel@tonic-gate 12600Sstevel@tonic-gate if ((sp->cis_flags & CW_VALID_CIS) && 12610Sstevel@tonic-gate (sp->cis[fn].flags & CW_VALID_CIS)) { 12620Sstevel@tonic-gate 12630Sstevel@tonic-gate /* 12640Sstevel@tonic-gate * Check to be sure that we have a non-NULL pointer to 12650Sstevel@tonic-gate * a CIS list. 12660Sstevel@tonic-gate */ 12670Sstevel@tonic-gate if (!(tuple->CISOffset)) { 12680Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 12690Sstevel@tonic-gate return (CS_NO_MORE_ITEMS); 12700Sstevel@tonic-gate } 12710Sstevel@tonic-gate 12720Sstevel@tonic-gate /* 12730Sstevel@tonic-gate * Since the tuple data buffer that the caller calls us with 12740Sstevel@tonic-gate * is preallocated in the tuple_t structure, we ignore any 12750Sstevel@tonic-gate * TupleDataMax value that the caller has setup and use the 12760Sstevel@tonic-gate * actual size of the tuple data buffer in the structure. 12770Sstevel@tonic-gate */ 12780Sstevel@tonic-gate tuple->TupleDataMax = sizeof (tuple->TupleData); 12790Sstevel@tonic-gate 12800Sstevel@tonic-gate /* 12810Sstevel@tonic-gate * Make sure the requested offset is not past the end of the 12820Sstevel@tonic-gate * tuple data body nor past the end of the user-supplied 12830Sstevel@tonic-gate * buffer. 12840Sstevel@tonic-gate */ 12850Sstevel@tonic-gate if ((int)tuple->TupleOffset >= min((int)tuple->TupleLink, 12860Sstevel@tonic-gate (int)tuple->TupleDataMax)) { 12870Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 12880Sstevel@tonic-gate return (CS_NO_MORE_ITEMS); 12890Sstevel@tonic-gate } 12900Sstevel@tonic-gate 12910Sstevel@tonic-gate tuple->TupleDataLen = tuple->TupleLink; 12920Sstevel@tonic-gate 12930Sstevel@tonic-gate if ((nbytes = min((int)tuple->TupleDataMax - 12940Sstevel@tonic-gate (int)tuple->TupleOffset, 12950Sstevel@tonic-gate (int)tuple->TupleDataLen - 12960Sstevel@tonic-gate (int)tuple->TupleOffset)) < 1) { 12970Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 12980Sstevel@tonic-gate return (CS_BAD_ARGS); 12990Sstevel@tonic-gate } 13000Sstevel@tonic-gate 13010Sstevel@tonic-gate /* 13020Sstevel@tonic-gate * The tuple data destination is always the tuple_t->TupleData 13030Sstevel@tonic-gate * buffer in the tuple_t structure no matter where we read the 13040Sstevel@tonic-gate * tuple data from. 13050Sstevel@tonic-gate */ 13060Sstevel@tonic-gate tdd = tuple->TupleData; 13070Sstevel@tonic-gate bzero((caddr_t)tdd, sizeof (tuple->TupleData)); 13080Sstevel@tonic-gate 13090Sstevel@tonic-gate /* 13100Sstevel@tonic-gate * Do we have a copy of the tuple data? If not, we have to 13110Sstevel@tonic-gate * get a pointer to the CIS and read the tuple data from the 13120Sstevel@tonic-gate * card itself. 13130Sstevel@tonic-gate */ 13140Sstevel@tonic-gate switch (tuple->CISOffset->flags & CISTPLF_SPACE_MASK) { 13150Sstevel@tonic-gate case CISTPLF_LM_SPACE: 13160Sstevel@tonic-gate tsd = (tuple->CISOffset->data + 13170Sstevel@tonic-gate (unsigned)tuple->TupleOffset); 13180Sstevel@tonic-gate while (nbytes--) 13190Sstevel@tonic-gate *tdd++ = *tsd++; 13200Sstevel@tonic-gate break; 13210Sstevel@tonic-gate case CISTPLF_AM_SPACE: 13220Sstevel@tonic-gate case CISTPLF_CM_SPACE: 13230Sstevel@tonic-gate newoffset = tuple->CISOffset->offset; 13240Sstevel@tonic-gate 13250Sstevel@tonic-gate /* 13260Sstevel@tonic-gate * Setup the proper space flags as well as setup the 13270Sstevel@tonic-gate * address offset to point to the start of the tuple 13280Sstevel@tonic-gate * data area; we need to do the latter since the 13290Sstevel@tonic-gate * cis_store_cis_addr function in cis.c sets up the 13300Sstevel@tonic-gate * tuple->CISOffset->offset offset to point to the 13310Sstevel@tonic-gate * start of the tuple. 13320Sstevel@tonic-gate */ 13330Sstevel@tonic-gate if (tuple->CISOffset->flags & CISTPLF_AM_SPACE) { 13340Sstevel@tonic-gate flags = CISTPLF_AM_SPACE; 13350Sstevel@tonic-gate newoffset += ((tuple->TupleOffset * 2) + 4); 13360Sstevel@tonic-gate } else { 13370Sstevel@tonic-gate flags = CISTPLF_CM_SPACE; 13380Sstevel@tonic-gate newoffset += (tuple->TupleOffset + 2); 13390Sstevel@tonic-gate } 13400Sstevel@tonic-gate 13410Sstevel@tonic-gate if (cs_init_cis_window(sp, &newoffset, &cis_handle, 13420Sstevel@tonic-gate flags) != CS_SUCCESS) { 13430Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 13440Sstevel@tonic-gate cmn_err(CE_CONT, "cs_get_tuple_data: socket %d " 13450Sstevel@tonic-gate "can't init CIS window\n", 13460Sstevel@tonic-gate sp->socket_num); 13470Sstevel@tonic-gate return (CS_GENERAL_FAILURE); 13480Sstevel@tonic-gate } /* cs_init_cis_window */ 13490Sstevel@tonic-gate while (nbytes--) { 13500Sstevel@tonic-gate *tdd++ = csx_Get8(cis_handle, newoffset++); 13510Sstevel@tonic-gate if (tuple->CISOffset->flags & CISTPLF_AM_SPACE) 13520Sstevel@tonic-gate newoffset++; 13530Sstevel@tonic-gate } /* while */ 13540Sstevel@tonic-gate break; 13550Sstevel@tonic-gate default: 13560Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 13570Sstevel@tonic-gate return (CS_GENERAL_FAILURE); 13580Sstevel@tonic-gate } /* switch */ 13590Sstevel@tonic-gate 13600Sstevel@tonic-gate ret = CS_SUCCESS; 13610Sstevel@tonic-gate } else { 13620Sstevel@tonic-gate ret = CS_NO_CIS; 13630Sstevel@tonic-gate } /* if (CW_VALID_CIS) */ 13640Sstevel@tonic-gate 13650Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 13660Sstevel@tonic-gate 13670Sstevel@tonic-gate return (ret); 13680Sstevel@tonic-gate } 13690Sstevel@tonic-gate 13700Sstevel@tonic-gate /* 13710Sstevel@tonic-gate * cs_validate_cis - validates the CIS on a card in the given socket; this 13720Sstevel@tonic-gate * is to support the ValidateCIS function call. 13730Sstevel@tonic-gate * 13740Sstevel@tonic-gate * Notes for regular PC card driver callers: 13750Sstevel@tonic-gate * 13760Sstevel@tonic-gate * Regular PC card drivers calling ValidateCIS will get the meaning of 13770Sstevel@tonic-gate * the structure members as specified in the standard. 13780Sstevel@tonic-gate * 13790Sstevel@tonic-gate * Notes for Socket Services, the "super-client" or CSI driver callers: 13800Sstevel@tonic-gate * 13810Sstevel@tonic-gate * with: Function Number = CS_GLOBAL_CIS 13820Sstevel@tonic-gate * 13830Sstevel@tonic-gate * For a single-function card, CS_NO_CIS will be returned and the 13840Sstevel@tonic-gate * cisinfo_t->Chains and cisinfo_t->Tuples members will be set to 0. 13850Sstevel@tonic-gate * 13860Sstevel@tonic-gate * For a multi-function card, cisinfo_t->Chains will contain a count of 13870Sstevel@tonic-gate * the number of CIS chains in the global portion of the CIS, and 13880Sstevel@tonic-gate * cisinfo_t->Tuples will contain a count of the number of tuples in 13890Sstevel@tonic-gate * the global portion of the CIS. 13900Sstevel@tonic-gate * 13910Sstevel@tonic-gate * with: 0 <= Function Number < CIS_MAX_FUNCTIONS 13920Sstevel@tonic-gate * 13930Sstevel@tonic-gate * For a single-function card, if the function number is equal to 0 and 13940Sstevel@tonic-gate * has a CIS, cisinfo_t->Chains will contain a count of the number of 13950Sstevel@tonic-gate * CIS chains in the CIS, and cisinfo_t->Tuples will contain a count of 13960Sstevel@tonic-gate * the number of tuples in the CIS. If the card does not have a CIS, or 13970Sstevel@tonic-gate * if the function number is not equal to 0, CS_NO_CIS will be returned 13980Sstevel@tonic-gate * and the cisinfo_t->Chains and cisinfo_t->Tuples members will be set 13990Sstevel@tonic-gate * to 0. 14000Sstevel@tonic-gate * 14010Sstevel@tonic-gate * For a multi-function card, cisinfo_t->Chains will contain a count of 14020Sstevel@tonic-gate * the number of CIS chains in the global and function-specific 14030Sstevel@tonic-gate * portions of the CIS, and cisinfo_t->Tuples will contain a count of 14040Sstevel@tonic-gate * the number of tuples in the global and function-specific portions of 14050Sstevel@tonic-gate * the CIS. If the function does not exist or has no CIS, CS_NO_CIS 14060Sstevel@tonic-gate * will be returned and the cisinfo_t->Chains and cisinfo_t->Tuples 14070Sstevel@tonic-gate * members will be set to 0. 14080Sstevel@tonic-gate * 14090Sstevel@tonic-gate * General notes: 14100Sstevel@tonic-gate * 14110Sstevel@tonic-gate * If the card does not have a CIS, or if the function does not exist 14120Sstevel@tonic-gate * or has no CIS, CS_NO_CIS will be returned and the cisinfo_t->Chains 14130Sstevel@tonic-gate * and cisinfo_t->Tuples members will be set to 0. 14140Sstevel@tonic-gate * 14150Sstevel@tonic-gate * Most of the work of validating the CIS has already been done by the 14160Sstevel@tonic-gate * CIS parser module, so we don't have to do much here except for 14170Sstevel@tonic-gate * looking at the various flags and tuple/chain counts that were already 14180Sstevel@tonic-gate * setup by the CIS parser. 14190Sstevel@tonic-gate * 14200Sstevel@tonic-gate * See notes for the cs_get_firstnext_tuple function. 14210Sstevel@tonic-gate */ 14220Sstevel@tonic-gate static int 14230Sstevel@tonic-gate cs_validate_cis(client_handle_t client_handle, cisinfo_t *cisinfo) 14240Sstevel@tonic-gate { 14250Sstevel@tonic-gate cs_socket_t *sp; 14260Sstevel@tonic-gate client_t *client; 14270Sstevel@tonic-gate uint32_t fn; 14280Sstevel@tonic-gate int ret; 14290Sstevel@tonic-gate 14300Sstevel@tonic-gate if ((ret = cs_get_socket(client_handle, &cisinfo->Socket, &fn, 14310Sstevel@tonic-gate &sp, &client)) != CS_SUCCESS) 14320Sstevel@tonic-gate return (ret); 14330Sstevel@tonic-gate 14340Sstevel@tonic-gate /* 14350Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not 14360Sstevel@tonic-gate * for this client, then return an error. 14370Sstevel@tonic-gate */ 14380Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) 14390Sstevel@tonic-gate return (CS_NO_CARD); 14400Sstevel@tonic-gate 14410Sstevel@tonic-gate mutex_enter(&sp->cis_lock); 14420Sstevel@tonic-gate if ((sp->cis_flags & CW_VALID_CIS) && 14430Sstevel@tonic-gate (sp->cis[fn].flags & CW_VALID_CIS)) { 14440Sstevel@tonic-gate cisinfo->Chains = sp->cis[fn].nchains; 14450Sstevel@tonic-gate cisinfo->Tuples = sp->cis[fn].ntuples; 14460Sstevel@tonic-gate 14470Sstevel@tonic-gate if ((fn != CS_GLOBAL_CIS) && 14480Sstevel@tonic-gate (sp->cis[CS_GLOBAL_CIS].flags & CW_VALID_CIS)) { 14490Sstevel@tonic-gate cisinfo->Chains += sp->cis[CS_GLOBAL_CIS].nchains; 14500Sstevel@tonic-gate cisinfo->Tuples += sp->cis[CS_GLOBAL_CIS].ntuples; 14510Sstevel@tonic-gate } /* !CS_GLOBAL_CIS */ 14520Sstevel@tonic-gate 14530Sstevel@tonic-gate ret = CS_SUCCESS; 14540Sstevel@tonic-gate } else { 14550Sstevel@tonic-gate cisinfo->Chains = 0; 14560Sstevel@tonic-gate cisinfo->Tuples = 0; 14570Sstevel@tonic-gate ret = CS_NO_CIS; 14580Sstevel@tonic-gate } 14590Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 14600Sstevel@tonic-gate 14610Sstevel@tonic-gate return (ret); 14620Sstevel@tonic-gate } 14630Sstevel@tonic-gate 14640Sstevel@tonic-gate /* 14650Sstevel@tonic-gate * cs_init_cis_window - initializes the CIS window for the passed socket 14660Sstevel@tonic-gate * 14670Sstevel@tonic-gate * calling: *sp - pointer to the per-socket structure 14680Sstevel@tonic-gate * *offset - offset from start of AM or CM space 14690Sstevel@tonic-gate * *hp - pointer to acc_handle_t to store modified 14700Sstevel@tonic-gate * window access handle in 14710Sstevel@tonic-gate * flags - one of: 14720Sstevel@tonic-gate * CISTPLF_AM_SPACE - set window to AM space 14730Sstevel@tonic-gate * CISTPLF_CM_SPACE - set window to CM space 14740Sstevel@tonic-gate * 14750Sstevel@tonic-gate * returns: CS_SUCCESS if CIS window was set up 14760Sstevel@tonic-gate * *offset - contains adjusted offset to use to access 14770Sstevel@tonic-gate * requested space 14780Sstevel@tonic-gate * CS_BAD_WINDOW if CIS window could not be setup 14790Sstevel@tonic-gate * CS_GENERAL_FAILURE if socket has a CIS window number 14800Sstevel@tonic-gate * but the window flags are wrong 14810Sstevel@tonic-gate * 14820Sstevel@tonic-gate * Note: This function will check to be sure that there is a valid 14830Sstevel@tonic-gate * CIS window allocated to this socket. 14840Sstevel@tonic-gate * If there is an error in setting up the window hardware, the 14850Sstevel@tonic-gate * CIS window information for this socket is cleared. 14860Sstevel@tonic-gate * This function is also used by routines that need to get 14870Sstevel@tonic-gate * a pointer to the base of AM space to access the card's 14880Sstevel@tonic-gate * configuration registers. 14890Sstevel@tonic-gate * The passed offset is the un-window-size-aligned offset. 14900Sstevel@tonic-gate */ 14910Sstevel@tonic-gate int 14920Sstevel@tonic-gate cs_init_cis_window(cs_socket_t *sp, uint32_t *offset, 14930Sstevel@tonic-gate acc_handle_t *hp, uint32_t flags) 14940Sstevel@tonic-gate { 14950Sstevel@tonic-gate set_window_t sw; 14960Sstevel@tonic-gate get_window_t gw; 14970Sstevel@tonic-gate inquire_window_t iw; 14980Sstevel@tonic-gate set_page_t set_page; 14990Sstevel@tonic-gate cs_window_t *cw; 15000Sstevel@tonic-gate 15010Sstevel@tonic-gate /* 15020Sstevel@tonic-gate * Check to be sure that we have a valid CIS window 15030Sstevel@tonic-gate */ 15040Sstevel@tonic-gate if (!SOCKET_HAS_CIS_WINDOW(sp)) { 15050Sstevel@tonic-gate cmn_err(CE_CONT, 15060Sstevel@tonic-gate "cs_init_cis_window: socket %d has no CIS window\n", 15070Sstevel@tonic-gate sp->socket_num); 15080Sstevel@tonic-gate return (CS_BAD_WINDOW); 15090Sstevel@tonic-gate } 15100Sstevel@tonic-gate 15110Sstevel@tonic-gate /* 15120Sstevel@tonic-gate * Check to be sure that this window is allocated for CIS use 15130Sstevel@tonic-gate */ 15140Sstevel@tonic-gate if ((cw = cs_get_wp(sp->cis_win_num)) == NULL) 15150Sstevel@tonic-gate return (CS_BAD_WINDOW); 15160Sstevel@tonic-gate 15170Sstevel@tonic-gate if (!(cw->state & CW_CIS)) { 15180Sstevel@tonic-gate cmn_err(CE_CONT, 15190Sstevel@tonic-gate "cs_init_cis_window: socket %d invalid CIS window state 0x%x\n", 15200Sstevel@tonic-gate sp->socket_num, cw->state); 15210Sstevel@tonic-gate return (CS_BAD_WINDOW); 15220Sstevel@tonic-gate } 15230Sstevel@tonic-gate 15240Sstevel@tonic-gate /* 15250Sstevel@tonic-gate * Get the characteristics of this window - we use this to 15260Sstevel@tonic-gate * determine whether we need to re-map the window or 15270Sstevel@tonic-gate * just move the window offset on the card. 15280Sstevel@tonic-gate */ 15290Sstevel@tonic-gate iw.window = sp->cis_win_num; 15300Sstevel@tonic-gate SocketServices(SS_InquireWindow, &iw); 15310Sstevel@tonic-gate 15320Sstevel@tonic-gate /* 15330Sstevel@tonic-gate * We've got a window, now set up the hardware. If we've got 15340Sstevel@tonic-gate * a variable sized window, then all we need to do is to 15350Sstevel@tonic-gate * get a valid mapping to the base of the window using 15360Sstevel@tonic-gate * the current window size; if we've got a fixed-size 15370Sstevel@tonic-gate * window, then we need to get a mapping to the window 15380Sstevel@tonic-gate * starting at offset zero of the window. 15390Sstevel@tonic-gate */ 15400Sstevel@tonic-gate if (iw.mem_win_char.MemWndCaps & WC_SIZE) { 15410Sstevel@tonic-gate sw.WindowSize = sp->cis_win_size; 15420Sstevel@tonic-gate set_page.offset = ((*offset / sp->cis_win_size) * 15430Sstevel@tonic-gate sp->cis_win_size); 15440Sstevel@tonic-gate } else { 15450Sstevel@tonic-gate set_page.offset = ((*offset / iw.mem_win_char.MinSize) * 15460Sstevel@tonic-gate iw.mem_win_char.MinSize); 15470Sstevel@tonic-gate sw.WindowSize = (((*offset & ~(PAGESIZE - 1)) & 15480Sstevel@tonic-gate (set_page.offset - 1)) + PAGESIZE); 15490Sstevel@tonic-gate } 15500Sstevel@tonic-gate 15510Sstevel@tonic-gate /* 15520Sstevel@tonic-gate * Return a normalized base offset; this takes care of the case 15530Sstevel@tonic-gate * where the required offset is greater than the window size. 15540Sstevel@tonic-gate * BugID 1236404 15550Sstevel@tonic-gate * code was: 15560Sstevel@tonic-gate * *offset = *offset & (set_page.offset - 1); 15570Sstevel@tonic-gate */ 15580Sstevel@tonic-gate *offset = *offset - set_page.offset; 15590Sstevel@tonic-gate 15600Sstevel@tonic-gate #ifdef CS_DEBUG 15610Sstevel@tonic-gate if (cs_debug > 1) 15620Sstevel@tonic-gate cmn_err(CE_CONT, "cs_init_cis_window: WindowSize 0x%x " 15630Sstevel@tonic-gate "offset 0x%x\n", 15640Sstevel@tonic-gate (int)sw.WindowSize, 15650Sstevel@tonic-gate (int)set_page.offset); 15660Sstevel@tonic-gate if (cs_debug > 1) 15670Sstevel@tonic-gate cmn_err(CE_CONT, "\t*offset = 0x%x space = %s\n", 15680Sstevel@tonic-gate (int)*offset, 15690Sstevel@tonic-gate (flags & CISTPLF_AM_SPACE)? 15700Sstevel@tonic-gate "CISTPLF_AM_SPACE":"CISTPLF_CM_SPACE"); 15710Sstevel@tonic-gate #endif 15720Sstevel@tonic-gate 15730Sstevel@tonic-gate sw.window = sp->cis_win_num; 15740Sstevel@tonic-gate sw.socket = sp->socket_num; 15750Sstevel@tonic-gate sw.state = (WS_ENABLED | WS_EXACT_MAPIN); 15760Sstevel@tonic-gate sw.attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 15770Sstevel@tonic-gate sw.attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 15780Sstevel@tonic-gate sw.attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 15790Sstevel@tonic-gate 15800Sstevel@tonic-gate /* 15810Sstevel@tonic-gate * The PCMCIA SS spec specifies this be expressed in 15820Sstevel@tonic-gate * a device speed format per 5.2.7.1.3 but 15830Sstevel@tonic-gate * our implementation of SS_SetWindow uses 15840Sstevel@tonic-gate * actual nanoseconds. 15850Sstevel@tonic-gate */ 15860Sstevel@tonic-gate sw.speed = CIS_DEFAULT_SPEED; 15870Sstevel@tonic-gate sw.base = 0; 15880Sstevel@tonic-gate /* 15890Sstevel@tonic-gate * Set up the window - if this fails, then just set the 15900Sstevel@tonic-gate * CIS window number back to it's initialized value so 15910Sstevel@tonic-gate * that we'll fail when we break out of the loop. 15920Sstevel@tonic-gate */ 15930Sstevel@tonic-gate if (SocketServices(SS_SetWindow, &sw) != SUCCESS) { 15940Sstevel@tonic-gate sp->cis_win_num = PCMCIA_MAX_WINDOWS; 15950Sstevel@tonic-gate cw->state = 0; /* XXX do we really want to do this? */ 15960Sstevel@tonic-gate return (CS_BAD_WINDOW); 15970Sstevel@tonic-gate } else { 15980Sstevel@tonic-gate set_page.window = sp->cis_win_num; 15990Sstevel@tonic-gate set_page.page = 0; 16000Sstevel@tonic-gate set_page.state = PS_ENABLED; 16010Sstevel@tonic-gate if (flags & CISTPLF_AM_SPACE) 16020Sstevel@tonic-gate set_page.state |= PS_ATTRIBUTE; 16030Sstevel@tonic-gate 16040Sstevel@tonic-gate if (SocketServices(SS_SetPage, &set_page) != SUCCESS) { 16050Sstevel@tonic-gate sp->cis_win_num = PCMCIA_MAX_WINDOWS; 16060Sstevel@tonic-gate cw->state = 0; /* XXX do we really want to do this? */ 16070Sstevel@tonic-gate return (CS_BAD_WINDOW); 16080Sstevel@tonic-gate } /* if (SS_SetPage) */ 16090Sstevel@tonic-gate } /* if (SS_SetWindow) */ 16100Sstevel@tonic-gate 16110Sstevel@tonic-gate /* 16120Sstevel@tonic-gate * Get the window information for the CIS window for this socket. 16130Sstevel@tonic-gate */ 16140Sstevel@tonic-gate gw.window = sp->cis_win_num; 16150Sstevel@tonic-gate gw.socket = sp->socket_num; /* XXX - SS_GetWindow should set this */ 16160Sstevel@tonic-gate if (SocketServices(SS_GetWindow, &gw) != SUCCESS) 16170Sstevel@tonic-gate return (CS_BAD_WINDOW); 16180Sstevel@tonic-gate 16190Sstevel@tonic-gate *hp = (acc_handle_t)gw.handle; 16200Sstevel@tonic-gate 16210Sstevel@tonic-gate return (CS_SUCCESS); 16220Sstevel@tonic-gate } 16230Sstevel@tonic-gate 16240Sstevel@tonic-gate /* 16250Sstevel@tonic-gate * ==== client registration/deregistration section ==== 16260Sstevel@tonic-gate */ 16270Sstevel@tonic-gate 16280Sstevel@tonic-gate /* 16290Sstevel@tonic-gate * cs_register_client - This supports the RegisterClient call. 16300Sstevel@tonic-gate * 16310Sstevel@tonic-gate * Upon successful registration, the client_handle_t * handle argument will 16320Sstevel@tonic-gate * contain the new client handle and we return CS_SUCCESS. 16330Sstevel@tonic-gate */ 16340Sstevel@tonic-gate static int 16350Sstevel@tonic-gate cs_register_client(client_handle_t *ch, client_reg_t *cr) 16360Sstevel@tonic-gate { 16370Sstevel@tonic-gate uint32_t sn; 16380Sstevel@tonic-gate int super_client = 0; 16390Sstevel@tonic-gate sclient_reg_t *scr = cr->priv; 16400Sstevel@tonic-gate struct sclient_list_t *scli; 16410Sstevel@tonic-gate 16420Sstevel@tonic-gate /* 16430Sstevel@tonic-gate * See if we're not supposed to register any new clients. 16440Sstevel@tonic-gate */ 16450Sstevel@tonic-gate if (cs_globals.init_state & GLOBAL_INIT_STATE_NO_CLIENTS) 16460Sstevel@tonic-gate return (CS_OUT_OF_RESOURCE); 16470Sstevel@tonic-gate 16480Sstevel@tonic-gate /* 16490Sstevel@tonic-gate * Do a version check - if the client expects a later version of 16500Sstevel@tonic-gate * Card Services than what we are, return CS_BAD_VERSION. 16510Sstevel@tonic-gate * XXX - How do we specify just a PARTICULAR version of CS?? 16520Sstevel@tonic-gate */ 16530Sstevel@tonic-gate if (CS_VERSION < cr->Version) 16540Sstevel@tonic-gate return (CS_BAD_VERSION); 16550Sstevel@tonic-gate 16560Sstevel@tonic-gate /* 16570Sstevel@tonic-gate * Check to be sure that the client has given us a valid set of 16580Sstevel@tonic-gate * client type flags. We also use this opportunity to see 16590Sstevel@tonic-gate * if the registering client is Socket Services or is a 16600Sstevel@tonic-gate * "super-client" or a CSI client. 16610Sstevel@tonic-gate * 16620Sstevel@tonic-gate * Note that SS can not set any flag in the Attributes field other 16630Sstevel@tonic-gate * than the INFO_SOCKET_SERVICES flag. 16640Sstevel@tonic-gate * 16650Sstevel@tonic-gate * Valid combinations of cr->Attributes and cr->EventMask flags: 16660Sstevel@tonic-gate * 16670Sstevel@tonic-gate * for Socket Services: 16680Sstevel@tonic-gate * cr->Attributes: 16690Sstevel@tonic-gate * set: 16700Sstevel@tonic-gate * INFO_SOCKET_SERVICES 16710Sstevel@tonic-gate * clear: 16720Sstevel@tonic-gate * {all other flags} 16730Sstevel@tonic-gate * cr->EventMask: 16740Sstevel@tonic-gate * don't care: 16750Sstevel@tonic-gate * {all flags} 16760Sstevel@tonic-gate * 16770Sstevel@tonic-gate * for regular clients: 16780Sstevel@tonic-gate * cr->Attributes: 16790Sstevel@tonic-gate * only one of: 16800Sstevel@tonic-gate * INFO_IO_CLIENT 16810Sstevel@tonic-gate * INFO_MTD_CLIENT 16820Sstevel@tonic-gate * INFO_MEM_CLIENT 16830Sstevel@tonic-gate * don't care: 16840Sstevel@tonic-gate * INFO_CARD_SHARE 16850Sstevel@tonic-gate * INFO_CARD_EXCL 16860Sstevel@tonic-gate * cr->EventMask: 16870Sstevel@tonic-gate * clear: 16880Sstevel@tonic-gate * CS_EVENT_ALL_CLIENTS 16890Sstevel@tonic-gate * don't care: 16900Sstevel@tonic-gate * {all other flags} 16910Sstevel@tonic-gate * 16920Sstevel@tonic-gate * for CSI clients: 16930Sstevel@tonic-gate * cr->Attributes: 16940Sstevel@tonic-gate * set: 16950Sstevel@tonic-gate * INFO_IO_CLIENT 16960Sstevel@tonic-gate * INFO_CSI_CLIENT 16970Sstevel@tonic-gate * clear: 16980Sstevel@tonic-gate * INFO_MTD_CLIENT 16990Sstevel@tonic-gate * INFO_MEM_CLIENT 17000Sstevel@tonic-gate * don't care: 17010Sstevel@tonic-gate * INFO_CARD_SHARE 17020Sstevel@tonic-gate * INFO_CARD_EXCL 17030Sstevel@tonic-gate * cr->EventMask: 17040Sstevel@tonic-gate * don't care: 17050Sstevel@tonic-gate * {all flags} 17060Sstevel@tonic-gate * 17070Sstevel@tonic-gate * for "super-clients": 17080Sstevel@tonic-gate * cr->Attributes: 17090Sstevel@tonic-gate * set: 17100Sstevel@tonic-gate * INFO_IO_CLIENT 17110Sstevel@tonic-gate * INFO_MTD_CLIENT 17120Sstevel@tonic-gate * INFO_SOCKET_SERVICES 17130Sstevel@tonic-gate * INFO_CARD_SHARE 17140Sstevel@tonic-gate * clear: 17150Sstevel@tonic-gate * INFO_MEM_CLIENT 17160Sstevel@tonic-gate * INFO_CARD_EXCL 17170Sstevel@tonic-gate * cr->EventMask: 17180Sstevel@tonic-gate * don't care: 17190Sstevel@tonic-gate * {all flags} 17200Sstevel@tonic-gate */ 17210Sstevel@tonic-gate switch (cr->Attributes & INFO_CLIENT_TYPE_MASK) { 17220Sstevel@tonic-gate /* 17230Sstevel@tonic-gate * Check first to see if this is Socket Services registering; if 17240Sstevel@tonic-gate * so, we don't do anything but return the client handle that is 17250Sstevel@tonic-gate * in the global SS client. 17260Sstevel@tonic-gate */ 17270Sstevel@tonic-gate case INFO_SOCKET_SERVICES: 17280Sstevel@tonic-gate *ch = cs_socket_services_client.client_handle; 17290Sstevel@tonic-gate return (CS_SUCCESS); 17300Sstevel@tonic-gate /* NOTREACHED */ 17310Sstevel@tonic-gate /* CSI clients */ 17320Sstevel@tonic-gate case (INFO_CSI_CLIENT | INFO_IO_CLIENT): 17330Sstevel@tonic-gate break; 17340Sstevel@tonic-gate /* regular clients */ 17350Sstevel@tonic-gate case INFO_IO_CLIENT: 17360Sstevel@tonic-gate case INFO_MTD_CLIENT: 17370Sstevel@tonic-gate case INFO_MEM_CLIENT: 17380Sstevel@tonic-gate if (cr->EventMask & CS_EVENT_ALL_CLIENTS) 17390Sstevel@tonic-gate return (CS_BAD_ATTRIBUTE); 17400Sstevel@tonic-gate break; 17410Sstevel@tonic-gate /* "super-client" clients */ 17420Sstevel@tonic-gate case (INFO_IO_CLIENT | INFO_MTD_CLIENT | INFO_SOCKET_SERVICES): 17430Sstevel@tonic-gate if ((!(cr->Attributes & INFO_CARD_SHARE)) || 17440Sstevel@tonic-gate (cr->Attributes & INFO_CARD_EXCL)) 17450Sstevel@tonic-gate return (CS_BAD_ATTRIBUTE); 17460Sstevel@tonic-gate /* 17470Sstevel@tonic-gate * We only allow one "super-client" per system. 17480Sstevel@tonic-gate */ 17490Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock); 17500Sstevel@tonic-gate if (cs_globals.flags & GLOBAL_SUPER_CLIENT_REGISTERED) { 17510Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock); 17520Sstevel@tonic-gate return (CS_NO_MORE_ITEMS); 17530Sstevel@tonic-gate } 17540Sstevel@tonic-gate cs_globals.flags |= GLOBAL_SUPER_CLIENT_REGISTERED; 17550Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock); 17560Sstevel@tonic-gate super_client = CLIENT_SUPER_CLIENT; 17570Sstevel@tonic-gate break; 17580Sstevel@tonic-gate default: 17590Sstevel@tonic-gate return (CS_BAD_ATTRIBUTE); 17600Sstevel@tonic-gate } /* switch (cr->Attributes) */ 17610Sstevel@tonic-gate 17620Sstevel@tonic-gate /* 17630Sstevel@tonic-gate * Now, actually create the client node on the socket; this will 17640Sstevel@tonic-gate * also return the new client handle if there were no errors 17650Sstevel@tonic-gate * creating the client node. 17660Sstevel@tonic-gate * The DIP2SOCKET_NUM macro will return the socket and function 17670Sstevel@tonic-gate * number using the encoding specified in the cs_priv.h file. 17680Sstevel@tonic-gate */ 17690Sstevel@tonic-gate if (super_client != CLIENT_SUPER_CLIENT) { 17700Sstevel@tonic-gate if (cr->Attributes & INFO_CSI_CLIENT) 17710Sstevel@tonic-gate sn = (uint32_t)(uintptr_t)cr->priv; 17720Sstevel@tonic-gate else 17730Sstevel@tonic-gate sn = DIP2SOCKET_NUM(cr->dip); 17740Sstevel@tonic-gate return (cs_add_client_to_socket(sn, ch, cr, super_client)); 17750Sstevel@tonic-gate } /* CLIENT_SUPER_CLIENT */ 17760Sstevel@tonic-gate 17770Sstevel@tonic-gate /* 17780Sstevel@tonic-gate * This registering client is a "super-client", so we create one 17790Sstevel@tonic-gate * client node for each socket in the system. We use the 17800Sstevel@tonic-gate * client_reg_t.priv structure member to point to a struct 17810Sstevel@tonic-gate * that the "super-client" client knows about. The client 17820Sstevel@tonic-gate * handle pointer is not used in this case. 17830Sstevel@tonic-gate * We return CS_SUCCESS if at least one client node could be 17840Sstevel@tonic-gate * created. The client must check the error codes in the 17850Sstevel@tonic-gate * error code array to determine which clients could not 17860Sstevel@tonic-gate * be created on which sockets. 17870Sstevel@tonic-gate * We return CS_BAD_HANDLE if no client nodes could be created. 17880Sstevel@tonic-gate */ 17890Sstevel@tonic-gate scr->num_clients = 0; 17900Sstevel@tonic-gate scr->max_socket_num = cs_globals.max_socket_num; 17910Sstevel@tonic-gate scr->num_sockets = cs_globals.num_sockets; 17920Sstevel@tonic-gate scr->num_windows = cs_globals.num_windows; 17930Sstevel@tonic-gate 17940Sstevel@tonic-gate *(scr->sclient_list) = cs_globals.sclient_list; 17950Sstevel@tonic-gate 17960Sstevel@tonic-gate for (sn = 0; sn < scr->num_sockets; sn++) { 17970Sstevel@tonic-gate scli = scr->sclient_list[sn]; 17980Sstevel@tonic-gate if ((scli->error = cs_add_client_to_socket(sn, &scli->client_handle, 17990Sstevel@tonic-gate cr, super_client)) == CS_SUCCESS) { 18000Sstevel@tonic-gate scr->num_clients++; 18010Sstevel@tonic-gate } 18020Sstevel@tonic-gate } 18030Sstevel@tonic-gate 18040Sstevel@tonic-gate /* 18050Sstevel@tonic-gate * If we couldn't create any client nodes at all, then 18060Sstevel@tonic-gate * return an error. 18070Sstevel@tonic-gate */ 18080Sstevel@tonic-gate if (!scr->num_clients) { 18090Sstevel@tonic-gate /* 18100Sstevel@tonic-gate * XXX - The global superclient lock now gets 18110Sstevel@tonic-gate * cleared in cs_deregister_client 18120Sstevel@tonic-gate */ 18130Sstevel@tonic-gate /* cs_clear_superclient_lock(super_client); */ 18140Sstevel@tonic-gate return (CS_BAD_HANDLE); 18150Sstevel@tonic-gate } 18160Sstevel@tonic-gate 18170Sstevel@tonic-gate return (CS_SUCCESS); 18180Sstevel@tonic-gate } 18190Sstevel@tonic-gate 18200Sstevel@tonic-gate /* 18210Sstevel@tonic-gate * cs_add_client_to_socket - this function creates the client node on the 18220Sstevel@tonic-gate * requested socket. 18230Sstevel@tonic-gate * 18240Sstevel@tonic-gate * Note that if we return an error, there is no state that can be cleaned 18250Sstevel@tonic-gate * up. The only way that we can return an error with allocated resources 18260Sstevel@tonic-gate * would be if one of the client handle functions had an internal error. 18270Sstevel@tonic-gate * Since we wouldn't get a valid client handle in this case anyway, there 18280Sstevel@tonic-gate * would be no way to find out what was allocated and what wasn't. 18290Sstevel@tonic-gate */ 18300Sstevel@tonic-gate static int 18310Sstevel@tonic-gate cs_add_client_to_socket(unsigned sn, client_handle_t *ch, 18320Sstevel@tonic-gate client_reg_t *cr, int super_client) 18330Sstevel@tonic-gate { 18340Sstevel@tonic-gate cs_socket_t *sp; 18350Sstevel@tonic-gate client_t *client, *cclp; 18360Sstevel@tonic-gate int error, cie = 1; 18370Sstevel@tonic-gate int client_lock_acquired; 18380Sstevel@tonic-gate 18390Sstevel@tonic-gate if (cr->event_handler == NULL) 18400Sstevel@tonic-gate return (CS_BAD_ARGS); 18410Sstevel@tonic-gate 18420Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) == NULL) 18430Sstevel@tonic-gate return (CS_BAD_SOCKET); 18440Sstevel@tonic-gate 18450Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 18460Sstevel@tonic-gate 18470Sstevel@tonic-gate /* 18480Sstevel@tonic-gate * Run through all of the registered clients and compare the passed 18490Sstevel@tonic-gate * dip to the dip of each client to make sure that this client 18500Sstevel@tonic-gate * is not trying to register more than once. If they are, then 18510Sstevel@tonic-gate * display a message and return an error. 18520Sstevel@tonic-gate * XXX - we should really check all the sockets in case the client 18530Sstevel@tonic-gate * manipulates the instance number in the dip. 18540Sstevel@tonic-gate * XXX - if we check each socket, we ned to also check for the 18550Sstevel@tonic-gate * "super-client" since it will use the same dip for all 18560Sstevel@tonic-gate * of it's client nodes. 18570Sstevel@tonic-gate */ 18580Sstevel@tonic-gate mutex_enter(&sp->lock); 18590Sstevel@tonic-gate client = sp->client_list; 18600Sstevel@tonic-gate while (client) { 18610Sstevel@tonic-gate if (!(cr->Attributes & INFO_CSI_CLIENT) && 18620Sstevel@tonic-gate (client->dip == cr->dip)) { 18630Sstevel@tonic-gate mutex_exit(&sp->lock); 18640Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 18650Sstevel@tonic-gate cmn_err(CE_CONT, "cs_add_client_to_socket: socket %d " 18660Sstevel@tonic-gate "function 0x%x\n" 18670Sstevel@tonic-gate "\tclient already registered with " 18680Sstevel@tonic-gate "handle 0x%x\n", 18690Sstevel@tonic-gate (int)CS_GET_SOCKET_NUMBER(sn), 18700Sstevel@tonic-gate (int)CS_GET_FUNCTION_NUMBER(sn), 18710Sstevel@tonic-gate (int)client->client_handle); 18720Sstevel@tonic-gate return (CS_BAD_HANDLE); 18730Sstevel@tonic-gate } 18740Sstevel@tonic-gate client = client->next; 18750Sstevel@tonic-gate } /* while (client) */ 18760Sstevel@tonic-gate mutex_exit(&sp->lock); 18770Sstevel@tonic-gate 18780Sstevel@tonic-gate /* 18790Sstevel@tonic-gate * Create a unique client handle then make sure that we can find it. 18800Sstevel@tonic-gate * This has the side effect of getting us a pointer to the 18810Sstevel@tonic-gate * client structure as well. 18820Sstevel@tonic-gate * Create a client list entry - cs_create_client_handle will use this 18830Sstevel@tonic-gate * as the new client node. 18840Sstevel@tonic-gate * We do it here so that we can grab the sp->lock mutex for the 18850Sstevel@tonic-gate * duration of our manipulation of the client list. 18860Sstevel@tonic-gate * If this function fails, then it will not have added the newly 18870Sstevel@tonic-gate * allocated client node to the client list on this socket, 18880Sstevel@tonic-gate * so we have to free the node that we allocated. 18890Sstevel@tonic-gate */ 18900Sstevel@tonic-gate cclp = (client_t *)kmem_zalloc(sizeof (client_t), KM_SLEEP); 18910Sstevel@tonic-gate 18920Sstevel@tonic-gate mutex_enter(&sp->lock); 18930Sstevel@tonic-gate if (!(*ch = cs_create_client_handle(sn, cclp))) { 18940Sstevel@tonic-gate mutex_exit(&sp->lock); 18950Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 18960Sstevel@tonic-gate kmem_free(cclp, sizeof (client_t)); 18970Sstevel@tonic-gate return (CS_OUT_OF_RESOURCE); 18980Sstevel@tonic-gate } 18990Sstevel@tonic-gate 19000Sstevel@tonic-gate /* 19010Sstevel@tonic-gate * Make sure that this is a valid client handle. We should never 19020Sstevel@tonic-gate * fail this since we just got a valid client handle. 19030Sstevel@tonic-gate * If this fails, then we have an internal error so don't bother 19040Sstevel@tonic-gate * trying to clean up the allocated client handle since the 19050Sstevel@tonic-gate * whole system is probably hosed anyway and will shortly 19060Sstevel@tonic-gate * esplode. 19070Sstevel@tonic-gate * It doesn't make sense to call cs_deregister_client at this point 19080Sstevel@tonic-gate * to clean up this broken client since the deregistration 19090Sstevel@tonic-gate * code will also call cs_find_client and most likely fail. 19100Sstevel@tonic-gate */ 19110Sstevel@tonic-gate if (!(client = cs_find_client(*ch, &error))) { 19120Sstevel@tonic-gate mutex_exit(&sp->lock); 19130Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 19140Sstevel@tonic-gate cmn_err(CE_CONT, "cs_add_client_to_socket: socket %d function 0x%x " 19150Sstevel@tonic-gate "invalid client handle created handle 0x%x\n", 19160Sstevel@tonic-gate (int)CS_GET_SOCKET_NUMBER(sn), 19170Sstevel@tonic-gate (int)CS_GET_FUNCTION_NUMBER(sn), 19180Sstevel@tonic-gate (int)*ch); 19190Sstevel@tonic-gate return (error); 19200Sstevel@tonic-gate } 19210Sstevel@tonic-gate 19220Sstevel@tonic-gate /* 19230Sstevel@tonic-gate * Save the DDI information. 19240Sstevel@tonic-gate */ 19250Sstevel@tonic-gate client->dip = cr->dip; 19260Sstevel@tonic-gate cr->driver_name[MODMAXNAMELEN - 1] = NULL; 19270Sstevel@tonic-gate client->driver_name = (char *)kmem_zalloc(strlen(cr->driver_name) + 1, 19280Sstevel@tonic-gate KM_SLEEP); 19290Sstevel@tonic-gate (void) strcpy(client->driver_name, cr->driver_name); 19300Sstevel@tonic-gate client->instance = ddi_get_instance(cr->dip); 19310Sstevel@tonic-gate 19320Sstevel@tonic-gate /* 19330Sstevel@tonic-gate * Copy over the interesting items that the client gave us. 19340Sstevel@tonic-gate */ 19350Sstevel@tonic-gate client->flags = (cr->Attributes & INFO_CLIENT_TYPE_MASK); 19360Sstevel@tonic-gate client->event_callback_handler = cr->event_handler; 19370Sstevel@tonic-gate bcopy((caddr_t)&cr->event_callback_args, 19380Sstevel@tonic-gate (caddr_t)&client->event_callback_args, 19390Sstevel@tonic-gate sizeof (event_callback_args_t)); 19400Sstevel@tonic-gate /* 19410Sstevel@tonic-gate * Set the client handle since the client needs a client handle 19420Sstevel@tonic-gate * when they call us for their event handler. 19430Sstevel@tonic-gate */ 19440Sstevel@tonic-gate client->event_callback_args.client_handle = *ch; 19450Sstevel@tonic-gate 19460Sstevel@tonic-gate /* 19470Sstevel@tonic-gate * Initialize the IO window numbers; if an IO window number is equal 19480Sstevel@tonic-gate * to PCMCIA_MAX_WINDOWS it means that IO range is not in use. 19490Sstevel@tonic-gate */ 19500Sstevel@tonic-gate client->io_alloc.Window1 = PCMCIA_MAX_WINDOWS; 19510Sstevel@tonic-gate client->io_alloc.Window2 = PCMCIA_MAX_WINDOWS; 19520Sstevel@tonic-gate 19530Sstevel@tonic-gate /* 19540Sstevel@tonic-gate * Give the client the iblock and idevice cookies to use in 19550Sstevel@tonic-gate * the client's event handler high priority mutex. 19560Sstevel@tonic-gate */ 19570Sstevel@tonic-gate cr->iblk_cookie = sp->iblk; 19580Sstevel@tonic-gate cr->idev_cookie = sp->idev; 19590Sstevel@tonic-gate 19600Sstevel@tonic-gate /* 19610Sstevel@tonic-gate * Set up the global event mask information; we copy this directly 19620Sstevel@tonic-gate * from the client; since we are the only source of events, 19630Sstevel@tonic-gate * any bogus bits that the client puts in here won't matter 19640Sstevel@tonic-gate * because we'll never look at them. 19650Sstevel@tonic-gate */ 19660Sstevel@tonic-gate client->global_mask = cr->EventMask; 19670Sstevel@tonic-gate 19680Sstevel@tonic-gate /* 19690Sstevel@tonic-gate * If this client registered as a CSI client, set the appropriate 19700Sstevel@tonic-gate * flag in the client's flags area. 19710Sstevel@tonic-gate */ 19720Sstevel@tonic-gate if (cr->Attributes & INFO_CSI_CLIENT) 19730Sstevel@tonic-gate client->flags |= CLIENT_CSI_CLIENT; 19740Sstevel@tonic-gate 19750Sstevel@tonic-gate /* 19760Sstevel@tonic-gate * If this client registered as a "super-client" set the appropriate 19770Sstevel@tonic-gate * flag in the client's flags area. 19780Sstevel@tonic-gate */ 19790Sstevel@tonic-gate if (super_client == CLIENT_SUPER_CLIENT) 19800Sstevel@tonic-gate client->flags |= CLIENT_SUPER_CLIENT; 19810Sstevel@tonic-gate 19820Sstevel@tonic-gate /* 19830Sstevel@tonic-gate * Save other misc information that this client gave us - it is 19840Sstevel@tonic-gate * used in the GetClientInfo function. 19850Sstevel@tonic-gate */ 19860Sstevel@tonic-gate client->flags |= (cr->Attributes & INFO_CARD_FLAGS_MASK); 19870Sstevel@tonic-gate 19880Sstevel@tonic-gate /* 19890Sstevel@tonic-gate * Determine if we should give artificial card insertion events and 19900Sstevel@tonic-gate * a registration complete event. Since we don't differentiate 19910Sstevel@tonic-gate * between sharable and exclusive use cards when giving clients 19920Sstevel@tonic-gate * event notification, we modify the definition of the share/excl 19930Sstevel@tonic-gate * flags as follows: 19940Sstevel@tonic-gate * 19950Sstevel@tonic-gate * If either INFO_CARD_SHARE or INFO_CARD_EXCL is set, 19960Sstevel@tonic-gate * the client will receive artificial card insertion 19970Sstevel@tonic-gate * events (if the client's card is currently in the 19980Sstevel@tonic-gate * socket) and a registration complete event. 19990Sstevel@tonic-gate * 20000Sstevel@tonic-gate * If neither of the INFO_CARD_SHARE or INFO_CARD_EXCL is 20010Sstevel@tonic-gate * set, the client will not receive an artificial card 20020Sstevel@tonic-gate * insertion event nor a registration complete event 20030Sstevel@tonic-gate * due to the client's call to register client. 20040Sstevel@tonic-gate * 20050Sstevel@tonic-gate * The client's event mask is not affected by the setting 20060Sstevel@tonic-gate * of these two bits. 20070Sstevel@tonic-gate */ 20080Sstevel@tonic-gate if (cr->Attributes & (INFO_CARD_SHARE | INFO_CARD_EXCL)) 20090Sstevel@tonic-gate client->pending_events = CS_EVENT_REGISTRATION_COMPLETE; 20100Sstevel@tonic-gate 20110Sstevel@tonic-gate /* 20120Sstevel@tonic-gate * Check to see if the card for this client is currently in 20130Sstevel@tonic-gate * the socket. If it is, then set CLIENT_CARD_INSERTED 20140Sstevel@tonic-gate * since clients that are calling GetStatus at attach 20150Sstevel@tonic-gate * time will typically check to see if their card is 20160Sstevel@tonic-gate * currently installed. 20170Sstevel@tonic-gate * If this is the CSI client, we also need to check to see 20180Sstevel@tonic-gate * if there is any card inserted in the socket, since 20190Sstevel@tonic-gate * the cs_card_for_client function will always return 20200Sstevel@tonic-gate * TRUE for a CSI client. 20210Sstevel@tonic-gate * XXX What about super-clients? 20220Sstevel@tonic-gate */ 20230Sstevel@tonic-gate if (client->flags & CLIENT_CSI_CLIENT) { 20240Sstevel@tonic-gate get_ss_status_t get_ss_status; 20250Sstevel@tonic-gate 20260Sstevel@tonic-gate get_ss_status.socket = sp->socket_num; 20270Sstevel@tonic-gate 20280Sstevel@tonic-gate if (SocketServices(SS_GetStatus, &get_ss_status) != SUCCESS) { 20290Sstevel@tonic-gate mutex_exit(&sp->lock); 20300Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 20310Sstevel@tonic-gate return (CS_BAD_SOCKET); 20320Sstevel@tonic-gate } /* SS_GetStatus */ 20330Sstevel@tonic-gate 20340Sstevel@tonic-gate if (!(cs_sbm2cse(get_ss_status.CardState) & 20350Sstevel@tonic-gate CS_EVENT_CARD_INSERTION)) 20360Sstevel@tonic-gate cie = 0; 20370Sstevel@tonic-gate 20380Sstevel@tonic-gate } /* CLIENT_CSI_CLIENT */ 20390Sstevel@tonic-gate 20400Sstevel@tonic-gate if (cs_card_for_client(client) && (cie != 0)) { 20410Sstevel@tonic-gate client->pending_events |= CS_EVENT_CARD_INSERTION; 20420Sstevel@tonic-gate client->flags |= CLIENT_CARD_INSERTED; 20430Sstevel@tonic-gate } /* cs_card_for_client */ 20440Sstevel@tonic-gate 20450Sstevel@tonic-gate sp->num_clients++; 20460Sstevel@tonic-gate mutex_exit(&sp->lock); 20470Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 20480Sstevel@tonic-gate 20490Sstevel@tonic-gate return (CS_SUCCESS); 20500Sstevel@tonic-gate } 20510Sstevel@tonic-gate 20520Sstevel@tonic-gate /* 20530Sstevel@tonic-gate * cs_deregister_client - This supports the DeregisterClient call. 20540Sstevel@tonic-gate */ 20550Sstevel@tonic-gate static int 20560Sstevel@tonic-gate cs_deregister_client(client_handle_t client_handle) 20570Sstevel@tonic-gate { 20580Sstevel@tonic-gate cs_socket_t *sp; 20590Sstevel@tonic-gate client_t *client; 20600Sstevel@tonic-gate int error, super_client = 0; 20610Sstevel@tonic-gate int client_lock_acquired; 20620Sstevel@tonic-gate 20630Sstevel@tonic-gate /* 20640Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it 20650Sstevel@tonic-gate * is, we don't do anything except for return success. 20660Sstevel@tonic-gate */ 20670Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) 20680Sstevel@tonic-gate return (CS_SUCCESS); 20690Sstevel@tonic-gate 20700Sstevel@tonic-gate /* 20710Sstevel@tonic-gate * Get a pointer to this client's socket structure. 20720Sstevel@tonic-gate */ 20730Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) 20740Sstevel@tonic-gate return (CS_BAD_SOCKET); 20750Sstevel@tonic-gate 20760Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 20770Sstevel@tonic-gate 20780Sstevel@tonic-gate /* 20790Sstevel@tonic-gate * Make sure that this is a valid client handle. 20800Sstevel@tonic-gate */ 20810Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) { 20820Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 20830Sstevel@tonic-gate return (error); 20840Sstevel@tonic-gate } 20850Sstevel@tonic-gate 20860Sstevel@tonic-gate /* 20870Sstevel@tonic-gate * Make sure that any resources allocated by this client are 20880Sstevel@tonic-gate * not still allocated, and that if this is an MTD that 20890Sstevel@tonic-gate * no MTD operations are still in progress. 20900Sstevel@tonic-gate */ 20910Sstevel@tonic-gate if (client->flags & (CLIENT_IO_ALLOCATED | 20920Sstevel@tonic-gate CLIENT_IRQ_ALLOCATED | 20930Sstevel@tonic-gate CLIENT_WIN_ALLOCATED | 20940Sstevel@tonic-gate REQ_CONFIGURATION_DONE | 20950Sstevel@tonic-gate REQ_SOCKET_MASK_DONE | 20960Sstevel@tonic-gate REQ_IO_DONE | 20970Sstevel@tonic-gate REQ_IRQ_DONE)) { 20980Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 20990Sstevel@tonic-gate return (CS_BUSY); 21000Sstevel@tonic-gate } 21010Sstevel@tonic-gate 21020Sstevel@tonic-gate if (client->flags & CLIENT_MTD_IN_PROGRESS) { 21030Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 21040Sstevel@tonic-gate return (CS_IN_USE); 21050Sstevel@tonic-gate } 21060Sstevel@tonic-gate 21070Sstevel@tonic-gate /* 21080Sstevel@tonic-gate * Any previously allocated resources are not allocated anymore, and 21090Sstevel@tonic-gate * no MTD operations are in progress, so if this is an MTD client 21100Sstevel@tonic-gate * then do any MTD-specific client deregistration, and then 21110Sstevel@tonic-gate * nuke this client. 21120Sstevel@tonic-gate * We expect cs_deregister_mtd to never fail. 21130Sstevel@tonic-gate */ 21140Sstevel@tonic-gate if (client->flags & INFO_MTD_CLIENT) 21150Sstevel@tonic-gate (void) cs_deregister_mtd(client_handle); 21160Sstevel@tonic-gate 21170Sstevel@tonic-gate if (client->flags & CLIENT_SUPER_CLIENT) 21180Sstevel@tonic-gate super_client = CLIENT_SUPER_CLIENT; 21190Sstevel@tonic-gate 21200Sstevel@tonic-gate kmem_free(client->driver_name, strlen(client->driver_name) + 1); 21210Sstevel@tonic-gate 21220Sstevel@tonic-gate error = cs_destroy_client_handle(client_handle); 21230Sstevel@tonic-gate 21240Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 21250Sstevel@tonic-gate 21260Sstevel@tonic-gate /* 21270Sstevel@tonic-gate * If this was the "super-client" deregistering, then this 21280Sstevel@tonic-gate * will clear the global "super-client" lock. 21290Sstevel@tonic-gate * XXX - move this outside the per-socket code. 21300Sstevel@tonic-gate */ 21310Sstevel@tonic-gate cs_clear_superclient_lock(super_client); 21320Sstevel@tonic-gate 21330Sstevel@tonic-gate return (error); 21340Sstevel@tonic-gate } 21350Sstevel@tonic-gate 21360Sstevel@tonic-gate /* 21370Sstevel@tonic-gate * cs_create_next_client_minor - returns the next available client minor 21380Sstevel@tonic-gate * number or 0 if none available 21390Sstevel@tonic-gate * 21400Sstevel@tonic-gate * Note that cs_find_client will always return a valid pointer to the 21410Sstevel@tonic-gate * global Socket Services client which has a client minor number 21420Sstevel@tonic-gate * of 0; this means that this function can never return a 0 as the 21430Sstevel@tonic-gate * next valid available client minor number. 21440Sstevel@tonic-gate */ 21450Sstevel@tonic-gate unsigned 21460Sstevel@tonic-gate cs_create_next_client_minor(unsigned socket_num, unsigned next_minor) 21470Sstevel@tonic-gate { 21480Sstevel@tonic-gate unsigned max_client_handles = cs_max_client_handles; 21490Sstevel@tonic-gate 21500Sstevel@tonic-gate do { 21510Sstevel@tonic-gate next_minor &= CS_MAX_CLIENTS_MASK; 21520Sstevel@tonic-gate if (!cs_find_client(MAKE_CLIENT_HANDLE( 21530Sstevel@tonic-gate CS_GET_SOCKET_NUMBER(socket_num), 21540Sstevel@tonic-gate CS_GET_FUNCTION_NUMBER(socket_num), 21550Sstevel@tonic-gate next_minor), NULL)) { 21560Sstevel@tonic-gate return (next_minor); 21570Sstevel@tonic-gate } 21580Sstevel@tonic-gate next_minor++; 21590Sstevel@tonic-gate } while (max_client_handles--); 21600Sstevel@tonic-gate 21610Sstevel@tonic-gate return (0); 21620Sstevel@tonic-gate } 21630Sstevel@tonic-gate 21640Sstevel@tonic-gate /* 21650Sstevel@tonic-gate * cs_find_client - finds the client pointer associated with the client handle 21660Sstevel@tonic-gate * or NULL if client not found 21670Sstevel@tonic-gate * 21680Sstevel@tonic-gate * returns: (client_t *)NULL - if client not found or an error occured 21690Sstevel@tonic-gate * If the error argument is not NULL, 21700Sstevel@tonic-gate * it is set to: 21710Sstevel@tonic-gate * CS_BAD_SOCKET - socket number in client_handle_t is 21720Sstevel@tonic-gate * invalid 21730Sstevel@tonic-gate * CS_BAD_HANDLE - client not found 21740Sstevel@tonic-gate * If no error, the error argument is not modified. 21750Sstevel@tonic-gate * (client_t *) - pointer to client_t structure 21760Sstevel@tonic-gate * 21770Sstevel@tonic-gate * Note that each socket always has a pseudo client with a client minor number 21780Sstevel@tonic-gate * of 0; this client minor number is used for Socket Services access to 21790Sstevel@tonic-gate * Card Services functions. The client pointer returned for client minor 21800Sstevel@tonic-gate * number 0 is the global Socket Services client pointer. 21810Sstevel@tonic-gate */ 21820Sstevel@tonic-gate static client_t * 21830Sstevel@tonic-gate cs_find_client(client_handle_t client_handle, int *error) 21840Sstevel@tonic-gate { 21850Sstevel@tonic-gate cs_socket_t *sp; 21860Sstevel@tonic-gate client_t *clp; 21870Sstevel@tonic-gate 21880Sstevel@tonic-gate /* 21890Sstevel@tonic-gate * If we are being asked to see if a client with a minor number 21900Sstevel@tonic-gate * of 0 exists, always return a pointer to the global Socket 21910Sstevel@tonic-gate * Services client, since this client always exists, and is 21920Sstevel@tonic-gate * only for use by Socket Services. There is no socket 21930Sstevel@tonic-gate * associated with this special client handle. 21940Sstevel@tonic-gate */ 21950Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) 21960Sstevel@tonic-gate return (&cs_socket_services_client); 21970Sstevel@tonic-gate 21980Sstevel@tonic-gate /* 21990Sstevel@tonic-gate * Check to be sure that the socket number is in range 22000Sstevel@tonic-gate */ 22010Sstevel@tonic-gate if (!(CHECK_SOCKET_NUM(GET_CLIENT_SOCKET(client_handle), 22020Sstevel@tonic-gate cs_globals.max_socket_num))) { 22030Sstevel@tonic-gate if (error) 22040Sstevel@tonic-gate *error = CS_BAD_SOCKET; 22050Sstevel@tonic-gate return (NULL); 22060Sstevel@tonic-gate } 22070Sstevel@tonic-gate 22080Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) { 22090Sstevel@tonic-gate if (error) 22100Sstevel@tonic-gate *error = CS_BAD_SOCKET; 22110Sstevel@tonic-gate return (NULL); 22120Sstevel@tonic-gate } 22130Sstevel@tonic-gate 22140Sstevel@tonic-gate clp = sp->client_list; 22150Sstevel@tonic-gate 22160Sstevel@tonic-gate while (clp) { 22170Sstevel@tonic-gate if (clp->client_handle == client_handle) 22180Sstevel@tonic-gate return (clp); 22190Sstevel@tonic-gate clp = clp->next; 22200Sstevel@tonic-gate } 22210Sstevel@tonic-gate 22220Sstevel@tonic-gate if (error) 22230Sstevel@tonic-gate *error = CS_BAD_HANDLE; 22240Sstevel@tonic-gate 22250Sstevel@tonic-gate return (NULL); 22260Sstevel@tonic-gate } 22270Sstevel@tonic-gate 22280Sstevel@tonic-gate /* 22290Sstevel@tonic-gate * cs_destroy_client_handle - destroys client handle and client structure of 22300Sstevel@tonic-gate * passed client handle 22310Sstevel@tonic-gate * 22320Sstevel@tonic-gate * returns: CS_SUCCESS - if client handle sucessfully destroyed 22330Sstevel@tonic-gate * CS_BAD_HANDLE - if client handle is invalid or if trying 22340Sstevel@tonic-gate * to destroy global SS client 22350Sstevel@tonic-gate * {other errors} - other errors from cs_find_client() 22360Sstevel@tonic-gate */ 22370Sstevel@tonic-gate static int 22380Sstevel@tonic-gate cs_destroy_client_handle(client_handle_t client_handle) 22390Sstevel@tonic-gate { 22400Sstevel@tonic-gate client_t *clp; 22410Sstevel@tonic-gate cs_socket_t *sp; 22420Sstevel@tonic-gate int error = CS_BAD_HANDLE; 22430Sstevel@tonic-gate 22440Sstevel@tonic-gate /* 22450Sstevel@tonic-gate * See if we were passed a valid client handle or if we're being asked 22460Sstevel@tonic-gate * to destroy the Socket Services client 22470Sstevel@tonic-gate */ 22480Sstevel@tonic-gate if ((!(clp = cs_find_client(client_handle, &error))) || 22490Sstevel@tonic-gate (CLIENT_HANDLE_IS_SS(client_handle))) 22500Sstevel@tonic-gate return (error); 22510Sstevel@tonic-gate 22520Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) 22530Sstevel@tonic-gate return (CS_BAD_SOCKET); 22540Sstevel@tonic-gate 22550Sstevel@tonic-gate /* 22560Sstevel@tonic-gate * Recycle this client's minor number. This will most likely 22570Sstevel@tonic-gate * be the next client minor number we use, but it is also 22580Sstevel@tonic-gate * a hint to cs_create_client_handle, and that function 22590Sstevel@tonic-gate * may actually create a new client handle using a minor 22600Sstevel@tonic-gate * number different that this number. 22610Sstevel@tonic-gate */ 22620Sstevel@tonic-gate mutex_enter(&sp->lock); 22630Sstevel@tonic-gate sp->next_cl_minor = GET_CLIENT_MINOR(client_handle); 22640Sstevel@tonic-gate 22650Sstevel@tonic-gate /* 22660Sstevel@tonic-gate * See if we're the first or not in the client list; if we're 22670Sstevel@tonic-gate * not first, then just adjust the client behind us to 22680Sstevel@tonic-gate * point to the client ahead of us; this could be NULL 22690Sstevel@tonic-gate * if we're the last client in the list. 22700Sstevel@tonic-gate */ 22710Sstevel@tonic-gate if (clp->prev) { 22720Sstevel@tonic-gate clp->prev->next = clp->next; 22730Sstevel@tonic-gate } else { 22740Sstevel@tonic-gate /* 22750Sstevel@tonic-gate * We are first, so adjust the client list head pointer 22760Sstevel@tonic-gate * in the socket to point to the client structure that 22770Sstevel@tonic-gate * follows us; this could turn out to be NULL if we're 22780Sstevel@tonic-gate * the only client on this socket. 22790Sstevel@tonic-gate */ 22800Sstevel@tonic-gate sp->client_list = clp->next; 22810Sstevel@tonic-gate } 22820Sstevel@tonic-gate 22830Sstevel@tonic-gate /* 22840Sstevel@tonic-gate * If we're not the last client in the list, point the next 22850Sstevel@tonic-gate * client to the client behind us; this could turn out 22860Sstevel@tonic-gate * to be NULL if we're the first client on this socket. 22870Sstevel@tonic-gate */ 22880Sstevel@tonic-gate if (clp->next) 22890Sstevel@tonic-gate clp->next->prev = clp->prev; 22900Sstevel@tonic-gate 22910Sstevel@tonic-gate sp->num_clients--; 22920Sstevel@tonic-gate mutex_exit(&sp->lock); 22930Sstevel@tonic-gate 22940Sstevel@tonic-gate /* 22950Sstevel@tonic-gate * Free this client's memory. 22960Sstevel@tonic-gate */ 22970Sstevel@tonic-gate kmem_free(clp, sizeof (client_t)); 22980Sstevel@tonic-gate 22990Sstevel@tonic-gate return (CS_SUCCESS); 23000Sstevel@tonic-gate } 23010Sstevel@tonic-gate 23020Sstevel@tonic-gate /* 23030Sstevel@tonic-gate * cs_create_client_handle - create a new client handle for the passed 23040Sstevel@tonic-gate * socket and function number 23050Sstevel@tonic-gate * 23060Sstevel@tonic-gate * returns: 0 - if can't create client for some reason 23070Sstevel@tonic-gate * client_handle_t - new client handle 23080Sstevel@tonic-gate */ 23090Sstevel@tonic-gate static client_handle_t 23100Sstevel@tonic-gate cs_create_client_handle(unsigned socket_num, client_t *cclp) 23110Sstevel@tonic-gate { 23120Sstevel@tonic-gate client_t *clp; 23130Sstevel@tonic-gate cs_socket_t *sp; 23140Sstevel@tonic-gate unsigned next_minor; 23150Sstevel@tonic-gate client_handle_t client_handle; 23160Sstevel@tonic-gate 23170Sstevel@tonic-gate if ((sp = cs_get_sp(socket_num)) == NULL) 23180Sstevel@tonic-gate return (0); 23190Sstevel@tonic-gate 23200Sstevel@tonic-gate /* 23210Sstevel@tonic-gate * Get the next available minor number that we can use. We use the 23220Sstevel@tonic-gate * next_cl_minor number as a hint to cs_create_next_client_minor 23230Sstevel@tonic-gate * and in most cases this will be the minor number we get back. 23240Sstevel@tonic-gate * If for some reason we can't get a minor number, return an error. 23250Sstevel@tonic-gate * The only way we could get an error would be if there are 23260Sstevel@tonic-gate * already the maximum number of clients for this socket. Since 23270Sstevel@tonic-gate * the maximum number of clients per socket is pretty large, 23280Sstevel@tonic-gate * this error is unlikely to occur. 23290Sstevel@tonic-gate */ 23300Sstevel@tonic-gate if (!(next_minor = 23310Sstevel@tonic-gate cs_create_next_client_minor(socket_num, sp->next_cl_minor))) 23320Sstevel@tonic-gate return (0); 23330Sstevel@tonic-gate 23340Sstevel@tonic-gate /* 23350Sstevel@tonic-gate * Got a new client minor number, now create a new client handle. 23360Sstevel@tonic-gate */ 23370Sstevel@tonic-gate client_handle = MAKE_CLIENT_HANDLE(CS_GET_SOCKET_NUMBER(socket_num), 23380Sstevel@tonic-gate CS_GET_FUNCTION_NUMBER(socket_num), 23390Sstevel@tonic-gate next_minor); 23400Sstevel@tonic-gate 23410Sstevel@tonic-gate /* 23420Sstevel@tonic-gate * If this client handle exists, then we have an internal 23430Sstevel@tonic-gate * error; this should never happen, BTW. This is really 23440Sstevel@tonic-gate * a double-check on the cs_create_next_client_minor 23450Sstevel@tonic-gate * function, which also calls cs_find_client. 23460Sstevel@tonic-gate */ 23470Sstevel@tonic-gate if (cs_find_client(client_handle, NULL)) { 23480Sstevel@tonic-gate cmn_err(CE_CONT, 23490Sstevel@tonic-gate "cs_create_client_handle: duplicate client handle 0x%x\n", 23500Sstevel@tonic-gate (int)client_handle); 23510Sstevel@tonic-gate return (0); 23520Sstevel@tonic-gate } 23530Sstevel@tonic-gate 23540Sstevel@tonic-gate /* 23550Sstevel@tonic-gate * If we don't have any clients on this socket yet, create 23560Sstevel@tonic-gate * a new client and hang it on the socket client list. 23570Sstevel@tonic-gate */ 23580Sstevel@tonic-gate if (!sp->client_list) { 23590Sstevel@tonic-gate sp->client_list = cclp; 23600Sstevel@tonic-gate clp = sp->client_list; 23610Sstevel@tonic-gate } else { 23620Sstevel@tonic-gate /* 23630Sstevel@tonic-gate * There are other clients on this socket, so look for 23640Sstevel@tonic-gate * the last client and add our new client after it. 23650Sstevel@tonic-gate */ 23660Sstevel@tonic-gate clp = sp->client_list; 23670Sstevel@tonic-gate while (clp->next) { 23680Sstevel@tonic-gate clp = clp->next; 23690Sstevel@tonic-gate } 23700Sstevel@tonic-gate 23710Sstevel@tonic-gate clp->next = cclp; 23720Sstevel@tonic-gate clp->next->prev = clp; 23730Sstevel@tonic-gate clp = clp->next; 23740Sstevel@tonic-gate } /* if (!sp->client_list) */ 23750Sstevel@tonic-gate 23760Sstevel@tonic-gate /* 23770Sstevel@tonic-gate * Assign the new client handle to this new client structure. 23780Sstevel@tonic-gate */ 23790Sstevel@tonic-gate clp->client_handle = client_handle; 23800Sstevel@tonic-gate 23810Sstevel@tonic-gate /* 23820Sstevel@tonic-gate * Create the next available client minor number for this socket 23830Sstevel@tonic-gate * and save it away. 23840Sstevel@tonic-gate */ 23850Sstevel@tonic-gate sp->next_cl_minor = 23860Sstevel@tonic-gate cs_create_next_client_minor(socket_num, sp->next_cl_minor); 23870Sstevel@tonic-gate 23880Sstevel@tonic-gate return (client_handle); 23890Sstevel@tonic-gate } 23900Sstevel@tonic-gate 23910Sstevel@tonic-gate /* 23920Sstevel@tonic-gate * cs_clear_superclient_lock - clears the global "super-client" lock 23930Sstevel@tonic-gate * 23940Sstevel@tonic-gate * Note: this function uses the cs_globals.global_lock so observe proper 23950Sstevel@tonic-gate * nexting of locks!! 23960Sstevel@tonic-gate */ 23970Sstevel@tonic-gate static void 23980Sstevel@tonic-gate cs_clear_superclient_lock(int super_client) 23990Sstevel@tonic-gate { 24000Sstevel@tonic-gate 24010Sstevel@tonic-gate /* 24020Sstevel@tonic-gate * If this was a "super-client" registering then we need 24030Sstevel@tonic-gate * to clear the GLOBAL_SUPER_CLIENT_REGISTERED flag 24040Sstevel@tonic-gate * so that other "super-clients" can register. 24050Sstevel@tonic-gate */ 24060Sstevel@tonic-gate if (super_client == CLIENT_SUPER_CLIENT) { 24070Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock); 24080Sstevel@tonic-gate cs_globals.flags &= ~GLOBAL_SUPER_CLIENT_REGISTERED; 24090Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock); 24100Sstevel@tonic-gate } 24110Sstevel@tonic-gate } 24120Sstevel@tonic-gate 24130Sstevel@tonic-gate /* 24140Sstevel@tonic-gate * ==== event handling section ==== 24150Sstevel@tonic-gate */ 24160Sstevel@tonic-gate 24170Sstevel@tonic-gate /* 24180Sstevel@tonic-gate * cs_event - CS event hi-priority callback handler 24190Sstevel@tonic-gate * 24200Sstevel@tonic-gate * This function gets called by SS and is passed the event type in 24210Sstevel@tonic-gate * the "event" argument, and the socket number in the "sn" 24220Sstevel@tonic-gate * argument. The "sn" argument is a valid logical socket 24230Sstevel@tonic-gate * number for all events except the PCE_SS_READY event. 24240Sstevel@tonic-gate * 24250Sstevel@tonic-gate * The PCE_SS_INIT_STATE, PCE_ADD_SOCKET and PCE_DROP_SOCKET events 24260Sstevel@tonic-gate * are never called at high priority. These events return 24270Sstevel@tonic-gate * the following return codes: 24280Sstevel@tonic-gate * 24290Sstevel@tonic-gate * CS_SUCCESS - operation sucessful 24300Sstevel@tonic-gate * CS_BAD_SOCKET - unable to complete operation 24310Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - bad subfunction of 24320Sstevel@tonic-gate * PCE_SS_INIT_STATE 24330Sstevel@tonic-gate * 24340Sstevel@tonic-gate * The caller MUST look at these return codes! 24350Sstevel@tonic-gate * 24360Sstevel@tonic-gate * This function is called at high-priority interrupt time for standard 24370Sstevel@tonic-gate * Card Services events, and the only standard Card Services 24380Sstevel@tonic-gate * event that it handles directly is the CS_EVENT_CARD_REMOVAL 24390Sstevel@tonic-gate * event, which gets shuttled right into the client's event 24400Sstevel@tonic-gate * handler. All other events are just queued up and the socket 24410Sstevel@tonic-gate * event thread is woken up via the soft interrupt handler. 24420Sstevel@tonic-gate * Note that CS_EVENT_CARD_INSERTION events are not set in the clients' 24430Sstevel@tonic-gate * event field, since the CS card insertion/card ready processing 24440Sstevel@tonic-gate * code is responsible for setting this event in a client's 24450Sstevel@tonic-gate * event field. 24460Sstevel@tonic-gate * 24470Sstevel@tonic-gate */ 24480Sstevel@tonic-gate /*ARGSUSED*/ 24490Sstevel@tonic-gate uint32_t 24500Sstevel@tonic-gate cs_event(event_t event, uint32_t sn, uint32_t arg) 24510Sstevel@tonic-gate { 24520Sstevel@tonic-gate client_t *client; 24530Sstevel@tonic-gate cs_socket_t *sp; 24540Sstevel@tonic-gate client_types_t *ct; 24550Sstevel@tonic-gate uint32_t ret = CS_SUCCESS; 24560Sstevel@tonic-gate 24570Sstevel@tonic-gate /* 24580Sstevel@tonic-gate * Handle special SS<->CS events 24590Sstevel@tonic-gate */ 24600Sstevel@tonic-gate switch (event) { 24610Sstevel@tonic-gate case PCE_SS_INIT_STATE: 24620Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock); 24630Sstevel@tonic-gate switch (sn) { 24640Sstevel@tonic-gate case PCE_SS_STATE_INIT: 24650Sstevel@tonic-gate if ((ret = cs_ss_init()) == CS_SUCCESS) 24660Sstevel@tonic-gate cs_globals.init_state |= GLOBAL_INIT_STATE_SS_READY; 24670Sstevel@tonic-gate break; 24680Sstevel@tonic-gate case PCE_SS_STATE_DEINIT: 24690Sstevel@tonic-gate cs_globals.init_state &= ~GLOBAL_INIT_STATE_SS_READY; 24700Sstevel@tonic-gate break; 24710Sstevel@tonic-gate default: 24720Sstevel@tonic-gate ret = CS_UNSUPPORTED_FUNCTION; 24730Sstevel@tonic-gate cmn_err(CE_CONT, "cs_event: PCE_SS_INIT_STATE invalid " 24740Sstevel@tonic-gate "directive: 0x%x\n", sn); 24750Sstevel@tonic-gate break; 24760Sstevel@tonic-gate } /* switch (sn) */ 24770Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock); 24780Sstevel@tonic-gate return (ret); 24790Sstevel@tonic-gate case PCE_ADD_SOCKET: 24800Sstevel@tonic-gate return (cs_add_socket(sn)); 24810Sstevel@tonic-gate case PCE_DROP_SOCKET: 24820Sstevel@tonic-gate return (cs_drop_socket(sn)); 24830Sstevel@tonic-gate } /* switch (event) */ 24840Sstevel@tonic-gate 24850Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) == NULL) 24860Sstevel@tonic-gate return (CS_BAD_SOCKET); 24870Sstevel@tonic-gate 24880Sstevel@tonic-gate /* 24890Sstevel@tonic-gate * Check to see if CS wants to unload - we do this since it's possible 24900Sstevel@tonic-gate * to disable certain sockets. Do NOT acquire any locks yet. 24910Sstevel@tonic-gate */ 24920Sstevel@tonic-gate if (sp->flags & SOCKET_UNLOAD_MODULE) { 24930Sstevel@tonic-gate if (event == PCE_CARD_INSERT) 24940Sstevel@tonic-gate cmn_err(CE_CONT, "PCMCIA: socket %d disabled - please " 24950Sstevel@tonic-gate "remove card\n", sn); 24960Sstevel@tonic-gate return (CS_SUCCESS); 24970Sstevel@tonic-gate } 24980Sstevel@tonic-gate 24990Sstevel@tonic-gate mutex_enter(&sp->lock); 25000Sstevel@tonic-gate 25010Sstevel@tonic-gate #ifdef CS_DEBUG 25020Sstevel@tonic-gate if (cs_debug > 1) { 25030Sstevel@tonic-gate event2text_t event2text; 25040Sstevel@tonic-gate 25050Sstevel@tonic-gate event2text.event = event; 25060Sstevel@tonic-gate (void) cs_event2text(&event2text, 0); 25070Sstevel@tonic-gate cmn_err(CE_CONT, "cs_event: event=%s (x%x), socket=0x%x\n", 25080Sstevel@tonic-gate event2text.text, (int)event, (int)sn); 25090Sstevel@tonic-gate } 25100Sstevel@tonic-gate #endif 25110Sstevel@tonic-gate 25120Sstevel@tonic-gate /* 25130Sstevel@tonic-gate * Convert SS events to CS events; handle the PRR if necessary. 25140Sstevel@tonic-gate */ 25150Sstevel@tonic-gate sp->events |= ss_to_cs_events(sp, event); 25160Sstevel@tonic-gate 25170Sstevel@tonic-gate /* 25180Sstevel@tonic-gate * We want to maintain the required event dispatching order as 25190Sstevel@tonic-gate * specified in the PCMCIA spec, so we cycle through all 25200Sstevel@tonic-gate * clients on this socket to make sure that they are 25210Sstevel@tonic-gate * notified in the correct order of any high-priority 25220Sstevel@tonic-gate * events. 25230Sstevel@tonic-gate */ 25240Sstevel@tonic-gate ct = &client_types[0]; 25250Sstevel@tonic-gate while (ct) { 25260Sstevel@tonic-gate /* 25270Sstevel@tonic-gate * Point to the head of the client list for this socket, and go 25280Sstevel@tonic-gate * through each client to set up the client events as well as 25290Sstevel@tonic-gate * call the client's event handler directly if we have a high 25300Sstevel@tonic-gate * priority event that we need to tell the client about. 25310Sstevel@tonic-gate */ 25320Sstevel@tonic-gate client = sp->client_list; 25330Sstevel@tonic-gate 25340Sstevel@tonic-gate if (ct->order & CLIENT_EVENTS_LIFO) { 25350Sstevel@tonic-gate client_t *clp = NULL; 25360Sstevel@tonic-gate 25370Sstevel@tonic-gate while (client) { 25380Sstevel@tonic-gate clp = client; 25390Sstevel@tonic-gate client = client->next; 25400Sstevel@tonic-gate } 25410Sstevel@tonic-gate client = clp; 25420Sstevel@tonic-gate } 25430Sstevel@tonic-gate 25440Sstevel@tonic-gate while (client) { 25450Sstevel@tonic-gate client->events |= ((sp->events & ~CS_EVENT_CARD_INSERTION) & 25460Sstevel@tonic-gate (client->event_mask | client->global_mask)); 25470Sstevel@tonic-gate if (client->flags & ct->type) { 25480Sstevel@tonic-gate #ifdef CS_DEBUG 25490Sstevel@tonic-gate if (cs_debug > 1) { 25500Sstevel@tonic-gate cmn_err(CE_CONT, "cs_event: socket %d client [%s] " 25510Sstevel@tonic-gate "events 0x%x flags 0x%x\n", 25520Sstevel@tonic-gate sn, client->driver_name, 25530Sstevel@tonic-gate (int)client->events, 25540Sstevel@tonic-gate (int)client->flags); 25550Sstevel@tonic-gate } 25560Sstevel@tonic-gate #endif 25570Sstevel@tonic-gate 25580Sstevel@tonic-gate /* 25590Sstevel@tonic-gate * Handle the suspend and card removal events 25600Sstevel@tonic-gate * specially here so that the client can receive 25610Sstevel@tonic-gate * these events at high-priority. 25620Sstevel@tonic-gate */ 25630Sstevel@tonic-gate if (client->events & CS_EVENT_PM_SUSPEND) { 25640Sstevel@tonic-gate if (client->flags & CLIENT_CARD_INSERTED) { 25650Sstevel@tonic-gate CLIENT_EVENT_CALLBACK(client, CS_EVENT_PM_SUSPEND, 25660Sstevel@tonic-gate CS_EVENT_PRI_HIGH); 25670Sstevel@tonic-gate } /* if (CLIENT_CARD_INSERTED) */ 25680Sstevel@tonic-gate client->events &= ~CS_EVENT_PM_SUSPEND; 25690Sstevel@tonic-gate } /* if (CS_EVENT_PM_SUSPEND) */ 25700Sstevel@tonic-gate 25710Sstevel@tonic-gate if (client->events & CS_EVENT_CARD_REMOVAL) { 25720Sstevel@tonic-gate if (client->flags & CLIENT_CARD_INSERTED) { 25730Sstevel@tonic-gate client->flags &= ~(CLIENT_CARD_INSERTED | 25740Sstevel@tonic-gate CLIENT_SENT_INSERTION); 25750Sstevel@tonic-gate CLIENT_EVENT_CALLBACK(client, 25760Sstevel@tonic-gate CS_EVENT_CARD_REMOVAL, 25770Sstevel@tonic-gate CS_EVENT_PRI_HIGH); 25780Sstevel@tonic-gate /* 25790Sstevel@tonic-gate * Check to see if the client wants low priority 25800Sstevel@tonic-gate * removal events as well. 25810Sstevel@tonic-gate */ 25820Sstevel@tonic-gate if ((client->event_mask | client->global_mask) & 25830Sstevel@tonic-gate CS_EVENT_CARD_REMOVAL_LOWP) { 25840Sstevel@tonic-gate client->events |= CS_EVENT_CARD_REMOVAL_LOWP; 25850Sstevel@tonic-gate } 25860Sstevel@tonic-gate } /* if (CLIENT_CARD_INSERTED) */ 25870Sstevel@tonic-gate client->events &= ~CS_EVENT_CARD_REMOVAL; 25880Sstevel@tonic-gate } /* if (CS_EVENT_CARD_REMOVAL) */ 25890Sstevel@tonic-gate 25900Sstevel@tonic-gate } /* if (ct->type) */ 25910Sstevel@tonic-gate if (ct->order & CLIENT_EVENTS_LIFO) { 25920Sstevel@tonic-gate client = client->prev; 25930Sstevel@tonic-gate } else { 25940Sstevel@tonic-gate client = client->next; 25950Sstevel@tonic-gate } 25960Sstevel@tonic-gate } /* while (client) */ 25970Sstevel@tonic-gate 25980Sstevel@tonic-gate ct = ct->next; 25990Sstevel@tonic-gate } /* while (ct) */ 26000Sstevel@tonic-gate 26010Sstevel@tonic-gate /* 26020Sstevel@tonic-gate * Set the SOCKET_NEEDS_THREAD flag so that the soft interrupt 26030Sstevel@tonic-gate * handler will wakeup this socket's event thread. 26040Sstevel@tonic-gate */ 26050Sstevel@tonic-gate if (sp->events) 26060Sstevel@tonic-gate sp->flags |= SOCKET_NEEDS_THREAD; 26070Sstevel@tonic-gate 26080Sstevel@tonic-gate /* 26090Sstevel@tonic-gate * Fire off a soft interrupt that will cause the socket thread 26100Sstevel@tonic-gate * to be woken up and any remaining events to be sent to 26110Sstevel@tonic-gate * the clients on this socket. 26120Sstevel@tonic-gate */ 26130Sstevel@tonic-gate if ((sp->init_state & SOCKET_INIT_STATE_SOFTINTR) && 26140Sstevel@tonic-gate !(cs_globals.init_state & GLOBAL_INIT_STATE_UNLOADING)) 26150Sstevel@tonic-gate ddi_trigger_softintr(sp->softint_id); 26160Sstevel@tonic-gate 26170Sstevel@tonic-gate mutex_exit(&sp->lock); 26180Sstevel@tonic-gate 26190Sstevel@tonic-gate return (CS_SUCCESS); 26200Sstevel@tonic-gate } 26210Sstevel@tonic-gate 26220Sstevel@tonic-gate /* 26230Sstevel@tonic-gate * cs_card_insertion - handle card insertion and card ready events 26240Sstevel@tonic-gate * 26250Sstevel@tonic-gate * We read the CIS, if present, and store it away, then tell SS that 26260Sstevel@tonic-gate * we have read the CIS and it's ready to be parsed. Since card 26270Sstevel@tonic-gate * insertion and card ready events are pretty closely intertwined, 26280Sstevel@tonic-gate * we handle both here. For card ready events that are not the 26290Sstevel@tonic-gate * result of a card insertion event, we expect that the caller has 26300Sstevel@tonic-gate * already done the appropriate processing and that we will not be 26310Sstevel@tonic-gate * called unless we received a card ready event right after a card 26320Sstevel@tonic-gate * insertion event, i.e. that the SOCKET_WAIT_FOR_READY flag in 26330Sstevel@tonic-gate * sp->thread_state was set or if we get a CARD_READY event right 26340Sstevel@tonic-gate * after a CARD_INSERTION event. 26350Sstevel@tonic-gate * 26360Sstevel@tonic-gate * calling: sp - pointer to socket structure 26370Sstevel@tonic-gate * event - event to handle, one of: 26380Sstevel@tonic-gate * CS_EVENT_CARD_INSERTION 26390Sstevel@tonic-gate * CS_EVENT_CARD_READY 26400Sstevel@tonic-gate * CS_EVENT_SS_UPDATED 26410Sstevel@tonic-gate */ 26420Sstevel@tonic-gate static int 26430Sstevel@tonic-gate cs_card_insertion(cs_socket_t *sp, event_t event) 26440Sstevel@tonic-gate { 26450Sstevel@tonic-gate int ret; 26460Sstevel@tonic-gate 26470Sstevel@tonic-gate /* 26480Sstevel@tonic-gate * Since we're only called while waiting for the card insertion 26490Sstevel@tonic-gate * and card ready sequence to occur, we may have a pending 26500Sstevel@tonic-gate * card ready timer that hasn't gone off yet if we got a 26510Sstevel@tonic-gate * real card ready event. 26520Sstevel@tonic-gate */ 26530Sstevel@tonic-gate UNTIMEOUT(sp->rdybsy_tmo_id); 26540Sstevel@tonic-gate 26550Sstevel@tonic-gate #ifdef CS_DEBUG 26560Sstevel@tonic-gate if (cs_debug > 1) { 26570Sstevel@tonic-gate cmn_err(CE_CONT, "cs_card_insertion: event=0x%x, socket=0x%x\n", 26580Sstevel@tonic-gate (int)event, sp->socket_num); 26590Sstevel@tonic-gate } 26600Sstevel@tonic-gate #endif 26610Sstevel@tonic-gate 26620Sstevel@tonic-gate /* 26630Sstevel@tonic-gate * Handle card insertion processing 26640Sstevel@tonic-gate */ 26650Sstevel@tonic-gate if (event & CS_EVENT_CARD_INSERTION) { 26660Sstevel@tonic-gate set_socket_t set_socket; 26670Sstevel@tonic-gate get_ss_status_t gs; 26680Sstevel@tonic-gate 26690Sstevel@tonic-gate /* 26700Sstevel@tonic-gate * Check to be sure that we have a valid CIS window 26710Sstevel@tonic-gate */ 26720Sstevel@tonic-gate if (!SOCKET_HAS_CIS_WINDOW(sp)) { 26730Sstevel@tonic-gate cmn_err(CE_CONT, 26740Sstevel@tonic-gate "cs_card_insertion: socket %d has no " 26750Sstevel@tonic-gate "CIS window\n", 26760Sstevel@tonic-gate sp->socket_num); 26770Sstevel@tonic-gate return (CS_GENERAL_FAILURE); 26780Sstevel@tonic-gate } 26790Sstevel@tonic-gate 26800Sstevel@tonic-gate /* 26810Sstevel@tonic-gate * Apply power to the socket, enable card detect and card ready 26820Sstevel@tonic-gate * events, then reset the socket. 26830Sstevel@tonic-gate */ 26840Sstevel@tonic-gate mutex_enter(&sp->lock); 26850Sstevel@tonic-gate sp->event_mask = (CS_EVENT_CARD_REMOVAL | 26860Sstevel@tonic-gate CS_EVENT_CARD_READY); 26870Sstevel@tonic-gate mutex_exit(&sp->lock); 26880Sstevel@tonic-gate set_socket.socket = sp->socket_num; 26890Sstevel@tonic-gate set_socket.SCIntMask = (SBM_CD | SBM_RDYBSY); 26900Sstevel@tonic-gate set_socket.IREQRouting = 0; 26910Sstevel@tonic-gate set_socket.IFType = IF_MEMORY; 26920Sstevel@tonic-gate set_socket.CtlInd = 0; /* turn off controls and indicators */ 26930Sstevel@tonic-gate set_socket.State = (unsigned)~0; /* clear latched state bits */ 26940Sstevel@tonic-gate 26950Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 50, VCC, 26960Sstevel@tonic-gate &set_socket.VccLevel); 26970Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 50, VPP1, 26980Sstevel@tonic-gate &set_socket.Vpp1Level); 26990Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 50, VPP2, 27000Sstevel@tonic-gate &set_socket.Vpp2Level); 27010Sstevel@tonic-gate 27020Sstevel@tonic-gate if ((ret = SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) { 27030Sstevel@tonic-gate cmn_err(CE_CONT, 27040Sstevel@tonic-gate "cs_card_insertion: socket %d SS_SetSocket failure %d\n", 27050Sstevel@tonic-gate sp->socket_num, ret); 27060Sstevel@tonic-gate return (ret); 27070Sstevel@tonic-gate } 27080Sstevel@tonic-gate 27090Sstevel@tonic-gate /* 27100Sstevel@tonic-gate * Clear the ready and ready_timeout events since they are now 27110Sstevel@tonic-gate * bogus since we're about to reset the socket. 27120Sstevel@tonic-gate * XXX - should these be cleared right after the RESET?? 27130Sstevel@tonic-gate */ 27140Sstevel@tonic-gate mutex_enter(&sp->lock); 27150Sstevel@tonic-gate 27160Sstevel@tonic-gate sp->events &= ~(CS_EVENT_CARD_READY | CS_EVENT_READY_TIMEOUT); 27170Sstevel@tonic-gate mutex_exit(&sp->lock); 27180Sstevel@tonic-gate 27190Sstevel@tonic-gate SocketServices(SS_ResetSocket, sp->socket_num, 27200Sstevel@tonic-gate RESET_MODE_CARD_ONLY); 27210Sstevel@tonic-gate 27220Sstevel@tonic-gate /* 27230Sstevel@tonic-gate * We are required by the PCMCIA spec to wait some number of 27240Sstevel@tonic-gate * milliseconds after reset before we access the card, so 27250Sstevel@tonic-gate * we set up a timer here that will wake us up and allow us 27260Sstevel@tonic-gate * to continue with our card initialization. 27270Sstevel@tonic-gate */ 27280Sstevel@tonic-gate mutex_enter(&sp->lock); 27290Sstevel@tonic-gate sp->thread_state |= SOCKET_RESET_TIMER; 27300Sstevel@tonic-gate (void) timeout(cs_ready_timeout, sp, 27310Sstevel@tonic-gate drv_usectohz(cs_reset_timeout_time * 1000)); 27320Sstevel@tonic-gate cv_wait(&sp->reset_cv, &sp->lock); 27330Sstevel@tonic-gate sp->thread_state &= ~SOCKET_RESET_TIMER; 27340Sstevel@tonic-gate mutex_exit(&sp->lock); 27350Sstevel@tonic-gate 27360Sstevel@tonic-gate #ifdef CS_DEBUG 27370Sstevel@tonic-gate if (cs_debug > 2) { 27380Sstevel@tonic-gate cmn_err(CE_CONT, "cs_card_insertion: socket %d out of RESET " 27390Sstevel@tonic-gate "for %d mS sp->events 0x%x\n", 27400Sstevel@tonic-gate sp->socket_num, cs_reset_timeout_time, (int)sp->events); 27410Sstevel@tonic-gate } 27420Sstevel@tonic-gate #endif 27430Sstevel@tonic-gate 27440Sstevel@tonic-gate /* 27450Sstevel@tonic-gate * If we have a pending CS_EVENT_CARD_REMOVAL event it 27460Sstevel@tonic-gate * means that we likely got CD line bounce on the 27470Sstevel@tonic-gate * insertion, so terminate this processing. 27480Sstevel@tonic-gate */ 27490Sstevel@tonic-gate if (sp->events & CS_EVENT_CARD_REMOVAL) { 27500Sstevel@tonic-gate #ifdef CS_DEBUG 27510Sstevel@tonic-gate if (cs_debug > 0) { 27520Sstevel@tonic-gate cmn_err(CE_CONT, "cs_card_insertion: socket %d " 27530Sstevel@tonic-gate "CS_EVENT_CARD_REMOVAL event " 27540Sstevel@tonic-gate "terminating insertion " 27550Sstevel@tonic-gate "processing\n", 27560Sstevel@tonic-gate sp->socket_num); 27570Sstevel@tonic-gate } 27580Sstevel@tonic-gate #endif 27590Sstevel@tonic-gate return (CS_SUCCESS); 27600Sstevel@tonic-gate } /* if (CS_EVENT_CARD_REMOVAL) */ 27610Sstevel@tonic-gate 27620Sstevel@tonic-gate /* 27630Sstevel@tonic-gate * If we got a card ready event after the reset, then don't 27640Sstevel@tonic-gate * bother setting up a card ready timer, since we'll blast 27650Sstevel@tonic-gate * right on through to the card ready processing. 27660Sstevel@tonic-gate * Get the current card status to see if it's ready; if it 27670Sstevel@tonic-gate * is, we probably won't get a card ready event. 27680Sstevel@tonic-gate */ 27690Sstevel@tonic-gate gs.socket = sp->socket_num; 27700Sstevel@tonic-gate gs.CardState = 0; 27710Sstevel@tonic-gate if ((ret = SocketServices(SS_GetStatus, &gs)) != SUCCESS) { 27720Sstevel@tonic-gate cmn_err(CE_CONT, 27730Sstevel@tonic-gate "cs_card_insertion: socket %d SS_GetStatus failure %d\n", 27740Sstevel@tonic-gate sp->socket_num, ret); 27750Sstevel@tonic-gate return (ret); 27760Sstevel@tonic-gate } 27770Sstevel@tonic-gate 27780Sstevel@tonic-gate mutex_enter(&sp->lock); 27790Sstevel@tonic-gate if ((sp->events & CS_EVENT_CARD_READY) || 27800Sstevel@tonic-gate (gs.CardState & SBM_RDYBSY)) { 27810Sstevel@tonic-gate event = CS_EVENT_CARD_READY; 27820Sstevel@tonic-gate #ifdef CS_DEBUG 27830Sstevel@tonic-gate if (cs_debug > 1) { 27840Sstevel@tonic-gate cmn_err(CE_CONT, "cs_card_insertion: socket %d card " 27850Sstevel@tonic-gate "READY\n", sp->socket_num); 27860Sstevel@tonic-gate } 27870Sstevel@tonic-gate #endif 27880Sstevel@tonic-gate 27890Sstevel@tonic-gate } else { 27900Sstevel@tonic-gate #ifdef CS_DEBUG 27910Sstevel@tonic-gate if (cs_debug > 1) { 27920Sstevel@tonic-gate cmn_err(CE_CONT, "cs_card_insertion: socket %d setting " 27930Sstevel@tonic-gate "READY timer\n", sp->socket_num); 27940Sstevel@tonic-gate } 27950Sstevel@tonic-gate #endif 27960Sstevel@tonic-gate 27970Sstevel@tonic-gate sp->rdybsy_tmo_id = timeout(cs_ready_timeout, sp, 27980Sstevel@tonic-gate READY_TIMEOUT_TIME); 27990Sstevel@tonic-gate sp->thread_state |= SOCKET_WAIT_FOR_READY; 28000Sstevel@tonic-gate 28010Sstevel@tonic-gate } /* if (CS_EVENT_CARD_READY) */ 28020Sstevel@tonic-gate 28030Sstevel@tonic-gate mutex_exit(&sp->lock); 28040Sstevel@tonic-gate 28050Sstevel@tonic-gate } /* if (CS_EVENT_CARD_INSERTION) */ 28060Sstevel@tonic-gate 28070Sstevel@tonic-gate /* 28080Sstevel@tonic-gate * Handle card ready processing. This is only card ready processing 28090Sstevel@tonic-gate * for card ready events in conjunction with a card insertion. 28100Sstevel@tonic-gate */ 28110Sstevel@tonic-gate if (event == CS_EVENT_CARD_READY) { 28120Sstevel@tonic-gate get_socket_t get_socket; 28130Sstevel@tonic-gate set_socket_t set_socket; 28140Sstevel@tonic-gate 28150Sstevel@tonic-gate /* 28160Sstevel@tonic-gate * The only events that we want to see now are card removal 28170Sstevel@tonic-gate * events. 28180Sstevel@tonic-gate */ 28190Sstevel@tonic-gate mutex_enter(&sp->lock); 28200Sstevel@tonic-gate sp->event_mask = CS_EVENT_CARD_REMOVAL; 28210Sstevel@tonic-gate mutex_exit(&sp->lock); 28220Sstevel@tonic-gate get_socket.socket = sp->socket_num; 28230Sstevel@tonic-gate if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) { 28240Sstevel@tonic-gate cmn_err(CE_CONT, 28250Sstevel@tonic-gate "cs_card_insertion: socket %d SS_GetSocket failed\n", 28260Sstevel@tonic-gate sp->socket_num); 28270Sstevel@tonic-gate return (CS_BAD_SOCKET); 28280Sstevel@tonic-gate } 28290Sstevel@tonic-gate 28300Sstevel@tonic-gate set_socket.socket = sp->socket_num; 28310Sstevel@tonic-gate set_socket.SCIntMask = SBM_CD; 28320Sstevel@tonic-gate set_socket.VccLevel = get_socket.VccLevel; 28330Sstevel@tonic-gate set_socket.Vpp1Level = get_socket.Vpp1Level; 28340Sstevel@tonic-gate set_socket.Vpp2Level = get_socket.Vpp2Level; 28350Sstevel@tonic-gate set_socket.IREQRouting = get_socket.IRQRouting; 28360Sstevel@tonic-gate set_socket.IFType = get_socket.IFType; 28370Sstevel@tonic-gate set_socket.CtlInd = get_socket.CtlInd; 28380Sstevel@tonic-gate /* XXX (is ~0 correct here?) to reset latched values */ 28390Sstevel@tonic-gate set_socket.State = (unsigned)~0; 28400Sstevel@tonic-gate 28410Sstevel@tonic-gate if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) { 28420Sstevel@tonic-gate cmn_err(CE_CONT, 28430Sstevel@tonic-gate "cs_card_insertion: socket %d SS_SetSocket failed\n", 28440Sstevel@tonic-gate sp->socket_num); 28450Sstevel@tonic-gate 28460Sstevel@tonic-gate return (CS_BAD_SOCKET); 28470Sstevel@tonic-gate } 28480Sstevel@tonic-gate 28490Sstevel@tonic-gate /* 28500Sstevel@tonic-gate * Grab the cis_lock mutex to protect the CIS-to-be and 28510Sstevel@tonic-gate * the CIS window, then fire off the CIS parser to 28520Sstevel@tonic-gate * create a local copy of the card's CIS. 28530Sstevel@tonic-gate */ 28540Sstevel@tonic-gate mutex_enter(&sp->cis_lock); 28550Sstevel@tonic-gate 28560Sstevel@tonic-gate if ((ret = cs_create_cis(sp)) != CS_SUCCESS) { 28570Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 28580Sstevel@tonic-gate return (ret); 28590Sstevel@tonic-gate } 28600Sstevel@tonic-gate 28610Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 28620Sstevel@tonic-gate 28630Sstevel@tonic-gate /* 28640Sstevel@tonic-gate * If we have a pending CS_EVENT_CARD_REMOVAL event it 28650Sstevel@tonic-gate * means that we likely got CD line bounce on the 28660Sstevel@tonic-gate * insertion, so destroy the CIS and terminate this 28670Sstevel@tonic-gate * processing. We'll get called back to handle the 28680Sstevel@tonic-gate * insertion again later. 28690Sstevel@tonic-gate */ 28700Sstevel@tonic-gate if (sp->events & CS_EVENT_CARD_REMOVAL) { 28710Sstevel@tonic-gate mutex_enter(&sp->cis_lock); 28720Sstevel@tonic-gate (void) cs_destroy_cis(sp); 28730Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 28740Sstevel@tonic-gate } else { 28750Sstevel@tonic-gate /* 28760Sstevel@tonic-gate * Schedule the call to the Socket Services work thread. 28770Sstevel@tonic-gate */ 28780Sstevel@tonic-gate mutex_enter(&sp->ss_thread_lock); 28790Sstevel@tonic-gate sp->ss_thread_state |= SOCKET_THREAD_CSCISInit; 28800Sstevel@tonic-gate cv_broadcast(&sp->ss_thread_cv); 28810Sstevel@tonic-gate mutex_exit(&sp->ss_thread_lock); 28820Sstevel@tonic-gate } /* if (CS_EVENT_CARD_REMOVAL) */ 28830Sstevel@tonic-gate } /* if (CS_EVENT_CARD_READY) */ 28840Sstevel@tonic-gate 28850Sstevel@tonic-gate /* 28860Sstevel@tonic-gate * Socket Services has parsed the CIS and has done any other 28870Sstevel@tonic-gate * work to get the client driver loaded and attached if 28880Sstevel@tonic-gate * necessary, so setup the per-client state. 28890Sstevel@tonic-gate */ 28900Sstevel@tonic-gate if (event == CS_EVENT_SS_UPDATED) { 28910Sstevel@tonic-gate client_t *client; 28920Sstevel@tonic-gate 28930Sstevel@tonic-gate /* 28940Sstevel@tonic-gate * Now that we and SS are done handling the card insertion 28950Sstevel@tonic-gate * semantics, go through each client on this socket and set 28960Sstevel@tonic-gate * the CS_EVENT_CARD_INSERTION event in each client's event 28970Sstevel@tonic-gate * field. We do this here instead of in cs_event so that 28980Sstevel@tonic-gate * when a client gets a CS_EVENT_CARD_INSERTION event, the 28990Sstevel@tonic-gate * card insertion and ready processing has already been done 29000Sstevel@tonic-gate * and SocketServices has had a chance to create a dip for 29010Sstevel@tonic-gate * the card in this socket. 29020Sstevel@tonic-gate */ 29030Sstevel@tonic-gate mutex_enter(&sp->lock); 29040Sstevel@tonic-gate client = sp->client_list; 29050Sstevel@tonic-gate while (client) { 29060Sstevel@tonic-gate client->events |= (CS_EVENT_CARD_INSERTION & 29070Sstevel@tonic-gate (client->event_mask | client->global_mask)); 29080Sstevel@tonic-gate client = client->next; 29090Sstevel@tonic-gate } /* while (client) */ 29100Sstevel@tonic-gate 29110Sstevel@tonic-gate mutex_exit(&sp->lock); 29120Sstevel@tonic-gate 29130Sstevel@tonic-gate } /* if (CS_EVENT_SS_UPDATED) */ 29140Sstevel@tonic-gate 29150Sstevel@tonic-gate return (CS_SUCCESS); 29160Sstevel@tonic-gate } 29170Sstevel@tonic-gate 29180Sstevel@tonic-gate /* 29190Sstevel@tonic-gate * cs_card_removal - handle card removal events 29200Sstevel@tonic-gate * 29210Sstevel@tonic-gate * Destroy the CIS. 29220Sstevel@tonic-gate * 29230Sstevel@tonic-gate * calling: sp - pointer to socket structure 29240Sstevel@tonic-gate * 29250Sstevel@tonic-gate */ 29260Sstevel@tonic-gate static int 29270Sstevel@tonic-gate cs_card_removal(cs_socket_t *sp) 29280Sstevel@tonic-gate { 29290Sstevel@tonic-gate set_socket_t set_socket; 29300Sstevel@tonic-gate int ret; 29310Sstevel@tonic-gate 29320Sstevel@tonic-gate #ifdef CS_DEBUG 29330Sstevel@tonic-gate if (cs_debug > 0) { 29340Sstevel@tonic-gate cmn_err(CE_CONT, "cs_card_removal: socket %d\n", sp->socket_num); 29350Sstevel@tonic-gate } 29360Sstevel@tonic-gate #endif 29370Sstevel@tonic-gate 29380Sstevel@tonic-gate /* 29390Sstevel@tonic-gate * Remove any pending card ready timer 29400Sstevel@tonic-gate */ 29410Sstevel@tonic-gate UNTIMEOUT(sp->rdybsy_tmo_id); 29420Sstevel@tonic-gate 29430Sstevel@tonic-gate /* 29440Sstevel@tonic-gate * Clear various flags so that everyone else knows that there's 29450Sstevel@tonic-gate * nothing on this socket anymore. Note that we clear the 29460Sstevel@tonic-gate * SOCKET_CARD_INSERTED and SOCKET_IS_IO flags in the 29470Sstevel@tonic-gate * ss_to_cs_events event mapping function. 29480Sstevel@tonic-gate */ 29490Sstevel@tonic-gate mutex_enter(&sp->lock); 29500Sstevel@tonic-gate sp->thread_state &= ~(SOCKET_WAIT_FOR_READY | SOCKET_RESET_TIMER); 29510Sstevel@tonic-gate 29520Sstevel@tonic-gate /* 29530Sstevel@tonic-gate * Turn off socket power and set the socket back to memory mode. 29540Sstevel@tonic-gate * Disable all socket events except for CARD_INSERTION events. 29550Sstevel@tonic-gate */ 29560Sstevel@tonic-gate sp->event_mask = CS_EVENT_CARD_INSERTION; 29570Sstevel@tonic-gate mutex_exit(&sp->lock); 29580Sstevel@tonic-gate set_socket.socket = sp->socket_num; 29590Sstevel@tonic-gate set_socket.SCIntMask = SBM_CD; 29600Sstevel@tonic-gate set_socket.IREQRouting = 0; 29610Sstevel@tonic-gate set_socket.IFType = IF_MEMORY; 29620Sstevel@tonic-gate set_socket.CtlInd = 0; /* turn off controls and indicators */ 29630Sstevel@tonic-gate set_socket.State = (unsigned)~0; /* clear latched state bits */ 29640Sstevel@tonic-gate 29650Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 0, VCC, 29660Sstevel@tonic-gate &set_socket.VccLevel); 29670Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 0, VPP1, 29680Sstevel@tonic-gate &set_socket.Vpp1Level); 29690Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 0, VPP2, 29700Sstevel@tonic-gate &set_socket.Vpp2Level); 29710Sstevel@tonic-gate 29720Sstevel@tonic-gate if ((ret = SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) { 29730Sstevel@tonic-gate cmn_err(CE_CONT, 29740Sstevel@tonic-gate "cs_card_removal: socket %d SS_SetSocket failure %d\n", 29750Sstevel@tonic-gate sp->socket_num, ret); 29760Sstevel@tonic-gate return (ret); 29770Sstevel@tonic-gate } 29780Sstevel@tonic-gate 29790Sstevel@tonic-gate #ifdef CS_DEBUG 29800Sstevel@tonic-gate if (cs_debug > 2) { 29810Sstevel@tonic-gate cmn_err(CE_CONT, "cs_card_removal: socket %d " 29820Sstevel@tonic-gate "calling cs_destroy_cis\n", 29830Sstevel@tonic-gate sp->socket_num); 29840Sstevel@tonic-gate } 29850Sstevel@tonic-gate #endif 29860Sstevel@tonic-gate 29870Sstevel@tonic-gate /* 29880Sstevel@tonic-gate * Destroy the CIS and tell Socket Services that we're done 29890Sstevel@tonic-gate * handling the card removal event. 29900Sstevel@tonic-gate */ 29910Sstevel@tonic-gate mutex_enter(&sp->cis_lock); 29920Sstevel@tonic-gate (void) cs_destroy_cis(sp); 29930Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 29940Sstevel@tonic-gate 29950Sstevel@tonic-gate #ifdef CS_DEBUG 29960Sstevel@tonic-gate if (cs_debug > 2) { 29970Sstevel@tonic-gate cmn_err(CE_CONT, "cs_card_removal: calling CSCardRemoved\n"); 29980Sstevel@tonic-gate } 29990Sstevel@tonic-gate #endif 30000Sstevel@tonic-gate 30010Sstevel@tonic-gate SocketServices(CSCardRemoved, sp->socket_num); 30020Sstevel@tonic-gate 30030Sstevel@tonic-gate return (CS_SUCCESS); 30040Sstevel@tonic-gate } 30050Sstevel@tonic-gate 30060Sstevel@tonic-gate /* 30070Sstevel@tonic-gate * ss_to_cs_events - convert Socket Services events to Card Services event 30080Sstevel@tonic-gate * masks; this function will not read the PRR if the 30090Sstevel@tonic-gate * socket is in IO mode; this happens in cs_event_thread 30100Sstevel@tonic-gate * 30110Sstevel@tonic-gate * This function returns a bit mask of events. 30120Sstevel@tonic-gate * 30130Sstevel@tonic-gate * Note that we do some simple hysterious on card insertion and card removal 30140Sstevel@tonic-gate * events to prevent spurious insertion and removal events from being 30150Sstevel@tonic-gate * propogated down the chain. 30160Sstevel@tonic-gate */ 30170Sstevel@tonic-gate static event_t 30180Sstevel@tonic-gate ss_to_cs_events(cs_socket_t *sp, event_t event) 30190Sstevel@tonic-gate { 30200Sstevel@tonic-gate event_t revent = 0; 30210Sstevel@tonic-gate 30220Sstevel@tonic-gate switch (event) { 30230Sstevel@tonic-gate case PCE_CARD_STATUS_CHANGE: 30240Sstevel@tonic-gate revent |= CS_EVENT_STATUS_CHANGE; 30250Sstevel@tonic-gate break; 30260Sstevel@tonic-gate case PCE_CARD_REMOVAL: 30270Sstevel@tonic-gate if (sp->flags & SOCKET_CARD_INSERTED) { 30280Sstevel@tonic-gate sp->flags &= ~(SOCKET_CARD_INSERTED | SOCKET_IS_IO); 30290Sstevel@tonic-gate revent |= CS_EVENT_CARD_REMOVAL; 30300Sstevel@tonic-gate /* 30310Sstevel@tonic-gate * If we're processing a removal event, it makes 30320Sstevel@tonic-gate * no sense to keep any insertion or ready events, 30330Sstevel@tonic-gate * so nuke them here. This will not clear any 30340Sstevel@tonic-gate * insertion events in the per-client event field. 30350Sstevel@tonic-gate */ 30360Sstevel@tonic-gate sp->events &= ~(CS_EVENT_CARD_INSERTION | 30370Sstevel@tonic-gate CS_EVENT_CARD_READY | 30380Sstevel@tonic-gate CS_EVENT_READY_TIMEOUT); 30390Sstevel@tonic-gate 30400Sstevel@tonic-gate /* 30410Sstevel@tonic-gate * We also don't need to wait for READY anymore since 30420Sstevel@tonic-gate * it probably won't show up, or if it does, it will 30430Sstevel@tonic-gate * be a bogus READY event as the card is sliding out 30440Sstevel@tonic-gate * of the socket. Since we never do a cv_wait on the 30450Sstevel@tonic-gate * card ready timer, it's OK for that timer to either 30460Sstevel@tonic-gate * never go off (via an UNTIMEOUT in cs_card_removal) 30470Sstevel@tonic-gate * or to go off but not do a cv_broadcast (since the 30480Sstevel@tonic-gate * SOCKET_WAIT_FOR_READY flag is cleared here). 30490Sstevel@tonic-gate */ 30500Sstevel@tonic-gate sp->thread_state &= ~SOCKET_WAIT_FOR_READY; 30510Sstevel@tonic-gate 30520Sstevel@tonic-gate } 30530Sstevel@tonic-gate break; 30540Sstevel@tonic-gate case PCE_CARD_INSERT: 30550Sstevel@tonic-gate if (!(sp->flags & SOCKET_CARD_INSERTED)) { 30560Sstevel@tonic-gate sp->flags |= SOCKET_CARD_INSERTED; 30570Sstevel@tonic-gate revent |= CS_EVENT_CARD_INSERTION; 30580Sstevel@tonic-gate } 30590Sstevel@tonic-gate break; 30600Sstevel@tonic-gate case PCE_CARD_READY: 30610Sstevel@tonic-gate if (sp->flags & SOCKET_CARD_INSERTED) 30620Sstevel@tonic-gate revent |= CS_EVENT_CARD_READY; 30630Sstevel@tonic-gate break; 30640Sstevel@tonic-gate case PCE_CARD_BATTERY_WARN: 30650Sstevel@tonic-gate if (sp->flags & SOCKET_CARD_INSERTED) 30660Sstevel@tonic-gate revent |= CS_EVENT_BATTERY_LOW; 30670Sstevel@tonic-gate break; 30680Sstevel@tonic-gate case PCE_CARD_BATTERY_DEAD: 30690Sstevel@tonic-gate if (sp->flags & SOCKET_CARD_INSERTED) 30700Sstevel@tonic-gate revent |= CS_EVENT_BATTERY_DEAD; 30710Sstevel@tonic-gate break; 30720Sstevel@tonic-gate case PCE_CARD_WRITE_PROTECT: 30730Sstevel@tonic-gate if (sp->flags & SOCKET_CARD_INSERTED) 30740Sstevel@tonic-gate revent |= CS_EVENT_WRITE_PROTECT; 30750Sstevel@tonic-gate break; 30760Sstevel@tonic-gate case PCE_PM_RESUME: 30770Sstevel@tonic-gate revent |= CS_EVENT_PM_RESUME; 30780Sstevel@tonic-gate break; 30790Sstevel@tonic-gate case PCE_PM_SUSPEND: 30800Sstevel@tonic-gate revent |= CS_EVENT_PM_SUSPEND; 30810Sstevel@tonic-gate break; 30820Sstevel@tonic-gate default: 30830Sstevel@tonic-gate cmn_err(CE_CONT, "ss_to_cs_events: unknown event 0x%x\n", 30840Sstevel@tonic-gate (int)event); 30850Sstevel@tonic-gate break; 30860Sstevel@tonic-gate } /* switch(event) */ 30870Sstevel@tonic-gate 30880Sstevel@tonic-gate return (revent); 30890Sstevel@tonic-gate } 30900Sstevel@tonic-gate 30910Sstevel@tonic-gate /* 30920Sstevel@tonic-gate * cs_ready_timeout - general purpose READY/BUSY and RESET timer 30930Sstevel@tonic-gate * 30940Sstevel@tonic-gate * Note that we really only expect one of the two events to be asserted when 30950Sstevel@tonic-gate * we are called. XXX - Perhaps this might be a problem later on?? 30960Sstevel@tonic-gate * 30970Sstevel@tonic-gate * There is also the problem of cv_broadcast dropping the interrupt 30980Sstevel@tonic-gate * priority, even though we have our high-priority mutex held. If 30990Sstevel@tonic-gate * we hold our high-priority mutex (sp->lock) over a cv_broadcast, and 31000Sstevel@tonic-gate * we get a high-priority interrupt during this time, the system will 31010Sstevel@tonic-gate * deadlock or panic. Thanks to Andy Banta for finding this out in 31020Sstevel@tonic-gate * the SPC/S (stc.c) driver. 31030Sstevel@tonic-gate * 31040Sstevel@tonic-gate * This callback routine can not grab the sp->client_lock mutex or deadlock 31050Sstevel@tonic-gate * will result. 31060Sstevel@tonic-gate */ 31070Sstevel@tonic-gate void 31080Sstevel@tonic-gate cs_ready_timeout(void *arg) 31090Sstevel@tonic-gate { 31100Sstevel@tonic-gate cs_socket_t *sp = arg; 31110Sstevel@tonic-gate kcondvar_t *cvp = NULL; 31120Sstevel@tonic-gate 31130Sstevel@tonic-gate mutex_enter(&sp->lock); 31140Sstevel@tonic-gate 31150Sstevel@tonic-gate if (sp->thread_state & SOCKET_RESET_TIMER) { 31160Sstevel@tonic-gate #ifdef CS_DEBUG 31170Sstevel@tonic-gate if (cs_debug > 1) { 31180Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ready_timeout: SOCKET_RESET_TIMER socket %d\n", 31190Sstevel@tonic-gate sp->socket_num); 31200Sstevel@tonic-gate } 31210Sstevel@tonic-gate #endif 31220Sstevel@tonic-gate 31230Sstevel@tonic-gate cvp = &sp->reset_cv; 31240Sstevel@tonic-gate } 31250Sstevel@tonic-gate 31260Sstevel@tonic-gate if (sp->thread_state & SOCKET_WAIT_FOR_READY) { 31270Sstevel@tonic-gate sp->events |= CS_EVENT_READY_TIMEOUT; 31280Sstevel@tonic-gate cvp = &sp->thread_cv; 31290Sstevel@tonic-gate 31300Sstevel@tonic-gate #ifdef CS_DEBUG 31310Sstevel@tonic-gate if (cs_debug > 1) { 31320Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ready_timeout: SOCKET_WAIT_FOR_READY " 31330Sstevel@tonic-gate "socket %d\n", sp->socket_num); 31340Sstevel@tonic-gate } 31350Sstevel@tonic-gate #endif 31360Sstevel@tonic-gate 31370Sstevel@tonic-gate } 31380Sstevel@tonic-gate 31390Sstevel@tonic-gate mutex_exit(&sp->lock); 31400Sstevel@tonic-gate 31410Sstevel@tonic-gate if (cvp) 31420Sstevel@tonic-gate cv_broadcast(cvp); 31430Sstevel@tonic-gate } 31440Sstevel@tonic-gate 31450Sstevel@tonic-gate /* 31460Sstevel@tonic-gate * cs_event_softintr_timeout - wrapper function to call cs_socket_event_softintr 31470Sstevel@tonic-gate */ 31480Sstevel@tonic-gate /* ARGSUSED */ 31490Sstevel@tonic-gate void 31500Sstevel@tonic-gate cs_event_softintr_timeout(void *arg) 31510Sstevel@tonic-gate { 31520Sstevel@tonic-gate 31530Sstevel@tonic-gate /* 31540Sstevel@tonic-gate * If we're trying to unload this module, then don't do 31550Sstevel@tonic-gate * anything but exit. 31560Sstevel@tonic-gate * We acquire the cs_globals.global_lock mutex here so that 31570Sstevel@tonic-gate * we can correctly synchronize with cs_deinit when it 31580Sstevel@tonic-gate * is telling us to shut down. XXX - is this bogus?? 31590Sstevel@tonic-gate */ 31600Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock); 31610Sstevel@tonic-gate if (!(cs_globals.init_state & GLOBAL_INIT_STATE_UNLOADING)) { 31620Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock); 31630Sstevel@tonic-gate (void) cs_socket_event_softintr(NULL); 31640Sstevel@tonic-gate cs_globals.sotfint_tmo = timeout(cs_event_softintr_timeout, 31650Sstevel@tonic-gate NULL, SOFTINT_TIMEOUT_TIME); 31660Sstevel@tonic-gate } else { 31670Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock); 31680Sstevel@tonic-gate } 31690Sstevel@tonic-gate } 31700Sstevel@tonic-gate 31710Sstevel@tonic-gate /* 31720Sstevel@tonic-gate * cs_socket_event_softintr - This function just does a cv_broadcast on behalf 31730Sstevel@tonic-gate * of the high-priority interrupt handler. 31740Sstevel@tonic-gate * 31750Sstevel@tonic-gate * Note: There is no calling argument. 31760Sstevel@tonic-gate */ 31770Sstevel@tonic-gate /*ARGSUSED*/ 31780Sstevel@tonic-gate uint32_t 31790Sstevel@tonic-gate cs_socket_event_softintr(caddr_t notused) 31800Sstevel@tonic-gate { 31810Sstevel@tonic-gate cs_socket_t *sp; 31820Sstevel@tonic-gate uint32_t sn; 31830Sstevel@tonic-gate int ret = DDI_INTR_UNCLAIMED; 31840Sstevel@tonic-gate 31850Sstevel@tonic-gate /* 31860Sstevel@tonic-gate * If the module is on it's way out, then don't bother 31870Sstevel@tonic-gate * to do anything else except return. 31880Sstevel@tonic-gate */ 31890Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock); 31900Sstevel@tonic-gate if ((cs_globals.init_state & GLOBAL_INIT_STATE_UNLOADING) || 31910Sstevel@tonic-gate (cs_globals.init_state & GLOBAL_IN_SOFTINTR)) { 31920Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock); 31930Sstevel@tonic-gate 31940Sstevel@tonic-gate /* 31950Sstevel@tonic-gate * Note that we return DDI_INTR_UNCLAIMED here 31960Sstevel@tonic-gate * since we don't want to be constantly 31970Sstevel@tonic-gate * called back. 31980Sstevel@tonic-gate */ 31990Sstevel@tonic-gate return (ret); 32000Sstevel@tonic-gate } else { 32010Sstevel@tonic-gate cs_globals.init_state |= GLOBAL_IN_SOFTINTR; 32020Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock); 32030Sstevel@tonic-gate } 32040Sstevel@tonic-gate 32050Sstevel@tonic-gate /* 32060Sstevel@tonic-gate * Go through each socket and dispatch the appropriate events. 32070Sstevel@tonic-gate * We have to funnel everything through this one routine because 32080Sstevel@tonic-gate * we can't do a cv_broadcast from a high level interrupt handler 32090Sstevel@tonic-gate * and we also can't have more than one soft interrupt handler 32100Sstevel@tonic-gate * on a single dip and using the same handler address. 32110Sstevel@tonic-gate */ 32120Sstevel@tonic-gate for (sn = 0; sn < cs_globals.max_socket_num; sn++) { 32130Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) != NULL) { 32140Sstevel@tonic-gate if (sp->init_state & SOCKET_INIT_STATE_READY) { 32150Sstevel@tonic-gate /* 32160Sstevel@tonic-gate * If we're being asked to unload CS, then don't bother 32170Sstevel@tonic-gate * waking up the socket event thread handler. 32180Sstevel@tonic-gate */ 32190Sstevel@tonic-gate if (!(sp->flags & SOCKET_UNLOAD_MODULE) && 32200Sstevel@tonic-gate (sp->flags & SOCKET_NEEDS_THREAD)) { 32210Sstevel@tonic-gate ret = DDI_INTR_CLAIMED; 32220Sstevel@tonic-gate mutex_enter(&sp->client_lock); 32230Sstevel@tonic-gate cv_broadcast(&sp->thread_cv); 32240Sstevel@tonic-gate mutex_exit(&sp->client_lock); 32250Sstevel@tonic-gate } /* if (SOCKET_NEEDS_THREAD) */ 32260Sstevel@tonic-gate } /* if (SOCKET_INIT_STATE_READY) */ 32270Sstevel@tonic-gate } /* cs_get_sp */ 32280Sstevel@tonic-gate } /* for (sn) */ 32290Sstevel@tonic-gate 32300Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock); 32310Sstevel@tonic-gate cs_globals.init_state &= ~GLOBAL_IN_SOFTINTR; 32320Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock); 32330Sstevel@tonic-gate 32340Sstevel@tonic-gate return (ret); 32350Sstevel@tonic-gate } 32360Sstevel@tonic-gate 32370Sstevel@tonic-gate /* 32380Sstevel@tonic-gate * cs_event_thread - This is the per-socket event thread. 32390Sstevel@tonic-gate */ 32400Sstevel@tonic-gate static void 32410Sstevel@tonic-gate cs_event_thread(uint32_t sn) 32420Sstevel@tonic-gate { 32430Sstevel@tonic-gate cs_socket_t *sp; 32440Sstevel@tonic-gate client_t *client; 32450Sstevel@tonic-gate client_types_t *ct; 32460Sstevel@tonic-gate 32470Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) == NULL) 32480Sstevel@tonic-gate return; 32490Sstevel@tonic-gate 32500Sstevel@tonic-gate #ifdef CS_DEBUG 32510Sstevel@tonic-gate if (cs_debug > 1) { 32520Sstevel@tonic-gate cmn_err(CE_CONT, "cs_event_thread: socket %d thread started\n", 32530Sstevel@tonic-gate sp->socket_num); 32540Sstevel@tonic-gate } 32550Sstevel@tonic-gate #endif 32560Sstevel@tonic-gate 32570Sstevel@tonic-gate CALLB_CPR_INIT(&sp->cprinfo_cs, &sp->client_lock, 32580Sstevel@tonic-gate callb_generic_cpr, "cs_event_thread"); 32590Sstevel@tonic-gate 32600Sstevel@tonic-gate mutex_enter(&sp->client_lock); 32610Sstevel@tonic-gate 32620Sstevel@tonic-gate for (;;) { 32630Sstevel@tonic-gate 32640Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&sp->cprinfo_cs); 32650Sstevel@tonic-gate cv_wait(&sp->thread_cv, &sp->client_lock); 32660Sstevel@tonic-gate CALLB_CPR_SAFE_END(&sp->cprinfo_cs, &sp->client_lock); 32670Sstevel@tonic-gate 32680Sstevel@tonic-gate mutex_enter(&sp->lock); 32690Sstevel@tonic-gate sp->flags &= ~SOCKET_NEEDS_THREAD; 32700Sstevel@tonic-gate mutex_exit(&sp->lock); 32710Sstevel@tonic-gate 32720Sstevel@tonic-gate /* 32730Sstevel@tonic-gate * Check to see if there are any special thread operations that 32740Sstevel@tonic-gate * we are being asked to perform. 32750Sstevel@tonic-gate */ 32760Sstevel@tonic-gate if (sp->thread_state & SOCKET_THREAD_EXIT) { 32770Sstevel@tonic-gate #ifdef CS_DEBUG 32780Sstevel@tonic-gate if (cs_debug > 1) { 32790Sstevel@tonic-gate cmn_err(CE_CONT, "cs_event_thread: socket %d " 32800Sstevel@tonic-gate "SOCKET_THREAD_EXIT\n", 32810Sstevel@tonic-gate sp->socket_num); 32820Sstevel@tonic-gate } 32830Sstevel@tonic-gate #endif 32840Sstevel@tonic-gate CALLB_CPR_EXIT(&sp->cprinfo_cs); 32850Sstevel@tonic-gate cv_broadcast(&sp->caller_cv); /* wakes up cs_deinit */ 32860Sstevel@tonic-gate mutex_exit(&sp->client_lock); 32870Sstevel@tonic-gate return; 32880Sstevel@tonic-gate } /* if (SOCKET_THREAD_EXIT) */ 32890Sstevel@tonic-gate 32900Sstevel@tonic-gate #ifdef CS_DEBUG 32910Sstevel@tonic-gate if (cs_debug > 1) { 32920Sstevel@tonic-gate cmn_err(CE_CONT, "cs_event_thread: socket %d sp->events 0x%x\n", 32930Sstevel@tonic-gate sp->socket_num, 32940Sstevel@tonic-gate (int)sp->events); 32950Sstevel@tonic-gate } 32960Sstevel@tonic-gate #endif 32970Sstevel@tonic-gate 32980Sstevel@tonic-gate /* 32990Sstevel@tonic-gate * Handle CS_EVENT_CARD_INSERTION events 33000Sstevel@tonic-gate */ 33010Sstevel@tonic-gate if (sp->events & CS_EVENT_CARD_INSERTION) { 33020Sstevel@tonic-gate mutex_enter(&sp->lock); 33030Sstevel@tonic-gate sp->events &= ~CS_EVENT_CARD_INSERTION; 33040Sstevel@tonic-gate mutex_exit(&sp->lock); 33050Sstevel@tonic-gate 33060Sstevel@tonic-gate /* 33070Sstevel@tonic-gate * If we have a pending CS_EVENT_CARD_REMOVAL event it 33080Sstevel@tonic-gate * means that we likely got CD line bounce on the 33090Sstevel@tonic-gate * insertion, so terminate this processing. 33100Sstevel@tonic-gate */ 33110Sstevel@tonic-gate if ((sp->events & CS_EVENT_CARD_REMOVAL) == 0) { 33120Sstevel@tonic-gate (void) cs_card_insertion(sp, CS_EVENT_CARD_INSERTION); 33130Sstevel@tonic-gate } 33140Sstevel@tonic-gate #ifdef CS_DEBUG 33150Sstevel@tonic-gate else if (cs_debug > 0) { 33160Sstevel@tonic-gate cmn_err(CE_CONT, "cs_event_thread: socket %d " 33170Sstevel@tonic-gate "CS_EVENT_CARD_REMOVAL event " 33180Sstevel@tonic-gate "terminating " 33190Sstevel@tonic-gate "CS_EVENT_CARD_INSERTION " 33200Sstevel@tonic-gate "processing\n", sp->socket_num); 33210Sstevel@tonic-gate } 33220Sstevel@tonic-gate #endif 33230Sstevel@tonic-gate } /* if (CS_EVENT_CARD_INSERTION) */ 33240Sstevel@tonic-gate 33250Sstevel@tonic-gate /* 33260Sstevel@tonic-gate * Handle CS_EVENT_CARD_READY and CS_EVENT_READY_TIMEOUT events 33270Sstevel@tonic-gate */ 33280Sstevel@tonic-gate if (sp->events & (CS_EVENT_CARD_READY | CS_EVENT_READY_TIMEOUT)) { 33290Sstevel@tonic-gate mutex_enter(&sp->lock); 33300Sstevel@tonic-gate sp->events &= ~(CS_EVENT_CARD_READY | CS_EVENT_READY_TIMEOUT); 33310Sstevel@tonic-gate mutex_exit(&sp->lock); 33320Sstevel@tonic-gate if (sp->thread_state & SOCKET_WAIT_FOR_READY) { 33330Sstevel@tonic-gate mutex_enter(&sp->lock); 33340Sstevel@tonic-gate sp->thread_state &= ~SOCKET_WAIT_FOR_READY; 33350Sstevel@tonic-gate mutex_exit(&sp->lock); 33360Sstevel@tonic-gate (void) cs_card_insertion(sp, CS_EVENT_CARD_READY); 33370Sstevel@tonic-gate } /* if (SOCKET_WAIT_FOR_READY) */ 33380Sstevel@tonic-gate } /* if (CS_EVENT_CARD_READY) */ 33390Sstevel@tonic-gate 33400Sstevel@tonic-gate /* 33410Sstevel@tonic-gate * Handle CS_EVENT_SS_UPDATED events 33420Sstevel@tonic-gate */ 33430Sstevel@tonic-gate if (sp->events & CS_EVENT_SS_UPDATED) { 33440Sstevel@tonic-gate mutex_enter(&sp->lock); 33450Sstevel@tonic-gate sp->events &= ~CS_EVENT_SS_UPDATED; 33460Sstevel@tonic-gate mutex_exit(&sp->lock); 33470Sstevel@tonic-gate (void) cs_card_insertion(sp, CS_EVENT_SS_UPDATED); 33480Sstevel@tonic-gate } /* if (CS_EVENT_SS_UPDATED) */ 33490Sstevel@tonic-gate 33500Sstevel@tonic-gate /* 33510Sstevel@tonic-gate * Handle CS_EVENT_STATUS_CHANGE events 33520Sstevel@tonic-gate */ 33530Sstevel@tonic-gate if (sp->events & CS_EVENT_STATUS_CHANGE) { 33540Sstevel@tonic-gate event_t revent; 33550Sstevel@tonic-gate 33560Sstevel@tonic-gate mutex_enter(&sp->cis_lock); 33570Sstevel@tonic-gate mutex_enter(&sp->lock); 33580Sstevel@tonic-gate sp->events &= ~CS_EVENT_STATUS_CHANGE; 33590Sstevel@tonic-gate 33600Sstevel@tonic-gate /* 33610Sstevel@tonic-gate * Go through each client and add any events that we saw to 33620Sstevel@tonic-gate * the client's event list if the client has that event 33630Sstevel@tonic-gate * enabled in their event mask. 33640Sstevel@tonic-gate * Remove any events that may be pending for this client if 33650Sstevel@tonic-gate * the client's event mask says that the client doesn't 33660Sstevel@tonic-gate * want to see those events anymore. This handles the 33670Sstevel@tonic-gate * case where the client had an event enabled in it's 33680Sstevel@tonic-gate * event mask when the event came in but between that 33690Sstevel@tonic-gate * time and the time we're called here the client 33700Sstevel@tonic-gate * disabled that event. 33710Sstevel@tonic-gate */ 33720Sstevel@tonic-gate client = sp->client_list; 33730Sstevel@tonic-gate 33740Sstevel@tonic-gate while (client) { 33750Sstevel@tonic-gate /* 33760Sstevel@tonic-gate * Read the PRR (if it exists) and check for any events. 33770Sstevel@tonic-gate * The PRR will only be read if the socket is in IO 33780Sstevel@tonic-gate * mode, if there is a card in the socket, and if there 33790Sstevel@tonic-gate * is a PRR. 33800Sstevel@tonic-gate * We don't have to clear revent before we call the 33810Sstevel@tonic-gate * cs_read_event_status function since it will 33820Sstevel@tonic-gate * clear it before adding any current events. 33830Sstevel@tonic-gate */ 33840Sstevel@tonic-gate if (client->flags & CLIENT_CARD_INSERTED) { 33850Sstevel@tonic-gate (void) cs_read_event_status(sp, client, 33860Sstevel@tonic-gate &revent, NULL, 0); 33870Sstevel@tonic-gate 33880Sstevel@tonic-gate client->events = ((client->events | revent) & 33890Sstevel@tonic-gate (client->event_mask | 33900Sstevel@tonic-gate client->global_mask)); 33910Sstevel@tonic-gate } /* CLIENT_CARD_INSERTED */ 33920Sstevel@tonic-gate client = client->next; 33930Sstevel@tonic-gate } /* while (client) */ 33940Sstevel@tonic-gate 33950Sstevel@tonic-gate mutex_exit(&sp->lock); 33960Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 33970Sstevel@tonic-gate } /* if (CS_EVENT_STATUS_CHANGE) */ 33980Sstevel@tonic-gate 33990Sstevel@tonic-gate /* 34000Sstevel@tonic-gate * We want to maintain the required event dispatching order as 34010Sstevel@tonic-gate * specified in the PCMCIA spec, so we cycle through all 34020Sstevel@tonic-gate * clients on this socket to make sure that they are 34030Sstevel@tonic-gate * notified in the correct order. 34040Sstevel@tonic-gate */ 34050Sstevel@tonic-gate ct = &client_types[0]; 34060Sstevel@tonic-gate while (ct) { 34070Sstevel@tonic-gate /* 34080Sstevel@tonic-gate * Point to the head of the client list for this socket, and go 34090Sstevel@tonic-gate * through each client to set up the client events as well 34100Sstevel@tonic-gate * as call the client's event handler directly if we have 34110Sstevel@tonic-gate * a high priority event that we need to tell the client 34120Sstevel@tonic-gate * about. 34130Sstevel@tonic-gate */ 34140Sstevel@tonic-gate client = sp->client_list; 34150Sstevel@tonic-gate 34160Sstevel@tonic-gate if (ct->order & CLIENT_EVENTS_LIFO) { 34170Sstevel@tonic-gate client_t *clp = NULL; 34180Sstevel@tonic-gate 34190Sstevel@tonic-gate while (client) { 34200Sstevel@tonic-gate clp = client; 34210Sstevel@tonic-gate client = client->next; 34220Sstevel@tonic-gate } 34230Sstevel@tonic-gate client = clp; 34240Sstevel@tonic-gate } 34250Sstevel@tonic-gate 34260Sstevel@tonic-gate while (client) { 34270Sstevel@tonic-gate if (client->flags & ct->type) { 34280Sstevel@tonic-gate uint32_t bit = 0; 34290Sstevel@tonic-gate event_t event; 34300Sstevel@tonic-gate 34310Sstevel@tonic-gate while (client->events) { 34320Sstevel@tonic-gate 34330Sstevel@tonic-gate switch (event = CS_BIT_GET(client->events, bit)) { 34340Sstevel@tonic-gate /* 34350Sstevel@tonic-gate * Clients always receive registration complete 34360Sstevel@tonic-gate * events, even if there is no card of 34370Sstevel@tonic-gate * their type currently in the socket. 34380Sstevel@tonic-gate */ 34390Sstevel@tonic-gate case CS_EVENT_REGISTRATION_COMPLETE: 34400Sstevel@tonic-gate CLIENT_EVENT_CALLBACK(client, event, 34410Sstevel@tonic-gate CS_EVENT_PRI_LOW); 34420Sstevel@tonic-gate break; 34430Sstevel@tonic-gate /* 34440Sstevel@tonic-gate * The client only gets a card insertion event 34450Sstevel@tonic-gate * if there is currently a card in the 34460Sstevel@tonic-gate * socket that the client can control. 34470Sstevel@tonic-gate * The nexus determines this. We also 34480Sstevel@tonic-gate * prevent the client from receiving 34490Sstevel@tonic-gate * multiple CS_EVENT_CARD_INSERTION 34500Sstevel@tonic-gate * events without receiving intervening 34510Sstevel@tonic-gate * CS_EVENT_CARD_REMOVAL events. 34520Sstevel@tonic-gate */ 34530Sstevel@tonic-gate case CS_EVENT_CARD_INSERTION: 34540Sstevel@tonic-gate if (cs_card_for_client(client)) { 34550Sstevel@tonic-gate int send_insertion; 34560Sstevel@tonic-gate 34570Sstevel@tonic-gate mutex_enter(&sp->lock); 34580Sstevel@tonic-gate send_insertion = client->flags; 34590Sstevel@tonic-gate client->flags |= 34600Sstevel@tonic-gate (CLIENT_CARD_INSERTED | 34610Sstevel@tonic-gate CLIENT_SENT_INSERTION); 34620Sstevel@tonic-gate mutex_exit(&sp->lock); 34630Sstevel@tonic-gate if (!(send_insertion & 34640Sstevel@tonic-gate CLIENT_SENT_INSERTION)) { 34650Sstevel@tonic-gate CLIENT_EVENT_CALLBACK(client, 34660Sstevel@tonic-gate event, CS_EVENT_PRI_LOW); 34670Sstevel@tonic-gate } /* if (!CLIENT_SENT_INSERTION) */ 34680Sstevel@tonic-gate } 34690Sstevel@tonic-gate break; 34700Sstevel@tonic-gate /* 34710Sstevel@tonic-gate * The CS_EVENT_CARD_REMOVAL_LOWP is a low 34720Sstevel@tonic-gate * priority CS_EVENT_CARD_REMOVAL event. 34730Sstevel@tonic-gate */ 34740Sstevel@tonic-gate case CS_EVENT_CARD_REMOVAL_LOWP: 34750Sstevel@tonic-gate mutex_enter(&sp->lock); 34760Sstevel@tonic-gate client->flags &= ~CLIENT_SENT_INSERTION; 34770Sstevel@tonic-gate mutex_exit(&sp->lock); 34780Sstevel@tonic-gate CLIENT_EVENT_CALLBACK(client, 34790Sstevel@tonic-gate CS_EVENT_CARD_REMOVAL, 34800Sstevel@tonic-gate CS_EVENT_PRI_LOW); 34810Sstevel@tonic-gate break; 34820Sstevel@tonic-gate /* 34830Sstevel@tonic-gate * The hardware card removal events are handed 34840Sstevel@tonic-gate * to the client in cs_event at high 34850Sstevel@tonic-gate * priority interrupt time; this card 34860Sstevel@tonic-gate * removal event is a software-generated 34870Sstevel@tonic-gate * event. 34880Sstevel@tonic-gate */ 34890Sstevel@tonic-gate case CS_EVENT_CARD_REMOVAL: 34900Sstevel@tonic-gate if (client->flags & CLIENT_CARD_INSERTED) { 34910Sstevel@tonic-gate mutex_enter(&sp->lock); 34920Sstevel@tonic-gate client->flags &= 34930Sstevel@tonic-gate ~(CLIENT_CARD_INSERTED | 34940Sstevel@tonic-gate CLIENT_SENT_INSERTION); 34950Sstevel@tonic-gate mutex_exit(&sp->lock); 34960Sstevel@tonic-gate CLIENT_EVENT_CALLBACK(client, event, 34970Sstevel@tonic-gate CS_EVENT_PRI_LOW); 34980Sstevel@tonic-gate } 34990Sstevel@tonic-gate break; 35000Sstevel@tonic-gate /* 35010Sstevel@tonic-gate * Write protect events require the info field 35020Sstevel@tonic-gate * of the client's event callback args to 35030Sstevel@tonic-gate * be zero if the card is not write 35040Sstevel@tonic-gate * protected and one if it is. 35050Sstevel@tonic-gate */ 35060Sstevel@tonic-gate case CS_EVENT_WRITE_PROTECT: 35070Sstevel@tonic-gate if (client->flags & CLIENT_CARD_INSERTED) { 35080Sstevel@tonic-gate get_ss_status_t gs; 35090Sstevel@tonic-gate 35100Sstevel@tonic-gate mutex_enter(&sp->cis_lock); 35110Sstevel@tonic-gate mutex_enter(&sp->lock); 35120Sstevel@tonic-gate (void) cs_read_event_status(sp, client, 35130Sstevel@tonic-gate NULL, 35140Sstevel@tonic-gate &gs, 0); 35150Sstevel@tonic-gate if (gs.CardState & SBM_WP) { 35160Sstevel@tonic-gate client->event_callback_args.info = 35170Sstevel@tonic-gate (void *) 35180Sstevel@tonic-gate CS_EVENT_WRITE_PROTECT_WPON; 35190Sstevel@tonic-gate } else { 35200Sstevel@tonic-gate client->event_callback_args.info = 35210Sstevel@tonic-gate (void *) 35220Sstevel@tonic-gate CS_EVENT_WRITE_PROTECT_WPOFF; 35230Sstevel@tonic-gate } 35240Sstevel@tonic-gate mutex_exit(&sp->lock); 35250Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 35260Sstevel@tonic-gate CLIENT_EVENT_CALLBACK(client, event, 35270Sstevel@tonic-gate CS_EVENT_PRI_LOW); 35280Sstevel@tonic-gate } /* CLIENT_CARD_INSERTED */ 35290Sstevel@tonic-gate break; 35300Sstevel@tonic-gate case CS_EVENT_CLIENT_INFO: 35310Sstevel@tonic-gate CLIENT_EVENT_CALLBACK(client, event, 35320Sstevel@tonic-gate CS_EVENT_PRI_LOW); 35330Sstevel@tonic-gate break; 35340Sstevel@tonic-gate case 0: 35350Sstevel@tonic-gate break; 35360Sstevel@tonic-gate default: 35370Sstevel@tonic-gate if (client->flags & CLIENT_CARD_INSERTED) { 35380Sstevel@tonic-gate CLIENT_EVENT_CALLBACK(client, event, 35390Sstevel@tonic-gate CS_EVENT_PRI_LOW); 35400Sstevel@tonic-gate } 35410Sstevel@tonic-gate break; 35420Sstevel@tonic-gate } /* switch */ 35430Sstevel@tonic-gate mutex_enter(&sp->lock); 35440Sstevel@tonic-gate CS_BIT_CLEAR(client->events, bit); 35450Sstevel@tonic-gate mutex_exit(&sp->lock); 35460Sstevel@tonic-gate bit++; 35470Sstevel@tonic-gate } /* while (client->events) */ 35480Sstevel@tonic-gate } /* if (ct->type) */ 35490Sstevel@tonic-gate if (ct->order & CLIENT_EVENTS_LIFO) { 35500Sstevel@tonic-gate client = client->prev; 35510Sstevel@tonic-gate } else { 35520Sstevel@tonic-gate client = client->next; 35530Sstevel@tonic-gate } 35540Sstevel@tonic-gate } /* while (client) */ 35550Sstevel@tonic-gate 35560Sstevel@tonic-gate ct = ct->next; 35570Sstevel@tonic-gate } /* while (ct) */ 35580Sstevel@tonic-gate 35590Sstevel@tonic-gate /* 35600Sstevel@tonic-gate * Handle CS_EVENT_CARD_REMOVAL events 35610Sstevel@tonic-gate */ 35620Sstevel@tonic-gate if (sp->events & CS_EVENT_CARD_REMOVAL) { 35630Sstevel@tonic-gate mutex_enter(&sp->lock); 35640Sstevel@tonic-gate sp->events &= ~CS_EVENT_CARD_REMOVAL; 35650Sstevel@tonic-gate mutex_exit(&sp->lock); 35660Sstevel@tonic-gate (void) cs_card_removal(sp); 35670Sstevel@tonic-gate } /* if (CS_EVENT_CARD_REMOVAL) */ 35680Sstevel@tonic-gate 35690Sstevel@tonic-gate /* 35700Sstevel@tonic-gate * If someone is waiting for us to complete, signal them now. 35710Sstevel@tonic-gate */ 35720Sstevel@tonic-gate if (sp->thread_state & SOCKET_WAIT_SYNC) { 35730Sstevel@tonic-gate mutex_enter(&sp->lock); 35740Sstevel@tonic-gate sp->thread_state &= ~SOCKET_WAIT_SYNC; 35750Sstevel@tonic-gate mutex_exit(&sp->lock); 35760Sstevel@tonic-gate cv_broadcast(&sp->caller_cv); 35770Sstevel@tonic-gate } /* SOCKET_WAIT_SYNC */ 35780Sstevel@tonic-gate 35790Sstevel@tonic-gate } /* for (;;) */ 35800Sstevel@tonic-gate } 35810Sstevel@tonic-gate 35820Sstevel@tonic-gate /* 35830Sstevel@tonic-gate * cs_card_for_client - checks to see if a card that the client can control 35840Sstevel@tonic-gate * is currently inserted in the socket. Socket Services 35850Sstevel@tonic-gate * has to tell us if this is the case. 35860Sstevel@tonic-gate */ 35870Sstevel@tonic-gate static int 35880Sstevel@tonic-gate cs_card_for_client(client_t *client) 35890Sstevel@tonic-gate { 35900Sstevel@tonic-gate 35910Sstevel@tonic-gate /* 35920Sstevel@tonic-gate * If the client has set the CS_EVENT_ALL_CLIENTS it means that they 35930Sstevel@tonic-gate * want to get all events for all clients, irrespective of 35940Sstevel@tonic-gate * whether or not there is a card in the socket. Such clients 35950Sstevel@tonic-gate * have to be very careful if they touch the card hardware in 35960Sstevel@tonic-gate * any way to prevent causing problems for other clients on the 35970Sstevel@tonic-gate * same socket. This flag will typically only be set by the 35980Sstevel@tonic-gate * "super-client" or CSI types of clients that wish to get 35990Sstevel@tonic-gate * information on other clients or cards in the system. 36000Sstevel@tonic-gate * Note that the CS_EVENT_ALL_CLIENTS must be set in either the 36010Sstevel@tonic-gate * client's global event mask or client event mask. 36020Sstevel@tonic-gate * The client must also have registered as a "super-client" or as a 36030Sstevel@tonic-gate * CSI client for this socket. 36040Sstevel@tonic-gate */ 36050Sstevel@tonic-gate if ((client->flags & (CLIENT_SUPER_CLIENT | CLIENT_CSI_CLIENT)) && 36060Sstevel@tonic-gate ((client->global_mask | client->event_mask) & 36070Sstevel@tonic-gate CS_EVENT_ALL_CLIENTS)) 36080Sstevel@tonic-gate return (1); 36090Sstevel@tonic-gate 36100Sstevel@tonic-gate /* 36110Sstevel@tonic-gate * Look for the PCM_DEV_ACTIVE property on this client's dip; if 36120Sstevel@tonic-gate * it's found, it means that this client can control the card 36130Sstevel@tonic-gate * that is currently in the socket. This is a boolean 36140Sstevel@tonic-gate * property managed by Socket Services. 36150Sstevel@tonic-gate */ 36160Sstevel@tonic-gate if (ddi_getprop(DDI_DEV_T_ANY, client->dip, (DDI_PROP_CANSLEEP | 36170Sstevel@tonic-gate DDI_PROP_NOTPROM), 36180Sstevel@tonic-gate PCM_DEV_ACTIVE, NULL)) { 36190Sstevel@tonic-gate #ifdef CS_DEBUG 36200Sstevel@tonic-gate if (cs_debug > 1) { 36210Sstevel@tonic-gate cmn_err(CE_CONT, "cs_card_for_client: client handle 0x%x " 36220Sstevel@tonic-gate "driver [%s] says %s found\n", 36230Sstevel@tonic-gate (int)client->client_handle, 36240Sstevel@tonic-gate client->driver_name, 36250Sstevel@tonic-gate PCM_DEV_ACTIVE); 36260Sstevel@tonic-gate } 36270Sstevel@tonic-gate #endif 36280Sstevel@tonic-gate return (1); 36290Sstevel@tonic-gate } 36300Sstevel@tonic-gate 36310Sstevel@tonic-gate return (0); 36320Sstevel@tonic-gate } 36330Sstevel@tonic-gate 36340Sstevel@tonic-gate /* 36350Sstevel@tonic-gate * cs_ss_thread - This is the Socket Services work thread. We fire off 36360Sstevel@tonic-gate * any calls to Socket Services here that we want 36370Sstevel@tonic-gate * to run on a thread that is seperate from the 36380Sstevel@tonic-gate * per-socket event thread. 36390Sstevel@tonic-gate */ 36400Sstevel@tonic-gate static void 36410Sstevel@tonic-gate cs_ss_thread(uint32_t sn) 36420Sstevel@tonic-gate { 36430Sstevel@tonic-gate cs_socket_t *sp; 36440Sstevel@tonic-gate 36450Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) == NULL) 36460Sstevel@tonic-gate return; 36470Sstevel@tonic-gate 36480Sstevel@tonic-gate /* 36490Sstevel@tonic-gate * Tell CPR that we've started a new thread. 36500Sstevel@tonic-gate */ 36510Sstevel@tonic-gate CALLB_CPR_INIT(&sp->cprinfo_ss, &sp->ss_thread_lock, 36520Sstevel@tonic-gate callb_generic_cpr, "cs_ss_thread"); 36530Sstevel@tonic-gate 36540Sstevel@tonic-gate mutex_enter(&sp->ss_thread_lock); 36550Sstevel@tonic-gate 36560Sstevel@tonic-gate for (;;) { 36570Sstevel@tonic-gate 36580Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&sp->cprinfo_ss); 36590Sstevel@tonic-gate cv_wait(&sp->ss_thread_cv, &sp->ss_thread_lock); 36600Sstevel@tonic-gate CALLB_CPR_SAFE_END(&sp->cprinfo_ss, &sp->ss_thread_lock); 36610Sstevel@tonic-gate 36620Sstevel@tonic-gate /* 36630Sstevel@tonic-gate * Check to see if there are any special thread operations 36640Sstevel@tonic-gate * that we are being asked to perform. 36650Sstevel@tonic-gate */ 36660Sstevel@tonic-gate if (sp->ss_thread_state & SOCKET_THREAD_EXIT) { 36670Sstevel@tonic-gate #ifdef CS_DEBUG 36680Sstevel@tonic-gate if (cs_debug > 1) { 36690Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ss_thread: socket %d " 36700Sstevel@tonic-gate "SOCKET_THREAD_EXIT\n", 36710Sstevel@tonic-gate sp->socket_num); 36720Sstevel@tonic-gate } 36730Sstevel@tonic-gate #endif 36740Sstevel@tonic-gate CALLB_CPR_EXIT(&sp->cprinfo_ss); 36750Sstevel@tonic-gate cv_broadcast(&sp->ss_caller_cv); /* wake up cs_deinit */ 36760Sstevel@tonic-gate mutex_exit(&sp->ss_thread_lock); 36770Sstevel@tonic-gate return; 36780Sstevel@tonic-gate } /* if (SOCKET_THREAD_EXIT) */ 36790Sstevel@tonic-gate 36800Sstevel@tonic-gate #ifdef CS_DEBUG 36810Sstevel@tonic-gate if (cs_debug > 1) { 36820Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ss_thread: socket %d " 36830Sstevel@tonic-gate "ss_thread_state = 0x%x\n", 36840Sstevel@tonic-gate (int)sp->socket_num, 36850Sstevel@tonic-gate (int)sp->ss_thread_state); 36860Sstevel@tonic-gate } 36870Sstevel@tonic-gate #endif 36880Sstevel@tonic-gate 36890Sstevel@tonic-gate /* 36900Sstevel@tonic-gate * Call SocketServices(CSCISInit) to have SS parse the 36910Sstevel@tonic-gate * CIS and load/attach any client drivers necessary. 36920Sstevel@tonic-gate */ 36930Sstevel@tonic-gate if (sp->ss_thread_state & SOCKET_THREAD_CSCISInit) { 36940Sstevel@tonic-gate 36950Sstevel@tonic-gate sp->ss_thread_state &= ~SOCKET_THREAD_CSCISInit; 36960Sstevel@tonic-gate 36970Sstevel@tonic-gate if (!(sp->flags & SOCKET_CARD_INSERTED)) { 36980Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ss_thread %d " 36990Sstevel@tonic-gate "card NOT inserted\n", 37000Sstevel@tonic-gate sp->socket_num); 37010Sstevel@tonic-gate } 37020Sstevel@tonic-gate 37030Sstevel@tonic-gate #ifdef CS_DEBUG 37040Sstevel@tonic-gate if (cs_debug > 1) { 37050Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ss_thread: socket %d calling " 37060Sstevel@tonic-gate "CSCISInit\n", sp->socket_num); 37070Sstevel@tonic-gate } 37080Sstevel@tonic-gate #endif 37090Sstevel@tonic-gate 37100Sstevel@tonic-gate /* 37110Sstevel@tonic-gate * Tell SS that we have a complete CIS and that it can now 37120Sstevel@tonic-gate * be parsed. 37130Sstevel@tonic-gate * Note that in some cases the client driver may block in 37140Sstevel@tonic-gate * their attach routine, causing this call to block until 37150Sstevel@tonic-gate * the client completes their attach. 37160Sstevel@tonic-gate */ 37170Sstevel@tonic-gate SocketServices(CSCISInit, sp->socket_num); 37180Sstevel@tonic-gate 37190Sstevel@tonic-gate /* 37200Sstevel@tonic-gate * Set the CS_EVENT_SS_UPDATED event for this socket so that the 37210Sstevel@tonic-gate * event thread can continue any card insertion processing 37220Sstevel@tonic-gate * that it has to do. 37230Sstevel@tonic-gate */ 37240Sstevel@tonic-gate mutex_enter(&sp->lock); 37250Sstevel@tonic-gate sp->events |= CS_EVENT_SS_UPDATED; 37260Sstevel@tonic-gate mutex_exit(&sp->lock); 37270Sstevel@tonic-gate 37280Sstevel@tonic-gate /* 37290Sstevel@tonic-gate * Wake up this socket's event thread so that clients can 37300Sstevel@tonic-gate * continue any card insertion or attach processing 37310Sstevel@tonic-gate * that they need to do. 37320Sstevel@tonic-gate */ 37330Sstevel@tonic-gate cv_broadcast(&sp->thread_cv); 37340Sstevel@tonic-gate } /* if ST_CSCISInit */ 37350Sstevel@tonic-gate 37360Sstevel@tonic-gate } /* for (;;) */ 37370Sstevel@tonic-gate } 37380Sstevel@tonic-gate 37390Sstevel@tonic-gate /* 37400Sstevel@tonic-gate * cs_request_socket_mask - set the client's event mask as well as causes 37410Sstevel@tonic-gate * any events pending from RegisterClient to 37420Sstevel@tonic-gate * be scheduled to be sent to the client 37430Sstevel@tonic-gate */ 37440Sstevel@tonic-gate static int 37450Sstevel@tonic-gate cs_request_socket_mask(client_handle_t client_handle, 37460Sstevel@tonic-gate request_socket_mask_t *se) 37470Sstevel@tonic-gate { 37480Sstevel@tonic-gate cs_socket_t *sp; 37490Sstevel@tonic-gate client_t *client; 37500Sstevel@tonic-gate int error; 37510Sstevel@tonic-gate int client_lock_acquired; 37520Sstevel@tonic-gate 37530Sstevel@tonic-gate /* 37540Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it 37550Sstevel@tonic-gate * is, we don't do anything except for return success. 37560Sstevel@tonic-gate */ 37570Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) 37580Sstevel@tonic-gate return (CS_SUCCESS); 37590Sstevel@tonic-gate 37600Sstevel@tonic-gate /* 37610Sstevel@tonic-gate * Get a pointer to this client's socket structure. 37620Sstevel@tonic-gate */ 37630Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) 37640Sstevel@tonic-gate return (CS_BAD_SOCKET); 37650Sstevel@tonic-gate 37660Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 37670Sstevel@tonic-gate 37680Sstevel@tonic-gate /* 37690Sstevel@tonic-gate * Make sure that this is a valid client handle. 37700Sstevel@tonic-gate */ 37710Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) { 37720Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 37730Sstevel@tonic-gate return (error); 37740Sstevel@tonic-gate } 37750Sstevel@tonic-gate 37760Sstevel@tonic-gate mutex_enter(&sp->lock); 37770Sstevel@tonic-gate 37780Sstevel@tonic-gate /* 37790Sstevel@tonic-gate * If this client has already done a RequestSocketMask without 37800Sstevel@tonic-gate * a corresponding ReleaseSocketMask, then return an error. 37810Sstevel@tonic-gate */ 37820Sstevel@tonic-gate if (client->flags & REQ_SOCKET_MASK_DONE) { 37830Sstevel@tonic-gate mutex_exit(&sp->lock); 37840Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 37850Sstevel@tonic-gate return (CS_IN_USE); 37860Sstevel@tonic-gate } 37870Sstevel@tonic-gate 37880Sstevel@tonic-gate /* 37890Sstevel@tonic-gate * Set up the event mask information; we copy this directly from 37900Sstevel@tonic-gate * the client; since we are the only source of events, any 37910Sstevel@tonic-gate * bogus bits that the client puts in here won't matter 37920Sstevel@tonic-gate * because we'll never look at them. 37930Sstevel@tonic-gate */ 37940Sstevel@tonic-gate client->event_mask = se->EventMask; 37950Sstevel@tonic-gate 37960Sstevel@tonic-gate /* 37970Sstevel@tonic-gate * If RegisterClient left us some events to process, set these 37980Sstevel@tonic-gate * events up here. 37990Sstevel@tonic-gate */ 38000Sstevel@tonic-gate if (client->pending_events) { 38010Sstevel@tonic-gate client->events |= client->pending_events; 38020Sstevel@tonic-gate client->pending_events = 0; 38030Sstevel@tonic-gate #ifdef CS_DEBUG 38040Sstevel@tonic-gate if (cs_debug > 1) { 38050Sstevel@tonic-gate cmn_err(CE_CONT, "cs_request_socket_mask: client_handle = 0x%x " 38060Sstevel@tonic-gate "driver_name = [%s] events = 0x%x\n", 38070Sstevel@tonic-gate (int)client->client_handle, 38080Sstevel@tonic-gate client->driver_name, 38090Sstevel@tonic-gate (int)client->events); 38100Sstevel@tonic-gate } 38110Sstevel@tonic-gate #endif 38120Sstevel@tonic-gate } 38130Sstevel@tonic-gate 38140Sstevel@tonic-gate client->flags |= REQ_SOCKET_MASK_DONE; 38150Sstevel@tonic-gate 38160Sstevel@tonic-gate /* 38170Sstevel@tonic-gate * Merge all the clients' event masks and set the socket 38180Sstevel@tonic-gate * to generate the appropriate events. 38190Sstevel@tonic-gate */ 38200Sstevel@tonic-gate (void) cs_set_socket_event_mask(sp, cs_merge_event_masks(sp, client)); 38210Sstevel@tonic-gate 38220Sstevel@tonic-gate mutex_exit(&sp->lock); 38230Sstevel@tonic-gate 38240Sstevel@tonic-gate /* 38250Sstevel@tonic-gate * Wakeup the event thread if there are any client events to process. 38260Sstevel@tonic-gate */ 38270Sstevel@tonic-gate if (client->events) { 38280Sstevel@tonic-gate cv_broadcast(&sp->thread_cv); 38290Sstevel@tonic-gate #ifdef CS_DEBUG 38300Sstevel@tonic-gate if (cs_debug > 1) { 38310Sstevel@tonic-gate cmn_err(CE_CONT, "cs_request_socket_mask: did cv_broadcast for " 38320Sstevel@tonic-gate "client_handle = 0x%x " 38330Sstevel@tonic-gate "driver_name = [%s] events = 0x%x\n", 38340Sstevel@tonic-gate (int)client->client_handle, 38350Sstevel@tonic-gate client->driver_name, 38360Sstevel@tonic-gate (int)client->events); 38370Sstevel@tonic-gate } 38380Sstevel@tonic-gate #endif 38390Sstevel@tonic-gate 38400Sstevel@tonic-gate } 38410Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 38420Sstevel@tonic-gate 38430Sstevel@tonic-gate return (CS_SUCCESS); 38440Sstevel@tonic-gate } 38450Sstevel@tonic-gate 38460Sstevel@tonic-gate /* 38470Sstevel@tonic-gate * cs_release_socket_mask - clear the client's event mask 38480Sstevel@tonic-gate * 38490Sstevel@tonic-gate * Once this function returns, the client is guaranteed 38500Sstevel@tonic-gate * not to get any more event callbacks. 38510Sstevel@tonic-gate */ 38520Sstevel@tonic-gate /*ARGSUSED*/ 38530Sstevel@tonic-gate static int 38540Sstevel@tonic-gate cs_release_socket_mask(client_handle_t client_handle, 38550Sstevel@tonic-gate release_socket_mask_t *rsm) 38560Sstevel@tonic-gate { 38570Sstevel@tonic-gate cs_socket_t *sp; 38580Sstevel@tonic-gate client_t *client; 38590Sstevel@tonic-gate int error; 38600Sstevel@tonic-gate int client_lock_acquired; 38610Sstevel@tonic-gate 38620Sstevel@tonic-gate /* 38630Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it 38640Sstevel@tonic-gate * is, we don't do anything except for return success. 38650Sstevel@tonic-gate */ 38660Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) 38670Sstevel@tonic-gate return (CS_SUCCESS); 38680Sstevel@tonic-gate 38690Sstevel@tonic-gate /* 38700Sstevel@tonic-gate * Get a pointer to this client's socket structure. 38710Sstevel@tonic-gate */ 38720Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) 38730Sstevel@tonic-gate return (CS_BAD_SOCKET); 38740Sstevel@tonic-gate 38750Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 38760Sstevel@tonic-gate 38770Sstevel@tonic-gate /* 38780Sstevel@tonic-gate * Make sure that this is a valid client handle. 38790Sstevel@tonic-gate */ 38800Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) { 38810Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 38820Sstevel@tonic-gate return (error); 38830Sstevel@tonic-gate } 38840Sstevel@tonic-gate 38850Sstevel@tonic-gate mutex_enter(&sp->lock); 38860Sstevel@tonic-gate 38870Sstevel@tonic-gate /* 38880Sstevel@tonic-gate * If this client has already done a RequestSocketMask without 38890Sstevel@tonic-gate * a corresponding ReleaseSocketMask, then return an error. 38900Sstevel@tonic-gate */ 38910Sstevel@tonic-gate if (!(client->flags & REQ_SOCKET_MASK_DONE)) { 38920Sstevel@tonic-gate mutex_exit(&sp->lock); 38930Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 38940Sstevel@tonic-gate return (CS_BAD_SOCKET); 38950Sstevel@tonic-gate } 38960Sstevel@tonic-gate 38970Sstevel@tonic-gate /* 38980Sstevel@tonic-gate * Clear both the client event mask and the global event mask. 38990Sstevel@tonic-gate * We clear both since the semantics of this function are 39000Sstevel@tonic-gate * that once it returns, the client will not be called at 39010Sstevel@tonic-gate * it's event handler for any events until RequestSocketMask 39020Sstevel@tonic-gate * is called again. 39030Sstevel@tonic-gate */ 39040Sstevel@tonic-gate client->event_mask = 0; 39050Sstevel@tonic-gate client->global_mask = 0; 39060Sstevel@tonic-gate client->flags &= ~REQ_SOCKET_MASK_DONE; 39070Sstevel@tonic-gate 39080Sstevel@tonic-gate /* 39090Sstevel@tonic-gate * Merge all the clients' event masks and set the socket 39100Sstevel@tonic-gate * to generate the appropriate events. 39110Sstevel@tonic-gate */ 39120Sstevel@tonic-gate (void) cs_set_socket_event_mask(sp, cs_merge_event_masks(sp, client)); 39130Sstevel@tonic-gate 39140Sstevel@tonic-gate mutex_exit(&sp->lock); 39150Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 39160Sstevel@tonic-gate 39170Sstevel@tonic-gate return (CS_SUCCESS); 39180Sstevel@tonic-gate } 39190Sstevel@tonic-gate 39200Sstevel@tonic-gate /* 39210Sstevel@tonic-gate * cs_get_event_mask - return the event mask for this client 39220Sstevel@tonic-gate */ 39230Sstevel@tonic-gate static int 39240Sstevel@tonic-gate cs_get_event_mask(client_handle_t client_handle, sockevent_t *se) 39250Sstevel@tonic-gate { 39260Sstevel@tonic-gate cs_socket_t *sp; 39270Sstevel@tonic-gate client_t *client; 39280Sstevel@tonic-gate int error; 39290Sstevel@tonic-gate int client_lock_acquired; 39300Sstevel@tonic-gate 39310Sstevel@tonic-gate /* 39320Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it 39330Sstevel@tonic-gate * is, we don't do anything except for return success. 39340Sstevel@tonic-gate */ 39350Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) 39360Sstevel@tonic-gate return (CS_SUCCESS); 39370Sstevel@tonic-gate 39380Sstevel@tonic-gate /* 39390Sstevel@tonic-gate * Get a pointer to this client's socket structure. 39400Sstevel@tonic-gate */ 39410Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) 39420Sstevel@tonic-gate return (CS_BAD_SOCKET); 39430Sstevel@tonic-gate 39440Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 39450Sstevel@tonic-gate 39460Sstevel@tonic-gate /* 39470Sstevel@tonic-gate * Make sure that this is a valid client handle. 39480Sstevel@tonic-gate */ 39490Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) { 39500Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 39510Sstevel@tonic-gate return (error); 39520Sstevel@tonic-gate } 39530Sstevel@tonic-gate 39540Sstevel@tonic-gate mutex_enter(&sp->lock); 39550Sstevel@tonic-gate 39560Sstevel@tonic-gate #ifdef XXX 39570Sstevel@tonic-gate /* 39580Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not 39590Sstevel@tonic-gate * for this client, then return an error. 39600Sstevel@tonic-gate * XXX - how can a client get their event masks if their card 39610Sstevel@tonic-gate * goes away? 39620Sstevel@tonic-gate */ 39630Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) { 39640Sstevel@tonic-gate mutex_exit(&sp->lock); 39650Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 39660Sstevel@tonic-gate return (CS_NO_CARD); 39670Sstevel@tonic-gate } 39680Sstevel@tonic-gate #endif 39690Sstevel@tonic-gate 39700Sstevel@tonic-gate /* 39710Sstevel@tonic-gate * We are only allowed to get the client event mask if a 39720Sstevel@tonic-gate * RequestSocketMask has been called previously. We 39730Sstevel@tonic-gate * are allowed to get the global event mask at any 39740Sstevel@tonic-gate * time. 39750Sstevel@tonic-gate * The global event mask is initially set by the client 39760Sstevel@tonic-gate * in the call to RegisterClient. The client event 39770Sstevel@tonic-gate * mask is set by the client in calls to SetEventMask 39780Sstevel@tonic-gate * and RequestSocketMask and gotten in calls to 39790Sstevel@tonic-gate * GetEventMask. 39800Sstevel@tonic-gate */ 39810Sstevel@tonic-gate if (se->Attributes & CONF_EVENT_MASK_CLIENT) { 39820Sstevel@tonic-gate if (!(client->flags & REQ_SOCKET_MASK_DONE)) { 39830Sstevel@tonic-gate mutex_exit(&sp->lock); 39840Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 39850Sstevel@tonic-gate return (CS_BAD_SOCKET); 39860Sstevel@tonic-gate } 39870Sstevel@tonic-gate se->EventMask = client->event_mask; 39880Sstevel@tonic-gate } else { 39890Sstevel@tonic-gate se->EventMask = client->global_mask; 39900Sstevel@tonic-gate } 39910Sstevel@tonic-gate 39920Sstevel@tonic-gate mutex_exit(&sp->lock); 39930Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 39940Sstevel@tonic-gate 39950Sstevel@tonic-gate return (CS_SUCCESS); 39960Sstevel@tonic-gate } 39970Sstevel@tonic-gate 39980Sstevel@tonic-gate /* 39990Sstevel@tonic-gate * cs_set_event_mask - set the event mask for this client 40000Sstevel@tonic-gate */ 40010Sstevel@tonic-gate static int 40020Sstevel@tonic-gate cs_set_event_mask(client_handle_t client_handle, sockevent_t *se) 40030Sstevel@tonic-gate { 40040Sstevel@tonic-gate cs_socket_t *sp; 40050Sstevel@tonic-gate client_t *client; 40060Sstevel@tonic-gate int error; 40070Sstevel@tonic-gate int client_lock_acquired; 40080Sstevel@tonic-gate 40090Sstevel@tonic-gate /* 40100Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it 40110Sstevel@tonic-gate * is, we don't do anything except for return success. 40120Sstevel@tonic-gate */ 40130Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) 40140Sstevel@tonic-gate return (CS_SUCCESS); 40150Sstevel@tonic-gate 40160Sstevel@tonic-gate /* 40170Sstevel@tonic-gate * Get a pointer to this client's socket structure. 40180Sstevel@tonic-gate */ 40190Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) 40200Sstevel@tonic-gate return (CS_BAD_SOCKET); 40210Sstevel@tonic-gate 40220Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 40230Sstevel@tonic-gate 40240Sstevel@tonic-gate /* 40250Sstevel@tonic-gate * Make sure that this is a valid client handle. 40260Sstevel@tonic-gate */ 40270Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) { 40280Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 40290Sstevel@tonic-gate return (error); 40300Sstevel@tonic-gate } 40310Sstevel@tonic-gate 40320Sstevel@tonic-gate mutex_enter(&sp->lock); 40330Sstevel@tonic-gate 40340Sstevel@tonic-gate #ifdef XXX 40350Sstevel@tonic-gate /* 40360Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not 40370Sstevel@tonic-gate * for this client, then return an error. 40380Sstevel@tonic-gate */ 40390Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) { 40400Sstevel@tonic-gate mutex_exit(&sp->lock); 40410Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 40420Sstevel@tonic-gate return (CS_NO_CARD); 40430Sstevel@tonic-gate } 40440Sstevel@tonic-gate #endif 40450Sstevel@tonic-gate 40460Sstevel@tonic-gate /* 40470Sstevel@tonic-gate * We are only allowed to set the client event mask if a 40480Sstevel@tonic-gate * RequestSocketMask has been called previously. We 40490Sstevel@tonic-gate * are allowed to set the global event mask at any 40500Sstevel@tonic-gate * time. 40510Sstevel@tonic-gate * The global event mask is initially set by the client 40520Sstevel@tonic-gate * in the call to RegisterClient. The client event 40530Sstevel@tonic-gate * mask is set by the client in calls to SetEventMask 40540Sstevel@tonic-gate * and RequestSocketMask and gotten in calls to 40550Sstevel@tonic-gate * GetEventMask. 40560Sstevel@tonic-gate */ 40570Sstevel@tonic-gate if (se->Attributes & CONF_EVENT_MASK_CLIENT) { 40580Sstevel@tonic-gate if (!(client->flags & REQ_SOCKET_MASK_DONE)) { 40590Sstevel@tonic-gate mutex_exit(&sp->lock); 40600Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 40610Sstevel@tonic-gate return (CS_BAD_SOCKET); 40620Sstevel@tonic-gate } 40630Sstevel@tonic-gate client->event_mask = se->EventMask; 40640Sstevel@tonic-gate } else { 40650Sstevel@tonic-gate client->global_mask = se->EventMask; 40660Sstevel@tonic-gate } 40670Sstevel@tonic-gate 40680Sstevel@tonic-gate /* 40690Sstevel@tonic-gate * Merge all the clients' event masks and set the socket 40700Sstevel@tonic-gate * to generate the appropriate events. 40710Sstevel@tonic-gate */ 40720Sstevel@tonic-gate (void) cs_set_socket_event_mask(sp, cs_merge_event_masks(sp, client)); 40730Sstevel@tonic-gate 40740Sstevel@tonic-gate mutex_exit(&sp->lock); 40750Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 40760Sstevel@tonic-gate 40770Sstevel@tonic-gate return (CS_SUCCESS); 40780Sstevel@tonic-gate } 40790Sstevel@tonic-gate 40800Sstevel@tonic-gate /* 40810Sstevel@tonic-gate * cs_read_event_status - handles PRR events and returns card status 40820Sstevel@tonic-gate * 40830Sstevel@tonic-gate * calling: *sp - socket struct point 40840Sstevel@tonic-gate * *client - client to check events on 40850Sstevel@tonic-gate * *revent - pointer to event mask to update; if NULL, will 40860Sstevel@tonic-gate * not be updated, if non-NULL, will be updated 40870Sstevel@tonic-gate * with CS-format events; it is NOT necessary 40880Sstevel@tonic-gate * to clear this value before calling this 40890Sstevel@tonic-gate * function 40900Sstevel@tonic-gate * *gs - pointer to a get_ss_status_t used for the SS GetStatus 40910Sstevel@tonic-gate * call; it is not necessary to initialize any 40920Sstevel@tonic-gate * members in this structure; set to NULL if 40930Sstevel@tonic-gate * not used 40940Sstevel@tonic-gate * flags - if CS_RES_IGNORE_NO_CARD is set, the check for a 40950Sstevel@tonic-gate * card present will not be done 40960Sstevel@tonic-gate * 40970Sstevel@tonic-gate * returns: CS_SUCCESS 40980Sstevel@tonic-gate * CS_NO_CARD - if no card is in the socket and the flags arg 40990Sstevel@tonic-gate * is not set to CS_RES_IGNORE_NO_CARD 41000Sstevel@tonic-gate * CS_BAD_SOCKET - if the SS_GetStatus function returned an 41010Sstevel@tonic-gate * error 41020Sstevel@tonic-gate * 41030Sstevel@tonic-gate * Note that if the client that configured this socket has told us that 41040Sstevel@tonic-gate * the READY pin in the PRR isn't valid and the socket is in IO 41050Sstevel@tonic-gate * mode, we always return that the card is READY. 41060Sstevel@tonic-gate * 41070Sstevel@tonic-gate * Note that if gs is not NULL, the current card state will be returned 41080Sstevel@tonic-gate * in the gs->CardState member; this will always reflect the 41090Sstevel@tonic-gate * current card state and the state will come from both the 41100Sstevel@tonic-gate * SS_GetStatus call and the PRR, whichever is appropriate for 41110Sstevel@tonic-gate * the mode that the socket is currently in. 41120Sstevel@tonic-gate */ 41130Sstevel@tonic-gate static int 41140Sstevel@tonic-gate cs_read_event_status(cs_socket_t *sp, client_t *client, event_t *revent, 41150Sstevel@tonic-gate get_ss_status_t *gs, int flags) 41160Sstevel@tonic-gate { 41170Sstevel@tonic-gate cfg_regs_t prrd = 0; 41180Sstevel@tonic-gate 41190Sstevel@tonic-gate /* 41200Sstevel@tonic-gate * SOCKET_IS_IO will only be set if a RequestConfiguration 41210Sstevel@tonic-gate * has been done by at least one client on this socket. 41220Sstevel@tonic-gate * If there isn't a card in the socket or the caller wants to ignore 41230Sstevel@tonic-gate * whether the card is in the socket or not, get the current 41240Sstevel@tonic-gate * card status. 41250Sstevel@tonic-gate */ 41260Sstevel@tonic-gate if ((sp->flags & SOCKET_CARD_INSERTED) || 41270Sstevel@tonic-gate (flags & CS_RES_IGNORE_NO_CARD)) { 41280Sstevel@tonic-gate if (sp->flags & SOCKET_IS_IO) { 41290Sstevel@tonic-gate if (client->present & CONFIG_PINREPL_REG_PRESENT) { 41300Sstevel@tonic-gate acc_handle_t cis_handle; 41310Sstevel@tonic-gate uint32_t newoffset = client->config_regs_offset; 41320Sstevel@tonic-gate 41330Sstevel@tonic-gate /* 41340Sstevel@tonic-gate * Get a handle to the CIS window 41350Sstevel@tonic-gate */ 41360Sstevel@tonic-gate if (cs_init_cis_window(sp, &newoffset, &cis_handle, 41370Sstevel@tonic-gate CISTPLF_AM_SPACE) != CS_SUCCESS) { 41380Sstevel@tonic-gate cmn_err(CE_CONT, "cs_read_event_status: socket %d " 41390Sstevel@tonic-gate "can't init CIS window\n", 41400Sstevel@tonic-gate sp->socket_num); 41410Sstevel@tonic-gate return (CS_GENERAL_FAILURE); 41420Sstevel@tonic-gate } /* cs_init_cis_window */ 41430Sstevel@tonic-gate 41440Sstevel@tonic-gate prrd = csx_Get8(cis_handle, client->config_regs.prr_p); 41450Sstevel@tonic-gate prrd &= client->pin; 41460Sstevel@tonic-gate 41470Sstevel@tonic-gate #ifdef CS_DEBUG 41480Sstevel@tonic-gate if (cs_debug > 1) { 41490Sstevel@tonic-gate cmn_err(CE_CONT, "cs_read_event_status: " 41500Sstevel@tonic-gate "prrd 0x%x client->pin 0x%x\n", 41510Sstevel@tonic-gate (int)prrd, 41520Sstevel@tonic-gate client->pin); 41530Sstevel@tonic-gate cmn_err(CE_CONT, "PRR(1) = [%s%s%s%s%s%s%s%s]\n", 41540Sstevel@tonic-gate ((prrd & PRR_WP_STATUS)? 41550Sstevel@tonic-gate "PRR_WP_STATUS ":""), 41560Sstevel@tonic-gate ((prrd & PRR_READY_STATUS)? 41570Sstevel@tonic-gate "PRR_READY_STATUS ":""), 41580Sstevel@tonic-gate ((prrd & PRR_BVD2_STATUS)? 41590Sstevel@tonic-gate "PRR_BVD2_STATUS ":""), 41600Sstevel@tonic-gate ((prrd & PRR_BVD1_STATUS)? 41610Sstevel@tonic-gate "PRR_BVD1_STATUS ":""), 41620Sstevel@tonic-gate ((prrd & PRR_WP_EVENT)? 41630Sstevel@tonic-gate "PRR_WP_EVENT ":""), 41640Sstevel@tonic-gate ((prrd & PRR_READY_EVENT)? 41650Sstevel@tonic-gate "PRR_READY_EVENT ":""), 41660Sstevel@tonic-gate ((prrd & PRR_BVD2_EVENT)? 41670Sstevel@tonic-gate "PRR_BVD2_EVENT ":""), 41680Sstevel@tonic-gate ((prrd & PRR_BVD1_EVENT)? 41690Sstevel@tonic-gate "PRR_BVD1_EVENT ":"")); 41700Sstevel@tonic-gate } 41710Sstevel@tonic-gate #endif 41720Sstevel@tonic-gate 41730Sstevel@tonic-gate /* 41740Sstevel@tonic-gate * The caller wants the event changes sent back and 41750Sstevel@tonic-gate * the PRR event change bits cleared. 41760Sstevel@tonic-gate */ 41770Sstevel@tonic-gate if (revent) { 41780Sstevel@tonic-gate get_socket_t get_socket; 41790Sstevel@tonic-gate set_socket_t set_socket; 41800Sstevel@tonic-gate 41810Sstevel@tonic-gate /* 41820Sstevel@tonic-gate * Bug ID: 1193636 - Card Services sends bogus 41830Sstevel@tonic-gate * events on CS_EVENT_STATUS_CHANGE events 41840Sstevel@tonic-gate * Clear this before we OR-in any values. 41850Sstevel@tonic-gate */ 41860Sstevel@tonic-gate *revent = 0; 41870Sstevel@tonic-gate 41880Sstevel@tonic-gate PRR_EVENT(prrd, PRR_WP_EVENT, PRR_WP_STATUS, 41890Sstevel@tonic-gate CS_EVENT_WRITE_PROTECT, *revent); 41900Sstevel@tonic-gate 41910Sstevel@tonic-gate PRR_EVENT(prrd, PRR_READY_EVENT, PRR_READY_STATUS, 41920Sstevel@tonic-gate CS_EVENT_CARD_READY, *revent); 41930Sstevel@tonic-gate 41940Sstevel@tonic-gate PRR_EVENT(prrd, PRR_BVD2_EVENT, PRR_BVD2_STATUS, 41950Sstevel@tonic-gate CS_EVENT_BATTERY_LOW, *revent); 41960Sstevel@tonic-gate 41970Sstevel@tonic-gate PRR_EVENT(prrd, PRR_BVD1_EVENT, PRR_BVD1_STATUS, 41980Sstevel@tonic-gate CS_EVENT_BATTERY_DEAD, *revent); 41990Sstevel@tonic-gate 42000Sstevel@tonic-gate 42010Sstevel@tonic-gate #ifdef CS_DEBUG 42020Sstevel@tonic-gate if (cs_debug > 1) { 42030Sstevel@tonic-gate 42040Sstevel@tonic-gate cmn_err(CE_CONT, "PRR() = [%s%s%s%s%s%s%s%s]\n", 42050Sstevel@tonic-gate ((prrd & PRR_WP_STATUS)? 42060Sstevel@tonic-gate "PRR_WP_STATUS ":""), 42070Sstevel@tonic-gate ((prrd & PRR_READY_STATUS)? 42080Sstevel@tonic-gate "PRR_READY_STATUS ":""), 42090Sstevel@tonic-gate ((prrd & PRR_BVD2_STATUS)? 42100Sstevel@tonic-gate "PRR_BVD2_STATUS ":""), 42110Sstevel@tonic-gate ((prrd & PRR_BVD1_STATUS)? 42120Sstevel@tonic-gate "PRR_BVD1_STATUS ":""), 42130Sstevel@tonic-gate ((prrd & PRR_WP_EVENT)? 42140Sstevel@tonic-gate "PRR_WP_EVENT ":""), 42150Sstevel@tonic-gate ((prrd & PRR_READY_EVENT)? 42160Sstevel@tonic-gate "PRR_READY_EVENT ":""), 42170Sstevel@tonic-gate ((prrd & PRR_BVD2_EVENT)? 42180Sstevel@tonic-gate "PRR_BVD2_EVENT ":""), 42190Sstevel@tonic-gate ((prrd & PRR_BVD1_EVENT)? 42200Sstevel@tonic-gate "PRR_BVD1_EVENT ":"")); 42210Sstevel@tonic-gate } 42220Sstevel@tonic-gate #endif 42230Sstevel@tonic-gate 42240Sstevel@tonic-gate if (prrd) 42250Sstevel@tonic-gate csx_Put8(cis_handle, client->config_regs.prr_p, 42260Sstevel@tonic-gate prrd); 42270Sstevel@tonic-gate 42280Sstevel@tonic-gate /* 42290Sstevel@tonic-gate * We now have to reenable the status change interrupts 42300Sstevel@tonic-gate * if there are any valid bits in the PRR. Since 42310Sstevel@tonic-gate * the BVD1 signal becomes the STATUS_CHANGE 42320Sstevel@tonic-gate * signal when the socket is in IO mode, we just 42330Sstevel@tonic-gate * have to set the SBM_BVD1 enable bit in the 42340Sstevel@tonic-gate * event mask. 42350Sstevel@tonic-gate */ 42360Sstevel@tonic-gate if (client->pin) { 42370Sstevel@tonic-gate get_socket.socket = sp->socket_num; 42380Sstevel@tonic-gate SocketServices(SS_GetSocket, &get_socket); 42390Sstevel@tonic-gate set_socket.socket = sp->socket_num; 42400Sstevel@tonic-gate set_socket.SCIntMask = 42410Sstevel@tonic-gate get_socket.SCIntMask | SBM_BVD1; 42420Sstevel@tonic-gate set_socket.VccLevel = get_socket.VccLevel; 42430Sstevel@tonic-gate set_socket.Vpp1Level = get_socket.Vpp1Level; 42440Sstevel@tonic-gate set_socket.Vpp2Level = get_socket.Vpp2Level; 42450Sstevel@tonic-gate set_socket.IREQRouting = get_socket.IRQRouting; 42460Sstevel@tonic-gate set_socket.IFType = get_socket.IFType; 42470Sstevel@tonic-gate set_socket.CtlInd = get_socket.CtlInd; 42480Sstevel@tonic-gate set_socket.State = get_socket.state; 42490Sstevel@tonic-gate SocketServices(SS_SetSocket, &set_socket); 42500Sstevel@tonic-gate } /* if (client->pin) */ 42510Sstevel@tonic-gate } /* if (revent) */ 42520Sstevel@tonic-gate 42530Sstevel@tonic-gate } /* if (CONFIG_PINREPL_REG_PRESENT) */ 42540Sstevel@tonic-gate } /* if (SOCKET_IS_IO) */ 42550Sstevel@tonic-gate 42560Sstevel@tonic-gate /* 42570Sstevel@tonic-gate * The caller wants the current card state; we just read 42580Sstevel@tonic-gate * it and return a copy of it but do not clear any of 42590Sstevel@tonic-gate * the event changed bits (if we're reading the PRR). 42600Sstevel@tonic-gate */ 42610Sstevel@tonic-gate if (gs) { 42620Sstevel@tonic-gate gs->socket = sp->socket_num; 42630Sstevel@tonic-gate gs->CardState = 0; 42640Sstevel@tonic-gate if (SocketServices(SS_GetStatus, gs) != SUCCESS) 42650Sstevel@tonic-gate return (CS_BAD_SOCKET); 42660Sstevel@tonic-gate if (sp->flags & SOCKET_IS_IO) { 42670Sstevel@tonic-gate /* 42680Sstevel@tonic-gate * If the socket is in IO mode, then clear the 42690Sstevel@tonic-gate * gs->CardState bits that are now in the PRR 42700Sstevel@tonic-gate */ 42710Sstevel@tonic-gate gs->CardState &= ~(SBM_WP | SBM_BVD1 | 42720Sstevel@tonic-gate SBM_BVD2 | SBM_RDYBSY); 42730Sstevel@tonic-gate 42740Sstevel@tonic-gate /* 42750Sstevel@tonic-gate * Convert PRR status to SS_GetStatus status 42760Sstevel@tonic-gate */ 42770Sstevel@tonic-gate if (prrd & PRR_WP_STATUS) 42780Sstevel@tonic-gate gs->CardState |= SBM_WP; 42790Sstevel@tonic-gate if (prrd & PRR_BVD2_STATUS) 42800Sstevel@tonic-gate gs->CardState |= SBM_BVD2; 42810Sstevel@tonic-gate if (prrd & PRR_BVD1_STATUS) 42820Sstevel@tonic-gate gs->CardState |= SBM_BVD1; 42830Sstevel@tonic-gate 42840Sstevel@tonic-gate /* 42850Sstevel@tonic-gate * If the client has indicated that there is no 42860Sstevel@tonic-gate * PRR or that the READY bit in the PRR isn't 42870Sstevel@tonic-gate * valid, then we simulate the READY bit by 42880Sstevel@tonic-gate * always returning READY. 42890Sstevel@tonic-gate */ 42900Sstevel@tonic-gate if (!(client->present & CONFIG_PINREPL_REG_PRESENT) || 42910Sstevel@tonic-gate ((client->present & CONFIG_PINREPL_REG_PRESENT) && 42920Sstevel@tonic-gate !((client->pin & 42930Sstevel@tonic-gate (PRR_READY_STATUS | PRR_READY_EVENT)) == 42940Sstevel@tonic-gate (PRR_READY_STATUS | PRR_READY_EVENT))) || 42950Sstevel@tonic-gate (prrd & PRR_READY_STATUS)) 42960Sstevel@tonic-gate gs->CardState |= SBM_RDYBSY; 42970Sstevel@tonic-gate 42980Sstevel@tonic-gate #ifdef CS_DEBUG 42990Sstevel@tonic-gate if (cs_debug > 1) { 43000Sstevel@tonic-gate cmn_err(CE_CONT, "cs_read_event_status: prrd 0x%x " 43010Sstevel@tonic-gate "client->pin 0x%x " 43020Sstevel@tonic-gate "gs->CardState 0x%x\n", 43030Sstevel@tonic-gate prrd, client->pin, gs->CardState); 43040Sstevel@tonic-gate } 43050Sstevel@tonic-gate #endif 43060Sstevel@tonic-gate 43070Sstevel@tonic-gate } /* if (SOCKET_IS_IO) */ 43080Sstevel@tonic-gate } /* if (gs) */ 43090Sstevel@tonic-gate return (CS_SUCCESS); 43100Sstevel@tonic-gate } /* if (SOCKET_CARD_INSERTED) */ 43110Sstevel@tonic-gate 43120Sstevel@tonic-gate return (CS_NO_CARD); 43130Sstevel@tonic-gate } 43140Sstevel@tonic-gate 43150Sstevel@tonic-gate /* 43160Sstevel@tonic-gate * cs_get_status - gets live card status and latched card status changes 43170Sstevel@tonic-gate * supports the GetStatus CS call 43180Sstevel@tonic-gate * 43190Sstevel@tonic-gate * returns: CS_SUCCESS 43200Sstevel@tonic-gate * CS_BAD_HANDLE if the passed client handle is invalid 43210Sstevel@tonic-gate * 43220Sstevel@tonic-gate * Note: This function resets the latched status values maintained 43230Sstevel@tonic-gate * by Socket Services 43240Sstevel@tonic-gate */ 43250Sstevel@tonic-gate static int 43260Sstevel@tonic-gate cs_get_status(client_handle_t client_handle, get_status_t *gs) 43270Sstevel@tonic-gate { 43280Sstevel@tonic-gate cs_socket_t *sp; 43290Sstevel@tonic-gate client_t *client; 43300Sstevel@tonic-gate get_ss_status_t get_ss_status; 43310Sstevel@tonic-gate get_socket_t get_socket; 43320Sstevel@tonic-gate set_socket_t set_socket; 43330Sstevel@tonic-gate int error; 43340Sstevel@tonic-gate int client_lock_acquired; 43350Sstevel@tonic-gate 43360Sstevel@tonic-gate /* 43370Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it 43380Sstevel@tonic-gate * is, we don't do anything except for return success. 43390Sstevel@tonic-gate */ 43400Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) 43410Sstevel@tonic-gate return (CS_SUCCESS); 43420Sstevel@tonic-gate 43430Sstevel@tonic-gate /* 43440Sstevel@tonic-gate * Get a pointer to this client's socket structure. 43450Sstevel@tonic-gate */ 43460Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) 43470Sstevel@tonic-gate return (CS_BAD_SOCKET); 43480Sstevel@tonic-gate 43490Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 43500Sstevel@tonic-gate 43510Sstevel@tonic-gate /* 43520Sstevel@tonic-gate * Make sure that this is a valid client handle. 43530Sstevel@tonic-gate */ 43540Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) { 43550Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 43560Sstevel@tonic-gate return (error); 43570Sstevel@tonic-gate } 43580Sstevel@tonic-gate 43590Sstevel@tonic-gate /* 43600Sstevel@tonic-gate * Get the current card status as well as the latched card 43610Sstevel@tonic-gate * state. Set the CS_RES_IGNORE_NO_CARD so that even 43620Sstevel@tonic-gate * if there is no card in the socket we'll still get 43630Sstevel@tonic-gate * a valid status. 43640Sstevel@tonic-gate * Note that it is not necessary to initialize any values 43650Sstevel@tonic-gate * in the get_ss_status structure. 43660Sstevel@tonic-gate */ 43670Sstevel@tonic-gate mutex_enter(&sp->cis_lock); 43680Sstevel@tonic-gate if ((error = cs_read_event_status(sp, client, NULL, &get_ss_status, 43690Sstevel@tonic-gate CS_RES_IGNORE_NO_CARD)) != CS_SUCCESS) { 43700Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 43710Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 43720Sstevel@tonic-gate return (error); 43730Sstevel@tonic-gate } 43740Sstevel@tonic-gate 43750Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 43760Sstevel@tonic-gate 43770Sstevel@tonic-gate gs->raw_CardState = cs_sbm2cse(get_ss_status.CardState); 43780Sstevel@tonic-gate 43790Sstevel@tonic-gate /* 43800Sstevel@tonic-gate * Assign the "live" card state to the "real" card state. If there's 43810Sstevel@tonic-gate * no card in the socket or the card in the socket is not 43820Sstevel@tonic-gate * for this client, then we lie and tell the caller that the 43830Sstevel@tonic-gate * card is not inserted. 43840Sstevel@tonic-gate */ 43850Sstevel@tonic-gate gs->CardState = gs->raw_CardState; 43860Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) 43870Sstevel@tonic-gate gs->CardState &= ~CS_EVENT_CARD_INSERTION; 43880Sstevel@tonic-gate 43890Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 43900Sstevel@tonic-gate 43910Sstevel@tonic-gate get_socket.socket = sp->socket_num; 43920Sstevel@tonic-gate if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) 43930Sstevel@tonic-gate return (CS_BAD_SOCKET); 43940Sstevel@tonic-gate 43950Sstevel@tonic-gate gs->SocketState = cs_sbm2cse(get_socket.state); 43960Sstevel@tonic-gate 43970Sstevel@tonic-gate set_socket.socket = sp->socket_num; 43980Sstevel@tonic-gate set_socket.SCIntMask = get_socket.SCIntMask; 43990Sstevel@tonic-gate set_socket.VccLevel = get_socket.VccLevel; 44000Sstevel@tonic-gate set_socket.Vpp1Level = get_socket.Vpp1Level; 44010Sstevel@tonic-gate set_socket.Vpp2Level = get_socket.Vpp2Level; 44020Sstevel@tonic-gate set_socket.IREQRouting = get_socket.IRQRouting; 44030Sstevel@tonic-gate set_socket.IFType = get_socket.IFType; 44040Sstevel@tonic-gate set_socket.CtlInd = get_socket.CtlInd; 44050Sstevel@tonic-gate /* XXX (is ~0 correct here?) reset latched values */ 44060Sstevel@tonic-gate set_socket.State = (unsigned)~0; 44070Sstevel@tonic-gate 44080Sstevel@tonic-gate if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) 44090Sstevel@tonic-gate return (CS_BAD_SOCKET); 44100Sstevel@tonic-gate 44110Sstevel@tonic-gate return (CS_SUCCESS); 44120Sstevel@tonic-gate } 44130Sstevel@tonic-gate 44140Sstevel@tonic-gate /* 44150Sstevel@tonic-gate * cs_cse2sbm - converts a CS event mask to an SS (SBM_XXX) event mask 44160Sstevel@tonic-gate */ 44170Sstevel@tonic-gate static event_t 44180Sstevel@tonic-gate cs_cse2sbm(event_t event_mask) 44190Sstevel@tonic-gate { 44200Sstevel@tonic-gate event_t sbm_event = 0; 44210Sstevel@tonic-gate 44220Sstevel@tonic-gate /* 44230Sstevel@tonic-gate * XXX - we need to handle PM_CHANGE and RESET here as well 44240Sstevel@tonic-gate */ 44250Sstevel@tonic-gate if (event_mask & CS_EVENT_WRITE_PROTECT) 44260Sstevel@tonic-gate sbm_event |= SBM_WP; 44270Sstevel@tonic-gate if (event_mask & CS_EVENT_BATTERY_DEAD) 44280Sstevel@tonic-gate sbm_event |= SBM_BVD1; 44290Sstevel@tonic-gate if (event_mask & CS_EVENT_BATTERY_LOW) 44300Sstevel@tonic-gate sbm_event |= SBM_BVD2; 44310Sstevel@tonic-gate if (event_mask & CS_EVENT_CARD_READY) 44320Sstevel@tonic-gate sbm_event |= SBM_RDYBSY; 44330Sstevel@tonic-gate if (event_mask & CS_EVENT_CARD_LOCK) 44340Sstevel@tonic-gate sbm_event |= SBM_LOCKED; 44350Sstevel@tonic-gate if (event_mask & CS_EVENT_EJECTION_REQUEST) 44360Sstevel@tonic-gate sbm_event |= SBM_EJECT; 44370Sstevel@tonic-gate if (event_mask & CS_EVENT_INSERTION_REQUEST) 44380Sstevel@tonic-gate sbm_event |= SBM_INSERT; 44390Sstevel@tonic-gate if (event_mask & (CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL)) 44400Sstevel@tonic-gate sbm_event |= SBM_CD; 44410Sstevel@tonic-gate 44420Sstevel@tonic-gate return (sbm_event); 44430Sstevel@tonic-gate } 44440Sstevel@tonic-gate 44450Sstevel@tonic-gate /* 44460Sstevel@tonic-gate * cs_sbm2cse - converts SBM_xxx state to CS event bits 44470Sstevel@tonic-gate * 44480Sstevel@tonic-gate * This function should never set any of the following bits: 44490Sstevel@tonic-gate * 44500Sstevel@tonic-gate * CS_EVENT_MTD_REQUEST 44510Sstevel@tonic-gate * CS_EVENT_CLIENT_INFO 44520Sstevel@tonic-gate * CS_EVENT_TIMER_EXPIRED 44530Sstevel@tonic-gate * CS_EVENT_CARD_REMOVAL 44540Sstevel@tonic-gate * CS_EVENT_CARD_REMOVAL_LOWP 44550Sstevel@tonic-gate * CS_EVENT_ALL_CLIENTS 44560Sstevel@tonic-gate * CS_EVENT_READY_TIMEOUT 44570Sstevel@tonic-gate * 44580Sstevel@tonic-gate * These bits are defined in the CS_STATUS_XXX series and are 44590Sstevel@tonic-gate * used by GetStatus. 44600Sstevel@tonic-gate */ 44610Sstevel@tonic-gate static uint32_t 44620Sstevel@tonic-gate cs_sbm2cse(uint32_t state) 44630Sstevel@tonic-gate { 44640Sstevel@tonic-gate uint32_t rstate = 0; 44650Sstevel@tonic-gate 44660Sstevel@tonic-gate /* 44670Sstevel@tonic-gate * XXX - we need to handle PM_CHANGE and RESET here as well 44680Sstevel@tonic-gate */ 44690Sstevel@tonic-gate if (state & SBM_WP) 44700Sstevel@tonic-gate rstate |= CS_EVENT_WRITE_PROTECT; 44710Sstevel@tonic-gate if (state & SBM_BVD1) 44720Sstevel@tonic-gate rstate |= CS_EVENT_BATTERY_DEAD; 44730Sstevel@tonic-gate if (state & SBM_BVD2) 44740Sstevel@tonic-gate rstate |= CS_EVENT_BATTERY_LOW; 44750Sstevel@tonic-gate if (state & SBM_RDYBSY) 44760Sstevel@tonic-gate rstate |= CS_EVENT_CARD_READY; 44770Sstevel@tonic-gate if (state & SBM_LOCKED) 44780Sstevel@tonic-gate rstate |= CS_EVENT_CARD_LOCK; 44790Sstevel@tonic-gate if (state & SBM_EJECT) 44800Sstevel@tonic-gate rstate |= CS_EVENT_EJECTION_REQUEST; 44810Sstevel@tonic-gate if (state & SBM_INSERT) 44820Sstevel@tonic-gate rstate |= CS_EVENT_INSERTION_REQUEST; 44830Sstevel@tonic-gate if (state & SBM_CD) 44840Sstevel@tonic-gate rstate |= CS_EVENT_CARD_INSERTION; 44850Sstevel@tonic-gate 44860Sstevel@tonic-gate return (rstate); 44870Sstevel@tonic-gate } 44880Sstevel@tonic-gate 44890Sstevel@tonic-gate /* 44900Sstevel@tonic-gate * cs_merge_event_masks - merge the CS global socket event mask with the 44910Sstevel@tonic-gate * passed client's event masks 44920Sstevel@tonic-gate */ 44930Sstevel@tonic-gate static unsigned 44940Sstevel@tonic-gate cs_merge_event_masks(cs_socket_t *sp, client_t *client) 44950Sstevel@tonic-gate { 44960Sstevel@tonic-gate unsigned SCIntMask; 44970Sstevel@tonic-gate uint32_t event_mask; 44980Sstevel@tonic-gate 44990Sstevel@tonic-gate /* 45000Sstevel@tonic-gate * We always want to see card detect and status change events. 45010Sstevel@tonic-gate */ 45020Sstevel@tonic-gate SCIntMask = SBM_CD; 45030Sstevel@tonic-gate 45040Sstevel@tonic-gate event_mask = client->event_mask | client->global_mask | 45050Sstevel@tonic-gate sp->event_mask; 45060Sstevel@tonic-gate 45070Sstevel@tonic-gate if (!(sp->flags & SOCKET_IS_IO)) { 45080Sstevel@tonic-gate SCIntMask |= cs_cse2sbm(event_mask); 45090Sstevel@tonic-gate } else { 45100Sstevel@tonic-gate /* 45110Sstevel@tonic-gate * If the socket is in IO mode and there is a PRR present, 45120Sstevel@tonic-gate * then we may need to enable PCE_CARD_STATUS_CHANGE 45130Sstevel@tonic-gate * events. 45140Sstevel@tonic-gate */ 45150Sstevel@tonic-gate if (client->present & CONFIG_PINREPL_REG_PRESENT) { 45160Sstevel@tonic-gate 45170Sstevel@tonic-gate SCIntMask |= (cs_cse2sbm(event_mask) & 45180Sstevel@tonic-gate ~(SBM_WP | SBM_BVD1 | SBM_BVD2 | SBM_RDYBSY)); 45190Sstevel@tonic-gate 45200Sstevel@tonic-gate if ((client->pin & (PRR_WP_STATUS | PRR_WP_EVENT)) == 45210Sstevel@tonic-gate (PRR_WP_STATUS | PRR_WP_EVENT)) 45220Sstevel@tonic-gate if (event_mask & CS_EVENT_WRITE_PROTECT) 45230Sstevel@tonic-gate SCIntMask |= SBM_BVD1; 45240Sstevel@tonic-gate 45250Sstevel@tonic-gate if ((client->pin & (PRR_READY_STATUS | PRR_READY_EVENT)) == 45260Sstevel@tonic-gate (PRR_READY_STATUS | PRR_READY_EVENT)) 45270Sstevel@tonic-gate if (event_mask & CS_EVENT_CARD_READY) 45280Sstevel@tonic-gate SCIntMask |= SBM_BVD1; 45290Sstevel@tonic-gate 45300Sstevel@tonic-gate if ((client->pin & (PRR_BVD2_STATUS | PRR_BVD2_EVENT)) == 45310Sstevel@tonic-gate (PRR_BVD2_STATUS | PRR_BVD2_EVENT)) 45320Sstevel@tonic-gate if (event_mask & CS_EVENT_BATTERY_LOW) 45330Sstevel@tonic-gate SCIntMask |= SBM_BVD1; 45340Sstevel@tonic-gate 45350Sstevel@tonic-gate if ((client->pin & (PRR_BVD1_STATUS | PRR_BVD1_EVENT)) == 45360Sstevel@tonic-gate (PRR_BVD1_STATUS | PRR_BVD1_EVENT)) 45370Sstevel@tonic-gate if (event_mask & CS_EVENT_BATTERY_DEAD) 45380Sstevel@tonic-gate SCIntMask |= SBM_BVD1; 45390Sstevel@tonic-gate 45400Sstevel@tonic-gate } /* if (CONFIG_PINREPL_REG_PRESENT) */ 45410Sstevel@tonic-gate } /* if (!SOCKET_IS_IO) */ 45420Sstevel@tonic-gate 45430Sstevel@tonic-gate return (SCIntMask); 45440Sstevel@tonic-gate } 45450Sstevel@tonic-gate 45460Sstevel@tonic-gate /* 45470Sstevel@tonic-gate * cs_set_socket_event_mask - set the event mask for the socket 45480Sstevel@tonic-gate */ 45490Sstevel@tonic-gate static int 45500Sstevel@tonic-gate cs_set_socket_event_mask(cs_socket_t *sp, unsigned event_mask) 45510Sstevel@tonic-gate { 45520Sstevel@tonic-gate get_socket_t get_socket; 45530Sstevel@tonic-gate set_socket_t set_socket; 45540Sstevel@tonic-gate 45550Sstevel@tonic-gate get_socket.socket = sp->socket_num; 45560Sstevel@tonic-gate if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) 45570Sstevel@tonic-gate return (CS_BAD_SOCKET); 45580Sstevel@tonic-gate 45590Sstevel@tonic-gate set_socket.socket = sp->socket_num; 45600Sstevel@tonic-gate set_socket.SCIntMask = event_mask; 45610Sstevel@tonic-gate set_socket.VccLevel = get_socket.VccLevel; 45620Sstevel@tonic-gate set_socket.Vpp1Level = get_socket.Vpp1Level; 45630Sstevel@tonic-gate set_socket.Vpp2Level = get_socket.Vpp2Level; 45640Sstevel@tonic-gate set_socket.IREQRouting = get_socket.IRQRouting; 45650Sstevel@tonic-gate set_socket.IFType = get_socket.IFType; 45660Sstevel@tonic-gate set_socket.CtlInd = get_socket.CtlInd; 45670Sstevel@tonic-gate /* XXX (is ~0 correct here?) reset latched values */ 45680Sstevel@tonic-gate set_socket.State = (unsigned)~0; 45690Sstevel@tonic-gate 45700Sstevel@tonic-gate if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) 45710Sstevel@tonic-gate return (CS_BAD_SOCKET); 45720Sstevel@tonic-gate 45730Sstevel@tonic-gate return (CS_SUCCESS); 45740Sstevel@tonic-gate } 45750Sstevel@tonic-gate 45760Sstevel@tonic-gate /* 45770Sstevel@tonic-gate * ==== MTD handling section ==== 45780Sstevel@tonic-gate */ 45790Sstevel@tonic-gate static int 45800Sstevel@tonic-gate cs_deregister_mtd(client_handle_t client_handle) 45810Sstevel@tonic-gate { 45820Sstevel@tonic-gate 45830Sstevel@tonic-gate cmn_err(CE_CONT, "cs_deregister_mtd: client_handle 0x%x\n", 45840Sstevel@tonic-gate (int)client_handle); 45850Sstevel@tonic-gate 45860Sstevel@tonic-gate return (CS_SUCCESS); 45870Sstevel@tonic-gate } 45880Sstevel@tonic-gate 45890Sstevel@tonic-gate /* 45900Sstevel@tonic-gate * ==== memory window handling section ==== 45910Sstevel@tonic-gate */ 45920Sstevel@tonic-gate 45930Sstevel@tonic-gate /* 45940Sstevel@tonic-gate * cs_request_window - searches through window list for the socket to find a 45950Sstevel@tonic-gate * memory window that matches the requested criteria; 45960Sstevel@tonic-gate * this is RequestWindow 45970Sstevel@tonic-gate * 45980Sstevel@tonic-gate * calling: cs_request_window(client_handle_t, *window_handle_t, win_req_t *) 45990Sstevel@tonic-gate * 46000Sstevel@tonic-gate * On sucessful return, the window_handle_t * pointed to will 46010Sstevel@tonic-gate * contain a valid window handle for this window. 46020Sstevel@tonic-gate * 46030Sstevel@tonic-gate * returns: CS_SUCCESS - if window found 46040Sstevel@tonic-gate * CS_OUT_OF_RESOURCE - if no windows match requirements 46050Sstevel@tonic-gate * CS_BAD_HANDLE - client handle is invalid 46060Sstevel@tonic-gate * CS_BAD_SIZE - if requested size can not be met 46070Sstevel@tonic-gate * CS_BAD_WINDOW - if an internal error occured 46080Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - if SS is trying to call us 46090Sstevel@tonic-gate * CS_NO_CARD - if no card is in socket 46100Sstevel@tonic-gate * CS_BAD_ATTRIBUTE - if any of the unsupported Attrbute 46110Sstevel@tonic-gate * flags are set 46120Sstevel@tonic-gate */ 46130Sstevel@tonic-gate static int 46140Sstevel@tonic-gate cs_request_window(client_handle_t client_handle, 46150Sstevel@tonic-gate window_handle_t *wh, 46160Sstevel@tonic-gate win_req_t *rw) 46170Sstevel@tonic-gate { 46180Sstevel@tonic-gate cs_socket_t *sp; 46190Sstevel@tonic-gate cs_window_t *cw; 46200Sstevel@tonic-gate client_t *client; 46210Sstevel@tonic-gate modify_win_t mw; 46220Sstevel@tonic-gate inquire_window_t iw; 46230Sstevel@tonic-gate uint32_t aw; 46240Sstevel@tonic-gate int error; 46250Sstevel@tonic-gate int client_lock_acquired; 46260Sstevel@tonic-gate uint32_t socket_num; 46270Sstevel@tonic-gate 46280Sstevel@tonic-gate /* 46290Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it 46300Sstevel@tonic-gate * is, we don't support SS using this call. 46310Sstevel@tonic-gate */ 46320Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) 46330Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION); 46340Sstevel@tonic-gate 46350Sstevel@tonic-gate /* 46360Sstevel@tonic-gate * Make sure that none of the unsupported flags are set. 46370Sstevel@tonic-gate */ 46380Sstevel@tonic-gate if (rw->Attributes & (/* Compatability */ 46390Sstevel@tonic-gate WIN_PAGED | 46400Sstevel@tonic-gate WIN_SHARED | 46410Sstevel@tonic-gate WIN_FIRST_SHARED | 46420Sstevel@tonic-gate WIN_BINDING_SPECIFIC | 46430Sstevel@tonic-gate /* CS internal */ 46440Sstevel@tonic-gate WIN_DATA_WIDTH_VALID | 46450Sstevel@tonic-gate /* IO window flags */ 46460Sstevel@tonic-gate WIN_MEMORY_TYPE_IO | 46470Sstevel@tonic-gate /* CardBus flags */ 46480Sstevel@tonic-gate WIN_DATA_WIDTH_32 | 46490Sstevel@tonic-gate WIN_PREFETCH_CACHE_MASK | 46500Sstevel@tonic-gate WIN_BAR_MASK)) 46510Sstevel@tonic-gate return (CS_BAD_ATTRIBUTE); 46520Sstevel@tonic-gate 46530Sstevel@tonic-gate mutex_enter(&cs_globals.window_lock); 46540Sstevel@tonic-gate 46550Sstevel@tonic-gate /* 46560Sstevel@tonic-gate * Get a pointer to this client's socket structure. 46570Sstevel@tonic-gate */ 46580Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) 46590Sstevel@tonic-gate return (CS_BAD_SOCKET); 46600Sstevel@tonic-gate 46610Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 46620Sstevel@tonic-gate 46630Sstevel@tonic-gate /* 46640Sstevel@tonic-gate * Make sure that this is a valid client handle. 46650Sstevel@tonic-gate */ 46660Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) { 46670Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 46680Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 46690Sstevel@tonic-gate return (error); 46700Sstevel@tonic-gate } 46710Sstevel@tonic-gate 46720Sstevel@tonic-gate mutex_enter(&sp->lock); 46730Sstevel@tonic-gate 46740Sstevel@tonic-gate /* 46750Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not 46760Sstevel@tonic-gate * for this client, then return an error. 46770Sstevel@tonic-gate */ 46780Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) { 46790Sstevel@tonic-gate mutex_exit(&sp->lock); 46800Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 46810Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 46820Sstevel@tonic-gate return (CS_NO_CARD); 46830Sstevel@tonic-gate } 46840Sstevel@tonic-gate 46850Sstevel@tonic-gate mutex_exit(&sp->lock); 46860Sstevel@tonic-gate 46870Sstevel@tonic-gate socket_num = CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle), 46880Sstevel@tonic-gate GET_CLIENT_FUNCTION(client_handle)); 46890Sstevel@tonic-gate 46900Sstevel@tonic-gate 46910Sstevel@tonic-gate /* 46920Sstevel@tonic-gate * See if we can find a window that matches the caller's criteria. 46930Sstevel@tonic-gate * If we can't, then thre's not much more that we can do except 46940Sstevel@tonic-gate * for return an error. 46950Sstevel@tonic-gate */ 46960Sstevel@tonic-gate if ((error = cs_find_mem_window(sp->socket_num, rw, &aw)) != 46970Sstevel@tonic-gate CS_SUCCESS) { 46980Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 46990Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 47000Sstevel@tonic-gate return (error); 47010Sstevel@tonic-gate } 47020Sstevel@tonic-gate 47030Sstevel@tonic-gate /* 47040Sstevel@tonic-gate * We got a window, now synthesize a new window handle for this 47050Sstevel@tonic-gate * client and get a pointer to the global window structs 47060Sstevel@tonic-gate * and assign this window to this client. 47070Sstevel@tonic-gate * We don't have to check for errors from cs_create_window_handle 47080Sstevel@tonic-gate * since that function always returns a valid window handle 47090Sstevel@tonic-gate * if it is given a valid window number. 47100Sstevel@tonic-gate */ 47110Sstevel@tonic-gate *wh = cs_create_window_handle(aw); 47120Sstevel@tonic-gate if ((cw = cs_get_wp(aw)) == NULL) { 47130Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 47140Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 47150Sstevel@tonic-gate return (CS_BAD_WINDOW); 47160Sstevel@tonic-gate } 47170Sstevel@tonic-gate 47180Sstevel@tonic-gate cw->window_handle = *wh; 47190Sstevel@tonic-gate cw->client_handle = client_handle; 47200Sstevel@tonic-gate cw->socket_num = sp->socket_num; 47210Sstevel@tonic-gate cw->state |= (CW_ALLOCATED | CW_MEM); 47220Sstevel@tonic-gate 47230Sstevel@tonic-gate mw.Attributes = ( 47240Sstevel@tonic-gate rw->Attributes | 47250Sstevel@tonic-gate WIN_DATA_WIDTH_VALID | 47260Sstevel@tonic-gate WIN_ACCESS_SPEED_VALID); 47270Sstevel@tonic-gate mw.AccessSpeed = rw->win_params.AccessSpeed; 47280Sstevel@tonic-gate 47290Sstevel@tonic-gate if ((error = cs_modify_mem_window(*wh, &mw, rw, socket_num)) != 47300Sstevel@tonic-gate CS_SUCCESS) { 47310Sstevel@tonic-gate cw->state = 0; 47320Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 47330Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 47340Sstevel@tonic-gate return (error); 47350Sstevel@tonic-gate } 47360Sstevel@tonic-gate 47370Sstevel@tonic-gate /* 47380Sstevel@tonic-gate * Get any required card offset and pass it back to the client. 47390Sstevel@tonic-gate * This is not defined in the current PCMCIA spec. It is 47400Sstevel@tonic-gate * an aid to clients that want to use it to generate an 47410Sstevel@tonic-gate * optimum card offset. 47420Sstevel@tonic-gate */ 47430Sstevel@tonic-gate iw.window = GET_WINDOW_NUMBER(*wh); 47440Sstevel@tonic-gate SocketServices(SS_InquireWindow, &iw); 47450Sstevel@tonic-gate 47460Sstevel@tonic-gate if (iw.mem_win_char.MemWndCaps & WC_CALIGN) 47470Sstevel@tonic-gate rw->ReqOffset = rw->Size; 47480Sstevel@tonic-gate else 47490Sstevel@tonic-gate rw->ReqOffset = iw.mem_win_char.ReqOffset; 47500Sstevel@tonic-gate 47510Sstevel@tonic-gate /* 47520Sstevel@tonic-gate * Increment the client's memory window count; this is how we know 47530Sstevel@tonic-gate * when a client has any allocated memory windows. 47540Sstevel@tonic-gate */ 47550Sstevel@tonic-gate client->memwin_count++; 47560Sstevel@tonic-gate 47570Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 47580Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 47590Sstevel@tonic-gate 47600Sstevel@tonic-gate return (CS_SUCCESS); 47610Sstevel@tonic-gate } 47620Sstevel@tonic-gate 47630Sstevel@tonic-gate /* 47640Sstevel@tonic-gate * cs_release_window - deallocates the window associated with the passed 47650Sstevel@tonic-gate * window handle; this is ReleaseWindow 47660Sstevel@tonic-gate * 47670Sstevel@tonic-gate * returns: CS_SUCCESS if window handle is valid and window was 47680Sstevel@tonic-gate * sucessfully deallocated 47690Sstevel@tonic-gate * CS_BAD_HANDLE if window handle is invalid or if window 47700Sstevel@tonic-gate * handle is valid but window is not allocated 47710Sstevel@tonic-gate */ 47720Sstevel@tonic-gate static int 47730Sstevel@tonic-gate cs_release_window(window_handle_t wh) 47740Sstevel@tonic-gate { 47750Sstevel@tonic-gate cs_socket_t *sp; 47760Sstevel@tonic-gate cs_window_t *cw; 47770Sstevel@tonic-gate client_t *client; 47780Sstevel@tonic-gate int error; 47790Sstevel@tonic-gate int client_lock_acquired; 47800Sstevel@tonic-gate 47810Sstevel@tonic-gate mutex_enter(&cs_globals.window_lock); 47820Sstevel@tonic-gate 47830Sstevel@tonic-gate if (!(cw = cs_find_window(wh))) { 47840Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 47850Sstevel@tonic-gate return (CS_BAD_HANDLE); 47860Sstevel@tonic-gate } 47870Sstevel@tonic-gate 47880Sstevel@tonic-gate /* 47890Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it 47900Sstevel@tonic-gate * is, we don't support SS using this call. 47910Sstevel@tonic-gate */ 47920Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(cw->client_handle)) { 47930Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 47940Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION); 47950Sstevel@tonic-gate } 47960Sstevel@tonic-gate 47970Sstevel@tonic-gate /* 47980Sstevel@tonic-gate * Get a pointer to this client's socket structure. 47990Sstevel@tonic-gate */ 48000Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(cw->client_handle))) == NULL) 48010Sstevel@tonic-gate return (CS_BAD_SOCKET); 48020Sstevel@tonic-gate 48030Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 48040Sstevel@tonic-gate 48050Sstevel@tonic-gate /* 48060Sstevel@tonic-gate * Make sure that this is a valid client handle. 48070Sstevel@tonic-gate */ 48080Sstevel@tonic-gate if (!(client = cs_find_client(cw->client_handle, &error))) { 48090Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 48100Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 48110Sstevel@tonic-gate return (error); 48120Sstevel@tonic-gate } 48130Sstevel@tonic-gate 48140Sstevel@tonic-gate /* 48150Sstevel@tonic-gate * Mark this window as not in use anymore. 48160Sstevel@tonic-gate */ 48170Sstevel@tonic-gate cw->state &= ~CW_WIN_IN_USE; 48180Sstevel@tonic-gate 48190Sstevel@tonic-gate /* 48200Sstevel@tonic-gate * Decrement the client's memory window count; this is how we know 48210Sstevel@tonic-gate * when a client has any allocated memory windows. 48220Sstevel@tonic-gate */ 48230Sstevel@tonic-gate if (!(--(client->memwin_count))) 48240Sstevel@tonic-gate client->flags &= ~CLIENT_WIN_ALLOCATED; 48250Sstevel@tonic-gate 48260Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 48270Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 48280Sstevel@tonic-gate 48290Sstevel@tonic-gate return (CS_SUCCESS); 48300Sstevel@tonic-gate } 48310Sstevel@tonic-gate 48320Sstevel@tonic-gate /* 48330Sstevel@tonic-gate * cs_modify_window - modifies a window's characteristics; this is ModifyWindow 48340Sstevel@tonic-gate */ 48350Sstevel@tonic-gate static int 48360Sstevel@tonic-gate cs_modify_window(window_handle_t wh, modify_win_t *mw) 48370Sstevel@tonic-gate { 48380Sstevel@tonic-gate cs_socket_t *sp; 48390Sstevel@tonic-gate cs_window_t *cw; 48400Sstevel@tonic-gate client_t *client; 48410Sstevel@tonic-gate int error; 48420Sstevel@tonic-gate int client_lock_acquired; 48430Sstevel@tonic-gate 48440Sstevel@tonic-gate mutex_enter(&cs_globals.window_lock); 48450Sstevel@tonic-gate 48460Sstevel@tonic-gate /* 48470Sstevel@tonic-gate * Do some sanity checking - make sure that we can find a pointer 48480Sstevel@tonic-gate * to the window structure, and if we can, get the client that 48490Sstevel@tonic-gate * has allocated that window. 48500Sstevel@tonic-gate */ 48510Sstevel@tonic-gate if (!(cw = cs_find_window(wh))) { 48520Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 48530Sstevel@tonic-gate return (CS_BAD_HANDLE); 48540Sstevel@tonic-gate } 48550Sstevel@tonic-gate 48560Sstevel@tonic-gate /* 48570Sstevel@tonic-gate * Get a pointer to this client's socket structure. 48580Sstevel@tonic-gate */ 48590Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(cw->client_handle))) == NULL) 48600Sstevel@tonic-gate return (CS_BAD_SOCKET); 48610Sstevel@tonic-gate 48620Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 48630Sstevel@tonic-gate 48640Sstevel@tonic-gate if (!(client = cs_find_client(cw->client_handle, &error))) { 48650Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 48660Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 48670Sstevel@tonic-gate return (error); 48680Sstevel@tonic-gate } 48690Sstevel@tonic-gate 48700Sstevel@tonic-gate mutex_enter(&sp->lock); 48710Sstevel@tonic-gate 48720Sstevel@tonic-gate /* 48730Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not 48740Sstevel@tonic-gate * for this client, then return an error. 48750Sstevel@tonic-gate */ 48760Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) { 48770Sstevel@tonic-gate mutex_exit(&sp->lock); 48780Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 48790Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 48800Sstevel@tonic-gate return (CS_NO_CARD); 48810Sstevel@tonic-gate } 48820Sstevel@tonic-gate 48830Sstevel@tonic-gate mutex_exit(&sp->lock); 48840Sstevel@tonic-gate 48850Sstevel@tonic-gate mw->Attributes &= ( 48860Sstevel@tonic-gate WIN_MEMORY_TYPE_MASK | 48870Sstevel@tonic-gate WIN_ENABLE | 48880Sstevel@tonic-gate WIN_ACCESS_SPEED_VALID | 48890Sstevel@tonic-gate WIN_ACC_ENDIAN_MASK | 48900Sstevel@tonic-gate WIN_ACC_ORDER_MASK); 48910Sstevel@tonic-gate 48920Sstevel@tonic-gate mw->Attributes &= ~WIN_DATA_WIDTH_VALID; 48930Sstevel@tonic-gate 48940Sstevel@tonic-gate if ((error = cs_modify_mem_window(wh, mw, NULL, NULL)) != CS_SUCCESS) { 48950Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 48960Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 48970Sstevel@tonic-gate return (error); 48980Sstevel@tonic-gate } 48990Sstevel@tonic-gate 49000Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 49010Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 49020Sstevel@tonic-gate 49030Sstevel@tonic-gate return (CS_SUCCESS); 49040Sstevel@tonic-gate } 49050Sstevel@tonic-gate 49060Sstevel@tonic-gate /* 49070Sstevel@tonic-gate * cs_modify_mem_window - modifies a window's characteristics; used internally 49080Sstevel@tonic-gate * by Card Services 49090Sstevel@tonic-gate * 49100Sstevel@tonic-gate * If *wr is NULL, it means that we're being called by ModifyWindow 49110Sstevel@tonic-gate * If *wr is non-NULL, it means that we are being called by RequestWindow 49120Sstevel@tonic-gate * and so we can't use SS_GetWindow. 49130Sstevel@tonic-gate */ 49140Sstevel@tonic-gate static int 49150Sstevel@tonic-gate cs_modify_mem_window(window_handle_t wh, modify_win_t *mw, 49160Sstevel@tonic-gate win_req_t *wr, int sn) 49170Sstevel@tonic-gate { 49180Sstevel@tonic-gate get_window_t gw; 49190Sstevel@tonic-gate set_window_t sw; 49200Sstevel@tonic-gate set_page_t set_page; 49210Sstevel@tonic-gate get_page_t get_page; 49220Sstevel@tonic-gate 49230Sstevel@tonic-gate /* 49240Sstevel@tonic-gate * If the win_req_t struct pointer is NULL, it means that 49250Sstevel@tonic-gate * we're being called by ModifyWindow, so get the 49260Sstevel@tonic-gate * current window characteristics. 49270Sstevel@tonic-gate */ 49280Sstevel@tonic-gate if (!wr) { 49290Sstevel@tonic-gate gw.window = GET_WINDOW_NUMBER(wh); 49300Sstevel@tonic-gate if (SocketServices(SS_GetWindow, &gw) != SUCCESS) 49310Sstevel@tonic-gate return (CS_BAD_WINDOW); 49320Sstevel@tonic-gate sw.state = gw.state; 49330Sstevel@tonic-gate sw.socket = gw.socket; 49340Sstevel@tonic-gate sw.WindowSize = gw.size; 49350Sstevel@tonic-gate } else { 49360Sstevel@tonic-gate sw.state = 0; 49370Sstevel@tonic-gate sw.socket = sn; 49380Sstevel@tonic-gate sw.WindowSize = wr->Size; 49390Sstevel@tonic-gate } 49400Sstevel@tonic-gate 49410Sstevel@tonic-gate /* 49420Sstevel@tonic-gate * If we're being called by RequestWindow, we must always have 49430Sstevel@tonic-gate * WIN_ACCESS_SPEED_VALID set since get_window_t is not 49440Sstevel@tonic-gate * defined. 49450Sstevel@tonic-gate */ 49460Sstevel@tonic-gate if (mw->Attributes & WIN_ACCESS_SPEED_VALID) { 49470Sstevel@tonic-gate convert_speed_t convert_speed; 49480Sstevel@tonic-gate 49490Sstevel@tonic-gate convert_speed.Attributes = CONVERT_DEVSPEED_TO_NS; 49500Sstevel@tonic-gate convert_speed.devspeed = mw->AccessSpeed; 49510Sstevel@tonic-gate 49520Sstevel@tonic-gate if (cs_convert_speed(&convert_speed) != CS_SUCCESS) 49530Sstevel@tonic-gate return (CS_BAD_SPEED); 49540Sstevel@tonic-gate 49550Sstevel@tonic-gate sw.speed = convert_speed.nS; 49560Sstevel@tonic-gate } else { 49570Sstevel@tonic-gate sw.speed = gw.speed; 49580Sstevel@tonic-gate } 49590Sstevel@tonic-gate 49600Sstevel@tonic-gate if (!wr) { 49610Sstevel@tonic-gate get_page.window = GET_WINDOW_NUMBER(wh); 49620Sstevel@tonic-gate get_page.page = 0; 49630Sstevel@tonic-gate if (SocketServices(SS_GetPage, &get_page) != SUCCESS) 49640Sstevel@tonic-gate return (CS_BAD_WINDOW); 49650Sstevel@tonic-gate set_page.state = get_page.state; 49660Sstevel@tonic-gate set_page.offset = get_page.offset; 49670Sstevel@tonic-gate } else { 49680Sstevel@tonic-gate set_page.state = 0; 49690Sstevel@tonic-gate set_page.offset = 0; 49700Sstevel@tonic-gate } 49710Sstevel@tonic-gate 49720Sstevel@tonic-gate if (mw->Attributes & WIN_ENABLE) { 49730Sstevel@tonic-gate sw.state |= WS_ENABLED; 49740Sstevel@tonic-gate set_page.state |= PS_ENABLED; 49750Sstevel@tonic-gate } else { 49760Sstevel@tonic-gate sw.state &= ~WS_ENABLED; 49770Sstevel@tonic-gate set_page.state &= ~PS_ENABLED; 49780Sstevel@tonic-gate } 49790Sstevel@tonic-gate 49800Sstevel@tonic-gate if (mw->Attributes & WIN_DATA_WIDTH_VALID) { 49810Sstevel@tonic-gate if (mw->Attributes & WIN_DATA_WIDTH_16) 49820Sstevel@tonic-gate sw.state |= WS_16BIT; 49830Sstevel@tonic-gate else 49840Sstevel@tonic-gate sw.state &= ~WS_16BIT; 49850Sstevel@tonic-gate } 49860Sstevel@tonic-gate 49870Sstevel@tonic-gate sw.window = GET_WINDOW_NUMBER(wh); 49880Sstevel@tonic-gate sw.base = 0; 49890Sstevel@tonic-gate 49900Sstevel@tonic-gate cs_set_acc_attributes(&sw, mw->Attributes); 49910Sstevel@tonic-gate 49920Sstevel@tonic-gate if (SocketServices(SS_SetWindow, &sw) != SUCCESS) 49930Sstevel@tonic-gate return (CS_BAD_WINDOW); 49940Sstevel@tonic-gate 49950Sstevel@tonic-gate if (mw->Attributes & WIN_MEMORY_TYPE_AM) 49960Sstevel@tonic-gate set_page.state |= PS_ATTRIBUTE; 49970Sstevel@tonic-gate else 49980Sstevel@tonic-gate set_page.state &= ~PS_ATTRIBUTE; 49990Sstevel@tonic-gate 50000Sstevel@tonic-gate set_page.window = GET_WINDOW_NUMBER(wh); 50010Sstevel@tonic-gate set_page.page = 0; 50020Sstevel@tonic-gate if (SocketServices(SS_SetPage, &set_page) != SUCCESS) 50030Sstevel@tonic-gate return (CS_BAD_OFFSET); 50040Sstevel@tonic-gate 50050Sstevel@tonic-gate /* 50060Sstevel@tonic-gate * Return the current base address of this window 50070Sstevel@tonic-gate */ 50080Sstevel@tonic-gate if (wr) { 50090Sstevel@tonic-gate gw.window = GET_WINDOW_NUMBER(wh); 50100Sstevel@tonic-gate if (SocketServices(SS_GetWindow, &gw) != SUCCESS) 50110Sstevel@tonic-gate return (CS_BAD_WINDOW); 50120Sstevel@tonic-gate 50130Sstevel@tonic-gate wr->Base.handle = (acc_handle_t)gw.handle; 50140Sstevel@tonic-gate } 50150Sstevel@tonic-gate 50160Sstevel@tonic-gate return (CS_SUCCESS); 50170Sstevel@tonic-gate } 50180Sstevel@tonic-gate 50190Sstevel@tonic-gate /* 50200Sstevel@tonic-gate * cs_map_mem_page - sets the card offset of the mapped window 50210Sstevel@tonic-gate */ 50220Sstevel@tonic-gate static int 50230Sstevel@tonic-gate cs_map_mem_page(window_handle_t wh, map_mem_page_t *mmp) 50240Sstevel@tonic-gate { 50250Sstevel@tonic-gate cs_socket_t *sp; 50260Sstevel@tonic-gate cs_window_t *cw; 50270Sstevel@tonic-gate client_t *client; 50280Sstevel@tonic-gate inquire_window_t iw; 50290Sstevel@tonic-gate get_window_t gw; 50300Sstevel@tonic-gate set_page_t set_page; 50310Sstevel@tonic-gate get_page_t get_page; 50320Sstevel@tonic-gate int error; 50330Sstevel@tonic-gate uint32_t size; 50340Sstevel@tonic-gate int client_lock_acquired; 50350Sstevel@tonic-gate 50360Sstevel@tonic-gate /* 50370Sstevel@tonic-gate * We don't support paged windows, so never allow a page number 50380Sstevel@tonic-gate * of other than 0 50390Sstevel@tonic-gate */ 50400Sstevel@tonic-gate if (mmp->Page) 50410Sstevel@tonic-gate return (CS_BAD_PAGE); 50420Sstevel@tonic-gate 50430Sstevel@tonic-gate mutex_enter(&cs_globals.window_lock); 50440Sstevel@tonic-gate 50450Sstevel@tonic-gate /* 50460Sstevel@tonic-gate * Do some sanity checking - make sure that we can find a pointer 50470Sstevel@tonic-gate * to the window structure, and if we can, get the client that 50480Sstevel@tonic-gate * has allocated that window. 50490Sstevel@tonic-gate */ 50500Sstevel@tonic-gate if (!(cw = cs_find_window(wh))) { 50510Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 50520Sstevel@tonic-gate return (CS_BAD_HANDLE); 50530Sstevel@tonic-gate } 50540Sstevel@tonic-gate 50550Sstevel@tonic-gate /* 50560Sstevel@tonic-gate * Get a pointer to this client's socket structure. 50570Sstevel@tonic-gate */ 50580Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(cw->client_handle))) == NULL) 50590Sstevel@tonic-gate return (CS_BAD_SOCKET); 50600Sstevel@tonic-gate 50610Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 50620Sstevel@tonic-gate 50630Sstevel@tonic-gate if (!(client = cs_find_client(cw->client_handle, &error))) { 50640Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 50650Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 50660Sstevel@tonic-gate return (error); 50670Sstevel@tonic-gate } 50680Sstevel@tonic-gate 50690Sstevel@tonic-gate mutex_enter(&sp->lock); 50700Sstevel@tonic-gate 50710Sstevel@tonic-gate /* 50720Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not 50730Sstevel@tonic-gate * for this client, then return an error. 50740Sstevel@tonic-gate */ 50750Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) { 50760Sstevel@tonic-gate mutex_exit(&sp->lock); 50770Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 50780Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 50790Sstevel@tonic-gate return (CS_NO_CARD); 50800Sstevel@tonic-gate } 50810Sstevel@tonic-gate 50820Sstevel@tonic-gate mutex_exit(&sp->lock); 50830Sstevel@tonic-gate 50840Sstevel@tonic-gate gw.window = GET_WINDOW_NUMBER(wh); 50850Sstevel@tonic-gate SocketServices(SS_GetWindow, &gw); 50860Sstevel@tonic-gate 50870Sstevel@tonic-gate iw.window = GET_WINDOW_NUMBER(wh); 50880Sstevel@tonic-gate SocketServices(SS_InquireWindow, &iw); 50890Sstevel@tonic-gate 50900Sstevel@tonic-gate if (iw.mem_win_char.MemWndCaps & WC_CALIGN) 50910Sstevel@tonic-gate size = gw.size; 50920Sstevel@tonic-gate else 50930Sstevel@tonic-gate size = iw.mem_win_char.ReqOffset; 50940Sstevel@tonic-gate 50950Sstevel@tonic-gate if (((mmp->CardOffset/size)*size) != mmp->CardOffset) { 50960Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 50970Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 50980Sstevel@tonic-gate return (CS_BAD_OFFSET); 50990Sstevel@tonic-gate } 51000Sstevel@tonic-gate 51010Sstevel@tonic-gate get_page.window = GET_WINDOW_NUMBER(wh); 51020Sstevel@tonic-gate get_page.page = 0; 51030Sstevel@tonic-gate SocketServices(SS_GetPage, &get_page); 51040Sstevel@tonic-gate 51050Sstevel@tonic-gate set_page.window = GET_WINDOW_NUMBER(wh); 51060Sstevel@tonic-gate set_page.page = 0; 51070Sstevel@tonic-gate set_page.state = get_page.state; 51080Sstevel@tonic-gate set_page.offset = mmp->CardOffset; 51090Sstevel@tonic-gate if (SocketServices(SS_SetPage, &set_page) != SUCCESS) { 51100Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 51110Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 51120Sstevel@tonic-gate return (CS_BAD_OFFSET); 51130Sstevel@tonic-gate } 51140Sstevel@tonic-gate 51150Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 51160Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 51170Sstevel@tonic-gate 51180Sstevel@tonic-gate return (CS_SUCCESS); 51190Sstevel@tonic-gate } 51200Sstevel@tonic-gate 51210Sstevel@tonic-gate /* 51220Sstevel@tonic-gate * cs_find_window - finds the window associated with the passed window 51230Sstevel@tonic-gate * handle; if the window handle is invalid or no 51240Sstevel@tonic-gate * windows match the passed window handle, NULL 51250Sstevel@tonic-gate * is returned. Note that the window must be 51260Sstevel@tonic-gate * allocated for this function to return a valid 51270Sstevel@tonic-gate * window pointer. 51280Sstevel@tonic-gate * 51290Sstevel@tonic-gate * returns: cs_window_t * pointer to the found window 51300Sstevel@tonic-gate * NULL if window handle invalid or window not allocated 51310Sstevel@tonic-gate */ 51320Sstevel@tonic-gate cs_window_t * 51330Sstevel@tonic-gate cs_find_window(window_handle_t wh) 51340Sstevel@tonic-gate { 51350Sstevel@tonic-gate cs_window_t *cw; 51360Sstevel@tonic-gate 51370Sstevel@tonic-gate if ((GET_WINDOW_NUMBER(wh) > cs_globals.num_windows) || 51380Sstevel@tonic-gate (GET_WINDOW_MAGIC(wh) != WINDOW_HANDLE_MAGIC)) 51390Sstevel@tonic-gate return ((cs_window_t *)NULL); 51400Sstevel@tonic-gate 51410Sstevel@tonic-gate if ((cw = cs_get_wp(GET_WINDOW_NUMBER(wh))) == NULL) 51420Sstevel@tonic-gate return (NULL); 51430Sstevel@tonic-gate 51440Sstevel@tonic-gate if ((cw->state & CW_ALLOCATED) && (cw->state & CW_MEM)) 51450Sstevel@tonic-gate return (cw); 51460Sstevel@tonic-gate 51470Sstevel@tonic-gate return ((cs_window_t *)NULL); 51480Sstevel@tonic-gate } 51490Sstevel@tonic-gate 51500Sstevel@tonic-gate /* 51510Sstevel@tonic-gate * cs_create_window_handle - creates a unique window handle based on the 51520Sstevel@tonic-gate * passed window number. 51530Sstevel@tonic-gate */ 51540Sstevel@tonic-gate static window_handle_t 51550Sstevel@tonic-gate cs_create_window_handle(uint32_t aw) 51560Sstevel@tonic-gate { 51570Sstevel@tonic-gate return (WINDOW_HANDLE_MAGIC | (aw & WINDOW_HANDLE_MASK)); 51580Sstevel@tonic-gate } 51590Sstevel@tonic-gate 51600Sstevel@tonic-gate /* 51610Sstevel@tonic-gate * cs_find_mem_window - tries to find a memory window matching the caller's 51620Sstevel@tonic-gate * criteria 51630Sstevel@tonic-gate * 51640Sstevel@tonic-gate * We return the first window that matches the requested criteria. 51650Sstevel@tonic-gate * 51660Sstevel@tonic-gate * returns: CS_SUCCESS - if memory window found 51670Sstevel@tonic-gate * CS_OUT_OF_RESOURCE - if no windows match requirements 51680Sstevel@tonic-gate * CS_BAD_SIZE - if requested size can not be met 51690Sstevel@tonic-gate * CS_BAD_WINDOW - if an internal error occured 51700Sstevel@tonic-gate */ 51710Sstevel@tonic-gate /* BEGIN CSTYLED */ 51720Sstevel@tonic-gate static int 51730Sstevel@tonic-gate cs_find_mem_window(uint32_t sn, win_req_t *rw, uint32_t *assigned_window) 51740Sstevel@tonic-gate { 51750Sstevel@tonic-gate uint32_t wn; 51760Sstevel@tonic-gate int error = CS_OUT_OF_RESOURCE; 51770Sstevel@tonic-gate uint32_t window_num = PCMCIA_MAX_WINDOWS; 51780Sstevel@tonic-gate uint32_t min_size = UINT_MAX; 51790Sstevel@tonic-gate inquire_window_t inquire_window, *iw; 51800Sstevel@tonic-gate uint32_t MinSize, MaxSize, ReqGran, MemWndCaps, WndCaps; 51810Sstevel@tonic-gate uint32_t tws; 51820Sstevel@tonic-gate 51830Sstevel@tonic-gate iw = &inquire_window; 51840Sstevel@tonic-gate 51850Sstevel@tonic-gate for (wn = 0; wn < cs_globals.num_windows; wn++) { 51860Sstevel@tonic-gate cs_window_t *cw; 51870Sstevel@tonic-gate 51880Sstevel@tonic-gate /* 51890Sstevel@tonic-gate * If we can't get a pointer to this window, we should contine 51900Sstevel@tonic-gate * with scanning the next window, since this window might have 51910Sstevel@tonic-gate * been dropped. 51920Sstevel@tonic-gate */ 51930Sstevel@tonic-gate if ((cw = cs_get_wp(wn)) != NULL) { 51940Sstevel@tonic-gate iw->window = wn; 51950Sstevel@tonic-gate 51960Sstevel@tonic-gate if (SocketServices(SS_InquireWindow, iw) != SUCCESS) 51970Sstevel@tonic-gate return (CS_BAD_WINDOW); 51980Sstevel@tonic-gate 51990Sstevel@tonic-gate MinSize = iw->mem_win_char.MinSize; 52000Sstevel@tonic-gate MaxSize = iw->mem_win_char.MaxSize; 52010Sstevel@tonic-gate ReqGran = iw->mem_win_char.ReqGran; 52020Sstevel@tonic-gate MemWndCaps = iw->mem_win_char.MemWndCaps; 52030Sstevel@tonic-gate WndCaps = iw->WndCaps; 52040Sstevel@tonic-gate 52050Sstevel@tonic-gate if (WINDOW_FOR_SOCKET(iw->Sockets, sn) && 52060Sstevel@tonic-gate WINDOW_AVAILABLE_FOR_MEM(cw) && 52070Sstevel@tonic-gate WndCaps & (WC_COMMON|WC_ATTRIBUTE)) { 52080Sstevel@tonic-gate if ((error = cs_valid_window_speed(iw, rw->win_params.AccessSpeed)) == 52090Sstevel@tonic-gate CS_SUCCESS) { 52100Sstevel@tonic-gate error = CS_OUT_OF_RESOURCE; 52110Sstevel@tonic-gate if (cs_memwin_space_and_map_ok(iw, rw)) { 52120Sstevel@tonic-gate error = CS_BAD_SIZE; 52130Sstevel@tonic-gate if (!rw->Size) { 52140Sstevel@tonic-gate min_size = min(min_size, MinSize); 52150Sstevel@tonic-gate window_num = wn; 52160Sstevel@tonic-gate goto found_window; 52170Sstevel@tonic-gate } else { 52180Sstevel@tonic-gate if (!(MemWndCaps & WC_SIZE)) { 52190Sstevel@tonic-gate if (rw->Size == MinSize) { 52200Sstevel@tonic-gate min_size = MinSize; 52210Sstevel@tonic-gate window_num = wn; 52220Sstevel@tonic-gate goto found_window; 52230Sstevel@tonic-gate } 52240Sstevel@tonic-gate } else { /* WC_SIZE */ 52250Sstevel@tonic-gate if (!ReqGran) { 52260Sstevel@tonic-gate error = CS_BAD_WINDOW; 52270Sstevel@tonic-gate } else { 52280Sstevel@tonic-gate if ((rw->Size >= MinSize) && 52290Sstevel@tonic-gate (rw->Size <= MaxSize)) { 52300Sstevel@tonic-gate if (MemWndCaps & WC_POW2) { 52310Sstevel@tonic-gate unsigned rg = ReqGran; 52320Sstevel@tonic-gate for (tws = MinSize; tws <= MaxSize; 52330Sstevel@tonic-gate rg = (rg<<1)) { 52340Sstevel@tonic-gate if (rw->Size == tws) { 52350Sstevel@tonic-gate min_size = tws; 52360Sstevel@tonic-gate window_num = wn; 52370Sstevel@tonic-gate goto found_window; 52380Sstevel@tonic-gate } 52390Sstevel@tonic-gate tws += rg; 52400Sstevel@tonic-gate } /* for (tws) */ 52410Sstevel@tonic-gate } else { 52420Sstevel@tonic-gate for (tws = MinSize; tws <= MaxSize; 52430Sstevel@tonic-gate tws += ReqGran) { 52440Sstevel@tonic-gate if (rw->Size == tws) { 52450Sstevel@tonic-gate min_size = tws; 52460Sstevel@tonic-gate window_num = wn; 52470Sstevel@tonic-gate goto found_window; 52480Sstevel@tonic-gate } 52490Sstevel@tonic-gate } /* for (tws) */ 52500Sstevel@tonic-gate } /* if (!WC_POW2) */ 52510Sstevel@tonic-gate } /* if (Size >= MinSize) */ 52520Sstevel@tonic-gate } /* if (!ReqGran) */ 52530Sstevel@tonic-gate } /* if (WC_SIZE) */ 52540Sstevel@tonic-gate } /* if (rw->Size) */ 52550Sstevel@tonic-gate } /* if (cs_space_and_map_ok) */ 52560Sstevel@tonic-gate } /* if (cs_valid_window_speed) */ 52570Sstevel@tonic-gate } /* if (WINDOW_FOR_SOCKET) */ 52580Sstevel@tonic-gate } /* if (cs_get_wp) */ 52590Sstevel@tonic-gate } /* for (wn) */ 52600Sstevel@tonic-gate 52610Sstevel@tonic-gate /* 52620Sstevel@tonic-gate * If we got here and the window_num wasn't set by any window 52630Sstevel@tonic-gate * matches in the above code, it means that we didn't 52640Sstevel@tonic-gate * find a window matching the caller's criteria. 52650Sstevel@tonic-gate * If the error is CS_BAD_TYPE, it means that the last reason 52660Sstevel@tonic-gate * that we couldn't match a window was because the caller's 52670Sstevel@tonic-gate * requested speed was out of range of the last window that 52680Sstevel@tonic-gate * we checked. We convert this error code to CS_OUT_OF_RESOURCE 52690Sstevel@tonic-gate * to conform to the RequestWindow section of the PCMCIA 52700Sstevel@tonic-gate * Card Services spec. 52710Sstevel@tonic-gate */ 52720Sstevel@tonic-gate if (window_num == PCMCIA_MAX_WINDOWS) { 52730Sstevel@tonic-gate if (error == CS_BAD_TYPE) 52740Sstevel@tonic-gate error = CS_OUT_OF_RESOURCE; 52750Sstevel@tonic-gate return (error); 52760Sstevel@tonic-gate } 52770Sstevel@tonic-gate 52780Sstevel@tonic-gate found_window: 52790Sstevel@tonic-gate rw->Size = min_size; 52800Sstevel@tonic-gate *assigned_window = window_num; 52810Sstevel@tonic-gate iw->window = window_num; 52820Sstevel@tonic-gate SocketServices(SS_InquireWindow, iw); 52830Sstevel@tonic-gate MemWndCaps = iw->mem_win_char.MemWndCaps; 52840Sstevel@tonic-gate 52850Sstevel@tonic-gate if (MemWndCaps & WC_CALIGN) 52860Sstevel@tonic-gate rw->Attributes |= WIN_OFFSET_SIZE; 52870Sstevel@tonic-gate else 52880Sstevel@tonic-gate rw->Attributes &= ~WIN_OFFSET_SIZE; 52890Sstevel@tonic-gate return (CS_SUCCESS); 52900Sstevel@tonic-gate } 52910Sstevel@tonic-gate /* END CSTYLED */ 52920Sstevel@tonic-gate 52930Sstevel@tonic-gate /* 52940Sstevel@tonic-gate * cs_memwin_space_and_map_ok - checks to see if the passed window mapping 52950Sstevel@tonic-gate * capabilities and window speeds are in the 52960Sstevel@tonic-gate * range of the passed window. 52970Sstevel@tonic-gate * 52980Sstevel@tonic-gate * returns: 0 - if the capabilities are out of range 52990Sstevel@tonic-gate * 1 - if the capabilities are in range 53000Sstevel@tonic-gate */ 53010Sstevel@tonic-gate static int 53020Sstevel@tonic-gate cs_memwin_space_and_map_ok(inquire_window_t *iw, win_req_t *rw) 53030Sstevel@tonic-gate { 53040Sstevel@tonic-gate 53050Sstevel@tonic-gate #ifdef CS_DEBUG 53060Sstevel@tonic-gate if (cs_debug > 240) 53070Sstevel@tonic-gate printf("-> s&m_ok: Attributes 0x%x AccessSpeed 0x%x " 53080Sstevel@tonic-gate "WndCaps 0x%x MemWndCaps 0x%x\n", 53090Sstevel@tonic-gate (int)rw->Attributes, 53100Sstevel@tonic-gate (int)rw->win_params.AccessSpeed, 53110Sstevel@tonic-gate iw->WndCaps, 53120Sstevel@tonic-gate iw->mem_win_char.MemWndCaps); 53130Sstevel@tonic-gate #endif 53140Sstevel@tonic-gate 53150Sstevel@tonic-gate if (rw->win_params.AccessSpeed & WIN_USE_WAIT) { 53160Sstevel@tonic-gate if (!(iw->WndCaps & WC_WAIT)) 53170Sstevel@tonic-gate return (0); 53180Sstevel@tonic-gate } 53190Sstevel@tonic-gate 53200Sstevel@tonic-gate if (rw->Attributes & WIN_DATA_WIDTH_16) { 53210Sstevel@tonic-gate if (!(iw->mem_win_char.MemWndCaps & WC_16BIT)) 53220Sstevel@tonic-gate return (0); 53230Sstevel@tonic-gate } else { 53240Sstevel@tonic-gate if (!(iw->mem_win_char.MemWndCaps & WC_8BIT)) 53250Sstevel@tonic-gate return (0); 53260Sstevel@tonic-gate } 53270Sstevel@tonic-gate 53280Sstevel@tonic-gate if (rw->Attributes & WIN_MEMORY_TYPE_AM) { 53290Sstevel@tonic-gate if (!(iw->WndCaps & WC_ATTRIBUTE)) 53300Sstevel@tonic-gate return (0); 53310Sstevel@tonic-gate } 53320Sstevel@tonic-gate 53330Sstevel@tonic-gate if (rw->Attributes & WIN_MEMORY_TYPE_CM) { 53340Sstevel@tonic-gate if (!(iw->WndCaps & WC_COMMON)) 53350Sstevel@tonic-gate return (0); 53360Sstevel@tonic-gate } 53370Sstevel@tonic-gate 53380Sstevel@tonic-gate return (1); 53390Sstevel@tonic-gate } 53400Sstevel@tonic-gate 53410Sstevel@tonic-gate /* 53420Sstevel@tonic-gate * cs_valid_window_speed - checks to see if requested window speed 53430Sstevel@tonic-gate * is in range of passed window 53440Sstevel@tonic-gate * 53450Sstevel@tonic-gate * The inquire_window_t struct gives us speeds in nS, and we 53460Sstevel@tonic-gate * get speeds in the AccessSpeed variable as a devspeed code. 53470Sstevel@tonic-gate * 53480Sstevel@tonic-gate * returns: CS_BAD_SPEED - if AccessSpeed is invalid devspeed code 53490Sstevel@tonic-gate * CS_BAD_TYPE - if AccessSpeed is not in range of valid 53500Sstevel@tonic-gate * speed for this window 53510Sstevel@tonic-gate * CS_SUCCESS - if window speed is in range 53520Sstevel@tonic-gate */ 53530Sstevel@tonic-gate static int 53540Sstevel@tonic-gate cs_valid_window_speed(inquire_window_t *iw, uint32_t AccessSpeed) 53550Sstevel@tonic-gate { 53560Sstevel@tonic-gate convert_speed_t convert_speed, *cs; 53570Sstevel@tonic-gate 53580Sstevel@tonic-gate cs = &convert_speed; 53590Sstevel@tonic-gate 53600Sstevel@tonic-gate cs->Attributes = CONVERT_DEVSPEED_TO_NS; 53610Sstevel@tonic-gate cs->devspeed = AccessSpeed; 53620Sstevel@tonic-gate 53630Sstevel@tonic-gate if (cs_convert_speed(cs) != CS_SUCCESS) 53640Sstevel@tonic-gate return (CS_BAD_SPEED); 53650Sstevel@tonic-gate 53660Sstevel@tonic-gate if ((cs->nS < iw->mem_win_char.Fastest) || 53670Sstevel@tonic-gate (cs->nS > iw->mem_win_char.Slowest)) 53680Sstevel@tonic-gate return (CS_BAD_TYPE); 53690Sstevel@tonic-gate 53700Sstevel@tonic-gate return (CS_SUCCESS); 53710Sstevel@tonic-gate } 53720Sstevel@tonic-gate 53730Sstevel@tonic-gate /* 53740Sstevel@tonic-gate * ==== IO window handling section ==== 53750Sstevel@tonic-gate */ 53760Sstevel@tonic-gate 53770Sstevel@tonic-gate /* 53780Sstevel@tonic-gate * cs_request_io - provides IO resources for clients; this is RequestIO 53790Sstevel@tonic-gate * 53800Sstevel@tonic-gate * calling: cs_request_io(client_handle_t, io_req_t *) 53810Sstevel@tonic-gate * 53820Sstevel@tonic-gate * returns: CS_SUCCESS - if IO resources available for client 53830Sstevel@tonic-gate * CS_OUT_OF_RESOURCE - if no windows match requirements 53840Sstevel@tonic-gate * CS_BAD_HANDLE - client handle is invalid 53850Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - if SS is trying to call us 53860Sstevel@tonic-gate * CS_NO_CARD - if no card is in socket 53870Sstevel@tonic-gate * CS_BAD_ATTRIBUTE - if any of the unsupported Attribute 53880Sstevel@tonic-gate * flags are set 53890Sstevel@tonic-gate * CS_BAD_BASE - if either or both base port addresses 53900Sstevel@tonic-gate * are invalid or out of range 53910Sstevel@tonic-gate * CS_CONFIGURATION_LOCKED - a RequestConfiguration has 53920Sstevel@tonic-gate * already been done 53930Sstevel@tonic-gate * CS_IN_USE - IO ports already in use or function has 53940Sstevel@tonic-gate * already been called 53950Sstevel@tonic-gate * CS_BAD_WINDOW - if failure while trying to set window 53960Sstevel@tonic-gate * characteristics 53970Sstevel@tonic-gate */ 53980Sstevel@tonic-gate static int 53990Sstevel@tonic-gate cs_request_io(client_handle_t client_handle, io_req_t *ior) 54000Sstevel@tonic-gate { 54010Sstevel@tonic-gate cs_socket_t *sp; 54020Sstevel@tonic-gate client_t *client; 54030Sstevel@tonic-gate int error; 54040Sstevel@tonic-gate int client_lock_acquired; 54050Sstevel@tonic-gate uint32_t socket_num; 54060Sstevel@tonic-gate 54070Sstevel@tonic-gate /* 54080Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it 54090Sstevel@tonic-gate * is, we don't support SS using this call. 54100Sstevel@tonic-gate */ 54110Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) 54120Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION); 54130Sstevel@tonic-gate 54140Sstevel@tonic-gate /* 54150Sstevel@tonic-gate * If the client has only requested one IO range, then make sure 54160Sstevel@tonic-gate * that the Attributes2 filed is clear. 54170Sstevel@tonic-gate */ 54180Sstevel@tonic-gate if (!ior->NumPorts2) 54190Sstevel@tonic-gate ior->Attributes2 = 0; 54200Sstevel@tonic-gate 54210Sstevel@tonic-gate /* 54220Sstevel@tonic-gate * Make sure that none of the unsupported or reserved flags are set. 54230Sstevel@tonic-gate */ 54240Sstevel@tonic-gate if ((ior->Attributes1 | ior->Attributes2) & (IO_SHARED | 54250Sstevel@tonic-gate IO_FIRST_SHARED | 54260Sstevel@tonic-gate IO_FORCE_ALIAS_ACCESS | 54270Sstevel@tonic-gate IO_DEALLOCATE_WINDOW | 54280Sstevel@tonic-gate IO_DISABLE_WINDOW)) 54290Sstevel@tonic-gate return (CS_BAD_ATTRIBUTE); 54300Sstevel@tonic-gate 54310Sstevel@tonic-gate /* 54320Sstevel@tonic-gate * Make sure that we have a port count for the first region. 54330Sstevel@tonic-gate */ 54340Sstevel@tonic-gate if (!ior->NumPorts1) 54350Sstevel@tonic-gate return (CS_BAD_BASE); 54360Sstevel@tonic-gate 54370Sstevel@tonic-gate /* 54380Sstevel@tonic-gate * If we're being asked for multiple IO ranges, then both base port 54390Sstevel@tonic-gate * members must be non-zero. 54400Sstevel@tonic-gate */ 54410Sstevel@tonic-gate if ((ior->NumPorts2) && !(ior->BasePort1.base && ior->BasePort2.base)) 54420Sstevel@tonic-gate return (CS_BAD_BASE); 54430Sstevel@tonic-gate 54440Sstevel@tonic-gate mutex_enter(&cs_globals.window_lock); 54450Sstevel@tonic-gate 54460Sstevel@tonic-gate /* 54470Sstevel@tonic-gate * Get a pointer to this client's socket structure. 54480Sstevel@tonic-gate */ 54490Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) 54500Sstevel@tonic-gate return (CS_BAD_SOCKET); 54510Sstevel@tonic-gate 54520Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 54530Sstevel@tonic-gate 54540Sstevel@tonic-gate /* 54550Sstevel@tonic-gate * Make sure that this is a valid client handle. 54560Sstevel@tonic-gate */ 54570Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) { 54580Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 54590Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 54600Sstevel@tonic-gate return (error); 54610Sstevel@tonic-gate } 54620Sstevel@tonic-gate 54630Sstevel@tonic-gate /* 54640Sstevel@tonic-gate * If RequestConfiguration has already been done, we don't allow 54650Sstevel@tonic-gate * this call. 54660Sstevel@tonic-gate */ 54670Sstevel@tonic-gate if (client->flags & REQ_CONFIGURATION_DONE) { 54680Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 54690Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 54700Sstevel@tonic-gate return (CS_CONFIGURATION_LOCKED); 54710Sstevel@tonic-gate } 54720Sstevel@tonic-gate 54730Sstevel@tonic-gate /* 54740Sstevel@tonic-gate * If RequestIO has already been done, we don't allow this call. 54750Sstevel@tonic-gate */ 54760Sstevel@tonic-gate if (client->flags & REQ_IO_DONE) { 54770Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 54780Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 54790Sstevel@tonic-gate return (CS_IN_USE); 54800Sstevel@tonic-gate } 54810Sstevel@tonic-gate 54820Sstevel@tonic-gate mutex_enter(&sp->lock); 54830Sstevel@tonic-gate 54840Sstevel@tonic-gate /* 54850Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not 54860Sstevel@tonic-gate * for this client, then return an error. 54870Sstevel@tonic-gate */ 54880Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) { 54890Sstevel@tonic-gate mutex_exit(&sp->lock); 54900Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 54910Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 54920Sstevel@tonic-gate return (CS_NO_CARD); 54930Sstevel@tonic-gate } 54940Sstevel@tonic-gate 54950Sstevel@tonic-gate mutex_exit(&sp->lock); 54960Sstevel@tonic-gate 54970Sstevel@tonic-gate /* 54980Sstevel@tonic-gate * If we're only being asked for one IO range, then set BasePort2 to 54990Sstevel@tonic-gate * zero, since we use it later on. 55000Sstevel@tonic-gate */ 55010Sstevel@tonic-gate if (!ior->NumPorts2) 55020Sstevel@tonic-gate ior->BasePort2.base = 0; 55030Sstevel@tonic-gate 55040Sstevel@tonic-gate /* 55050Sstevel@tonic-gate * See if we can allow Card Services to select the base address 55060Sstevel@tonic-gate * value for this card; if the client has specified a non-zero 55070Sstevel@tonic-gate * base IO address but the card doesn't decode enough IO 55080Sstevel@tonic-gate * address lines to uniquely use that address, then we have 55090Sstevel@tonic-gate * the flexibility to choose an alternative base address. 55100Sstevel@tonic-gate * Note that if the client specifies that the card decodes zero 55110Sstevel@tonic-gate * IO address lines, then we have to use the NumPortsX 55120Sstevel@tonic-gate * values to figure out how many address lines the card 55130Sstevel@tonic-gate * actually decodes, and we have to round the NumPortsX 55140Sstevel@tonic-gate * values up to the closest power of two. 55150Sstevel@tonic-gate */ 55160Sstevel@tonic-gate if (ior->IOAddrLines) { 55170Sstevel@tonic-gate ior->BasePort1.base = IOADDR_FROBNITZ(ior->BasePort1.base, 55180Sstevel@tonic-gate ior->IOAddrLines); 55190Sstevel@tonic-gate ior->BasePort2.base = IOADDR_FROBNITZ(ior->BasePort2.base, 55200Sstevel@tonic-gate ior->IOAddrLines); 55210Sstevel@tonic-gate } else { 55220Sstevel@tonic-gate ior->BasePort1.base = ior->BasePort1.base & 55230Sstevel@tonic-gate ((IONUMPORTS_FROBNITZ(ior->NumPorts1) + 55240Sstevel@tonic-gate IONUMPORTS_FROBNITZ(ior->NumPorts2)) - 1); 55250Sstevel@tonic-gate ior->BasePort2.base = ior->BasePort2.base & 55260Sstevel@tonic-gate ((IONUMPORTS_FROBNITZ(ior->NumPorts1) + 55270Sstevel@tonic-gate IONUMPORTS_FROBNITZ(ior->NumPorts2)) - 1); 55280Sstevel@tonic-gate } 55290Sstevel@tonic-gate 55300Sstevel@tonic-gate socket_num = CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle), 55310Sstevel@tonic-gate GET_CLIENT_FUNCTION(client_handle)); 55320Sstevel@tonic-gate 55330Sstevel@tonic-gate 55340Sstevel@tonic-gate #ifdef USE_IOMMAP_WINDOW 55350Sstevel@tonic-gate /* 55360Sstevel@tonic-gate * Here is where the code diverges, depending on the type of IO windows 55370Sstevel@tonic-gate * that this socket supports. If this socket supportes memory 55380Sstevel@tonic-gate * mapped IO windows, as determined by cs_init allocating an 55390Sstevel@tonic-gate * io_mmap_window_t structure on the socket structure, then we 55400Sstevel@tonic-gate * use one IO window for all the clients on this socket. We can 55410Sstevel@tonic-gate * do this safely since a memory mapped IO window implies that 55420Sstevel@tonic-gate * only this socket shares the complete IO space of the card. 55430Sstevel@tonic-gate * See the next major block of code for a description of what we do 55440Sstevel@tonic-gate * if a socket doesn't support memory mapped IO windows. 55450Sstevel@tonic-gate */ 55460Sstevel@tonic-gate if (sp->io_mmap_window) { 55470Sstevel@tonic-gate cs_window_t *cw; 55480Sstevel@tonic-gate io_mmap_window_t *imw = sp->io_mmap_window; 55490Sstevel@tonic-gate uint32_t offset; 55500Sstevel@tonic-gate 55510Sstevel@tonic-gate /* 55520Sstevel@tonic-gate * If we haven't allocated an IO window yet, do it now. 55530Sstevel@tonic-gate * Try to allocate the IO window that cs_init found for us; 55540Sstevel@tonic-gate * if that fails, then call cs_find_io_win to find a window. 55550Sstevel@tonic-gate */ 55560Sstevel@tonic-gate if (!imw->count) { 55570Sstevel@tonic-gate set_window_t set_window; 55580Sstevel@tonic-gate 55590Sstevel@tonic-gate if (!WINDOW_AVAILABLE_FOR_IO(imw->number)) { 55600Sstevel@tonic-gate iowin_char_t iowin_char; 55610Sstevel@tonic-gate 55620Sstevel@tonic-gate iowin_char.IOWndCaps = (WC_IO_RANGE_PER_WINDOW | 55630Sstevel@tonic-gate WC_8BIT | 55640Sstevel@tonic-gate WC_16BIT); 55650Sstevel@tonic-gate if ((error = cs_find_io_win(sp->socket_num, &iowin_char, 55660Sstevel@tonic-gate &imw->number, &imw->size)) != CS_SUCCESS) { 55670Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 55680Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 55690Sstevel@tonic-gate } /* cs_find_io_win */ 55700Sstevel@tonic-gate } /* if (!WINDOW_AVAILABLE_FOR_IO) */ 55710Sstevel@tonic-gate 55720Sstevel@tonic-gate set_window.socket = socket_num; 55730Sstevel@tonic-gate set_window.window = imw->number; 55740Sstevel@tonic-gate set_window.speed = IO_WIN_SPEED; 55750Sstevel@tonic-gate set_window.base.base = 0; 55760Sstevel@tonic-gate set_window.WindowSize = imw->size; 55770Sstevel@tonic-gate set_window.state = (WS_ENABLED | WS_16BIT | 55780Sstevel@tonic-gate WS_EXACT_MAPIN | WS_IO); 55790Sstevel@tonic-gate 55800Sstevel@tonic-gate /* XXX - what to d here? XXX */ 55810Sstevel@tonic-gate cs_set_acc_attributes(&set_window, Attributes); 55820Sstevel@tonic-gate 55830Sstevel@tonic-gate if (SocketServices(SS_SetWindow, &set_window) != SUCCESS) { 55840Sstevel@tonic-gate (void) cs_setup_io_win(socket_num, imw->number, 55850Sstevel@tonic-gate NULL, NULL, NULL, 55860Sstevel@tonic-gate (IO_DEALLOCATE_WINDOW | 55870Sstevel@tonic-gate IO_DISABLE_WINDOW)); 55880Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 55890Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 55900Sstevel@tonic-gate return (CS_BAD_WINDOW); 55910Sstevel@tonic-gate } 55920Sstevel@tonic-gate 55930Sstevel@tonic-gate imw->handle = set_window.base.handle; 55940Sstevel@tonic-gate imw->size = set_window.WindowSize; 55950Sstevel@tonic-gate 55960Sstevel@tonic-gate /* 55970Sstevel@tonic-gate * Check the caller's port requirements to be sure that they 55980Sstevel@tonic-gate * fit within our found IO window. 55990Sstevel@tonic-gate */ 56000Sstevel@tonic-gate if ((ior->BasePort1.base + ior->NumPorts1 + 56010Sstevel@tonic-gate ior->BasePort2.base + ior->NumPorts2) > imw->size) { 56020Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 56030Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 56040Sstevel@tonic-gate return (CS_BAD_BASE); 56050Sstevel@tonic-gate } 56060Sstevel@tonic-gate 56070Sstevel@tonic-gate if ((cw = cs_get_wp(imw->number)) == NULL) { 56080Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 56090Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 56100Sstevel@tonic-gate return (CS_BAD_WINDOW) 56110Sstevel@tonic-gate } 56120Sstevel@tonic-gate cw->state |= (CW_ALLOCATED | CW_IO); 56130Sstevel@tonic-gate 56140Sstevel@tonic-gate } /* if (!imw->count) */ 56150Sstevel@tonic-gate 56160Sstevel@tonic-gate imw->count++; 56170Sstevel@tonic-gate 56180Sstevel@tonic-gate /* 56190Sstevel@tonic-gate * All common access handles for this type of adapter are 56200Sstevel@tonic-gate * duped. We never give the original back to the caller. 56210Sstevel@tonic-gate */ 56220Sstevel@tonic-gate /* XXX need to set endianess and data ordering flags */ 56230Sstevel@tonic-gate csx_DupHandle(imw->handle, &ior->BasePort1.handle, 0); 56240Sstevel@tonic-gate csx_GetHandleOffset(ior->BasePort1.handle, &offset); 56250Sstevel@tonic-gate csx_SetHandleOffset(ior->BasePort1.handle, 56260Sstevel@tonic-gate ior->BasePort1.base + offset); 56270Sstevel@tonic-gate 56280Sstevel@tonic-gate if (ior->NumPorts2) { 56290Sstevel@tonic-gate /* XXX need to set endianess and data ordering flags */ 56300Sstevel@tonic-gate csx_DupHandle(imw->handle, &ior->BasePort2.handle, 0); 56310Sstevel@tonic-gate csx_GetHandleOffset(ior->BasePort2.handle, &offset); 56320Sstevel@tonic-gate csx_SetHandleOffset(ior->BasePort2.handle, 56330Sstevel@tonic-gate ior->BasePort1.base + offset); 56340Sstevel@tonic-gate } 56350Sstevel@tonic-gate 56360Sstevel@tonic-gate /* 56370Sstevel@tonic-gate * We don't really use these two values if we've got a memory 56380Sstevel@tonic-gate * mapped IO window since the assigned window number is stored 56390Sstevel@tonic-gate * in imw->number. 56400Sstevel@tonic-gate */ 56410Sstevel@tonic-gate client->io_alloc.Window1 = imw->number; 56420Sstevel@tonic-gate client->io_alloc.Window2 = PCMCIA_MAX_WINDOWS; 56430Sstevel@tonic-gate 56440Sstevel@tonic-gate /* 56450Sstevel@tonic-gate * This socket supports only IO port IO windows. 56460Sstevel@tonic-gate */ 56470Sstevel@tonic-gate } else { 56480Sstevel@tonic-gate #else /* USE_IOMMAP_WINDOW */ 56490Sstevel@tonic-gate { 56500Sstevel@tonic-gate #endif /* USE_IOMMAP_WINDOW */ 56510Sstevel@tonic-gate baseaddru_t baseaddru; 56520Sstevel@tonic-gate 56530Sstevel@tonic-gate baseaddru.base = ior->BasePort1.base; 56540Sstevel@tonic-gate 56550Sstevel@tonic-gate if ((error = cs_allocate_io_win(sp->socket_num, ior->Attributes1, 56560Sstevel@tonic-gate &client->io_alloc.Window1)) != CS_SUCCESS) { 56570Sstevel@tonic-gate 56580Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 56590Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 56600Sstevel@tonic-gate return (error); 56610Sstevel@tonic-gate } /* if (cs_allocate_io_win(1)) */ 56620Sstevel@tonic-gate 56630Sstevel@tonic-gate /* 56640Sstevel@tonic-gate * Setup the window hardware; if this fails, then we need to 56650Sstevel@tonic-gate * deallocate the previously allocated window. 56660Sstevel@tonic-gate */ 56670Sstevel@tonic-gate if ((error = cs_setup_io_win(socket_num, 56680Sstevel@tonic-gate client->io_alloc.Window1, 56690Sstevel@tonic-gate &baseaddru, 56700Sstevel@tonic-gate &ior->NumPorts1, 56710Sstevel@tonic-gate ior->IOAddrLines, 56720Sstevel@tonic-gate ior->Attributes1)) != 56730Sstevel@tonic-gate CS_SUCCESS) { 56740Sstevel@tonic-gate (void) cs_setup_io_win(socket_num, client->io_alloc.Window1, 56750Sstevel@tonic-gate NULL, NULL, NULL, 56760Sstevel@tonic-gate ( 56770Sstevel@tonic-gate IO_DEALLOCATE_WINDOW | 56780Sstevel@tonic-gate IO_DISABLE_WINDOW)); 56790Sstevel@tonic-gate 56800Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 56810Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 56820Sstevel@tonic-gate return (error); 56830Sstevel@tonic-gate } /* if (cs_setup_io_win(1)) */ 56840Sstevel@tonic-gate 56850Sstevel@tonic-gate ior->BasePort1.handle = (acc_handle_t)baseaddru.handle; 56860Sstevel@tonic-gate ior->BasePort1.base = baseaddru.base; 56870Sstevel@tonic-gate 56880Sstevel@tonic-gate /* 56890Sstevel@tonic-gate * See if the client wants two IO ranges. 56900Sstevel@tonic-gate */ 56910Sstevel@tonic-gate if (ior->NumPorts2) { 56920Sstevel@tonic-gate baseaddru_t baseaddru; 56930Sstevel@tonic-gate 56940Sstevel@tonic-gate baseaddru.base = ior->BasePort2.base; 56950Sstevel@tonic-gate 56960Sstevel@tonic-gate /* 56970Sstevel@tonic-gate * If we fail to allocate this window, then we must deallocate 56980Sstevel@tonic-gate * the previous IO window that is already allocated. 56990Sstevel@tonic-gate */ 57000Sstevel@tonic-gate if ((error = cs_allocate_io_win(sp->socket_num, 57010Sstevel@tonic-gate ior->Attributes2, 57020Sstevel@tonic-gate &client->io_alloc.Window2)) != 57030Sstevel@tonic-gate CS_SUCCESS) { 57040Sstevel@tonic-gate (void) cs_setup_io_win(socket_num, 57050Sstevel@tonic-gate client->io_alloc.Window2, 57060Sstevel@tonic-gate NULL, NULL, NULL, 57070Sstevel@tonic-gate ( 57080Sstevel@tonic-gate IO_DEALLOCATE_WINDOW | 57090Sstevel@tonic-gate IO_DISABLE_WINDOW)); 57100Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 57110Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 57120Sstevel@tonic-gate return (error); 57130Sstevel@tonic-gate } /* if (cs_allocate_io_win(2)) */ 57140Sstevel@tonic-gate /* 57150Sstevel@tonic-gate * Setup the window hardware; if this fails, then we need to 57160Sstevel@tonic-gate * deallocate the previously allocated window. 57170Sstevel@tonic-gate */ 57180Sstevel@tonic-gate if ((error = cs_setup_io_win(socket_num, 57190Sstevel@tonic-gate client->io_alloc.Window2, 57200Sstevel@tonic-gate &baseaddru, 57210Sstevel@tonic-gate &ior->NumPorts2, 57220Sstevel@tonic-gate ior->IOAddrLines, 57230Sstevel@tonic-gate ior->Attributes2)) != 57240Sstevel@tonic-gate CS_SUCCESS) { 57250Sstevel@tonic-gate (void) cs_setup_io_win(socket_num, 57260Sstevel@tonic-gate client->io_alloc.Window1, 57270Sstevel@tonic-gate NULL, NULL, NULL, 57280Sstevel@tonic-gate ( 57290Sstevel@tonic-gate IO_DEALLOCATE_WINDOW | 57300Sstevel@tonic-gate IO_DISABLE_WINDOW)); 57310Sstevel@tonic-gate (void) cs_setup_io_win(socket_num, 57320Sstevel@tonic-gate client->io_alloc.Window2, 57330Sstevel@tonic-gate NULL, NULL, NULL, 57340Sstevel@tonic-gate ( 57350Sstevel@tonic-gate IO_DEALLOCATE_WINDOW | 57360Sstevel@tonic-gate IO_DISABLE_WINDOW)); 57370Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 57380Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 57390Sstevel@tonic-gate return (error); 57400Sstevel@tonic-gate } /* if (cs_setup_io_win(2)) */ 57410Sstevel@tonic-gate 57420Sstevel@tonic-gate ior->BasePort2.handle = (acc_handle_t)baseaddru.handle; 57430Sstevel@tonic-gate ior->BasePort2.base = baseaddru.base; 57440Sstevel@tonic-gate 57450Sstevel@tonic-gate } else { 57460Sstevel@tonic-gate client->io_alloc.Window2 = PCMCIA_MAX_WINDOWS; 57470Sstevel@tonic-gate } /* if (ior->NumPorts2) */ 57480Sstevel@tonic-gate } /* if (sp->io_mmap_window) */ 57490Sstevel@tonic-gate 57500Sstevel@tonic-gate /* 57510Sstevel@tonic-gate * Save a copy of the client's port information so that we 57520Sstevel@tonic-gate * can use it in the RequestConfiguration call. We set 57530Sstevel@tonic-gate * the IO window number(s) allocated in the respective 57540Sstevel@tonic-gate * section of code, above. 57550Sstevel@tonic-gate */ 57560Sstevel@tonic-gate client->io_alloc.BasePort1.base = ior->BasePort1.base; 57570Sstevel@tonic-gate client->io_alloc.BasePort1.handle = ior->BasePort1.handle; 57580Sstevel@tonic-gate client->io_alloc.NumPorts1 = ior->NumPorts1; 57590Sstevel@tonic-gate client->io_alloc.Attributes1 = ior->Attributes1; 57600Sstevel@tonic-gate client->io_alloc.BasePort2.base = ior->BasePort2.base; 57610Sstevel@tonic-gate client->io_alloc.BasePort2.handle = ior->BasePort2.handle; 57620Sstevel@tonic-gate client->io_alloc.NumPorts2 = ior->NumPorts2; 57630Sstevel@tonic-gate client->io_alloc.Attributes2 = ior->Attributes2; 57640Sstevel@tonic-gate client->io_alloc.IOAddrLines = ior->IOAddrLines; 57650Sstevel@tonic-gate 57660Sstevel@tonic-gate /* 57670Sstevel@tonic-gate * Mark this client as having done a successful RequestIO call. 57680Sstevel@tonic-gate */ 57690Sstevel@tonic-gate client->flags |= (REQ_IO_DONE | CLIENT_IO_ALLOCATED); 57700Sstevel@tonic-gate 57710Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 57720Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 57730Sstevel@tonic-gate 57740Sstevel@tonic-gate return (CS_SUCCESS); 57750Sstevel@tonic-gate } 57760Sstevel@tonic-gate 57770Sstevel@tonic-gate /* 57780Sstevel@tonic-gate * cs_release_io - releases IO resources allocated by RequestIO; this is 57790Sstevel@tonic-gate * ReleaseIO 57800Sstevel@tonic-gate * 57810Sstevel@tonic-gate * calling: cs_release_io(client_handle_t, io_req_t *) 57820Sstevel@tonic-gate * 57830Sstevel@tonic-gate * returns: CS_SUCCESS - if IO resources sucessfully deallocated 57840Sstevel@tonic-gate * CS_BAD_HANDLE - client handle is invalid 57850Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - if SS is trying to call us 57860Sstevel@tonic-gate * CS_CONFIGURATION_LOCKED - a RequestConfiguration has been 57870Sstevel@tonic-gate * done without a ReleaseConfiguration 57880Sstevel@tonic-gate * CS_IN_USE - no RequestIO has been done 57890Sstevel@tonic-gate */ 57900Sstevel@tonic-gate static int 57910Sstevel@tonic-gate cs_release_io(client_handle_t client_handle, io_req_t *ior) 57920Sstevel@tonic-gate { 57930Sstevel@tonic-gate cs_socket_t *sp; 57940Sstevel@tonic-gate client_t *client; 57950Sstevel@tonic-gate int error; 57960Sstevel@tonic-gate int client_lock_acquired; 57970Sstevel@tonic-gate uint32_t socket_num; 57980Sstevel@tonic-gate 57990Sstevel@tonic-gate #ifdef lint 58000Sstevel@tonic-gate ior = NULL; 58010Sstevel@tonic-gate #endif 58020Sstevel@tonic-gate 58030Sstevel@tonic-gate /* 58040Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it 58050Sstevel@tonic-gate * is, we don't support SS using this call. 58060Sstevel@tonic-gate */ 58070Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) 58080Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION); 58090Sstevel@tonic-gate 58100Sstevel@tonic-gate mutex_enter(&cs_globals.window_lock); 58110Sstevel@tonic-gate 58120Sstevel@tonic-gate /* 58130Sstevel@tonic-gate * Get a pointer to this client's socket structure. 58140Sstevel@tonic-gate */ 58150Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) 58160Sstevel@tonic-gate return (CS_BAD_SOCKET); 58170Sstevel@tonic-gate 58180Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 58190Sstevel@tonic-gate 58200Sstevel@tonic-gate /* 58210Sstevel@tonic-gate * Make sure that this is a valid client handle. 58220Sstevel@tonic-gate */ 58230Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) { 58240Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 58250Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 58260Sstevel@tonic-gate return (error); 58270Sstevel@tonic-gate } 58280Sstevel@tonic-gate 58290Sstevel@tonic-gate /* 58300Sstevel@tonic-gate * If RequestConfiguration has already been done, we don't allow 58310Sstevel@tonic-gate * this call. 58320Sstevel@tonic-gate */ 58330Sstevel@tonic-gate if (client->flags & REQ_CONFIGURATION_DONE) { 58340Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 58350Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 58360Sstevel@tonic-gate return (CS_CONFIGURATION_LOCKED); 58370Sstevel@tonic-gate } 58380Sstevel@tonic-gate 58390Sstevel@tonic-gate /* 58400Sstevel@tonic-gate * If RequestIO has not been done, we don't allow this call. 58410Sstevel@tonic-gate */ 58420Sstevel@tonic-gate if (!(client->flags & REQ_IO_DONE)) { 58430Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 58440Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 58450Sstevel@tonic-gate return (CS_IN_USE); 58460Sstevel@tonic-gate } 58470Sstevel@tonic-gate 58480Sstevel@tonic-gate socket_num = CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle), 58490Sstevel@tonic-gate GET_CLIENT_FUNCTION(client_handle)); 58500Sstevel@tonic-gate 58510Sstevel@tonic-gate #ifdef XXX 58520Sstevel@tonic-gate /* 58530Sstevel@tonic-gate * Check the passed IO allocation with the stored allocation; if 58540Sstevel@tonic-gate * they don't match, then return an error. 58550Sstevel@tonic-gate */ 58560Sstevel@tonic-gate if ((client->io_alloc.BasePort1 != ior->BasePort1) || 58570Sstevel@tonic-gate (client->io_alloc.NumPorts1 != ior->NumPorts1) || 58580Sstevel@tonic-gate (client->io_alloc.Attributes1 != ior->Attributes1) || 58590Sstevel@tonic-gate (client->io_alloc.BasePort2 != ior->BasePort2) || 58600Sstevel@tonic-gate (client->io_alloc.NumPorts2 != ior->NumPorts2) || 58610Sstevel@tonic-gate (client->io_alloc.Attributes2 != ior->Attributes2) || 58620Sstevel@tonic-gate (client->io_alloc.IOAddrLines != ior->IOAddrLines)) { 58630Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 58640Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 58650Sstevel@tonic-gate return (CS_BAD_ARGS); 58660Sstevel@tonic-gate } 58670Sstevel@tonic-gate #endif 58680Sstevel@tonic-gate 58690Sstevel@tonic-gate #ifdef USE_IOMMAP_WINDOW 58700Sstevel@tonic-gate /* 58710Sstevel@tonic-gate * The code diverges here depending on if this socket supports 58720Sstevel@tonic-gate * memory mapped IO windows or not. See comments in the 58730Sstevel@tonic-gate * cs_request_io function for a description of what's 58740Sstevel@tonic-gate * going on here. 58750Sstevel@tonic-gate */ 58760Sstevel@tonic-gate if (sp->io_mmap_window) { 58770Sstevel@tonic-gate io_mmap_window_t *imw = sp->io_mmap_window; 58780Sstevel@tonic-gate 58790Sstevel@tonic-gate /* 58800Sstevel@tonic-gate * We should never see this; if we do, it's an internal 58810Sstevel@tonic-gate * consistency error. 58820Sstevel@tonic-gate */ 58830Sstevel@tonic-gate if (!imw->count) { 58840Sstevel@tonic-gate cmn_err(CE_CONT, "cs_release_io: socket %d !imw->count\n", 58850Sstevel@tonic-gate sp->socket_num); 58860Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 58870Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 58880Sstevel@tonic-gate return (CS_GENERAL_FAILURE); 58890Sstevel@tonic-gate } 58900Sstevel@tonic-gate 58910Sstevel@tonic-gate /* 58920Sstevel@tonic-gate * All common access handles for this type of adapter are 58930Sstevel@tonic-gate * duped. We never give the original back to the caller, 58940Sstevel@tonic-gate * so it's OK to unconditionally free the handle here. 58950Sstevel@tonic-gate */ 58960Sstevel@tonic-gate csx_FreeHandle(&ior->BasePort1.handle); 58970Sstevel@tonic-gate 58980Sstevel@tonic-gate /* 58990Sstevel@tonic-gate * If the IO window referance count is zero, then deallocate 59000Sstevel@tonic-gate * and disable this window. 59010Sstevel@tonic-gate */ 59020Sstevel@tonic-gate if (!--(imw->count)) { 59030Sstevel@tonic-gate (void) cs_setup_io_win(socket_num, imw->number, NULL, 59040Sstevel@tonic-gate NULL, NULL, 59050Sstevel@tonic-gate ( 59060Sstevel@tonic-gate IO_DEALLOCATE_WINDOW | 59070Sstevel@tonic-gate IO_DISABLE_WINDOW)); 59080Sstevel@tonic-gate } /* if (imw->count) */ 59090Sstevel@tonic-gate } else { 59100Sstevel@tonic-gate #endif /* USE_IOMMAP_WINDOW */ 59110Sstevel@tonic-gate (void) cs_setup_io_win(socket_num, client->io_alloc.Window1, 59120Sstevel@tonic-gate NULL, NULL, NULL, 59130Sstevel@tonic-gate ( 59140Sstevel@tonic-gate IO_DEALLOCATE_WINDOW | 59150Sstevel@tonic-gate IO_DISABLE_WINDOW)); 59160Sstevel@tonic-gate if (client->io_alloc.Window2 != PCMCIA_MAX_WINDOWS) 59170Sstevel@tonic-gate (void) cs_setup_io_win(socket_num, client->io_alloc.Window2, 59180Sstevel@tonic-gate NULL, NULL, NULL, 59190Sstevel@tonic-gate ( 59200Sstevel@tonic-gate IO_DEALLOCATE_WINDOW | 59210Sstevel@tonic-gate IO_DISABLE_WINDOW)); 59220Sstevel@tonic-gate #ifdef USE_IOMMAP_WINDOW 59230Sstevel@tonic-gate } /* if (sp->io_mmap_window) */ 59240Sstevel@tonic-gate #endif /* USE_IOMMAP_WINDOW */ 59250Sstevel@tonic-gate 59260Sstevel@tonic-gate /* 59270Sstevel@tonic-gate * Mark the client as not having any IO resources allocated. 59280Sstevel@tonic-gate */ 59290Sstevel@tonic-gate client->flags &= ~(REQ_IO_DONE | CLIENT_IO_ALLOCATED); 59300Sstevel@tonic-gate 59310Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 59320Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 59330Sstevel@tonic-gate return (CS_SUCCESS); 59340Sstevel@tonic-gate } 59350Sstevel@tonic-gate 59360Sstevel@tonic-gate /* 59370Sstevel@tonic-gate * cs_find_io_win - finds an IO window that matches the parameters specified 59380Sstevel@tonic-gate * in the flags argument 59390Sstevel@tonic-gate * 59400Sstevel@tonic-gate * calling: sn - socket number to look for IO window on 59410Sstevel@tonic-gate * *iwc - other window characteristics to match 59420Sstevel@tonic-gate * *assigned_window - pointer to where we return the assigned 59430Sstevel@tonic-gate * window number if we found a window or 59440Sstevel@tonic-gate * undefined otherwise 59450Sstevel@tonic-gate * *size - if non-NULL, the found window size will be stored here 59460Sstevel@tonic-gate * 59470Sstevel@tonic-gate * returns: CS_SUCCESS - if IO window found 59480Sstevel@tonic-gate * CS_OUT_OF_RESOURCE - if no windows match requirements 59490Sstevel@tonic-gate */ 59500Sstevel@tonic-gate static int 59510Sstevel@tonic-gate cs_find_io_win(uint32_t sn, iowin_char_t *iwc, uint32_t *assigned_window, 59520Sstevel@tonic-gate uint32_t *size) 59530Sstevel@tonic-gate { 59540Sstevel@tonic-gate inquire_window_t inquire_window, *iw; 59550Sstevel@tonic-gate unsigned wn; 59560Sstevel@tonic-gate 59570Sstevel@tonic-gate iw = &inquire_window; 59580Sstevel@tonic-gate 59590Sstevel@tonic-gate for (wn = 0; wn < cs_globals.num_windows; wn++) { 59600Sstevel@tonic-gate iowin_char_t *iowc; 59610Sstevel@tonic-gate cs_window_t *cw; 59620Sstevel@tonic-gate 59630Sstevel@tonic-gate if ((cw = cs_get_wp(wn)) != NULL) { 59640Sstevel@tonic-gate 59650Sstevel@tonic-gate iw->window = wn; 59660Sstevel@tonic-gate SocketServices(SS_InquireWindow, iw); 59670Sstevel@tonic-gate 59680Sstevel@tonic-gate iowc = &iw->iowin_char; 59690Sstevel@tonic-gate 59700Sstevel@tonic-gate if (WINDOW_FOR_SOCKET(iw->Sockets, sn) && 59710Sstevel@tonic-gate WINDOW_AVAILABLE_FOR_IO(cw) && 59720Sstevel@tonic-gate (iw->WndCaps & WC_IO) && 59730Sstevel@tonic-gate ((iowc->IOWndCaps & iwc->IOWndCaps) == iwc->IOWndCaps)) { 59740Sstevel@tonic-gate 59750Sstevel@tonic-gate *assigned_window = wn; 59760Sstevel@tonic-gate 59770Sstevel@tonic-gate if (size) 59780Sstevel@tonic-gate *size = iw->iowin_char.ReqGran; 59790Sstevel@tonic-gate return (CS_SUCCESS); 59800Sstevel@tonic-gate } /* if (WINDOW_FOR_SOCKET) */ 59810Sstevel@tonic-gate } /* cs_get_wp */ 59820Sstevel@tonic-gate } /* for (wn) */ 59830Sstevel@tonic-gate 59840Sstevel@tonic-gate return (CS_OUT_OF_RESOURCE); 59850Sstevel@tonic-gate } 59860Sstevel@tonic-gate 59870Sstevel@tonic-gate /* 59880Sstevel@tonic-gate * cs_allocate_io_win - finds and allocates an IO window 59890Sstevel@tonic-gate * 59900Sstevel@tonic-gate * calling: sn - socket number to look for window on 59910Sstevel@tonic-gate * Attributes - window attributes in io_req_t.Attributes format 59920Sstevel@tonic-gate * *assigned_window - pointer to return assigned window number 59930Sstevel@tonic-gate * 59940Sstevel@tonic-gate * returns: CS_SUCCESS - IO window found and allocated 59950Sstevel@tonic-gate * CS_OUT_OF_RESOURCE - if cs_find_io_win couldn't find a 59960Sstevel@tonic-gate * window that matches the passed criteria 59970Sstevel@tonic-gate * 59980Sstevel@tonic-gate * Note: This fucntion will find and allocate an IO window. The caller is 59990Sstevel@tonic-gate * responsible for deallocating the window. 60000Sstevel@tonic-gate */ 60010Sstevel@tonic-gate static int 60020Sstevel@tonic-gate cs_allocate_io_win(uint32_t sn, uint32_t Attributes, uint32_t *assigned_window) 60030Sstevel@tonic-gate { 60040Sstevel@tonic-gate iowin_char_t iowin_char; 60050Sstevel@tonic-gate cs_window_t *cw; 60060Sstevel@tonic-gate 60070Sstevel@tonic-gate iowin_char.IOWndCaps = 60080Sstevel@tonic-gate ((Attributes & IO_DATA_PATH_WIDTH_16)?WC_16BIT:WC_8BIT); 60090Sstevel@tonic-gate 60100Sstevel@tonic-gate if (cs_find_io_win(sn, &iowin_char, assigned_window, NULL) == 60110Sstevel@tonic-gate CS_SUCCESS) { 60120Sstevel@tonic-gate if ((cw = cs_get_wp(*assigned_window)) == NULL) 60130Sstevel@tonic-gate return (CS_OUT_OF_RESOURCE); 60140Sstevel@tonic-gate 60150Sstevel@tonic-gate cw->state = (cw->state & CW_WINDOW_VALID) | (CW_ALLOCATED | CW_IO); 60160Sstevel@tonic-gate return (CS_SUCCESS); 60170Sstevel@tonic-gate } 60180Sstevel@tonic-gate 60190Sstevel@tonic-gate return (CS_OUT_OF_RESOURCE); 60200Sstevel@tonic-gate } 60210Sstevel@tonic-gate 60220Sstevel@tonic-gate /* 60230Sstevel@tonic-gate * cs_setup_io_win - setup and destroy an IO window 60240Sstevel@tonic-gate * 60250Sstevel@tonic-gate * calling: sn - socket number 60260Sstevel@tonic-gate * wn - window number 60270Sstevel@tonic-gate * XXX Base - pointer to XXX 60280Sstevel@tonic-gate * *NumPorts - pointer to number of allocated ports to return 60290Sstevel@tonic-gate * IOAddrLines - number of IO address lines decoded by this card 60300Sstevel@tonic-gate * Attributes - either io_req_t attributes, or a combination of 60310Sstevel@tonic-gate * the following flags: 60320Sstevel@tonic-gate * IO_DEALLOCATE_WINDOW - deallocate the window 60330Sstevel@tonic-gate * IO_DISABLE_WINDOW - disable the window 60340Sstevel@tonic-gate * When either of these two flags are set, *Base 60350Sstevel@tonic-gate * and NumPorts should be NULL. 60360Sstevel@tonic-gate * 60370Sstevel@tonic-gate * returns: CS_SUCCESS - if no failure 60380Sstevel@tonic-gate * CS_BAD_WINDOW - if error while trying to configure window 60390Sstevel@tonic-gate * 60400Sstevel@tonic-gate * Note: We use the IOAddrLines value to determine what base address to pass 60410Sstevel@tonic-gate * to Socket Services. 60420Sstevel@tonic-gate */ 60430Sstevel@tonic-gate static int 60440Sstevel@tonic-gate cs_setup_io_win(uint32_t sn, uint32_t wn, baseaddru_t *Base, uint32_t *NumPorts, 60450Sstevel@tonic-gate uint32_t IOAddrLines, uint32_t Attributes) 60460Sstevel@tonic-gate { 60470Sstevel@tonic-gate set_window_t set_window; 60480Sstevel@tonic-gate 60490Sstevel@tonic-gate if (Attributes & (IO_DEALLOCATE_WINDOW | IO_DISABLE_WINDOW)) { 60500Sstevel@tonic-gate 60510Sstevel@tonic-gate if (Attributes & IO_DEALLOCATE_WINDOW) { 60520Sstevel@tonic-gate cs_window_t *cw; 60530Sstevel@tonic-gate 60540Sstevel@tonic-gate if ((cw = cs_get_wp(wn)) == NULL) 60550Sstevel@tonic-gate return (CS_BAD_WINDOW); 60560Sstevel@tonic-gate cw->state &= CW_WINDOW_VALID; 60570Sstevel@tonic-gate 60580Sstevel@tonic-gate } /* IO_DEALLOCATE_WINDOW */ 60590Sstevel@tonic-gate 60600Sstevel@tonic-gate if (Attributes & IO_DISABLE_WINDOW) { 60610Sstevel@tonic-gate get_window_t get_window; 60620Sstevel@tonic-gate 60630Sstevel@tonic-gate get_window.window = wn; 60640Sstevel@tonic-gate 60650Sstevel@tonic-gate SocketServices(SS_GetWindow, &get_window); 60660Sstevel@tonic-gate 60670Sstevel@tonic-gate set_window.socket = get_window.socket; 60680Sstevel@tonic-gate set_window.window = get_window.window; 60690Sstevel@tonic-gate set_window.speed = get_window.speed; 60700Sstevel@tonic-gate set_window.base = 0; 60710Sstevel@tonic-gate set_window.WindowSize = get_window.size; 60720Sstevel@tonic-gate set_window.state = get_window.state & ~WS_ENABLED; 60730Sstevel@tonic-gate 60740Sstevel@tonic-gate cs_set_acc_attributes(&set_window, Attributes); 60750Sstevel@tonic-gate 60760Sstevel@tonic-gate SocketServices(SS_SetWindow, &set_window); 60770Sstevel@tonic-gate } /* IO_DISABLE_WINDOW */ 60780Sstevel@tonic-gate 60790Sstevel@tonic-gate return (CS_SUCCESS); 60800Sstevel@tonic-gate 60810Sstevel@tonic-gate } /* if (IO_DEALLOCATE_WINDOW | IO_DISABLE_WINDOW) */ 60820Sstevel@tonic-gate 60830Sstevel@tonic-gate /* 60840Sstevel@tonic-gate * See if we can allow Socket Services to select the base address 60850Sstevel@tonic-gate * value for this card; if the client has specified a non-zero 60860Sstevel@tonic-gate * base IO address but the card doesn't decode enough IO 60870Sstevel@tonic-gate * address lines to uniquely use that address, then we have 60880Sstevel@tonic-gate * the flexibility to choose an alternative base address. 60890Sstevel@tonic-gate * XXX - Is this really correct in all cases? 60900Sstevel@tonic-gate */ 60910Sstevel@tonic-gate if (!IOAddrLines) 60920Sstevel@tonic-gate Base->base = 0; 60930Sstevel@tonic-gate else 60940Sstevel@tonic-gate Base->base = IOADDR_FROBNITZ(Base->base, IOAddrLines); 60950Sstevel@tonic-gate 60960Sstevel@tonic-gate set_window.socket = sn; 60970Sstevel@tonic-gate set_window.window = wn; 60980Sstevel@tonic-gate set_window.speed = IO_WIN_SPEED; 60990Sstevel@tonic-gate set_window.base = Base->base; 61000Sstevel@tonic-gate set_window.WindowSize = *NumPorts; 61010Sstevel@tonic-gate set_window.state = (WS_ENABLED | WS_IO | 61020Sstevel@tonic-gate ((Attributes & IO_DATA_PATH_WIDTH_16)?WS_16BIT:0)); 61030Sstevel@tonic-gate 61040Sstevel@tonic-gate cs_set_acc_attributes(&set_window, Attributes); 61050Sstevel@tonic-gate 61060Sstevel@tonic-gate if (SocketServices(SS_SetWindow, &set_window) != SUCCESS) 61070Sstevel@tonic-gate return (CS_BAD_WINDOW); 61080Sstevel@tonic-gate 61090Sstevel@tonic-gate Base->base = set_window.base; 61100Sstevel@tonic-gate Base->handle = set_window.handle; 61110Sstevel@tonic-gate *NumPorts = set_window.WindowSize; 61120Sstevel@tonic-gate 61130Sstevel@tonic-gate return (CS_SUCCESS); 61140Sstevel@tonic-gate } 61150Sstevel@tonic-gate 61160Sstevel@tonic-gate /* 61170Sstevel@tonic-gate * ==== IRQ handling functions ==== 61180Sstevel@tonic-gate */ 61190Sstevel@tonic-gate 61200Sstevel@tonic-gate /* 61210Sstevel@tonic-gate * cs_request_irq - add's client's IRQ handler; supports RequestIRQ 61220Sstevel@tonic-gate * 61230Sstevel@tonic-gate * calling: irq_req_t.Attributes - must have the IRQ_TYPE_EXCLUSIVE 61240Sstevel@tonic-gate * flag set, and all other flags clear, or 61250Sstevel@tonic-gate * CS_BAD_ATTRIBUTE will be returned 61260Sstevel@tonic-gate * 61270Sstevel@tonic-gate * returns: CS_SUCCESS - if IRQ resources available for client 61280Sstevel@tonic-gate * CS_BAD_IRQ - if IRQ can not be allocated 61290Sstevel@tonic-gate * CS_BAD_HANDLE - client handle is invalid 61300Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - if SS is trying to call us 61310Sstevel@tonic-gate * CS_NO_CARD - if no card is in socket 61320Sstevel@tonic-gate * CS_BAD_ATTRIBUTE - if any of the unsupported Attribute 61330Sstevel@tonic-gate * flags are set 61340Sstevel@tonic-gate * CS_CONFIGURATION_LOCKED - a RequestConfiguration has 61350Sstevel@tonic-gate * already been done 61360Sstevel@tonic-gate * CS_IN_USE - IRQ ports already in use or function has 61370Sstevel@tonic-gate * already been called 61380Sstevel@tonic-gate * 61390Sstevel@tonic-gate * Note: We only allow level-mode interrupts. 61400Sstevel@tonic-gate */ 61410Sstevel@tonic-gate static int 61420Sstevel@tonic-gate cs_request_irq(client_handle_t client_handle, irq_req_t *irqr) 61430Sstevel@tonic-gate { 61440Sstevel@tonic-gate cs_socket_t *sp; 61450Sstevel@tonic-gate client_t *client; 61460Sstevel@tonic-gate set_irq_handler_t set_irq_handler; 61470Sstevel@tonic-gate int error; 61480Sstevel@tonic-gate int client_lock_acquired; 61490Sstevel@tonic-gate 61500Sstevel@tonic-gate /* 61510Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it 61520Sstevel@tonic-gate * is, we don't support SS using this call. 61530Sstevel@tonic-gate */ 61540Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) 61550Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION); 61560Sstevel@tonic-gate 61570Sstevel@tonic-gate /* 61580Sstevel@tonic-gate * Make sure that none of the unsupported or reserved flags are set. 61590Sstevel@tonic-gate */ 61600Sstevel@tonic-gate if ((irqr->Attributes & (IRQ_TYPE_TIME | IRQ_TYPE_DYNAMIC_SHARING | 61610Sstevel@tonic-gate IRQ_FIRST_SHARED | IRQ_PULSE_ALLOCATED | 61620Sstevel@tonic-gate IRQ_FORCED_PULSE)) || 61630Sstevel@tonic-gate !(irqr->Attributes & IRQ_TYPE_EXCLUSIVE)) 61640Sstevel@tonic-gate return (CS_BAD_ATTRIBUTE); 61650Sstevel@tonic-gate 61660Sstevel@tonic-gate /* 61670Sstevel@tonic-gate * Get a pointer to this client's socket structure. 61680Sstevel@tonic-gate */ 61690Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) 61700Sstevel@tonic-gate return (CS_BAD_SOCKET); 61710Sstevel@tonic-gate 61720Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 61730Sstevel@tonic-gate 61740Sstevel@tonic-gate /* 61750Sstevel@tonic-gate * Make sure that this is a valid client handle. 61760Sstevel@tonic-gate */ 61770Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) { 61780Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 61790Sstevel@tonic-gate return (error); 61800Sstevel@tonic-gate } 61810Sstevel@tonic-gate 61820Sstevel@tonic-gate /* 61830Sstevel@tonic-gate * If RequestConfiguration has already been done, we don't allow 61840Sstevel@tonic-gate * this call. 61850Sstevel@tonic-gate */ 61860Sstevel@tonic-gate if (client->flags & REQ_CONFIGURATION_DONE) { 61870Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 61880Sstevel@tonic-gate return (CS_CONFIGURATION_LOCKED); 61890Sstevel@tonic-gate } 61900Sstevel@tonic-gate 61910Sstevel@tonic-gate /* 61920Sstevel@tonic-gate * If RequestIRQ has already been done, we don't allow this call. 61930Sstevel@tonic-gate */ 61940Sstevel@tonic-gate if (client->flags & REQ_IRQ_DONE) { 61950Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 61960Sstevel@tonic-gate return (CS_IN_USE); 61970Sstevel@tonic-gate } 61980Sstevel@tonic-gate 61990Sstevel@tonic-gate /* 62000Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not 62010Sstevel@tonic-gate * for this client, then return an error. 62020Sstevel@tonic-gate */ 62030Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) { 62040Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 62050Sstevel@tonic-gate return (CS_NO_CARD); 62060Sstevel@tonic-gate } 62070Sstevel@tonic-gate 62080Sstevel@tonic-gate /* 62090Sstevel@tonic-gate * Set up the parameters and ask Socket Services to give us an IRQ 62100Sstevel@tonic-gate * for this client. We don't really do much, since the IRQ 62110Sstevel@tonic-gate * resources are managed by SS and the kernel. We also don't 62120Sstevel@tonic-gate * care which IRQ level we are given. 62130Sstevel@tonic-gate */ 62140Sstevel@tonic-gate set_irq_handler.socket = 62150Sstevel@tonic-gate CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle), 62160Sstevel@tonic-gate GET_CLIENT_FUNCTION(client_handle)); 62170Sstevel@tonic-gate set_irq_handler.irq = IRQ_ANY; 62180Sstevel@tonic-gate 62190Sstevel@tonic-gate set_irq_handler.handler_id = client_handle; 62200Sstevel@tonic-gate set_irq_handler.handler = (f_t *)irqr->irq_handler; 62210Sstevel@tonic-gate set_irq_handler.arg1 = irqr->irq_handler_arg; 62220Sstevel@tonic-gate set_irq_handler.arg2 = NULL; 62230Sstevel@tonic-gate 62240Sstevel@tonic-gate if ((error = SocketServices(SS_SetIRQHandler, 62250Sstevel@tonic-gate &set_irq_handler)) != SUCCESS) { 62260Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 62270Sstevel@tonic-gate return (CS_BAD_IRQ); 62280Sstevel@tonic-gate } 62290Sstevel@tonic-gate 62300Sstevel@tonic-gate irqr->iblk_cookie = set_irq_handler.iblk_cookie; 62310Sstevel@tonic-gate irqr->idev_cookie = set_irq_handler.idev_cookie; 62320Sstevel@tonic-gate 62330Sstevel@tonic-gate /* 62340Sstevel@tonic-gate * Save the allocated IRQ information for this client. 62350Sstevel@tonic-gate */ 62360Sstevel@tonic-gate client->irq_alloc.Attributes = irqr->Attributes; 62370Sstevel@tonic-gate client->irq_alloc.irq = set_irq_handler.irq; 62380Sstevel@tonic-gate client->irq_alloc.handler_id = set_irq_handler.handler_id; 62390Sstevel@tonic-gate client->irq_alloc.irq_handler = (f_t *)set_irq_handler.handler; 62400Sstevel@tonic-gate client->irq_alloc.irq_handler_arg1 = set_irq_handler.arg1; 62410Sstevel@tonic-gate client->irq_alloc.irq_handler_arg2 = set_irq_handler.arg2; 62420Sstevel@tonic-gate 62430Sstevel@tonic-gate #ifdef CS_DEBUG 62440Sstevel@tonic-gate if (cs_debug > 0) 62450Sstevel@tonic-gate cmn_err(CE_CONT, "cs_request_irq: socket %d irqr->Attributes 0x%x " 62460Sstevel@tonic-gate "set_irq_handler.irq 0x%x\n", 62470Sstevel@tonic-gate sp->socket_num, 62480Sstevel@tonic-gate (int)irqr->Attributes, 62490Sstevel@tonic-gate set_irq_handler.irq); 62500Sstevel@tonic-gate #endif 62510Sstevel@tonic-gate 62520Sstevel@tonic-gate /* 62530Sstevel@tonic-gate * Mark this client as having done a successful RequestIRQ call. 62540Sstevel@tonic-gate */ 62550Sstevel@tonic-gate client->flags |= (REQ_IRQ_DONE | CLIENT_IRQ_ALLOCATED); 62560Sstevel@tonic-gate 62570Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 62580Sstevel@tonic-gate return (CS_SUCCESS); 62590Sstevel@tonic-gate } 62600Sstevel@tonic-gate 62610Sstevel@tonic-gate /* 62620Sstevel@tonic-gate * cs_release_irq - releases IRQ resources allocated by RequestIRQ; this is 62630Sstevel@tonic-gate * ReleaseIRQ 62640Sstevel@tonic-gate * 62650Sstevel@tonic-gate * calling: cs_release_irq(client_handle_t, irq_req_t *) 62660Sstevel@tonic-gate * 62670Sstevel@tonic-gate * returns: CS_SUCCESS - if IRQ resources sucessfully deallocated 62680Sstevel@tonic-gate * CS_BAD_IRQ - if IRQ can not be deallocated 62690Sstevel@tonic-gate * CS_BAD_HANDLE - client handle is invalid 62700Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - if SS is trying to call us 62710Sstevel@tonic-gate * CS_CONFIGURATION_LOCKED - a RequestConfiguration has been 62720Sstevel@tonic-gate * done without a ReleaseConfiguration 62730Sstevel@tonic-gate * CS_IN_USE - no RequestIRQ has been done 62740Sstevel@tonic-gate */ 62750Sstevel@tonic-gate static int 62760Sstevel@tonic-gate cs_release_irq(client_handle_t client_handle, irq_req_t *irqr) 62770Sstevel@tonic-gate { 62780Sstevel@tonic-gate cs_socket_t *sp; 62790Sstevel@tonic-gate client_t *client; 62800Sstevel@tonic-gate clear_irq_handler_t clear_irq_handler; 62810Sstevel@tonic-gate int error; 62820Sstevel@tonic-gate int client_lock_acquired; 62830Sstevel@tonic-gate 62840Sstevel@tonic-gate #ifdef lint 62850Sstevel@tonic-gate irqr = NULL; 62860Sstevel@tonic-gate #endif 62870Sstevel@tonic-gate 62880Sstevel@tonic-gate /* 62890Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it 62900Sstevel@tonic-gate * is, we don't support SS using this call. 62910Sstevel@tonic-gate */ 62920Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) 62930Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION); 62940Sstevel@tonic-gate 62950Sstevel@tonic-gate /* 62960Sstevel@tonic-gate * Get a pointer to this client's socket structure. 62970Sstevel@tonic-gate */ 62980Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) 62990Sstevel@tonic-gate return (CS_BAD_SOCKET); 63000Sstevel@tonic-gate 63010Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 63020Sstevel@tonic-gate 63030Sstevel@tonic-gate /* 63040Sstevel@tonic-gate * Make sure that this is a valid client handle. 63050Sstevel@tonic-gate */ 63060Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) { 63070Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 63080Sstevel@tonic-gate return (error); 63090Sstevel@tonic-gate } 63100Sstevel@tonic-gate 63110Sstevel@tonic-gate /* 63120Sstevel@tonic-gate * If RequestConfiguration has already been done, we don't allow 63130Sstevel@tonic-gate * this call. 63140Sstevel@tonic-gate */ 63150Sstevel@tonic-gate if (client->flags & REQ_CONFIGURATION_DONE) { 63160Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 63170Sstevel@tonic-gate return (CS_CONFIGURATION_LOCKED); 63180Sstevel@tonic-gate } 63190Sstevel@tonic-gate 63200Sstevel@tonic-gate /* 63210Sstevel@tonic-gate * If RequestIRQ has not been done, we don't allow this call. 63220Sstevel@tonic-gate */ 63230Sstevel@tonic-gate if (!(client->flags & REQ_IRQ_DONE)) { 63240Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 63250Sstevel@tonic-gate return (CS_IN_USE); 63260Sstevel@tonic-gate } 63270Sstevel@tonic-gate 63280Sstevel@tonic-gate /* 63290Sstevel@tonic-gate * Tell Socket Services that we want to deregister this client's 63300Sstevel@tonic-gate * IRQ handler. 63310Sstevel@tonic-gate */ 63320Sstevel@tonic-gate clear_irq_handler.socket = 63330Sstevel@tonic-gate CS_MAKE_SOCKET_NUMBER(GET_CLIENT_SOCKET(client_handle), 63340Sstevel@tonic-gate GET_CLIENT_FUNCTION(client_handle)); 63350Sstevel@tonic-gate clear_irq_handler.handler_id = client->irq_alloc.handler_id; 63360Sstevel@tonic-gate clear_irq_handler.handler = (f_t *)client->irq_alloc.irq_handler; 63370Sstevel@tonic-gate 63380Sstevel@tonic-gate /* 63390Sstevel@tonic-gate * At this point, we should never fail this SS call; if we do, it 63400Sstevel@tonic-gate * means that there is an internal consistancy error in either 63410Sstevel@tonic-gate * Card Services or Socket Services. 63420Sstevel@tonic-gate */ 63430Sstevel@tonic-gate if ((error = SocketServices(SS_ClearIRQHandler, &clear_irq_handler)) != 63440Sstevel@tonic-gate SUCCESS) { 63450Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 63460Sstevel@tonic-gate return (CS_BAD_IRQ); 63470Sstevel@tonic-gate } 63480Sstevel@tonic-gate 63490Sstevel@tonic-gate /* 63500Sstevel@tonic-gate * Mark the client as not having any IRQ resources allocated. 63510Sstevel@tonic-gate */ 63520Sstevel@tonic-gate client->flags &= ~(REQ_IRQ_DONE | CLIENT_IRQ_ALLOCATED); 63530Sstevel@tonic-gate 63540Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 63550Sstevel@tonic-gate return (CS_SUCCESS); 63560Sstevel@tonic-gate } 63570Sstevel@tonic-gate 63580Sstevel@tonic-gate /* 63590Sstevel@tonic-gate * ==== configuration handling functions ==== 63600Sstevel@tonic-gate */ 63610Sstevel@tonic-gate 63620Sstevel@tonic-gate /* 63630Sstevel@tonic-gate * cs_request_configuration - sets up socket and card configuration on behalf 63640Sstevel@tonic-gate * of the client; this is RequestConfiguration 63650Sstevel@tonic-gate * 63660Sstevel@tonic-gate * returns: CS_SUCCESS - if configuration sucessfully set 63670Sstevel@tonic-gate * CS_BAD_SOCKET - if Socket Services returns an error 63680Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - if SS is trying to call us 63690Sstevel@tonic-gate * CS_BAD_ATTRIBUTE - if any unsupported or reserved flags 63700Sstevel@tonic-gate * are set 63710Sstevel@tonic-gate * CS_BAD_TYPE - if the socket doesn't support a mem and IO 63720Sstevel@tonic-gate * interface (SOCKET_INTERFACE_MEMORY_AND_IO set) 63730Sstevel@tonic-gate * CS_CONFIGURATION_LOCKED - a RequestConfiguration has 63740Sstevel@tonic-gate * already been done 63750Sstevel@tonic-gate * CS_BAD_VCC - if Vcc value is not supported by socket 63760Sstevel@tonic-gate * CS_BAD_VPP1 - if Vpp1 value is not supported by socket 63770Sstevel@tonic-gate * CS_BAD_VPP2 - if Vpp2 value is not supported by socket 63780Sstevel@tonic-gate * 63790Sstevel@tonic-gate * Bug ID: 1193637 - Card Services RequestConfiguration does not conform 63800Sstevel@tonic-gate * to PCMCIA standard 63810Sstevel@tonic-gate * We allow clients to do a RequestConfiguration even if they haven't 63820Sstevel@tonic-gate * done a RequestIO or RequestIRQ. 63830Sstevel@tonic-gate */ 63840Sstevel@tonic-gate static int 63850Sstevel@tonic-gate cs_request_configuration(client_handle_t client_handle, config_req_t *cr) 63860Sstevel@tonic-gate { 63870Sstevel@tonic-gate cs_socket_t *sp; 63880Sstevel@tonic-gate client_t *client; 63890Sstevel@tonic-gate volatile config_regs_t *crt; 63900Sstevel@tonic-gate set_socket_t set_socket; 63910Sstevel@tonic-gate get_socket_t get_socket; 63920Sstevel@tonic-gate acc_handle_t cis_handle; 63930Sstevel@tonic-gate int error; 63940Sstevel@tonic-gate uint32_t newoffset; 63950Sstevel@tonic-gate int client_lock_acquired; 63960Sstevel@tonic-gate 63970Sstevel@tonic-gate /* 63980Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it 63990Sstevel@tonic-gate * is, we don't support SS using this call. 64000Sstevel@tonic-gate */ 64010Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) 64020Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION); 64030Sstevel@tonic-gate 64040Sstevel@tonic-gate #ifdef XXX 64050Sstevel@tonic-gate /* 64060Sstevel@tonic-gate * If the client specifies Vcc = 0 and any non-zero value for 64070Sstevel@tonic-gate * either of the Vpp members, that's an illegal condition. 64080Sstevel@tonic-gate */ 64090Sstevel@tonic-gate if (!(cr->Vcc) && (cr->Vpp1 || cr->Vpp2)) 64100Sstevel@tonic-gate return (CS_BAD_VCC); 64110Sstevel@tonic-gate #endif 64120Sstevel@tonic-gate 64130Sstevel@tonic-gate /* 64140Sstevel@tonic-gate * Get a pointer to this client's socket structure. 64150Sstevel@tonic-gate */ 64160Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) 64170Sstevel@tonic-gate return (CS_BAD_SOCKET); 64180Sstevel@tonic-gate 64190Sstevel@tonic-gate /* 64200Sstevel@tonic-gate * If the client is asking for a memory and IO interface on this 64210Sstevel@tonic-gate * socket, then check the socket capabilities to be sure that 64220Sstevel@tonic-gate * this socket supports this configuration. 64230Sstevel@tonic-gate */ 64240Sstevel@tonic-gate if (cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO) { 64250Sstevel@tonic-gate inquire_socket_t inquire_socket; 64260Sstevel@tonic-gate 64270Sstevel@tonic-gate inquire_socket.socket = sp->socket_num; 64280Sstevel@tonic-gate 64290Sstevel@tonic-gate if (SocketServices(SS_InquireSocket, &inquire_socket) != SUCCESS) 64300Sstevel@tonic-gate return (CS_BAD_SOCKET); 64310Sstevel@tonic-gate 64320Sstevel@tonic-gate if (!(inquire_socket.SocketCaps & IF_IO)) 64330Sstevel@tonic-gate return (CS_BAD_TYPE); 64340Sstevel@tonic-gate 64350Sstevel@tonic-gate } /* if (SOCKET_INTERFACE_MEMORY_AND_IO) */ 64360Sstevel@tonic-gate 64370Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 64380Sstevel@tonic-gate 64390Sstevel@tonic-gate /* 64400Sstevel@tonic-gate * Make sure that this is a valid client handle. 64410Sstevel@tonic-gate */ 64420Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) { 64430Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 64440Sstevel@tonic-gate return (error); 64450Sstevel@tonic-gate } 64460Sstevel@tonic-gate 64470Sstevel@tonic-gate /* 64480Sstevel@tonic-gate * If RequestConfiguration has already been done, we don't allow 64490Sstevel@tonic-gate * this call. 64500Sstevel@tonic-gate */ 64510Sstevel@tonic-gate if (client->flags & REQ_CONFIGURATION_DONE) { 64520Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 64530Sstevel@tonic-gate return (CS_CONFIGURATION_LOCKED); 64540Sstevel@tonic-gate } 64550Sstevel@tonic-gate 64560Sstevel@tonic-gate /* 64570Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not 64580Sstevel@tonic-gate * for this client, then return an error. 64590Sstevel@tonic-gate */ 64600Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) { 64610Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 64620Sstevel@tonic-gate return (CS_NO_CARD); 64630Sstevel@tonic-gate } 64640Sstevel@tonic-gate 64650Sstevel@tonic-gate /* 64660Sstevel@tonic-gate * At this point, most of the client's calling parameters have been 64670Sstevel@tonic-gate * validated, so we can go ahead and configure the socket and 64680Sstevel@tonic-gate * the card. 64690Sstevel@tonic-gate */ 64700Sstevel@tonic-gate mutex_enter(&sp->cis_lock); 64710Sstevel@tonic-gate 64720Sstevel@tonic-gate /* 64730Sstevel@tonic-gate * Configure the socket with the interface type and voltages requested 64740Sstevel@tonic-gate * by the client. 64750Sstevel@tonic-gate */ 64760Sstevel@tonic-gate get_socket.socket = sp->socket_num; 64770Sstevel@tonic-gate 64780Sstevel@tonic-gate if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) { 64790Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 64800Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 64810Sstevel@tonic-gate return (CS_BAD_SOCKET); 64820Sstevel@tonic-gate } 64830Sstevel@tonic-gate 64840Sstevel@tonic-gate #ifdef CS_DEBUG 64850Sstevel@tonic-gate if (cs_debug > 0) 64860Sstevel@tonic-gate cmn_err(CE_CONT, "cs_request_configuration: socket %d " 64870Sstevel@tonic-gate "client->irq_alloc.irq 0x%x " 64880Sstevel@tonic-gate "get_socket.IRQRouting 0x%x\n", 64890Sstevel@tonic-gate sp->socket_num, 64900Sstevel@tonic-gate (int)client->irq_alloc.irq, 64910Sstevel@tonic-gate get_socket.IRQRouting); 64920Sstevel@tonic-gate #endif 64930Sstevel@tonic-gate 64940Sstevel@tonic-gate bzero(&set_socket, sizeof (set_socket)); 64950Sstevel@tonic-gate set_socket.socket = sp->socket_num; 64960Sstevel@tonic-gate set_socket.IREQRouting = client->irq_alloc.irq & ~IRQ_ENABLE; 64970Sstevel@tonic-gate 64980Sstevel@tonic-gate set_socket.CtlInd = get_socket.CtlInd; 64990Sstevel@tonic-gate set_socket.State = 0; /* don't reset latched values */ 65000Sstevel@tonic-gate 65010Sstevel@tonic-gate if (cs_convert_powerlevel(sp->socket_num, cr->Vcc, VCC, 65020Sstevel@tonic-gate &set_socket.VccLevel) != CS_SUCCESS) { 65030Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 65040Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 65050Sstevel@tonic-gate return (CS_BAD_VCC); 65060Sstevel@tonic-gate } 65070Sstevel@tonic-gate 65080Sstevel@tonic-gate if (cs_convert_powerlevel(sp->socket_num, cr->Vpp1, VPP1, 65090Sstevel@tonic-gate &set_socket.Vpp1Level) != CS_SUCCESS) { 65100Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 65110Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 65120Sstevel@tonic-gate return (CS_BAD_VPP); 65130Sstevel@tonic-gate } 65140Sstevel@tonic-gate 65150Sstevel@tonic-gate if (cs_convert_powerlevel(sp->socket_num, cr->Vpp2, VPP2, 65160Sstevel@tonic-gate &set_socket.Vpp2Level) != CS_SUCCESS) { 65170Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 65180Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 65190Sstevel@tonic-gate return (CS_BAD_VPP); 65200Sstevel@tonic-gate } 65210Sstevel@tonic-gate 65220Sstevel@tonic-gate if (!(cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO)) 65230Sstevel@tonic-gate set_socket.IFType = IF_MEMORY; 65240Sstevel@tonic-gate else { 65250Sstevel@tonic-gate set_socket.IFType = IF_IO; 65260Sstevel@tonic-gate 65270Sstevel@tonic-gate /* 65280Sstevel@tonic-gate * The Cirrus Logic PD6710/672X/others? adapters will write 65290Sstevel@tonic-gate * protect the CIS if the socket is in MEMORY mode and the 65300Sstevel@tonic-gate * WP/IOCS16 pin is true. When this happens, the CIS registers 65310Sstevel@tonic-gate * will fail to be written. Go ahead and set the socket, 65320Sstevel@tonic-gate * even though the event mask isn't complete yet, so we can 65330Sstevel@tonic-gate * configure the adapter. Afterwards, set the socket again 65340Sstevel@tonic-gate * to make sure the event mask is correct. 65350Sstevel@tonic-gate */ 65360Sstevel@tonic-gate if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) { 65370Sstevel@tonic-gate sp->flags &= ~SOCKET_IS_IO; 65380Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 65390Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 65400Sstevel@tonic-gate return (CS_BAD_SOCKET); 65410Sstevel@tonic-gate } 65420Sstevel@tonic-gate } 65430Sstevel@tonic-gate 65440Sstevel@tonic-gate if (cs_rc2_delay) 65450Sstevel@tonic-gate drv_usecwait(cs_rc2_delay * 1000); 65460Sstevel@tonic-gate 65470Sstevel@tonic-gate /* 65480Sstevel@tonic-gate * Get a pointer to a window that contains the configuration 65490Sstevel@tonic-gate * registers. 65500Sstevel@tonic-gate */ 65510Sstevel@tonic-gate mutex_enter(&sp->lock); 65520Sstevel@tonic-gate client->config_regs_offset = cr->ConfigBase; 65530Sstevel@tonic-gate newoffset = client->config_regs_offset; 65540Sstevel@tonic-gate mutex_exit(&sp->lock); 65550Sstevel@tonic-gate if (cs_init_cis_window(sp, &newoffset, &cis_handle, 65560Sstevel@tonic-gate CISTPLF_AM_SPACE) != CS_SUCCESS) { 65570Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 65580Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 65590Sstevel@tonic-gate cmn_err(CE_CONT, "cs_request_configuration: socket %d can't init " 65600Sstevel@tonic-gate "CIS window\n", sp->socket_num); 65610Sstevel@tonic-gate return (CS_GENERAL_FAILURE); 65620Sstevel@tonic-gate } 65630Sstevel@tonic-gate 65640Sstevel@tonic-gate /* 65650Sstevel@tonic-gate * Setup the config register pointers. 65660Sstevel@tonic-gate * Note that these pointers are not the complete virtual address; 65670Sstevel@tonic-gate * the complete address is constructed each time the registers 65680Sstevel@tonic-gate * are accessed. 65690Sstevel@tonic-gate */ 65700Sstevel@tonic-gate mutex_enter(&sp->lock); 65710Sstevel@tonic-gate crt = &client->config_regs; 65720Sstevel@tonic-gate client->present = cr->Present; 65730Sstevel@tonic-gate 65740Sstevel@tonic-gate bzero((char *)crt, sizeof (config_regs_t)); 65750Sstevel@tonic-gate 65760Sstevel@tonic-gate /* Configuration Option Register */ 65770Sstevel@tonic-gate if (client->present & CONFIG_OPTION_REG_PRESENT) 65780Sstevel@tonic-gate crt->cor_p = (newoffset + CONFIG_OPTION_REG_OFFSET); 65790Sstevel@tonic-gate 65800Sstevel@tonic-gate /* Configuration and Status Register */ 65810Sstevel@tonic-gate if (client->present & CONFIG_STATUS_REG_PRESENT) 65820Sstevel@tonic-gate crt->ccsr_p = (newoffset + CONFIG_STATUS_REG_OFFSET); 65830Sstevel@tonic-gate 65840Sstevel@tonic-gate /* Pin Replacement Register */ 65850Sstevel@tonic-gate if (client->present & CONFIG_PINREPL_REG_PRESENT) 65860Sstevel@tonic-gate crt->prr_p = (newoffset + CONFIG_PINREPL_REG_OFFSET); 65870Sstevel@tonic-gate 65880Sstevel@tonic-gate /* Socket and Copy Register */ 65890Sstevel@tonic-gate if (client->present & CONFIG_COPY_REG_PRESENT) 65900Sstevel@tonic-gate crt->scr_p = (newoffset + CONFIG_COPY_REG_OFFSET); 65910Sstevel@tonic-gate 65920Sstevel@tonic-gate /* Extended Status Register */ 65930Sstevel@tonic-gate if (client->present & CONFIG_EXSTAT_REG_PRESENT) 65940Sstevel@tonic-gate crt->exstat_p = (newoffset + CONFIG_EXSTAT_REG_OFFSET); 65950Sstevel@tonic-gate 65960Sstevel@tonic-gate /* IO Base 0 Register */ 65970Sstevel@tonic-gate if (client->present & CONFIG_IOBASE0_REG_PRESENT) 65980Sstevel@tonic-gate crt->iobase0_p = (newoffset + CONFIG_IOBASE0_REG_OFFSET); 65990Sstevel@tonic-gate 66000Sstevel@tonic-gate /* IO Base 1 Register */ 66010Sstevel@tonic-gate if (client->present & CONFIG_IOBASE1_REG_PRESENT) 66020Sstevel@tonic-gate crt->iobase1_p = (newoffset + CONFIG_IOBASE1_REG_OFFSET); 66030Sstevel@tonic-gate 66040Sstevel@tonic-gate /* IO Base 2 Register */ 66050Sstevel@tonic-gate if (client->present & CONFIG_IOBASE2_REG_PRESENT) 66060Sstevel@tonic-gate crt->iobase2_p = (newoffset + CONFIG_IOBASE2_REG_OFFSET); 66070Sstevel@tonic-gate 66080Sstevel@tonic-gate /* IO Base 3 Register */ 66090Sstevel@tonic-gate if (client->present & CONFIG_IOBASE3_REG_PRESENT) 66100Sstevel@tonic-gate crt->iobase3_p = (newoffset + CONFIG_IOBASE3_REG_OFFSET); 66110Sstevel@tonic-gate 66120Sstevel@tonic-gate /* IO Limit Register */ 66130Sstevel@tonic-gate if (client->present & CONFIG_IOLIMIT_REG_PRESENT) 66140Sstevel@tonic-gate crt->iolimit_p = (newoffset + CONFIG_IOLIMIT_REG_OFFSET); 66150Sstevel@tonic-gate 66160Sstevel@tonic-gate /* 66170Sstevel@tonic-gate * Setup the bits in the PRR mask that are valid; this is easy, just 66180Sstevel@tonic-gate * copy the Pin value that the client gave us. Note that for 66190Sstevel@tonic-gate * this to work, the client must set both of the XXX_STATUS 66200Sstevel@tonic-gate * and the XXX_EVENT bits in the Pin member. 66210Sstevel@tonic-gate */ 66220Sstevel@tonic-gate client->pin = cr->Pin; 66230Sstevel@tonic-gate 66240Sstevel@tonic-gate #ifdef CS_DEBUG 66250Sstevel@tonic-gate if (cs_debug > 128) 66260Sstevel@tonic-gate cmn_err(CE_CONT, "cs_request_configuration: client->pin 0x%x " 66270Sstevel@tonic-gate "client->config_regs_offset 0x%x newoffset 0x%x cor_p 0x%x " 66280Sstevel@tonic-gate "ccsr_p 0x%x prr_p 0x%x scr_p 0x%x\n", 66290Sstevel@tonic-gate client->pin, (int)client->config_regs_offset, newoffset, 66300Sstevel@tonic-gate (int)crt->cor_p, (int)crt->ccsr_p, (int)crt->prr_p, 66310Sstevel@tonic-gate (int)crt->scr_p); 66320Sstevel@tonic-gate #endif 66330Sstevel@tonic-gate 66340Sstevel@tonic-gate /* 66350Sstevel@tonic-gate * If the socket isn't in IO mode, WP is asserted, and we're going to 66360Sstevel@tonic-gate * write any of the config registers, issue a warning. 66370Sstevel@tonic-gate */ 66380Sstevel@tonic-gate if ((client->present != 0) && 66390Sstevel@tonic-gate (!(cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO)) && 66400Sstevel@tonic-gate (get_socket.state & SBM_WP)) { 66410Sstevel@tonic-gate cmn_err(CE_NOTE, "!cs_request_configuration: attempting to " 66420Sstevel@tonic-gate "write CIS config regs with WP set\n"); 66430Sstevel@tonic-gate } 66440Sstevel@tonic-gate 66450Sstevel@tonic-gate /* 66460Sstevel@tonic-gate * Write any configuration registers that the client tells us are 66470Sstevel@tonic-gate * present to the card; save a copy of what we wrote so that we 66480Sstevel@tonic-gate * can return them if the client calls GetConfigurationInfo. 66490Sstevel@tonic-gate * The order in which we write the configuration registers is 66500Sstevel@tonic-gate * specified by the PCMCIA spec; we must write the socket/copy 66510Sstevel@tonic-gate * register first (if it exists), and then we can write the 66520Sstevel@tonic-gate * registers in any arbitrary order. 66530Sstevel@tonic-gate */ 66540Sstevel@tonic-gate /* Socket and Copy Register */ 66550Sstevel@tonic-gate if (client->present & CONFIG_COPY_REG_PRESENT) { 66560Sstevel@tonic-gate crt->scr = cr->Copy; 66570Sstevel@tonic-gate csx_Put8(cis_handle, crt->scr_p, crt->scr); 66580Sstevel@tonic-gate } 66590Sstevel@tonic-gate 66600Sstevel@tonic-gate /* Pin Replacement Register */ 66610Sstevel@tonic-gate if (client->present & CONFIG_PINREPL_REG_PRESENT) { 66620Sstevel@tonic-gate crt->prr = cr->Pin; 66630Sstevel@tonic-gate csx_Put8(cis_handle, crt->prr_p, crt->prr); 66640Sstevel@tonic-gate } 66650Sstevel@tonic-gate 66660Sstevel@tonic-gate /* Configuration and Status Register */ 66670Sstevel@tonic-gate /* XXX should we set CCSR_SIG_CHG in the CCSR? XXX */ 66680Sstevel@tonic-gate if (client->present & CONFIG_STATUS_REG_PRESENT) { 66690Sstevel@tonic-gate crt->ccsr = cr->Status; 66700Sstevel@tonic-gate csx_Put8(cis_handle, crt->ccsr_p, crt->ccsr); 66710Sstevel@tonic-gate } 66720Sstevel@tonic-gate 66730Sstevel@tonic-gate /* Extended Status Register */ 66740Sstevel@tonic-gate if (client->present & CONFIG_EXSTAT_REG_PRESENT) { 66750Sstevel@tonic-gate crt->exstat = cr->ExtendedStatus; 66760Sstevel@tonic-gate csx_Put8(cis_handle, crt->exstat_p, crt->exstat); 66770Sstevel@tonic-gate } 66780Sstevel@tonic-gate 66790Sstevel@tonic-gate /* 66800Sstevel@tonic-gate * If any IO base and limit registers exist, and this client 66810Sstevel@tonic-gate * has done a RequestIO, setup the IO Base and IO Limit 66820Sstevel@tonic-gate * registers. 66830Sstevel@tonic-gate */ 66840Sstevel@tonic-gate if (client->flags & REQ_IO_DONE) { 66850Sstevel@tonic-gate if (client->present & CONFIG_IOBASE0_REG_PRESENT) { 66860Sstevel@tonic-gate uint32_t base = client->io_alloc.BasePort1.base; 66870Sstevel@tonic-gate uint32_t present = (client->present & 66880Sstevel@tonic-gate CONFIG_IOBASE_REG_MASK) >> 66890Sstevel@tonic-gate CONFIG_IOBASE_REG_SHIFT; 66900Sstevel@tonic-gate uint32_t reg = crt->iobase0_p; 66910Sstevel@tonic-gate 66920Sstevel@tonic-gate do { 66930Sstevel@tonic-gate csx_Put8(cis_handle, reg, base & 0x0ff); 66940Sstevel@tonic-gate reg = reg + 2; 66950Sstevel@tonic-gate base = base >> 8; 66960Sstevel@tonic-gate present = present >> 1; 66970Sstevel@tonic-gate } while (present); 66980Sstevel@tonic-gate } /* CONFIG_IOBASE0_REG_PRESENT */ 66990Sstevel@tonic-gate 67000Sstevel@tonic-gate if (client->present & CONFIG_IOLIMIT_REG_PRESENT) { 67010Sstevel@tonic-gate uint32_t np = client->io_alloc.NumPorts1 + 67020Sstevel@tonic-gate client->io_alloc.NumPorts2; 67030Sstevel@tonic-gate uint32_t limit, do_bit = 0; 67040Sstevel@tonic-gate int lm; 67050Sstevel@tonic-gate 67060Sstevel@tonic-gate limit = (IONUMPORTS_FROBNITZ(np) - 1); 67070Sstevel@tonic-gate 67080Sstevel@tonic-gate for (lm = 7; lm >= 0; lm--) { 67090Sstevel@tonic-gate if (limit & (1 << lm)) 67100Sstevel@tonic-gate do_bit = 1; 67110Sstevel@tonic-gate if (do_bit) 67120Sstevel@tonic-gate limit |= (1 << lm); 67130Sstevel@tonic-gate } /* for */ 67140Sstevel@tonic-gate 67150Sstevel@tonic-gate csx_Put8(cis_handle, crt->iolimit_p, limit); 67160Sstevel@tonic-gate } /* CONFIG_IOLIMIT_REG_PRESENT */ 67170Sstevel@tonic-gate } /* REQ_IO_DONE */ 67180Sstevel@tonic-gate 67190Sstevel@tonic-gate /* 67200Sstevel@tonic-gate * Mark the socket as being in IO mode. 67210Sstevel@tonic-gate */ 67220Sstevel@tonic-gate if (cr->IntType & SOCKET_INTERFACE_MEMORY_AND_IO) 67230Sstevel@tonic-gate sp->flags |= SOCKET_IS_IO; 67240Sstevel@tonic-gate 67250Sstevel@tonic-gate mutex_exit(&sp->lock); 67260Sstevel@tonic-gate 67270Sstevel@tonic-gate /* 67280Sstevel@tonic-gate * Enable the interrupt if needed 67290Sstevel@tonic-gate */ 67300Sstevel@tonic-gate if (cr->Attributes & CONF_ENABLE_IRQ_STEERING) 67310Sstevel@tonic-gate set_socket.IREQRouting |= IRQ_ENABLE; 67320Sstevel@tonic-gate 67330Sstevel@tonic-gate /* 67340Sstevel@tonic-gate * Now that we know if the PRR is present and if it is, which 67350Sstevel@tonic-gate * bits in the PRR are valid, we can construct the correct 67360Sstevel@tonic-gate * socket event mask. 67370Sstevel@tonic-gate */ 67380Sstevel@tonic-gate set_socket.SCIntMask = cs_merge_event_masks(sp, client); 67390Sstevel@tonic-gate 67400Sstevel@tonic-gate /* 67410Sstevel@tonic-gate * Configuration Option Register - we handle this specially since 67420Sstevel@tonic-gate * we don't allow the client to manipulate the RESET or 67430Sstevel@tonic-gate * INTERRUPT bits (although a client can manipulate these 67440Sstevel@tonic-gate * bits via an AccessConfigurationRegister call - explain 67450Sstevel@tonic-gate * THAT logic to me). 67460Sstevel@tonic-gate * XXX - we force level-mode interrupts (COR_LEVEL_IRQ) 67470Sstevel@tonic-gate * XXX - we always enable the function on a multi-function card 67480Sstevel@tonic-gate */ 67490Sstevel@tonic-gate if (client->present & CONFIG_OPTION_REG_PRESENT) { 67500Sstevel@tonic-gate crt->cor = (cr->ConfigIndex & ~COR_SOFT_RESET) | COR_LEVEL_IRQ; 67510Sstevel@tonic-gate if (client->present & CONFIG_IOBASE0_REG_PRESENT) 67520Sstevel@tonic-gate crt->cor |= COR_ENABLE_BASE_LIMIT; 67530Sstevel@tonic-gate if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) { 67540Sstevel@tonic-gate crt->cor |= COR_ENABLE_FUNCTION; 67550Sstevel@tonic-gate crt->cor &= ~COR_ENABLE_IREQ_ROUTING; 67560Sstevel@tonic-gate if (cr->Attributes & CONF_ENABLE_IRQ_STEERING) 67570Sstevel@tonic-gate crt->cor |= COR_ENABLE_IREQ_ROUTING; 67580Sstevel@tonic-gate } /* CW_MULTI_FUNCTION_CIS */ 67590Sstevel@tonic-gate 67600Sstevel@tonic-gate #ifdef CS_DEBUG 67610Sstevel@tonic-gate if (cs_debug > 0) 67620Sstevel@tonic-gate cmn_err(CE_CONT, "cs_request_configuration " 67630Sstevel@tonic-gate "cor=x%x ConfigIndex=x%x Attributes=x%x flags=x%x\n" 67640Sstevel@tonic-gate "present=x%x cis_handle=%p cor_p=x%x\n", 67650Sstevel@tonic-gate crt->cor, cr->ConfigIndex, cr->Attributes, sp->cis_flags, 67660Sstevel@tonic-gate client->present, cis_handle, crt->cor_p); 67670Sstevel@tonic-gate #endif 67680Sstevel@tonic-gate 67690Sstevel@tonic-gate csx_Put8(cis_handle, crt->cor_p, crt->cor); 67700Sstevel@tonic-gate } /* CONFIG_OPTION_REG_PRESENT */ 67710Sstevel@tonic-gate 67720Sstevel@tonic-gate if (cs_rc1_delay) 67730Sstevel@tonic-gate drv_usecwait(cs_rc1_delay * 1000); 67740Sstevel@tonic-gate 67750Sstevel@tonic-gate /* 67760Sstevel@tonic-gate * Set the socket to the parameters that the client requested. 67770Sstevel@tonic-gate */ 67780Sstevel@tonic-gate if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) { 67790Sstevel@tonic-gate if (client->present & CONFIG_OPTION_REG_PRESENT) { 67800Sstevel@tonic-gate crt->cor = 0; /* XXX is 0 the right thing here? */ 67810Sstevel@tonic-gate csx_Put8(cis_handle, crt->cor_p, crt->cor); 67820Sstevel@tonic-gate } 67830Sstevel@tonic-gate sp->flags &= ~SOCKET_IS_IO; 67840Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 67850Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 67860Sstevel@tonic-gate return (CS_BAD_SOCKET); 67870Sstevel@tonic-gate } 67880Sstevel@tonic-gate 67890Sstevel@tonic-gate if (cs_rc2_delay) 67900Sstevel@tonic-gate drv_usecwait(cs_rc2_delay * 1000); 67910Sstevel@tonic-gate 67920Sstevel@tonic-gate /* 67930Sstevel@tonic-gate * Mark this client as having done a successful RequestConfiguration 67940Sstevel@tonic-gate * call. 67950Sstevel@tonic-gate */ 67960Sstevel@tonic-gate client->flags |= REQ_CONFIGURATION_DONE; 67970Sstevel@tonic-gate 67980Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 67990Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 68000Sstevel@tonic-gate 68010Sstevel@tonic-gate return (CS_SUCCESS); 68020Sstevel@tonic-gate } 68030Sstevel@tonic-gate 68040Sstevel@tonic-gate /* 68050Sstevel@tonic-gate * cs_release_configuration - releases configuration previously set via the 68060Sstevel@tonic-gate * RequestConfiguration call; this is ReleaseConfiguration 68070Sstevel@tonic-gate * 68080Sstevel@tonic-gate * returns: CS_SUCCESS - if configuration sucessfully released 68090Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - if SS is trying to call us 68100Sstevel@tonic-gate * CS_BAD_SOCKET - if Socket Services returns an error 68110Sstevel@tonic-gate * CS_BAD_HANDLE - a RequestConfiguration has not been done 68120Sstevel@tonic-gate */ 68130Sstevel@tonic-gate /*ARGSUSED*/ 68140Sstevel@tonic-gate static int 68150Sstevel@tonic-gate cs_release_configuration(client_handle_t client_handle, release_config_t *rcfg) 68160Sstevel@tonic-gate { 68170Sstevel@tonic-gate cs_socket_t *sp; 68180Sstevel@tonic-gate client_t *client; 68190Sstevel@tonic-gate volatile config_regs_t *crt; 68200Sstevel@tonic-gate set_socket_t set_socket; 68210Sstevel@tonic-gate get_socket_t get_socket; 68220Sstevel@tonic-gate acc_handle_t cis_handle; 68230Sstevel@tonic-gate int error; 68240Sstevel@tonic-gate uint32_t newoffset; 68250Sstevel@tonic-gate int client_lock_acquired; 68260Sstevel@tonic-gate 68270Sstevel@tonic-gate /* 68280Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it 68290Sstevel@tonic-gate * is, we don't support SS using this call. 68300Sstevel@tonic-gate */ 68310Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) 68320Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION); 68330Sstevel@tonic-gate 68340Sstevel@tonic-gate /* 68350Sstevel@tonic-gate * Get a pointer to this client's socket structure. 68360Sstevel@tonic-gate */ 68370Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) 68380Sstevel@tonic-gate return (CS_BAD_SOCKET); 68390Sstevel@tonic-gate 68400Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 68410Sstevel@tonic-gate 68420Sstevel@tonic-gate /* 68430Sstevel@tonic-gate * Make sure that this is a valid client handle. 68440Sstevel@tonic-gate */ 68450Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) { 68460Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 68470Sstevel@tonic-gate return (error); 68480Sstevel@tonic-gate } 68490Sstevel@tonic-gate 68500Sstevel@tonic-gate /* 68510Sstevel@tonic-gate * If RequestConfiguration has not been done, we don't allow 68520Sstevel@tonic-gate * this call. 68530Sstevel@tonic-gate */ 68540Sstevel@tonic-gate if (!(client->flags & REQ_CONFIGURATION_DONE)) { 68550Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 68560Sstevel@tonic-gate return (CS_BAD_HANDLE); 68570Sstevel@tonic-gate } 68580Sstevel@tonic-gate 68590Sstevel@tonic-gate #ifdef CS_DEBUG 68600Sstevel@tonic-gate if (cs_debug > 0) 68610Sstevel@tonic-gate cmn_err(CE_CONT, "cs_release_configuration: " 68620Sstevel@tonic-gate "flags=0x%x CW_MULTI_FUNCTION_CIS =0x%x \n", 68630Sstevel@tonic-gate sp->cis_flags, CW_MULTI_FUNCTION_CIS); 68640Sstevel@tonic-gate 68650Sstevel@tonic-gate #endif 68660Sstevel@tonic-gate mutex_enter(&sp->cis_lock); 68670Sstevel@tonic-gate 68680Sstevel@tonic-gate /* 68690Sstevel@tonic-gate * Set the card back to a memory-only interface byte writing a zero 68700Sstevel@tonic-gate * to the COR. Note that we don't update our soft copy of the 68710Sstevel@tonic-gate * COR state since the PCMCIA spec only requires us to maintain 68720Sstevel@tonic-gate * the last value that was written to that register during a 68730Sstevel@tonic-gate * call to RequestConfiguration. 68740Sstevel@tonic-gate */ 68750Sstevel@tonic-gate crt = &client->config_regs; 68760Sstevel@tonic-gate 68770Sstevel@tonic-gate newoffset = client->config_regs_offset; 68780Sstevel@tonic-gate if (cs_init_cis_window(sp, &newoffset, &cis_handle, 68790Sstevel@tonic-gate CISTPLF_AM_SPACE) != CS_SUCCESS) { 68800Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 68810Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 68820Sstevel@tonic-gate cmn_err(CE_CONT, "cs_release_configuration: socket %d can't init " 68830Sstevel@tonic-gate "CIS window\n", sp->socket_num); 68840Sstevel@tonic-gate return (CS_GENERAL_FAILURE); 68850Sstevel@tonic-gate } 68860Sstevel@tonic-gate 68870Sstevel@tonic-gate if (sp->cis_flags & CW_MULTI_FUNCTION_CIS) { 68880Sstevel@tonic-gate /* 68890Sstevel@tonic-gate * For the Multifunction cards do not reset the socket 68900Sstevel@tonic-gate * to a memory only interface but do clear the 68910Sstevel@tonic-gate * Configuration Option Register and mark this client 68920Sstevel@tonic-gate * as not having a configuration by clearing the 68930Sstevel@tonic-gate * REQ_CONFIGURATION_DONE flag. 68940Sstevel@tonic-gate */ 68950Sstevel@tonic-gate client->flags &= ~REQ_CONFIGURATION_DONE; 68960Sstevel@tonic-gate csx_Put8(cis_handle, crt->cor_p, 0); 68970Sstevel@tonic-gate 68980Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 68990Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 69000Sstevel@tonic-gate return (CS_SUCCESS); 69010Sstevel@tonic-gate } 69020Sstevel@tonic-gate 69030Sstevel@tonic-gate /* 69040Sstevel@tonic-gate * Set the socket back to a memory-only interface; don't change 69050Sstevel@tonic-gate * any other parameter of the socket. 69060Sstevel@tonic-gate */ 69070Sstevel@tonic-gate get_socket.socket = sp->socket_num; 69080Sstevel@tonic-gate 69090Sstevel@tonic-gate if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) { 69100Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 69110Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 69120Sstevel@tonic-gate return (CS_BAD_SOCKET); 69130Sstevel@tonic-gate } 69140Sstevel@tonic-gate 69150Sstevel@tonic-gate mutex_enter(&sp->lock); 69160Sstevel@tonic-gate sp->flags &= ~SOCKET_IS_IO; 69170Sstevel@tonic-gate set_socket.SCIntMask = cs_merge_event_masks(sp, client); 69180Sstevel@tonic-gate mutex_exit(&sp->lock); 69190Sstevel@tonic-gate 69200Sstevel@tonic-gate set_socket.socket = sp->socket_num; 69210Sstevel@tonic-gate set_socket.IREQRouting = 0; 69220Sstevel@tonic-gate set_socket.CtlInd = get_socket.CtlInd; 69230Sstevel@tonic-gate set_socket.State = 0; /* don't reset latched values */ 69240Sstevel@tonic-gate set_socket.VccLevel = get_socket.VccLevel; 69250Sstevel@tonic-gate set_socket.Vpp1Level = get_socket.Vpp1Level; 69260Sstevel@tonic-gate set_socket.Vpp2Level = get_socket.Vpp2Level; 69270Sstevel@tonic-gate set_socket.IFType = IF_MEMORY; 69280Sstevel@tonic-gate 69290Sstevel@tonic-gate if (client->present & CONFIG_OPTION_REG_PRESENT) 69300Sstevel@tonic-gate csx_Put8(cis_handle, crt->cor_p, 0); 69310Sstevel@tonic-gate 69320Sstevel@tonic-gate if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) { 69330Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 69340Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 69350Sstevel@tonic-gate return (CS_BAD_SOCKET); 69360Sstevel@tonic-gate } 69370Sstevel@tonic-gate 69380Sstevel@tonic-gate /* 69390Sstevel@tonic-gate * Mark this client as not having a configuration. 69400Sstevel@tonic-gate */ 69410Sstevel@tonic-gate client->flags &= ~REQ_CONFIGURATION_DONE; 69420Sstevel@tonic-gate 69430Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 69440Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 69450Sstevel@tonic-gate 69460Sstevel@tonic-gate return (CS_SUCCESS); 69470Sstevel@tonic-gate } 69480Sstevel@tonic-gate 69490Sstevel@tonic-gate /* 69500Sstevel@tonic-gate * cs_modify_configuration - modifies a configuration established by 69510Sstevel@tonic-gate * RequestConfiguration; this is ModifyConfiguration 69520Sstevel@tonic-gate * 69530Sstevel@tonic-gate * returns: CS_SUCCESS - if configuration sucessfully modified 69540Sstevel@tonic-gate * CS_BAD_SOCKET - if Socket Services returns an error 69550Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - if SS is trying to call us 69560Sstevel@tonic-gate * CS_BAD_HANDLE - a RequestConfiguration has not been done 69570Sstevel@tonic-gate * CS_NO_CARD - if no card in socket 69580Sstevel@tonic-gate * CS_BAD_ATTRIBUTE - if any unsupported or reserved flags 69590Sstevel@tonic-gate * are set 69600Sstevel@tonic-gate * CS_BAD_VCC - if Vcc value is not supported by socket 69610Sstevel@tonic-gate * CS_BAD_VPP1 - if Vpp1 value is not supported by socket 69620Sstevel@tonic-gate * CS_BAD_VPP2 - if Vpp2 value is not supported by socket 69630Sstevel@tonic-gate */ 69640Sstevel@tonic-gate static int 69650Sstevel@tonic-gate cs_modify_configuration(client_handle_t client_handle, modify_config_t *mc) 69660Sstevel@tonic-gate { 69670Sstevel@tonic-gate cs_socket_t *sp; 69680Sstevel@tonic-gate client_t *client; 69690Sstevel@tonic-gate set_socket_t set_socket; 69700Sstevel@tonic-gate get_socket_t get_socket; 69710Sstevel@tonic-gate int error; 69720Sstevel@tonic-gate int client_lock_acquired; 69730Sstevel@tonic-gate 69740Sstevel@tonic-gate /* 69750Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it 69760Sstevel@tonic-gate * is, we don't support SS using this call. 69770Sstevel@tonic-gate */ 69780Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) 69790Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION); 69800Sstevel@tonic-gate 69810Sstevel@tonic-gate /* 69820Sstevel@tonic-gate * Get a pointer to this client's socket structure. 69830Sstevel@tonic-gate */ 69840Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) 69850Sstevel@tonic-gate return (CS_BAD_SOCKET); 69860Sstevel@tonic-gate 69870Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 69880Sstevel@tonic-gate 69890Sstevel@tonic-gate /* 69900Sstevel@tonic-gate * Make sure that this is a valid client handle. 69910Sstevel@tonic-gate */ 69920Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) { 69930Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 69940Sstevel@tonic-gate return (error); 69950Sstevel@tonic-gate } 69960Sstevel@tonic-gate 69970Sstevel@tonic-gate /* 69980Sstevel@tonic-gate * If RequestConfiguration has not been done, we don't allow 69990Sstevel@tonic-gate * this call. 70000Sstevel@tonic-gate */ 70010Sstevel@tonic-gate if (!(client->flags & REQ_CONFIGURATION_DONE)) { 70020Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 70030Sstevel@tonic-gate return (CS_BAD_HANDLE); 70040Sstevel@tonic-gate } 70050Sstevel@tonic-gate 70060Sstevel@tonic-gate /* 70070Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not 70080Sstevel@tonic-gate * for this client, then return an error. 70090Sstevel@tonic-gate */ 70100Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) { 70110Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 70120Sstevel@tonic-gate return (CS_NO_CARD); 70130Sstevel@tonic-gate } 70140Sstevel@tonic-gate 70150Sstevel@tonic-gate /* 70160Sstevel@tonic-gate * Get the current socket parameters so that we can modify them. 70170Sstevel@tonic-gate */ 70180Sstevel@tonic-gate get_socket.socket = sp->socket_num; 70190Sstevel@tonic-gate 70200Sstevel@tonic-gate if (SocketServices(SS_GetSocket, &get_socket) != SUCCESS) { 70210Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 70220Sstevel@tonic-gate return (CS_BAD_SOCKET); 70230Sstevel@tonic-gate } 70240Sstevel@tonic-gate 70250Sstevel@tonic-gate #ifdef CS_DEBUG 70260Sstevel@tonic-gate if (cs_debug > 0) 70270Sstevel@tonic-gate cmn_err(CE_CONT, "cs_modify_configuration: socket %d " 70280Sstevel@tonic-gate "client->irq_alloc.irq 0x%x " 70290Sstevel@tonic-gate "get_socket.IRQRouting 0x%x\n", 70300Sstevel@tonic-gate sp->socket_num, (int)client->irq_alloc.irq, 70310Sstevel@tonic-gate get_socket.IRQRouting); 70320Sstevel@tonic-gate #endif 70330Sstevel@tonic-gate 70340Sstevel@tonic-gate set_socket.socket = sp->socket_num; 70350Sstevel@tonic-gate set_socket.SCIntMask = get_socket.SCIntMask; 70360Sstevel@tonic-gate set_socket.CtlInd = get_socket.CtlInd; 70370Sstevel@tonic-gate set_socket.State = 0; /* don't reset latched values */ 70380Sstevel@tonic-gate set_socket.IFType = get_socket.IFType; 70390Sstevel@tonic-gate 70400Sstevel@tonic-gate set_socket.IREQRouting = get_socket.IRQRouting; 70410Sstevel@tonic-gate 70420Sstevel@tonic-gate /* 70430Sstevel@tonic-gate * Modify the IRQ routing if the client wants it modified. 70440Sstevel@tonic-gate */ 70450Sstevel@tonic-gate if (mc->Attributes & CONF_IRQ_CHANGE_VALID) { 70460Sstevel@tonic-gate set_socket.IREQRouting &= ~IRQ_ENABLE; 70470Sstevel@tonic-gate 70480Sstevel@tonic-gate if ((sp->cis_flags & CW_MULTI_FUNCTION_CIS) && 70490Sstevel@tonic-gate (client->present & CONFIG_OPTION_REG_PRESENT)) { 70500Sstevel@tonic-gate config_regs_t *crt = &client->config_regs; 70510Sstevel@tonic-gate acc_handle_t cis_handle; 70520Sstevel@tonic-gate uint32_t newoffset = client->config_regs_offset; 70530Sstevel@tonic-gate 70540Sstevel@tonic-gate /* 70550Sstevel@tonic-gate * Get a pointer to a window that contains the configuration 70560Sstevel@tonic-gate * registers. 70570Sstevel@tonic-gate */ 70580Sstevel@tonic-gate if (cs_init_cis_window(sp, &newoffset, &cis_handle, 70590Sstevel@tonic-gate CISTPLF_AM_SPACE) != CS_SUCCESS) { 70600Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 70610Sstevel@tonic-gate cmn_err(CE_CONT, 70620Sstevel@tonic-gate "cs_modify_configuration: socket %d can't init " 70630Sstevel@tonic-gate "CIS window\n", sp->socket_num); 70640Sstevel@tonic-gate return (CS_GENERAL_FAILURE); 70650Sstevel@tonic-gate } /* cs_init_cis_window */ 70660Sstevel@tonic-gate 70670Sstevel@tonic-gate crt->cor &= ~COR_ENABLE_IREQ_ROUTING; 70680Sstevel@tonic-gate 70690Sstevel@tonic-gate if (mc->Attributes & CONF_ENABLE_IRQ_STEERING) 70700Sstevel@tonic-gate crt->cor |= COR_ENABLE_IREQ_ROUTING; 70710Sstevel@tonic-gate 70720Sstevel@tonic-gate #ifdef CS_DEBUG 70730Sstevel@tonic-gate if (cs_debug > 0) 70740Sstevel@tonic-gate cmn_err(CE_CONT, "cs_modify_configuration:" 70750Sstevel@tonic-gate " cor_p=0x%x cor=0x%x\n", 70760Sstevel@tonic-gate crt->cor_p, crt->cor); 70770Sstevel@tonic-gate #endif 70780Sstevel@tonic-gate csx_Put8(cis_handle, crt->cor_p, crt->cor); 70790Sstevel@tonic-gate 70800Sstevel@tonic-gate } /* CW_MULTI_FUNCTION_CIS */ 70810Sstevel@tonic-gate 70820Sstevel@tonic-gate if (mc->Attributes & CONF_ENABLE_IRQ_STEERING) 70830Sstevel@tonic-gate set_socket.IREQRouting |= IRQ_ENABLE; 70840Sstevel@tonic-gate 70850Sstevel@tonic-gate } /* CONF_IRQ_CHANGE_VALID */ 70860Sstevel@tonic-gate 70870Sstevel@tonic-gate /* 70880Sstevel@tonic-gate * Modify the voltage levels that the client specifies. 70890Sstevel@tonic-gate */ 70900Sstevel@tonic-gate set_socket.VccLevel = get_socket.VccLevel; 70910Sstevel@tonic-gate 70920Sstevel@tonic-gate if (mc->Attributes & CONF_VPP1_CHANGE_VALID) { 70930Sstevel@tonic-gate if (cs_convert_powerlevel(sp->socket_num, mc->Vpp1, VPP1, 70940Sstevel@tonic-gate &set_socket.Vpp1Level) != CS_SUCCESS) { 70950Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 70960Sstevel@tonic-gate return (CS_BAD_VPP); 70970Sstevel@tonic-gate } 70980Sstevel@tonic-gate } else { 70990Sstevel@tonic-gate set_socket.Vpp1Level = get_socket.Vpp1Level; 71000Sstevel@tonic-gate } 71010Sstevel@tonic-gate 71020Sstevel@tonic-gate if (mc->Attributes & CONF_VPP2_CHANGE_VALID) { 71030Sstevel@tonic-gate if (cs_convert_powerlevel(sp->socket_num, mc->Vpp2, VPP2, 71040Sstevel@tonic-gate &set_socket.Vpp2Level) != CS_SUCCESS) { 71050Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 71060Sstevel@tonic-gate return (CS_BAD_VPP); 71070Sstevel@tonic-gate } 71080Sstevel@tonic-gate } else { 71090Sstevel@tonic-gate set_socket.Vpp2Level = get_socket.Vpp2Level; 71100Sstevel@tonic-gate } 71110Sstevel@tonic-gate 71120Sstevel@tonic-gate /* 71130Sstevel@tonic-gate * Setup the modified socket configuration. 71140Sstevel@tonic-gate */ 71150Sstevel@tonic-gate if (SocketServices(SS_SetSocket, &set_socket) != SUCCESS) { 71160Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 71170Sstevel@tonic-gate return (CS_BAD_SOCKET); 71180Sstevel@tonic-gate } 71190Sstevel@tonic-gate 71200Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 71210Sstevel@tonic-gate return (CS_SUCCESS); 71220Sstevel@tonic-gate } 71230Sstevel@tonic-gate 71240Sstevel@tonic-gate /* 71250Sstevel@tonic-gate * cs_access_configuration_register - provides a client access to the card's 71260Sstevel@tonic-gate * configuration registers; this is AccessConfigurationRegister 71270Sstevel@tonic-gate * 71280Sstevel@tonic-gate * returns: CS_SUCCESS - if register accessed successfully 71290Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - if SS is trying to call us 71300Sstevel@tonic-gate * CS_BAD_ARGS - if arguments are out of range 71310Sstevel@tonic-gate * CS_NO_CARD - if no card in socket 71320Sstevel@tonic-gate * CS_BAD_BASE - if no config registers base address 71330Sstevel@tonic-gate * CS_UNSUPPORTED_MODE - if no RequestConfiguration has 71340Sstevel@tonic-gate * been done yet 71350Sstevel@tonic-gate */ 71360Sstevel@tonic-gate static int 71370Sstevel@tonic-gate cs_access_configuration_register(client_handle_t client_handle, 71380Sstevel@tonic-gate access_config_reg_t *acr) 71390Sstevel@tonic-gate { 71400Sstevel@tonic-gate cs_socket_t *sp; 71410Sstevel@tonic-gate client_t *client; 71420Sstevel@tonic-gate acc_handle_t cis_handle; 71430Sstevel@tonic-gate int error; 71440Sstevel@tonic-gate uint32_t newoffset; 71450Sstevel@tonic-gate int client_lock_acquired; 71460Sstevel@tonic-gate 71470Sstevel@tonic-gate /* 71480Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it 71490Sstevel@tonic-gate * is, we don't support SS using this call. 71500Sstevel@tonic-gate */ 71510Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) 71520Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION); 71530Sstevel@tonic-gate 71540Sstevel@tonic-gate /* 71550Sstevel@tonic-gate * Make sure that the specifed offset is in range. 71560Sstevel@tonic-gate */ 71570Sstevel@tonic-gate if (acr->Offset > ((CISTPL_CONFIG_MAX_CONFIG_REGS * 2) - 2)) 71580Sstevel@tonic-gate return (CS_BAD_ARGS); 71590Sstevel@tonic-gate 71600Sstevel@tonic-gate /* 71610Sstevel@tonic-gate * Get a pointer to this client's socket structure. 71620Sstevel@tonic-gate */ 71630Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) 71640Sstevel@tonic-gate return (CS_BAD_SOCKET); 71650Sstevel@tonic-gate 71660Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 71670Sstevel@tonic-gate 71680Sstevel@tonic-gate /* 71690Sstevel@tonic-gate * Make sure that this is a valid client handle. 71700Sstevel@tonic-gate */ 71710Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) { 71720Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 71730Sstevel@tonic-gate return (error); 71740Sstevel@tonic-gate } 71750Sstevel@tonic-gate 71760Sstevel@tonic-gate /* 71770Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not 71780Sstevel@tonic-gate * for this client, then return an error. 71790Sstevel@tonic-gate */ 71800Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) { 71810Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 71820Sstevel@tonic-gate return (CS_NO_CARD); 71830Sstevel@tonic-gate } 71840Sstevel@tonic-gate 71850Sstevel@tonic-gate /* 71860Sstevel@tonic-gate * If RequestConfiguration has not been done, we don't allow 71870Sstevel@tonic-gate * this call. 71880Sstevel@tonic-gate */ 71890Sstevel@tonic-gate if (!(client->flags & REQ_CONFIGURATION_DONE)) { 71900Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 71910Sstevel@tonic-gate return (CS_UNSUPPORTED_MODE); 71920Sstevel@tonic-gate } 71930Sstevel@tonic-gate 71940Sstevel@tonic-gate mutex_enter(&sp->cis_lock); 71950Sstevel@tonic-gate 71960Sstevel@tonic-gate /* 71970Sstevel@tonic-gate * Get a pointer to the CIS window 71980Sstevel@tonic-gate */ 71990Sstevel@tonic-gate newoffset = client->config_regs_offset + acr->Offset; 72000Sstevel@tonic-gate if (cs_init_cis_window(sp, &newoffset, &cis_handle, 72010Sstevel@tonic-gate CISTPLF_AM_SPACE) != CS_SUCCESS) { 72020Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 72030Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 72040Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ACR: socket %d can't init CIS window\n", 72050Sstevel@tonic-gate sp->socket_num); 72060Sstevel@tonic-gate return (CS_GENERAL_FAILURE); 72070Sstevel@tonic-gate } 72080Sstevel@tonic-gate 72090Sstevel@tonic-gate /* 72100Sstevel@tonic-gate * Create the address for the config register that the client 72110Sstevel@tonic-gate * wants to access. 72120Sstevel@tonic-gate */ 72130Sstevel@tonic-gate mutex_enter(&sp->lock); 72140Sstevel@tonic-gate 72150Sstevel@tonic-gate #ifdef CS_DEBUG 72160Sstevel@tonic-gate if (cs_debug > 1) { 72170Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ACR: config_regs_offset 0x%x " 72180Sstevel@tonic-gate "Offset 0x%x newoffset 0x%x\n", 72190Sstevel@tonic-gate (int)client->config_regs_offset, 72200Sstevel@tonic-gate (int)acr->Offset, newoffset); 72210Sstevel@tonic-gate } 72220Sstevel@tonic-gate #endif 72230Sstevel@tonic-gate 72240Sstevel@tonic-gate /* 72250Sstevel@tonic-gate * Determine what the client wants us to do. The client is 72260Sstevel@tonic-gate * allowed to specify any valid offset, even if it would 72270Sstevel@tonic-gate * cause an unimplemented configuration register to be 72280Sstevel@tonic-gate * accessed. 72290Sstevel@tonic-gate */ 72300Sstevel@tonic-gate error = CS_SUCCESS; 72310Sstevel@tonic-gate switch (acr->Action) { 72320Sstevel@tonic-gate case CONFIG_REG_READ: 72330Sstevel@tonic-gate acr->Value = csx_Get8(cis_handle, newoffset); 72340Sstevel@tonic-gate break; 72350Sstevel@tonic-gate case CONFIG_REG_WRITE: 72360Sstevel@tonic-gate csx_Put8(cis_handle, newoffset, acr->Value); 72370Sstevel@tonic-gate break; 72380Sstevel@tonic-gate default: 72390Sstevel@tonic-gate error = CS_BAD_ARGS; 72400Sstevel@tonic-gate break; 72410Sstevel@tonic-gate } /* switch */ 72420Sstevel@tonic-gate 72430Sstevel@tonic-gate mutex_exit(&sp->lock); 72440Sstevel@tonic-gate mutex_exit(&sp->cis_lock); 72450Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 72460Sstevel@tonic-gate 72470Sstevel@tonic-gate return (error); 72480Sstevel@tonic-gate } 72490Sstevel@tonic-gate 72500Sstevel@tonic-gate /* 72510Sstevel@tonic-gate * ==== RESET and general info functions ==== 72520Sstevel@tonic-gate */ 72530Sstevel@tonic-gate 72540Sstevel@tonic-gate /* 72550Sstevel@tonic-gate * cs_reset_function - RESET the requested function on the card; this 72560Sstevel@tonic-gate * is ResetFunction 72570Sstevel@tonic-gate * 72580Sstevel@tonic-gate * Note: We don't support this functionality yet, and the standard 72590Sstevel@tonic-gate * says it's OK to reutrn CS_IN_USE if we can't do this 72600Sstevel@tonic-gate * operation. 72610Sstevel@tonic-gate */ 72620Sstevel@tonic-gate /*ARGSUSED*/ 72630Sstevel@tonic-gate static int 72640Sstevel@tonic-gate cs_reset_function(client_handle_t ch, reset_function_t *rf) 72650Sstevel@tonic-gate { 72660Sstevel@tonic-gate return (CS_IN_USE); 72670Sstevel@tonic-gate } 72680Sstevel@tonic-gate 72690Sstevel@tonic-gate /* 72700Sstevel@tonic-gate * cs_get_configuration_info - return configuration info for the passed 72710Sstevel@tonic-gate * socket and function number to the caller; 72720Sstevel@tonic-gate * this is GetConfigurationInfo 72730Sstevel@tonic-gate */ 72740Sstevel@tonic-gate /*ARGSUSED*/ 72750Sstevel@tonic-gate static int 72760Sstevel@tonic-gate cs_get_configuration_info(client_handle_t *chp, get_configuration_info_t *gci) 72770Sstevel@tonic-gate { 72780Sstevel@tonic-gate cs_socket_t *sp; 72790Sstevel@tonic-gate uint32_t fn; 72800Sstevel@tonic-gate client_t *client; 72810Sstevel@tonic-gate int client_lock_acquired; 72820Sstevel@tonic-gate 72830Sstevel@tonic-gate /* 72840Sstevel@tonic-gate * Get a pointer to this client's socket structure. 72850Sstevel@tonic-gate */ 72860Sstevel@tonic-gate if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(gci->Socket))) == NULL) 72870Sstevel@tonic-gate return (CS_BAD_SOCKET); 72880Sstevel@tonic-gate 72890Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 72900Sstevel@tonic-gate mutex_enter(&sp->lock); 72910Sstevel@tonic-gate 72920Sstevel@tonic-gate fn = CS_GET_FUNCTION_NUMBER(gci->Socket); 72930Sstevel@tonic-gate 72940Sstevel@tonic-gate client = sp->client_list; 72950Sstevel@tonic-gate while (client) { 72960Sstevel@tonic-gate 72970Sstevel@tonic-gate if (GET_CLIENT_FUNCTION(client->client_handle) == fn) { 72980Sstevel@tonic-gate 72990Sstevel@tonic-gate /* 73000Sstevel@tonic-gate * If there's no card in the socket or the card in the 73010Sstevel@tonic-gate * socket is not for this client, then return 73020Sstevel@tonic-gate * an error. 73030Sstevel@tonic-gate */ 73040Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) { 73050Sstevel@tonic-gate mutex_exit(&sp->lock); 73060Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 73070Sstevel@tonic-gate return (CS_NO_CARD); 73080Sstevel@tonic-gate } 73090Sstevel@tonic-gate 73100Sstevel@tonic-gate mutex_exit(&sp->lock); 73110Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 73120Sstevel@tonic-gate return (CS_SUCCESS); 73130Sstevel@tonic-gate 73140Sstevel@tonic-gate } /* GET_CLIENT_FUNCTION == fn */ 73150Sstevel@tonic-gate 73160Sstevel@tonic-gate client = client->next; 73170Sstevel@tonic-gate } /* while (client) */ 73180Sstevel@tonic-gate 73190Sstevel@tonic-gate mutex_exit(&sp->lock); 73200Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 73210Sstevel@tonic-gate 73220Sstevel@tonic-gate return (CS_BAD_SOCKET); 73230Sstevel@tonic-gate } 73240Sstevel@tonic-gate 73250Sstevel@tonic-gate /* 73260Sstevel@tonic-gate * cs_get_cardservices_info - return info about Card Services to the 73270Sstevel@tonic-gate * caller; this is GetCardServicesInfo 73280Sstevel@tonic-gate */ 73290Sstevel@tonic-gate /*ARGSUSED*/ 73300Sstevel@tonic-gate static int 73310Sstevel@tonic-gate cs_get_cardservices_info(client_handle_t ch, get_cardservices_info_t *gcsi) 73320Sstevel@tonic-gate { 73330Sstevel@tonic-gate gcsi->Signature[0] = 'C'; 73340Sstevel@tonic-gate gcsi->Signature[1] = 'S'; 73350Sstevel@tonic-gate gcsi->NumSockets = cs_globals.num_sockets; 73360Sstevel@tonic-gate gcsi->Revision = CS_INTERNAL_REVISION_LEVEL; 73370Sstevel@tonic-gate gcsi->CSLevel = CS_VERSION; 73380Sstevel@tonic-gate gcsi->FuncsPerSocket = CIS_MAX_FUNCTIONS; 73390Sstevel@tonic-gate (void) strncpy(gcsi->VendorString, 73400Sstevel@tonic-gate CS_GET_CARDSERVICES_INFO_VENDOR_STRING, 73410Sstevel@tonic-gate CS_GET_CARDSERVICES_INFO_MAX_VS_LEN); 73420Sstevel@tonic-gate 73430Sstevel@tonic-gate return (CS_SUCCESS); 73440Sstevel@tonic-gate } 73450Sstevel@tonic-gate 73460Sstevel@tonic-gate /* 73470Sstevel@tonic-gate * cs_get_physical_adapter_info - returns information about the requested 73480Sstevel@tonic-gate * physical adapter; this is 73490Sstevel@tonic-gate * GetPhysicalAdapterInfo 73500Sstevel@tonic-gate * 73510Sstevel@tonic-gate * calling: client_handle_t: 73520Sstevel@tonic-gate * NULL - use map_log_socket_t->LogSocket member 73530Sstevel@tonic-gate * to specify logical socket number 73540Sstevel@tonic-gate * !NULL - extract logical socket number from 73550Sstevel@tonic-gate * client_handle_t 73560Sstevel@tonic-gate * 73570Sstevel@tonic-gate * returns: CS_SUCCESS 73580Sstevel@tonic-gate * CS_BAD_SOCKET - if client_handle_t is NULL and invalid 73590Sstevel@tonic-gate * socket number is specified in 73600Sstevel@tonic-gate * map_log_socket_t->LogSocket 73610Sstevel@tonic-gate * CS_BAD_HANDLE - if client_handle_t is !NULL and invalid 73620Sstevel@tonic-gate * client handle is specified 73630Sstevel@tonic-gate */ 73640Sstevel@tonic-gate static int 73650Sstevel@tonic-gate cs_get_physical_adapter_info(client_handle_t ch, 73660Sstevel@tonic-gate get_physical_adapter_info_t *gpai) 73670Sstevel@tonic-gate { 73680Sstevel@tonic-gate cs_socket_t *sp; 73690Sstevel@tonic-gate int client_lock_acquired; 73700Sstevel@tonic-gate 73710Sstevel@tonic-gate if (ch == NULL) 73720Sstevel@tonic-gate gpai->PhySocket = CS_GET_SOCKET_NUMBER(gpai->LogSocket); 73730Sstevel@tonic-gate else 73740Sstevel@tonic-gate gpai->PhySocket = GET_CLIENT_SOCKET(ch); 73750Sstevel@tonic-gate 73760Sstevel@tonic-gate /* 73770Sstevel@tonic-gate * Determine if the passed socket number is valid or not. 73780Sstevel@tonic-gate */ 73790Sstevel@tonic-gate if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(gpai->PhySocket))) == NULL) 73800Sstevel@tonic-gate return ((ch == NULL) ? CS_BAD_SOCKET : CS_BAD_HANDLE); 73810Sstevel@tonic-gate 73820Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 73830Sstevel@tonic-gate 73840Sstevel@tonic-gate /* 73850Sstevel@tonic-gate * If we were passed a client handle, determine if it's valid or not. 73860Sstevel@tonic-gate */ 73870Sstevel@tonic-gate if (ch != NULL) { 73880Sstevel@tonic-gate if (cs_find_client(ch, NULL) == NULL) { 73890Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 73900Sstevel@tonic-gate return (CS_BAD_HANDLE); 73910Sstevel@tonic-gate } /* cs_find_client */ 73920Sstevel@tonic-gate } /* ch != NULL */ 73930Sstevel@tonic-gate 73940Sstevel@tonic-gate gpai->flags = sp->adapter.flags; 73950Sstevel@tonic-gate (void) strcpy(gpai->name, sp->adapter.name); 73960Sstevel@tonic-gate gpai->major = sp->adapter.major; 73970Sstevel@tonic-gate gpai->minor = sp->adapter.minor; 73980Sstevel@tonic-gate gpai->instance = sp->adapter.instance; 73990Sstevel@tonic-gate gpai->number = sp->adapter.number; 74000Sstevel@tonic-gate gpai->num_sockets = sp->adapter.num_sockets; 74010Sstevel@tonic-gate gpai->first_socket = sp->adapter.first_socket; 74020Sstevel@tonic-gate 74030Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 74040Sstevel@tonic-gate 74050Sstevel@tonic-gate return (CS_SUCCESS); 74060Sstevel@tonic-gate } 74070Sstevel@tonic-gate 74080Sstevel@tonic-gate /* 74090Sstevel@tonic-gate * ==== general functions ==== 74100Sstevel@tonic-gate */ 74110Sstevel@tonic-gate 74120Sstevel@tonic-gate /* 74130Sstevel@tonic-gate * cs_map_log_socket - returns the physical socket number associated with 74140Sstevel@tonic-gate * either the passed client handle or the passed 74150Sstevel@tonic-gate * logical socket number; this is MapLogSocket 74160Sstevel@tonic-gate * 74170Sstevel@tonic-gate * calling: client_handle_t: 74180Sstevel@tonic-gate * NULL - use map_log_socket_t->LogSocket member 74190Sstevel@tonic-gate * to specify logical socket number 74200Sstevel@tonic-gate * !NULL - extract logical socket number from 74210Sstevel@tonic-gate * client_handle_t 74220Sstevel@tonic-gate * 74230Sstevel@tonic-gate * returns: CS_SUCCESS 74240Sstevel@tonic-gate * CS_BAD_SOCKET - if client_handle_t is NULL and invalid 74250Sstevel@tonic-gate * socket number is specified in 74260Sstevel@tonic-gate * map_log_socket_t->LogSocket 74270Sstevel@tonic-gate * CS_BAD_HANDLE - if client_handle_t is !NULL and invalid 74280Sstevel@tonic-gate * client handle is specified 74290Sstevel@tonic-gate * 74300Sstevel@tonic-gate * Note: We provide this function since the instance number of a client 74310Sstevel@tonic-gate * driver doesn't necessary correspond to the physical 74320Sstevel@tonic-gate * socket number 74330Sstevel@tonic-gate */ 74340Sstevel@tonic-gate static int 74350Sstevel@tonic-gate cs_map_log_socket(client_handle_t ch, map_log_socket_t *mls) 74360Sstevel@tonic-gate { 74370Sstevel@tonic-gate cs_socket_t *sp; 74380Sstevel@tonic-gate int client_lock_acquired; 74390Sstevel@tonic-gate 74400Sstevel@tonic-gate if (ch == NULL) 74410Sstevel@tonic-gate mls->PhySocket = CS_GET_SOCKET_NUMBER(mls->LogSocket); 74420Sstevel@tonic-gate else 74430Sstevel@tonic-gate mls->PhySocket = GET_CLIENT_SOCKET(ch); 74440Sstevel@tonic-gate 74450Sstevel@tonic-gate /* 74460Sstevel@tonic-gate * Determine if the passed socket number is valid or not. 74470Sstevel@tonic-gate */ 74480Sstevel@tonic-gate if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(mls->PhySocket))) == NULL) 74490Sstevel@tonic-gate return ((ch == NULL) ? CS_BAD_SOCKET : CS_BAD_HANDLE); 74500Sstevel@tonic-gate 74510Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 74520Sstevel@tonic-gate 74530Sstevel@tonic-gate /* 74540Sstevel@tonic-gate * If we were passed a client handle, determine if it's valid or not. 74550Sstevel@tonic-gate */ 74560Sstevel@tonic-gate if (ch != NULL) { 74570Sstevel@tonic-gate if (cs_find_client(ch, NULL) == NULL) { 74580Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 74590Sstevel@tonic-gate return (CS_BAD_HANDLE); 74600Sstevel@tonic-gate } /* cs_find_client */ 74610Sstevel@tonic-gate } /* ch != NULL */ 74620Sstevel@tonic-gate 74630Sstevel@tonic-gate mls->PhyAdapter = sp->adapter.number; 74640Sstevel@tonic-gate 74650Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 74660Sstevel@tonic-gate 74670Sstevel@tonic-gate return (CS_SUCCESS); 74680Sstevel@tonic-gate } 74690Sstevel@tonic-gate 74700Sstevel@tonic-gate /* 74710Sstevel@tonic-gate * cs_convert_speed - convers nS to devspeed and devspeed to nS 74720Sstevel@tonic-gate * 74730Sstevel@tonic-gate * The actual function is is in the CIS parser module; this 74740Sstevel@tonic-gate * is only a wrapper. 74750Sstevel@tonic-gate */ 74760Sstevel@tonic-gate static int 74770Sstevel@tonic-gate cs_convert_speed(convert_speed_t *cs) 74780Sstevel@tonic-gate { 74790Sstevel@tonic-gate return ((int)(uintptr_t)CIS_PARSER(CISP_CIS_CONV_DEVSPEED, cs)); 74800Sstevel@tonic-gate } 74810Sstevel@tonic-gate 74820Sstevel@tonic-gate /* 74830Sstevel@tonic-gate * cs_convert_size - converts a devsize value to a size in bytes value 74840Sstevel@tonic-gate * or a size in bytes value to a devsize value 74850Sstevel@tonic-gate * 74860Sstevel@tonic-gate * The actual function is is in the CIS parser module; this 74870Sstevel@tonic-gate * is only a wrapper. 74880Sstevel@tonic-gate */ 74890Sstevel@tonic-gate static int 74900Sstevel@tonic-gate cs_convert_size(convert_size_t *cs) 74910Sstevel@tonic-gate { 74920Sstevel@tonic-gate return ((int)(uintptr_t)CIS_PARSER(CISP_CIS_CONV_DEVSIZE, cs)); 74930Sstevel@tonic-gate } 74940Sstevel@tonic-gate 74950Sstevel@tonic-gate /* 74960Sstevel@tonic-gate * cs_convert_powerlevel - converts a power level in tenths of a volt 74970Sstevel@tonic-gate * to a power table entry for the specified socket 74980Sstevel@tonic-gate * 74990Sstevel@tonic-gate * returns: CS_SUCCESS - if volts converted to a valid power level 75000Sstevel@tonic-gate * CS_BAD_ADAPTER - if SS_InquireAdapter fails 75010Sstevel@tonic-gate * CS_BAD_ARGS - if volts are not supported on this socket 75020Sstevel@tonic-gate * and adapter 75030Sstevel@tonic-gate */ 75040Sstevel@tonic-gate static int 75050Sstevel@tonic-gate cs_convert_powerlevel(uint32_t sn, uint32_t volts, uint32_t flags, unsigned *pl) 75060Sstevel@tonic-gate { 75070Sstevel@tonic-gate inquire_adapter_t inquire_adapter; 75080Sstevel@tonic-gate int i; 75090Sstevel@tonic-gate 75100Sstevel@tonic-gate #ifdef lint 75110Sstevel@tonic-gate if (sn == 0) 75120Sstevel@tonic-gate panic("lint panic"); 75130Sstevel@tonic-gate #endif 75140Sstevel@tonic-gate 75150Sstevel@tonic-gate *pl = 0; 75160Sstevel@tonic-gate 75170Sstevel@tonic-gate if (SocketServices(SS_InquireAdapter, &inquire_adapter) != SUCCESS) 75180Sstevel@tonic-gate return (CS_BAD_ADAPTER); 75190Sstevel@tonic-gate 75200Sstevel@tonic-gate for (i = 0; (i < inquire_adapter.NumPower); i++) { 75210Sstevel@tonic-gate if ((inquire_adapter.power_entry[i].ValidSignals & flags) && 75220Sstevel@tonic-gate (inquire_adapter.power_entry[i].PowerLevel == volts)) { 75230Sstevel@tonic-gate *pl = i; 75240Sstevel@tonic-gate return (CS_SUCCESS); 75250Sstevel@tonic-gate } 75260Sstevel@tonic-gate } 75270Sstevel@tonic-gate 75280Sstevel@tonic-gate return (CS_BAD_ARGS); 75290Sstevel@tonic-gate } 75300Sstevel@tonic-gate 75310Sstevel@tonic-gate /* 75320Sstevel@tonic-gate * cs_event2text - returns text string(s) associated with the event; this 75330Sstevel@tonic-gate * function supports the Event2Text CS call. 75340Sstevel@tonic-gate * 75350Sstevel@tonic-gate * calling: event2text_t * - pointer to event2text struct 75360Sstevel@tonic-gate * int event_source - specifies event type in event2text_t: 75370Sstevel@tonic-gate * 0 - SS event 75380Sstevel@tonic-gate * 1 - CS event 75390Sstevel@tonic-gate * 75400Sstevel@tonic-gate * returns: CS_SUCCESS 75410Sstevel@tonic-gate */ 75420Sstevel@tonic-gate static int 75430Sstevel@tonic-gate cs_event2text(event2text_t *e2t, int event_source) 75440Sstevel@tonic-gate { 75450Sstevel@tonic-gate event_t event; 75460Sstevel@tonic-gate char *sepchar = "|"; 75470Sstevel@tonic-gate 75480Sstevel@tonic-gate /* 75490Sstevel@tonic-gate * If event_source is 0, this is a SS event 75500Sstevel@tonic-gate */ 75510Sstevel@tonic-gate if (!event_source) { 75520Sstevel@tonic-gate for (event = 0; event < MAX_SS_EVENTS; event++) { 75530Sstevel@tonic-gate if (cs_ss_event_text[event].ss_event == e2t->event) { 75540Sstevel@tonic-gate (void) strcpy(e2t->text, cs_ss_event_text[event].text); 75550Sstevel@tonic-gate return (CS_SUCCESS); 75560Sstevel@tonic-gate } 75570Sstevel@tonic-gate } 75580Sstevel@tonic-gate (void) strcpy(e2t->text, cs_ss_event_text[MAX_CS_EVENTS].text); 75590Sstevel@tonic-gate return (CS_SUCCESS); 75600Sstevel@tonic-gate } else { 75610Sstevel@tonic-gate /* 75620Sstevel@tonic-gate * This is a CS event 75630Sstevel@tonic-gate */ 75640Sstevel@tonic-gate e2t->text[0] = '\0'; 75650Sstevel@tonic-gate for (event = 0; event < MAX_CS_EVENTS; event++) { 75660Sstevel@tonic-gate if (cs_ss_event_text[event].cs_event & e2t->event) { 75670Sstevel@tonic-gate (void) strcat(e2t->text, cs_ss_event_text[event].text); 75680Sstevel@tonic-gate (void) strcat(e2t->text, sepchar); 75690Sstevel@tonic-gate } /* if (cs_ss_event_text) */ 75700Sstevel@tonic-gate } /* for (event) */ 75710Sstevel@tonic-gate if (e2t->text[0]) 75720Sstevel@tonic-gate e2t->text[strlen(e2t->text)-1] = NULL; 75730Sstevel@tonic-gate } /* if (!event_source) */ 75740Sstevel@tonic-gate 75750Sstevel@tonic-gate return (CS_SUCCESS); 75760Sstevel@tonic-gate } 75770Sstevel@tonic-gate 75780Sstevel@tonic-gate /* 75790Sstevel@tonic-gate * cs_error2text - returns a pointer to a text string containing the name 75800Sstevel@tonic-gate * of the passed Card Services function or return code 75810Sstevel@tonic-gate * 75820Sstevel@tonic-gate * This function supports the Error2Text CS call. 75830Sstevel@tonic-gate */ 75840Sstevel@tonic-gate static char * 75850Sstevel@tonic-gate cs_error2text(int function, int type) 75860Sstevel@tonic-gate { 75870Sstevel@tonic-gate cs_csfunc2text_strings_t *cfs; 75880Sstevel@tonic-gate int end_marker; 75890Sstevel@tonic-gate 75900Sstevel@tonic-gate if (type == CSFUN2TEXT_FUNCTION) { 75910Sstevel@tonic-gate cfs = cs_csfunc2text_funcstrings; 75920Sstevel@tonic-gate end_marker = CSFuncListEnd; 75930Sstevel@tonic-gate } else { 75940Sstevel@tonic-gate cfs = cs_csfunc2text_returnstrings; 75950Sstevel@tonic-gate end_marker = CS_ERRORLIST_END; 75960Sstevel@tonic-gate } 75970Sstevel@tonic-gate 75980Sstevel@tonic-gate while (cfs->item != end_marker) { 75990Sstevel@tonic-gate if (cfs->item == function) 76000Sstevel@tonic-gate return (cfs->text); 76010Sstevel@tonic-gate cfs++; 76020Sstevel@tonic-gate } 76030Sstevel@tonic-gate 76040Sstevel@tonic-gate return (cfs->text); 76050Sstevel@tonic-gate } 76060Sstevel@tonic-gate 76070Sstevel@tonic-gate /* 76080Sstevel@tonic-gate * cs_make_device_node - creates/removes device nodes on a client's behalf; 76090Sstevel@tonic-gate * this is MakeDeviceNode and RemoveDeviceNode 76100Sstevel@tonic-gate * 76110Sstevel@tonic-gate * returns: CS_SUCCESS - if all device nodes successfully created/removed 76120Sstevel@tonic-gate * CS_BAD_ATTRIBUTE - if NumDevNodes is not zero when Action 76130Sstevel@tonic-gate * is REMOVAL_ALL_DEVICES 76140Sstevel@tonic-gate * CS_BAD_ARGS - if an invalid Action code is specified 76150Sstevel@tonic-gate * CS_UNSUPPORTED_FUNCTION - if SS is trying to call us 76160Sstevel@tonic-gate * CS_OUT_OF_RESOURCE - if can't create/remove device node 76170Sstevel@tonic-gate */ 76180Sstevel@tonic-gate static int 76190Sstevel@tonic-gate cs_make_device_node(client_handle_t client_handle, make_device_node_t *mdn) 76200Sstevel@tonic-gate { 76210Sstevel@tonic-gate cs_socket_t *sp; 76220Sstevel@tonic-gate client_t *client; 76230Sstevel@tonic-gate ss_make_device_node_t ss_make_device_node; 76240Sstevel@tonic-gate int error, i; 76250Sstevel@tonic-gate int client_lock_acquired; 76260Sstevel@tonic-gate 76270Sstevel@tonic-gate /* 76280Sstevel@tonic-gate * Check to see if this is the Socket Services client handle; if it 76290Sstevel@tonic-gate * is, we don't support SS using this call. 76300Sstevel@tonic-gate */ 76310Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) 76320Sstevel@tonic-gate return (CS_UNSUPPORTED_FUNCTION); 76330Sstevel@tonic-gate 76340Sstevel@tonic-gate /* 76350Sstevel@tonic-gate * Get a pointer to this client's socket structure. 76360Sstevel@tonic-gate */ 76370Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) 76380Sstevel@tonic-gate return (CS_BAD_SOCKET); 76390Sstevel@tonic-gate 76400Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 76410Sstevel@tonic-gate 76420Sstevel@tonic-gate /* 76430Sstevel@tonic-gate * Make sure that this is a valid client handle. 76440Sstevel@tonic-gate */ 76450Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &error))) { 76460Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 76470Sstevel@tonic-gate return (error); 76480Sstevel@tonic-gate } 76490Sstevel@tonic-gate 76500Sstevel@tonic-gate #ifdef XXX 76510Sstevel@tonic-gate /* 76520Sstevel@tonic-gate * If there's no card in the socket or the card in the socket is not 76530Sstevel@tonic-gate * for this client, then return an error. 76540Sstevel@tonic-gate */ 76550Sstevel@tonic-gate if (!(client->flags & CLIENT_CARD_INSERTED)) { 76560Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 76570Sstevel@tonic-gate return (CS_NO_CARD); 76580Sstevel@tonic-gate } 76590Sstevel@tonic-gate #endif 76600Sstevel@tonic-gate 76610Sstevel@tonic-gate /* 76620Sstevel@tonic-gate * Setup the client's dip, since we use it later on. 76630Sstevel@tonic-gate */ 76640Sstevel@tonic-gate ss_make_device_node.dip = client->dip; 76650Sstevel@tonic-gate 76660Sstevel@tonic-gate /* 76670Sstevel@tonic-gate * Make sure that we're being given a valid Action. Set the default 76680Sstevel@tonic-gate * error code as well. 76690Sstevel@tonic-gate */ 76700Sstevel@tonic-gate error = CS_BAD_ARGS; /* for default case */ 76710Sstevel@tonic-gate switch (mdn->Action) { 76720Sstevel@tonic-gate case CREATE_DEVICE_NODE: 76730Sstevel@tonic-gate case REMOVE_DEVICE_NODE: 76740Sstevel@tonic-gate break; 76750Sstevel@tonic-gate case REMOVAL_ALL_DEVICE_NODES: 76760Sstevel@tonic-gate if (mdn->NumDevNodes) { 76770Sstevel@tonic-gate error = CS_BAD_ATTRIBUTE; 76780Sstevel@tonic-gate } else { 76790Sstevel@tonic-gate ss_make_device_node.flags = SS_CSINITDEV_REMOVE_DEVICE; 76800Sstevel@tonic-gate ss_make_device_node.name = NULL; 76810Sstevel@tonic-gate SocketServices(CSInitDev, &ss_make_device_node); 76820Sstevel@tonic-gate error = CS_SUCCESS; 76830Sstevel@tonic-gate } 76840Sstevel@tonic-gate /* fall-through case */ 76850Sstevel@tonic-gate default: 76860Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 76870Sstevel@tonic-gate return (error); 76880Sstevel@tonic-gate /* NOTREACHED */ 76890Sstevel@tonic-gate } /* switch */ 76900Sstevel@tonic-gate 76910Sstevel@tonic-gate /* 76920Sstevel@tonic-gate * Loop through the device node descriptions and create or destroy 76930Sstevel@tonic-gate * the device node. 76940Sstevel@tonic-gate */ 76950Sstevel@tonic-gate for (i = 0; i < mdn->NumDevNodes; i++) { 76960Sstevel@tonic-gate devnode_desc_t *devnode_desc = &mdn->devnode_desc[i]; 76970Sstevel@tonic-gate 76980Sstevel@tonic-gate ss_make_device_node.name = devnode_desc->name; 76990Sstevel@tonic-gate ss_make_device_node.spec_type = devnode_desc->spec_type; 77000Sstevel@tonic-gate ss_make_device_node.minor_num = devnode_desc->minor_num; 77010Sstevel@tonic-gate ss_make_device_node.node_type = devnode_desc->node_type; 77020Sstevel@tonic-gate 77030Sstevel@tonic-gate /* 77040Sstevel@tonic-gate * Set the appropriate flag for the action that we want 77050Sstevel@tonic-gate * SS to perform. Note that if we ever OR-in the flag 77060Sstevel@tonic-gate * here, we need to be sure to clear the flags member 77070Sstevel@tonic-gate * since we sometimes OR-in other flags below. 77080Sstevel@tonic-gate */ 77090Sstevel@tonic-gate if (mdn->Action == CREATE_DEVICE_NODE) { 77100Sstevel@tonic-gate ss_make_device_node.flags = SS_CSINITDEV_CREATE_DEVICE; 77110Sstevel@tonic-gate } else { 77120Sstevel@tonic-gate ss_make_device_node.flags = SS_CSINITDEV_REMOVE_DEVICE; 77130Sstevel@tonic-gate } 77140Sstevel@tonic-gate 77150Sstevel@tonic-gate /* 77160Sstevel@tonic-gate * If this is not the last device to process, then we need 77170Sstevel@tonic-gate * to tell SS that more device process requests are on 77180Sstevel@tonic-gate * their way after this one. 77190Sstevel@tonic-gate */ 77200Sstevel@tonic-gate if (i < (mdn->NumDevNodes - 1)) 77210Sstevel@tonic-gate ss_make_device_node.flags |= SS_CSINITDEV_MORE_DEVICES; 77220Sstevel@tonic-gate 77230Sstevel@tonic-gate if (SocketServices(CSInitDev, &ss_make_device_node) != SUCCESS) { 77240Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 77250Sstevel@tonic-gate return (CS_OUT_OF_RESOURCE); 77260Sstevel@tonic-gate } /* CSInitDev */ 77270Sstevel@tonic-gate } /* for (mdn->NumDevNodes) */ 77280Sstevel@tonic-gate 77290Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 77300Sstevel@tonic-gate return (CS_SUCCESS); 77310Sstevel@tonic-gate } 77320Sstevel@tonic-gate 77330Sstevel@tonic-gate /* 77340Sstevel@tonic-gate * cs_remove_device_node - removes device nodes 77350Sstevel@tonic-gate * 77360Sstevel@tonic-gate * (see cs_make_device_node for a description of the calling 77370Sstevel@tonic-gate * and return parameters) 77380Sstevel@tonic-gate */ 77390Sstevel@tonic-gate static int 77400Sstevel@tonic-gate cs_remove_device_node(client_handle_t client_handle, remove_device_node_t *rdn) 77410Sstevel@tonic-gate { 77420Sstevel@tonic-gate 77430Sstevel@tonic-gate /* 77440Sstevel@tonic-gate * XXX - Note the assumption here that the make_device_node_t and 77450Sstevel@tonic-gate * remove_device_node_t structures are identical. 77460Sstevel@tonic-gate */ 77470Sstevel@tonic-gate return (cs_make_device_node(client_handle, (make_device_node_t *)rdn)); 77480Sstevel@tonic-gate } 77490Sstevel@tonic-gate 77500Sstevel@tonic-gate /* 77510Sstevel@tonic-gate * cs_ddi_info - this function is used by clients that need to support 77520Sstevel@tonic-gate * the xxx_getinfo function; this is CS_DDI_Info 77530Sstevel@tonic-gate */ 77540Sstevel@tonic-gate static int 77550Sstevel@tonic-gate cs_ddi_info(cs_ddi_info_t *cdi) 77560Sstevel@tonic-gate { 77570Sstevel@tonic-gate cs_socket_t *sp; 77580Sstevel@tonic-gate client_t *client; 77590Sstevel@tonic-gate int client_lock_acquired; 77600Sstevel@tonic-gate 77610Sstevel@tonic-gate if (cdi->driver_name == NULL) 77620Sstevel@tonic-gate return (CS_BAD_ATTRIBUTE); 77630Sstevel@tonic-gate 77640Sstevel@tonic-gate #ifdef CS_DEBUG 77650Sstevel@tonic-gate if (cs_debug > 0) { 77660Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ddi_info: socket %d client [%s]\n", 77670Sstevel@tonic-gate (int)cdi->Socket, cdi->driver_name); 77680Sstevel@tonic-gate } 77690Sstevel@tonic-gate #endif 77700Sstevel@tonic-gate 77710Sstevel@tonic-gate /* 77720Sstevel@tonic-gate * Check to see if the socket number is in range - the system 77730Sstevel@tonic-gate * framework may cause a client driver to call us with 77740Sstevel@tonic-gate * a socket number that used to be present but isn't 77750Sstevel@tonic-gate * anymore. This is not a bug, and it's OK to return 77760Sstevel@tonic-gate * an error if the socket number is out of range. 77770Sstevel@tonic-gate */ 77780Sstevel@tonic-gate if (!CHECK_SOCKET_NUM(cdi->Socket, cs_globals.max_socket_num)) { 77790Sstevel@tonic-gate 77800Sstevel@tonic-gate #ifdef CS_DEBUG 77810Sstevel@tonic-gate if (cs_debug > 0) { 77820Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ddi_info: socket %d client [%s] " 77830Sstevel@tonic-gate "SOCKET IS OUT OF RANGE\n", 77840Sstevel@tonic-gate (int)cdi->Socket, 77850Sstevel@tonic-gate cdi->driver_name); 77860Sstevel@tonic-gate } 77870Sstevel@tonic-gate #endif 77880Sstevel@tonic-gate 77890Sstevel@tonic-gate return (CS_BAD_SOCKET); 77900Sstevel@tonic-gate } /* if (!CHECK_SOCKET_NUM) */ 77910Sstevel@tonic-gate 77920Sstevel@tonic-gate /* 77930Sstevel@tonic-gate * Get a pointer to this client's socket structure. 77940Sstevel@tonic-gate */ 77950Sstevel@tonic-gate if ((sp = cs_get_sp(cdi->Socket)) == NULL) 77960Sstevel@tonic-gate return (CS_BAD_SOCKET); 77970Sstevel@tonic-gate 77980Sstevel@tonic-gate EVENT_THREAD_MUTEX_ENTER(client_lock_acquired, sp); 77990Sstevel@tonic-gate 78000Sstevel@tonic-gate client = sp->client_list; 78010Sstevel@tonic-gate while (client) { 78020Sstevel@tonic-gate 78030Sstevel@tonic-gate #ifdef CS_DEBUG 78040Sstevel@tonic-gate if (cs_debug > 0) { 78050Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ddi_info: socket %d checking client [%s] " 78060Sstevel@tonic-gate "handle 0x%x\n", 78070Sstevel@tonic-gate (int)cdi->Socket, 78080Sstevel@tonic-gate client->driver_name, 78090Sstevel@tonic-gate (int)client->client_handle); 78100Sstevel@tonic-gate } 78110Sstevel@tonic-gate #endif 78120Sstevel@tonic-gate 78130Sstevel@tonic-gate if (client->driver_name != NULL) { 78140Sstevel@tonic-gate if (!(strcmp(client->driver_name, cdi->driver_name))) { 78150Sstevel@tonic-gate cdi->dip = client->dip; 78160Sstevel@tonic-gate cdi->instance = client->instance; 78170Sstevel@tonic-gate 78180Sstevel@tonic-gate #ifdef CS_DEBUG 78190Sstevel@tonic-gate if (cs_debug > 0) { 78200Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ddi_info: found client [%s] " 78210Sstevel@tonic-gate "instance %d handle 0x%x\n", 78220Sstevel@tonic-gate client->driver_name, client->instance, 78230Sstevel@tonic-gate (int)client->client_handle); 78240Sstevel@tonic-gate } 78250Sstevel@tonic-gate #endif 78260Sstevel@tonic-gate 78270Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 78280Sstevel@tonic-gate return (CS_SUCCESS); 78290Sstevel@tonic-gate } /* strcmp */ 78300Sstevel@tonic-gate } /* driver_name != NULL */ 78310Sstevel@tonic-gate client = client->next; 78320Sstevel@tonic-gate } /* while (client) */ 78330Sstevel@tonic-gate 78340Sstevel@tonic-gate EVENT_THREAD_MUTEX_EXIT(client_lock_acquired, sp); 78350Sstevel@tonic-gate return (CS_BAD_SOCKET); 78360Sstevel@tonic-gate } 78370Sstevel@tonic-gate 78380Sstevel@tonic-gate /* 78390Sstevel@tonic-gate * cs_sys_ctl - Card Services system control; this is CS_Sys_Ctl 78400Sstevel@tonic-gate */ 78410Sstevel@tonic-gate static int 78420Sstevel@tonic-gate cs_sys_ctl(cs_sys_ctl_t *csc) 78430Sstevel@tonic-gate { 78440Sstevel@tonic-gate cs_socket_t *sp; 78450Sstevel@tonic-gate client_t *cp; 78460Sstevel@tonic-gate int sn, ret = CS_UNSUPPORTED_MODE; 78470Sstevel@tonic-gate 78480Sstevel@tonic-gate switch (csc->Action) { 78490Sstevel@tonic-gate case CS_SYS_CTL_SEND_EVENT: 78500Sstevel@tonic-gate if (csc->Flags & CS_SYS_CTL_EVENT_SOCKET) 78510Sstevel@tonic-gate sn = CS_GET_SOCKET_NUMBER(csc->Socket); 78520Sstevel@tonic-gate else 78530Sstevel@tonic-gate sn = GET_CLIENT_SOCKET(csc->client_handle); 78540Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) == NULL) 78550Sstevel@tonic-gate return (CS_BAD_SOCKET); 78560Sstevel@tonic-gate mutex_enter(&sp->client_lock); 78570Sstevel@tonic-gate mutex_enter(&sp->lock); 78580Sstevel@tonic-gate csc->Events &= CS_EVENT_CLIENT_EVENTS_MASK; 78590Sstevel@tonic-gate if (csc->Flags & CS_SYS_CTL_EVENT_SOCKET) 78600Sstevel@tonic-gate sp->events |= csc->Events; 78610Sstevel@tonic-gate if (csc->Flags & CS_SYS_CTL_EVENT_CLIENT) { 78620Sstevel@tonic-gate if ((cp = cs_find_client(csc->client_handle, &ret)) == 78630Sstevel@tonic-gate NULL) { 78640Sstevel@tonic-gate mutex_exit(&sp->lock); 78650Sstevel@tonic-gate mutex_exit(&sp->client_lock); 78660Sstevel@tonic-gate return (ret); 78670Sstevel@tonic-gate } /* cs_find_client */ 78680Sstevel@tonic-gate /* 78690Sstevel@tonic-gate * Setup the events that we want to send to the client. 78700Sstevel@tonic-gate */ 78710Sstevel@tonic-gate cp->events |= (csc->Events & 78720Sstevel@tonic-gate (cp->event_mask | cp->global_mask)); 78730Sstevel@tonic-gate } /* CS_SYS_CTL_EVENT_CLIENT */ 78740Sstevel@tonic-gate 78750Sstevel@tonic-gate if (csc->Flags & CS_SYS_CTL_WAIT_SYNC) { 78760Sstevel@tonic-gate sp->thread_state |= SOCKET_WAIT_SYNC; 78770Sstevel@tonic-gate mutex_exit(&sp->lock); 78780Sstevel@tonic-gate cv_broadcast(&sp->thread_cv); 78790Sstevel@tonic-gate cv_wait(&sp->caller_cv, &sp->client_lock); 78800Sstevel@tonic-gate } else { 78810Sstevel@tonic-gate mutex_exit(&sp->lock); 78820Sstevel@tonic-gate cv_broadcast(&sp->thread_cv); 78830Sstevel@tonic-gate } /* CS_SYS_CTL_WAIT_SYNC */ 78840Sstevel@tonic-gate mutex_exit(&sp->client_lock); 78850Sstevel@tonic-gate ret = CS_SUCCESS; 78860Sstevel@tonic-gate break; 78870Sstevel@tonic-gate default: 78880Sstevel@tonic-gate break; 78890Sstevel@tonic-gate } /* switch */ 78900Sstevel@tonic-gate 78910Sstevel@tonic-gate return (ret); 78920Sstevel@tonic-gate } 78930Sstevel@tonic-gate 78940Sstevel@tonic-gate /* 78950Sstevel@tonic-gate * cs_get_sp - returns pointer to per-socket structure for passed 78960Sstevel@tonic-gate * socket number 78970Sstevel@tonic-gate * 78980Sstevel@tonic-gate * return: (cs_socket_t *) - pointer to socket structure 78990Sstevel@tonic-gate * NULL - invalid socket number passed in 79000Sstevel@tonic-gate */ 79010Sstevel@tonic-gate static cs_socket_t * 79020Sstevel@tonic-gate cs_get_sp(uint32_t sn) 79030Sstevel@tonic-gate { 79040Sstevel@tonic-gate cs_socket_t *sp = cs_globals.sp; 79050Sstevel@tonic-gate 79060Sstevel@tonic-gate if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY)) 79070Sstevel@tonic-gate return (NULL); 79080Sstevel@tonic-gate 79090Sstevel@tonic-gate if ((sp = cs_find_sp(sn)) == NULL) 79100Sstevel@tonic-gate return (NULL); 79110Sstevel@tonic-gate 79120Sstevel@tonic-gate if (sp->flags & SOCKET_IS_VALID) 79130Sstevel@tonic-gate return (sp); 79140Sstevel@tonic-gate 79150Sstevel@tonic-gate return (NULL); 79160Sstevel@tonic-gate } 79170Sstevel@tonic-gate 79180Sstevel@tonic-gate /* 79190Sstevel@tonic-gate * cs_find_sp - searches socket list and returns pointer to passed socket 79200Sstevel@tonic-gate * number 79210Sstevel@tonic-gate * 79220Sstevel@tonic-gate * return: (cs_socket_t *) - pointer to socket structure if found 79230Sstevel@tonic-gate * NULL - socket not found 79240Sstevel@tonic-gate */ 79250Sstevel@tonic-gate static cs_socket_t * 79260Sstevel@tonic-gate cs_find_sp(uint32_t sn) 79270Sstevel@tonic-gate { 79280Sstevel@tonic-gate cs_socket_t *sp = cs_globals.sp; 79290Sstevel@tonic-gate 79300Sstevel@tonic-gate while (sp) { 79310Sstevel@tonic-gate if (sp->socket_num == CS_GET_SOCKET_NUMBER(sn)) 79320Sstevel@tonic-gate return (sp); 79330Sstevel@tonic-gate sp = sp->next; 79340Sstevel@tonic-gate } /* while */ 79350Sstevel@tonic-gate 79360Sstevel@tonic-gate return (NULL); 79370Sstevel@tonic-gate } 79380Sstevel@tonic-gate 79390Sstevel@tonic-gate /* 79400Sstevel@tonic-gate * cs_add_socket - add a socket 79410Sstevel@tonic-gate * 79420Sstevel@tonic-gate * call: sn - socket number to add 79430Sstevel@tonic-gate * 79440Sstevel@tonic-gate * return: CS_SUCCESS - operation sucessful 79450Sstevel@tonic-gate * CS_BAD_SOCKET - unable to add socket 79460Sstevel@tonic-gate * CS_BAD_WINDOW - unable to get CIS window for socket 79470Sstevel@tonic-gate * 79480Sstevel@tonic-gate * We get called here once for each socket that the framework wants to 79490Sstevel@tonic-gate * add. When we are called, the framework guarentees that until we 79500Sstevel@tonic-gate * complete this routine, no other adapter instances will be allowed 79510Sstevel@tonic-gate * to attach and thus no other PCE_ADD_SOCKET events will occur. 79520Sstevel@tonic-gate * It is safe to call SS_InquireAdapter to get the number of 79530Sstevel@tonic-gate * windows that the framework currently knows about. 79540Sstevel@tonic-gate */ 79550Sstevel@tonic-gate static uint32_t 79560Sstevel@tonic-gate cs_add_socket(uint32_t sn) 79570Sstevel@tonic-gate { 79580Sstevel@tonic-gate cs_socket_t *sp; 79590Sstevel@tonic-gate sservice_t sservice; 79600Sstevel@tonic-gate get_cookies_and_dip_t *gcad; 79610Sstevel@tonic-gate win_req_t win_req; 79620Sstevel@tonic-gate convert_speed_t convert_speed; 79630Sstevel@tonic-gate set_socket_t set_socket; 79640Sstevel@tonic-gate cs_window_t *cw; 79650Sstevel@tonic-gate inquire_adapter_t inquire_adapter; 79660Sstevel@tonic-gate inquire_window_t inquire_window; 79670Sstevel@tonic-gate int ret, added_windows; 79680Sstevel@tonic-gate 79690Sstevel@tonic-gate if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY)) 79700Sstevel@tonic-gate return (CS_BAD_SOCKET); 79710Sstevel@tonic-gate 79720Sstevel@tonic-gate /* 79730Sstevel@tonic-gate * See if this socket has already been added - if it has, we 79740Sstevel@tonic-gate * fail this. If we can't find the socket, then allocate 79750Sstevel@tonic-gate * a new socket structure. If we do find the socket, then 79760Sstevel@tonic-gate * check to see if it's already added; if it is, then 79770Sstevel@tonic-gate * this is an error and return CS_BAD_SOCKET; if not, 79780Sstevel@tonic-gate * then traverse the socket structure list and add this 79790Sstevel@tonic-gate * next socket strcture to the end of the list. 79800Sstevel@tonic-gate * XXX What about locking this list while we update it? Is 79810Sstevel@tonic-gate * that necessary since we're using the SOCKET_IS_VALID 79820Sstevel@tonic-gate * flag and since we never delete a socket from the 79830Sstevel@tonic-gate * list once it's been added? 79840Sstevel@tonic-gate */ 79850Sstevel@tonic-gate if ((sp = cs_find_sp(sn)) == NULL) { 79860Sstevel@tonic-gate cs_socket_t *spp = cs_globals.sp; 79870Sstevel@tonic-gate 79880Sstevel@tonic-gate sp = (cs_socket_t *)kmem_zalloc(sizeof (cs_socket_t), KM_SLEEP); 79890Sstevel@tonic-gate 79900Sstevel@tonic-gate if (cs_globals.sp == NULL) 79910Sstevel@tonic-gate cs_globals.sp = sp; 79920Sstevel@tonic-gate else 79930Sstevel@tonic-gate while (spp) { 79940Sstevel@tonic-gate if (spp->next == NULL) { 79950Sstevel@tonic-gate spp->next = sp; 79960Sstevel@tonic-gate break; 79970Sstevel@tonic-gate } /* if */ 79980Sstevel@tonic-gate spp = spp->next; 79990Sstevel@tonic-gate } /* while */ 80000Sstevel@tonic-gate 80010Sstevel@tonic-gate } else { 80020Sstevel@tonic-gate if (sp->flags & SOCKET_IS_VALID) 80030Sstevel@tonic-gate return (CS_BAD_SOCKET); 80040Sstevel@tonic-gate } /* cs_find_sp */ 80050Sstevel@tonic-gate 80060Sstevel@tonic-gate /* 80070Sstevel@tonic-gate * Setup the socket number 80080Sstevel@tonic-gate */ 80090Sstevel@tonic-gate sp->socket_num = sn; 80100Sstevel@tonic-gate 80110Sstevel@tonic-gate /* 80120Sstevel@tonic-gate * Find out how many windows the framework knows about 80130Sstevel@tonic-gate * so far. If this number of windows is greater 80140Sstevel@tonic-gate * than our current window count, bump up our 80150Sstevel@tonic-gate * current window count. 80160Sstevel@tonic-gate * XXX Note that there is a BIG assumption here and that 80170Sstevel@tonic-gate * is that once the framework tells us that it has 80180Sstevel@tonic-gate * a window (as reflected in the NumWindows 80190Sstevel@tonic-gate * value) it can NEVER remove that window. 80200Sstevel@tonic-gate * When we really get the drop socket and drop 80210Sstevel@tonic-gate * window mechanism working correctly, we'll have 80220Sstevel@tonic-gate * to revisit this. 80230Sstevel@tonic-gate */ 80240Sstevel@tonic-gate SocketServices(SS_InquireAdapter, &inquire_adapter); 80250Sstevel@tonic-gate 80260Sstevel@tonic-gate mutex_enter(&cs_globals.window_lock); 80270Sstevel@tonic-gate added_windows = inquire_adapter.NumWindows - cs_globals.num_windows; 80280Sstevel@tonic-gate if (added_windows > 0) { 80290Sstevel@tonic-gate if (cs_add_windows(added_windows, 80300Sstevel@tonic-gate cs_globals.num_windows) != CS_SUCCESS) { 80310Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 80320Sstevel@tonic-gate return (CS_BAD_WINDOW); 80330Sstevel@tonic-gate } /* cs_add_windows */ 80340Sstevel@tonic-gate 80350Sstevel@tonic-gate cs_globals.num_windows = inquire_adapter.NumWindows; 80360Sstevel@tonic-gate 80370Sstevel@tonic-gate } /* if (added_windows) */ 80380Sstevel@tonic-gate 80390Sstevel@tonic-gate /* 80400Sstevel@tonic-gate * Find a window that we can use for this socket's CIS window. 80410Sstevel@tonic-gate */ 80420Sstevel@tonic-gate sp->cis_win_num = PCMCIA_MAX_WINDOWS; 80430Sstevel@tonic-gate 80440Sstevel@tonic-gate convert_speed.Attributes = CONVERT_NS_TO_DEVSPEED; 80450Sstevel@tonic-gate convert_speed.nS = CIS_DEFAULT_SPEED; 80460Sstevel@tonic-gate (void) cs_convert_speed(&convert_speed); 80470Sstevel@tonic-gate 80480Sstevel@tonic-gate win_req.win_params.AccessSpeed = convert_speed.devspeed; 80490Sstevel@tonic-gate win_req.Attributes = (WIN_MEMORY_TYPE_AM | WIN_DATA_WIDTH_8); 80500Sstevel@tonic-gate win_req.Attributes = (WIN_MEMORY_TYPE_AM | WIN_MEMORY_TYPE_CM); 80510Sstevel@tonic-gate win_req.Base.base = 0; 80520Sstevel@tonic-gate win_req.Size = 0; 80530Sstevel@tonic-gate 80540Sstevel@tonic-gate if ((ret = cs_find_mem_window(sp->socket_num, &win_req, 80550Sstevel@tonic-gate &sp->cis_win_num)) != CS_SUCCESS) { 80560Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 80570Sstevel@tonic-gate sp->cis_win_num = PCMCIA_MAX_WINDOWS; 80580Sstevel@tonic-gate cmn_err(CE_CONT, "cs_add_socket: socket %d can't get CIS " 80590Sstevel@tonic-gate "window - error 0x%x\n", 80600Sstevel@tonic-gate sp->socket_num, ret); 80610Sstevel@tonic-gate return (CS_BAD_WINDOW); 80620Sstevel@tonic-gate } /* cs_find_mem_window */ 80630Sstevel@tonic-gate 80640Sstevel@tonic-gate if ((cw = cs_get_wp(sp->cis_win_num)) == NULL) { 80650Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 80660Sstevel@tonic-gate return (CS_BAD_WINDOW); 80670Sstevel@tonic-gate } 80680Sstevel@tonic-gate 80690Sstevel@tonic-gate inquire_window.window = sp->cis_win_num; 80700Sstevel@tonic-gate SocketServices(SS_InquireWindow, &inquire_window); 80710Sstevel@tonic-gate 80720Sstevel@tonic-gate /* 80730Sstevel@tonic-gate * If the CIS window is a variable sized window, then use 80740Sstevel@tonic-gate * the size that cs_find_mem_window returned to us, 80750Sstevel@tonic-gate * since this will be the minimum size that we can 80760Sstevel@tonic-gate * set this window to. If the CIS window is a fixed 80770Sstevel@tonic-gate * sized window, then use the system pagesize as the 80780Sstevel@tonic-gate * CIS window size. 80790Sstevel@tonic-gate */ 80800Sstevel@tonic-gate if (inquire_window.mem_win_char.MemWndCaps & WC_SIZE) { 80810Sstevel@tonic-gate sp->cis_win_size = win_req.Size; 80820Sstevel@tonic-gate } else { 80830Sstevel@tonic-gate sp->cis_win_size = PAGESIZE; 80840Sstevel@tonic-gate } 80850Sstevel@tonic-gate 80860Sstevel@tonic-gate cw->state |= (CW_CIS | CW_ALLOCATED); 80870Sstevel@tonic-gate cw->socket_num = sp->socket_num; 80880Sstevel@tonic-gate 80890Sstevel@tonic-gate mutex_exit(&cs_globals.window_lock); 80900Sstevel@tonic-gate 80910Sstevel@tonic-gate #if defined(CS_DEBUG) 80920Sstevel@tonic-gate if (cs_debug > 1) { 80930Sstevel@tonic-gate cmn_err(CE_CONT, "cs_add_socket: socket %d using CIS window %d " 80940Sstevel@tonic-gate "size 0x%x\n", (int)sp->socket_num, 80950Sstevel@tonic-gate (int)sp->cis_win_num, 80960Sstevel@tonic-gate (int)sp->cis_win_size); 80970Sstevel@tonic-gate } 80980Sstevel@tonic-gate #endif 80990Sstevel@tonic-gate 81000Sstevel@tonic-gate /* 81010Sstevel@tonic-gate * Get the adapter information associated with this socket so 81020Sstevel@tonic-gate * that we can initialize the mutexes, condition variables, 81030Sstevel@tonic-gate * soft interrupt handler and per-socket adapter info. 81040Sstevel@tonic-gate */ 81050Sstevel@tonic-gate gcad = &sservice.get_cookies; 81060Sstevel@tonic-gate gcad->socket = sp->socket_num; 81070Sstevel@tonic-gate if (SocketServices(CSGetCookiesAndDip, &sservice) != SUCCESS) { 81080Sstevel@tonic-gate cmn_err(CE_CONT, "cs_add_socket: socket %d CSGetCookiesAndDip " 81090Sstevel@tonic-gate "failure\n", sp->socket_num); 81100Sstevel@tonic-gate return (CS_BAD_SOCKET); 81110Sstevel@tonic-gate } /* CSGetCookiesAndDip */ 81120Sstevel@tonic-gate 81130Sstevel@tonic-gate /* 81140Sstevel@tonic-gate * Save the iblock and idev cookies for RegisterClient 81150Sstevel@tonic-gate */ 81160Sstevel@tonic-gate sp->iblk = gcad->iblock; 81170Sstevel@tonic-gate sp->idev = gcad->idevice; 81180Sstevel@tonic-gate 81190Sstevel@tonic-gate /* 81200Sstevel@tonic-gate * Setup the per-socket adapter info 81210Sstevel@tonic-gate */ 81220Sstevel@tonic-gate sp->adapter.flags = 0; 81230Sstevel@tonic-gate (void) strcpy(sp->adapter.name, gcad->adapter_info.name); 81240Sstevel@tonic-gate sp->adapter.major = gcad->adapter_info.major; 81250Sstevel@tonic-gate sp->adapter.minor = gcad->adapter_info.minor; 81260Sstevel@tonic-gate sp->adapter.instance = ddi_get_instance(gcad->dip); 81270Sstevel@tonic-gate sp->adapter.number = gcad->adapter_info.number; 81280Sstevel@tonic-gate sp->adapter.num_sockets = gcad->adapter_info.num_sockets; 81290Sstevel@tonic-gate sp->adapter.first_socket = gcad->adapter_info.first_socket; 81300Sstevel@tonic-gate 81310Sstevel@tonic-gate /* Setup for cs_event and cs_event_thread */ 81320Sstevel@tonic-gate mutex_init(&sp->lock, NULL, MUTEX_DRIVER, *(gcad->iblock)); 81330Sstevel@tonic-gate mutex_init(&sp->client_lock, NULL, MUTEX_DRIVER, NULL); 81340Sstevel@tonic-gate mutex_init(&sp->cis_lock, NULL, MUTEX_DRIVER, NULL); 81350Sstevel@tonic-gate 81360Sstevel@tonic-gate /* Setup for Socket Services work thread */ 81370Sstevel@tonic-gate mutex_init(&sp->ss_thread_lock, NULL, MUTEX_DRIVER, NULL); 81380Sstevel@tonic-gate 81390Sstevel@tonic-gate sp->init_state |= SOCKET_INIT_STATE_MUTEX; 81400Sstevel@tonic-gate 81410Sstevel@tonic-gate /* Setup for cs_event_thread */ 81420Sstevel@tonic-gate cv_init(&sp->thread_cv, NULL, CV_DRIVER, NULL); 81430Sstevel@tonic-gate cv_init(&sp->caller_cv, NULL, CV_DRIVER, NULL); 81440Sstevel@tonic-gate cv_init(&sp->reset_cv, NULL, CV_DRIVER, NULL); 81450Sstevel@tonic-gate 81460Sstevel@tonic-gate /* Setup for Socket Services work thread */ 81470Sstevel@tonic-gate cv_init(&sp->ss_thread_cv, NULL, CV_DRIVER, NULL); 81480Sstevel@tonic-gate cv_init(&sp->ss_caller_cv, NULL, CV_DRIVER, NULL); 81490Sstevel@tonic-gate 81500Sstevel@tonic-gate sp->init_state |= SOCKET_INIT_STATE_CV; 81510Sstevel@tonic-gate 81520Sstevel@tonic-gate /* 81530Sstevel@tonic-gate * If we haven't installed it yet, then install the soft interrupt 81540Sstevel@tonic-gate * handler and save away the softint id. 81550Sstevel@tonic-gate */ 81560Sstevel@tonic-gate if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SOFTINTR)) { 81570Sstevel@tonic-gate if (ddi_add_softintr(gcad->dip, DDI_SOFTINT_HIGH, 81580Sstevel@tonic-gate &sp->softint_id, 81590Sstevel@tonic-gate NULL, NULL, 81600Sstevel@tonic-gate cs_socket_event_softintr, 81610Sstevel@tonic-gate (caddr_t)NULL) != DDI_SUCCESS) { 81620Sstevel@tonic-gate cmn_err(CE_CONT, "cs_add_socket: socket %d can't add " 81630Sstevel@tonic-gate "softintr\n", sp->socket_num); 81640Sstevel@tonic-gate return (CS_BAD_SOCKET); 81650Sstevel@tonic-gate } /* ddi_add_softintr */ 81660Sstevel@tonic-gate 81670Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock); 81680Sstevel@tonic-gate cs_globals.softint_id = sp->softint_id; 81690Sstevel@tonic-gate cs_globals.init_state |= GLOBAL_INIT_STATE_SOFTINTR; 81700Sstevel@tonic-gate /* XXX this timer is hokey at best... */ 81710Sstevel@tonic-gate cs_globals.sotfint_tmo = timeout(cs_event_softintr_timeout, 81720Sstevel@tonic-gate NULL, SOFTINT_TIMEOUT_TIME); 81730Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock); 81740Sstevel@tonic-gate } else { 81750Sstevel@tonic-gate /* 81760Sstevel@tonic-gate * We've already added the soft interrupt handler, so just 81770Sstevel@tonic-gate * store away the softint id. 81780Sstevel@tonic-gate */ 81790Sstevel@tonic-gate sp->softint_id = cs_globals.softint_id; 81800Sstevel@tonic-gate } /* if (!GLOBAL_INIT_STATE_SOFTINTR) */ 81810Sstevel@tonic-gate 81820Sstevel@tonic-gate /* 81830Sstevel@tonic-gate * While this next flag doesn't really describe a per-socket 81840Sstevel@tonic-gate * resource, we still set it for each socket. When the soft 81850Sstevel@tonic-gate * interrupt handler finally gets removed in cs_deinit, this 81860Sstevel@tonic-gate * flag will get cleared. 81870Sstevel@tonic-gate */ 81880Sstevel@tonic-gate sp->init_state |= SOCKET_INIT_STATE_SOFTINTR; 81890Sstevel@tonic-gate 81900Sstevel@tonic-gate /* 81910Sstevel@tonic-gate * Socket Services defaults all sockets to power off and 81920Sstevel@tonic-gate * clears all event masks. We want to receive at least 81930Sstevel@tonic-gate * card insertion events, so enable them. Turn off power 81940Sstevel@tonic-gate * to the socket as well. We will turn it on again when 81950Sstevel@tonic-gate * we get a card insertion event. 81960Sstevel@tonic-gate */ 81970Sstevel@tonic-gate sp->event_mask = CS_EVENT_CARD_INSERTION; 81980Sstevel@tonic-gate set_socket.socket = sp->socket_num; 81990Sstevel@tonic-gate set_socket.SCIntMask = SBM_CD; 82000Sstevel@tonic-gate set_socket.IREQRouting = 0; 82010Sstevel@tonic-gate set_socket.IFType = IF_MEMORY; 82020Sstevel@tonic-gate set_socket.CtlInd = 0; /* turn off controls and indicators */ 82030Sstevel@tonic-gate set_socket.State = (unsigned)~0; /* clear latched state bits */ 82040Sstevel@tonic-gate 82050Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 0, VCC, 82060Sstevel@tonic-gate &set_socket.VccLevel); 82070Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 0, VPP1, 82080Sstevel@tonic-gate &set_socket.Vpp1Level); 82090Sstevel@tonic-gate (void) cs_convert_powerlevel(sp->socket_num, 0, VPP2, 82100Sstevel@tonic-gate &set_socket.Vpp2Level); 82110Sstevel@tonic-gate 82120Sstevel@tonic-gate if ((ret = SocketServices(SS_SetSocket, &set_socket)) != SUCCESS) { 82130Sstevel@tonic-gate cmn_err(CE_CONT, "cs_add_socket: socket %d SS_SetSocket " 82140Sstevel@tonic-gate "failure %d\n", sp->socket_num, ret); 82150Sstevel@tonic-gate return (CS_BAD_SOCKET); 82160Sstevel@tonic-gate } /* SS_SetSocket */ 82170Sstevel@tonic-gate 82180Sstevel@tonic-gate /* 82190Sstevel@tonic-gate * The various socket-specific variables are now set up, so 82200Sstevel@tonic-gate * increment the global socket count and also mark the 82210Sstevel@tonic-gate * socket as available. We need to set this before we 82220Sstevel@tonic-gate * start any of the per-socket threads so that the threads 82230Sstevel@tonic-gate * can get a valid socket pointer when they start. 82240Sstevel@tonic-gate */ 82250Sstevel@tonic-gate mutex_enter(&cs_globals.global_lock); 82260Sstevel@tonic-gate cs_globals.num_sockets++; 82270Sstevel@tonic-gate cs_globals.max_socket_num = 82280Sstevel@tonic-gate max(cs_globals.max_socket_num, sp->socket_num + 1); 82290Sstevel@tonic-gate mutex_exit(&cs_globals.global_lock); 82300Sstevel@tonic-gate sp->flags = SOCKET_IS_VALID; 82310Sstevel@tonic-gate 82320Sstevel@tonic-gate /* 82330Sstevel@tonic-gate * Create the per-socket event handler thread. 82340Sstevel@tonic-gate */ 82350Sstevel@tonic-gate sp->event_thread = CREATE_SOCKET_EVENT_THREAD(cs_event_thread, 82360Sstevel@tonic-gate (uintptr_t)sn); 82370Sstevel@tonic-gate 82380Sstevel@tonic-gate mutex_enter(&sp->lock); 82390Sstevel@tonic-gate sp->init_state |= SOCKET_INIT_STATE_THREAD; 82400Sstevel@tonic-gate mutex_exit(&sp->lock); 82410Sstevel@tonic-gate 82420Sstevel@tonic-gate /* 82430Sstevel@tonic-gate * Create the per-socket Socket Services work thread. 82440Sstevel@tonic-gate */ 82450Sstevel@tonic-gate sp->ss_thread = CREATE_SOCKET_EVENT_THREAD(cs_ss_thread, 82460Sstevel@tonic-gate (uintptr_t)sn); 82470Sstevel@tonic-gate 82480Sstevel@tonic-gate mutex_enter(&sp->lock); 82490Sstevel@tonic-gate sp->init_state |= (SOCKET_INIT_STATE_SS_THREAD | 82500Sstevel@tonic-gate SOCKET_INIT_STATE_READY); 82510Sstevel@tonic-gate sp->event_mask = CS_EVENT_CARD_INSERTION; 82520Sstevel@tonic-gate mutex_exit(&sp->lock); 82530Sstevel@tonic-gate 82540Sstevel@tonic-gate return (CS_SUCCESS); 82550Sstevel@tonic-gate } 82560Sstevel@tonic-gate 82570Sstevel@tonic-gate /* 82580Sstevel@tonic-gate * cs_drop_socket - drop a socket 82590Sstevel@tonic-gate * 82600Sstevel@tonic-gate * call: sn - socket number to drop 82610Sstevel@tonic-gate * 82620Sstevel@tonic-gate * return: CS_SUCCESS - operation sucessful 82630Sstevel@tonic-gate * CS_BAD_SOCKET - unable to drop socket 82640Sstevel@tonic-gate */ 82650Sstevel@tonic-gate /*ARGSUSED*/ 82660Sstevel@tonic-gate static uint32_t 82670Sstevel@tonic-gate cs_drop_socket(uint32_t sn) 82680Sstevel@tonic-gate { 82690Sstevel@tonic-gate #ifdef XXX 82700Sstevel@tonic-gate cs_socket_t *sp; 82710Sstevel@tonic-gate 82720Sstevel@tonic-gate /* 82730Sstevel@tonic-gate * Tell the socket event thread to exit and then wait for it 82740Sstevel@tonic-gate * to do so. 82750Sstevel@tonic-gate */ 82760Sstevel@tonic-gate mutex_enter(&sp->client_lock); 82770Sstevel@tonic-gate sp->thread_state |= SOCKET_THREAD_EXIT; 82780Sstevel@tonic-gate cv_broadcast(&sp->thread_cv); 82790Sstevel@tonic-gate cv_wait(&sp->caller_cv, &sp->client_lock); 82800Sstevel@tonic-gate mutex_exit(&sp->client_lock); 82810Sstevel@tonic-gate 82820Sstevel@tonic-gate /* 82830Sstevel@tonic-gate * Tell the socket SS thread to exit and then wait for it 82840Sstevel@tonic-gate * to do so. 82850Sstevel@tonic-gate */ 82860Sstevel@tonic-gate 82870Sstevel@tonic-gate /* 82880Sstevel@tonic-gate * Mark the socket as dropped. 82890Sstevel@tonic-gate */ 82900Sstevel@tonic-gate sp->flags &= ~SOCKET_IS_VALID; 82910Sstevel@tonic-gate 82920Sstevel@tonic-gate #endif /* XXX */ 82930Sstevel@tonic-gate 82940Sstevel@tonic-gate /* XXX for now don't allow dropping sockets XXX */ 82950Sstevel@tonic-gate return (CS_BAD_SOCKET); 82960Sstevel@tonic-gate } 82970Sstevel@tonic-gate 82980Sstevel@tonic-gate /* 82990Sstevel@tonic-gate * cs_get_socket - returns the socket and function numbers and a pointer 83000Sstevel@tonic-gate * to the socket structure 83010Sstevel@tonic-gate * 83020Sstevel@tonic-gate * calling: client_handle_t client_handle - client handle to extract 83030Sstevel@tonic-gate * socket number from 83040Sstevel@tonic-gate * uint32_t *socket - pointer to socket number to use if 83050Sstevel@tonic-gate * client_handle is for the SS client; 83060Sstevel@tonic-gate * this value will be filled in on 83070Sstevel@tonic-gate * return with the correct socket 83080Sstevel@tonic-gate * and function numbers if we 83090Sstevel@tonic-gate * return CS_SUCCESS 83100Sstevel@tonic-gate * uint32_t *function - pointer to return function number into 83110Sstevel@tonic-gate * if not NULL 83120Sstevel@tonic-gate * cs_socket_t **sp - pointer to a pointer where a pointer 83130Sstevel@tonic-gate * to the socket struct will be 83140Sstevel@tonic-gate * placed if this is non-NULL 83150Sstevel@tonic-gate * client_t **clp - pointer to a pointer where a pointer 83160Sstevel@tonic-gate * to the client struct will be 83170Sstevel@tonic-gate * placed if this is non-NULL 83180Sstevel@tonic-gate * 83190Sstevel@tonic-gate * The socket and function numbers are derived as follows: 83200Sstevel@tonic-gate * 83210Sstevel@tonic-gate * Client Type Socket Number Function Number 83220Sstevel@tonic-gate * PC card client From client_handle From client_handle 83230Sstevel@tonic-gate * Socket Services client From *socket From *socket 83240Sstevel@tonic-gate * CSI client From client_handle From *socket 83250Sstevel@tonic-gate */ 83260Sstevel@tonic-gate static uint32_t 83270Sstevel@tonic-gate cs_get_socket(client_handle_t client_handle, uint32_t *socket, 83280Sstevel@tonic-gate uint32_t *function, cs_socket_t **csp, client_t **clp) 83290Sstevel@tonic-gate { 83300Sstevel@tonic-gate cs_socket_t *sp; 83310Sstevel@tonic-gate client_t *client; 83320Sstevel@tonic-gate uint32_t sn, fn; 83330Sstevel@tonic-gate int ret; 83340Sstevel@tonic-gate 83350Sstevel@tonic-gate sn = *socket; 83360Sstevel@tonic-gate 83370Sstevel@tonic-gate /* 83380Sstevel@tonic-gate * If this is the Socket Services client, then return the 83390Sstevel@tonic-gate * socket and function numbers specified in the passed 83400Sstevel@tonic-gate * socket number parameter, otherwise extract the socket 83410Sstevel@tonic-gate * and function numbers from the client handle. 83420Sstevel@tonic-gate */ 83430Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) { 83440Sstevel@tonic-gate fn = CS_GET_FUNCTION_NUMBER(sn); 83450Sstevel@tonic-gate sn = CS_GET_SOCKET_NUMBER(sn); 83460Sstevel@tonic-gate } else { 83470Sstevel@tonic-gate fn = GET_CLIENT_FUNCTION(client_handle); 83480Sstevel@tonic-gate sn = GET_CLIENT_SOCKET(client_handle); 83490Sstevel@tonic-gate } 83500Sstevel@tonic-gate 83510Sstevel@tonic-gate /* 83520Sstevel@tonic-gate * Check to be sure that the socket number is in range 83530Sstevel@tonic-gate */ 83540Sstevel@tonic-gate if (!(CHECK_SOCKET_NUM(sn, cs_globals.max_socket_num))) 83550Sstevel@tonic-gate return (CS_BAD_SOCKET); 83560Sstevel@tonic-gate 83570Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) == NULL) 83580Sstevel@tonic-gate return (CS_BAD_SOCKET); 83590Sstevel@tonic-gate 83600Sstevel@tonic-gate /* 83610Sstevel@tonic-gate * If we were given a pointer, then fill it in with a pointer 83620Sstevel@tonic-gate * to this socket. 83630Sstevel@tonic-gate */ 83640Sstevel@tonic-gate if (csp) 83650Sstevel@tonic-gate *csp = sp; 83660Sstevel@tonic-gate 83670Sstevel@tonic-gate /* 83680Sstevel@tonic-gate * Search for the client; if it's not found, return an error. 83690Sstevel@tonic-gate */ 83700Sstevel@tonic-gate mutex_enter(&sp->lock); 83710Sstevel@tonic-gate if (!(client = cs_find_client(client_handle, &ret))) { 83720Sstevel@tonic-gate mutex_exit(&sp->lock); 83730Sstevel@tonic-gate return (ret); 83740Sstevel@tonic-gate } 83750Sstevel@tonic-gate 83760Sstevel@tonic-gate /* 83770Sstevel@tonic-gate * If we're a CIS client, then extract the function number 83780Sstevel@tonic-gate * from the socket number. 83790Sstevel@tonic-gate */ 83800Sstevel@tonic-gate if (client->flags & CLIENT_CSI_CLIENT) 83810Sstevel@tonic-gate fn = CS_GET_FUNCTION_NUMBER(*socket); 83820Sstevel@tonic-gate 83830Sstevel@tonic-gate mutex_exit(&sp->lock); 83840Sstevel@tonic-gate 83850Sstevel@tonic-gate /* 83860Sstevel@tonic-gate * Return the found client pointer if the caller wants it. 83870Sstevel@tonic-gate */ 83880Sstevel@tonic-gate if (clp) 83890Sstevel@tonic-gate *clp = client; 83900Sstevel@tonic-gate 83910Sstevel@tonic-gate /* 83920Sstevel@tonic-gate * Return a socket number that is made up of the socket number 83930Sstevel@tonic-gate * and the function number. 83940Sstevel@tonic-gate */ 83950Sstevel@tonic-gate *socket = CS_MAKE_SOCKET_NUMBER(sn, fn); 83960Sstevel@tonic-gate 83970Sstevel@tonic-gate /* 83980Sstevel@tonic-gate * Return the function number if the caller wants it. 83990Sstevel@tonic-gate */ 84000Sstevel@tonic-gate if (function) 84010Sstevel@tonic-gate *function = fn; 84020Sstevel@tonic-gate 84030Sstevel@tonic-gate return (CS_SUCCESS); 84040Sstevel@tonic-gate } 84050Sstevel@tonic-gate 84060Sstevel@tonic-gate /* 84070Sstevel@tonic-gate * cs_get_wp - returns pointer to passed window number 84080Sstevel@tonic-gate * 84090Sstevel@tonic-gate * return: (cs_window_t *) - pointer to window structure 84100Sstevel@tonic-gate * NULL - if invalid window number passed in 84110Sstevel@tonic-gate */ 84120Sstevel@tonic-gate static cs_window_t * 84130Sstevel@tonic-gate cs_get_wp(uint32_t wn) 84140Sstevel@tonic-gate { 84150Sstevel@tonic-gate cs_window_t *cw; 84160Sstevel@tonic-gate 84170Sstevel@tonic-gate if (!(cs_globals.init_state & GLOBAL_INIT_STATE_SS_READY)) 84180Sstevel@tonic-gate return (NULL); 84190Sstevel@tonic-gate 84200Sstevel@tonic-gate if ((cw = cs_find_wp(wn)) == NULL) 84210Sstevel@tonic-gate return (NULL); 84220Sstevel@tonic-gate 84230Sstevel@tonic-gate if (cw->state & CW_WINDOW_VALID) 84240Sstevel@tonic-gate return (cw); 84250Sstevel@tonic-gate 84260Sstevel@tonic-gate #ifdef CS_DEBUG 84270Sstevel@tonic-gate if (cs_debug > 0) { 84280Sstevel@tonic-gate cmn_err(CE_CONT, "cs_get_wp(): wn=%d cw=%p\n", 84290Sstevel@tonic-gate (int)wn, (void *)cw); 84300Sstevel@tonic-gate } 84310Sstevel@tonic-gate #endif 84320Sstevel@tonic-gate 84330Sstevel@tonic-gate return (NULL); 84340Sstevel@tonic-gate } 84350Sstevel@tonic-gate 84360Sstevel@tonic-gate /* 84370Sstevel@tonic-gate * cs_find_wp - searches window list and returns pointer to passed window 84380Sstevel@tonic-gate * number 84390Sstevel@tonic-gate * 84400Sstevel@tonic-gate * return: (cs_window_t *) - pointer to window structure 84410Sstevel@tonic-gate * NULL - window not found 84420Sstevel@tonic-gate */ 84430Sstevel@tonic-gate static cs_window_t * 84440Sstevel@tonic-gate cs_find_wp(uint32_t wn) 84450Sstevel@tonic-gate { 84460Sstevel@tonic-gate cs_window_t *cw = cs_globals.cw; 84470Sstevel@tonic-gate 84480Sstevel@tonic-gate while (cw) { 84490Sstevel@tonic-gate if (cw->window_num == wn) 84500Sstevel@tonic-gate return (cw); 84510Sstevel@tonic-gate cw = cw->next; 84520Sstevel@tonic-gate } /* while */ 84530Sstevel@tonic-gate 84540Sstevel@tonic-gate #ifdef CS_DEBUG 84550Sstevel@tonic-gate if (cs_debug > 0) { 84560Sstevel@tonic-gate cmn_err(CE_CONT, "cs_find_wp(): wn=%d window_num=%d cw=%p\n", 84570Sstevel@tonic-gate (int)wn, (int)cw->window_num, (void *)cw); 84580Sstevel@tonic-gate } 84590Sstevel@tonic-gate #endif 84600Sstevel@tonic-gate 84610Sstevel@tonic-gate return (NULL); 84620Sstevel@tonic-gate } 84630Sstevel@tonic-gate 84640Sstevel@tonic-gate /* 84650Sstevel@tonic-gate * cs_add_windows - adds number of windows specified in "aw" to 84660Sstevel@tonic-gate * the global window list; start the window 84670Sstevel@tonic-gate * numbering at "bn" 84680Sstevel@tonic-gate * 84690Sstevel@tonic-gate * return: CS_SUCCESS - if windows added sucessfully 84700Sstevel@tonic-gate * CS_BAD_WINDOW - if unable to add windows 84710Sstevel@tonic-gate * 84720Sstevel@tonic-gate * Note: The window list must be protected by a lock by the caller. 84730Sstevel@tonic-gate */ 84740Sstevel@tonic-gate static int 84750Sstevel@tonic-gate cs_add_windows(int aw, uint32_t bn) 84760Sstevel@tonic-gate { 84770Sstevel@tonic-gate cs_window_t *cwp = cs_globals.cw; 84780Sstevel@tonic-gate cs_window_t *cw, *cwpp; 84790Sstevel@tonic-gate 84800Sstevel@tonic-gate if (aw <= 0) 84810Sstevel@tonic-gate return (CS_BAD_WINDOW); 84820Sstevel@tonic-gate 84830Sstevel@tonic-gate while (cwp) { 84840Sstevel@tonic-gate cwpp = cwp; 84850Sstevel@tonic-gate cwp = cwp->next; 84860Sstevel@tonic-gate } 84870Sstevel@tonic-gate 84880Sstevel@tonic-gate while (aw--) { 84890Sstevel@tonic-gate cw = (cs_window_t *)kmem_zalloc(sizeof (cs_window_t), KM_SLEEP); 84900Sstevel@tonic-gate 84910Sstevel@tonic-gate if (cs_globals.cw == NULL) { 84920Sstevel@tonic-gate cs_globals.cw = cw; 84930Sstevel@tonic-gate cwpp = cs_globals.cw; 84940Sstevel@tonic-gate } else { 84950Sstevel@tonic-gate cwpp->next = cw; 84960Sstevel@tonic-gate cwpp = cwpp->next; 84970Sstevel@tonic-gate } 84980Sstevel@tonic-gate 84990Sstevel@tonic-gate cwpp->window_num = bn++; 85000Sstevel@tonic-gate cwpp->state = CW_WINDOW_VALID; 85010Sstevel@tonic-gate 85020Sstevel@tonic-gate } /* while (aw) */ 85030Sstevel@tonic-gate 85040Sstevel@tonic-gate return (CS_SUCCESS); 85050Sstevel@tonic-gate } 85060Sstevel@tonic-gate 85070Sstevel@tonic-gate /* 85080Sstevel@tonic-gate * cs_ss_init - initialize CS items that need to wait until we receive 85090Sstevel@tonic-gate * a PCE_SS_INIT_STATE/PCE_SS_STATE_INIT event 85100Sstevel@tonic-gate * 85110Sstevel@tonic-gate * return: CS_SUCESS - if sucessfully initialized 85120Sstevel@tonic-gate * (various) if error initializing 85130Sstevel@tonic-gate * 85140Sstevel@tonic-gate * At this point, we expect that Socket Services has setup the 85150Sstevel@tonic-gate * following global variables for us: 85160Sstevel@tonic-gate * 85170Sstevel@tonic-gate * cs_socket_services - Socket Services entry point 85180Sstevel@tonic-gate * cis_parser - CIS parser entry point 85190Sstevel@tonic-gate */ 85200Sstevel@tonic-gate static uint32_t 85210Sstevel@tonic-gate cs_ss_init() 85220Sstevel@tonic-gate { 85230Sstevel@tonic-gate cs_register_cardservices_t rcs; 85240Sstevel@tonic-gate csregister_t csr; 85250Sstevel@tonic-gate uint32_t ret; 85260Sstevel@tonic-gate 85270Sstevel@tonic-gate /* 85280Sstevel@tonic-gate * Fill out the parameters for CISP_CIS_SETUP 85290Sstevel@tonic-gate */ 85300Sstevel@tonic-gate csr.cs_magic = PCCS_MAGIC; 85310Sstevel@tonic-gate csr.cs_version = PCCS_VERSION; 85320Sstevel@tonic-gate csr.cs_card_services = CardServices; 85330Sstevel@tonic-gate csr.cs_event = NULL; 85340Sstevel@tonic-gate 85350Sstevel@tonic-gate /* 85360Sstevel@tonic-gate * Call into the CIS module and tell it what the private 85370Sstevel@tonic-gate * Card Services entry point is. The CIS module will 85380Sstevel@tonic-gate * call us back at CardServices(CISRegister, ...) 85390Sstevel@tonic-gate * with the address of various CIS-specific global 85400Sstevel@tonic-gate * data structures. 85410Sstevel@tonic-gate */ 85420Sstevel@tonic-gate CIS_PARSER(CISP_CIS_SETUP, &csr); 85430Sstevel@tonic-gate 85440Sstevel@tonic-gate /* 85450Sstevel@tonic-gate * Register with the Card Services kernel stubs module 85460Sstevel@tonic-gate */ 85470Sstevel@tonic-gate rcs.magic = CS_STUBS_MAGIC; 85480Sstevel@tonic-gate rcs.function = CS_ENTRY_REGISTER; 85490Sstevel@tonic-gate rcs.cardservices = CardServices; 85500Sstevel@tonic-gate 85510Sstevel@tonic-gate if ((ret = csx_register_cardservices(&rcs)) != CS_SUCCESS) { 85520Sstevel@tonic-gate cmn_err(CE_CONT, "cs_ss_init: can't register with " 85530Sstevel@tonic-gate "cs_stubs, retcode = 0x%x\n", ret); 85540Sstevel@tonic-gate return (ret); 85550Sstevel@tonic-gate } /* csx_register_cardservices */ 85560Sstevel@tonic-gate 85570Sstevel@tonic-gate return (CS_SUCCESS); 85580Sstevel@tonic-gate } 85590Sstevel@tonic-gate 85600Sstevel@tonic-gate /* 85610Sstevel@tonic-gate * cs_create_cis - reads CIS on card in socket and creates CIS lists 85620Sstevel@tonic-gate * 85630Sstevel@tonic-gate * Most of the work is done in the CIS module in the CISP_CIS_LIST_CREATE 85640Sstevel@tonic-gate * function. 85650Sstevel@tonic-gate * 85660Sstevel@tonic-gate * This function returns: 85670Sstevel@tonic-gate * 85680Sstevel@tonic-gate * CS_SUCCESS - if the CIS lists were created sucessfully 85690Sstevel@tonic-gate * CS_BAD_WINDOW or CS_GENERAL_FAILURE - if CIS window could 85700Sstevel@tonic-gate * not be setup 85710Sstevel@tonic-gate * CS_BAD_CIS - if error creating CIS chains 85720Sstevel@tonic-gate * CS_BAD_OFFSET - if the CIS parser tried to read past the 85730Sstevel@tonic-gate * boundries of the allocated CIS window 85740Sstevel@tonic-gate */ 85750Sstevel@tonic-gate static int 85760Sstevel@tonic-gate cs_create_cis(cs_socket_t *sp) 85770Sstevel@tonic-gate { 85780Sstevel@tonic-gate uint32_t ret; 85790Sstevel@tonic-gate 85800Sstevel@tonic-gate ret = (uint32_t)(uintptr_t)CIS_PARSER(CISP_CIS_LIST_CREATE, 85810Sstevel@tonic-gate cis_cistpl_std_callout, sp); 85820Sstevel@tonic-gate 85830Sstevel@tonic-gate #ifdef CS_DEBUG 85840Sstevel@tonic-gate if (ret == CS_NO_CIS) { 85850Sstevel@tonic-gate if (cs_debug > 0) 85860Sstevel@tonic-gate cmn_err(CE_CONT, "cs_create_cis: socket %d has no CIS\n", 85870Sstevel@tonic-gate sp->socket_num); 85880Sstevel@tonic-gate } else if (ret != CS_SUCCESS) { 85890Sstevel@tonic-gate if (cs_debug > 0) 85900Sstevel@tonic-gate cmn_err(CE_CONT, "cs_create_cis: socket %d ERROR = 0x%x\n", 85910Sstevel@tonic-gate sp->socket_num, ret); 85920Sstevel@tonic-gate return (ret); 85930Sstevel@tonic-gate } 85940Sstevel@tonic-gate #else 85950Sstevel@tonic-gate if (ret != CS_NO_CIS) 85960Sstevel@tonic-gate if (ret != CS_SUCCESS) 85970Sstevel@tonic-gate return (ret); 85980Sstevel@tonic-gate #endif 85990Sstevel@tonic-gate 86000Sstevel@tonic-gate /* 86010Sstevel@tonic-gate * If this card didn't have any CIS at all, there's not much 86020Sstevel@tonic-gate * else for us to do. 86030Sstevel@tonic-gate */ 86040Sstevel@tonic-gate if (!(sp->cis_flags & CW_VALID_CIS)) 86050Sstevel@tonic-gate return (CS_SUCCESS); 86060Sstevel@tonic-gate 86070Sstevel@tonic-gate /* 86080Sstevel@tonic-gate * If this is a single-function card, we need to move the CIS list 86090Sstevel@tonic-gate * that is currently on CS_GLOBAL_CIS to the function zero 86100Sstevel@tonic-gate * CIS list. 86110Sstevel@tonic-gate */ 86120Sstevel@tonic-gate if (!(sp->cis_flags & CW_MULTI_FUNCTION_CIS)) { 86130Sstevel@tonic-gate bcopy((caddr_t)&sp->cis[CS_GLOBAL_CIS], 86140Sstevel@tonic-gate (caddr_t)&sp->cis[0], sizeof (cis_info_t)); 86150Sstevel@tonic-gate bzero((caddr_t)&sp->cis[CS_GLOBAL_CIS], sizeof (cis_info_t)); 86160Sstevel@tonic-gate } /* !CW_MULTI_FUNCTION_CIS */ 86170Sstevel@tonic-gate 86180Sstevel@tonic-gate return (CS_SUCCESS); 86190Sstevel@tonic-gate } 86200Sstevel@tonic-gate 86210Sstevel@tonic-gate /* 86220Sstevel@tonic-gate * cs_destroy_cis - destroys CIS list for socket 86230Sstevel@tonic-gate */ 86240Sstevel@tonic-gate static int 86250Sstevel@tonic-gate cs_destroy_cis(cs_socket_t *sp) 86260Sstevel@tonic-gate { 86270Sstevel@tonic-gate CIS_PARSER(CISP_CIS_LIST_DESTROY, sp); 86280Sstevel@tonic-gate 86290Sstevel@tonic-gate return (CS_SUCCESS); 86300Sstevel@tonic-gate } 86310Sstevel@tonic-gate 86320Sstevel@tonic-gate /* 86330Sstevel@tonic-gate * cs_get_client_info - This function is GetClientInfo. 86340Sstevel@tonic-gate * 86350Sstevel@tonic-gate * calling: client_handle_t - client handle to get client info on 86360Sstevel@tonic-gate * client_info_t * - pointer to a client_info_t structure 86370Sstevel@tonic-gate * to return client information in 86380Sstevel@tonic-gate * 86390Sstevel@tonic-gate * returns: CS_SUCCESS - if client info retreived from client 86400Sstevel@tonic-gate * CS_BAD_SOCKET, CS_BAD_HANDLE - if invalid client 86410Sstevel@tonic-gate * handle passed in 86420Sstevel@tonic-gate * CS_NO_MORE_ITEMS - if client does not handle the 86430Sstevel@tonic-gate * CS_EVENT_CLIENT_INFO event 86440Sstevel@tonic-gate * or if invalid client info 86450Sstevel@tonic-gate * retreived from client 86460Sstevel@tonic-gate */ 86470Sstevel@tonic-gate static int 86480Sstevel@tonic-gate cs_get_client_info(client_handle_t client_handle, client_info_t *ci) 86490Sstevel@tonic-gate { 86500Sstevel@tonic-gate cs_socket_t *sp; 86510Sstevel@tonic-gate client_t *client; 86520Sstevel@tonic-gate client_info_t *cinfo; 86530Sstevel@tonic-gate int ret = CS_SUCCESS; 86540Sstevel@tonic-gate 86550Sstevel@tonic-gate if (CLIENT_HANDLE_IS_SS(client_handle)) { 86560Sstevel@tonic-gate ci->Attributes = (CS_CLIENT_INFO_SOCKET_SERVICES | 86570Sstevel@tonic-gate CS_CLIENT_INFO_VALID); 86580Sstevel@tonic-gate return (CS_SUCCESS); 86590Sstevel@tonic-gate } /* CLIENT_HANDLE_IS_SS */ 86600Sstevel@tonic-gate 86610Sstevel@tonic-gate if ((sp = cs_get_sp(GET_CLIENT_SOCKET(client_handle))) == NULL) 86620Sstevel@tonic-gate return (CS_BAD_SOCKET); 86630Sstevel@tonic-gate 86640Sstevel@tonic-gate mutex_enter(&sp->client_lock); 86650Sstevel@tonic-gate mutex_enter(&sp->lock); 86660Sstevel@tonic-gate 86670Sstevel@tonic-gate if ((client = cs_find_client(client_handle, &ret)) == NULL) { 86680Sstevel@tonic-gate mutex_exit(&sp->lock); 86690Sstevel@tonic-gate mutex_exit(&sp->client_lock); 86700Sstevel@tonic-gate return (ret); 86710Sstevel@tonic-gate } /* cs_find_client */ 86720Sstevel@tonic-gate 86730Sstevel@tonic-gate /* 86740Sstevel@tonic-gate * If this client is not handling CS_EVENT_CLIENT_INFO events, 86750Sstevel@tonic-gate * then don't bother to even wake up the event thread. 86760Sstevel@tonic-gate */ 86770Sstevel@tonic-gate if (!((client->event_mask | client->global_mask) & 86780Sstevel@tonic-gate CS_EVENT_CLIENT_INFO)) { 86790Sstevel@tonic-gate mutex_exit(&sp->lock); 86800Sstevel@tonic-gate mutex_exit(&sp->client_lock); 86810Sstevel@tonic-gate return (CS_NO_MORE_ITEMS); 86820Sstevel@tonic-gate } /* !CS_EVENT_CLIENT_INFO */ 86830Sstevel@tonic-gate 86840Sstevel@tonic-gate cinfo = &client->event_callback_args.client_info; 86850Sstevel@tonic-gate 86860Sstevel@tonic-gate bzero((caddr_t)cinfo, sizeof (client_info_t)); 86870Sstevel@tonic-gate cinfo->Attributes = (ci->Attributes & CS_CLIENT_INFO_SUBSVC_MASK); 86880Sstevel@tonic-gate 86890Sstevel@tonic-gate client->events |= CS_EVENT_CLIENT_INFO; 86900Sstevel@tonic-gate 86910Sstevel@tonic-gate sp->thread_state |= SOCKET_WAIT_SYNC; 86920Sstevel@tonic-gate mutex_exit(&sp->lock); 86930Sstevel@tonic-gate cv_broadcast(&sp->thread_cv); 86940Sstevel@tonic-gate cv_wait(&sp->caller_cv, &sp->client_lock); 86950Sstevel@tonic-gate 86960Sstevel@tonic-gate if (cinfo->Attributes & CS_CLIENT_INFO_VALID) { 86970Sstevel@tonic-gate bcopy((caddr_t)cinfo, (caddr_t)ci, sizeof (client_info_t)); 86980Sstevel@tonic-gate ci->Attributes &= (CS_CLIENT_INFO_FLAGS_MASK | 86990Sstevel@tonic-gate CS_CLIENT_INFO_SUBSVC_MASK); 87000Sstevel@tonic-gate ci->Attributes &= ~(CS_CLIENT_INFO_CLIENT_MASK | 87010Sstevel@tonic-gate INFO_CARD_FLAGS_MASK | 87020Sstevel@tonic-gate CS_CLIENT_INFO_CLIENT_ACTIVE); 87030Sstevel@tonic-gate ci->Attributes |= (client->flags & (CS_CLIENT_INFO_CLIENT_MASK | 87040Sstevel@tonic-gate INFO_CARD_FLAGS_MASK)); 87050Sstevel@tonic-gate (void) strcpy(ci->DriverName, client->driver_name); 87060Sstevel@tonic-gate if (cs_card_for_client(client)) 87070Sstevel@tonic-gate ci->Attributes |= CS_CLIENT_INFO_CLIENT_ACTIVE; 87080Sstevel@tonic-gate } else { 87090Sstevel@tonic-gate ret = CS_NO_MORE_ITEMS; 87100Sstevel@tonic-gate } /* CS_CLIENT_INFO_VALID */ 87110Sstevel@tonic-gate 87120Sstevel@tonic-gate mutex_exit(&sp->client_lock); 87130Sstevel@tonic-gate 87140Sstevel@tonic-gate return (ret); 87150Sstevel@tonic-gate } 87160Sstevel@tonic-gate 87170Sstevel@tonic-gate /* 87180Sstevel@tonic-gate * cs_get_firstnext_client - This function is GetFirstClient and 87190Sstevel@tonic-gate * GetNextClient 87200Sstevel@tonic-gate * 87210Sstevel@tonic-gate * calling: get_firstnext_client_t * - pointer to a get_firstnext_client_t 87220Sstevel@tonic-gate * structure to return client handle and 87230Sstevel@tonic-gate * attributes in 87240Sstevel@tonic-gate * flags - one of the following: 87250Sstevel@tonic-gate * CS_GET_FIRST_FLAG - get first client handle 87260Sstevel@tonic-gate * CS_GET_NEXT_FLAG - get next client handle 87270Sstevel@tonic-gate * 87280Sstevel@tonic-gate * returns: CS_SUCCESS - if client info retreived from client 87290Sstevel@tonic-gate * CS_BAD_SOCKET, CS_BAD_HANDLE - if invalid client 87300Sstevel@tonic-gate * handle passed in 87310Sstevel@tonic-gate * CS_NO_MORE_ITEMS - if client does not handle the 87320Sstevel@tonic-gate * CS_EVENT_CLIENT_INFO event 87330Sstevel@tonic-gate * or if invalid client info 87340Sstevel@tonic-gate * retreived from client 87350Sstevel@tonic-gate */ 87360Sstevel@tonic-gate static int 87370Sstevel@tonic-gate cs_get_firstnext_client(get_firstnext_client_t *fnc, uint32_t flags) 87380Sstevel@tonic-gate { 87390Sstevel@tonic-gate cs_socket_t *sp; 87400Sstevel@tonic-gate client_t *client; 87410Sstevel@tonic-gate uint32_t sn = 0; 87420Sstevel@tonic-gate int ret = CS_SUCCESS; 87430Sstevel@tonic-gate 87440Sstevel@tonic-gate switch (flags) { 87450Sstevel@tonic-gate case CS_GET_FIRST_FLAG: 87460Sstevel@tonic-gate if (fnc->Attributes & CS_GET_FIRSTNEXT_CLIENT_ALL_CLIENTS) { 87470Sstevel@tonic-gate while (sn < cs_globals.max_socket_num) { 87480Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) != NULL) { 87490Sstevel@tonic-gate mutex_enter(&sp->client_lock); 87500Sstevel@tonic-gate if ((client = sp->client_list) != NULL) 87510Sstevel@tonic-gate break; 87520Sstevel@tonic-gate mutex_exit(&sp->client_lock); 87530Sstevel@tonic-gate } /* if */ 87540Sstevel@tonic-gate sn++; 87550Sstevel@tonic-gate } /* while */ 87560Sstevel@tonic-gate 87570Sstevel@tonic-gate if (sn == cs_globals.max_socket_num) 87580Sstevel@tonic-gate return (CS_NO_MORE_ITEMS); 87590Sstevel@tonic-gate } else if (fnc->Attributes & 87600Sstevel@tonic-gate CS_GET_FIRSTNEXT_CLIENT_SOCKET_ONLY) { 87610Sstevel@tonic-gate if ((sp = cs_get_sp(CS_GET_SOCKET_NUMBER(fnc->Socket))) == 87620Sstevel@tonic-gate NULL) 87630Sstevel@tonic-gate return (CS_BAD_SOCKET); 87640Sstevel@tonic-gate mutex_enter(&sp->client_lock); 87650Sstevel@tonic-gate if ((client = sp->client_list) == NULL) { 87660Sstevel@tonic-gate mutex_exit(&sp->client_lock); 87670Sstevel@tonic-gate return (CS_NO_MORE_ITEMS); 87680Sstevel@tonic-gate } 87690Sstevel@tonic-gate } else { 87700Sstevel@tonic-gate return (CS_BAD_ATTRIBUTE); 87710Sstevel@tonic-gate } 87720Sstevel@tonic-gate 87730Sstevel@tonic-gate fnc->client_handle = client->client_handle; 87740Sstevel@tonic-gate fnc->num_clients = sp->num_clients; 87750Sstevel@tonic-gate mutex_exit(&sp->client_lock); 87760Sstevel@tonic-gate break; 87770Sstevel@tonic-gate case CS_GET_NEXT_FLAG: 87780Sstevel@tonic-gate if (fnc->Attributes & CS_GET_FIRSTNEXT_CLIENT_ALL_CLIENTS) { 87790Sstevel@tonic-gate sn = GET_CLIENT_SOCKET(fnc->client_handle); 87800Sstevel@tonic-gate 87810Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) == NULL) 87820Sstevel@tonic-gate return (CS_BAD_SOCKET); 87830Sstevel@tonic-gate 87840Sstevel@tonic-gate mutex_enter(&sp->client_lock); 87850Sstevel@tonic-gate if ((client = cs_find_client(fnc->client_handle, 87860Sstevel@tonic-gate &ret)) == NULL) { 87870Sstevel@tonic-gate mutex_exit(&sp->client_lock); 87880Sstevel@tonic-gate return (ret); 87890Sstevel@tonic-gate } 87900Sstevel@tonic-gate if ((client = client->next) == NULL) { 87910Sstevel@tonic-gate mutex_exit(&sp->client_lock); 87920Sstevel@tonic-gate sn++; 87930Sstevel@tonic-gate while (sn < cs_globals.max_socket_num) { 87940Sstevel@tonic-gate if ((sp = cs_get_sp(sn)) != NULL) { 87950Sstevel@tonic-gate mutex_enter(&sp->client_lock); 87960Sstevel@tonic-gate if ((client = sp->client_list) != NULL) 87970Sstevel@tonic-gate break; 87980Sstevel@tonic-gate mutex_exit(&sp->client_lock); 87990Sstevel@tonic-gate } /* if */ 88000Sstevel@tonic-gate sn++; 88010Sstevel@tonic-gate } /* while */ 88020Sstevel@tonic-gate 88030Sstevel@tonic-gate if (sn == cs_globals.max_socket_num) 88040Sstevel@tonic-gate return (CS_NO_MORE_ITEMS); 88050Sstevel@tonic-gate } /* client = client->next */ 88060Sstevel@tonic-gate 88070Sstevel@tonic-gate } else if (fnc->Attributes & 88080Sstevel@tonic-gate CS_GET_FIRSTNEXT_CLIENT_SOCKET_ONLY) { 88090Sstevel@tonic-gate sp = cs_get_sp(GET_CLIENT_SOCKET(fnc->client_handle)); 88100Sstevel@tonic-gate if (sp == NULL) 88110Sstevel@tonic-gate return (CS_BAD_SOCKET); 88120Sstevel@tonic-gate mutex_enter(&sp->client_lock); 88130Sstevel@tonic-gate if ((client = cs_find_client(fnc->client_handle, 88140Sstevel@tonic-gate &ret)) == NULL) { 88150Sstevel@tonic-gate mutex_exit(&sp->client_lock); 88160Sstevel@tonic-gate return (ret); 88170Sstevel@tonic-gate } 88180Sstevel@tonic-gate if ((client = client->next) == NULL) { 88190Sstevel@tonic-gate mutex_exit(&sp->client_lock); 88200Sstevel@tonic-gate return (CS_NO_MORE_ITEMS); 88210Sstevel@tonic-gate } 88220Sstevel@tonic-gate } else { 88230Sstevel@tonic-gate return (CS_BAD_ATTRIBUTE); 88240Sstevel@tonic-gate } 88250Sstevel@tonic-gate 88260Sstevel@tonic-gate fnc->client_handle = client->client_handle; 88270Sstevel@tonic-gate fnc->num_clients = sp->num_clients; 88280Sstevel@tonic-gate mutex_exit(&sp->client_lock); 88290Sstevel@tonic-gate break; 88300Sstevel@tonic-gate default: 88310Sstevel@tonic-gate ret = CS_BAD_ATTRIBUTE; 88320Sstevel@tonic-gate break; 88330Sstevel@tonic-gate 88340Sstevel@tonic-gate } /* switch */ 88350Sstevel@tonic-gate 88360Sstevel@tonic-gate return (ret); 88370Sstevel@tonic-gate } 88380Sstevel@tonic-gate 88390Sstevel@tonic-gate /* 88400Sstevel@tonic-gate * cs_set_acc_attributes - converts Card Services endianness and 88410Sstevel@tonic-gate * data ordering values to values 88420Sstevel@tonic-gate * that Socket Services understands 88430Sstevel@tonic-gate * 88440Sstevel@tonic-gate * calling: *sw - pointer to a set_window_t to set attributes in 88450Sstevel@tonic-gate * Attributes - CS attributes 88460Sstevel@tonic-gate */ 88470Sstevel@tonic-gate static void 88480Sstevel@tonic-gate cs_set_acc_attributes(set_window_t *sw, uint32_t Attributes) 88490Sstevel@tonic-gate { 88500Sstevel@tonic-gate sw->attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 88510Sstevel@tonic-gate 88520Sstevel@tonic-gate switch (Attributes & WIN_ACC_ENDIAN_MASK) { 88530Sstevel@tonic-gate case WIN_ACC_LITTLE_ENDIAN: 88540Sstevel@tonic-gate sw->attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 88550Sstevel@tonic-gate break; 88560Sstevel@tonic-gate case WIN_ACC_BIG_ENDIAN: 88570Sstevel@tonic-gate sw->attr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC; 88580Sstevel@tonic-gate break; 88590Sstevel@tonic-gate case WIN_ACC_NEVER_SWAP: 88600Sstevel@tonic-gate default: 88610Sstevel@tonic-gate sw->attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 88620Sstevel@tonic-gate break; 88630Sstevel@tonic-gate } /* switch */ 88640Sstevel@tonic-gate 88650Sstevel@tonic-gate switch (Attributes & WIN_ACC_ORDER_MASK) { 88660Sstevel@tonic-gate case WIN_ACC_UNORDERED_OK: 88670Sstevel@tonic-gate sw->attr.devacc_attr_dataorder = DDI_UNORDERED_OK_ACC; 88680Sstevel@tonic-gate break; 88690Sstevel@tonic-gate case WIN_ACC_MERGING_OK: 88700Sstevel@tonic-gate sw->attr.devacc_attr_dataorder = DDI_MERGING_OK_ACC; 88710Sstevel@tonic-gate break; 88720Sstevel@tonic-gate case WIN_ACC_LOADCACHING_OK: 88730Sstevel@tonic-gate sw->attr.devacc_attr_dataorder = DDI_LOADCACHING_OK_ACC; 88740Sstevel@tonic-gate break; 88750Sstevel@tonic-gate case WIN_ACC_STORECACHING_OK: 88760Sstevel@tonic-gate sw->attr.devacc_attr_dataorder = DDI_STORECACHING_OK_ACC; 88770Sstevel@tonic-gate break; 88780Sstevel@tonic-gate case WIN_ACC_STRICT_ORDER: 88790Sstevel@tonic-gate default: 88800Sstevel@tonic-gate sw->attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 88810Sstevel@tonic-gate break; 88820Sstevel@tonic-gate } /* switch */ 88830Sstevel@tonic-gate } 8884